diff --git a/recipes-kernel/linux/linux-stm32mp-archiver.inc b/recipes-kernel/linux/linux-stm32mp-archiver.inc new file mode 100644 index 0000000..01b4ff5 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp-archiver.inc @@ -0,0 +1,9 @@ +# +# Archiver Configuration +# +SRC_URI_append = " file://README.HOW_TO.txt " + +inherit archiver +ARCHIVER_MODE[src] = "original" + +inherit archiver_stm32mp_clean diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0001-ARM-stm32mp1-r2-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0001-ARM-stm32mp1-r2-MACHINE.patch new file mode 100644 index 0000000..ed3f1f0 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0001-ARM-stm32mp1-r2-MACHINE.patch @@ -0,0 +1,82 @@ +From 747a93a65dc5e3761539c365a272186f0b7fca08 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:11:59 +0200 +Subject: [PATCH 01/30] ARM stm32mp1 r2 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.49/0002-ARM-stm32mp1-r2-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0002-ARM-stm32mp1-r2-CRYPTO.patch new file mode 100644 index 0000000..251a4a9 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0002-ARM-stm32mp1-r2-CRYPTO.patch @@ -0,0 +1,1109 @@ +From 6a4b2788be21d13d65a726973003dc48405da004 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:11:59 +0200 +Subject: [PATCH 02/30] ARM stm32mp1 r2 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 | 8 +- + drivers/crypto/stm32/stm32_crc32.c | 387 -------------------------------- + 7 files changed, 503 insertions(+), 415 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 3664c26..7d0d6b4 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 590d735..990bbbf 100644 +--- a/drivers/crypto/stm32/stm32-hash.c ++++ b/drivers/crypto/stm32/stm32-hash.c +@@ -365,7 +365,7 @@ static int stm32_hash_xmit_cpu(struct stm32_hash_dev *hdev, + return -ETIMEDOUT; + + if ((hdev->flags & HASH_FLAGS_HMAC) && +- (hdev->flags & ~HASH_FLAGS_HMAC_KEY)) { ++ (!(hdev->flags & HASH_FLAGS_HMAC_KEY))) { + hdev->flags |= HASH_FLAGS_HMAC_KEY; + stm32_hash_write_key(hdev); + if (stm32_hash_wait_busy(hdev)) +@@ -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.49/0003-ARM-stm32mp1-r2-BLUETOOTH-CHAR.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0003-ARM-stm32mp1-r2-BLUETOOTH-CHAR.patch new file mode 100644 index 0000000..4f59830 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0003-ARM-stm32mp1-r2-BLUETOOTH-CHAR.patch @@ -0,0 +1,61 @@ +From 613535e3904f7615aff655384c65cd897312e3b0 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:11:59 +0200 +Subject: [PATCH 03/30] ARM stm32mp1 r2 BLUETOOTH CHAR + +--- + drivers/bluetooth/hci_bcm.c | 3 ++- + drivers/char/hw_random/stm32-rng.c | 9 +++++++++ + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c +index 8001323..31da580 100644 +--- a/drivers/bluetooth/hci_bcm.c ++++ b/drivers/bluetooth/hci_bcm.c +@@ -1299,7 +1299,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 042860d..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); +@@ -169,6 +170,13 @@ static int stm32_rng_probe(struct platform_device *ofdev) + return devm_hwrng_register(dev, &priv->rng); + } + ++static int stm32_rng_remove(struct platform_device *ofdev) ++{ ++ pm_runtime_disable(&ofdev->dev); ++ ++ return 0; ++} ++ + #ifdef CONFIG_PM + static int stm32_rng_runtime_suspend(struct device *dev) + { +@@ -210,6 +218,7 @@ static struct platform_driver stm32_rng_driver = { + .of_match_table = stm32_rng_match, + }, + .probe = stm32_rng_probe, ++ .remove = stm32_rng_remove, + }; + + module_platform_driver(stm32_rng_driver); +-- +2.7.4 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0002-ARM-stm32mp1-r0-rc1-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0004-ARM-stm32mp1-r2-CLOCK.patch similarity index 82% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0002-ARM-stm32mp1-r0-rc1-CLOCK.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0004-ARM-stm32mp1-r2-CLOCK.patch index 43b9b90..996623d 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0002-ARM-stm32mp1-r0-rc1-CLOCK.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0004-ARM-stm32mp1-r2-CLOCK.patch @@ -1,17 +1,17 @@ -From 2eae46b85e51f0b995ddfdd6176501d4a6cf1520 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:15:45 +0100 -Subject: [PATCH 02/52] ARM: stm32mp1-r0-rc1: CLOCK +From 787309b96cc3eb1ed824dff1a9814d88a437bebb Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:11:59 +0200 +Subject: [PATCH 04/30] ARM stm32mp1 r2 CLOCK --- - drivers/clk/clk-stm32mp1.c | 1022 ++++++++++++++++++++++++++--- + drivers/clk/clk-stm32mp1.c | 1061 ++++++++++++++++++++++++++--- drivers/clk/clk.c | 24 +- include/dt-bindings/clock/stm32mp1-clks.h | 3 - include/linux/clk.h | 1 + - 4 files changed, 968 insertions(+), 82 deletions(-) + 4 files changed, 1004 insertions(+), 85 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index a907555..50d739a 100644 +index a907555..fba9626 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -5,15 +5,22 @@ @@ -37,7 +37,15 @@ index a907555..50d739a 100644 #include -@@ -101,6 +108,10 @@ static DEFINE_SPINLOCK(rlock); +@@ -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 @@ -48,7 +56,7 @@ index a907555..50d739a 100644 #define RCC_CLR 0x4 -@@ -121,7 +132,7 @@ static const char * const cpu_src[] = { +@@ -121,7 +133,7 @@ static const char * const cpu_src[] = { }; static const char * const axi_src[] = { @@ -57,7 +65,7 @@ index a907555..50d739a 100644 }; static const char * const per_src[] = { -@@ -225,19 +236,19 @@ static const char * const usart6_src[] = { +@@ -225,19 +237,19 @@ static const char * const usart6_src[] = { }; static const char * const fdcan_src[] = { @@ -81,7 +89,7 @@ index a907555..50d739a 100644 }; static const char * const dsi_src[] = { -@@ -269,7 +280,7 @@ static const struct clk_div_table axi_div_table[] = { +@@ -269,7 +281,7 @@ static const struct clk_div_table axi_div_table[] = { static const struct clk_div_table mcu_div_table[] = { { 0, 1 }, { 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 }, { 5, 32 }, { 6, 64 }, { 7, 128 }, @@ -90,7 +98,7 @@ index a907555..50d739a 100644 { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, { 0 }, }; -@@ -356,17 +367,20 @@ struct stm32_gate_cfg { +@@ -356,17 +368,20 @@ struct stm32_gate_cfg { struct gate_cfg *gate; struct stm32_mgate *mgate; const struct clk_ops *ops; @@ -111,7 +119,7 @@ index a907555..50d739a 100644 }; /* STM32 Composite clock */ -@@ -376,6 +390,11 @@ struct stm32_composite_cfg { +@@ -376,6 +391,11 @@ struct stm32_composite_cfg { const struct stm32_mux_cfg *mux; }; @@ -123,7 +131,7 @@ index a907555..50d739a 100644 static struct clk_hw * _clk_hw_register_gate(struct device *dev, struct clk_hw_onecell_data *clk_data, -@@ -592,6 +611,9 @@ clk_stm32_register_gate_ops(struct device *dev, +@@ -592,6 +612,9 @@ clk_stm32_register_gate_ops(struct device *dev, if (cfg->ops) init.ops = cfg->ops; @@ -133,7 +141,7 @@ index a907555..50d739a 100644 hw = _get_stm32_gate(base, cfg, lock); if (IS_ERR(hw)) return ERR_PTR(-ENOMEM); -@@ -630,6 +652,9 @@ clk_stm32_register_composite(struct device *dev, +@@ -630,6 +653,9 @@ clk_stm32_register_composite(struct device *dev, if (cfg->mux->ops) mux_ops = cfg->mux->ops; @@ -143,7 +151,7 @@ index a907555..50d739a 100644 } } -@@ -641,6 +666,9 @@ clk_stm32_register_composite(struct device *dev, +@@ -641,6 +667,9 @@ clk_stm32_register_composite(struct device *dev, if (cfg->div->ops) div_ops = cfg->div->ops; @@ -153,7 +161,7 @@ index a907555..50d739a 100644 } } -@@ -652,6 +680,9 @@ clk_stm32_register_composite(struct device *dev, +@@ -652,6 +681,9 @@ clk_stm32_register_composite(struct device *dev, if (cfg->gate->ops) gate_ops = cfg->gate->ops; @@ -163,7 +171,7 @@ index a907555..50d739a 100644 } } -@@ -1193,7 +1224,8 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1193,7 +1225,8 @@ _clk_stm32_register_composite(struct device *dev, .func = _clk_stm32_register_gate,\ } @@ -173,7 +181,7 @@ index a907555..50d739a 100644 (&(struct stm32_gate_cfg) {\ &(struct gate_cfg) {\ .reg_off = _gate_offset,\ -@@ -1202,6 +1234,7 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1202,6 +1235,7 @@ _clk_stm32_register_composite(struct device *dev, },\ .mgate = _mgate,\ .ops = _ops,\ @@ -181,7 +189,7 @@ index a907555..50d739a 100644 }) #define _STM32_MGATE(_mgate)\ -@@ -1209,11 +1242,11 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1209,11 +1243,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,\ @@ -195,7 +203,7 @@ index a907555..50d739a 100644 #define _MGATE_MP1(_mgate)\ .gate = &per_gate_cfg[_mgate] -@@ -1227,7 +1260,7 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1227,7 +1261,7 @@ _clk_stm32_register_composite(struct device *dev, _STM32_MGATE(_mgate)) #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ @@ -204,7 +212,7 @@ index a907555..50d739a 100644 .div = &(struct stm32_div_cfg) {\ &(struct div_cfg) {\ .reg_off = _div_offset,\ -@@ -1237,13 +1270,14 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1237,13 +1271,14 @@ _clk_stm32_register_composite(struct device *dev, .table = _div_table,\ },\ .ops = _ops,\ @@ -221,7 +229,7 @@ index a907555..50d739a 100644 .mux = &(struct stm32_mux_cfg) {\ &(struct mux_cfg) {\ .reg_off = _offset,\ -@@ -1254,10 +1288,11 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1254,10 +1289,11 @@ _clk_stm32_register_composite(struct device *dev, },\ .mmux = _mmux,\ .ops = _ops,\ @@ -234,7 +242,7 @@ index a907555..50d739a 100644 #define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] -@@ -1286,10 +1321,513 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1286,10 +1322,513 @@ _clk_stm32_register_composite(struct device *dev, MGATE_MP1(_id, _name, _parent, _flags, _mgate) #define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ @@ -478,7 +486,7 @@ index a907555..50d739a 100644 + unsigned long parent_rate) +{ + struct clk_divider *divider = to_clk_divider(hw); -+ unsigned int value; ++ int value; + unsigned long flags = 0; + u32 val; + @@ -752,7 +760,15 @@ index a907555..50d739a 100644 enum { G_SAI1, -@@ -1408,7 +1946,7 @@ enum { +@@ -1401,6 +1940,7 @@ enum { + G_CRYP1, + G_HASH1, + G_BKPSRAM, ++ G_DDRPERFM, + + G_LAST + }; +@@ -1408,7 +1948,7 @@ enum { static struct stm32_mgate mp1_mgate[G_LAST]; #define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ @@ -761,7 +777,7 @@ index a907555..50d739a 100644 [_id] = {\ &(struct gate_cfg) {\ .reg_off = _gate_offset,\ -@@ -1417,15 +1955,24 @@ static struct stm32_mgate mp1_mgate[G_LAST]; +@@ -1417,15 +1957,24 @@ static struct stm32_mgate mp1_mgate[G_LAST]; },\ .mgate = _mgate,\ .ops = _ops,\ @@ -788,7 +804,11 @@ index a907555..50d739a 100644 /* Peripheral gates */ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { -@@ -1490,17 +2037,17 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { +@@ -1487,20 +2036,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), @@ -817,7 +837,7 @@ index a907555..50d739a 100644 K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), -@@ -1529,11 +2076,11 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { +@@ -1529,11 +2079,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), @@ -834,7 +854,7 @@ index a907555..50d739a 100644 K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), -@@ -1541,12 +2088,15 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { +@@ -1541,12 +2091,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), @@ -850,7 +870,7 @@ index a907555..50d739a 100644 K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), }; -@@ -1591,7 +2141,7 @@ enum { +@@ -1591,7 +2144,7 @@ enum { static struct stm32_mmux ker_mux[M_LAST]; @@ -859,7 +879,7 @@ index a907555..50d739a 100644 [_id] = {\ &(struct mux_cfg) {\ .reg_off = _offset,\ -@@ -1602,15 +2152,24 @@ static struct stm32_mmux ker_mux[M_LAST]; +@@ -1602,15 +2155,24 @@ static struct stm32_mmux ker_mux[M_LAST]; },\ .mmux = _mmux,\ .ops = _ops,\ @@ -886,7 +906,7 @@ index a907555..50d739a 100644 static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { /* Kernel multi mux */ -@@ -1626,7 +2185,7 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { +@@ -1626,7 +2188,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), @@ -895,7 +915,7 @@ index a907555..50d739a 100644 /* Kernel simple mux */ K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), -@@ -1647,10 +2206,10 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { +@@ -1647,23 +2209,24 @@ 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), @@ -910,8 +930,11 @@ index a907555..50d739a 100644 }; static const struct clock_config stm32mp1_clock_cfg[] = { -@@ -1659,11 +2218,12 @@ static const struct clock_config stm32mp1_clock_cfg[] = { - CLK_DIVIDER_READ_ONLY), + /* Oscillator divider */ +- DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, +- CLK_DIVIDER_READ_ONLY), ++ DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO, ++ RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), /* External / Internal Oscillators */ - GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), @@ -928,7 +951,7 @@ index a907555..50d739a 100644 FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), -@@ -1685,24 +2245,24 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1685,24 +2248,24 @@ static const struct clock_config stm32mp1_clock_cfg[] = { /* ODF */ COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, @@ -961,7 +984,7 @@ index a907555..50d739a 100644 COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, _GATE(RCC_PLL3CR, 4, 0), -@@ -1738,20 +2298,20 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1738,20 +2301,20 @@ static const struct clock_config stm32mp1_clock_cfg[] = { MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, RCC_CPERCKSELR, 0, 2, 0), @@ -987,7 +1010,15 @@ index a907555..50d739a 100644 DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, 3, CLK_DIVIDER_READ_ONLY, apb_div_table), -@@ -1906,7 +2466,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1896,6 +2459,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), +@@ -1906,7 +2470,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), @@ -996,7 +1027,7 @@ index a907555..50d739a 100644 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), -@@ -1952,19 +2512,20 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1952,19 +2516,19 @@ static const struct clock_config stm32mp1_clock_cfg[] = { MGATE_MP1(GPU_K, "gpu_k", "pll2_q", 0, G_GPU), MGATE_MP1(DAC12_K, "dac12_k", "ck_lsi", 0, G_DAC12), @@ -1005,13 +1036,13 @@ index a907555..50d739a 100644 + 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, 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, 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, @@ -1022,7 +1053,7 @@ index a907555..50d739a 100644 _NO_DIV), /* MCO clocks */ -@@ -2082,21 +2643,334 @@ static int stm32_rcc_init(struct device_node *np, +@@ -2082,21 +2646,364 @@ static int stm32_rcc_init(struct device_node *np, return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); } @@ -1061,8 +1092,6 @@ index a907555..50d739a 100644 + * + */ + -+static struct regmap *pwr_syscon; -+ +struct reg { + u32 address; + u32 val; @@ -1086,82 +1115,91 @@ index a907555..50d739a 100644 + 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[] = { -+ { 0xA00, 0 }, /* APB1 */ -+ { 0xA08, 0 }, /* APB2 */ -+ { 0xA10, 0 }, /* APB3 */ -+ { 0x200, 0 }, /* APB4 */ -+ { 0x208, 1 }, /* APB5 */ -+ { 0x210, 1 }, /* AHB5 */ -+ { 0x218, 0 }, /* AHB6 */ -+ { 0xA18, 0 }, /* AHB2 */ -+ { 0xA20, 0 }, /* AHB3 */ -+ { 0xA28, 0 }, /* AHB4 */ -+ { 0xA38, 0 }, /* MLAHB */ -+ { 0x800, 0 }, /* MCO1 */ -+ { 0x804, 0 }, /* MCO2 */ -+ { 0x894, 0 }, /* PLL4 */ -+ { 0x89C, 0 }, /* PLL4CFGR2 */ ++ 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 { -+ const char *name; -+ struct clk *clk; -+ struct clk *clkp; ++ u32 clk_id; ++ u32 mux_id; ++ struct clk_hw *hw; +}; + -+#define KER_SRC(_clk_name)\ ++#define KER_SRC(_clk_id, _mux_id)\ +{\ -+ .name = _clk_name,\ ++ .clk_id = _clk_id,\ ++ .mux_id = _mux_id,\ +} + -+struct smux _mux_kernel[] = { -+ KER_SRC("sdmmc1_k"), -+ KER_SRC("spi2_k"), -+ KER_SRC("spi4_k"), -+ KER_SRC("i2c1_k"), -+ KER_SRC("i2c3_k"), -+ KER_SRC("lptim2_k"), -+ KER_SRC("lptim3_k"), -+ KER_SRC("usart2_k"), -+ KER_SRC("usart3_k"), -+ KER_SRC("uart7_k"), -+ KER_SRC("sai1_k"), -+ KER_SRC("ethck_k"), -+ KER_SRC("i2c4_k"), -+ KER_SRC("rng2_k"), -+ KER_SRC("sdmmc3_k"), -+ KER_SRC("fmc_k"), -+ KER_SRC("qspi_k"), -+ KER_SRC("usbphy_k"), -+ KER_SRC("usbo_k"), -+ KER_SRC("spdif_k"), -+ KER_SRC("spi1_k"), -+ KER_SRC("cec_k"), -+ KER_SRC("lptim1_k"), -+ KER_SRC("uart6_k"), -+ KER_SRC("fdcan_k"), -+ KER_SRC("sai2_k"), -+ KER_SRC("sai3_k"), -+ KER_SRC("sai4_k"), -+ KER_SRC("adc12_k"), -+ KER_SRC("dsi_k"), -+ KER_SRC("ck_per"), -+ KER_SRC("rng1_k"), -+ KER_SRC("stgen_k"), -+ KER_SRC("usart1_k"), -+ KER_SRC("spi6_k"), ++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[] = { -+ { 0x880, 0 }, /* PLL3 */ -+ { 0x894, 0 }, /* PLL4 */ ++ SREG(RCC_PLL3CR, 0, 0), ++ SREG(RCC_PLL4CR, 0, 0), +}; + +static struct sreg mcu_source[] = { -+ { 0x048, 0 }, /* MSSCKSELR */ ++ SREG(RCC_MCUDIVR, 0, 0), ++ SREG(RCC_MSSCKSELR, 0, 0), +}; + +#define RCC_IRQ_FLAGS_MASK 0x110F1F @@ -1173,9 +1211,6 @@ index a907555..50d739a 100644 +#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"); @@ -1197,7 +1232,7 @@ index a907555..50d739a 100644 +static void stm32mp1_restore_sreg(struct sreg *sreg, int size) +{ + int i; -+ u32 val, address; ++ u32 val, address, reg; + int soc_secured; + + soc_secured = _is_soc_secured(rcc_base); @@ -1206,11 +1241,21 @@ index a907555..50d739a 100644 + val = sreg[i].val; + address = sreg[i].address; + -+ if (soc_secured && sreg[i].secured) -+ SMC(STM32_SVC_RCC, STM32_WRITE, -+ address, val); -+ else ++ 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); ++ } + } +} + @@ -1236,22 +1281,52 @@ index a907555..50d739a 100644 + } +} + -+static void stm32mp1_backup_mux(struct smux *smux, int size) ++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++) { -+ smux[i].clk = __clk_lookup(smux[i].name); -+ smux[i].clkp = clk_get_parent(smux[i].clk); ++ 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; + -+ for (i = 0; i < size; i++) -+ clk_set_parent_force(smux[i].clk, smux[i].clkp); ++ /* 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 @@ -1275,38 +1350,27 @@ index a907555..50d739a 100644 + /* Save clock gating regs */ + stm32mp1_backup_sreg(clock_gating, ARRAY_SIZE(clock_gating)); + -+ /* Save kernel clock regs */ -+ stm32mp1_backup_mux(_mux_kernel, ARRAY_SIZE(_mux_kernel)); -+ + /* 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) +{ -+ u32 power_flags_rcc, power_flags_pwr; + -+ /* Read power flags and decide what to resume */ -+ regmap_read(pwr_syscon, PWR_MPUCR, &power_flags_pwr); -+ power_flags_rcc = readl_relaxed(rcc_base + RCC_RSTSR); ++ /* Restore pll */ ++ stm32mp1_restore_pll(pll_clock, ARRAY_SIZE(pll_clock)); + -+ if ((power_flags_pwr & STOP_FLAG) == STOP_FLAG) { -+ /* Restore pll */ -+ stm32mp1_restore_pll(pll_clock, ARRAY_SIZE(pll_clock)); ++ /* Restore mcu source */ ++ stm32mp1_restore_sreg(mcu_source, ARRAY_SIZE(mcu_source)); + -+ /* Restore mcu source */ -+ stm32mp1_restore_sreg(mcu_source, ARRAY_SIZE(mcu_source)); -+ } else if (((power_flags_rcc & SBF) == SBF) || -+ ((power_flags_rcc & SBF_MPU) == SBF_MPU)) { -+ stm32mp1_restore_sreg(clock_gating, ARRAY_SIZE(clock_gating)); ++ stm32mp1_restore_sreg(clock_gating, ARRAY_SIZE(clock_gating)); + -+ stm32mp1_restore_mux(_mux_kernel, ARRAY_SIZE(_mux_kernel)); -+ } -+ -+ SMC(STM32_SVC_RCC, STM32_WRITE, RCC_RSTSR, 0); ++ 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, @@ -1330,17 +1394,11 @@ index a907555..50d739a 100644 + int ret; + int i; + -+ pwr_syscon = syscon_regmap_lookup_by_phandle(np, "st,pwr"); -+ if (IS_ERR(pwr_syscon)) { -+ pr_err("%s: pwr syscon required !\n", __func__); -+ return PTR_ERR(pwr_syscon); -+ } -+ + /* register generic irq */ + irq = of_irq_get(np, 0); -+ if (irq < 0) { ++ if (irq <= 0) { + pr_err("%s: failed to get RCC generic IRQ\n", __func__); -+ return irq; ++ return irq ? irq : -ENXIO; + } + + ret = setup_irq(irq, &rcc_irq); @@ -1359,12 +1417,15 @@ index a907555..50d739a 100644 + + 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 d31055a..6d8326d 100644 +index 5413ffa..25a4af5 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2204,7 +2204,8 @@ bool clk_has_parent(struct clk *clk, struct clk *parent) diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0003-ARM-stm32mp1-r0-rc1-DMA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0005-ARM-stm32mp1-r2-DMA.patch similarity index 86% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0003-ARM-stm32mp1-r0-rc1-DMA.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0005-ARM-stm32mp1-r2-DMA.patch index 9f436ab..ea1c1cc 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0003-ARM-stm32mp1-r0-rc1-DMA.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0005-ARM-stm32mp1-r2-DMA.patch @@ -1,16 +1,16 @@ -From 234beab933e3faccae9ea8ea383ac85fa718a886 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:16:55 +0100 -Subject: [PATCH 03/52] ARM: stm32mp1-r0-rc1: DMA +From d13371d49b7675f62cdd16b4937eac738d862acd Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:00 +0200 +Subject: [PATCH 05/30] ARM stm32mp1 r2 DMA --- - drivers/dma/stm32-dma.c | 1030 ++++++++++++++++++++++++++++++++++++++------ + drivers/dma/stm32-dma.c | 1142 +++++++++++++++++++++++++++++++++++++------- drivers/dma/stm32-dmamux.c | 110 ++++- - drivers/dma/stm32-mdma.c | 222 +++++++++- - 3 files changed, 1195 insertions(+), 167 deletions(-) + drivers/dma/stm32-mdma.c | 232 ++++++++- + 3 files changed, 1285 insertions(+), 199 deletions(-) diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 379e8d5..4830f8e 100644 +index 379e8d5..87db5a7 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -15,14 +15,18 @@ @@ -53,7 +53,7 @@ index 379e8d5..4830f8e 100644 enum stm32_dma_width { STM32_DMA_BYTE, -@@ -176,15 +187,31 @@ struct stm32_dma_chan_reg { +@@ -176,15 +187,32 @@ struct stm32_dma_chan_reg { u32 dma_sfcr; }; @@ -83,10 +83,11 @@ index 379e8d5..4830f8e 100644 u32 num_sgs; + dma_addr_t dma_buf; + void *dma_buf_cpu; ++ u32 dma_buf_size; struct stm32_dma_sg_req sg_req[]; }; -@@ -201,6 +228,10 @@ struct stm32_dma_chan { +@@ -201,6 +229,10 @@ struct stm32_dma_chan { u32 threshold; u32 mem_burst; u32 mem_width; @@ -97,7 +98,7 @@ index 379e8d5..4830f8e 100644 }; struct stm32_dma_device { -@@ -210,6 +241,7 @@ struct stm32_dma_device { +@@ -210,6 +242,7 @@ struct stm32_dma_device { struct reset_control *rst; bool mem2mem; struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS]; @@ -105,7 +106,7 @@ index 379e8d5..4830f8e 100644 }; static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) -@@ -308,20 +340,12 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, +@@ -308,20 +341,12 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold) { @@ -132,7 +133,39 @@ index 379e8d5..4830f8e 100644 } static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold, -@@ -497,11 +521,15 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) +@@ -436,7 +461,6 @@ 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; + + id = chan->id; +@@ -446,19 +470,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); + +- do { +- dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); +- dma_scr &= STM32_DMA_SCR_EN; +- if (!dma_scr) +- break; +- +- if (time_after_eq(jiffies, timeout)) { +- dev_err(chan2dev(chan), "%s: timeout!\n", +- __func__); +- return -EBUSY; +- } +- cond_resched(); +- } while (1); ++ return readl_relaxed_poll_timeout_atomic( ++ dmadev->base + STM32_DMA_SCR(id), ++ dma_scr, !(dma_scr & STM32_DMA_SCR_EN), ++ 10, 1000000); + } + + return 0; +@@ -497,13 +512,23 @@ 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); @@ -140,15 +173,26 @@ index 379e8d5..4830f8e 100644 unsigned long flags; LIST_HEAD(head); - spin_lock_irqsave(&chan->vchan.lock, flags); +- spin_lock_irqsave(&chan->vchan.lock, flags); -+ if (chan->use_mdma) +- if (chan->busy) { +- stm32_dma_stop(chan); ++ if (chan->use_mdma) { ++ spin_lock_irqsave_nested(&chan->vchan.lock, flags, ++ SINGLE_DEPTH_NESTING); + dmaengine_terminate_async(mchan->chan); ++ } 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) ++ stm32_dma_stop(chan); chan->desc = NULL; -@@ -514,9 +542,96 @@ static int stm32_dma_terminate_all(struct dma_chan *c) + } + +@@ -514,9 +539,96 @@ static int stm32_dma_terminate_all(struct dma_chan *c) return 0; } @@ -245,7 +289,7 @@ index 379e8d5..4830f8e 100644 vchan_synchronize(&chan->vchan); } -@@ -539,62 +654,206 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) +@@ -539,62 +651,205 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); } @@ -374,7 +418,7 @@ index 379e8d5..4830f8e 100644 + dev_err(chan2dev(chan), + "%s timeout waiting for last bytes\n", + __func__); -+ break; ++ return -EBUSY; + } + cpu_relax(); + residue = stm32_dma_get_remaining_bytes(chan); @@ -438,7 +482,6 @@ index 379e8d5..4830f8e 100644 - if (status) - stm32_dma_irq_clear(chan, status); + if (chan->next_sg == chan->desc->num_sgs) { -+ list_del(&chan->desc->vdesc.node); + vchan_cookie_complete(&chan->desc->vdesc); + chan->desc = NULL; + } @@ -490,7 +533,7 @@ index 379e8d5..4830f8e 100644 } static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) -@@ -626,35 +885,146 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) +@@ -626,35 +881,147 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) } } @@ -518,6 +561,8 @@ index 379e8d5..4830f8e 100644 + if (!vdesc) + return; + ++ list_del(&vdesc->node); ++ + chan->desc = to_stm32_dma_desc(vdesc); + chan->next_sg = 0; + } else { @@ -625,7 +670,6 @@ index 379e8d5..4830f8e 100644 + if (chan->use_mdma && chan->mchan.dir != DMA_MEM_TO_DEV) + return; + if (chan->next_sg == chan->desc->num_sgs) { -+ list_del(&chan->desc->vdesc.node); + vchan_cookie_complete(&chan->desc->vdesc); + chan->desc = NULL; + } @@ -649,7 +693,7 @@ index 379e8d5..4830f8e 100644 if (status & STM32_DMA_TCI) { stm32_dma_irq_clear(chan, STM32_DMA_TCI); -@@ -669,10 +1039,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) +@@ -669,10 +1036,12 @@ 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; @@ -666,15 +710,27 @@ index 379e8d5..4830f8e 100644 } if (status) { stm32_dma_irq_clear(chan, status); -@@ -695,7 +1067,6 @@ static void stm32_dma_issue_pending(struct dma_chan *c) +@@ -691,12 +1060,17 @@ static void stm32_dma_issue_pending(struct dma_chan *c) + struct stm32_dma_chan *chan = to_stm32_dma_chan(c); + unsigned long flags; + +- spin_lock_irqsave(&chan->vchan.lock, flags); ++ if (chan->use_mdma) ++ spin_lock_irqsave_nested(&chan->vchan.lock, flags, ++ SINGLE_DEPTH_NESTING); ++ else ++ spin_lock_irqsave(&chan->vchan.lock, flags); ++ 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); } -@@ -836,16 +1207,167 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) + +@@ -836,16 +1210,169 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); } @@ -695,6 +751,7 @@ index 379e8d5..4830f8e 100644 + &desc->dma_buf); + if (!desc->dma_buf_cpu) + return -ENOMEM; ++ desc->dma_buf_size = chan->sram_size; + + sram_period = chan->sram_size / 2; + @@ -711,6 +768,7 @@ index 379e8d5..4830f8e 100644 + dev_err(chan2dev(chan), + "max buf size = %d bytes\n", + chan->sram_size); ++ ret = -EINVAL; + goto free_alloc; + } + } else { @@ -787,7 +845,7 @@ index 379e8d5..4830f8e 100644 + } +free_alloc: + gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu, -+ chan->sram_size); ++ desc->dma_buf_size); + return ret; +} + @@ -845,7 +903,7 @@ index 379e8d5..4830f8e 100644 int i, ret; if (!chan->config_init) { -@@ -868,48 +1390,142 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -868,48 +1395,141 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( else chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -916,7 +974,7 @@ index 379e8d5..4830f8e 100644 + + gen_pool_free(dmadev->sram_pool, + (unsigned long)desc->dma_buf_cpu, -+ chan->sram_size); ++ desc->dma_buf_size); + } kfree(desc); + @@ -932,7 +990,6 @@ index 379e8d5..4830f8e 100644 + struct stm32_dma_mdma *mchan = &chan->mchan; + struct stm32_dma_mdma_desc *m_desc = &desc->sg_req[0].m_desc; + struct dma_slave_config config; -+ dma_addr_t mem; + int ret; + + chan->sram_size = ALIGN(period_len, STM32_DMA_SRAM_GRANULARITY); @@ -941,9 +998,9 @@ index 379e8d5..4830f8e 100644 + &desc->dma_buf); + if (!desc->dma_buf_cpu) + return -ENOMEM; ++ desc->dma_buf_size = 2 * chan->sram_size; + + memset(&config, 0, sizeof(config)); -+ mem = buf_addr; + + /* Configure MDMA channel */ + if (chan->mchan.dir == DMA_MEM_TO_DEV) @@ -990,7 +1047,7 @@ index 379e8d5..4830f8e 100644 +err: + gen_pool_free(dmadev->sram_pool, + (unsigned long)desc->dma_buf_cpu, -+ chan->sram_size); ++ desc->dma_buf_size); + return ret; +} + @@ -1008,7 +1065,7 @@ index 379e8d5..4830f8e 100644 int i, ret; if (!buf_len || !period_len) { -@@ -957,28 +1573,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -957,28 +1577,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; @@ -1029,7 +1086,7 @@ index 379e8d5..4830f8e 100644 + + 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) @@ -1038,7 +1095,7 @@ index 379e8d5..4830f8e 100644 + } else { + dma_buf = buf_addr; + } - ++ + for (i = 0; i < num_periods; i++) { + sg_dma_len(&desc->sg_req[i].stm32_sgl_req) = period_len; + sg_dma_address(&desc->sg_req[i].stm32_sgl_req) = dma_buf; @@ -1070,7 +1127,7 @@ index 379e8d5..4830f8e 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -@@ -1019,13 +1656,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1019,13 +1660,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( STM32_DMA_SCR_PINC | STM32_DMA_SCR_TCIE | STM32_DMA_SCR_TEIE; @@ -1086,46 +1143,108 @@ index 379e8d5..4830f8e 100644 } desc->num_sgs = num_sgs; -@@ -1034,18 +1671,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1034,16 +1675,28 @@ 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_device *dmadev = stm32_dma_get_dev(chan); ++ struct stm32_dma_sg_req *sg_req; ++ u32 dma_scr, dma_smar, id; + - 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, - struct stm32_dma_desc *desc, +@@ -1051,28 +1704,52 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, u32 next_sg) -@@ -1054,6 +1679,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, - u32 residue = 0; + { + 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]; 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 -@@ -1069,7 +1698,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, - * transferred +- * 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. */ - for (i = next_sg; i < desc->num_sgs; i++) -- residue += desc->sg_req[i].len; -+ residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req); - residue += stm32_dma_get_remaining_bytes(chan); +- 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; ++ residue = sg_dma_len(&sg_req->stm32_sgl_req); + } - end: -@@ -1089,11 +1718,23 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, + /* +- * 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 + */ +- 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++) ++ residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req); + +-end: + if (!chan->mem_burst) + return residue; + +@@ -1089,11 +1766,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); @@ -1149,7 +1268,7 @@ index 379e8d5..4830f8e 100644 status = dma_cookie_status(c, cookie, state); if (status == DMA_COMPLETE || !state) return status; -@@ -1120,15 +1761,14 @@ static int stm32_dma_alloc_chan_resources(struct dma_chan *c) +@@ -1120,15 +1809,14 @@ static int stm32_dma_alloc_chan_resources(struct dma_chan *c) int ret; chan->config_init = false; @@ -1169,7 +1288,7 @@ index 379e8d5..4830f8e 100644 return ret; } -@@ -1148,28 +1788,48 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) +@@ -1148,28 +1836,48 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) spin_unlock_irqrestore(&chan->vchan.lock, flags); } @@ -1200,7 +1319,7 @@ index 379e8d5..4830f8e 100644 + + gen_pool_free(dmadev->sram_pool, + (unsigned long)desc->dma_buf_cpu, -+ chan->sram_size); ++ desc->dma_buf_size); + } + + kfree(desc); @@ -1224,7 +1343,7 @@ index 379e8d5..4830f8e 100644 } static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, -@@ -1207,6 +1867,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1207,6 +1915,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, stm32_dma_set_config(chan, &cfg); @@ -1234,7 +1353,7 @@ index 379e8d5..4830f8e 100644 return c; } -@@ -1219,10 +1882,12 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); +@@ -1219,10 +1930,12 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); static int stm32_dma_probe(struct platform_device *pdev) { struct stm32_dma_chan *chan; @@ -1247,7 +1366,7 @@ index 379e8d5..4830f8e 100644 int i, ret; match = of_match_device(stm32_dma_of_match, &pdev->dev); -@@ -1248,6 +1913,12 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1248,6 +1961,12 @@ static int stm32_dma_probe(struct platform_device *pdev) return PTR_ERR(dmadev->clk); } @@ -1260,7 +1379,7 @@ index 379e8d5..4830f8e 100644 dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node, "st,mem2mem"); -@@ -1258,6 +1929,13 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1258,6 +1977,15 @@ static int stm32_dma_probe(struct platform_device *pdev) reset_control_deassert(dmadev->rst); } @@ -1270,19 +1389,23 @@ index 379e8d5..4830f8e 100644 + else + dev_dbg(&pdev->dev, "SRAM pool: %zu KiB\n", + gen_pool_size(dmadev->sram_pool) / 1024); ++ ++ dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); + dma_cap_set(DMA_SLAVE, dd->cap_mask); dma_cap_set(DMA_PRIVATE, dd->cap_mask); dma_cap_set(DMA_CYCLIC, dd->cap_mask); -@@ -1279,6 +1957,7 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1278,7 +2006,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; ++ dd->copy_align = DMAENGINE_ALIGN_32_BYTES; dd->max_burst = STM32_DMA_MAX_BURST; + dd->descriptor_reuse = true; dd->dev = &pdev->dev; INIT_LIST_HEAD(&dd->channels); -@@ -1293,11 +1972,21 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1293,21 +2023,34 @@ 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); @@ -1305,7 +1428,25 @@ index 379e8d5..4830f8e 100644 for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; -@@ -1329,20 +2018,95 @@ static int stm32_dma_probe(struct platform_device *pdev) +- 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); +@@ -1329,20 +2072,95 @@ static int stm32_dma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dmadev); @@ -1401,7 +1542,7 @@ index 379e8d5..4830f8e 100644 }, }; -@@ -1350,4 +2114,4 @@ static int __init stm32_dma_init(void) +@@ -1350,4 +2168,4 @@ static int __init stm32_dma_init(void) { return platform_driver_probe(&stm32_dma_driver, stm32_dma_probe); } @@ -1587,7 +1728,7 @@ index b922db9..a878b7c 100644 }; diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c -index 06dd172..077ef5c 100644 +index 06dd172..fb4a7e3 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -37,6 +37,7 @@ @@ -1784,7 +1925,29 @@ index 06dd172..077ef5c 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); -@@ -1287,14 +1352,28 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan, +@@ -1137,6 +1202,8 @@ static void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan) + return; + } + ++ list_del(&vdesc->node); ++ + 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) + LIST_HEAD(head); + + spin_lock_irqsave(&chan->vchan.lock, flags); +- if (chan->busy) { +- stm32_mdma_stop(chan); ++ if (chan->desc) { ++ vchan_terminate_vdesc(&chan->desc->vdesc); ++ if (chan->busy) ++ stm32_mdma_stop(chan); + 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, { struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); struct stm32_mdma_hwdesc *hwdesc = desc->node[0].hwdesc; @@ -1816,7 +1979,7 @@ index 06dd172..077ef5c 100644 cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)); residue += cbndtr & STM32_MDMA_CBNDTR_BNDT_MASK; -@@ -1314,24 +1393,39 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, +@@ -1314,24 +1397,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); @@ -1861,7 +2024,15 @@ index 06dd172..077ef5c 100644 dma_set_residue(state, residue); spin_unlock_irqrestore(&chan->vchan.lock, flags); -@@ -1456,15 +1550,13 @@ static int stm32_mdma_alloc_chan_resources(struct dma_chan *c) +@@ -1341,7 +1439,6 @@ static enum dma_status stm32_mdma_tx_status(struct dma_chan *c, + + static void stm32_mdma_xfer_end(struct stm32_mdma_chan *chan) + { +- list_del(&chan->desc->vdesc.node); + 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; } @@ -1880,7 +2051,7 @@ index 06dd172..077ef5c 100644 return ret; } -@@ -1484,7 +1576,7 @@ static void stm32_mdma_free_chan_resources(struct dma_chan *c) +@@ -1484,7 +1579,7 @@ static void stm32_mdma_free_chan_resources(struct dma_chan *c) spin_unlock_irqrestore(&chan->vchan.lock, flags); } @@ -1889,7 +2060,7 @@ index 06dd172..077ef5c 100644 vchan_free_chan_resources(to_virt_chan(c)); dmam_pool_destroy(chan->desc_pool); chan->desc_pool = NULL; -@@ -1498,7 +1590,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1498,7 +1593,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; @@ -1898,7 +2069,7 @@ index 06dd172..077ef5c 100644 dev_err(mdma2dev(dmadev), "Bad number of args\n"); return NULL; } -@@ -1508,6 +1600,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1508,6 +1603,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]; @@ -1906,7 +2077,7 @@ index 06dd172..077ef5c 100644 if (config.request >= dmadev->nr_requests) { dev_err(mdma2dev(dmadev), "Bad request line\n"); -@@ -1597,6 +1690,12 @@ static int stm32_mdma_probe(struct platform_device *pdev) +@@ -1597,6 +1693,12 @@ static int stm32_mdma_probe(struct platform_device *pdev) return ret; } @@ -1919,7 +2090,7 @@ index 06dd172..077ef5c 100644 dmadev->rst = devm_reset_control_get(&pdev->dev, NULL); if (!IS_ERR(dmadev->rst)) { reset_control_assert(dmadev->rst); -@@ -1621,6 +1720,8 @@ static int stm32_mdma_probe(struct platform_device *pdev) +@@ -1621,6 +1723,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; @@ -1928,7 +2099,7 @@ index 06dd172..077ef5c 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 +1747,20 @@ static int stm32_mdma_probe(struct platform_device *pdev) +@@ -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"); @@ -1952,7 +2123,7 @@ index 06dd172..077ef5c 100644 ret = of_dma_controller_register(of_node, stm32_mdma_of_xlate, dmadev); if (ret < 0) { -@@ -1668,6 +1770,10 @@ static int stm32_mdma_probe(struct platform_device *pdev) +@@ -1668,6 +1773,10 @@ static int stm32_mdma_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, dmadev); @@ -1963,7 +2134,7 @@ index 06dd172..077ef5c 100644 dev_info(&pdev->dev, "STM32 MDMA driver registered\n"); -@@ -1675,15 +1781,85 @@ static int stm32_mdma_probe(struct platform_device *pdev) +@@ -1675,15 +1784,86 @@ static int stm32_mdma_probe(struct platform_device *pdev) err_unregister: dma_async_device_unregister(dd); @@ -2002,7 +2173,8 @@ index 06dd172..077ef5c 100644 +static int stm32_mdma_pw_suspend(struct device *dev) +{ + struct stm32_mdma_device *dmadev = dev_get_drvdata(dev); -+ u32 ccr, id, ret; ++ u32 ccr, id; ++ int ret; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0018-ARM-stm32mp1-r0-rc2-DRM-KMS.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0006-ARM-stm32mp1-r2-DRM.patch similarity index 75% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0018-ARM-stm32mp1-r0-rc2-DRM-KMS.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0006-ARM-stm32mp1-r2-DRM.patch index fbd7322..ea5dfb7 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0018-ARM-stm32mp1-r0-rc2-DRM-KMS.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0006-ARM-stm32mp1-r2-DRM.patch @@ -1,48 +1,24 @@ -From fd965c7b7da4a0a21bd7750be8c3851be80a576f Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Tue, 27 Nov 2018 09:39:21 +0100 -Subject: [PATCH 18/52] ARM-stm32mp1-r0-rc2-DRM-KMS +From ee6d275b13c56f9d60acd0dc2790262153d92668 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:00 +0200 +Subject: [PATCH 06/30] ARM stm32mp1 r2 DRM --- - .../devicetree/bindings/display/bridge/sii902x.txt | 9 + - drivers/gpu/drm/bridge/Kconfig | 1 + - drivers/gpu/drm/bridge/sii902x.c | 844 +++++++++++++++++++-- - drivers/gpu/drm/drm_modes.c | 19 +- - drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 12 +- - drivers/gpu/drm/panel/panel-raydium-rm68200.c | 12 +- - drivers/gpu/drm/stm/drv.c | 46 +- - drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 53 ++ - drivers/gpu/drm/stm/ltdc.c | 191 +++-- - drivers/gpu/drm/stm/ltdc.h | 6 + - include/uapi/drm/drm_mode.h | 6 + - 11 files changed, 1060 insertions(+), 139 deletions(-) + drivers/gpu/drm/bridge/Kconfig | 1 + + drivers/gpu/drm/bridge/sii902x.c | 867 +++++++++++++++++++++-- + drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 12 + + 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 | 46 +- + drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 114 ++- + drivers/gpu/drm/stm/ltdc.c | 222 ++++-- + drivers/gpu/drm/stm/ltdc.h | 6 + + include/drm/bridge/dw_mipi_dsi.h | 1 + + include/uapi/drm/drm_mode.h | 6 + + 13 files changed, 1210 insertions(+), 188 deletions(-) -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/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index bf6cad6..fe91c20 100644 --- a/drivers/gpu/drm/bridge/Kconfig @@ -56,7 +32,7 @@ index bf6cad6..fe91c20 100644 Silicon Image sii902x bridge chip driver. diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c -index e59a135..512eb03 100644 +index e59a135..170657a 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1,4 +1,6 @@ @@ -339,7 +315,9 @@ index e59a135..512eb03 100644 - SII902X_SYS_CTRL_DDC_BUS_REQ); - if (ret) - return ret; -- ++ bool hdmi_mode = false; ++ int num = 0, ret; + - timeout = jiffies + - msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS); - do { @@ -348,9 +326,7 @@ index e59a135..512eb03 100644 - 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; @@ -418,19 +394,12 @@ index e59a135..512eb03 100644 return num; } -@@ -240,17 +397,29 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) - regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, - SII902X_SYS_CTRL_PWR_DWN, - SII902X_SYS_CTRL_PWR_DWN); -+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); - } - +@@ -245,12 +402,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; -+ pinctrl_pm_select_default_state(&sii902x->i2c->dev); regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL, SII902X_AVI_POWER_STATE_MSK, SII902X_AVI_POWER_STATE_D(0)); @@ -448,7 +417,25 @@ index e59a135..512eb03 100644 } static void sii902x_bridge_mode_set(struct drm_bridge *bridge, -@@ -329,6 +498,267 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) +@@ -261,8 +428,17 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, + struct regmap *regmap = sii902x->regmap; + u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; + struct hdmi_avi_infoframe frame; ++ unsigned int status = 0; + int ret; + ++ DRM_DEBUG_DRIVER("\n"); ++ ++ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); ++ ++ /* due to old tv, need to restore pinctrl as soon as possible */ ++ if (status & SII902X_PLUGGED_STATUS) ++ pinctrl_pm_select_default_state(&sii902x->i2c->dev); ++ + buf[0] = adj->clock; + buf[1] = adj->clock >> 8; + buf[2] = adj->vrefresh; +@@ -329,6 +505,267 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) return 0; } @@ -716,7 +703,7 @@ index e59a135..512eb03 100644 static const struct drm_bridge_funcs sii902x_bridge_funcs = { .attach = sii902x_bridge_attach, .mode_set = sii902x_bridge_mode_set, -@@ -348,10 +778,39 @@ static const struct regmap_access_table sii902x_volatile_table = { +@@ -348,10 +785,39 @@ static const struct regmap_access_table sii902x_volatile_table = { static const struct regmap_config sii902x_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -756,7 +743,18 @@ index e59a135..512eb03 100644 static irqreturn_t sii902x_interrupt(int irq, void *data) { struct sii902x *sii902x = data; -@@ -366,15 +825,134 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) +@@ -360,21 +826,145 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) + regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); + regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); + ++ if (status & SII902X_PLUGGED_STATUS) ++ pinctrl_pm_select_default_state(&sii902x->i2c->dev); ++ else ++ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); ++ + if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) + drm_helper_hpd_irq_event(sii902x->bridge.dev); + return IRQ_HANDLED; } @@ -891,7 +889,7 @@ index e59a135..512eb03 100644 sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL); if (!sii902x) return -ENOMEM; -@@ -392,39 +970,67 @@ static int sii902x_probe(struct i2c_client *client, +@@ -392,39 +982,67 @@ static int sii902x_probe(struct i2c_client *client, return PTR_ERR(sii902x->reset_gpio); } @@ -965,7 +963,7 @@ index e59a135..512eb03 100644 } sii902x->bridge.funcs = &sii902x_bridge_funcs; -@@ -433,7 +1039,31 @@ static int sii902x_probe(struct i2c_client *client, +@@ -433,7 +1051,33 @@ static int sii902x_probe(struct i2c_client *client, i2c_set_clientdata(client, sii902x); @@ -975,14 +973,15 @@ index e59a135..512eb03 100644 + sii902x_i2c_bypass_deselect); + if (!sii902x->i2cmux) { + dev_err(dev, "failed to allocate I2C mux\n"); -+ return -ENOMEM; ++ ret = -ENOMEM; ++ goto err_disable_regulator; + } + + 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; ++ goto err_disable_regulator; + } + + sii902x_register_audio_driver(dev, sii902x); @@ -990,6 +989,7 @@ index e59a135..512eb03 100644 return 0; + +err_disable_regulator: ++ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); + regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); + @@ -997,7 +997,7 @@ index e59a135..512eb03 100644 } static int sii902x_remove(struct i2c_client *client) -@@ -441,11 +1071,76 @@ static int sii902x_remove(struct i2c_client *client) +@@ -441,11 +1085,85 @@ static int sii902x_remove(struct i2c_client *client) { struct sii902x *sii902x = i2c_get_clientdata(client); @@ -1024,6 +1024,8 @@ index e59a135..512eb03 100644 + + regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); ++ ++ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); + return 0; } @@ -1039,10 +1041,17 @@ index e59a135..512eb03 100644 + .len = 2, + .buf = data, + }; ++ unsigned int status = 0; + int ret; + + DRM_DEBUG_DRIVER("\n"); + ++ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); ++ ++ /* due to old tv, need to restore pinctrl as soon as possible */ ++ if (status & SII902X_PLUGGED_STATUS) ++ pinctrl_pm_select_default_state(&sii902x->i2c->dev); ++ + ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); + if (ret) { @@ -1074,7 +1083,7 @@ index e59a135..512eb03 100644 static const struct of_device_id sii902x_dt_ids[] = { { .compatible = "sil,sii9022", }, { } -@@ -464,6 +1159,7 @@ static struct i2c_driver sii902x_driver = { +@@ -464,6 +1182,7 @@ static struct i2c_driver sii902x_driver = { .driver = { .name = "sii902x", .of_match_table = sii902x_dt_ids, @@ -1082,8 +1091,69 @@ index e59a135..512eb03 100644 }, .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..8cd3ee9 100644 +--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c ++++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +@@ -488,6 +488,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 +501,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 +594,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 +610,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 02db9ac..d9d9ad9 100644 +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); @@ -1127,7 +1197,7 @@ index 02db9ac..d9d9ad9 100644 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 87fa316..a76d03a 100644 +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 { @@ -1135,25 +1205,146 @@ index 87fa316..a76d03a 100644 static const struct drm_display_mode default_mode = { - .clock = 32729, -+ .clock = 33000, ++ .clock = 29700, .hdisplay = 480, - .hsync_start = 480 + 120, +- .hsync_start = 480 + 120, - .hsync_end = 480 + 120 + 63, - .htotal = 480 + 120 + 63 + 120, -+ .hsync_end = 480 + 120 + 64, -+ .htotal = 480 + 120 + 64 + 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 + 14, -+ .vsync_end = 800 + 14 + 14, -+ .vtotal = 800 + 14 + 14 + 14, ++ .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..94436ea 100644 +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 { @@ -1178,6 +1369,28 @@ index 7759353..94436ea 100644 .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..cf61875 100644 --- a/drivers/gpu/drm/stm/drv.c @@ -1283,7 +1496,7 @@ index f2021b2..cf61875 100644 }; diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -index a514b59..a6edd86 100644 +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 @@ @@ -1302,19 +1515,75 @@ index a514b59..a6edd86 100644 }; static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val) -@@ -318,16 +320,30 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) +@@ -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(dev, "phy-dsi"); ++ dsi->vdd_supply = devm_regulator_get_optional(dev, "phy-dsi"); + if (IS_ERR(dsi->vdd_supply)) { -+ DRM_ERROR("can't get power supply\n"); -+ return PTR_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) { -+ DRM_ERROR("can't enable power supply\n"); ++ dev_err(dev, "failed to enable regulator: %d\n", ret); + return ret; + } + @@ -1322,26 +1591,65 @@ index a514b59..a6edd86 100644 if (IS_ERR(dsi->pllref_clk)) { ret = PTR_ERR(dsi->pllref_clk); dev_err(dev, "Unable to get pll reference clock: %d\n", ret); -+ regulator_disable(dsi->vdd_supply); - return 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__); -+ regulator_disable(dsi->vdd_supply); - return ret; +- 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; } -@@ -339,6 +355,7 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) + 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"); -+ regulator_disable(dsi->vdd_supply); - clk_disable_unprepare(dsi->pllref_clk); - return PTR_ERR(dsi->dsi); +- clk_disable_unprepare(dsi->pllref_clk); +- return PTR_ERR(dsi->dsi); ++ goto err_pclk_get; } -@@ -351,17 +368,53 @@ static int dw_mipi_dsi_stm_remove(struct platform_device *pdev) + + 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); @@ -1396,7 +1704,7 @@ index a514b59..a6edd86 100644 }; diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c -index 808d9fb..599d2f8 100644 +index 808d9fb..3527e69 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -148,6 +148,8 @@ @@ -1466,10 +1774,14 @@ index 808d9fb..599d2f8 100644 } #define CLK_TOLERANCE_HZ 50 -@@ -497,13 +533,10 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, - * TODO clk_round_rate() does not work yet. When ready, it can - * be used instead of clk_set_rate() then clk_get_rate(). - */ +@@ -493,20 +529,16 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, + struct ltdc_device *ldev = crtc_to_ltdc(crtc); + int rate = mode->clock * 1000; + +- /* +- * TODO clk_round_rate() does not work yet. When ready, it can +- * be used instead of clk_set_rate() then clk_get_rate(). +- */ - - clk_disable(ldev->pixel_clk); if (clk_set_rate(ldev->pixel_clk, rate) < 0) { @@ -1480,7 +1792,13 @@ index 808d9fb..599d2f8 100644 adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000; -@@ -518,6 +551,11 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) ++ DRM_DEBUG_DRIVER("requested clock %dkHz, adjusted clock %dkHz\n", ++ mode->clock, adjusted_mode->clock); ++ + return true; + } + +@@ -518,6 +550,11 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; u32 total_width, total_height; u32 val; @@ -1492,7 +1810,7 @@ index 808d9fb..599d2f8 100644 drm_display_mode_to_videomode(mode, &vm); -@@ -546,10 +584,10 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) +@@ -546,10 +583,10 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) val |= GCR_VSPOL; @@ -1505,7 +1823,7 @@ index 808d9fb..599d2f8 100644 val |= GCR_PCPOL; reg_update_bits(ldev->regs, LTDC_GCR, -@@ -611,8 +649,14 @@ static const struct drm_crtc_helper_funcs ltdc_crtc_helper_funcs = { +@@ -611,8 +648,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); @@ -1520,7 +1838,7 @@ index 808d9fb..599d2f8 100644 reg_set(ldev->regs, LTDC_IER, IER_LIE); return 0; -@@ -623,9 +667,58 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) +@@ -623,9 +666,58 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) struct ltdc_device *ldev = crtc_to_ltdc(crtc); DRM_DEBUG_DRIVER("\n"); @@ -1579,7 +1897,7 @@ index 808d9fb..599d2f8 100644 static const struct drm_crtc_funcs ltdc_crtc_funcs = { .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, -@@ -646,24 +739,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, +@@ -646,24 +738,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; @@ -1608,10 +1926,7 @@ index 808d9fb..599d2f8 100644 + 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, @@ -1625,7 +1940,10 @@ index 808d9fb..599d2f8 100644 + if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 || + crtc_state->mode.vdisplay <= dst->y2)) + return -EINVAL; -+ + +- /* Reject scaling */ +- if (src_w != state->crtc_w || src_h != state->crtc_h) { +- DRM_ERROR("Scaling is not supported"); + /* 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) @@ -1634,7 +1952,7 @@ index 808d9fb..599d2f8 100644 return 0; } -@@ -673,44 +786,36 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -673,44 +785,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; @@ -1689,7 +2007,7 @@ index 808d9fb..599d2f8 100644 reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); -@@ -730,7 +835,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -730,7 +834,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) * @@ -1698,7 +2016,7 @@ index 808d9fb..599d2f8 100644 val = ((pitch_in_bytes << 16) | line_length); reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, LXCFBLR_CFBLL | LXCFBLR_CFBP, val); -@@ -753,7 +858,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -753,7 +857,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, LXBFCR_BF2 | LXBFCR_BF1, val); /* Configures the frame buffer line number */ @@ -1707,7 +2025,7 @@ index 808d9fb..599d2f8 100644 reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); /* Sets the FB address */ -@@ -772,11 +877,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -772,11 +876,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, mutex_lock(&ldev->err_lock); if (ldev->error_status & ISR_FUIF) { @@ -1721,8 +2039,57 @@ index 808d9fb..599d2f8 100644 ldev->error_status &= ~ISR_TERRIF; } mutex_unlock(&ldev->err_lock); -@@ -1055,10 +1160,10 @@ int ltdc_load(struct drm_device *ddev) - return -ENODEV; +@@ -814,6 +918,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, +@@ -822,6 +933,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 = { +@@ -841,6 +953,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++) { +@@ -868,7 +984,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; + +@@ -1051,14 +1167,15 @@ 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)) { @@ -1736,7 +2103,26 @@ index 808d9fb..599d2f8 100644 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ldev->regs = devm_ioremap_resource(dev, res); -@@ -1150,7 +1255,7 @@ int ltdc_load(struct drm_device *ddev) +@@ -1070,6 +1187,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; + +@@ -1129,6 +1249,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"); +@@ -1150,7 +1272,7 @@ int ltdc_load(struct drm_device *ddev) for (i = 0; i < MAX_ENDPOINTS; i++) drm_panel_bridge_remove(bridge[i]); @@ -1745,7 +2131,7 @@ index 808d9fb..599d2f8 100644 return ret; } -@@ -1165,7 +1270,7 @@ void ltdc_unload(struct drm_device *ddev) +@@ -1165,7 +1287,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); @@ -1773,6 +2159,18 @@ index d5afb89..08bd69d 100644 int ltdc_load(struct drm_device *ddev); void ltdc_unload(struct drm_device *ddev); +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 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0007-ARM-stm32mp1-r2-GPIO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0007-ARM-stm32mp1-r2-GPIO.patch new file mode 100644 index 0000000..c10b917 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0007-ARM-stm32mp1-r2-GPIO.patch @@ -0,0 +1,202 @@ +From fc0e7f3b161868a6ab3e40938cb820ef23d223f6 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Tue, 17 Sep 2019 14:27:05 +0200 +Subject: [PATCH 07/30] ARM stm32mp1 r2 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 fd713326..af5d0e6 100644 +--- a/drivers/gpio/gpiolib.c ++++ b/drivers/gpio/gpiolib.c +@@ -2519,6 +2519,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 +@@ -2547,20 +2555,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; +@@ -2634,8 +2641,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 */ +@@ -2643,16 +2650,16 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) + return gpiod_direction_input(desc); + } + 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 */ + if (!value) + return gpiod_direction_input(desc); + } 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: +@@ -2684,7 +2691,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); + +@@ -2721,7 +2728,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); +@@ -3858,6 +3865,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.49/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch new file mode 100644 index 0000000..e4fb183 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch @@ -0,0 +1,249 @@ +From 7f9a7065bc23ee2da17c45ff4097cdbc9b70065d Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:00 +0200 +Subject: [PATCH 08/30] ARM stm32mp1 r2 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.9/0004-ARM-stm32mp1-r0-rc1-I2C.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0009-ARM-stm32mp1-r2-HWTRACING-I2C.patch similarity index 56% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0004-ARM-stm32mp1-r0-rc1-I2C.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0009-ARM-stm32mp1-r2-HWTRACING-I2C.patch index 8a921dd..d4e3d1f 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0004-ARM-stm32mp1-r0-rc1-I2C.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0009-ARM-stm32mp1-r2-HWTRACING-I2C.patch @@ -1,17 +1,157 @@ -From 656c7df3520f4422b871a4e69c68e6a9daf7ba61 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:18:06 +0100 -Subject: [PATCH 04/52] ARM: stm32mp1-r0-rc1: I2C +From 7394fe2e090d58063b852b0baeca2fc65f8cd07b Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:00 +0200 +Subject: [PATCH 09/30] ARM stm32mp1 r2 HWTRACING I2C --- - drivers/i2c/busses/i2c-stm32f7.c | 369 +++++++++++++++++++++++++++++++++------ - 1 file changed, 320 insertions(+), 49 deletions(-) + drivers/hwtracing/coresight/coresight-stm.c | 58 +++- + drivers/i2c/busses/i2c-stm32f7.c | 470 ++++++++++++++++++++++++---- + 2 files changed, 469 insertions(+), 59 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/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index 62d023e..c1cbf93 100644 +index a492da9..b052f3e 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c -@@ -21,12 +21,17 @@ +@@ -21,12 +21,16 @@ #include #include #include @@ -19,7 +159,7 @@ index 62d023e..c1cbf93 100644 #include #include #include - #include +-#include #include #include +#include @@ -29,7 +169,7 @@ index 62d023e..c1cbf93 100644 #include #include -@@ -46,6 +51,7 @@ +@@ -46,6 +50,7 @@ /* STM32F7 I2C control 1 */ #define STM32F7_I2C_CR1_PECEN BIT(23) @@ -37,7 +177,7 @@ index 62d023e..c1cbf93 100644 #define STM32F7_I2C_CR1_SBC BIT(16) #define STM32F7_I2C_CR1_RXDMAEN BIT(15) #define STM32F7_I2C_CR1_TXDMAEN BIT(14) -@@ -163,6 +169,26 @@ +@@ -163,6 +168,26 @@ #define STM32F7_SCLH_MAX BIT(8) #define STM32F7_SCLL_MAX BIT(8) @@ -64,7 +204,7 @@ index 62d023e..c1cbf93 100644 /** * struct stm32f7_i2c_spec - private i2c specification timing * @rate: I2C bus speed (Hz) -@@ -259,6 +285,8 @@ struct stm32f7_i2c_msg { +@@ -259,6 +284,8 @@ struct stm32f7_i2c_msg { * struct stm32f7_i2c_dev - private data of the controller * @adap: I2C adapter for this controller * @dev: device for this controller @@ -73,11 +213,16 @@ index 62d023e..c1cbf93 100644 * @base: virtual memory area * @complete: completion of I2C message * @clk: hw i2c clock -@@ -276,11 +304,14 @@ struct stm32f7_i2c_msg { +@@ -276,11 +303,19 @@ struct stm32f7_i2c_msg { * 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 ++ * @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 */ struct stm32f7_i2c_dev { struct i2c_adapter adap; @@ -88,7 +233,7 @@ index 62d023e..c1cbf93 100644 struct completion complete; struct clk *clk; int speed; -@@ -292,10 +323,12 @@ struct stm32f7_i2c_dev { +@@ -292,10 +327,17 @@ struct stm32f7_i2c_dev { struct stm32f7_i2c_timings timing; struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE]; struct i2c_client *slave_running; @@ -97,11 +242,59 @@ index 62d023e..c1cbf93 100644 bool master_mode; struct stm32_i2c_dma *dma; bool use_dma; -+ struct regmap *regmap; ++ struct regmap *sregmap; ++ struct regmap *cregmap; ++ u32 regmap_sreg; ++ u32 regmap_smask; ++ u32 regmap_creg; ++ u32 regmap_cmask; }; /** -@@ -1545,15 +1578,13 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, +@@ -468,8 +510,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; + } + } + +@@ -941,6 +987,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; +@@ -1178,6 +1227,8 @@ static void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev) + STM32F7_I2C_CR1_TXIE; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); + ++ /* Write 1st data byte */ ++ writel_relaxed(value, base + STM32F7_I2C_TXDR); + } else { + /* Notify i2c slave that new write transfer is starting */ + i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); +@@ -1517,7 +1568,9 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) + mask = STM32F7_I2C_XFER_IRQ_MASK; + else + mask = STM32F7_I2C_ALL_IRQ_MASK; +- stm32f7_i2c_disable_irq(i2c_dev, mask); ++ ++ if (!i2c_dev->slave_running) ++ stm32f7_i2c_disable_irq(i2c_dev, mask); + + /* Disable dma */ + if (i2c_dev->use_dma) { +@@ -1545,15 +1598,13 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, i2c_dev->msg_id = 0; f7_msg->smbus = false; @@ -120,7 +313,7 @@ index 62d023e..c1cbf93 100644 stm32f7_i2c_xfer_msg(i2c_dev, msgs); -@@ -1569,8 +1600,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, +@@ -1569,8 +1620,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, ret = -ETIMEDOUT; } @@ -132,7 +325,7 @@ index 62d023e..c1cbf93 100644 return (ret < 0) ? ret : num; } -@@ -1592,39 +1624,37 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, +@@ -1592,39 +1644,37 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, f7_msg->read_write = read_write; f7_msg->smbus = true; @@ -179,7 +372,7 @@ index 62d023e..c1cbf93 100644 } if (read_write && size != I2C_SMBUS_QUICK) { -@@ -1649,11 +1679,15 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, +@@ -1649,11 +1699,15 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, } } @@ -197,7 +390,7 @@ index 62d023e..c1cbf93 100644 static int stm32f7_i2c_reg_slave(struct i2c_client *slave) { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); -@@ -1676,13 +1710,12 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +@@ -1676,13 +1730,12 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) if (ret) return ret; @@ -217,7 +410,7 @@ index 62d023e..c1cbf93 100644 if (id == 0) { /* Configure Own Address 1 */ -@@ -1703,7 +1736,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +@@ -1703,7 +1756,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) oar2 &= ~STM32F7_I2C_OAR2_MASK; if (slave->flags & I2C_CLIENT_TEN) { ret = -EOPNOTSUPP; @@ -226,7 +419,7 @@ index 62d023e..c1cbf93 100644 } oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr); -@@ -1712,7 +1745,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +@@ -1712,7 +1765,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2); } else { ret = -ENODEV; @@ -235,7 +428,7 @@ index 62d023e..c1cbf93 100644 } /* Enable ACK */ -@@ -1723,11 +1756,13 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +@@ -1723,11 +1776,13 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) STM32F7_I2C_CR1_PE; stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); @@ -253,7 +446,7 @@ index 62d023e..c1cbf93 100644 return ret; } -@@ -1745,6 +1780,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) +@@ -1745,6 +1800,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) WARN_ON(!i2c_dev->slave[id]); @@ -264,7 +457,7 @@ index 62d023e..c1cbf93 100644 if (id == 0) { mask = STM32F7_I2C_OAR1_OA1EN; stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask); -@@ -1755,14 +1794,56 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) +@@ -1755,21 +1814,106 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) i2c_dev->slave[id] = NULL; @@ -296,6 +489,32 @@ index 62d023e..c1cbf93 100644 + 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->speed != STM32_I2C_SPEED_FAST_PLUS || ++ 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) +{ @@ -303,8 +522,8 @@ index 62d023e..c1cbf93 100644 + int ret; + u32 reg, mask; + -+ i2c_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp"); -+ if (IS_ERR(i2c_dev->regmap)) { ++ i2c_dev->sregmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp"); ++ if (IS_ERR(i2c_dev->sregmap)) { + /* Optional */ + return 0; + } @@ -317,39 +536,93 @@ index 62d023e..c1cbf93 100644 + if (ret) + return ret; + -+ return regmap_update_bits(i2c_dev->regmap, reg, mask, mask); ++ 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 u32 stm32f7_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE | -@@ -1786,7 +1867,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + 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; + } + + static struct i2c_algorithm stm32f7_i2c_algo = { +@@ -1782,15 +1926,14 @@ static struct i2c_algorithm stm32f7_i2c_algo = { + + static int stm32f7_i2c_probe(struct platform_device *pdev) + { +- struct device_node *np = pdev->dev.of_node; struct stm32f7_i2c_dev *i2c_dev; const struct stm32f7_i2c_setup *setup; struct resource *res; - u32 irq_error, irq_event, clk_rate, rise_time, fall_time; -+ u32 irq_error, clk_rate, rise_time, fall_time; ++ u32 clk_rate, rise_time, fall_time; struct i2c_adapter *adap; struct reset_control *rst; dma_addr_t phy_addr; -@@ -1802,13 +1883,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +- int ret; ++ int irq_error, ret; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) +@@ -1802,16 +1945,28 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) return PTR_ERR(i2c_dev->base); phy_addr = (dma_addr_t)res->start; - irq_event = irq_of_parse_and_map(np, 0); - if (!irq_event) { -+ i2c_dev->irq_event = of_irq_get_byname(np, "event"); -+ if (!i2c_dev->irq_event) { - dev_err(&pdev->dev, "IRQ event missing or invalid\n"); - return -EINVAL; +- dev_err(&pdev->dev, "IRQ event missing or invalid\n"); +- return -EINVAL; ++ 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", ++ i2c_dev->irq_event); ++ return i2c_dev->irq_event; } - irq_error = irq_of_parse_and_map(np, 1); -+ irq_error = of_irq_get_byname(np, "error"); - if (!irq_error) { - dev_err(&pdev->dev, "IRQ error missing or invalid\n"); - return -EINVAL; -@@ -1819,6 +1900,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +- if (!irq_error) { +- dev_err(&pdev->dev, "IRQ error missing or invalid\n"); +- return -EINVAL; ++ 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", ++ irq_error); ++ return irq_error; ++ } ++ ++ 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); +@@ -1819,6 +1974,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Error: Missing controller clock\n"); return PTR_ERR(i2c_dev->clk); } @@ -357,7 +630,7 @@ index 62d023e..c1cbf93 100644 ret = clk_prepare_enable(i2c_dev->clk); if (ret) { dev_err(&pdev->dev, "Failed to prepare_enable clock\n"); -@@ -1828,12 +1910,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -1828,12 +1984,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) i2c_dev->speed = STM32_I2C_SPEED_STANDARD; ret = device_property_read_u32(&pdev->dev, "clock-frequency", &clk_rate); @@ -365,9 +638,6 @@ index 62d023e..c1cbf93 100644 + if (!ret && clk_rate >= 1000000) { i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS; - else if (!ret && clk_rate >= 400000) -+ 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) @@ -377,7 +647,7 @@ index 62d023e..c1cbf93 100644 rst = devm_reset_control_get(&pdev->dev, NULL); if (IS_ERR(rst)) { -@@ -1847,14 +1933,14 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -1847,14 +2004,14 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) i2c_dev->dev = &pdev->dev; @@ -394,27 +664,30 @@ index 62d023e..c1cbf93 100644 goto clk_free; } -@@ -1888,8 +1974,6 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -1888,7 +2045,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) if (ret) goto clk_free; - stm32f7_i2c_hw_config(i2c_dev); -- ++ if (i2c_dev->speed == STM32_I2C_SPEED_FAST_PLUS) { ++ 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)", -@@ -1908,18 +1992,45 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -1908,18 +2069,47 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) STM32F7_I2C_TXDR, STM32F7_I2C_RXDR); - ret = i2c_add_adapter(adap); - if (ret) - goto clk_free; -+ i2c_dev->irq_wakeup = of_irq_get_byname(np, "wakeup"); + if (i2c_dev->irq_wakeup > 0) { + ret = stm32f7_i2c_setup_wakeup(i2c_dev); + if (ret) -+ goto clk_free; ++ goto fmp_clear; + } platform_set_drvdata(pdev, i2c_dev); @@ -449,20 +722,24 @@ index 62d023e..c1cbf93 100644 + pm_runtime_disable(i2c_dev->dev); + pm_runtime_set_suspended(i2c_dev->dev); + pm_runtime_dont_use_autosuspend(i2c_dev->dev); ++ ++fmp_clear: ++ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); + clk_free: clk_disable_unprepare(i2c_dev->clk); -@@ -1936,11 +2047,170 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) +@@ -1936,12 +2126,175 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) } i2c_del_adapter(&i2c_dev->adap); + pm_runtime_get_sync(i2c_dev->dev); + ++ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); ++ + dev_pm_clear_wake_irq(i2c_dev->dev); + device_init_wakeup(i2c_dev->dev, false); - -- clk_unprepare(i2c_dev->clk); ++ + clk_disable_unprepare(i2c_dev->clk); + + pm_runtime_put_noidle(i2c_dev->dev); @@ -496,9 +773,9 @@ index 62d023e..c1cbf93 100644 + return ret; + } + } - - return 0; - } ++ ++ return 0; ++} +#endif + +#ifdef CONFIG_PM_SLEEP @@ -516,6 +793,7 @@ index 62d023e..c1cbf93 100644 + 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); + @@ -546,6 +824,7 @@ index 62d023e..c1cbf93 100644 + 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); + @@ -583,15 +862,16 @@ index 62d023e..c1cbf93 100644 + ret = stm32f7_i2c_regs_backup(i2c_dev); + if (ret < 0) + return ret; -+ + +- clk_unprepare(i2c_dev->clk); + if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { + pinctrl_pm_select_sleep_state(dev); + pm_runtime_force_suspend(dev); + } -+ -+ return 0; -+} -+ + + return 0; + } + +static int stm32f7_i2c_resume(struct device *dev) +{ + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -622,10 +902,11 @@ index 62d023e..c1cbf93 100644 + 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}, -@@ -1952,6 +2222,7 @@ static struct platform_driver stm32f7_i2c_driver = { + {}, +@@ -1952,6 +2305,7 @@ static struct platform_driver stm32f7_i2c_driver = { .driver = { .name = "stm32f7-i2c", .of_match_table = stm32f7_i2c_match, diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0005-ARM-stm32mp1-r0-rc1-IIO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0010-ARM-stm32mp1-r2-IIO.patch similarity index 76% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0005-ARM-stm32mp1-r0-rc1-IIO.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0010-ARM-stm32mp1-r2-IIO.patch index 4aa5eeb..dbe7e11 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0005-ARM-stm32mp1-r0-rc1-IIO.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0010-ARM-stm32mp1-r2-IIO.patch @@ -1,27 +1,38 @@ -From 4134cd0a2ec7d17327dbdf141ec05268e195cd71 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:19:04 +0100 -Subject: [PATCH 05/52] ARM: stm32mp1-r0-rc1: IIO +From 6fddc08f91cc0eb406ced8e610aabac3ce7320de Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:01 +0200 +Subject: [PATCH 10/30] ARM stm32mp1 r2 IIO --- - drivers/iio/adc/Kconfig | 10 + + drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + - drivers/iio/adc/stm32-adc-core.c | 399 ++++++-- - drivers/iio/adc/stm32-adc-core.h | 87 ++ - drivers/iio/adc/stm32-adc-temp.c | 412 +++++++++ - drivers/iio/adc/stm32-adc.c | 1431 ++++++++++++++++++++++++----- - drivers/iio/adc/stm32-dfsdm-adc.c | 627 ++++++++++--- - drivers/iio/adc/stm32-dfsdm-core.c | 176 +++- + drivers/iio/adc/stm32-adc-core.c | 720 ++++++++++++-- + drivers/iio/adc/stm32-adc-core.h | 99 ++ + drivers/iio/adc/stm32-adc-temp.c | 412 ++++++++ + drivers/iio/adc/stm32-adc.c | 1471 ++++++++++++++++++++++++----- + drivers/iio/adc/stm32-dfsdm-adc.c | 853 +++++++++++++---- + drivers/iio/adc/stm32-dfsdm-core.c | 184 +++- + 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 +++- - 10 files changed, 2870 insertions(+), 495 deletions(-) + 13 files changed, 3657 insertions(+), 578 deletions(-) create mode 100644 drivers/iio/adc/stm32-adc-temp.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig -index 4a75492..f2c1d8b 100644 +index 9421c1e..66af479 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig -@@ -679,6 +679,16 @@ config STM32_ADC +@@ -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. @@ -51,10 +62,10 @@ index 03db7b5..527f9ef 100644 obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index ca432e7..a32e826 100644 +index ca432e7..dc40c05 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c -@@ -10,12 +10,16 @@ +@@ -10,12 +10,18 @@ */ #include @@ -64,14 +75,16 @@ index ca432e7..a32e826 100644 #include #include #include ++#include #include #include +#include +#include ++#include #include #include -@@ -23,12 +27,29 @@ +@@ -23,12 +29,29 @@ /* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */ #define STM32F4_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) @@ -102,7 +115,7 @@ index ca432e7..a32e826 100644 /* STM32F4_ADC_CCR - bit fields */ #define STM32F4_ADC_ADCPRE_SHIFT 16 -@@ -36,11 +57,30 @@ +@@ -36,11 +59,30 @@ /* STM32H7 - common registers for all ADC instances */ #define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) @@ -134,7 +147,12 @@ index ca432e7..a32e826 100644 /* STM32H7_ADC_CCR - bit fields */ #define STM32H7_PRESC_SHIFT 18 -@@ -51,15 +91,23 @@ +@@ -48,18 +90,32 @@ + #define STM32H7_CKMODE_SHIFT 16 + #define STM32H7_CKMODE_MASK GENMASK(17, 16) + ++#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000 ++ /** * stm32_adc_common_regs - stm32 common registers, compatible dependent data * @csr: common status register offset @@ -145,6 +163,8 @@ index ca432e7..a32e826 100644 + * @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; @@ -155,24 +175,40 @@ index ca432e7..a32e826 100644 + u32 jeoc1_msk; + u32 jeoc2_msk; + u32 jeoc3_msk; ++ u32 ier; ++ u32 eocie_msk; }; struct stm32_adc_priv; -@@ -69,11 +117,13 @@ struct stm32_adc_priv; +@@ -69,11 +125,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; }; /** -@@ -82,18 +132,22 @@ struct stm32_adc_priv_cfg { +@@ -82,18 +154,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 @@ -181,6 +217,10 @@ index ca432e7..a32e826 100644 * @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]; @@ -188,14 +228,20 @@ index ca432e7..a32e826 100644 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) -@@ -129,7 +183,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, +@@ -129,7 +215,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, } for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { @@ -204,7 +250,7 @@ index ca432e7..a32e826 100644 break; } if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { -@@ -218,7 +272,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -218,7 +304,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (ckmode) continue; @@ -213,7 +259,7 @@ index ca432e7..a32e826 100644 goto out; } } -@@ -238,7 +292,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -238,7 +324,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (!ckmode) continue; @@ -222,7 +268,7 @@ index ca432e7..a32e826 100644 goto out; } -@@ -265,16 +319,23 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -265,18 +351,43 @@ 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, @@ -236,6 +282,8 @@ index ca432e7..a32e826 100644 + .jeoc1_msk = STM32F4_JEOC_MASK1, + .jeoc2_msk = STM32F4_JEOC_MASK2, + .jeoc3_msk = STM32F4_JEOC_MASK3, ++ .ier = STM32F4_ADC_CR1, ++ .eocie_msk = STM32F4_EOCIE, }; /* STM32H7 common registers definitions */ @@ -248,11 +296,56 @@ index ca432e7..a32e826 100644 + .eoc2_msk = STM32H7_EOC_MASK2, + .jeoc1_msk = STM32H7_JEOC_MASK1, + .jeoc2_msk = STM32H7_JEOC_MASK2, ++ .ier = STM32H7_ADC_IER, ++ .eocie_msk = STM32H7_EOCIE, ++}; ++ ++static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = { ++ 0, STM32_ADC_OFFSET, STM32_ADC_OFFSET * 2, }; ++static unsigned int stm32_adc_eoc_enabled(struct stm32_adc_priv *priv, ++ unsigned int adc) ++{ ++ u32 ier, offset = stm32_adc_offset[adc]; ++ ++ ier = readl_relaxed(priv->common.base + offset + priv->cfg->regs->ier); ++ ++ return ier & priv->cfg->regs->eocie_msk; ++} ++ /* ADC common interrupt for all instances */ -@@ -296,6 +357,15 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) - if (status & priv->cfg->regs->eoc3_msk) + static void stm32_adc_irq_handler(struct irq_desc *desc) + { +@@ -287,15 +398,39 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) + chained_irq_enter(chip, desc); + status = readl_relaxed(priv->common.base + priv->cfg->regs->csr); + +- if (status & priv->cfg->regs->eoc1_msk) ++ /* ++ * End of conversion may be handled by using IRQ or DMA. There may be a ++ * race here when two conversions complete at the same time on several ++ * ADCs. EOC may be read 'set' for several ADCs, with: ++ * - an ADC configured to use DMA (EOC triggers the DMA request, and ++ * is then automatically cleared by DR read in hardware) ++ * - an ADC configured to use IRQs (EOCIE bit is set. The handler must ++ * be called in this case) ++ * So both EOC status bit in CSR and EOCIE control bit must be checked ++ * before invoking the interrupt handler (e.g. call ISR only for ++ * IRQ-enabled ADCs). ++ */ ++ if (status & priv->cfg->regs->eoc1_msk && ++ stm32_adc_eoc_enabled(priv, 0)) + generic_handle_irq(irq_find_mapping(priv->domain, 0)); + +- if (status & priv->cfg->regs->eoc2_msk) ++ if (status & priv->cfg->regs->eoc2_msk && ++ stm32_adc_eoc_enabled(priv, 1)) + generic_handle_irq(irq_find_mapping(priv->domain, 1)); + +- if (status & priv->cfg->regs->eoc3_msk) ++ if (status & priv->cfg->regs->eoc3_msk && ++ stm32_adc_eoc_enabled(priv, 2)) generic_handle_irq(irq_find_mapping(priv->domain, 2)); + if (status & priv->cfg->regs->jeoc1_msk) @@ -267,7 +360,7 @@ index ca432e7..a32e826 100644 chained_irq_exit(chip, desc); }; -@@ -344,7 +414,8 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, +@@ -344,7 +479,8 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, } } @@ -277,7 +370,7 @@ index ca432e7..a32e826 100644 &stm32_adc_domain_ops, priv); if (!priv->domain) { -@@ -368,7 +439,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, +@@ -368,7 +504,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, int hwirq; unsigned int i; @@ -286,7 +379,7 @@ index ca432e7..a32e826 100644 irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); irq_domain_remove(priv->domain); -@@ -379,13 +450,186 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, +@@ -379,13 +515,415 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, } } @@ -407,16 +500,182 @@ index ca432e7..a32e826 100644 + 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"); -+ return ret; ++ goto err_switches_disable; + } + + if (priv->bclk) { @@ -444,6 +703,8 @@ index ca432e7..a32e826 100644 + clk_disable_unprepare(priv->bclk); +err_regulator_disable: + regulator_disable(priv->vref); ++err_switches_disable: ++ stm32_adc_switches_supply_dis(dev); + + return ret; +} @@ -460,6 +721,67 @@ index ca432e7..a32e826 100644 + 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) @@ -474,7 +796,7 @@ index ca432e7..a32e826 100644 if (!pdev->dev.of_node) return -ENODEV; -@@ -393,6 +637,7 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -393,6 +931,7 @@ static int stm32_adc_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -482,7 +804,7 @@ index ca432e7..a32e826 100644 priv->cfg = (const struct stm32_adc_priv_cfg *) of_match_device(dev->driver->of_match_table, dev)->data; -@@ -402,6 +647,8 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -402,6 +941,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; @@ -491,7 +813,7 @@ index ca432e7..a32e826 100644 priv->vref = devm_regulator_get(&pdev->dev, "vref"); if (IS_ERR(priv->vref)) { -@@ -410,67 +657,60 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -410,67 +951,87 @@ static int stm32_adc_probe(struct platform_device *pdev) return ret; } @@ -499,16 +821,30 @@ index ca432e7..a32e826 100644 - 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); @@ -551,8 +887,17 @@ index ca432e7..a32e826 100644 - 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); @@ -563,7 +908,7 @@ index ca432e7..a32e826 100644 + 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); + @@ -573,7 +918,7 @@ index ca432e7..a32e826 100644 + 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; @@ -591,11 +936,12 @@ index ca432e7..a32e826 100644 ret = of_platform_populate(np, NULL, NULL, &pdev->dev); if (ret < 0) { -@@ -478,21 +718,18 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -478,21 +1039,19 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_irq_remove; } -+ pm_runtime_put(dev); ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); + return 0; @@ -621,7 +967,7 @@ index ca432e7..a32e826 100644 return ret; } -@@ -502,33 +739,58 @@ static int stm32_adc_remove(struct platform_device *pdev) +@@ -502,33 +1061,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); @@ -680,12 +1026,13 @@ index ca432e7..a32e826 100644 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[] = { -@@ -552,6 +814,7 @@ static struct platform_driver stm32_adc_driver = { +@@ -552,6 +1137,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc-core", .of_match_table = stm32_adc_of_match, @@ -694,10 +1041,10 @@ index ca432e7..a32e826 100644 }; 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 8af507b..a209ea4 100644 +index 8af507b..a7a4e54 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h -@@ -25,20 +25,107 @@ +@@ -25,20 +25,119 @@ * -------------------------------------------------------- */ #define STM32_ADC_MAX_ADCS 3 @@ -721,12 +1068,24 @@ index 8af507b..a209ea4 100644 + bool calibrated; +}; + ++/* STM32F4 - registers for each ADC instance */ ++#define STM32F4_ADC_CR1 0x04 ++ ++/* STM32F4_ADC_CR1 - bit fields */ ++#define STM32F4_EOCIE BIT(5) ++ +/* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */ +#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04) + +/* STM32F4_ADC_CCR - bit fields */ +#define STM32F4_ADC_TSVREFE BIT(23) + ++/* STM32H7 - registers for each instance */ ++#define STM32H7_ADC_IER 0x04 ++ ++/* STM32H7_ADC_IER - bit fields */ ++#define STM32H7_EOCIE BIT(2) ++ +/* STM32H7 - common registers for all ADC instances */ +#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) + @@ -1224,7 +1583,7 @@ index 0000000..dd31916 +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 3784118..980355e 100644 +index 3784118..e82d4c5 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -12,6 +12,7 @@ @@ -1235,15 +1594,26 @@ index 3784118..980355e 100644 #include #include #include -@@ -22,6 +23,7 @@ +@@ -20,8 +21,10 @@ + #include + #include #include ++#include #include #include +#include #include #include -@@ -46,14 +48,26 @@ +@@ -29,7 +32,6 @@ + + /* STM32F4 - Registers for each ADC instance */ + #define STM32F4_ADC_SR 0x00 +-#define STM32F4_ADC_CR1 0x04 + #define STM32F4_ADC_CR2 0x08 + #define STM32F4_ADC_SMPR1 0x0C + #define STM32F4_ADC_SMPR2 0x10 +@@ -46,14 +48,25 @@ #define STM32F4_ADC_DR 0x4C /* STM32F4_ADC_SR - bit fields */ @@ -1262,15 +1632,15 @@ index 3784118..980355e 100644 +#define STM32F4_JAWDEN BIT(22) +#define STM32F4_AWDSGL BIT(9) #define STM32F4_SCAN BIT(8) +-#define STM32F4_EOCIE BIT(5) +#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) -@@ -61,6 +75,11 @@ +@@ -61,6 +74,11 @@ #define STM32F4_EXTEN_MASK GENMASK(29, 28) #define STM32F4_EXTSEL_SHIFT 24 #define STM32F4_EXTSEL_MASK GENMASK(27, 24) @@ -1282,7 +1652,13 @@ index 3784118..980355e 100644 #define STM32F4_EOCS BIT(10) #define STM32F4_DDS BIT(9) #define STM32F4_DMA BIT(8) -@@ -74,21 +93,44 @@ +@@ -68,28 +86,49 @@ + + /* STM32H7 - Registers for each ADC instance */ + #define STM32H7_ADC_ISR 0x00 +-#define STM32H7_ADC_IER 0x04 + #define STM32H7_ADC_CR 0x08 + #define STM32H7_ADC_CFGR 0x0C #define STM32H7_ADC_SMPR1 0x14 #define STM32H7_ADC_SMPR2 0x18 #define STM32H7_ADC_PCSEL 0x1C @@ -1319,15 +1695,16 @@ index 3784118..980355e 100644 #define STM32H7_ADRDY BIT(0) /* STM32H7_ADC_IER - bit fields */ +-#define STM32H7_EOCIE STM32H7_EOC +#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 */ -@@ -104,12 +146,19 @@ + #define STM32H7_ADCAL BIT(31) +@@ -104,12 +143,19 @@ #define STM32H7_LINCALRDYW1 BIT(22) #define STM32H7_ADCALLIN BIT(16) #define STM32H7_BOOST BIT(8) @@ -1347,7 +1724,7 @@ index 3784118..980355e 100644 #define STM32H7_EXTEN_SHIFT 10 #define STM32H7_EXTEN_MASK GENMASK(11, 10) #define STM32H7_EXTSEL_SHIFT 5 -@@ -126,6 +175,12 @@ enum stm32h7_adc_dmngt { +@@ -126,6 +172,12 @@ enum stm32h7_adc_dmngt { STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */ }; @@ -1360,7 +1737,7 @@ index 3784118..980355e 100644 /* STM32H7_ADC_CALFACT - bit fields */ #define STM32H7_CALFACT_D_SHIFT 16 #define STM32H7_CALFACT_D_MASK GENMASK(26, 16) -@@ -136,18 +191,17 @@ enum stm32h7_adc_dmngt { +@@ -136,18 +188,17 @@ enum stm32h7_adc_dmngt { #define STM32H7_LINCALFACT_SHIFT 0 #define STM32H7_LINCALFACT_MASK GENMASK(29, 0) @@ -1377,11 +1754,11 @@ index 3784118..980355e 100644 #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_AUTO_SUSPEND_DELAY_MS 2000 ++#define STM32_ADC_HW_STOP_DELAY_MS 100 #define STM32_DMA_BUFFER_SIZE PAGE_SIZE -@@ -159,53 +213,6 @@ enum stm32_adc_exten { +@@ -159,53 +210,6 @@ enum stm32_adc_exten { STM32_EXTEN_HWTRIG_BOTH_EDGES, }; @@ -1435,7 +1812,7 @@ index 3784118..980355e 100644 /** * stm32_adc_regs - stm32 ADC misc registers & bitfield desc * @reg: register offset -@@ -219,27 +226,73 @@ struct stm32_adc_regs { +@@ -219,27 +223,73 @@ struct stm32_adc_regs { }; /** @@ -1509,7 +1886,7 @@ index 3784118..980355e 100644 }; struct stm32_adc; -@@ -251,12 +304,12 @@ struct stm32_adc; +@@ -251,12 +301,12 @@ struct stm32_adc; * @trigs: external trigger sources * @clk_required: clock is required * @has_vregready: vregready status flag presence @@ -1523,7 +1900,7 @@ index 3784118..980355e 100644 */ struct stm32_adc_cfg { const struct stm32_adc_regspec *regs; -@@ -264,18 +317,39 @@ struct stm32_adc_cfg { +@@ -264,18 +314,39 @@ struct stm32_adc_cfg { struct stm32_adc_trig_info *trigs; bool clk_required; bool has_vregready; @@ -1564,7 +1941,7 @@ index 3784118..980355e 100644 * @cfg: compatible configuration data * @completion: end of single conversion completion * @buffer: data buffer -@@ -290,15 +364,15 @@ struct stm32_adc_cfg { +@@ -290,15 +361,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 @@ -1576,6 +1953,7 @@ index 3784118..980355e 100644 + * @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; @@ -1584,7 +1962,7 @@ index 3784118..980355e 100644 const struct stm32_adc_cfg *cfg; struct completion completion; u16 buffer[STM32_ADC_MAX_SQ]; -@@ -313,11 +387,10 @@ struct stm32_adc { +@@ -313,11 +385,11 @@ struct stm32_adc { u8 *rx_buf; dma_addr_t rx_dma_buf; unsigned int rx_buf_sz; @@ -1596,10 +1974,11 @@ index 3784118..980355e 100644 + bool injected; + struct list_head evt_list; + u32 awd_mask; ++ struct irq_work work; }; struct stm32_adc_diff_channel { -@@ -342,9 +415,9 @@ static const unsigned int stm32f4_adc_resolutions[] = { +@@ -342,9 +414,9 @@ static const unsigned int stm32f4_adc_resolutions[] = { 12, 10, 8, 6, }; @@ -1611,7 +1990,7 @@ index 3784118..980355e 100644 .resolutions = stm32f4_adc_resolutions, .num_res = ARRAY_SIZE(stm32f4_adc_resolutions), }; -@@ -390,25 +463,58 @@ static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = { +@@ -390,25 +462,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[] = { @@ -1685,7 +2064,7 @@ index 3784118..980355e 100644 * stm32f4_smp_bits[] - describe sampling time register index & bit fields * Sorted so it can be indexed by channel number. */ -@@ -441,17 +547,46 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { +@@ -441,17 +546,46 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { 3, 15, 28, 56, 84, 112, 144, 480, }; @@ -1732,7 +2111,7 @@ index 3784118..980355e 100644 }; static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = { -@@ -476,26 +611,41 @@ static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = { +@@ -476,26 +610,41 @@ static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = { { STM32H7_ADC_SQR4, GENMASK(10, 6), 6 }, }; @@ -1792,7 +2171,7 @@ index 3784118..980355e 100644 {}, }; -@@ -533,17 +683,72 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { +@@ -533,17 +682,72 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { 1, 2, 8, 16, 32, 64, 387, 810, }; @@ -1865,7 +2244,7 @@ index 3784118..980355e 100644 }; /** -@@ -599,8 +804,12 @@ static void stm32_adc_clr_bits(struct stm32_adc *adc, u32 reg, u32 bits) +@@ -599,8 +803,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) { @@ -1880,7 +2259,7 @@ index 3784118..980355e 100644 }; /** -@@ -609,8 +818,30 @@ static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) +@@ -609,8 +817,30 @@ static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) */ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) { @@ -1913,7 +2292,7 @@ index 3784118..980355e 100644 } static void stm32_adc_set_res(struct stm32_adc *adc) -@@ -623,6 +854,57 @@ static void stm32_adc_set_res(struct stm32_adc *adc) +@@ -623,6 +853,57 @@ static void stm32_adc_set_res(struct stm32_adc *adc) stm32_adc_writel(adc, res->reg, val); } @@ -1971,7 +2350,7 @@ index 3784118..980355e 100644 /** * stm32f4_adc_start_conv() - Start conversions for regular channels. * @adc: stm32 adc instance -@@ -635,30 +917,80 @@ static void stm32_adc_set_res(struct stm32_adc *adc) +@@ -635,30 +916,80 @@ static void stm32_adc_set_res(struct stm32_adc *adc) */ static void stm32f4_adc_start_conv(struct stm32_adc *adc, bool dma) { @@ -1988,13 +2367,13 @@ index 3784118..980355e 100644 + 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); ++ /* Wait for Power-up time (tSTAB from datasheet) */ ++ usleep_range(2, 3); ++ } ++ + if (adc->injected) { + trig_msk = STM32F4_JEXTEN_MASK; + start_msk = STM32F4_JSWSTART; @@ -2063,7 +2442,7 @@ index 3784118..980355e 100644 } static void stm32h7_adc_start_conv(struct stm32_adc *adc, bool dma) -@@ -667,6 +999,11 @@ static void stm32h7_adc_start_conv(struct stm32_adc *adc, bool dma) +@@ -667,6 +998,11 @@ static void stm32h7_adc_start_conv(struct stm32_adc *adc, bool dma) unsigned long flags; u32 val; @@ -2075,7 +2454,7 @@ index 3784118..980355e 100644 if (dma) dmngt = STM32H7_DMNGT_DMA_CIRC; else -@@ -687,6 +1024,16 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) +@@ -687,6 +1023,16 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) int ret; u32 val; @@ -2092,7 +2471,7 @@ index 3784118..980355e 100644 stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTP); ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val, -@@ -704,6 +1051,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) +@@ -704,6 +1050,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) int ret; u32 val; @@ -2103,7 +2482,7 @@ index 3784118..980355e 100644 /* 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); -@@ -730,6 +1081,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) +@@ -730,6 +1080,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc) { @@ -2114,7 +2493,7 @@ index 3784118..980355e 100644 stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST); /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ -@@ -742,6 +1097,9 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) +@@ -742,6 +1096,9 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) int ret; u32 val; @@ -2124,7 +2503,7 @@ index 3784118..980355e 100644 stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN); /* Poll for ADRDY to be set (after adc startup time) */ -@@ -765,6 +1123,10 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) +@@ -765,6 +1122,10 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) int ret; u32 val; @@ -2135,7 +2514,7 @@ index 3784118..980355e 100644 /* 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, -@@ -777,18 +1139,15 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) +@@ -777,18 +1138,15 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) /** * stm32h7_adc_read_selfcalib() - read calibration shadow regs, save result * @adc: stm32 adc instance @@ -2156,7 +2535,7 @@ index 3784118..980355e 100644 /* Read linearity calibration */ lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { -@@ -801,27 +1160,25 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) +@@ -801,27 +1159,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"); @@ -2179,21 +2558,21 @@ index 3784118..980355e 100644 - 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; -- --disable: -- stm32h7_adc_disable(adc); + 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; } /** -@@ -832,11 +1189,16 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) +@@ -832,11 +1188,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); @@ -2212,7 +2591,7 @@ index 3784118..980355e 100644 stm32_adc_writel(adc, STM32H7_ADC_CALFACT, val); lincalrdyw_mask = STM32H7_LINCALRDYW6; -@@ -846,7 +1208,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) +@@ -846,7 +1207,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. */ @@ -2221,7 +2600,7 @@ index 3784118..980355e 100644 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, -@@ -873,7 +1235,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) +@@ -873,7 +1234,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) return ret; } val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2); @@ -2230,7 +2609,7 @@ index 3784118..980355e 100644 dev_err(&indio_dev->dev, "calfact not consistent\n"); return -EIO; } -@@ -898,19 +1260,19 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) +@@ -898,19 +1259,19 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) #define STM32H7_ADC_CALIB_TIMEOUT_US 100000 /** @@ -2255,7 +2634,7 @@ index 3784118..980355e 100644 /* * Select calibration mode: -@@ -927,7 +1289,7 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) +@@ -927,7 +1288,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"); @@ -2264,7 +2643,7 @@ index 3784118..980355e 100644 } /* -@@ -944,18 +1306,13 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) +@@ -944,18 +1305,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"); @@ -2285,7 +2664,7 @@ index 3784118..980355e 100644 return ret; } -@@ -972,23 +1329,43 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) +@@ -972,23 +1328,43 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) */ static int stm32h7_adc_prepare(struct stm32_adc *adc) { @@ -2334,7 +2713,7 @@ index 3784118..980355e 100644 return 0; -@@ -996,39 +1373,196 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) +@@ -996,39 +1372,196 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) stm32h7_adc_disable(adc); pwr_dwn: stm32h7_adc_enter_pwr_down(adc); @@ -2361,10 +2740,9 @@ index 3784118..980355e 100644 stm32h7_adc_disable(adc); stm32h7_adc_enter_pwr_down(adc); + mutex_unlock(&adc->common->inj[adc->id]); - } - - /** -- * stm32_adc_conf_scan_seq() - Build regular channels scan sequence ++} ++ ++/** + * stm32_adc_find_unused_awd() - Find an unused analog watchdog + * @adc: stm32 adc instance + * @@ -2392,9 +2770,10 @@ index 3784118..980355e 100644 + 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 + * @@ -2537,7 +2916,7 @@ index 3784118..980355e 100644 for_each_set_bit(bit, scan_mask, indio_dev->masklength) { chan = indio_dev->channels + bit; -@@ -1037,11 +1571,12 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, +@@ -1037,11 +1570,12 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, * sequence, starting with SQ1. */ i++; @@ -2553,7 +2932,7 @@ index 3784118..980355e 100644 val = stm32_adc_readl(adc, sqr[i].reg); val &= ~sqr[i].mask; -@@ -1071,18 +1606,36 @@ static int stm32_adc_get_trig_extsel(struct iio_dev *indio_dev, +@@ -1071,18 +1605,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); @@ -2592,7 +2971,7 @@ index 3784118..980355e 100644 } } -@@ -1102,10 +1655,24 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, +@@ -1102,10 +1654,24 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, struct iio_trigger *trig) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -2618,7 +2997,7 @@ index 3784118..980355e 100644 if (trig) { ret = stm32_adc_get_trig_extsel(indio_dev, trig); if (ret < 0) -@@ -1117,11 +1684,9 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, +@@ -1117,11 +1683,9 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, } spin_lock_irqsave(&adc->lock, flags); @@ -2633,7 +3012,7 @@ index 3784118..980355e 100644 spin_unlock_irqrestore(&adc->lock, flags); return 0; -@@ -1174,36 +1739,47 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, +@@ -1174,36 +1738,47 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, int *res) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -2693,7 +3072,7 @@ index 3784118..980355e 100644 stm32_adc_conv_irq_enable(adc); -@@ -1224,8 +1800,8 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, +@@ -1224,8 +1799,8 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, stm32_adc_conv_irq_disable(adc); @@ -2704,7 +3083,7 @@ index 3784118..980355e 100644 return ret; } -@@ -1272,14 +1848,72 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, +@@ -1272,14 +1847,72 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, } } @@ -2778,14 +3157,15 @@ index 3784118..980355e 100644 /* Reading DR also clears EOC status flag */ adc->buffer[adc->bufi] = stm32_adc_readw(adc, regs->dr); if (iio_buffer_enabled(indio_dev)) { -@@ -1291,10 +1925,48 @@ static irqreturn_t stm32_adc_isr(int irq, void *data) +@@ -1291,10 +1924,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; + @@ -2822,14 +3202,13 @@ index 3784118..980355e 100644 + + /* AWD has detected an event, need to wake IRQ thread */ + ret = IRQ_WAKE_THREAD; - } - -- return IRQ_NONE; ++ } ++ + return ret; } /** -@@ -1333,13 +2005,168 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, +@@ -1333,13 +2004,168 @@ 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); @@ -3000,7 +3379,7 @@ index 3784118..980355e 100644 return 0; } -@@ -1371,12 +2198,23 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, +@@ -1371,12 +2197,23 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, unsigned *readval) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -3024,7 +3403,7 @@ index 3784118..980355e 100644 return 0; } -@@ -1385,6 +2223,10 @@ static const struct iio_info stm32_adc_iio_info = { +@@ -1385,6 +2222,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, @@ -3035,7 +3414,50 @@ index 3784118..980355e 100644 .debugfs_reg_access = stm32_adc_debugfs_reg_access, .of_xlate = stm32_adc_of_xlate, }; -@@ -1459,21 +2301,28 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev) +@@ -1414,11 +2255,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) +@@ -1449,7 +2311,7 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev) + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) { +- dmaengine_terminate_all(adc->dma_chan); ++ dmaengine_terminate_sync(adc->dma_chan); + return ret; + } + +@@ -1459,21 +2321,28 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev) return 0; } @@ -3070,7 +3492,7 @@ index 3784118..980355e 100644 } ret = stm32_adc_dma_start(indio_dev); -@@ -1482,13 +2331,11 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) +@@ -1482,13 +2351,11 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) goto err_clr_trig; } @@ -3086,7 +3508,7 @@ index 3784118..980355e 100644 if (!adc->dma_chan) stm32_adc_conv_irq_enable(adc); -@@ -1496,30 +2343,42 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) +@@ -1496,39 +2363,66 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) return 0; @@ -3138,9 +3560,13 @@ index 3784118..980355e 100644 - dev_err(&indio_dev->dev, "predisable failed\n"); + stm32_adc_ovr_irq_disable(adc); - if (adc->dma_chan) - dmaengine_terminate_all(adc->dma_chan); -@@ -1527,8 +2386,21 @@ static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev) +- if (adc->dma_chan) +- dmaengine_terminate_all(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"); @@ -3164,7 +3590,7 @@ index 3784118..980355e 100644 return ret; } -@@ -1613,6 +2485,7 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev) +@@ -1613,6 +2507,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]; @@ -3172,7 +3598,7 @@ index 3784118..980355e 100644 u32 period_ns, shift = smpr->shift, mask = smpr->mask; unsigned int smp, r = smpr->reg; -@@ -1625,7 +2498,7 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) +@@ -1625,7 +2520,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) */ @@ -3181,7 +3607,7 @@ index 3784118..980355e 100644 } static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, -@@ -1634,6 +2507,8 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -1634,6 +2529,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]; @@ -3190,7 +3616,7 @@ index 3784118..980355e 100644 chan->type = IIO_VOLTAGE; chan->channel = vinp; -@@ -1654,14 +2529,16 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -1654,14 +2551,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; @@ -3210,7 +3636,7 @@ index 3784118..980355e 100644 } } -@@ -1677,6 +2554,11 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) +@@ -1677,6 +2576,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; @@ -3222,7 +3648,16 @@ index 3784118..980355e 100644 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"); -@@ -1828,6 +2710,7 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1797,6 +2701,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: +@@ -1828,6 +2734,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; @@ -3230,7 +3665,7 @@ index 3784118..980355e 100644 indio_dev->name = dev_name(&pdev->dev); indio_dev->dev.parent = &pdev->dev; -@@ -1838,10 +2721,18 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1838,10 +2745,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); @@ -3250,7 +3685,7 @@ index 3784118..980355e 100644 adc->irq = platform_get_irq(pdev, 0); if (adc->irq < 0) { -@@ -1849,8 +2740,9 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1849,8 +2764,9 @@ static int stm32_adc_probe(struct platform_device *pdev) return adc->irq; } @@ -3262,7 +3697,7 @@ index 3784118..980355e 100644 if (ret) { dev_err(&pdev->dev, "failed to request IRQ\n"); return ret; -@@ -1867,32 +2759,17 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1867,32 +2783,17 @@ static int stm32_adc_probe(struct platform_device *pdev) } } @@ -3298,14 +3733,14 @@ index 3784118..980355e 100644 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, -@@ -1903,15 +2780,35 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1903,15 +2804,35 @@ 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_AUTO_SUSPEND_DELAY_MS); ++ pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + @@ -3335,7 +3770,7 @@ index 3784118..980355e 100644 iio_triggered_buffer_cleanup(indio_dev); err_dma_disable: -@@ -1921,9 +2818,6 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1921,9 +2842,6 @@ static int stm32_adc_probe(struct platform_device *pdev) adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } @@ -3345,7 +3780,7 @@ index 3784118..980355e 100644 return ret; } -@@ -1933,7 +2827,12 @@ static int stm32_adc_remove(struct platform_device *pdev) +@@ -1933,7 +2851,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); @@ -3358,7 +3793,7 @@ index 3784118..980355e 100644 iio_triggered_buffer_cleanup(indio_dev); if (adc->dma_chan) { dma_free_coherent(adc->dma_chan->device->dev, -@@ -1941,12 +2840,62 @@ static int stm32_adc_remove(struct platform_device *pdev) +@@ -1941,12 +2864,62 @@ static int stm32_adc_remove(struct platform_device *pdev) adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } @@ -3423,7 +3858,7 @@ index 3784118..980355e 100644 static const struct stm32_adc_cfg stm32f4_adc_cfg = { .regs = &stm32f4_adc_regspec, .adc_info = &stm32f4_adc_info, -@@ -1955,18 +2904,19 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = { +@@ -1955,18 +2928,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, @@ -3444,7 +3879,7 @@ index 3784118..980355e 100644 }; static const struct stm32_adc_cfg stm32mp1_adc_cfg = { -@@ -1974,12 +2924,12 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { +@@ -1974,12 +2948,12 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .adc_info = &stm32h7_adc_info, .trigs = stm32h7_adc_trigs, .has_vregready = true, @@ -3458,7 +3893,7 @@ index 3784118..980355e 100644 }; static const struct of_device_id stm32_adc_of_match[] = { -@@ -1996,6 +2946,7 @@ static struct platform_driver stm32_adc_driver = { +@@ -1996,6 +2970,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc", .of_match_table = stm32_adc_of_match, @@ -3467,7 +3902,7 @@ index 3784118..980355e 100644 }; 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 fcd4a1c..c97d9ee 100644 +index fcd4a1c..ae6b166 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -12,6 +12,11 @@ @@ -3482,19 +3917,32 @@ index fcd4a1c..c97d9ee 100644 #include #include #include -@@ -38,6 +43,11 @@ - #define DFSDM_MAX_RES BIT(31) - #define DFSDM_DATA_RES BIT(23) +@@ -34,9 +39,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, - DFSDM_IIO, -@@ -54,6 +64,8 @@ struct stm32_dfsdm_adc { +@@ -54,6 +71,8 @@ struct stm32_dfsdm_adc { struct stm32_dfsdm *dfsdm; const struct stm32_dfsdm_dev_data *dev_data; unsigned int fl_id; @@ -3503,10 +3951,12 @@ index fcd4a1c..c97d9ee 100644 /* ADC specific */ unsigned int oversamp; -@@ -114,6 +126,61 @@ static int stm32_dfsdm_str2val(const char *str, +@@ -114,14 +133,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 @@ -3562,20 +4012,153 @@ index fcd4a1c..c97d9ee 100644 + return -EINVAL; +} + - static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, - unsigned int fast, unsigned int oversamp) ++static int stm32_dfsdm_compute_osrs(struct stm32_dfsdm_filter *fl, ++ unsigned int fast, unsigned int oversamp) { -@@ -200,19 +267,39 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, + 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 +215,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 +241,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_start_channel(struct stm32_dfsdm_adc *adc) ++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; @@ -3592,14 +4175,10 @@ index fcd4a1c..c97d9ee 100644 + } + + return 0; - } - --static void stm32_dfsdm_stop_channel(struct stm32_dfsdm *dfsdm, -- unsigned int ch_id) ++} ++ +static void stm32_dfsdm_stop_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; @@ -3614,7 +4193,7 @@ index fcd4a1c..c97d9ee 100644 } static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, -@@ -237,9 +324,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, +@@ -237,9 +387,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); } @@ -3628,7 +4207,7 @@ index fcd4a1c..c97d9ee 100644 int ret; /* Enable filter */ -@@ -248,7 +337,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, +@@ -248,7 +400,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, if (ret < 0) return ret; @@ -3641,7 +4220,7 @@ index fcd4a1c..c97d9ee 100644 return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RSWSTART_MASK, DFSDM_CR1_RSWSTART(1)); -@@ -262,11 +355,45 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, +@@ -262,22 +418,101 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); } @@ -3678,6 +4257,50 @@ index fcd4a1c..c97d9ee 100644 + 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) @@ -3685,13 +4308,27 @@ index fcd4a1c..c97d9ee 100644 + 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 */ -@@ -286,15 +413,68 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, + 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 +521,74 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, if (ret) return ret; @@ -3705,6 +4342,12 @@ index fcd4a1c..c97d9ee 100644 - return regmap_update_bits(regmap, DFSDM_CR1(fl_id), - DFSDM_CR1_RSYNC_MASK, - DFSDM_CR1_RSYNC(fl->sync_mode)); ++ ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), ++ DFSDM_CR1_FAST_MASK, ++ DFSDM_CR1_FAST(fl->fast)); ++ if (ret) ++ return ret; ++ + /* + * DFSDM modes configuration W.R.T audio/iio type modes + * ---------------------------------------------------------------- @@ -3766,7 +4409,7 @@ index fcd4a1c..c97d9ee 100644 } static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, -@@ -378,13 +558,37 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, +@@ -378,13 +672,36 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); } @@ -3775,20 +4418,19 @@ index fcd4a1c..c97d9ee 100644 + unsigned int spi_freq) +{ + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); -+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; + unsigned int oversamp; + int ret; + + oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq); + if (spi_freq % sample_freq) -+ dev_warn(&indio_dev->dev, "Sampling rate not accurate (%d)\n", -+ spi_freq / oversamp); ++ dev_dbg(&indio_dev->dev, ++ "Rate not accurate. requested (%u), actual (%u)\n", ++ sample_freq, spi_freq / oversamp); + -+ ret = stm32_dfsdm_set_osrs(fl, 0, oversamp); -+ if (ret < 0) { -+ dev_err(&indio_dev->dev, "No filter parameters that match!\n"); ++ ret = stm32_dfsdm_compute_all_osrs(indio_dev, oversamp); ++ if (ret < 0) + return ret; -+ } ++ + adc->sample_freq = spi_freq / oversamp; + adc->oversamp = oversamp; + @@ -3805,7 +4447,7 @@ index fcd4a1c..c97d9ee 100644 struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel]; unsigned int sample_freq = adc->sample_freq; unsigned int spi_freq; -@@ -403,17 +607,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, +@@ -403,17 +720,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, return -EINVAL; if (sample_freq) { @@ -3825,7 +4467,7 @@ index fcd4a1c..c97d9ee 100644 } adc->spi_freq = spi_freq; -@@ -421,72 +617,44 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, +@@ -421,72 +730,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, @@ -3838,16 +4480,15 @@ index fcd4a1c..c97d9ee 100644 - unsigned int dma_en = 0, cont_en = 0; - ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel); -+ ret = stm32_dfsdm_start_channel(adc); ++ 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); -+ ret = stm32_dfsdm_filter_configure(adc, adc->fl_id, trig); - if (ret < 0) - goto stop_channels; - +- if (ret < 0) +- goto stop_channels; +- - if (dma) { - /* Enable DMA transfer*/ - dma_en = DFSDM_CR1_RDMAEN(1); @@ -3857,29 +4498,32 @@ index fcd4a1c..c97d9ee 100644 - /* Enable DMA transfer*/ - ret = regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK, dma_en); -+ ret = stm32_dfsdm_start_filter(adc, adc->fl_id, trig); ++ 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); -- if (ret < 0) -- goto stop_channels; -- ++ 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); -- if (ret < 0) ++ 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), +- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RDMAEN_MASK, 0); - -- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), ++filter_unconfigure: + 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); @@ -3910,7 +4554,7 @@ index fcd4a1c..c97d9ee 100644 } static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, -@@ -494,6 +662,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, +@@ -494,6 +779,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; @@ -3918,7 +4562,7 @@ index fcd4a1c..c97d9ee 100644 /* * DMA cyclic transfers are used, buffer is split into two periods. -@@ -502,7 +671,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, +@@ -502,7 +788,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))); @@ -3927,11 +4571,35 @@ index fcd4a1c..c97d9ee 100644 return 0; } -@@ -532,13 +701,41 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) +@@ -532,13 +818,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; @@ -3940,7 +4608,9 @@ index fcd4a1c..c97d9ee 100644 + int available = stm32_dfsdm_adc_dma_residue(adc); + + 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); + + iio_push_to_buffers_with_timestamp(indio_dev, buffer, + pf->timestamp); @@ -3970,7 +4640,21 @@ index fcd4a1c..c97d9ee 100644 /* * FIXME: In Kernel interface does not support cyclic DMA buffer,and * offers only an interface to push data samples per samples. -@@ -566,6 +763,9 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) +@@ -553,10 +893,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 +906,9 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) adc->bufi = 0; old_pos = 0; } @@ -3980,10 +4664,15 @@ index fcd4a1c..c97d9ee 100644 } if (adc->cb) adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, -@@ -575,6 +775,10 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) +@@ -575,6 +918,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, @@ -3991,7 +4680,7 @@ index fcd4a1c..c97d9ee 100644 struct dma_async_tx_descriptor *desc; dma_cookie_t cookie; int ret; -@@ -585,6 +789,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) +@@ -585,6 +937,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); @@ -4006,7 +4695,7 @@ index fcd4a1c..c97d9ee 100644 /* Prepare a DMA cyclic transaction */ desc = dmaengine_prep_dma_cyclic(adc->dma_chan, adc->dma_buf, -@@ -594,71 +806,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) +@@ -594,71 +954,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) if (!desc) return -EBUSY; @@ -4184,7 +4873,7 @@ index fcd4a1c..c97d9ee 100644 return 0; } -@@ -736,7 +1031,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, +@@ -736,7 +1179,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, if (ret < 0) goto stop_dfsdm; @@ -4195,23 +4884,33 @@ index fcd4a1c..c97d9ee 100644 if (ret < 0) { regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id), DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0)); -@@ -757,7 +1054,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, +@@ -757,7 +1202,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); -@@ -777,16 +1074,23 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, +@@ -770,23 +1217,29 @@ 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 (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: +- ret = stm32_dfsdm_set_osrs(fl, 0, val); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; - ret = stm32_dfsdm_set_osrs(fl, 0, val); ++ ret = stm32_dfsdm_compute_all_osrs(indio_dev, val); if (!ret) adc->oversamp = val; - @@ -4229,7 +4928,7 @@ index fcd4a1c..c97d9ee 100644 switch (ch->src) { case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: spi_freq = adc->dfsdm->spi_master_freq; -@@ -799,20 +1103,9 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, +@@ -799,20 +1252,9 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, spi_freq = adc->spi_freq; } @@ -4253,7 +4952,7 @@ index fcd4a1c..c97d9ee 100644 } return -EINVAL; -@@ -827,11 +1120,15 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -827,11 +1269,15 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: @@ -4269,7 +4968,7 @@ index fcd4a1c..c97d9ee 100644 return ret; } ret = stm32_dfsdm_single_conv(indio_dev, chan, val); -@@ -840,8 +1137,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -840,8 +1286,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); @@ -4280,7 +4979,7 @@ index fcd4a1c..c97d9ee 100644 return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -@@ -858,15 +1157,25 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -858,15 +1306,25 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, return -EINVAL; } @@ -4306,7 +5005,7 @@ index fcd4a1c..c97d9ee 100644 }; static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) -@@ -926,12 +1235,6 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) +@@ -926,12 +1384,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); @@ -4319,7 +5018,7 @@ index fcd4a1c..c97d9ee 100644 adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); if (!adc->dma_chan) -@@ -941,23 +1244,14 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) +@@ -941,23 +1393,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) { @@ -4347,7 +5046,7 @@ index fcd4a1c..c97d9ee 100644 } static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, -@@ -978,7 +1272,8 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -978,14 +1421,15 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling */ ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); @@ -4356,8 +5055,17 @@ index fcd4a1c..c97d9ee 100644 + BIT(IIO_CHAN_INFO_SAMP_FREQ); if (adc->dev_data->type == DFSDM_AUDIO) { - ch->scan_type.sign = 's'; -@@ -1000,9 +1295,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) +- ch->scan_type.sign = 's'; + ch->ext_info = dfsdm_adc_audio_ext_info; + } else { +- ch->scan_type.sign = 'u'; ++ ch->scan_type.shift = 8; + } ++ ch->scan_type.sign = 's'; + ch->scan_type.realbits = 24; + ch->scan_type.storagebits = 32; + +@@ -1000,9 +1444,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) struct stm32_dfsdm_channel *d_ch; int ret; @@ -4367,7 +5075,17 @@ index fcd4a1c..c97d9ee 100644 ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); if (!ch) return -ENOMEM; -@@ -1070,6 +1362,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) +@@ -1034,8 +1475,7 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + int ret, chan_idx; + + 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; + +@@ -1070,6 +1510,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) init_completion(&adc->completion); @@ -4393,7 +5111,7 @@ index fcd4a1c..c97d9ee 100644 return 0; } -@@ -1117,7 +1428,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) +@@ -1117,7 +1576,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) iio->dev.parent = dev; iio->dev.of_node = np; @@ -4402,7 +5120,20 @@ index fcd4a1c..c97d9ee 100644 platform_set_drvdata(pdev, adc); -@@ -1203,10 +1514,48 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) +@@ -1144,6 +1603,12 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) + * So IRQ associated to filter instance 0 is dedicated to the Filter 0. + */ + irq = platform_get_irq(pdev, 0); ++ if (irq < 0) { ++ if (irq != -EPROBE_DEFER) ++ dev_err(dev, "Failed to get IRQ: %d\n", irq); ++ return irq; ++ } ++ + ret = devm_request_irq(dev, irq, stm32_dfsdm_irq, + 0, pdev->name, adc); + if (ret < 0) { +@@ -1203,10 +1668,48 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) return 0; } @@ -4452,7 +5183,7 @@ index fcd4a1c..c97d9ee 100644 .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 bf089f5..2d2c640 100644 +index bf089f5..9609515 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -12,6 +12,8 @@ @@ -4588,7 +5319,29 @@ index bf089f5..2d2c640 100644 } dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, atomic_read(&priv->n_active_ch)); -@@ -243,13 +263,18 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, +@@ -213,6 +233,8 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, + } + priv->dfsdm.phys_base = res->start; + priv->dfsdm.base = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(priv->dfsdm.base)) ++ return PTR_ERR(priv->dfsdm.base); + + /* + * "dfsdm" clock is mandatory for DFSDM peripheral clocking. +@@ -222,8 +244,10 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, + */ + priv->clk = devm_clk_get(&pdev->dev, "dfsdm"); + if (IS_ERR(priv->clk)) { +- dev_err(&pdev->dev, "No stm32_dfsdm_clk clock found\n"); +- return -EINVAL; ++ ret = PTR_ERR(priv->clk); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "Failed to get clock (%d)\n", ret); ++ return ret; + } + + priv->aclk = devm_clk_get(&pdev->dev, "audio"); +@@ -243,13 +267,18 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, return 0; } @@ -4609,7 +5362,7 @@ index bf089f5..2d2c640 100644 if (rem) { dev_warn(&pdev->dev, "SPI clock not accurate\n"); -@@ -318,14 +343,115 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) +@@ -318,14 +347,115 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dfsdm); @@ -4639,8 +5392,8 @@ index bf089f5..2d2c640 100644 + 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); @@ -4670,8 +5423,8 @@ index bf089f5..2d2c640 100644 + 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); @@ -4726,8 +5479,51 @@ index bf089f5..2d2c640 100644 }, }; +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..2a49cce 100644 +index 42fb8ba..2a49cce0e 100644 --- a/drivers/iio/counter/stm32-lptimer-cnt.c +++ b/drivers/iio/counter/stm32-lptimer-cnt.c @@ -14,6 +14,7 @@ @@ -4827,6 +5623,398 @@ index 42fb8ba..2a49cce 100644 }, }; 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 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0011-ARM-stm32mp1-r2-INPUT-IRQ-Mailbox.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0011-ARM-stm32mp1-r2-INPUT-IRQ-Mailbox.patch new file mode 100644 index 0000000..520ebea --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0011-ARM-stm32mp1-r2-INPUT-IRQ-Mailbox.patch @@ -0,0 +1,1099 @@ +From a7a3aa42479bf82ba9ed31d2960ad299a5bb214b Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:01 +0200 +Subject: [PATCH 11/30] ARM stm32mp1 r2 INPUT IRQ Mailbox + +--- + drivers/input/misc/Kconfig | 11 ++ + drivers/input/misc/Makefile | 2 + + drivers/input/misc/stpmic1_onkey.c | 197 +++++++++++++++++++ + drivers/input/touchscreen/edt-ft5x06.c | 8 +- + drivers/input/touchscreen/goodix.c | 9 + + drivers/irqchip/irq-stm32-exti.c | 339 +++++++++++++++++++++++++++------ + drivers/mailbox/mailbox-test.c | 26 +-- + drivers/mailbox/stm32-ipcc.c | 54 ++++-- + 8 files changed, 555 insertions(+), 91 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..6a7f08b +--- /dev/null ++++ b/drivers/input/misc/stpmic1_onkey.c +@@ -0,0 +1,197 @@ ++// 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..c1c6f2a 100644 +--- a/drivers/input/touchscreen/edt-ft5x06.c ++++ b/drivers/input/touchscreen/edt-ft5x06.c +@@ -1033,7 +1033,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; + } + +@@ -1152,11 +1152,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 +1174,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 f2d9c2c..9ce8db4 100644 +--- a/drivers/input/touchscreen/goodix.c ++++ b/drivers/input/touchscreen/goodix.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -357,6 +358,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); +@@ -949,6 +957,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 58bfafc..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; +@@ -363,22 +363,24 @@ static int mbox_test_probe(struct platform_device *pdev) + + /* It's okay for MMIO to be NULL */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- size = resource_size(res); + tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); +- if (PTR_ERR(tdev->tx_mmio) == -EBUSY) ++ if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { + /* if reserved area in SRAM, try just ioremap */ ++ size = resource_size(res); + tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); +- else if (IS_ERR(tdev->tx_mmio)) ++ } else if (IS_ERR(tdev->tx_mmio)) { + tdev->tx_mmio = NULL; ++ } + + /* If specified, second reg entry is Rx MMIO */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +- size = resource_size(res); + tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res); +- if (PTR_ERR(tdev->rx_mmio) == -EBUSY) ++ if (PTR_ERR(tdev->rx_mmio) == -EBUSY) { ++ size = resource_size(res); + tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); +- else if (IS_ERR(tdev->rx_mmio)) ++ } else if (IS_ERR(tdev->rx_mmio)) { + tdev->rx_mmio = tdev->tx_mmio; ++ } + + tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); + tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); +@@ -416,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 533b0da..eaf4ea4 100644 +--- a/drivers/mailbox/stm32-ipcc.c ++++ b/drivers/mailbox/stm32-ipcc.c +@@ -8,9 +8,9 @@ + #include + #include + #include ++#include + #include + #include +-#include + #include + #include + +@@ -50,6 +50,7 @@ struct stm32_ipcc { + void __iomem *reg_base; + void __iomem *reg_proc; + struct clk *clk; ++ spinlock_t lock; /* protect access to IPCC registers */ + int irqs[IPCC_IRQ_NUM]; + int wkp; + u32 proc_id; +@@ -58,14 +59,24 @@ struct stm32_ipcc { + u32 xmr; + }; + +-static inline void stm32_ipcc_set_bits(void __iomem *reg, u32 mask) ++static inline void stm32_ipcc_set_bits(spinlock_t *lock, void __iomem *reg, ++ u32 mask) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(lock, flags); + writel_relaxed(readl_relaxed(reg) | mask, reg); ++ spin_unlock_irqrestore(lock, flags); + } + +-static inline void stm32_ipcc_clr_bits(void __iomem *reg, u32 mask) ++static inline void stm32_ipcc_clr_bits(spinlock_t *lock, void __iomem *reg, ++ u32 mask) + { ++ unsigned long flags; ++ ++ spin_lock_irqsave(lock, flags); + writel_relaxed(readl_relaxed(reg) & ~mask, reg); ++ spin_unlock_irqrestore(lock, flags); + } + + static irqreturn_t stm32_ipcc_rx_irq(int irq, void *data) +@@ -92,7 +103,7 @@ static irqreturn_t stm32_ipcc_rx_irq(int irq, void *data) + + mbox_chan_received_data(&ipcc->controller.chans[chan], NULL); + +- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XSCR, ++ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XSCR, + RX_BIT_CHAN(chan)); + + ret = IRQ_HANDLED; +@@ -121,7 +132,7 @@ static irqreturn_t stm32_ipcc_tx_irq(int irq, void *data) + dev_dbg(dev, "%s: chan:%d tx\n", __func__, chan); + + /* mask 'tx channel free' interrupt */ +- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR, ++ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR, + TX_BIT_CHAN(chan)); + + mbox_chan_txdone(&ipcc->controller.chans[chan], 0); +@@ -141,10 +152,12 @@ static int stm32_ipcc_send_data(struct mbox_chan *link, void *data) + dev_dbg(ipcc->controller.dev, "%s: chan:%d\n", __func__, chan); + + /* set channel n occupied */ +- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XSCR, TX_BIT_CHAN(chan)); ++ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XSCR, ++ TX_BIT_CHAN(chan)); + + /* unmask 'tx channel free' interrupt */ +- stm32_ipcc_clr_bits(ipcc->reg_proc + IPCC_XMR, TX_BIT_CHAN(chan)); ++ stm32_ipcc_clr_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR, ++ TX_BIT_CHAN(chan)); + + return 0; + } +@@ -163,7 +176,8 @@ static int stm32_ipcc_startup(struct mbox_chan *link) + } + + /* unmask 'rx channel occupied' interrupt */ +- stm32_ipcc_clr_bits(ipcc->reg_proc + IPCC_XMR, RX_BIT_CHAN(chan)); ++ stm32_ipcc_clr_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR, ++ RX_BIT_CHAN(chan)); + + return 0; + } +@@ -175,7 +189,7 @@ static void stm32_ipcc_shutdown(struct mbox_chan *link) + controller); + + /* mask rx/tx interrupt */ +- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR, ++ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR, + RX_BIT_CHAN(chan) | TX_BIT_CHAN(chan)); + + clk_disable_unprepare(ipcc->clk); +@@ -208,6 +222,8 @@ static int stm32_ipcc_probe(struct platform_device *pdev) + if (!ipcc) + return -ENOMEM; + ++ spin_lock_init(&ipcc->lock); ++ + /* proc_id */ + if (of_property_read_u32(np, "st,proc-id", &ipcc->proc_id)) { + dev_err(dev, "Missing st,proc-id\n"); +@@ -240,9 +256,11 @@ static int stm32_ipcc_probe(struct platform_device *pdev) + + /* irq */ + for (i = 0; i < IPCC_IRQ_NUM; i++) { +- ipcc->irqs[i] = of_irq_get_byname(dev->of_node, irq_name[i]); ++ ipcc->irqs[i] = platform_get_irq_byname(pdev, irq_name[i]); + if (ipcc->irqs[i] < 0) { +- dev_err(dev, "no IRQ specified %s\n", irq_name[i]); ++ if (ipcc->irqs[i] != -EPROBE_DEFER) ++ dev_err(dev, "no IRQ specified %s\n", ++ irq_name[i]); + ret = ipcc->irqs[i]; + goto err_clk; + } +@@ -257,15 +275,17 @@ static int stm32_ipcc_probe(struct platform_device *pdev) + } + + /* mask and enable rx/tx irq */ +- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XMR, ++ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XMR, + RX_BIT_MASK | TX_BIT_MASK); +- stm32_ipcc_set_bits(ipcc->reg_proc + IPCC_XCR, XCR_RXOIE | XCR_TXOIE); ++ stm32_ipcc_set_bits(&ipcc->lock, ipcc->reg_proc + IPCC_XCR, ++ XCR_RXOIE | XCR_TXOIE); + + /* wakeup */ + if (of_property_read_bool(np, "wakeup-source")) { +- ipcc->wkp = of_irq_get_byname(dev->of_node, "wakeup"); ++ ipcc->wkp = platform_get_irq_byname(pdev, "wakeup"); + if (ipcc->wkp < 0) { +- dev_err(dev, "could not get wakeup IRQ\n"); ++ if (ipcc->wkp != -EPROBE_DEFER) ++ dev_err(dev, "could not get wakeup IRQ\n"); + ret = ipcc->wkp; + goto err_clk; + } +@@ -276,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 */ +-- +2.7.4 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0012-ARM-stm32mp1-r2-MEDIA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0012-ARM-stm32mp1-r2-MEDIA.patch new file mode 100644 index 0000000..67562c9 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0012-ARM-stm32mp1-r2-MEDIA.patch @@ -0,0 +1,1774 @@ +From c26e518bb565acef9af071733f60227f67a048ee Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:01 +0200 +Subject: [PATCH 12/30] ARM stm32mp1 r2 MEDIA + +--- + drivers/media/i2c/ov5640.c | 995 +++++++++++++++++++----------- + drivers/media/platform/stm32/stm32-cec.c | 96 ++- + drivers/media/platform/stm32/stm32-dcmi.c | 70 ++- + 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 + + 7 files changed, 811 insertions(+), 381 deletions(-) + +diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c +index d5c0ffc..4432188 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 */ +@@ -261,8 +277,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 +304,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,27 +359,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}, ++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}, +@@ -377,33 +373,13 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_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_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_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}, +@@ -416,13 +392,12 @@ 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_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}, +@@ -435,13 +410,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_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}, +@@ -454,70 +428,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}, +- {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_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}, +- {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_15fps_NTSC_720_480[] = { +- {0x3035, 0x22, 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}, +@@ -530,32 +446,12 @@ static const struct reg_value ov5640_setting_15fps_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}, +-}; +- +-static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = { +- {0x3035, 0x12, 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}, ++ {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}, ++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}, +@@ -568,14 +464,12 @@ static const struct reg_value ov5640_setting_15fps_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_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 +482,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 +501,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,15 +513,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}, ++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}, +@@ -661,40 +531,9 @@ static const struct reg_value ov5640_setting_15fps_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, 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}, +- {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, 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 +544,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 +712,387 @@ 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)); ++} ++ ++/* 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); + } + ++/* download ov5640 settings to sensor through i2c */ + static int ov5640_load_regs(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) + { +@@ -957,7 +1120,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 +1225,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 +1591,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 (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { ++ ret = ov5640_set_jpeg_timings(sensor, mode); ++ if (ret < 0) ++ return ret; ++ } ++ ++ 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 +1636,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 +1825,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 +1847,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 +1887,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 +1937,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 +2138,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, +@@ -2061,46 +2279,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 +2507,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) +@@ -2412,11 +2682,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; +@@ -2501,10 +2766,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,11 +2834,12 @@ 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; ++ } + +- sensor->current_fr = frame_rate; +- sensor->frame_interval = fi->interval; + mode = ov5640_find_mode(sensor, frame_rate, mode->hact, + mode->vact, true); + if (!mode) { +@@ -2581,7 +2847,10 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, + goto out; + } + +- if (mode != sensor->current_mode) { ++ if (mode != sensor->current_mode || ++ frame_rate != sensor->current_fr) { ++ sensor->current_fr = frame_rate; ++ sensor->frame_interval = fi->interval; + sensor->current_mode = mode; + sensor->pending_mode_change = true; + } +@@ -2734,7 +3003,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/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 d386822..1737892 100644 +--- a/drivers/media/platform/stm32/stm32-dcmi.c ++++ b/drivers/media/platform/stm32/stm32-dcmi.c +@@ -95,8 +95,13 @@ 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 ++ + struct dcmi_graph_entity { + struct device_node *node; + +@@ -164,6 +169,9 @@ struct stm32_dcmi { + int errors_count; + int overrun_count; + int buffers_count; ++ ++ /* Ensure DMA operations atomicity */ ++ struct mutex dma_lock; + }; + + static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) +@@ -314,6 +322,13 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, + return ret; + } + ++ /* ++ * Avoid call of dmaengine_terminate_all() between ++ * dmaengine_prep_slave_single() and dmaengine_submit() ++ * by locking the whole DMA submission sequence ++ */ ++ mutex_lock(&dcmi->dma_lock); ++ + /* Prepare a DMA transaction */ + desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr, + buf->size, +@@ -322,6 +337,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, + if (!desc) { + dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n", + __func__, &buf->paddr, buf->size); ++ mutex_unlock(&dcmi->dma_lock); + return -EINVAL; + } + +@@ -333,9 +349,12 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, + dcmi->dma_cookie = dmaengine_submit(desc); + if (dma_submit_error(dcmi->dma_cookie)) { + dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__); ++ mutex_unlock(&dcmi->dma_lock); + return -ENXIO; + } + ++ mutex_unlock(&dcmi->dma_lock); ++ + dma_async_issue_pending(dcmi->dma_chan); + + return 0; +@@ -432,11 +451,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) { +@@ -570,9 +591,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) + int ret; + + ret = pm_runtime_get_sync(dcmi->dev); +- if (ret) { +- dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n", +- __func__); ++ if (ret < 0) { ++ dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n", ++ __func__, ret); + goto err_release_buffers; + } + +@@ -621,8 +642,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.subdev, &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); +@@ -659,7 +703,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) + } + + /* 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; + +@@ -717,7 +764,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) + spin_unlock_irq(&dcmi->irqlock); + + /* Stop all pending DMA operations */ ++ mutex_lock(&dcmi->dma_lock); + dmaengine_terminate_all(dcmi->dma_chan); ++ mutex_unlock(&dcmi->dma_lock); + + pm_runtime_put(dcmi->dev); + +@@ -1719,6 +1768,7 @@ static int dcmi_probe(struct platform_device *pdev) + + spin_lock_init(&dcmi->irqlock); + mutex_init(&dcmi->lock); ++ mutex_init(&dcmi->dma_lock); + init_completion(&dcmi->complete); + INIT_LIST_HEAD(&dcmi->buffers); + +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; + + } +-- +2.7.4 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0008-ARM-stm32mp1-r0-rc1-MFD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0013-ARM-stm32mp1-r2-MFD.patch similarity index 84% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0008-ARM-stm32mp1-r0-rc1-MFD.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0013-ARM-stm32mp1-r2-MFD.patch index 36b8687..e6af02a 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0008-ARM-stm32mp1-r0-rc1-MFD.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0013-ARM-stm32mp1-r2-MFD.patch @@ -1,18 +1,21 @@ -From 254a1f3c99a65578044558234a01b4fbc180b3d6 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:22:30 +0100 -Subject: [PATCH 08/52] ARM: stm32mp1-r0-rc1: MFD +From 1e1b3d357ac9971d70631b624301524294ea5d3c Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:02 +0200 +Subject: [PATCH 13/30] ARM stm32mp1 r2 MFD --- drivers/mfd/Kconfig | 31 ++ drivers/mfd/Makefile | 4 +- - drivers/mfd/stm32-pwr.c | 287 ++++++++++++++++ + drivers/mfd/stm32-pwr.c | 400 ++++++++++++++++++++++ drivers/mfd/stmfx.c | 626 +++++++++++++++++++++++++++++++++++ - drivers/mfd/stpmic1.c | 413 +++++++++++++++++++++++ + drivers/mfd/stpmic1.c | 409 +++++++++++++++++++++++ + drivers/mfd/syscon.c | 19 ++ + drivers/mfd/wm8994-core.c | 21 ++ include/dt-bindings/mfd/st,stpmic1.h | 46 +++ include/linux/mfd/stmfx.h | 27 ++ - include/linux/mfd/stpmic1.h | 213 ++++++++++++ - 8 files changed, 1646 insertions(+), 1 deletion(-) + include/linux/mfd/stpmic1.h | 212 ++++++++++++ + include/linux/mfd/wm8994/pdata.h | 6 + + 11 files changed, 1800 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 @@ -84,10 +87,10 @@ index 5856a94..d794a2d 100644 +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..377e2f5 +index 0000000..92744bf --- /dev/null +++ b/drivers/mfd/stm32-pwr.c -@@ -0,0 +1,287 @@ +@@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -95,7 +98,11 @@ index 0000000..377e2f5 + */ + +#include ++#include ++#include +#include ++#include ++#include +#include +#include +#include @@ -127,18 +134,21 @@ index 0000000..377e2f5 + WKUP_PULL_RESERVED +}; + -+#define SMC(class, op, offset, val) \ -+{ \ ++#define SMC(class, op, offset, val) do { \ + struct arm_smccc_res res; \ -+ arm_smccc_smc(class, op, SMC_PWR_BASE + offset, val, \ ++ arm_smccc_smc(class, op, SMC_PWR_BASE + (offset), val, \ + 0, 0, 0, 0, &res); \ -+} \ ++} while (0) \ + +struct stm32_pwr_data { -+ struct device *dev; /* self device */ ++ 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) @@ -149,12 +159,24 @@ index 0000000..377e2f5 + 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); -+ SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, BIT(d->hwirq)); ++ priv->masked |= BIT(d->hwirq); ++ stm32_pwr_irq_set_enable(d); +} + +static void stm32_pwr_irq_unmask(struct irq_data *d) @@ -162,18 +184,26 @@ index 0000000..377e2f5 + 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, MPUWKUPENR, BIT(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) -+ enable_irq_wake(priv->irq); -+ else -+ disable_irq_wake(priv->irq); ++ 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; +} @@ -205,6 +235,7 @@ index 0000000..377e2f5 + default: + return -EINVAL; + } ++ + SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); + + if (en) @@ -213,22 +244,59 @@ index 0000000..377e2f5 + 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", ++ .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_map(struct irq_domain *h, unsigned int virq, -+ irq_hw_number_t hw) -+{ -+ irq_set_chip_and_handler(virq, &stm32_pwr_irq_chip, handle_edge_irq); -+ return 0; -+} -+ +static int stm32_pwr_irq_set_pull_config(struct irq_domain *d, int pin_id, + enum wkup_pull_setting config) +{ @@ -238,13 +306,14 @@ index 0000000..377e2f5 + dev_dbg(priv->dev, "irq:%d pull config:0x%x\n", pin_id, config); + + if (config >= WKUP_PULL_RESERVED) { -+ dev_err(priv->dev, "%s: bad irq pull config\n", __func__); ++ 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; @@ -254,10 +323,8 @@ index 0000000..377e2f5 + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ -+ struct stm32_pwr_data *priv = d->host_data; -+ + if (WARN_ON(intsize < 3)) { -+ dev_err(priv->dev, "%s: bad irq config parameters\n", __func__); ++ pr_err("%s: bad irq config parameters\n", __func__); + return -EINVAL; + } + @@ -267,9 +334,23 @@ index 0000000..377e2f5 + 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 = { -+ .map = stm32_pwr_irq_map, ++ .alloc = stm32_pwr_alloc, + .xlate = stm32_pwr_xlate, ++ .free = irq_domain_free_irqs_common, +}; + +/* @@ -285,36 +366,59 @@ index 0000000..377e2f5 + + 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); -+ generic_handle_irq(irq_find_mapping(priv->domain, 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 device_node *np = pdev->dev.of_node; + struct stm32_pwr_data *priv; -+ ++ struct device_node *np = dev->of_node; + struct resource *res; + int ret; + -+ priv = devm_kzalloc(dev, sizeof(struct stm32_pwr_data), GFP_KERNEL); ++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; -+ -+ platform_set_drvdata(pdev, priv); + priv->dev = dev; ++ dev_set_drvdata(dev, priv); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ priv->base = devm_ioremap_resource(&pdev->dev, res); ++ priv->base = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->base)) { -+ dev_err(dev, "%s: Unable to map IO memory\n", __func__); ++ dev_err(dev, "Unable to map registers\n"); + return PTR_ERR(priv->base); + } + @@ -327,46 +431,51 @@ index 0000000..377e2f5 + &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 = platform_get_irq(pdev, 0); ++ ret = irq_of_parse_and_map(np, 0); + if (ret < 0) { + dev_err(dev, "failed to get PWR IRQ\n"); -+ goto err; ++ ret = priv->irq; ++ goto out_domain; + } ++ + priv->irq = ret; ++ irq_set_chained_handler_and_data(priv->irq, stm32_pwr_handle_irq, priv); + -+ irq_set_chained_handler_and_data(priv->irq, -+ stm32_pwr_handle_irq, priv); ++ of_node_clear_flag(np, OF_POPULATED); + -+out: + return 0; -+err: ++ ++out_domain: + irq_domain_remove(priv->domain); ++out: + return ret; +} + +static int stm32_pwr_remove(struct platform_device *pdev) +{ -+ struct stm32_pwr_data *priv = platform_get_drvdata(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_match[] = { -+ { .compatible = "st,stm32mp1-pwr" }, ++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", -+ .owner = THIS_MODULE, -+ .of_match_table = stm32_pwr_match, ++ .probe = stm32_pwr_probe, ++ .remove = stm32_pwr_remove, ++ .driver = { ++ .name = "stm32_pwr", ++ .of_match_table = stm32_pwr_ids, ++ .pm = &stm32_pwr_pm, + }, +}; + @@ -374,7 +483,14 @@ index 0000000..377e2f5 +{ + 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..cfd4fca @@ -1009,10 +1125,10 @@ index 0000000..cfd4fca +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c new file mode 100644 -index 0000000..5bf6328 +index 0000000..648315d --- /dev/null +++ b/drivers/mfd/stpmic1.c -@@ -0,0 +1,413 @@ +@@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet @@ -1283,13 +1399,8 @@ index 0000000..5bf6328 + return ddata->irq; + } + -+ ddata->irq_wake = of_irq_get(np, STPMIC1_WAKEUP_IRQ); -+ if (ddata->irq_wake > 0) { ++ if (of_property_read_bool(np, "wakeup-source")) + device_init_wakeup(dev, true); -+ ret = dev_pm_set_dedicated_wake_irq(dev, ddata->irq_wake); -+ if (ret) -+ dev_warn(dev, "failed to set up wakeup irq"); -+ } + + if (!of_property_read_u32(np, "st,main-control-register", ®)) { + ret = regmap_update_bits(ddata->regmap, @@ -1386,8 +1497,8 @@ index 0000000..5bf6328 + struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); + + disable_irq(pmic_dev->irq); -+ if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev)) -+ enable_irq_wake(pmic_dev->irq_wake); ++ if (device_may_wakeup(dev)) ++ enable_irq_wake(pmic_dev->irq); + + return 0; +} @@ -1402,9 +1513,10 @@ index 0000000..5bf6328 + if (ret) + return ret; + ++ if (device_may_wakeup(dev)) ++ disable_irq_wake(pmic_dev->irq); ++ + enable_irq(pmic_dev->irq); -+ if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev)) -+ disable_irq_wake(pmic_dev->irq_wake); + + return 0; +} @@ -1426,6 +1538,103 @@ index 0000000..5bf6328 +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..b2d6c83 @@ -1513,10 +1722,10 @@ index 0000000..35c3d42 +#endif diff --git a/include/linux/mfd/stpmic1.h b/include/linux/mfd/stpmic1.h new file mode 100644 -index 0000000..4abe5f1 +index 0000000..fa3f99f --- /dev/null +++ b/include/linux/mfd/stpmic1.h -@@ -0,0 +1,213 @@ +@@ -0,0 +1,212 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -1725,11 +1934,27 @@ index 0000000..4abe5f1 + struct device *dev; + struct regmap *regmap; + int irq; -+ int irq_wake; + 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.9/0009-ARM-stm32mp1-r0-rc1-MMC-MTD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0014-ARM-stm32mp1-r2-MMC-MTD.patch similarity index 76% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0009-ARM-stm32mp1-r0-rc1-MMC-MTD.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0014-ARM-stm32mp1-r2-MMC-MTD.patch index d11c0d2..2f1cc29 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0009-ARM-stm32mp1-r0-rc1-MMC-MTD.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0014-ARM-stm32mp1-r2-MMC-MTD.patch @@ -1,22 +1,25 @@ -From c40b273973671e355eacd8bad62bd938b0ebc05f Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:23:12 +0100 -Subject: [PATCH 09/52] ARM: stm32mp1-r0-rc1: MMC MTD +From ae70b2603fb4622389c5b26d5214a2f6879714e9 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:02 +0200 +Subject: [PATCH 14/30] ARM stm32mp1 r2 MMC MTD --- drivers/mmc/host/Kconfig | 10 + drivers/mmc/host/Makefile | 1 + - drivers/mmc/host/mmci.c | 811 +++++++++---- - drivers/mmc/host/mmci.h | 180 ++- + drivers/mmc/host/mmci.c | 900 ++++++++++---- + drivers/mmc/host/mmci.h | 195 +++- drivers/mmc/host/mmci_qcom_dml.c | 17 +- - drivers/mmc/host/mmci_stm32_sdmmc.c | 282 +++++ + 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 | 2031 ++++++++++++++++++++++++++++++++ - include/linux/amba/mmci.h | 11 +- - 10 files changed, 3067 insertions(+), 286 deletions(-) + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2005 ++++++++++++++++++++++++++++++++ + drivers/mtd/spi-nor/Kconfig | 7 - + drivers/mtd/spi-nor/Makefile | 1 - + drivers/mtd/spi-nor/stm32-quadspi.c | 720 ------------ + 12 files changed, 3277 insertions(+), 1018 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 @@ -52,10 +55,18 @@ index ce8398e..f14410f 100644 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 1841d250..db50d1e 100644 +index 1841d250..0b7b607 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c -@@ -21,6 +21,7 @@ +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -21,15 +22,16 @@ #include #include #include @@ -63,7 +74,8 @@ index 1841d250..db50d1e 100644 #include #include #include -@@ -28,8 +29,7 @@ ++#include + #include #include #include #include @@ -73,7 +85,7 @@ index 1841d250..db50d1e 100644 #include #include #include -@@ -37,6 +37,7 @@ +@@ -37,6 +39,7 @@ #include #include #include @@ -81,7 +93,7 @@ index 1841d250..db50d1e 100644 #include #include -@@ -46,41 +47,79 @@ +@@ -46,41 +49,79 @@ #define DRIVER_NAME "mmci-pl18x" @@ -161,7 +173,7 @@ index 1841d250..db50d1e 100644 }; static struct variant_data variant_u300 = { -@@ -88,7 +127,13 @@ 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, @@ -173,9 +185,10 @@ index 1841d250..db50d1e 100644 + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, - .st_sdio = true, +- .st_sdio = true, .pwrreg_powerup = MCI_PWR_ON, -@@ -97,8 +142,10 @@ static struct variant_data variant_u300 = { + .f_max = 100000000, + .signal_direction = true, .pwrreg_clkgate = true, .pwrreg_nopower = true, .mmcimask1 = true, @@ -183,10 +196,11 @@ index 1841d250..db50d1e 100644 .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, ++ .quirks = MMCI_QUIRK_ST_SDIO, }; static struct variant_data variant_nomadik = { -@@ -106,7 +153,13 @@ 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, @@ -198,9 +212,11 @@ index 1841d250..db50d1e 100644 + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, - .st_sdio = true, +- .st_sdio = true, .st_clkdiv = true, -@@ -116,8 +169,10 @@ static struct variant_data variant_nomadik = { + .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, @@ -208,10 +224,11 @@ index 1841d250..db50d1e 100644 .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, ++ .quirks = MMCI_QUIRK_ST_SDIO, }; static struct variant_data variant_ux500 = { -@@ -127,7 +182,13 @@ 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, @@ -223,9 +240,11 @@ index 1841d250..db50d1e 100644 + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, - .st_sdio = true, +- .st_sdio = true, .st_clkdiv = true, -@@ -141,8 +202,10 @@ static struct variant_data variant_ux500 = { + .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, @@ -233,10 +252,11 @@ index 1841d250..db50d1e 100644 .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, ++ .quirks = MMCI_QUIRK_ST_SDIO, }; static struct variant_data variant_ux500v2 = { -@@ -152,8 +215,14 @@ 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, @@ -249,9 +269,11 @@ index 1841d250..db50d1e 100644 + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, - .st_sdio = true, +- .st_sdio = true, .st_clkdiv = true, -@@ -168,8 +237,10 @@ static struct variant_data variant_ux500v2 = { + .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, @@ -259,10 +281,11 @@ index 1841d250..db50d1e 100644 .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, ++ .quirks = MMCI_QUIRK_ST_SDIO, }; static struct variant_data variant_stm32 = { -@@ -179,7 +250,14 @@ 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, @@ -275,13 +298,14 @@ index 1841d250..db50d1e 100644 + .datactrl_blocksz = 11, + .datactrl_dpsm_enable = MCI_DPSM_ENABLE, .datactrl_mask_sdio = MCI_DPSM_ST_SDIOEN, - .st_sdio = true, +- .st_sdio = true, .st_clkdiv = true, -@@ -187,6 +265,56 @@ static struct variant_data variant_stm32 = { + .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 = { @@ -300,12 +324,15 @@ index 1841d250..db50d1e 100644 + .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 = { @@ -324,6 +351,7 @@ index 1841d250..db50d1e 100644 + .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, @@ -331,10 +359,12 @@ index 1841d250..db50d1e 100644 + .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 +325,22 @@ 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, @@ -357,7 +387,7 @@ index 1841d250..db50d1e 100644 .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, .init = qcom_variant_init, -@@ -226,24 +361,6 @@ static int mmci_card_busy(struct mmc_host *mmc) +@@ -226,24 +369,6 @@ static int mmci_card_busy(struct mmc_host *mmc) return busy; } @@ -382,7 +412,7 @@ index 1841d250..db50d1e 100644 static void mmci_reg_delay(struct mmci_host *host) { /* -@@ -262,7 +379,7 @@ 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 */ @@ -391,7 +421,7 @@ index 1841d250..db50d1e 100644 { if (host->clk_reg != clk) { host->clk_reg = clk; -@@ -273,7 +390,7 @@ static void mmci_write_clkreg(struct mmci_host *host, u32 clk) +@@ -273,7 +398,7 @@ static void mmci_write_clkreg(struct mmci_host *host, u32 clk) /* * This must be called with host->lock held */ @@ -400,7 +430,7 @@ index 1841d250..db50d1e 100644 { if (host->pwr_reg != pwr) { host->pwr_reg = pwr; -@@ -357,9 +474,156 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) +@@ -357,9 +482,157 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) mmci_write_clkreg(host, clk); } @@ -435,7 +465,8 @@ index 1841d250..db50d1e 100644 + 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; @@ -557,7 +588,7 @@ index 1841d250..db50d1e 100644 writel(0, host->base + MMCICOMMAND); BUG_ON(host->data); -@@ -378,7 +642,7 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) +@@ -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); @@ -566,7 +597,7 @@ index 1841d250..db50d1e 100644 mask0 |= mask; writel(mask0, base + MMCIMASK0); -@@ -415,31 +679,50 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) +@@ -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 @@ -628,7 +659,7 @@ index 1841d250..db50d1e 100644 else txname = "none"; -@@ -450,66 +733,84 @@ static void mmci_dma_setup(struct mmci_host *host) +@@ -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. */ @@ -737,7 +768,7 @@ index 1841d250..db50d1e 100644 /* Wait up to 1ms for the DMA to complete */ for (i = 0; ; i++) { status = readl(host->base + MMCISTATUS); -@@ -525,13 +826,12 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +@@ -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) { @@ -754,7 +785,7 @@ index 1841d250..db50d1e 100644 /* * Use of DMA with scatter-gather is impossible. -@@ -543,15 +843,16 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +@@ -543,15 +852,16 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) } host->dma_in_progress = false; @@ -774,7 +805,7 @@ index 1841d250..db50d1e 100644 struct variant_data *variant = host->variant; struct dma_slave_config conf = { .src_addr = host->phybase + MMCIFIFO, -@@ -570,10 +871,10 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, +@@ -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; @@ -787,7 +818,7 @@ index 1841d250..db50d1e 100644 } /* If there's no DMA channel, fall back to PIO */ -@@ -610,160 +911,137 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, +@@ -610,160 +920,137 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, return -ENOMEM; } @@ -813,20 +844,20 @@ index 1841d250..db50d1e 100644 /* No job were prepared thus do it now. */ - return __mmci_dma_prep_data(host, data, &host->dma_current, - &host->dma_desc_current); +-} +- +-static inline int mmci_dma_prep_next(struct mmci_host *host, +- struct mmc_data *data) +-{ +- struct mmci_host_next *nd = &host->next_data; +- return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc); + 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) +-static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +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; @@ -865,15 +896,12 @@ index 1841d250..db50d1e 100644 } -static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) -+void mmci_dmae_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)); -+ struct mmci_dmae_priv *dmae = host->dma_priv; -+ struct mmci_dmae_next *next = &dmae->next_data; - +- - host->dma_desc_current = next->dma_desc; - host->dma_current = next->dma_chan; - next->dma_desc = NULL; @@ -881,11 +909,14 @@ index 1841d250..db50d1e 100644 -} - -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; @@ -1022,8 +1053,11 @@ index 1841d250..db50d1e 100644 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) { -@@ -793,11 +1071,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) - BUG_ON(1 << blksz_bits != data->blksz); +@@ -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); @@ -1034,10 +1068,30 @@ index 1841d250..db50d1e 100644 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; -@@ -831,7 +1109,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) +@@ -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 */ @@ -1046,7 +1100,7 @@ index 1841d250..db50d1e 100644 return; /* IRQ mode, map the SG list for CPU reading/writing */ -@@ -864,21 +1142,40 @@ static void +@@ -864,21 +1161,44 @@ static void mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) { void __iomem *base = host->base; @@ -1076,7 +1130,7 @@ index 1841d250..db50d1e 100644 + 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) @@ -1086,12 +1140,16 @@ index 1841d250..db50d1e 100644 + 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; -@@ -895,21 +1192,22 @@ static void +@@ -895,21 +1215,22 @@ static void mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { @@ -1121,7 +1179,7 @@ index 1841d250..db50d1e 100644 /* * Calculate how far we are into the transfer. Note that -@@ -918,22 +1216,26 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, +@@ -918,22 +1239,26 @@ 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. */ @@ -1156,7 +1214,7 @@ index 1841d250..db50d1e 100644 if (success > host->variant->fifosize) success -= host->variant->fifosize; else -@@ -947,8 +1249,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, +@@ -947,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) { @@ -1167,17 +1225,35 @@ index 1841d250..db50d1e 100644 mmci_stop_data(host); if (!data->error) -@@ -968,7 +1270,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + /* 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); +- } + } + } + +@@ -968,11 +1292,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, unsigned int status) { void __iomem *base = host->base; -+ bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY); - bool sbc; +- bool sbc; ++ bool busy_resp, sbc; + u32 err_msk; if (!cmd) return; -@@ -980,18 +1284,21 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + ++ busy_resp = !!(cmd->flags & MMC_RSP_BUSY); + sbc = (cmd == host->mrq->sbc); + + /* +@@ -980,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. */ @@ -1203,7 +1279,7 @@ index 1841d250..db50d1e 100644 (status & host->variant->busy_detect_flag)) return; -@@ -1001,9 +1308,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -1001,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. */ @@ -1216,7 +1292,7 @@ index 1841d250..db50d1e 100644 /* Clear the busy start IRQ */ writel(host->variant->busy_detect_mask, -@@ -1045,6 +1352,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -1045,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; @@ -1226,7 +1302,7 @@ index 1841d250..db50d1e 100644 } else { cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[1] = readl(base + MMCIRESPONSE1); -@@ -1055,16 +1365,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -1055,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 */ @@ -1247,7 +1323,22 @@ index 1841d250..db50d1e 100644 mmci_start_data(host, cmd->data); } } -@@ -1264,7 +1573,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) +@@ -1252,11 +1583,14 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) + static irqreturn_t mmci_irq(int irq, void *dev_id) + { + struct mmci_host *host = dev_id; ++ bool busy_resp; + u32 status; + int ret = 0; + + spin_lock(&host->lock); + ++ busy_resp = host->cmd ? !!(host->cmd->flags & MMC_RSP_BUSY) : false; ++ + do { + status = readl(host->base + MMCISTATUS); + +@@ -1264,7 +1598,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) if (status & host->mask1_reg) mmci_pio_irq(irq, dev_id); @@ -1256,7 +1347,7 @@ index 1841d250..db50d1e 100644 } /* -@@ -1277,7 +1586,8 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) +@@ -1277,7 +1611,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. */ @@ -1266,7 +1357,18 @@ index 1841d250..db50d1e 100644 if (host->variant->busy_detect) writel(status & ~host->variant->busy_detect_mask, host->base + MMCICLEAR); -@@ -1301,6 +1611,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) +@@ -1295,12 +1630,16 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) + } + + /* +- * Don't poll for busy completion in irq context. ++ * Don't poll for: ++ * -busy completion in irq context. ++ * -cmd without busy response check like cmd11 + */ +- if (host->variant->busy_detect && host->busy_status) ++ if (host->variant->busy_detect && ++ (!busy_resp || host->busy_status)) status &= ~host->variant->busy_detect_flag; ret = 1; @@ -1274,7 +1376,7 @@ index 1841d250..db50d1e 100644 } while (status); spin_unlock(&host->lock); -@@ -1328,7 +1639,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) +@@ -1328,7 +1667,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) if (mrq->data) mmci_get_next_data(host, mrq->data); @@ -1284,7 +1386,7 @@ index 1841d250..db50d1e 100644 mmci_start_data(host, mrq->data); if (mrq->sbc) -@@ -1438,8 +1750,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +@@ -1438,8 +1778,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); @@ -1303,7 +1405,70 @@ index 1841d250..db50d1e 100644 mmci_reg_delay(host); spin_unlock_irqrestore(&host->lock, flags); -@@ -1518,6 +1838,12 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) +@@ -1462,6 +1810,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)) { +@@ -1474,6 +1824,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, +@@ -1488,6 +1860,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, +@@ -1496,6 +1878,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) +@@ -1518,6 +1901,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; @@ -1316,7 +1481,7 @@ index 1841d250..db50d1e 100644 if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) mmc->caps |= MMC_CAP_MMC_HIGHSPEED; -@@ -1644,6 +1970,8 @@ static int mmci_probe(struct amba_device *dev, +@@ -1644,6 +2033,8 @@ static int mmci_probe(struct amba_device *dev, */ if (variant->st_clkdiv) mmc->f_min = DIV_ROUND_UP(host->mclk, 257); @@ -1325,7 +1490,7 @@ index 1841d250..db50d1e 100644 else if (variant->explicit_mclk_control) mmc->f_min = clk_round_rate(host->clk, 100000); else -@@ -1665,6 +1993,12 @@ static int mmci_probe(struct amba_device *dev, +@@ -1665,6 +2056,12 @@ static int mmci_probe(struct amba_device *dev, dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); @@ -1338,7 +1503,7 @@ index 1841d250..db50d1e 100644 /* Get regulators and the supported OCR mask */ ret = mmc_regulator_get_supply(mmc); if (ret) -@@ -1675,13 +2009,6 @@ static int mmci_probe(struct amba_device *dev, +@@ -1675,12 +2072,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"); @@ -1348,11 +1513,11 @@ index 1841d250..db50d1e 100644 - 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; - -@@ -1689,6 +2016,8 @@ static int mmci_probe(struct amba_device *dev, +@@ -1689,6 +2081,8 @@ static int mmci_probe(struct amba_device *dev, * Enable busy detection. */ if (variant->busy_detect) { @@ -1361,7 +1526,7 @@ index 1841d250..db50d1e 100644 mmci_ops.card_busy = mmci_card_busy; /* * Not all variants have a flag to enable busy detection -@@ -1698,7 +2027,18 @@ static int mmci_probe(struct amba_device *dev, +@@ -1698,7 +2092,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; @@ -1381,7 +1546,7 @@ index 1841d250..db50d1e 100644 } mmc->ops = &mmci_ops; -@@ -1727,13 +2067,13 @@ static int mmci_probe(struct amba_device *dev, +@@ -1727,13 +2132,13 @@ static int mmci_probe(struct amba_device *dev, /* * Block size can be up to 2048 bytes, but must be a power of two. */ @@ -1397,7 +1562,7 @@ index 1841d250..db50d1e 100644 spin_lock_init(&host->lock); -@@ -1749,30 +2089,16 @@ static int mmci_probe(struct amba_device *dev, +@@ -1749,30 +2154,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 @@ -1433,7 +1598,7 @@ index 1841d250..db50d1e 100644 } ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED, -@@ -1789,7 +2115,7 @@ static int mmci_probe(struct amba_device *dev, +@@ -1789,7 +2180,7 @@ static int mmci_probe(struct amba_device *dev, goto clk_disable; } @@ -1442,7 +1607,7 @@ index 1841d250..db50d1e 100644 amba_set_drvdata(dev, mmc); -@@ -1876,7 +2202,8 @@ static void mmci_restore(struct mmci_host *host) +@@ -1876,7 +2267,8 @@ static void mmci_restore(struct mmci_host *host) writel(host->datactrl_reg, host->base + MMCIDATACTRL); writel(host->pwr_reg, host->base + MMCIPOWER); } @@ -1452,7 +1617,7 @@ index 1841d250..db50d1e 100644 mmci_reg_delay(host); spin_unlock_irqrestore(&host->lock, flags); -@@ -1971,6 +2298,16 @@ static const struct amba_id mmci_ids[] = { +@@ -1971,6 +2363,16 @@ static const struct amba_id mmci_ids[] = { .mask = 0x00ffffff, .data = &variant_stm32, }, @@ -1470,7 +1635,7 @@ index 1841d250..db50d1e 100644 { .id = 0x00051180, diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h -index 517591d..36a744a 100644 +index 517591d..e10093e 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -23,6 +23,14 @@ @@ -1524,7 +1689,20 @@ index 517591d..36a744a 100644 #define MMCIRESPCMD 0x010 #define MMCIRESPONSE0 0x014 -@@ -130,6 +160,10 @@ +@@ -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) @@ -1532,10 +1710,11 @@ index 517591d..36a744a 100644 +#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 +209,45 @@ +@@ -175,21 +216,45 @@ #define MCI_ST_SDIOITMASK (1 << 22) #define MCI_ST_CEATAENDMASK (1 << 23) #define MCI_ST_BUSYENDMASK (1 << 24) @@ -1585,7 +1764,7 @@ index 517591d..36a744a 100644 #define NR_SG 128 #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain" -@@ -204,6 +262,11 @@ struct mmci_host; +@@ -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 @@ -1597,9 +1776,10 @@ index 517591d..36a744a 100644 * @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) -@@ -212,11 +275,17 @@ struct mmci_host; + * @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_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. @@ -1615,7 +1795,7 @@ index 517591d..36a744a 100644 * @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 +302,77 @@ struct mmci_host; +@@ -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. @@ -1626,6 +1806,7 @@ index 517591d..36a744a 100644 * @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; @@ -1651,7 +1832,6 @@ index 517591d..36a744a 100644 + unsigned int datactrl_dpsm_enable; + u8 datactrl_first:1; + u8 datacnt_useless:1; -+ u8 st_sdio:1; + u8 st_clkdiv:1; + u8 stm32_clkdiv:1; + u8 blksz_datactrl16:1; @@ -1685,9 +1865,14 @@ index 517591d..36a744a 100644 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); @@ -1710,10 +1895,11 @@ index 517591d..36a744a 100644 + 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 +380,13 @@ struct mmci_host { +@@ -287,10 +392,13 @@ struct mmci_host { void __iomem *base; struct mmc_request *mrq; struct mmc_command *cmd; @@ -1728,7 +1914,7 @@ index 517591d..36a744a 100644 spinlock_t lock; -@@ -301,10 +397,11 @@ struct mmci_host { +@@ -301,13 +409,15 @@ struct mmci_host { u32 pwr_reg; u32 pwr_reg_add; u32 clk_reg; @@ -1741,7 +1927,11 @@ index 517591d..36a744a 100644 struct mmci_platform_data *plat; struct mmci_host_ops *ops; struct variant_data *variant; -@@ -323,18 +420,25 @@ struct mmci_host { ++ 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); @@ -1831,23 +2021,40 @@ index be3fab5..25d0a75 100644 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..cfbfc6f +index 0000000..675d6f60 --- /dev/null +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c -@@ -0,0 +1,282 @@ +@@ -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) + @@ -1857,13 +2064,19 @@ index 0000000..cfbfc6f + u32 idmasize; +}; + -+struct sdmmc_priv { ++struct sdmmc_idma { + dma_addr_t sg_dma; + void *sg_cpu; +}; + -+int sdmmc_idma_validate_data(struct mmci_host *host, -+ struct mmc_data *data) ++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; @@ -1873,8 +2086,8 @@ index 0000000..cfbfc6f + * 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); @@ -1882,7 +2095,7 @@ index 0000000..cfbfc6f + } + } + -+ 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); @@ -1929,7 +2142,7 @@ index 0000000..cfbfc6f + +static int sdmmc_idma_setup(struct mmci_host *host) +{ -+ struct sdmmc_priv *idma; ++ struct sdmmc_idma *idma; + + idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); + if (!idma) @@ -1960,7 +2173,7 @@ index 0000000..cfbfc6f +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; @@ -2063,12 +2276,24 @@ index 0000000..cfbfc6f + 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); @@ -2102,6 +2327,102 @@ index 0000000..cfbfc6f + } +} + ++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, @@ -2111,11 +2432,27 @@ index 0000000..cfbfc6f + .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 @@ -2149,10 +2486,10 @@ index d5a5f98..4ef7559 100644 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..a6d60c2 +index 0000000..aaaad34 --- /dev/null +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c -@@ -0,0 +1,2031 @@ +@@ -0,0 +1,2005 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 @@ -3000,7 +3337,7 @@ index 0000000..a6d60c2 + + /* Wait DMA data transfer completion */ + if (!wait_for_completion_timeout(&fmc2->dma_data_complete, -+ msecs_to_jiffies(100))) { ++ msecs_to_jiffies(500))) { + dev_err(fmc2->dev, "data DMA timeout\n"); + dmaengine_terminate_all(dma_ch); + ret = -ETIMEDOUT; @@ -3009,7 +3346,7 @@ index 0000000..a6d60c2 + /* Wait DMA ecc transfer completion */ + if (!write_data && !raw) { + if (!wait_for_completion_timeout(&fmc2->dma_ecc_complete, -+ msecs_to_jiffies(100))) { ++ msecs_to_jiffies(500))) { + dev_err(fmc2->dev, "ecc DMA timeout\n"); + dmaengine_terminate_all(fmc2->dma_ecc_ch); + ret = -ETIMEDOUT; @@ -3535,21 +3872,16 @@ index 0000000..a6d60c2 + struct stm32_fmc2_timings *tims = &nand->timings; + unsigned long hclk = clk_get_rate(fmc2->clk); + unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000); -+ int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att; ++ unsigned long timing, tar, tclr, thiz, twait; ++ unsigned long tset_mem, tset_att, thold_mem, thold_att; + -+ tar = hclkp; -+ if (tar < sdrt->tAR_min) -+ tar = sdrt->tAR_min; -+ tims->tar = DIV_ROUND_UP(tar, hclkp) - 1; -+ if (tims->tar > FMC2_PCR_TIMING_MASK) -+ tims->tar = FMC2_PCR_TIMING_MASK; ++ 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 = hclkp; -+ if (tclr < sdrt->tCLR_min) -+ tclr = sdrt->tCLR_min; -+ tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1; -+ if (tims->tclr > FMC2_PCR_TIMING_MASK) -+ tims->tclr = FMC2_PCR_TIMING_MASK; ++ 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; @@ -3559,18 +3891,11 @@ index 0000000..a6d60c2 + * tWAIT > tWP + * tWAIT > tREA + tIO + */ -+ twait = hclkp; -+ if (twait < sdrt->tRP_min) -+ twait = sdrt->tRP_min; -+ if (twait < sdrt->tWP_min) -+ twait = sdrt->tWP_min; -+ if (twait < sdrt->tREA_max + FMC2_TIO) -+ twait = sdrt->tREA_max + FMC2_TIO; -+ tims->twait = DIV_ROUND_UP(twait, hclkp); -+ if (tims->twait == 0) -+ tims->twait = 1; -+ else if (tims->twait > FMC2_PMEM_PATT_TIMING_MASK) -+ tims->twait = FMC2_PMEM_PATT_TIMING_MASK; ++ twait = max_t(unsigned long, hclkp, sdrt->tRP_min); ++ twait = max_t(unsigned long, twait, sdrt->tWP_min); ++ twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO); ++ timing = DIV_ROUND_UP(twait, hclkp); ++ tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); + + /* + * tSETUP_MEM > tCS - tWAIT @@ -3585,20 +3910,15 @@ index 0000000..a6d60c2 + if (twait > thiz && (sdrt->tDS_min > twait - thiz) && + (tset_mem < sdrt->tDS_min - (twait - thiz))) + tset_mem = sdrt->tDS_min - (twait - thiz); -+ tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp); -+ if (tims->tset_mem == 0) -+ tims->tset_mem = 1; -+ else if (tims->tset_mem > FMC2_PMEM_PATT_TIMING_MASK) -+ tims->tset_mem = FMC2_PMEM_PATT_TIMING_MASK; ++ timing = DIV_ROUND_UP(tset_mem, hclkp); ++ tims->tset_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); + + /* + * tHOLD_MEM > tCH + * tHOLD_MEM > tREH - tSETUP_MEM + * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT) + */ -+ thold_mem = hclkp; -+ if (thold_mem < sdrt->tCH_min) -+ thold_mem = sdrt->tCH_min; ++ thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min); + if (sdrt->tREH_min > tset_mem && + (thold_mem < sdrt->tREH_min - tset_mem)) + thold_mem = sdrt->tREH_min - tset_mem; @@ -3608,11 +3928,8 @@ index 0000000..a6d60c2 + if ((sdrt->tWC_min > tset_mem + twait) && + (thold_mem < sdrt->tWC_min - (tset_mem + twait))) + thold_mem = sdrt->tWC_min - (tset_mem + twait); -+ tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp); -+ if (tims->thold_mem == 0) -+ tims->thold_mem = 1; -+ else if (tims->thold_mem > FMC2_PMEM_PATT_TIMING_MASK) -+ tims->thold_mem = FMC2_PMEM_PATT_TIMING_MASK; ++ timing = DIV_ROUND_UP(thold_mem, hclkp); ++ tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); + + /* + * tSETUP_ATT > tCS - tWAIT @@ -3634,11 +3951,8 @@ index 0000000..a6d60c2 + if (twait > thiz && (sdrt->tDS_min > twait - thiz) && + (tset_att < sdrt->tDS_min - (twait - thiz))) + tset_att = sdrt->tDS_min - (twait - thiz); -+ tims->tset_att = DIV_ROUND_UP(tset_att, hclkp); -+ if (tims->tset_att == 0) -+ tims->tset_att = 1; -+ else if (tims->tset_att > FMC2_PMEM_PATT_TIMING_MASK) -+ tims->tset_att = FMC2_PMEM_PATT_TIMING_MASK; ++ timing = DIV_ROUND_UP(tset_att, hclkp); ++ tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); + + /* + * tHOLD_ATT > tALH @@ -3653,17 +3967,11 @@ index 0000000..a6d60c2 + * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT) + * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) + */ -+ thold_att = hclkp; -+ if (thold_att < sdrt->tALH_min) -+ thold_att = sdrt->tALH_min; -+ if (thold_att < sdrt->tCH_min) -+ thold_att = sdrt->tCH_min; -+ if (thold_att < sdrt->tCLH_min) -+ thold_att = sdrt->tCLH_min; -+ if (thold_att < sdrt->tCOH_min) -+ thold_att = sdrt->tCOH_min; -+ if (thold_att < sdrt->tDH_min) -+ thold_att = sdrt->tDH_min; ++ thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min); ++ thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min); ++ thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min); ++ thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min); ++ thold_att = max_t(unsigned long, thold_att, sdrt->tDH_min); + if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) && + (thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem)) + thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem; @@ -3682,11 +3990,8 @@ index 0000000..a6d60c2 + if ((sdrt->tWC_min > tset_att + twait) && + (thold_att < sdrt->tWC_min - (tset_att + twait))) + thold_att = sdrt->tWC_min - (tset_att + twait); -+ tims->thold_att = DIV_ROUND_UP(thold_att, hclkp); -+ if (tims->thold_att == 0) -+ tims->thold_att = 1; -+ else if (tims->thold_att > FMC2_PMEM_PATT_TIMING_MASK) -+ tims->thold_att = FMC2_PMEM_PATT_TIMING_MASK; ++ timing = DIV_ROUND_UP(thold_att, hclkp); ++ tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); +} + +static int stm32_fmc2_setup_interface(struct mtd_info *mtd, int chipnr, @@ -4019,6 +4324,12 @@ index 0000000..a6d60c2 + } + + 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) { @@ -4184,33 +4495,757 @@ index 0000000..a6d60c2 +MODULE_AUTHOR("Christophe Kerello "); +MODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 nand driver"); +MODULE_LICENSE("GPL v2"); -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; - }; +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. - #endif +-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.49/0015-ARM-stm32mp1-r2-NET.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0015-ARM-stm32mp1-r2-NET.patch new file mode 100644 index 0000000..090ba56 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0015-ARM-stm32mp1-r2-NET.patch @@ -0,0 +1,477 @@ +From edca8bc73b6a7e2057b821cc41e68fe3d7c0bb03 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:02 +0200 +Subject: [PATCH 15/30] ARM stm32mp1 r2 NET + +--- + drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 166 +++++++++++++++++---- + 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 - + 7 files changed, 189 insertions(+), 41 deletions(-) + +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +index 7e2e79d..6e260e9 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,64 @@ 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; + +- 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; ++ /* 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 +427,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 +448,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 50c0082..1df9027 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); + +@@ -4485,14 +4485,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 */ +@@ -4514,6 +4513,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); +@@ -4554,6 +4557,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; +@@ -4585,7 +4589,28 @@ 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; ++ } ++ ++ if (ndev->phydev) ++ phy_start(ndev->phydev); + + stmmac_hw_setup(ndev, false); + stmmac_init_tx_coalesce(priv); +@@ -4597,10 +4622,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.9/0011-ARM-stm32mp1-r0-rc1-NVMEM.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0016-ARM-stm32mp1-r2-NVMEM.patch similarity index 90% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0011-ARM-stm32mp1-r0-rc1-NVMEM.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0016-ARM-stm32mp1-r2-NVMEM.patch index 2e2cad7..a6049dc 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0011-ARM-stm32mp1-r0-rc1-NVMEM.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0016-ARM-stm32mp1-r2-NVMEM.patch @@ -1,15 +1,15 @@ -From a38a0eadf1db60bd8d1ff084c2ddc8016432b4fb Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:25:05 +0100 -Subject: [PATCH 11/52] ARM: stm32mp1-r0-rc1: NVMEM +From 7a1e0bedb3066a32ff522e25daacd490d306ea40 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:03 +0200 +Subject: [PATCH 16/30] ARM stm32mp1 r2 NVMEM --- drivers/nvmem/Kconfig | 10 ++ drivers/nvmem/Makefile | 2 + drivers/nvmem/core.c | 37 ++++++++ - drivers/nvmem/stm32-romem.c | 205 +++++++++++++++++++++++++++++++++++++++++ + drivers/nvmem/stm32-romem.c | 203 +++++++++++++++++++++++++++++++++++++++++ include/linux/nvmem-consumer.h | 7 ++ - 5 files changed, 261 insertions(+) + 5 files changed, 259 insertions(+) create mode 100644 drivers/nvmem/stm32-romem.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig @@ -96,10 +96,10 @@ index 7c530c8..60dacd7 100644 * @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..198872f +index 0000000..34b388c --- /dev/null +++ b/drivers/nvmem/stm32-romem.c -@@ -0,0 +1,205 @@ +@@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * STM32 Factory-programmed memory read access driver @@ -121,6 +121,12 @@ index 0000000..198872f +#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; +}; @@ -179,13 +185,21 @@ index 0000000..198872f + return -EINVAL; + + for (i = roffset; (i < roffset + rbytes); i += 4) { -+ ret = stm32_bsec_smc(STM32_SMC_READ_OTP, i >> 2, 0, &val); -+ if (ret) { -+ dev_err(priv->dev, "Failed to read data%d (%d)\n", -+ i >> 2, ret); -+ return ret; -+ } ++ 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)); @@ -229,7 +243,6 @@ index 0000000..198872f + const struct stm32_romem_cfg *cfg; + struct device *dev = &pdev->dev; + struct stm32_romem_priv *priv; -+ struct nvmem_device *nvmem; + struct resource *res; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -256,26 +269,12 @@ index 0000000..198872f + priv->cfg.size = resource_size(res); + priv->cfg.reg_read = stm32_romem_read; + } else { -+ priv->cfg.read_only = false; + priv->cfg.size = cfg->size; + priv->cfg.reg_read = stm32_bsec_read; + priv->cfg.reg_write = stm32_bsec_write; + } + -+ nvmem = nvmem_register(&priv->cfg); -+ if (IS_ERR(nvmem)) -+ return PTR_ERR(nvmem); -+ -+ platform_set_drvdata(pdev, nvmem); -+ -+ return 0; -+} -+ -+static int stm32_romem_remove(struct platform_device *pdev) -+{ -+ struct nvmem_device *nvmem = platform_get_drvdata(pdev); -+ -+ return nvmem_unregister(nvmem); ++ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); +} + +static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { @@ -293,7 +292,6 @@ index 0000000..198872f + +static struct platform_driver stm32_romem_driver = { + .probe = stm32_romem_probe, -+ .remove = stm32_romem_remove, + .driver = { + .name = "stm32-romem", + .of_match_table = of_match_ptr(stm32_romem_of_match), diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0017-ARM-stm32mp1-r2-PERF.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0017-ARM-stm32mp1-r2-PERF.patch new file mode 100644 index 0000000..2590c9f --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0017-ARM-stm32mp1-r2-PERF.patch @@ -0,0 +1,603 @@ +From 34f2e1a678f0017522aeba5633b3729590b2f811 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Tue, 17 Sep 2019 14:27:10 +0200 +Subject: [PATCH 17/30] ARM stm32mp1 r2 PERF + +--- + Documentation/perf/stm32-ddr-pmu.txt | 41 +++ + drivers/perf/Kconfig | 6 + + drivers/perf/Makefile | 1 + + 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 +--- /dev/null ++++ b/Documentation/perf/stm32-ddr-pmu.txt +@@ -0,0 +1,41 @@ ++STM32 DDR Performance Monitor (DDRPERFM) ++======================================== ++ ++The DDRPERFM is the DDR Performance Monitor embedded in STM32MP1 SOC. ++See STM32MP157 reference manual RM0436 to get a description of this peripheral. ++ ++ ++The five following counters are supported by stm32-ddr-pmu driver: ++ cnt0: read operations counters (read_cnt) ++ cnt1: write operations counters (write_cnt) ++ cnt2: active state counters (activate_cnt) ++ cnt3: idle state counters (idle_cnt) ++ tcnt: time count, present for all sets (time_cnt) ++ ++The stm32-ddr-pmu driver relies on the perf PMU framework to expose the ++counters via sysfs: ++ $ ls /sys/bus/event_source/devices/ddrperfm/events ++ activate_cnt idle_cnt read_cnt time_cnt write_cnt ++ ++ ++The perf PMU framework is usually invoked via the 'perf stat' tool. ++ ++The DDRPERFM is a system monitor that cannot isolate the traffic coming from a ++given thread or CPU, that is why stm32-ddr-pmu driver rejects any 'perf stat' ++call that does not request a system-wide collection: the '-a, --all-cpus' ++option is mandatory! ++ ++Example: ++ $ perf stat -e ddrperfm/read_cnt/,ddrperfm/time_cnt/ -a sleep 20 ++ Performance counter stats for 'system wide': ++ ++ 342541560 ddrperfm/read_cnt/ ++ 10660011400 ddrperfm/time_cnt/ ++ ++ 20.021068551 seconds time elapsed ++ ++ ++The driver also exposes a 'bandwidth' attribute that can be used to display ++the read/write/total bandwidth achieved during the last 'perf stat' execution. ++ $ 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 +--- a/drivers/perf/Kconfig ++++ b/drivers/perf/Kconfig +@@ -87,6 +87,12 @@ config QCOM_L3_PMU + Adds the L3 cache PMU into the perf events subsystem for + monitoring L3 cache events. + ++config STM32_DDR_PMU ++ bool "STM32 DDR PMU" ++ depends on MACH_STM32MP157 ++ help ++ Support for STM32 DDR performance monitor (DDRPERFM). ++ + config XGENE_PMU + depends on ARCH_XGENE + bool "APM X-Gene SoC PMU" +diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile +index b3902bd..04f7f64 100644 +--- a/drivers/perf/Makefile ++++ b/drivers/perf/Makefile +@@ -7,5 +7,6 @@ obj-$(CONFIG_ARM_PMU_ACPI) += arm_pmu_acpi.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_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 +--- /dev/null ++++ b/drivers/perf/stm32_ddr_pmu.c +@@ -0,0 +1,505 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * This file is the STM32 DDR performance monitor (DDRPERFM) driver ++ * ++ * Copyright (C) 2019, STMicroelectronics - All Rights Reserved ++ * Author: Gerald Baeza ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define POLL_MS 4000 /* The counter roll over after ~8s @533MHz */ ++#define WORD_LENGTH 4 /* Bytes */ ++#define BURST_LENGTH 8 /* Words */ ++ ++#define DDRPERFM_CTL 0x000 ++#define DDRPERFM_CFG 0x004 ++#define DDRPERFM_STATUS 0x008 ++#define DDRPERFM_CCR 0x00C ++#define DDRPERFM_IER 0x010 ++#define DDRPERFM_ISR 0x014 ++#define DDRPERFM_ICR 0x018 ++#define DDRPERFM_TCNT 0x020 ++#define DDRPERFM_CNT(X) (0x030 + 8 * (X)) ++#define DDRPERFM_HWCFG 0x3F0 ++#define DDRPERFM_VER 0x3F4 ++#define DDRPERFM_ID 0x3F8 ++#define DDRPERFM_SID 0x3FC ++ ++#define CTL_START 0x00000001 ++#define CTL_STOP 0x00000002 ++#define CCR_CLEAR_ALL 0x8000000F ++#define SID_MAGIC_ID 0xA3C5DD01 ++ ++#define STRING "Read = %llu, Write = %llu, Read & Write = %llu (MB/s)\n" ++ ++enum { ++ READ_CNT, ++ WRITE_CNT, ++ ACTIVATE_CNT, ++ IDLE_CNT, ++ TIME_CNT, ++ PMU_NR_COUNTERS ++}; ++ ++struct stm32_ddr_pmu { ++ struct pmu pmu; ++ void __iomem *membase; ++ struct clk *clk; ++ struct clk *clk_ddr; ++ unsigned long clk_ddr_rate; ++ struct hrtimer hrtimer; ++ ktime_t poll_period; ++ spinlock_t lock; /* for shared registers access */ ++ struct perf_event *events[PMU_NR_COUNTERS]; ++ u64 events_cnt[PMU_NR_COUNTERS]; ++}; ++ ++static inline struct stm32_ddr_pmu *pmu_to_stm32_ddr_pmu(struct pmu *p) ++{ ++ return container_of(p, struct stm32_ddr_pmu, pmu); ++} ++ ++static inline struct stm32_ddr_pmu *hrtimer_to_stm32_ddr_pmu(struct hrtimer *h) ++{ ++ return container_of(h, struct stm32_ddr_pmu, hrtimer); ++} ++ ++static u64 stm32_ddr_pmu_compute_bw(struct stm32_ddr_pmu *stm32_ddr_pmu, ++ int counter) ++{ ++ u64 bw = stm32_ddr_pmu->events_cnt[counter], tmp; ++ u64 div = stm32_ddr_pmu->events_cnt[TIME_CNT]; ++ u32 prediv = 1, premul = 1; ++ ++ if (bw && div) { ++ /* Maximize the dividend into 64 bits */ ++ while ((bw < 0x8000000000000000ULL) && ++ (premul < 0x40000000UL)) { ++ bw = bw << 1; ++ premul *= 2; ++ } ++ /* Minimize the dividor to fit in 32 bits */ ++ while ((div > 0xffffffffUL) && (prediv < 0x40000000UL)) { ++ div = div >> 1; ++ prediv *= 2; ++ } ++ /* Divide counter per time and multiply per DDR settings */ ++ do_div(bw, div); ++ tmp = bw * BURST_LENGTH * WORD_LENGTH; ++ tmp *= stm32_ddr_pmu->clk_ddr_rate; ++ if (tmp < bw) ++ goto error; ++ bw = tmp; ++ /* Cancel the prediv and premul factors */ ++ while (prediv > 1) { ++ bw = bw >> 1; ++ prediv /= 2; ++ } ++ while (premul > 1) { ++ bw = bw >> 1; ++ premul /= 2; ++ } ++ /* Convert MHz to Hz and B to MB, to finally get MB/s */ ++ tmp = bw * 1000000; ++ if (tmp < bw) ++ goto error; ++ bw = tmp; ++ premul = 1024 * 1024; ++ while (premul > 1) { ++ bw = bw >> 1; ++ premul /= 2; ++ } ++ } ++ return bw; ++ ++error: ++ pr_warn("stm32-ddr-pmu: overflow detected\n"); ++ return 0; ++} ++ ++static void stm32_ddr_pmu_event_configure(struct perf_event *event) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu); ++ unsigned long lock_flags, config_base = event->hw.config_base; ++ u32 val; ++ ++ spin_lock_irqsave(&stm32_ddr_pmu->lock, lock_flags); ++ writel_relaxed(CTL_STOP, stm32_ddr_pmu->membase + DDRPERFM_CTL); ++ ++ if (config_base < TIME_CNT) { ++ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_CFG); ++ val |= (1 << config_base); ++ writel_relaxed(val, stm32_ddr_pmu->membase + DDRPERFM_CFG); ++ } ++ spin_unlock_irqrestore(&stm32_ddr_pmu->lock, lock_flags); ++} ++ ++static void stm32_ddr_pmu_event_read(struct perf_event *event) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu); ++ unsigned long flags, config_base = event->hw.config_base; ++ struct hw_perf_event *hw = &event->hw; ++ u64 prev_count, new_count, mask; ++ u32 val, offset, bit; ++ ++ spin_lock_irqsave(&stm32_ddr_pmu->lock, flags); ++ ++ writel_relaxed(CTL_STOP, stm32_ddr_pmu->membase + DDRPERFM_CTL); ++ ++ if (config_base == TIME_CNT) { ++ offset = DDRPERFM_TCNT; ++ bit = 1 << 31; ++ } else { ++ offset = DDRPERFM_CNT(config_base); ++ bit = 1 << config_base; ++ } ++ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_STATUS); ++ if (val & bit) ++ pr_warn("stm32_ddr_pmu hardware overflow\n"); ++ val = readl_relaxed(stm32_ddr_pmu->membase + offset); ++ writel_relaxed(bit, stm32_ddr_pmu->membase + DDRPERFM_CCR); ++ writel_relaxed(CTL_START, stm32_ddr_pmu->membase + DDRPERFM_CTL); ++ ++ do { ++ prev_count = local64_read(&hw->prev_count); ++ new_count = prev_count + val; ++ } while (local64_xchg(&hw->prev_count, new_count) != prev_count); ++ ++ mask = GENMASK_ULL(31, 0); ++ local64_add(val & mask, &event->count); ++ ++ if (new_count < prev_count) ++ pr_warn("STM32 DDR PMU counter saturated\n"); ++ ++ spin_unlock_irqrestore(&stm32_ddr_pmu->lock, flags); ++} ++ ++static void stm32_ddr_pmu_event_start(struct perf_event *event, int flags) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu); ++ struct hw_perf_event *hw = &event->hw; ++ unsigned long lock_flags; ++ ++ if (WARN_ON_ONCE(!(hw->state & PERF_HES_STOPPED))) ++ return; ++ ++ if (flags & PERF_EF_RELOAD) ++ WARN_ON_ONCE(!(hw->state & PERF_HES_UPTODATE)); ++ ++ stm32_ddr_pmu_event_configure(event); ++ ++ /* Clear all counters to synchronize them, then start */ ++ spin_lock_irqsave(&stm32_ddr_pmu->lock, lock_flags); ++ writel_relaxed(CCR_CLEAR_ALL, stm32_ddr_pmu->membase + DDRPERFM_CCR); ++ writel_relaxed(CTL_START, stm32_ddr_pmu->membase + DDRPERFM_CTL); ++ spin_unlock_irqrestore(&stm32_ddr_pmu->lock, lock_flags); ++ ++ hw->state = 0; ++} ++ ++static void stm32_ddr_pmu_event_stop(struct perf_event *event, int flags) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu); ++ unsigned long lock_flags, config_base = event->hw.config_base; ++ struct hw_perf_event *hw = &event->hw; ++ u32 val, bit; ++ ++ if (WARN_ON_ONCE(hw->state & PERF_HES_STOPPED)) ++ return; ++ ++ spin_lock_irqsave(&stm32_ddr_pmu->lock, lock_flags); ++ writel_relaxed(CTL_STOP, stm32_ddr_pmu->membase + DDRPERFM_CTL); ++ if (config_base == TIME_CNT) ++ bit = 1 << 31; ++ else ++ bit = 1 << config_base; ++ writel_relaxed(bit, stm32_ddr_pmu->membase + DDRPERFM_CCR); ++ if (config_base < TIME_CNT) { ++ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_CFG); ++ val &= ~bit; ++ writel_relaxed(val, stm32_ddr_pmu->membase + DDRPERFM_CFG); ++ } ++ spin_unlock_irqrestore(&stm32_ddr_pmu->lock, lock_flags); ++ ++ hw->state |= PERF_HES_STOPPED; ++ ++ if (flags & PERF_EF_UPDATE) { ++ stm32_ddr_pmu_event_read(event); ++ hw->state |= PERF_HES_UPTODATE; ++ } ++} ++ ++static int stm32_ddr_pmu_event_add(struct perf_event *event, int flags) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu); ++ unsigned long config_base = event->hw.config_base; ++ struct hw_perf_event *hw = &event->hw; ++ ++ stm32_ddr_pmu->events_cnt[config_base] = 0; ++ stm32_ddr_pmu->events[config_base] = event; ++ ++ clk_enable(stm32_ddr_pmu->clk); ++ hrtimer_start(&stm32_ddr_pmu->hrtimer, stm32_ddr_pmu->poll_period, ++ HRTIMER_MODE_REL); ++ ++ stm32_ddr_pmu_event_configure(event); ++ ++ hw->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; ++ ++ if (flags & PERF_EF_START) ++ stm32_ddr_pmu_event_start(event, 0); ++ ++ return 0; ++} ++ ++static void stm32_ddr_pmu_event_del(struct perf_event *event, int flags) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = pmu_to_stm32_ddr_pmu(event->pmu); ++ unsigned long config_base = event->hw.config_base; ++ bool stop = true; ++ int i; ++ ++ stm32_ddr_pmu_event_stop(event, PERF_EF_UPDATE); ++ ++ stm32_ddr_pmu->events_cnt[config_base] += local64_read(&event->count); ++ stm32_ddr_pmu->events[config_base] = NULL; ++ ++ for (i = 0; i < PMU_NR_COUNTERS; i++) ++ if (stm32_ddr_pmu->events[i]) ++ stop = false; ++ if (stop) ++ hrtimer_cancel(&stm32_ddr_pmu->hrtimer); ++ ++ clk_disable(stm32_ddr_pmu->clk); ++} ++ ++static int stm32_ddr_pmu_event_init(struct perf_event *event) ++{ ++ struct hw_perf_event *hw = &event->hw; ++ ++ if (event->attr.type != event->pmu->type) ++ return -ENOENT; ++ ++ if (is_sampling_event(event)) ++ return -EINVAL; ++ ++ if (event->attach_state & PERF_ATTACH_TASK) ++ return -EINVAL; ++ ++ if (event->attr.exclude_user || ++ event->attr.exclude_kernel || ++ event->attr.exclude_hv || ++ event->attr.exclude_idle || ++ event->attr.exclude_host || ++ event->attr.exclude_guest) ++ return -EINVAL; ++ ++ if (event->cpu < 0) ++ return -EINVAL; ++ ++ hw->config_base = event->attr.config; ++ ++ return 0; ++} ++ ++static enum hrtimer_restart stm32_ddr_pmu_poll(struct hrtimer *hrtimer) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = hrtimer_to_stm32_ddr_pmu(hrtimer); ++ int i; ++ ++ for (i = 0; i < PMU_NR_COUNTERS; i++) ++ if (stm32_ddr_pmu->events[i]) ++ stm32_ddr_pmu_event_read(stm32_ddr_pmu->events[i]); ++ ++ hrtimer_forward_now(hrtimer, stm32_ddr_pmu->poll_period); ++ ++ return HRTIMER_RESTART; ++} ++ ++static ssize_t stm32_ddr_pmu_sysfs_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct dev_ext_attribute *eattr; ++ ++ eattr = container_of(attr, struct dev_ext_attribute, attr); ++ ++ return sprintf(buf, "config=0x%lx\n", (unsigned long)eattr->var); ++} ++ ++static ssize_t bandwidth_show(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = dev_get_drvdata(dev); ++ u64 r_bw, w_bw; ++ int ret; ++ ++ if (stm32_ddr_pmu->events_cnt[TIME_CNT]) { ++ r_bw = stm32_ddr_pmu_compute_bw(stm32_ddr_pmu, READ_CNT); ++ w_bw = stm32_ddr_pmu_compute_bw(stm32_ddr_pmu, WRITE_CNT); ++ ++ ret = snprintf(buf, PAGE_SIZE, STRING, ++ r_bw, w_bw, (r_bw + w_bw)); ++ } else { ++ ret = snprintf(buf, PAGE_SIZE, "No data available\n"); ++ } ++ ++ return ret; ++} ++ ++#define STM32_DDR_PMU_ATTR(_name, _func, _config) \ ++ (&((struct dev_ext_attribute[]) { \ ++ { __ATTR(_name, 0444, _func, NULL), (void *)_config } \ ++ })[0].attr.attr) ++ ++#define STM32_DDR_PMU_EVENT_ATTR(_name, _config) \ ++ STM32_DDR_PMU_ATTR(_name, stm32_ddr_pmu_sysfs_show, \ ++ (unsigned long)_config) ++ ++static struct attribute *stm32_ddr_pmu_event_attrs[] = { ++ STM32_DDR_PMU_EVENT_ATTR(read_cnt, READ_CNT), ++ STM32_DDR_PMU_EVENT_ATTR(write_cnt, WRITE_CNT), ++ STM32_DDR_PMU_EVENT_ATTR(activate_cnt, ACTIVATE_CNT), ++ STM32_DDR_PMU_EVENT_ATTR(idle_cnt, IDLE_CNT), ++ STM32_DDR_PMU_EVENT_ATTR(time_cnt, TIME_CNT), ++ NULL ++}; ++ ++static DEVICE_ATTR_RO(bandwidth); ++static struct attribute *stm32_ddr_pmu_bandwidth_attrs[] = { ++ &dev_attr_bandwidth.attr, ++ NULL, ++}; ++ ++static struct attribute_group stm32_ddr_pmu_event_attrs_group = { ++ .name = "events", ++ .attrs = stm32_ddr_pmu_event_attrs, ++}; ++ ++static struct attribute_group stm32_ddr_pmu_bandwidth_attrs_group = { ++ .attrs = stm32_ddr_pmu_bandwidth_attrs, ++}; ++ ++static const struct attribute_group *stm32_ddr_pmu_attr_groups[] = { ++ &stm32_ddr_pmu_event_attrs_group, ++ &stm32_ddr_pmu_bandwidth_attrs_group, ++ NULL, ++}; ++ ++static int stm32_ddr_pmu_device_probe(struct platform_device *pdev) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu; ++ struct resource *res; ++ int i, ret; ++ u32 val; ++ ++ stm32_ddr_pmu = devm_kzalloc(&pdev->dev, sizeof(struct stm32_ddr_pmu), ++ GFP_KERNEL); ++ if (!stm32_ddr_pmu) ++ return -ENOMEM; ++ platform_set_drvdata(pdev, stm32_ddr_pmu); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ stm32_ddr_pmu->membase = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(stm32_ddr_pmu->membase)) { ++ pr_warn("Unable to get STM32 DDR PMU membase\n"); ++ return PTR_ERR(stm32_ddr_pmu->membase); ++ } ++ ++ stm32_ddr_pmu->clk = devm_clk_get(&pdev->dev, "bus"); ++ if (IS_ERR(stm32_ddr_pmu->clk)) { ++ pr_warn("Unable to get STM32 DDR PMU clock\n"); ++ return PTR_ERR(stm32_ddr_pmu->clk); ++ } ++ ++ ret = clk_prepare_enable(stm32_ddr_pmu->clk); ++ if (ret) { ++ pr_warn("Unable to prepare STM32 DDR PMU clock\n"); ++ return ret; ++ } ++ ++ stm32_ddr_pmu->clk_ddr = devm_clk_get(&pdev->dev, "ddr"); ++ if (IS_ERR(stm32_ddr_pmu->clk_ddr)) { ++ pr_warn("Unable to get STM32 DDR clock\n"); ++ return PTR_ERR(stm32_ddr_pmu->clk_ddr); ++ } ++ stm32_ddr_pmu->clk_ddr_rate = clk_get_rate(stm32_ddr_pmu->clk_ddr); ++ stm32_ddr_pmu->clk_ddr_rate /= 1000000; ++ ++ stm32_ddr_pmu->poll_period = ms_to_ktime(POLL_MS); ++ hrtimer_init(&stm32_ddr_pmu->hrtimer, CLOCK_MONOTONIC, ++ HRTIMER_MODE_REL); ++ stm32_ddr_pmu->hrtimer.function = stm32_ddr_pmu_poll; ++ spin_lock_init(&stm32_ddr_pmu->lock); ++ ++ for (i = 0; i < PMU_NR_COUNTERS; i++) { ++ stm32_ddr_pmu->events[i] = NULL; ++ stm32_ddr_pmu->events_cnt[i] = 0; ++ } ++ ++ val = readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_SID); ++ if (val != SID_MAGIC_ID) ++ return -EINVAL; ++ ++ stm32_ddr_pmu->pmu = (struct pmu) { ++ .task_ctx_nr = perf_invalid_context, ++ .start = stm32_ddr_pmu_event_start, ++ .stop = stm32_ddr_pmu_event_stop, ++ .add = stm32_ddr_pmu_event_add, ++ .del = stm32_ddr_pmu_event_del, ++ .event_init = stm32_ddr_pmu_event_init, ++ .attr_groups = stm32_ddr_pmu_attr_groups, ++ }; ++ ret = perf_pmu_register(&stm32_ddr_pmu->pmu, "ddrperfm", -1); ++ if (ret) { ++ pr_warn("Unable to register STM32 DDR PMU\n"); ++ return ret; ++ } ++ ++ pr_info("stm32-ddr-pmu: probed (ID=0x%08x VER=0x%08x), DDR@%luMHz\n", ++ readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_ID), ++ readl_relaxed(stm32_ddr_pmu->membase + DDRPERFM_VER), ++ stm32_ddr_pmu->clk_ddr_rate); ++ ++ clk_disable(stm32_ddr_pmu->clk); ++ ++ return 0; ++} ++ ++static int stm32_ddr_pmu_device_remove(struct platform_device *pdev) ++{ ++ struct stm32_ddr_pmu *stm32_ddr_pmu = platform_get_drvdata(pdev); ++ ++ perf_pmu_unregister(&stm32_ddr_pmu->pmu); ++ ++ return 0; ++} ++ ++static const struct of_device_id stm32_ddr_pmu_of_match[] = { ++ { .compatible = "st,stm32-ddr-pmu" }, ++ { }, ++}; ++ ++static struct platform_driver stm32_ddr_pmu_driver = { ++ .driver = { ++ .name = "stm32-ddr-pmu", ++ .of_match_table = of_match_ptr(stm32_ddr_pmu_of_match), ++ }, ++ .probe = stm32_ddr_pmu_device_probe, ++ .remove = stm32_ddr_pmu_device_remove, ++}; ++ ++module_platform_driver(stm32_ddr_pmu_driver); ++ ++MODULE_DESCRIPTION("Perf driver for STM32 DDR performance monitor"); ++MODULE_AUTHOR("Gerald Baeza "); ++MODULE_LICENSE("GPL v2"); +-- +2.7.4 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0012-ARM-stm32mp1-r0-rc1-PINCTRL-PWM-RESET-RTC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0018-ARM-stm32mp1-r2-PHY-PINCTRL-PWM.patch similarity index 75% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0012-ARM-stm32mp1-r0-rc1-PINCTRL-PWM-RESET-RTC.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0018-ARM-stm32mp1-r2-PHY-PINCTRL-PWM.patch index a2031ca..1640815 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0012-ARM-stm32mp1-r0-rc1-PINCTRL-PWM-RESET-RTC.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0018-ARM-stm32mp1-r2-PHY-PINCTRL-PWM.patch @@ -1,34 +1,640 @@ -From c617af0e078307484930384232ec1cd8d33eed2c Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:26:32 +0100 -Subject: [PATCH 12/52] ARM: stm32mp1-r0-rc1: PINCTRL PWM RESET RTC +From 6c5c0debff2505c77c0d9545da09ac4b311619d4 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:03 +0200 +Subject: [PATCH 18/30] ARM stm32mp1 r2 PHY PINCTRL PWM --- + drivers/phy/st/phy-stm32-usbphyc.c | 451 +++++++++-- drivers/pinctrl/Kconfig | 12 + drivers/pinctrl/Makefile | 1 + - drivers/pinctrl/pinctrl-stmfx.c | 821 ++++++++++++++++++++ - drivers/pinctrl/stm32/pinctrl-stm32.c | 203 ++++- + drivers/pinctrl/core.c | 28 +- + drivers/pinctrl/pinctrl-stmfx.c | 832 ++++++++++++++++++++ + drivers/pinctrl/stm32/pinctrl-stm32.c | 452 +++++++++-- drivers/pinctrl/stm32/pinctrl-stm32.h | 52 +- drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1095 ++++++++++++++++----------- drivers/pwm/pwm-stm32-lp.c | 44 ++ - drivers/pwm/pwm-stm32.c | 103 ++- + drivers/pwm/pwm-stm32.c | 105 ++- drivers/pwm/sysfs.c | 12 +- - drivers/regulator/Kconfig | 19 + - drivers/regulator/Makefile | 2 + - drivers/regulator/stm32-pwr.c | 242 ++++++ - drivers/regulator/stm32-vrefbuf.c | 123 ++- - drivers/regulator/stpmic1_regulator.c | 674 +++++++++++++++++ - drivers/reset/reset-stm32mp1.c | 48 ++ - drivers/rtc/Kconfig | 1 + - drivers/rtc/rtc-stm32.c | 119 +++ include/dt-bindings/pinctrl/stm32-pinfunc.h | 6 + - include/dt-bindings/rtc/rtc-stm32.h | 13 + - 19 files changed, 3084 insertions(+), 506 deletions(-) + include/linux/pinctrl/pinctrl.h | 7 + + 13 files changed, 2481 insertions(+), 616 deletions(-) create mode 100644 drivers/pinctrl/pinctrl-stmfx.c - create mode 100644 drivers/regulator/stm32-pwr.c - create mode 100644 drivers/regulator/stpmic1_regulator.c - create mode 100644 include/dt-bindings/rtc/rtc-stm32.h +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..bbd3908 100644 --- a/drivers/pinctrl/Kconfig @@ -64,12 +670,75 @@ index 46ef9bd..9abcaa59 100644 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..e253ed1 +index 0000000..327c00d --- /dev/null +++ b/drivers/pinctrl/pinctrl-stmfx.c -@@ -0,0 +1,821 @@ +@@ -0,0 +1,832 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander @@ -288,7 +957,7 @@ index 0000000..e253ed1 + struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + u32 param = pinconf_to_config_param(*config); + struct pinctrl_gpio_range *range; -+ u32 dir, type, pupd; ++ int dir, type, pupd; + u32 arg = 0; + int ret; + @@ -372,29 +1041,29 @@ index 0000000..e253ed1 + 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: -+ if (!dir) -+ ret = stmfx_pinconf_set_type(pctl, pin, 1); -+ else -+ ret = stmfx_pinconf_set_type(pctl, pin, 0); -+ if (ret) -+ return ret; -+ break; -+ case PIN_CONFIG_DRIVE_PUSH_PULL: -+ if (!dir) -+ ret = stmfx_pinconf_set_type(pctl, pin, 0); -+ else -+ ret = stmfx_pinconf_set_type(pctl, pin, 1); ++ ret = stmfx_pinconf_set_type(pctl, pin, 1); + if (ret) + return ret; + break; @@ -614,6 +1283,7 @@ index 0000000..e253ed1 + 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; + @@ -622,10 +1292,8 @@ index 0000000..e253ed1 + if (ret) + return IRQ_NONE; + -+ ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_ACK, -+ 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) { @@ -633,6 +1301,9 @@ index 0000000..e253ed1 + 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; +} + @@ -696,6 +1367,7 @@ index 0000000..e253ed1 + 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); @@ -735,6 +1407,14 @@ index 0000000..e253ed1 + 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; @@ -892,10 +1572,20 @@ index 0000000..e253ed1 +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 a9bec6e..e25917f 100644 +index a9bec6e..5b71c97 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c -@@ -31,6 +31,7 @@ +@@ -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" @@ -903,7 +1593,7 @@ index a9bec6e..e25917f 100644 #define STM32_GPIO_MODER 0x00 #define STM32_GPIO_TYPER 0x04 -@@ -43,6 +44,18 @@ +@@ -43,6 +46,18 @@ #define STM32_GPIO_AFRL 0x20 #define STM32_GPIO_AFRH 0x24 @@ -922,7 +1612,17 @@ index a9bec6e..e25917f 100644 #define STM32_GPIO_PINS_PER_BANK 16 #define STM32_GPIO_IRQ_LINE 16 -@@ -76,6 +89,9 @@ struct stm32_gpio_bank { +@@ -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", +@@ -76,6 +94,9 @@ struct stm32_gpio_bank { struct irq_domain *domain; u32 bank_nr; u32 bank_ioport_nr; @@ -932,18 +1632,46 @@ index a9bec6e..e25917f 100644 }; struct stm32_pinctrl { -@@ -91,6 +107,10 @@ struct stm32_pinctrl { +@@ -91,6 +112,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) -@@ -131,6 +151,8 @@ static inline u32 stm32_gpio_get_alt(u32 function) +@@ -126,11 +154,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) { @@ -952,7 +1680,57 @@ index a9bec6e..e25917f 100644 if (!value) offset += STM32_GPIO_PINS_PER_BANK; -@@ -352,16 +374,16 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) +@@ -300,9 +350,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 +412,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 +434,16 @@ 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) { @@ -973,43 +1751,308 @@ index a9bec6e..e25917f 100644 if (func->num == fnum) return true; func++; -@@ -594,6 +616,8 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank, +@@ -410,7 +492,7 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + unsigned int num_configs; + bool has_config = 0; + unsigned reserve = 0; +- int num_pins, num_funcs, maps_per_pin, i, err; ++ int num_pins, num_funcs, maps_per_pin, i, err = 0; + + pctl = pinctrl_dev_get_drvdata(pctldev); + +@@ -437,41 +519,45 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + if (has_config && num_pins >= 1) + maps_per_pin++; + +- if (!num_pins || !maps_per_pin) +- return -EINVAL; ++ if (!num_pins || !maps_per_pin) { ++ err = -EINVAL; ++ goto exit; ++ } + + reserve = num_pins * maps_per_pin; + + err = pinctrl_utils_reserve_map(pctldev, map, + reserved_maps, num_maps, reserve); + if (err) +- return err; ++ goto exit; + + for (i = 0; i < num_pins; i++) { + err = of_property_read_u32_index(node, "pinmux", + i, &pinfunc); + if (err) +- return err; ++ goto exit; + + pin = STM32_GET_PIN_NO(pinfunc); + func = STM32_GET_PIN_FUNC(pinfunc); + + if (!stm32_pctrl_is_function_valid(pctl, pin, func)) { + dev_err(pctl->dev, "invalid function.\n"); +- return -EINVAL; ++ err = -EINVAL; ++ goto exit; + } + + grp = stm32_pctrl_find_group_by_pin(pctl, pin); + if (!grp) { + dev_err(pctl->dev, "unable to match pin %d to group\n", + pin); +- return -EINVAL; ++ err = -EINVAL; ++ goto exit; + } + + err = stm32_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map, + reserved_maps, num_maps); + if (err) +- return err; ++ goto exit; + + if (has_config) { + err = pinctrl_utils_add_map_configs(pctldev, map, +@@ -479,11 +565,13 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + configs, num_configs, + PIN_MAP_TYPE_CONFIGS_GROUP); + if (err) +- return err; ++ goto exit; + } + } + +- return 0; ++exit: ++ kfree(configs); ++ return err; + } + + static int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, +@@ -573,17 +661,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); +@@ -594,8 +692,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; } -@@ -694,6 +718,8 @@ static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank, + + void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, +@@ -652,9 +757,7 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, + 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, +@@ -664,9 +767,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 = { +@@ -680,22 +781,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; } -@@ -730,6 +756,8 @@ static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank, + + static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, +@@ -716,22 +834,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; } -@@ -766,6 +794,8 @@ static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank, + + static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, +@@ -752,22 +887,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; } -@@ -893,6 +923,8 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, + + static u32 stm32_pconf_get_bias(struct stm32_gpio_bank *bank, +@@ -830,22 +982,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); +@@ -893,6 +1045,8 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned int pin) { @@ -1018,7 +2061,7 @@ index a9bec6e..e25917f 100644 struct pinctrl_gpio_range *range; struct stm32_gpio_bank *bank; int offset; -@@ -942,7 +974,9 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, +@@ -942,7 +1096,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); @@ -1029,7 +2072,52 @@ index a9bec6e..e25917f 100644 drive ? "open drain" : "push pull", biasing[bias], speeds[speed], "speed"); -@@ -1105,7 +1139,7 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) +@@ -1049,23 +1205,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); +@@ -1105,7 +1273,7 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) struct stm32_pinctrl *pctl = platform_get_drvdata(pdev); int i; @@ -1038,7 +2126,7 @@ index a9bec6e..e25917f 100644 /* Allocate groups */ pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups, -@@ -1119,19 +1153,51 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) +@@ -1119,19 +1287,51 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) if (!pctl->grp_names) return -ENOMEM; @@ -1093,8 +2181,35 @@ index a9bec6e..e25917f 100644 int stm32_pctl_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; -@@ -1162,6 +1228,19 @@ int stm32_pctl_probe(struct platform_device *pdev) +@@ -1140,7 +1340,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; +@@ -1160,36 +1360,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; + @@ -1113,7 +2228,13 @@ index a9bec6e..e25917f 100644 ret = stm32_pctrl_build_state(pdev); if (ret) { dev_err(dev, "build state failed: %d\n", ret); -@@ -1174,22 +1253,23 @@ int stm32_pctl_probe(struct platform_device *pdev) + 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; } @@ -1141,7 +2262,7 @@ index a9bec6e..e25917f 100644 pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, pctl); -@@ -1227,3 +1307,100 @@ int stm32_pctl_probe(struct platform_device *pdev) +@@ -1227,3 +1457,115 @@ int stm32_pctl_probe(struct platform_device *pdev) return 0; } @@ -1183,22 +2304,23 @@ index a9bec6e..e25917f 100644 + bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT; +} + -+void stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin) ++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; ++ return 0; + + pin_is_irq = gpiochip_line_is_irq(range->gc, offset); + + if (!desc || (!pin_is_irq && !desc->gpio_owner)) -+ return; ++ return 0; + + bank = gpiochip_get_data(range->gc); + @@ -1207,7 +2329,10 @@ index a9bec6e..e25917f 100644 + mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK; + mode >>= STM32_GPIO_BKP_MODE_SHIFT; + -+ stm32_pmx_set_mode(bank, offset, mode, alt); ++ 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; @@ -1216,28 +2341,39 @@ index a9bec6e..e25917f 100644 + + val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE); + val >>= STM32_GPIO_BKP_TYPE; -+ stm32_pconf_set_driving(bank, offset, val); ++ 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; -+ stm32_pconf_set_speed(bank, offset, val); ++ 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; -+ stm32_pconf_set_bias(bank, offset, val); ++ 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; ++ int i, ret; + -+ for (i = g->pin; i < g->pin + pctl->ngroups; i++) -+ stm32_pinctrl_restore_gpio_regs(pctl, i); ++ for (i = g->pin; i < g->pin + pctl->ngroups; i++) { ++ ret = stm32_pinctrl_restore_gpio_regs(pctl, i); ++ if (ret) ++ return ret; ++ } + + return 0; +} @@ -4146,7 +5282,7 @@ index 0059b24c..322df1f 100644 }; module_platform_driver(stm32_pwm_lp_driver); diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c -index 4f84255..5a6c765 100644 +index 4f84255..4688425 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -12,6 +12,7 @@ @@ -4257,7 +5393,13 @@ index 4f84255..5a6c765 100644 } static void stm32_pwm_detect_complementary(struct stm32_pwm *priv) -@@ -612,7 +621,7 @@ static int stm32_pwm_probe(struct platform_device *pdev) +@@ -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; @@ -4266,7 +5408,7 @@ index 4f84255..5a6c765 100644 if (ret) return ret; -@@ -645,6 +654,53 @@ static int stm32_pwm_remove(struct platform_device *pdev) +@@ -645,6 +656,53 @@ static int stm32_pwm_remove(struct platform_device *pdev) return 0; } @@ -4320,7 +5462,7 @@ index 4f84255..5a6c765 100644 static const struct of_device_id stm32_pwm_of_match[] = { { .compatible = "st,stm32-pwm", }, { /* end node */ }, -@@ -657,6 +713,7 @@ static struct platform_driver stm32_pwm_driver = { +@@ -657,6 +715,7 @@ static struct platform_driver stm32_pwm_driver = { .driver = { .name = "stm32-pwm", .of_match_table = stm32_pwm_of_match, @@ -4379,1552 +5521,6 @@ index 7c71cdb..ceb233d 100644 /* for device_find_child() */ put_device(child); device_unregister(child); -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 801d9a3..3506ec2 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/stm32-pwr.c b/drivers/regulator/stm32-pwr.c -new file mode 100644 -index 0000000..f4e1198 ---- /dev/null -+++ b/drivers/regulator/stm32-pwr.c -@@ -0,0 +1,242 @@ -+/* -+ * 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, -+}; -+ -+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, -+}; -+ -+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, -+}; -+ -+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..29cca32 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; - -+ 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_ENVR) | STM32_HIZ; - 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 = { -@@ -130,6 +191,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 +202,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 +230,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 +250,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 +300,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..96f1808 ---- /dev/null -+++ b/drivers/regulator/stpmic1_regulator.c -@@ -0,0 +1,674 @@ -+// SPDX-License-Identifier: GPL-2.0 -+// Copyright (C) STMicroelectronics 2018 -+// Author: Pascal Paillet for STMicroelectronics. -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/** -+ * stpmic1 regulator description -+ * @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; -+}; -+ -+/** -+ * stpmic1 regulator data: this structure is used as driver data -+ * @regul_id: regulator id -+ * @reg_node: DT node of regulator (unused on non-DT platforms) -+ * @cfg: stpmic specific regulator description -+ * @mask_reset: mask_reset bit value -+ * @irq_curlim: current limit interrupt number -+ * @regmap: point to parent regmap structure -+ */ -+struct stpmic1_regulator { -+ unsigned int regul_id; -+ struct device_node *reg_node; -+ struct stpmic1_regulator_cfg *cfg; -+ u8 mask_reset; -+ int irq_curlim; -+ struct regmap *regmap; -+}; -+ -+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 int stpmic1_regulator_parse_dt(void *driver_data); -+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 -+ -+#define STPMIC1_BUCK_MODE_NORMAL 0 -+#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK -+ -+struct regulator_linear_range buck1_ranges[] = { -+ REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000), -+ REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0), -+}; -+ -+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), -+}; -+ -+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), -+ -+}; -+ -+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), -+ -+}; -+ -+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), -+ -+}; -+ -+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), -+ -+}; -+ -+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), -+}; -+ -+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), -+}; -+ -+struct regulator_linear_range ldo6_ranges[] = { -+ REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000), -+ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), -+}; -+ -+static 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_pull_down = regulator_set_pull_down_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static 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, -+ .set_pull_down = regulator_set_pull_down_regmap, -+ .get_bypass = regulator_get_bypass_regmap, -+ .set_bypass = regulator_set_bypass_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .set_pull_down = regulator_set_pull_down_regmap, -+ .set_over_current_protection = stpmic1_set_icc, -+}; -+ -+static 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 struct regulator_ops stpmic1_vref_ddr_ops = { -+ .is_enabled = regulator_is_enabled_regmap, -+ .enable = regulator_enable_regmap, -+ .disable = regulator_disable_regmap, -+ .set_pull_down = regulator_set_pull_down_regmap, -+}; -+ -+static 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, -+}; -+ -+#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, \ -+ .pull_down_reg = ids##_PULL_DOWN_REG, \ -+ .pull_down_mask = ids##_PULL_DOWN_MASK, \ -+ .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, \ -+ .pull_down_reg = ids##_PULL_DOWN_REG, \ -+ .pull_down_mask = ids##_PULL_DOWN_MASK, \ -+ .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, \ -+ .pull_down_reg = ids##_PULL_DOWN_REG, \ -+ .pull_down_mask = ids##_PULL_DOWN_MASK, \ -+ .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, \ -+ .pull_down_reg = ids##_PULL_DOWN_REG, \ -+ .pull_down_mask = ids##_PULL_DOWN_MASK, \ -+ .supply_name = #base, \ -+} -+ -+#define REG_SWITCH(ids, base, reg, mask, val) { \ -+ .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 = (reg), \ -+ .enable_mask = (mask), \ -+ .enable_val = (val), \ -+ .disable_val = 0, \ -+ .enable_time = PMIC_ENABLE_TIME_US, \ -+ .supply_name = #base, \ -+} -+ -+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_SWITCH(BOOST, boost, BST_SW_CR, -+ BOOST_ENABLED, -+ BOOST_ENABLED), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(6), -+ }, -+ [STPMIC1_VBUS_OTG] = { -+ .desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR, -+ USBSW_OTG_SWITCH_ENABLED, -+ USBSW_OTG_SWITCH_ENABLED), -+ .icc_reg = BUCKS_ICCTO_CR, -+ .icc_mask = BIT(4), -+ }, -+ [STPMIC1_SW_OUT] = { -+ .desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR, -+ SWIN_SWOUT_ENABLED, -+ SWIN_SWOUT_ENABLED), -+ .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 -EINVAL; -+ } -+} -+ -+static unsigned int stpmic1_get_mode(struct regulator_dev *rdev) -+{ -+ int value; -+ -+ regmap_read(rdev->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; -+ -+ 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(rdev->regmap, rdev->desc->enable_reg, -+ STPMIC1_BUCK_MODE_LP, value); -+} -+ -+static int stpmic1_set_icc(struct regulator_dev *rdev) -+{ -+ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); -+ -+ /* enable switch off in case of over current */ -+ return regmap_update_bits(regul->regmap, regul->cfg->icc_reg, -+ regul->cfg->icc_mask, regul->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; -+} -+ -+static int stpmic1_regulator_init(struct platform_device *pdev, -+ struct regulator_dev *rdev) -+{ -+ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); -+ int ret = 0; -+ -+ /* set mask reset */ -+ if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) { -+ ret = regmap_update_bits(regul->regmap, -+ regul->cfg->mask_reset_reg, -+ regul->cfg->mask_reset_mask, -+ regul->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 */ -+ if (regul->irq_curlim > 0) { -+ ret = devm_request_threaded_irq(&pdev->dev, -+ regul->irq_curlim, 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; -+} -+ -+#define MATCH(_name, _id) \ -+ [STPMIC1_##_id] = { \ -+ .name = #_name, \ -+ .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \ -+ } -+ -+static struct of_regulator_match stpmic1_regulators_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_parse_dt(void *driver_data) -+{ -+ struct stpmic1_regulator *regul = -+ (struct stpmic1_regulator *)driver_data; -+ -+ if (!regul) -+ return -EINVAL; -+ -+ if (of_get_property(regul->reg_node, "st,mask-reset", NULL)) -+ regul->mask_reset = 1; -+ -+ regul->irq_curlim = of_irq_get(regul->reg_node, 0); -+ -+ return 0; -+} -+ -+static struct -+regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id, -+ struct regulator_init_data *init_data, -+ struct stpmic1_regulator *regul) -+{ -+ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); -+ struct regulator_dev *rdev; -+ struct regulator_config config = {}; -+ -+ config.dev = &pdev->dev; -+ config.init_data = init_data; -+ config.of_node = stpmic1_regulators_matches[id].of_node; -+ config.regmap = pmic_dev->regmap; -+ config.driver_data = regul; -+ -+ regul->regul_id = id; -+ regul->reg_node = config.of_node; -+ regul->cfg = &stpmic1_regulator_cfgs[id]; -+ regul->regmap = pmic_dev->regmap; -+ -+ rdev = devm_regulator_register(&pdev->dev, ®ul->cfg->desc, &config); -+ if (IS_ERR(rdev)) { -+ dev_err(&pdev->dev, "failed to register %s regulator\n", -+ regul->cfg->desc.name); -+ } -+ -+ return rdev; -+} -+ -+static int stpmic1_regulator_probe(struct platform_device *pdev) -+{ -+ struct regulator_dev *rdev; -+ struct stpmic1_regulator *regul; -+ struct regulator_init_data *init_data; -+ struct device_node *np; -+ int i, ret; -+ -+ np = pdev->dev.of_node; -+ -+ ret = of_regulator_match(&pdev->dev, np, -+ stpmic1_regulators_matches, -+ ARRAY_SIZE(stpmic1_regulators_matches)); -+ if (ret < 0) { -+ dev_err(&pdev->dev, -+ "Error in PMIC regulator device tree node"); -+ return ret; -+ } -+ -+ regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) * -+ sizeof(struct stpmic1_regulator), -+ GFP_KERNEL); -+ if (!regul) -+ return -ENOMEM; -+ -+ for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { -+ /* Parse DT & find regulators to register */ -+ init_data = stpmic1_regulators_matches[i].init_data; -+ if (init_data) -+ init_data->regulator_init = &stpmic1_regulator_parse_dt; -+ -+ rdev = stpmic1_regulator_register(pdev, i, init_data, regul); -+ if (IS_ERR(rdev)) -+ return PTR_ERR(rdev); -+ -+ ret = stpmic1_regulator_init(pdev, rdev); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "failed to initialize regulator %d\n", ret); -+ return ret; -+ } -+ -+ regul++; -+ } -+ -+ 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/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/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 c5908cf..87f26c1 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 = { -@@ -818,6 +919,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 -@@ -854,6 +970,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/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h index b5a2174..e928aea 100644 --- a/include/dt-bindings/pinctrl/stm32-pinfunc.h @@ -5941,25 +5537,38 @@ index b5a2174..e928aea 100644 + #endif /* _DT_BINDINGS_STM32_PINFUNC_H */ -diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h -new file mode 100644 -index 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. -+ */ +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); + -+#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 + /* 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.49/0019-ARM-stm32mp1-r2-REGULATOR.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0019-ARM-stm32mp1-r2-REGULATOR.patch new file mode 100644 index 0000000..2da94d9 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0019-ARM-stm32mp1-r2-REGULATOR.patch @@ -0,0 +1,1223 @@ +From c26270a4d76f20b3ee1af133269ac67e60185e8c Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:03 +0200 +Subject: [PATCH 19/30] ARM stm32mp1 r2 REGULATOR + +--- + drivers/regulator/Kconfig | 19 + + drivers/regulator/Makefile | 2 + + drivers/regulator/stm32-pwr.c | 245 +++++++++++++ + drivers/regulator/stm32-vrefbuf.c | 123 ++++++- + drivers/regulator/stpmic1_regulator.c | 663 ++++++++++++++++++++++++++++++++++ + 5 files changed, 1045 insertions(+), 7 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 801d9a3..3506ec2 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/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..29cca32 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; + ++ 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_ENVR) | STM32_HIZ; + 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 = { +@@ -130,6 +191,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 +202,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 +230,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 +250,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 +300,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..31c960c +--- /dev/null ++++ b/drivers/regulator/stpmic1_regulator.c +@@ -0,0 +1,663 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) STMicroelectronics 2018 ++// Author: Pascal Paillet for STMicroelectronics. ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * stpmic1 regulator description ++ * @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; ++}; ++ ++/** ++ * stpmic1 regulator data: this structure is used as driver data ++ * @regul_id: regulator id ++ * @reg_node: DT node of regulator (unused on non-DT platforms) ++ * @cfg: stpmic specific regulator description ++ * @mask_reset: mask_reset bit value ++ * @irq_curlim: current limit interrupt number ++ * @regmap: point to parent regmap structure ++ */ ++struct stpmic1_regulator { ++ unsigned int regul_id; ++ struct device_node *reg_node; ++ struct stpmic1_regulator_cfg *cfg; ++ u8 mask_reset; ++ int irq_curlim; ++ struct regmap *regmap; ++}; ++ ++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 int stpmic1_regulator_parse_dt(void *driver_data); ++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 ++ ++#define STPMIC1_BUCK_MODE_NORMAL 0 ++#define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK ++ ++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), ++}; ++ ++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), ++}; ++ ++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), ++ ++}; ++ ++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), ++ ++}; ++ ++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), ++ ++}; ++ ++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), ++ ++}; ++ ++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), ++}; ++ ++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), ++}; ++ ++struct regulator_linear_range ldo6_ranges[] = { ++ REGULATOR_LINEAR_RANGE(900000, 0, 24, 100000), ++ REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), ++}; ++ ++static 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 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 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 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 struct regulator_ops stpmic1_vref_ddr_ops = { ++ .is_enabled = regulator_is_enabled_regmap, ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++}; ++ ++static 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, ++}; ++ ++#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_SWITCH(ids, base, reg, mask, val) { \ ++ .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 = (reg), \ ++ .enable_mask = (mask), \ ++ .enable_val = (val), \ ++ .disable_val = 0, \ ++ .enable_time = PMIC_ENABLE_TIME_US, \ ++ .supply_name = #base, \ ++} ++ ++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_SWITCH(BOOST, boost, BST_SW_CR, ++ BOOST_ENABLED, ++ BOOST_ENABLED), ++ .icc_reg = BUCKS_ICCTO_CR, ++ .icc_mask = BIT(6), ++ }, ++ [STPMIC1_VBUS_OTG] = { ++ .desc = REG_SWITCH(VBUS_OTG, pwr_sw1, BST_SW_CR, ++ USBSW_OTG_SWITCH_ENABLED, ++ USBSW_OTG_SWITCH_ENABLED), ++ .icc_reg = BUCKS_ICCTO_CR, ++ .icc_mask = BIT(4), ++ }, ++ [STPMIC1_SW_OUT] = { ++ .desc = REG_SWITCH(SW_OUT, pwr_sw2, BST_SW_CR, ++ SWIN_SWOUT_ENABLED, ++ SWIN_SWOUT_ENABLED), ++ .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 -EINVAL; ++ } ++} ++ ++static unsigned int stpmic1_get_mode(struct regulator_dev *rdev) ++{ ++ int value; ++ ++ regmap_read(rdev->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; ++ ++ 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(rdev->regmap, rdev->desc->enable_reg, ++ STPMIC1_BUCK_MODE_LP, value); ++} ++ ++static int stpmic1_set_icc(struct regulator_dev *rdev) ++{ ++ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); ++ ++ /* enable switch off in case of over current */ ++ return regmap_update_bits(regul->regmap, regul->cfg->icc_reg, ++ regul->cfg->icc_mask, regul->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; ++} ++ ++static int stpmic1_regulator_init(struct platform_device *pdev, ++ struct regulator_dev *rdev) ++{ ++ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); ++ int ret = 0; ++ ++ /* set mask reset */ ++ if (regul->mask_reset && regul->cfg->mask_reset_reg != 0) { ++ ret = regmap_update_bits(regul->regmap, ++ regul->cfg->mask_reset_reg, ++ regul->cfg->mask_reset_mask, ++ regul->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 */ ++ if (regul->irq_curlim > 0) { ++ ret = devm_request_threaded_irq(&pdev->dev, ++ regul->irq_curlim, 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; ++} ++ ++#define MATCH(_name, _id) \ ++ [STPMIC1_##_id] = { \ ++ .name = #_name, \ ++ .desc = &stpmic1_regulator_cfgs[STPMIC1_##_id].desc, \ ++ } ++ ++static struct of_regulator_match stpmic1_regulators_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_parse_dt(void *driver_data) ++{ ++ struct stpmic1_regulator *regul = ++ (struct stpmic1_regulator *)driver_data; ++ ++ if (!regul) ++ return -EINVAL; ++ ++ if (of_get_property(regul->reg_node, "st,mask-reset", NULL)) ++ regul->mask_reset = 1; ++ ++ regul->irq_curlim = of_irq_get(regul->reg_node, 0); ++ ++ return 0; ++} ++ ++static struct ++regulator_dev *stpmic1_regulator_register(struct platform_device *pdev, int id, ++ struct regulator_init_data *init_data, ++ struct stpmic1_regulator *regul) ++{ ++ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); ++ struct regulator_dev *rdev; ++ struct regulator_config config = {}; ++ ++ config.dev = &pdev->dev; ++ config.init_data = init_data; ++ config.of_node = stpmic1_regulators_matches[id].of_node; ++ config.regmap = pmic_dev->regmap; ++ config.driver_data = regul; ++ ++ regul->regul_id = id; ++ regul->reg_node = config.of_node; ++ regul->cfg = &stpmic1_regulator_cfgs[id]; ++ regul->regmap = pmic_dev->regmap; ++ ++ rdev = devm_regulator_register(&pdev->dev, ®ul->cfg->desc, &config); ++ if (IS_ERR(rdev)) { ++ dev_err(&pdev->dev, "failed to register %s regulator\n", ++ regul->cfg->desc.name); ++ } ++ ++ return rdev; ++} ++ ++static int stpmic1_regulator_probe(struct platform_device *pdev) ++{ ++ struct regulator_dev *rdev; ++ struct stpmic1_regulator *regul; ++ struct regulator_init_data *init_data; ++ struct device_node *np; ++ int i, ret; ++ ++ np = pdev->dev.of_node; ++ ++ ret = of_regulator_match(&pdev->dev, np, ++ stpmic1_regulators_matches, ++ ARRAY_SIZE(stpmic1_regulators_matches)); ++ if (ret < 0) { ++ dev_err(&pdev->dev, ++ "Error in PMIC regulator device tree node"); ++ return ret; ++ } ++ ++ regul = devm_kzalloc(&pdev->dev, ARRAY_SIZE(stpmic1_regulator_cfgs) * ++ sizeof(struct stpmic1_regulator), ++ GFP_KERNEL); ++ if (!regul) ++ return -ENOMEM; ++ ++ for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { ++ /* Parse DT & find regulators to register */ ++ init_data = stpmic1_regulators_matches[i].init_data; ++ if (init_data) ++ init_data->regulator_init = &stpmic1_regulator_parse_dt; ++ ++ rdev = stpmic1_regulator_register(pdev, i, init_data, regul); ++ if (IS_ERR(rdev)) ++ return PTR_ERR(rdev); ++ ++ ret = stpmic1_regulator_init(pdev, rdev); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "failed to initialize regulator %d\n", ret); ++ return ret; ++ } ++ ++ regul++; ++ } ++ ++ 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"); +-- +2.7.4 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0013-ARM-stm32mp1-r0-rc1-REMOTEPROC-RPMSG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0020-ARM-stm32mp1-r2-REMOTEPROC-RPMSG-RESET.patch similarity index 55% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0013-ARM-stm32mp1-r0-rc1-REMOTEPROC-RPMSG.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0020-ARM-stm32mp1-r2-REMOTEPROC-RPMSG-RESET.patch index ca00097..3ce9100 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0013-ARM-stm32mp1-r0-rc1-REMOTEPROC-RPMSG.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0020-ARM-stm32mp1-r2-REMOTEPROC-RPMSG-RESET.patch @@ -1,63 +1,35 @@ -From 80b6c916e8d8900d2449726c59ed7ad8609c9976 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:28:00 +0100 -Subject: [PATCH 13/52] ARM: stm32mp1-r0-rc1: REMOTEPROC RPMSG +From 0feaf56c6535420b9c89752e55353887e8266959 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:04 +0200 +Subject: [PATCH 20/30] ARM stm32mp1 r2 REMOTEPROC RPMSG RESET --- - Documentation/remoteproc.txt | 23 + - drivers/remoteproc/Kconfig | 36 ++ - drivers/remoteproc/Makefile | 3 + - drivers/remoteproc/remoteproc_core.c | 45 +- - drivers/remoteproc/rproc_srm_core.c | 303 ++++++++++++ - drivers/remoteproc/rproc_srm_core.h | 110 +++++ - drivers/remoteproc/rproc_srm_dev.c | 928 +++++++++++++++++++++++++++++++++++ - drivers/remoteproc/stm32_rproc.c | 585 ++++++++++++++++++++++ - 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 | 305 ++++++++++++ - drivers/rpmsg/virtio_rpmsg_bus.c | 11 + - include/linux/remoteproc.h | 2 + - include/linux/rpmsg.h | 9 + - 16 files changed, 2382 insertions(+), 9 deletions(-) + 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 | 833 ++++++++++++++++++++++++++++++ + drivers/remoteproc/stm32_rproc.c | 847 +++++++++++++++++++++++++++++++ + 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 | 305 +++++++++++ + drivers/rpmsg/virtio_rpmsg_bus.c | 17 +- + include/linux/remoteproc.h | 38 +- + include/linux/rpmsg.h | 9 + + 19 files changed, 3200 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/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/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 052d4dd..c1f3f00 100644 --- a/drivers/remoteproc/Kconfig @@ -131,18 +103,865 @@ index 03332fa..1e43aa6 100644 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..21726f0 100644 +index aa62067..6430747 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c -@@ -41,6 +41,7 @@ +@@ -39,8 +39,11 @@ + #include + #include #include ++#include ++#include #include #include +#include #include #include "remoteproc_internal.h" -@@ -987,7 +988,11 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) +@@ -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; @@ -155,7 +974,56 @@ index aa62067..21726f0 100644 /* * if enabling an IOMMU isn't relevant for this rproc, this is -@@ -1290,7 +1295,7 @@ static void rproc_crash_handler_work(struct work_struct *work) +@@ -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) { @@ -164,7 +1032,7 @@ index aa62067..21726f0 100644 struct device *dev; int ret; -@@ -1321,11 +1326,17 @@ int rproc_boot(struct rproc *rproc) +@@ -1321,11 +1716,17 @@ int rproc_boot(struct rproc *rproc) dev_info(dev, "powering up %s\n", rproc->name); @@ -187,7 +1055,7 @@ index aa62067..21726f0 100644 } ret = rproc_fw_boot(rproc, firmware_p); -@@ -1479,8 +1490,22 @@ int rproc_add(struct rproc *rproc) +@@ -1479,8 +1880,22 @@ int rproc_add(struct rproc *rproc) /* create debugfs entries */ rproc_create_debug_dir(rproc); @@ -212,7 +1080,7 @@ index aa62067..21726f0 100644 ret = rproc_trigger_auto_boot(rproc); if (ret < 0) return ret; -@@ -1706,6 +1731,8 @@ int rproc_del(struct rproc *rproc) +@@ -1706,6 +2121,8 @@ int rproc_del(struct rproc *rproc) list_del(&rproc->node); mutex_unlock(&rproc_list_mutex); @@ -221,9 +1089,204 @@ index aa62067..21726f0 100644 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..66be92e +index 0000000..fc61e8b --- /dev/null +++ b/drivers/remoteproc/rproc_srm_core.c @@ -0,0 +1,303 @@ @@ -418,7 +1481,7 @@ index 0000000..66be92e + /* 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, "bind timeout\n"); ++ dev_err(dev, "failed to bind one or more system resource device(s)\n"); + ret = -ETIMEDOUT; + goto master; + } @@ -532,10 +1595,10 @@ index 0000000..66be92e +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..7915f35 +index 0000000..7dffdb38 --- /dev/null +++ b/drivers/remoteproc/rproc_srm_core.h -@@ -0,0 +1,110 @@ +@@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -558,12 +1621,10 @@ index 0000000..7915f35 +/** + * Resource type used in resource manager rpmsg: + * RPROC_SRM_RSC_CLOCK: clock resource -+ * RPROC_SRM_RSC_PIN: pin resource + * RPROC_SRM_RSC_REGU: regulator resource + */ +#define RPROC_SRM_RSC_CLOCK 0x00 -+#define RPROC_SRM_RSC_PIN 0x01 -+#define RPROC_SRM_RSC_REGU 0x02 ++#define RPROC_SRM_RSC_REGU 0x01 + +/** + * struct clock_cfg - clock configuration used in resource manager rpmsg @@ -601,14 +1662,6 @@ index 0000000..7915f35 +}; + +/** -+ * struct pin_cfg - pin configuration used in resource manager rpmsg -+ * @name: current pin configuration name (meaningful in GetConfig message) -+ */ -+struct pin_cfg { -+ u8 name[16]; -+}; -+ -+/** + * struct rpmsg_srm_msg - message structure used between processors to + * dynamically update resources configuration + * @message_type: type of the message: see RPROC_SRM_MSG* @@ -619,7 +1672,6 @@ index 0000000..7915f35 + * 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 -+ * @pin_cfg: pin config - relevant if &rsc_type is RPROC_SRM_RSC_PIN + */ +struct rpmsg_srm_msg { + u32 message_type; @@ -628,7 +1680,6 @@ index 0000000..7915f35 + union { + struct clock_cfg clock_cfg; + struct regu_cfg regu_cfg; -+ struct pin_cfg pin_cfg; + }; +}; + @@ -648,10 +1699,10 @@ index 0000000..7915f35 +#endif diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c new file mode 100644 -index 0000000..b026f961 +index 0000000..7dc99c5 --- /dev/null +++ b/drivers/remoteproc/rproc_srm_dev.c -@@ -0,0 +1,928 @@ +@@ -0,0 +1,833 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -685,7 +1736,6 @@ index 0000000..b026f961 + struct list_head list; + unsigned int index; + char *name; -+ bool selected; +}; + +struct rproc_srm_regu_info { @@ -1198,83 +2248,6 @@ index 0000000..b026f961 +} + +/* Pins */ -+static int rproc_srm_dev_pin_set_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct pin_cfg *cfg) -+{ -+ struct rproc_srm_pin_info *pi, *p = NULL; -+ struct device *dev = rproc_srm_dev->dev; -+ struct pinctrl_state *state; -+ int ret; -+ -+ list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) { -+ if (!strcmp(pi->name, cfg->name)) { -+ p = pi; -+ break; -+ } -+ } -+ -+ if (!p) { -+ dev_err(dev, "unknown pin config (%s)\n", cfg->name); -+ return -EINVAL; -+ } -+ -+ state = pinctrl_lookup_state(rproc_srm_dev->pctrl, cfg->name); -+ if (IS_ERR(state)) { -+ dev_err(dev, "cannot get pin config (%s)\n", cfg->name); -+ return -EINVAL; -+ } -+ -+ ret = pinctrl_select_state(rproc_srm_dev->pctrl, state); -+ if (ret < 0) { -+ dev_err(dev, "cannot set pin config (%s)\n", cfg->name); -+ return ret; -+ } -+ -+ list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) { -+ pi->selected = (pi == p); -+ } -+ -+ dev_dbg(dev, "pin config (%s) selected\n", p->name); -+ -+ return 0; -+} -+ -+static int rproc_srm_dev_pin_get_cfg(struct rproc_srm_dev *rproc_srm_dev, -+ struct pin_cfg *cfg) -+{ -+ struct rproc_srm_pin_info *p; -+ -+ list_for_each_entry(p, &rproc_srm_dev->pin_list_head, list) { -+ if (p->selected) { -+ strlcpy(cfg->name, p->name, sizeof(cfg->name)); -+ return 0; -+ } -+ } -+ -+ dev_warn(rproc_srm_dev->dev, "cannot find selected pin state\n"); -+ strcpy(cfg->name, ""); -+ -+ return 0; -+} -+ -+static int rproc_srm_dev_pins_setup(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct rproc_srm_pin_info *p; -+ struct pin_cfg cfg = { .name = "rproc_default" }; -+ -+ if (rproc_srm_dev->early_boot) -+ /* in early_boot mode do not update pin config */ -+ return 0; -+ -+ /* set the "rproc_default" pin config if defined */ -+ list_for_each_entry(p, &rproc_srm_dev->pin_list_head, list) { -+ if (!strcmp(p->name, cfg.name)) -+ return rproc_srm_dev_pin_set_cfg(rproc_srm_dev, &cfg); -+ } -+ -+ return 0; -+} -+ +static void rproc_srm_dev_pins_put(struct rproc_srm_dev *rproc_srm_dev) +{ + struct device *dev = rproc_srm_dev->dev; @@ -1331,11 +2304,9 @@ index 0000000..b026f961 + } + p->name = devm_kstrdup(dev, name, GFP_KERNEL); + -+ if (!strcmp(p->name, PINCTRL_STATE_DEFAULT)) { -+ if (rproc_srm_dev->early_boot) -+ dev_warn(dev, "pin config potentially overwritten!\n"); -+ p->selected = true; -+ } ++ /* pinctrl-names shall not be "default" (but "rproc_default") */ ++ if (!strcmp(p->name, PINCTRL_STATE_DEFAULT)) ++ dev_warn(dev, "pin config potentially overwritten!\n"); + + p->index = i; + @@ -1380,13 +2351,6 @@ index 0000000..b026f961 + ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, + &o.clock_cfg); + break; -+ case RPROC_SRM_RSC_PIN: -+ ret = rproc_srm_dev_pin_set_cfg(rproc_srm_dev, -+ &i->pin_cfg); -+ if (!ret) -+ ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev, -+ &o.pin_cfg); -+ break; + case RPROC_SRM_RSC_REGU: + ret = rproc_srm_dev_regu_set_cfg(rproc_srm_dev, + &i->regu_cfg); @@ -1406,10 +2370,6 @@ index 0000000..b026f961 + ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, + &o.clock_cfg); + break; -+ case RPROC_SRM_RSC_PIN: -+ ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev, -+ &o.pin_cfg); -+ break; + case RPROC_SRM_RSC_REGU: + ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, + &o.regu_cfg); @@ -1464,11 +2424,7 @@ index 0000000..b026f961 + if (ret) + return ret; + -+ ret = rproc_srm_dev_pins_setup(rproc_srm_dev); -+ if (ret) -+ return ret; -+ -+ /* For IRQs: nothing to setup */ ++ /* For pins and IRQs: nothing to setup */ + return 0; +} + @@ -1582,10 +2538,10 @@ index 0000000..b026f961 +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c new file mode 100644 -index 0000000..998de67 +index 0000000..6533503 --- /dev/null +++ b/drivers/remoteproc/stm32_rproc.c -@@ -0,0 +1,585 @@ +@@ -0,0 +1,847 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -1595,14 +2551,17 @@ index 0000000..998de67 + +#include +#include ++#include +#include +#include +#include +#include +#include ++#include +#include +#include +#include ++#include + +#include "remoteproc_internal.h" + @@ -1616,8 +2575,10 @@ index 0000000..998de67 +#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_SHUTDOWN "init_shdn" ++#define STM32_MBX_VQ1_ID 1 ++#define STM32_MBX_SHUTDOWN "shutdown" + +struct stm32_syscon { + struct regmap *map; @@ -1626,16 +2587,24 @@ index 0000000..998de67 +}; + +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; +}; + @@ -1643,13 +2612,87 @@ index 0000000..998de67 + struct reset_control *rst; + struct stm32_syscon hold_boot; + struct stm32_syscon pdds; -+ struct stm32_rproc_mem ram[2]; ++ 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; -+ u32 rsc_addr; ++ void __iomem *rsc_va; + u32 rsc_len; +}; + ++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) +{ @@ -1659,6 +2702,56 @@ index 0000000..998de67 + 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; @@ -1689,11 +2782,9 @@ index 0000000..998de67 + return 0; + } + -+ if (ddata->rsc_addr) { ++ if (ddata->rsc_va) { + tablesz = ddata->rsc_len; -+ table = (struct resource_table *) -+ rproc_da_to_va(rproc, (u64)ddata->rsc_addr, -+ ddata->rsc_len); ++ table = (struct resource_table *)ddata->rsc_va; + rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL); + if (!rproc->cached_table) + return -ENOMEM; @@ -1712,6 +2803,62 @@ index 0000000..998de67 + 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) @@ -1721,12 +2868,7 @@ index 0000000..998de67 + if (!rproc->early_boot) + return rproc_elf_find_loaded_rsc_table(rproc, fw); + -+ if (ddata->rsc_addr) -+ return (struct resource_table *) -+ rproc_da_to_va(rproc, (u64)ddata->rsc_addr, -+ ddata->rsc_len); -+ -+ return NULL; ++ return (struct resource_table *)ddata->rsc_va; +} + +static int stm32_rproc_elf_sanity_check(struct rproc *rproc, @@ -1756,13 +2898,22 @@ index 0000000..998de67 + 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) @@ -1780,7 +2931,7 @@ index 0000000..998de67 +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, @@ -1788,7 +2939,7 @@ index 0000000..998de67 + }, + { + .name = STM32_MBX_VQ1, -+ .vq_id = 1, ++ .vq_id = STM32_MBX_VQ1_ID, + .client = { + .rx_callback = stm32_rproc_mb_callback, + .tx_block = false, @@ -1827,6 +2978,10 @@ index 0000000..998de67 + 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); ++ } + } +} + @@ -1854,13 +3009,48 @@ index 0000000..998de67 + 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. ++ * is set to catch any crash. + */ + if (!rproc->early_boot) { + err = stm32_rproc_set_hold_boot(rproc, false); @@ -1936,33 +3126,12 @@ index 0000000..998de67 + } +} + -+static void *stm32_rproc_da_to_va(struct rproc *rproc, u64 da, int len) -+{ -+ struct stm32_rproc *ddata = rproc->priv; -+ void *va = NULL; -+ u32 offset; -+ unsigned int i; -+ -+ for (i = 0; i < 2; i++) { -+ if (da >= ddata->ram[i].dev_addr && da + len <= -+ ddata->ram[i].dev_addr + ddata->ram[i].size) { -+ offset = da - ddata->ram[i].dev_addr; -+ /* __force to make sparse happy with type conversion */ -+ va = (__force void *)(ddata->ram[i].cpu_addr + offset); -+ break; -+ } -+ } -+ -+ return va; -+} -+ +static struct rproc_ops st_rproc_ops = { + .start = stm32_rproc_start, + .stop = stm32_rproc_stop, + .kick = stm32_rproc_kick, -+ .da_to_va = stm32_rproc_da_to_va, + .load = stm32_rproc_elf_load_segments, -+ .parse_fw = stm32_rproc_elf_load_rsc_table, ++ .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, @@ -2002,12 +3171,16 @@ index 0000000..998de67 + struct device_node *np = dev->of_node; + struct rproc *rproc = platform_get_drvdata(pdev); + struct stm32_rproc *ddata = rproc->priv; -+ struct resource *res; + struct stm32_syscon tz; -+ unsigned int tzen, i = 0; ++ 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); @@ -2016,6 +3189,13 @@ index 0000000..998de67 + 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"); + } + @@ -2054,46 +3234,40 @@ index 0000000..998de67 + if (err) + dev_warn(dev, "failed to get pdds\n"); + -+ while ((res = platform_get_resource(pdev, IORESOURCE_MEM, i))) { -+ ddata->ram[i].cpu_addr = devm_ioremap_resource(dev, res); -+ if (IS_ERR(ddata->ram[i].cpu_addr)) -+ return err; -+ -+ ddata->ram[i].bus_addr = res->start; -+ ddata->ram[i].size = resource_size(res); -+ -+ /* -+ * the m4 has retram at address 0 in its view (DA) -+ * so for retram DA=0x0 PA=bus_addr else DA=PA=bus_addr -+ */ -+ if (i == 0) -+ ddata->ram[i].dev_addr = 0x0; -+ else -+ ddata->ram[i].dev_addr = ddata->ram[i].bus_addr; -+ -+ i++; -+ } + + 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; ++ err = of_property_read_u32(np, "rsc-address", &rsc_da); ++ if (err) ++ /* no optional rsc table found */ ++ return 0; + -+ err = of_property_read_u32(np, "rsc-address", &ddata->rsc_addr); -+ if (!err) { -+ err = of_property_read_u32(np, "rsc-size", -+ &ddata->rsc_len); ++ err = of_property_read_u32(np, "rsc-size", &ddata->rsc_len); ++ if (err) { ++ dev_err(dev, "resource table size required as address defined\n"); ++ return err; ++ } + -+ if (err) { -+ dev_err(dev, "resource table size required as address defined\n"); -+ return err; -+ } ++ err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); ++ if (err) ++ return err; ++ ++ ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, ddata->rsc_len); ++ if (IS_ERR_OR_NULL(ddata->rsc_va)) { ++ dev_err(dev, "Unable to map memory region: %pa+%zx\n", ++ &rsc_pa, ddata->rsc_len); ++ ddata->rsc_va = NULL; ++ return -ENOMEM; + } + } + -+ of_reserved_mem_device_init(dev); -+ + return 0; +} + @@ -2111,17 +3285,23 @@ index 0000000..998de67 + + 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; + + if (!rproc->early_boot) { + ret = stm32_rproc_stop(rproc); + if (ret) -+ goto free_mem; ++ goto free_rproc; + } + + stm32_rproc_request_mbox(rproc); @@ -2134,9 +3314,13 @@ index 0000000..998de67 + +free_mb: + stm32_rproc_free_mbox(rproc); -+free_mem: -+ of_reserved_mem_device_release(dev); ++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; +} @@ -2144,24 +3328,58 @@ index 0000000..998de67 +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) -+ dev_warn(dev, "Releasing rproc while firmware running!\n"); ++ rproc_shutdown(rproc); + + rproc_del(rproc); + stm32_rproc_free_mbox(rproc); -+ of_reserved_mem_device_release(dev); ++ 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), + }, +}; @@ -2171,6 +3389,97 @@ index 0000000..998de67 +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 @@ -2251,7 +3560,7 @@ index 0d791c3..65bcb52 100644 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..2826118 +index 0000000..26814d3 --- /dev/null +++ b/drivers/rpmsg/rpmsg_tty.c @@ -0,0 +1,305 @@ @@ -2392,11 +3701,11 @@ index 0000000..2826118 + tbuf = buf; + do { + /* send a message to our remote processor */ -+ ret = rpmsg_send(rpdev->ept, (void *)tbuf, -+ count > msg_size ? msg_size : count); ++ ret = rpmsg_trysend(rpdev->ept, (void *)tbuf, ++ count > msg_size ? msg_size : count); + if (ret) { -+ dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret); -+ return ret; ++ dev_dbg(&rpdev->dev, "rpmsg_send failed: %d\n", ret); ++ return 0; + } + + if (count > msg_size) { @@ -2561,7 +3870,7 @@ index 0000000..2826118 +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..481eaea 100644 +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, @@ -2590,32 +3899,167 @@ index 664f957..481eaea 100644 + struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev); + struct virtproc_info *vrp = vch->vrp; + -+ return vrp->buf_size; ++ 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..787fd18 100644 +index e3c5d85..cd540c0 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h -@@ -440,6 +440,7 @@ struct rproc_dump_segment { +@@ -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 +473,7 @@ struct rproc { +@@ -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 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0021-ARM-stm32mp1-r2-RTC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0021-ARM-stm32mp1-r2-RTC.patch new file mode 100644 index 0000000..f1b05eb --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0021-ARM-stm32mp1-r2-RTC.patch @@ -0,0 +1,276 @@ +From dbec0d5fe9520a172a3cba71781d9e19e659f43a Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:04 +0200 +Subject: [PATCH 21/30] ARM stm32mp1 r2 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.49/0022-ARM-stm32mp1-r2-SOC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0022-ARM-stm32mp1-r2-SOC.patch new file mode 100644 index 0000000..5011fd8 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0022-ARM-stm32mp1-r2-SOC.patch @@ -0,0 +1,658 @@ +From 5b0a5e8f93e04129a2115dd5883ad5ca561c009a Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:05 +0200 +Subject: [PATCH 22/30] ARM stm32mp1 r2 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 113e884..a16f673 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.49/0023-ARM-stm32mp1-r2-SPI.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0023-ARM-stm32mp1-r2-SPI.patch new file mode 100644 index 0000000..fb63c97 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0023-ARM-stm32mp1-r2-SPI.patch @@ -0,0 +1,1608 @@ +From 7e96d3b92f935af4c9b85bbc25cc3e63323fd5bc Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:05 +0200 +Subject: [PATCH 23/30] ARM stm32mp1 r2 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.9/0024-ARM-stm32mp1-r0-rc2-THERMAL.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0024-ARM-stm32mp1-r2-THERMAL.patch similarity index 58% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0024-ARM-stm32mp1-r0-rc2-THERMAL.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0024-ARM-stm32mp1-r2-THERMAL.patch index 76073e8..e1aa5f2 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0024-ARM-stm32mp1-r0-rc2-THERMAL.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0024-ARM-stm32mp1-r2-THERMAL.patch @@ -1,86 +1,17 @@ -From 7a16fa25c3bd9a0c078b4d9d2ae445b975afaf69 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:42:41 +0100 -Subject: [PATCH 24/52] ARM-stm32mp1-r0-rc2-THERMAL +From acf08f1eb571f76ff42e343efa928f9b3c6112c5 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:05 +0200 +Subject: [PATCH 24/30] ARM stm32mp1 r2 THERMAL --- - .../devicetree/bindings/thermal/stm32-thermal.txt | 61 ++ - drivers/thermal/Kconfig | 2 +- - drivers/thermal/Makefile | 2 +- - drivers/thermal/st/Kconfig | 14 + - drivers/thermal/st/Makefile | 1 + - drivers/thermal/st/stm_thermal.c | 760 +++++++++++++++++++++ - 6 files changed, 838 insertions(+), 2 deletions(-) - create mode 100644 Documentation/devicetree/bindings/thermal/stm32-thermal.txt + 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/Documentation/devicetree/bindings/thermal/stm32-thermal.txt b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt -new file mode 100644 -index 0000000..8c0d5a4 ---- /dev/null -+++ b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt -@@ -0,0 +1,61 @@ -+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. -+ -+DTS provides interrupt notification mechanism by threshold. This mechanism -+offers two temperature trip points: passive and critical. The first is intended -+for passive cooling notification while the second is used for over-temperature -+reset. -+ -+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 = <0>; -+ type = "passive"; -+ }; -+ -+ cpu-crit: cpu-crit { -+ temperature = <120000>; -+ hysteresis = <0>; -+ 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/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 0e69edc..5422523 100644 --- a/drivers/thermal/Kconfig @@ -145,10 +76,10 @@ index b388789..b2b9e9b 100644 \ 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..bbd73c5 +index 0000000..8cafc37 --- /dev/null +++ b/drivers/thermal/st/stm_thermal.c -@@ -0,0 +1,760 @@ +@@ -0,0 +1,604 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -181,7 +112,7 @@ index 0000000..bbd73c5 +#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) @@ -202,10 +133,15 @@ index 0000000..bbd73c5 +/* 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 */ @@ -227,59 +163,69 @@ index 0000000..bbd73c5 +#define ONE_MHZ 1000000 +#define POLL_TIMEOUT 5000 +#define STARTUP_TIME 40 -+#define TS1_T0_VAL0 30 -+#define TS1_T0_VAL1 130 ++#define TS1_T0_VAL0 30000 /* 30 celsius */ ++#define TS1_T0_VAL1 110000 /* 110 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; + int irq; -+ unsigned int irq_enabled; + void __iomem *base; + int t0, fmt0, ramp_coeff; ++ int low_en, high_en; +}; + -+static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata) ++static void stm_thermal_disable_irq(struct stm_thermal_sensor *sensor) +{ -+ struct stm_thermal_sensor *sensor = sdata; ++ u32 itenr; + -+ disable_irq_nosync(irq); -+ sensor->irq_enabled = false; ++ /* Disable IT generation */ ++ itenr = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); ++ itenr &= ~ITENR_MASK; ++ writel_relaxed(itenr, sensor->base + DTS_ITENR_OFFSET); ++} + -+ return IRQ_WAKE_THREAD; ++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) +{ -+ 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); -+ -+ if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD) -+ writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_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; +} + @@ -311,6 +257,8 @@ index 0000000..bbd73c5 + writel_relaxed(value, sensor->base + + DTS_CFGR1_OFFSET); + ++ sensor->mode = THERMAL_DEVICE_ENABLED; ++ + return 0; +} + @@ -318,6 +266,8 @@ index 0000000..bbd73c5 +{ + u32 value; + ++ sensor->mode = THERMAL_DEVICE_DISABLED; ++ + /* Stop measuring */ + value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); + value &= ~TS1_START; @@ -347,12 +297,8 @@ index 0000000..bbd73c5 + if (!clk_freq) + return -EINVAL; + -+ prescaler = 0; -+ clk_freq /= ONE_MHZ; -+ if (clk_freq) { -+ while (prescaler <= clk_freq) -+ prescaler++; -+ } ++ /* calculate divider for maximum 1MHz PCLK */ ++ prescaler = clk_freq / ONE_MHZ + 1; + + value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); + @@ -360,7 +306,7 @@ index 0000000..bbd73c5 + value &= ~HSREF_CLK_DIV_MASK; + + /* Set prescaler. pclk_freq/prescaler < 1MHz */ -+ value |= (prescaler << HSREF_CLK_DIV_POS); ++ value |= (prescaler << HSREF_CLK_DIV_POS) & HSREF_CLK_DIV_MASK; + + /* Select PCLK as reference clock */ + value &= ~REFCLK_SEL; @@ -414,140 +360,17 @@ index 0000000..bbd73c5 + 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 - sensor->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); -+ -+ return 0; -+} -+ -+/* Disable temperature interrupt */ -+static int stm_disable_irq(struct stm_thermal_sensor *sensor) -+{ -+ u32 value; -+ -+ /* Disable IT generation for low and high thresholds */ -+ 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__); -+ -+ return 0; -+} -+ -+/* Enable temperature interrupt */ -+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); -+ -+ /* Enable IT generation for low threshold */ -+ 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); -+ -+ /* Enable IT generation for high threshold */ -+ value |= HIGH_THRESHOLD; -+ } -+ -+ /* Enable thresholds */ -+ writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET); -+ -+ dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__); -+ -+ return 0; -+} -+ -+static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor) -+{ -+ int ret; -+ -+ sensor->mode = THERMAL_DEVICE_DISABLED; -+ -+ ret = stm_sensor_power_off(sensor); -+ if (ret) -+ return ret; -+ -+ ret = stm_disable_irq(sensor); -+ if (ret) -+ return ret; -+ -+ ret = stm_thermal_set_threshold(sensor); -+ if (ret) -+ return ret; -+ -+ ret = stm_enable_irq(sensor); -+ if (ret) -+ return ret; -+ -+ ret = stm_sensor_power_on(sensor); -+ if (ret) -+ return ret; -+ -+ sensor->mode = THERMAL_DEVICE_ENABLED; ++ dev_dbg(sensor->dev, "freqM=%d Hz, threshold=0x%x", freqM, *th); + + return 0; +} @@ -556,77 +379,76 @@ index 0000000..bbd73c5 +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)); ++ *temp = (freqM - sensor->fmt0) * 1000 / sensor->ramp_coeff + sensor->t0; + -+ dev_dbg(sensor->dev, "%s: temperature = %d millicelsius", -+ __func__, *temp); ++ dev_dbg(sensor->dev, "periods=0x%x t=%d mC", periods, *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; -+ } ++ return 0; ++} + -+ 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; -+ } ++static int stm_thermal_set_trips(void *data, int low, int high) ++{ ++ struct stm_thermal_sensor *sensor = data; ++ u32 itr1, th; ++ int 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); -+ } ++ 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; +} + @@ -644,8 +466,7 @@ index 0000000..bbd73c5 + } + + ret = devm_request_threaded_irq(dev, sensor->irq, -+ stm_thermal_alarm_irq, -+ stm_thermal_alarm_irq_thread, ++ NULL, stm_thermal_alarm_irq_thread, + IRQF_ONESHOT, + dev->driver->name, sensor); + if (ret) { @@ -654,8 +475,6 @@ index 0000000..bbd73c5 + return ret; + } + -+ sensor->irq_enabled = true; -+ + dev_dbg(dev, "%s: thermal IRQ registered", __func__); + + return 0; @@ -665,6 +484,8 @@ index 0000000..bbd73c5 +{ + int ret; + ++ stm_thermal_disable_irq(sensor); ++ + ret = stm_sensor_power_off(sensor); + if (ret) + return ret; @@ -677,7 +498,6 @@ index 0000000..bbd73c5 +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) @@ -691,26 +511,8 @@ index 0000000..bbd73c5 + 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); + @@ -728,8 +530,6 @@ index 0000000..bbd73c5 + if (ret) + return ret; + -+ sensor->mode = THERMAL_DEVICE_DISABLED; -+ + return 0; +} + @@ -743,7 +543,12 @@ index 0000000..bbd73c5 + 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_thermal_set_irq_state(sensor); + + return 0; +} @@ -753,6 +558,7 @@ index 0000000..bbd73c5 + +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[] = { @@ -765,9 +571,8 @@ index 0000000..bbd73c5 +{ + 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", @@ -798,10 +603,23 @@ index 0000000..bbd73c5 + return PTR_ERR(sensor->clk); + } + -+ /* Register IRQ into GIC */ -+ ret = stm_register_irq(sensor); -+ if (ret) ++ 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, @@ -814,53 +632,12 @@ index 0000000..bbd73c5 + return ret; + } + -+ if (!sensor->th_dev->ops->get_crit_temp) { -+ /* Critical point must be provided */ -+ ret = -EINVAL; ++ /* Register IRQ into GIC */ ++ ret = stm_register_irq(sensor); ++ if (ret) + 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); -+ 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_thermal_set_irq_state(sensor); + + /* + * Thermal_zone doesn't enable hwmon as default, @@ -871,8 +648,6 @@ index 0000000..bbd73c5 + if (ret) + goto err_tz; + -+ sensor->mode = THERMAL_DEVICE_ENABLED; -+ + dev_info(&pdev->dev, "%s: Driver initialized successfully\n", + __func__); + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0025-ARM-stm32mp1-r2-TTY-USB.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0025-ARM-stm32mp1-r2-TTY-USB.patch new file mode 100644 index 0000000..781930c --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0025-ARM-stm32mp1-r2-TTY-USB.patch @@ -0,0 +1,3808 @@ +From 8b909622c1d507518a617c58d5fe42470bc7f73a Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:06 +0200 +Subject: [PATCH 25/30] ARM stm32mp1 r2 TTY USB + +--- + drivers/tty/serial/stm32-usart.c | 585 +++++++++++++++++++------ + 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 | 140 +++++- + drivers/usb/dwc2/hcd.c | 63 ++- + drivers/usb/dwc2/hw.h | 25 ++ + drivers/usb/dwc2/params.c | 40 ++ + drivers/usb/dwc2/platform.c | 166 ++++++- + 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 + + 18 files changed, 2182 insertions(+), 255 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..fdcc214 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; + } +@@ -180,22 +179,26 @@ static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, + *sr = readl_relaxed(port->membase + ofs->isr); + + if (threaded && stm32_port->rx_ch) { ++ if (stm32_port->rx_dma_cb == CALLBACK_CALLED) ++ return 1; + status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &state); + if ((status == DMA_IN_PROGRESS) && +- (*last_res != state.residue)) ++ (*last_res != state.residue)) { ++ stm32_port->rx_dma_cb = CALLBACK_IGNORED; + return 1; +- else ++ } 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(struct uart_port *port, u32 *sr, ++ int *last_res) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +@@ -203,12 +206,18 @@ stm32_get_char(struct uart_port *port, u32 *sr, int *last_res) + + if (stm32_port->rx_ch) { + c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; +- if ((*last_res) == 0) ++ if ((*last_res) == 0) { + *last_res = RX_BUF_L; +- return c; ++ if (stm32_port->rx_dma_cb == CALLBACK_CALLED) ++ stm32_port->rx_dma_cb = CALLBACK_NOT_CALLED; ++ } + } 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) +@@ -216,44 +225,65 @@ 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 c; ++ unsigned long c, flags; + u32 sr; + char flag; + + 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); ++ + while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { + 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(port, &sr, &stm32_port->last_res); ++ 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)) +@@ -261,9 +291,12 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) + uart_insert_char(port, sr, USART_SR_ORE, c, flag); + } + +- spin_unlock(&port->lock); ++ 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 +304,39 @@ 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; ++ struct stm32_port *stm32port = to_stm32_port(port); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ ++ /* ++ * If the dma controller is sending the data on ++ * the fly then we have CALLBACK_IGNORED ++ */ ++ ++ if (stm32port->rx_dma_cb == CALLBACK_NOT_CALLED) { ++ stm32port->rx_dma_cb = CALLBACK_CALLED; ++ spin_unlock_irqrestore(&port->lock, flags); ++ stm32_receive_chars(port, true); ++ return; ++ } ++ ++ spin_unlock_irqrestore(&port->lock, flags); + } + + static void stm32_transmit_chars_pio(struct uart_port *port) +@@ -299,27 +344,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 +425,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 +448,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 +469,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,10 +484,12 @@ 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); +@@ -441,10 +497,11 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) + if ((sr & USART_SR_RXNE) && !(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; +@@ -456,13 +513,24 @@ static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) + { + struct uart_port *port = ptr; + struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ unsigned long flags; + +- spin_lock(&port->lock); +- +- if (stm32_port->rx_ch) ++ if (stm32_port->rx_ch) { ++ spin_lock_irqsave(&port->lock, flags); ++ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ spin_unlock_irqrestore(&port->lock, flags); ++ dma_sync_single_for_cpu(port->dev, ++ stm32_port->rx_dma_buf, ++ RX_BUF_L, DMA_FROM_DEVICE); + stm32_receive_chars(port, true); +- +- spin_unlock(&port->lock); ++ dma_sync_single_for_device(port->dev, ++ stm32_port->rx_dma_buf, ++ RX_BUF_L, DMA_FROM_DEVICE); ++ spin_lock_irqsave(&port->lock, flags); ++ stm32_set_bits(port, ofs->cr3, USART_CR3_DMAR); ++ spin_unlock_irqrestore(&port->lock, flags); ++ } + + return IRQ_HANDLED; + } +@@ -472,7 +540,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 +569,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 +591,22 @@ 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) { ++ spin_lock(&port->lock); ++ dmaengine_terminate_async(stm32_port->tx_ch); ++ spin_unlock(&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 +615,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 +630,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 +643,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,7 +658,6 @@ 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; + u32 val; + int ret; +@@ -565,18 +668,12 @@ 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); + +- 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 +684,62 @@ 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); ++ + 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 +747,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 +761,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 +872,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). +@@ -715,8 +908,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 +960,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 +983,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 +998,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 +1098,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]; + } + +@@ -890,10 +1130,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, + + /* 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"); ++ if (!stm32port->rx_ch) + return -ENODEV; +- } + stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, + &stm32port->rx_dma_buf, + GFP_KERNEL); +@@ -925,9 +1163,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, + goto config_err; + } + +- /* No callback as dma buffer is drained on usart interrupt */ +- desc->callback = NULL; +- desc->callback_param = NULL; ++ desc->callback = stm32_rx_dma_complete; ++ desc->callback_param = port; + + /* Push current DMA transaction in the pending queue */ + cookie = dmaengine_submit(desc); +@@ -962,10 +1199,8 @@ 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"); ++ if (!stm32port->tx_ch) + return -ENODEV; +- } + stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, + &stm32port->tx_dma_buf, + GFP_KERNEL); +@@ -1020,15 +1255,22 @@ 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 = dev_pm_set_dedicated_wake_irq(&pdev->dev, ++ stm32port->wakeirq); ++ if (ret) ++ goto err_nowup; ++ ++ device_set_wakeup_enable(&pdev->dev, false); + } + + ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); + if (ret) +- goto err_nowup; ++ goto err_wirq; + + ret = stm32_of_dma_rx_probe(stm32port, pdev); + if (ret) +@@ -1040,10 +1282,19 @@ static int stm32_serial_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, &stm32port->port); + ++ 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_wirq: ++ 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 +1308,16 @@ 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; ++ ++ pm_runtime_get_sync(&pdev->dev); + + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + +- if (stm32_port->rx_ch) ++ if (stm32_port->rx_ch) { ++ dmaengine_terminate_async(stm32_port->rx_ch); + dma_release_channel(stm32_port->rx_ch); ++ } + + if (stm32_port->rx_dma_buf) + dma_free_coherent(&pdev->dev, +@@ -1071,20 +1326,29 @@ 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); ++ err = uart_remove_one_port(&stm32_usart_driver, port); ++ ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); ++ ++ return err; + } + + +@@ -1195,7 +1459,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 +1471,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 +1509,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..2a68bc4 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,6 +99,7 @@ struct stm32_usart_info stm32h7_info = { + .has_7bits_data = true, + .has_wakeup = true, + .has_fifo = true, ++ .fifosize = 16, + } + }; + +@@ -108,7 +112,6 @@ struct stm32_usart_info stm32h7_info = { + #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,10 @@ 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_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 +150,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 +167,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 +205,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 +236,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 +249,15 @@ 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_L 160 /* 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 TX_BUF_L RX_BUF_L /* dma tx buffer length */ ++ ++enum dma_cb { ++ CALLBACK_NOT_CALLED, ++ CALLBACK_CALLED, ++ CALLBACK_IGNORED, ++}; + + struct stm32_port { + struct uart_port port; +@@ -256,11 +269,16 @@ 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; ++ enum dma_cb rx_dma_cb; /* dma rx callback status */ + 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 */ + }; + + 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 55d5ae2..712cef9 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 03614ef..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; + } +@@ -3125,6 +3181,7 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) + hsotg->connected = 0; + hsotg->test_mode = 0; + ++ /* all endpoints should be shutdown */ + for (ep = 0; ep < hsotg->num_of_eps; ep++) { + if (hsotg->eps_in[ep]) + kill_all_requests(hsotg, hsotg->eps_in[ep], +@@ -3175,6 +3232,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) + GINTSTS_PTXFEMP | \ + GINTSTS_RXFLVL) + ++static int dwc2_hsotg_ep_disable(struct usb_ep *ep); + /** + * dwc2_hsotg_core_init - issue softreset to the core + * @hsotg: The device state +@@ -3189,13 +3247,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, + u32 val; + u32 usbcfg; + u32 dcfg = 0; ++ int ep; + + /* Kill any ep0 requests as controller will be reinitialized */ + kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); + +- if (!is_usb_reset) ++ if (!is_usb_reset) { + if (dwc2_core_reset(hsotg, true)) + return; ++ } else { ++ /* all endpoints should be shutdown */ ++ for (ep = 1; ep < hsotg->num_of_eps; ep++) { ++ if (hsotg->eps_in[ep]) ++ dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); ++ if (hsotg->eps_out[ep]) ++ dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); ++ } ++ } + + /* + * we must now enable ep0 ready for host detection and then +@@ -3310,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", +@@ -3366,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); + +@@ -3378,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); +@@ -3387,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); + } + + /** +@@ -3674,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; +@@ -3993,7 +4074,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) + struct dwc2_hsotg *hsotg = hs_ep->parent; + int dir_in = hs_ep->dir_in; + int index = hs_ep->index; +- unsigned long flags; + u32 epctrl_reg; + u32 ctrl; + +@@ -4011,8 +4091,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) + + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); + +- spin_lock_irqsave(&hsotg->lock, flags); +- + ctrl = dwc2_readl(hsotg, epctrl_reg); + + if (ctrl & DXEPCTL_EPENA) +@@ -4035,10 +4113,22 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) + hs_ep->fifo_index = 0; + hs_ep->fifo_size = 0; + +- spin_unlock_irqrestore(&hsotg->lock, flags); + return 0; + } + ++static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) ++{ ++ struct dwc2_hsotg_ep *hs_ep = our_ep(ep); ++ struct dwc2_hsotg *hsotg = hs_ep->parent; ++ unsigned long flags; ++ int ret; ++ ++ spin_lock_irqsave(&hsotg->lock, flags); ++ ret = dwc2_hsotg_ep_disable(ep); ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ return ret; ++} ++ + /** + * on_list - check request is on the given endpoint + * @ep: The endpoint to check. +@@ -4186,7 +4276,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) + + static const struct usb_ep_ops dwc2_hsotg_ep_ops = { + .enable = dwc2_hsotg_ep_enable, +- .disable = dwc2_hsotg_ep_disable, ++ .disable = dwc2_hsotg_ep_disable_lock, + .alloc_request = dwc2_hsotg_ep_alloc_request, + .free_request = dwc2_hsotg_ep_free_request, + .queue = dwc2_hsotg_ep_queue_lock, +@@ -4326,9 +4416,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) + /* all endpoints should be shutdown */ + for (ep = 1; ep < hsotg->num_of_eps; ep++) { + if (hsotg->eps_in[ep]) +- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); ++ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); + if (hsotg->eps_out[ep]) +- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); ++ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); + } + + spin_lock_irqsave(&hsotg->lock, flags); +@@ -4774,11 +4864,11 @@ 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(&hsotg->eps_in[ep]->ep); ++ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); + if (hsotg->eps_out[ep]) +- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); ++ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); + } + } + +@@ -4945,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 260010a..7f128b1 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; +@@ -3564,6 +3542,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + u32 port_status; + u32 speed; + u32 pcgctl; ++ u32 pwr; + + switch (typereq) { + case ClearHubFeature: +@@ -3612,8 +3591,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + dev_dbg(hsotg->dev, + "ClearPortFeature USB_PORT_FEAT_POWER\n"); + hprt0 = dwc2_read_hprt0(hsotg); ++ pwr = hprt0 & HPRT0_PWR; + hprt0 &= ~HPRT0_PWR; + dwc2_writel(hsotg, hprt0, HPRT0); ++ if (pwr) ++ dwc2_vbus_supply_exit(hsotg); + break; + + case USB_PORT_FEAT_INDICATOR: +@@ -3823,8 +3805,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + dev_dbg(hsotg->dev, + "SetPortFeature - USB_PORT_FEAT_POWER\n"); + hprt0 = dwc2_read_hprt0(hsotg); ++ pwr = hprt0 & HPRT0_PWR; + hprt0 |= HPRT0_PWR; + dwc2_writel(hsotg, hprt0, HPRT0); ++ if (!pwr) ++ dwc2_vbus_supply_init(hsotg); + break; + + case USB_PORT_FEAT_RESET: +@@ -3841,6 +3826,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + dwc2_writel(hsotg, 0, PCGCTL); + + hprt0 = dwc2_read_hprt0(hsotg); ++ pwr = hprt0 & HPRT0_PWR; + /* Clear suspend bit if resetting from suspend state */ + hprt0 &= ~HPRT0_SUSP; + +@@ -3854,6 +3840,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + dev_dbg(hsotg->dev, + "In host mode, hprt0=%08x\n", hprt0); + dwc2_writel(hsotg, hprt0, HPRT0); ++ if (!pwr) ++ dwc2_vbus_supply_init(hsotg); + } + + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ +@@ -4393,6 +4381,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + struct usb_bus *bus = hcd_to_bus(hcd); + unsigned long flags; ++ u32 hprt0; + int ret; + + dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); +@@ -4409,12 +4398,16 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) + + dwc2_hcd_reinit(hsotg); + +- /* enable external vbus supply before resuming root hub */ +- spin_unlock_irqrestore(&hsotg->lock, flags); +- ret = dwc2_vbus_supply_init(hsotg); +- if (ret) +- return ret; +- spin_lock_irqsave(&hsotg->lock, flags); ++ hprt0 = dwc2_read_hprt0(hsotg); ++ /* Has vbus power been turned on in dwc2_core_host_init ? */ ++ if (hprt0 & HPRT0_PWR) { ++ /* Enable external vbus supply before resuming root hub */ ++ spin_unlock_irqrestore(&hsotg->lock, flags); ++ ret = dwc2_vbus_supply_init(hsotg); ++ if (ret) ++ return ret; ++ spin_lock_irqsave(&hsotg->lock, flags); ++ } + + /* Initialize and connect root hub if one is not already attached */ + if (bus->root_hub) { +@@ -4436,6 +4429,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) + { + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + unsigned long flags; ++ u32 hprt0; + + /* Turn off all host-specific interrupts */ + dwc2_disable_host_interrupts(hsotg); +@@ -4444,6 +4438,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) + synchronize_irq(hcd->irq); + + spin_lock_irqsave(&hsotg->lock, flags); ++ hprt0 = dwc2_read_hprt0(hsotg); + /* Ensure hcd is disconnected */ + dwc2_hcd_disconnect(hsotg, true); + dwc2_hcd_stop(hsotg); +@@ -4452,7 +4447,9 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore(&hsotg->lock, flags); + +- dwc2_vbus_supply_exit(hsotg); ++ /* keep balanced supply init/exit by checking HPRT0_PWR */ ++ if (hprt0 & HPRT0_PWR) ++ dwc2_vbus_supply_exit(hsotg); + + usleep_range(1000, 3000); + } +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 dff2c6e..ce4657c 100644 +--- a/drivers/usb/dwc2/params.c ++++ b/drivers/usb/dwc2/params.c +@@ -88,6 +88,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) + p->host_perio_tx_fifo_size = 256; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT; ++ p->power_down = 0; + } + + static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) +@@ -151,6 +152,35 @@ 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; ++} ++ ++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 }, +@@ -172,6 +202,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); +@@ -308,9 +342,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)) { +@@ -601,6 +638,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); +@@ -789,6 +827,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/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 00141e0..4813b2f 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.9/0014-ARM-stm32mp1-r0-rc1-WATCHDOG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0026-ARM-stm32mp1-r2-WATCHDOG.patch similarity index 51% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0014-ARM-stm32mp1-r0-rc1-WATCHDOG.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0026-ARM-stm32mp1-r2-WATCHDOG.patch index 9f3bd80..c02913e 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0014-ARM-stm32mp1-r0-rc1-WATCHDOG.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0026-ARM-stm32mp1-r2-WATCHDOG.patch @@ -1,13 +1,14 @@ -From 0d162ed61018cda930bb77680ab88b63633d5ce0 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:29:27 +0100 -Subject: [PATCH 14/52] ARM: stm32mp1-r0-rc1: WATCHDOG +From cbd843990c118aaf21b72565d68b852bea8cae1b Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:06 +0200 +Subject: [PATCH 26/30] ARM stm32mp1 r2 WATCHDOG --- drivers/watchdog/Kconfig | 12 ++++ drivers/watchdog/Makefile | 1 + + drivers/watchdog/stm32_iwdg.c | 65 +++++++++++-------- drivers/watchdog/stpmic1_wdt.c | 139 +++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 152 insertions(+) + 4 files changed, 192 insertions(+), 25 deletions(-) create mode 100644 drivers/watchdog/stpmic1_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig @@ -42,6 +43,148 @@ index bf92e7b..2649cf3 100644 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..2208e8c 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); diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c new file mode 100644 index 0000000..a6cbc27 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0019-ARM-stm32mp1-r0-rc2-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0027-ARM-stm32mp1-r2-SOUND.patch similarity index 65% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0019-ARM-stm32mp1-r0-rc2-SOUND.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0027-ARM-stm32mp1-r2-SOUND.patch index a9c1094..c4eccb9 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0019-ARM-stm32mp1-r0-rc2-SOUND.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0027-ARM-stm32mp1-r2-SOUND.patch @@ -1,41 +1,23 @@ -From f0e754855e06c3b8eb04ee09e6b1ea8a1bd9af7c Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:39:24 +0100 -Subject: [PATCH 19/52] ARM-stm32mp1-r0-rc2-SOUND +From 6c0e9cf5c087999be8208a304a575aa79fa948be Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:06 +0200 +Subject: [PATCH 27/30] ARM stm32mp1 r2 SOUND --- - include/linux/mfd/wm8994/pdata.h | 6 + - sound/soc/codecs/Kconfig | 4 +- - sound/soc/codecs/cs42l51-i2c.c | 6 + - sound/soc/codecs/cs42l51.c | 155 +++++++++++++++--- - sound/soc/codecs/cs42l51.h | 1 + - sound/soc/codecs/wm8994.c | 79 ++++++++- - sound/soc/stm/Kconfig | 1 + - sound/soc/stm/stm32_adfsdm.c | 17 +- - sound/soc/stm/stm32_i2s.c | 172 +++++++++++++------- - sound/soc/stm/stm32_sai.c | 67 +++++++- - sound/soc/stm/stm32_sai.h | 57 +++++-- - sound/soc/stm/stm32_sai_sub.c | 335 +++++++++++++++++++++++++++++++++------ - sound/soc/stm/stm32_spdifrx.c | 81 +++++++++- - 13 files changed, 819 insertions(+), 162 deletions(-) + 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 | 215 ++++++++++++++-------- + sound/soc/stm/stm32_sai.c | 139 ++++++++++++-- + sound/soc/stm/stm32_sai.h | 59 ++++-- + sound/soc/stm/stm32_sai_sub.c | 406 +++++++++++++++++++++++++++++++++++------ + sound/soc/stm/stm32_spdifrx.c | 82 ++++++++- + 12 files changed, 1110 insertions(+), 214 deletions(-) -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 diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efb095d..58161d1 100644 --- a/sound/soc/codecs/Kconfig @@ -59,10 +41,16 @@ index efb095d..58161d1 100644 config SND_SOC_WM8995 tristate diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c -index 4b5731a..8333dbf 100644 +index 4b5731a..9abbd98 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c -@@ -35,12 +35,18 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c, +@@ -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)); } @@ -70,11 +58,37 @@ index 4b5731a..8333dbf 100644 +{ + 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, @@ -82,7 +96,7 @@ index 4b5731a..8333dbf 100644 }; diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c -index 5080d7a3..fceee59 100644 +index 5080d7a3..83313ec 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -21,6 +21,7 @@ @@ -93,39 +107,51 @@ index 5080d7a3..fceee59 100644 #include #include #include -@@ -29,7 +30,9 @@ +@@ -29,20 +30,14 @@ #include #include #include +-#include +- +#include - #include -+#include - #include "cs42l51.h" -@@ -39,10 +42,21 @@ enum master_slave_mode { - MODE_MASTER, - }; - -+#define CS42L51_NUM_SUPPLIES 4 +-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", -+}; -+ - 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; }; #define CS42L51_FORMATS ( \ -@@ -165,6 +179,7 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, +@@ -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); @@ -133,7 +159,7 @@ index 5080d7a3..fceee59 100644 break; } -@@ -193,7 +208,8 @@ static const struct snd_kcontrol_new cs42l51_adcr_mux_controls = +@@ -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[] = { @@ -143,7 +169,7 @@ index 5080d7a3..fceee59 100644 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 +253,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { +@@ -237,6 +237,10 @@ static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { &cs42l51_adcr_mux_controls), }; @@ -154,7 +180,7 @@ index 5080d7a3..fceee59 100644 static const struct snd_soc_dapm_route cs42l51_routes[] = { {"HPL", NULL, "Left DAC"}, {"HPR", NULL, "Right DAC"}, -@@ -323,6 +343,19 @@ static struct cs42l51_ratios slave_auto_ratios[] = { +@@ -323,6 +327,19 @@ static struct cs42l51_ratios slave_auto_ratios[] = { { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 }, }; @@ -174,7 +200,7 @@ index 5080d7a3..fceee59 100644 static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { -@@ -345,11 +378,13 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream, +@@ -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; @@ -190,7 +216,7 @@ index 5080d7a3..fceee59 100644 case MODE_SLAVE: ratios = slave_ratios; nr_ratios = ARRAY_SIZE(slave_ratios); -@@ -385,7 +420,16 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream, +@@ -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; @@ -208,51 +234,21 @@ index 5080d7a3..fceee59 100644 break; case MODE_SLAVE: power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); -@@ -465,28 +509,42 @@ static const struct snd_soc_dai_ops cs42l51_dai_ops = { - .digital_mute = cs42l51_dai_mute, - }; - --static struct snd_soc_dai_driver cs42l51_dai = { -- .name = "cs42l51-hifi", -- .playback = { -- .stream_name = "Playback", -- .channels_min = 1, -- .channels_max = 2, -- .rates = SNDRV_PCM_RATE_8000_96000, -- .formats = CS42L51_FORMATS, -- }, -- .capture = { -- .stream_name = "Capture", -- .channels_min = 1, -- .channels_max = 2, -- .rates = SNDRV_PCM_RATE_8000_96000, -- .formats = CS42L51_FORMATS, -+static struct snd_soc_dai_driver cs42l51_dai[] = { -+ { -+ .name = "cs42l51-hifi0", -+ .playback = { -+ .stream_name = "Playback", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_96000, -+ .formats = CS42L51_FORMATS, -+ }, -+ .ops = &cs42l51_dai_ops, - }, -- .ops = &cs42l51_dai_ops, -+ { -+ .name = "cs42l51-hifi1", -+ .capture = { -+ .stream_name = "Capture", -+ .channels_min = 1, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_96000, -+ .formats = CS42L51_FORMATS, -+ }, -+ .ops = &cs42l51_dai_ops, -+ } - }; +@@ -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; @@ -267,7 +263,121 @@ index 5080d7a3..fceee59 100644 /* * DAC configuration -@@ -528,7 +586,7 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) +@@ -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; @@ -276,10 +386,12 @@ index 5080d7a3..fceee59 100644 if (IS_ERR(regmap)) return PTR_ERR(regmap); -@@ -540,6 +598,41 @@ int cs42l51_probe(struct device *dev, struct regmap *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) @@ -314,16 +426,13 @@ index 5080d7a3..fceee59 100644 + 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); - if (ret < 0) { -@@ -557,12 +650,30 @@ int cs42l51_probe(struct device *dev, struct regmap *regmap) - val & CS42L51_CHIP_REV_MASK); +@@ -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); -+ &soc_component_device_cs42l51, cs42l51_dai, 2); + &soc_component_device_cs42l51, &cs42l51_dai, 1); + if (ret < 0) + goto error; + @@ -351,10 +460,17 @@ index 5080d7a3..fceee59 100644 { .compatible = "cirrus,cs42l51", }, { } diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h -index 0ca8054..aef0ede 100644 +index 0ca8054..a086f7e 100644 --- a/sound/soc/codecs/cs42l51.h +++ b/sound/soc/codecs/cs42l51.h -@@ -22,6 +22,7 @@ struct device; +@@ -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); @@ -362,8 +478,31 @@ index 0ca8054..aef0ede 100644 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 14f1b0c..eb222da 100644 +index 14f1b0c..c83ae39 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -11,6 +11,7 @@ @@ -406,7 +545,7 @@ index 14f1b0c..eb222da 100644 + break; + case SND_SOC_DAPM_POST_PMD: + dev_dbg(comp->dev, "Disable master clock %s\n", -+ mclk_id ? "MCLK1" : "MCLK2"); ++ mclk_id ? "MCLK2" : "MCLK1"); + clk_disable_unprepare(mclk); + break; + } @@ -417,7 +556,15 @@ index 14f1b0c..eb222da 100644 static void vmid_reference(struct snd_soc_component *component) { struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); -@@ -1775,6 +1812,16 @@ static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = { +@@ -1156,7 +1193,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)) +@@ -1775,6 +1811,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), }; @@ -434,7 +581,7 @@ index 14f1b0c..eb222da 100644 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), -@@ -1999,10 +2046,10 @@ static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { +@@ -1999,10 +2045,10 @@ static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { }; static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { @@ -449,7 +596,7 @@ index 14f1b0c..eb222da 100644 { "MICBIAS1", NULL, "CLK_SYS" }, { "MICBIAS1", NULL, "MICBIAS Supply" }, { "MICBIAS2", NULL, "CLK_SYS" }, -@@ -2376,11 +2423,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, +@@ -2376,11 +2422,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); @@ -476,7 +623,7 @@ index 14f1b0c..eb222da 100644 break; default: -@@ -3990,6 +4052,7 @@ static int wm8994_component_probe(struct snd_soc_component *component) +@@ -3990,6 +4051,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); @@ -484,7 +631,7 @@ index 14f1b0c..eb222da 100644 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); unsigned int reg; int ret, i; -@@ -4271,6 +4334,14 @@ static int wm8994_component_probe(struct snd_soc_component *component) +@@ -4271,6 +4333,14 @@ static int wm8994_component_probe(struct snd_soc_component *component) case WM8994: snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, ARRAY_SIZE(wm8994_specific_dapm_widgets)); @@ -512,80 +659,107 @@ index 9b26813..c66ffa7 100644 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 706ff00..71d341b 100644 +index 24948b9..3a4d2c8 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c -@@ -9,6 +9,7 @@ +@@ -18,6 +18,7 @@ + #include - #include - #include -+#include - #include - #include + #include ++#include + #include -@@ -37,6 +38,8 @@ struct stm32_adfsdm_priv { - /* PCM buffer */ - unsigned char *pcm_buff; - unsigned int pos; -+ -+ struct mutex lock; /* protect against race condition on iio state */ - }; + #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 = { -@@ -62,10 +65,12 @@ static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream, - { - struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); + .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, -+ mutex_lock(&priv->lock); - if (priv->iio_active) { - iio_channel_stop_all_cb(priv->iio_cb); - priv->iio_active = false; - } -+ mutex_unlock(&priv->lock); - } + .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", + }; - static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, -@@ -74,13 +79,19 @@ static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, - struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); - int ret; - -+ mutex_lock(&priv->lock); -+ if (priv->iio_active) { -+ iio_channel_stop_all_cb(priv->iio_cb); -+ priv->iio_active = false; ++void 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; i > 0; i--) { ++ *d++ = *s++; ++ s++; + } ++} + - ret = iio_write_channel_attribute(priv->iio_ch, - substream->runtime->rate, 0, - IIO_CHAN_INFO_SAMP_FREQ); - if (ret < 0) { - dev_err(dai->dev, "%s: Failed to set %d sampling rate\n", - __func__, substream->runtime->rate); -- return ret; -+ goto out; + 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) ++ 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; } - if (!priv->iio_active) { -@@ -92,6 +103,9 @@ static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, - __func__, ret); - } - -+out: -+ mutex_unlock(&priv->lock); +- memcpy(&pcm_buff[priv->pos], &src_buff[size - cur_size], cur_size); ++ if (format == SNDRV_PCM_FORMAT_S16_LE) ++ 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); + - return ret; - } + priv->pos = (priv->pos + cur_size) % buff_size; -@@ -298,6 +312,7 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) - - priv->dev = &pdev->dev; - priv->dai_drv = stm32_adfsdm_dai; -+ mutex_init(&priv->lock); - - dev_set_drvdata(&pdev->dev, priv); +- 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 6d0bf78..9dcf946 100644 +index 6d0bf78..490352c 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -16,6 +16,7 @@ @@ -639,23 +813,35 @@ index 6d0bf78..9dcf946 100644 #define STM32_I2S_FIFO_SIZE 16 #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER) -@@ -200,7 +221,6 @@ enum i2s_datlen { +@@ -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 +241,6 @@ struct stm32_i2s_data { +@@ -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; -@@ -246,8 +265,8 @@ static irqreturn_t stm32_i2s_isr(int irq, void *devid) +@@ -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); +@@ -246,8 +267,8 @@ static irqreturn_t stm32_i2s_isr(int irq, void *devid) return IRQ_NONE; } @@ -666,12 +852,24 @@ index 6d0bf78..9dcf946 100644 if (flags & I2S_SR_OVR) { dev_dbg(&pdev->dev, "Overrun\n"); -@@ -276,10 +295,13 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) +@@ -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,10 +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_IFCR_REG: - case STM32_I2S_TXDR_REG: +- case STM32_I2S_TXDR_REG: case STM32_I2S_RXDR_REG: case STM32_I2S_CGFR_REG: + case STM32_I2S_HWCFGR_REG: @@ -681,7 +879,16 @@ index 6d0bf78..9dcf946 100644 return true; default: return false; -@@ -488,7 +510,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, +@@ -289,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: +@@ -488,20 +513,14 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); int format = params_width(params); @@ -690,7 +897,12 @@ index 6d0bf78..9dcf946 100644 unsigned int fthlv; int ret; -@@ -501,7 +523,7 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, +- 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); @@ -699,7 +911,7 @@ index 6d0bf78..9dcf946 100644 break; case 32: cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_32) | -@@ -529,30 +551,29 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, +@@ -529,30 +548,36 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, if (ret < 0) return ret; @@ -720,27 +932,34 @@ index 6d0bf78..9dcf946 100644 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); + +- return regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, +- I2S_IFCR_MASK, I2S_IFCR_MASK); + 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_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, -- I2S_IFCR_MASK, I2S_IFCR_MASK); ++ + return regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); } static int stm32_i2s_hw_params(struct snd_pcm_substream *substream, -@@ -587,7 +608,12 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, +@@ -587,7 +612,12 @@ 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 */ @@ -754,7 +973,7 @@ index 6d0bf78..9dcf946 100644 ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, I2S_CR1_SPE, I2S_CR1_SPE); -@@ -596,28 +622,29 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, +@@ -596,28 +626,29 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } @@ -780,8 +999,10 @@ index 6d0bf78..9dcf946 100644 ier = I2S_IER_OVRIE; - spin_lock(&i2s->lock_fd); - if (i2s->refcount == 1) - /* dummy write to trigger capture */ +- 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); @@ -790,7 +1011,7 @@ index 6d0bf78..9dcf946 100644 if (STM32_I2S_IS_SLAVE(i2s)) ier |= I2S_IER_TIFREIE; -@@ -627,6 +654,9 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, +@@ -627,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: @@ -800,7 +1021,7 @@ index 6d0bf78..9dcf946 100644 if (playback_flg) regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, I2S_IER_UDRIE, -@@ -642,16 +672,15 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, +@@ -642,16 +676,15 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, spin_unlock(&i2s->lock_fd); break; } @@ -819,16 +1040,26 @@ index 6d0bf78..9dcf946 100644 cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, -@@ -673,6 +702,8 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, +@@ -668,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) -@@ -698,11 +729,12 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { +@@ -698,11 +736,13 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -837,12 +1068,13 @@ index 6d0bf78..9dcf946 100644 .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 = { -@@ -717,7 +749,8 @@ static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { +@@ -717,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, @@ -852,7 +1084,7 @@ index 6d0bf78..9dcf946 100644 .periods_min = 2, .periods_max = 8, }; -@@ -753,12 +786,8 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, +@@ -753,12 +794,8 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, if (!dai_ptr) return -ENOMEM; @@ -865,7 +1097,19 @@ index 6d0bf78..9dcf946 100644 dai_ptr->id = 1; stm32_i2s_dai_init(&dai_ptr->playback, "playback"); stm32_i2s_dai_init(&dai_ptr->capture, "capture"); -@@ -853,6 +882,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, +@@ -828,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, +@@ -853,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; @@ -873,7 +1117,14 @@ index 6d0bf78..9dcf946 100644 int ret; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); -@@ -872,47 +902,50 @@ static int stm32_i2s_probe(struct platform_device *pdev) +@@ -866,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; @@ -946,21 +1197,25 @@ index 6d0bf78..9dcf946 100644 return ret; } -@@ -929,10 +962,35 @@ static int stm32_i2s_remove(struct platform_device *pdev) - - MODULE_DEVICE_TABLE(of, stm32_i2s_ids); +-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; -+} -+ + + 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); @@ -973,7 +1228,7 @@ index 6d0bf78..9dcf946 100644 +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", @@ -981,20 +1236,24 @@ index 6d0bf78..9dcf946 100644 + .pm = &stm32_i2s_pm_ops, }, .probe = stm32_i2s_probe, - .remove = stm32_i2s_remove, +- .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 f226542..1426d90 100644 +index f226542..d6763a1 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c -@@ -21,6 +21,7 @@ +@@ -21,6 +21,8 @@ #include #include #include +#include ++#include #include #include -@@ -29,13 +30,20 @@ +@@ -29,13 +31,20 @@ #include "stm32_sai.h" static const struct stm32_sai_conf stm32_sai_conf_f4 = { @@ -1019,7 +1278,108 @@ index f226542..1426d90 100644 }; static const struct of_device_id stm32_sai_ids[] = { -@@ -130,6 +138,8 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -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; + } +@@ -112,16 +138,22 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, + if (!sai_provider) { + dev_err(&sai_client->pdev->dev, + "SAI sync provider data not found\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto error; + } + + /* Configure sync client */ + ret = stm32_sai_sync_conf_client(sai_client, synci); + if (ret < 0) +- return ret; ++ goto error; + + /* Configure sync provider */ +- return stm32_sai_sync_conf_provider(sai_provider, synco); ++ ret = stm32_sai_sync_conf_provider(sai_provider, synco); ++ ++error: ++ put_device(&pdev->dev); ++ of_node_put(np_provider); ++ return ret; + } + + static int stm32_sai_probe(struct platform_device *pdev) +@@ -130,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; @@ -1028,7 +1388,7 @@ index f226542..1426d90 100644 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); if (!sai) -@@ -142,7 +152,8 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -142,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) @@ -1038,7 +1398,7 @@ index f226542..1426d90 100644 else return -EINVAL; -@@ -181,6 +192,30 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -181,6 +216,30 @@ static int stm32_sai_probe(struct platform_device *pdev) reset_control_deassert(rst); } @@ -1069,7 +1429,7 @@ index f226542..1426d90 100644 sai->pdev = pdev; sai->set_sync = &stm32_sai_set_sync; platform_set_drvdata(pdev, sai); -@@ -188,12 +223,34 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -188,12 +247,54 @@ static int stm32_sai_probe(struct platform_device *pdev) return devm_of_platform_populate(&pdev->dev); } @@ -1081,11 +1441,31 @@ index f226542..1426d90 100644 + */ +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 */ @@ -1105,7 +1485,7 @@ index f226542..1426d90 100644 .probe = stm32_sai_probe, }; diff --git a/sound/soc/stm/stm32_sai.h b/sound/soc/stm/stm32_sai.h -index f254221..042f94f 100644 +index f254221..158c73f 100644 --- a/sound/soc/stm/stm32_sai.h +++ b/sound/soc/stm/stm32_sai.h @@ -37,6 +37,12 @@ @@ -1201,7 +1581,7 @@ index f254221..042f94f 100644 }; /** -@@ -262,7 +293,7 @@ struct stm32_sai_conf { +@@ -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 @@ -1209,8 +1589,11 @@ index f254221..042f94f 100644 + * @conf: SAI hardware capabitilites * @irq: SAI interrupt line * @set_sync: pointer to synchro mode configuration callback ++ * @gcr: SAI Global Configuration Register */ -@@ -272,7 +303,7 @@ struct stm32_sai_data { + 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; @@ -1219,8 +1602,10 @@ index f254221..042f94f 100644 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 06fba96..1f23ca4 100644 +index 2fb2b91..24f13ea 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -17,6 +17,7 @@ @@ -1264,7 +1649,15 @@ index 06fba96..1f23ca4 100644 * @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 -@@ -110,6 +114,7 @@ struct stm32_sai_sub_data { +@@ -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; @@ -1272,7 +1665,15 @@ index 06fba96..1f23ca4 100644 dma_addr_t phys_addr; unsigned int mclk_rate; unsigned int id; -@@ -151,6 +156,10 @@ static bool stm32_sai_sub_readable_reg(struct device *dev, unsigned int reg) +@@ -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: @@ -1283,7 +1684,7 @@ index 06fba96..1f23ca4 100644 return true; default: return false; -@@ -161,6 +170,7 @@ static bool stm32_sai_sub_volatile_reg(struct device *dev, unsigned int reg) +@@ -161,6 +172,7 @@ static bool stm32_sai_sub_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { case STM_SAI_DR_REGX: @@ -1291,7 +1692,7 @@ index 06fba96..1f23ca4 100644 return true; default: return false; -@@ -175,7 +185,6 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) +@@ -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: @@ -1299,7 +1700,7 @@ index 06fba96..1f23ca4 100644 case STM_SAI_CLRFR_REGX: case STM_SAI_DR_REGX: case STM_SAI_PDMCR_REGX: -@@ -195,6 +204,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { +@@ -195,6 +206,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, @@ -1307,7 +1708,7 @@ index 06fba96..1f23ca4 100644 }; static const struct regmap_config stm32_sai_sub_regmap_config_h7 = { -@@ -206,6 +216,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = { +@@ -206,6 +218,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, @@ -1315,7 +1716,7 @@ index 06fba96..1f23ca4 100644 }; static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, -@@ -251,6 +262,175 @@ static const struct snd_kcontrol_new iec958_ctls = { +@@ -251,6 +264,194 @@ static const struct snd_kcontrol_new iec958_ctls = { .put = snd_pcm_iec958_put, }; @@ -1370,6 +1771,25 @@ index 06fba96..1f23ca4 100644 + 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) +{ @@ -1491,7 +1911,7 @@ index 06fba96..1f23ca4 100644 static irqreturn_t stm32_sai_isr(int irq, void *devid) { struct stm32_sai_sub_data *sai = (struct stm32_sai_sub_data *)devid; -@@ -265,8 +445,8 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) +@@ -265,8 +466,8 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) if (!flags) return IRQ_NONE; @@ -1502,12 +1922,24 @@ index 06fba96..1f23ca4 100644 if (!sai->substream) { dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr); -@@ -312,15 +492,25 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, +@@ -300,8 +501,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 +515,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) { -+ if (dir == SND_SOC_CLOCK_OUT) { ++ if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) { ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, (unsigned int)~SAI_XCR1_NODIV); @@ -1515,22 +1947,38 @@ index 06fba96..1f23ca4 100644 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; -+ -+ if (sai->sai_mclk) { -+ ret = clk_set_rate_exclusive(sai->sai_mclk, -+ sai->mclk_rate); -+ if (ret) { -+ dev_err(cpu_dai->dev, -+ "Could not set mclk rate\n"); -+ return ret; -+ } -+ } } return 0; -@@ -505,9 +695,8 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, +@@ -495,8 +712,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,9 +733,8 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, } /* Enable ITs */ @@ -1542,7 +1990,7 @@ index 06fba96..1f23ca4 100644 imr = SAI_XIMR_OVRUDRIE; if (STM_SAI_IS_CAPTURE(sai)) { -@@ -539,10 +728,10 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, +@@ -547,10 +766,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. */ @@ -1557,24 +2005,31 @@ index 06fba96..1f23ca4 100644 /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { -@@ -715,15 +904,9 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -722,31 +941,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 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 -@@ -731,14 +914,22 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, +- 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)) { @@ -1604,7 +2059,7 @@ index 06fba96..1f23ca4 100644 } else { /* * TDM mode : -@@ -750,8 +941,10 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -758,13 +981,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)) { @@ -1617,12 +2072,22 @@ index 06fba96..1f23ca4 100644 } else { if (sai->mclk_rate) { mclk_ratio = sai->mclk_rate / rate; -@@ -764,31 +957,22 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, + if (mclk_ratio == 512) { +- mask = SAI_XCR1_OSR; + cr1 = SAI_XCR1_OSR; + } else if (mclk_ratio != 256) { + dev_err(cpu_dai->dev, +@@ -772,31 +996,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); ++ ++ regmap_update_bits(sai->regmap, ++ STM_SAI_CR1_REGX, ++ SAI_XCR1_OSR, cr1); ++ + div = stm32_sai_get_clk_div(sai, sai_clk_rate, + sai->mclk_rate); + if (div < 0) @@ -1658,41 +2123,43 @@ index 06fba96..1f23ca4 100644 } static int stm32_sai_hw_params(struct snd_pcm_substream *substream, -@@ -881,6 +1065,9 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, +@@ -882,14 +1102,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; + + regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); + + 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); + -+ clk_rate_exclusive_put(sai->sai_mclk); -+ ++ spin_lock_irqsave(&sai->irq_lock, flags); sai->substream = NULL; ++ spin_unlock_irqrestore(&sai->irq_lock, flags); } -@@ -888,11 +1075,12 @@ static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, - struct snd_soc_dai *cpu_dai) + static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, +@@ -910,7 +1140,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); -+ struct snd_kcontrol_new knew = iec958_ctls; - - if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { - dev_dbg(&sai->pdev->dev, "%s: register iec controls", __func__); -- return snd_ctl_add(rtd->pcm->card, -- snd_ctl_new1(&iec958_ctls, sai)); -+ knew.device = rtd->pcm->device; -+ return snd_ctl_add(rtd->pcm->card, snd_ctl_new1(&knew, sai)); - } - - return 0; -@@ -903,6 +1091,8 @@ 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; - -+ sai->cpu_dai = cpu_dai; +- 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); /* - * DMA supports 4, 8 or 16 burst sizes. Burst size 4 is the best choice, -@@ -910,6 +1100,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) +@@ -919,6 +1151,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) * constraints). */ sai->dma_params.maxburst = 4; @@ -1701,7 +2168,46 @@ index 06fba96..1f23ca4 100644 /* Buswidth will be set by framework at runtime */ sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; -@@ -1080,7 +1272,7 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, +@@ -938,8 +1172,10 @@ 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; +@@ -994,6 +1230,16 @@ static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream, + return 0; + } + ++/* No support of mmap in S/PDIF mode */ ++static const struct snd_pcm_hardware stm32_sai_pcm_hw_spdif = { ++ .info = SNDRV_PCM_INFO_INTERLEAVED, ++ .buffer_bytes_max = 8 * PAGE_SIZE, ++ .period_bytes_min = 1024, ++ .period_bytes_max = PAGE_SIZE, ++ .periods_min = 2, ++ .periods_max = 8, ++}; ++ + static const struct snd_pcm_hardware stm32_sai_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, + .buffer_bytes_max = 8 * PAGE_SIZE, +@@ -1050,7 +1296,7 @@ static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config = { + }; + + static const struct snd_dmaengine_pcm_config stm32_sai_pcm_config_spdif = { +- .pcm_hardware = &stm32_sai_pcm_hw, ++ .pcm_hardware = &stm32_sai_pcm_hw_spdif, + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .process = stm32_sai_pcm_process_spdif, + }; +@@ -1089,7 +1335,7 @@ 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 */ @@ -1710,7 +2216,7 @@ index 06fba96..1f23ca4 100644 sai->regmap_config = &stm32_sai_sub_regmap_config_h7; sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", -@@ -1182,6 +1374,23 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, +@@ -1191,6 +1437,23 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return PTR_ERR(sai->sai_ck); } @@ -1734,7 +2240,15 @@ index 06fba96..1f23ca4 100644 return 0; } -@@ -1266,10 +1475,34 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) +@@ -1235,6 +1498,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); +@@ -1275,10 +1539,34 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) return 0; } @@ -1770,7 +2284,7 @@ index 06fba96..1f23ca4 100644 .probe = stm32_sai_sub_probe, }; diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c -index 373df4f..693e30d 100644 +index 373df4f..ac3cd15 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -16,11 +16,13 @@ @@ -1871,7 +2385,7 @@ index 373df4f..693e30d 100644 } static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) -@@ -633,11 +661,12 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { +@@ -633,11 +661,13 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -1880,12 +2394,13 @@ index 373df4f..693e30d 100644 .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) -@@ -835,7 +864,8 @@ static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { +@@ -835,7 +865,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, @@ -1895,7 +2410,7 @@ index 373df4f..693e30d 100644 .periods_min = 2, .periods_max = 8, }; -@@ -901,6 +931,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) +@@ -901,6 +932,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; @@ -1903,7 +2418,7 @@ index 373df4f..693e30d 100644 int ret; spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); -@@ -957,7 +988,19 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) +@@ -957,7 +989,19 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) goto error; } @@ -1924,7 +2439,7 @@ index 373df4f..693e30d 100644 error: if (!IS_ERR(spdifrx->ctrl_chan)) -@@ -983,10 +1026,34 @@ static int stm32_spdifrx_remove(struct platform_device *pdev) +@@ -983,10 +1027,34 @@ static int stm32_spdifrx_remove(struct platform_device *pdev) MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0028-ARM-stm32mp1-r2-MISC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0028-ARM-stm32mp1-r2-MISC.patch new file mode 100644 index 0000000..7b9d2d4 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0028-ARM-stm32mp1-r2-MISC.patch @@ -0,0 +1,253 @@ +From a3c9e0d977420d451f6e13873a4a0921d8a9b88f Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:07 +0200 +Subject: [PATCH 28/30] ARM stm32mp1 r2 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 f6fcb8a..88849c1 100644 +--- a/arch/arm/Kconfig.debug ++++ b/arch/arm/Kconfig.debug +@@ -1184,6 +1184,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 +@@ -1468,6 +1504,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 +@@ -1517,6 +1557,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 +@@ -1580,6 +1621,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 +@@ -1673,10 +1716,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 +@@ -1788,7 +1833,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.9/0016-ARM-stm32mp1-r0-rc1-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0029-ARM-stm32mp1-r2-DEVICETREE.patch similarity index 54% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0016-ARM-stm32mp1-r0-rc1-DEVICETREE.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0029-ARM-stm32mp1-r2-DEVICETREE.patch index 6a57985..f9beb9c 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0016-ARM-stm32mp1-r0-rc1-DEVICETREE.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0029-ARM-stm32mp1-r2-DEVICETREE.patch @@ -1,69 +1,136 @@ -From adbdec4cf36d1cf2127da0c16b43ec88a5e7253c Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:31:28 +0100 -Subject: [PATCH 16/52] ARM: stm32mp1-r0-rc1: DEVICETREE +From 3c9063e4da42c0fdc9a0e6a5dc9b0707cdb0f22a Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:10 +0200 +Subject: [PATCH 29/30] ARM stm32mp1 r2 DEVICETREE --- - .../devicetree/bindings/dma/stm32-dma.txt | 32 +- - .../devicetree/bindings/dma/stm32-dmamux.txt | 5 +- - .../devicetree/bindings/dma/stm32-mdma.txt | 22 +- - .../devicetree/bindings/i2c/i2c-stm32.txt | 48 +- - .../devicetree/bindings/iio/adc/st,stm32-adc.txt | 64 ++- - .../bindings/iio/counter/stm32-lptimer-cnt.txt | 8 +- - .../bindings/iio/timer/stm32-timer-trigger.txt | 9 + - .../devicetree/bindings/input/st,stpmic1-onkey.txt | 28 + - .../devicetree/bindings/mfd/st,stm32mp1-pwr.txt | 53 ++ - .../devicetree/bindings/mfd/st,stpmic1.txt | 132 +++++ - Documentation/devicetree/bindings/mfd/stmfx.txt | 28 + - Documentation/devicetree/bindings/mmc/mmci.txt | 11 + - .../devicetree/bindings/mtd/stm32-fmc2-nand.txt | 59 ++ - .../devicetree/bindings/nvmem/st,stm32-romem.txt | 31 ++ - .../devicetree/bindings/pinctrl/pinctrl-stmfx.txt | 116 ++++ - .../bindings/pinctrl/st,stm32-pinctrl.txt | 2 + - .../devicetree/bindings/pwm/pwm-stm32-lp.txt | 9 +- - .../devicetree/bindings/pwm/pwm-stm32.txt | 8 +- - .../bindings/regulator/st,stm32mp1-pwr-reg.txt | 31 ++ - .../bindings/regulator/st,stpmic1-regulator.txt | 68 +++ - .../devicetree/bindings/remoteproc/rproc-srm.txt | 57 ++ - .../devicetree/bindings/remoteproc/stm32-rproc.txt | 78 +++ - .../devicetree/bindings/rtc/st,stm32-rtc.txt | 10 +- - .../devicetree/bindings/serial/st,stm32-usart.txt | 40 +- - .../devicetree/bindings/spi/spi-stm32-qspi.txt | 44 ++ - .../bindings/watchdog/st,stpmic1-wdt.txt | 11 + - arch/arm/boot/dts/Makefile | 2 + - arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 603 ++++++++++++++++++++- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 412 ++++++++++++++ - arch/arm/boot/dts/stm32mp157c-dk2.dts | 22 + - arch/arm/boot/dts/stm32mp157c-ed1.dts | 301 +++++++++- - arch/arm/boot/dts/stm32mp157c-ev1.dts | 121 ++++- - arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi | 436 +++++++++++++++ - arch/arm/boot/dts/stm32mp157c.dtsi | 457 ++++++++++++++-- - 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 +++ - 38 files changed, 3526 insertions(+), 124 deletions(-) + .../bindings/connector/usb-connector.txt | 2 + + .../devicetree/bindings/display/bridge/sii902x.txt | 9 + + .../devicetree/bindings/dma/stm32-dma.txt | 32 +- + .../devicetree/bindings/dma/stm32-dmamux.txt | 5 +- + .../devicetree/bindings/dma/stm32-mdma.txt | 22 +- + Documentation/devicetree/bindings/gpio/gpio.txt | 12 + + .../bindings/hwlock/st,stm32-hwspinlock.txt | 23 + + .../devicetree/bindings/i2c/i2c-stm32.txt | 85 +- + .../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 | 132 +++ + 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 | 3 + + .../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 | 68 ++ + .../devicetree/bindings/remoteproc/rproc-srm.txt | 61 + + .../devicetree/bindings/remoteproc/stm32-rproc.txt | 80 ++ + .../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 | 756 +++++++++++++ + arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts | 14 + + arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts | 157 +++ + arch/arm/boot/dts/stm32mp157c-dk2.dts | 145 +++ + arch/arm/boot/dts/stm32mp157c-ed1.dts | 378 ++++++- + arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts | 33 + + arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts | 162 +++ + arch/arm/boot/dts/stm32mp157c-ev1.dts | 623 +++++++++- + arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi | 436 +++++++ + arch/arm/boot/dts/stm32mp157c.dtsi | 1021 ++++++++++++++++- + 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 + + 57 files changed, 6444 insertions(+), 204 deletions(-) + 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/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..163be09 100644 --- a/Documentation/devicetree/bindings/dma/stm32-dma.txt @@ -156,7 +223,7 @@ index 1b893b2..8e092d2 100644 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..1810f87 100644 +index d18772d..1810f876 100644 --- a/Documentation/devicetree/bindings/dma/stm32-mdma.txt +++ b/Documentation/devicetree/bindings/dma/stm32-mdma.txt @@ -10,7 +10,7 @@ Required properties: @@ -217,13 +284,75 @@ index d18772d..1810f87 100644 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..e76fe82 100644 +index 3b54899..94cd4bd 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt -@@ -7,10 +7,12 @@ Required properties : - - reg : Offset and length of the register set for the device - - interrupts : Must contain the interrupt id for I2C event and then the +@@ -1,33 +1,49 @@ + * 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. - resets: Must contain the phandle to the reset controller. @@ -235,19 +364,47 @@ index 3b54899..e76fe82 100644 - #address-cells = <1>; - #size-cells = <0>; -@@ -26,6 +28,11 @@ Optional properties : - - i2c-scl-falling-time-ns : Only for STM32F7, I2C SCL Falling time for the board - (default: 10) +-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: Only for STM32F7, use to set Fast Mode Plus bit within SYSCFG -+ whether Fast Mode Plus speed is selected by slave. -+ 1st cell : phandle to syscfg -+ 2nd cell : register offset within SYSCFG -+ 3rd cell : register bitmask for FMP bit ++- st,syscfg-fmp: Use to set Fast Mode Plus bit within SYSCFG when Fast Mode ++ Plus speed is selected by slave. ++ 1st cell: phandle to syscfg ++ 2nd cell: register offset within SYSCFG ++ 3rd cell: register bitmask for FMP bit ++ For STM32F7, STM32H7 and STM32MP1 only. ++- st,syscfg-fmp-clr: Use to clear Fast Mode Plus bit within SYSCFG when Fast ++ Mode Plus speed is selected by slave. ++ 1st cell: phandle to syscfg ++ 2nd cell: clear register offset within SYSCFG ++ 3rd cell: register bitmask for FMP clear bit ++ For STM32MP1 family only. - Example : +-Example : ++Example: -@@ -52,5 +59,42 @@ Example : + i2c@40005400 { + compatible = "st,stm32f4-i2c"; +@@ -52,5 +68,44 @@ Example : resets = <&rcc STM32F7_APB1_RESET(I2C1)>; clocks = <&rcc 1 CLK_I2C1>; pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; @@ -255,6 +412,7 @@ index 3b54899..e76fe82 100644 + 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 { @@ -269,6 +427,7 @@ index 3b54899..e76fe82 100644 + clocks = <&rcc I2C2_K>; + resets = <&rcc I2C2_R>; + st,syscfg-fmp = <&syscfg 0x4 0x2>; ++ st,syscfg-fmp-clr = <&syscfg 0x44 0x2>; + }; + + @@ -277,13 +436,13 @@ index 3b54899..e76fe82 100644 +An I2C device connected onto STM32 I2C controller must use a format described by +i2c.txt file. + -+Required properties : ++Required properties: +- compatible + Device driver compatible name +- reg + I2C slave addresses (see i2c.txt for more details) + -+Optional properties : ++Optional properties: + + i2c@40013000 { + camera@3c { @@ -292,19 +451,53 @@ index 3b54899..e76fe82 100644 + }; }; diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -index 8346bcb..c46598c 100644 +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,8 @@ Required properties: +@@ -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 +65,8 @@ Required properties: +@@ -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. @@ -315,7 +508,7 @@ index 8346bcb..c46598c 100644 - 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 +93,38 @@ Optional properties: +@@ -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. @@ -354,7 +547,7 @@ index 8346bcb..c46598c 100644 Example: adc: adc@40012000 { -@@ -119,9 +153,16 @@ Example: +@@ -119,9 +187,16 @@ Example: dmas = <&dma2 0 0 0x400 0x0>; dma-names = "rx"; assigned-resolution-bits = <8>; @@ -371,7 +564,7 @@ index 8346bcb..c46598c 100644 }; Example to setup: -@@ -138,3 +179,22 @@ Example to setup: +@@ -138,3 +213,22 @@ Example to setup: st,adc-diff-channels = <2 6>, <3 7>; }; }; @@ -480,12 +673,74 @@ index 0000000..4494613 + 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..8e04895 +index 0000000..eb62238 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt -@@ -0,0 +1,53 @@ +@@ -0,0 +1,57 @@ +STMicroelectronics STM32MP1 Power Management Controller +======================================================= + @@ -500,6 +755,7 @@ index 0000000..8e04895 +- 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 @@ -519,6 +775,10 @@ index 0000000..8e04895 + 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>; + }; + @@ -534,14 +794,13 @@ index 0000000..8e04895 + linux,code = ; + interrupt-parent = <&pwr>; + interrupts = <3 IRQ_TYPE_EDGE_FALLING 1>; -+ status = "okay"; + 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..54b64e2 +index 0000000..0fab08a --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt @@ -0,0 +1,132 @@ @@ -551,7 +810,6 @@ index 0000000..54b64e2 +- compatible: "st,stpmic1" +- reg: The I2C slave address for the STPMIC1 chip. +- interrupts: The interrupt lines the device is connected to. -+ The second interrupt is used for wake-up. +- #interrupt-cells: Should be 2. +- interrupt-controller: Describes the STPMIC1 as an interrupt + controller (has its own domain). Interrupt number are the following: @@ -628,6 +886,7 @@ index 0000000..54b64e2 + -bit 5: SW_OUT discharge is enabled + -bit 6: VBUS_OTG detection is enabled + -bit 7: BOOST_OVP is disabled ++- wakeup-source: bool flag to indicate this device has wakeup capabilities + +STPMIC1 consists in a varied group of sub-devices. +Each sub-device binding is be described in own documentation file. @@ -711,14 +970,28 @@ index 0000000..f0c2f7f + }; + +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..6d3c626 100644 +index 03796cf..da6d59e 100644 --- a/Documentation/devicetree/bindings/mmc/mmci.txt +++ b/Documentation/devicetree/bindings/mmc/mmci.txt -@@ -15,8 +15,11 @@ Required properties: +@@ -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 @@ -727,7 +1000,7 @@ index 03796cf..6d3c626 100644 - 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 +27,14 @@ Optional properties: +@@ -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. @@ -807,6 +1080,34 @@ index 0000000..70e76be + #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 @@ -844,6 +1145,138 @@ index 0000000..fbff52e + }; + ... + }; +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 @@ -967,15 +1400,16 @@ index 0000000..c1b4c18 + }; + } diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -index ef4f2ff..286c981 100644 +index ef4f2ff..1a5d1e2 100644 --- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -@@ -56,6 +56,8 @@ Optional properties: +@@ -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 @@ -1007,10 +1441,10 @@ index bd23302..6521bc4 100644 }; }; diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt -index 3e6d550..0e7a30b 100644 +index 3e6d550..f1620c1 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. +@@ -5,9 +5,12 @@ See ../mfd/stm32-timers.txt for details about the parent node. Required parameters: - compatible: Must be "st,stm32-pwm". @@ -1020,11 +1454,16 @@ index 3e6d550..0e7a30b 100644 + 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: -@@ -29,7 +30,8 @@ Example: + - 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>; @@ -1034,10 +1473,10 @@ index 3e6d550..0e7a30b 100644 }; 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..cee27d5 +index 0000000..12acf9d --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.txt -@@ -0,0 +1,31 @@ +@@ -0,0 +1,42 @@ +STM32MP1 POWER Regulators +------------------------- + @@ -1050,12 +1489,17 @@ index 0000000..cee27d5 +- 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"; @@ -1068,6 +1512,12 @@ index 0000000..cee27d5 + 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 @@ -1145,10 +1595,10 @@ index 0000000..a3f4762 +}; diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt new file mode 100644 -index 0000000..dce10c0 +index 0000000..19a5255 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -@@ -0,0 +1,57 @@ +@@ -0,0 +1,61 @@ +Remoteproc System Resource Manager +---------------------------------- + @@ -1174,12 +1624,16 @@ index 0000000..dce10c0 +- clocks: clocks required by the coprocessor +- clock-names: see clock-bindings.txt +- pinctrl-x: pins configurations required by the coprocessor -+- pinctrl-names: see pinctrl-bindings.txt. -+ "rproc_default" is a special pin configuration which is applied except -+ if the 'early-booted' property is set. -+ In a general way, it is recommended to use names prefixed with "rproc_". ++ The SRM reserves the pins for the coprocessor, which prevents the local ++ processor to use them. ++- pinctrl-names: all names must be prefixed with "rproc_" (ex: "rproc_default"). ++ This rule must be strictly followed in order to prevent the SRM to ++ (over)write a pin configuration which is done by the coprocessor. +- x-supply: power supplies required by the coprocessor -+- interrupts: see interrupts.txt ++- 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 + @@ -1208,10 +1662,10 @@ index 0000000..dce10c0 + }; diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt new file mode 100644 -index 0000000..ee00f1c +index 0000000..957adcd --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -@@ -0,0 +1,78 @@ +@@ -0,0 +1,80 @@ +STMicroelectronics STM32 Remoteproc +----------------------------------- +This document defines the binding for the remoteproc component that loads and @@ -1219,10 +1673,12 @@ index 0000000..ee00f1c + +Required properties: +- compatible: Must be "st,stm32mp1-rproc" -+- reg: Should contain the address ranges for specific internal memory -+ regions. -+- reg-names: Should contain the corresponding names for specific internal -+ memory regions. ++- 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 @@ -1240,6 +1696,9 @@ index 0000000..ee00f1c +- 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. @@ -1247,18 +1706,15 @@ index 0000000..ee00f1c + - 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 for two different purposes: -+ - used by the remote proc to signal when it has completed -+ its critical initalisation. -+ Mono-directional channel: from remote to local -+ - 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 ++ - 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 "init_shdn" for channel (c) ++ - 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 @@ -1319,10 +1775,10 @@ index 130ca5b..bab0df8 100644 + 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..90ba52f 100644 +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,48 @@ Required properties: +@@ -10,15 +10,49 @@ Required properties: - interrupts: - The interrupt line for the USART instance, - An optional wake-up interrupt. @@ -1331,6 +1787,7 @@ index 9d3efed..90ba52f 100644 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. @@ -1372,7 +1829,7 @@ index 9d3efed..90ba52f 100644 Examples: usart4: serial@40004c00 { -@@ -26,8 +59,11 @@ usart4: serial@40004c00 { +@@ -26,8 +60,11 @@ usart4: serial@40004c00 { reg = <0x40004c00 0x400>; interrupts = <52>; clocks = <&clk_pclk1>; @@ -1385,12 +1842,57 @@ index 9d3efed..90ba52f 100644 }; 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..adeeb63 +index 0000000..bfc038b --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-stm32-qspi.txt -@@ -0,0 +1,44 @@ +@@ -0,0 +1,47 @@ +* STMicroelectronics Quad Serial Peripheral Interface(QSPI) + +Required properties: @@ -1412,8 +1914,11 @@ index 0000000..adeeb63 +- reg: chip-Select number (QSPI controller may connect 2 flashes) +- spi-max-frequency: max frequency of spi bus + -+Optional property: ++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: + @@ -1435,6 +1940,161 @@ index 0000000..adeeb63 + ... + }; +}; +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 @@ -1453,23 +2113,38 @@ index 0000000..7cc1407 + compatible = "st,stpmic1-wdt"; +}; diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index b5bd3de..b264fa0 100644 +index b5bd3de..5665290 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -922,6 +922,8 @@ dtb-$(CONFIG_ARCH_STM32) += \ +@@ -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.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..4409db2 100644 +index c485127..dd796ec 100644 --- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -@@ -24,8 +24,7 @@ +@@ -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"; @@ -1479,7 +2154,7 @@ index c485127..4409db2 100644 }; gpiob: gpio@50003000 { -@@ -36,8 +35,7 @@ +@@ -36,8 +36,7 @@ reg = <0x1000 0x400>; clocks = <&rcc GPIOB>; st,bank-name = "GPIOB"; @@ -1489,7 +2164,7 @@ index c485127..4409db2 100644 }; gpioc: gpio@50004000 { -@@ -48,8 +46,7 @@ +@@ -48,8 +47,7 @@ reg = <0x2000 0x400>; clocks = <&rcc GPIOC>; st,bank-name = "GPIOC"; @@ -1499,7 +2174,7 @@ index c485127..4409db2 100644 }; gpiod: gpio@50005000 { -@@ -60,8 +57,7 @@ +@@ -60,8 +58,7 @@ reg = <0x3000 0x400>; clocks = <&rcc GPIOD>; st,bank-name = "GPIOD"; @@ -1509,7 +2184,7 @@ index c485127..4409db2 100644 }; gpioe: gpio@50006000 { -@@ -72,8 +68,7 @@ +@@ -72,8 +69,7 @@ reg = <0x4000 0x400>; clocks = <&rcc GPIOE>; st,bank-name = "GPIOE"; @@ -1519,7 +2194,7 @@ index c485127..4409db2 100644 }; gpiof: gpio@50007000 { -@@ -84,8 +79,7 @@ +@@ -84,8 +80,7 @@ reg = <0x5000 0x400>; clocks = <&rcc GPIOF>; st,bank-name = "GPIOF"; @@ -1529,7 +2204,7 @@ index c485127..4409db2 100644 }; gpiog: gpio@50008000 { -@@ -96,8 +90,7 @@ +@@ -96,8 +91,7 @@ reg = <0x6000 0x400>; clocks = <&rcc GPIOG>; st,bank-name = "GPIOG"; @@ -1539,7 +2214,7 @@ index c485127..4409db2 100644 }; gpioh: gpio@50009000 { -@@ -108,8 +101,7 @@ +@@ -108,8 +102,7 @@ reg = <0x7000 0x400>; clocks = <&rcc GPIOH>; st,bank-name = "GPIOH"; @@ -1549,7 +2224,7 @@ index c485127..4409db2 100644 }; gpioi: gpio@5000a000 { -@@ -120,8 +112,7 @@ +@@ -120,8 +113,7 @@ reg = <0x8000 0x400>; clocks = <&rcc GPIOI>; st,bank-name = "GPIOI"; @@ -1559,7 +2234,7 @@ index c485127..4409db2 100644 }; gpioj: gpio@5000b000 { -@@ -132,8 +123,7 @@ +@@ -132,8 +124,7 @@ reg = <0x9000 0x400>; clocks = <&rcc GPIOJ>; st,bank-name = "GPIOJ"; @@ -1569,7 +2244,7 @@ index c485127..4409db2 100644 }; gpiok: gpio@5000c000 { -@@ -144,8 +134,29 @@ +@@ -144,8 +135,29 @@ reg = <0xa000 0x400>; clocks = <&rcc GPIOK>; st,bank-name = "GPIOK"; @@ -1601,10 +2276,31 @@ index c485127..4409db2 100644 }; cec_pins_a: cec-0 { -@@ -157,6 +168,57 @@ +@@ -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 = ; @@ -1617,12 +2313,53 @@ index c485127..4409db2 100644 + }; + }; + ++ dcmi_pins_a: dcmi-0 { ++ pins { ++ pinmux = ,/* DCMI_HSYNC */ ++ ,/* DCMI_VSYNC */ ++ ,/* DCMI_PIXCLK */ ++ ,/* DCMI_D0 */ ++ ,/* DCMI_D1 */ ++ ,/* DCMI_D2 */ ++ ,/* DCMI_D3 */ ++ ,/* DCMI_D4 */ ++ ,/* DCMI_D5 */ ++ ,/* DCMI_D6 */ ++ ,/* DCMI_D7 */ ++ ,/* DCMI_D8 */ ++ ,/* DCMI_D9 */ ++ ,/* DCMI_D10 */ ++ ;/* DCMI_D11 */ ++ bias-disable; ++ }; ++ }; ++ ++ dcmi_sleep_pins_a: dcmi-sleep-0 { ++ pins { ++ pinmux = ,/* DCMI_HSYNC */ ++ ,/* DCMI_VSYNC */ ++ ,/* DCMI_PIXCLK */ ++ ,/* DCMI_D0 */ ++ ,/* DCMI_D1 */ ++ ,/* DCMI_D2 */ ++ ,/* DCMI_D3 */ ++ ,/* DCMI_D4 */ ++ ,/* DCMI_D5 */ ++ ,/* DCMI_D6 */ ++ ,/* DCMI_D7 */ ++ ,/* DCMI_D8 */ ++ ,/* DCMI_D9 */ ++ ,/* DCMI_D10 */ ++ ;/* DCMI_D11 */ ++ }; ++ }; ++ + dfsdm_clkout_pins_a: dfsdm-clkout-pins-0 { + pins { + pinmux = ; /* DFSDM_CKOUT */ + bias-disable; + drive-push-pull; -+ slew-rate = <1>; ++ slew-rate = <0>; + }; + }; + @@ -1659,7 +2396,28 @@ index c485127..4409db2 100644 ethernet0_rgmii_pins_a: rgmii-0 { pins1 { pinmux = , /* ETH_RGMII_CLK125 */ -@@ -203,6 +265,50 @@ +@@ -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 @@ }; }; @@ -1680,7 +2438,7 @@ index c485127..4409db2 100644 + ; /* FMC_NE2_FMC_NCE */ + bias-disable; + drive-push-pull; -+ slew-rate = <2>; ++ slew-rate = <1>; + }; + pins2 { + pinmux = ; /* FMC_NWAIT */ @@ -1706,11 +2464,56 @@ index c485127..4409db2 100644 + ; /* 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 +319,13 @@ +@@ -213,6 +432,13 @@ }; }; @@ -1724,7 +2527,7 @@ index c485127..4409db2 100644 i2c2_pins_a: i2c2-0 { pins { pinmux = , /* I2C2_SCL */ -@@ -223,6 +336,13 @@ +@@ -223,6 +449,13 @@ }; }; @@ -1738,7 +2541,7 @@ index c485127..4409db2 100644 i2c5_pins_a: i2c5-0 { pins { pinmux = , /* I2C5_SCL */ -@@ -233,6 +353,14 @@ +@@ -233,10 +466,175 @@ }; }; @@ -1749,11 +2552,173 @@ index c485127..4409db2 100644 + + }; + }; ++ ++ 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 */ -@@ -246,6 +374,32 @@ +- slew-rate = <1>; ++ slew-rate = <0>; + drive-push-pull; + bias-disable; + }; +@@ -246,6 +644,32 @@ }; }; @@ -1786,7 +2751,7 @@ index c485127..4409db2 100644 pwm2_pins_a: pwm2-0 { pins { pinmux = ; /* TIM2_CH4 */ -@@ -255,6 +409,74 @@ +@@ -255,6 +679,74 @@ }; }; @@ -1861,7 +2826,7 @@ index c485127..4409db2 100644 pwm8_pins_a: pwm8-0 { pins { pinmux = ; /* TIM8_CH4 */ -@@ -264,6 +486,12 @@ +@@ -264,6 +756,12 @@ }; }; @@ -1874,36 +2839,37 @@ index c485127..4409db2 100644 pwm12_pins_a: pwm12-0 { pins { pinmux = ; /* TIM12_CH1 */ -@@ -273,6 +501,12 @@ +@@ -273,12 +771,9 @@ }; }; +- qspi_clk_pins_a: qspi-clk-0 { + pwm12_sleep_pins_a: pwm12-sleep-0 { -+ pins { -+ pinmux = ; /* TIM12_CH1 */ -+ }; -+ }; -+ - qspi_clk_pins_a: qspi-clk-0 { pins { - pinmux = ; /* QSPI_CLK */ -@@ -282,6 +516,12 @@ +- pinmux = ; /* QSPI_CLK */ +- bias-disable; +- drive-push-pull; +- slew-rate = <3>; ++ pinmux = ; /* TIM12_CH1 */ }; }; -+ qspi_clk_sleep_pins_a: qspi-clk-sleep-0 { -+ pins { -+ pinmux = ; /* QSPI_CLK */ +@@ -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_pins_a: qspi-bk1-0 { - pins1 { - pinmux = , /* QSPI_BK1_IO0 */ -@@ -300,6 +540,16 @@ - }; - }; - + qspi_bk1_sleep_pins_a: qspi-bk1-sleep-0 { + pins { + pinmux = , /* QSPI_BK1_IO0 */ @@ -1911,16 +2877,29 @@ index c485127..4409db2 100644 + , /* QSPI_BK1_IO2 */ + , /* QSPI_BK1_IO3 */ + ; /* QSPI_BK1_NCS */ -+ }; -+ }; -+ - qspi_bk2_pins_a: qspi-bk2-0 { - pins1 { - pinmux = , /* QSPI_BK2_IO0 */ -@@ -318,6 +568,180 @@ }; }; +@@ -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 */ @@ -1931,21 +2910,114 @@ index c485127..4409db2 100644 + }; + }; + ++ 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 */ + }; + }; + -+ sdmmc1_b4_pins_a: sdmmc1-b4-0 { ++ 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_CK */ + ; /* SDMMC1_CMD */ -+ slew-rate = <3>; ++ slew-rate = <1>; ++ drive-push-pull; ++ bias-disable; ++ }; ++ pins2 { ++ pinmux = ; /* SDMMC1_CK */ ++ slew-rate = <2>; + drive-push-pull; + bias-disable; + }; @@ -1956,15 +3028,20 @@ index c485127..4409db2 100644 + pinmux = , /* SDMMC1_D0 */ + , /* SDMMC1_D1 */ + , /* SDMMC1_D2 */ -+ , /* SDMMC1_D3 */ -+ ; /* SDMMC1_CK */ -+ slew-rate = <3>; ++ ; /* 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 = <3>; ++ slew-rate = <1>; + drive-open-drain; + bias-disable; + }; @@ -1986,7 +3063,7 @@ index c485127..4409db2 100644 + pinmux = , /* SDMMC1_D0DIR */ + , /* SDMMC1_D123DIR */ + ; /* SDMMC1_CDIR */ -+ slew-rate = <3>; ++ slew-rate = <1>; + drive-push-pull; + bias-pull-up; + }; @@ -2006,14 +3083,19 @@ index c485127..4409db2 100644 + }; + + sdmmc2_b4_pins_a: sdmmc2-b4-0 { -+ pins { ++ pins1 { + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ + , /* SDMMC2_D3 */ -+ , /* SDMMC2_CK */ + ; /* SDMMC2_CMD */ -+ slew-rate = <3>; ++ slew-rate = <1>; ++ drive-push-pull; ++ bias-pull-up; ++ }; ++ pins2 { ++ pinmux = ; /* SDMMC2_CK */ ++ slew-rate = <2>; + drive-push-pull; + bias-pull-up; + }; @@ -2024,15 +3106,20 @@ index c485127..4409db2 100644 + pinmux = , /* SDMMC2_D0 */ + , /* SDMMC2_D1 */ + , /* SDMMC2_D2 */ -+ , /* SDMMC2_D3 */ -+ ; /* SDMMC2_CK */ -+ slew-rate = <3>; ++ ; /* 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 = <3>; ++ slew-rate = <1>; + drive-open-drain; + bias-pull-up; + }; @@ -2049,13 +3136,56 @@ index c485127..4409db2 100644 + }; + }; + ++ 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 = <3>; ++ slew-rate = <1>; + drive-push-pull; + bias-pull-up; + }; @@ -2071,17 +3201,46 @@ index c485127..4409db2 100644 + }; + + sdmmc3_b4_pins_a: sdmmc3-b4-0 { -+ pins { ++ pins1 { + pinmux = , /* SDMMC3_D0 */ + , /* SDMMC3_D1 */ + , /* SDMMC3_D2 */ + , /* SDMMC3_D3 */ -+ , /* SDMMC3_CK */ + ; /* SDMMC3_CMD */ -+ slew-rate = <3>; ++ 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 { @@ -2095,10 +3254,80 @@ index c485127..4409db2 100644 + }; + }; + - uart4_pins_a: uart4-0 { - pins1 { - pinmux = ; /* UART4_TX */ -@@ -330,6 +754,131 @@ ++ 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; }; }; @@ -2120,13 +3349,43 @@ index c485127..4409db2 100644 + }; + }; + ++ 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 = <3>; ++ slew-rate = <0>; + }; + pins2 { + pinmux = , /* USART2_RX */ @@ -2226,11 +3485,32 @@ index c485127..4409db2 100644 + , /* 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 { -@@ -350,8 +899,7 @@ +@@ -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>; @@ -2240,7 +3520,7 @@ index c485127..4409db2 100644 }; i2c4_pins_a: i2c4-0 { -@@ -364,6 +912,13 @@ +@@ -364,6 +1457,13 @@ }; }; @@ -2254,12 +3534,27 @@ index c485127..4409db2 100644 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..866eed7 +index 0000000..2b01a01 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -0,0 +1,412 @@ +@@ -0,0 +1,756 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -2271,7 +3566,6 @@ index 0000000..866eed7 +#include "stm32mp157c.dtsi" +#include "stm32mp157c-m4-srm.dtsi" +#include "stm32mp157cac-pinctrl.dtsi" -+#include +#include +#include + @@ -2279,6 +3573,13 @@ index 0000000..866eed7 + 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"; + }; @@ -2292,20 +3593,46 @@ index 0000000..866eed7 + #size-cells = <1>; + ranges; + -+ ipc_share: sram_rproc@10040000 { ++ retram: retram@0x38000000 { + compatible = "shared-dma-pool"; -+ reg = <0x10040000 0x10000>; ++ reg = <0x38000000 0x10000>; + no-map; + }; -+ }; + -+ aliases { -+ serial0 = &uart4; -+ }; ++ mcuram: mcuram@0x30000000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x30000000 0x40000>; ++ no-map; ++ }; + -+ iio-hwmon { -+ compatible = "iio-hwmon"; -+ io-channels = <&adc_temp>; ++ 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 { @@ -2330,13 +3657,37 @@ index 0000000..866eed7 + default-state = "off"; + }; + }; ++ ++ sound { ++ compatible = "audio-graph-card"; ++ label = "STM32MP1-DK"; ++ routing = ++ "Playback" , "MCLK", ++ "Capture" , "MCLK", ++ "MICL" , "Mic Bias"; ++ dais = <&sai2a_port &sai2b_port &i2s2_port>; ++ status = "okay"; ++ }; ++ ++ usb_phy_tuning: usb-phy-tuning { ++ st,hs-dc-level = <2>; ++ st,fs-rftime-tuning; ++ st,hs-rftime-reduction; ++ st,hs-current-trim = <15>; ++ st,hs-impedance-trim = <1>; ++ st,squelch-level = <3>; ++ st,hs-rx-offset = <2>; ++ st,no-lsfs-sc; ++ }; +}; + +&adc { + pinctrl-names = "default"; -+ pinctrl-0 = <&adc12_usb_pwr_pins_a>; ++ pinctrl-0 = <&adc12_ain_pins_a>, <&adc12_usb_pwr_pins_a>; ++ vdd-supply = <&vdd>; ++ vdda-supply = <&vdd>; + vref-supply = <&vrefbuf>; -+ status = "okay"; ++ status = "disabled"; + adc1: adc@0 { + /* + * Type-C USB_PWR_CC1 & USB_PWR_CC2 on in18 & in19. @@ -2345,13 +3696,13 @@ index 0000000..866eed7 + * Use arbitrary margin here (e.g. 5µs). + */ + st,min-sample-time-nsecs = <5000>; -+ /* ANA0, ANA1, USB Type-C CC1 & CC2 */ -+ st,adc-channels = <0 1 18 19>; ++ /* AIN connector, USB Type-C CC1 & CC2 */ ++ st,adc-channels = <0 1 6 13 18 19>; + status = "okay"; + }; + adc2: adc@100 { -+ /* ANA0, ANA1, temp sensor, USB Type-C CC1 & CC2 */ -+ st,adc-channels = <0 1 12 18 19>; ++ /* AIN connector, temp sensor, USB Type-C CC1 & CC2 */ ++ st,adc-channels = <0 1 2 6 12 18 19>; + /* temperature sensor min sample time */ + st,min-sample-time-nsecs = <10000>; + status = "okay"; @@ -2361,6 +3712,13 @@ index 0000000..866eed7 + }; +}; + ++&cec { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&cec_pins_b>; ++ pinctrl-1 = <&cec_pins_sleep_b>; ++ status = "okay"; ++}; ++ +&dma1 { + sram = <&dma_pool>; +}; @@ -2369,6 +3727,34 @@ index 0000000..866eed7 + 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>; @@ -2378,6 +3764,75 @@ index 0000000..866eed7 + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; ++ ++ cs42l51: cs42l51@4a { ++ compatible = "cirrus,cs42l51"; ++ reg = <0x4a>; ++ #sound-dai-cells = <0>; ++ status = "okay"; ++ ++ VL-supply = <&v3v3>; ++ VD-supply = <&v1v8_audio>; ++ VA-supply = <&v1v8_audio>; ++ VAHP-supply = <&v1v8_audio>; ++ ++ reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>; ++ ++ clocks = <&sai2a>; ++ clock-names = "MCLK"; ++ ++ cs42l51_port: port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cs42l51_tx_endpoint: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&sai2a_endpoint>; ++ frame-master; ++ bitclock-master; ++ }; ++ ++ cs42l51_rx_endpoint: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&sai2b_endpoint>; ++ frame-master; ++ bitclock-master; ++ }; ++ }; ++ }; ++ ++ hdmi-transmitter@39 { ++ compatible = "sil,sii9022"; ++ reg = <0x39>; ++ iovcc-supply = <&v3v3_hdmi>; ++ cvcc12-supply = <&v1v2_hdmi>; ++ reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>; ++ interrupts = <1 IRQ_TYPE_EDGE_FALLING>; ++ interrupt-parent = <&gpiog>; ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <<dc_pins_a>; ++ pinctrl-1 = <<dc_pins_sleep_a>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ sii9022_in: endpoint { ++ remote-endpoint = <<dc_ep0_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ sii9022_tx_endpoint: endpoint { ++ remote-endpoint = <&i2s2_endpoint>; ++ }; ++ }; ++ }; ++ }; +}; + +&i2c4 { @@ -2390,18 +3845,34 @@ index 0000000..866eed7 + /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 = <&pwr 0 IRQ_TYPE_EDGE_FALLING 1>, -+ <&exti 55 1>; ++ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; + + st,main-control-register = <0x04>; + st,vin-control-register = <0xc0>; -+ st,usb-control-register = <0x30>; ++ st,usb-control-register = <0x20>; + + regulators { + compatible = "st,stpmic1-regulators"; @@ -2414,7 +3885,7 @@ index 0000000..866eed7 + + vddcore: buck1 { + regulator-name = "vddcore"; -+ regulator-min-microvolt = <800000>; ++ regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; @@ -2436,7 +3907,7 @@ index 0000000..866eed7 + regulator-max-microvolt = <3300000>; + regulator-always-on; + st,mask-reset; -+ regulator-initial-mode = <2>; ++ regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + @@ -2446,7 +3917,7 @@ index 0000000..866eed7 + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-over-current-protection; -+ regulator-initial-mode = <2>; ++ regulator-initial-mode = <0>; + }; + + v1v8_audio: ldo1 { @@ -2532,6 +4003,33 @@ index 0000000..866eed7 + + 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>; + }; + }; +}; @@ -2545,17 +4043,40 @@ index 0000000..866eed7 + 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 = <&ipc_share>; ++ memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, ++ <&vdev0vring1>, <&vdev0buffer>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; -+ mbox-names = "vq0", "vq1", "init_shdn"; ++ 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"; +}; @@ -2564,22 +4085,94 @@ index 0000000..866eed7 + 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,negedge; ++ 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>; @@ -2594,6 +4187,7 @@ index 0000000..866eed7 +&timers3 { + /delete-property/dmas; + /delete-property/dma-names; ++ status = "disabled"; + pwm { + pinctrl-0 = <&pwm3_pins_a>; + pinctrl-1 = <&pwm3_sleep_pins_a>; @@ -2608,6 +4202,7 @@ index 0000000..866eed7 +&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>; @@ -2622,6 +4217,7 @@ index 0000000..866eed7 +&timers5 { + /delete-property/dmas; + /delete-property/dma-names; ++ status = "disabled"; + pwm { + pinctrl-0 = <&pwm5_pins_a>; + pinctrl-1 = <&pwm5_sleep_pins_a>; @@ -2646,6 +4242,7 @@ index 0000000..866eed7 +&timers12 { + /delete-property/dmas; + /delete-property/dma-names; ++ status = "disabled"; + pwm { + pinctrl-0 = <&pwm12_pins_a>; + pinctrl-1 = <&pwm12_sleep_pins_a>; @@ -2666,18 +4263,243 @@ index 0000000..866eed7 + status = "okay"; +}; + ++&uart7 { ++ pinctrl-names = "default", "sleep", "idle"; ++ pinctrl-0 = <&uart7_pins_a>; ++ pinctrl-1 = <&uart7_sleep_pins_a>; ++ pinctrl-2 = <&uart7_idle_pins_a>; ++ status = "disabled"; ++}; ++ ++&usart3 { ++ pinctrl-names = "default", "sleep", "idle"; ++ pinctrl-0 = <&usart3_pins_b>; ++ pinctrl-1 = <&usart3_sleep_pins_b>; ++ pinctrl-2 = <&usart3_idle_pins_b>; ++ status = "disabled"; ++}; ++ ++&usbh_ehci { ++ phys = <&usbphyc_port0>; ++ phy-names = "usb"; ++ status = "okay"; ++}; ++ ++&usbotg_hs { ++ 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..15c0c91 +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts +@@ -0,0 +1,157 @@ ++// 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 = "rproc_default"; ++ pinctrl-0 = <&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 = "rproc_default", "rproc_sleep"; ++ pinctrl-0 = <&leds_orange_pins>; ++ pinctrl-1 = <&leds_orange_sleep_pins>; ++ status = "okay"; ++ }; ++ }; ++}; ++ ++&m4_spi4 { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&spi4_pins_a>; ++ status = "okay"; ++}; ++ ++ ++&m4_timers2 { ++ pinctrl-names = "rproc_default"; ++ status = "okay"; ++}; ++ ++&m4_timers1 { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&timer1_pins>; ++ status = "okay"; ++}; ++ ++&m4_uart7 { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&uart7_pins>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ uart7_pins: uart7-test-0 { ++ pins1 { ++ pinmux = ; /* UART7_TX */ ++ bias-disable; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ pins2 { ++ pinmux = ; /* UART7_RX */ ++ bias-disable; ++ }; ++ }; ++ ++ timer1_pins: pwm1-test-0 { ++ pins { ++ pinmux = ; /* TIM1_CH1 */ ++ bias-pull-down; ++ drive-push-pull; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ leds_orange_pins: leds_orange_test-0 { ++ pins { ++ pinmux = ; ++ bias-pull-up; ++ drive-push-pull; ++ output-low; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ leds_orange_sleep_pins: leds_orange_sleep_test-0 { ++ 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..4175b65 +index 0000000..d11fbb8 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -0,0 +1,22 @@ +@@ -0,0 +1,145 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -2692,6 +4514,91 @@ index 0000000..4175b65 +/ { + 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@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>; ++ status = "okay"; ++ }; ++ touchscreen@38 { ++ compatible = "focaltech,ft6336"; ++ reg = <0x38>; ++ interrupts = <2 2>; ++ interrupt-parent = <&gpiof>; ++ interrupt-controller; ++ touchscreen-size-x = <480>; ++ touchscreen-size-y = <800>; ++ status = "okay"; ++ }; ++}; ++ ++<dc { ++ status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ltdc_ep1_out: endpoint@1 { ++ reg = <1>; ++ remote-endpoint = <&dsi_in>; ++ }; ++ }; +}; + +&rtc { @@ -2700,23 +4607,60 @@ index 0000000..4175b65 + 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..1b074e9 100644 +index f77bea4..c9eabc1 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts -@@ -6,7 +6,10 @@ +@@ -6,7 +6,9 @@ /dts-v1/; #include "stm32mp157c.dtsi" -#include "stm32mp157-pinctrl.dtsi" +#include "stm32mp157c-m4-srm.dtsi" +#include "stm32mp157caa-pinctrl.dtsi" -+#include +#include / { model = "STMicroelectronics STM32MP157C eval daughter"; -@@ -20,41 +23,251 @@ +@@ -20,41 +22,305 @@ reg = <0xC0000000 0x40000000>; }; @@ -2725,9 +4669,44 @@ index f77bea4..1b074e9 100644 + #size-cells = <1>; + ranges; + -+ ipc_share: sram_rproc@10040000 { ++ retram: retram@0x38000000 { + compatible = "shared-dma-pool"; -+ reg = <0x10040000 0x10000>; ++ 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; + }; + }; @@ -2742,17 +4721,6 @@ index f77bea4..1b074e9 100644 - regulator-min-microvolt = <1100000>; - regulator-max-microvolt = <1100000>; - regulator-always-on; -+ iio-hwmon { -+ compatible = "iio-hwmon"; -+ io-channels = <&adc_temp>; - }; - -- reg18: reg18 { -- compatible = "regulator-fixed"; -- regulator-name = "reg18"; -- regulator-min-microvolt = <1800000>; -- regulator-max-microvolt = <1800000>; -- regulator-always-on; + sram: sram@10050000 { + compatible = "mmio-sram"; + reg = <0x10050000 0x10000>; @@ -2766,12 +4734,9 @@ index f77bea4..1b074e9 100644 + }; }; -- vdd_usb: vdd-usb { +- reg18: reg18 { - compatible = "regulator-fixed"; -- regulator-name = "vdd_usb"; -- regulator-min-microvolt = <3300000>; -- regulator-max-microvolt = <3300000>; -- regulator-always-on; +- regulator-name = "reg18"; + led { + compatible = "gpio-leds"; + blue { @@ -2780,12 +4745,33 @@ index f77bea4..1b074e9 100644 + 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>; }; - }; ++}; --&i2c4 { +- 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 { @@ -2806,9 +4792,10 @@ index f77bea4..1b074e9 100644 + }; + adc_temp: temp { + status = "okay"; -+ }; -+}; -+ + }; + }; + +-&i2c4 { +&dac { pinctrl-names = "default"; + pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; @@ -2830,6 +4817,15 @@ index f77bea4..1b074e9 100644 + sram = <&dma_pool>; +}; + ++&dts { ++ status = "okay"; ++}; ++ ++&gpu { ++ contiguous-area = <&gpu_reserved>; ++ status = "okay"; ++}; ++ +&i2c4 { + pinctrl-names = "default", "sleep"; pinctrl-0 = <&i2c4_pins_a>; @@ -2843,15 +4839,14 @@ index f77bea4..1b074e9 100644 + pmic: stpmic@33 { + compatible = "st,stpmic1"; + reg = <0x33>; -+ interrupts-extended = <&pwr 0 IRQ_TYPE_EDGE_FALLING 1>, -+ <&exti 55 1>; ++ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; + + st,main-control-register = <0x04>; + st,vin-control-register = <0xc0>; -+ st,usb-control-register = <0x30>; ++ st,usb-control-register = <0x20>; + + regulators { + compatible = "st,stpmic1-regulators"; @@ -2866,7 +4861,7 @@ index f77bea4..1b074e9 100644 + + vddcore: buck1 { + regulator-name = "vddcore"; -+ regulator-min-microvolt = <800000>; ++ regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + regulator-initial-mode = <0>; @@ -2888,7 +4883,7 @@ index f77bea4..1b074e9 100644 + regulator-max-microvolt = <3300000>; + regulator-always-on; + st,mask-reset; -+ regulator-initial-mode = <2>; ++ regulator-initial-mode = <0>; + regulator-over-current-protection; + }; + @@ -2898,7 +4893,7 @@ index f77bea4..1b074e9 100644 + regulator-max-microvolt = <3300000>; + regulator-always-on; + regulator-over-current-protection; -+ regulator-initial-mode = <2>; ++ regulator-initial-mode = <0>; + }; + + vdda: ldo1 { @@ -2951,10 +4946,10 @@ index f77bea4..1b074e9 100644 + regulator-over-current-protection; + }; + -+ bst_out: boost { ++ bst_out: boost { + regulator-name = "bst_out"; + interrupts = ; -+ }; ++ }; + + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; @@ -2978,6 +4973,7 @@ index f77bea4..1b074e9 100644 + + watchdog { + compatible = "st,stpmic1-wdt"; ++ status = "disabled"; + }; + }; +}; @@ -2987,25 +4983,34 @@ index f77bea4..1b074e9 100644 }; &iwdg2 { -@@ -62,6 +275,17 @@ +@@ -62,6 +328,26 @@ status = "okay"; }; +&m4_rproc { -+ memory-region = <&ipc_share>; ++ memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, ++ <&vdev0vring1>, <&vdev0buffer>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; -+ mbox-names = "vq0", "vq1", "init_shdn"; ++ 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,16 +294,51 @@ +@@ -70,27 +356,65 @@ status = "okay"; }; @@ -3020,6 +5025,12 @@ index f77bea4..1b074e9 100644 + 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"; +}; + @@ -3031,10 +5042,11 @@ index f77bea4..1b074e9 100644 + non-removable; + no-sd; + no-sdio; -+ st,negedge; ++ st,neg-edge; + bus-width = <8>; + vmmc-supply = <&v3v3>; + vqmmc-supply = <&v3v3>; ++ mmc-ddr-3_3v; + status = "okay"; +}; + @@ -3058,19 +5070,242 @@ index f77bea4..1b074e9 100644 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..50c274f +--- /dev/null ++++ b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts +@@ -0,0 +1,162 @@ ++// 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 = "rproc_default"; ++ pinctrl-0 = <&i2c5_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_qspi { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &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 = "rproc_default", "rproc_sleep"; ++ pinctrl-0 = <&leds_orange_pins>; ++ pinctrl-1 = <&leds_orange_sleep_pins>; ++ status = "okay"; ++ }; ++ }; ++}; ++ ++&m4_rng2 { ++ status = "okay"; ++}; ++ ++&m4_spi1 { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&spi1_pins_a>; ++ status = "okay"; ++}; ++ ++ ++&m4_timers2 { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&pwm2_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_timers1 { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&pwm1_pins_a>; ++ status = "okay"; ++}; ++ ++&m4_usart3 { ++ pinctrl-names = "rproc_default"; ++ pinctrl-0 = <&usart3_pins_a>; ++ status = "okay"; ++}; ++ ++&pinctrl { ++ leds_orange_pins: leds_orange_test-0 { ++ pins { ++ pinmux = ; ++ bias-pull-up; ++ drive-push-pull; ++ output-low; ++ slew-rate = <0>; ++ }; ++ }; ++ ++ leds_orange_sleep_pins: leds_orange_sleep_test-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 372bc2e..fe59c6d 100644 +index 372bc2e..559b9b9 100644 --- a/arch/arm/boot/dts/stm32mp157c-ev1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts -@@ -6,6 +6,7 @@ +@@ -6,6 +6,8 @@ /dts-v1/; #include "stm32mp157c-ed1.dts" +#include ++#include / { model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; -@@ -16,9 +17,46 @@ +@@ -16,9 +18,327 @@ }; aliases { @@ -3079,6 +5314,14 @@ index 372bc2e..fe59c6d 100644 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>; @@ -3114,19 +5357,304 @@ index 372bc2e..fe59c6d 100644 + interrupt-parent = <&stmfx_pinctrl>; + interrupts = <4 IRQ_TYPE_EDGE_RISING>; + }; ++ }; ++ ++ panel_backlight: panel-backlight { ++ compatible = "gpio-backlight"; ++ gpios = <&gpiod 13 GPIO_ACTIVE_LOW>; ++ default-on; ++ status = "okay"; ++ }; ++ ++ spdif_out: spdif-out { ++ #sound-dai-cells = <0>; ++ compatible = "linux,spdif-dit"; ++ status = "okay"; ++ ++ spdif_out_port: port { ++ spdif_out_endpoint: endpoint { ++ remote-endpoint = <&sai4a_endpoint>; ++ }; ++ }; ++ }; ++ ++ spdif_in: spdif-in { ++ #sound-dai-cells = <0>; ++ compatible = "linux,spdif-dir"; ++ status = "okay"; ++ ++ spdif_in_port: port { ++ spdif_in_endpoint: endpoint { ++ remote-endpoint = <&spdifrx_endpoint>; ++ }; ++ }; ++ }; ++ ++ sound { ++ compatible = "audio-graph-card"; ++ label = "STM32MP1-EV"; ++ routing = ++ "AIF1CLK" , "MCLK1", ++ "AIF2CLK" , "MCLK1", ++ "IN1LN" , "MICBIAS2", ++ "DMIC2DAT" , "MICBIAS1", ++ "DMIC1DAT" , "MICBIAS1"; ++ dais = <&sai2a_port &sai2b_port &sai4a_port &spdifrx_port ++ &dfsdm0_port &dfsdm1_port &dfsdm2_port &dfsdm3_port>; ++ status = "okay"; ++ }; ++ ++ dmic0: dmic-0 { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <1>; ++ status = "okay"; ++ ++ port { ++ dmic0_endpoint: endpoint { ++ remote-endpoint = <&dfsdm_endpoint0>; ++ }; ++ }; ++ }; ++ ++ dmic1: dmic-1 { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <1>; ++ status = "okay"; ++ ++ port { ++ dmic1_endpoint: endpoint { ++ remote-endpoint = <&dfsdm_endpoint1>; ++ }; ++ }; ++ }; ++ ++ dmic2: dmic-2 { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <1>; ++ status = "okay"; ++ ++ port { ++ dmic2_endpoint: endpoint { ++ remote-endpoint = <&dfsdm_endpoint2>; ++ }; ++ }; ++ }; ++ ++ dmic3: dmic-3 { ++ compatible = "dmic-codec"; ++ #sound-dai-cells = <1>; ++ status = "okay"; ++ ++ port { ++ dmic3_endpoint: endpoint { ++ remote-endpoint = <&dfsdm_endpoint3>; ++ }; ++ }; ++ }; ++ ++ usb_phy_tuning: usb-phy-tuning { ++ st,hs-dc-level = <2>; ++ st,fs-rftime-tuning; ++ st,hs-rftime-reduction; ++ st,hs-current-trim = <15>; ++ st,hs-impedance-trim = <1>; ++ st,squelch-level = <3>; ++ st,hs-rx-offset = <2>; ++ st,no-lsfs-sc; ++ }; ++}; ++ ++&cec { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&cec_pins_a>; ++ pinctrl-1 = <&cec_pins_sleep_a>; ++}; ++ ++&dcmi { ++ status = "okay"; ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&dcmi_pins_a>; ++ pinctrl-1 = <&dcmi_sleep_pins_a>; ++ ++ port { ++ dcmi_0: endpoint { ++ remote-endpoint = <&ov5640_0>; ++ bus-width = <8>; ++ hsync-active = <0>; ++ vsync-active = <0>; ++ pclk-sample = <1>; ++ pclk-max-frequency = <77000000>; ++ }; ++ }; ++}; ++ ++&dfsdm { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&dfsdm_clkout_pins_a ++ &dfsdm_data1_pins_a &dfsdm_data3_pins_a>; ++ pinctrl-1 = <&dfsdm_clkout_sleep_pins_a ++ &dfsdm_data1_sleep_pins_a &dfsdm_data3_sleep_pins_a>; ++ spi-max-frequency = <2048000>; ++ ++ clocks = <&rcc DFSDM_K>, <&rcc ADFSDM_K>; ++ clock-names = "dfsdm", "audio"; ++ status = "okay"; ++ ++ dfsdm0: filter@0 { ++ compatible = "st,stm32-dfsdm-dmic"; ++ st,adc-channels = <3>; ++ st,adc-channel-names = "dmic_u1"; ++ st,adc-channel-types = "SPI_R"; ++ st,adc-channel-clk-src = "CLKOUT"; ++ st,filter-order = <3>; ++ status = "okay"; ++ ++ asoc_pdm0: dfsdm-dai { ++ compatible = "st,stm32h7-dfsdm-dai"; ++ #sound-dai-cells = <0>; ++ io-channels = <&dfsdm0 0>; ++ status = "okay"; ++ ++ dfsdm0_port: port { ++ dfsdm_endpoint0: endpoint { ++ remote-endpoint = <&dmic0_endpoint>; ++ }; ++ }; ++ }; ++ }; ++ ++ dfsdm1: filter@1 { ++ compatible = "st,stm32-dfsdm-dmic"; ++ st,adc-channels = <1>; ++ st,adc-channel-names = "dmic_u2"; ++ st,adc-channel-types = "SPI_F"; ++ st,adc-channel-clk-src = "CLKOUT"; ++ st,filter-order = <3>; ++ status = "okay"; ++ ++ asoc_pdm1: dfsdm-dai { ++ compatible = "st,stm32h7-dfsdm-dai"; ++ #sound-dai-cells = <0>; ++ io-channels = <&dfsdm1 0>; ++ status = "okay"; ++ ++ dfsdm1_port: port { ++ dfsdm_endpoint1: endpoint { ++ remote-endpoint = <&dmic1_endpoint>; ++ }; ++ }; ++ }; ++ }; ++ ++ dfsdm2: filter@2 { ++ compatible = "st,stm32-dfsdm-dmic"; ++ st,adc-channels = <3>; ++ st,adc-channel-names = "dmic_u3"; ++ st,adc-channel-types = "SPI_F"; ++ st,adc-channel-clk-src = "CLKOUT"; ++ st,filter-order = <3>; ++ status = "okay"; ++ ++ asoc_pdm2: dfsdm-dai { ++ compatible = "st,stm32h7-dfsdm-dai"; ++ #sound-dai-cells = <0>; ++ io-channels = <&dfsdm2 0>; ++ status = "okay"; ++ ++ dfsdm2_port: port { ++ dfsdm_endpoint2: endpoint { ++ remote-endpoint = <&dmic2_endpoint>; ++ }; ++ }; ++ }; ++ }; ++ ++ dfsdm3: filter@3 { ++ compatible = "st,stm32-dfsdm-dmic"; ++ st,adc-channels = <1>; ++ st,adc-channel-names = "dmic_u4"; ++ st,adc-channel-types = "SPI_R"; ++ st,adc-channel-clk-src = "CLKOUT"; ++ st,filter-order = <3>; ++ status = "okay"; ++ ++ asoc_pdm3: dfsdm-dai { ++ compatible = "st,stm32h7-dfsdm-dai"; ++ #sound-dai-cells = <0>; ++ io-channels = <&dfsdm3 0>; ++ status = "okay"; ++ ++ dfsdm3_port: port { ++ dfsdm_endpoint3: endpoint { ++ remote-endpoint = <&dmic3_endpoint>; ++ }; ++ }; ++ }; ++ }; ++}; ++ ++&dsi { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ dsi_in: endpoint { ++ remote-endpoint = <<dc_ep0_out>; ++ }; ++ }; ++ ++ port@1 { ++ reg = <1>; ++ dsi_out: endpoint { ++ remote-endpoint = <&dsi_panel_in>; ++ }; ++ }; ++ }; ++ ++ panel-dsi@0 { ++ compatible = "raydium,rm68200"; ++ reg = <0>; ++ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; ++ power-supply = <&v3v3>; ++ backlight = <&panel_backlight>; ++ status = "okay"; ++ ++ port { ++ dsi_panel_in: endpoint { ++ remote-endpoint = <&dsi_out>; ++ }; ++ }; + }; }; ðernet0 { -@@ -46,37 +84,85 @@ - status = "okay"; +@@ -26,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>; + +@@ -40,43 +360,200 @@ + }; }; +-&cec { +- pinctrl-names = "default"; +- pinctrl-0 = <&cec_pins_a>; +&fmc { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&fmc_pins_a>; + pinctrl-1 = <&fmc_sleep_pins_a>; -+ status = "okay"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + @@ -3138,6 +5666,17 @@ index 372bc2e..fe59c6d 100644 + }; +}; + ++&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"; @@ -3149,6 +5688,72 @@ index 372bc2e..fe59c6d 100644 + /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>; @@ -3163,13 +5768,38 @@ index 372bc2e..fe59c6d 100644 + 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"; -+ drive-push-pull; + bias-pull-down; + }; + }; ++ }; ++ ++ gt9147: goodix_ts@5d { ++ compatible = "goodix,gt9147"; ++ reg = <0x5d>; ++ status = "okay"; ++ ++ irq-gpios = <&stmfx_pinctrl 14 GPIO_ACTIVE_HIGH>; ++ irq-flags = ; ++ }; ++}; ++ ++&i2c4 { ++ pmic: stpmic@33 { ++ regulators { ++ v1v8: ldo6 { ++ regulator-enable-ramp-delay = <300000>; ++ }; ++ }; + }; }; @@ -3180,9 +5810,22 @@ index 372bc2e..fe59c6d 100644 + 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 { + status = "okay"; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ ltdc_ep0_out: endpoint@0 { ++ reg = <0>; ++ remote-endpoint = <&dsi_in>; ++ }; ++ }; }; &m_can1 { @@ -3208,7 +5851,7 @@ index 372bc2e..fe59c6d 100644 reg = <0>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; -@@ -85,6 +171,7 @@ +@@ -85,6 +562,7 @@ }; flash1: mx66l51235l@1 { @@ -3216,7 +5859,105 @@ index 372bc2e..fe59c6d 100644 reg = <1>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; -@@ -101,9 +188,13 @@ +@@ -93,17 +571,110 @@ + }; + }; + ++&sai2 { ++ clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_R>; ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&sai2a_pins_a>, <&sai2b_pins_a>; ++ pinctrl-1 = <&sai2a_sleep_pins_a>, <&sai2b_sleep_pins_a>; ++ clock-names = "pclk", "x8k", "x11k"; ++ status = "okay"; ++ ++ sai2a: audio-controller@4400b004 { ++ #clock-cells = <0>; ++ dma-names = "tx"; ++ clocks = <&rcc SAI2_K>; ++ clock-names = "sai_ck"; ++ status = "okay"; ++ ++ sai2a_port: port { ++ sai2a_endpoint: endpoint { ++ remote-endpoint = <&wm8994_tx_endpoint>; ++ format = "i2s"; ++ mclk-fs = <256>; ++ }; ++ }; ++ }; ++ ++ sai2b: audio-controller@4400b024 { ++ dma-names = "rx"; ++ clocks = <&rcc SAI2_K>, <&sai2a>; ++ clock-names = "sai_ck", "MCLK"; ++ status = "okay"; ++ ++ sai2b_port: port { ++ sai2b_endpoint: endpoint { ++ remote-endpoint = <&wm8994_rx_endpoint>; ++ format = "i2s"; ++ mclk-fs = <256>; ++ }; ++ }; ++ }; ++}; ++ ++&sai4 { ++ clocks = <&rcc SAI4>, <&rcc PLL3_Q>, <&rcc PLL3_R>; ++ clock-names = "pclk", "x8k", "x11k"; ++ status = "okay"; ++ ++ sai4a: audio-controller@50027004 { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&sai4a_pins_a>; ++ pinctrl-1 = <&sai4a_sleep_pins_a>; ++ dma-names = "tx"; ++ clocks = <&rcc SAI4_K>; ++ clock-names = "sai_ck"; ++ st,iec60958; ++ status = "okay"; ++ ++ sai4a_port: port { ++ sai4a_endpoint: endpoint { ++ remote-endpoint = <&spdif_out_endpoint>; ++ }; ++ }; ++ }; ++}; ++ ++&sdmmc3 { ++ pinctrl-names = "default", "opendrain", "sleep"; ++ pinctrl-0 = <&sdmmc3_b4_pins_a>; ++ pinctrl-1 = <&sdmmc3_b4_od_pins_a>; ++ pinctrl-2 = <&sdmmc3_b4_sleep_pins_a>; ++ vmmc-supply = <&v3v3>; ++ broken-cd; ++ st,neg-edge; ++ bus-width = <4>; ++ status = "disabled"; ++}; ++ ++&spdifrx { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&spdifrx_pins_a>; ++ pinctrl-1 = <&spdifrx_sleep_pins_a>; ++ status = "okay"; ++ ++ spdifrx_port: port { ++ spdifrx_endpoint: endpoint { ++ remote-endpoint = <&spdif_in_endpoint>; ++ }; ++ }; ++}; ++ + &spi1 { +- pinctrl-names = "default"; ++ pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spi1_pins_a>; ++ pinctrl-1 = <&spi1_sleep_pins_a>; + status = "disabled"; + }; &timers2 { status = "disabled"; @@ -3231,7 +5972,7 @@ index 372bc2e..fe59c6d 100644 status = "okay"; }; timer@1 { -@@ -113,9 +204,12 @@ +@@ -113,9 +684,12 @@ &timers8 { status = "disabled"; @@ -3245,7 +5986,7 @@ index 372bc2e..fe59c6d 100644 status = "okay"; }; timer@7 { -@@ -125,9 +219,12 @@ +@@ -125,9 +699,12 @@ &timers12 { status = "disabled"; @@ -3259,7 +6000,7 @@ index 372bc2e..fe59c6d 100644 status = "okay"; }; timer@11 { -@@ -135,6 +232,14 @@ +@@ -135,14 +712,24 @@ }; }; @@ -3274,9 +6015,32 @@ index 372bc2e..fe59c6d 100644 &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"; +@@ -151,3 +738,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..a1d132d0 +index 0000000..9ea9736 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi @@ -0,0 +1,436 @@ @@ -3287,106 +6051,106 @@ index 0000000..a1d132d0 + + m4_timers2: timer@40000000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40000000 0x400>; ++ reg = <0x40000000>; + clocks = <&rcc TIM2_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers3: timer@40001000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40001000 0x400>; ++ reg = <0x40001000>; + clocks = <&rcc TIM3_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers4: timer@40002000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40002000 0x400>; ++ reg = <0x40002000>; + clocks = <&rcc TIM4_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers5: timer@40003000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40003000 0x400>; ++ reg = <0x40003000>; + clocks = <&rcc TIM5_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers6: timer@40004000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40004000 0x400>; ++ reg = <0x40004000>; + clocks = <&rcc TIM6_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers7: timer@40005000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40005000 0x400>; ++ reg = <0x40005000>; + clocks = <&rcc TIM7_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers12: timer@40006000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40006000 0x400>; ++ reg = <0x40006000>; + clocks = <&rcc TIM12_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers13: timer@40007000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40007000 0x400>; ++ reg = <0x40007000>; + clocks = <&rcc TIM13_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers14: timer@40008000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40008000 0x400>; ++ reg = <0x40008000>; + clocks = <&rcc TIM14_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_lptimer1: timer@40009000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40009000 0x400>; ++ reg = <0x40009000>; + clocks = <&rcc LPTIM1_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_spi2: spi@4000b000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4000b000 0x400>; ++ reg = <0x4000b000>; + clocks = <&rcc SPI2_K>; + status = "disabled"; + }; + m4_i2s2: audio-controller@4000b000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4000b000 0x400>; ++ reg = <0x4000b000>; + status = "disabled"; + }; + m4_spi3: spi@4000c000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4000c000 0x400>; ++ reg = <0x4000c000>; + clocks = <&rcc SPI3_K>; + status = "disabled"; + }; + m4_i2s3: audio-controller@4000c000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4000c000 0x400>; ++ reg = <0x4000c000>; + status = "disabled"; + }; + m4_spdifrx: audio-controller@4000d000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4000d000 0x400>; ++ reg = <0x4000d000>; + clocks = <&rcc SPDIF_K>; + clock-names = "kclk"; + status = "disabled"; + }; + m4_usart2: serial@4000e000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4000e000 0x400>; ++ reg = <0x4000e000>; + interrupt-parent = <&exti>; + interrupts = <27 1>; + clocks = <&rcc USART2_K>; @@ -3394,7 +6158,7 @@ index 0000000..a1d132d0 + }; + m4_usart3: serial@4000f000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4000f000 0x400>; ++ reg = <0x4000f000>; + interrupt-parent = <&exti>; + interrupts = <28 1>; + clocks = <&rcc USART3_K>; @@ -3402,7 +6166,7 @@ index 0000000..a1d132d0 + }; + m4_uart4: serial@40010000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40010000 0x400>; ++ reg = <0x40010000>; + interrupt-parent = <&exti>; + interrupts = <30 1>; + clocks = <&rcc UART4_K>; @@ -3410,7 +6174,7 @@ index 0000000..a1d132d0 + }; + m4_uart5: serial@40011000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40011000 0x400>; ++ reg = <0x40011000>; + interrupt-parent = <&exti>; + interrupts = <31 1>; + clocks = <&rcc UART5_K>; @@ -3418,7 +6182,7 @@ index 0000000..a1d132d0 + }; + m4_i2c1: i2c@40012000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40012000 0x400>; ++ reg = <0x40012000>; + interrupt-parent = <&exti>; + interrupts = <21 1>; + clocks = <&rcc I2C1_K>; @@ -3426,7 +6190,7 @@ index 0000000..a1d132d0 + }; + m4_i2c2: i2c@40013000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40013000 0x400>; ++ reg = <0x40013000>; + interrupt-parent = <&exti>; + interrupts = <22 1>; + clocks = <&rcc I2C2_K>; @@ -3434,7 +6198,7 @@ index 0000000..a1d132d0 + }; + m4_i2c3: i2c@40014000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40014000 0x400>; ++ reg = <0x40014000>; + interrupt-parent = <&exti>; + interrupts = <23 1>; + clocks = <&rcc I2C3_K>; @@ -3442,7 +6206,7 @@ index 0000000..a1d132d0 + }; + m4_i2c5: i2c@40015000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40015000 0x400>; ++ reg = <0x40015000>; + interrupt-parent = <&exti>; + interrupts = <25 1>; + clocks = <&rcc I2C5_K>; @@ -3450,7 +6214,7 @@ index 0000000..a1d132d0 + }; + m4_cec: cec@40016000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40016000 0x400>; ++ reg = <0x40016000>; + interrupt-parent = <&exti>; + interrupts = <69 1>; + clocks = <&rcc CEC_K>, <&rcc CK_LSE>; @@ -3459,14 +6223,14 @@ index 0000000..a1d132d0 + }; + m4_dac: dac@40017000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40017000 0x400>; ++ reg = <0x40017000>; + clocks = <&rcc DAC12>; + clock-names = "pclk"; + status = "disabled"; + }; + m4_uart7: serial@40018000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40018000 0x400>; ++ reg = <0x40018000>; + interrupt-parent = <&exti>; + interrupts = <32 1>; + clocks = <&rcc UART7_K>; @@ -3474,7 +6238,7 @@ index 0000000..a1d132d0 + }; + m4_uart8: serial@40019000 { + compatible = "rproc-srm-dev"; -+ reg = <0x40019000 0x400>; ++ reg = <0x40019000>; + interrupt-parent = <&exti>; + interrupts = <33 1>; + clocks = <&rcc UART8_K>; @@ -3482,21 +6246,21 @@ index 0000000..a1d132d0 + }; + m4_timers1: timer@44000000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44000000 0x400>; ++ reg = <0x44000000>; + clocks = <&rcc TIM1_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers8: timer@44001000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44001000 0x400>; ++ reg = <0x44001000>; + clocks = <&rcc TIM8_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_usart6: serial@44003000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44003000 0x400>; ++ reg = <0x44003000>; + interrupt-parent = <&exti>; + interrupts = <29 1>; + clocks = <&rcc USART6_K>; @@ -3504,203 +6268,203 @@ index 0000000..a1d132d0 + }; + m4_spi1: spi@44004000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44004000 0x400>; ++ reg = <0x44004000>; + clocks = <&rcc SPI1_K>; + status = "disabled"; + }; + m4_i2s1: audio-controller@44004000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44004000 0x400>; ++ reg = <0x44004000>; + status = "disabled"; + }; + m4_spi4: spi@44005000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44005000 0x400>; ++ reg = <0x44005000>; + clocks = <&rcc SPI4_K>; + status = "disabled"; + }; + m4_timers15: timer@44006000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44006000 0x400>; ++ reg = <0x44006000>; + clocks = <&rcc TIM15_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers16: timer@44007000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44007000 0x400>; ++ reg = <0x44007000>; + clocks = <&rcc TIM16_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_timers17: timer@44008000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44008000 0x400>; ++ reg = <0x44008000>; + clocks = <&rcc TIM17_K>; + clock-names = "int"; + status = "disabled"; + }; + m4_spi5: spi@44009000 { + compatible = "rproc-srm-dev"; -+ reg = <0x44009000 0x400>; ++ reg = <0x44009000>; + clocks = <&rcc SPI5_K>; + status = "disabled"; + }; + m4_sai1: sai@4400a000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4400a000 0x4>; ++ reg = <0x4400a000>; + clocks = <&rcc SAI1_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_sai2: sai@4400b000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4400b000 0x4>; ++ reg = <0x4400b000>; + clocks = <&rcc SAI2_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_sai3: sai@4400c000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4400c000 0x4>; ++ reg = <0x4400c000>; + clocks = <&rcc SAI3_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_dfsdm: dfsdm@4400d000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4400d000 0x800>; ++ reg = <0x4400d000>; + clocks = <&rcc DFSDM_K>; + clock-names = "dfsdm"; + status = "disabled"; + }; + m4_m_can1: can@4400e000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4400e000 0x400>, <0x44011000 0x2800>; -+ clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ 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 0x400>, <0x44011000 0x2800>; -+ clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; ++ 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 0x400>; ++ reg = <0x48000000>; + clocks = <&rcc DMA1>; + status = "disabled"; + }; + m4_dma2: dma@48001000 { + compatible = "rproc-srm-dev"; -+ reg = <0x48001000 0x400>; ++ reg = <0x48001000>; + clocks = <&rcc DMA2>; + status = "disabled"; + }; + m4_dmamux1: dma-router@48002000 { + compatible = "rproc-srm-dev"; -+ reg = <0x48002000 0x1c>; ++ reg = <0x48002000>; + clocks = <&rcc DMAMUX>; + status = "disabled"; + }; + m4_adc: adc@48003000 { + compatible = "rproc-srm-dev"; -+ reg = <0x48003000 0x400>; ++ reg = <0x48003000>; + 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>; ++ reg = <0x48004000>, <0x48005000>; + clocks = <&rcc SDMMC3_K>; + status = "disabled"; + }; + m4_usbotg_hs: usb-otg@49000000 { + compatible = "rproc-srm-dev"; -+ reg = <0x49000000 0x10000>; ++ reg = <0x49000000>; + clocks = <&rcc USBO_K>; + clock-names = "otg"; + status = "disabled"; + }; + m4_hash2: hash@4c002000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4c002000 0x400>; ++ reg = <0x4c002000>; + clocks = <&rcc HASH2>; + status = "disabled"; + }; + m4_rng2: rng@4c003000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4c003000 0x400>; ++ reg = <0x4c003000>; + clocks = <&rcc RNG2_K>; + status = "disabled"; + }; + m4_crc2: crc@4c004000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4c004000 0x400>; ++ reg = <0x4c004000>; + clocks = <&rcc CRC2>; + status = "disabled"; + }; + m4_cryp2: cryp@4c005000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4c005000 0x400>; ++ reg = <0x4c005000>; + clocks = <&rcc CRYP2>; + status = "disabled"; + }; + m4_dcmi: dcmi@4c006000 { + compatible = "rproc-srm-dev"; -+ reg = <0x4c006000 0x400>; ++ reg = <0x4c006000>; + clocks = <&rcc DCMI>; + clock-names = "mclk"; + status = "disabled"; + }; + m4_lptimer2: timer@50021000 { + compatible = "rproc-srm-dev"; -+ reg = <0x50021000 0x400>; ++ reg = <0x50021000>; + clocks = <&rcc LPTIM2_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_lptimer3: timer@50022000 { + compatible = "rproc-srm-dev"; -+ reg = <0x50022000 0x400>; ++ reg = <0x50022000>; + clocks = <&rcc LPTIM3_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_lptimer4: timer@50023000 { + compatible = "rproc-srm-dev"; -+ reg = <0x50023000 0x400>; ++ reg = <0x50023000>; + clocks = <&rcc LPTIM4_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_lptimer5: timer@50024000 { + compatible = "rproc-srm-dev"; -+ reg = <0x50024000 0x400>; ++ reg = <0x50024000>; + clocks = <&rcc LPTIM5_K>; + clock-names = "mux"; + status = "disabled"; + }; + m4_sai4: sai@50027000 { + compatible = "rproc-srm-dev"; -+ reg = <0x50027000 0x4>; ++ reg = <0x50027000>; + clocks = <&rcc SAI4_K>; + clock-names = "sai_ck"; + status = "disabled"; + }; + m4_qspi: qspi@58003000 { + compatible = "rproc-srm-dev"; -+ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; ++ reg = <0x58003000>, <0x70000000>; + clocks = <&rcc QSPI_K>; + status = "disabled"; + }; + m4_ethernet0: ethernet@5800a000 { + compatible = "rproc-srm-dev"; -+ reg = <0x5800a000 0x2000>; ++ reg = <0x5800a000>; + clock-names = "stmmaceth", + "mac-clk-tx", + "mac-clk-rx", @@ -3717,12 +6481,40 @@ index 0000000..a1d132d0 +}; + diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index 185541a..b4bae4d 100644 +index 185541a..e8f995a 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -29,10 +29,8 @@ +@@ -5,6 +5,7 @@ + */ + #include + #include ++#include + #include + + / { +@@ -19,20 +20,28 @@ + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <0>; ++ clock-frequency = <650000000>; + }; + + cpu1: cpu@1 { + compatible = "arm,cortex-a7"; + device_type = "cpu"; + reg = <1>; ++ clock-frequency = <650000000>; + }; }; ++ arm-pmu { ++ compatible = "arm,cortex-a7-pmu"; ++ interrupts = , ++ ; ++ interrupt-affinity = <&cpu0>, <&cpu1>; ++ interrupt-parent = <&intc>; ++ }; ++ psci { - compatible = "arm,psci"; + compatible = "arm,psci-1.0"; @@ -3732,10 +6524,32 @@ index 185541a..b4bae4d 100644 }; intc: interrupt-controller@a0021000 { -@@ -84,6 +82,26 @@ - }; +@@ -50,6 +59,7 @@ + , + ; + interrupt-parent = <&intc>; ++ always-on; }; + clocks { +@@ -82,6 +92,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>; @@ -3756,10 +6570,57 @@ index 185541a..b4bae4d 100644 + }; + }; + ++ 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 { - compatible = "simple-bus"; - #address-cells = <1>; -@@ -98,6 +116,12 @@ +@@ -98,10 +189,17 @@ reg = <0x40000000 0x400>; clocks = <&rcc TIM2_K>; clock-names = "int"; @@ -3772,7 +6633,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -119,6 +143,13 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -119,10 +217,18 @@ reg = <0x40001000 0x400>; clocks = <&rcc TIM3_K>; clock-names = "int"; @@ -3786,7 +6652,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -140,6 +171,11 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -140,10 +246,16 @@ reg = <0x40002000 0x400>; clocks = <&rcc TIM4_K>; clock-names = "int"; @@ -3798,7 +6669,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -161,6 +197,13 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -161,10 +273,18 @@ reg = <0x40003000 0x400>; clocks = <&rcc TIM5_K>; clock-names = "int"; @@ -3812,7 +6688,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -182,6 +225,8 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -182,6 +302,8 @@ reg = <0x40004000 0x400>; clocks = <&rcc TIM6_K>; clock-names = "int"; @@ -3821,7 +6702,7 @@ index 185541a..b4bae4d 100644 status = "disabled"; timer@5 { -@@ -198,6 +243,8 @@ +@@ -198,6 +320,8 @@ reg = <0x40005000 0x400>; clocks = <&rcc TIM7_K>; clock-names = "int"; @@ -3830,7 +6711,31 @@ index 185541a..b4bae4d 100644 status = "disabled"; timer@6 { -@@ -277,6 +324,7 @@ +@@ -218,6 +342,7 @@ + + pwm { + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -239,6 +364,7 @@ + + pwm { + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -260,6 +386,7 @@ + + pwm { + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -277,6 +404,7 @@ reg = <0x40009000 0x400>; clocks = <&rcc LPTIM1_K>; clock-names = "mux"; @@ -3838,19 +6743,63 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -308,6 +356,7 @@ - dmas = <&dmamux1 39 0x400 0x05>, - <&dmamux1 40 0x400 0x05>; - dma-names = "rx", "tx"; +@@ -305,8 +433,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"; }; - -@@ -322,90 +371,131 @@ - dmas = <&dmamux1 61 0x400 0x05>, - <&dmamux1 62 0x400 0x05>; +@@ -319,93 +459,166 @@ + 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"; }; @@ -3862,6 +6811,7 @@ index 185541a..b4bae4d 100644 + interrupts-extended = <&intc GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>, + <&exti 27 1>; clocks = <&rcc USART2_K>; ++ resets = <&rcc USART2_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; @@ -3875,6 +6825,7 @@ index 185541a..b4bae4d 100644 + interrupts-extended = <&intc GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>, + <&exti 28 1>; clocks = <&rcc USART3_K>; ++ resets = <&rcc USART3_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; @@ -3888,6 +6839,7 @@ index 185541a..b4bae4d 100644 + interrupts-extended = <&intc GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>, + <&exti 30 1>; clocks = <&rcc UART4_K>; ++ resets = <&rcc UART4_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; @@ -3901,6 +6853,7 @@ index 185541a..b4bae4d 100644 + interrupts-extended = <&intc GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>, + <&exti 31 1>; clocks = <&rcc UART5_K>; ++ resets = <&rcc UART5_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; @@ -3925,6 +6878,7 @@ index 185541a..b4bae4d 100644 + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x1>; ++ st,syscfg-fmp-clr = <&syscfg 0x44 0x1>; status = "disabled"; }; @@ -3947,6 +6901,7 @@ index 185541a..b4bae4d 100644 + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x2>; ++ st,syscfg-fmp-clr = <&syscfg 0x44 0x2>; status = "disabled"; }; @@ -3969,6 +6924,7 @@ index 185541a..b4bae4d 100644 + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x4>; ++ st,syscfg-fmp-clr = <&syscfg 0x44 0x4>; status = "disabled"; }; @@ -3991,18 +6947,22 @@ index 185541a..b4bae4d 100644 + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x10>; ++ st,syscfg-fmp-clr = <&syscfg 0x44 0x10>; status = "disabled"; }; -@@ -415,6 +505,7 @@ +@@ -413,8 +626,9 @@ + compatible = "st,stm32-cec"; + reg = <0x40016000 0x400>; interrupts = ; - clocks = <&rcc CEC_K>, <&clk_lse>; +- 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 +536,24 @@ +@@ -445,16 +659,26 @@ uart7: serial@40018000 { compatible = "st,stm32h7-uart"; reg = <0x40018000 0x400>; @@ -4011,6 +6971,7 @@ index 185541a..b4bae4d 100644 + interrupts-extended = <&intc GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>, + <&exti 32 1>; clocks = <&rcc UART7_K>; ++ resets = <&rcc UART7_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; @@ -4024,12 +6985,13 @@ index 185541a..b4bae4d 100644 + interrupts-extended = <&intc GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>, + <&exti 33 1>; clocks = <&rcc UART8_K>; ++ resets = <&rcc UART8_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; -@@ -465,6 +564,15 @@ +@@ -465,10 +689,20 @@ reg = <0x44000000 0x400>; clocks = <&rcc TIM1_K>; clock-names = "int"; @@ -4045,7 +7007,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -486,6 +594,15 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -486,10 +720,20 @@ reg = <0x44001000 0x400>; clocks = <&rcc TIM8_K>; clock-names = "int"; @@ -4061,7 +7028,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -503,8 +620,12 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -503,8 +747,13 @@ usart6: serial@44003000 { compatible = "st,stm32h7-uart"; reg = <0x44003000 0x400>; @@ -4070,28 +7042,49 @@ index 185541a..b4bae4d 100644 + interrupts-extended = <&intc GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>, + <&exti 29 1>; clocks = <&rcc USART6_K>; ++ resets = <&rcc USART6_R>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; -@@ -519,6 +640,7 @@ - dmas = <&dmamux1 37 0x400 0x05>, - <&dmamux1 38 0x400 0x05>; +@@ -516,8 +765,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 +791,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"; }; -@@ -533,6 +655,7 @@ - dmas = <&dmamux1 83 0x400 0x05>, - <&dmamux1 84 0x400 0x05>; - dma-names = "rx", "tx"; -+ power-domains = <&pd_core>; - status = "disabled"; - }; - -@@ -543,6 +666,11 @@ +@@ -543,10 +805,16 @@ reg = <0x44006000 0x400>; clocks = <&rcc TIM15_K>; clock-names = "int"; @@ -4103,7 +7096,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -564,6 +692,9 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -564,10 +832,14 @@ reg = <0x44007000 0x400>; clocks = <&rcc TIM16_K>; clock-names = "int"; @@ -4113,7 +7111,12 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -584,6 +715,9 @@ + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + timer@15 { +@@ -584,10 +856,14 @@ reg = <0x44008000 0x400>; clocks = <&rcc TIM17_K>; clock-names = "int"; @@ -4123,15 +7126,120 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -609,6 +743,7 @@ - dmas = <&dmamux1 85 0x400 0x05>, - <&dmamux1 86 0x400 0x05>; + compatible = "st,stm32-pwm"; ++ #pwm-cells = <3>; + status = "disabled"; + }; + +@@ -606,10 +882,105 @@ + 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"; ++ }; }; -@@ -684,7 +819,7 @@ + dfsdm: dfsdm@4400d000 { +@@ -684,12 +1055,12 @@ m_can1: can@4400e000 { compatible = "bosch,m_can"; @@ -4140,16 +7248,29 @@ index 185541a..b4bae4d 100644 reg-names = "m_can", "message_ram"; interrupts = , ; -@@ -704,7 +839,7 @@ interrupt-names = "int0", "int1"; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; +- 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 +1073,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"; }; -@@ -723,6 +858,15 @@ +@@ -720,9 +1091,19 @@ + , + ; + clocks = <&rcc DMA1>; ++ resets = <&rcc DMA1_R>; #dma-cells = <4>; st,mem2mem; dma-requests = <8>; @@ -4165,7 +7286,11 @@ index 185541a..b4bae4d 100644 }; dma2: dma@48001000 { -@@ -740,6 +884,15 @@ +@@ -737,9 +1118,19 @@ + , + ; + clocks = <&rcc DMA2>; ++ resets = <&rcc DMA2_R>; #dma-cells = <4>; st,mem2mem; dma-requests = <8>; @@ -4181,9 +7306,40 @@ index 185541a..b4bae4d 100644 }; dmamux1: dma-router@48002000 { -@@ -784,10 +937,61 @@ +@@ -750,6 +1141,7 @@ + dma-masters = <&dma1 &dma2>; + dma-channels = <16>; + clocks = <&rcc DMAMUX>; ++ resets = <&rcc DMAMUX_R>; + }; + + adc: adc@48003000 { +@@ -760,6 +1152,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 +1167,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 +1178,117 @@ + reg = <0x100>; + interrupt-parent = <&adc>; interrupts = <1>; - dmas = <&dmamux1 10 0x400 0x01>; +- dmas = <&dmamux1 10 0x400 0x01>; ++ dmas = <&dmamux1 10 0x400 0x05>; dma-names = "rx"; + /* temperature sensor */ + st,adc-channels = <12>; @@ -4227,8 +7383,8 @@ index 185541a..b4bae4d 100644 + sdmmc3: sdmmc@48004000 { + compatible = "arm,pl18x", "arm,primecell"; -+ arm,primecell-periphid = <0x10153180>; -+ reg = <0x48004000 0x400>; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x48004000 0x400>, <0x48005000 0x400>; + interrupts = ; + interrupt-names = "cmd_irq"; + clocks = <&rcc SDMMC3_K>; @@ -4241,16 +7397,36 @@ index 185541a..b4bae4d 100644 + }; + usbotg_hs: usb-otg@49000000 { - compatible = "snps,dwc2"; +- compatible = "snps,dwc2"; ++ compatible = "st,stm32mp1-hsotg", "snps,dwc2"; reg = <0x49000000 0x10000>; -@@ -800,6 +1004,23 @@ + 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>; @@ -4264,15 +7440,26 @@ index 185541a..b4bae4d 100644 + 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 +1029,41 @@ +@@ -808,6 +1297,47 @@ reg = <0x50000000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; + interrupts = ; -+ st,pwr = <&pwr>; + }; + + pwr: pwr@50001000 { @@ -4284,6 +7471,13 @@ index 185541a..b4bae4d 100644 + 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>; @@ -4309,7 +7503,32 @@ index 185541a..b4bae4d 100644 }; exti: interrupt-controller@5000d000 { -@@ -829,6 +1085,7 @@ +@@ -815,11 +1345,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 +1372,7 @@ reg = <0x50021000 0x400>; clocks = <&rcc LPTIM2_K>; clock-names = "mux"; @@ -4317,7 +7536,7 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -856,6 +1113,7 @@ +@@ -856,6 +1400,7 @@ reg = <0x50022000 0x400>; clocks = <&rcc LPTIM3_K>; clock-names = "mux"; @@ -4325,7 +7544,7 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -876,6 +1134,7 @@ +@@ -876,6 +1421,7 @@ reg = <0x50023000 0x400>; clocks = <&rcc LPTIM4_K>; clock-names = "mux"; @@ -4333,7 +7552,7 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -890,6 +1149,7 @@ +@@ -890,6 +1436,7 @@ reg = <0x50024000 0x400>; clocks = <&rcc LPTIM5_K>; clock-names = "mux"; @@ -4341,20 +7560,211 @@ index 185541a..b4bae4d 100644 status = "disabled"; pwm { -@@ -923,7 +1183,7 @@ - interrupts = ; - clocks = <&rcc HASH1>; - resets = <&rcc HASH1_R>; -- dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0 0x0>; -+ dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0 0x0 0x0>; - dma-names = "in"; - dma-maxburst = <2>; +@@ -908,6 +1455,198 @@ status = "disabled"; -@@ -942,11 +1202,30 @@ + }; + ++ 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>; +@@ -942,21 +1681,74 @@ reg = <0x58000000 0x1000>; interrupts = ; clocks = <&rcc MDMA>; - #dma-cells = <5>; ++ resets = <&rcc MDMA_R>; + #dma-cells = <6>; dma-channels = <32>; dma-requests = <48>; @@ -4382,14 +7792,20 @@ index 185541a..b4bae4d 100644 qspi: qspi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; -@@ -957,6 +1236,36 @@ + reg-names = "qspi", "qspi_mm"; + interrupts = ; ++ dmas = <&mdma1 22 0x10 0x100002 0x0 0x0 0x0>, ++ <&mdma1 22 0x10 0x100008 0x0 0x0 0x0>; ++ dma-names = "tx", "rx"; + clocks = <&rcc QSPI_K>; + resets = <&rcc QSPI_R>; status = "disabled"; }; + sdmmc1: sdmmc@58005000 { + compatible = "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"; + clocks = <&rcc SDMMC1_K>; @@ -4403,8 +7819,8 @@ index 185541a..b4bae4d 100644 + + sdmmc2: sdmmc@58007000 { + compatible = "arm,pl18x", "arm,primecell"; -+ arm,primecell-periphid = <0x10153180>; -+ reg = <0x58007000 0x1000>; ++ arm,primecell-periphid = <0x00253180>; ++ reg = <0x58007000 0x1000>, <0x58008000 0x1000>; + interrupts = ; + interrupt-names = "cmd_irq"; + clocks = <&rcc SDMMC2_K>; @@ -4419,7 +7835,7 @@ index 185541a..b4bae4d 100644 crc1: crc@58009000 { compatible = "st,stm32f7-crc"; reg = <0x58009000 0x400>; -@@ -974,8 +1283,12 @@ +@@ -974,23 +1766,27 @@ compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; reg = <0x5800a000 0x2000>; reg-names = "stmmaceth"; @@ -4434,15 +7850,84 @@ index 185541a..b4bae4d 100644 clock-names = "stmmaceth", "mac-clk-tx", "mac-clk-rx", -@@ -991,6 +1304,7 @@ +- "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"; }; -@@ -1065,8 +1379,12 @@ +@@ -1008,8 +1804,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 +1830,7 @@ + clock-names = "pclk", "ref", "px_clk"; + resets = <&rcc DSI_R>; + reset-names = "apb"; ++ phy-dsi-supply = <®18>; + status = "disabled"; + }; + +@@ -1045,10 +1856,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 +1876,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>; @@ -4451,12 +7936,13 @@ index 185541a..b4bae4d 100644 + 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 +1396,29 @@ +@@ -1078,22 +1906,30 @@ interrupts = ; clocks = <&rcc SPI6_K>; resets = <&rcc SPI6_R>; @@ -4488,10 +7974,11 @@ index 185541a..b4bae4d 100644 + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x8>; ++ st,syscfg-fmp-clr = <&syscfg 0x44 0x8>; status = "disabled"; }; -@@ -1102,20 +1427,76 @@ +@@ -1102,21 +1938,88 @@ reg = <0x5c004000 0x400>; clocks = <&rcc RTCAPB>, <&rcc RTC>; clock-names = "pclk", "rtc_ck"; @@ -4533,8 +8020,9 @@ index 185541a..b4bae4d 100644 + dma-names = "rx", "tx"; + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x20>; -+ status = "disabled"; -+ }; ++ st,syscfg-fmp-clr = <&syscfg 0x44 0x20>; + status = "disabled"; + }; + + tamp: tamp@5c00a000 { + compatible = "simple-bus", "syscon", "simple-mfd"; @@ -4557,9 +8045,12 @@ index 185541a..b4bae4d 100644 + + m4_rproc: m4@0 { + compatible = "st,stm32mp1-rproc"; -+ reg = <0x38000000 0x10000>, -+ <0x10000000 0x40000>; -+ reg-names = "retram", "mcusram"; ++ #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>; @@ -4569,9 +8060,17 @@ index 185541a..b4bae4d 100644 + + m4_system_resources { + compatible = "rproc-srm-core"; - status = "disabled"; - }; ++ 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 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0017-ARM-stm32mp1-r0-rc1-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0030-ARM-stm32mp1-r2-DEFCONFIG.patch similarity index 81% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0017-ARM-stm32mp1-r0-rc1-DEFCONFIG.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0030-ARM-stm32mp1-r2-DEFCONFIG.patch index 481d7fb..a249780 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0017-ARM-stm32mp1-r0-rc1-DEFCONFIG.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0030-ARM-stm32mp1-r2-DEFCONFIG.patch @@ -1,12 +1,13 @@ -From ae7d85a994c77d68e3e6a20a24160a5010ba42cc Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:32:03 +0100 -Subject: [PATCH 17/52] ARM: stm32mp1-r0-rc1: DEFCONFIG +From 8352ebfd1953c5dc6514c0be878f7c8a47e33fa7 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Thu, 11 Jul 2019 14:12:10 +0200 +Subject: [PATCH 30/30] ARM stm32mp1 r2 DEFCONFIG --- .../arm/configs/fragment-01-multiv7_cleanup.config | 69 +++ - arch/arm/configs/fragment-02-multiv7_addons.config | 462 +++++++++++++++++++++ - 2 files changed, 531 insertions(+) + arch/arm/configs/fragment-02-multiv7_addons.config | 509 +++++++++++++++++++++ + arch/arm/configs/multi_v7_defconfig | 1 + + 3 files changed, 579 insertions(+) create mode 100644 arch/arm/configs/fragment-01-multiv7_cleanup.config create mode 100644 arch/arm/configs/fragment-02-multiv7_addons.config @@ -87,15 +88,16 @@ index 0000000..22f6ffb + 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..c91840c +index 0000000..7ba8387 --- /dev/null +++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -0,0 +1,462 @@ +@@ -0,0 +1,509 @@ +# +# General setup +# +CONFIG_POSIX_MQUEUE=y +CONFIG_USELIB=y ++CONFIG_FUTEX=y + +# +# RCU Subsystem @@ -147,7 +149,6 @@ index 0000000..c91840c +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +# CONFIG_KEXEC is not set -+# CONFIG_EFI is not set + +# +# CPU Power Management @@ -190,7 +191,10 @@ index 0000000..c91840c +# +# Bluetooth device drivers +# -+ ++CONFIG_BT_RTL=m ++CONFIG_BT_HCIBTUSB=m ++CONFIG_BT_HCIBTUSB=m ++CONFIG_BT_HCIBTUSB_RTL=y +# +# Device Drivers +# @@ -212,9 +216,6 @@ index 0000000..c91840c +# +# LPDDR & LPDDR2 PCM memory drivers +# -+CONFIG_OF_RESOLVE=y -+CONFIG_OF_OVERLAY=y -+CONFIG_OF_CONFIGFS=y + +# +# Misc devices @@ -229,8 +230,12 @@ index 0000000..c91840c +# +# MII PHY device drivers +# -+# CONFIG_REALTEK_PHY is not set -+ ++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 +# @@ -246,6 +251,12 @@ index 0000000..c91840c +# 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 @@ -272,6 +283,7 @@ index 0000000..c91840c +# +# SPI Master Controller Drivers +# ++CONFIG_SPI_STM32=y +CONFIG_SPI_STM32_QSPI=y + +# @@ -307,7 +319,7 @@ index 0000000..c91840c +# +# Watchdog Device Drivers +# -+ ++CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Sonics Silicon Backplane @@ -330,6 +342,7 @@ index 0000000..c91840c +# +# USB HDMI CEC adapters +# ++CONFIG_VIDEO_STM32_HDMI_CEC=m + +# +# Media ancillary drivers (tuners, sensors, i2c, spi, frontends) @@ -339,6 +352,7 @@ index 0000000..c91840c +# +# Camera sensor devices +# ++CONFIG_VIDEO_OV5640=y + +# +# Graphics support @@ -354,10 +368,14 @@ index 0000000..c91840c +# +# Display Panels +# ++CONFIG_DRM_PANEL_ORISETECH_OTM8009A=y ++CONFIG_DRM_PANEL_RAYDIUM_RM68200=y + +# +# Display Interface Bridges +# ++CONFIG_VIDEO_ADV7511=y ++CONFIG_DRM_SII902X=y + +# +# Frame buffer hardware drivers @@ -366,15 +384,34 @@ index 0000000..c91840c +# +# Console display driver support +# ++CONFIG_DRM_STM=y ++CONFIG_DRM_STM_DSI=y ++ ++# ++# Backlight support ++# ++CONFIG_BACKLIGHT_GPIO=y + +# +# HD-Audio +# ++CONFIG_SOUND=y ++CONFIG_SND=y ++CONFIG_SND_SOC=y ++CONFIG_SND_SOC_STM32_SAI=y ++CONFIG_SND_SOC_STM32_I2S=y ++CONFIG_SND_SOC_STM32_SPDIFRX=y ++CONFIG_SND_SOC_STM32_DFSDM=y ++CONFIG_SND_AUDIO_GRAPH_CARD=y + +# +# CODEC drivers +# -+ ++CONFIG_MFD_WM8994=y ++CONFIG_SND_SOC_WM8994=y ++CONFIG_SND_SOC_DMIC=y ++CONFIG_SND_SOC_CS42L42=y ++CONFIG_SND_SOC_CS42L51_I2C=y + +# +# USB Device Class drivers @@ -393,10 +430,13 @@ index 0000000..c91840c +# +# Gadget/Dual-role mode requires USB Gadget support to be enabled +# ++CONFIG_USB_CONFIGFS=y + +# +# USB Physical Layer drivers +# ++CONFIG_TYPEC=y ++CONFIG_TYPEC_STUSB=y + +# +# Platform Support @@ -418,6 +458,8 @@ index 0000000..c91840c +# File systems +# +CONFIG_OVERLAY_FS=y ++# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set ++CONFIG_JFFS2_FS=y + +# +# Pseudo filesystems @@ -553,6 +595,24 @@ index 0000000..c91840c +# STM32 DAC +# +CONFIG_STM32_DAC=y ++ ++# ++# STM32 HSEM ++# ++CONFIG_HWSPINLOCK=y ++CONFIG_HWSPINLOCK_STM32=y +diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig +index fc33444..ac1e50b 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 + CONFIG_TWL4030_USB=m ++CONFIG_STM32_DDR_PMU=y + CONFIG_NVMEM_IMX_OCOTP=y + CONFIG_NVMEM_SUNXI_SID=y + CONFIG_NVMEM_VF610_OCOTP=y -- 2.7.4 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0001-ARM-stm32mp1-r0-rc1-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0001-ARM-stm32mp1-r0-rc1-MACHINE.patch deleted file mode 100644 index 933bbf8..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0001-ARM-stm32mp1-r0-rc1-MACHINE.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 07a8a17983431bcc47ef52be1370f156e56119ce Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:14:29 +0100 -Subject: [PATCH 01/52] ARM: stm32mp1-r0-rc1: MACHINE - ---- - arch/arm/mach-stm32/Kconfig | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - -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 --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0006-ARM-stm32mp1-r0-rc1-IRQ-Mailbox.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0006-ARM-stm32mp1-r0-rc1-IRQ-Mailbox.patch deleted file mode 100644 index d31883e..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0006-ARM-stm32mp1-r0-rc1-IRQ-Mailbox.patch +++ /dev/null @@ -1,154 +0,0 @@ -From 358a1325502b2362a6fb74af3027f3f165684375 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:19:47 +0100 -Subject: [PATCH 06/52] ARM: stm32mp1-r0-rc1: IRQ Mailbox - ---- - drivers/irqchip/irq-stm32-exti.c | 23 ++++++++++++++++++----- - drivers/mailbox/mailbox-test.c | 26 ++++++++++++++------------ - drivers/mailbox/stm32-ipcc.c | 4 ++-- - 3 files changed, 34 insertions(+), 19 deletions(-) - -diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index 0a2088e..e185ed8 100644 ---- a/drivers/irqchip/irq-stm32-exti.c -+++ b/drivers/irqchip/irq-stm32-exti.c -@@ -650,11 +650,6 @@ 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); -- writel_relaxed(0, base + stm32_bank->rtsr_ofst); -- writel_relaxed(0, base + stm32_bank->ftsr_ofst); -- writel_relaxed(~0UL, base + stm32_bank->rpr_ofst); -- if (stm32_bank->fpr_ofst != UNDEF_REG) -- writel_relaxed(~0UL, base + stm32_bank->fpr_ofst); - - pr_info("%s: bank%d, External IRQs available:%#x\n", - node->full_name, bank_idx, irqs_mask); -@@ -735,9 +730,27 @@ 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 -diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c -index 58bfafc..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; -@@ -363,22 +363,24 @@ static int mbox_test_probe(struct platform_device *pdev) - - /* It's okay for MMIO to be NULL */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- size = resource_size(res); - tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); -- if (PTR_ERR(tdev->tx_mmio) == -EBUSY) -+ if (PTR_ERR(tdev->tx_mmio) == -EBUSY) { - /* if reserved area in SRAM, try just ioremap */ -+ size = resource_size(res); - tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); -- else if (IS_ERR(tdev->tx_mmio)) -+ } else if (IS_ERR(tdev->tx_mmio)) { - tdev->tx_mmio = NULL; -+ } - - /* If specified, second reg entry is Rx MMIO */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); -- size = resource_size(res); - tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res); -- if (PTR_ERR(tdev->rx_mmio) == -EBUSY) -+ if (PTR_ERR(tdev->rx_mmio) == -EBUSY) { -+ size = resource_size(res); - tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); -- else if (IS_ERR(tdev->rx_mmio)) -+ } else if (IS_ERR(tdev->rx_mmio)) { - tdev->rx_mmio = tdev->tx_mmio; -+ } - - tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); - tdev->rx_channel = mbox_test_request_channel(pdev, "rx"); -@@ -416,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 533b0da..cd5ceca 100644 ---- a/drivers/mailbox/stm32-ipcc.c -+++ b/drivers/mailbox/stm32-ipcc.c -@@ -276,8 +276,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 */ --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0007-ARM-stm32mp1-r0-rc1-INPUT-TTY.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0007-ARM-stm32mp1-r0-rc1-INPUT-TTY.patch deleted file mode 100644 index 8e1e08d..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0007-ARM-stm32mp1-r0-rc1-INPUT-TTY.patch +++ /dev/null @@ -1,1099 +0,0 @@ -From feb0bf2d9b83cb19c75be4cd12b3e7a584f513b5 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:21:06 +0100 -Subject: [PATCH 07/52] ARM: stm32mp1-r0-rc1: INPUT TTY - ---- - drivers/input/misc/Kconfig | 11 + - drivers/input/misc/Makefile | 2 + - drivers/input/misc/stpmic1_onkey.c | 197 ++++++++++++++++++ - drivers/tty/serial/stm32-usart.c | 398 +++++++++++++++++++++++++++++-------- - drivers/tty/serial/stm32-usart.h | 34 +++- - 5 files changed, 550 insertions(+), 92 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..6a7f08b ---- /dev/null -+++ b/drivers/input/misc/stpmic1_onkey.c -@@ -0,0 +1,197 @@ -+// 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/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c -index e8d7a7b..5c6c3c0 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 -@@ -180,14 +182,18 @@ static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, - *sr = readl_relaxed(port->membase + ofs->isr); - - if (threaded && stm32_port->rx_ch) { -+ if (stm32_port->rx_dma_cb == CALLBACK_CALLED) -+ return 1; - status = dmaengine_tx_status(stm32_port->rx_ch, - stm32_port->rx_ch->cookie, - &state); - if ((status == DMA_IN_PROGRESS) && -- (*last_res != state.residue)) -+ (*last_res != state.residue)) { -+ stm32_port->rx_dma_cb = CALLBACK_IGNORED; - return 1; -- else -+ } else { - return 0; -+ } - } else if (*sr & USART_SR_RXNE) { - return 1; - } -@@ -203,8 +209,11 @@ stm32_get_char(struct uart_port *port, u32 *sr, int *last_res) - - if (stm32_port->rx_ch) { - c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--]; -- if ((*last_res) == 0) -+ if ((*last_res) == 0) { - *last_res = RX_BUF_L; -+ if (stm32_port->rx_dma_cb == CALLBACK_CALLED) -+ stm32_port->rx_dma_cb = CALLBACK_NOT_CALLED; -+ } - return c; - } else { - return readl_relaxed(port->membase + ofs->rdr); -@@ -271,22 +280,8 @@ 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); - -+ dmaengine_terminate_async(stm32port->tx_ch); - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32port->tx_dma_busy = false; - -@@ -294,32 +289,56 @@ static void stm32_tx_dma_complete(void *arg) - stm32_transmit_chars(port); - } - -+static void stm32_rx_dma_complete(void *arg) -+{ -+ struct uart_port *port = arg; -+ struct stm32_port *stm32port = to_stm32_port(port); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ -+ /* -+ * If the dma controller is sending the data on -+ * the fly then we have CALLBACK_IGNORED -+ */ -+ -+ if (stm32port->rx_dma_cb == CALLBACK_NOT_CALLED) { -+ stm32port->rx_dma_cb = CALLBACK_CALLED; -+ stm32_receive_chars(port, true); -+ } -+ -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ - 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 +396,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 +419,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 -+ stm32_set_bits(port, ofs->icr, USART_ICR_TCCF); - - if (stm32_port->tx_ch) - stm32_transmit_chars_dma(port); -@@ -419,8 +440,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) -@@ -434,6 +459,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) - - 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); -@@ -456,11 +485,21 @@ static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) - { - struct uart_port *port = ptr; - struct stm32_port *stm32_port = to_stm32_port(port); -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - - spin_lock(&port->lock); - -- if (stm32_port->rx_ch) -+ if (stm32_port->rx_ch) { -+ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); -+ dma_sync_single_for_cpu(port->dev, -+ stm32_port->rx_dma_buf, -+ RX_BUF_L, DMA_FROM_DEVICE); - stm32_receive_chars(port, true); -+ dma_sync_single_for_device(port->dev, -+ stm32_port->rx_dma_buf, -+ RX_BUF_L, DMA_FROM_DEVICE); -+ stm32_set_bits(port, ofs->cr3, USART_CR3_DMAR); -+ } - - spin_unlock(&port->lock); - -@@ -472,7 +511,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 +540,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 +562,22 @@ 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) { -+ spin_lock(&port->lock); -+ dmaengine_terminate_async(stm32_port->tx_ch); -+ spin_unlock(&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 +586,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 +601,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 +614,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,31 +629,41 @@ 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; -- u32 val; -+ u32 val, sr, dr; - int ret; - -+ sr = readl_relaxed(port->membase + ofs->isr); -+ -+ if ((sr & USART_SR_RXNE) && (stm32_port->rx_ch)) { -+ ret = readl_relaxed_poll_timeout_atomic(port->membase + -+ ofs->rdr, -+ dr, -+ !(sr & USART_SR_RXNE), -+ 10, 100000); -+ if (ret) -+ return ret; -+ } -+ - ret = request_threaded_irq(port->irq, stm32_interrupt, - stm32_threaded_interrupt, - IRQF_NO_SUSPEND, name, 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; -- } -- } -- -- val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; -+ val = stm32_port->cr1_irq | USART_CR1_TE | USART_CR1_RE; - if (stm32_port->fifoen) - val |= USART_CR1_FIFOEN; - stm32_set_bits(port, ofs->cr1, val); - -+ 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); -+ } -+ - return 0; - } - -@@ -587,15 +672,29 @@ 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); -+ - free_irq(port->irq, port); - } - -@@ -606,7 +705,7 @@ 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; -@@ -622,16 +721,50 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - /* Stop serial port and reset value */ - writel_relaxed(0, port->membase + ofs->cr1); - -- cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; -+ cr1 = USART_CR1_TE | USART_CR1_RE; - - if (stm32_port->fifoen) - cr1 |= USART_CR1_FIFOEN; - cr2 = 0; -- cr3 = 0; -+ cr3 = readl_relaxed(port->membase + ofs->cr3); -+ cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE -+ | USART_CR3_TXFTCFG_MASK; - - if (cflag & CSTOPB) - cr2 |= USART_CR2_STOP_2B; - -+ if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || -+ stm32_port->fifoen)) { -+ switch (cflag & CSIZE) { -+ case CS5: -+ bits = 7; -+ break; -+ case CS6: -+ bits = 8; -+ break; -+ case CS7: -+ bits = 9; -+ break; -+ default: -+ bits = 10; /* CS8 */ -+ break; -+ } -+ -+ if (cflag & CSTOPB) -+ bits++; /* 2 stop bits */ -+ -+ /* 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 & PARENB) { - cr1 |= USART_CR1_PCE; - if ((cflag & CSIZE) == CS8) { -@@ -715,8 +848,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 +900,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 +923,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, -@@ -808,13 +944,19 @@ static int stm32_init_port(struct stm32_port *stm32port, - 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; -+ port->irq = platform_get_irq_byname(pdev, "event"); -+ port->fifosize = stm32port->info->cfg.fifosize; - -+ port->rs485_config = stm32_config_rs485; - stm32_init_rs485(port, pdev); - -- stm32port->wakeirq = platform_get_irq(pdev, 1); -+ stm32port->wakeirq = platform_get_irq_byname(pdev, "wakeup"); - stm32port->fifoen = stm32port->info->cfg.has_fifo; -+ stm32port->console_pins = pinctrl_lookup_state(pdev->dev.pins->p, -+ "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); -@@ -862,7 +1004,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]; - } - -@@ -890,10 +1036,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, - - /* 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"); -+ if (!stm32port->rx_ch) - return -ENODEV; -- } - stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, - &stm32port->rx_dma_buf, - GFP_KERNEL); -@@ -925,9 +1069,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, - goto config_err; - } - -- /* No callback as dma buffer is drained on usart interrupt */ -- desc->callback = NULL; -- desc->callback_param = NULL; -+ desc->callback = stm32_rx_dma_complete; -+ desc->callback_param = port; - - /* Push current DMA transaction in the pending queue */ - cookie = dmaengine_submit(desc); -@@ -962,10 +1105,8 @@ 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"); -+ if (!stm32port->tx_ch) - return -ENODEV; -- } - stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, - &stm32port->tx_dma_buf, - GFP_KERNEL); -@@ -1024,11 +1165,18 @@ static int stm32_serial_probe(struct platform_device *pdev) - ret = device_init_wakeup(&pdev->dev, true); - 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); - } - - ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); - if (ret) -- goto err_nowup; -+ goto err_wirq; - - ret = stm32_of_dma_rx_probe(stm32port, pdev); - if (ret) -@@ -1040,8 +1188,17 @@ static int stm32_serial_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, &stm32port->port); - -+ 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_wirq: -+ if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) -+ dev_pm_clear_wake_irq(&pdev->dev); -+ - err_nowup: - if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) - device_init_wakeup(&pdev->dev, false); -@@ -1058,11 +1215,16 @@ static int stm32_serial_remove(struct platform_device *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; -+ -+ pm_runtime_get_sync(&pdev->dev); - - stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - -- if (stm32_port->rx_ch) -+ if (stm32_port->rx_ch) { -+ dmaengine_terminate_async(stm32_port->rx_ch); - dma_release_channel(stm32_port->rx_ch); -+ } - - if (stm32_port->rx_dma_buf) - dma_free_coherent(&pdev->dev, -@@ -1071,20 +1233,29 @@ 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 (cfg->has_wakeup && 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); -+ err = uart_remove_one_port(&stm32_usart_driver, port); -+ -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ return err; - } - - -@@ -1215,14 +1386,41 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) - 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); -+ struct tty_struct *tty = port->state->port.tty; - -- uart_suspend_port(&stm32_usart_driver, port); -+ if (tty) { -+ struct device *tty_dev = tty->dev; -+ -+ if (tty_dev && (device_may_wakeup(tty_dev) -+ != device_may_wakeup(dev))) { -+ dev_err(port->dev, -+ "UART and TTY wakeup are not coherent\n"); -+ return -EINVAL; -+ } -+ } - - if (device_may_wakeup(dev)) - stm32_serial_enable_wakeup(port, true); - else - stm32_serial_enable_wakeup(port, false); - -+ uart_suspend_port(&stm32_usart_driver, port); -+ -+ 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)) -+ pinctrl_pm_select_idle_state(dev); -+ else -+ pinctrl_pm_select_sleep_state(dev); -+ } -+ - return 0; - } - -@@ -1230,6 +1428,8 @@ static int stm32_serial_resume(struct device *dev) - { - struct uart_port *port = dev_get_drvdata(dev); - -+ pinctrl_pm_select_default_state(dev); -+ - if (device_may_wakeup(dev)) - stm32_serial_enable_wakeup(port, false); - -@@ -1237,7 +1437,31 @@ static int stm32_serial_resume(struct device *dev) - } - #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..f1f5c1c 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,6 +99,7 @@ struct stm32_usart_info stm32h7_info = { - .has_7bits_data = true, - .has_wakeup = true, - .has_fifo = true, -+ .fifosize = 16, - } - }; - -@@ -125,9 +129,6 @@ struct stm32_usart_info stm32h7_info = { - /* 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) - -@@ -209,6 +210,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) -@@ -242,9 +256,15 @@ 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_L 160 /* 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 TX_BUF_L RX_BUF_L /* dma tx buffer length */ -+ -+enum dma_cb { -+ CALLBACK_NOT_CALLED, -+ CALLBACK_CALLED, -+ CALLBACK_IGNORED, -+}; - - struct stm32_port { - struct uart_port port; -@@ -256,11 +276,15 @@ 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; -+ enum dma_cb rx_dma_cb; /* dma rx callback status */ - bool tx_dma_busy; /* dma tx busy */ - bool hw_flow_control; - bool fifoen; - int wakeirq; -+ struct pinctrl_state *console_pins; - }; - - static struct stm32_port stm32_ports[STM32_MAX_PORTS]; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0010-ARM-stm32mp1-r0-rc1-ETH.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0010-ARM-stm32mp1-r0-rc1-ETH.patch deleted file mode 100644 index e8c9b06..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0010-ARM-stm32mp1-r0-rc1-ETH.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 82c6107d054adcc906e43190ef150840876c2618 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:23:50 +0100 -Subject: [PATCH 10/52] ARM: stm32mp1-r0-rc1: ETH - ---- - drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 30 ++++++++++++++++++++++- - 1 file changed, 29 insertions(+), 1 deletion(-) - -diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -index 7e2e79d..d1cf145 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -@@ -42,6 +42,7 @@ struct stm32_dwmac { - struct clk *clk_ethstp; - struct clk *syscfg_clk; - bool int_phyclk; /* Clock from RCC to drive PHY */ -+ int irq_pwr_wakeup; - u32 mode_reg; /* MAC glue-logic mode register */ - struct regmap *regmap; - u32 speed; -@@ -232,7 +233,9 @@ 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; - - dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk"); - -@@ -260,7 +263,26 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, - return PTR_ERR(dwmac->syscfg_clk); - } - -- return 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->int_phyclk && 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 +348,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; - } - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0015-ARM-stm32mp1-r0-rc1-MISC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0015-ARM-stm32mp1-r0-rc1-MISC.patch deleted file mode 100644 index 4c9cfe7..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0015-ARM-stm32mp1-r0-rc1-MISC.patch +++ /dev/null @@ -1,901 +0,0 @@ -From 535343fc0142b45ec82958a4cbea41945d4d93c9 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 13 Nov 2018 12:30:43 +0100 -Subject: [PATCH 15/52] ARM: stm32mp1-r0-rc1: MISC - ---- - arch/arm/mach-integrator/integrator_cp.c | 2 - - arch/arm/mach-versatile/versatile_dt.c | 4 - - drivers/soc/Kconfig | 1 + - drivers/soc/Makefile | 1 + - drivers/soc/st/Kconfig | 9 + - drivers/soc/st/Makefile | 1 + - drivers/soc/st/stm32_pm_domain.c | 212 ++++++++++++ - drivers/spi/Kconfig | 9 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-stm32-qspi.c | 541 +++++++++++++++++++++++++++++++ - 10 files changed, 775 insertions(+), 6 deletions(-) - create mode 100644 drivers/soc/st/Kconfig - create mode 100644 drivers/soc/st/Makefile - create mode 100644 drivers/soc/st/stm32_pm_domain.c - create mode 100644 drivers/spi/spi-stm32-qspi.c - -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-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, - }; - - /* -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 113e884..a16f673 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..82ee423 ---- /dev/null -+++ b/drivers/soc/st/Kconfig -@@ -0,0 +1,9 @@ -+if ARCH_STM32 -+ -+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 0000000..8d7f291 ---- /dev/null -+++ b/drivers/soc/st/Makefile -@@ -0,0 +1 @@ -+obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o -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/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..3e8ca10 ---- /dev/null -+++ b/drivers/spi/spi-stm32-qspi.c -@@ -0,0 +1,541 @@ -+// 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 -+ -+#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_MASK GENMASK(12, 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 -+ -+struct stm32_qspi_flash { -+ struct stm32_qspi *qspi; -+ u32 cs; -+ u32 presc; -+}; -+ -+struct stm32_qspi { -+ struct device *dev; -+ 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; -+ -+ 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 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); -+ -+ 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_interruptible_timeout(&qspi->data_completion, -+ msecs_to_jiffies(1000))) { -+ 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 = FIELD_PREP(CR_FTHRES_MASK, 3) | 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; -+} -+ -+/* -+ * 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); -+ 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); -+ -+ 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); -+ 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); -+ 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"); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0020-ARM-stm32mp1-r0-rc2-MEDIA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0020-ARM-stm32mp1-r0-rc2-MEDIA.patch deleted file mode 100644 index ae23aee..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0020-ARM-stm32mp1-r0-rc2-MEDIA.patch +++ /dev/null @@ -1,984 +0,0 @@ -From 8f36e7dd830ff5d93e240a62da54ea2afc580cca Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:39:57 +0100 -Subject: [PATCH 20/52] ARM-stm32mp1-r0-rc2-MEDIA - ---- - .../devicetree/bindings/media/video-interfaces.txt | 2 + - drivers/media/i2c/ov5640.c | 663 ++++++++++++--------- - drivers/media/platform/stm32/stm32-dcmi.c | 41 +- - drivers/media/v4l2-core/v4l2-fwnode.c | 3 + - include/media/v4l2-fwnode.h | 2 + - 5 files changed, 413 insertions(+), 298 deletions(-) - -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/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 30b15e9..27b75e7 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 -@@ -261,8 +262,8 @@ 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}, -+ {0x3034, 0x18, 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}, -@@ -344,85 +345,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}, -- {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_QVGA_320_240[] = { -- {0x3035, 0x14, 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}, -@@ -436,12 +360,12 @@ static const struct reg_value ov5640_setting_30fps_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}, {0x4713, 0x03, 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_15fps_QVGA_320_240[] = { -- {0x3035, 0x22, 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}, -@@ -455,12 +379,11 @@ static const struct reg_value ov5640_setting_15fps_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}, {0x4713, 0x03, 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_30fps_QCIF_176_144[] = { -- {0x3035, 0x14, 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}, -@@ -474,12 +397,11 @@ static const struct reg_value ov5640_setting_30fps_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}, {0x4713, 0x03, 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_15fps_QCIF_176_144[] = { -- {0x3035, 0x22, 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}, -@@ -493,12 +415,11 @@ static const struct reg_value ov5640_setting_15fps_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}, {0x4713, 0x03, 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_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}, -@@ -512,31 +433,11 @@ static const struct reg_value ov5640_setting_30fps_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}, {0x4713, 0x03, 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_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}, -@@ -550,52 +451,11 @@ static const struct reg_value ov5640_setting_30fps_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}, {0x4713, 0x03, 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_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}, -- {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}, {0x4005, 0x1a, 0, 0}, -- {0x3008, 0x02, 0, 0}, {0x3503, 0, 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}, -+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}, -@@ -608,47 +468,13 @@ static const struct reg_value ov5640_setting_15fps_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}, --}; -- --static const struct reg_value ov5640_setting_30fps_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, 0x11, 0, 0}, -- {0x3036, 0x54, 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}, -- {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}, -+ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, -+ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, - }; - --static const struct reg_value ov5640_setting_15fps_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}, -@@ -662,9 +488,9 @@ static const struct reg_value ov5640_setting_15fps_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}, {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}, -+ {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}, -@@ -674,12 +500,11 @@ static const struct reg_value ov5640_setting_15fps_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}, {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}, -@@ -693,8 +518,8 @@ static const struct reg_value ov5640_setting_15fps_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}, {0x4713, 0x03, 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 */ -@@ -705,79 +530,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,6 +698,272 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, - return ov5640_write_reg(sensor, reg, val); - } - -+/* -+ * After spending way too much time trying the various combinations, I -+ * believe the clock tree is as follows: -+ * -+ * +--------------+ -+ * | Oscillator | -+ * +------+-------+ -+ * | -+ * +------+-------+ -+ * | System clock | - reg 0x3035, bits 4-7 -+ * +------+-------+ -+ * | -+ * +------+-------+ - reg 0x3036, for the multiplier -+ * | PLL | - reg 0x3037, bits 4 for the root divider -+ * +------+-------+ - reg 0x3037, bits 0-3 for the pre-divider -+ * | -+ * +------+-------+ -+ * | SCLK | - reg 0x3108, bits 0-1 for the root divider -+ * +------+-------+ -+ * | -+ * +------+-------+ -+ * | PCLK | - reg 0x3108, bits 4-5 for the root divider -+ * +--------------+ -+ * -+ * 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. However, changing the SCLK divider value has a direct -+ * effect on the PCLK rate, which wouldn't be the case if both PCLK -+ * and SCLK were to be sourced from the PLL. -+ * -+ * These parameters also match perfectly the rate that is output by -+ * the sensor, so we shouldn't have too much factors missing (or they -+ * would be set to 1). -+ */ -+ -+/* -+ * FIXME: 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. -+ * -+ * Moreover issues are seen with SYSDIV set to 1: -+ * Strange behaviour is observed when requesting 75MHz pixel clock output -+ * for 1280x720 (1892x740) resolution, pixel clock is about 100MHz with -+ * blanking (register values: 0x3035=0x11 and 0x3036=0x13). -+ * When forcing system clock divider to 2, pixel clock is 75Mhz continuous -+ * as expected (register values: 0x3035=0x21 and 0x3036=0x26). -+ */ -+#define OV5640_SYSDIV_MIN 2 -+#define OV5640_SYSDIV_MAX 2 -+ -+static unsigned long ov5640_calc_sysclk(struct ov5640_dev *sensor, -+ unsigned long rate, -+ u8 *sysdiv) -+{ -+ unsigned long best = ~0; -+ u8 best_sysdiv = 1; -+ u8 _sysdiv; -+ -+ for (_sysdiv = OV5640_SYSDIV_MIN; -+ _sysdiv <= OV5640_SYSDIV_MAX; -+ _sysdiv++) { -+ unsigned long tmp; -+ -+ tmp = sensor->xclk_freq / _sysdiv; -+ if (abs(rate - tmp) < abs(rate - best)) { -+ best = tmp; -+ best_sysdiv = _sysdiv; -+ } -+ -+ if (tmp == rate) -+ goto out; -+ } -+ -+out: -+ *sysdiv = best_sysdiv; -+ return best; -+} -+ -+/* -+ * FIXME: 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_MIN 3 -+#define OV5640_PLL_PREDIV_MAX 3 -+ -+/* -+ * FIXME: This is supposed to be ranging from 1 to 2, but the value is -+ * always set to 1 in the vendor kernels. -+ */ -+#define OV5640_PLL_ROOT_DIV_MIN 1 -+#define OV5640_PLL_ROOT_DIV_MAX 1 -+ -+#define OV5640_PLL_MULT_MIN 4 -+#define OV5640_PLL_MULT_MAX 252 -+ -+static unsigned long ov5640_calc_pll(struct ov5640_dev *sensor, -+ unsigned long rate, -+ u8 *sysdiv, u8 *prediv, u8 *rdiv, u8 *mult) -+{ -+ unsigned long best = ~0; -+ u8 best_sysdiv = 1, best_prediv = 1, best_mult = 1, best_rdiv = 1; -+ u8 _prediv, _mult, _rdiv; -+ -+ for (_prediv = OV5640_PLL_PREDIV_MIN; -+ _prediv <= OV5640_PLL_PREDIV_MAX; -+ _prediv++) { -+ for (_mult = OV5640_PLL_MULT_MIN; -+ _mult <= OV5640_PLL_MULT_MAX; -+ _mult++) { -+ for (_rdiv = OV5640_PLL_ROOT_DIV_MIN; -+ _rdiv <= OV5640_PLL_ROOT_DIV_MAX; -+ _rdiv++) { -+ unsigned long pll; -+ unsigned long sysclk; -+ u8 _sysdiv; -+ -+ /* -+ * The PLL multiplier cannot be odd if -+ * above 127. -+ */ -+ if (_mult > 127 && !(_mult % 2)) -+ continue; -+ -+ sysclk = rate * _prediv * _rdiv / _mult; -+ sysclk = ov5640_calc_sysclk(sensor, sysclk, -+ &_sysdiv); -+ -+ pll = sysclk / _rdiv / _prediv * _mult; -+ if (abs(rate - pll) < abs(rate - best)) { -+ best = pll; -+ best_sysdiv = _sysdiv; -+ best_prediv = _prediv; -+ best_mult = _mult; -+ best_rdiv = _rdiv; -+ } -+ -+ if (pll == rate) -+ goto out; -+ } -+ } -+ } -+ -+out: -+ *sysdiv = best_sysdiv; -+ *prediv = best_prediv; -+ *mult = best_mult; -+ *rdiv = best_rdiv; -+ -+ return best; -+} -+ -+/* -+ * FIXME: 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_MIN 1 -+#define OV5640_PCLK_ROOT_DIV_MAX 1 -+ -+static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor, -+ unsigned long rate, -+ u8 *sysdiv, u8 *prediv, u8 *pll_rdiv, -+ u8 *mult, u8 *pclk_rdiv) -+{ -+ unsigned long best = ~0; -+ u8 best_sysdiv = 1, best_prediv = 1, best_mult = 1, best_pll_rdiv = 1; -+ u8 best_pclk_rdiv = 1; -+ u8 _pclk_rdiv; -+ -+ for (_pclk_rdiv = OV5640_PCLK_ROOT_DIV_MIN; -+ _pclk_rdiv <= OV5640_PCLK_ROOT_DIV_MAX; -+ _pclk_rdiv <<= 1) { -+ unsigned long pll, pclk; -+ u8 sysdiv, prediv, mult, pll_rdiv; -+ -+ pll = rate * OV5640_SCLK_ROOT_DIVIDER_DEFAULT * _pclk_rdiv; -+ pll = ov5640_calc_pll(sensor, pll, &sysdiv, &prediv, &pll_rdiv, -+ &mult); -+ -+ pclk = pll / OV5640_SCLK_ROOT_DIVIDER_DEFAULT / _pclk_rdiv; -+ if (abs(rate - pclk) < abs(rate - best)) { -+ best = pclk; -+ best_sysdiv = sysdiv; -+ best_prediv = prediv; -+ best_pll_rdiv = pll_rdiv; -+ best_pclk_rdiv = _pclk_rdiv; -+ best_mult = mult; -+ } -+ -+ if (pclk == rate) -+ goto out; -+ } -+ -+out: -+ *sysdiv = best_sysdiv; -+ *prediv = best_prediv; -+ *pll_rdiv = best_pll_rdiv; -+ *mult = best_mult; -+ *pclk_rdiv = best_pclk_rdiv; -+ return best; -+} -+ -+static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, -+ const struct ov5640_mode_info *mode, -+ unsigned long rate) -+{ -+ u8 sysdiv, prediv, mult, pll_rdiv, pclk_rdiv; -+ int ret; -+ struct i2c_client *client = sensor->i2c_client; -+ u8 dvp_pclk_divider = mode->hact < 1024 ? 2 : 1;//FIXME -+ unsigned int pclk_freq, max_pclk_freq; -+ -+ 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, &sysdiv, &prediv, &pll_rdiv, &mult, -+ &pclk_rdiv); -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, -+ 0xf0, 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, -+ 0xff, prediv | ((pll_rdiv - 1) << 4)); -+ if (ret) -+ return ret; -+ -+ return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, -+ 0x30, ilog2(pclk_rdiv) << 4); -+} -+ -+static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor, unsigned long rate) -+{ -+ u8 sysdiv, prediv, mult, pll_rdiv, pclk_rdiv; -+ int ret; -+ -+ ov5640_calc_pclk(sensor, rate, &sysdiv, &prediv, &pll_rdiv, &mult, -+ &pclk_rdiv); -+ ret = ov5640_write_reg(sensor, OV5640_REG_SC_PLL_CTRL1, -+ (sysdiv << 4) | pclk_rdiv); -+ if (ret) -+ return ret; -+ -+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, -+ 0xff, mult); -+ if (ret) -+ return ret; -+ -+ return ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, -+ 0xff, prediv | ((pll_rdiv - 1) << 4)); -+} -+ - /* download ov5640 settings to sensor through i2c */ - static int ov5640_set_timings(struct ov5640_dev *sensor, - const struct ov5640_mode_info *mode) -@@ -1444,8 +1499,8 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, - { - 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); - -@@ -1637,8 +1692,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 +1714,24 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) - goto restore_auto_gain; - } - -+ /* -+ * All the formats we support have 2 bytes per pixel, except for JPEG -+ * which is 1 byte per pixel, but JPEG requires the same rate -+ * than YUV (horizontal lines blanking). -+ */ -+ rate = mode->vtot * mode->htot * 2; -+ 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 { -+ ret = ov5640_set_dvp_pclk(sensor, mode, rate); -+ } -+ -+ if (ret < 0) -+ return 0; -+ - if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) || - (dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) { - /* -@@ -2502,10 +2579,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; -@@ -2573,8 +2650,6 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, - if (frame_rate < 0) - frame_rate = OV5640_15_FPS; - -- sensor->current_fr = frame_rate; -- sensor->frame_interval = fi->interval; - mode = ov5640_find_mode(sensor, frame_rate, mode->hact, - mode->vact, true); - if (!mode) { -@@ -2582,7 +2657,10 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, - goto out; - } - -- if (mode != sensor->current_mode) { -+ if (mode != sensor->current_mode || -+ (frame_rate != sensor->current_fr)) { -+ sensor->current_fr = frame_rate; -+ sensor->frame_interval = fi->interval; - sensor->current_mode = mode; - sensor->pending_mode_change = true; - } -@@ -2613,7 +2691,8 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) - - if (sensor->streaming == !enable) { - if (enable && sensor->pending_mode_change) { -- ret = ov5640_set_mode(sensor); -+ ret = ov5640_set_mode(sensor, sensor->last_mode); -+ - if (ret) - goto out; - } -@@ -2735,7 +2814,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/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c -index 7215641..49849e6 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 - - struct dcmi_graph_entity { -@@ -570,9 +573,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - int ret; - - ret = pm_runtime_get_sync(dcmi->dev); -- if (ret) { -- dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n", -- __func__); -+ if (ret < 0) { -+ dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n", -+ __func__, ret); - goto err_release_buffers; - } - -@@ -621,8 +624,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.subdev, &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); -@@ -659,7 +685,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) - } - - /* 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; - -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/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; - }; - - /** --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0021-ARM-stm32mp1-r0-rc2-PINCTRL.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0021-ARM-stm32mp1-r0-rc2-PINCTRL.patch deleted file mode 100644 index 568137e..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0021-ARM-stm32mp1-r0-rc2-PINCTRL.patch +++ /dev/null @@ -1,288 +0,0 @@ -From 85d48072cfb2e491d10a235c4ade2460e3bbc93a Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:40:42 +0100 -Subject: [PATCH 21/52] ARM-stm32mp1-r0-rc2-PINCTRL - ---- - .../bindings/pinctrl/st,stm32-pinctrl.txt | 1 + - drivers/pinctrl/core.c | 15 +---- - drivers/pinctrl/pinctrl-stmfx.c | 8 +++ - drivers/pinctrl/stm32/pinctrl-stm32.c | 71 +++++++++++++++++++++- - include/linux/pinctrl/pinctrl.h | 2 + - 5 files changed, 83 insertions(+), 14 deletions(-) - -diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -index 286c981..1a5d1e2 100644 ---- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -+++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt -@@ -58,6 +58,7 @@ Optional properties: - 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 -diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c -index a3dd777..0220d43 100644 ---- a/drivers/pinctrl/core.c -+++ b/drivers/pinctrl/core.c -@@ -1992,7 +1992,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 +2030,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 -index e253ed1..15d5757 100644 ---- a/drivers/pinctrl/pinctrl-stmfx.c -+++ b/drivers/pinctrl/pinctrl-stmfx.c -@@ -663,6 +663,14 @@ static int stmfx_pinctrl_probe(struct platform_device *pdev) - 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; -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c -index e25917f..914bee4 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c -@@ -8,6 +8,7 @@ - */ - #include - #include -+#include - #include - #include - #include -@@ -64,6 +65,8 @@ - #define gpio_range_to_bank(chip) \ - container_of(chip, struct stm32_gpio_bank, range) - -+#define HWSPINLOCK_TIMEOUT 5 /* msec */ -+ - static const char * const stm32_gpio_functions[] = { - "gpio", "af0", "af1", - "af2", "af3", "af4", -@@ -111,6 +114,7 @@ struct stm32_pinctrl { - u32 npins; - u32 pkg; - u32 pin_base_shift; -+ struct hwspinlock *hwlock; - }; - - static inline int stm32_gpio_pin(int gpio) -@@ -598,14 +602,24 @@ static int stm32_pmx_get_func_groups(struct pinctrl_dev *pctldev, - static void 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 = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); -+ -+ 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); -@@ -618,6 +632,10 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank, - - stm32_gpio_backup_mode(bank, pin, mode, alt); - -+ if (pctl->hwlock) -+ hwspin_unlock(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); - } -@@ -707,12 +725,22 @@ static const struct pinmux_ops stm32_pmx_ops = { - static void 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 = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); -+ -+ 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; -@@ -720,6 +748,10 @@ static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank, - - stm32_gpio_backup_driving(bank, offset, drive); - -+ if (pctl->hwlock) -+ hwspin_unlock(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); - } -@@ -745,12 +777,22 @@ static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, - static void 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 = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); -+ -+ 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); -@@ -758,6 +800,10 @@ static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank, - - stm32_gpio_backup_speed(bank, offset, speed); - -+ if (pctl->hwlock) -+ hwspin_unlock(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); - } -@@ -783,12 +829,22 @@ static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, - static void 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 = hwspin_lock_timeout(pctl->hwlock, HWSPINLOCK_TIMEOUT); -+ -+ 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); -@@ -796,6 +852,10 @@ static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank, - - stm32_gpio_backup_bias(bank, offset, bias); - -+ if (pctl->hwlock) -+ hwspin_unlock(pctl->hwlock); -+ -+unlock: - spin_unlock_irqrestore(&bank->lock, flags); - clk_disable(bank->clk); - } -@@ -1206,7 +1266,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; -@@ -1226,6 +1286,15 @@ int stm32_pctl_probe(struct platform_device *pdev) - - platform_set_drvdata(pdev, pctl); - -+ /* 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); -+ } -+ - pctl->dev = dev; - pctl->match_data = match->data; - -diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h -index 8f5dbb8..bbeaa29 100644 ---- a/include/linux/pinctrl/pinctrl.h -+++ b/include/linux/pinctrl/pinctrl.h -@@ -148,6 +148,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.9/0022-ARM-stm32mp1-r0-rc2-MFD-IRQ.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0022-ARM-stm32mp1-r0-rc2-MFD-IRQ.patch deleted file mode 100644 index 330c717..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0022-ARM-stm32mp1-r0-rc2-MFD-IRQ.patch +++ /dev/null @@ -1,781 +0,0 @@ -From aed35270f0be1c5c61a028d7c183e60269f3abe3 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:41:37 +0100 -Subject: [PATCH 22/52] ARM-stm32mp1-r0-rc2-MFD-IRQ - ---- - .../interrupt-controller/st,stm32-exti.txt | 34 +++++- - .../devicetree/bindings/mfd/st,stpmic1.txt | 2 +- - Documentation/devicetree/bindings/mfd/syscon.txt | 1 + - drivers/irqchip/irq-stm32-exti.c | 133 ++++++++++++++++++--- - drivers/mfd/stm32-pwr.c | 131 +++++++++----------- - drivers/mfd/stpmic1.c | 16 +-- - drivers/mfd/syscon.c | 19 +++ - drivers/mfd/wm8994-core.c | 15 +++ - include/linux/mfd/stpmic1.h | 1 - - 9 files changed, 247 insertions(+), 105 deletions(-) - -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/mfd/st,stpmic1.txt b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt -index 54b64e2..0fab08a 100644 ---- a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt -+++ b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt -@@ -4,7 +4,6 @@ Required parent device properties: - - compatible: "st,stpmic1" - - reg: The I2C slave address for the STPMIC1 chip. - - interrupts: The interrupt lines the device is connected to. -- The second interrupt is used for wake-up. - - #interrupt-cells: Should be 2. - - interrupt-controller: Describes the STPMIC1 as an interrupt - controller (has its own domain). Interrupt number are the following: -@@ -81,6 +80,7 @@ Optional parent device properties: - -bit 5: SW_OUT discharge is enabled - -bit 6: VBUS_OTG detection is enabled - -bit 7: BOOST_OVP is disabled -+- wakeup-source: bool flag to indicate this device has wakeup capabilities - - STPMIC1 consists in a varied group of sub-devices. - Each sub-device binding is be described in own documentation file. -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/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index e185ed8..9cc15f1 100644 ---- a/drivers/irqchip/irq-stm32-exti.c -+++ b/drivers/irqchip/irq-stm32-exti.c -@@ -6,6 +6,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -20,6 +21,8 @@ - - #define IRQS_PER_BANK 32 - -+#define HWSPINLOCK_TIMEOUT 5 /* msec */ -+ - struct stm32_exti_bank { - u32 imr_ofst; - u32 emr_ofst; -@@ -47,6 +50,7 @@ struct stm32_exti_drv_data { - struct stm32_exti_chip_data { - struct stm32_exti_host_data *host_data; - const struct stm32_exti_bank *reg_bank; -+ struct hwspinlock *hwlock; - struct raw_spinlock rlock; - u32 wake_active; - u32 mask_cache; -@@ -275,25 +279,34 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type) - struct stm32_exti_chip_data *chip_data = gc->private; - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; - u32 rtsr, ftsr; -- int err; -+ int err = 0; - - irq_gc_lock(gc); - -+ if (chip_data->hwlock) -+ err = hwspin_lock_timeout(chip_data->hwlock, -+ HWSPINLOCK_TIMEOUT); -+ -+ 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: -+ if (chip_data->hwlock) -+ hwspin_unlock(chip_data->hwlock); -+unlock: - irq_gc_unlock(gc); - -- return 0; -+ return err; - } - - static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data, -@@ -457,22 +470,36 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; - void __iomem *base = chip_data->host_data->base; - u32 rtsr, ftsr; -- int err; -+ int err = 0; - - raw_spin_lock(&chip_data->rlock); -+ -+ if (chip_data->hwlock) -+ err = hwspin_lock_timeout(chip_data->hwlock, -+ HWSPINLOCK_TIMEOUT); -+ -+ 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: -+ if (chip_data->hwlock) -+ hwspin_unlock(chip_data->hwlock); -+unlock: - raw_spin_unlock(&chip_data->rlock); - -+ if (d->parent_data->chip) -+ irq_chip_set_type_parent(d, type); -+ - return 0; - } - -@@ -490,6 +517,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; - } - -@@ -502,6 +532,12 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, - return -EINVAL; - } - -+static void stm32_exti_h_ack(struct irq_data *d) -+{ -+ if (d->parent_data->chip) -+ irq_chip_ack_parent(d); -+} -+ - #ifdef CONFIG_PM - static int stm32_exti_h_suspend(void) - { -@@ -547,6 +583,7 @@ static inline void stm32_exti_h_syscore_init(void) {} - 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, -@@ -574,15 +611,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; -@@ -665,6 +716,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, - int nr_irqs, ret, i; - struct irq_chip_generic *gc; - struct irq_domain *domain; -+ struct hwspinlock *hwlock = NULL; - - host_data = stm32_exti_host_init(drv_data, node); - if (!host_data) -@@ -687,12 +739,22 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, - goto out_free_domain; - } - -+ /* hwspinlock is optional */ -+ ret = of_hwspin_lock_get_id(node, 0); -+ if (ret < 0) { -+ if (ret == -EPROBE_DEFER) -+ goto out_free_domain; -+ } else { -+ hwlock = hwspin_lock_request_specific(ret); -+ } -+ - for (i = 0; i < drv_data->bank_nr; i++) { - const struct stm32_exti_bank *stm32_bank; - struct stm32_exti_chip_data *chip_data; - - stm32_bank = drv_data->exti_banks[i]; - chip_data = stm32_exti_chip_init(host_data, i, node); -+ chip_data->hwlock = hwlock; - - gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); - -@@ -760,11 +822,12 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, - { - struct irq_domain *parent_domain, *domain; - struct stm32_exti_host_data *host_data; -+ struct device_node *child; - int ret, i; - - parent_domain = irq_find_host(parent); - if (!parent_domain) { -- pr_err("interrupt-parent not found\n"); -+ pr_err("GIC interrupt-parent not found\n"); - return -EINVAL; - } - -@@ -786,6 +849,40 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, - goto out_unmap; - } - -+ for_each_child_of_node(node, child) { -+ struct device_node *parent_node; -+ u32 nirqs; -+ -+ parent_node = of_irq_find_parent(child); -+ parent_domain = irq_find_host(parent_node); -+ -+ if (!parent_domain) { -+ pr_err("%s: child interrupt-parent not found\n", -+ child->name); -+ ret = -EINVAL; -+ goto out_unmap; -+ } -+ -+ ret = of_property_read_u32(child, "st,irq-number", &nirqs); -+ if (ret != 0 || nirqs == 0) { -+ pr_err("%s: Missing or bad irq-number property\n" -+ , __func__); -+ ret = -EINVAL; -+ goto out_unmap; -+ } -+ -+ domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs, -+ child, -+ &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; -+ } -+ } -+ - stm32_exti_h_syscore_init(); - - return 0; -diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c -index 377e2f5..206a933 100644 ---- a/drivers/mfd/stm32-pwr.c -+++ b/drivers/mfd/stm32-pwr.c -@@ -5,7 +5,9 @@ - */ - - #include -+#include - #include -+#include - #include - #include - #include -@@ -45,7 +47,6 @@ enum wkup_pull_setting { - } \ - - struct stm32_pwr_data { -- struct device *dev; /* self device */ - void __iomem *base; /* IO Memory base address */ - struct irq_domain *domain; /* Domain for this controller */ - int irq; /* Parent interrupt */ -@@ -53,25 +54,19 @@ struct stm32_pwr_data { - - 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); -+ pr_debug("irq:%lu\n", d->hwirq); - SMC(STM32_SVC_PWR, STM32_SET_BITS, WKUPCR, 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); -+ pr_debug("irq:%lu\n", d->hwirq); - SMC(STM32_SVC_PWR, STM32_CLEAR_BITS, MPUWKUPENR, BIT(d->hwirq)); - } - - 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); -+ pr_debug("irq:%lu\n", d->hwirq); - SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq)); - } - -@@ -79,7 +74,7 @@ static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on) - { - struct stm32_pwr_data *priv = d->domain->host_data; - -- dev_dbg(priv->dev, "irq:%lu on:%d\n", d->hwirq, on); -+ pr_debug("irq:%lu on:%d\n", d->hwirq, on); - if (on) - enable_irq_wake(priv->irq); - else -@@ -95,7 +90,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) - u32 wkupcr; - int en; - -- dev_dbg(priv->dev, "irq:%lu\n", d->hwirq); -+ pr_debug("irq:%lu\n", d->hwirq); - - en = readl_relaxed(priv->base + MPUWKUPENR) & BIT(pin_id); - /* reference manual request to disable the wakeup pin while -@@ -115,6 +110,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) - default: - return -EINVAL; - } -+ - SMC(STM32_SVC_PWR, STM32_WRITE, WKUPCR, wkupcr); - - if (en) -@@ -124,7 +120,7 @@ static int stm32_pwr_irq_set_type(struct irq_data *d, unsigned int flow_type) - } - - static struct irq_chip stm32_pwr_irq_chip = { -- .name = "stm32_pwr-irq", -+ .name = "stm32-pwr-irq", - .irq_ack = stm32_pwr_irq_ack, - .irq_mask = stm32_pwr_irq_mask, - .irq_unmask = stm32_pwr_irq_unmask, -@@ -132,29 +128,23 @@ static struct irq_chip stm32_pwr_irq_chip = { - .irq_set_wake = stm32_pwr_irq_set_wake, - }; - --static int stm32_pwr_irq_map(struct irq_domain *h, unsigned int virq, -- irq_hw_number_t hw) --{ -- irq_set_chip_and_handler(virq, &stm32_pwr_irq_chip, handle_edge_irq); -- return 0; --} -- - 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); -+ pr_debug("irq:%d pull config:0x%x\n", pin_id, config); - - if (config >= WKUP_PULL_RESERVED) { -- dev_err(priv->dev, "%s: bad irq pull config\n", __func__); -+ 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; -@@ -164,10 +154,8 @@ 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) - { -- struct stm32_pwr_data *priv = d->host_data; -- - if (WARN_ON(intsize < 3)) { -- dev_err(priv->dev, "%s: bad irq config parameters\n", __func__); -+ pr_err("%s: bad irq config parameters\n", __func__); - return -EINVAL; - } - -@@ -177,9 +165,23 @@ static int stm32_pwr_xlate(struct irq_domain *d, struct device_node *ctrlr, - 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 = { -- .map = stm32_pwr_irq_map, -+ .alloc = stm32_pwr_alloc, - .xlate = stm32_pwr_xlate, -+ .free = irq_domain_free_irqs_common, - }; - - /* -@@ -195,9 +197,10 @@ static void stm32_pwr_handle_irq(struct irq_desc *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))) { -- dev_dbg(priv->dev, "handle wkup irq:%d\n", i); -+ pr_debug("handle wkup irq:%d\n", i); - generic_handle_irq(irq_find_mapping(priv->domain, i)); - } - } -@@ -205,27 +208,21 @@ static void stm32_pwr_handle_irq(struct irq_desc *desc) - chained_irq_exit(chip, desc); - } - --static int stm32_pwr_probe(struct platform_device *pdev) -+static int __init stm32_pwr_init(struct device_node *np, -+ struct device_node *parent) - { -- struct device *dev = &pdev->dev; -- struct device_node *np = pdev->dev.of_node; - struct stm32_pwr_data *priv; -- -- struct resource *res; - int ret; - -- priv = devm_kzalloc(dev, sizeof(struct stm32_pwr_data), GFP_KERNEL); -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - -- platform_set_drvdata(pdev, priv); -- priv->dev = dev; -- -- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- priv->base = devm_ioremap_resource(&pdev->dev, res); -+ priv->base = of_iomap(np, 0); - if (IS_ERR(priv->base)) { -- dev_err(dev, "%s: Unable to map IO memory\n", __func__); -- return PTR_ERR(priv->base); -+ pr_err("%s: Unable to map IO memory\n", __func__); -+ ret = PTR_ERR(priv->base); -+ goto out_free; - } - - /* Disable all wake-up pins */ -@@ -236,52 +233,38 @@ static int stm32_pwr_probe(struct platform_device *pdev) - 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__); -- goto out; -+ pr_err("%s: Unable to add irq domain!\n", __func__); -+ ret = -ENOMEM; -+ goto out_unmap; - } - -- ret = platform_get_irq(pdev, 0); -- if (ret < 0) { -- dev_err(dev, "failed to get PWR IRQ\n"); -- goto err; -+ priv->irq = irq_of_parse_and_map(np, 0); -+ if (priv->irq < 0) { -+ pr_err("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); - --out: -+ of_node_clear_flag(np, OF_POPULATED); -+ - return 0; --err: -+ -+out_domain: - irq_domain_remove(priv->domain); -+out_unmap: -+ iounmap(priv->base); -+out_free: -+ kfree(priv); - return ret; - } - --static int stm32_pwr_remove(struct platform_device *pdev) -+static int __init stm32_pwr_of_init(struct device_node *np, -+ struct device_node *parent) - { -- struct stm32_pwr_data *priv = platform_get_drvdata(pdev); -- -- irq_domain_remove(priv->domain); -- return 0; -+ return stm32_pwr_init(np, parent); - } - --static const struct of_device_id stm32_pwr_match[] = { -- { .compatible = "st,stm32mp1-pwr" }, -- {}, --}; -- --static struct platform_driver stm32_pwr_driver = { -- .probe = stm32_pwr_probe, -- .remove = stm32_pwr_remove, -- .driver = { -- .name = "stm32-pwr", -- .owner = THIS_MODULE, -- .of_match_table = stm32_pwr_match, -- }, --}; -- --static int __init stm32_pwr_init(void) --{ -- return platform_driver_register(&stm32_pwr_driver); --} --arch_initcall(stm32_pwr_init); -+IRQCHIP_DECLARE(stm32mp1_pwr_irq, "st,stm32mp1-pwr", stm32_pwr_of_init); -diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c -index 5bf6328..648315d 100644 ---- a/drivers/mfd/stpmic1.c -+++ b/drivers/mfd/stpmic1.c -@@ -268,13 +268,8 @@ static int stpmic1_probe(struct i2c_client *i2c, - return ddata->irq; - } - -- ddata->irq_wake = of_irq_get(np, STPMIC1_WAKEUP_IRQ); -- if (ddata->irq_wake > 0) { -+ if (of_property_read_bool(np, "wakeup-source")) - device_init_wakeup(dev, true); -- ret = dev_pm_set_dedicated_wake_irq(dev, ddata->irq_wake); -- if (ret) -- dev_warn(dev, "failed to set up wakeup irq"); -- } - - if (!of_property_read_u32(np, "st,main-control-register", ®)) { - ret = regmap_update_bits(ddata->regmap, -@@ -371,8 +366,8 @@ static int stpmic1_suspend(struct device *dev) - struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); - - disable_irq(pmic_dev->irq); -- if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev)) -- enable_irq_wake(pmic_dev->irq_wake); -+ if (device_may_wakeup(dev)) -+ enable_irq_wake(pmic_dev->irq); - - return 0; - } -@@ -387,9 +382,10 @@ 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); -- if ((pmic_dev->irq_wake > 0) && device_may_wakeup(dev)) -- disable_irq_wake(pmic_dev->irq_wake); - - return 0; - } -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..755863a 100644 ---- a/drivers/mfd/wm8994-core.c -+++ b/drivers/mfd/wm8994-core.c -@@ -12,6 +12,7 @@ - * - */ - -+#include - #include - #include - #include -@@ -314,6 +315,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/linux/mfd/stpmic1.h b/include/linux/mfd/stpmic1.h -index 4abe5f1..fa3f99f 100644 ---- a/include/linux/mfd/stpmic1.h -+++ b/include/linux/mfd/stpmic1.h -@@ -206,7 +206,6 @@ struct stpmic1 { - struct device *dev; - struct regmap *regmap; - int irq; -- int irq_wake; - struct regmap_irq_chip_data *irq_data; - }; - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0023-ARM-stm32mp1-r0-rc2-USB.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0023-ARM-stm32mp1-r0-rc2-USB.patch deleted file mode 100644 index c0eede0..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0023-ARM-stm32mp1-r0-rc2-USB.patch +++ /dev/null @@ -1,1199 +0,0 @@ -From 1829c178ee6739cc89484f6f6dc475a257e713ef Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:49:28 +0100 -Subject: [PATCH 23/52] ARM-stm32mp1-r0-rc2-USB - ---- - .../devicetree/bindings/phy/phy-stm32-usbphyc.txt | 65 ++- - Documentation/devicetree/bindings/usb/dwc2.txt | 7 + - Documentation/devicetree/bindings/usb/usb-ehci.txt | 1 + - drivers/phy/st/phy-stm32-usbphyc.c | 451 ++++++++++++++++++--- - drivers/usb/dwc2/core.c | 2 + - drivers/usb/dwc2/core.h | 7 + - drivers/usb/dwc2/hcd.c | 60 +-- - drivers/usb/dwc2/hw.h | 2 + - drivers/usb/dwc2/params.c | 31 ++ - drivers/usb/dwc2/platform.c | 47 +++ - drivers/usb/host/ehci-platform.c | 32 ++ - 11 files changed, 602 insertions(+), 103 deletions(-) - -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/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt -index 46da5f1..32b245c 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,10 @@ 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. - - Deprecated properties: - - g-use-dma: gadget DMA mode is automatically detected -diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt -index 0f1b753..f5d91d0 100644 ---- a/Documentation/devicetree/bindings/usb/usb-ehci.txt -+++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt -@@ -18,6 +18,7 @@ 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 - - additionally the properties from usb-hcd.txt (in the current directory) are - supported. -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/usb/dwc2/core.c b/drivers/usb/dwc2/core.c -index 55d5ae2..a298fae 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; -@@ -122,6 +123,7 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) - 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; -diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index cc9c93a..4c689d1 100644 ---- a/drivers/usb/dwc2/core.h -+++ b/drivers/usb/dwc2/core.h -@@ -397,6 +397,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 -@@ -463,6 +467,7 @@ struct dwc2_core_params { - bool hird_threshold_en; - 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; -@@ -653,6 +658,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 +675,7 @@ struct dwc2_gregs_backup { - u32 grxfsiz; - u32 gnptxfsiz; - u32 gi2cctl; -+ u32 ggpio; - u32 glpmcfg; - u32 pcgcctl; - u32 pcgcctl1; -diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c -index 260010a..12fa6c0 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) -@@ -3564,6 +3545,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - u32 port_status; - u32 speed; - u32 pcgctl; -+ u32 pwr; - - switch (typereq) { - case ClearHubFeature: -@@ -3612,8 +3594,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - dev_dbg(hsotg->dev, - "ClearPortFeature USB_PORT_FEAT_POWER\n"); - hprt0 = dwc2_read_hprt0(hsotg); -+ pwr = hprt0 & HPRT0_PWR; - hprt0 &= ~HPRT0_PWR; - dwc2_writel(hsotg, hprt0, HPRT0); -+ if (pwr) -+ dwc2_vbus_supply_exit(hsotg); - break; - - case USB_PORT_FEAT_INDICATOR: -@@ -3823,8 +3808,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - dev_dbg(hsotg->dev, - "SetPortFeature - USB_PORT_FEAT_POWER\n"); - hprt0 = dwc2_read_hprt0(hsotg); -+ pwr = hprt0 & HPRT0_PWR; - hprt0 |= HPRT0_PWR; - dwc2_writel(hsotg, hprt0, HPRT0); -+ if (!pwr) -+ dwc2_vbus_supply_init(hsotg); - break; - - case USB_PORT_FEAT_RESET: -@@ -3841,6 +3829,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - dwc2_writel(hsotg, 0, PCGCTL); - - hprt0 = dwc2_read_hprt0(hsotg); -+ pwr = hprt0 & HPRT0_PWR; - /* Clear suspend bit if resetting from suspend state */ - hprt0 &= ~HPRT0_SUSP; - -@@ -3854,6 +3843,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, - dev_dbg(hsotg->dev, - "In host mode, hprt0=%08x\n", hprt0); - dwc2_writel(hsotg, hprt0, HPRT0); -+ if (!pwr) -+ dwc2_vbus_supply_init(hsotg); - } - - /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ -@@ -4393,6 +4384,7 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) - struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); - struct usb_bus *bus = hcd_to_bus(hcd); - unsigned long flags; -+ u32 hprt0; - int ret; - - dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); -@@ -4409,12 +4401,16 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd) - - dwc2_hcd_reinit(hsotg); - -- /* enable external vbus supply before resuming root hub */ -- spin_unlock_irqrestore(&hsotg->lock, flags); -- ret = dwc2_vbus_supply_init(hsotg); -- if (ret) -- return ret; -- spin_lock_irqsave(&hsotg->lock, flags); -+ hprt0 = dwc2_read_hprt0(hsotg); -+ /* Has vbus power been turned on in dwc2_core_host_init ? */ -+ if (hprt0 & HPRT0_PWR) { -+ /* Enable external vbus supply before resuming root hub */ -+ spin_unlock_irqrestore(&hsotg->lock, flags); -+ ret = dwc2_vbus_supply_init(hsotg); -+ if (ret) -+ return ret; -+ spin_lock_irqsave(&hsotg->lock, flags); -+ } - - /* Initialize and connect root hub if one is not already attached */ - if (bus->root_hub) { -@@ -4436,6 +4432,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) - { - struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); - unsigned long flags; -+ u32 hprt0; - - /* Turn off all host-specific interrupts */ - dwc2_disable_host_interrupts(hsotg); -@@ -4444,6 +4441,7 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) - synchronize_irq(hcd->irq); - - spin_lock_irqsave(&hsotg->lock, flags); -+ hprt0 = dwc2_read_hprt0(hsotg); - /* Ensure hcd is disconnected */ - dwc2_hcd_disconnect(hsotg, true); - dwc2_hcd_stop(hsotg); -@@ -4452,7 +4450,9 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd) - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - spin_unlock_irqrestore(&hsotg->lock, flags); - -- dwc2_vbus_supply_exit(hsotg); -+ /* keep balanced supply init/exit by checking HPRT0_PWR */ -+ if (hprt0 & HPRT0_PWR) -+ dwc2_vbus_supply_exit(hsotg); - - usleep_range(1000, 3000); - } -diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h -index 0ca8e7b..afde335 100644 ---- a/drivers/usb/dwc2/hw.h -+++ b/drivers/usb/dwc2/hw.h -@@ -227,6 +227,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 bf7052e..63ccfc9 100644 ---- a/drivers/usb/dwc2/params.c -+++ b/drivers/usb/dwc2/params.c -@@ -143,6 +143,33 @@ 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; -+} -+ -+static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_hsotg *hsotg) -+{ -+ struct dwc2_core_params *p = &hsotg->params; -+ -+ p->activate_stm_id_vb_detection = true; -+ p->host_rx_fifo_size = 440; -+ p->host_nperio_tx_fifo_size = 256; -+ p->host_perio_tx_fifo_size = 256; -+ p->power_down = false; -+} -+ - 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 }, -@@ -163,6 +190,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 5776428..2061254 100644 ---- a/drivers/usb/dwc2/platform.c -+++ b/drivers/usb/dwc2/platform.c -@@ -432,6 +432,14 @@ static int dwc2_driver_probe(struct platform_device *dev) - if (retval) - return retval; - -+ 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,6 +474,45 @@ static int dwc2_driver_probe(struct platform_device *dev) - if (retval) - goto error; - -+ if (hsotg->params.activate_stm_id_vb_detection) { -+ struct regulator *usb33d; -+ u32 ggpio; -+ -+ usb33d = devm_regulator_get(hsotg->dev, "usb33d"); -+ if (IS_ERR(usb33d)) { -+ retval = PTR_ERR(usb33d); -+ dev_err(hsotg->dev, -+ "can't get voltage level detector supply\n"); -+ goto error; -+ } -+ retval = regulator_enable(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); -+ } -+ -+ 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) -diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c -index 4c306fb..c429b52 100644 ---- a/drivers/usb/host/ehci-platform.c -+++ b/drivers/usb/host/ehci-platform.c -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -43,6 +44,7 @@ - struct ehci_platform_priv { - struct clk *clks[EHCI_MAX_CLKS]; - struct reset_control *rsts; -+ struct regulator *vbus_supply; - bool reset_on_resume; - }; - -@@ -73,6 +75,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 +132,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 +223,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) --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0025-ARM-stm32mp1-r0-rc2-REMOTEPROC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0025-ARM-stm32mp1-r0-rc2-REMOTEPROC.patch deleted file mode 100644 index 56ed52d..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0025-ARM-stm32mp1-r0-rc2-REMOTEPROC.patch +++ /dev/null @@ -1,372 +0,0 @@ -From 222782ff647dfeb33bb442031792a893372fad82 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:43:58 +0100 -Subject: [PATCH 25/52] ARM-stm32mp1-r0-rc2-REMOTEPROC - ---- - .../devicetree/bindings/remoteproc/rproc-srm.txt | 14 ++- - .../devicetree/bindings/remoteproc/stm32-rproc.txt | 15 ++- - drivers/nvmem/stm32-romem.c | 44 +++++---- - drivers/remoteproc/rproc_srm_core.h | 14 +-- - drivers/remoteproc/rproc_srm_dev.c | 103 +-------------------- - drivers/remoteproc/stm32_rproc.c | 2 +- - 6 files changed, 42 insertions(+), 150 deletions(-) - -diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -index dce10c0..19a5255 100644 ---- a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -+++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -@@ -23,12 +23,16 @@ Optional properties: - - clocks: clocks required by the coprocessor - - clock-names: see clock-bindings.txt - - pinctrl-x: pins configurations required by the coprocessor --- pinctrl-names: see pinctrl-bindings.txt. -- "rproc_default" is a special pin configuration which is applied except -- if the 'early-booted' property is set. -- In a general way, it is recommended to use names prefixed with "rproc_". -+ The SRM reserves the pins for the coprocessor, which prevents the local -+ processor to use them. -+- pinctrl-names: all names must be prefixed with "rproc_" (ex: "rproc_default"). -+ This rule must be strictly followed in order to prevent the SRM to -+ (over)write a pin configuration which is done by the coprocessor. - - x-supply: power supplies required by the coprocessor --- interrupts: see interrupts.txt -+- 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 - -diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -index ee00f1c..7df6a26 100644 ---- a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -+++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -@@ -33,18 +33,15 @@ Optional properties: - - 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 for two different purposes: -- - used by the remote proc to signal when it has completed -- its critical initalisation. -- Mono-directional channel: from remote to local -- - 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 -+ - 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 "init_shdn" for channel (c) -+ - 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 -diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c -index 198872f..34b388c 100644 ---- a/drivers/nvmem/stm32-romem.c -+++ b/drivers/nvmem/stm32-romem.c -@@ -19,6 +19,12 @@ - #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; - }; -@@ -77,13 +83,21 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf, - return -EINVAL; - - for (i = roffset; (i < roffset + rbytes); i += 4) { -- ret = stm32_bsec_smc(STM32_SMC_READ_OTP, i >> 2, 0, &val); -- if (ret) { -- dev_err(priv->dev, "Failed to read data%d (%d)\n", -- i >> 2, ret); -- return ret; -+ 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)); -@@ -127,7 +141,6 @@ 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 nvmem_device *nvmem; - struct resource *res; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -@@ -154,26 +167,12 @@ static int stm32_romem_probe(struct platform_device *pdev) - priv->cfg.size = resource_size(res); - priv->cfg.reg_read = stm32_romem_read; - } else { -- priv->cfg.read_only = false; - priv->cfg.size = cfg->size; - priv->cfg.reg_read = stm32_bsec_read; - priv->cfg.reg_write = stm32_bsec_write; - } - -- nvmem = nvmem_register(&priv->cfg); -- if (IS_ERR(nvmem)) -- return PTR_ERR(nvmem); -- -- platform_set_drvdata(pdev, nvmem); -- -- return 0; --} -- --static int stm32_romem_remove(struct platform_device *pdev) --{ -- struct nvmem_device *nvmem = platform_get_drvdata(pdev); -- -- return nvmem_unregister(nvmem); -+ return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); - } - - static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { -@@ -191,7 +190,6 @@ MODULE_DEVICE_TABLE(of, stm32_romem_of_match); - - static struct platform_driver stm32_romem_driver = { - .probe = stm32_romem_probe, -- .remove = stm32_romem_remove, - .driver = { - .name = "stm32-romem", - .of_match_table = of_match_ptr(stm32_romem_of_match), -diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h -index 7915f35..7dffdb38 100644 ---- a/drivers/remoteproc/rproc_srm_core.h -+++ b/drivers/remoteproc/rproc_srm_core.h -@@ -20,12 +20,10 @@ - /** - * Resource type used in resource manager rpmsg: - * RPROC_SRM_RSC_CLOCK: clock resource -- * RPROC_SRM_RSC_PIN: pin resource - * RPROC_SRM_RSC_REGU: regulator resource - */ - #define RPROC_SRM_RSC_CLOCK 0x00 --#define RPROC_SRM_RSC_PIN 0x01 --#define RPROC_SRM_RSC_REGU 0x02 -+#define RPROC_SRM_RSC_REGU 0x01 - - /** - * struct clock_cfg - clock configuration used in resource manager rpmsg -@@ -63,14 +61,6 @@ struct regu_cfg { - }; - - /** -- * struct pin_cfg - pin configuration used in resource manager rpmsg -- * @name: current pin configuration name (meaningful in GetConfig message) -- */ --struct pin_cfg { -- u8 name[16]; --}; -- --/** - * struct rpmsg_srm_msg - message structure used between processors to - * dynamically update resources configuration - * @message_type: type of the message: see RPROC_SRM_MSG* -@@ -81,7 +71,6 @@ struct pin_cfg { - * 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 -- * @pin_cfg: pin config - relevant if &rsc_type is RPROC_SRM_RSC_PIN - */ - struct rpmsg_srm_msg { - u32 message_type; -@@ -90,7 +79,6 @@ struct rpmsg_srm_msg { - union { - struct clock_cfg clock_cfg; - struct regu_cfg regu_cfg; -- struct pin_cfg pin_cfg; - }; - }; - -diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c -index b026f961..7dc99c5 100644 ---- a/drivers/remoteproc/rproc_srm_dev.c -+++ b/drivers/remoteproc/rproc_srm_dev.c -@@ -31,7 +31,6 @@ struct rproc_srm_pin_info { - struct list_head list; - unsigned int index; - char *name; -- bool selected; - }; - - struct rproc_srm_regu_info { -@@ -544,83 +543,6 @@ static int rproc_srm_dev_regus_get(struct rproc_srm_dev *rproc_srm_dev) - } - - /* Pins */ --static int rproc_srm_dev_pin_set_cfg(struct rproc_srm_dev *rproc_srm_dev, -- struct pin_cfg *cfg) --{ -- struct rproc_srm_pin_info *pi, *p = NULL; -- struct device *dev = rproc_srm_dev->dev; -- struct pinctrl_state *state; -- int ret; -- -- list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) { -- if (!strcmp(pi->name, cfg->name)) { -- p = pi; -- break; -- } -- } -- -- if (!p) { -- dev_err(dev, "unknown pin config (%s)\n", cfg->name); -- return -EINVAL; -- } -- -- state = pinctrl_lookup_state(rproc_srm_dev->pctrl, cfg->name); -- if (IS_ERR(state)) { -- dev_err(dev, "cannot get pin config (%s)\n", cfg->name); -- return -EINVAL; -- } -- -- ret = pinctrl_select_state(rproc_srm_dev->pctrl, state); -- if (ret < 0) { -- dev_err(dev, "cannot set pin config (%s)\n", cfg->name); -- return ret; -- } -- -- list_for_each_entry(pi, &rproc_srm_dev->pin_list_head, list) { -- pi->selected = (pi == p); -- } -- -- dev_dbg(dev, "pin config (%s) selected\n", p->name); -- -- return 0; --} -- --static int rproc_srm_dev_pin_get_cfg(struct rproc_srm_dev *rproc_srm_dev, -- struct pin_cfg *cfg) --{ -- struct rproc_srm_pin_info *p; -- -- list_for_each_entry(p, &rproc_srm_dev->pin_list_head, list) { -- if (p->selected) { -- strlcpy(cfg->name, p->name, sizeof(cfg->name)); -- return 0; -- } -- } -- -- dev_warn(rproc_srm_dev->dev, "cannot find selected pin state\n"); -- strcpy(cfg->name, ""); -- -- return 0; --} -- --static int rproc_srm_dev_pins_setup(struct rproc_srm_dev *rproc_srm_dev) --{ -- struct rproc_srm_pin_info *p; -- struct pin_cfg cfg = { .name = "rproc_default" }; -- -- if (rproc_srm_dev->early_boot) -- /* in early_boot mode do not update pin config */ -- return 0; -- -- /* set the "rproc_default" pin config if defined */ -- list_for_each_entry(p, &rproc_srm_dev->pin_list_head, list) { -- if (!strcmp(p->name, cfg.name)) -- return rproc_srm_dev_pin_set_cfg(rproc_srm_dev, &cfg); -- } -- -- return 0; --} -- - static void rproc_srm_dev_pins_put(struct rproc_srm_dev *rproc_srm_dev) - { - struct device *dev = rproc_srm_dev->dev; -@@ -677,11 +599,9 @@ static int rproc_srm_dev_pins_get(struct rproc_srm_dev *rproc_srm_dev) - } - p->name = devm_kstrdup(dev, name, GFP_KERNEL); - -- if (!strcmp(p->name, PINCTRL_STATE_DEFAULT)) { -- if (rproc_srm_dev->early_boot) -- dev_warn(dev, "pin config potentially overwritten!\n"); -- p->selected = true; -- } -+ /* pinctrl-names shall not be "default" (but "rproc_default") */ -+ if (!strcmp(p->name, PINCTRL_STATE_DEFAULT)) -+ dev_warn(dev, "pin config potentially overwritten!\n"); - - p->index = i; - -@@ -726,13 +646,6 @@ static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt, - ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, - &o.clock_cfg); - break; -- case RPROC_SRM_RSC_PIN: -- ret = rproc_srm_dev_pin_set_cfg(rproc_srm_dev, -- &i->pin_cfg); -- if (!ret) -- ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev, -- &o.pin_cfg); -- break; - case RPROC_SRM_RSC_REGU: - ret = rproc_srm_dev_regu_set_cfg(rproc_srm_dev, - &i->regu_cfg); -@@ -752,10 +665,6 @@ static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt, - ret = rproc_srm_dev_clock_get_cfg(rproc_srm_dev, - &o.clock_cfg); - break; -- case RPROC_SRM_RSC_PIN: -- ret = rproc_srm_dev_pin_get_cfg(rproc_srm_dev, -- &o.pin_cfg); -- break; - case RPROC_SRM_RSC_REGU: - ret = rproc_srm_dev_regu_get_cfg(rproc_srm_dev, - &o.regu_cfg); -@@ -810,11 +719,7 @@ rproc_srm_dev_bind(struct device *dev, struct device *master, void *data) - if (ret) - return ret; - -- ret = rproc_srm_dev_pins_setup(rproc_srm_dev); -- if (ret) -- return ret; -- -- /* For IRQs: nothing to setup */ -+ /* For pins and IRQs: nothing to setup */ - return 0; - } - -diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index 998de67..548afdd 100644 ---- a/drivers/remoteproc/stm32_rproc.c -+++ b/drivers/remoteproc/stm32_rproc.c -@@ -29,7 +29,7 @@ - - #define STM32_MBX_VQ0 "vq0" - #define STM32_MBX_VQ1 "vq1" --#define STM32_MBX_SHUTDOWN "init_shdn" -+#define STM32_MBX_SHUTDOWN "shutdown" - - struct stm32_syscon { - struct regmap *map; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0026-ARM-stm32mp1-r0-rc2-NET.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0026-ARM-stm32mp1-r0-rc2-NET.patch deleted file mode 100644 index b3ae5d9..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0026-ARM-stm32mp1-r0-rc2-NET.patch +++ /dev/null @@ -1,273 +0,0 @@ -From f03da721a19075ead436b2edbe4c4080feb8dac8 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:44:24 +0100 -Subject: [PATCH 26/52] ARM-stm32mp1-r0-rc2-NET - ---- - .../devicetree/bindings/net/stm32-dwmac.txt | 6 +- - drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 102 +++++++++++++++++---- - .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 + - .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 ++ - 4 files changed, 94 insertions(+), 23 deletions(-) - -diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt -index 1341012..f42dc68 100644 ---- a/Documentation/devicetree/bindings/net/stm32-dwmac.txt -+++ b/Documentation/devicetree/bindings/net/stm32-dwmac.txt -@@ -24,9 +24,9 @@ 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 -+- 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/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -index d1cf145..545b168 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,15 +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 */ -+ int eth_clk_sel_reg; -+ int eth_ref_clk_sel_reg; - int irq_pwr_wakeup; -- u32 mode_reg; /* MAC glue-logic mode register */ -+ u32 mode_reg; /* MAC glue-logic mode register */ - struct regmap *regmap; - u32 speed; - const struct stm32_ops *ops; -@@ -103,7 +157,7 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare) - if (ret) - return ret; - -- if (dwmac->int_phyclk) { -+ if (dwmac->clk_eth_ck) { - ret = clk_prepare_enable(dwmac->clk_eth_ck); - if (ret) { - clk_disable_unprepare(dwmac->syscfg_clk); -@@ -112,7 +166,7 @@ static int stm32mp1_clk_prepare(struct stm32_dwmac *dwmac, bool prepare) - } - } else { - clk_disable_unprepare(dwmac->syscfg_clk); -- if (dwmac->int_phyclk) -+ if (dwmac->clk_eth_ck) - clk_disable_unprepare(dwmac->clk_eth_ck); - } - return ret; -@@ -122,7 +176,7 @@ 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; -+ int val, ret; - - switch (plat_dat->interface) { - case PHY_INTERFACE_MODE_MII: -@@ -131,19 +185,19 @@ 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: - 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; -@@ -154,6 +208,11 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) - return -EINVAL; - } - -+ /* Need to update PMCCLRR (clear register) */ -+ ret = regmap_update_bits(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, -+ dwmac->ops->syscfg_eth_mask, ~val); -+ -+ /* Update PMCSETR (set register) */ - return regmap_update_bits(dwmac->regmap, reg, - dwmac->ops->syscfg_eth_mask, val); - } -@@ -237,22 +296,25 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, - struct device_node *np = dev->of_node; - int err = 0; - -- 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); - } - -@@ -268,7 +330,7 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, - */ - dwmac->irq_pwr_wakeup = platform_get_irq_byname(pdev, - "stm32_pwr_wakeup"); -- if (!dwmac->int_phyclk && dwmac->irq_pwr_wakeup >= 0) { -+ 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"); -@@ -370,7 +432,7 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac) - - clk_disable_unprepare(dwmac->clk_tx); - clk_disable_unprepare(dwmac->syscfg_clk); -- if (dwmac->int_phyclk) -+ if (dwmac->clk_eth_ck) - clk_disable_unprepare(dwmac->clk_eth_ck); - - return ret; -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; - } --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0027-ARM-stm32mp1-r0-rc2-HWCLK-SPI.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0027-ARM-stm32mp1-r0-rc2-HWCLK-SPI.patch deleted file mode 100644 index 975810c..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0027-ARM-stm32mp1-r0-rc2-HWCLK-SPI.patch +++ /dev/null @@ -1,1082 +0,0 @@ -From 064e22b81e0a4a24f48af50df7b6505a80fdcb42 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:45:11 +0100 -Subject: [PATCH 27/52] ARM-stm32mp1-r0-rc2-HWCLK-SPI - ---- - .../bindings/hwlock/st,stm32-hwspinlock.txt | 23 ++ - arch/arm/include/debug/stm32.S | 48 +++ - drivers/clk/clk-stm32mp1.c | 100 +++--- - drivers/spi/spi-stm32.c | 380 +++++++++++++-------- - 4 files changed, 352 insertions(+), 199 deletions(-) - create mode 100644 Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt - create mode 100644 arch/arm/include/debug/stm32.S - -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/arch/arm/include/debug/stm32.S b/arch/arm/include/debug/stm32.S -new file mode 100644 -index 0000000..427561e ---- /dev/null -+++ b/arch/arm/include/debug/stm32.S -@@ -0,0 +1,48 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (C) STMicroelectronics SA 2017 - All Rights Reserved -+ * Author: Gerald Baeza for STMicroelectronics. -+ */ -+ -+#ifdef CONFIG_ARM_SINGLE_ARMV7M -+#define STM32_UART_BASE_PHYS 0x40011000 /* USART1 */ -+#define STM32_UART_BASE_VIRT STM32_UART_BASE_PHYS /* no MMU */ -+#else -+#define STM32_UART_BASE_PHYS 0x40010000 /* UART4 */ -+#define STM32_UART_BASE_VIRT 0xfe010000 /* UART4 */ -+#endif -+ -+ -+#ifdef CONFIG_STM32F4_DEBUG_UART -+#define STM32_USART_SR_OFF 0x00 -+#define STM32_USART_TDR_OFF 0x04 -+#endif -+ -+#ifdef CONFIG_STM32F7_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, =STM32_UART_BASE_PHYS @ physical base -+ ldr \rv, =STM32_UART_BASE_VIRT @ virt base -+.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/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index 50d739a..7eccaa1 100644 ---- a/drivers/clk/clk-stm32mp1.c -+++ b/drivers/clk/clk-stm32mp1.c -@@ -52,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 -@@ -2672,8 +2673,6 @@ CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); - * - */ - --static struct regmap *pwr_syscon; -- - struct reg { - u32 address; - u32 val; -@@ -2697,24 +2696,31 @@ 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[] = { -- { 0xA00, 0 }, /* APB1 */ -- { 0xA08, 0 }, /* APB2 */ -- { 0xA10, 0 }, /* APB3 */ -- { 0x200, 0 }, /* APB4 */ -- { 0x208, 1 }, /* APB5 */ -- { 0x210, 1 }, /* AHB5 */ -- { 0x218, 0 }, /* AHB6 */ -- { 0xA18, 0 }, /* AHB2 */ -- { 0xA20, 0 }, /* AHB3 */ -- { 0xA28, 0 }, /* AHB4 */ -- { 0xA38, 0 }, /* MLAHB */ -- { 0x800, 0 }, /* MCO1 */ -- { 0x804, 0 }, /* MCO2 */ -- { 0x894, 0 }, /* PLL4 */ -- { 0x89C, 0 }, /* PLL4CFGR2 */ -+ 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 { -@@ -2767,12 +2773,13 @@ struct smux _mux_kernel[] = { - }; - - static struct sreg pll_clock[] = { -- { 0x880, 0 }, /* PLL3 */ -- { 0x894, 0 }, /* PLL4 */ -+ SREG(RCC_PLL3CR, 0, 0), -+ SREG(RCC_PLL4CR, 0, 0), - }; - - static struct sreg mcu_source[] = { -- { 0x048, 0 }, /* MSSCKSELR */ -+ SREG(RCC_MCUDIVR, 0, 0), -+ SREG(RCC_MSSCKSELR, 0, 0), - }; - - #define RCC_IRQ_FLAGS_MASK 0x110F1F -@@ -2784,9 +2791,6 @@ static struct sreg mcu_source[] = { - #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"); -@@ -2808,7 +2812,7 @@ static void stm32mp1_backup_sreg(struct sreg *sreg, int size) - static void stm32mp1_restore_sreg(struct sreg *sreg, int size) - { - int i; -- u32 val, address; -+ u32 val, address, reg; - int soc_secured; - - soc_secured = _is_soc_secured(rcc_base); -@@ -2817,11 +2821,21 @@ static void stm32mp1_restore_sreg(struct sreg *sreg, int size) - val = sreg[i].val; - address = sreg[i].address; - -- if (soc_secured && sreg[i].secured) -- SMC(STM32_SVC_RCC, STM32_WRITE, -- address, val); -- else -+ 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); -+ } - } - } - -@@ -2893,31 +2907,23 @@ static int stm32mp1_clk_suspend(void) - 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) - { -- u32 power_flags_rcc, power_flags_pwr; - -- /* Read power flags and decide what to resume */ -- regmap_read(pwr_syscon, PWR_MPUCR, &power_flags_pwr); -- power_flags_rcc = readl_relaxed(rcc_base + RCC_RSTSR); -+ /* Restore pll */ -+ stm32mp1_restore_pll(pll_clock, ARRAY_SIZE(pll_clock)); - -- if ((power_flags_pwr & STOP_FLAG) == STOP_FLAG) { -- /* Restore pll */ -- stm32mp1_restore_pll(pll_clock, ARRAY_SIZE(pll_clock)); -+ /* Restore mcu source */ -+ stm32mp1_restore_sreg(mcu_source, ARRAY_SIZE(mcu_source)); - -- /* Restore mcu source */ -- stm32mp1_restore_sreg(mcu_source, ARRAY_SIZE(mcu_source)); -- } else if (((power_flags_rcc & SBF) == SBF) || -- ((power_flags_rcc & SBF_MPU) == SBF_MPU)) { -- stm32mp1_restore_sreg(clock_gating, ARRAY_SIZE(clock_gating)); -+ stm32mp1_restore_sreg(clock_gating, ARRAY_SIZE(clock_gating)); - -- stm32mp1_restore_mux(_mux_kernel, ARRAY_SIZE(_mux_kernel)); -- } -- -- SMC(STM32_SVC_RCC, STM32_WRITE, RCC_RSTSR, 0); -+ 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, -@@ -2941,12 +2947,6 @@ static int stm32_rcc_init_pwr(struct device_node *np) - int ret; - int i; - -- pwr_syscon = syscon_regmap_lookup_by_phandle(np, "st,pwr"); -- if (IS_ERR(pwr_syscon)) { -- pr_err("%s: pwr syscon required !\n", __func__); -- return PTR_ERR(pwr_syscon); -- } -- - /* register generic irq */ - irq = of_irq_get(np, 0); - if (irq < 0) { -diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c -index ad1e55d..789e335 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); - -@@ -282,19 +282,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 +305,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 +368,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 +398,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 +424,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 +459,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 +504,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 +512,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 +667,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 +727,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 +742,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 +759,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 +775,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 +814,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 +827,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 +843,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 +854,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 +867,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 +882,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 +916,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 +947,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 +974,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 +1018,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 +1036,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 +1133,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 +1146,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); -@@ -1179,36 +1238,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 +1289,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 +1301,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 +1319,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 +1360,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.9/0028-ARM-stm32mp1-r0-rc2-MMC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0028-ARM-stm32mp1-r0-rc2-MMC.patch deleted file mode 100644 index e4edefb..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0028-ARM-stm32mp1-r0-rc2-MMC.patch +++ /dev/null @@ -1,241 +0,0 @@ -From bf3772b12539b3595e60b8b334051160269f9071 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:45:33 +0100 -Subject: [PATCH 28/52] ARM-stm32mp1-r0-rc2-MMC - ---- - drivers/mmc/host/mmci.c | 36 +++++++++++++++++++++++++----------- - drivers/mmc/host/mmci.h | 13 +++++++++++-- - 2 files changed, 36 insertions(+), 13 deletions(-) - -diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index db50d1e..02b631f 100644 ---- a/drivers/mmc/host/mmci.c -+++ b/drivers/mmc/host/mmci.c -@@ -135,7 +135,6 @@ static struct variant_data variant_u300 = { - .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, -@@ -146,6 +145,7 @@ static struct variant_data variant_u300 = { - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, - .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_nomadik = { -@@ -161,7 +161,6 @@ static struct variant_data variant_nomadik = { - .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, -@@ -173,6 +172,7 @@ static struct variant_data variant_nomadik = { - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, - .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_ux500 = { -@@ -190,7 +190,6 @@ static struct variant_data variant_ux500 = { - .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, -@@ -206,6 +205,7 @@ static struct variant_data variant_ux500 = { - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, - .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_ux500v2 = { -@@ -224,7 +224,6 @@ static struct variant_data variant_ux500v2 = { - .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, -@@ -241,6 +240,7 @@ static struct variant_data variant_ux500v2 = { - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, - .init = mmci_variant_init, -+ .quirks = MMCI_QUIRK_ST_SDIO, - }; - - static struct variant_data variant_stm32 = { -@@ -259,13 +259,13 @@ static struct variant_data variant_stm32 = { - .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 = { -@@ -284,12 +284,14 @@ static struct variant_data variant_stm32_sdmmc = { - .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, - }; - - static struct variant_data variant_stm32_sdmmcv2 = { -@@ -308,6 +310,7 @@ static struct variant_data variant_stm32_sdmmcv2 = { - .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, -@@ -315,6 +318,7 @@ static struct variant_data variant_stm32_sdmmcv2 = { - .busy_detect_flag = MCI_STM32_BUSYD0, - .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, - .init = sdmmc_variant_init, -+ .quirks = MMCI_QUIRK_STM32_DTMODE, - }; - - static struct variant_data variant_qcom = { -@@ -505,7 +509,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; -@@ -1068,7 +1073,6 @@ 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 = variant->datactrl_dpsm_enable | (data->blksz << 16); -@@ -1077,6 +1081,16 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) - else - 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; - -@@ -1091,7 +1105,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; -@@ -1257,11 +1272,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, - /* 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); -- } - } - } - -diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h -index 36a744a..55867fc 100644 ---- a/drivers/mmc/host/mmci.h -+++ b/drivers/mmc/host/mmci.h -@@ -131,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 -@@ -273,7 +279,6 @@ struct mmci_host; - * @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. -@@ -309,6 +314,7 @@ struct mmci_host; - * @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; -@@ -330,7 +336,6 @@ struct variant_data { - unsigned int datactrl_dpsm_enable; - u8 datactrl_first:1; - u8 datacnt_useless:1; -- u8 st_sdio:1; - u8 st_clkdiv:1; - u8 stm32_clkdiv:1; - u8 blksz_datactrl16:1; -@@ -355,9 +360,13 @@ struct variant_data { - 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 */ -+ - /* mmci variant callbacks */ - struct mmci_host_ops { - int (*validate_data)(struct mmci_host *host, struct mmc_data *data); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0029-ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0029-ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C.patch deleted file mode 100644 index f1c6e73..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0029-ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C.patch +++ /dev/null @@ -1,771 +0,0 @@ -From 72179a889501ef339df094abe108846b19e7a06c Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:46:26 +0100 -Subject: [PATCH 29/52] ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C - ---- - .../devicetree/bindings/iio/adc/st,stm32-adc.txt | 34 +++ - arch/arm/Kconfig.debug | 27 ++ - drivers/hwspinlock/Kconfig | 9 + - drivers/hwspinlock/Makefile | 1 + - drivers/hwspinlock/stm32_hwspinlock.c | 157 +++++++++++ - drivers/i2c/busses/i2c-stm32f7.c | 6 +- - drivers/iio/adc/stm32-adc-core.c | 296 ++++++++++++++++++++- - drivers/iio/adc/stm32-adc.c | 4 +- - 8 files changed, 529 insertions(+), 5 deletions(-) - create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c - -diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -index c46598c..a6aa796 100644 ---- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -+++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -@@ -49,6 +49,40 @@ Optional properties: - - 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: - ----------------------------------- - An ADC block node should contain at least one subnode, representing an -diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index f6fcb8a..d5ec6c3 100644 ---- a/arch/arm/Kconfig.debug -+++ b/arch/arm/Kconfig.debug -@@ -1184,6 +1184,28 @@ choice - - If unsure, say N. - -+ config STM32F4_DEBUG_UART -+ bool "Use STM32F4 UART for low-level debug" -+ depends on ARCH_STM32 -+ 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. -+ -+ If unsure, say N. -+ -+ config STM32F7_DEBUG_UART -+ bool "Use STM32F7 UART for low-level debug" -+ depends on ARCH_STM32 -+ 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. -+ -+ 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 -@@ -1468,6 +1490,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 -@@ -1517,6 +1543,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 -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/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c -new file mode 100644 -index 0000000..3242b72 ---- /dev/null -+++ b/drivers/hwspinlock/stm32_hwspinlock.c -@@ -0,0 +1,157 @@ -+// 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 "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 const struct hwspinlock_ops stm32_hwspinlock_ops = { -+ .trylock = stm32_hwspinlock_trylock, -+ .unlock = stm32_hwspinlock_unlock, -+}; -+ -+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 "); -diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index c1cbf93..ac30aea 100644 ---- a/drivers/i2c/busses/i2c-stm32f7.c -+++ b/drivers/i2c/busses/i2c-stm32f7.c -@@ -457,7 +457,7 @@ 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 = setup->fall_time - i2c_specs[setup->speed].hddat_min - -+ sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - - af_delay_min - (setup->dnf + 3) * i2cclk; - - sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - -@@ -501,8 +501,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; - } - } - -diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index a32e826..6234456 100644 ---- a/drivers/iio/adc/stm32-adc-core.c -+++ b/drivers/iio/adc/stm32-adc-core.c -@@ -16,10 +16,12 @@ - #include - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - #include - -@@ -88,6 +90,8 @@ - #define STM32H7_CKMODE_SHIFT 16 - #define STM32H7_CKMODE_MASK GENMASK(17, 16) - -+#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000 -+ - /** - * stm32_adc_common_regs - stm32 common registers, compatible dependent data - * @csr: common status register offset -@@ -117,16 +121,30 @@ 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; -+}; -+ -+/** - * struct stm32_adc_priv - stm32 ADC core private data - * @irq: irq(s) for ADC block - * @domain: irq domain reference -@@ -137,6 +155,10 @@ struct stm32_adc_priv_cfg { - * @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]; -@@ -144,10 +166,16 @@ struct stm32_adc_priv { - 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) -@@ -567,16 +595,187 @@ static int stm32_adc_triggers_probe(struct platform_device *pdev, - 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_update_bits(priv->vbooster_clr.regmap, -+ priv->vbooster_clr.reg, -+ priv->vbooster_clr.mask, -+ 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_update_bits(priv->anaswvdd_clr.regmap, -+ priv->anaswvdd_clr.reg, -+ priv->anaswvdd_clr.mask, -+ 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_update_bits(priv->vbooster_clr.regmap, -+ priv->vbooster_clr.reg, -+ priv->vbooster_clr.mask, -+ 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_update_bits(priv->anaswvdd_clr.regmap, -+ priv->anaswvdd_clr.reg, -+ priv->anaswvdd_clr.mask, -+ 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_update_bits(priv->vbooster_clr.regmap, -+ priv->vbooster_clr.reg, -+ priv->vbooster_clr.mask, -+ 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"); -- return ret; -+ goto err_switches_disable; - } - - if (priv->bclk) { -@@ -604,6 +803,8 @@ static int stm32_adc_core_hw_start(struct device *dev) - clk_disable_unprepare(priv->bclk); - err_regulator_disable: - regulator_disable(priv->vref); -+err_switches_disable: -+ stm32_adc_switches_supply_dis(dev); - - return ret; - } -@@ -620,6 +821,68 @@ static void stm32_adc_core_hw_stop(struct device *dev) - 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)) { -+ pr_debug("FGA: %s %ld\n", prop, PTR_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) -@@ -657,6 +920,24 @@ static int stm32_adc_probe(struct platform_device *pdev) - 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; -+ } -+ } -+ -+ 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->aclk = devm_clk_get(&pdev->dev, "adc"); - if (IS_ERR(priv->aclk)) { - ret = PTR_ERR(priv->aclk); -@@ -677,8 +958,17 @@ static int stm32_adc_probe(struct platform_device *pdev) - priv->bclk = NULL; - } - -+ 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); -@@ -718,7 +1008,8 @@ static int stm32_adc_probe(struct platform_device *pdev) - goto err_irq_remove; - } - -- pm_runtime_put(dev); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); - - return 0; - -@@ -789,6 +1080,7 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { - 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, - }; -diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c -index 980355e..13d2e3c 100644 ---- a/drivers/iio/adc/stm32-adc.c -+++ b/drivers/iio/adc/stm32-adc.c -@@ -201,7 +201,7 @@ enum stm32h7_adc_dmngt { - #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_AUTO_SUSPEND_DELAY_MS 2000 -+#define STM32_ADC_HW_STOP_DELAY_MS 100 - - #define STM32_DMA_BUFFER_SIZE PAGE_SIZE - -@@ -2783,7 +2783,7 @@ static int stm32_adc_probe(struct platform_device *pdev) - /* Get stm32-adc-core PM online */ - pm_runtime_get_noresume(dev); - pm_runtime_set_active(dev); -- pm_runtime_set_autosuspend_delay(dev, STM32_ADC_AUTO_SUSPEND_DELAY_MS); -+ pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS); - pm_runtime_use_autosuspend(dev); - pm_runtime_enable(dev); - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0030-ARM-stm32mp1-r0-rc2-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0030-ARM-stm32mp1-r0-rc2-DEVICETREE.patch deleted file mode 100644 index 111a8cd..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0030-ARM-stm32mp1-r0-rc2-DEVICETREE.patch +++ /dev/null @@ -1,2514 +0,0 @@ -From ee54d2cd85d8254c5e31548986b545c33c75dd04 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:46:41 +0100 -Subject: [PATCH 30/52] ARM-stm32mp1-r0-rc2-DEVICETREE - ---- - arch/arm/boot/dts/Makefile | 4 +- - arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 424 +++++++++++++++++- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 274 +++++++++++- - arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts | 156 +++++++ - arch/arm/boot/dts/stm32mp157c-dk2.dts | 112 +++++ - arch/arm/boot/dts/stm32mp157c-ed1.dts | 43 +- - arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts | 161 +++++++ - arch/arm/boot/dts/stm32mp157c-ev1.dts | 499 +++++++++++++++++++++- - arch/arm/boot/dts/stm32mp157c.dtsi | 284 +++++++++++- - 9 files changed, 1910 insertions(+), 47 deletions(-) - create mode 100644 arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts - -diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index b264fa0..fdf53f5 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -924,8 +924,10 @@ dtb-$(CONFIG_ARCH_STM32) += \ - stm32h743i-disco.dtb \ - stm32mp157a-dk1.dtb \ - stm32mp157c-dk2.dtb \ -+ stm32mp157c-dk2-m4-examples.dtb \ - stm32mp157c-ed1.dtb \ -- stm32mp157c-ev1.dtb -+ stm32mp157c-ev1.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 4409db2..659094e 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 { -@@ -168,6 +169,27 @@ - }; - }; - -+ 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 = ; -@@ -180,6 +202,47 @@ - }; - }; - -+ 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 */ -@@ -361,6 +424,163 @@ - }; - }; - -+ 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 = <2>; -+ }; -+ }; -+ -+ 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 = <2>; -+ }; -+ }; -+ -+ 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 */ -@@ -507,21 +727,6 @@ - }; - }; - -- 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 */ -@@ -578,12 +783,110 @@ - }; - }; - -+ 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 { -+ pins1 { -+ pinmux = , /* SAI2_SCK_A */ -+ , /* SAI2_SD_A */ -+ ; /* SAI2_FS_A */ -+ slew-rate = <1>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ pins2 { -+ pinmux = ; /* SAI2_MCLK_A */ -+ slew-rate = <2>; -+ 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 */ -+ slew-rate = <1>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ pins2 { -+ pinmux = ; /* SAI2_MCLK_B */ -+ slew-rate = <2>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ pins3 { -+ 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 = <1>; -+ 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 */ -@@ -742,6 +1045,65 @@ - }; - }; - -+ 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 */ -+ }; -+ }; -+ - uart4_pins_a: uart4-0 { - pins1 { - pinmux = ; /* UART4_TX */ -@@ -879,6 +1241,19 @@ - ; /* 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 { -@@ -889,6 +1264,7 @@ - pins-are-numbered; - interrupt-parent = <&exti>; - st,syscfg = <&exti 0x60 0xff>; -+ hwlocks = <&hsem 1>; - - gpioz: gpio@54004000 { - gpio-controller; -@@ -902,6 +1278,16 @@ - status = "disabled"; - }; - -+ btreg: bt_reg_on-0 { -+ pins { -+ pinmux = ; -+ drive-push-pull; -+ bias-pull-up; -+ output-high; -+ slew-rate = <0>; -+ }; -+ }; -+ - i2c4_pins_a: i2c4-0 { - pins { - pinmux = , /* I2C4_SCL */ -@@ -933,6 +1319,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 -index 866eed7..2f01e97 100644 ---- a/arch/arm/boot/dts/stm32mp157a-dk1.dts -+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -17,6 +17,11 @@ - model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; - compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; - -+ aliases { -+ ethernet0 = ðernet0; -+ serial0 = &uart4; -+ }; -+ - chosen { - stdout-path = "serial0:115200n8"; - }; -@@ -35,10 +40,11 @@ - reg = <0x10040000 0x10000>; - no-map; - }; -- }; - -- aliases { -- serial0 = &uart4; -+ gpu_reserved: gpu@dc000000 { -+ reg = <0xdc000000 0x4000000>; -+ no-map; -+ }; - }; - - iio-hwmon { -@@ -68,11 +74,34 @@ - default-state = "off"; - }; - }; -+ -+ sound { -+ compatible = "audio-graph-card"; -+ routing = -+ "Playback" , "MCLK", -+ "Capture" , "MCLK", -+ "MICL" , "Mic Bias"; -+ dais = <&sai2a_port &sai2b_port &i2s2_port>; -+ status = "okay"; -+ }; -+ -+ usb_phy_tuning: usb-phy-tuning { -+ st,hs-dc-level = <2>; -+ st,fs-rftime-tuning; -+ st,hs-rftime-reduction; -+ st,hs-current-trim = <15>; -+ st,hs-impedance-trim = <1>; -+ st,squelch-level = <3>; -+ st,hs-rx-offset = <2>; -+ st,no-lsfs-sc; -+ }; - }; - - &adc { - pinctrl-names = "default"; - pinctrl-0 = <&adc12_usb_pwr_pins_a>; -+ vdd-supply = <&vdd>; -+ vdda-supply = <&vdd>; - vref-supply = <&vrefbuf>; - status = "okay"; - adc1: adc@0 { -@@ -99,6 +128,13 @@ - }; - }; - -+&cec { -+ pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <&cec_pins_b>; -+ pinctrl-1 = <&cec_pins_sleep_b>; -+ status = "okay"; -+}; -+ - &dma1 { - sram = <&dma_pool>; - }; -@@ -107,6 +143,34 @@ - sram = <&dma_pool>; - }; - -+ðernet0 { -+ status = "okay"; -+ pinctrl-0 = <ðernet0_rgmii_pins_a>; -+ pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; -+ pinctrl-names = "default", "sleep"; -+ phy-mode = "rgmii"; -+ max-speed = <1000>; -+ phy-handle = <&phy0>; -+ -+ mdio0 { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ compatible = "snps,dwmac-mdio"; -+ phy0: ethernet-phy@0 { -+ reg = <0>; -+ }; -+ }; -+}; -+ -+&gpu { -+ contiguous-area = <&gpu_reserved>; -+ status = "okay"; -+}; -+ -+&hsem { -+ status = "okay"; -+}; -+ - &i2c1 { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&i2c1_pins_a>; -@@ -116,6 +180,75 @@ - status = "okay"; - /delete-property/dmas; - /delete-property/dma-names; -+ -+ cs42l51: cs42l51@4a { -+ compatible = "cirrus,cs42l51"; -+ reg = <0x4a>; -+ #sound-dai-cells = <0>; -+ status = "okay"; -+ -+ VL-supply = <&v3v3>; -+ VD-supply = <&v1v8_audio>; -+ VA-supply = <&v1v8_audio>; -+ VAHP-supply = <&v1v8_audio>; -+ -+ reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>; -+ -+ clocks = <&sai2a>; -+ clock-names = "MCLK"; -+ -+ cs42l51_port: port { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ cs42l51_tx_endpoint: endpoint@0 { -+ reg = <0>; -+ remote-endpoint = <&sai2a_endpoint>; -+ frame-master; -+ bitclock-master; -+ }; -+ -+ cs42l51_rx_endpoint: endpoint@1 { -+ reg = <1>; -+ remote-endpoint = <&sai2b_endpoint>; -+ frame-master; -+ bitclock-master; -+ }; -+ }; -+ }; -+ -+ hdmi-transmitter@39 { -+ compatible = "sil,sii9022"; -+ reg = <0x39>; -+ iovcc-supply = <&v3v3_hdmi>; -+ cvcc12-supply = <&v1v2_hdmi>; -+ reset-gpios = <&gpioa 10 GPIO_ACTIVE_LOW>; -+ interrupts = <1 IRQ_TYPE_EDGE_FALLING>; -+ interrupt-parent = <&gpiog>; -+ pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <<dc_pins_a>; -+ pinctrl-1 = <<dc_pins_sleep_a>; -+ status = "okay"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ reg = <0>; -+ sii9022_in: endpoint { -+ remote-endpoint = <<dc_ep0_out>; -+ }; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ sii9022_tx_endpoint: endpoint { -+ remote-endpoint = <&i2s2_endpoint>; -+ }; -+ }; -+ }; -+ }; - }; - - &i2c4 { -@@ -131,8 +264,7 @@ - pmic: stpmic@33 { - compatible = "st,stpmic1"; - reg = <0x33>; -- interrupts-extended = <&pwr 0 IRQ_TYPE_EDGE_FALLING 1>, -- <&exti 55 1>; -+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; - interrupt-controller; - #interrupt-cells = <2>; - status = "okay"; -@@ -274,6 +406,23 @@ - }; - }; - -+&i2s2 { -+ clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL4_Q>; -+ 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"; - }; -@@ -283,10 +432,24 @@ - 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 = <&ipc_share>; - mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; -- mbox-names = "vq0", "vq1", "init_shdn"; -+ mbox-names = "vq0", "vq1", "shutdown"; - interrupt-parent = <&exti>; - interrupts = <68 1>; - interrupt-names = "wdg"; -@@ -294,6 +457,10 @@ - status = "okay"; - }; - -+&pwr { -+ pwr-supply = <&vdd>; -+}; -+ - &rng1 { - status = "okay"; - }; -@@ -302,18 +469,77 @@ - status = "okay"; - }; - -+&sai2 { -+ clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_Q>; -+ 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,negedge; -+ st,neg-edge; - bus-width = <4>; - vmmc-supply = <&v3v3>; - status = "okay"; - }; - -+&spi4 { -+ pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <&spi4_pins_a>; -+ pinctrl-1 = <&spi4_sleep_pins_a>; -+ status = "disabled"; -+}; -+ -+&spi5 { -+ pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <&spi5_pins_a>; -+ pinctrl-1 = <&spi5_sleep_pins_a>; -+ status = "disabled"; -+}; -+ - &timers1 { - /* spare dmas for other usage */ - /delete-property/dmas; -@@ -404,6 +630,40 @@ - status = "okay"; - }; - -+&usart3 { -+ pinctrl-names = "default", "sleep", "idle"; -+ pinctrl-0 = <&usart3_pins_b>; -+ pinctrl-1 = <&usart3_sleep_pins_b>; -+ pinctrl-2 = <&usart3_idle_pins_b>; -+ status = "disabled"; -+}; -+ -+&usbh_ehci { -+ phys = <&usbphyc_port0>; -+ phy-names = "usb"; -+ status = "okay"; -+}; -+ -+&usbotg_hs { -+ dr_mode = "peripheral"; -+ 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>; -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..8956b06 ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts -@@ -0,0 +1,156 @@ -+// 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 { -+ status = "okay"; -+}; -+ -+&m4_dma2 { -+ status = "okay"; -+}; -+ -+&m4_crc2 { -+ status = "okay"; -+}; -+ -+&m4_cryp2 { -+ status = "okay"; -+}; -+ -+&m4_hash2 { -+ status = "okay"; -+}; -+ -+&m4_i2c5 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&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 = "rproc_default", "rproc_sleep"; -+ pinctrl-0 = <&leds_orange_pins>; -+ pinctrl-1 = <&leds_orange_sleep_pins>; -+ status = "okay"; -+ }; -+ }; -+}; -+ -+&m4_spi4 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&spi4_pins_a>; -+ status = "okay"; -+}; -+ -+ -+&m4_timers2 { -+ pinctrl-names = "rproc_default"; -+ status = "okay"; -+}; -+ -+&m4_timers1 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&timer1_pins>; -+ status = "okay"; -+}; -+ -+&m4_uart7 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&uart7_pins>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ uart7_pins: uart7-test-0 { -+ pins1 { -+ pinmux = ; /* UART7_TX */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <0>; -+ }; -+ pins2 { -+ pinmux = ; /* UART7_RX */ -+ bias-disable; -+ }; -+ }; -+ -+ timer1_pins: pwm1-test-0 { -+ pins { -+ pinmux = ; /* TIM1_CH1 */ -+ bias-pull-down; -+ drive-push-pull; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ leds_orange_pins: leds_orange_test-0 { -+ pins { -+ pinmux = ; -+ bias-pull-up; -+ drive-push-pull; -+ output-low; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ leds_orange_sleep_pins: leds_orange_sleep_test-0 { -+ pins { -+ pinmux = ; -+ }; -+ }; -+}; -+ -+&timers1 { -+ status = "disabled"; -+}; -diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -index 4175b65..fd00386 100644 ---- a/arch/arm/boot/dts/stm32mp157c-dk2.dts -+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -12,6 +12,80 @@ - / { - model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; - compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; -+ -+ aliases { -+ serial1 = &usart2; -+ }; -+ -+ wifi_pwrseq: wifi-pwrseq { -+ compatible = "mmc-pwrseq-simple"; -+ reset-gpios = <&gpioh 4 GPIO_ACTIVE_LOW>; -+ }; -+}; -+ -+&dsi { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ reg = <0>; -+ dsi_in: endpoint { -+ remote-endpoint = <<dc_ep1_out>; -+ }; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ dsi_out: endpoint { -+ remote-endpoint = <&panel_in>; -+ }; -+ }; -+ }; -+ -+ panel@0 { -+ compatible = "orisetech,otm8009a"; -+ reg = <0>; -+ reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; -+ status = "okay"; -+ -+ port { -+ panel_in: endpoint { -+ remote-endpoint = <&dsi_out>; -+ }; -+ }; -+ }; -+}; -+ -+&i2c1 { -+ touchscreen@2a { -+ compatible = "focaltech,ft6236"; -+ reg = <0x2a>; -+ interrupts = <2 2>; -+ interrupt-parent = <&gpiof>; -+ interrupt-controller; -+ touchscreen-size-x = <480>; -+ touchscreen-size-y = <800>; -+ status = "okay"; -+ }; -+}; -+ -+<dc { -+ status = "okay"; -+ -+ port { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ltdc_ep1_out: endpoint@1 { -+ reg = <1>; -+ remote-endpoint = <&dsi_in>; -+ }; -+ }; - }; - - &rtc { -@@ -20,3 +94,41 @@ - pinctrl-names = "default"; - }; - -+/* Wifi */ -+&sdmmc2 { -+ pinctrl-names = "default", "opendrain", "sleep"; -+ pinctrl-0 = <&sdmmc2_b4_pins_a>; -+ pinctrl-1 = <&sdmmc2_b4_od_pins_a>; -+ pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; -+ non-removable; -+ st,neg-edge; -+ bus-width = <4>; -+ vmmc-supply = <&v3v3>; -+ mmc-pwrseq = <&wifi_pwrseq>; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ keep-power-in-suspend; -+ status = "okay"; -+ -+ brcmf: bcrmf@1 { -+ reg = <1>; -+ compatible = "brcm,bcm4329-fmac"; -+ }; -+}; -+ -+/* Bluetooth */ -+&usart2 { -+ pinctrl-names = "default", "sleep", "idle"; -+ pinctrl-0 = <&usart2_pins_a>; -+ pinctrl-1 = <&usart2_sleep_pins_a>; -+ pinctrl-2 = <&usart2_idle_pins_a>; -+ st,hw-flow-ctrl; -+ status = "okay"; -+ -+ bluetooth { -+ pinctrl-names = "default"; -+ pinctrl-0 = <&btreg>; -+ compatible = "brcm,bcm43438-bt"; -+ max-speed = <3000000>; -+ }; -+}; -diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index 1b074e9..4f46b41 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ed1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts -@@ -33,6 +33,11 @@ - reg = <0x10040000 0x10000>; - no-map; - }; -+ -+ gpu_reserved: gpu@f8000000 { -+ reg = <0xf8000000 0x8000000>; -+ no-map; -+ }; - }; - - aliases { -@@ -70,6 +75,8 @@ - - &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 { -@@ -114,6 +121,15 @@ - sram = <&dma_pool>; - }; - -+&gpu { -+ contiguous-area = <&gpu_reserved>; -+ status = "okay"; -+}; -+ -+&hsem { -+ status = "okay"; -+}; -+ - &i2c4 { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&i2c4_pins_a>; -@@ -127,8 +143,7 @@ - pmic: stpmic@33 { - compatible = "st,stpmic1"; - reg = <0x33>; -- interrupts-extended = <&pwr 0 IRQ_TYPE_EDGE_FALLING 1>, -- <&exti 55 1>; -+ interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; - interrupt-controller; - #interrupt-cells = <2>; - status = "okay"; -@@ -235,10 +250,10 @@ - regulator-over-current-protection; - }; - -- bst_out: boost { -+ bst_out: boost { - regulator-name = "bst_out"; - interrupts = ; -- }; -+ }; - - vbus_otg: pwr_sw1 { - regulator-name = "vbus_otg"; -@@ -278,7 +293,7 @@ - &m4_rproc { - memory-region = <&ipc_share>; - mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; -- mbox-names = "vq0", "vq1", "init_shdn"; -+ mbox-names = "vq0", "vq1", "shutdown"; - interrupt-parent = <&exti>; - interrupts = <68 1>; - interrupt-names = "wdg"; -@@ -286,6 +301,10 @@ - status = "okay"; - }; - -+&pwr { -+ pwr-supply = <&vdd>; -+}; -+ - &rng1 { - status = "okay"; - }; -@@ -316,7 +335,7 @@ - non-removable; - no-sd; - no-sdio; -- st,negedge; -+ st,neg-edge; - bus-width = <8>; - vmmc-supply = <&v3v3>; - vqmmc-supply = <&v3v3>; -@@ -342,14 +361,10 @@ - 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-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts -new file mode 100644 -index 0000000..ef2938d ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts -@@ -0,0 +1,161 @@ -+// 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 { -+ status = "okay"; -+}; -+ -+&m4_dma2 { -+ status = "okay"; -+}; -+ -+&m4_hash2 { -+ status = "okay"; -+}; -+ -+&m4_i2c5 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&i2c5_pins_a>; -+ status = "okay"; -+}; -+ -+&m4_qspi { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &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 = "rproc_default", "rproc_sleep"; -+ pinctrl-0 = <&leds_orange_pins>; -+ pinctrl-1 = <&leds_orange_sleep_pins>; -+ status = "okay"; -+ }; -+ }; -+}; -+ -+&m4_rng2 { -+ status = "okay"; -+}; -+ -+&m4_spi1 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&spi1_pins_a>; -+ status = "okay"; -+}; -+ -+ -+&m4_timers2 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&pwm2_pins_a>; -+ status = "okay"; -+}; -+ -+&m4_timers1 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&pwm1_pins_a>; -+ status = "okay"; -+}; -+ -+&m4_usart3 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&usart3_pins_a>; -+ status = "okay"; -+}; -+ -+&pinctrl { -+ leds_orange_pins: leds_orange_test-0 { -+ pins { -+ pinmux = ; -+ bias-pull-up; -+ drive-push-pull; -+ output-low; -+ slew-rate = <0>; -+ }; -+ }; -+ -+ leds_orange_sleep_pins: leds_orange_sleep_test-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 fe59c6d..b60bffc 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ev1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts -@@ -7,6 +7,7 @@ - - #include "stm32mp157c-ed1.dts" - #include -+#include - - / { - model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; -@@ -21,6 +22,14 @@ - 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>; -@@ -57,6 +66,284 @@ - 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"; -+ routing = -+ "AIF1CLK" , "MCLK1", -+ "AIF2CLK" , "MCLK1", -+ "IN1LN" , "MICBIAS2", -+ "DMIC2DAT" , "MICBIAS1", -+ "DMIC1DAT" , "MICBIAS1"; -+ dais = <&sai2a_port &sai2b_port &sai4a_port &spdifrx_port>; -+ status = "okay"; -+ }; -+ -+ dmics { -+ compatible = "audio-graph-card"; -+ dais = <&cpu_port0 &cpu_port1 &cpu_port2 &cpu_port3>; -+ 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", "sleep"; -+ pinctrl-0 = <&cec_pins_a>; -+ pinctrl-1 = <&cec_pins_sleep_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"; -+ -+ cpu_port0: 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"; -+ -+ cpu_port1: 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"; -+ -+ cpu_port2: 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"; -+ -+ cpu_port3: port { -+ dfsdm_endpoint3: endpoint { -+ remote-endpoint = <&dmic3_endpoint>; -+ }; -+ }; -+ }; -+ }; -+}; -+ -+&dsi { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ status = "okay"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ port@0 { -+ reg = <0>; -+ dsi_in: endpoint { -+ remote-endpoint = <<dc_ep0_out>; -+ }; -+ }; -+ -+ port@1 { -+ reg = <1>; -+ dsi_out: endpoint { -+ remote-endpoint = <&dsi_panel_in>; -+ }; -+ }; -+ }; -+ -+ panel-dsi@0 { -+ compatible = "raydium,rm68200"; -+ reg = <0>; -+ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; -+ power-supply = <&v1v8>; -+ backlight = <&panel_backlight>; -+ status = "okay"; -+ -+ port { -+ dsi_panel_in: endpoint { -+ remote-endpoint = <&dsi_out>; -+ }; -+ }; -+ }; - }; - - ðernet0 { -@@ -78,12 +365,6 @@ - }; - }; - --&cec { -- pinctrl-names = "default"; -- pinctrl-0 = <&cec_pins_a>; -- status = "okay"; --}; -- - &fmc { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&fmc_pins_a>; -@@ -110,6 +391,74 @@ - /delete-property/dmas; - /delete-property/dma-names; - -+ wm8994: wm8994@1b { -+ compatible = "wlf,wm8994"; -+ #sound-dai-cells = <0>; -+ reg = <0x1b>; -+ status = "okay"; -+ -+ gpio-controller; -+ #gpio-cells = <2>; -+ -+ DBVDD-supply = <&vdd>; -+ SPKVDD1-supply = <&vdd>; -+ SPKVDD2-supply = <&vdd>; -+ AVDD2-supply = <&v1v8>; -+ CPVDD-supply = <&v1v8>; -+ -+ wlf,ldoena-always-driven; -+ -+ clocks = <&sai2a>; -+ clock-names = "MCLK1"; -+ -+ wlf,gpio-cfg = <0x8101 0xa100 0xa100 0xa100 0xa101 0xa101 0xa100 0xa101 0xa101 0xa101 0xa101>; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ wm8994_tx_port: port@0 { -+ reg = <0>; -+ wm8994_tx_endpoint: endpoint { -+ remote-endpoint = <&sai2a_endpoint>; -+ }; -+ }; -+ -+ wm8994_rx_port: port@1 { -+ reg = <1>; -+ wm8994_rx_endpoint: endpoint { -+ remote-endpoint = <&sai2b_endpoint>; -+ }; -+ }; -+ }; -+ }; -+ -+ ov5640: camera@3c { -+ compatible = "ovti,ov5640"; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&ov5640_pins>; -+ reg = <0x3c>; -+ clocks = <&clk_ext_camera>; -+ clock-names = "xclk"; -+ DOVDD-supply = <&v2v8>; -+ powerdown-gpios = <&stmfx_pinctrl 18 GPIO_ACTIVE_HIGH>; -+ reset-gpios = <&stmfx_pinctrl 19 GPIO_ACTIVE_LOW>; -+ rotation = <180>; -+ status = "okay"; -+ -+ port { -+ ov5640_0: endpoint { -+ remote-endpoint = <&dcmi_0>; -+ bus-width = <8>; -+ data-shift = <2>; /* lines 9:2 are used */ -+ hsync-active = <0>; -+ vsync-active = <0>; -+ pclk-sample = <1>; -+ pclk-max-frequency = <77000000>; -+ }; -+ }; -+ }; -+ - stmfx: stmfx@42 { - compatible = "st,stmfx-0300"; - reg = <0x42>; -@@ -124,12 +473,45 @@ - interrupt-controller; - #interrupt-cells = <2>; - gpio-ranges = <&stmfx_pinctrl 0 0 24>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&hog_pins>; -+ -+ hog_pins: hog { -+ pins = "gpio14"; -+ drive-push-pull; -+ bias-pull-down; -+ }; - - joystick_pins: joystick { - pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; - drive-push-pull; - bias-pull-down; - }; -+ -+ ov5640_pins: camera { -+ pins = "agpio2", "agpio3"; /* stmfx pins 18 & 19 */ -+ drive-push-pull; -+ output-low; -+ }; -+ }; -+ }; -+ -+ gt9147: goodix_ts@5d { -+ compatible = "goodix,gt9147"; -+ reg = <0x5d>; -+ status = "okay"; -+ -+ irq-gpios = <&stmfx_pinctrl 14 GPIO_ACTIVE_HIGH>; -+ irq-flags = ; -+ }; -+}; -+ -+&i2c4 { -+ pmic: stpmic@33 { -+ regulators { -+ v1v8: ldo6 { -+ regulator-enable-ramp-delay = <300000>; -+ }; - }; - }; - }; -@@ -145,6 +527,20 @@ - /delete-property/dma-names; - }; - -+<dc { -+ status = "okay"; -+ -+ port { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ ltdc_ep0_out: endpoint@0 { -+ reg = <0>; -+ remote-endpoint = <&dsi_in>; -+ }; -+ }; -+}; -+ - &m_can1 { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&m_can1_pins_a>; -@@ -180,9 +576,86 @@ - }; - }; - -+&sai2 { -+ clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL4_Q>; -+ 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 PLL4_Q>; -+ 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>; -+ }; -+ }; -+ }; -+}; -+ -+&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"; -+ pinctrl-names = "default", "sleep"; - pinctrl-0 = <&spi1_pins_a>; -+ pinctrl-1 = <&spi1_sleep_pins_a>; - status = "disabled"; - }; - -@@ -243,11 +716,13 @@ - &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"; -@@ -256,3 +731,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.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index b4bae4d..cef7b3e 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -19,15 +19,25 @@ - compatible = "arm,cortex-a7"; - device_type = "cpu"; - reg = <0>; -+ clock-frequency = <650000000>; - }; - - cpu1: cpu@1 { - compatible = "arm,cortex-a7"; - device_type = "cpu"; - reg = <1>; -+ clock-frequency = <650000000>; - }; - }; - -+ arm-pmu { -+ compatible = "arm,cortex-a7-pmu"; -+ interrupts = , -+ ; -+ interrupt-affinity = <&cpu0>, <&cpu1>; -+ interrupt-parent = <&intc>; -+ }; -+ - psci { - compatible = "arm,psci-1.0"; - method = "smc"; -@@ -80,6 +90,18 @@ - compatible = "fixed-clock"; - clock-frequency = <4000000>; - }; -+ -+ clk_i2s_ckin: i2s_ckin { -+ #clock-cells = <0>; -+ compatible = "fixed-clock"; -+ clock-frequency = <0>; -+ }; -+ -+ clk_dsi_phy: ck_dsi_phy { -+ #clock-cells = <0>; -+ compatible = "fixed-clock"; -+ clock-frequency = <0>; -+ }; - }; - - pm_domain { -@@ -102,6 +124,38 @@ - }; - }; - -+ thermal-zones { -+ cpu_thermal: cpu-thermal { -+ polling-delay-passive = <0>; -+ polling-delay = <0>; -+ thermal-sensors = <&dts>; -+ -+ trips { -+ cpu_alert1: cpu-alert1 { -+ temperature = <85000>; -+ hysteresis = <0>; -+ type = "passive"; -+ }; -+ -+ cpu-crit { -+ temperature = <120000>; -+ hysteresis = <0>; -+ type = "critical"; -+ }; -+ }; -+ -+ cooling-maps { -+ }; -+ }; -+ }; -+ -+ reboot { -+ compatible = "syscon-reboot"; -+ regmap = <&rcc>; -+ offset = <0x404>; -+ mask = <0x1>; -+ }; -+ - soc { - compatible = "simple-bus"; - #address-cells = <1>; -@@ -360,6 +414,17 @@ - status = "disabled"; - }; - -+ i2s2: audio-controller@4000b000 { -+ compatible = "st,stm32h7-i2s"; -+ #sound-dai-cells = <0>; -+ reg = <0x4000b000 0x400>; -+ interrupts = ; -+ dmas = <&dmamux1 39 0x400 0x01>, -+ <&dmamux1 40 0x400 0x01>; -+ dma-names = "rx", "tx"; -+ status = "disabled"; -+ }; -+ - spi3: spi@4000c000 { - #address-cells = <1>; - #size-cells = <0>; -@@ -375,6 +440,30 @@ - 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>; -@@ -644,6 +733,17 @@ - status = "disabled"; - }; - -+ i2s1: audio-controller@44004000 { -+ compatible = "st,stm32h7-i2s"; -+ #sound-dai-cells = <0>; -+ reg = <0x44004000 0x400>; -+ interrupts = ; -+ dmas = <&dmamux1 37 0x400 0x01>, -+ <&dmamux1 38 0x400 0x01>; -+ dma-names = "rx", "tx"; -+ status = "disabled"; -+ }; -+ - spi4: spi@44005000 { - #address-cells = <1>; - #size-cells = <0>; -@@ -747,6 +847,88 @@ - status = "disabled"; - }; - -+ sai1: sai@4400a000 { -+ compatible = "st,stm32h7-sai"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0 0x4400a000 0x400>; -+ reg = <0x4400a000 0x4>; -+ interrupts = ; -+ resets = <&rcc SAI1_R>; -+ status = "disabled"; -+ -+ sai1a: audio-controller@4400a004 { -+ #sound-dai-cells = <0>; -+ -+ compatible = "st,stm32-sai-sub-a"; -+ reg = <0x4 0x1c>; -+ dmas = <&dmamux1 87 0x400 0x01>; -+ status = "disabled"; -+ }; -+ -+ sai1b: audio-controller@4400a024 { -+ #sound-dai-cells = <0>; -+ compatible = "st,stm32-sai-sub-b"; -+ reg = <0x24 0x1c>; -+ dmas = <&dmamux1 88 0x400 0x01>; -+ status = "disabled"; -+ }; -+ }; -+ -+ sai2: sai@4400b000 { -+ compatible = "st,stm32h7-sai"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0 0x4400b000 0x400>; -+ reg = <0x4400b000 0x4>; -+ interrupts = ; -+ resets = <&rcc SAI2_R>; -+ status = "disabled"; -+ -+ sai2a: audio-controller@4400b004 { -+ #sound-dai-cells = <0>; -+ compatible = "st,stm32-sai-sub-a"; -+ reg = <0x4 0x1c>; -+ dmas = <&dmamux1 89 0x400 0x01>; -+ status = "disabled"; -+ }; -+ -+ sai2b: audio-controller@4400b024 { -+ #sound-dai-cells = <0>; -+ compatible = "st,stm32-sai-sub-b"; -+ reg = <0x24 0x1c>; -+ dmas = <&dmamux1 90 0x400 0x01>; -+ status = "disabled"; -+ }; -+ }; -+ -+ sai3: sai@4400c000 { -+ compatible = "st,stm32h7-sai"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0 0x4400c000 0x400>; -+ reg = <0x4400c000 0x4>; -+ interrupts = ; -+ resets = <&rcc SAI3_R>; -+ status = "disabled"; -+ -+ sai3a: audio-controller@4400c004 { -+ #sound-dai-cells = <0>; -+ compatible = "st,stm32-sai-sub-a"; -+ reg = <0x04 0x1c>; -+ dmas = <&dmamux1 113 0x400 0x01>; -+ status = "disabled"; -+ }; -+ -+ sai3b: audio-controller@4400c024 { -+ #sound-dai-cells = <0>; -+ compatible = "st,stm32-sai-sub-b"; -+ reg = <0x24 0x1c>; -+ dmas = <&dmamux1 114 0x400 0x01>; -+ status = "disabled"; -+ }; -+ }; -+ - dfsdm: dfsdm@4400d000 { - compatible = "st,stm32mp1-dfsdm"; - reg = <0x4400d000 0x800>; -@@ -913,6 +1095,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>; -@@ -993,7 +1179,7 @@ - }; - - usbotg_hs: usb-otg@49000000 { -- compatible = "snps,dwc2"; -+ compatible = "st,stm32mp1-hsotg", "snps,dwc2"; - reg = <0x49000000 0x10000>; - clocks = <&rcc USBO_K>; - clock-names = "otg"; -@@ -1004,10 +1190,20 @@ - g-np-tx-fifo-size = <32>; - g-tx-fifo-size = <128 128 64 64 64 64 32 32>; - dr_mode = "otg"; -+ usb33d-supply = <&usb33>; - power-domains = <&pd_core>; - status = "disabled"; - }; - -+ hsem: hwspinlock@4c000000 { -+ compatible = "st,stm32-hwspinlock"; -+ #hwlock-cells = <1>; -+ reg = <0x4c000000 0x400>; -+ clocks = <&rcc HSEM>; -+ clock-names = "hsem"; -+ status = "disabled"; -+ }; -+ - ipcc: mailbox@4c001000 { - compatible = "st,stm32mp1-ipcc"; - #mbox-cells = <1>; -@@ -1024,13 +1220,24 @@ - status = "disabled"; - }; - -+ dcmi: dcmi@4c006000 { -+ compatible = "st,stm32-dcmi"; -+ reg = <0x4c006000 0x400>; -+ interrupts = ; -+ resets = <&rcc CAMITF_R>; -+ clocks = <&rcc DCMI>; -+ clock-names = "mclk"; -+ dmas = <&dmamux1 75 0x400 0xd>; -+ dma-names = "tx"; -+ status = "disabled"; -+ }; -+ - rcc: rcc@50000000 { - compatible = "st,stm32mp1-rcc", "syscon"; - reg = <0x50000000 0x1000>; - #clock-cells = <1>; - #reset-cells = <1>; - interrupts = ; -- st,pwr = <&pwr>; - }; - - pwr: pwr@50001000 { -@@ -1071,11 +1278,24 @@ - interrupt-controller; - #interrupt-cells = <2>; - reg = <0x5000d000 0x400>; -+ hwlocks = <&hsem 2>; -+ -+ /* 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 { -@@ -1168,6 +1388,45 @@ - status = "disabled"; - }; - -+ sai4: sai@50027000 { -+ compatible = "st,stm32h7-sai"; -+ #address-cells = <1>; -+ #size-cells = <1>; -+ ranges = <0 0x50027000 0x400>; -+ reg = <0x50027000 0x4>; -+ interrupts = ; -+ resets = <&rcc SAI4_R>; -+ status = "disabled"; -+ -+ sai4a: audio-controller@50027004 { -+ #sound-dai-cells = <0>; -+ compatible = "st,stm32-sai-sub-a"; -+ reg = <0x04 0x1c>; -+ clocks = <&rcc SAI4_K>; -+ clock-names = "sai_ck"; -+ dmas = <&dmamux1 99 0x400 0x01>; -+ status = "disabled"; -+ }; -+ -+ sai4b: audio-controller@50027024 { -+ #sound-dai-cells = <0>; -+ compatible = "st,stm32-sai-sub-b"; -+ reg = <0x24 0x1c>; -+ dmas = <&dmamux1 100 0x400 0x01>; -+ status = "disabled"; -+ }; -+ }; -+ -+ dts: thermal@50028000 { -+ compatible = "st,stm32-thermal"; -+ reg = <0x50028000 0x100>; -+ interrupts = ; -+ clocks = <&rcc TMPSENS>; -+ clock-names = "pclk"; -+ #thermal-sensor-cells = <0>; -+ status = "disabled"; -+ }; -+ - cryp1: cryp@54001000 { - compatible = "st,stm32mp1-cryp"; - reg = <0x54001000 0x400>; -@@ -1327,6 +1586,16 @@ - 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>; -@@ -1334,6 +1603,7 @@ - clock-names = "pclk", "ref", "px_clk"; - resets = <&rcc DSI_R>; - reset-names = "apb"; -+ phy-dsi-supply = <®18>; - status = "disabled"; - }; - -@@ -1359,10 +1629,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 { -@@ -1500,4 +1773,11 @@ - status = "disabled"; - }; - }; -+ -+ firmware { -+ optee { -+ compatible = "linaro,optee-tz"; -+ method = "smc"; -+ }; -+ }; - }; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0031-ARM-stm32mp1-r0-rc2-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0031-ARM-stm32mp1-r0-rc2-DEFCONFIG.patch deleted file mode 100644 index a10a14f..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0031-ARM-stm32mp1-r0-rc2-DEFCONFIG.patch +++ /dev/null @@ -1,130 +0,0 @@ -From 73813749b7f0f33a59eb8f321f7d0f9d88dbfbb3 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Mon, 26 Nov 2018 14:46:52 +0100 -Subject: [PATCH 31/52] ARM-stm32mp1-r0-rc2-DEFCONFIG - ---- - arch/arm/configs/fragment-02-multiv7_addons.config | 42 +++++++++++++++++++++- - 1 file changed, 41 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config -index c91840c..4470d85 100644 ---- a/arch/arm/configs/fragment-02-multiv7_addons.config -+++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -3,6 +3,7 @@ - # - CONFIG_POSIX_MQUEUE=y - CONFIG_USELIB=y -+CONFIG_FUTEX=y - - # - # RCU Subsystem -@@ -153,6 +154,12 @@ CONFIG_SERIAL_NONSTANDARD=y - # 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 -@@ -179,6 +186,7 @@ CONFIG_SERIAL_NONSTANDARD=y - # - # SPI Master Controller Drivers - # -+CONFIG_SPI_STM32=y - CONFIG_SPI_STM32_QSPI=y - - # -@@ -237,6 +245,7 @@ CONFIG_PROTECTION_CONSUMER=y - # - # USB HDMI CEC adapters - # -+CONFIG_VIDEO_STM32_HDMI_CEC=m - - # - # Media ancillary drivers (tuners, sensors, i2c, spi, frontends) -@@ -246,6 +255,7 @@ CONFIG_PROTECTION_CONSUMER=y - # - # Camera sensor devices - # -+CONFIG_VIDEO_OV5640=y - - # - # Graphics support -@@ -261,10 +271,14 @@ CONFIG_PROTECTION_CONSUMER=y - # - # Display Panels - # -+CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m -+CONFIG_DRM_PANEL_RAYDIUM_RM68200=m - - # - # Display Interface Bridges - # -+CONFIG_VIDEO_ADV7511=m -+CONFIG_DRM_SII902X=m - - # - # Frame buffer hardware drivers -@@ -273,15 +287,34 @@ CONFIG_PROTECTION_CONSUMER=y - # - # Console display driver support - # -+CONFIG_DRM_STM=m -+CONFIG_DRM_STM_DSI=m -+ -+# -+# Backlight support -+# -+CONFIG_BACKLIGHT_GPIO=y - - # - # HD-Audio - # -+CONFIG_SOUND=y -+CONFIG_SND=y -+CONFIG_SND_SOC=y -+CONFIG_SND_SOC_STM32_SAI=y -+CONFIG_SND_SOC_STM32_I2S=y -+CONFIG_SND_SOC_STM32_SPDIFRX=y -+CONFIG_SND_SOC_STM32_DFSDM=y -+CONFIG_SND_AUDIO_GRAPH_CARD=y - - # - # CODEC drivers - # -- -+CONFIG_MFD_WM8994=y -+CONFIG_SND_SOC_WM8994=y -+CONFIG_SND_SOC_DMIC=y -+CONFIG_SND_SOC_CS42L42=y -+CONFIG_SND_SOC_CS42L51_I2C=y - - # - # USB Device Class drivers -@@ -300,6 +333,7 @@ CONFIG_PROTECTION_CONSUMER=y - # - # Gadget/Dual-role mode requires USB Gadget support to be enabled - # -+CONFIG_USB_CONFIGFS=y - - # - # USB Physical Layer drivers -@@ -460,3 +494,9 @@ CONFIG_STM32_ADC_TEMP=y - # STM32 DAC - # - CONFIG_STM32_DAC=y -+ -+# -+# STM32 HSEM -+# -+CONFIG_HWSPINLOCK=y -+CONFIG_HWSPINLOCK_STM32=y --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0032-ARM-stm32mp1-r0-rc3-DMA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0032-ARM-stm32mp1-r0-rc3-DMA.patch deleted file mode 100644 index 2ee2106..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0032-ARM-stm32mp1-r0-rc3-DMA.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 1028166948f7116f4dcddc74094125db0a7595c8 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:34:56 +0100 -Subject: [PATCH 32/52] ARM: stm32mp1-r0-rc3: DMA - ---- - drivers/dma/stm32-dma.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 4830f8e..1f9d606 100644 ---- a/drivers/dma/stm32-dma.c -+++ b/drivers/dma/stm32-dma.c -@@ -212,6 +212,7 @@ struct stm32_dma_desc { - u32 num_sgs; - dma_addr_t dma_buf; - void *dma_buf_cpu; -+ u32 dma_buf_size; - struct stm32_dma_sg_req sg_req[]; - }; - -@@ -1224,6 +1225,7 @@ static int stm32_dma_mdma_prep_slave_sg(struct stm32_dma_chan *chan, - &desc->dma_buf); - if (!desc->dma_buf_cpu) - return -ENOMEM; -+ desc->dma_buf_size = chan->sram_size; - - sram_period = chan->sram_size / 2; - -@@ -1316,7 +1318,7 @@ static int stm32_dma_mdma_prep_slave_sg(struct stm32_dma_chan *chan, - } - free_alloc: - gen_pool_free(dmadev->sram_pool, (unsigned long)desc->dma_buf_cpu, -- chan->sram_size); -+ desc->dma_buf_size); - return ret; - } - -@@ -1437,7 +1439,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( - - gen_pool_free(dmadev->sram_pool, - (unsigned long)desc->dma_buf_cpu, -- chan->sram_size); -+ desc->dma_buf_size); - } - kfree(desc); - -@@ -1462,6 +1464,7 @@ static int stm32_dma_mdma_prep_dma_cyclic(struct stm32_dma_chan *chan, - &desc->dma_buf); - if (!desc->dma_buf_cpu) - return -ENOMEM; -+ desc->dma_buf_size = 2 * chan->sram_size; - - memset(&config, 0, sizeof(config)); - mem = buf_addr; -@@ -1511,7 +1514,7 @@ static int stm32_dma_mdma_prep_dma_cyclic(struct stm32_dma_chan *chan, - err: - gen_pool_free(dmadev->sram_pool, - (unsigned long)desc->dma_buf_cpu, -- chan->sram_size); -+ desc->dma_buf_size); - return ret; - } - -@@ -1813,7 +1816,7 @@ static void stm32_dma_desc_free(struct virt_dma_desc *vdesc) - - gen_pool_free(dmadev->sram_pool, - (unsigned long)desc->dma_buf_cpu, -- chan->sram_size); -+ desc->dma_buf_size); - } - - kfree(desc); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0033-ARM-stm32mp1-r0-rc3-DISPLAY.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0033-ARM-stm32mp1-r0-rc3-DISPLAY.patch deleted file mode 100644 index 915cf2c..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0033-ARM-stm32mp1-r0-rc3-DISPLAY.patch +++ /dev/null @@ -1,133 +0,0 @@ -From dc9ea19f397651b7671ec4268a12d3f49e2bbda0 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:48:07 +0100 -Subject: [PATCH 33/52] ARM: stm32mp1-r0-rc3: DISPLAY - ---- - drivers/gpu/drm/bridge/sii902x.c | 31 +++++++++++++++++++++++++++---- - drivers/gpu/drm/drm_gem.c | 6 ------ - 2 files changed, 27 insertions(+), 10 deletions(-) - -diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c -index 512eb03..170657a 100644 ---- a/drivers/gpu/drm/bridge/sii902x.c -+++ b/drivers/gpu/drm/bridge/sii902x.c -@@ -397,7 +397,6 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) - regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, - SII902X_SYS_CTRL_PWR_DWN, - SII902X_SYS_CTRL_PWR_DWN); -- pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); - } - - static void sii902x_bridge_enable(struct drm_bridge *bridge) -@@ -405,7 +404,6 @@ static void sii902x_bridge_enable(struct drm_bridge *bridge) - struct sii902x *sii902x = bridge_to_sii902x(bridge); - bool hdmi_mode; - -- pinctrl_pm_select_default_state(&sii902x->i2c->dev); - regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL, - SII902X_AVI_POWER_STATE_MSK, - SII902X_AVI_POWER_STATE_D(0)); -@@ -430,8 +428,17 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, - struct regmap *regmap = sii902x->regmap; - u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; - struct hdmi_avi_infoframe frame; -+ unsigned int status = 0; - int ret; - -+ DRM_DEBUG_DRIVER("\n"); -+ -+ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); -+ -+ /* due to old tv, need to restore pinctrl as soon as possible */ -+ if (status & SII902X_PLUGGED_STATUS) -+ pinctrl_pm_select_default_state(&sii902x->i2c->dev); -+ - buf[0] = adj->clock; - buf[1] = adj->clock >> 8; - buf[2] = adj->vrefresh; -@@ -819,6 +826,11 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) - regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); - regmap_write(sii902x->regmap, SII902X_INT_STATUS, status); - -+ if (status & SII902X_PLUGGED_STATUS) -+ pinctrl_pm_select_default_state(&sii902x->i2c->dev); -+ else -+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); -+ - if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) - drm_helper_hpd_irq_event(sii902x->bridge.dev); - -@@ -1045,14 +1057,15 @@ static int sii902x_probe(struct i2c_client *client, - sii902x_i2c_bypass_deselect); - if (!sii902x->i2cmux) { - dev_err(dev, "failed to allocate I2C mux\n"); -- return -ENOMEM; -+ ret = -ENOMEM; -+ goto err_disable_regulator; - } - - 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; -+ goto err_disable_regulator; - } - - sii902x_register_audio_driver(dev, sii902x); -@@ -1060,6 +1073,7 @@ static int sii902x_probe(struct i2c_client *client, - return 0; - - err_disable_regulator: -+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); - regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), - sii902x->supplies); - -@@ -1095,6 +1109,8 @@ static int sii902x_pm_suspend(struct device *dev) - regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), - sii902x->supplies); - -+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); -+ - return 0; - } - -@@ -1109,10 +1125,17 @@ static int sii902x_pm_resume(struct device *dev) - .len = 2, - .buf = data, - }; -+ unsigned int status = 0; - int ret; - - DRM_DEBUG_DRIVER("\n"); - -+ regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); -+ -+ /* due to old tv, need to restore pinctrl as soon as possible */ -+ if (status & SII902X_PLUGGED_STATUS) -+ pinctrl_pm_select_default_state(&sii902x->i2c->dev); -+ - ret = regulator_bulk_enable(ARRAY_SIZE(sii902x->supplies), - sii902x->supplies); - if (ret) { -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; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0034-ARM-stm32mp1-r0-rc3-ETH.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0034-ARM-stm32mp1-r0-rc3-ETH.patch deleted file mode 100644 index 8d15508..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0034-ARM-stm32mp1-r0-rc3-ETH.patch +++ /dev/null @@ -1,169 +0,0 @@ -From f7da805ac84601d1dbbaf51e8f080844e1e5ae4e Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:40:00 +0100 -Subject: [PATCH 34/52] ARM: stm32mp1-r0-rc3: ETH - ---- - .../devicetree/bindings/net/stm32-dwmac.txt | 4 +-- - drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 36 ++++++++++++++-------- - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++------ - 3 files changed, 36 insertions(+), 24 deletions(-) - -diff --git a/Documentation/devicetree/bindings/net/stm32-dwmac.txt b/Documentation/devicetree/bindings/net/stm32-dwmac.txt -index f42dc68..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 -@@ -25,6 +24,7 @@ Required properties: - - Optional properties: - - clock-names: For MPU family "eth-ck" for PHY without quartz -+ "syscfg-clk" for SYSCFG clock. - - st,eth_clk_sel (boolean) : set this property in RGMII PHY when you do not want use 125Mhz - - st,eth_ref_clk_sel (boolean) : set this property in RMII mode when you have PHY without crystal 50MHz - -diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -index 545b168..8b4ca12 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -@@ -153,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->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) -@@ -209,8 +218,8 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) - } - - /* Need to update PMCCLRR (clear register) */ -- ret = regmap_update_bits(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, -- dwmac->ops->syscfg_eth_mask, ~val); -+ ret = regmap_write(dwmac->regmap, reg + SYSCFG_PMCCLRR_OFFSET, -+ dwmac->ops->syscfg_eth_mask); - - /* Update PMCSETR (set register) */ - return regmap_update_bits(dwmac->regmap, reg, -@@ -318,11 +327,13 @@ 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); -+ err = PTR_ERR(dwmac->syscfg_clk); -+ if (err != -ENOENT) -+ return err; -+ dwmac->syscfg_clk = NULL; - } - - /* Get IRQ information early to have an ability to ask for deferred -@@ -431,7 +442,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/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -index 75896d6..281d9c7 100644 ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -2547,12 +2547,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) - netdev_warn(priv->dev, "PTP init failed\n"); - } - --#ifdef CONFIG_DEBUG_FS -- ret = stmmac_init_fs(dev); -- if (ret < 0) -- netdev_warn(priv->dev, "%s: failed debugFS registration\n", -- __func__); --#endif - priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS; - - if (priv->use_riwt) { -@@ -2753,10 +2747,6 @@ static int stmmac_release(struct net_device *dev) - - netif_carrier_off(dev); - --#ifdef CONFIG_DEBUG_FS -- stmmac_exit_fs(dev); --#endif -- - stmmac_release_ptp(priv); - - return 0; -@@ -4394,6 +4384,13 @@ int stmmac_dvr_probe(struct device *device, - goto error_netdev_register; - } - -+#ifdef CONFIG_DEBUG_FS -+ ret = stmmac_init_fs(ndev); -+ if (ret < 0) -+ netdev_warn(priv->dev, "%s: failed debugFS registration\n", -+ __func__); -+#endif -+ - return ret; - - error_netdev_register: -@@ -4429,6 +4426,9 @@ int stmmac_dvr_remove(struct device *dev) - - netdev_info(priv->dev, "%s: removing driver", __func__); - -+#ifdef CONFIG_DEBUG_FS -+ stmmac_exit_fs(ndev); -+#endif - stmmac_stop_all_dma(priv); - - stmmac_mac_set(priv, priv->ioaddr, false); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0035-ARM-stm32mp1-r0-rc3-IIO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0035-ARM-stm32mp1-r0-rc3-IIO.patch deleted file mode 100644 index a10435f..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0035-ARM-stm32mp1-r0-rc3-IIO.patch +++ /dev/null @@ -1,479 +0,0 @@ -From 461aa8f3143d009efd0365889bddf247cfeafdce Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:35:33 +0100 -Subject: [PATCH 35/52] ARM: stm32mp1-r0-rc3: IIO - ---- - drivers/iio/adc/stm32-adc-core.c | 35 +++++----- - drivers/iio/dac/stm32-dac-core.c | 142 ++++++++++++++++++++++++++++++--------- - drivers/iio/dac/stm32-dac.c | 96 +++++++++++++++++++++++++- - 3 files changed, 220 insertions(+), 53 deletions(-) - -diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index 6234456..ed64bb0 100644 ---- a/drivers/iio/adc/stm32-adc-core.c -+++ b/drivers/iio/adc/stm32-adc-core.c -@@ -677,10 +677,9 @@ static int stm32_adc_switches_supply_en(struct device *dev) - priv->vbooster.reg, - priv->vbooster.mask, en_booster); - else -- ret = regmap_update_bits(priv->vbooster_clr.regmap, -- priv->vbooster_clr.reg, -- priv->vbooster_clr.mask, -- priv->vbooster_clr.mask); -+ 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; -@@ -697,10 +696,9 @@ static int stm32_adc_switches_supply_en(struct device *dev) - priv->anaswvdd.reg, - priv->anaswvdd.mask, anaswvdd); - else -- ret = regmap_update_bits(priv->anaswvdd_clr.regmap, -- priv->anaswvdd_clr.reg, -- priv->anaswvdd_clr.mask, -- priv->anaswvdd_clr.mask); -+ 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; -@@ -714,10 +712,9 @@ static int stm32_adc_switches_supply_en(struct device *dev) - regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg, - priv->vbooster.mask, 0); - else -- regmap_update_bits(priv->vbooster_clr.regmap, -- priv->vbooster_clr.reg, -- priv->vbooster_clr.mask, -- priv->vbooster_clr.mask); -+ 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); -@@ -741,20 +738,18 @@ static void stm32_adc_switches_supply_dis(struct device *dev) - priv->anaswvdd.reg, - priv->anaswvdd.mask, 0); - else -- regmap_update_bits(priv->anaswvdd_clr.regmap, -- priv->anaswvdd_clr.reg, -- priv->anaswvdd_clr.mask, -- priv->anaswvdd_clr.mask); -+ 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_update_bits(priv->vbooster_clr.regmap, -- priv->vbooster_clr.reg, -- priv->vbooster_clr.mask, -- priv->vbooster_clr.mask); -+ 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); -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); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0036-ARM-stm32mp1-r0-rc3-INPUT-TTY.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0036-ARM-stm32mp1-r0-rc3-INPUT-TTY.patch deleted file mode 100644 index e96669a..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0036-ARM-stm32mp1-r0-rc3-INPUT-TTY.patch +++ /dev/null @@ -1,135 +0,0 @@ -From adfe9751275d51343a5b7f26ea93246ae617d986 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:37:06 +0100 -Subject: [PATCH 36/52] ARM: stm32mp1-r0-rc3: INPUT TTY - ---- - .../devicetree/bindings/serial/st,stm32-usart.txt | 1 + - drivers/input/touchscreen/edt-ft5x06.c | 8 +++++++- - drivers/input/touchscreen/goodix.c | 9 +++++++++ - drivers/tty/serial/stm32-usart.c | 18 ++++++++++++++++-- - 4 files changed, 33 insertions(+), 3 deletions(-) - -diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt -index 90ba52f..08b4990 100644 ---- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt -+++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt -@@ -14,6 +14,7 @@ Required properties: - - clocks: The input clock of the USART instance - - Optional properties: -+- resets: Must contain the phandle to the reset controller. - - pinctrl-names: Set to "default". An additional "sleep" state can be defined - to set pins in sleep state when in low power. In case the device is used as - a wakeup source, "idle" state is defined in order to keep RX pin active. -diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c -index 1e18ca0..c1c6f2a 100644 ---- a/drivers/input/touchscreen/edt-ft5x06.c -+++ b/drivers/input/touchscreen/edt-ft5x06.c -@@ -1033,7 +1033,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; - } - -@@ -1152,11 +1152,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 +1174,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 f2d9c2c..9ce8db4 100644 ---- a/drivers/input/touchscreen/goodix.c -+++ b/drivers/input/touchscreen/goodix.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -357,6 +358,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); -@@ -949,6 +957,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/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c -index 5c6c3c0..d606eb5 100644 ---- a/drivers/tty/serial/stm32-usart.c -+++ b/drivers/tty/serial/stm32-usart.c -@@ -938,6 +938,7 @@ 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; -@@ -952,8 +953,21 @@ static int stm32_init_port(struct stm32_port *stm32port, - - stm32port->wakeirq = platform_get_irq_byname(pdev, "wakeup"); - stm32port->fifoen = stm32port->info->cfg.has_fifo; -- stm32port->console_pins = pinctrl_lookup_state(pdev->dev.pins->p, -- "no_console_suspend"); -+ -+ 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); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0037-ARM-stm32mp1-r0-rc3-IRQ-Mailbox.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0037-ARM-stm32mp1-r0-rc3-IRQ-Mailbox.patch deleted file mode 100644 index 7896510..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0037-ARM-stm32mp1-r0-rc3-IRQ-Mailbox.patch +++ /dev/null @@ -1,277 +0,0 @@ -From 4cc987cced2179b54ebc0a977ff3ef4210acb38c Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:36:09 +0100 -Subject: [PATCH 37/52] ARM: stm32mp1-r0-rc3: IRQ Mailbox - ---- - drivers/irqchip/irq-stm32-exti.c | 122 ++++++++++++++++++++++++++------------- - 1 file changed, 83 insertions(+), 39 deletions(-) - -diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index 9cc15f1..223ee2e 100644 ---- a/drivers/irqchip/irq-stm32-exti.c -+++ b/drivers/irqchip/irq-stm32-exti.c -@@ -6,6 +6,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -21,7 +22,8 @@ - - #define IRQS_PER_BANK 32 - --#define HWSPINLOCK_TIMEOUT 5 /* msec */ -+#define HWSPNLCK_TIMEOUT 1000 /* usec */ -+#define HWSPNLCK_RETRY_DELAY 100 /* usec */ - - struct stm32_exti_bank { - u32 imr_ofst; -@@ -35,6 +37,12 @@ struct stm32_exti_bank { - - #define UNDEF_REG ~0 - -+enum stm32_exti_hwspinlock { -+ HWSPINLOCK_UNKNOWN, -+ HWSPINLOCK_NONE, -+ HWSPINLOCK_READY, -+}; -+ - struct stm32_desc_irq { - u32 exti; - u32 irq_parent; -@@ -50,7 +58,6 @@ struct stm32_exti_drv_data { - struct stm32_exti_chip_data { - struct stm32_exti_host_data *host_data; - const struct stm32_exti_bank *reg_bank; -- struct hwspinlock *hwlock; - struct raw_spinlock rlock; - u32 wake_active; - u32 mask_cache; -@@ -62,6 +69,9 @@ struct stm32_exti_host_data { - void __iomem *base; - struct stm32_exti_chip_data *chips_data; - const struct stm32_exti_drv_data *drv_data; -+ struct device_node *node; -+ enum stm32_exti_hwspinlock hwlock_state; -+ struct hwspinlock *hwlock; - }; - - static struct stm32_exti_host_data *stm32_host_data; -@@ -273,20 +283,75 @@ 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) -+{ -+ struct stm32_exti_host_data *host_data = chip_data->host_data; -+ struct hwspinlock *hwlock; -+ int id, ret = 0, timeout = 0; -+ -+ /* first time, check for hwspinlock availability */ -+ if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) { -+ id = of_hwspin_lock_get_id(host_data->node, 0); -+ if (id >= 0) { -+ hwlock = hwspin_lock_request_specific(id); -+ if (hwlock) { -+ /* found valid hwspinlock */ -+ host_data->hwlock_state = HWSPINLOCK_READY; -+ host_data->hwlock = hwlock; -+ pr_debug("%s hwspinlock = %d\n", __func__, id); -+ } else { -+ host_data->hwlock_state = HWSPINLOCK_NONE; -+ } -+ } else if (id != -EPROBE_DEFER) { -+ host_data->hwlock_state = HWSPINLOCK_NONE; -+ } else { -+ /* hwspinlock driver shall be ready at that stage */ -+ ret = -EPROBE_DEFER; -+ } -+ } -+ -+ if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) { -+ /* -+ * 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(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 (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY)) -+ 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; - u32 rtsr, ftsr; -- int err = 0; -+ int err; - - irq_gc_lock(gc); - -- if (chip_data->hwlock) -- err = hwspin_lock_timeout(chip_data->hwlock, -- HWSPINLOCK_TIMEOUT); -- -+ err = stm32_exti_hwspin_lock(chip_data); - if (err) - goto unlock; - -@@ -301,8 +366,7 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type) - irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); - - unspinlock: -- if (chip_data->hwlock) -- hwspin_unlock(chip_data->hwlock); -+ stm32_exti_hwspin_unlock(chip_data); - unlock: - irq_gc_unlock(gc); - -@@ -470,14 +534,11 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) - const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; - void __iomem *base = chip_data->host_data->base; - u32 rtsr, ftsr; -- int err = 0; -+ int err; - - raw_spin_lock(&chip_data->rlock); - -- if (chip_data->hwlock) -- err = hwspin_lock_timeout(chip_data->hwlock, -- HWSPINLOCK_TIMEOUT); -- -+ err = stm32_exti_hwspin_lock(chip_data); - if (err) - goto unlock; - -@@ -492,15 +553,14 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) - writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); - - unspinlock: -- if (chip_data->hwlock) -- hwspin_unlock(chip_data->hwlock); -+ stm32_exti_hwspin_unlock(chip_data); - unlock: - raw_spin_unlock(&chip_data->rlock); - - if (d->parent_data->chip) - irq_chip_set_type_parent(d, type); - -- return 0; -+ return err; - } - - static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) -@@ -650,6 +710,8 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, - return NULL; - - host_data->drv_data = dd; -+ host_data->node = node; -+ host_data->hwlock_state = HWSPINLOCK_UNKNOWN; - host_data->chips_data = kcalloc(dd->bank_nr, - sizeof(struct stm32_exti_chip_data), - GFP_KERNEL); -@@ -676,13 +738,11 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, - - static struct - stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, -- u32 bank_idx, -- struct device_node *node) -+ u32 bank_idx) - { - 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]; -@@ -691,10 +751,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 -@@ -702,8 +758,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", h_data->node, bank_idx); - - return chip_data; - } -@@ -716,7 +771,6 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, - int nr_irqs, ret, i; - struct irq_chip_generic *gc; - struct irq_domain *domain; -- struct hwspinlock *hwlock = NULL; - - host_data = stm32_exti_host_init(drv_data, node); - if (!host_data) -@@ -739,22 +793,12 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, - goto out_free_domain; - } - -- /* hwspinlock is optional */ -- ret = of_hwspin_lock_get_id(node, 0); -- if (ret < 0) { -- if (ret == -EPROBE_DEFER) -- goto out_free_domain; -- } else { -- hwlock = hwspin_lock_request_specific(ret); -- } -- - for (i = 0; i < drv_data->bank_nr; i++) { - const struct stm32_exti_bank *stm32_bank; - struct stm32_exti_chip_data *chip_data; - - stm32_bank = drv_data->exti_banks[i]; -- chip_data = stm32_exti_chip_init(host_data, i, node); -- chip_data->hwlock = hwlock; -+ chip_data = stm32_exti_chip_init(host_data, i); - - gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); - -@@ -836,7 +880,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, - return -ENOMEM; - - for (i = 0; i < drv_data->bank_nr; i++) -- stm32_exti_chip_init(host_data, i, node); -+ stm32_exti_chip_init(host_data, i); - - domain = irq_domain_add_hierarchy(parent_domain, 0, - drv_data->bank_nr * IRQS_PER_BANK, --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0038-ARM-stm32mp1-r0-rc3-MEDIA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0038-ARM-stm32mp1-r0-rc3-MEDIA.patch deleted file mode 100644 index fe3c019..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0038-ARM-stm32mp1-r0-rc3-MEDIA.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 6c1f5d14ed9c421276ad7beac5475e1114520369 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:48:55 +0100 -Subject: [PATCH 38/52] ARM: stm32mp1-r0-rc3: MEDIA - ---- - drivers/media/i2c/ov5640.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 27b75e7..22ddfca4 100644 ---- a/drivers/media/i2c/ov5640.c -+++ b/drivers/media/i2c/ov5640.c -@@ -2691,8 +2691,7 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) - - if (sensor->streaming == !enable) { - if (enable && sensor->pending_mode_change) { -- ret = ov5640_set_mode(sensor, sensor->last_mode); -- -+ ret = ov5640_set_mode(sensor); - if (ret) - goto out; - } --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0039-ARM-stm32mp1-r0-rc3-MMC-MTD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0039-ARM-stm32mp1-r0-rc3-MMC-MTD.patch deleted file mode 100644 index 767d64c..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0039-ARM-stm32mp1-r0-rc3-MMC-MTD.patch +++ /dev/null @@ -1,478 +0,0 @@ -From 0affc90bd300ecd2c60aee7fd97251a8d2aad01f Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:38:59 +0100 -Subject: [PATCH 39/52] ARM: stm32mp1-r0-rc3: MMC MTD - ---- - Documentation/devicetree/bindings/mmc/mmci.txt | 2 + - drivers/mmc/host/mmci.c | 61 +++++++++- - drivers/mmc/host/mmci.h | 8 +- - drivers/mmc/host/mmci_stm32_sdmmc.c | 162 ++++++++++++++++++++++++- - 4 files changed, 219 insertions(+), 14 deletions(-) - -diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt -index 6d3c626..da6d59e 100644 ---- a/Documentation/devicetree/bindings/mmc/mmci.txt -+++ b/Documentation/devicetree/bindings/mmc/mmci.txt -@@ -15,6 +15,8 @@ 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 -diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index 02b631f..6c2b1a0 100644 ---- a/drivers/mmc/host/mmci.c -+++ b/drivers/mmc/host/mmci.c -@@ -14,6 +14,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -25,6 +26,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -291,7 +293,8 @@ static struct variant_data variant_stm32_sdmmc = { - .busy_detect_flag = MCI_STM32_BUSYD0, - .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, - .init = sdmmc_variant_init, -- .quirks = MMCI_QUIRK_STM32_DTMODE, -+ .quirks = MMCI_QUIRK_STM32_DTMODE | -+ MMCI_QUIRK_STM32_VSWITCH, - }; - - static struct variant_data variant_stm32_sdmmcv2 = { -@@ -318,7 +321,8 @@ static struct variant_data variant_stm32_sdmmcv2 = { - .busy_detect_flag = MCI_STM32_BUSYD0, - .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, - .init = sdmmc_variant_init, -- .quirks = MMCI_QUIRK_STM32_DTMODE, -+ .quirks = MMCI_QUIRK_STM32_DTMODE | -+ MMCI_QUIRK_STM32_VSWITCH, - }; - - static struct variant_data variant_qcom = { -@@ -1191,6 +1195,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) - 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; - -@@ -1284,13 +1292,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - unsigned int status) - { - void __iomem *base = host->base; -- bool busy_resp = !!(cmd->flags & MMC_RSP_BUSY); -- bool sbc; -+ bool busy_resp, sbc; - u32 err_msk; - - if (!cmd) - return; - -+ busy_resp = !!(cmd->flags & MMC_RSP_BUSY); - sbc = (cmd == host->mrq->sbc); - - /* -@@ -1575,11 +1583,14 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id) - static irqreturn_t mmci_irq(int irq, void *dev_id) - { - struct mmci_host *host = dev_id; -+ bool busy_resp; - u32 status; - int ret = 0; - - spin_lock(&host->lock); - -+ busy_resp = host->cmd ? !!(host->cmd->flags & MMC_RSP_BUSY) : false; -+ - do { - status = readl(host->base + MMCISTATUS); - -@@ -1619,9 +1630,12 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) - } - - /* -- * Don't poll for busy completion in irq context. -+ * Don't poll for: -+ * -busy completion in irq context. -+ * -cmd without busy response check like cmd11 - */ -- if (host->variant->busy_detect && host->busy_status) -+ if (host->variant->busy_detect && -+ (!busy_resp || host->busy_status)) - status &= ~host->variant->busy_detect_flag; - - ret = 1; -@@ -1796,6 +1810,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)) { -@@ -1808,6 +1824,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, -@@ -1822,6 +1860,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, -@@ -1830,6 +1878,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) -diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h -index 55867fc..e10093e 100644 ---- a/drivers/mmc/host/mmci.h -+++ b/drivers/mmc/host/mmci.h -@@ -170,6 +170,7 @@ - #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) -@@ -364,8 +365,9 @@ struct variant_data { - 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_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 { -@@ -382,6 +384,7 @@ 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); -+ int (*execute_tuning)(struct mmc_host *mmc, u32 opcode); - }; - - struct mmci_host { -@@ -414,6 +417,7 @@ struct mmci_host { - 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; -diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c -index cfbfc6f..e5ccc68 100644 ---- a/drivers/mmc/host/mmci_stm32_sdmmc.c -+++ b/drivers/mmc/host/mmci_stm32_sdmmc.c -@@ -3,14 +3,31 @@ - * 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) - -@@ -20,11 +37,17 @@ struct sdmmc_lli_desc { - 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 +59,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 +68,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,7 +115,7 @@ 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; - - idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); - if (!idma) -@@ -123,7 +146,7 @@ static int sdmmc_idma_setup(struct mmci_host *host) - 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; -@@ -226,12 +249,24 @@ 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; - - 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); -@@ -265,6 +300,105 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) - } - } - -+static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb, -+ int unit, int phase, bool sampler) -+{ -+ u32 cr, cfgr; -+ -+ writel_relaxed(DLYB_CR_SEN, 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); -+ -+ cr = DLYB_CR_DEN; -+ if (sampler) -+ cr |= DLYB_CR_SEN; -+ -+ writel_relaxed(cr, 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, -@@ -274,9 +408,25 @@ 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, -+ .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; - } --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0040-ARM-stm32mp1-r0-rc3-PINCTRL-PWM-RESET-RTC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0040-ARM-stm32mp1-r0-rc3-PINCTRL-PWM-RESET-RTC.patch deleted file mode 100644 index 218a514..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0040-ARM-stm32mp1-r0-rc3-PINCTRL-PWM-RESET-RTC.patch +++ /dev/null @@ -1,604 +0,0 @@ -From d00006c83840de8fa5a6049ce31117d4e9c76184 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:40:47 +0100 -Subject: [PATCH 40/52] ARM: stm32mp1-r0-rc3: PINCTRL PWM RESET RTC - ---- - drivers/pinctrl/stm32/pinctrl-stm32.c | 219 +++++++++++++++++++++++----------- - drivers/regulator/stpmic1_regulator.c | 17 +-- - 2 files changed, 152 insertions(+), 84 deletions(-) - -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c -index 914bee4..7a27431 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c -@@ -7,6 +7,7 @@ - * Heavily based on Mediatek's pinctrl driver - */ - #include -+#include - #include - #include - #include -@@ -65,7 +66,8 @@ - #define gpio_range_to_bank(chip) \ - container_of(chip, struct stm32_gpio_bank, range) - --#define HWSPINLOCK_TIMEOUT 5 /* msec */ -+#define HWSPNLCK_TIMEOUT 1000 /* usec */ -+#define HWSPNLCK_RETRY_DELAY 100 /* usec */ - - static const char * const stm32_gpio_functions[] = { - "gpio", "af0", "af1", -@@ -110,6 +112,8 @@ 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; -@@ -150,6 +154,26 @@ 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, -@@ -326,9 +350,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, -@@ -357,6 +412,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 */ -@@ -436,7 +492,7 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, - unsigned int num_configs; - bool has_config = 0; - unsigned reserve = 0; -- int num_pins, num_funcs, maps_per_pin, i, err; -+ int num_pins, num_funcs, maps_per_pin, i, err = 0; - - pctl = pinctrl_dev_get_drvdata(pctldev); - -@@ -463,41 +519,45 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, - if (has_config && num_pins >= 1) - maps_per_pin++; - -- if (!num_pins || !maps_per_pin) -- return -EINVAL; -+ if (!num_pins || !maps_per_pin) { -+ err = -EINVAL; -+ goto exit; -+ } - - reserve = num_pins * maps_per_pin; - - err = pinctrl_utils_reserve_map(pctldev, map, - reserved_maps, num_maps, reserve); - if (err) -- return err; -+ goto exit; - - for (i = 0; i < num_pins; i++) { - err = of_property_read_u32_index(node, "pinmux", - i, &pinfunc); - if (err) -- return err; -+ goto exit; - - pin = STM32_GET_PIN_NO(pinfunc); - func = STM32_GET_PIN_FUNC(pinfunc); - - if (!stm32_pctrl_is_function_valid(pctl, pin, func)) { - dev_err(pctl->dev, "invalid function.\n"); -- return -EINVAL; -+ err = -EINVAL; -+ goto exit; - } - - grp = stm32_pctrl_find_group_by_pin(pctl, pin); - if (!grp) { - dev_err(pctl->dev, "unable to match pin %d to group\n", - pin); -- return -EINVAL; -+ err = -EINVAL; -+ goto exit; - } - - err = stm32_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map, - reserved_maps, num_maps); - if (err) -- return err; -+ goto exit; - - if (has_config) { - err = pinctrl_utils_add_map_configs(pctldev, map, -@@ -505,11 +565,13 @@ static int stm32_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, - configs, num_configs, - PIN_MAP_TYPE_CONFIGS_GROUP); - if (err) -- return err; -+ goto exit; - } - } - -- return 0; -+exit: -+ kfree(configs); -+ return err; - } - - static int stm32_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev, -@@ -599,8 +661,8 @@ 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; -@@ -612,12 +674,12 @@ static void 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 = 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); -@@ -633,11 +695,12 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank, - stm32_gpio_backup_mode(bank, pin, mode, alt); - - if (pctl->hwlock) -- hwspin_unlock(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, -@@ -694,9 +757,7 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, - 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, -@@ -706,9 +767,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 = { -@@ -722,8 +781,8 @@ 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; -@@ -733,12 +792,12 @@ static void 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 = 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); -@@ -749,11 +808,12 @@ static void stm32_pconf_set_driving(struct stm32_gpio_bank *bank, - stm32_gpio_backup_driving(bank, offset, drive); - - if (pctl->hwlock) -- hwspin_unlock(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, -@@ -774,8 +834,8 @@ 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; -@@ -785,12 +845,12 @@ static void 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 = 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); -@@ -801,11 +861,12 @@ static void stm32_pconf_set_speed(struct stm32_gpio_bank *bank, - stm32_gpio_backup_speed(bank, offset, speed); - - if (pctl->hwlock) -- hwspin_unlock(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, -@@ -826,8 +887,8 @@ 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; -@@ -837,12 +898,12 @@ static void 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 = 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); -@@ -853,11 +914,12 @@ static void stm32_pconf_set_bias(struct stm32_gpio_bank *bank, - stm32_gpio_backup_bias(bank, offset, bias); - - if (pctl->hwlock) -- hwspin_unlock(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, -@@ -920,22 +982,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); -@@ -1295,6 +1357,8 @@ int stm32_pctl_probe(struct platform_device *pdev) - pctl->hwlock = hwspin_lock_request_specific(hwlock_id); - } - -+ spin_lock_init(&pctl->irqmux_lock); -+ - pctl->dev = dev; - pctl->match_data = match->data; - -@@ -1414,22 +1478,23 @@ void stm32_gpio_backup_bias(struct stm32_gpio_bank *bank, - bank->pin_backup[offset] |= bias << STM32_GPIO_BKP_PUPD_SHIFT; - } - --void stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin) -+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; -+ return 0; - - pin_is_irq = gpiochip_line_is_irq(range->gc, offset); - - if (!desc || (!pin_is_irq && !desc->gpio_owner)) -- return; -+ return 0; - - bank = gpiochip_get_data(range->gc); - -@@ -1438,7 +1503,10 @@ void stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin) - mode = bank->pin_backup[offset] & STM32_GPIO_BKP_MODE_MASK; - mode >>= STM32_GPIO_BKP_MODE_SHIFT; - -- stm32_pmx_set_mode(bank, offset, mode, alt); -+ 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; -@@ -1447,28 +1515,39 @@ void stm32_pinctrl_restore_gpio_regs(struct stm32_pinctrl *pctl, u32 pin) - - val = bank->pin_backup[offset] & BIT(STM32_GPIO_BKP_TYPE); - val >>= STM32_GPIO_BKP_TYPE; -- stm32_pconf_set_driving(bank, offset, val); -+ 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; -- stm32_pconf_set_speed(bank, offset, val); -+ 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; -- stm32_pconf_set_bias(bank, offset, val); -+ 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; -+ int i, ret; - -- for (i = g->pin; i < g->pin + pctl->ngroups; i++) -- stm32_pinctrl_restore_gpio_regs(pctl, i); -+ for (i = g->pin; i < g->pin + pctl->ngroups; i++) { -+ ret = stm32_pinctrl_restore_gpio_regs(pctl, i); -+ if (ret) -+ return ret; -+ } - - return 0; - } -diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c -index 96f1808..31c960c 100644 ---- a/drivers/regulator/stpmic1_regulator.c -+++ b/drivers/regulator/stpmic1_regulator.c -@@ -76,8 +76,9 @@ enum { - #define STPMIC1_BUCK_MODE_LP BUCK_HPLP_ENABLE_MASK - - struct regulator_linear_range buck1_ranges[] = { -- REGULATOR_LINEAR_RANGE(600000, 0, 30, 25000), -- REGULATOR_LINEAR_RANGE(1350000, 31, 63, 0), -+ REGULATOR_LINEAR_RANGE(725000, 0, 4, 0), -+ REGULATOR_LINEAR_RANGE(725000, 5, 36, 25000), -+ REGULATOR_LINEAR_RANGE(1500000, 37, 63, 0), - }; - - struct regulator_linear_range buck2_ranges[] = { -@@ -157,7 +158,6 @@ static struct regulator_ops stpmic1_ldo_ops = { - .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_over_current_protection = stpmic1_set_icc, - }; - -@@ -169,7 +169,6 @@ static struct regulator_ops stpmic1_ldo3_ops = { - .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, - .get_bypass = regulator_get_bypass_regmap, - .set_bypass = regulator_set_bypass_regmap, - .set_over_current_protection = stpmic1_set_icc, -@@ -179,7 +178,6 @@ static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, -- .set_pull_down = regulator_set_pull_down_regmap, - .set_over_current_protection = stpmic1_set_icc, - }; - -@@ -201,7 +199,6 @@ static struct regulator_ops stpmic1_vref_ddr_ops = { - .is_enabled = regulator_is_enabled_regmap, - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, -- .set_pull_down = regulator_set_pull_down_regmap, - }; - - static struct regulator_ops stpmic1_switch_regul_ops = { -@@ -227,8 +224,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = { - .enable_val = 1, \ - .disable_val = 0, \ - .enable_time = PMIC_ENABLE_TIME_US, \ -- .pull_down_reg = ids##_PULL_DOWN_REG, \ -- .pull_down_mask = ids##_PULL_DOWN_MASK, \ - .supply_name = #base, \ - } - -@@ -252,8 +247,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = { - .bypass_mask = LDO_BYPASS_MASK, \ - .bypass_val_on = LDO_BYPASS_MASK, \ - .bypass_val_off = 0, \ -- .pull_down_reg = ids##_PULL_DOWN_REG, \ -- .pull_down_mask = ids##_PULL_DOWN_MASK, \ - .supply_name = #base, \ - } - -@@ -271,8 +264,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = { - .enable_val = 1, \ - .disable_val = 0, \ - .enable_time = PMIC_ENABLE_TIME_US, \ -- .pull_down_reg = ids##_PULL_DOWN_REG, \ -- .pull_down_mask = ids##_PULL_DOWN_MASK, \ - .supply_name = #base, \ - } - -@@ -312,8 +303,6 @@ static struct regulator_ops stpmic1_switch_regul_ops = { - .enable_val = 1, \ - .disable_val = 0, \ - .enable_time = PMIC_ENABLE_TIME_US, \ -- .pull_down_reg = ids##_PULL_DOWN_REG, \ -- .pull_down_mask = ids##_PULL_DOWN_MASK, \ - .supply_name = #base, \ - } - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0041-ARM-stm32mp1-r0-rc3-REMOTEPROC-RPMSG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0041-ARM-stm32mp1-r0-rc3-REMOTEPROC-RPMSG.patch deleted file mode 100644 index 44c6cfd..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0041-ARM-stm32mp1-r0-rc3-REMOTEPROC-RPMSG.patch +++ /dev/null @@ -1,1617 +0,0 @@ -From 0fbfdc3872adc5747402b6b9e91c00708b8ac842 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:41:19 +0100 -Subject: [PATCH 41/52] ARM: stm32mp1-r0-rc3: REMOTEPROC RPMSG - ---- - .../devicetree/bindings/remoteproc/stm32-rproc.txt | 10 +- - drivers/remoteproc/remoteproc_core.c | 634 ++++++++++++++++----- - drivers/remoteproc/remoteproc_debugfs.c | 22 +- - drivers/remoteproc/remoteproc_internal.h | 12 +- - drivers/remoteproc/remoteproc_virtio.c | 56 +- - drivers/remoteproc/stm32_rproc.c | 228 ++++++-- - drivers/rpmsg/virtio_rpmsg_bus.c | 6 +- - include/linux/remoteproc.h | 36 +- - 8 files changed, 808 insertions(+), 196 deletions(-) - -diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -index 7df6a26..98d1e31e 100644 ---- a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -+++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -@@ -5,10 +5,12 @@ boots firmwares on the ST32MP family chipset. - - Required properties: - - compatible: Must be "st,stm32mp1-rproc" --- reg: Should contain the address ranges for specific internal memory -- regions. --- reg-names: Should contain the corresponding names for specific internal -- memory regions. -+- 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 -diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c -index 21726f0..dd7e348 100644 ---- a/drivers/remoteproc/remoteproc_core.c -+++ b/drivers/remoteproc/remoteproc_core.c -@@ -39,6 +39,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - #include -@@ -54,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); - -@@ -141,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 -@@ -184,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; -@@ -202,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); - } - - /* -@@ -233,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; -@@ -242,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; - } -@@ -288,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 */ -@@ -317,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 -@@ -349,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) -@@ -380,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++) { -@@ -411,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; - } - -@@ -424,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); - } - - /** -@@ -454,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) { -@@ -470,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; - } -@@ -500,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; - } -@@ -585,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. -@@ -658,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; -@@ -679,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. - */ -@@ -846,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 - */ -@@ -868,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 */ -@@ -897,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); - } -@@ -1014,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) { -@@ -1021,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; -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..9ee63c0 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,48 @@ 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; -+ } -+ } -+ } -+ - vdev->id.device = id, - vdev->config = &rproc_virtio_config_ops, - vdev->dev.parent = dev; -diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index 548afdd..9a7e034 100644 ---- a/drivers/remoteproc/stm32_rproc.c -+++ b/drivers/remoteproc/stm32_rproc.c -@@ -7,6 +7,7 @@ - - #include - #include -+#include - #include - #include - #include -@@ -38,12 +39,19 @@ struct stm32_syscon { - }; - - 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; -@@ -55,13 +63,63 @@ struct stm32_rproc { - struct reset_control *rst; - struct stm32_syscon hold_boot; - struct stm32_syscon pdds; -- struct stm32_rproc_mem ram[2]; -+ u32 nb_rmems; -+ struct stm32_rproc_mem *rmems; - struct stm32_mbox mb[MBOX_NB_MBX]; - bool secured_soc; - u32 rsc_addr; - u32 rsc_len; - }; - -+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, "da %llx to pa %#x\n", *da, pa); -+ return 0; -+ } -+ -+ 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) - { -@@ -71,6 +129,56 @@ static int stm32_rproc_elf_load_segments(struct rproc *rproc, - 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; -@@ -88,12 +196,22 @@ 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) - { -- int status; -+ int status, i; - struct resource_table *table = NULL; - struct stm32_rproc *ddata = rproc->priv; - size_t tablesz = 0; -+ const struct elf32_hdr *ehdr; -+ const struct elf32_phdr *phdr; - - if (!rproc->early_boot) { -+ /* set coredump segments */ -+ ehdr = (const struct elf32_hdr *)fw->data; -+ phdr = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff); -+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) -+ rproc_coredump_add_segment(rproc, phdr->p_paddr, -+ phdr->p_memsz); -+ -+ /* load resource table */ - status = rproc_elf_load_rsc_table(rproc, fw); - if (status) - goto no_rsc_table; -@@ -124,6 +242,58 @@ static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, - 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); -+ } 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) -@@ -348,33 +518,12 @@ static void stm32_rproc_kick(struct rproc *rproc, int vqid) - } - } - --static void *stm32_rproc_da_to_va(struct rproc *rproc, u64 da, int len) --{ -- struct stm32_rproc *ddata = rproc->priv; -- void *va = NULL; -- u32 offset; -- unsigned int i; -- -- for (i = 0; i < 2; i++) { -- if (da >= ddata->ram[i].dev_addr && da + len <= -- ddata->ram[i].dev_addr + ddata->ram[i].size) { -- offset = da - ddata->ram[i].dev_addr; -- /* __force to make sparse happy with type conversion */ -- va = (__force void *)(ddata->ram[i].cpu_addr + offset); -- break; -- } -- } -- -- return va; --} -- - static struct rproc_ops st_rproc_ops = { - .start = stm32_rproc_start, - .stop = stm32_rproc_stop, - .kick = stm32_rproc_kick, -- .da_to_va = stm32_rproc_da_to_va, - .load = stm32_rproc_elf_load_segments, -- .parse_fw = stm32_rproc_elf_load_rsc_table, -+ .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, -@@ -414,9 +563,8 @@ 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 resource *res; - struct stm32_syscon tz; -- unsigned int tzen, i = 0; -+ unsigned int tzen; - int err, irq; - - irq = platform_get_irq_byname(pdev, "wdg"); -@@ -466,25 +614,6 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) - if (err) - dev_warn(dev, "failed to get pdds\n"); - -- while ((res = platform_get_resource(pdev, IORESOURCE_MEM, i))) { -- ddata->ram[i].cpu_addr = devm_ioremap_resource(dev, res); -- if (IS_ERR(ddata->ram[i].cpu_addr)) -- return err; -- -- ddata->ram[i].bus_addr = res->start; -- ddata->ram[i].size = resource_size(res); -- -- /* -- * the m4 has retram at address 0 in its view (DA) -- * so for retram DA=0x0 PA=bus_addr else DA=PA=bus_addr -- */ -- if (i == 0) -- ddata->ram[i].dev_addr = 0x0; -- else -- ddata->ram[i].dev_addr = ddata->ram[i].bus_addr; -- -- i++; -- } - - rproc->auto_boot = of_property_read_bool(np, "auto_boot"); - rproc->recovery_disabled = !of_property_read_bool(np, "recovery"); -@@ -504,9 +633,7 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) - } - } - -- of_reserved_mem_device_init(dev); -- -- return 0; -+ return stm32_rproc_of_memory_translations(rproc); - } - - static int stm32_rproc_probe(struct platform_device *pdev) -@@ -533,7 +660,7 @@ static int stm32_rproc_probe(struct platform_device *pdev) - if (!rproc->early_boot) { - ret = stm32_rproc_stop(rproc); - if (ret) -- goto free_mem; -+ goto free_rproc; - } - - stm32_rproc_request_mbox(rproc); -@@ -546,8 +673,6 @@ static int stm32_rproc_probe(struct platform_device *pdev) - - free_mb: - stm32_rproc_free_mbox(rproc); --free_mem: -- of_reserved_mem_device_release(dev); - free_rproc: - rproc_free(rproc); - return ret; -@@ -563,7 +688,6 @@ static int stm32_rproc_remove(struct platform_device *pdev) - - rproc_del(rproc); - stm32_rproc_free_mbox(rproc); -- of_reserved_mem_device_release(dev); - rproc_free(rproc); - - return 0; -diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c -index 481eaea..bc5877a 100644 ---- a/drivers/rpmsg/virtio_rpmsg_bus.c -+++ b/drivers/rpmsg/virtio_rpmsg_bus.c -@@ -923,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) { -@@ -991,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); -@@ -1026,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 787fd18..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; - - /** -@@ -441,6 +454,7 @@ struct rproc_dump_segment { - * @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; -@@ -474,6 +488,7 @@ struct rproc { - bool auto_boot; - struct list_head dump_segments; - bool early_boot; -+ int nb_vdev; - }; - - /** -@@ -501,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 -@@ -511,7 +525,6 @@ struct rproc_subdev { - */ - struct rproc_vring { - void *va; -- dma_addr_t dma; - int len; - u32 da; - u32 align; -@@ -523,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 -@@ -530,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; -@@ -542,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); -@@ -555,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); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0042-ARM-stm32mp1-r0-rc3-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0042-ARM-stm32mp1-r0-rc3-SOUND.patch deleted file mode 100644 index 0b637d5..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0042-ARM-stm32mp1-r0-rc3-SOUND.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 6c92e60d3e402e1fcbd1bfa11185c995ce41d190 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:47:43 +0100 -Subject: [PATCH 42/52] ARM: stm32mp1-r0-rc3: SOUND - ---- - sound/soc/stm/stm32_sai_sub.c | 58 ++++++++++++++++++++++++++++++------------- - 1 file changed, 41 insertions(+), 17 deletions(-) - -diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c -index 1f23ca4..3f0540a 100644 ---- a/sound/soc/stm/stm32_sai_sub.c -+++ b/sound/soc/stm/stm32_sai_sub.c -@@ -313,6 +313,23 @@ static int stm32_sai_set_clk_div(struct stm32_sai_sub_data *sai, - 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, "Set parent clock returned: %d\n", ret); -+ -+ return ret; -+} -+ - static long stm32_sai_mclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) - { -@@ -492,25 +509,26 @@ 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) { -+ if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) { - ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, - SAI_XCR1_NODIV, - (unsigned int)~SAI_XCR1_NODIV); - if (ret < 0) - return ret; - -- dev_dbg(cpu_dai->dev, "SAI MCLK frequency is %uHz\n", freq); -- 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; - -- if (sai->sai_mclk) { -- ret = clk_set_rate_exclusive(sai->sai_mclk, -- sai->mclk_rate); -- if (ret) { -- dev_err(cpu_dai->dev, -- "Could not set mclk rate\n"); -- return ret; -- } -+ ret = clk_set_rate_exclusive(sai->sai_mclk, freq); -+ if (ret) { -+ dev_err(cpu_dai->dev, "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; -@@ -906,11 +924,13 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, - int cr1, mask, div = 0; - int sai_clk_rate, mclk_ratio, den; - unsigned int rate = params_rate(params); -+ int 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); -+ if (!sai->sai_mclk) { -+ ret = stm32_sai_set_parent_clock(sai, rate); -+ if (ret) -+ return ret; -+ } - sai_clk_rate = clk_get_rate(sai->sai_ck); - - if (STM_SAI_IS_F4(sai->pdata)) { -@@ -1064,9 +1084,13 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, - regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, - SAI_XCR1_NODIV); - -- clk_disable_unprepare(sai->sai_ck); -+ /* 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_rate_exclusive_put(sai->sai_mclk); -+ clk_disable_unprepare(sai->sai_ck); - - sai->substream = NULL; - } --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0043-ARM-stm32mp1-r0-rc3-MISC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0043-ARM-stm32mp1-r0-rc3-MISC.patch deleted file mode 100644 index 123e396..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0043-ARM-stm32mp1-r0-rc3-MISC.patch +++ /dev/null @@ -1,1067 +0,0 @@ -From 64b878ba46af224fa2c1d0bf7c784927e1890f3a Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:53:08 +0100 -Subject: [PATCH 43/52] ARM: stm32mp1-r0-rc3: MISC - ---- - .../devicetree/bindings/soc/stm32/stm32_hdp.txt | 39 ++++ - arch/arm/Kconfig.debug | 30 ++- - arch/arm/boot/dts/Makefile | 2 + - arch/arm/include/debug/stm32.S | 19 +- - drivers/hwspinlock/hwspinlock_core.c | 15 +- - drivers/hwspinlock/stm32_hwspinlock.c | 7 + - drivers/hwtracing/coresight/coresight-stm.c | 58 ++++- - drivers/soc/st/Kconfig | 8 + - drivers/soc/st/Makefile | 1 + - drivers/soc/st/stm32_hdp.c | 242 +++++++++++++++++++++ - drivers/spi/spi-stm32-qspi.c | 192 +++++++++++++++- - include/dt-bindings/soc/stm32-hdp.h | 108 +++++++++ - 12 files changed, 694 insertions(+), 27 deletions(-) - create mode 100644 Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt - create mode 100644 drivers/soc/st/stm32_hdp.c - create mode 100644 include/dt-bindings/soc/stm32-hdp.h - -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/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index d5ec6c3..88849c1 100644 ---- a/arch/arm/Kconfig.debug -+++ b/arch/arm/Kconfig.debug -@@ -1186,23 +1186,37 @@ choice - - config STM32F4_DEBUG_UART - bool "Use STM32F4 UART for low-level debug" -- depends on ARCH_STM32 -+ 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. -+ 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 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. -+ 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. - -@@ -1607,6 +1621,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 -@@ -1700,10 +1716,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 -@@ -1815,7 +1833,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/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index fdf53f5..5665290 100644 ---- a/arch/arm/boot/dts/Makefile -+++ b/arch/arm/boot/dts/Makefile -@@ -924,9 +924,11 @@ dtb-$(CONFIG_ARCH_STM32) += \ - 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-a7-examples.dtb \ - stm32mp157c-ev1-m4-examples.dtb - dtb-$(CONFIG_MACH_SUN4I) += \ - sun4i-a10-a1000.dtb \ -diff --git a/arch/arm/include/debug/stm32.S b/arch/arm/include/debug/stm32.S -index 427561e..3353a81 100644 ---- a/arch/arm/include/debug/stm32.S -+++ b/arch/arm/include/debug/stm32.S -@@ -4,21 +4,12 @@ - * Author: Gerald Baeza for STMicroelectronics. - */ - --#ifdef CONFIG_ARM_SINGLE_ARMV7M --#define STM32_UART_BASE_PHYS 0x40011000 /* USART1 */ --#define STM32_UART_BASE_VIRT STM32_UART_BASE_PHYS /* no MMU */ --#else --#define STM32_UART_BASE_PHYS 0x40010000 /* UART4 */ --#define STM32_UART_BASE_VIRT 0xfe010000 /* UART4 */ --#endif -- -- - #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) || defined(CONFIG_STM32MP1_DEBUG_UART) - #define STM32_USART_SR_OFF 0x1C - #define STM32_USART_TDR_OFF 0x28 - #endif -@@ -27,8 +18,12 @@ - #define STM32_USART_TXE (1 << 7) /* Tx data reg empty */ - - .macro addruart, rp, rv, tmp -- ldr \rp, =STM32_UART_BASE_PHYS @ physical base -- ldr \rv, =STM32_UART_BASE_VIRT @ virt base -+ 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 -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 -index 3242b72..b9b9b99 100644 ---- a/drivers/hwspinlock/stm32_hwspinlock.c -+++ b/drivers/hwspinlock/stm32_hwspinlock.c -@@ -5,6 +5,7 @@ - */ - - #include -+#include - #include - #include - #include -@@ -42,9 +43,15 @@ static void stm32_hwspinlock_unlock(struct hwspinlock *lock) - 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) -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/soc/st/Kconfig b/drivers/soc/st/Kconfig -index 82ee423..8ab6049 100644 ---- a/drivers/soc/st/Kconfig -+++ b/drivers/soc/st/Kconfig -@@ -6,4 +6,12 @@ config STM32_PM_DOMAINS - 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 -index 8d7f291..85905b7 100644 ---- a/drivers/soc/st/Makefile -+++ b/drivers/soc/st/Makefile -@@ -1 +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/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c -index 3e8ca10..9c67718 100644 ---- a/drivers/spi/spi-stm32-qspi.c -+++ b/drivers/spi/spi-stm32-qspi.c -@@ -5,7 +5,10 @@ - */ - #include - #include -+#include -+#include - #include -+#include - #include - #include - #include -@@ -84,6 +87,7 @@ - #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; -@@ -93,6 +97,7 @@ struct stm32_qspi_flash { - - struct stm32_qspi { - struct device *dev; -+ phys_addr_t phys_base; - void __iomem *io_base; - void __iomem *mm_base; - resource_size_t mm_size; -@@ -102,6 +107,11 @@ struct stm32_qspi { - 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; - -@@ -180,6 +190,131 @@ static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, - 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_interruptible_timeout(&qspi->dma_completion, -+ msecs_to_jiffies(t_out))) -+ err = -ETIMEDOUT; -+ -+ if (dma_async_is_tx_complete(dma_ch, cookie, -+ NULL, NULL) != DMA_COMPLETE) -+ 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) -@@ -187,6 +322,10 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) - - 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); - } -@@ -217,7 +356,7 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, - writel_relaxed(cr | CR_TCIE | CR_TEIE, qspi->io_base + QSPI_CR); - - if (!wait_for_completion_interruptible_timeout(&qspi->data_completion, -- msecs_to_jiffies(1000))) { -+ msecs_to_jiffies(STM32_COMP_TIMEOUT_MS))) { - err = -ETIMEDOUT; - } else { - sr = readl_relaxed(qspi->io_base + QSPI_SR); -@@ -386,6 +525,52 @@ static int stm32_qspi_setup(struct spi_device *spi) - 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. -@@ -398,6 +583,8 @@ 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); - } -@@ -422,6 +609,8 @@ static int stm32_qspi_probe(struct platform_device *pdev) - 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)) -@@ -464,6 +653,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) - - 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 -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.9/0044-ARM-stm32mp1-r0-rc3-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0044-ARM-stm32mp1-r0-rc3-DEVICETREE.patch deleted file mode 100644 index 084d363..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0044-ARM-stm32mp1-r0-rc3-DEVICETREE.patch +++ /dev/null @@ -1,1392 +0,0 @@ -From 494124b8ba0cd0d06a1cf099df668a93ee5e3f23 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:53:27 +0100 -Subject: [PATCH 44/52] ARM: stm32mp1-r0-rc3: DEVICETREE - ---- - arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 375 +++++++++++++++++++--- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 47 ++- - arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts | 14 + - arch/arm/boot/dts/stm32mp157c-dk2.dts | 10 + - arch/arm/boot/dts/stm32mp157c-ed1.dts | 66 +++- - arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts | 15 + - arch/arm/boot/dts/stm32mp157c-ev1.dts | 46 ++- - arch/arm/boot/dts/stm32mp157c.dtsi | 221 ++++++++++++- - 8 files changed, 705 insertions(+), 89 deletions(-) - create mode 100644 arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts - create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts - -diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -index 659094e..183d7ba 100644 ---- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -@@ -295,7 +295,7 @@ - ; /* ETH_MDC */ - bias-disable; - drive-push-pull; -- slew-rate = <3>; -+ slew-rate = <2>; - }; - pins2 { - pinmux = , /* ETH_RGMII_RXD0 */ -@@ -345,7 +345,7 @@ - ; /* FMC_NE2_FMC_NCE */ - bias-disable; - drive-push-pull; -- slew-rate = <2>; -+ slew-rate = <1>; - }; - pins2 { - pinmux = ; /* FMC_NWAIT */ -@@ -372,6 +372,246 @@ - }; - }; - -+ hdp0_pins_a: hdp0-0 { -+ pins { -+ pinmux = ; /* HDP0 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp0_pins_sleep_a: hdp0-sleep-0 { -+ pins { -+ pinmux = ; /* HDP0 */ -+ }; -+ }; -+ -+ hdp0_pins_b: hdp0-1 { -+ pins { -+ pinmux = ; /* HDP0 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp0_pins_sleep_b: hdp0-sleep-1 { -+ pins { -+ pinmux = ; /* HDP0 */ -+ }; -+ }; -+ -+ hdp1_pins_a: hdp1-0 { -+ pins { -+ pinmux = ; /* HDP1 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp1_pins_sleep_a: hdp1-sleep-0 { -+ pins { -+ pinmux = ; /* HDP1 */ -+ }; -+ }; -+ -+ hdp1_pins_b: hdp1-1 { -+ pins { -+ pinmux = ; /* HDP1 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp1_pins_sleep_b: hdp1-sleep-1 { -+ pins { -+ pinmux = ; /* HDP1 */ -+ }; -+ }; -+ -+ hdp2_pins_a: hdp2-0 { -+ pins { -+ pinmux = ; /* HDP2 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp2_pins_sleep_a: hdp2-sleep-0 { -+ pins { -+ pinmux = ; /* HDP2 */ -+ }; -+ }; -+ -+ hdp2_pins_b: hdp2-1 { -+ pins { -+ pinmux = ; /* HDP2 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp2_pins_sleep_b: hdp2-sleep-1 { -+ pins { -+ pinmux = ; /* HDP2 */ -+ }; -+ }; -+ -+ hdp3_pins_a: hdp3-0 { -+ pins { -+ pinmux = ; /* HDP3 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp3_pins_sleep_a: hdp3-sleep-0 { -+ pins { -+ pinmux = ; /* HDP3 */ -+ }; -+ }; -+ -+ hdp3_pins_b: hdp3-1 { -+ pins { -+ pinmux = ; /* HDP3 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp3_pins_sleep_b: hdp3-sleep-1 { -+ pins { -+ pinmux = ; /* HDP3 */ -+ }; -+ }; -+ -+ hdp4_pins_a: hdp4-0 { -+ pins { -+ pinmux = ; /* HDP4 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp4_pins_sleep_a: hdp4-sleep-0 { -+ pins { -+ pinmux = ; /* HDP4 */ -+ }; -+ }; -+ -+ hdp4_pins_b: hdp4-1 { -+ pins { -+ pinmux = ; /* HDP4 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp4_pins_sleep_b: hdp4-sleep-1 { -+ pins { -+ pinmux = ; /* HDP4 */ -+ }; -+ }; -+ -+ hdp5_pins_a: hdp5-0 { -+ pins { -+ pinmux = ; /* HDP5 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp5_pins_sleep_a: hdp5-sleep-0 { -+ pins { -+ pinmux = ; /* HDP5 */ -+ }; -+ }; -+ -+ hdp5_pins_b: hdp5-1 { -+ pins { -+ pinmux = ; /* HDP5 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp5_pins_sleep_b: hdp5-sleep-1 { -+ pins { -+ pinmux = ; /* HDP5 */ -+ }; -+ }; -+ -+ hdp6_pins_a: hdp6-0 { -+ pins { -+ pinmux = ; /* HDP6 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp6_pins_sleep_a: hdp6-sleep-0 { -+ pins { -+ pinmux = ; /* HDP6 */ -+ }; -+ }; -+ -+ hdp6_pins_b: hdp6-1 { -+ pins { -+ pinmux = ; /* HDP6 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp6_pins_sleep_b: hdp6-sleep-1 { -+ pins { -+ pinmux = ; /* HDP6 */ -+ }; -+ }; -+ -+ hdp7_pins_a: hdp7-0 { -+ pins { -+ pinmux = ; /* HDP7 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp7_pins_sleep_a: hdp7-sleep-0 { -+ pins { -+ pinmux = ; /* HDP7 */ -+ }; -+ }; -+ -+ hdp7_pins_b: hdp7-1 { -+ pins { -+ pinmux = ; /* HDP7 */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <2>; -+ }; -+ }; -+ -+ hdp7_pins_sleep_b: hdp7-sleep-1 { -+ pins { -+ pinmux = ; /* HDP7 */ -+ }; -+ }; -+ - i2c1_pins_a: i2c1-0 { - pins { - pinmux = , /* I2C1_SCL */ -@@ -475,7 +715,7 @@ - ; /* LCD_B7 */ - bias-disable; - drive-push-pull; -- slew-rate = <2>; -+ slew-rate = <1>; - }; - }; - -@@ -544,7 +784,7 @@ - ; /* LCD_B7 */ - bias-disable; - drive-push-pull; -- slew-rate = <2>; -+ slew-rate = <1>; - }; - }; - -@@ -584,7 +824,7 @@ - m_can1_pins_a: m-can1-0 { - pins1 { - pinmux = ; /* CAN1_TX */ -- slew-rate = <1>; -+ slew-rate = <0>; - drive-push-pull; - bias-disable; - }; -@@ -735,13 +975,13 @@ - ; /* 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>; - }; - }; - -@@ -763,13 +1003,13 @@ - ; /* 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>; - }; - }; - -@@ -805,17 +1045,12 @@ - }; - - sai2a_pins_a: sai2a-0 { -- pins1 { -+ pins { - pinmux = , /* SAI2_SCK_A */ - , /* SAI2_SD_A */ -- ; /* SAI2_FS_A */ -- slew-rate = <1>; -- drive-push-pull; -- bias-disable; -- }; -- pins2 { -- pinmux = ; /* SAI2_MCLK_A */ -- slew-rate = <2>; -+ , /* SAI2_FS_A */ -+ ; /* SAI2_MCLK_A */ -+ slew-rate = <0>; - drive-push-pull; - bias-disable; - }; -@@ -833,18 +1068,13 @@ - sai2b_pins_a: sai2b-0 { - pins1 { - pinmux = , /* SAI2_SCK_B */ -- ; /* SAI2_FS_B */ -- slew-rate = <1>; -+ , /* SAI2_FS_B */ -+ ; /* SAI2_MCLK_B */ -+ slew-rate = <0>; - drive-push-pull; - bias-disable; - }; - pins2 { -- pinmux = ; /* SAI2_MCLK_B */ -- slew-rate = <2>; -- drive-push-pull; -- bias-disable; -- }; -- pins3 { - pinmux = ; /* SAI2_SD_B */ - bias-disable; - }; -@@ -875,7 +1105,7 @@ - sai4a_pins_a: sai4a-0 { - pins { - pinmux = ; /* SAI4_SD_A */ -- slew-rate = <1>; -+ slew-rate = <0>; - drive-push-pull; - bias-disable; - }; -@@ -888,14 +1118,19 @@ - }; - - sdmmc1_b4_pins_a: sdmmc1-b4-0 { -- pins { -+ pins1 { - pinmux = , /* SDMMC1_D0 */ - , /* SDMMC1_D1 */ - , /* SDMMC1_D2 */ - , /* SDMMC1_D3 */ -- , /* SDMMC1_CK */ - ; /* SDMMC1_CMD */ -- slew-rate = <3>; -+ slew-rate = <1>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ pins2 { -+ pinmux = ; /* SDMMC1_CK */ -+ slew-rate = <2>; - drive-push-pull; - bias-disable; - }; -@@ -906,15 +1141,20 @@ - pinmux = , /* SDMMC1_D0 */ - , /* SDMMC1_D1 */ - , /* SDMMC1_D2 */ -- , /* SDMMC1_D3 */ -- ; /* SDMMC1_CK */ -- slew-rate = <3>; -+ ; /* 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 = <3>; -+ slew-rate = <1>; - drive-open-drain; - bias-disable; - }; -@@ -936,7 +1176,7 @@ - pinmux = , /* SDMMC1_D0DIR */ - , /* SDMMC1_D123DIR */ - ; /* SDMMC1_CDIR */ -- slew-rate = <3>; -+ slew-rate = <1>; - drive-push-pull; - bias-pull-up; - }; -@@ -956,14 +1196,19 @@ - }; - - sdmmc2_b4_pins_a: sdmmc2-b4-0 { -- pins { -+ pins1 { - pinmux = , /* SDMMC2_D0 */ - , /* SDMMC2_D1 */ - , /* SDMMC2_D2 */ - , /* SDMMC2_D3 */ -- , /* SDMMC2_CK */ - ; /* SDMMC2_CMD */ -- slew-rate = <3>; -+ slew-rate = <1>; -+ drive-push-pull; -+ bias-pull-up; -+ }; -+ pins2 { -+ pinmux = ; /* SDMMC2_CK */ -+ slew-rate = <2>; - drive-push-pull; - bias-pull-up; - }; -@@ -974,15 +1219,20 @@ - pinmux = , /* SDMMC2_D0 */ - , /* SDMMC2_D1 */ - , /* SDMMC2_D2 */ -- , /* SDMMC2_D3 */ -- ; /* SDMMC2_CK */ -- slew-rate = <3>; -+ ; /* 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 = <3>; -+ slew-rate = <1>; - drive-open-drain; - bias-pull-up; - }; -@@ -1005,7 +1255,7 @@ - , /* SDMMC2_D5 */ - , /* SDMMC2_D6 */ - ; /* SDMMC2_D7 */ -- slew-rate = <3>; -+ slew-rate = <1>; - drive-push-pull; - bias-pull-up; - }; -@@ -1021,19 +1271,48 @@ - }; - - sdmmc3_b4_pins_a: sdmmc3-b4-0 { -- pins { -+ pins1 { - pinmux = , /* SDMMC3_D0 */ - , /* SDMMC3_D1 */ - , /* SDMMC3_D2 */ - , /* SDMMC3_D3 */ -- , /* SDMMC3_CK */ - ; /* SDMMC3_CMD */ -- slew-rate = <3>; -+ 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 */ -@@ -1140,7 +1419,7 @@ - ; /* USART2_RTS */ - bias-disable; - drive-push-pull; -- slew-rate = <3>; -+ slew-rate = <0>; - }; - pins2 { - pinmux = , /* USART2_RX */ -@@ -1264,7 +1543,7 @@ - pins-are-numbered; - interrupt-parent = <&exti>; - st,syscfg = <&exti 0x60 0xff>; -- hwlocks = <&hsem 1>; -+ hwlocks = <&hsem 0>; - - gpioz: gpio@54004000 { - gpio-controller; -diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -index 2f01e97..0a6cf35 100644 ---- a/arch/arm/boot/dts/stm32mp157a-dk1.dts -+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -35,9 +35,39 @@ - #size-cells = <1>; - ranges; - -- ipc_share: sram_rproc@10040000 { -+ retram: retram@0x38000000 { - compatible = "shared-dma-pool"; -- reg = <0x10040000 0x10000>; -+ 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; - }; - -@@ -77,6 +107,7 @@ - - sound { - compatible = "audio-graph-card"; -+ label = "STM32MP1-DK"; - routing = - "Playback" , "MCLK", - "Capture" , "MCLK", -@@ -306,7 +337,7 @@ - regulator-max-microvolt = <3300000>; - regulator-always-on; - st,mask-reset; -- regulator-initial-mode = <2>; -+ regulator-initial-mode = <0>; - regulator-over-current-protection; - }; - -@@ -316,7 +347,7 @@ - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-over-current-protection; -- regulator-initial-mode = <2>; -+ regulator-initial-mode = <0>; - }; - - v1v8_audio: ldo1 { -@@ -402,12 +433,13 @@ - - watchdog { - compatible = "st,stpmic1-wdt"; -+ status = "disabled"; - }; - }; - }; - - &i2s2 { -- clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL4_Q>; -+ 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>; -@@ -447,7 +479,8 @@ - }; - - &m4_rproc { -- memory-region = <&ipc_share>; -+ memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, -+ <&vdev0vring1>, <&vdev0buffer>; - mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; - mbox-names = "vq0", "vq1", "shutdown"; - interrupt-parent = <&exti>; -@@ -470,7 +503,7 @@ - }; - - &sai2 { -- clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL3_Q>; -+ 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>; -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.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -index fd00386..c276c59 100644 ---- a/arch/arm/boot/dts/stm32mp157c-dk2.dts -+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -72,6 +72,16 @@ - touchscreen-size-y = <800>; - status = "okay"; - }; -+ touchscreen@38 { -+ compatible = "focaltech,ft6336"; -+ reg = <0x38>; -+ interrupts = <2 2>; -+ interrupt-parent = <&gpiof>; -+ interrupt-controller; -+ touchscreen-size-x = <480>; -+ touchscreen-size-y = <800>; -+ status = "okay"; -+ }; - }; - - <dc { -diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index 4f46b41..798580e 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ed1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts -@@ -28,9 +28,39 @@ - #size-cells = <1>; - ranges; - -- ipc_share: sram_rproc@10040000 { -+ retram: retram@0x38000000 { - compatible = "shared-dma-pool"; -- reg = <0x10040000 0x10000>; -+ 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; - }; - -@@ -71,6 +101,19 @@ - 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>; -+ }; - }; - - &adc { -@@ -121,6 +164,10 @@ - sram = <&dma_pool>; - }; - -+&dts { -+ status = "okay"; -+}; -+ - &gpu { - contiguous-area = <&gpu_reserved>; - status = "okay"; -@@ -187,7 +234,7 @@ - regulator-max-microvolt = <3300000>; - regulator-always-on; - st,mask-reset; -- regulator-initial-mode = <2>; -+ regulator-initial-mode = <0>; - regulator-over-current-protection; - }; - -@@ -197,7 +244,7 @@ - regulator-max-microvolt = <3300000>; - regulator-always-on; - regulator-over-current-protection; -- regulator-initial-mode = <2>; -+ regulator-initial-mode = <0>; - }; - - vdda: ldo1 { -@@ -277,6 +324,7 @@ - - watchdog { - compatible = "st,stpmic1-wdt"; -+ status = "disabled"; - }; - }; - }; -@@ -291,7 +339,8 @@ - }; - - &m4_rproc { -- memory-region = <&ipc_share>; -+ memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, -+ <&vdev0vring1>, <&vdev0buffer>; - mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; - mbox-names = "vq0", "vq1", "shutdown"; - interrupt-parent = <&exti>; -@@ -324,6 +373,12 @@ - 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"; - }; - -@@ -339,6 +394,7 @@ - bus-width = <8>; - vmmc-supply = <&v3v3>; - vqmmc-supply = <&v3v3>; -+ mmc-ddr-3_3v; - status = "okay"; - }; - -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..5682fb3 ---- /dev/null -+++ b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts -@@ -0,0 +1,15 @@ -+// 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 Linux A7 examples"; -+ compatible = "st,stm32mp157c-ev1-a7-examples", "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; -+}; -+ -diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts -index b60bffc..49a62aa 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ev1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts -@@ -8,6 +8,7 @@ - #include "stm32mp157c-ed1.dts" - #include - #include -+#include - - / { - model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; -@@ -100,19 +101,15 @@ - - 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>; -- status = "okay"; -- }; -- -- dmics { -- compatible = "audio-graph-card"; -- dais = <&cpu_port0 &cpu_port1 &cpu_port2 &cpu_port3>; -+ dais = <&sai2a_port &sai2b_port &sai4a_port &spdifrx_port -+ &dfsdm0_port &dfsdm1_port &dfsdm2_port &dfsdm3_port>; - status = "okay"; - }; - -@@ -228,7 +225,7 @@ - io-channels = <&dfsdm0 0>; - status = "okay"; - -- cpu_port0: port { -+ dfsdm0_port: port { - dfsdm_endpoint0: endpoint { - remote-endpoint = <&dmic0_endpoint>; - }; -@@ -251,7 +248,7 @@ - io-channels = <&dfsdm1 0>; - status = "okay"; - -- cpu_port1: port { -+ dfsdm1_port: port { - dfsdm_endpoint1: endpoint { - remote-endpoint = <&dmic1_endpoint>; - }; -@@ -274,7 +271,7 @@ - io-channels = <&dfsdm2 0>; - status = "okay"; - -- cpu_port2: port { -+ dfsdm2_port: port { - dfsdm_endpoint2: endpoint { - remote-endpoint = <&dmic2_endpoint>; - }; -@@ -297,7 +294,7 @@ - io-channels = <&dfsdm3 0>; - status = "okay"; - -- cpu_port3: port { -+ dfsdm3_port: port { - dfsdm_endpoint3: endpoint { - remote-endpoint = <&dmic3_endpoint>; - }; -@@ -381,6 +378,17 @@ - }; - }; - -+&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>; -@@ -577,7 +585,7 @@ - }; - - &sai2 { -- clocks = <&rcc SAI2>, <&rcc PLL3_Q>, <&rcc PLL4_Q>; -+ 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>; -@@ -617,7 +625,7 @@ - }; - - &sai4 { -- clocks = <&rcc SAI4>, <&rcc PLL3_Q>, <&rcc PLL4_Q>; -+ clocks = <&rcc SAI4>, <&rcc PLL3_Q>, <&rcc PLL3_R>; - clock-names = "pclk", "x8k", "x11k"; - status = "okay"; - -@@ -639,6 +647,18 @@ - }; - }; - -+&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>; -diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index cef7b3e..7a7ef47 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -156,6 +156,29 @@ - mask = <0x1>; - }; - -+ replicator { -+ /* -+ * non-configurable replicators don't show up on the -+ * AMBA bus. As such no need to add "arm,primecell" -+ */ -+ compatible = "arm,coresight-replicator"; -+ clocks = <&rcc CK_TRACE>; -+ clock-names = "apb_pclk"; -+ -+ ports { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ /* replicator output ports */ -+ port@0 { -+ reg = <0>; -+ replicator_out_port0: endpoint { -+ remote-endpoint = <&funnel_in_port4>; -+ }; -+ }; -+ }; -+ }; -+ - soc { - compatible = "simple-bus"; - #address-cells = <1>; -@@ -471,6 +494,7 @@ - interrupts-extended = <&intc GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>, - <&exti 27 1>; - clocks = <&rcc USART2_K>; -+ resets = <&rcc USART2_R>; - wakeup-source; - power-domains = <&pd_core>; - status = "disabled"; -@@ -483,6 +507,7 @@ - interrupts-extended = <&intc GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>, - <&exti 28 1>; - clocks = <&rcc USART3_K>; -+ resets = <&rcc USART3_R>; - wakeup-source; - power-domains = <&pd_core>; - status = "disabled"; -@@ -495,6 +520,7 @@ - interrupts-extended = <&intc GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>, - <&exti 30 1>; - clocks = <&rcc UART4_K>; -+ resets = <&rcc UART4_R>; - wakeup-source; - power-domains = <&pd_core>; - status = "disabled"; -@@ -507,6 +533,7 @@ - interrupts-extended = <&intc GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>, - <&exti 31 1>; - clocks = <&rcc UART5_K>; -+ resets = <&rcc UART5_R>; - wakeup-source; - power-domains = <&pd_core>; - status = "disabled"; -@@ -629,6 +656,7 @@ - interrupts-extended = <&intc GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>, - <&exti 32 1>; - clocks = <&rcc UART7_K>; -+ resets = <&rcc UART7_R>; - wakeup-source; - power-domains = <&pd_core>; - status = "disabled"; -@@ -641,6 +669,7 @@ - interrupts-extended = <&intc GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>, - <&exti 33 1>; - clocks = <&rcc UART8_K>; -+ resets = <&rcc UART8_R>; - wakeup-source; - power-domains = <&pd_core>; - status = "disabled"; -@@ -713,6 +742,7 @@ - interrupts-extended = <&intc GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>, - <&exti 29 1>; - clocks = <&rcc USART6_K>; -+ resets = <&rcc USART6_R>; - wakeup-source; - power-domains = <&pd_core>; - status = "disabled"; -@@ -1110,7 +1140,7 @@ - reg = <0x0>; - interrupt-parent = <&adc>; - interrupts = <0>; -- dmas = <&dmamux1 9 0x400 0x01>; -+ dmas = <&dmamux1 9 0x400 0x05>; - dma-names = "rx"; - status = "disabled"; - }; -@@ -1121,7 +1151,7 @@ - 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>; -@@ -1165,8 +1195,8 @@ - - sdmmc3: sdmmc@48004000 { - compatible = "arm,pl18x", "arm,primecell"; -- arm,primecell-periphid = <0x10153180>; -- reg = <0x48004000 0x400>; -+ arm,primecell-periphid = <0x00253180>; -+ reg = <0x48004000 0x400>, <0x48005000 0x400>; - interrupts = ; - interrupt-names = "cmd_irq"; - clocks = <&rcc SDMMC3_K>; -@@ -1278,7 +1308,7 @@ - interrupt-controller; - #interrupt-cells = <2>; - reg = <0x5000d000 0x400>; -- hwlocks = <&hsem 2>; -+ hwlocks = <&hsem 1>; - - /* exti_pwr is an extra interrupt controller used for - * EXTI 55 to 60. It's mapped on pwr interrupt -@@ -1427,6 +1457,157 @@ - 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>; -@@ -1490,6 +1671,9 @@ - reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; - reg-names = "qspi", "qspi_mm"; - interrupts = ; -+ dmas = <&mdma1 22 0x10 0x100002 0x0 0x0 0x0>, -+ <&mdma1 22 0x10 0x100008 0x0 0x0 0x0>; -+ dma-names = "tx", "rx"; - clocks = <&rcc QSPI_K>; - resets = <&rcc QSPI_R>; - status = "disabled"; -@@ -1497,8 +1681,8 @@ - - 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"; - clocks = <&rcc SDMMC1_K>; -@@ -1512,8 +1696,8 @@ - - sdmmc2: sdmmc@58007000 { - compatible = "arm,pl18x", "arm,primecell"; -- arm,primecell-periphid = <0x10153180>; -- reg = <0x58007000 0x1000>; -+ arm,primecell-periphid = <0x00253180>; -+ reg = <0x58007000 0x1000>, <0x58008000 0x1000>; - interrupts = ; - interrupt-names = "cmd_irq"; - clocks = <&rcc SDMMC2_K>; -@@ -1551,16 +1735,15 @@ - 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>; -@@ -1573,6 +1756,7 @@ - clocks = <&rcc USBH>; - resets = <&rcc USBH_R>; - interrupts = ; -+ power-domains = <&pd_core>; - status = "disabled"; - }; - -@@ -1583,6 +1767,7 @@ - resets = <&rcc USBH_R>; - interrupts = ; - companion = <&usbh_ohci>; -+ power-domains = <&pd_core>; - status = "disabled"; - }; - -@@ -1656,6 +1841,7 @@ - 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"; -@@ -1758,9 +1944,12 @@ - - m4_rproc: m4@0 { - compatible = "st,stm32mp1-rproc"; -- reg = <0x38000000 0x10000>, -- <0x10000000 0x40000>; -- reg-names = "retram", "mcusram"; -+ #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>; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0045-ARM-stm32mp1-r0-rc3-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0045-ARM-stm32mp1-r0-rc3-DEFCONFIG.patch deleted file mode 100644 index a36c956..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0045-ARM-stm32mp1-r0-rc3-DEFCONFIG.patch +++ /dev/null @@ -1,101 +0,0 @@ -From c38f0f42372e03b8b284804190fdf53ce02722db Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Mon, 10 Dec 2018 15:53:55 +0100 -Subject: [PATCH 45/52] ARM: stm32mp1-r0-rc3: DEFCONFIG - ---- - arch/arm/configs/fragment-02-multiv7_addons.config | 39 +++++++++++++++++----- - 1 file changed, 31 insertions(+), 8 deletions(-) - -diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config -index 4470d85..6ae0453 100644 ---- a/arch/arm/configs/fragment-02-multiv7_addons.config -+++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -98,7 +98,10 @@ CONFIG_CAN_M_CAN=y - # - # Bluetooth device drivers - # -- -+CONFIG_BT_RTL=m -+CONFIG_BT_HCIBTUSB=m -+CONFIG_BT_HCIBTUSB=m -+CONFIG_BT_HCIBTUSB_RTL=y - # - # Device Drivers - # -@@ -138,7 +141,12 @@ CONFIG_CHR_DEV_SG=y - # MII PHY device drivers - # - # CONFIG_REALTEK_PHY is not set -- -+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 - # -@@ -271,14 +279,14 @@ CONFIG_VIDEO_OV5640=y - # - # Display Panels - # --CONFIG_DRM_PANEL_ORISETECH_OTM8009A=m --CONFIG_DRM_PANEL_RAYDIUM_RM68200=m -+CONFIG_DRM_PANEL_ORISETECH_OTM8009A=y -+CONFIG_DRM_PANEL_RAYDIUM_RM68200=y - - # - # Display Interface Bridges - # --CONFIG_VIDEO_ADV7511=m --CONFIG_DRM_SII902X=m -+CONFIG_VIDEO_ADV7511=y -+CONFIG_DRM_SII902X=y - - # - # Frame buffer hardware drivers -@@ -287,8 +295,8 @@ CONFIG_DRM_SII902X=m - # - # Console display driver support - # --CONFIG_DRM_STM=m --CONFIG_DRM_STM_DSI=m -+CONFIG_DRM_STM=y -+CONFIG_DRM_STM_DSI=y - - # - # Backlight support -@@ -359,6 +367,8 @@ CONFIG_USB_CONFIGFS=y - # File systems - # - CONFIG_OVERLAY_FS=y -+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set -+CONFIG_JFFS2_FS=y - - # - # Pseudo filesystems -@@ -452,6 +462,19 @@ CONFIG_REGULATOR_STM32_VREFBUF=y - CONFIG_NVMEM_STM32_ROMEM=y - - # -+# STM32 CORESIGHT -+# -+CONFIG_STM_SOURCE_CONSOLE=y -+CONFIG_STM_SOURCE_FTRACE=y -+CONFIG_FUNCTION_TRACER=y -+CONFIG_CORESIGHT=y -+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y -+CONFIG_CORESIGHT_SINK_TPIU=y -+CONFIG_CORESIGHT_SINK_ETBV10=y -+CONFIG_CORESIGHT_SOURCE_ETM3X=y -+CONFIG_CORESIGHT_STM=y -+ -+# - # STM32 IPCC - # - CONFIG_STM32_IPCC=y --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0046-ARM-stm32mp1-r0-rc4-MMC-MTD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0046-ARM-stm32mp1-r0-rc4-MMC-MTD.patch deleted file mode 100644 index 52ec427..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0046-ARM-stm32mp1-r0-rc4-MMC-MTD.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1c6166a178939316cfdd437f8c999616ddf9a7bd Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Fri, 21 Dec 2018 16:57:57 +0100 -Subject: [PATCH 46/52] ARM: stm32mp1-r0-rc4: MMC MTD - ---- - drivers/mmc/host/mmci.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index 6c2b1a0..0b7b607 100644 ---- a/drivers/mmc/host/mmci.c -+++ b/drivers/mmc/host/mmci.c -@@ -2072,6 +2072,8 @@ 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; - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0047-ARM-stm32mp1-r0-rc4-PINCTRL-PWM-RESET-RTC.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0047-ARM-stm32mp1-r0-rc4-PINCTRL-PWM-RESET-RTC.patch deleted file mode 100644 index fd29035..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0047-ARM-stm32mp1-r0-rc4-PINCTRL-PWM-RESET-RTC.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 41d9204c142d8245f898ca877b4e4044d5db2426 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Fri, 21 Dec 2018 16:58:12 +0100 -Subject: [PATCH 47/52] ARM: stm32mp1-r0-rc4: PINCTRL PWM RESET RTC - ---- - drivers/pinctrl/pinctrl-stmfx.c | 10 ++++++---- - 1 file changed, 6 insertions(+), 4 deletions(-) - -diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c -index 15d5757..b68fece 100644 ---- a/drivers/pinctrl/pinctrl-stmfx.c -+++ b/drivers/pinctrl/pinctrl-stmfx.c -@@ -542,6 +542,7 @@ 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; - -@@ -550,10 +551,8 @@ static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id) - if (ret) - return IRQ_NONE; - -- ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_ACK, -- 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) { -@@ -561,6 +560,9 @@ static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id) - 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; - } - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0048-ARM-stm32mp1-r0-rc4-REMOTEPROC-RPMSG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0048-ARM-stm32mp1-r0-rc4-REMOTEPROC-RPMSG.patch deleted file mode 100644 index a33e96e..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0048-ARM-stm32mp1-r0-rc4-REMOTEPROC-RPMSG.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 457cfdb049a39670f15df8cae1d78a2479962ef9 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Fri, 21 Dec 2018 16:57:38 +0100 -Subject: [PATCH 48/52] ARM: stm32mp1-r0-rc4: REMOTEPROC RPMSG - ---- - drivers/remoteproc/rproc_srm_core.c | 2 +- - drivers/remoteproc/stm32_rproc.c | 40 +++++++++++++++++++++++++++---------- - 2 files changed, 30 insertions(+), 12 deletions(-) - -diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c -index 66be92e..fc61e8b 100644 ---- a/drivers/remoteproc/rproc_srm_core.c -+++ b/drivers/remoteproc/rproc_srm_core.c -@@ -189,7 +189,7 @@ static int rproc_srm_core_prepare(struct rproc_subdev *subdev) - /* 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, "bind timeout\n"); -+ dev_err(dev, "failed to bind one or more system resource device(s)\n"); - ret = -ETIMEDOUT; - goto master; - } -diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index 9a7e034..70b7e55c 100644 ---- a/drivers/remoteproc/stm32_rproc.c -+++ b/drivers/remoteproc/stm32_rproc.c -@@ -196,22 +196,12 @@ 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) - { -- int status, i; -+ int status; - struct resource_table *table = NULL; - struct stm32_rproc *ddata = rproc->priv; - size_t tablesz = 0; -- const struct elf32_hdr *ehdr; -- const struct elf32_phdr *phdr; - - if (!rproc->early_boot) { -- /* set coredump segments */ -- ehdr = (const struct elf32_hdr *)fw->data; -- phdr = (const struct elf32_phdr *)(fw->data + ehdr->e_phoff); -- for (i = 0; i < ehdr->e_phnum; i++, phdr++) -- rproc_coredump_add_segment(rproc, phdr->p_paddr, -- phdr->p_memsz); -- -- /* load resource table */ - status = rproc_elf_load_rsc_table(rproc, fw); - if (status) - goto no_rsc_table; -@@ -276,6 +266,10 @@ static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) - 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, -@@ -436,10 +430,34 @@ static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) - 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) - { - int err; - -+ stm32_rproc_add_coredump_trace(rproc); -+ - /* - * If M4 previously started by bootloader, just guarantee holdboot - * is set to catch any crash. --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0049-ARM-stm32mp1-r0-rc4-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0049-ARM-stm32mp1-r0-rc4-SOUND.patch deleted file mode 100644 index 4092145..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0049-ARM-stm32mp1-r0-rc4-SOUND.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 06f5ef8ca4c11074b595a4318dba9766092886d5 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Fri, 21 Dec 2018 16:58:47 +0100 -Subject: [PATCH 49/52] ARM: stm32mp1-r0-rc4: SOUND - ---- - sound/soc/codecs/wm8994.c | 3 +-- - sound/soc/stm/stm32_sai_sub.c | 21 ++++++++++++++++++++- - 2 files changed, 21 insertions(+), 3 deletions(-) - -diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c -index eb222da..c83ae39 100644 ---- a/sound/soc/codecs/wm8994.c -+++ b/sound/soc/codecs/wm8994.c -@@ -868,7 +868,7 @@ static int mclk_event(struct snd_soc_dapm_widget *w, - break; - case SND_SOC_DAPM_POST_PMD: - dev_dbg(comp->dev, "Disable master clock %s\n", -- mclk_id ? "MCLK1" : "MCLK2"); -+ mclk_id ? "MCLK2" : "MCLK1"); - clk_disable_unprepare(mclk); - break; - } -@@ -1193,7 +1193,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)) -diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c -index 3f0540a..a9b37f9 100644 ---- a/sound/soc/stm/stm32_sai_sub.c -+++ b/sound/soc/stm/stm32_sai_sub.c -@@ -102,6 +102,7 @@ - * @spdif_frm_cnt: S/PDIF playback frame counter - * @snd_aes_iec958: iec958 data - * @ctrl_lock: control lock -+ * @spinlock_t: prevent race condition with IRQ - */ - struct stm32_sai_sub_data { - struct platform_device *pdev; -@@ -133,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 { -@@ -497,8 +499,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; - } -@@ -703,8 +707,19 @@ 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, -+ SNDRV_PCM_HW_PARAM_FORMAT, -+ SNDRV_PCM_FMTBIT_S32_LE); -+ snd_pcm_hw_constraint_single(substream->runtime, -+ SNDRV_PCM_HW_PARAM_CHANNELS, 2); -+ } - - ret = clk_prepare_enable(sai->sai_ck); - if (ret < 0) { -@@ -1078,6 +1093,7 @@ 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; - - regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); - -@@ -1092,7 +1108,9 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, - - 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, -@@ -1459,6 +1477,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); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0050-ARM-stm32mp1-r0-rc4-USB.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0050-ARM-stm32mp1-r0-rc4-USB.patch deleted file mode 100644 index c95a2e4..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0050-ARM-stm32mp1-r0-rc4-USB.patch +++ /dev/null @@ -1,266 +0,0 @@ -From fc74bada7f6940619f8930556b7c61fe618f2a64 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Fri, 21 Dec 2018 16:56:27 +0100 -Subject: [PATCH 50/52] ARM: stm32mp1-r0-rc4: USB - ---- - Documentation/devicetree/bindings/usb/dwc2.txt | 2 + - drivers/usb/dwc2/core.h | 11 ++++ - drivers/usb/dwc2/core_intr.c | 4 +- - drivers/usb/dwc2/hw.h | 2 + - drivers/usb/dwc2/params.c | 7 ++- - drivers/usb/dwc2/platform.c | 74 +++++++++++++++++++++++--- - 6 files changed, 90 insertions(+), 10 deletions(-) - -diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt -index 32b245c..03c62de 100644 ---- a/Documentation/devicetree/bindings/usb/dwc2.txt -+++ b/Documentation/devicetree/bindings/usb/dwc2.txt -@@ -43,6 +43,8 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties - doesn't drive it. - - usb33d-supply: external VBUS and ID sensing comparators supply, in order to - perform OTG operation, used on STM32MP1 SoCs. -+- force-b-session-valid: force B-peripheral session instead of relying on -+ VBUS sensing (only valid when dr_mode = "peripheral"). - - Deprecated properties: - - g-use-dma: gadget DMA mode is automatically detected -diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index 4c689d1..4c1736f 100644 ---- a/drivers/usb/dwc2/core.h -+++ b/drivers/usb/dwc2/core.h -@@ -415,6 +415,12 @@ enum dwc2_ep0_state { - * in DWORDS with possible values from from - * 16-32768 (default: 256, 256, 256, 256, 768, - * 768, 768, 768, 0, 0, 0, 0, 0, 0, 0). -+ * @force_b_session_valid: force B-peripheral session instead of relying on -+ * VBUS sensing (only valid when dr_mode = "peripheral"). -+ * @suspend_ignore_power_down: prevent the controller to enter low power mode -+ * upon suspend interrupt. This may help in device mode, -+ * when suspend (3ms idle bus) gets detected before -+ * device session end (VBUS discharge > 3ms). - * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL - * while full&low speed device connect. And change speed - * back to DWC2_SPEED_PARAM_HIGH while device is gone. -@@ -492,6 +498,8 @@ struct dwc2_core_params { - u32 g_rx_fifo_size; - u32 g_np_tx_fifo_size; - u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; -+ bool force_b_session_valid; -+ bool suspend_ignore_power_down; - - bool change_speed_quirk; - }; -@@ -849,6 +857,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 -@@ -1032,6 +1042,7 @@ 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; -diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c -index 19ae259..7b4162c 100644 ---- a/drivers/usb/dwc2/core_intr.c -+++ b/drivers/usb/dwc2/core_intr.c -@@ -492,7 +492,9 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) - hsotg->hw_params.hibernation); - - /* Ignore suspend request before enumeration */ -- if (!dwc2_is_device_connected(hsotg)) { -+ if (!dwc2_is_device_connected(hsotg) || -+ hsotg->params.force_b_session_valid || -+ hsotg->params.suspend_ignore_power_down) { - dev_dbg(hsotg->dev, - "ignore suspend request before enumeration\n"); - return; -diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h -index afde335..31f8c60 100644 ---- a/drivers/usb/dwc2/hw.h -+++ b/drivers/usb/dwc2/hw.h -@@ -54,6 +54,8 @@ - #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_SESREQ BIT(1) - #define GOTGCTL_SESREQSCS BIT(0) - -diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c -index 63ccfc9..7fef905 100644 ---- a/drivers/usb/dwc2/params.c -+++ b/drivers/usb/dwc2/params.c -@@ -167,7 +167,7 @@ static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_hsotg *hsotg) - p->host_rx_fifo_size = 440; - p->host_nperio_tx_fifo_size = 256; - p->host_perio_tx_fifo_size = 256; -- p->power_down = false; -+ p->suspend_ignore_power_down = true; - } - - const struct of_device_id dwc2_of_match_table[] = { -@@ -404,6 +404,11 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) - - if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL)) - p->oc_disable = true; -+ -+ if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) -+ p->force_b_session_valid = -+ of_property_read_bool(hsotg->dev->of_node, -+ "force-b-session-valid"); - } - - static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) -diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index 2061254..b2e5ddc 100644 ---- a/drivers/usb/dwc2/platform.c -+++ b/drivers/usb/dwc2/platform.c -@@ -324,6 +324,10 @@ 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 && -+ !hsotg->params.force_b_session_valid) -+ regulator_disable(hsotg->usb33d); -+ - if (hsotg->ll_hw_enabled) - dwc2_lowlevel_hw_disable(hsotg); - -@@ -474,18 +478,18 @@ static int dwc2_driver_probe(struct platform_device *dev) - if (retval) - goto error; - -- if (hsotg->params.activate_stm_id_vb_detection) { -- struct regulator *usb33d; -+ if (hsotg->params.activate_stm_id_vb_detection && -+ !hsotg->params.force_b_session_valid) { - u32 ggpio; - -- usb33d = devm_regulator_get(hsotg->dev, "usb33d"); -- if (IS_ERR(usb33d)) { -- retval = PTR_ERR(usb33d); -+ 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(usb33d); -+ retval = regulator_enable(hsotg->usb33d); - if (retval) { - dev_err(hsotg->dev, - "can't enable voltage level detector supply\n"); -@@ -498,6 +502,15 @@ static int dwc2_driver_probe(struct platform_device *dev) - dwc2_writel(hsotg, ggpio, GGPIO); - } - -+ if (hsotg->params.force_b_session_valid) { -+ u32 gotgctl; -+ -+ gotgctl = dwc2_readl(hsotg, GOTGCTL); -+ gotgctl |= GOTGCTL_BVALOVAL; /* B-peripheral session value */ -+ gotgctl |= GOTGCTL_BVALOEN; /* B-peripheral override enable */ -+ dwc2_writel(hsotg, gotgctl, GOTGCTL); -+ } -+ - if (hsotg->params.activate_stm_fs_transceiver) { - u32 ggpio; - -@@ -516,7 +529,7 @@ static int dwc2_driver_probe(struct platform_device *dev) - if (hsotg->dr_mode != USB_DR_MODE_HOST) { - retval = dwc2_gadget_init(hsotg); - if (retval) -- goto error; -+ goto error_init; - hsotg->gadget_enabled = 1; - } - -@@ -525,7 +538,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; - } -@@ -541,6 +554,10 @@ static int dwc2_driver_probe(struct platform_device *dev) - - return 0; - -+error_init: -+ if (hsotg->params.activate_stm_id_vb_detection && -+ !hsotg->params.force_b_session_valid) -+ regulator_disable(hsotg->usb33d); - error: - dwc2_lowlevel_hw_disable(hsotg); - return retval; -@@ -554,6 +571,18 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - if (dwc2_is_device_mode(dwc2)) - dwc2_hsotg_suspend(dwc2); - -+ if (dwc2->params.activate_stm_id_vb_detection && -+ !dwc2->params.force_b_session_valid) { -+ u32 ggpio; -+ -+ 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); - -@@ -571,6 +600,35 @@ static int __maybe_unused dwc2_resume(struct device *dev) - return ret; - } - -+ /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ -+ dwc2_force_dr_mode(dwc2); -+ -+ if (dwc2->params.activate_stm_id_vb_detection && -+ !dwc2->params.force_b_session_valid) { -+ u32 ggpio; -+ -+ 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); -+ } -+ -+ if (dwc2->params.force_b_session_valid) { -+ u32 gotgctl; -+ -+ gotgctl = dwc2_readl(dwc2, GOTGCTL); -+ gotgctl |= GOTGCTL_BVALOVAL; /* B-peripheral session value */ -+ gotgctl |= GOTGCTL_BVALOEN; /* B-peripheral override enable */ -+ dwc2_writel(dwc2, gotgctl, GOTGCTL); -+ } -+ - if (dwc2_is_device_mode(dwc2)) - ret = dwc2_hsotg_resume(dwc2); - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0051-ARM-stm32mp1-r0-rc4-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0051-ARM-stm32mp1-r0-rc4-DEVICETREE.patch deleted file mode 100644 index f76dbb1..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0051-ARM-stm32mp1-r0-rc4-DEVICETREE.patch +++ /dev/null @@ -1,607 +0,0 @@ -From a3f6ac74fe67cfacb73bda2ba631d1e5e2680988 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Fri, 21 Dec 2018 16:56:44 +0100 -Subject: [PATCH 51/52] ARM: stm32mp1-r0-rc4: DEVICETREE - ---- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 14 ++-- - arch/arm/boot/dts/stm32mp157c-ed1.dts | 9 --- - arch/arm/boot/dts/stm32mp157c-ev1.dts | 2 - - arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi | 122 +++++++++++++++--------------- - arch/arm/boot/dts/stm32mp157c.dtsi | 2 +- - 5 files changed, 67 insertions(+), 82 deletions(-) - -diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -index 0a6cf35..7e911f3 100644 ---- a/arch/arm/boot/dts/stm32mp157a-dk1.dts -+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -77,11 +77,6 @@ - }; - }; - -- iio-hwmon { -- compatible = "iio-hwmon"; -- io-channels = <&adc_temp>; -- }; -- - sram: sram@10050000 { - compatible = "mmio-sram"; - reg = <0x10050000 0x10000>; -@@ -174,6 +169,10 @@ - sram = <&dma_pool>; - }; - -+&dts { -+ status = "okay"; -+}; -+ - ðernet0 { - status = "okay"; - pinctrl-0 = <ðernet0_rgmii_pins_a>; -@@ -198,10 +197,6 @@ - status = "okay"; - }; - --&hsem { -- status = "okay"; --}; -- - &i2c1 { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&i2c1_pins_a>; -@@ -679,6 +674,7 @@ - - &usbotg_hs { - dr_mode = "peripheral"; -+ force-b-session-valid; - phys = <&usbphyc_port1 0>; - phy-names = "usb2-phy"; - status = "okay"; -diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index 798580e..cf2750e 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ed1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts -@@ -74,11 +74,6 @@ - serial0 = &uart4; - }; - -- iio-hwmon { -- compatible = "iio-hwmon"; -- io-channels = <&adc_temp>; -- }; -- - sram: sram@10050000 { - compatible = "mmio-sram"; - reg = <0x10050000 0x10000>; -@@ -173,10 +168,6 @@ - status = "okay"; - }; - --&hsem { -- status = "okay"; --}; -- - &i2c4 { - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&i2c4_pins_a>; -diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts -index 49a62aa..18742e8 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ev1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts -@@ -177,7 +177,6 @@ - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&cec_pins_a>; - pinctrl-1 = <&cec_pins_sleep_a>; -- status = "okay"; - }; - - &dcmi { -@@ -530,7 +529,6 @@ - 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; - }; -diff --git a/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi -index a1d132d0..5ebe24b 100644 ---- a/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi -@@ -5,106 +5,106 @@ - - m4_timers2: timer@40000000 { - compatible = "rproc-srm-dev"; -- reg = <0x40000000 0x400>; -+ reg = <0x40000000>; - clocks = <&rcc TIM2_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers3: timer@40001000 { - compatible = "rproc-srm-dev"; -- reg = <0x40001000 0x400>; -+ reg = <0x40001000>; - clocks = <&rcc TIM3_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers4: timer@40002000 { - compatible = "rproc-srm-dev"; -- reg = <0x40002000 0x400>; -+ reg = <0x40002000>; - clocks = <&rcc TIM4_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers5: timer@40003000 { - compatible = "rproc-srm-dev"; -- reg = <0x40003000 0x400>; -+ reg = <0x40003000>; - clocks = <&rcc TIM5_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers6: timer@40004000 { - compatible = "rproc-srm-dev"; -- reg = <0x40004000 0x400>; -+ reg = <0x40004000>; - clocks = <&rcc TIM6_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers7: timer@40005000 { - compatible = "rproc-srm-dev"; -- reg = <0x40005000 0x400>; -+ reg = <0x40005000>; - clocks = <&rcc TIM7_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers12: timer@40006000 { - compatible = "rproc-srm-dev"; -- reg = <0x40006000 0x400>; -+ reg = <0x40006000>; - clocks = <&rcc TIM12_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers13: timer@40007000 { - compatible = "rproc-srm-dev"; -- reg = <0x40007000 0x400>; -+ reg = <0x40007000>; - clocks = <&rcc TIM13_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers14: timer@40008000 { - compatible = "rproc-srm-dev"; -- reg = <0x40008000 0x400>; -+ reg = <0x40008000>; - clocks = <&rcc TIM14_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_lptimer1: timer@40009000 { - compatible = "rproc-srm-dev"; -- reg = <0x40009000 0x400>; -+ reg = <0x40009000>; - clocks = <&rcc LPTIM1_K>; - clock-names = "mux"; - status = "disabled"; - }; - m4_spi2: spi@4000b000 { - compatible = "rproc-srm-dev"; -- reg = <0x4000b000 0x400>; -+ reg = <0x4000b000>; - clocks = <&rcc SPI2_K>; - status = "disabled"; - }; - m4_i2s2: audio-controller@4000b000 { - compatible = "rproc-srm-dev"; -- reg = <0x4000b000 0x400>; -+ reg = <0x4000b000>; - status = "disabled"; - }; - m4_spi3: spi@4000c000 { - compatible = "rproc-srm-dev"; -- reg = <0x4000c000 0x400>; -+ reg = <0x4000c000>; - clocks = <&rcc SPI3_K>; - status = "disabled"; - }; - m4_i2s3: audio-controller@4000c000 { - compatible = "rproc-srm-dev"; -- reg = <0x4000c000 0x400>; -+ reg = <0x4000c000>; - status = "disabled"; - }; - m4_spdifrx: audio-controller@4000d000 { - compatible = "rproc-srm-dev"; -- reg = <0x4000d000 0x400>; -+ reg = <0x4000d000>; - clocks = <&rcc SPDIF_K>; - clock-names = "kclk"; - status = "disabled"; - }; - m4_usart2: serial@4000e000 { - compatible = "rproc-srm-dev"; -- reg = <0x4000e000 0x400>; -+ reg = <0x4000e000>; - interrupt-parent = <&exti>; - interrupts = <27 1>; - clocks = <&rcc USART2_K>; -@@ -112,7 +112,7 @@ - }; - m4_usart3: serial@4000f000 { - compatible = "rproc-srm-dev"; -- reg = <0x4000f000 0x400>; -+ reg = <0x4000f000>; - interrupt-parent = <&exti>; - interrupts = <28 1>; - clocks = <&rcc USART3_K>; -@@ -120,7 +120,7 @@ - }; - m4_uart4: serial@40010000 { - compatible = "rproc-srm-dev"; -- reg = <0x40010000 0x400>; -+ reg = <0x40010000>; - interrupt-parent = <&exti>; - interrupts = <30 1>; - clocks = <&rcc UART4_K>; -@@ -128,7 +128,7 @@ - }; - m4_uart5: serial@40011000 { - compatible = "rproc-srm-dev"; -- reg = <0x40011000 0x400>; -+ reg = <0x40011000>; - interrupt-parent = <&exti>; - interrupts = <31 1>; - clocks = <&rcc UART5_K>; -@@ -136,7 +136,7 @@ - }; - m4_i2c1: i2c@40012000 { - compatible = "rproc-srm-dev"; -- reg = <0x40012000 0x400>; -+ reg = <0x40012000>; - interrupt-parent = <&exti>; - interrupts = <21 1>; - clocks = <&rcc I2C1_K>; -@@ -144,7 +144,7 @@ - }; - m4_i2c2: i2c@40013000 { - compatible = "rproc-srm-dev"; -- reg = <0x40013000 0x400>; -+ reg = <0x40013000>; - interrupt-parent = <&exti>; - interrupts = <22 1>; - clocks = <&rcc I2C2_K>; -@@ -152,7 +152,7 @@ - }; - m4_i2c3: i2c@40014000 { - compatible = "rproc-srm-dev"; -- reg = <0x40014000 0x400>; -+ reg = <0x40014000>; - interrupt-parent = <&exti>; - interrupts = <23 1>; - clocks = <&rcc I2C3_K>; -@@ -160,7 +160,7 @@ - }; - m4_i2c5: i2c@40015000 { - compatible = "rproc-srm-dev"; -- reg = <0x40015000 0x400>; -+ reg = <0x40015000>; - interrupt-parent = <&exti>; - interrupts = <25 1>; - clocks = <&rcc I2C5_K>; -@@ -168,7 +168,7 @@ - }; - m4_cec: cec@40016000 { - compatible = "rproc-srm-dev"; -- reg = <0x40016000 0x400>; -+ reg = <0x40016000>; - interrupt-parent = <&exti>; - interrupts = <69 1>; - clocks = <&rcc CEC_K>, <&rcc CK_LSE>; -@@ -177,14 +177,14 @@ - }; - m4_dac: dac@40017000 { - compatible = "rproc-srm-dev"; -- reg = <0x40017000 0x400>; -+ reg = <0x40017000>; - clocks = <&rcc DAC12>; - clock-names = "pclk"; - status = "disabled"; - }; - m4_uart7: serial@40018000 { - compatible = "rproc-srm-dev"; -- reg = <0x40018000 0x400>; -+ reg = <0x40018000>; - interrupt-parent = <&exti>; - interrupts = <32 1>; - clocks = <&rcc UART7_K>; -@@ -192,7 +192,7 @@ - }; - m4_uart8: serial@40019000 { - compatible = "rproc-srm-dev"; -- reg = <0x40019000 0x400>; -+ reg = <0x40019000>; - interrupt-parent = <&exti>; - interrupts = <33 1>; - clocks = <&rcc UART8_K>; -@@ -200,21 +200,21 @@ - }; - m4_timers1: timer@44000000 { - compatible = "rproc-srm-dev"; -- reg = <0x44000000 0x400>; -+ reg = <0x44000000>; - clocks = <&rcc TIM1_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers8: timer@44001000 { - compatible = "rproc-srm-dev"; -- reg = <0x44001000 0x400>; -+ reg = <0x44001000>; - clocks = <&rcc TIM8_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_usart6: serial@44003000 { - compatible = "rproc-srm-dev"; -- reg = <0x44003000 0x400>; -+ reg = <0x44003000>; - interrupt-parent = <&exti>; - interrupts = <29 1>; - clocks = <&rcc USART6_K>; -@@ -222,203 +222,203 @@ - }; - m4_spi1: spi@44004000 { - compatible = "rproc-srm-dev"; -- reg = <0x44004000 0x400>; -+ reg = <0x44004000>; - clocks = <&rcc SPI1_K>; - status = "disabled"; - }; - m4_i2s1: audio-controller@44004000 { - compatible = "rproc-srm-dev"; -- reg = <0x44004000 0x400>; -+ reg = <0x44004000>; - status = "disabled"; - }; - m4_spi4: spi@44005000 { - compatible = "rproc-srm-dev"; -- reg = <0x44005000 0x400>; -+ reg = <0x44005000>; - clocks = <&rcc SPI4_K>; - status = "disabled"; - }; - m4_timers15: timer@44006000 { - compatible = "rproc-srm-dev"; -- reg = <0x44006000 0x400>; -+ reg = <0x44006000>; - clocks = <&rcc TIM15_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers16: timer@44007000 { - compatible = "rproc-srm-dev"; -- reg = <0x44007000 0x400>; -+ reg = <0x44007000>; - clocks = <&rcc TIM16_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_timers17: timer@44008000 { - compatible = "rproc-srm-dev"; -- reg = <0x44008000 0x400>; -+ reg = <0x44008000>; - clocks = <&rcc TIM17_K>; - clock-names = "int"; - status = "disabled"; - }; - m4_spi5: spi@44009000 { - compatible = "rproc-srm-dev"; -- reg = <0x44009000 0x400>; -+ reg = <0x44009000>; - clocks = <&rcc SPI5_K>; - status = "disabled"; - }; - m4_sai1: sai@4400a000 { - compatible = "rproc-srm-dev"; -- reg = <0x4400a000 0x4>; -+ reg = <0x4400a000>; - clocks = <&rcc SAI1_K>; - clock-names = "sai_ck"; - status = "disabled"; - }; - m4_sai2: sai@4400b000 { - compatible = "rproc-srm-dev"; -- reg = <0x4400b000 0x4>; -+ reg = <0x4400b000>; - clocks = <&rcc SAI2_K>; - clock-names = "sai_ck"; - status = "disabled"; - }; - m4_sai3: sai@4400c000 { - compatible = "rproc-srm-dev"; -- reg = <0x4400c000 0x4>; -+ reg = <0x4400c000>; - clocks = <&rcc SAI3_K>; - clock-names = "sai_ck"; - status = "disabled"; - }; - m4_dfsdm: dfsdm@4400d000 { - compatible = "rproc-srm-dev"; -- reg = <0x4400d000 0x800>; -+ reg = <0x4400d000>; - clocks = <&rcc DFSDM_K>; - clock-names = "dfsdm"; - status = "disabled"; - }; - m4_m_can1: can@4400e000 { - compatible = "rproc-srm-dev"; -- reg = <0x4400e000 0x400>, <0x44011000 0x2800>; -+ reg = <0x4400e000>, <0x44011000>; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; - clock-names = "hclk", "cclk"; - status = "disabled"; - }; - m4_m_can2: can@4400f000 { - compatible = "rproc-srm-dev"; -- reg = <0x4400f000 0x400>, <0x44011000 0x2800>; -+ reg = <0x4400f000>, <0x44011000>; - clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; - clock-names = "hclk", "cclk"; - status = "disabled"; - }; - m4_dma1: dma@48000000 { - compatible = "rproc-srm-dev"; -- reg = <0x48000000 0x400>; -+ reg = <0x48000000>; - clocks = <&rcc DMA1>; - status = "disabled"; - }; - m4_dma2: dma@48001000 { - compatible = "rproc-srm-dev"; -- reg = <0x48001000 0x400>; -+ reg = <0x48001000>; - clocks = <&rcc DMA2>; - status = "disabled"; - }; - m4_dmamux1: dma-router@48002000 { - compatible = "rproc-srm-dev"; -- reg = <0x48002000 0x1c>; -+ reg = <0x48002000>; - clocks = <&rcc DMAMUX>; - status = "disabled"; - }; - m4_adc: adc@48003000 { - compatible = "rproc-srm-dev"; -- reg = <0x48003000 0x400>; -+ reg = <0x48003000>; - 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>; -+ reg = <0x48004000>, <0x48005000>; - clocks = <&rcc SDMMC3_K>; - status = "disabled"; - }; - m4_usbotg_hs: usb-otg@49000000 { - compatible = "rproc-srm-dev"; -- reg = <0x49000000 0x10000>; -+ reg = <0x49000000>; - clocks = <&rcc USBO_K>; - clock-names = "otg"; - status = "disabled"; - }; - m4_hash2: hash@4c002000 { - compatible = "rproc-srm-dev"; -- reg = <0x4c002000 0x400>; -+ reg = <0x4c002000>; - clocks = <&rcc HASH2>; - status = "disabled"; - }; - m4_rng2: rng@4c003000 { - compatible = "rproc-srm-dev"; -- reg = <0x4c003000 0x400>; -+ reg = <0x4c003000>; - clocks = <&rcc RNG2_K>; - status = "disabled"; - }; - m4_crc2: crc@4c004000 { - compatible = "rproc-srm-dev"; -- reg = <0x4c004000 0x400>; -+ reg = <0x4c004000>; - clocks = <&rcc CRC2>; - status = "disabled"; - }; - m4_cryp2: cryp@4c005000 { - compatible = "rproc-srm-dev"; -- reg = <0x4c005000 0x400>; -+ reg = <0x4c005000>; - clocks = <&rcc CRYP2>; - status = "disabled"; - }; - m4_dcmi: dcmi@4c006000 { - compatible = "rproc-srm-dev"; -- reg = <0x4c006000 0x400>; -+ reg = <0x4c006000>; - clocks = <&rcc DCMI>; - clock-names = "mclk"; - status = "disabled"; - }; - m4_lptimer2: timer@50021000 { - compatible = "rproc-srm-dev"; -- reg = <0x50021000 0x400>; -+ reg = <0x50021000>; - clocks = <&rcc LPTIM2_K>; - clock-names = "mux"; - status = "disabled"; - }; - m4_lptimer3: timer@50022000 { - compatible = "rproc-srm-dev"; -- reg = <0x50022000 0x400>; -+ reg = <0x50022000>; - clocks = <&rcc LPTIM3_K>; - clock-names = "mux"; - status = "disabled"; - }; - m4_lptimer4: timer@50023000 { - compatible = "rproc-srm-dev"; -- reg = <0x50023000 0x400>; -+ reg = <0x50023000>; - clocks = <&rcc LPTIM4_K>; - clock-names = "mux"; - status = "disabled"; - }; - m4_lptimer5: timer@50024000 { - compatible = "rproc-srm-dev"; -- reg = <0x50024000 0x400>; -+ reg = <0x50024000>; - clocks = <&rcc LPTIM5_K>; - clock-names = "mux"; - status = "disabled"; - }; - m4_sai4: sai@50027000 { - compatible = "rproc-srm-dev"; -- reg = <0x50027000 0x4>; -+ reg = <0x50027000>; - clocks = <&rcc SAI4_K>; - clock-names = "sai_ck"; - status = "disabled"; - }; - m4_qspi: qspi@58003000 { - compatible = "rproc-srm-dev"; -- reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; -+ reg = <0x58003000>, <0x70000000>; - clocks = <&rcc QSPI_K>; - status = "disabled"; - }; - m4_ethernet0: ethernet@5800a000 { - compatible = "rproc-srm-dev"; -- reg = <0x5800a000 0x2000>; -+ reg = <0x5800a000>; - clock-names = "stmmaceth", - "mac-clk-tx", - "mac-clk-rx", -diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index 7a7ef47..4de499e 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -1231,7 +1231,7 @@ - reg = <0x4c000000 0x400>; - clocks = <&rcc HSEM>; - clock-names = "hsem"; -- status = "disabled"; -+ status = "okay"; - }; - - ipcc: mailbox@4c001000 { --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0052-ARM-stm32mp1-r0-rc4-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0052-ARM-stm32mp1-r0-rc4-DEFCONFIG.patch deleted file mode 100644 index 3632650..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0052-ARM-stm32mp1-r0-rc4-DEFCONFIG.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 619ff8e35045cb1cb0f235bd24236ff36453186a Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Fri, 21 Dec 2018 16:57:19 +0100 -Subject: [PATCH 52/52] ARM: stm32mp1-r0-rc4: DEFCONFIG - ---- - arch/arm/configs/fragment-02-multiv7_addons.config | 13 ------------- - 1 file changed, 13 deletions(-) - -diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config -index 6ae0453..38c5562 100644 ---- a/arch/arm/configs/fragment-02-multiv7_addons.config -+++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -462,19 +462,6 @@ CONFIG_REGULATOR_STM32_VREFBUF=y - CONFIG_NVMEM_STM32_ROMEM=y - - # --# STM32 CORESIGHT --# --CONFIG_STM_SOURCE_CONSOLE=y --CONFIG_STM_SOURCE_FTRACE=y --CONFIG_FUNCTION_TRACER=y --CONFIG_CORESIGHT=y --CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y --CONFIG_CORESIGHT_SINK_TPIU=y --CONFIG_CORESIGHT_SINK_ETBV10=y --CONFIG_CORESIGHT_SOURCE_ETM3X=y --CONFIG_CORESIGHT_STM=y -- --# - # STM32 IPCC - # - CONFIG_STM32_IPCC=y --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0053-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DRIVERS.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0053-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DRIVERS.patch deleted file mode 100644 index 30f5d81..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0053-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DRIVERS.patch +++ /dev/null @@ -1,1145 +0,0 @@ -From 0ab8d3145b982810bf5b1c1d2388f5c3820151a8 Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Mon, 14 Jan 2019 17:18:56 +0100 -Subject: [PATCH 53/55] ARM stm32mp1 r0 rc4 hotfix-w903.1 DRIVERS - ---- - .../bindings/connector/usb-connector.txt | 2 + - .../devicetree/bindings/usb/st,typec-stusb.txt | 32 ++ - drivers/bluetooth/hci_bcm.c | 3 +- - drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 9 +- - drivers/iio/adc/stm32-dfsdm-adc.c | 5 +- - drivers/media/platform/stm32/stm32-dcmi.c | 17 + - drivers/mfd/stm32-pwr.c | 14 - - .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 5 + - drivers/remoteproc/remoteproc_core.c | 10 + - drivers/remoteproc/remoteproc_virtio.c | 2 + - drivers/remoteproc/stm32_rproc.c | 63 ++- - drivers/usb/typec/Kconfig | 9 + - drivers/usb/typec/Makefile | 1 + - drivers/usb/typec/class.c | 15 + - drivers/usb/typec/typec_stusb.c | 589 +++++++++++++++++++++ - include/linux/usb/typec.h | 1 + - sound/soc/stm/stm32_adfsdm.c | 21 +- - 17 files changed, 761 insertions(+), 37 deletions(-) - create mode 100644 Documentation/devicetree/bindings/usb/st,typec-stusb.txt - create mode 100644 drivers/usb/typec/typec_stusb.c - -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/usb/st,typec-stusb.txt b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt -new file mode 100644 -index 0000000..817360d ---- /dev/null -+++ b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt -@@ -0,0 +1,32 @@ -+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. -+ -+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>; -+ -+ usb_con: connector { -+ compatible = "usb-c-connector"; -+ label = "USB-C"; -+ power-role = "dual"; -+ power-opmode = "1.5A"; -+ data-role = "dual"; -+ }; -+ }; -+ -diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c -index ddbd8c6..7a23fee 100644 ---- a/drivers/bluetooth/hci_bcm.c -+++ b/drivers/bluetooth/hci_bcm.c -@@ -1295,7 +1295,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/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -index a6edd86..a373651 100644 ---- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -@@ -227,7 +227,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) { -@@ -347,6 +346,14 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) - return ret; - } - -+ dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; -+ if (dsi->hw_version != HWVER_130 && dsi->hw_version != HWVER_131) { -+ dev_err(dev, "bad dsi hardware version\n"); -+ clk_disable_unprepare(dsi->pllref_clk); -+ regulator_disable(dsi->vdd_supply); -+ return -ENODEV; -+ } -+ - dw_mipi_dsi_stm_plat_data.base = dsi->base; - dw_mipi_dsi_stm_plat_data.priv_data = dsi; - -diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c -index c97d9ee..13854b7 100644 ---- a/drivers/iio/adc/stm32-dfsdm-adc.c -+++ b/drivers/iio/adc/stm32-dfsdm-adc.c -@@ -569,8 +569,9 @@ static int dfsdm_adc_set_samp_freq(struct iio_dev *indio_dev, - - oversamp = DIV_ROUND_CLOSEST(spi_freq, sample_freq); - if (spi_freq % sample_freq) -- dev_warn(&indio_dev->dev, "Sampling rate not accurate (%d)\n", -- spi_freq / oversamp); -+ dev_dbg(&indio_dev->dev, -+ "Rate not accurate. requested (%u), actual (%u)\n", -+ sample_freq, spi_freq / oversamp); - - ret = stm32_dfsdm_set_osrs(fl, 0, oversamp); - if (ret < 0) { -diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c -index 49849e6..6f6dc66 100644 ---- a/drivers/media/platform/stm32/stm32-dcmi.c -+++ b/drivers/media/platform/stm32/stm32-dcmi.c -@@ -167,6 +167,9 @@ struct stm32_dcmi { - int errors_count; - int overrun_count; - int buffers_count; -+ -+ /* Ensure DMA operations atomicity */ -+ struct mutex dma_lock; - }; - - static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) -@@ -317,6 +320,13 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, - return ret; - } - -+ /* -+ * Avoid call of dmaengine_terminate_all() between -+ * dmaengine_prep_slave_single() and dmaengine_submit() -+ * by locking the whole DMA submission sequence -+ */ -+ mutex_lock(&dcmi->dma_lock); -+ - /* Prepare a DMA transaction */ - desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr, - buf->size, -@@ -325,6 +335,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, - if (!desc) { - dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n", - __func__, &buf->paddr, buf->size); -+ mutex_unlock(&dcmi->dma_lock); - return -EINVAL; - } - -@@ -336,9 +347,12 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, - dcmi->dma_cookie = dmaengine_submit(desc); - if (dma_submit_error(dcmi->dma_cookie)) { - dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__); -+ mutex_unlock(&dcmi->dma_lock); - return -ENXIO; - } - -+ mutex_unlock(&dcmi->dma_lock); -+ - dma_async_issue_pending(dcmi->dma_chan); - - return 0; -@@ -746,7 +760,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) - spin_unlock_irq(&dcmi->irqlock); - - /* Stop all pending DMA operations */ -+ mutex_lock(&dcmi->dma_lock); - dmaengine_terminate_all(dcmi->dma_chan); -+ mutex_unlock(&dcmi->dma_lock); - - pm_runtime_put(dcmi->dev); - -@@ -1740,6 +1756,7 @@ static int dcmi_probe(struct platform_device *pdev) - - spin_lock_init(&dcmi->irqlock); - mutex_init(&dcmi->lock); -+ mutex_init(&dcmi->dma_lock); - init_completion(&dcmi->complete); - INIT_LIST_HEAD(&dcmi->buffers); - -diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c -index 206a933..088b3d6 100644 ---- a/drivers/mfd/stm32-pwr.c -+++ b/drivers/mfd/stm32-pwr.c -@@ -70,19 +70,6 @@ static void stm32_pwr_irq_unmask(struct irq_data *d) - SMC(STM32_SVC_PWR, STM32_SET_BITS, MPUWKUPENR, BIT(d->hwirq)); - } - --static int stm32_pwr_irq_set_wake(struct irq_data *d, unsigned int on) --{ -- struct stm32_pwr_data *priv = d->domain->host_data; -- -- pr_debug("irq:%lu on:%d\n", d->hwirq, on); -- if (on) -- enable_irq_wake(priv->irq); -- else -- disable_irq_wake(priv->irq); -- -- 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; -@@ -125,7 +112,6 @@ static struct irq_chip stm32_pwr_irq_chip = { - .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, - }; - - static int stm32_pwr_irq_set_pull_config(struct irq_domain *d, int pin_id, -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/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c -index dd7e348..6430747 100644 ---- a/drivers/remoteproc/remoteproc_core.c -+++ b/drivers/remoteproc/remoteproc_core.c -@@ -1456,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); - -@@ -1614,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) { -diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c -index 9ee63c0..78462f5 100644 ---- a/drivers/remoteproc/remoteproc_virtio.c -+++ b/drivers/remoteproc/remoteproc_virtio.c -@@ -359,6 +359,8 @@ int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id) - } - } - -+ /* 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/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index 70b7e55c..1d2be11 100644 ---- a/drivers/remoteproc/stm32_rproc.c -+++ b/drivers/remoteproc/stm32_rproc.c -@@ -67,7 +67,7 @@ struct stm32_rproc { - struct stm32_rproc_mem *rmems; - struct stm32_mbox mb[MBOX_NB_MBX]; - bool secured_soc; -- u32 rsc_addr; -+ void __iomem *rsc_va; - u32 rsc_len; - }; - -@@ -84,7 +84,27 @@ static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) - pa >= p_mem->bus_addr + p_mem->size) - continue; - *da = pa - p_mem->bus_addr + p_mem->dev_addr; -- dev_dbg(rproc->dev.parent, "da %llx to pa %#x\n", *da, pa); -+ 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_err(rproc->dev.parent, "da %llx to pa %#x\n", da, *pa); - return 0; - } - -@@ -209,11 +229,9 @@ static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, - return 0; - } - -- if (ddata->rsc_addr) { -+ if (ddata->rsc_va) { - tablesz = ddata->rsc_len; -- table = (struct resource_table *) -- rproc_da_to_va(rproc, (u64)ddata->rsc_addr, -- ddata->rsc_len); -+ table = (struct resource_table *)ddata->rsc_va; - rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL); - if (!rproc->cached_table) - return -ENOMEM; -@@ -297,12 +315,7 @@ stm32_rproc_elf_find_loaded_rsc_table(struct rproc *rproc, - if (!rproc->early_boot) - return rproc_elf_find_loaded_rsc_table(rproc, fw); - -- if (ddata->rsc_addr) -- return (struct resource_table *) -- rproc_da_to_va(rproc, (u64)ddata->rsc_addr, -- ddata->rsc_len); -- -- return NULL; -+ return (struct resource_table *)ddata->rsc_va; - } - - static int stm32_rproc_elf_sanity_check(struct rproc *rproc, -@@ -582,6 +595,8 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) - struct rproc *rproc = platform_get_drvdata(pdev); - struct stm32_rproc *ddata = rproc->priv; - struct stm32_syscon tz; -+ phys_addr_t rsc_pa; -+ u32 rsc_da; - unsigned int tzen; - int err, irq; - -@@ -636,10 +651,14 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) - 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; - -- err = of_property_read_u32(np, "rsc-address", &ddata->rsc_addr); -+ err = of_property_read_u32(np, "rsc-address", &rsc_da); - if (!err) { - err = of_property_read_u32(np, "rsc-size", - &ddata->rsc_len); -@@ -649,9 +668,19 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) - return err; - } - } -+ err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); -+ if (err) -+ return err; -+ ddata->rsc_va = ioremap_wc(rsc_pa, ddata->rsc_len); -+ if (IS_ERR_OR_NULL(ddata->rsc_va)) { -+ dev_err(dev, "Unable to map memory region: %pa+%zx\n", -+ &rsc_pa, ddata->rsc_len); -+ ddata->rsc_va = NULL; -+ return -ENOMEM; -+ } - } - -- return stm32_rproc_of_memory_translations(rproc); -+ return 0; - } - - static int stm32_rproc_probe(struct platform_device *pdev) -@@ -699,13 +728,15 @@ 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 device *dev = &pdev->dev; -+ struct stm32_rproc *ddata = rproc->priv; - - if (atomic_read(&rproc->power) > 0) -- dev_warn(dev, "Releasing rproc while firmware running!\n"); -+ rproc_shutdown(rproc); - - rproc_del(rproc); - stm32_rproc_free_mbox(rproc); -+ if (ddata->rsc_va) -+ iounmap(ddata->rsc_va); - rproc_free(rproc); - - return 0; -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 e61dffb..b518360 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..a2884fd ---- /dev/null -+++ b/drivers/usb/typec/typec_stusb.c -@@ -0,0 +1,589 @@ -+// 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 -+ -+#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, -+}; -+ -+struct stusb { -+ struct device *dev; -+ struct regmap *regmap; -+ struct regulator *vdd_supply; -+ struct regulator *vsys_supply; -+ struct regulator *vconn_supply; -+ -+ struct typec_port *port; -+ struct typec_capability capability; -+ -+ enum typec_port_type port_type; -+ enum typec_pwr_opmode pwr_opmode; -+}; -+ -+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 >= 0x00 && 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 int stusb_init(struct stusb *chip) -+{ -+ 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) -+ return 0; -+ -+ /* 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; -+ } -+ -+ /* 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); -+ -+ return ret; -+} -+ -+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->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; -+ } else { -+ ret = regulator_enable(chip->vdd_supply); -+ if (ret) { -+ dev_err(chip->dev, -+ "Failed to enable vdd supply: %d\n", ret); -+ return ret; -+ } -+ } -+ -+ 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) -+ goto vdd_reg_disable; -+ chip->vsys_supply = NULL; -+ } else { -+ ret = regulator_enable(chip->vsys_supply); -+ if (ret) { -+ dev_err(chip->dev, -+ "Failed to enable vsys supply: %d\n", ret); -+ goto vdd_reg_disable; -+ } -+ } -+ -+ 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) -+ goto vsys_reg_disable; -+ chip->vconn_supply = NULL; -+ } -+ -+ ret = stusb_get_caps(chip, &try_role); -+ if (ret) { -+ dev_err(chip->dev, "failed to get port caps: %d\n", ret); -+ goto vsys_reg_disable; -+ } -+ -+ ret = stusb_init(chip); -+ if (ret) { -+ dev_err(chip->dev, "failed to init port: %d\n", ret); -+ goto vsys_reg_disable; -+ } -+ -+ chip->port = typec_register_port(chip->dev, &chip->capability); -+ if (!chip->port) { -+ ret = -ENODEV; -+ goto all_reg_disable; -+ } -+ -+ /* To be moved in attach/detach procedure with interrupt support */ -+ typec_set_pwr_opmode(chip->port, chip->pwr_opmode); -+ -+ dev_info(chip->dev, "STUSB driver registered\n"); -+ -+ return 0; -+ -+all_reg_disable: -+ if (stusb_get_vconn(chip)) -+ stusb_set_vconn(chip, false); -+vsys_reg_disable: -+ if (chip->vsys_supply) -+ regulator_disable(chip->vsys_supply); -+vdd_reg_disable: -+ if (chip->vdd_supply) -+ regulator_disable(chip->vdd_supply); -+ -+ return ret; -+} -+ -+static int stusb_remove(struct i2c_client *client) -+{ -+ struct stusb *chip = i2c_get_clientdata(client); -+ -+ typec_unregister_port(chip->port); -+ -+ if (stusb_get_vconn(chip)) -+ stusb_set_vconn(chip, false); -+ -+ if (chip->vdd_supply) -+ regulator_disable(chip->vdd_supply); -+ -+ if (chip->vsys_supply) -+ regulator_disable(chip->vsys_supply); -+ -+ return 0; -+} -+ -+#ifdef CONFIG_PM_SLEEP -+static int stusb_resume(struct device *dev) -+{ -+ struct stusb *chip = dev_get_drvdata(dev); -+ -+ return stusb_init(chip); -+} -+#endif -+ -+static SIMPLE_DEV_PM_OPS(stusb_pm_ops, NULL, 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); -diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c -index 71d341b..24948b9 100644 ---- a/sound/soc/stm/stm32_adfsdm.c -+++ b/sound/soc/stm/stm32_adfsdm.c -@@ -304,6 +304,7 @@ MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match); - static int stm32_adfsdm_probe(struct platform_device *pdev) - { - struct stm32_adfsdm_priv *priv; -+ struct snd_soc_component *component; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); -@@ -331,9 +332,15 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) - if (IS_ERR(priv->iio_cb)) - return PTR_ERR(priv->iio_cb); - -- ret = devm_snd_soc_register_component(&pdev->dev, -- &stm32_adfsdm_soc_platform, -- NULL, 0); -+ component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL); -+ if (!component) -+ return -ENOMEM; -+#ifdef CONFIG_DEBUG_FS -+ component->debugfs_prefix = "pcm"; -+#endif -+ -+ ret = snd_soc_add_component(&pdev->dev, component, -+ &stm32_adfsdm_soc_platform, NULL, 0); - if (ret < 0) - dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", - __func__); -@@ -341,12 +348,20 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) - return ret; - } - -+static int stm32_adfsdm_remove(struct platform_device *pdev) -+{ -+ snd_soc_unregister_component(&pdev->dev); -+ -+ return 0; -+} -+ - static struct platform_driver stm32_adfsdm_driver = { - .driver = { - .name = STM32_ADFSDM_DRV_NAME, - .of_match_table = stm32_adfsdm_of_match, - }, - .probe = stm32_adfsdm_probe, -+ .remove = stm32_adfsdm_remove, - }; - - module_platform_driver(stm32_adfsdm_driver); --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0054-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0054-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEVICETREE.patch deleted file mode 100644 index 6a592e5..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0054-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEVICETREE.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 5648392b05ff7bb1f513ad9e9eb27b5420ce745d Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Mon, 14 Jan 2019 17:19:51 +0100 -Subject: [PATCH 54/55] ARM stm32mp1 r0 rc4 hotfix-w903.1 DEVICETREE - ---- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 13 +++++++++++++ - arch/arm/boot/dts/stm32mp157c-dk2.dts | 1 + - arch/arm/boot/dts/stm32mp157c.dtsi | 14 ++++++++++++++ - 3 files changed, 28 insertions(+) - -diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -index 7e911f3..28017e4 100644 ---- a/arch/arm/boot/dts/stm32mp157a-dk1.dts -+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -287,6 +287,19 @@ - /delete-property/dmas; - /delete-property/dma-names; - -+ typec: stusb1600@28 { -+ compatible = "st,stusb1600"; -+ reg = <0x28>; -+ status = "okay"; -+ -+ typec_con: connector { -+ compatible = "usb-c-connector"; -+ label = "USB-C"; -+ power-role = "sink"; -+ power-opmode = "default"; -+ }; -+ }; -+ - pmic: stpmic@33 { - compatible = "st,stpmic1"; - reg = <0x33>; -diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -index c276c59..340e022 100644 ---- a/arch/arm/boot/dts/stm32mp157c-dk2.dts -+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -106,6 +106,7 @@ - - /* Wifi */ - &sdmmc2 { -+ arm,primecell-periphid = <0x10153180>; - pinctrl-names = "default", "opendrain", "sleep"; - pinctrl-0 = <&sdmmc2_b4_pins_a>; - pinctrl-1 = <&sdmmc2_b4_od_pins_a>; -diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index 4de499e..b09ef8b 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -892,6 +892,8 @@ - - compatible = "st,stm32-sai-sub-a"; - reg = <0x4 0x1c>; -+ clocks = <&rcc SAI1_K>; -+ clock-names = "sai_ck"; - dmas = <&dmamux1 87 0x400 0x01>; - status = "disabled"; - }; -@@ -900,6 +902,8 @@ - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; -+ clocks = <&rcc SAI1_K>; -+ clock-names = "sai_ck"; - dmas = <&dmamux1 88 0x400 0x01>; - status = "disabled"; - }; -@@ -919,6 +923,8 @@ - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-a"; - reg = <0x4 0x1c>; -+ clocks = <&rcc SAI2_K>; -+ clock-names = "sai_ck"; - dmas = <&dmamux1 89 0x400 0x01>; - status = "disabled"; - }; -@@ -927,6 +933,8 @@ - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; -+ clocks = <&rcc SAI2_K>; -+ clock-names = "sai_ck"; - dmas = <&dmamux1 90 0x400 0x01>; - status = "disabled"; - }; -@@ -946,6 +954,8 @@ - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-a"; - reg = <0x04 0x1c>; -+ clocks = <&rcc SAI3_K>; -+ clock-names = "sai_ck"; - dmas = <&dmamux1 113 0x400 0x01>; - status = "disabled"; - }; -@@ -954,6 +964,8 @@ - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; -+ clocks = <&rcc SAI3_K>; -+ clock-names = "sai_ck"; - dmas = <&dmamux1 114 0x400 0x01>; - status = "disabled"; - }; -@@ -1442,6 +1454,8 @@ - #sound-dai-cells = <0>; - compatible = "st,stm32-sai-sub-b"; - reg = <0x24 0x1c>; -+ clocks = <&rcc SAI4_K>; -+ clock-names = "sai_ck"; - dmas = <&dmamux1 100 0x400 0x01>; - status = "disabled"; - }; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0055-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0055-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEFCONFIG.patch deleted file mode 100644 index 3d4ed1f..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0055-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEFCONFIG.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 449bea3af472f64774547738478ca3b2cfa91cae Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Mon, 14 Jan 2019 17:20:30 +0100 -Subject: [PATCH 55/55] ARM stm32mp1 r0 rc4 hotfix-w903.1 DEFCONFIG - ---- - arch/arm/configs/fragment-02-multiv7_addons.config | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config -index 38c5562..ddf15a9 100644 ---- a/arch/arm/configs/fragment-02-multiv7_addons.config -+++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -346,6 +346,8 @@ CONFIG_USB_CONFIGFS=y - # - # USB Physical Layer drivers - # -+CONFIG_TYPEC=y -+CONFIG_TYPEC_STUSB=y - - # - # Platform Support --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0056-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DRIVERS.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0056-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DRIVERS.patch deleted file mode 100644 index 70b6a67..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0056-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DRIVERS.patch +++ /dev/null @@ -1,554 +0,0 @@ -From b6678ec426d7dbc5248a2d98c0c2c7a5b55e4d5f Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Wed, 16 Jan 2019 17:51:05 +0100 -Subject: [PATCH 56/58] ARM stm32mp1 r0 rc4 hotfix w903.3 DRIVERS - ---- - drivers/clk/clk-stm32mp1.c | 142 ++++++++++++++++++++-------------- - drivers/i2c/busses/i2c-stm32f7.c | 33 +++++++- - drivers/irqchip/irq-stm32-exti.c | 160 +++++++++++++++++++++++++-------------- - kernel/power/suspend.c | 1 - - 4 files changed, 218 insertions(+), 118 deletions(-) - -diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index 7eccaa1..56d7b86 100644 ---- a/drivers/clk/clk-stm32mp1.c -+++ b/drivers/clk/clk-stm32mp1.c -@@ -2215,8 +2215,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { - - static const struct clock_config stm32mp1_clock_cfg[] = { - /* Oscillator divider */ -- DIV(NO_ID, "clk-hsi-div", "clk-hsi", 0, RCC_HSICFGR, 0, 2, -- CLK_DIVIDER_READ_ONLY), -+ DIV(NO_ID, "clk-hsi-div", "clk-hsi", CLK_DIVIDER_POWER_OF_TWO, -+ RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), - - /* External / Internal Oscillators */ - SGATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), -@@ -2517,11 +2517,10 @@ 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 */ -- SDIV(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, -@@ -2724,52 +2723,53 @@ static struct sreg clock_gating[] = { - }; - - struct smux { -- const char *name; -- struct clk *clk; -- struct clk *clkp; -+ u32 clk_id; -+ u32 mux_id; -+ struct clk_hw *hw; - }; - --#define KER_SRC(_clk_name)\ -+#define KER_SRC(_clk_id, _mux_id)\ - {\ -- .name = _clk_name,\ --} -- --struct smux _mux_kernel[] = { -- KER_SRC("sdmmc1_k"), -- KER_SRC("spi2_k"), -- KER_SRC("spi4_k"), -- KER_SRC("i2c1_k"), -- KER_SRC("i2c3_k"), -- KER_SRC("lptim2_k"), -- KER_SRC("lptim3_k"), -- KER_SRC("usart2_k"), -- KER_SRC("usart3_k"), -- KER_SRC("uart7_k"), -- KER_SRC("sai1_k"), -- KER_SRC("ethck_k"), -- KER_SRC("i2c4_k"), -- KER_SRC("rng2_k"), -- KER_SRC("sdmmc3_k"), -- KER_SRC("fmc_k"), -- KER_SRC("qspi_k"), -- KER_SRC("usbphy_k"), -- KER_SRC("usbo_k"), -- KER_SRC("spdif_k"), -- KER_SRC("spi1_k"), -- KER_SRC("cec_k"), -- KER_SRC("lptim1_k"), -- KER_SRC("uart6_k"), -- KER_SRC("fdcan_k"), -- KER_SRC("sai2_k"), -- KER_SRC("sai3_k"), -- KER_SRC("sai4_k"), -- KER_SRC("adc12_k"), -- KER_SRC("dsi_k"), -- KER_SRC("ck_per"), -- KER_SRC("rng1_k"), -- KER_SRC("stgen_k"), -- KER_SRC("usart1_k"), -- KER_SRC("spi6_k"), -+ .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[] = { -@@ -2861,22 +2861,52 @@ static void stm32mp1_restore_pll(struct sreg *sreg, int size) - } - } - --static void stm32mp1_backup_mux(struct smux *smux, int size) -+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++) { -- smux[i].clk = __clk_lookup(smux[i].name); -- smux[i].clkp = clk_get_parent(smux[i].clk); -+ 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; - -- for (i = 0; i < size; i++) -- clk_set_parent_force(smux[i].clk, smux[i].clkp); -+ /* 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 -@@ -2900,9 +2930,6 @@ static int stm32mp1_clk_suspend(void) - /* Save clock gating regs */ - stm32mp1_backup_sreg(clock_gating, ARRAY_SIZE(clock_gating)); - -- /* Save kernel clock regs */ -- stm32mp1_backup_mux(_mux_kernel, ARRAY_SIZE(_mux_kernel)); -- - /* 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); -@@ -2970,6 +2997,9 @@ static int stm32_rcc_init_pwr(struct device_node *np) - - 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/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index ac30aea..3af2637 100644 ---- a/drivers/i2c/busses/i2c-stm32f7.c -+++ b/drivers/i2c/busses/i2c-stm32f7.c -@@ -978,6 +978,26 @@ 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: -+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { -+ dev_err(dev, "Invalid block %s size %d\n", -+ f7_msg->read_write == I2C_SMBUS_READ ? -+ "read" : "write", -+ data->block[0]); -+ return -EINVAL; -+ } -+ -+ if (f7_msg->read_write) { -+ f7_msg->stop = false; -+ f7_msg->count = data->block[0]; -+ cr2 &= ~STM32F7_I2C_CR2_RD_WRN; -+ } else { -+ f7_msg->stop = true; -+ f7_msg->count = data->block[0] + 1; -+ for (i = 1; i <= data->block[0]; i++) -+ f7_msg->smbus_buf[i] = data->block[i]; -+ } -+ break; - default: - dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size); - return -EOPNOTSUPP; -@@ -986,7 +1006,8 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, - f7_msg->buf = f7_msg->smbus_buf; - - /* Configure PEC */ -- if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) { -+ if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK && -+ f7_msg->size != I2C_SMBUS_I2C_BLOCK_DATA) { - cr1 |= STM32F7_I2C_CR1_PECEN; - cr2 |= STM32F7_I2C_CR2_PECBYTE; - if (!f7_msg->read_write) -@@ -1655,7 +1676,8 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - } - - /* Check PEC */ -- if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) { -+ if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && -+ size != I2C_SMBUS_I2C_BLOCK_DATA && read_write) { - ret = stm32f7_i2c_smbus_check_pec(i2c_dev); - if (ret) - goto pm_free; -@@ -1672,6 +1694,10 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, - data->word = f7_msg->smbus_buf[0] | - (f7_msg->smbus_buf[1] << 8); - break; -+ case I2C_SMBUS_I2C_BLOCK_DATA: -+ for (i = 0; i < data->block[0]; i++) -+ data->block[i + 1] = f7_msg->smbus_buf[i]; -+ break; - case I2C_SMBUS_BLOCK_DATA: - case I2C_SMBUS_BLOCK_PROC_CALL: - for (i = 0; i <= f7_msg->smbus_buf[0]; i++) -@@ -1854,7 +1880,8 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap) - 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; - } - - static struct i2c_algorithm stm32f7_i2c_algo = { -diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index 223ee2e..793be075a 100644 ---- a/drivers/irqchip/irq-stm32-exti.c -+++ b/drivers/irqchip/irq-stm32-exti.c -@@ -14,8 +14,10 @@ - #include - #include - #include -+#include - #include - #include -+#include - #include - - #include -@@ -37,12 +39,6 @@ struct stm32_exti_bank { - - #define UNDEF_REG ~0 - --enum stm32_exti_hwspinlock { -- HWSPINLOCK_UNKNOWN, -- HWSPINLOCK_NONE, -- HWSPINLOCK_READY, --}; -- - struct stm32_desc_irq { - u32 exti; - u32 irq_parent; -@@ -69,8 +65,6 @@ struct stm32_exti_host_data { - void __iomem *base; - struct stm32_exti_chip_data *chips_data; - const struct stm32_exti_drv_data *drv_data; -- struct device_node *node; -- enum stm32_exti_hwspinlock hwlock_state; - struct hwspinlock *hwlock; - }; - -@@ -285,49 +279,27 @@ static int stm32_exti_set_type(struct irq_data *d, - - static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) - { -- struct stm32_exti_host_data *host_data = chip_data->host_data; -- struct hwspinlock *hwlock; -- int id, ret = 0, timeout = 0; -- -- /* first time, check for hwspinlock availability */ -- if (unlikely(host_data->hwlock_state == HWSPINLOCK_UNKNOWN)) { -- id = of_hwspin_lock_get_id(host_data->node, 0); -- if (id >= 0) { -- hwlock = hwspin_lock_request_specific(id); -- if (hwlock) { -- /* found valid hwspinlock */ -- host_data->hwlock_state = HWSPINLOCK_READY; -- host_data->hwlock = hwlock; -- pr_debug("%s hwspinlock = %d\n", __func__, id); -- } else { -- host_data->hwlock_state = HWSPINLOCK_NONE; -- } -- } else if (id != -EPROBE_DEFER) { -- host_data->hwlock_state = HWSPINLOCK_NONE; -- } else { -- /* hwspinlock driver shall be ready at that stage */ -- ret = -EPROBE_DEFER; -- } -- } -+ int ret, timeout = 0; - -- if (likely(host_data->hwlock_state == HWSPINLOCK_READY)) { -- /* -- * 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(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 (!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); -@@ -337,7 +309,7 @@ static int stm32_exti_hwspin_lock(struct stm32_exti_chip_data *chip_data) - - static void stm32_exti_hwspin_unlock(struct stm32_exti_chip_data *chip_data) - { -- if (likely(chip_data->host_data->hwlock_state == HWSPINLOCK_READY)) -+ if (chip_data->host_data->hwlock) - hwspin_unlock_raw(chip_data->host_data->hwlock); - } - -@@ -710,8 +682,6 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, - return NULL; - - host_data->drv_data = dd; -- host_data->node = node; -- host_data->hwlock_state = HWSPINLOCK_UNKNOWN; - host_data->chips_data = kcalloc(dd->bank_nr, - sizeof(struct stm32_exti_chip_data), - GFP_KERNEL); -@@ -738,7 +708,8 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, - - static struct - stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, -- u32 bank_idx) -+ u32 bank_idx, -+ struct device_node *node) - { - const struct stm32_exti_bank *stm32_bank; - struct stm32_exti_chip_data *chip_data; -@@ -758,7 +729,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("%pOF: bank%d\n", h_data->node, bank_idx); -+ pr_info("%pOF: bank%d\n", node, bank_idx); - - return chip_data; - } -@@ -798,7 +769,7 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, - struct stm32_exti_chip_data *chip_data; - - stm32_bank = drv_data->exti_banks[i]; -- chip_data = stm32_exti_chip_init(host_data, i); -+ chip_data = stm32_exti_chip_init(host_data, i, node); - - gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); - -@@ -880,7 +851,7 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, - return -ENOMEM; - - for (i = 0; i < drv_data->bank_nr; i++) -- stm32_exti_chip_init(host_data, i); -+ stm32_exti_chip_init(host_data, i, node); - - domain = irq_domain_add_hierarchy(parent_domain, 0, - drv_data->bank_nr * IRQS_PER_BANK, -@@ -938,6 +909,71 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, - return ret; - } - -+/* Note : stm32_exti_probe() is called after stm32*_exti_of_init() */ -+static int stm32_exti_probe(struct platform_device *pdev) -+{ -+ int id, ret = 0; -+ -+ id = of_hwspin_lock_get_id(pdev->dev.of_node, 0); -+ -+ if (id == -EPROBE_DEFER) -+ /* hwspinlock framework not ready */ -+ return -EPROBE_DEFER; -+ -+ if (id == -ENOENT) -+ /* no hwspinlock defined (not an error, it is optional) */ -+ return 0; -+ -+ if (id >= 0) { -+ stm32_host_data->hwlock = hwspin_lock_request_specific(id); -+ if (!stm32_host_data->hwlock) { -+ dev_err(&pdev->dev, "Failed to request hwspinlock\n"); -+ ret = -EINVAL; -+ } -+ } else { -+ dev_err(&pdev->dev, "Failed to get hwspinlock\n"); -+ ret = id; -+ } -+ -+ return ret; -+} -+ -+static int stm32_exti_remove(struct platform_device *pdev) -+{ -+ if (stm32_host_data->hwlock) -+ return hwspin_lock_free(stm32_host_data->hwlock); -+ -+ return 0; -+} -+ -+static const struct of_device_id stm32_exti_ids[] = { -+ { .compatible = "st,stm32mp1-exti", }, -+ {}, -+}; -+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); -+ - static int __init stm32f4_exti_of_init(struct device_node *np, - struct device_node *parent) - { -@@ -957,7 +993,15 @@ 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); -+ int ret; -+ -+ ret = stm32_exti_hierarchy_init(&stm32mp1_drv_data, np, parent); -+ -+ /* Clear the OF_POPULATED flag so that stm32_exti_probe can be called */ -+ if (!ret) -+ of_node_clear_flag(np, OF_POPULATED); -+ -+ return ret; - } - - IRQCHIP_DECLARE(stm32mp1_exti, "st,stm32mp1-exti", stm32mp1_exti_of_init); -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.9/0057-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0057-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEVICETREE.patch deleted file mode 100644 index 311a32c..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0057-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEVICETREE.patch +++ /dev/null @@ -1,119 +0,0 @@ -From f30f869d9bb396c6981fc2800149c373d21586de Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Wed, 16 Jan 2019 17:52:31 +0100 -Subject: [PATCH 57/58] ARM stm32mp1 r0 rc4 hotfix w903.3 DEVICETREE - ---- - arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 30 ++++++++++++++++++++++++++++++ - arch/arm/boot/dts/stm32mp157a-dk1.dts | 12 +++++++++++- - arch/arm/boot/dts/stm32mp157c-dk2.dts | 2 +- - arch/arm/boot/dts/stm32mp157c-ed1.dts | 2 +- - 4 files changed, 43 insertions(+), 3 deletions(-) - -diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -index 183d7ba..474e7e3 100644 ---- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -@@ -1413,6 +1413,36 @@ - }; - }; - -+ uart7_pins_a: uart7-0 { -+ pins1 { -+ pinmux = ; /* USART7_TX */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <0>; -+ }; -+ pins2 { -+ pinmux = ; /* USART7_RX */ -+ bias-disable; -+ }; -+ }; -+ -+ uart7_idle_pins_a: uart7-idle-0 { -+ pins1 { -+ pinmux = ; /* USART7_TX */ -+ }; -+ pins2 { -+ pinmux = ; /* USART7_RX */ -+ bias-disable; -+ }; -+ }; -+ -+ uart7_sleep_pins_a: uart7-sleep-0 { -+ pins { -+ pinmux = , /* USART7_TX */ -+ ; /* USART7_RX */ -+ }; -+ }; -+ - usart2_pins_a: usart2-0 { - pins1 { - pinmux = , /* USART2_TX */ -diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -index 28017e4..467c226 100644 ---- a/arch/arm/boot/dts/stm32mp157a-dk1.dts -+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -20,6 +20,8 @@ - aliases { - ethernet0 = ðernet0; - serial0 = &uart4; -+ serial1 = &usart3; -+ serial2 = &uart7; - }; - - chosen { -@@ -310,7 +312,7 @@ - - st,main-control-register = <0x04>; - st,vin-control-register = <0xc0>; -- st,usb-control-register = <0x30>; -+ st,usb-control-register = <0x20>; - - regulators { - compatible = "st,stpmic1-regulators"; -@@ -671,6 +673,14 @@ - status = "okay"; - }; - -+&uart7 { -+ pinctrl-names = "default", "sleep", "idle"; -+ pinctrl-0 = <&uart7_pins_a>; -+ pinctrl-1 = <&uart7_sleep_pins_a>; -+ pinctrl-2 = <&uart7_idle_pins_a>; -+ status = "disabled"; -+}; -+ - &usart3 { - pinctrl-names = "default", "sleep", "idle"; - pinctrl-0 = <&usart3_pins_b>; -diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -index 340e022..4da15cd 100644 ---- a/arch/arm/boot/dts/stm32mp157c-dk2.dts -+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -14,7 +14,7 @@ - compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; - - aliases { -- serial1 = &usart2; -+ serial3 = &usart2; - }; - - wifi_pwrseq: wifi-pwrseq { -diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index cf2750e..6d49f21 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ed1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts -@@ -188,7 +188,7 @@ - - st,main-control-register = <0x04>; - st,vin-control-register = <0xc0>; -- st,usb-control-register = <0x30>; -+ st,usb-control-register = <0x20>; - - regulators { - compatible = "st,stpmic1-regulators"; --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0058-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0058-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEFCONFIG.patch deleted file mode 100644 index ba00f78..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0058-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEFCONFIG.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 2cfb67b0a4403e68016a50c1302da9a8eeb15a6b Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Wed, 16 Jan 2019 17:53:15 +0100 -Subject: [PATCH 58/58] ARM stm32mp1 r0 rc4 hotfix w903.3 DEFCONFIG - ---- - arch/arm/configs/fragment-02-multiv7_addons.config | 3 --- - 1 file changed, 3 deletions(-) - -diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config -index ddf15a9..7b489e4 100644 ---- a/arch/arm/configs/fragment-02-multiv7_addons.config -+++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -123,9 +123,6 @@ CONFIG_CMA_SIZE_MBYTES=128 - # - # LPDDR & LPDDR2 PCM memory drivers - # --CONFIG_OF_RESOLVE=y --CONFIG_OF_OVERLAY=y --CONFIG_OF_CONFIGFS=y - - # - # Misc devices --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0059-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DRIVERS.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0059-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DRIVERS.patch deleted file mode 100644 index 3919425..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0059-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DRIVERS.patch +++ /dev/null @@ -1,927 +0,0 @@ -From dbfd12db19506dc6d598c11d72aa0fb81c41aa82 Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Thu, 24 Jan 2019 10:51:36 +0100 -Subject: [PATCH 59/60] ARM stm32mp1 r0 rc4 hotfix w904.3 DRIVERS - ---- - drivers/dma/stm32-dma.c | 4 + - drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 64 +++++------ - drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 51 ++++++--- - drivers/remoteproc/stm32_rproc.c | 21 ++-- - drivers/tty/serial/stm32-usart.c | 8 ++ - drivers/tty/serial/stm32-usart.h | 2 +- - drivers/usb/dwc2/core.h | 29 +++++ - drivers/usb/dwc2/debugfs.c | 1 + - drivers/usb/dwc2/gadget.c | 133 +++++++++++++++++++++-- - drivers/usb/dwc2/hcd.c | 3 - - drivers/usb/dwc2/hcd.h | 2 +- - drivers/usb/dwc2/hcd_queue.c | 19 ++-- - drivers/usb/dwc2/hw.h | 17 +++ - drivers/usb/dwc2/params.c | 18 ++- - 14 files changed, 294 insertions(+), 78 deletions(-) - -diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 1f9d606..5abfa4f 100644 ---- a/drivers/dma/stm32-dma.c -+++ b/drivers/dma/stm32-dma.c -@@ -1242,6 +1242,7 @@ static int stm32_dma_mdma_prep_slave_sg(struct stm32_dma_chan *chan, - dev_err(chan2dev(chan), - "max buf size = %d bytes\n", - chan->sram_size); -+ ret = -EINVAL; - goto free_alloc; - } - } else { -@@ -1939,6 +1940,8 @@ static int stm32_dma_probe(struct platform_device *pdev) - dev_dbg(&pdev->dev, "SRAM pool: %zu KiB\n", - gen_pool_size(dmadev->sram_pool) / 1024); - -+ dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); -+ - dma_cap_set(DMA_SLAVE, dd->cap_mask); - dma_cap_set(DMA_PRIVATE, dd->cap_mask); - dma_cap_set(DMA_CYCLIC, dd->cap_mask); -@@ -1959,6 +1962,7 @@ 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; -+ dd->copy_align = DMAENGINE_ALIGN_32_BYTES; - dd->max_burst = STM32_DMA_MAX_BURST; - dd->descriptor_reuse = true; - dd->dev = &pdev->dev; -diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -index a76d03a..ee7486b 100644 ---- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -@@ -254,24 +254,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; -@@ -280,16 +268,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; - -- regulator_disable(ctx->supply); -+ msleep(10); -+ -+ ret = mipi_dsi_dcs_enter_sleep_mode(dsi); -+ if (ret) -+ return ret; -+ -+ msleep(120); - - ctx->prepared = false; - -@@ -304,20 +299,6 @@ static int otm8009a_prepare(struct drm_panel *panel) - if (ctx->prepared) - return 0; - -- ret = regulator_enable(ctx->supply); -- if (ret < 0) { -- DRM_ERROR("failed to enable supply: %d\n", ret); -- return ret; -- } -- -- 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); -- } -- - ret = otm8009a_init_sequence(ctx); - if (ret) - return ret; -@@ -475,6 +456,20 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) - return ret; - } - -+ ret = regulator_enable(ctx->supply); -+ if (ret < 0) { -+ DRM_ERROR("failed to enable supply: %d\n", ret); -+ return ret; -+ } -+ -+ 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); -+ } -+ - return 0; - } - -@@ -485,6 +480,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); -+ msleep(20); -+ } -+ -+ regulator_disable(ctx->supply); -+ - return 0; - } - -diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -index a373651..7b37f97 100644 ---- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -+++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -@@ -305,6 +305,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; - -@@ -335,23 +336,13 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) - if (IS_ERR(dsi->pllref_clk)) { - ret = PTR_ERR(dsi->pllref_clk); - dev_err(dev, "Unable to get pll reference clock: %d\n", ret); -- regulator_disable(dsi->vdd_supply); -- 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__); -- regulator_disable(dsi->vdd_supply); -- return ret; -- } -- -- dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION; -- if (dsi->hw_version != HWVER_130 && dsi->hw_version != HWVER_131) { -- dev_err(dev, "bad dsi hardware version\n"); -- clk_disable_unprepare(dsi->pllref_clk); -- regulator_disable(dsi->vdd_supply); -- return -ENODEV; -+ goto err_clk_get; - } - - dw_mipi_dsi_stm_plat_data.base = dsi->base; -@@ -361,13 +352,43 @@ 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"); -- regulator_disable(dsi->vdd_supply); -- clk_disable_unprepare(dsi->pllref_clk); -- return PTR_ERR(dsi->dsi); -+ goto err_probe; -+ } -+ -+ 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_probe; -+ } -+ -+ ret = clk_prepare_enable(pclk); -+ if (ret) { -+ dev_err(dev, "%s: Failed to enable peripheral clk\n", __func__); -+ goto err_probe; -+ } -+ -+ 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_probe; - } - - return 0; -+ -+err_probe: -+ 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) -diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index 1d2be11..1827c25 100644 ---- a/drivers/remoteproc/stm32_rproc.c -+++ b/drivers/remoteproc/stm32_rproc.c -@@ -104,10 +104,12 @@ static int stm32_rproc_da_to_pa(struct rproc *rproc, u64 da, phys_addr_t *pa) - da >= p_mem->dev_addr + p_mem->size) - continue; - *pa = da - p_mem->dev_addr + p_mem->bus_addr; -- dev_err(rproc->dev.parent, "da %llx to pa %#x\n", da, *pa); -+ 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; - } - -@@ -657,20 +659,21 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) - - if (of_property_read_bool(np, "early-booted")) { - rproc->early_boot = true; -- - err = of_property_read_u32(np, "rsc-address", &rsc_da); -- if (!err) { -- err = of_property_read_u32(np, "rsc-size", -- &ddata->rsc_len); -+ if (err) -+ /* no optional rsc table found */ -+ return 0; - -- if (err) { -- dev_err(dev, "resource table size required as address defined\n"); -- return err; -- } -+ err = of_property_read_u32(np, "rsc-size", &ddata->rsc_len); -+ if (err) { -+ dev_err(dev, "resource table size required as address defined\n"); -+ return err; - } -+ - err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); - if (err) - return err; -+ - ddata->rsc_va = ioremap_wc(rsc_pa, ddata->rsc_len); - if (IS_ERR_OR_NULL(ddata->rsc_va)) { - dev_err(dev, "Unable to map memory region: %pa+%zx\n", -diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c -index d606eb5..6fc57fc 100644 ---- a/drivers/tty/serial/stm32-usart.c -+++ b/drivers/tty/serial/stm32-usart.c -@@ -250,8 +250,16 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) - ofs->icr); - port->icount.overrun++; - } else if (sr & USART_SR_PE) { -+ if (ofs->icr != UNDEF_REG) -+ writel_relaxed(USART_ICR_PECF, -+ port->membase + -+ ofs->icr); - port->icount.parity++; - } else if (sr & USART_SR_FE) { -+ if (ofs->icr != UNDEF_REG) -+ writel_relaxed(USART_ICR_FECF, -+ port->membase + -+ ofs->icr); - port->icount.frame++; - } - -diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h -index f1f5c1c..53d7e7b 100644 ---- a/drivers/tty/serial/stm32-usart.h -+++ b/drivers/tty/serial/stm32-usart.h -@@ -241,7 +241,7 @@ 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_FECF BIT(1) /* F7 */ - #define USART_ICR_NCF BIT(2) /* F7 */ - #define USART_ICR_ORECF BIT(3) /* F7 */ - #define USART_ICR_IDLECF BIT(4) /* F7 */ -diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index 4c1736f..3d8fa58 100644 ---- a/drivers/usb/dwc2/core.h -+++ b/drivers/usb/dwc2/core.h -@@ -393,6 +393,20 @@ 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) -@@ -426,6 +440,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 -@@ -471,6 +488,7 @@ 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; -@@ -479,6 +497,10 @@ struct dwc2_core_params { - 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; -@@ -618,6 +640,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; -@@ -648,6 +674,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]; -@@ -1372,6 +1399,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; } -@@ -1406,6 +1434,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/gadget.c b/drivers/usb/dwc2/gadget.c -index 220c0f9..55ef3cc 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 - * -@@ -2812,6 +2851,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; - } -@@ -3127,6 +3183,7 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) - hsotg->connected = 0; - hsotg->test_mode = 0; - -+ /* all endpoints should be shutdown */ - for (ep = 0; ep < hsotg->num_of_eps; ep++) { - if (hsotg->eps_in[ep]) - kill_all_requests(hsotg, hsotg->eps_in[ep], -@@ -3177,6 +3234,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) - GINTSTS_PTXFEMP | \ - GINTSTS_RXFLVL) - -+static int dwc2_hsotg_ep_disable(struct usb_ep *ep); - /** - * dwc2_hsotg_core_init - issue softreset to the core - * @hsotg: The device state -@@ -3191,13 +3249,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, - u32 val; - u32 usbcfg; - u32 dcfg = 0; -+ int ep; - - /* Kill any ep0 requests as controller will be reinitialized */ - kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); - -- if (!is_usb_reset) -+ if (!is_usb_reset) { - if (dwc2_core_reset(hsotg, true)) - return; -+ } else { -+ /* all endpoints should be shutdown */ -+ for (ep = 1; ep < hsotg->num_of_eps; ep++) { -+ if (hsotg->eps_in[ep]) -+ dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); -+ if (hsotg->eps_out[ep]) -+ dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); -+ } -+ } - - /* - * we must now enable ep0 ready for host detection and then -@@ -3312,6 +3380,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", -@@ -3368,6 +3440,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); - -@@ -3676,6 +3752,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; -@@ -3990,7 +4070,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) - struct dwc2_hsotg *hsotg = hs_ep->parent; - int dir_in = hs_ep->dir_in; - int index = hs_ep->index; -- unsigned long flags; - u32 epctrl_reg; - u32 ctrl; - -@@ -4008,8 +4087,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) - - epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); - -- spin_lock_irqsave(&hsotg->lock, flags); -- - ctrl = dwc2_readl(hsotg, epctrl_reg); - - if (ctrl & DXEPCTL_EPENA) -@@ -4032,10 +4109,22 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) - hs_ep->fifo_index = 0; - hs_ep->fifo_size = 0; - -- spin_unlock_irqrestore(&hsotg->lock, flags); - return 0; - } - -+static int dwc2_hsotg_ep_disable_lock(struct usb_ep *ep) -+{ -+ struct dwc2_hsotg_ep *hs_ep = our_ep(ep); -+ struct dwc2_hsotg *hsotg = hs_ep->parent; -+ unsigned long flags; -+ int ret; -+ -+ spin_lock_irqsave(&hsotg->lock, flags); -+ ret = dwc2_hsotg_ep_disable(ep); -+ spin_unlock_irqrestore(&hsotg->lock, flags); -+ return ret; -+} -+ - /** - * on_list - check request is on the given endpoint - * @ep: The endpoint to check. -@@ -4183,7 +4272,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value) - - static const struct usb_ep_ops dwc2_hsotg_ep_ops = { - .enable = dwc2_hsotg_ep_enable, -- .disable = dwc2_hsotg_ep_disable, -+ .disable = dwc2_hsotg_ep_disable_lock, - .alloc_request = dwc2_hsotg_ep_alloc_request, - .free_request = dwc2_hsotg_ep_free_request, - .queue = dwc2_hsotg_ep_queue_lock, -@@ -4323,9 +4412,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) - /* all endpoints should be shutdown */ - for (ep = 1; ep < hsotg->num_of_eps; ep++) { - if (hsotg->eps_in[ep]) -- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); -+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); - if (hsotg->eps_out[ep]) -- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); -+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); - } - - spin_lock_irqsave(&hsotg->lock, flags); -@@ -4773,9 +4862,9 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) - - for (ep = 0; ep < hsotg->num_of_eps; ep++) { - if (hsotg->eps_in[ep]) -- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); -+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); - if (hsotg->eps_out[ep]) -- dwc2_hsotg_ep_disable(&hsotg->eps_out[ep]->ep); -+ dwc2_hsotg_ep_disable_lock(&hsotg->eps_out[ep]->ep); - } - } - -@@ -4942,8 +5031,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 12fa6c0..7f128b1 100644 ---- a/drivers/usb/dwc2/hcd.c -+++ b/drivers/usb/dwc2/hcd.c -@@ -1309,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; -diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h -index 3f9bccc..c089ffa 100644 ---- a/drivers/usb/dwc2/hcd.h -+++ b/drivers/usb/dwc2/hcd.h -@@ -366,7 +366,7 @@ struct dwc2_qh { - u32 desc_list_sz; - u32 *n_bytes; - struct timer_list unreserve_timer; -- struct timer_list wait_timer; -+ struct hrtimer wait_timer; - struct dwc2_tt *dwc_tt; - int ttport; - unsigned tt_buffer_dirty:1; -diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c -index 40839591..ea3aa64 100644 ---- a/drivers/usb/dwc2/hcd_queue.c -+++ b/drivers/usb/dwc2/hcd_queue.c -@@ -59,7 +59,7 @@ - #define DWC2_UNRESERVE_DELAY (msecs_to_jiffies(5)) - - /* If we get a NAK, wait this long before retrying */ --#define DWC2_RETRY_WAIT_DELAY (msecs_to_jiffies(1)) -+#define DWC2_RETRY_WAIT_DELAY 1*1E6L - - /** - * dwc2_periodic_channel_available() - Checks that a channel is available for a -@@ -1464,10 +1464,12 @@ static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg, - * qh back to the "inactive" list, then queues transactions. - * - * @t: Pointer to wait_timer in a qh. -+ * -+ * Return: HRTIMER_NORESTART to not automatically restart this timer. - */ --static void dwc2_wait_timer_fn(struct timer_list *t) -+static enum hrtimer_restart dwc2_wait_timer_fn(struct hrtimer *t) - { -- struct dwc2_qh *qh = from_timer(qh, t, wait_timer); -+ struct dwc2_qh *qh = container_of(t, struct dwc2_qh, wait_timer); - struct dwc2_hsotg *hsotg = qh->hsotg; - unsigned long flags; - -@@ -1491,6 +1493,7 @@ static void dwc2_wait_timer_fn(struct timer_list *t) - } - - spin_unlock_irqrestore(&hsotg->lock, flags); -+ return HRTIMER_NORESTART; - } - - /** -@@ -1521,7 +1524,8 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, - /* Initialize QH */ - qh->hsotg = hsotg; - timer_setup(&qh->unreserve_timer, dwc2_unreserve_timer_fn, 0); -- timer_setup(&qh->wait_timer, dwc2_wait_timer_fn, 0); -+ hrtimer_init(&qh->wait_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); -+ qh->wait_timer.function = &dwc2_wait_timer_fn; - qh->ep_type = ep_type; - qh->ep_is_in = ep_is_in; - -@@ -1690,7 +1694,7 @@ void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) - * won't do anything anyway, but we want it to finish before we free - * memory. - */ -- del_timer_sync(&qh->wait_timer); -+ hrtimer_cancel(&qh->wait_timer); - - dwc2_host_put_tt_info(hsotg, qh->dwc_tt); - -@@ -1716,6 +1720,7 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) - { - int status; - u32 intr_mask; -+ ktime_t delay; - - if (dbg_qh(qh)) - dev_vdbg(hsotg->dev, "%s()\n", __func__); -@@ -1734,8 +1739,8 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) - list_add_tail(&qh->qh_list_entry, - &hsotg->non_periodic_sched_waiting); - qh->wait_timer_cancel = false; -- mod_timer(&qh->wait_timer, -- jiffies + DWC2_RETRY_WAIT_DELAY + 1); -+ delay = ktime_set(0, DWC2_RETRY_WAIT_DELAY); -+ hrtimer_start(&qh->wait_timer, delay, HRTIMER_MODE_REL); - } else { - list_add_tail(&qh->qh_list_entry, - &hsotg->non_periodic_sched_inactive); -diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h -index 31f8c60..4980ecb 100644 ---- a/drivers/usb/dwc2/hw.h -+++ b/drivers/usb/dwc2/hw.h -@@ -316,6 +316,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 -@@ -336,6 +337,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) -@@ -408,6 +411,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 */ - -@@ -447,6 +463,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 7fef905..bdcabb1 100644 ---- a/drivers/usb/dwc2/params.c -+++ b/drivers/usb/dwc2/params.c -@@ -71,6 +71,13 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) - p->power_down = false; - } - -+static void dwc2_set_s3c6400_params(struct dwc2_hsotg *hsotg) -+{ -+ struct dwc2_core_params *p = &hsotg->params; -+ -+ p->power_down = 0; -+} -+ - static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) - { - struct dwc2_core_params *p = &hsotg->params; -@@ -81,6 +88,7 @@ static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) - p->host_perio_tx_fifo_size = 256; - p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << - GAHBCFG_HBSTLEN_SHIFT; -+ p->power_down = 0; - } - - static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) -@@ -110,6 +118,7 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) - p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; - p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 << - GAHBCFG_HBSTLEN_SHIFT; -+ p->power_down = DWC2_POWER_DOWN_PARAM_NONE; - } - - static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) -@@ -177,7 +186,8 @@ const struct of_device_id dwc2_of_match_table[] = { - { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params }, - { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params }, - { .compatible = "snps,dwc2" }, -- { .compatible = "samsung,s3c6400-hsotg" }, -+ { .compatible = "samsung,s3c6400-hsotg", -+ .data = dwc2_set_s3c6400_params }, - { .compatible = "amlogic,meson8-usb", - .data = dwc2_set_amlogic_params }, - { .compatible = "amlogic,meson8b-usb", -@@ -330,9 +340,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)) { -@@ -628,6 +641,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); -@@ -816,6 +830,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) >> --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0060-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0060-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DEVICETREE.patch deleted file mode 100644 index 5411f00..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0060-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DEVICETREE.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 56b9c52ec61df693bd997e3ef1465230a6cb1834 Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Thu, 24 Jan 2019 10:52:11 +0100 -Subject: [PATCH 60/60] ARM stm32mp1 r0 rc4 hotfix w904.3 DEVICETREE - ---- - arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 43 +++++++++++++++++++++++++++++++ - arch/arm/boot/dts/stm32mp157a-dk1.dts | 2 +- - arch/arm/boot/dts/stm32mp157c-dk2.dts | 4 +-- - arch/arm/boot/dts/stm32mp157c-ed1.dts | 2 +- - arch/arm/boot/dts/stm32mp157c.dtsi | 22 +++++++--------- - 5 files changed, 57 insertions(+), 16 deletions(-) - -diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -index 474e7e3..6e4e5c9 100644 ---- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -+++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi -@@ -1249,6 +1249,49 @@ - }; - }; - -+ sdmmc2_b4_pins_b: sdmmc2-b4-1 { -+ pins1 { -+ pinmux = , /* SDMMC2_D0 */ -+ , /* SDMMC2_D1 */ -+ , /* SDMMC2_D2 */ -+ , /* SDMMC2_D3 */ -+ ; /* SDMMC2_CMD */ -+ slew-rate = <1>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ pins2 { -+ pinmux = ; /* SDMMC2_CK */ -+ slew-rate = <2>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ }; -+ -+ sdmmc2_b4_od_pins_b: sdmmc2-b4-od-1 { -+ pins1 { -+ pinmux = , /* SDMMC2_D0 */ -+ , /* SDMMC2_D1 */ -+ , /* SDMMC2_D2 */ -+ ; /* SDMMC2_D3 */ -+ slew-rate = <1>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ pins2 { -+ pinmux = ; /* SDMMC2_CK */ -+ slew-rate = <2>; -+ drive-push-pull; -+ bias-disable; -+ }; -+ pins3 { -+ pinmux = ; /* SDMMC2_CMD */ -+ slew-rate = <1>; -+ drive-open-drain; -+ bias-disable; -+ }; -+ }; -+ - sdmmc2_d47_pins_a: sdmmc2-d47-0 { - pins { - pinmux = , /* SDMMC2_D4 */ -diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -index 467c226..e3a36d3 100644 ---- a/arch/arm/boot/dts/stm32mp157a-dk1.dts -+++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -325,7 +325,7 @@ - - vddcore: buck1 { - regulator-name = "vddcore"; -- regulator-min-microvolt = <800000>; -+ regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1350000>; - regulator-always-on; - regulator-initial-mode = <0>; -diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -index 4da15cd..20a86f1 100644 ---- a/arch/arm/boot/dts/stm32mp157c-dk2.dts -+++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -108,8 +108,8 @@ - &sdmmc2 { - arm,primecell-periphid = <0x10153180>; - pinctrl-names = "default", "opendrain", "sleep"; -- pinctrl-0 = <&sdmmc2_b4_pins_a>; -- pinctrl-1 = <&sdmmc2_b4_od_pins_a>; -+ pinctrl-0 = <&sdmmc2_b4_pins_b>; -+ pinctrl-1 = <&sdmmc2_b4_od_pins_b>; - pinctrl-2 = <&sdmmc2_b4_sleep_pins_a>; - non-removable; - st,neg-edge; -diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index 6d49f21..780c992 100644 ---- a/arch/arm/boot/dts/stm32mp157c-ed1.dts -+++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts -@@ -203,7 +203,7 @@ - - vddcore: buck1 { - regulator-name = "vddcore"; -- regulator-min-microvolt = <800000>; -+ regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1350000>; - regulator-always-on; - regulator-initial-mode = <0>; -diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index b09ef8b..694e6e0 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -430,8 +430,8 @@ - interrupts = ; - clocks = <&rcc SPI2_K>; - resets = <&rcc SPI2_R>; -- dmas = <&dmamux1 39 0x400 0x05>, -- <&dmamux1 40 0x400 0x05>; -+ dmas = <&dmamux1 39 0x400 0x01>, -+ <&dmamux1 40 0x400 0x01>; - dma-names = "rx", "tx"; - power-domains = <&pd_core>; - status = "disabled"; -@@ -456,8 +456,8 @@ - interrupts = ; - clocks = <&rcc SPI3_K>; - resets = <&rcc SPI3_R>; -- dmas = <&dmamux1 61 0x400 0x05>, -- <&dmamux1 62 0x400 0x05>; -+ dmas = <&dmamux1 61 0x400 0x01>, -+ <&dmamux1 62 0x400 0x01>; - dma-names = "rx", "tx"; - power-domains = <&pd_core>; - status = "disabled"; -@@ -756,8 +756,8 @@ - interrupts = ; - clocks = <&rcc SPI1_K>; - resets = <&rcc SPI1_R>; -- dmas = <&dmamux1 37 0x400 0x05>, -- <&dmamux1 38 0x400 0x05>; -+ dmas = <&dmamux1 37 0x400 0x01>, -+ <&dmamux1 38 0x400 0x01>; - dma-names = "rx", "tx"; - power-domains = <&pd_core>; - status = "disabled"; -@@ -782,8 +782,8 @@ - interrupts = ; - clocks = <&rcc SPI4_K>; - resets = <&rcc SPI4_R>; -- dmas = <&dmamux1 83 0x400 0x05>, -- <&dmamux1 84 0x400 0x05>; -+ dmas = <&dmamux1 83 0x400 0x01>, -+ <&dmamux1 84 0x400 0x01>; - dma-names = "rx", "tx"; - power-domains = <&pd_core>; - status = "disabled"; -@@ -870,8 +870,8 @@ - interrupts = ; - clocks = <&rcc SPI5_K>; - resets = <&rcc SPI5_R>; -- dmas = <&dmamux1 85 0x400 0x05>, -- <&dmamux1 86 0x400 0x05>; -+ dmas = <&dmamux1 85 0x400 0x01>, -+ <&dmamux1 86 0x400 0x01>; - dma-names = "rx", "tx"; - power-domains = <&pd_core>; - status = "disabled"; -@@ -1770,7 +1770,6 @@ - clocks = <&rcc USBH>; - resets = <&rcc USBH_R>; - interrupts = ; -- power-domains = <&pd_core>; - status = "disabled"; - }; - -@@ -1781,7 +1780,6 @@ - resets = <&rcc USBH_R>; - interrupts = ; - companion = <&usbh_ohci>; -- power-domains = <&pd_core>; - status = "disabled"; - }; - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0061-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DRIVERS.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0061-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DRIVERS.patch deleted file mode 100644 index 3c843b6..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0061-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DRIVERS.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 5f558583046192d07b1718d6db15cef522fa0bce Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Mon, 28 Jan 2019 10:49:20 +0100 -Subject: [PATCH 61/62] ARM stm32mp1 r0 rc4 hotfix w904.5 DRIVERS - ---- - drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 38 ++++++++++++++---------- - drivers/usb/dwc2/platform.c | 13 ++++++-- - 2 files changed, 33 insertions(+), 18 deletions(-) - -diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -index ee7486b..78a7e62 100644 ---- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -+++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -@@ -284,7 +284,9 @@ static int otm8009a_unprepare(struct drm_panel *panel) - if (ret) - return ret; - -- msleep(120); -+ msleep(10); -+ -+ regulator_disable(ctx->supply); - - ctx->prepared = false; - -@@ -299,6 +301,26 @@ 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); -+ } -+ -+ msleep(20); -+ -+ ret = regulator_enable(ctx->supply); -+ if (ret < 0) { -+ DRM_ERROR("failed to enable supply: %d\n", ret); -+ return ret; -+ } -+ -+ msleep(120); -+ -+ if (ctx->reset_gpio) { -+ gpiod_set_value_cansleep(ctx->reset_gpio, 0); -+ msleep(20); -+ } -+ - ret = otm8009a_init_sequence(ctx); - if (ret) - return ret; -@@ -456,20 +478,6 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) - return ret; - } - -- ret = regulator_enable(ctx->supply); -- if (ret < 0) { -- DRM_ERROR("failed to enable supply: %d\n", ret); -- return ret; -- } -- -- 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); -- } -- - return 0; - } - -diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index b2e5ddc..b80d046 100644 ---- a/drivers/usb/dwc2/platform.c -+++ b/drivers/usb/dwc2/platform.c -@@ -568,13 +568,17 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); - int ret = 0; - -- if (dwc2_is_device_mode(dwc2)) -- dwc2_hsotg_suspend(dwc2); -- - if (dwc2->params.activate_stm_id_vb_detection && - !dwc2->params.force_b_session_valid) { - u32 ggpio; - -+ /* -+ * Need to force the mode to the current mode to avoid Mode -+ * Mismatch Interrupt when ID and VBUS detection will be -+ * disabled -+ */ -+ dwc2_force_mode(dwc2, dwc2_is_host_mode(dwc2)); -+ - ggpio = dwc2_readl(dwc2, GGPIO); - ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; - ggpio &= ~GGPIO_STM32_OTG_GCCFG_VBDEN; -@@ -583,6 +587,9 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - regulator_disable(dwc2->usb33d); - } - -+ if (dwc2_is_device_mode(dwc2)) -+ dwc2_hsotg_suspend(dwc2); -+ - if (dwc2->ll_hw_enabled) - ret = __dwc2_lowlevel_hw_disable(dwc2); - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0062-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0062-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DEVICETREE.patch deleted file mode 100644 index b830f15..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0062-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DEVICETREE.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 771fc61468f4af9f733beb9dbe070033ea2b826a Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Mon, 28 Jan 2019 10:49:58 +0100 -Subject: [PATCH 62/62] ARM stm32mp1 r0 rc4 hotfix w904.5 DEVICETREE - ---- - arch/arm/boot/dts/stm32mp157c.dtsi | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index 694e6e0..9647119 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -1233,7 +1233,6 @@ - g-tx-fifo-size = <128 128 64 64 64 64 32 32>; - dr_mode = "otg"; - usb33d-supply = <&usb33>; -- power-domains = <&pd_core>; - status = "disabled"; - }; - --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0063-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DRIVERS.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0063-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DRIVERS.patch deleted file mode 100644 index 3a5cc8c..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0063-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DRIVERS.patch +++ /dev/null @@ -1,188 +0,0 @@ -From 67b204258838dd2c940d5b1508318b4890324a06 Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Tue, 29 Jan 2019 17:31:19 +0100 -Subject: [PATCH 63/64] ARM stm32mp1 r0 rc4 hotfix w905.2 DRIVERS - ---- - drivers/dma/stm32-dma.c | 70 ++++++++++++++++++++++++++++++++++++--------- - drivers/usb/dwc2/platform.c | 38 ++++++++++++++++++------ - 2 files changed, 87 insertions(+), 21 deletions(-) - -diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 5abfa4f..dc3ba91 100644 ---- a/drivers/dma/stm32-dma.c -+++ b/drivers/dma/stm32-dma.c -@@ -1675,37 +1675,81 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( - return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); - } - -+static bool stm32_dma_is_current_sg(struct stm32_dma_chan *chan) -+{ -+ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -+ struct stm32_dma_sg_req *sg_req; -+ u32 dma_scr, dma_smar, id; -+ -+ id = chan->id; -+ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); -+ -+ 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, - struct stm32_dma_desc *desc, - 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]; - 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; -+ 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 - */ -- for (i = next_sg; i < desc->num_sgs; i++) -- residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req); -- residue += stm32_dma_get_remaining_bytes(chan); -+ if (!chan->desc->cyclic || n_sg != 0) -+ for (i = n_sg; i < desc->num_sgs; i++) -+ residue += sg_dma_len(&desc->sg_req[i].stm32_sgl_req); - --end: - if (!chan->mem_burst) - return residue; - -diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index b80d046..7e6960c 100644 ---- a/drivers/usb/dwc2/platform.c -+++ b/drivers/usb/dwc2/platform.c -@@ -568,16 +568,35 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); - int ret = 0; - -+ if (dwc2_is_device_mode(dwc2)) -+ dwc2_hsotg_suspend(dwc2); -+ - if (dwc2->params.activate_stm_id_vb_detection && - !dwc2->params.force_b_session_valid) { -- u32 ggpio; -+ 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 and VBUS detection will be -- * disabled -+ * Mismatch Interrupt when ID detection will be disabled. - */ -- dwc2_force_mode(dwc2, dwc2_is_host_mode(dwc2)); -+ dwc2_force_mode(dwc2, is_host); -+ -+ if (!is_host) { -+ gotgctl = dwc2_readl(dwc2, GOTGCTL); -+ /* -+ * We're about to disable Vbus detection hw before low -+ * power mode entry. Then an undesired disconnect -+ * interrupt may occur which is racy with low power -+ * (low-level hw disable). Then check valid session -+ * to force B-peripheral session value. -+ */ -+ if (gotgctl & GOTGCTL_BSESVLD) { -+ gotgctl |= GOTGCTL_BVALOVAL; -+ gotgctl |= GOTGCTL_BVALOEN; -+ dwc2_writel(dwc2, gotgctl, GOTGCTL); -+ } -+ } - - ggpio = dwc2_readl(dwc2, GGPIO); - ggpio &= ~GGPIO_STM32_OTG_GCCFG_IDEN; -@@ -587,9 +606,6 @@ static int __maybe_unused dwc2_suspend(struct device *dev) - regulator_disable(dwc2->usb33d); - } - -- if (dwc2_is_device_mode(dwc2)) -- dwc2_hsotg_suspend(dwc2); -- - if (dwc2->ll_hw_enabled) - ret = __dwc2_lowlevel_hw_disable(dwc2); - -@@ -612,7 +628,7 @@ static int __maybe_unused dwc2_resume(struct device *dev) - - if (dwc2->params.activate_stm_id_vb_detection && - !dwc2->params.force_b_session_valid) { -- u32 ggpio; -+ u32 ggpio, gotgctl; - - ret = regulator_enable(dwc2->usb33d); - if (ret) -@@ -625,6 +641,12 @@ static int __maybe_unused dwc2_resume(struct device *dev) - - /* ID/VBUS detection startup time */ - usleep_range(5000, 7000); -+ -+ /* Unconditionally clear B-Session Valid override */ -+ gotgctl = dwc2_readl(dwc2, GOTGCTL); -+ gotgctl &= ~GOTGCTL_BVALOVAL; -+ gotgctl &= ~GOTGCTL_BVALOEN; -+ dwc2_writel(dwc2, gotgctl, GOTGCTL); - } - - if (dwc2->params.force_b_session_valid) { --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0064-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0064-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DEVICETREE.patch deleted file mode 100644 index c3d2916..0000000 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.9/0064-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DEVICETREE.patch +++ /dev/null @@ -1,24 +0,0 @@ -From cad13a8b78d8d320394dbed545df8e47c199bbd1 Mon Sep 17 00:00:00 2001 -From: christophe montaud -Date: Tue, 29 Jan 2019 17:31:53 +0100 -Subject: [PATCH 64/64] ARM stm32mp1 r0 rc4 hotfix w905.2 DEVICETREE - ---- - arch/arm/boot/dts/stm32mp157c.dtsi | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index 9647119..5581a1c 100644 ---- a/arch/arm/boot/dts/stm32mp157c.dtsi -+++ b/arch/arm/boot/dts/stm32mp157c.dtsi -@@ -58,6 +58,7 @@ - , - ; - interrupt-parent = <&intc>; -+ always-on; - }; - - clocks { --- -2.7.4 - diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-systemd.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-systemd.config index f17c66e..a61801f 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-systemd.config +++ b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-03-systemd.config @@ -92,7 +92,7 @@ CONFIG_INET_XFRM_MODE_TUNNEL=m CONFIG_INET_XFRM_MODE_BEET=m CONFIG_INET_DIAG=m CONFIG_INET_UDP_DIAG=m -CONFIG_INET_RAW_DIAG=mCONFIG_BPF_SYSCALL=y +CONFIG_INET_RAW_DIAG=m CONFIG_INET_DIAG_DESTROY=y CONFIG_TCP_CONG_ADVANCED=y CONFIG_TCP_MD5SIG=y @@ -127,7 +127,7 @@ CONFIG_NF_CONNTRACK_SNMP=m CONFIG_NF_CONNTRACK_PPTP=m CONFIG_NF_CONNTRACK_SIP=m CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NF_CT_NETLINK=mCONFIG_BPF_SYSCALL=y +CONFIG_NF_CT_NETLINK=m CONFIG_NF_CT_NETLINK_TIMEOUT=m CONFIG_NF_CT_NETLINK_HELPER=m CONFIG_NETFILTER_NETLINK_GLUE_CT=y diff --git a/recipes-kernel/linux/linux-stm32mp_4.19.bb b/recipes-kernel/linux/linux-stm32mp_4.19.bb index 06af78e..f10c6e4 100644 --- a/recipes-kernel/linux/linux-stm32mp_4.19.bb +++ b/recipes-kernel/linux/linux-stm32mp_4.19.bb @@ -5,87 +5,48 @@ 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.9.tar.xz" -SRC_URI[md5sum] = "d7e09d6be85ec8548c73e8713531e958" -SRC_URI[sha256sum] = "fc116cc6829c73944215d3b3ac0fc368dde9e8235b456744afffde001269dbf2" +SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.49.tar.xz" +SRC_URI[md5sum] = "0cb9baf0f5ed8f56d42cccc508d841b0" +SRC_URI[sha256sum] = "92d920b3973c0dbca5516271afa405be6e5822a9b831df8c085f9c9eb838bbcd" SRC_URI += " \ - file://${LINUX_VERSION}/4.19.9/0001-ARM-stm32mp1-r0-rc1-MACHINE.patch \ - file://${LINUX_VERSION}/4.19.9/0002-ARM-stm32mp1-r0-rc1-CLOCK.patch \ - file://${LINUX_VERSION}/4.19.9/0003-ARM-stm32mp1-r0-rc1-DMA.patch \ - file://${LINUX_VERSION}/4.19.9/0004-ARM-stm32mp1-r0-rc1-I2C.patch \ - file://${LINUX_VERSION}/4.19.9/0005-ARM-stm32mp1-r0-rc1-IIO.patch \ - file://${LINUX_VERSION}/4.19.9/0006-ARM-stm32mp1-r0-rc1-IRQ-Mailbox.patch \ - file://${LINUX_VERSION}/4.19.9/0007-ARM-stm32mp1-r0-rc1-INPUT-TTY.patch \ - file://${LINUX_VERSION}/4.19.9/0008-ARM-stm32mp1-r0-rc1-MFD.patch \ - file://${LINUX_VERSION}/4.19.9/0009-ARM-stm32mp1-r0-rc1-MMC-MTD.patch \ - file://${LINUX_VERSION}/4.19.9/0010-ARM-stm32mp1-r0-rc1-ETH.patch \ - file://${LINUX_VERSION}/4.19.9/0011-ARM-stm32mp1-r0-rc1-NVMEM.patch \ - file://${LINUX_VERSION}/4.19.9/0012-ARM-stm32mp1-r0-rc1-PINCTRL-PWM-RESET-RTC.patch \ - file://${LINUX_VERSION}/4.19.9/0013-ARM-stm32mp1-r0-rc1-REMOTEPROC-RPMSG.patch \ - file://${LINUX_VERSION}/4.19.9/0014-ARM-stm32mp1-r0-rc1-WATCHDOG.patch \ - file://${LINUX_VERSION}/4.19.9/0015-ARM-stm32mp1-r0-rc1-MISC.patch \ - file://${LINUX_VERSION}/4.19.9/0016-ARM-stm32mp1-r0-rc1-DEVICETREE.patch \ - file://${LINUX_VERSION}/4.19.9/0017-ARM-stm32mp1-r0-rc1-DEFCONFIG.patch \ - file://${LINUX_VERSION}/4.19.9/0018-ARM-stm32mp1-r0-rc2-DRM-KMS.patch \ - file://${LINUX_VERSION}/4.19.9/0019-ARM-stm32mp1-r0-rc2-SOUND.patch \ - file://${LINUX_VERSION}/4.19.9/0020-ARM-stm32mp1-r0-rc2-MEDIA.patch \ - file://${LINUX_VERSION}/4.19.9/0021-ARM-stm32mp1-r0-rc2-PINCTRL.patch \ - file://${LINUX_VERSION}/4.19.9/0022-ARM-stm32mp1-r0-rc2-MFD-IRQ.patch \ - file://${LINUX_VERSION}/4.19.9/0023-ARM-stm32mp1-r0-rc2-USB.patch \ - file://${LINUX_VERSION}/4.19.9/0024-ARM-stm32mp1-r0-rc2-THERMAL.patch \ - file://${LINUX_VERSION}/4.19.9/0025-ARM-stm32mp1-r0-rc2-REMOTEPROC.patch \ - file://${LINUX_VERSION}/4.19.9/0026-ARM-stm32mp1-r0-rc2-NET.patch \ - file://${LINUX_VERSION}/4.19.9/0027-ARM-stm32mp1-r0-rc2-HWCLK-SPI.patch \ - file://${LINUX_VERSION}/4.19.9/0028-ARM-stm32mp1-r0-rc2-MMC.patch \ - file://${LINUX_VERSION}/4.19.9/0029-ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C.patch \ - file://${LINUX_VERSION}/4.19.9/0030-ARM-stm32mp1-r0-rc2-DEVICETREE.patch \ - file://${LINUX_VERSION}/4.19.9/0031-ARM-stm32mp1-r0-rc2-DEFCONFIG.patch \ - file://${LINUX_VERSION}/4.19.9/0032-ARM-stm32mp1-r0-rc3-DMA.patch \ - file://${LINUX_VERSION}/4.19.9/0033-ARM-stm32mp1-r0-rc3-DISPLAY.patch \ - file://${LINUX_VERSION}/4.19.9/0034-ARM-stm32mp1-r0-rc3-ETH.patch \ - file://${LINUX_VERSION}/4.19.9/0035-ARM-stm32mp1-r0-rc3-IIO.patch \ - file://${LINUX_VERSION}/4.19.9/0036-ARM-stm32mp1-r0-rc3-INPUT-TTY.patch \ - file://${LINUX_VERSION}/4.19.9/0037-ARM-stm32mp1-r0-rc3-IRQ-Mailbox.patch \ - file://${LINUX_VERSION}/4.19.9/0038-ARM-stm32mp1-r0-rc3-MEDIA.patch \ - file://${LINUX_VERSION}/4.19.9/0039-ARM-stm32mp1-r0-rc3-MMC-MTD.patch \ - file://${LINUX_VERSION}/4.19.9/0040-ARM-stm32mp1-r0-rc3-PINCTRL-PWM-RESET-RTC.patch \ - file://${LINUX_VERSION}/4.19.9/0041-ARM-stm32mp1-r0-rc3-REMOTEPROC-RPMSG.patch \ - file://${LINUX_VERSION}/4.19.9/0042-ARM-stm32mp1-r0-rc3-SOUND.patch \ - file://${LINUX_VERSION}/4.19.9/0043-ARM-stm32mp1-r0-rc3-MISC.patch \ - file://${LINUX_VERSION}/4.19.9/0044-ARM-stm32mp1-r0-rc3-DEVICETREE.patch \ - file://${LINUX_VERSION}/4.19.9/0045-ARM-stm32mp1-r0-rc3-DEFCONFIG.patch \ - file://${LINUX_VERSION}/4.19.9/0046-ARM-stm32mp1-r0-rc4-MMC-MTD.patch \ - file://${LINUX_VERSION}/4.19.9/0047-ARM-stm32mp1-r0-rc4-PINCTRL-PWM-RESET-RTC.patch \ - file://${LINUX_VERSION}/4.19.9/0048-ARM-stm32mp1-r0-rc4-REMOTEPROC-RPMSG.patch \ - file://${LINUX_VERSION}/4.19.9/0049-ARM-stm32mp1-r0-rc4-SOUND.patch \ - file://${LINUX_VERSION}/4.19.9/0050-ARM-stm32mp1-r0-rc4-USB.patch \ - file://${LINUX_VERSION}/4.19.9/0051-ARM-stm32mp1-r0-rc4-DEVICETREE.patch \ - file://${LINUX_VERSION}/4.19.9/0052-ARM-stm32mp1-r0-rc4-DEFCONFIG.patch \ - \ - file://${LINUX_VERSION}/4.19.9/0053-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DRIVERS.patch \ - file://${LINUX_VERSION}/4.19.9/0054-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEVICETREE.patch \ - file://${LINUX_VERSION}/4.19.9/0055-ARM-stm32mp1-r0-rc4-hotfix-w903.1-DEFCONFIG.patch \ - \ - file://${LINUX_VERSION}/4.19.9/0056-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DRIVERS.patch \ - file://${LINUX_VERSION}/4.19.9/0057-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEVICETREE.patch \ - file://${LINUX_VERSION}/4.19.9/0058-ARM-stm32mp1-r0-rc4-hotfix-w903.3-DEFCONFIG.patch \ - \ - file://${LINUX_VERSION}/4.19.9/0059-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DRIVERS.patch \ - file://${LINUX_VERSION}/4.19.9/0060-ARM-stm32mp1-r0-rc4-hotfix-w904.3-DEVICETREE.patch \ - \ - file://${LINUX_VERSION}/4.19.9/0061-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DRIVERS.patch \ - file://${LINUX_VERSION}/4.19.9/0062-ARM-stm32mp1-r0-rc4-hotfix-w904.5-DEVICETREE.patch \ - \ - file://${LINUX_VERSION}/4.19.9/0063-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DRIVERS.patch \ - file://${LINUX_VERSION}/4.19.9/0064-ARM-stm32mp1-r0-rc4-hotfix-w905.2-DEVICETREE.patch \ + file://${LINUX_VERSION}/4.19.49/0001-ARM-stm32mp1-r2-MACHINE.patch \ + file://${LINUX_VERSION}/4.19.49/0002-ARM-stm32mp1-r2-CRYPTO.patch \ + file://${LINUX_VERSION}/4.19.49/0003-ARM-stm32mp1-r2-BLUETOOTH-CHAR.patch \ + file://${LINUX_VERSION}/4.19.49/0004-ARM-stm32mp1-r2-CLOCK.patch \ + file://${LINUX_VERSION}/4.19.49/0005-ARM-stm32mp1-r2-DMA.patch \ + file://${LINUX_VERSION}/4.19.49/0006-ARM-stm32mp1-r2-DRM.patch \ + file://${LINUX_VERSION}/4.19.49/0007-ARM-stm32mp1-r2-GPIO.patch \ + file://${LINUX_VERSION}/4.19.49/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch \ + file://${LINUX_VERSION}/4.19.49/0009-ARM-stm32mp1-r2-HWTRACING-I2C.patch \ + file://${LINUX_VERSION}/4.19.49/0010-ARM-stm32mp1-r2-IIO.patch \ + file://${LINUX_VERSION}/4.19.49/0011-ARM-stm32mp1-r2-INPUT-IRQ-Mailbox.patch \ + file://${LINUX_VERSION}/4.19.49/0012-ARM-stm32mp1-r2-MEDIA.patch \ + file://${LINUX_VERSION}/4.19.49/0013-ARM-stm32mp1-r2-MFD.patch \ + file://${LINUX_VERSION}/4.19.49/0014-ARM-stm32mp1-r2-MMC-MTD.patch \ + file://${LINUX_VERSION}/4.19.49/0015-ARM-stm32mp1-r2-NET.patch \ + file://${LINUX_VERSION}/4.19.49/0016-ARM-stm32mp1-r2-NVMEM.patch \ + file://${LINUX_VERSION}/4.19.49/0017-ARM-stm32mp1-r2-PERF.patch \ + file://${LINUX_VERSION}/4.19.49/0018-ARM-stm32mp1-r2-PHY-PINCTRL-PWM.patch \ + file://${LINUX_VERSION}/4.19.49/0019-ARM-stm32mp1-r2-REGULATOR.patch \ + file://${LINUX_VERSION}/4.19.49/0020-ARM-stm32mp1-r2-REMOTEPROC-RPMSG-RESET.patch \ + file://${LINUX_VERSION}/4.19.49/0021-ARM-stm32mp1-r2-RTC.patch \ + file://${LINUX_VERSION}/4.19.49/0022-ARM-stm32mp1-r2-SOC.patch \ + file://${LINUX_VERSION}/4.19.49/0023-ARM-stm32mp1-r2-SPI.patch \ + file://${LINUX_VERSION}/4.19.49/0024-ARM-stm32mp1-r2-THERMAL.patch \ + file://${LINUX_VERSION}/4.19.49/0025-ARM-stm32mp1-r2-TTY-USB.patch \ + file://${LINUX_VERSION}/4.19.49/0026-ARM-stm32mp1-r2-WATCHDOG.patch \ + file://${LINUX_VERSION}/4.19.49/0027-ARM-stm32mp1-r2-SOUND.patch \ + file://${LINUX_VERSION}/4.19.49/0028-ARM-stm32mp1-r2-MISC.patch \ + file://${LINUX_VERSION}/4.19.49/0029-ARM-stm32mp1-r2-DEVICETREE.patch \ + file://${LINUX_VERSION}/4.19.49/0030-ARM-stm32mp1-r2-DEFCONFIG.patch \ " LINUX_VERSION = "4.19" PV = "${LINUX_VERSION}" -S = "${WORKDIR}/linux-4.19.9" +S = "${WORKDIR}/linux-4.19.49" # --------------------------------- # Configure devupstream class usage @@ -93,7 +54,7 @@ S = "${WORKDIR}/linux-4.19.9" 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_class-devupstream = "9cc80ff80f5ea5f1ff35122f61afaa7b11ad22ae" SRCREV_FORMAT_class-devupstream = "linux" PV_class-devupstream = "${LINUX_VERSION}+github+${SRCPV}" @@ -104,6 +65,11 @@ 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 # @@ -126,12 +92,3 @@ SRC_URI_class-devupstream += " file://4.19/fragment-05-modules.config;subdir=fra # Kernel Args # KERNEL_EXTRA_ARGS += "LOADADDR=${ST_KERNEL_LOADADDR}" - -# ------------------------------------------------------------- -# Archiver -# -inherit archiver -ARCHIVER_MODE[src] = "${@'original' if d.getVar('ST_ARCHIVER_ENABLE') == '1' else ''}" -SRC_URI =+ "file://README.HOW_TO.txt" - -inherit archiver_stm32mp_clean