diff --git a/recipes-kernel/linux/linux-stm32mp.inc b/recipes-kernel/linux/linux-stm32mp.inc index 195d76f..a920819 100644 --- a/recipes-kernel/linux/linux-stm32mp.inc +++ b/recipes-kernel/linux/linux-stm32mp.inc @@ -4,9 +4,9 @@ inherit kernel DEPENDS += "openssl-native util-linux-native" -B = "${WORKDIR}/linux-${MACHINE}-standard-build" +B = "${WORKDIR}/build" # Configure build dir for externalsrc class usage through devtool -EXTERNALSRC_BUILD_pn-${PN} = "${WORKDIR}/linux-${MACHINE}-standard-build" +EXTERNALSRC_BUILD_pn-${PN} = "${WORKDIR}/build" # To share config fragments between layers FILESEXTRAPATHS_prepend := "${THISDIR}:" 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.94/0001-ARM-stm32mp1-r3-MACHINE.patch similarity index 93% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0001-ARM-stm32mp1-r2-MACHINE.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch index ed3f1f0..2177a44 100644 --- 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.94/0001-ARM-stm32mp1-r3-MACHINE.patch @@ -1,7 +1,7 @@ -From 747a93a65dc5e3761539c365a272186f0b7fca08 Mon Sep 17 00:00:00 2001 +From 72d1b59c3ca272dd153ebd350ef9e403dac3db59 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 +Date: Fri, 8 Nov 2019 16:52:38 +0100 +Subject: [PATCH 01/31] ARM stm32mp1 r3 MACHINE --- arch/arm/mach-integrator/integrator_cp.c | 2 -- diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch new file mode 100644 index 0000000..b27de52 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch @@ -0,0 +1,163 @@ +From 704a13efcc696fa4d151b741e0882f4c42eef870 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Thu, 30 Jan 2020 15:28:05 +0100 +Subject: [PATCH 02/31] ARM stm32mp1 r3 CPUFREQ + +--- + drivers/cpufreq/Kconfig.arm | 7 +++ + drivers/cpufreq/Makefile | 1 + + drivers/cpufreq/cpufreq-dt-platdev.c | 1 + + drivers/cpufreq/stm32-cpufreq.c | 99 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 108 insertions(+) + create mode 100644 drivers/cpufreq/stm32-cpufreq.c + +diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm +index 0cd8eb7..b950d5a 100644 +--- a/drivers/cpufreq/Kconfig.arm ++++ b/drivers/cpufreq/Kconfig.arm +@@ -255,6 +255,13 @@ config ARM_STI_CPUFREQ + this config option if you wish to add CPUFreq support for STi based + SoCs. + ++config ARM_STM32_CPUFREQ ++ tristate "STM32 CPUFreq support" ++ depends on MACH_STM32MP157 ++ default y ++ help ++ This adds the CPUFreq driver support for STM32 MPU SOCs. ++ + config ARM_TANGO_CPUFREQ + bool + depends on CPUFREQ_DT && ARCH_TANGO +diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile +index c1ffeab..c15b4f7 100644 +--- a/drivers/cpufreq/Makefile ++++ b/drivers/cpufreq/Makefile +@@ -79,6 +79,7 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o + obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o + obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o + obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o ++obj-$(CONFIG_ARM_STM32_CPUFREQ) += stm32-cpufreq.o + obj-$(CONFIG_ARM_TANGO_CPUFREQ) += tango-cpufreq.o + obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o + obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o +diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c +index fe14c57..d61a02a 100644 +--- a/drivers/cpufreq/cpufreq-dt-platdev.c ++++ b/drivers/cpufreq/cpufreq-dt-platdev.c +@@ -121,6 +121,7 @@ static const struct of_device_id blacklist[] __initconst = { + + { .compatible = "st,stih407", }, + { .compatible = "st,stih410", }, ++ { .compatible = "st,stm32mp157", }, + + { .compatible = "sigma,tango4", }, + +diff --git a/drivers/cpufreq/stm32-cpufreq.c b/drivers/cpufreq/stm32-cpufreq.c +new file mode 100644 +index 0000000..f4a41e0 +--- /dev/null ++++ b/drivers/cpufreq/stm32-cpufreq.c +@@ -0,0 +1,99 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Authors: Alexandre Torgue for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct stm32_cpufreq_priv { ++ struct opp_table *opps; ++ struct platform_device *cpufreq_dt_pdev; ++}; ++ ++static int stm32_cpufreq_probe(struct platform_device *pdev) ++{ ++ struct stm32_cpufreq_priv *priv; ++ struct device_node *opp_node; ++ struct device *cpu_dev; ++ u8 part_number; ++ u32 supported_hw; ++ int ret; ++ ++ cpu_dev = get_cpu_device(0); ++ if (!cpu_dev) { ++ dev_err(&pdev->dev, "failed to get cpu0 device\n"); ++ return -ENODEV; ++ } ++ opp_node = dev_pm_opp_of_get_opp_desc_node(cpu_dev); ++ if (!opp_node) { ++ dev_err(&pdev->dev, "OPP-v2 not supported\n"); ++ return -ENODEV; ++ } ++ ++ /* Get chip info */ ++ ret = nvmem_cell_read_u8(cpu_dev, "part_number", &part_number); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to get chip info: %d\n", ret); ++ return ret; ++ } ++ ++ supported_hw = BIT((part_number & 0x80) >> 7); ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->opps = dev_pm_opp_set_supported_hw(cpu_dev, &supported_hw, 1); ++ if (IS_ERR(priv->opps)) { ++ ret = PTR_ERR(priv->opps); ++ dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret); ++ return ret; ++ } ++ ++ of_node_put(opp_node); ++ priv->cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", ++ -1, NULL, 0); ++ ++ platform_set_drvdata(pdev, priv); ++ ++ return 0; ++} ++ ++static int stm32_cpufreq_remove(struct platform_device *pdev) ++{ ++ struct stm32_cpufreq_priv *priv = platform_get_drvdata(pdev); ++ ++ platform_device_unregister(priv->cpufreq_dt_pdev); ++ dev_pm_opp_put_supported_hw(priv->opps); ++ ++ return 0; ++} ++ ++static int stm32_cpufreq_init(void) ++{ ++ platform_device_register_simple("stm32-cpufreq", -1, NULL, 0); ++ ++ return 0; ++} ++module_init(stm32_cpufreq_init); ++ ++static struct platform_driver stm32_cpufreq_platdrv = { ++ .driver = { ++ .name = "stm32-cpufreq", ++ }, ++ .probe = stm32_cpufreq_probe, ++ .remove = stm32_cpufreq_remove, ++}; ++module_platform_driver(stm32_cpufreq_platdrv); ++ ++MODULE_DESCRIPTION("STM32 CPU freq driver"); ++MODULE_AUTHOR("Alexandre Torgue "); ++MODULE_LICENSE("GPL v2"); +-- +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.94/0003-ARM-stm32mp1-r3-CRYPTO.patch similarity index 97% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0002-ARM-stm32mp1-r2-CRYPTO.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch index 251a4a9..2d56ee2 100644 --- 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.94/0003-ARM-stm32mp1-r3-CRYPTO.patch @@ -1,7 +1,7 @@ -From 6a4b2788be21d13d65a726973003dc48405da004 Mon Sep 17 00:00:00 2001 +From ba1e344b74257a65d21b7b82f99df31dcf3f5a7c 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 +Date: Fri, 8 Nov 2019 16:52:38 +0100 +Subject: [PATCH 03/31] ARM stm32mp1 r3 CRYPTO --- crypto/testmgr.c | 7 + @@ -9,14 +9,14 @@ Subject: [PATCH 02/30] ARM stm32mp1 r2 CRYPTO 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-hash.c | 6 +- drivers/crypto/stm32/stm32_crc32.c | 387 -------------------------------- - 7 files changed, 503 insertions(+), 415 deletions(-) + 7 files changed, 502 insertions(+), 414 deletions(-) create mode 100644 drivers/crypto/stm32/stm32-crc32.c delete mode 100644 drivers/crypto/stm32/stm32_crc32.c diff --git a/crypto/testmgr.c b/crypto/testmgr.c -index 3664c26..7d0d6b4 100644 +index 13cb2ea..35a4ac5 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1918,6 +1918,13 @@ static int alg_test_crc32c(const struct alg_test_desc *desc, @@ -679,18 +679,9 @@ index 23b0b7b..cd8c439 100644 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 +index 641b110..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); 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.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch similarity index 51% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0003-ARM-stm32mp1-r2-BLUETOOTH-CHAR.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch index 4f59830..b0243e9 100644 --- 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.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch @@ -1,18 +1,18 @@ -From 613535e3904f7615aff655384c65cd897312e3b0 Mon Sep 17 00:00:00 2001 +From bcd539392e9bc23b9b47250eacf84907dd993089 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 +Date: Fri, 8 Nov 2019 16:52:39 +0100 +Subject: [PATCH 04/31] ARM stm32mp1 r3 BLUETOOTH CHAR --- drivers/bluetooth/hci_bcm.c | 3 ++- - drivers/char/hw_random/stm32-rng.c | 9 +++++++++ - 2 files changed, 11 insertions(+), 1 deletion(-) + drivers/char/hw_random/stm32-rng.c | 1 + + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c -index 8001323..31da580 100644 +index 59e5fc5..c553235 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) +@@ -1324,7 +1324,8 @@ static int bcm_serdev_probe(struct serdev_device *serdev) if (!bcmdev->shutdown) { dev_warn(&serdev->dev, "No reset resource, using default baud rate\n"); @@ -23,7 +23,7 @@ index 8001323..31da580 100644 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 +index 37b338a..0ef5b6a 100644 --- a/drivers/char/hw_random/stm32-rng.c +++ b/drivers/char/hw_random/stm32-rng.c @@ -161,6 +161,7 @@ static int stm32_rng_probe(struct platform_device *ofdev) @@ -34,28 +34,6 @@ index 042860d..0ef5b6a 100644 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.49/0004-ARM-stm32mp1-r2-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch similarity index 83% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0004-ARM-stm32mp1-r2-CLOCK.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch index 996623d..ab87092 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0004-ARM-stm32mp1-r2-CLOCK.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch @@ -1,17 +1,17 @@ -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 +From 035fdb208f6ba7b3c84fddbb476ab7be33866cb4 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Mon, 20 Jan 2020 18:07:02 +0100 +Subject: [PATCH 05/31] ARM stm32mp1 r3 CLOCK --- - drivers/clk/clk-stm32mp1.c | 1061 ++++++++++++++++++++++++++--- - drivers/clk/clk.c | 24 +- + drivers/clk/clk-stm32mp1.c | 1124 +++++++++++++++++++++++++++-- + drivers/clk/clk.c | 6 + include/dt-bindings/clock/stm32mp1-clks.h | 3 - - include/linux/clk.h | 1 + - 4 files changed, 1004 insertions(+), 85 deletions(-) + include/linux/clk-provider.h | 1 + + 4 files changed, 1061 insertions(+), 73 deletions(-) diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index a907555..fba9626 100644 +index bf3b6a4..95ed875 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -5,15 +5,22 @@ @@ -56,48 +56,6 @@ index a907555..fba9626 100644 #define RCC_CLR 0x4 -@@ -121,7 +133,7 @@ static const char * const cpu_src[] = { - }; - - static const char * const axi_src[] = { -- "ck_hsi", "ck_hse", "pll2_p", "pll3_p" -+ "ck_hsi", "ck_hse", "pll2_p" - }; - - static const char * const per_src[] = { -@@ -225,19 +237,19 @@ static const char * const usart6_src[] = { - }; - - static const char * const fdcan_src[] = { -- "ck_hse", "pll3_q", "pll4_q" -+ "ck_hse", "pll3_q", "pll4_q", "pll4_r" - }; - - static const char * const sai_src[] = { -- "pll4_q", "pll3_q", "i2s_ckin", "ck_per" -+ "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "pll3_r" - }; - - static const char * const sai2_src[] = { -- "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb" -+ "pll4_q", "pll3_q", "i2s_ckin", "ck_per", "spdif_ck_symb", "pll3_r" - }; - - static const char * const adc12_src[] = { -- "pll4_q", "ck_per" -+ "pll4_r", "ck_per", "pll3_q" - }; - - static const char * const dsi_src[] = { -@@ -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 }, -- { 8, 512 }, { 9, 512 }, { 10, 512}, { 11, 512 }, -+ { 8, 256 }, { 9, 512 }, { 10, 512}, { 11, 512 }, - { 12, 512 }, { 13, 512 }, { 14, 512}, { 15, 512 }, - { 0 }, - }; @@ -356,17 +368,20 @@ struct stm32_gate_cfg { struct gate_cfg *gate; struct stm32_mgate *mgate; @@ -171,7 +129,60 @@ index a907555..fba9626 100644 } } -@@ -1193,7 +1225,8 @@ _clk_stm32_register_composite(struct device *dev, +@@ -714,7 +746,7 @@ static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) + + for (n = 0; n < clk_mmux->mmux->nbr_clk; n++) + if (clk_mmux->mmux->hws[n] != hw) +- clk_hw_reparent(clk_mmux->mmux->hws[n], hwp); ++ clk_hw_set_parent(clk_mmux->mmux->hws[n], hwp); + + return 0; + } +@@ -867,6 +899,7 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name, + const char *parent_name, + void __iomem *reg, + unsigned long flags, ++ const struct clk_ops *ops, + spinlock_t *lock) + { + struct stm32_pll_obj *element; +@@ -879,7 +912,7 @@ static struct clk_hw *clk_register_pll(struct device *dev, const char *name, + return ERR_PTR(-ENOMEM); + + init.name = name; +- init.ops = &pll_ops; ++ init.ops = ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; +@@ -1033,6 +1066,8 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, + + struct stm32_pll_cfg { + u32 offset; ++ const struct clk_ops *ops; ++ const struct clk_ops *ops_sec; + }; + + static struct clk_hw *_clk_register_pll(struct device *dev, +@@ -1043,7 +1078,8 @@ static struct clk_hw *_clk_register_pll(struct device *dev, + struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; + + return clk_register_pll(dev, cfg->name, cfg->parent_name, +- base + stm_pll_cfg->offset, cfg->flags, lock); ++ base + stm_pll_cfg->offset, cfg->flags, ++ stm_pll_cfg->ops, lock); + } + + struct stm32_cktim_cfg { +@@ -1161,6 +1197,7 @@ _clk_stm32_register_composite(struct device *dev, + .flags = _flags,\ + .cfg = &(struct stm32_pll_cfg) {\ + .offset = _offset,\ ++ .ops = &pll_ops\ + },\ + .func = _clk_register_pll,\ + } +@@ -1193,7 +1230,8 @@ _clk_stm32_register_composite(struct device *dev, .func = _clk_stm32_register_gate,\ } @@ -181,7 +192,7 @@ index a907555..fba9626 100644 (&(struct stm32_gate_cfg) {\ &(struct gate_cfg) {\ .reg_off = _gate_offset,\ -@@ -1202,6 +1235,7 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1202,6 +1240,7 @@ _clk_stm32_register_composite(struct device *dev, },\ .mgate = _mgate,\ .ops = _ops,\ @@ -189,7 +200,7 @@ index a907555..fba9626 100644 }) #define _STM32_MGATE(_mgate)\ -@@ -1209,11 +1243,11 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1209,11 +1248,11 @@ _clk_stm32_register_composite(struct device *dev, #define _GATE(_gate_offset, _gate_bit_idx, _gate_flags)\ _STM32_GATE(_gate_offset, _gate_bit_idx, _gate_flags,\ @@ -203,7 +214,7 @@ index a907555..fba9626 100644 #define _MGATE_MP1(_mgate)\ .gate = &per_gate_cfg[_mgate] -@@ -1227,7 +1261,7 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1227,7 +1266,7 @@ _clk_stm32_register_composite(struct device *dev, _STM32_MGATE(_mgate)) #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ @@ -212,7 +223,7 @@ index a907555..fba9626 100644 .div = &(struct stm32_div_cfg) {\ &(struct div_cfg) {\ .reg_off = _div_offset,\ -@@ -1237,13 +1271,14 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1237,13 +1276,14 @@ _clk_stm32_register_composite(struct device *dev, .table = _div_table,\ },\ .ops = _ops,\ @@ -229,7 +240,7 @@ index a907555..fba9626 100644 .mux = &(struct stm32_mux_cfg) {\ &(struct mux_cfg) {\ .reg_off = _offset,\ -@@ -1254,10 +1289,11 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1254,10 +1294,11 @@ _clk_stm32_register_composite(struct device *dev, },\ .mmux = _mmux,\ .ops = _ops,\ @@ -242,19 +253,10 @@ index a907555..fba9626 100644 #define _MMUX(_mmux) .mux = &ker_mux_cfg[_mmux] -@@ -1286,10 +1322,513 @@ _clk_stm32_register_composite(struct device *dev, - MGATE_MP1(_id, _name, _parent, _flags, _mgate) +@@ -1292,6 +1333,581 @@ _clk_stm32_register_composite(struct device *dev, + _MMUX(_mmux),\ + _NO_DIV) - #define KCLK(_id, _name, _parents, _flags, _mgate, _mmux)\ -- COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE | _flags,\ -- _MGATE_MP1(_mgate),\ -- _MMUX(_mmux),\ -- _NO_DIV) -+ COMPOSITE(_id, _name, _parents, CLK_OPS_PARENT_ENABLE |\ -+ CLK_SET_RATE_NO_REPARENT | _flags,\ -+ _MGATE_MP1(_mgate),\ -+ _MMUX(_mmux),\ -+ _NO_DIV) +/* + * + * Security management @@ -266,6 +268,10 @@ index a907555..fba9626 100644 +#define STM32_SET_BITS 0x2 +#define STM32_CLR_BITS 0x3 + ++#define STM32_SMC_RCC_OPP 0x82001009 ++#define STM32_SMC_RCC_OPP_SET 0 ++#define STM32_SMC_RCC_OPP_ROUND 1 ++ +#define SMC(class, op, address, val)\ + ({\ + struct arm_smccc_res res;\ @@ -519,6 +525,10 @@ index a907555..fba9626 100644 + .set_rate = clk_sdivider_set_rate, +}; + ++static const struct clk_ops clk_sdivider_pll1_p_ops = { ++ .recalc_rate = clk_sdivider_recalc_rate, ++}; ++ +static struct clk_hw * +clk_hw_register_sdivider_table(struct device *dev, const char *name, + const char *parent_name, @@ -600,6 +610,65 @@ index a907555..fba9626 100644 + lock); +} + ++static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct arm_smccc_res res; ++ ++ arm_smccc_smc(STM32_SMC_RCC_OPP, STM32_SMC_RCC_OPP_ROUND, rate, 0, 0, 0, ++ 0, 0, &res); ++ ++ return res.a1; ++} ++ ++static int pll1_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ SMC(STM32_SMC_RCC_OPP, STM32_SMC_RCC_OPP_SET, rate, 0); ++ ++ return 0; ++} ++ ++static const struct clk_ops pll1_ops = { ++ .enable = pll_enable, ++ .disable = pll_disable, ++ .recalc_rate = pll_recalc_rate, ++ .round_rate = clk_pll1_round_rate, ++ .set_rate = pll1_set_rate, ++ .is_enabled = pll_is_enabled, ++}; ++ ++static struct clk_hw *_clk_sregister_pll(struct device *dev, ++ struct clk_hw_onecell_data *clk_data, ++ void __iomem *base, spinlock_t *lock, ++ const struct clock_config *cfg) ++{ ++ struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; ++ ++ if (!_is_soc_secured(base)) ++ return clk_register_pll(dev, cfg->name, cfg->parent_name, ++ base + stm_pll_cfg->offset, cfg->flags, ++ stm_pll_cfg->ops, lock); ++ else ++ return clk_register_pll(dev, cfg->name, cfg->parent_name, ++ base + stm_pll_cfg->offset, cfg->flags, ++ stm_pll_cfg->ops_sec, lock); ++} ++ ++#define PLL_1(_id, _name, _parent, _flags, _offset)\ ++{\ ++ .id = _id,\ ++ .name = _name,\ ++ .parent_name = _parent,\ ++ .flags = _flags,\ ++ .cfg = &(struct stm32_pll_cfg) {\ ++ .offset = _offset,\ ++ .ops = &pll_ops,\ ++ .ops_sec = &pll1_ops,\ ++ },\ ++ .func = _clk_sregister_pll,\ ++} ++ +static int mp1_sgate_clk_enable(struct clk_hw *hw) +{ + struct clk_gate *gate = to_clk_gate(hw); @@ -757,10 +826,16 @@ index a907555..fba9626 100644 +#define _S_MUX(_offset, _shift, _width, _mux_flags)\ + _STM32_MUX(_offset, _shift, _width, _mux_flags,\ + NULL, NULL, &clk_smux_ops) - ++ ++#define _S_PLL1_P_DIV(_div_offset, _div_shift, _div_width, _div_flags,\ ++ _div_table)\ ++ _STM32_DIV(_div_offset, _div_shift, _div_width,\ ++ _div_flags, _div_table, NULL, &clk_sdivider_pll1_p_ops) ++ enum { G_SAI1, -@@ -1401,6 +1940,7 @@ enum { + G_SAI2, +@@ -1402,6 +2018,7 @@ enum { G_CRYP1, G_HASH1, G_BKPSRAM, @@ -768,7 +843,7 @@ index a907555..fba9626 100644 G_LAST }; -@@ -1408,7 +1948,7 @@ enum { +@@ -1409,7 +2026,7 @@ enum { static struct stm32_mgate mp1_mgate[G_LAST]; #define _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ @@ -777,7 +852,7 @@ index a907555..fba9626 100644 [_id] = {\ &(struct gate_cfg) {\ .reg_off = _gate_offset,\ -@@ -1417,15 +1957,24 @@ static struct stm32_mgate mp1_mgate[G_LAST]; +@@ -1418,15 +2035,24 @@ static struct stm32_mgate mp1_mgate[G_LAST]; },\ .mgate = _mgate,\ .ops = _ops,\ @@ -804,7 +879,7 @@ index a907555..fba9626 100644 /* Peripheral gates */ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { -@@ -1487,20 +2036,21 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { +@@ -1488,20 +2114,21 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { K_GATE(G_STGENRO, RCC_APB4ENSETR, 20, 0), K_MGATE(G_USBPHY, RCC_APB4ENSETR, 16, 0), K_GATE(G_IWDG2, RCC_APB4ENSETR, 15, 0), @@ -837,7 +912,7 @@ index a907555..fba9626 100644 K_MGATE(G_SDMMC3, RCC_AHB2ENSETR, 16, 0), K_MGATE(G_USBO, RCC_AHB2ENSETR, 8, 0), -@@ -1529,11 +2079,11 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { +@@ -1530,11 +2157,11 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { K_GATE(G_GPIOB, RCC_AHB4ENSETR, 1, 0), K_GATE(G_GPIOA, RCC_AHB4ENSETR, 0, 0), @@ -854,7 +929,7 @@ index a907555..fba9626 100644 K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), -@@ -1541,12 +2091,15 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { +@@ -1542,12 +2169,15 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { K_MGATE(G_SDMMC1, RCC_AHB6ENSETR, 16, 0), K_MGATE(G_QSPI, RCC_AHB6ENSETR, 14, 0), K_MGATE(G_FMC, RCC_AHB6ENSETR, 12, 0), @@ -870,7 +945,7 @@ index a907555..fba9626 100644 K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), }; -@@ -1591,7 +2144,7 @@ enum { +@@ -1592,7 +2222,7 @@ enum { static struct stm32_mmux ker_mux[M_LAST]; @@ -879,7 +954,7 @@ index a907555..fba9626 100644 [_id] = {\ &(struct mux_cfg) {\ .reg_off = _offset,\ -@@ -1602,15 +2155,24 @@ static struct stm32_mmux ker_mux[M_LAST]; +@@ -1603,15 +2233,24 @@ static struct stm32_mmux ker_mux[M_LAST]; },\ .mmux = _mmux,\ .ops = _ops,\ @@ -906,7 +981,7 @@ index a907555..fba9626 100644 static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { /* Kernel multi mux */ -@@ -1626,7 +2188,7 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { +@@ -1627,7 +2266,7 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { K_MMUX(M_UART78, RCC_UART78CKSELR, 0, 3, 0), K_MMUX(M_SAI1, RCC_SAI1CKSELR, 0, 3, 0), K_MMUX(M_ETHCK, RCC_ETHCKSELR, 0, 2, 0), @@ -915,7 +990,7 @@ index a907555..fba9626 100644 /* Kernel simple mux */ K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), -@@ -1647,23 +2209,24 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { +@@ -1648,10 +2287,10 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { K_MUX(M_ADC12, RCC_ADCCKSELR, 0, 2, 0), K_MUX(M_DSI, RCC_DSICKSELR, 0, 1, 0), K_MUX(M_CKPER, RCC_CPERCKSELR, 0, 2, 0), @@ -930,11 +1005,8 @@ index a907555..fba9626 100644 }; 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), +@@ -1660,11 +2299,12 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + RCC_HSICFGR, 0, 2, CLK_DIVIDER_READ_ONLY), /* External / Internal Oscillators */ - GATE_MP1(CK_HSE, "ck_hse", "clk-hse", 0, RCC_OCENSETR, 8, 0), @@ -951,15 +1023,24 @@ index a907555..fba9626 100644 FIXED_FACTOR(CK_HSE_DIV2, "clk-hse-div2", "ck_hse", 0, 1, 2), -@@ -1685,24 +2248,24 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1679,31 +2319,31 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + 0, 2, CLK_MUX_READ_ONLY), + + /* PLLs */ +- PLL(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), ++ PLL_1(PLL1, "pll1", "ref1", CLK_IGNORE_UNUSED, RCC_PLL1CR), + PLL(PLL2, "pll2", "ref1", CLK_IGNORE_UNUSED, RCC_PLL2CR), + PLL(PLL3, "pll3", "ref3", CLK_IGNORE_UNUSED, RCC_PLL3CR), + PLL(PLL4, "pll4", "ref4", CLK_IGNORE_UNUSED, RCC_PLL4CR), /* ODF */ - COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, +- COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), 0, - _GATE(RCC_PLL1CR, 4, 0), ++ COMPOSITE(PLL1_P, "pll1_p", PARENT("pll1"), CLK_SET_RATE_PARENT, + _S_GATE(RCC_PLL1CR, 4, 0), _NO_MUX, - _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), -+ _S_DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), ++ _S_PLL1_P_DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), COMPOSITE(PLL2_P, "pll2_p", PARENT("pll2"), 0, - _GATE(RCC_PLL2CR, 4, 0), @@ -984,13 +1065,15 @@ index a907555..fba9626 100644 COMPOSITE(PLL3_P, "pll3_p", PARENT("pll3"), 0, _GATE(RCC_PLL3CR, 4, 0), -@@ -1738,20 +2301,20 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1739,20 +2379,21 @@ static const struct clock_config stm32mp1_clock_cfg[] = { MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, RCC_CPERCKSELR, 0, 2, 0), - MUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | +- CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), + SMUX(CK_MPU, "ck_mpu", cpu_src, CLK_OPS_PARENT_ENABLE | - CLK_IS_CRITICAL, RCC_MPCKSELR, 0, 2, 0), ++ CLK_SET_RATE_PARENT | CLK_IS_CRITICAL, ++ RCC_MPCKSELR, 0, 2, 0), COMPOSITE(CK_AXI, "ck_axi", axi_src, CLK_IS_CRITICAL | CLK_OPS_PARENT_ENABLE, @@ -1010,7 +1093,7 @@ index a907555..fba9626 100644 DIV_TABLE(NO_ID, "pclk1", "ck_mcu", CLK_IGNORE_UNUSED, RCC_APB1DIVR, 0, 3, CLK_DIVIDER_READ_ONLY, apb_div_table), -@@ -1896,6 +2459,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1897,6 +2538,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), @@ -1018,7 +1101,7 @@ index a907555..fba9626 100644 /* 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[] = { +@@ -1907,7 +2549,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), @@ -1027,13 +1110,8 @@ index a907555..fba9626 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 +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), - -- COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE, -+ COMPOSITE(ETHPTP_K, "ethptp_k", eth_src, CLK_OPS_PARENT_ENABLE | -+ CLK_SET_RATE_NO_REPARENT, +@@ -1957,16 +2599,15 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + CLK_SET_RATE_NO_REPARENT, _NO_GATE, _MMUX(M_ETHCK), - _DIV(RCC_ETHCKSELR, 4, 4, CLK_DIVIDER_ALLOW_ZERO, NULL)), @@ -1053,7 +1131,7 @@ index a907555..fba9626 100644 _NO_DIV), /* MCO clocks */ -@@ -2082,21 +2646,364 @@ static int stm32_rcc_init(struct device_node *np, +@@ -2084,21 +2725,364 @@ static int stm32_rcc_init(struct device_node *np, return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); } @@ -1425,84 +1503,22 @@ index a907555..fba9626 100644 + return 0; +} diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c -index 5413ffa..25a4af5 100644 +index 5413ffa..4290d9e 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) - EXPORT_SYMBOL_GPL(clk_has_parent); - - static int clk_core_set_parent_nolock(struct clk_core *core, -- struct clk_core *parent) -+ struct clk_core *parent, -+ bool force) - { - int ret = 0; - int p_index = 0; -@@ -2215,7 +2216,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core, - if (!core) - return 0; - -- if (core->parent == parent) -+ if (core->parent == parent && !force) - return 0; - - /* verify ops for for multi-parent clks */ -@@ -2272,6 +2273,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core, - * clk_set_parent - switch the parent of a mux clk - * @clk: the mux clk whose input we are switching - * @parent: the new input to clk -+ * @force: don't test if parent is already set - * - * Re-parent clk to use parent as its new input source. If clk is in - * prepared state, the clk will get enabled for the duration of this call. If -@@ -2285,7 +2287,7 @@ static int clk_core_set_parent_nolock(struct clk_core *core, - * - * Returns 0 on success, -EERROR otherwise. - */ --int clk_set_parent(struct clk *clk, struct clk *parent) -+int _clk_set_parent(struct clk *clk, struct clk *parent, bool force) - { - int ret; - -@@ -2298,7 +2300,8 @@ int clk_set_parent(struct clk *clk, struct clk *parent) - clk_core_rate_unprotect(clk->core); - - ret = clk_core_set_parent_nolock(clk->core, -- parent ? parent->core : NULL); -+ parent ? parent->core : NULL, -+ force); - - if (clk->exclusive_count) - clk_core_rate_protect(clk->core); -@@ -2307,8 +2310,19 @@ int clk_set_parent(struct clk *clk, struct clk *parent) - +@@ -2268,6 +2268,12 @@ static int clk_core_set_parent_nolock(struct clk_core *core, return ret; } -+ -+int clk_set_parent(struct clk *clk, struct clk *parent) -+{ -+ return _clk_set_parent(clk, parent, 0); -+} - EXPORT_SYMBOL_GPL(clk_set_parent); -+int clk_set_parent_force(struct clk *clk, struct clk *parent) ++int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *parent) +{ -+ return _clk_set_parent(clk, parent, 1); ++ return clk_core_set_parent_nolock(hw->core, parent->core); +} -+EXPORT_SYMBOL_GPL(clk_set_parent_force); ++EXPORT_SYMBOL_GPL(clk_hw_set_parent); + - static int clk_core_set_phase_nolock(struct clk_core *core, int degrees) - { - int ret = -EINVAL; -@@ -3350,7 +3364,7 @@ void clk_unregister(struct clk *clk) - /* Reparent all children to the orphan list. */ - hlist_for_each_entry_safe(child, t, &clk->core->children, - child_node) -- clk_core_set_parent_nolock(child, NULL); -+ clk_core_set_parent_nolock(child, NULL, 0); - } - - hlist_del_init(&clk->core->child_node); + /** + * clk_set_parent - switch the parent of a mux clk + * @clk: the mux clk whose input we are switching diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h index 90ec780..4cdaf13 100644 --- a/include/dt-bindings/clock/stm32mp1-clks.h @@ -1515,18 +1531,18 @@ index 90ec780..4cdaf13 100644 -#define ETHMAC_K ETHCK_K - #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ -diff --git a/include/linux/clk.h b/include/linux/clk.h -index 4f750c4..ffbae16 100644 ---- a/include/linux/clk.h -+++ b/include/linux/clk.h -@@ -602,6 +602,7 @@ int clk_set_max_rate(struct clk *clk, unsigned long rate); - * Returns success (0) or negative errno. - */ - int clk_set_parent(struct clk *clk, struct clk *parent); -+int clk_set_parent_force(struct clk *clk, struct clk *parent); - - /** - * clk_get_parent - get the parent clock source for this clock +diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h +index d1b6d2c..ec4c906 100644 +--- a/include/linux/clk-provider.h ++++ b/include/linux/clk-provider.h +@@ -778,6 +778,7 @@ unsigned int clk_hw_get_num_parents(const struct clk_hw *hw); + struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw); + struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, + unsigned int index); ++int clk_hw_set_parent(struct clk_hw *hw, struct clk_hw *new_parent); + unsigned int __clk_get_enable_count(struct clk *clk); + unsigned long clk_hw_get_rate(const struct clk_hw *hw); + unsigned long __clk_get_flags(struct clk *clk); -- 2.7.4 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0005-ARM-stm32mp1-r2-DMA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch similarity index 85% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0005-ARM-stm32mp1-r2-DMA.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch index ea1c1cc..b4c389c 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0005-ARM-stm32mp1-r2-DMA.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch @@ -1,16 +1,71 @@ -From d13371d49b7675f62cdd16b4937eac738d862acd Mon Sep 17 00:00:00 2001 +From ba9b118a08bddb954d75f84134705c9c28673128 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 +Date: Fri, 8 Nov 2019 16:52:39 +0100 +Subject: [PATCH 06/31] ARM stm32mp1 r3 DMA --- - drivers/dma/stm32-dma.c | 1142 +++++++++++++++++++++++++++++++++++++------- + drivers/dma/dmaengine.c | 35 ++ + drivers/dma/stm32-dma.c | 1164 ++++++++++++++++++++++++++++++++++++++------ drivers/dma/stm32-dmamux.c | 110 ++++- - drivers/dma/stm32-mdma.c | 232 ++++++++- - 3 files changed, 1285 insertions(+), 199 deletions(-) + drivers/dma/stm32-mdma.c | 234 ++++++++- + include/linux/dmaengine.h | 11 + + 5 files changed, 1358 insertions(+), 196 deletions(-) +diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c +index f1a441ab..48483ab 100644 +--- a/drivers/dma/dmaengine.c ++++ b/drivers/dma/dmaengine.c +@@ -737,6 +737,34 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name) + EXPORT_SYMBOL_GPL(dma_request_chan); + + /** ++ * dma_request_chan_linked - try to allocate an exclusive slave channel ++ * @dev: pointer to client device structure ++ * @name: slave channel name ++ * ++ * Returns pointer to appropriate DMA channel on success or an error pointer. ++ * Create device link between DMA channel provider and client device consumer. ++ */ ++struct dma_chan *dma_request_chan_linked(struct device *dev, const char *name) ++{ ++ struct dma_chan *ch = dma_request_chan(dev, name); ++ struct device *provider_dev = ch->device->dev; ++ struct device_link *link; ++ ++ if (!IS_ERR_OR_NULL(ch)) { ++ link = device_link_add(dev, provider_dev, DL_FLAG_STATELESS); ++ if (!link) { ++ dev_err(provider_dev, ++ "failed to add dev link with %s\n", ++ dev_name(dev)); ++ return ERR_PTR(-EINVAL); ++ } ++ } ++ ++ return ch; ++} ++EXPORT_SYMBOL_GPL(dma_request_chan_linked); ++ ++/** + * dma_request_slave_channel - try to allocate an exclusive slave channel + * @dev: pointer to client device structure + * @name: slave channel name +@@ -794,6 +822,13 @@ void dma_release_channel(struct dma_chan *chan) + } + EXPORT_SYMBOL_GPL(dma_release_channel); + ++void dma_release_chan_linked(struct device *dev, struct dma_chan *chan) ++{ ++ device_link_remove(dev, chan->device->dev); ++ dma_release_channel(chan); ++} ++EXPORT_SYMBOL_GPL(dma_release_chan_linked); ++ + /** + * dmaengine_get - register interest in dma_channels + */ diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 379e8d5..87db5a7 100644 +index 4903a40..810420a 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -15,14 +15,18 @@ @@ -32,15 +87,18 @@ index 379e8d5..87db5a7 100644 #include #include #include -@@ -118,6 +122,7 @@ +@@ -116,8 +120,10 @@ + #define STM32_DMA_FIFO_THRESHOLD_HALFFULL 0x01 + #define STM32_DMA_FIFO_THRESHOLD_3QUARTERSFULL 0x02 #define STM32_DMA_FIFO_THRESHOLD_FULL 0x03 ++#define STM32_DMA_FIFO_THRESHOLD_NONE 0x04 #define STM32_DMA_MAX_DATA_ITEMS 0xffff +#define STM32_DMA_SRAM_GRANULARITY PAGE_SIZE /* * Valid transfer starts from @0 to @0xFFFE leading to unaligned scatter * gather at boundary. Thus it's safer to round down this value on FIFO -@@ -135,6 +140,12 @@ +@@ -135,6 +141,15 @@ /* DMA Features */ #define STM32_DMA_THRESHOLD_FTR_MASK GENMASK(1, 0) #define STM32_DMA_THRESHOLD_FTR_GET(n) ((n) & STM32_DMA_THRESHOLD_FTR_MASK) @@ -50,10 +108,13 @@ index 379e8d5..87db5a7 100644 +#define STM32_DMA_MDMA_SRAM_SIZE_MASK GENMASK(4, 3) +#define STM32_DMA_MDMA_SRAM_SIZE_GET(n) (((n) & STM32_DMA_MDMA_SRAM_SIZE_MASK) \ + >> 3) ++#define STM32_DMA_DIRECT_MODE_MASK BIT(5) ++#define STM32_DMA_DIRECT_MODE_GET(n) (((n) & STM32_DMA_DIRECT_MODE_MASK) \ ++ >> 5) enum stm32_dma_width { STM32_DMA_BYTE, -@@ -176,15 +187,32 @@ struct stm32_dma_chan_reg { +@@ -176,15 +191,32 @@ struct stm32_dma_chan_reg { u32 dma_sfcr; }; @@ -87,7 +148,7 @@ index 379e8d5..87db5a7 100644 struct stm32_dma_sg_req sg_req[]; }; -@@ -201,6 +229,10 @@ struct stm32_dma_chan { +@@ -201,6 +233,10 @@ struct stm32_dma_chan { u32 threshold; u32 mem_burst; u32 mem_width; @@ -98,7 +159,7 @@ index 379e8d5..87db5a7 100644 }; struct stm32_dma_device { -@@ -210,6 +242,7 @@ struct stm32_dma_device { +@@ -210,6 +246,7 @@ struct stm32_dma_device { struct reset_control *rst; bool mem2mem; struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS]; @@ -106,34 +167,28 @@ index 379e8d5..87db5a7 100644 }; static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) -@@ -308,20 +341,12 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, +@@ -287,6 +324,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, + { + u32 remaining; + ++ if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE) ++ return false; ++ + if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) { + if (burst != 0) { + /* +@@ -308,6 +348,10 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, static bool stm32_dma_is_burst_possible(u32 buf_len, u32 threshold) { -- switch (threshold) { -- case STM32_DMA_FIFO_THRESHOLD_FULL: -- if (buf_len >= STM32_DMA_MAX_BURST) -- return true; -- else -- return false; -- case STM32_DMA_FIFO_THRESHOLD_HALFFULL: -- if (buf_len >= STM32_DMA_MAX_BURST / 2) -- return true; -- else -- return false; -- default: -- return false; -- } -+ /* -+ * Buffer or period length has to be aligned on FIFO depth. -+ * Otherwise bytes may be stuck within FIFO at buffer or period -+ * length. -+ */ -+ return ((buf_len % ((threshold + 1) * 4)) == 0); - } - - static u32 stm32_dma_get_best_burst(u32 buf_len, u32 max_burst, u32 threshold, -@@ -436,7 +461,6 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) ++ /* If FIFO direct mode, burst is not possible */ ++ if (threshold == STM32_DMA_FIFO_THRESHOLD_NONE) ++ return false; ++ + /* + * Buffer or period length has to be aligned on FIFO depth. + * Otherwise bytes may be stuck within FIFO at buffer or period +@@ -428,7 +472,6 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) { struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); @@ -141,7 +196,7 @@ index 379e8d5..87db5a7 100644 u32 dma_scr, id; id = chan->id; -@@ -446,19 +470,10 @@ static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) +@@ -438,19 +481,10 @@ static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) dma_scr &= ~STM32_DMA_SCR_EN; stm32_dma_write(dmadev, STM32_DMA_SCR(id), dma_scr); @@ -165,7 +220,7 @@ index 379e8d5..87db5a7 100644 } return 0; -@@ -497,13 +512,23 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) +@@ -489,13 +523,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); @@ -192,7 +247,7 @@ index 379e8d5..87db5a7 100644 chan->desc = NULL; } -@@ -514,9 +539,96 @@ static int stm32_dma_terminate_all(struct dma_chan *c) +@@ -506,9 +550,96 @@ static int stm32_dma_terminate_all(struct dma_chan *c) return 0; } @@ -289,7 +344,7 @@ index 379e8d5..87db5a7 100644 vchan_synchronize(&chan->vchan); } -@@ -539,62 +651,205 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) +@@ -531,62 +662,205 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); } @@ -533,7 +588,7 @@ index 379e8d5..87db5a7 100644 } 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) +@@ -618,35 +892,147 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) } } @@ -693,7 +748,7 @@ index 379e8d5..87db5a7 100644 if (status & STM32_DMA_TCI) { stm32_dma_irq_clear(chan, STM32_DMA_TCI); -@@ -669,10 +1036,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) +@@ -661,10 +1047,19 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) if (status & STM32_DMA_FEI) { stm32_dma_irq_clear(chan, STM32_DMA_FEI); status &= ~STM32_DMA_FEI; @@ -706,11 +761,18 @@ index 379e8d5..87db5a7 100644 + dev_err(chan2dev(chan), "FIFO Error\n"); + else + dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); ++ } ++ } ++ if (status & STM32_DMA_DMEI) { ++ stm32_dma_irq_clear(chan, STM32_DMA_DMEI); ++ status &= ~STM32_DMA_DMEI; ++ if (sfcr & STM32_DMA_SCR_DMEIE) { ++ dev_dbg(chan2dev(chan), "Direct mode overrun\n"); + } } if (status) { stm32_dma_irq_clear(chan, status); -@@ -691,12 +1060,17 @@ static void stm32_dma_issue_pending(struct dma_chan *c) +@@ -683,12 +1078,17 @@ static void stm32_dma_issue_pending(struct dma_chan *c) struct stm32_dma_chan *chan = to_stm32_dma_chan(c); unsigned long flags; @@ -730,7 +792,97 @@ index 379e8d5..87db5a7 100644 spin_unlock_irqrestore(&chan->vchan.lock, flags); } -@@ -836,16 +1210,169 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) +@@ -701,13 +1101,13 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + int src_bus_width, dst_bus_width; + int src_burst_size, dst_burst_size; + u32 src_maxburst, dst_maxburst, src_best_burst, dst_best_burst; +- u32 dma_scr, threshold; ++ u32 dma_scr, fifoth; + + src_addr_width = chan->dma_sconfig.src_addr_width; + dst_addr_width = chan->dma_sconfig.dst_addr_width; + src_maxburst = chan->dma_sconfig.src_maxburst; + dst_maxburst = chan->dma_sconfig.dst_maxburst; +- threshold = chan->threshold; ++ fifoth = chan->threshold; + + switch (direction) { + case DMA_MEM_TO_DEV: +@@ -719,7 +1119,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + /* Set device burst size */ + dst_best_burst = stm32_dma_get_best_burst(buf_len, + dst_maxburst, +- threshold, ++ fifoth, + dst_addr_width); + + dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); +@@ -727,7 +1127,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + return dst_burst_size; + + /* Set memory data size */ +- src_addr_width = stm32_dma_get_max_width(buf_len, threshold); ++ src_addr_width = stm32_dma_get_max_width(buf_len, fifoth); + chan->mem_width = src_addr_width; + src_bus_width = stm32_dma_get_width(chan, src_addr_width); + if (src_bus_width < 0) +@@ -737,7 +1137,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + src_maxburst = STM32_DMA_MAX_BURST; + src_best_burst = stm32_dma_get_best_burst(buf_len, + src_maxburst, +- threshold, ++ fifoth, + src_addr_width); + src_burst_size = stm32_dma_get_burst(chan, src_best_burst); + if (src_burst_size < 0) +@@ -751,7 +1151,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + + /* Set FIFO threshold */ + chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; +- chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(threshold); ++ if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE) ++ chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(fifoth); + + /* Set peripheral address */ + chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr; +@@ -767,7 +1168,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + /* Set device burst size */ + src_best_burst = stm32_dma_get_best_burst(buf_len, + src_maxburst, +- threshold, ++ fifoth, + src_addr_width); + chan->mem_burst = src_best_burst; + src_burst_size = stm32_dma_get_burst(chan, src_best_burst); +@@ -775,7 +1176,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + return src_burst_size; + + /* Set memory data size */ +- dst_addr_width = stm32_dma_get_max_width(buf_len, threshold); ++ dst_addr_width = stm32_dma_get_max_width(buf_len, fifoth); + chan->mem_width = dst_addr_width; + dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); + if (dst_bus_width < 0) +@@ -785,7 +1186,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + dst_maxburst = STM32_DMA_MAX_BURST; + dst_best_burst = stm32_dma_get_best_burst(buf_len, + dst_maxburst, +- threshold, ++ fifoth, + dst_addr_width); + chan->mem_burst = dst_best_burst; + dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); +@@ -800,7 +1201,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, + + /* Set FIFO threshold */ + chan->chan_reg.dma_sfcr &= ~STM32_DMA_SFCR_FTH_MASK; +- chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(threshold); ++ if (fifoth != STM32_DMA_FIFO_THRESHOLD_NONE) ++ chan->chan_reg.dma_sfcr |= STM32_DMA_SFCR_FTH(fifoth); + + /* Set peripheral address */ + chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr; +@@ -828,16 +1230,169 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); } @@ -903,7 +1055,7 @@ index 379e8d5..87db5a7 100644 int i, ret; if (!chan->config_init) { -@@ -868,48 +1395,141 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -860,48 +1415,141 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( else chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -912,12 +1064,12 @@ index 379e8d5..87db5a7 100644 - sg_dma_len(sg)); - if (ret < 0) - goto err; +- +- desc->sg_req[i].len = sg_dma_len(sg); + if (chan->use_mdma) { + struct sg_table new_sgt; + struct scatterlist *s, *_sgl; -- desc->sg_req[i].len = sg_dma_len(sg); -- - nb_data_items = desc->sg_req[i].len / buswidth; - if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) { - dev_err(chan2dev(chan), "nb items not supported\n"); @@ -1065,7 +1217,7 @@ index 379e8d5..87db5a7 100644 int i, ret; if (!buf_len || !period_len) { -@@ -957,28 +1577,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -949,28 +1597,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; @@ -1083,10 +1235,10 @@ index 379e8d5..87db5a7 100644 - desc->sg_req[i].len = period_len; + desc->num_sgs = num_periods; + desc->cyclic = true; -+ + + if (chan->use_mdma) { + chan->mchan.dir = direction; - ++ + ret = stm32_dma_mdma_prep_dma_cyclic(chan, buf_addr, buf_len, + period_len, desc); + if (ret < 0) @@ -1127,7 +1279,7 @@ index 379e8d5..87db5a7 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -@@ -1019,13 +1660,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1011,13 +1680,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( STM32_DMA_SCR_PINC | STM32_DMA_SCR_TCIE | STM32_DMA_SCR_TEIE; @@ -1143,7 +1295,7 @@ index 379e8d5..87db5a7 100644 } desc->num_sgs = num_sgs; -@@ -1034,16 +1675,28 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1026,16 +1695,28 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } @@ -1178,7 +1330,7 @@ index 379e8d5..87db5a7 100644 } static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, -@@ -1051,28 +1704,52 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1043,28 +1724,52 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, u32 next_sg) { u32 modulo, burst_size; @@ -1244,7 +1396,7 @@ index 379e8d5..87db5a7 100644 if (!chan->mem_burst) return residue; -@@ -1089,11 +1766,23 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, +@@ -1081,11 +1786,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); @@ -1268,7 +1420,7 @@ index 379e8d5..87db5a7 100644 status = dma_cookie_status(c, cookie, state); if (status == DMA_COMPLETE || !state) return status; -@@ -1120,15 +1809,14 @@ static int stm32_dma_alloc_chan_resources(struct dma_chan *c) +@@ -1112,15 +1829,14 @@ static int stm32_dma_alloc_chan_resources(struct dma_chan *c) int ret; chan->config_init = false; @@ -1288,7 +1440,7 @@ index 379e8d5..87db5a7 100644 return ret; } -@@ -1148,28 +1836,48 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) +@@ -1140,28 +1856,50 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) spin_unlock_irqrestore(&chan->vchan.lock, flags); } @@ -1340,10 +1492,12 @@ index 379e8d5..87db5a7 100644 + chan->use_mdma = STM32_DMA_MDMA_CHAIN_FTR_GET(cfg->features); + chan->sram_size = (1 << STM32_DMA_MDMA_SRAM_SIZE_GET(cfg->features)) * + STM32_DMA_SRAM_GRANULARITY; ++ if (STM32_DMA_DIRECT_MODE_GET(cfg->features)) ++ chan->threshold = STM32_DMA_FIFO_THRESHOLD_NONE; } 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, +@@ -1199,6 +1937,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, stm32_dma_set_config(chan, &cfg); @@ -1353,7 +1507,7 @@ index 379e8d5..87db5a7 100644 return c; } -@@ -1219,10 +1930,12 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); +@@ -1211,10 +1952,12 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); static int stm32_dma_probe(struct platform_device *pdev) { struct stm32_dma_chan *chan; @@ -1366,7 +1520,7 @@ index 379e8d5..87db5a7 100644 int i, ret; match = of_match_device(stm32_dma_of_match, &pdev->dev); -@@ -1248,6 +1961,12 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1240,6 +1983,12 @@ static int stm32_dma_probe(struct platform_device *pdev) return PTR_ERR(dmadev->clk); } @@ -1379,7 +1533,7 @@ index 379e8d5..87db5a7 100644 dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node, "st,mem2mem"); -@@ -1258,6 +1977,15 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1250,6 +1999,15 @@ static int stm32_dma_probe(struct platform_device *pdev) reset_control_deassert(dmadev->rst); } @@ -1395,7 +1549,7 @@ index 379e8d5..87db5a7 100644 dma_cap_set(DMA_SLAVE, dd->cap_mask); dma_cap_set(DMA_PRIVATE, dd->cap_mask); dma_cap_set(DMA_CYCLIC, dd->cap_mask); -@@ -1278,7 +2006,9 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1270,7 +2028,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; @@ -1405,7 +1559,7 @@ index 379e8d5..87db5a7 100644 dd->dev = &pdev->dev; INIT_LIST_HEAD(&dd->channels); -@@ -1293,21 +2023,34 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1285,21 +2045,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); @@ -1446,7 +1600,7 @@ index 379e8d5..87db5a7 100644 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) +@@ -1321,20 +2094,95 @@ static int stm32_dma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dmadev); @@ -1542,7 +1696,7 @@ index 379e8d5..87db5a7 100644 }, }; -@@ -1350,4 +2168,4 @@ static int __init stm32_dma_init(void) +@@ -1342,4 +2190,4 @@ static int __init stm32_dma_init(void) { return platform_driver_probe(&stm32_dma_driver, stm32_dma_probe); } @@ -1728,7 +1882,7 @@ index b922db9..a878b7c 100644 }; diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c -index 06dd172..fb4a7e3 100644 +index 8c3c3e5..759d0ab 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -37,6 +37,7 @@ @@ -1739,15 +1893,17 @@ index 06dd172..fb4a7e3 100644 #include #include -@@ -211,6 +212,8 @@ +@@ -209,7 +210,9 @@ + #define STM32_MDMA_MAX_CHANNELS 63 + #define STM32_MDMA_MAX_REQUESTS 256 #define STM32_MDMA_MAX_BURST 128 - #define STM32_MDMA_VERY_HIGH_PRIORITY 0x11 - -+#define STM32_DMA_SRAM_GRANULARITY PAGE_SIZE +-#define STM32_MDMA_VERY_HIGH_PRIORITY 0x11 ++#define STM32_MDMA_VERY_HIGH_PRIORITY 0x3 + ++#define STM32_DMA_SRAM_GRANULARITY PAGE_SIZE + enum stm32_mdma_trigger_mode { STM32_MDMA_BUFFER, - STM32_MDMA_BLOCK, @@ -237,6 +240,7 @@ struct stm32_mdma_chan_config { u32 transfer_config; u32 mask_addr; @@ -2221,6 +2377,45 @@ index 06dd172..fb4a7e3 100644 }, }; +diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h +index 0647f43..942c707 100644 +--- a/include/linux/dmaengine.h ++++ b/include/linux/dmaengine.h +@@ -1318,9 +1318,11 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, + struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); + + struct dma_chan *dma_request_chan(struct device *dev, const char *name); ++struct dma_chan *dma_request_chan_linked(struct device *dev, const char *name); + struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask); + + void dma_release_channel(struct dma_chan *chan); ++void dma_release_chan_linked(struct device *dev, struct dma_chan *chan); + int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps); + #else + static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) +@@ -1353,6 +1355,11 @@ static inline struct dma_chan *dma_request_chan(struct device *dev, + { + return ERR_PTR(-ENODEV); + } ++static inline struct dma_chan *dma_request_chan_linked(struct device *dev, ++ const char *name) ++{ ++ return ERR_PTR(-ENODEV); ++} + static inline struct dma_chan *dma_request_chan_by_mask( + const dma_cap_mask_t *mask) + { +@@ -1361,6 +1368,10 @@ static inline struct dma_chan *dma_request_chan_by_mask( + static inline void dma_release_channel(struct dma_chan *chan) + { + } ++static inline void dma_release_chan_linked(struct device *dev, ++ struct dma_chan *chan) ++{ ++} + static inline int dma_get_slave_caps(struct dma_chan *chan, + struct dma_slave_caps *caps) + { -- 2.7.4 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0006-ARM-stm32mp1-r2-DRM.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch similarity index 82% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0006-ARM-stm32mp1-r2-DRM.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch index ea5dfb7..79ba076 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0006-ARM-stm32mp1-r2-DRM.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch @@ -1,29 +1,29 @@ -From ee6d275b13c56f9d60acd0dc2790262153d92668 Mon Sep 17 00:00:00 2001 +From e2fff57ea5561d1fef1ca923bffe34985ebf3e8c 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 +Date: Fri, 8 Nov 2019 16:52:39 +0100 +Subject: [PATCH 07/31] ARM stm32mp1 r3 DRM --- drivers/gpu/drm/bridge/Kconfig | 1 + - drivers/gpu/drm/bridge/sii902x.c | 867 +++++++++++++++++++++-- - drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 12 + + drivers/gpu/drm/bridge/sii902x.c | 840 +++++++++++++++++++++-- + drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 102 ++- drivers/gpu/drm/drm_gem.c | 6 - drivers/gpu/drm/drm_modes.c | 19 +- - drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 78 +- + drivers/gpu/drm/panel/panel-orisetech-otm8009a.c | 78 ++- drivers/gpu/drm/panel/panel-raydium-rm68200.c | 20 +- - drivers/gpu/drm/stm/drv.c | 46 +- + drivers/gpu/drm/stm/drv.c | 76 +- drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 114 ++- - drivers/gpu/drm/stm/ltdc.c | 222 ++++-- - drivers/gpu/drm/stm/ltdc.h | 6 + + drivers/gpu/drm/stm/ltdc.c | 282 ++++++-- + drivers/gpu/drm/stm/ltdc.h | 7 + include/drm/bridge/dw_mipi_dsi.h | 1 + include/uapi/drm/drm_mode.h | 6 + - 13 files changed, 1210 insertions(+), 188 deletions(-) + 13 files changed, 1352 insertions(+), 200 deletions(-) diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig -index bf6cad6..fe91c20 100644 +index 7a3e5a8..7695fdf 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig -@@ -95,6 +95,7 @@ config DRM_SII902X +@@ -96,6 +96,7 @@ config DRM_SII902X depends on OF select DRM_KMS_HELPER select REGMAP_I2C @@ -32,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..170657a 100644 +index 0cc6dbb..b41dd44 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -1,4 +1,6 @@ @@ -42,7 +42,7 @@ index e59a135..170657a 100644 * Copyright (C) 2016 Atmel * Bo Shen * -@@ -20,16 +22,23 @@ +@@ -20,16 +22,22 @@ * GNU General Public License for more details. */ @@ -51,7 +51,6 @@ index e59a135..170657a 100644 +#include #include #include -+#include +#include #include +#include @@ -66,7 +65,7 @@ index e59a135..170657a 100644 #define SII902X_TPI_VIDEO_DATA 0x0 #define SII902X_TPI_PIXEL_REPETITION 0x8 -@@ -71,23 +80,229 @@ +@@ -71,23 +79,229 @@ #define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0) #define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK) @@ -296,7 +295,7 @@ index e59a135..170657a 100644 static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge) { return container_of(bridge, struct sii902x, bridge); -@@ -135,45 +350,18 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { +@@ -135,45 +349,18 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { static int sii902x_get_modes(struct drm_connector *connector) { struct sii902x *sii902x = connector_to_sii902x(connector); @@ -315,9 +314,7 @@ index e59a135..170657a 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 { @@ -326,7 +323,9 @@ index e59a135..170657a 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; @@ -348,7 +347,7 @@ index e59a135..170657a 100644 } ret = drm_display_info_set_bus_formats(&connector->display_info, -@@ -181,41 +369,10 @@ static int sii902x_get_modes(struct drm_connector *connector) +@@ -181,41 +368,10 @@ static int sii902x_get_modes(struct drm_connector *connector) if (ret) return ret; @@ -394,7 +393,7 @@ index e59a135..170657a 100644 return num; } -@@ -245,12 +402,22 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) +@@ -245,12 +401,22 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) static void sii902x_bridge_enable(struct drm_bridge *bridge) { struct sii902x *sii902x = bridge_to_sii902x(bridge); @@ -417,25 +416,7 @@ index e59a135..170657a 100644 } static void sii902x_bridge_mode_set(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) +@@ -330,6 +496,267 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge) return 0; } @@ -703,7 +684,7 @@ index e59a135..170657a 100644 static const struct drm_bridge_funcs sii902x_bridge_funcs = { .attach = sii902x_bridge_attach, .mode_set = sii902x_bridge_mode_set, -@@ -348,10 +785,39 @@ static const struct regmap_access_table sii902x_volatile_table = { +@@ -349,10 +776,39 @@ static const struct regmap_access_table sii902x_volatile_table = { static const struct regmap_config sii902x_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -743,18 +724,7 @@ index e59a135..170657a 100644 static irqreturn_t sii902x_interrupt(int irq, void *data) { struct sii902x *sii902x = 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); - +@@ -367,15 +823,134 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) return IRQ_HANDLED; } @@ -889,7 +859,7 @@ index e59a135..170657a 100644 sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL); if (!sii902x) return -ENOMEM; -@@ -392,39 +982,67 @@ static int sii902x_probe(struct i2c_client *client, +@@ -393,39 +968,66 @@ static int sii902x_probe(struct i2c_client *client, return PTR_ERR(sii902x->reset_gpio); } @@ -910,7 +880,6 @@ index e59a135..170657a 100644 + return ret; + } + -+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); sii902x_reset(sii902x); ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); @@ -963,7 +932,7 @@ index e59a135..170657a 100644 } sii902x->bridge.funcs = &sii902x_bridge_funcs; -@@ -433,7 +1051,33 @@ static int sii902x_probe(struct i2c_client *client, +@@ -434,7 +1036,31 @@ static int sii902x_probe(struct i2c_client *client, i2c_set_clientdata(client, sii902x); @@ -973,15 +942,14 @@ index e59a135..170657a 100644 + sii902x_i2c_bypass_deselect); + if (!sii902x->i2cmux) { + dev_err(dev, "failed to allocate I2C mux\n"); -+ ret = -ENOMEM; -+ goto err_disable_regulator; ++ return -ENOMEM; + } + + sii902x->i2cmux->priv = sii902x; + ret = i2c_mux_add_adapter(sii902x->i2cmux, 0, 0, 0); + if (ret) { + dev_err(dev, "Couldn't add i2c mux adapter\n"); -+ goto err_disable_regulator; ++ return ret; + } + + sii902x_register_audio_driver(dev, sii902x); @@ -989,7 +957,6 @@ index e59a135..170657a 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 +964,7 @@ index e59a135..170657a 100644 } static int sii902x_remove(struct i2c_client *client) -@@ -441,11 +1085,85 @@ static int sii902x_remove(struct i2c_client *client) +@@ -442,11 +1068,76 @@ static int sii902x_remove(struct i2c_client *client) { struct sii902x *sii902x = i2c_get_clientdata(client); @@ -1024,8 +991,6 @@ index e59a135..170657a 100644 + + regulator_bulk_disable(ARRAY_SIZE(sii902x->supplies), + sii902x->supplies); -+ -+ pinctrl_pm_select_sleep_state(&sii902x->i2c->dev); + return 0; } @@ -1041,17 +1006,10 @@ index e59a135..170657a 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) { @@ -1083,7 +1041,7 @@ index e59a135..170657a 100644 static const struct of_device_id sii902x_dt_ids[] = { { .compatible = "sil,sii9022", }, { } -@@ -464,6 +1182,7 @@ static struct i2c_driver sii902x_driver = { +@@ -465,6 +1156,7 @@ static struct i2c_driver sii902x_driver = { .driver = { .name = "sii902x", .of_match_table = sii902x_dt_ids, @@ -1092,10 +1050,145 @@ index e59a135..170657a 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 +index fd79996..2e4334f 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) +@@ -206,6 +206,20 @@ + + #define DSI_INT_ST0 0xbc + #define DSI_INT_ST1 0xc0 ++#define GPRXE BIT(12) ++#define GPRDE BIT(11) ++#define GPTXE BIT(10) ++#define GPWRE BIT(9) ++#define GCWRE BIT(8) ++#define DPIPLDWE BIT(7) ++#define EOTPE BIT(6) ++#define PSE BIT(5) ++#define CRCE BIT(4) ++#define ECCME BIT(3) ++#define ECCSE BIT(2) ++#define TOLPRX BIT(1) ++#define TOHSTX BIT(0) ++ + #define DSI_INT_MSK0 0xc4 + #define DSI_INT_MSK1 0xc8 + +@@ -357,6 +371,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) + return 0; + } + ++static int dw_mipi_dsi_read_status(struct dw_mipi_dsi *dsi) ++{ ++ u32 val; ++ ++ val = dsi_read(dsi, DSI_INT_ST1); ++ ++ if (val & GPRXE) ++ DRM_DEBUG_DRIVER("DSI Generic payload receive error\n"); ++ if (val & GPRDE) ++ DRM_DEBUG_DRIVER("DSI Generic payload read error\n"); ++ if (val & GPTXE) ++ DRM_DEBUG_DRIVER("DSI Generic payload transmit error\n"); ++ if (val & GPWRE) ++ DRM_DEBUG_DRIVER("DSI Generic payload write error\n"); ++ if (val & GCWRE) ++ DRM_DEBUG_DRIVER("DSI Generic command write error\n"); ++ if (val & DPIPLDWE) ++ DRM_DEBUG_DRIVER("DSI DPI payload write error\n"); ++ if (val & EOTPE) ++ DRM_DEBUG_DRIVER("DSI EoTp error\n"); ++ if (val & PSE) ++ DRM_DEBUG_DRIVER("DSI Packet size error\n"); ++ if (val & CRCE) ++ DRM_DEBUG_DRIVER("DSI CRC error\n"); ++ if (val & ECCME) ++ DRM_DEBUG_DRIVER("DSI ECC multi-bit error\n"); ++ if (val & ECCSE) ++ DRM_DEBUG_DRIVER("DSI ECC single-bit error\n"); ++ if (val & TOLPRX) ++ DRM_DEBUG_DRIVER("DSI Timeout low-power reception\n"); ++ if (val & TOHSTX) ++ DRM_DEBUG_DRIVER("DSI Timeout high-speed transmission\n"); ++ ++ return val; ++} ++ + static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, + const struct mipi_dsi_packet *packet) + { +@@ -386,6 +436,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, + "failed to get available write payload FIFO\n"); + return ret; + } ++ ++ val = dw_mipi_dsi_read_status(dsi); ++ if (val) { ++ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); ++ return -EINVAL; ++ } + } + + word = 0; +@@ -419,6 +475,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, + return ret; + } + ++ val = dw_mipi_dsi_read_status(dsi); ++ if (val) { ++ dev_err(dsi->dev, "dsi status error 0x%0x\n", val); ++ return -EINVAL; ++ } ++ + val = dsi_read(dsi, DSI_GEN_PLD_DATA); + for (j = 0; j < 4 && j + i < len; j++) + buf[i + j] = val >> (8 * j); +@@ -433,6 +495,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, + struct dw_mipi_dsi *dsi = host_to_dsi(host); + struct mipi_dsi_packet packet; + int ret, nb_bytes; ++ int retry = 3; + + ret = mipi_dsi_create_packet(&packet, msg); + if (ret) { +@@ -442,19 +505,26 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, + + dw_mipi_message_config(dsi, msg); + +- ret = dw_mipi_dsi_write(dsi, &packet); +- if (ret) +- return ret; +- +- if (msg->rx_buf && msg->rx_len) { +- ret = dw_mipi_dsi_read(dsi, msg); ++ while (retry--) { ++ ret = dw_mipi_dsi_write(dsi, &packet); + if (ret) +- return ret; +- nb_bytes = msg->rx_len; +- } else { +- nb_bytes = packet.size; ++ continue; ++ ++ if (msg->rx_buf && msg->rx_len) { ++ ret = dw_mipi_dsi_read(dsi, msg); ++ if (ret) ++ continue; ++ nb_bytes = msg->rx_len; ++ break; ++ } else { ++ nb_bytes = packet.size; ++ break; ++ } + } + ++ if (ret) ++ return ret; ++ + return nb_bytes; + } + +@@ -488,6 +558,9 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, unsigned long mode_flags) { @@ -1105,7 +1198,7 @@ index fd79996..8cd3ee9 100644 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, +@@ -498,6 +571,9 @@ static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); } @@ -1115,7 +1208,7 @@ index fd79996..8cd3ee9 100644 dsi_write(dsi, DSI_PWR_UP, POWERUP); } -@@ -588,6 +594,9 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, +@@ -588,6 +664,9 @@ static void dw_mipi_dsi_video_packet_config(struct dw_mipi_dsi *dsi, static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) { @@ -1125,7 +1218,7 @@ index fd79996..8cd3ee9 100644 /* * 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) +@@ -601,6 +680,9 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) */ dsi_write(dsi, DSI_BTA_TO_CNT, 0xd00); dsi_write(dsi, DSI_MODE_CFG, ENABLE_CMD_MODE); @@ -1392,10 +1485,18 @@ index 7759353..9fe15a4 100644 } diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c -index f2021b2..cf61875 100644 +index f2021b2..f578da4 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c -@@ -26,7 +26,6 @@ +@@ -10,6 +10,7 @@ + + #include + #include ++#include + + #include + #include +@@ -26,7 +27,6 @@ static const struct drm_mode_config_funcs drv_mode_config_funcs = { .fb_create = drm_gem_fb_create, @@ -1403,7 +1504,7 @@ index f2021b2..cf61875 100644 .atomic_check = drm_atomic_helper_check, .atomic_commit = drm_atomic_helper_commit, }; -@@ -52,7 +51,6 @@ DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); +@@ -52,7 +52,6 @@ DEFINE_DRM_GEM_CMA_FOPS(drv_driver_fops); static struct drm_driver drv_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, @@ -1411,7 +1512,7 @@ index f2021b2..cf61875 100644 .name = "stm", .desc = "STMicroelectronics SoC DRM", .date = "20170330", -@@ -72,6 +70,8 @@ static struct drm_driver drv_driver = { +@@ -72,6 +71,8 @@ static struct drm_driver drv_driver = { .gem_prime_vmap = drm_gem_cma_prime_vmap, .gem_prime_vunmap = drm_gem_cma_prime_vunmap, .gem_prime_mmap = drm_gem_cma_prime_mmap, @@ -1420,7 +1521,7 @@ index f2021b2..cf61875 100644 }; static int drv_load(struct drm_device *ddev) -@@ -108,12 +108,6 @@ static int drv_load(struct drm_device *ddev) +@@ -108,12 +109,6 @@ static int drv_load(struct drm_device *ddev) drm_mode_config_reset(ddev); drm_kms_helper_poll_init(ddev); @@ -1433,7 +1534,7 @@ index f2021b2..cf61875 100644 platform_set_drvdata(pdev, ddev); return 0; -@@ -126,12 +120,43 @@ static void drv_unload(struct drm_device *ddev) +@@ -126,12 +121,72 @@ static void drv_unload(struct drm_device *ddev) { DRM_DEBUG("%s\n", __func__); @@ -1449,13 +1550,14 @@ index f2021b2..cf61875 100644 + struct ltdc_device *ldev = ddev->dev_private; + struct drm_atomic_state *state; + -+ drm_kms_helper_poll_disable(ddev); ++ WARN_ON(ldev->suspend_state); ++ + state = drm_atomic_helper_suspend(ddev); -+ if (IS_ERR(state)) { -+ drm_kms_helper_poll_enable(ddev); ++ if (IS_ERR(state)) + return PTR_ERR(state); -+ } ++ + ldev->suspend_state = state; ++ pm_runtime_force_suspend(dev); + + return 0; +} @@ -1464,21 +1566,49 @@ index f2021b2..cf61875 100644 +{ + struct drm_device *ddev = dev_get_drvdata(dev); + struct ltdc_device *ldev = ddev->dev_private; ++ int ret; + -+ drm_atomic_helper_resume(ddev, ldev->suspend_state); -+ drm_kms_helper_poll_enable(ddev); ++ if (WARN_ON(!ldev->suspend_state)) ++ return -ENOENT; ++ ++ pm_runtime_force_resume(dev); ++ ret = drm_atomic_helper_resume(ddev, ldev->suspend_state); ++ if (ret) ++ pm_runtime_force_suspend(dev); ++ ++ ldev->suspend_state = NULL; ++ ++ return ret; ++} ++ ++static __maybe_unused int drv_runtime_suspend(struct device *dev) ++{ ++ struct drm_device *ddev = dev_get_drvdata(dev); ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ltdc_suspend(ddev); + + return 0; +} + ++static __maybe_unused int drv_runtime_resume(struct device *dev) ++{ ++ struct drm_device *ddev = dev_get_drvdata(dev); ++ ++ DRM_DEBUG_DRIVER("\n"); ++ return ltdc_resume(ddev); ++} ++ +static const struct dev_pm_ops drv_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(drv_suspend, drv_resume) ++ SET_RUNTIME_PM_OPS(drv_runtime_suspend, ++ drv_runtime_resume, NULL) +}; + static int stm_drm_platform_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; -@@ -154,6 +179,8 @@ static int stm_drm_platform_probe(struct platform_device *pdev) +@@ -154,6 +209,8 @@ static int stm_drm_platform_probe(struct platform_device *pdev) if (ret) goto err_put; @@ -1487,7 +1617,7 @@ index f2021b2..cf61875 100644 return 0; err_put: -@@ -187,6 +214,7 @@ static struct platform_driver stm_drm_platform_driver = { +@@ -187,6 +244,7 @@ static struct platform_driver stm_drm_platform_driver = { .driver = { .name = "stm32-display", .of_match_table = drv_dt_ids, @@ -1704,10 +1834,19 @@ index a514b59..44e29af 100644 }; diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c -index 808d9fb..3527e69 100644 +index 477d0a2..013b9f9 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c -@@ -148,6 +148,8 @@ +@@ -12,6 +12,8 @@ + #include + #include + #include ++#include ++#include + #include + + #include +@@ -149,6 +151,8 @@ #define IER_TERRIE BIT(2) /* Transfer ERRor Interrupt Enable */ #define IER_RRIE BIT(3) /* Register Reload Interrupt enable */ @@ -1716,73 +1855,57 @@ index 808d9fb..3527e69 100644 #define ISR_LIF BIT(0) /* Line Interrupt Flag */ #define ISR_FUIF BIT(1) /* Fifo Underrun Interrupt Flag */ #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ -@@ -348,6 +350,33 @@ static inline u32 get_pixelformat_without_alpha(u32 drm) - } +@@ -421,9 +425,6 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, + /* Immediately commit the planes */ + reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); + +- /* Enable LTDC */ +- reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); +- + drm_crtc_vblank_on(crtc); } -+static int ltdc_power_up(struct ltdc_device *ldev) -+{ -+ int ret; -+ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ if (!ldev->power_on) { -+ ret = clk_prepare_enable(ldev->pixel_clk); -+ if (ret) { -+ DRM_ERROR("failed to enable pixel clock (%d)\n", -+ ret); -+ return ret; -+ } -+ ldev->power_on = true; -+ } -+ -+ return 0; -+} -+ -+static void ltdc_power_down(struct ltdc_device *ldev) -+{ -+ DRM_DEBUG_DRIVER("\n"); -+ -+ clk_disable_unprepare(ldev->pixel_clk); -+ ldev->power_on = false; -+} -+ - static irqreturn_t ltdc_irq_thread(int irq, void *arg) - { - struct drm_device *ddev = arg; -@@ -408,9 +437,14 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, - struct drm_crtc_state *old_state) +@@ -431,19 +432,19 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, + struct drm_crtc_state *old_state) { struct ltdc_device *ldev = crtc_to_ltdc(crtc); -+ int ret; ++ struct drm_device *ddev = crtc->dev; DRM_DEBUG_DRIVER("\n"); -+ ret = ltdc_power_up(ldev); -+ if (ret) -+ return; -+ - /* Sets the background color value */ - reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); + drm_crtc_vblank_off(crtc); -@@ -443,6 +477,8 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, +- /* disable LTDC */ +- reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); +- + /* disable IRQ */ + reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); /* immediately commit disable of layers before switching off LTDC */ reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); + -+ ltdc_power_down(ldev); ++ pm_runtime_put_sync(ddev->dev); } #define CLK_TOLERANCE_HZ 50 -@@ -493,20 +529,16 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, +@@ -492,33 +493,55 @@ static bool ltdc_crtc_mode_fixup(struct drm_crtc *crtc, + struct drm_display_mode *adjusted_mode) + { struct ltdc_device *ldev = crtc_to_ltdc(crtc); ++ struct drm_device *ddev = crtc->dev; int rate = mode->clock * 1000; ++ bool runtime_active; ++ int ret; - /* - * TODO clk_round_rate() does not work yet. When ready, it can - * be used instead of clk_set_rate() then clk_get_rate(). - */ -- ++ runtime_active = pm_runtime_active(ddev->dev); ++ ++ if (runtime_active) ++ pm_runtime_put_sync(ddev->dev); + - clk_disable(ldev->pixel_clk); if (clk_set_rate(ldev->pixel_clk, rate) < 0) { DRM_ERROR("Cannot set rate (%dHz) for pixel clk\n", rate); @@ -1792,25 +1915,42 @@ index 808d9fb..3527e69 100644 adjusted_mode->clock = clk_get_rate(ldev->pixel_clk) / 1000; ++ if (runtime_active) { ++ ret = pm_runtime_get_sync(ddev->dev); ++ if (ret) { ++ DRM_ERROR("Failed to fixup mode, cannot get sync\n"); ++ return false; ++ } ++ } ++ + DRM_DEBUG_DRIVER("requested clock %dkHz, adjusted clock %dkHz\n", + mode->clock, adjusted_mode->clock); + return true; } -@@ -518,6 +550,11 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) + static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) + { + struct ltdc_device *ldev = crtc_to_ltdc(crtc); ++ struct drm_device *ddev = crtc->dev; + struct drm_display_mode *mode = &crtc->state->adjusted_mode; + struct videomode vm; u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; u32 total_width, total_height; u32 val; + int ret; + -+ ret = ltdc_power_up(ldev); -+ if (ret) -+ return; ++ if (!pm_runtime_active(ddev->dev)) { ++ ret = pm_runtime_get_sync(ddev->dev); ++ if (ret) { ++ DRM_ERROR("Failed to set mode, cannot get sync\n"); ++ return; ++ } ++ } drm_display_mode_to_videomode(mode, &vm); -@@ -546,10 +583,10 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) +@@ -547,10 +570,10 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) val |= GCR_VSPOL; @@ -1823,31 +1963,7 @@ index 808d9fb..3527e69 100644 val |= GCR_PCPOL; reg_update_bits(ldev->regs, LTDC_GCR, -@@ -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); -+ int ret; - - DRM_DEBUG_DRIVER("\n"); -+ -+ ret = ltdc_power_up(ldev); -+ if (ret) -+ return ret; -+ - reg_set(ldev->regs, LTDC_IER, IER_LIE); - - return 0; -@@ -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"); -+ -+ if (!ldev->power_on) { -+ DRM_WARN("power is already down\n"); -+ return; -+ } -+ +@@ -627,6 +650,53 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) reg_clear(ldev->regs, LTDC_IER, IER_LIE); } @@ -1876,15 +1992,19 @@ index 808d9fb..3527e69 100644 + * Computation for the two first cases are identical so we can + * simplify the code and only test if line > vactive_end + */ -+ line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS; -+ vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP; -+ vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH; -+ vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH; ++ if (pm_runtime_active(ddev->dev)) { ++ line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS; ++ vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP; ++ vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH; ++ vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH; + -+ if (line > vactive_end) -+ *vpos = line - vtotal - vactive_start; -+ else -+ *vpos = line - vactive_start; ++ if (line > vactive_end) ++ *vpos = line - vtotal - vactive_start; ++ else ++ *vpos = line - vactive_start; ++ } else { ++ *vpos = 0; ++ } + + *hpos = 0; + @@ -1897,7 +2017,7 @@ index 808d9fb..3527e69 100644 static const struct drm_crtc_funcs ltdc_crtc_funcs = { .destroy = drm_crtc_cleanup, .set_config = drm_atomic_helper_set_config, -@@ -646,24 +738,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, +@@ -647,24 +717,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; @@ -1926,7 +2046,10 @@ index 808d9fb..3527e69 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, @@ -1940,10 +2063,7 @@ index 808d9fb..3527e69 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) @@ -1952,7 +2072,7 @@ index 808d9fb..3527e69 100644 return 0; } -@@ -673,44 +785,36 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -674,44 +764,36 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, { struct ltdc_device *ldev = plane_to_ltdc(plane); struct drm_plane_state *state = plane->state; @@ -2007,7 +2127,7 @@ index 808d9fb..3527e69 100644 reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); -@@ -730,7 +834,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -731,7 +813,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, /* Configures the color frame buffer pitch in bytes & line length */ pitch_in_bytes = fb->pitches[0]; line_length = drm_format_plane_cpp(fb->format->format, 0) * @@ -2016,7 +2136,7 @@ index 808d9fb..3527e69 100644 val = ((pitch_in_bytes << 16) | line_length); reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, LXCFBLR_CFBLL | LXCFBLR_CFBP, val); -@@ -753,7 +857,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -754,7 +836,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, LXBFCR_BF2 | LXBFCR_BF1, val); /* Configures the frame buffer line number */ @@ -2025,7 +2145,7 @@ index 808d9fb..3527e69 100644 reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); /* Sets the FB address */ -@@ -772,11 +876,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -773,11 +855,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, mutex_lock(&ldev->err_lock); if (ldev->error_status & ISR_FUIF) { @@ -2039,7 +2159,7 @@ index 808d9fb..3527e69 100644 ldev->error_status &= ~ISR_TERRIF; } mutex_unlock(&ldev->err_lock); -@@ -814,6 +918,13 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p, +@@ -815,6 +897,13 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p, fpsi->counter = 0; } @@ -2053,7 +2173,7 @@ index 808d9fb..3527e69 100644 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 = { +@@ -823,6 +912,7 @@ static const struct drm_plane_funcs ltdc_plane_funcs = { .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, .atomic_print_state = ltdc_plane_atomic_print_state, @@ -2061,7 +2181,7 @@ index 808d9fb..3527e69 100644 }; 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, +@@ -843,6 +933,10 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, u32 formats[NB_PF * 2]; u32 drm_fmt, drm_fmt_no_alpha; int ret; @@ -2072,7 +2192,7 @@ index 808d9fb..3527e69 100644 /* 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, +@@ -870,7 +964,7 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, ret = drm_universal_plane_init(ddev, plane, possible_crtcs, <dc_plane_funcs, formats, nb_fmt, @@ -2081,7 +2201,102 @@ index 808d9fb..3527e69 100644 if (ret < 0) return NULL; -@@ -1051,14 +1167,15 @@ int ltdc_load(struct drm_device *ddev) +@@ -942,6 +1036,54 @@ static const struct drm_encoder_funcs ltdc_encoder_funcs = { + .destroy = drm_encoder_cleanup, + }; + ++static void ltdc_encoder_disable(struct drm_encoder *encoder) ++{ ++ struct drm_device *ddev = encoder->dev; ++ struct ltdc_device *ldev = ddev->dev_private; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ /* Disable LTDC */ ++ reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); ++ ++ /* Set to sleep state the pinctrl whatever type of encoder */ ++ pinctrl_pm_select_sleep_state(ddev->dev); ++} ++ ++static void ltdc_encoder_enable(struct drm_encoder *encoder) ++{ ++ struct drm_device *ddev = encoder->dev; ++ struct ltdc_device *ldev = ddev->dev_private; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ /* Enable LTDC */ ++ reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); ++} ++ ++static void ltdc_encoder_mode_set(struct drm_encoder *encoder, ++ struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct drm_device *ddev = encoder->dev; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ /* ++ * Set to default state the pinctrl only with DPI type. ++ * Others types like DSI, don't need pinctrl due to ++ * internal bridge (the signals do not come out of the chipset). ++ */ ++ if (encoder->encoder_type == DRM_MODE_ENCODER_DPI) ++ pinctrl_pm_select_default_state(ddev->dev); ++} ++ ++static const struct drm_encoder_helper_funcs ltdc_encoder_helper_funcs = { ++ .disable = ltdc_encoder_disable, ++ .enable = ltdc_encoder_enable, ++ .mode_set = ltdc_encoder_mode_set, ++}; ++ + static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) + { + struct drm_encoder *encoder; +@@ -957,6 +1099,8 @@ static int ltdc_encoder_init(struct drm_device *ddev, struct drm_bridge *bridge) + drm_encoder_init(ddev, encoder, <dc_encoder_funcs, + DRM_MODE_ENCODER_DPI, NULL); + ++ drm_encoder_helper_add(encoder, <dc_encoder_helper_funcs); ++ + ret = drm_bridge_attach(encoder, bridge, NULL); + if (ret) { + drm_encoder_cleanup(encoder); +@@ -1014,6 +1158,30 @@ static int ltdc_get_caps(struct drm_device *ddev) + return 0; + } + ++void ltdc_suspend(struct drm_device *ddev) ++{ ++ struct ltdc_device *ldev = ddev->dev_private; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ clk_disable_unprepare(ldev->pixel_clk); ++} ++ ++int ltdc_resume(struct drm_device *ddev) ++{ ++ struct ltdc_device *ldev = ddev->dev_private; ++ int ret; ++ ++ DRM_DEBUG_DRIVER("\n"); ++ ++ ret = clk_prepare_enable(ldev->pixel_clk); ++ if (ret) { ++ DRM_ERROR("failed to enable pixel clock (%d)\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ + int ltdc_load(struct drm_device *ddev) + { + struct platform_device *pdev = to_platform_device(ddev->dev); +@@ -1053,8 +1221,9 @@ int ltdc_load(struct drm_device *ddev) ldev->pixel_clk = devm_clk_get(dev, "lcd"); if (IS_ERR(ldev->pixel_clk)) { @@ -2092,18 +2307,8 @@ index 808d9fb..3527e69 100644 + return PTR_ERR(ldev->pixel_clk); } -- if (clk_prepare_enable(ldev->pixel_clk)) { -- DRM_ERROR("Unable to prepare pixel clock\n"); -- return -ENODEV; -- } -+ ldev->power_on = false; -+ ret = ltdc_power_up(ldev); -+ if (ret) -+ return ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ldev->regs = devm_ioremap_resource(dev, res); -@@ -1070,6 +1187,9 @@ int ltdc_load(struct drm_device *ddev) + if (clk_prepare_enable(ldev->pixel_clk)) { +@@ -1072,6 +1241,9 @@ int ltdc_load(struct drm_device *ddev) for (i = 0; i < MAX_IRQ; i++) { irq = platform_get_irq(pdev, i); @@ -2113,7 +2318,7 @@ index 808d9fb..3527e69 100644 if (irq < 0) continue; -@@ -1129,6 +1249,8 @@ int ltdc_load(struct drm_device *ddev) +@@ -1131,6 +1303,8 @@ int ltdc_load(struct drm_device *ddev) goto err; } @@ -2122,34 +2327,47 @@ index 808d9fb..3527e69 100644 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) +@@ -1146,8 +1320,13 @@ int ltdc_load(struct drm_device *ddev) + /* Allow usage of vblank without having to call drm_irq_install */ + ddev->irq_enabled = 1; + +- return 0; ++ clk_disable_unprepare(ldev->pixel_clk); ++ ++ pinctrl_pm_select_sleep_state(ddev->dev); ++ ++ pm_runtime_enable(ddev->dev); + ++ return 0; + err: for (i = 0; i < MAX_ENDPOINTS; i++) drm_panel_bridge_remove(bridge[i]); +@@ -1159,7 +1338,6 @@ int ltdc_load(struct drm_device *ddev) -- clk_disable_unprepare(ldev->pixel_clk); -+ ltdc_power_down(ldev); + void ltdc_unload(struct drm_device *ddev) + { +- struct ltdc_device *ldev = ddev->dev_private; + int i; - return ret; - } -@@ -1165,7 +1287,7 @@ void ltdc_unload(struct drm_device *ddev) + DRM_DEBUG_DRIVER("\n"); +@@ -1167,7 +1345,7 @@ void ltdc_unload(struct drm_device *ddev) for (i = 0; i < MAX_ENDPOINTS; i++) drm_of_panel_bridge_remove(ddev->dev->of_node, 0, i); - clk_disable_unprepare(ldev->pixel_clk); -+ ltdc_power_down(ldev); ++ pm_runtime_disable(ddev->dev); } MODULE_AUTHOR("Philippe Cornu "); diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h -index d5afb89..08bd69d 100644 +index d5afb89..9b410c6 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h -@@ -36,8 +36,14 @@ struct ltdc_device { +@@ -36,9 +36,16 @@ struct ltdc_device { u32 error_status; u32 irq_status; struct fps_info plane_fpsi[LTDC_MAX_LAYER]; + struct drm_atomic_state *suspend_state; -+ bool power_on; }; +bool ltdc_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, @@ -2158,7 +2376,10 @@ index d5afb89..08bd69d 100644 + const struct drm_display_mode *mode); int ltdc_load(struct drm_device *ddev); void ltdc_unload(struct drm_device *ddev); ++void ltdc_suspend(struct drm_device *ddev); ++int ltdc_resume(struct drm_device *ddev); + #endif diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h index d9c6d54..0fdc550 100644 --- a/include/drm/bridge/dw_mipi_dsi.h 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.94/0008-ARM-stm32mp1-r3-GPIO.patch similarity index 88% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0007-ARM-stm32mp1-r2-GPIO.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch index c10b917..d0e5686 100644 --- 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.94/0008-ARM-stm32mp1-r3-GPIO.patch @@ -1,7 +1,7 @@ -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 +From 7aa67bec68104aebb6a182e12cbfd62dfa81a5d3 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Fri, 8 Nov 2019 16:52:40 +0100 +Subject: [PATCH 08/31] ARM stm32mp1 r3 GPIO --- drivers/gpio/gpiolib-of.c | 5 +++++ @@ -29,10 +29,10 @@ index e0f149b..a8cba78 100644 } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c -index fd713326..af5d0e6 100644 +index a24f13d..aa750f9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c -@@ -2519,6 +2519,14 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); +@@ -2537,6 +2537,14 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc); * rely on gpio_request() having been called beforehand. */ @@ -47,7 +47,7 @@ index fd713326..af5d0e6 100644 /** * 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) +@@ -2573,20 +2581,19 @@ int gpiod_direction_input(struct gpio_desc *desc) if (status == 0) clear_bit(FLAG_IS_OUT, &desc->flags); @@ -75,7 +75,7 @@ index fd713326..af5d0e6 100644 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) +@@ -2672,8 +2679,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) gc = desc->gdev->chip; if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) { /* First see if we can enable open drain in hardware */ @@ -86,8 +86,8 @@ index fd713326..af5d0e6 100644 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); +@@ -2683,8 +2690,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) + } } else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) { - ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), @@ -97,8 +97,9 @@ index fd713326..af5d0e6 100644 if (!ret) goto set_output_value; /* Emulate open source by not actively driving the line low */ - if (!value) - return gpiod_direction_input(desc); +@@ -2693,8 +2700,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value) + goto set_output_flag; + } } else { - gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc), - PIN_CONFIG_DRIVE_PUSH_PULL); @@ -107,7 +108,7 @@ index fd713326..af5d0e6 100644 } set_output_value: -@@ -2684,7 +2691,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) +@@ -2737,7 +2744,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce) } config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce); @@ -116,7 +117,7 @@ index fd713326..af5d0e6 100644 } EXPORT_SYMBOL_GPL(gpiod_set_debounce); -@@ -2721,7 +2728,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) +@@ -2774,7 +2781,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory) packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE, !transitory); gpio = gpio_chip_hwgpio(desc); @@ -125,7 +126,7 @@ index fd713326..af5d0e6 100644 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, +@@ -3908,6 +3915,17 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, if (lflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); 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.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch similarity index 97% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch index e4fb183..5f226fe 100644 --- 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.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch @@ -1,7 +1,7 @@ -From 7f9a7065bc23ee2da17c45ff4097cdbc9b70065d Mon Sep 17 00:00:00 2001 +From da8d8b897bc61f58b87237394c4a9ff4f89e906d 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 +Date: Fri, 8 Nov 2019 16:52:40 +0100 +Subject: [PATCH 09/31] ARM stm32mp1 r3 HWSPINLOCK --- drivers/hwspinlock/Kconfig | 9 ++ diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0009-ARM-stm32mp1-r2-HWTRACING-I2C.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch similarity index 51% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0009-ARM-stm32mp1-r2-HWTRACING-I2C.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch index d4e3d1f..d58bde2 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0009-ARM-stm32mp1-r2-HWTRACING-I2C.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch @@ -1,12 +1,13 @@ -From 7394fe2e090d58063b852b0baeca2fc65f8cd07b Mon Sep 17 00:00:00 2001 +From 4091e5a5278a8434585a9a3ab578d8920f41351c 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 +Date: Fri, 8 Nov 2019 16:52:40 +0100 +Subject: [PATCH 10/31] ARM stm32mp1 r3 HWTRACING I2C --- - drivers/hwtracing/coresight/coresight-stm.c | 58 +++- - drivers/i2c/busses/i2c-stm32f7.c | 470 ++++++++++++++++++++++++---- - 2 files changed, 469 insertions(+), 59 deletions(-) + drivers/hwtracing/coresight/coresight-stm.c | 58 +- + drivers/i2c/busses/Kconfig | 1 + + drivers/i2c/busses/i2c-stm32f7.c | 834 ++++++++++++++++++++++++---- + 3 files changed, 774 insertions(+), 119 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index c46c70a..65687c0 100644 @@ -147,11 +148,27 @@ index c46c70a..65687c0 100644 ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res); if (ret) return ret; +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index ee6dd1b..48bbbc9 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -963,6 +963,7 @@ config I2C_STM32F7 + tristate "STMicroelectronics STM32F7 I2C support" + depends on ARCH_STM32 || COMPILE_TEST + select I2C_SLAVE ++ select I2C_SMBUS + help + Enable this option to add support for STM32 I2C controller embedded + in STM32F7 SoCs. diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index a492da9..b052f3e 100644 +index f4e3613..08b7416 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c -@@ -21,12 +21,16 @@ +@@ -18,14 +18,20 @@ + #include + #include + #include ++#include #include #include #include @@ -159,7 +176,6 @@ index a492da9..b052f3e 100644 #include #include #include --#include #include #include +#include @@ -169,15 +185,42 @@ index a492da9..b052f3e 100644 #include #include -@@ -46,6 +50,7 @@ +@@ -45,6 +51,9 @@ /* STM32F7 I2C control 1 */ #define STM32F7_I2C_CR1_PECEN BIT(23) ++#define STM32F7_I2C_CR1_ALERTEN BIT(22) ++#define STM32F7_I2C_CR1_SMBHEN BIT(20) +#define STM32F7_I2C_CR1_WUPEN BIT(18) #define STM32F7_I2C_CR1_SBC BIT(16) #define STM32F7_I2C_CR1_RXDMAEN BIT(15) #define STM32F7_I2C_CR1_TXDMAEN BIT(14) -@@ -163,6 +168,26 @@ +@@ -115,6 +124,7 @@ + (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) + #define STM32F7_I2C_ISR_DIR BIT(16) + #define STM32F7_I2C_ISR_BUSY BIT(15) ++#define STM32F7_I2C_ISR_ALERT BIT(13) + #define STM32F7_I2C_ISR_PECERR BIT(11) + #define STM32F7_I2C_ISR_ARLO BIT(9) + #define STM32F7_I2C_ISR_BERR BIT(8) +@@ -128,6 +138,7 @@ + #define STM32F7_I2C_ISR_TXE BIT(0) + + /* STM32F7 I2C Interrupt Clear */ ++#define STM32F7_I2C_ICR_ALERTCF BIT(13) + #define STM32F7_I2C_ICR_PECCF BIT(11) + #define STM32F7_I2C_ICR_ARLOCF BIT(9) + #define STM32F7_I2C_ICR_BERRCF BIT(8) +@@ -144,7 +155,7 @@ + + #define STM32F7_I2C_MAX_LEN 0xff + #define STM32F7_I2C_DMA_LEN_MIN 0x16 +-#define STM32F7_I2C_MAX_SLAVE 0x2 ++#define STM32F7_I2C_MAX_SLAVE 0x3 + + #define STM32F7_I2C_DNF_DEFAULT 0 + #define STM32F7_I2C_DNF_MAX 16 +@@ -162,11 +173,29 @@ #define STM32F7_SCLH_MAX BIT(8) #define STM32F7_SCLL_MAX BIT(8) @@ -204,7 +247,63 @@ index a492da9..b052f3e 100644 /** * struct stm32f7_i2c_spec - private i2c specification timing * @rate: I2C bus speed (Hz) -@@ -259,6 +284,8 @@ struct stm32f7_i2c_msg { +- * @rate_min: 80% of I2C bus speed (Hz) +- * @rate_max: 100% of I2C bus speed (Hz) + * @fall_max: Max fall time of both SDA and SCL signals (ns) + * @rise_max: Max rise time of both SDA and SCL signals (ns) + * @hddat_min: Min data hold time (ns) +@@ -177,8 +206,6 @@ + */ + struct stm32f7_i2c_spec { + u32 rate; +- u32 rate_min; +- u32 rate_max; + u32 fall_max; + u32 rise_max; + u32 hddat_min; +@@ -190,7 +217,6 @@ struct stm32f7_i2c_spec { + + /** + * struct stm32f7_i2c_setup - private I2C timing setup parameters +- * @speed: I2C speed mode (standard, Fast Plus) + * @speed_freq: I2C speed frequency (Hz) + * @clock_src: I2C clock source frequency (Hz) + * @rise_time: Rise time (ns) +@@ -199,7 +225,6 @@ struct stm32f7_i2c_spec { + * @analog_filter: Analog filter delay (On/Off) + */ + struct stm32f7_i2c_setup { +- enum stm32_i2c_speed speed; + u32 speed_freq; + u32 clock_src; + u32 rise_time; +@@ -255,13 +280,38 @@ struct stm32f7_i2c_msg { + }; + + /** ++ * struct stm32f7_i2c_host - SMBus host specific data ++ * @client: I2C slave device that represents SMBus host ++ * @notify_start: indicate that this is the start of the notify transaction ++ * @addr: device address of SMBus device that initiate SMBus host protocol ++ */ ++struct stm32f7_i2c_host { ++ struct i2c_client *client; ++ bool notify_start; ++ u8 addr; ++}; ++ ++/** ++ * struct stm32f7_i2c_alert - SMBus alert specific data ++ * @setup: platform data for the smbus_alert i2c client ++ * @ara: I2C slave device used to respond to the SMBus Alert with Alert ++ * Response Address ++ */ ++struct stm32f7_i2c_alert { ++ struct i2c_smbus_alert_setup setup; ++ struct i2c_client *ara; ++}; ++ ++/** * struct stm32f7_i2c_dev - private data of the controller * @adap: I2C adapter for this controller * @dev: device for this controller @@ -213,17 +312,26 @@ index a492da9..b052f3e 100644 * @base: virtual memory area * @complete: completion of I2C message * @clk: hw i2c clock -@@ -276,11 +303,19 @@ struct stm32f7_i2c_msg { +- * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+ ++ * @bus_rate: I2C clock frequency of the controller. + * @msg: Pointer to data to be written + * @msg_num: number of I2C messages to be executed + * @msg_id: message identifiant +@@ -275,14 +325,25 @@ struct stm32f7_i2c_msg { * slave) * @dma: dma data * @use_dma: boolean to know if dma is used in the current transfer +- */ + * @sregmap: holds SYSCFG phandle for Fast Mode Plus bits + * @cregmap: holds SYSCFG phandle for Fast Mode Plus clear bits + * @regmap_sreg: register address for setting Fast Mode Plus bits + * @regmap_smask: mask for Fast Mode Plus bits in set register + * @regmap_creg: register address for setting Fast Mode Plus bits + * @regmap_cmask: mask for Fast Mode Plus bits in set register - */ ++ * @is_suspended: boolean to know if the driver has been suspended ++ * @host: SMBus host protocol specific data ++ * @alert: SMBus alert specific data ++*/ struct stm32f7_i2c_dev { struct i2c_adapter adap; struct device *dev; @@ -232,8 +340,12 @@ index a492da9..b052f3e 100644 + int irq_wakeup; struct completion complete; struct clk *clk; - int speed; -@@ -292,10 +327,17 @@ struct stm32f7_i2c_dev { +- int speed; ++ unsigned int bus_rate; + struct i2c_msg *msg; + unsigned int msg_num; + unsigned int msg_id; +@@ -291,10 +352,20 @@ struct stm32f7_i2c_dev { struct stm32f7_i2c_timings timing; struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE]; struct i2c_client *slave_running; @@ -248,10 +360,141 @@ index a492da9..b052f3e 100644 + u32 regmap_smask; + u32 regmap_creg; + u32 regmap_cmask; ++ bool is_suspended; ++ struct stm32f7_i2c_host *host; ++ struct stm32f7_i2c_alert *alert; }; - /** -@@ -468,8 +510,12 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + /* +@@ -304,11 +375,13 @@ struct stm32f7_i2c_dev { + * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast, + * and Fast-mode Plus I2C-bus devices + */ ++#define I2C_STD_RATE 100000 ++#define I2C_FAST_RATE 400000 ++#define I2C_FASTPLUS_RATE 1000000 + static struct stm32f7_i2c_spec i2c_specs[] = { +- [STM32_I2C_SPEED_STANDARD] = { +- .rate = 100000, +- .rate_min = 80000, +- .rate_max = 100000, ++ /* Standard - 100KHz */ ++ { ++ .rate = I2C_STD_RATE, + .fall_max = 300, + .rise_max = 1000, + .hddat_min = 0, +@@ -317,10 +390,9 @@ static struct stm32f7_i2c_spec i2c_specs[] = { + .l_min = 4700, + .h_min = 4000, + }, +- [STM32_I2C_SPEED_FAST] = { +- .rate = 400000, +- .rate_min = 320000, +- .rate_max = 400000, ++ /* Fast - 400KHz */ ++ { ++ .rate = I2C_FAST_RATE, + .fall_max = 300, + .rise_max = 300, + .hddat_min = 0, +@@ -329,10 +401,9 @@ static struct stm32f7_i2c_spec i2c_specs[] = { + .l_min = 1300, + .h_min = 600, + }, +- [STM32_I2C_SPEED_FAST_PLUS] = { +- .rate = 1000000, +- .rate_min = 800000, +- .rate_max = 1000000, ++ /* FastPlus - 1MHz */ ++ { ++ .rate = I2C_FASTPLUS_RATE, + .fall_max = 100, + .rise_max = 120, + .hddat_min = 0, +@@ -365,10 +436,24 @@ static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); + } + ++static struct stm32f7_i2c_spec *get_specs(u32 rate) ++{ ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++) ++ if (rate <= i2c_specs[i].rate) ++ return &i2c_specs[i]; ++ ++ /* NOT REACHED */ ++ return ERR_PTR(-EINVAL); ++} ++ ++#define RATE_MIN(rate) (rate / 100 * 80) + static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + struct stm32f7_i2c_setup *setup, + struct stm32f7_i2c_timings *output) + { ++ struct stm32f7_i2c_spec *specs; + u32 p_prev = STM32F7_PRESC_MAX; + u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, + setup->clock_src); +@@ -386,18 +471,19 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + u16 p, l, a, h; + int ret = 0; + +- if (setup->speed >= STM32_I2C_SPEED_END) { +- dev_err(i2c_dev->dev, "speed out of bound {%d/%d}\n", +- setup->speed, STM32_I2C_SPEED_END - 1); ++ specs = get_specs(setup->speed_freq); ++ if (specs == ERR_PTR(-EINVAL)) { ++ dev_err(i2c_dev->dev, "speed out of bound {%d}\n", ++ setup->speed_freq); + return -EINVAL; + } + +- if ((setup->rise_time > i2c_specs[setup->speed].rise_max) || +- (setup->fall_time > i2c_specs[setup->speed].fall_max)) { ++ if ((setup->rise_time > specs->rise_max) || ++ (setup->fall_time > specs->fall_max)) { + dev_err(i2c_dev->dev, + "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", +- setup->rise_time, i2c_specs[setup->speed].rise_max, +- setup->fall_time, i2c_specs[setup->speed].fall_max); ++ setup->rise_time, specs->rise_max, ++ setup->fall_time, specs->fall_max); + return -EINVAL; + } + +@@ -408,12 +494,6 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + return -EINVAL; + } + +- if (setup->speed_freq > i2c_specs[setup->speed].rate) { +- dev_err(i2c_dev->dev, "ERROR: Freq {%d/%d}\n", +- setup->speed_freq, i2c_specs[setup->speed].rate); +- return -EINVAL; +- } +- + /* Analog and Digital Filters */ + af_delay_min = + (setup->analog_filter ? +@@ -423,13 +503,13 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); + dnf_delay = setup->dnf * i2cclk; + +- sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - ++ sdadel_min = specs->hddat_min + setup->fall_time - + af_delay_min - (setup->dnf + 3) * i2cclk; + +- sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - ++ sdadel_max = specs->vddat_max - setup->rise_time - + af_delay_max - (setup->dnf + 4) * i2cclk; + +- scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min; ++ scldel_min = setup->rise_time + specs->sudat_min; + + if (sdadel_min < 0) + sdadel_min = 0; +@@ -467,8 +547,12 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, list_add_tail(&v->node, &solutions); @@ -264,7 +507,98 @@ index a492da9..b052f3e 100644 } } -@@ -941,6 +987,9 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, +@@ -480,8 +564,8 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + + tsync = af_delay_min + dnf_delay + (2 * i2cclk); + s = NULL; +- clk_max = NSEC_PER_SEC / i2c_specs[setup->speed].rate_min; +- clk_min = NSEC_PER_SEC / i2c_specs[setup->speed].rate_max; ++ clk_max = NSEC_PER_SEC / RATE_MIN(setup->speed_freq); ++ clk_min = NSEC_PER_SEC / setup->speed_freq; + + /* + * Among Prescaler possibilities discovered above figures out SCL Low +@@ -499,7 +583,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + for (l = 0; l < STM32F7_SCLL_MAX; l++) { + u32 tscl_l = (l + 1) * prescaler + tsync; + +- if ((tscl_l < i2c_specs[setup->speed].l_min) || ++ if ((tscl_l < specs->l_min) || + (i2cclk >= + ((tscl_l - af_delay_min - dnf_delay) / 4))) { + continue; +@@ -511,7 +595,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + setup->rise_time + setup->fall_time; + + if ((tscl >= clk_min) && (tscl <= clk_max) && +- (tscl_h >= i2c_specs[setup->speed].h_min) && ++ (tscl_h >= specs->h_min) && + (i2cclk < tscl_h)) { + int clk_error = tscl - i2cbus; + +@@ -557,13 +641,23 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, + return ret; + } + ++static u32 get_lower_rate(u32 rate) ++{ ++ int i; ++ ++ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--) ++ if (i2c_specs[i].rate < rate) ++ return i2c_specs[i].rate; ++ ++ return i2c_specs[0].rate; ++} ++ + static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, + struct stm32f7_i2c_setup *setup) + { + int ret = 0; + +- setup->speed = i2c_dev->speed; +- setup->speed_freq = i2c_specs[setup->speed].rate; ++ setup->speed_freq = i2c_dev->bus_rate; + setup->clock_src = clk_get_rate(i2c_dev->clk); + + if (!setup->clock_src) { +@@ -577,14 +671,12 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, + if (ret) { + dev_err(i2c_dev->dev, + "failed to compute I2C timings.\n"); +- if (i2c_dev->speed > STM32_I2C_SPEED_STANDARD) { +- i2c_dev->speed--; +- setup->speed = i2c_dev->speed; ++ if (setup->speed_freq > I2C_STD_RATE) { + setup->speed_freq = +- i2c_specs[setup->speed].rate; ++ get_lower_rate(setup->speed_freq); + dev_warn(i2c_dev->dev, + "downgrade I2C Speed Freq to (%i)\n", +- i2c_specs[setup->speed].rate); ++ setup->speed_freq); + } else { + break; + } +@@ -596,13 +688,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, + return ret; + } + +- dev_dbg(i2c_dev->dev, "I2C Speed(%i), Freq(%i), Clk Source(%i)\n", +- setup->speed, setup->speed_freq, setup->clock_src); ++ dev_dbg(i2c_dev->dev, "I2C Freq(%i), Clk Source(%i)\n", ++ setup->speed_freq, setup->clock_src); + dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n", + setup->rise_time, setup->fall_time); + dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n", + (setup->analog_filter ? "On" : "Off"), setup->dnf); + ++ i2c_dev->bus_rate = setup->speed_freq; ++ + return 0; + } + +@@ -940,6 +1034,9 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, cr2 &= ~STM32F7_I2C_CR2_RD_WRN; f7_msg->read_write = I2C_SMBUS_READ; break; @@ -274,27 +608,63 @@ index a492da9..b052f3e 100644 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); +@@ -1249,11 +1346,21 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, + int i; -+ /* 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); + /* +- * slave[0] supports 7-bit and 10-bit slave address +- * slave[1] supports 7-bit slave address only ++ * slave[0] support only SMBus Host address (0x8) ++ * slave[1] supports 7-bit and 10-bit slave address ++ * slave[2] supports 7-bit slave address only + */ +- for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { +- if (i == 1 && (slave->flags & I2C_CLIENT_PEC)) ++ if (i2c_dev->host) { ++ if (slave->addr == 0x08) { ++ if (i2c_dev->slave[0]) ++ goto fail; ++ *id = 0; ++ return 0; ++ } ++ } + -+ if (!i2c_dev->slave_running) -+ stm32f7_i2c_disable_irq(i2c_dev, mask); ++ for (i = STM32F7_I2C_MAX_SLAVE - 1; i >= 0; i--) { ++ if (i == 2 && (slave->flags & I2C_CLIENT_TEN)) + continue; + if (!i2c_dev->slave[i]) { + *id = i; +@@ -1261,6 +1368,7 @@ static int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, + } + } - /* Disable dma */ - if (i2c_dev->use_dma) { -@@ -1545,15 +1598,13 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, ++fail: + dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr); + + return -EINVAL; +@@ -1513,6 +1621,13 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) + f7_msg->result = -EINVAL; + } + ++ if (status & STM32F7_I2C_ISR_ALERT) { ++ dev_dbg(dev, "<%s>: SMBus alert received\n", __func__); ++ writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); ++ i2c_handle_smbus_alert(i2c_dev->alert->ara); ++ return IRQ_HANDLED; ++ } ++ + if (!i2c_dev->slave_running) { + u32 mask; + /* Disable interrupts */ +@@ -1544,20 +1659,21 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, + unsigned long time_left; + int ret; + ++ if (i2c_dev->is_suspended) ++ return -EBUSY; ++ + i2c_dev->msg = msgs; + i2c_dev->msg_num = num; i2c_dev->msg_id = 0; f7_msg->smbus = false; @@ -313,7 +683,7 @@ index a492da9..b052f3e 100644 stm32f7_i2c_xfer_msg(i2c_dev, msgs); -@@ -1569,8 +1620,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, +@@ -1573,8 +1689,9 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, ret = -ETIMEDOUT; } @@ -325,7 +695,15 @@ index a492da9..b052f3e 100644 return (ret < 0) ? ret : num; } -@@ -1592,39 +1644,37 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, +@@ -1591,44 +1708,45 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + unsigned long timeout; + int i, ret; + ++ if (i2c_dev->is_suspended) ++ return -EBUSY; ++ + f7_msg->addr = addr; + f7_msg->size = size; f7_msg->read_write = read_write; f7_msg->smbus = true; @@ -372,7 +750,7 @@ index a492da9..b052f3e 100644 } if (read_write && size != I2C_SMBUS_QUICK) { -@@ -1649,11 +1699,15 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, +@@ -1653,11 +1771,15 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, } } @@ -390,7 +768,7 @@ index a492da9..b052f3e 100644 static int stm32f7_i2c_reg_slave(struct i2c_client *slave) { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); -@@ -1676,13 +1730,12 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +@@ -1680,15 +1802,20 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) if (ret) return ret; @@ -404,13 +782,31 @@ index a492da9..b052f3e 100644 + ret = pm_runtime_get_sync(dev); + if (ret < 0) + return ret; -+ + +- if (id == 0) { + if (!stm32f7_i2c_is_slave_registered(i2c_dev)) + stm32f7_i2c_enable_wakeup(i2c_dev, true); - - if (id == 0) { ++ ++ switch (id) { ++ case 0: ++ /* Slave SMBus Host */ ++ i2c_dev->slave[id] = slave; ++ break; ++ ++ case 1: /* Configure Own Address 1 */ -@@ -1703,7 +1756,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); + oar1 &= ~STM32F7_I2C_OAR1_MASK; +@@ -1701,22 +1828,27 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + oar1 |= STM32F7_I2C_OAR1_OA1EN; + i2c_dev->slave[id] = slave; + writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1); +- } else if (id == 1) { ++ break; ++ ++ case 2: + /* Configure Own Address 2 */ + oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); oar2 &= ~STM32F7_I2C_OAR2_MASK; if (slave->flags & I2C_CLIENT_TEN) { ret = -EOPNOTSUPP; @@ -419,16 +815,21 @@ index a492da9..b052f3e 100644 } oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr); -@@ -1712,7 +1765,7 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) + oar2 |= STM32F7_I2C_OAR2_OA2EN; + i2c_dev->slave[id] = slave; writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2); - } else { +- } else { ++ break; ++ ++ default: ++ dev_err(dev, "I2C slave id not supported\n"); ret = -ENODEV; - goto exit; + goto pm_free; } /* Enable ACK */ -@@ -1723,11 +1776,13 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) +@@ -1727,11 +1859,13 @@ static int stm32f7_i2c_reg_slave(struct i2c_client *slave) STM32F7_I2C_CR1_PE; stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); @@ -446,18 +847,23 @@ index a492da9..b052f3e 100644 return ret; } -@@ -1745,6 +1800,10 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) +@@ -1749,31 +1883,246 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) WARN_ON(!i2c_dev->slave[id]); +- if (id == 0) { + ret = pm_runtime_get_sync(i2c_dev->dev); + if (ret < 0) + return ret; + - if (id == 0) { ++ if (id == 1) { mask = STM32F7_I2C_OAR1_OA1EN; stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask); -@@ -1755,21 +1814,106 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) +- } else { ++ } else if (id == 2) { + mask = STM32F7_I2C_OAR2_OA2EN; + stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask); + } i2c_dev->slave[id] = NULL; @@ -466,14 +872,14 @@ index a492da9..b052f3e 100644 stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); - clk_disable(i2c_dev->clk); + stm32f7_i2c_enable_wakeup(i2c_dev, false); - } - ++ } ++ + pm_runtime_mark_last_busy(i2c_dev->dev); + pm_runtime_put_autosuspend(i2c_dev->dev); + - return 0; - } - ++ return 0; ++} ++ +static int stm32f7_i2c_setup_wakeup(struct stm32f7_i2c_dev *i2c_dev) +{ + int ret; @@ -495,7 +901,7 @@ index a492da9..b052f3e 100644 + int ret; + u32 reg, mask; + -+ if (i2c_dev->speed != STM32_I2C_SPEED_FAST_PLUS || ++ if (i2c_dev->bus_rate <= I2C_FAST_RATE || + IS_ERR_OR_NULL(i2c_dev->sregmap)) { + /* Optional */ + return 0; @@ -554,6 +960,132 @@ index a492da9..b052f3e 100644 + + return stm32f7_i2c_write_fm_plus_bits(i2c_dev, 1); +} ++ ++static int stm32f7_i2c_smbus_host_cb(struct i2c_client *client, ++ enum i2c_slave_event event, ++ u8 *val) ++{ ++ struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(client->adapter); ++ struct stm32f7_i2c_host *host = i2c_dev->host; ++ int ret; ++ ++ switch (event) { ++ case I2C_SLAVE_WRITE_REQUESTED: ++ host->notify_start = true; ++ break; ++ case I2C_SLAVE_WRITE_RECEIVED: ++ /* We only retrieve the first byte received (addr) ++ * From Documentation/i2c/smbus-protocol: ++ * There is currently no way to retrieve the data parameter ++ * from the client. ++ */ ++ if (!host->notify_start) ++ break; ++ host->addr = *val; ++ host->notify_start = false; ++ break; ++ case I2C_SLAVE_STOP: ++ ret = i2c_handle_smbus_host_notify(client->adapter, ++ host->addr); ++ if (ret < 0) { ++ dev_dbg(i2c_dev->dev, "failed to handle host_notify (%d)\n", ++ ret); ++ return ret; ++ } ++ break; ++ default: ++ dev_err(i2c_dev->dev, "slave event not supported\n"); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ struct stm32f7_i2c_host *host; ++ struct i2c_adapter *adap = &i2c_dev->adap; ++ struct device *dev = i2c_dev->dev; ++ void __iomem *base = i2c_dev->base; ++ struct i2c_board_info host_notify_board_info = { ++ I2C_BOARD_INFO("smbus_host_notify", 0x8), ++ .flags = I2C_CLIENT_SLAVE, ++ }; ++ int ret; ++ ++ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); ++ if (!host) ++ return -ENOMEM; ++ ++ host->client = i2c_new_device(adap, &host_notify_board_info); ++ if (!host->client) ++ return -ENOMEM; ++ ++ i2c_dev->host = host; ++ ++ ret = i2c_slave_register(host->client, stm32f7_i2c_smbus_host_cb); ++ if (ret) { ++ i2c_dev->host = NULL; ++ i2c_unregister_device(host->client); ++ return ret; + } + ++ /* Enable SMBus Host address */ ++ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_SMBHEN); ++ + return 0; + } + ++static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ void __iomem *base = i2c_dev->base; ++ struct stm32f7_i2c_host *host = i2c_dev->host; ++ ++ if (host) { ++ /* Disable SMBus Host address */ ++ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, ++ STM32F7_I2C_CR1_SMBHEN); ++ i2c_slave_unregister(host->client); ++ i2c_dev->host = NULL; ++ i2c_unregister_device(host->client); ++ } ++} ++ ++static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ struct stm32f7_i2c_alert *alert; ++ struct i2c_adapter *adap = &i2c_dev->adap; ++ struct device *dev = i2c_dev->dev; ++ void __iomem *base = i2c_dev->base; ++ ++ alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL); ++ if (!alert) ++ return -ENOMEM; ++ ++ alert->ara = i2c_setup_smbus_alert(adap, &alert->setup); ++ if (!alert->ara) ++ return -ENOMEM; ++ ++ i2c_dev->alert = alert; ++ ++ /* Enable SMBus Alert */ ++ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN); ++ ++ return 0; ++} ++ ++static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev) ++{ ++ struct stm32f7_i2c_alert *alert = i2c_dev->alert; ++ void __iomem *base = i2c_dev->base; ++ ++ if (alert) { ++ /* Disable SMBus Alert */ ++ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, ++ STM32F7_I2C_CR1_ALERTEN); ++ i2c_unregister_device(alert->ara); ++ } ++} + static u32 stm32f7_i2c_func(struct i2c_adapter *adap) { @@ -563,66 +1095,60 @@ index a492da9..b052f3e 100644 I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | - I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC; + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC | -+ I2C_FUNC_SMBUS_I2C_BLOCK; ++ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HOST_NOTIFY; } 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; +@@ -1789,11 +2138,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) struct stm32f7_i2c_dev *i2c_dev; const struct stm32f7_i2c_setup *setup; struct resource *res; -- u32 irq_error, irq_event, clk_rate, rise_time, fall_time; -+ u32 clk_rate, rise_time, fall_time; +- u32 clk_rate, rise_time, fall_time; ++ u32 rise_time, fall_time; struct i2c_adapter *adap; struct reset_control *rst; dma_addr_t phy_addr; -- int ret; +- int irq_error, irq_event, 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) +@@ -1805,15 +2154,15 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) return PTR_ERR(i2c_dev->base); phy_addr = (dma_addr_t)res->start; -- irq_event = irq_of_parse_and_map(np, 0); -- if (!irq_event) { -- dev_err(&pdev->dev, "IRQ event missing or invalid\n"); -- return -EINVAL; +- irq_event = platform_get_irq(pdev, 0); +- if (irq_event <= 0) { +- if (irq_event != -EPROBE_DEFER) + i2c_dev->irq_event = platform_get_irq_byname(pdev, "event"); -+ if (i2c_dev->irq_event < 0) { ++ if (i2c_dev->irq_event <= 0) { + if (i2c_dev->irq_event != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "Failed to get IRQ event: %d\n", + dev_err(&pdev->dev, "Failed to get IRQ event: %d\n", +- irq_event); +- return irq_event ? : -ENOENT; + i2c_dev->irq_event); -+ return i2c_dev->irq_event; ++ return i2c_dev->irq_event ? : -ENOENT; } -- irq_error = irq_of_parse_and_map(np, 1); -- if (!irq_error) { -- dev_err(&pdev->dev, "IRQ error missing or invalid\n"); -- return -EINVAL; +- irq_error = platform_get_irq(pdev, 1); + irq_error = platform_get_irq_byname(pdev, "error"); -+ if (irq_error < 0) { -+ if (irq_error != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "Failed to get IRQ error: %d\n", -+ irq_error); -+ return irq_error; -+ } -+ + if (irq_error <= 0) { + if (irq_error != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get IRQ error: %d\n", +@@ -1821,26 +2170,36 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + return irq_error ? : -ENOENT; + } + + i2c_dev->irq_wakeup = platform_get_irq_byname(pdev, "wakeup"); + if (i2c_dev->irq_wakeup < 0 && i2c_dev->irq_wakeup != -ENXIO) { + if (i2c_dev->irq_wakeup != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get IRQ wakeup: %d\n", + i2c_dev->irq_wakeup); + return i2c_dev->irq_wakeup; - } - ++ } ++ i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); -@@ -1819,6 +1974,7 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) + if (IS_ERR(i2c_dev->clk)) { dev_err(&pdev->dev, "Error: Missing controller clock\n"); return PTR_ERR(i2c_dev->clk); } @@ -630,24 +1156,31 @@ index a492da9..b052f3e 100644 ret = clk_prepare_enable(i2c_dev->clk); if (ret) { dev_err(&pdev->dev, "Failed to prepare_enable clock\n"); -@@ -1828,12 +1984,13 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) - i2c_dev->speed = STM32_I2C_SPEED_STANDARD; + return ret; + } + +- i2c_dev->speed = STM32_I2C_SPEED_STANDARD; ret = device_property_read_u32(&pdev->dev, "clock-frequency", - &clk_rate); +- &clk_rate); - if (!ret && clk_rate >= 1000000) -+ if (!ret && clk_rate >= 1000000) { - i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS; +- i2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS; - else if (!ret && clk_rate >= 400000) -+ } else if (!ret && clk_rate >= 400000) { - i2c_dev->speed = STM32_I2C_SPEED_FAST; +- i2c_dev->speed = STM32_I2C_SPEED_FAST; - else if (!ret && clk_rate >= 100000) -+ } else if (!ret && clk_rate >= 100000) { - i2c_dev->speed = STM32_I2C_SPEED_STANDARD; +- i2c_dev->speed = STM32_I2C_SPEED_STANDARD; ++ &i2c_dev->bus_rate); ++ if (ret) ++ i2c_dev->bus_rate = I2C_STD_RATE; ++ ++ if (i2c_dev->bus_rate > I2C_FASTPLUS_RATE) { ++ dev_err(&pdev->dev, "Invalid bus speed (%i>%i)\n", ++ i2c_dev->bus_rate, I2C_FASTPLUS_RATE); ++ return -EINVAL; + } rst = devm_reset_control_get(&pdev->dev, NULL); if (IS_ERR(rst)) { -@@ -1847,14 +2004,14 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -1854,14 +2213,14 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) i2c_dev->dev = &pdev->dev; @@ -664,12 +1197,13 @@ index a492da9..b052f3e 100644 goto clk_free; } -@@ -1888,7 +2045,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -1895,7 +2254,12 @@ 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) { ++ /* Setup Fast mode plus if necessary */ ++ if (i2c_dev->bus_rate > I2C_FAST_RATE) { + ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); + if (ret) + goto clk_free; @@ -677,22 +1211,18 @@ index a492da9..b052f3e 100644 adap = &i2c_dev->adap; i2c_set_adapdata(adap, i2c_dev); -@@ -1908,18 +2069,47 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -1915,18 +2279,77 @@ 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; + if (i2c_dev->irq_wakeup > 0) { + ret = stm32f7_i2c_setup_wakeup(i2c_dev); + if (ret) -+ goto fmp_clear; ++ goto dma_free; + } - - platform_set_drvdata(pdev, i2c_dev); - -- clk_disable(i2c_dev->clk); ++ ++ platform_set_drvdata(pdev, i2c_dev); ++ + pm_runtime_set_autosuspend_delay(i2c_dev->dev, + STM32F7_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(i2c_dev->dev); @@ -703,10 +1233,33 @@ index a492da9..b052f3e 100644 + + stm32f7_i2c_hw_config(i2c_dev); + -+ ret = i2c_add_adapter(adap); -+ if (ret) + ret = i2c_add_adapter(adap); + if (ret) +- goto clk_free; + goto pm_disable; +- platform_set_drvdata(pdev, i2c_dev); ++ if (device_property_read_bool(&pdev->dev, "st,smbus-host-notify")) { ++ ret = stm32f7_i2c_enable_smbus_host(i2c_dev); ++ if (ret) { ++ dev_err(i2c_dev->dev, ++ "failed to enable SMBus host notify (%d)\n", ++ ret); ++ goto i2c_adapter_remove; ++ } ++ } + +- clk_disable(i2c_dev->clk); ++ if (device_property_read_bool(&pdev->dev, "st,smbus-alert")) { ++ ret = stm32f7_i2c_enable_smbus_alert(i2c_dev); ++ if (ret) { ++ dev_err(i2c_dev->dev, ++ "failed to enable SMBus alert protocol (%d)\n", ++ ret); ++ goto host_notify_disable; ++ } ++ } + dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr); + pm_runtime_mark_last_busy(i2c_dev->dev); @@ -714,6 +1267,12 @@ index a492da9..b052f3e 100644 + return 0; ++host_notify_disable: ++ stm32f7_i2c_disable_smbus_host(i2c_dev); ++ ++i2c_adapter_remove: ++ i2c_del_adapter(adap); ++ +pm_disable: + dev_pm_clear_wake_irq(i2c_dev->dev); + device_init_wakeup(i2c_dev->dev, false); @@ -723,30 +1282,45 @@ index a492da9..b052f3e 100644 + pm_runtime_set_suspended(i2c_dev->dev); + pm_runtime_dont_use_autosuspend(i2c_dev->dev); + -+fmp_clear: ++dma_free: ++ if (i2c_dev->dma) { ++ stm32_i2c_dma_free(i2c_dev->dma); ++ i2c_dev->dma = NULL; ++ } + stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); + clk_free: clk_disable_unprepare(i2c_dev->clk); -@@ -1936,12 +2126,175 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) - } +@@ -1937,18 +2360,192 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) + { + struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - i2c_del_adapter(&i2c_dev->adap); -+ pm_runtime_get_sync(i2c_dev->dev); ++ stm32f7_i2c_disable_smbus_alert(i2c_dev); + -+ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); ++ stm32f7_i2c_disable_smbus_host(i2c_dev); ++ ++ i2c_del_adapter(&i2c_dev->adap); ++ pm_runtime_get_sync(i2c_dev->dev); + + dev_pm_clear_wake_irq(i2c_dev->dev); + device_init_wakeup(i2c_dev->dev, false); + -+ clk_disable_unprepare(i2c_dev->clk); -+ + pm_runtime_put_noidle(i2c_dev->dev); + pm_runtime_disable(i2c_dev->dev); + pm_runtime_set_suspended(i2c_dev->dev); + pm_runtime_dont_use_autosuspend(i2c_dev->dev); + + if (i2c_dev->dma) { + stm32_i2c_dma_free(i2c_dev->dma); + i2c_dev->dma = NULL; + } ++ stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); + +- i2c_del_adapter(&i2c_dev->adap); ++ clk_disable_unprepare(i2c_dev->clk); + +- clk_unprepare(i2c_dev->clk); + return 0; +} + @@ -859,11 +1433,14 @@ index a492da9..b052f3e 100644 + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); + int ret; + ++ i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); ++ i2c_dev->is_suspended = true; ++ i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); ++ + ret = stm32f7_i2c_regs_backup(i2c_dev); + if (ret < 0) + return ret; - -- clk_unprepare(i2c_dev->clk); ++ + if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { + pinctrl_pm_select_sleep_state(dev); + pm_runtime_force_suspend(dev); @@ -888,6 +1465,10 @@ index a492da9..b052f3e 100644 + if (ret < 0) + return ret; + ++ i2c_lock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); ++ i2c_dev->is_suspended = false; ++ i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); ++ + return 0; +} +#else @@ -906,7 +1487,7 @@ index a492da9..b052f3e 100644 static const struct of_device_id stm32f7_i2c_match[] = { { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup}, {}, -@@ -1952,6 +2305,7 @@ static struct platform_driver stm32f7_i2c_driver = { +@@ -1959,6 +2556,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.49/0010-ARM-stm32mp1-r2-IIO.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch similarity index 90% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0010-ARM-stm32mp1-r2-IIO.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch index dbe7e11..2b31874 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0010-ARM-stm32mp1-r2-IIO.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch @@ -1,23 +1,24 @@ -From 6fddc08f91cc0eb406ced8e610aabac3ce7320de Mon Sep 17 00:00:00 2001 +From 46ab5b40eb3e51c796f28fb2bd098b4177b20d50 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 +Date: Fri, 8 Nov 2019 16:52:41 +0100 +Subject: [PATCH 11/31] ARM stm32mp1 r3 IIO --- drivers/iio/adc/Kconfig | 11 + drivers/iio/adc/Makefile | 1 + - drivers/iio/adc/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/sd_adc_modulator.c | 84 +- + drivers/iio/adc/stm32-adc-core.c | 637 +++++++++++-- + drivers/iio/adc/stm32-adc-core.h | 170 ++++ + drivers/iio/adc/stm32-adc-temp.c | 412 +++++++++ + drivers/iio/adc/stm32-adc.c | 1416 ++++++++++++++++++++++++----- + drivers/iio/adc/stm32-dfsdm-adc.c | 975 ++++++++++++++++---- + drivers/iio/adc/stm32-dfsdm-core.c | 176 +++- drivers/iio/adc/stm32-dfsdm.h | 24 +- drivers/iio/counter/stm32-lptimer-cnt.c | 55 ++ drivers/iio/dac/stm32-dac-core.c | 142 ++- drivers/iio/dac/stm32-dac.c | 96 +- drivers/iio/trigger/stm32-timer-trigger.c | 167 +++- - 13 files changed, 3657 insertions(+), 578 deletions(-) + 14 files changed, 3777 insertions(+), 589 deletions(-) create mode 100644 drivers/iio/adc/stm32-adc-temp.c diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig @@ -61,11 +62,134 @@ index 03db7b5..527f9ef 100644 obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o +diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c +index 560d8c7..c0a6e89 100644 +--- a/drivers/iio/adc/sd_adc_modulator.c ++++ b/drivers/iio/adc/sd_adc_modulator.c +@@ -10,8 +10,7 @@ + #include + #include + #include +- +-static const struct iio_info iio_sd_mod_iio_info; ++#include + + static const struct iio_chan_spec iio_sd_mod_ch = { + .type = IIO_VOLTAGE, +@@ -21,36 +20,99 @@ static const struct iio_chan_spec iio_sd_mod_ch = { + .realbits = 1, + .shift = 0, + }, ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), ++}; ++ ++static const struct iio_chan_spec iio_sd_mod_ch_ads = { ++ .type = IIO_VOLTAGE, ++ .indexed = 1, ++ .scan_type = { ++ .sign = 'u', ++ .realbits = 1, ++ .shift = 0, ++ }, ++ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), ++ .differential = 1, ++}; ++ ++struct iio_sd_mod_priv { ++ int vref_mv; ++}; ++ ++static const struct of_device_id sd_adc_of_match[] = { ++ { .compatible = "sd-modulator", .data = &iio_sd_mod_ch }, ++ { .compatible = "ads1201", .data = &iio_sd_mod_ch_ads }, ++ { } ++}; ++ ++static int iio_sd_mod_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, int *val, ++ int *val2, long mask) ++{ ++ struct iio_sd_mod_priv *priv = iio_priv(indio_dev); ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_SCALE: ++ *val = priv->vref_mv; ++ *val2 = chan->scan_type.realbits; ++ return IIO_VAL_INT; ++ } ++ ++ return -EINVAL; ++} ++ ++static const struct iio_info iio_sd_mod_iio_info = { ++ .read_raw = iio_sd_mod_read_raw, + }; + + static int iio_sd_mod_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; ++ struct iio_sd_mod_priv *priv; ++ struct regulator *vref; + struct iio_dev *iio; ++ int ret; + +- iio = devm_iio_device_alloc(dev, 0); ++ iio = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!iio) + return -ENOMEM; + ++ iio->channels = (const struct iio_chan_spec *) ++ of_match_device(sd_adc_of_match, &pdev->dev)->data; ++ ++ priv = iio_priv(iio); ++ + iio->dev.parent = dev; + iio->dev.of_node = dev->of_node; + iio->name = dev_name(dev); + iio->info = &iio_sd_mod_iio_info; + iio->modes = INDIO_BUFFER_HARDWARE; +- + iio->num_channels = 1; +- iio->channels = &iio_sd_mod_ch; + +- platform_set_drvdata(pdev, iio); ++ vref = devm_regulator_get_optional(dev, "vref"); ++ if (IS_ERR(vref)) { ++ ret = PTR_ERR(vref); ++ if (ret != -ENODEV) { ++ if (ret != -EPROBE_DEFER) ++ dev_err(dev, "vref get failed, %d\n", ret); ++ return ret; ++ } ++ } ++ ++ if (!IS_ERR(vref)) { ++ ret = regulator_get_voltage(vref); ++ if (ret < 0) { ++ dev_err(dev, "vref get failed, %d\n", ret); ++ return ret; ++ } ++ ++ priv->vref_mv = ret / 1000; ++ dev_dbg(dev, "vref+=%dmV\n", priv->vref_mv); ++ } + + return devm_iio_device_register(&pdev->dev, iio); + } + +-static const struct of_device_id sd_adc_of_match[] = { +- { .compatible = "sd-modulator" }, +- { .compatible = "ads1201" }, +- { } +-}; + MODULE_DEVICE_TABLE(of, sd_adc_of_match); + + static struct platform_driver iio_sd_mod_adc = { diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index ca432e7..dc40c05 100644 +index 38eb966..5062661 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c -@@ -10,12 +10,18 @@ +@@ -10,31 +10,47 @@ */ #include @@ -84,72 +208,7 @@ index ca432e7..dc40c05 100644 #include #include -@@ -23,12 +29,29 @@ - - /* STM32F4 - common registers for all ADC instances: 1, 2 & 3 */ - #define STM32F4_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) --#define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04) - - /* STM32F4_ADC_CSR - bit fields */ -+#define STM32F4_OVR3 BIT(21) -+#define STM32F4_JEOC3 BIT(18) - #define STM32F4_EOC3 BIT(17) -+#define STM32F4_AWD3 BIT(16) -+#define STM32F4_OVR2 BIT(13) -+#define STM32F4_JEOC2 BIT(10) - #define STM32F4_EOC2 BIT(9) -+#define STM32F4_AWD2 BIT(8) -+#define STM32F4_OVR1 BIT(5) -+#define STM32F4_JEOC1 BIT(2) - #define STM32F4_EOC1 BIT(1) -+#define STM32F4_AWD1 BIT(0) -+#define STM32F4_EOC_MASK1 (STM32F4_EOC1 | STM32F4_AWD1 | \ -+ STM32F4_OVR1) -+#define STM32F4_EOC_MASK2 (STM32F4_EOC2 | STM32F4_AWD2 | \ -+ STM32F4_OVR2) -+#define STM32F4_EOC_MASK3 (STM32F4_EOC3 | STM32F4_AWD3 | \ -+ STM32F4_OVR3) -+#define STM32F4_JEOC_MASK1 (STM32F4_JEOC1 | STM32F4_AWD1) -+#define STM32F4_JEOC_MASK2 (STM32F4_JEOC2 | STM32F4_AWD2) -+#define STM32F4_JEOC_MASK3 (STM32F4_JEOC3 | STM32F4_AWD3) - - /* STM32F4_ADC_CCR - bit fields */ - #define STM32F4_ADC_ADCPRE_SHIFT 16 -@@ -36,11 +59,30 @@ - - /* STM32H7 - common registers for all ADC instances */ - #define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) --#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) - - /* STM32H7_ADC_CSR - bit fields */ -+#define STM32H7_AWD3_SLV BIT(25) -+#define STM32H7_AWD2_SLV BIT(24) -+#define STM32H7_AWD1_SLV BIT(23) -+#define STM32H7_JEOS_SLV BIT(22) -+#define STM32H7_OVR_SLV BIT(20) - #define STM32H7_EOC_SLV BIT(18) -+#define STM32H7_AWD3_MST BIT(9) -+#define STM32H7_AWD2_MST BIT(8) -+#define STM32H7_AWD1_MST BIT(7) -+#define STM32H7_JEOS_MST BIT(6) -+#define STM32H7_OVR_MST BIT(4) - #define STM32H7_EOC_MST BIT(2) -+#define STM32H7_EOC_MASK1 (STM32H7_EOC_MST | STM32H7_AWD1_MST | \ -+ STM32H7_AWD2_MST | STM32H7_AWD3_MST | \ -+ STM32H7_OVR_MST) -+#define STM32H7_EOC_MASK2 (STM32H7_EOC_SLV | STM32H7_AWD1_SLV | \ -+ STM32H7_AWD2_SLV | STM32H7_AWD3_SLV | \ -+ STM32H7_OVR_SLV) -+#define STM32H7_JEOC_MASK1 (STM32H7_JEOS_MST | STM32H7_AWD1_MST | \ -+ STM32H7_AWD2_MST | STM32H7_AWD3_MST) -+#define STM32H7_JEOC_MASK2 (STM32H7_JEOS_SLV | STM32H7_AWD1_SLV | \ -+ STM32H7_AWD2_SLV | STM32H7_AWD3_SLV) - - /* STM32H7_ADC_CCR - bit fields */ - #define STM32H7_PRESC_SHIFT 18 -@@ -48,18 +90,32 @@ - #define STM32H7_CKMODE_SHIFT 16 - #define STM32H7_CKMODE_MASK GENMASK(17, 16) + #include "stm32-adc-core.h" +#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000 + @@ -163,8 +222,8 @@ index ca432e7..dc40c05 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 + * @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; @@ -175,12 +234,10 @@ index ca432e7..dc40c05 100644 + u32 jeoc1_msk; + u32 jeoc2_msk; + u32 jeoc3_msk; -+ u32 ier; -+ u32 eocie_msk; + u32 ier; + u32 eocie_msk; }; - - struct stm32_adc_priv; -@@ -69,11 +125,27 @@ struct stm32_adc_priv; +@@ -46,11 +62,27 @@ struct stm32_adc_priv; * @regs: common registers for all instances * @clk_sel: clock selection routine * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) @@ -208,7 +265,7 @@ index ca432e7..dc40c05 100644 }; /** -@@ -82,18 +154,32 @@ struct stm32_adc_priv_cfg { +@@ -59,18 +91,32 @@ struct stm32_adc_priv_cfg { * @domain: irq domain reference * @aclk: clock reference for the analog circuitry * @bclk: bus clock common for all ADCs, depends on part used @@ -241,7 +298,7 @@ index ca432e7..dc40c05 100644 }; static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) -@@ -129,7 +215,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, +@@ -106,7 +152,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, } for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { @@ -250,7 +307,7 @@ index ca432e7..dc40c05 100644 break; } if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { -@@ -218,7 +304,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -195,7 +241,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (ckmode) continue; @@ -259,7 +316,7 @@ index ca432e7..dc40c05 100644 goto out; } } -@@ -238,7 +324,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -215,7 +261,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (!ckmode) continue; @@ -268,7 +325,7 @@ index ca432e7..dc40c05 100644 goto out; } -@@ -265,18 +351,43 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -242,9 +288,13 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, /* STM32F4 common registers definitions */ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { .csr = STM32F4_ADC_CSR, @@ -282,10 +339,10 @@ index ca432e7..dc40c05 100644 + .jeoc1_msk = STM32F4_JEOC_MASK1, + .jeoc2_msk = STM32F4_JEOC_MASK2, + .jeoc3_msk = STM32F4_JEOC_MASK3, -+ .ier = STM32F4_ADC_CR1, -+ .eocie_msk = STM32F4_EOCIE, + .ier = STM32F4_ADC_CR1, + .eocie_msk = STM32F4_EOCIE, }; - +@@ -252,8 +302,11 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { /* STM32H7 common registers definitions */ static const struct stm32_adc_common_regs stm32h7_adc_common_regs = { .csr = STM32H7_ADC_CSR, @@ -296,56 +353,11 @@ index ca432e7..dc40c05 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, + .ier = STM32H7_ADC_IER, + .eocie_msk = STM32H7_EOCIE, }; - -+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 */ - 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)) +@@ -306,6 +359,15 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) + stm32_adc_eoc_enabled(priv, 2)) generic_handle_irq(irq_find_mapping(priv->domain, 2)); + if (status & priv->cfg->regs->jeoc1_msk) @@ -360,7 +372,7 @@ index ca432e7..dc40c05 100644 chained_irq_exit(chip, desc); }; -@@ -344,7 +479,8 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, +@@ -354,7 +416,8 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, } } @@ -370,7 +382,7 @@ index ca432e7..dc40c05 100644 &stm32_adc_domain_ops, priv); if (!priv->domain) { -@@ -368,7 +504,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, +@@ -378,7 +441,7 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, int hwirq; unsigned int i; @@ -379,7 +391,7 @@ index ca432e7..dc40c05 100644 irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); irq_domain_remove(priv->domain); -@@ -379,13 +515,415 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, +@@ -389,13 +452,415 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, } } @@ -796,7 +808,7 @@ index ca432e7..dc40c05 100644 if (!pdev->dev.of_node) return -ENODEV; -@@ -393,6 +931,7 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -403,6 +868,7 @@ static int stm32_adc_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -804,7 +816,7 @@ index ca432e7..dc40c05 100644 priv->cfg = (const struct stm32_adc_priv_cfg *) of_match_device(dev->driver->of_match_table, dev)->data; -@@ -402,6 +941,8 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -412,6 +878,8 @@ static int stm32_adc_probe(struct platform_device *pdev) if (IS_ERR(priv->common.base)) return PTR_ERR(priv->common.base); priv->common.phys_base = res->start; @@ -813,7 +825,7 @@ index ca432e7..dc40c05 100644 priv->vref = devm_regulator_get(&pdev->dev, "vref"); if (IS_ERR(priv->vref)) { -@@ -410,67 +951,87 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -420,67 +888,87 @@ static int stm32_adc_probe(struct platform_device *pdev) return ret; } @@ -892,8 +904,8 @@ index ca432e7..dc40c05 100644 + 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); @@ -908,7 +920,7 @@ index ca432e7..dc40c05 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); + @@ -918,7 +930,7 @@ index ca432e7..dc40c05 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; @@ -936,7 +948,7 @@ index ca432e7..dc40c05 100644 ret = of_platform_populate(np, NULL, NULL, &pdev->dev); if (ret < 0) { -@@ -478,21 +1039,19 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -488,21 +976,19 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_irq_remove; } @@ -967,7 +979,7 @@ index ca432e7..dc40c05 100644 return ret; } -@@ -502,33 +1061,59 @@ static int stm32_adc_remove(struct platform_device *pdev) +@@ -512,33 +998,59 @@ static int stm32_adc_remove(struct platform_device *pdev) struct stm32_adc_common *common = platform_get_drvdata(pdev); struct stm32_adc_priv *priv = to_stm32_adc_priv(common); @@ -983,18 +995,18 @@ index ca432e7..dc40c05 100644 + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); - - return 0; - } - -+#if defined(CONFIG_PM) -+static int stm32_adc_core_runtime_suspend(struct device *dev) -+{ -+ stm32_adc_core_hw_stop(dev); + + return 0; +} + ++#if defined(CONFIG_PM) ++static int stm32_adc_core_runtime_suspend(struct device *dev) ++{ ++ stm32_adc_core_hw_stop(dev); + + return 0; + } + +static int stm32_adc_core_runtime_resume(struct device *dev) +{ + return stm32_adc_core_hw_start(dev); @@ -1032,7 +1044,7 @@ index ca432e7..dc40c05 100644 }; static const struct of_device_id stm32_adc_of_match[] = { -@@ -552,6 +1137,7 @@ static struct platform_driver stm32_adc_driver = { +@@ -562,6 +1074,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc-core", .of_match_table = stm32_adc_of_match, @@ -1041,15 +1053,190 @@ index ca432e7..dc40c05 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..a7a4e54 100644 +index 2579d51..3eacb06 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h -@@ -25,20 +25,119 @@ - * -------------------------------------------------------- - */ - #define STM32_ADC_MAX_ADCS 3 -+#define STM32_ADC_OFFSET 0x100 - #define STM32_ADCX_COMN_OFFSET 0x300 +@@ -51,14 +51,26 @@ + #define STM32F4_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x04) + + /* STM32F4_ADC_SR - bit fields */ ++#define STM32F4_OVR BIT(5) + #define STM32F4_STRT BIT(4) ++#define STM32F4_JSTRT BIT(3) ++#define STM32F4_JEOC BIT(2) + #define STM32F4_EOC BIT(1) ++#define STM32F4_AWD BIT(0) + + /* STM32F4_ADC_CR1 - bit fields */ ++#define STM32F4_OVRIE BIT(26) + #define STM32F4_RES_SHIFT 24 + #define STM32F4_RES_MASK GENMASK(25, 24) ++#define STM32F4_AWDEN BIT(23) ++#define STM32F4_JAWDEN BIT(22) ++#define STM32F4_AWDSGL BIT(9) + #define STM32F4_SCAN BIT(8) ++#define STM32F4_JEOCIE BIT(7) ++#define STM32F4_AWDIE BIT(6) + #define STM32F4_EOCIE BIT(5) ++#define STM32F4_AWDCH_SHIFT 0 ++#define STM32F4_AWDCH_MASK GENMASK(4, 0) + + /* STM32F4_ADC_CR2 - bit fields */ + #define STM32F4_SWSTART BIT(30) +@@ -66,17 +78,41 @@ + #define STM32F4_EXTEN_MASK GENMASK(29, 28) + #define STM32F4_EXTSEL_SHIFT 24 + #define STM32F4_EXTSEL_MASK GENMASK(27, 24) ++#define STM32F4_JSWSTART BIT(22) ++#define STM32F4_JEXTEN_SHIFT 20 ++#define STM32F4_JEXTEN_MASK GENMASK(21, 20) ++#define STM32F4_JEXTSEL_SHIFT 16 ++#define STM32F4_JEXTSEL_MASK GENMASK(19, 16) + #define STM32F4_EOCS BIT(10) + #define STM32F4_DDS BIT(9) + #define STM32F4_DMA BIT(8) + #define STM32F4_ADON BIT(0) + + /* STM32F4_ADC_CSR - bit fields */ ++#define STM32F4_OVR3 BIT(21) ++#define STM32F4_JEOC3 BIT(18) + #define STM32F4_EOC3 BIT(17) ++#define STM32F4_AWD3 BIT(16) ++#define STM32F4_OVR2 BIT(13) ++#define STM32F4_JEOC2 BIT(10) + #define STM32F4_EOC2 BIT(9) ++#define STM32F4_AWD2 BIT(8) ++#define STM32F4_OVR1 BIT(5) ++#define STM32F4_JEOC1 BIT(2) + #define STM32F4_EOC1 BIT(1) ++#define STM32F4_AWD1 BIT(0) ++#define STM32F4_EOC_MASK1 (STM32F4_EOC1 | STM32F4_AWD1 | \ ++ STM32F4_OVR1) ++#define STM32F4_EOC_MASK2 (STM32F4_EOC2 | STM32F4_AWD2 | \ ++ STM32F4_OVR2) ++#define STM32F4_EOC_MASK3 (STM32F4_EOC3 | STM32F4_AWD3 | \ ++ STM32F4_OVR3) ++#define STM32F4_JEOC_MASK1 (STM32F4_JEOC1 | STM32F4_AWD1) ++#define STM32F4_JEOC_MASK2 (STM32F4_JEOC2 | STM32F4_AWD2) ++#define STM32F4_JEOC_MASK3 (STM32F4_JEOC3 | STM32F4_AWD3) + + /* STM32F4_ADC_CCR - bit fields */ ++#define STM32F4_ADC_TSVREFE BIT(23) + #define STM32F4_ADC_ADCPRE_SHIFT 16 + #define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16) + +@@ -88,11 +124,24 @@ + #define STM32H7_ADC_SMPR1 0x14 + #define STM32H7_ADC_SMPR2 0x18 + #define STM32H7_ADC_PCSEL 0x1C ++#define STM32H7_ADC_LTR1 0x20 ++#define STM32H7_ADC_HTR1 0x24 + #define STM32H7_ADC_SQR1 0x30 + #define STM32H7_ADC_SQR2 0x34 + #define STM32H7_ADC_SQR3 0x38 + #define STM32H7_ADC_SQR4 0x3C + #define STM32H7_ADC_DR 0x40 ++#define STM32H7_ADC_JSQR 0x4C ++#define STM32H7_ADC_JDR1 0x80 ++#define STM32H7_ADC_JDR2 0x84 ++#define STM32H7_ADC_JDR3 0x88 ++#define STM32H7_ADC_JDR4 0x8C ++#define STM32H7_ADC_AWD2CR 0xA0 ++#define STM32H7_ADC_AWD3CR 0xA4 ++#define STM32H7_ADC_LTR2 0xB0 ++#define STM32H7_ADC_HTR2 0xB4 ++#define STM32H7_ADC_LTR3 0xB8 ++#define STM32H7_ADC_HTR3 0xBC + #define STM32H7_ADC_DIFSEL 0xC0 + #define STM32H7_ADC_CALFACT 0xC4 + #define STM32H7_ADC_CALFACT2 0xC8 +@@ -103,10 +152,20 @@ + + /* STM32H7_ADC_ISR - bit fields */ + #define STM32MP1_VREGREADY BIT(12) ++#define STM32H7_AWD3 BIT(9) ++#define STM32H7_AWD2 BIT(8) ++#define STM32H7_AWD1 BIT(7) ++#define STM32H7_JEOS BIT(6) ++#define STM32H7_OVR BIT(4) + #define STM32H7_EOC BIT(2) + #define STM32H7_ADRDY BIT(0) + + /* STM32H7_ADC_IER - bit fields */ ++#define STM32H7_AWD3IE STM32H7_AWD3 ++#define STM32H7_AWD2IE STM32H7_AWD2 ++#define STM32H7_AWD1IE STM32H7_AWD1 ++#define STM32H7_JEOSIE STM32H7_JEOS ++#define STM32H7_OVRIE STM32H7_OVR + #define STM32H7_EOCIE STM32H7_EOC + + /* STM32H7_ADC_CR - bit fields */ +@@ -122,12 +181,19 @@ + #define STM32H7_LINCALRDYW1 BIT(22) + #define STM32H7_ADCALLIN BIT(16) + #define STM32H7_BOOST BIT(8) ++#define STM32H7_JADSTP BIT(5) + #define STM32H7_ADSTP BIT(4) ++#define STM32H7_JADSTART BIT(3) + #define STM32H7_ADSTART BIT(2) + #define STM32H7_ADDIS BIT(1) + #define STM32H7_ADEN BIT(0) + + /* STM32H7_ADC_CFGR bit fields */ ++#define STM32H7_AWD1CH_SHIFT 26 ++#define STM32H7_AWD1CH_MASK GENMASK(30, 26) ++#define STM32H7_JAWD1EN BIT(24) ++#define STM32H7_AWD1EN BIT(23) ++#define STM32H7_AWD1SGL BIT(22) + #define STM32H7_EXTEN_SHIFT 10 + #define STM32H7_EXTEN_MASK GENMASK(11, 10) + #define STM32H7_EXTSEL_SHIFT 5 +@@ -144,6 +210,12 @@ enum stm32h7_adc_dmngt { + STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */ + }; + ++/* STM32H7_ADC_JSQR - bit fields */ ++#define STM32H7_JEXTEN_SHIFT 7 ++#define STM32H7_JEXTEN_MASK GENMASK(8, 7) ++#define STM32H7_JEXTSEL_SHIFT 2 ++#define STM32H7_JEXTSEL_MASK GENMASK(6, 2) ++ + /* STM32H7_ADC_CALFACT - bit fields */ + #define STM32H7_CALFACT_D_SHIFT 16 + #define STM32H7_CALFACT_D_MASK GENMASK(26, 16) +@@ -155,27 +227,125 @@ enum stm32h7_adc_dmngt { + #define STM32H7_LINCALFACT_MASK GENMASK(29, 0) + + /* STM32H7_ADC_CSR - bit fields */ ++#define STM32H7_AWD3_SLV BIT(25) ++#define STM32H7_AWD2_SLV BIT(24) ++#define STM32H7_AWD1_SLV BIT(23) ++#define STM32H7_JEOS_SLV BIT(22) ++#define STM32H7_OVR_SLV BIT(20) + #define STM32H7_EOC_SLV BIT(18) ++#define STM32H7_AWD3_MST BIT(9) ++#define STM32H7_AWD2_MST BIT(8) ++#define STM32H7_AWD1_MST BIT(7) ++#define STM32H7_JEOS_MST BIT(6) ++#define STM32H7_OVR_MST BIT(4) + #define STM32H7_EOC_MST BIT(2) ++#define STM32H7_EOC_MASK1 (STM32H7_EOC_MST | STM32H7_AWD1_MST | \ ++ STM32H7_AWD2_MST | STM32H7_AWD3_MST | \ ++ STM32H7_OVR_MST) ++#define STM32H7_EOC_MASK2 (STM32H7_EOC_SLV | STM32H7_AWD1_SLV | \ ++ STM32H7_AWD2_SLV | STM32H7_AWD3_SLV | \ ++ STM32H7_OVR_SLV) ++#define STM32H7_JEOC_MASK1 (STM32H7_JEOS_MST | STM32H7_AWD1_MST | \ ++ STM32H7_AWD2_MST | STM32H7_AWD3_MST) ++#define STM32H7_JEOC_MASK2 (STM32H7_JEOS_SLV | STM32H7_AWD1_SLV | \ ++ STM32H7_AWD2_SLV | STM32H7_AWD3_SLV) + + /* STM32H7_ADC_CCR - bit fields */ ++#define STM32H7_VSENSEEN BIT(23) + #define STM32H7_PRESC_SHIFT 18 + #define STM32H7_PRESC_MASK GENMASK(21, 18) + #define STM32H7_CKMODE_SHIFT 16 + #define STM32H7_CKMODE_MASK GENMASK(17, 16) +/* Number of linear calibration shadow registers / LINCALRDYW control bits */ +#define STM32H7_LINCALFACT_NUM 6 @@ -1067,30 +1254,6 @@ index 8af507b..a7a4e54 100644 + u32 lincalfact[STM32H7_LINCALFACT_NUM]; + 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) -+ -+/* STM32H7_ADC_CCR - bit fields */ -+#define STM32H7_VSENSEEN BIT(23) + /** * struct stm32_adc_common - stm32 ADC driver common data (for all instances) @@ -1104,6 +1267,9 @@ index 8af507b..a7a4e54 100644 + * @difsel bitmask array to set single-ended/differential channel + * @pcsel bitmask array to preselect channels on some devices + * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) ++ * @prepcnt: counter to manage prepare() calls concurrency ++ * @inj: mutex to protect regular/injected concurrency ++ * @cal: optional calibration data on some devices */ struct stm32_adc_common { void __iomem *base; @@ -1583,7 +1749,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..e82d4c5 100644 +index 0409dcf..55c8362 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -12,6 +12,7 @@ @@ -1594,7 +1760,7 @@ index 3784118..e82d4c5 100644 #include #include #include -@@ -20,8 +21,10 @@ +@@ -20,25 +21,26 @@ #include #include #include @@ -1605,141 +1771,7 @@ index 3784118..e82d4c5 100644 #include #include -@@ -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 */ -+#define STM32F4_OVR BIT(5) - #define STM32F4_STRT BIT(4) -+#define STM32F4_JSTRT BIT(3) -+#define STM32F4_JEOC BIT(2) - #define STM32F4_EOC BIT(1) -+#define STM32F4_AWD BIT(0) - - /* STM32F4_ADC_CR1 - bit fields */ - #define STM32F4_RES_SHIFT 24 -+#define STM32F4_OVRIE BIT(26) - #define STM32F4_RES_MASK GENMASK(25, 24) -+#define STM32F4_AWDEN BIT(23) -+#define STM32F4_JAWDEN BIT(22) -+#define STM32F4_AWDSGL BIT(9) - #define STM32F4_SCAN BIT(8) --#define STM32F4_EOCIE BIT(5) -+#define STM32F4_JEOCIE BIT(7) -+#define STM32F4_AWDIE BIT(6) -+#define STM32F4_AWDCH_SHIFT 0 -+#define STM32F4_AWDCH_MASK GENMASK(4, 0) - - /* STM32F4_ADC_CR2 - bit fields */ - #define STM32F4_SWSTART BIT(30) -@@ -61,6 +74,11 @@ - #define STM32F4_EXTEN_MASK GENMASK(29, 28) - #define STM32F4_EXTSEL_SHIFT 24 - #define STM32F4_EXTSEL_MASK GENMASK(27, 24) -+#define STM32F4_JSWSTART BIT(22) -+#define STM32F4_JEXTEN_SHIFT 20 -+#define STM32F4_JEXTEN_MASK GENMASK(21, 20) -+#define STM32F4_JEXTSEL_SHIFT 16 -+#define STM32F4_JEXTSEL_MASK GENMASK(19, 16) - #define STM32F4_EOCS BIT(10) - #define STM32F4_DDS BIT(9) - #define STM32F4_DMA BIT(8) -@@ -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 -+#define STM32H7_ADC_LTR1 0x20 -+#define STM32H7_ADC_HTR1 0x24 - #define STM32H7_ADC_SQR1 0x30 - #define STM32H7_ADC_SQR2 0x34 - #define STM32H7_ADC_SQR3 0x38 - #define STM32H7_ADC_SQR4 0x3C - #define STM32H7_ADC_DR 0x40 -+#define STM32H7_ADC_JSQR 0x4C -+#define STM32H7_ADC_JDR1 0x80 -+#define STM32H7_ADC_JDR2 0x84 -+#define STM32H7_ADC_JDR3 0x88 -+#define STM32H7_ADC_JDR4 0x8C -+#define STM32H7_ADC_AWD2CR 0xA0 -+#define STM32H7_ADC_AWD3CR 0xA4 -+#define STM32H7_ADC_LTR2 0xB0 -+#define STM32H7_ADC_HTR2 0xB4 -+#define STM32H7_ADC_LTR3 0xB8 -+#define STM32H7_ADC_HTR3 0xBC - #define STM32H7_ADC_DIFSEL 0xC0 - #define STM32H7_ADC_CALFACT 0xC4 - #define STM32H7_ADC_CALFACT2 0xC8 - - /* STM32H7_ADC_ISR - bit fields */ - #define STM32MP1_VREGREADY BIT(12) -+#define STM32H7_AWD3 BIT(9) -+#define STM32H7_AWD2 BIT(8) -+#define STM32H7_AWD1 BIT(7) -+#define STM32H7_JEOS BIT(6) -+#define STM32H7_OVR BIT(4) - #define STM32H7_EOC BIT(2) - #define STM32H7_ADRDY BIT(0) - - /* STM32H7_ADC_IER - bit fields */ --#define STM32H7_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 - - /* STM32H7_ADC_CR - bit fields */ - #define STM32H7_ADCAL BIT(31) -@@ -104,12 +143,19 @@ - #define STM32H7_LINCALRDYW1 BIT(22) - #define STM32H7_ADCALLIN BIT(16) - #define STM32H7_BOOST BIT(8) -+#define STM32H7_JADSTP BIT(5) - #define STM32H7_ADSTP BIT(4) -+#define STM32H7_JADSTART BIT(3) - #define STM32H7_ADSTART BIT(2) - #define STM32H7_ADDIS BIT(1) - #define STM32H7_ADEN BIT(0) - - /* STM32H7_ADC_CFGR bit fields */ -+#define STM32H7_AWD1CH_SHIFT 26 -+#define STM32H7_AWD1CH_MASK GENMASK(30, 26) -+#define STM32H7_JAWD1EN BIT(24) -+#define STM32H7_AWD1EN BIT(23) -+#define STM32H7_AWD1SGL BIT(22) - #define STM32H7_EXTEN_SHIFT 10 - #define STM32H7_EXTEN_MASK GENMASK(11, 10) - #define STM32H7_EXTSEL_SHIFT 5 -@@ -126,6 +172,12 @@ enum stm32h7_adc_dmngt { - STM32H7_DMNGT_DMA_CIRC, /* DMA circular mode */ - }; - -+/* STM32H7_ADC_JSQR - bit fields */ -+#define STM32H7_JEXTEN_SHIFT 7 -+#define STM32H7_JEXTEN_MASK GENMASK(8, 7) -+#define STM32H7_JEXTSEL_SHIFT 2 -+#define STM32H7_JEXTSEL_MASK GENMASK(6, 2) -+ - /* STM32H7_ADC_CALFACT - bit fields */ - #define STM32H7_CALFACT_D_SHIFT 16 - #define STM32H7_CALFACT_D_MASK GENMASK(26, 16) -@@ -136,18 +188,17 @@ enum stm32h7_adc_dmngt { - #define STM32H7_LINCALFACT_SHIFT 0 - #define STM32H7_LINCALFACT_MASK GENMASK(29, 0) + #include "stm32-adc-core.h" -/* Number of linear calibration shadow registers / LINCALRDYW control bits */ -#define STM32H7_LINCALFACT_NUM 6 @@ -1758,7 +1790,7 @@ index 3784118..e82d4c5 100644 #define STM32_DMA_BUFFER_SIZE PAGE_SIZE -@@ -159,53 +210,6 @@ enum stm32_adc_exten { +@@ -50,53 +52,6 @@ enum stm32_adc_exten { STM32_EXTEN_HWTRIG_BOTH_EDGES, }; @@ -1812,7 +1844,7 @@ index 3784118..e82d4c5 100644 /** * stm32_adc_regs - stm32 ADC misc registers & bitfield desc * @reg: register offset -@@ -219,27 +223,73 @@ struct stm32_adc_regs { +@@ -110,27 +65,73 @@ struct stm32_adc_regs { }; /** @@ -1886,7 +1918,7 @@ index 3784118..e82d4c5 100644 }; struct stm32_adc; -@@ -251,12 +301,12 @@ struct stm32_adc; +@@ -142,12 +143,12 @@ struct stm32_adc; * @trigs: external trigger sources * @clk_required: clock is required * @has_vregready: vregready status flag presence @@ -1900,7 +1932,7 @@ index 3784118..e82d4c5 100644 */ struct stm32_adc_cfg { const struct stm32_adc_regspec *regs; -@@ -264,18 +314,39 @@ struct stm32_adc_cfg { +@@ -155,18 +156,39 @@ struct stm32_adc_cfg { struct stm32_adc_trig_info *trigs; bool clk_required; bool has_vregready; @@ -1941,7 +1973,7 @@ index 3784118..e82d4c5 100644 * @cfg: compatible configuration data * @completion: end of single conversion completion * @buffer: data buffer -@@ -290,15 +361,16 @@ struct stm32_adc_cfg { +@@ -181,15 +203,16 @@ struct stm32_adc_cfg { * @rx_buf: dma rx buffer cpu address * @rx_dma_buf: dma rx buffer bus address * @rx_buf_sz: dma rx buffer size @@ -1962,7 +1994,7 @@ index 3784118..e82d4c5 100644 const struct stm32_adc_cfg *cfg; struct completion completion; u16 buffer[STM32_ADC_MAX_SQ]; -@@ -313,11 +385,11 @@ struct stm32_adc { +@@ -204,11 +227,11 @@ struct stm32_adc { u8 *rx_buf; dma_addr_t rx_dma_buf; unsigned int rx_buf_sz; @@ -1978,7 +2010,7 @@ index 3784118..e82d4c5 100644 }; struct stm32_adc_diff_channel { -@@ -342,9 +414,9 @@ static const unsigned int stm32f4_adc_resolutions[] = { +@@ -233,9 +256,9 @@ static const unsigned int stm32f4_adc_resolutions[] = { 12, 10, 8, 6, }; @@ -1990,7 +2022,7 @@ index 3784118..e82d4c5 100644 .resolutions = stm32f4_adc_resolutions, .num_res = ARRAY_SIZE(stm32f4_adc_resolutions), }; -@@ -390,25 +462,58 @@ static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = { +@@ -281,25 +304,58 @@ static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = { /* STM32F4 external trigger sources for all instances */ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { @@ -2064,7 +2096,7 @@ index 3784118..e82d4c5 100644 * stm32f4_smp_bits[] - describe sampling time register index & bit fields * Sorted so it can be indexed by channel number. */ -@@ -441,17 +546,46 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { +@@ -332,17 +388,46 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { 3, 15, 28, 56, 84, 112, 144, 480, }; @@ -2111,7 +2143,7 @@ index 3784118..e82d4c5 100644 }; 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] = { +@@ -367,26 +452,41 @@ static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = { { STM32H7_ADC_SQR4, GENMASK(10, 6), 6 }, }; @@ -2171,7 +2203,7 @@ index 3784118..e82d4c5 100644 {}, }; -@@ -533,17 +682,72 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { +@@ -424,17 +524,72 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { 1, 2, 8, 16, 32, 64, 387, 810, }; @@ -2244,7 +2276,7 @@ index 3784118..e82d4c5 100644 }; /** -@@ -599,8 +803,12 @@ static void stm32_adc_clr_bits(struct stm32_adc *adc, u32 reg, u32 bits) +@@ -490,8 +645,12 @@ static void stm32_adc_clr_bits(struct stm32_adc *adc, u32 reg, u32 bits) */ static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) { @@ -2259,7 +2291,7 @@ index 3784118..e82d4c5 100644 }; /** -@@ -609,8 +817,30 @@ static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) +@@ -500,8 +659,30 @@ static void stm32_adc_conv_irq_enable(struct stm32_adc *adc) */ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) { @@ -2292,7 +2324,7 @@ index 3784118..e82d4c5 100644 } static void stm32_adc_set_res(struct stm32_adc *adc) -@@ -623,6 +853,57 @@ static void stm32_adc_set_res(struct stm32_adc *adc) +@@ -514,6 +695,57 @@ static void stm32_adc_set_res(struct stm32_adc *adc) stm32_adc_writel(adc, res->reg, val); } @@ -2350,7 +2382,7 @@ index 3784118..e82d4c5 100644 /** * stm32f4_adc_start_conv() - Start conversions for regular channels. * @adc: stm32 adc instance -@@ -635,30 +916,80 @@ static void stm32_adc_set_res(struct stm32_adc *adc) +@@ -526,30 +758,80 @@ static void stm32_adc_set_res(struct stm32_adc *adc) */ static void stm32f4_adc_start_conv(struct stm32_adc *adc, bool dma) { @@ -2442,7 +2474,7 @@ index 3784118..e82d4c5 100644 } 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) +@@ -558,6 +840,11 @@ static void stm32h7_adc_start_conv(struct stm32_adc *adc, bool dma) unsigned long flags; u32 val; @@ -2454,7 +2486,7 @@ index 3784118..e82d4c5 100644 if (dma) dmngt = STM32H7_DMNGT_DMA_CIRC; else -@@ -687,6 +1023,16 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) +@@ -578,6 +865,16 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) int ret; u32 val; @@ -2471,7 +2503,7 @@ index 3784118..e82d4c5 100644 stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTP); ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_CR, val, -@@ -704,6 +1050,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) +@@ -595,6 +892,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) int ret; u32 val; @@ -2482,7 +2514,7 @@ index 3784118..e82d4c5 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 +1080,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) +@@ -621,6 +922,10 @@ static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc) { @@ -2493,7 +2525,7 @@ index 3784118..e82d4c5 100644 stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST); /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ -@@ -742,6 +1096,9 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) +@@ -633,6 +938,9 @@ static int stm32h7_adc_enable(struct stm32_adc *adc) int ret; u32 val; @@ -2503,7 +2535,7 @@ index 3784118..e82d4c5 100644 stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN); /* Poll for ADRDY to be set (after adc startup time) */ -@@ -765,6 +1122,10 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) +@@ -656,6 +964,10 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) int ret; u32 val; @@ -2514,7 +2546,7 @@ index 3784118..e82d4c5 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 +1138,15 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) +@@ -668,18 +980,15 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) /** * stm32h7_adc_read_selfcalib() - read calibration shadow regs, save result * @adc: stm32 adc instance @@ -2535,7 +2567,7 @@ index 3784118..e82d4c5 100644 /* Read linearity calibration */ lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { -@@ -801,27 +1159,25 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) +@@ -692,27 +1001,25 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) 100, STM32_ADC_TIMEOUT_US); if (ret) { dev_err(&indio_dev->dev, "Failed to read calfact\n"); @@ -2572,7 +2604,7 @@ index 3784118..e82d4c5 100644 } /** -@@ -832,11 +1188,16 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) +@@ -723,11 +1030,16 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) { struct iio_dev *indio_dev = iio_priv_to_dev(adc); @@ -2591,7 +2623,7 @@ index 3784118..e82d4c5 100644 stm32_adc_writel(adc, STM32H7_ADC_CALFACT, val); lincalrdyw_mask = STM32H7_LINCALRDYW6; -@@ -846,7 +1207,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) +@@ -737,7 +1049,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) * Write CALFACT2, and set LINCALRDYW[6..1] bit to trigger * data write. Then poll to wait for complete transfer. */ @@ -2600,7 +2632,7 @@ index 3784118..e82d4c5 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 +1234,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) +@@ -764,7 +1076,7 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) return ret; } val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2); @@ -2609,7 +2641,7 @@ index 3784118..e82d4c5 100644 dev_err(&indio_dev->dev, "calfact not consistent\n"); return -EIO; } -@@ -898,19 +1259,19 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) +@@ -789,19 +1101,19 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) #define STM32H7_ADC_CALIB_TIMEOUT_US 100000 /** @@ -2634,7 +2666,7 @@ index 3784118..e82d4c5 100644 /* * Select calibration mode: -@@ -927,7 +1288,7 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) +@@ -818,7 +1130,7 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { dev_err(&indio_dev->dev, "calibration failed\n"); @@ -2643,7 +2675,7 @@ index 3784118..e82d4c5 100644 } /* -@@ -944,18 +1305,13 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) +@@ -835,18 +1147,13 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { dev_err(&indio_dev->dev, "calibration failed\n"); @@ -2664,7 +2696,7 @@ index 3784118..e82d4c5 100644 return ret; } -@@ -972,23 +1328,43 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) +@@ -863,23 +1170,43 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) */ static int stm32h7_adc_prepare(struct stm32_adc *adc) { @@ -2713,7 +2745,7 @@ index 3784118..e82d4c5 100644 return 0; -@@ -996,39 +1372,196 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) +@@ -887,39 +1214,196 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) stm32h7_adc_disable(adc); pwr_dwn: stm32h7_adc_enter_pwr_down(adc); @@ -2916,7 +2948,7 @@ index 3784118..e82d4c5 100644 for_each_set_bit(bit, scan_mask, indio_dev->masklength) { chan = indio_dev->channels + bit; -@@ -1037,11 +1570,12 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, +@@ -928,11 +1412,12 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, * sequence, starting with SQ1. */ i++; @@ -2932,7 +2964,7 @@ index 3784118..e82d4c5 100644 val = stm32_adc_readl(adc, sqr[i].reg); val &= ~sqr[i].mask; -@@ -1071,18 +1605,36 @@ static int stm32_adc_get_trig_extsel(struct iio_dev *indio_dev, +@@ -962,18 +1447,36 @@ static int stm32_adc_get_trig_extsel(struct iio_dev *indio_dev, struct iio_trigger *trig) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -2971,7 +3003,7 @@ index 3784118..e82d4c5 100644 } } -@@ -1102,10 +1654,24 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, +@@ -993,10 +1496,24 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, struct iio_trigger *trig) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -2997,7 +3029,7 @@ index 3784118..e82d4c5 100644 if (trig) { ret = stm32_adc_get_trig_extsel(indio_dev, trig); if (ret < 0) -@@ -1117,11 +1683,9 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, +@@ -1008,11 +1525,9 @@ static int stm32_adc_set_trig(struct iio_dev *indio_dev, } spin_lock_irqsave(&adc->lock, flags); @@ -3012,7 +3044,7 @@ index 3784118..e82d4c5 100644 spin_unlock_irqrestore(&adc->lock, flags); return 0; -@@ -1174,36 +1738,47 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, +@@ -1065,36 +1580,47 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, int *res) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -3072,18 +3104,19 @@ index 3784118..e82d4c5 100644 stm32_adc_conv_irq_enable(adc); -@@ -1224,8 +1799,8 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, +@@ -1115,8 +1641,9 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, stm32_adc_conv_irq_disable(adc); - if (adc->cfg->unprepare) - adc->cfg->unprepare(adc); ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return ret; } -@@ -1272,14 +1847,72 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, +@@ -1163,14 +1690,72 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, } } @@ -3157,7 +3190,7 @@ index 3784118..e82d4c5 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 +1924,48 @@ static irqreturn_t stm32_adc_isr(int irq, void *data) +@@ -1182,10 +1767,48 @@ static irqreturn_t stm32_adc_isr(int irq, void *data) } else { complete(&adc->completion); } @@ -3208,7 +3241,7 @@ index 3784118..e82d4c5 100644 } /** -@@ -1333,13 +2004,168 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, +@@ -1224,13 +1847,169 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -3226,6 +3259,7 @@ index 3784118..e82d4c5 100644 ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask); - if (ret) - return ret; ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + @@ -3379,7 +3413,7 @@ index 3784118..e82d4c5 100644 return 0; } -@@ -1371,12 +2197,23 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, +@@ -1262,12 +2041,24 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, unsigned *readval) { struct stm32_adc *adc = iio_priv(indio_dev); @@ -3397,13 +3431,14 @@ index 3784118..e82d4c5 100644 else *readval = stm32_adc_readl(adc, reg); ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; } -@@ -1385,6 +2222,10 @@ static const struct iio_info stm32_adc_iio_info = { +@@ -1276,6 +2067,10 @@ static const struct iio_info stm32_adc_iio_info = { .validate_trigger = stm32_adc_validate_trigger, .hwfifo_set_watermark = stm32_adc_set_watermark, .update_scan_mode = stm32_adc_update_scan_mode, @@ -3414,7 +3449,7 @@ index 3784118..e82d4c5 100644 .debugfs_reg_access = stm32_adc_debugfs_reg_access, .of_xlate = stm32_adc_of_xlate, }; -@@ -1414,11 +2255,32 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc) +@@ -1305,11 +2100,32 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc) return 0; } @@ -3448,16 +3483,7 @@ index 3784118..e82d4c5 100644 } 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) +@@ -1350,21 +2166,28 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev) return 0; } @@ -3492,7 +3518,7 @@ index 3784118..e82d4c5 100644 } ret = stm32_adc_dma_start(indio_dev); -@@ -1482,13 +2351,11 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) +@@ -1373,13 +2196,11 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) goto err_clr_trig; } @@ -3508,7 +3534,7 @@ index 3784118..e82d4c5 100644 if (!adc->dma_chan) stm32_adc_conv_irq_enable(adc); -@@ -1496,39 +2363,66 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) +@@ -1387,39 +2208,68 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) return 0; @@ -3523,6 +3549,7 @@ index 3784118..e82d4c5 100644 +err_clr_awd: + stm32_adc_awd_clear(adc); +err_pm_put: ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); @@ -3561,9 +3588,8 @@ index 3784118..e82d4c5 100644 + stm32_adc_ovr_irq_disable(adc); - if (adc->dma_chan) -- dmaengine_terminate_all(adc->dma_chan); + if (adc->dma_chan) { -+ dmaengine_terminate_sync(adc->dma_chan); + dmaengine_terminate_sync(adc->dma_chan); + irq_work_sync(&adc->work); + } @@ -3574,6 +3600,7 @@ index 3784118..e82d4c5 100644 - adc->cfg->unprepare(adc); + stm32_adc_awd_clear(adc); + ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); +} @@ -3590,7 +3617,7 @@ index 3784118..e82d4c5 100644 return ret; } -@@ -1613,6 +2507,7 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev) +@@ -1504,6 +2354,7 @@ static int stm32_adc_of_get_resolution(struct iio_dev *indio_dev) static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) { const struct stm32_adc_regs *smpr = &adc->cfg->regs->smp_bits[channel]; @@ -3598,7 +3625,7 @@ index 3784118..e82d4c5 100644 u32 period_ns, shift = smpr->shift, mask = smpr->mask; unsigned int smp, r = smpr->reg; -@@ -1625,7 +2520,7 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) +@@ -1516,7 +2367,7 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) smp = STM32_ADC_MAX_SMP; /* pre-build sampling time registers (e.g. smpr1, smpr2) */ @@ -3607,7 +3634,7 @@ index 3784118..e82d4c5 100644 } 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, +@@ -1525,6 +2376,8 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, { struct stm32_adc *adc = iio_priv(indio_dev); char *name = adc->chan_name[vinp]; @@ -3616,7 +3643,7 @@ index 3784118..e82d4c5 100644 chan->type = IIO_VOLTAGE; chan->channel = vinp; -@@ -1654,14 +2551,16 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -1545,14 +2398,16 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, chan->scan_type.realbits = adc->cfg->adc_info->resolutions[adc->res]; chan->scan_type.storagebits = 16; chan->ext_info = stm32_adc_ext_info; @@ -3636,7 +3663,7 @@ index 3784118..e82d4c5 100644 } } -@@ -1677,6 +2576,11 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) +@@ -1568,6 +2423,11 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) int scan_index = 0, num_channels = 0, num_diff = 0, ret, i; u32 val, smp = 0; @@ -3648,7 +3675,7 @@ index 3784118..e82d4c5 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"); -@@ -1797,6 +2701,8 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev) +@@ -1688,6 +2548,8 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev) if (ret) goto err_free; @@ -3657,7 +3684,7 @@ index 3784118..e82d4c5 100644 return 0; err_free: -@@ -1828,6 +2734,7 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1719,6 +2581,7 @@ static int stm32_adc_probe(struct platform_device *pdev) init_completion(&adc->completion); adc->cfg = (const struct stm32_adc_cfg *) of_match_device(dev->driver->of_match_table, dev)->data; @@ -3665,7 +3692,7 @@ index 3784118..e82d4c5 100644 indio_dev->name = dev_name(&pdev->dev); indio_dev->dev.parent = &pdev->dev; -@@ -1838,10 +2745,18 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1729,10 +2592,18 @@ static int stm32_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adc); ret = of_property_read_u32(pdev->dev.of_node, "reg", &adc->offset); @@ -3685,7 +3712,7 @@ index 3784118..e82d4c5 100644 adc->irq = platform_get_irq(pdev, 0); if (adc->irq < 0) { -@@ -1849,8 +2764,9 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1740,8 +2611,9 @@ static int stm32_adc_probe(struct platform_device *pdev) return adc->irq; } @@ -3697,7 +3724,7 @@ index 3784118..e82d4c5 100644 if (ret) { dev_err(&pdev->dev, "failed to request IRQ\n"); return ret; -@@ -1867,32 +2783,17 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1758,32 +2630,17 @@ static int stm32_adc_probe(struct platform_device *pdev) } } @@ -3733,7 +3760,7 @@ index 3784118..e82d4c5 100644 ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, -@@ -1903,15 +2804,35 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1794,15 +2651,36 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_dma_disable; } @@ -3755,6 +3782,7 @@ index 3784118..e82d4c5 100644 + goto err_hw_stop; } ++ pm_runtime_mark_last_busy(dev->parent); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + @@ -3770,7 +3798,7 @@ index 3784118..e82d4c5 100644 iio_triggered_buffer_cleanup(indio_dev); err_dma_disable: -@@ -1921,9 +2842,6 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -1812,9 +2690,6 @@ static int stm32_adc_probe(struct platform_device *pdev) adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } @@ -3780,7 +3808,7 @@ index 3784118..e82d4c5 100644 return ret; } -@@ -1933,7 +2851,12 @@ static int stm32_adc_remove(struct platform_device *pdev) +@@ -1824,7 +2699,12 @@ static int stm32_adc_remove(struct platform_device *pdev) struct stm32_adc *adc = platform_get_drvdata(pdev); struct iio_dev *indio_dev = iio_priv_to_dev(adc); @@ -3793,7 +3821,7 @@ index 3784118..e82d4c5 100644 iio_triggered_buffer_cleanup(indio_dev); if (adc->dma_chan) { dma_free_coherent(adc->dma_chan->device->dev, -@@ -1941,12 +2864,62 @@ static int stm32_adc_remove(struct platform_device *pdev) +@@ -1832,12 +2712,62 @@ static int stm32_adc_remove(struct platform_device *pdev) adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } @@ -3858,7 +3886,7 @@ index 3784118..e82d4c5 100644 static const struct stm32_adc_cfg stm32f4_adc_cfg = { .regs = &stm32f4_adc_regspec, .adc_info = &stm32f4_adc_info, -@@ -1955,18 +2928,19 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = { +@@ -1846,18 +2776,19 @@ static const struct stm32_adc_cfg stm32f4_adc_cfg = { .start_conv = stm32f4_adc_start_conv, .stop_conv = stm32f4_adc_stop_conv, .smp_cycles = stm32f4_adc_smp_cycles, @@ -3879,7 +3907,7 @@ index 3784118..e82d4c5 100644 }; static const struct stm32_adc_cfg stm32mp1_adc_cfg = { -@@ -1974,12 +2948,12 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { +@@ -1865,12 +2796,12 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .adc_info = &stm32h7_adc_info, .trigs = stm32h7_adc_trigs, .has_vregready = true, @@ -3893,7 +3921,7 @@ index 3784118..e82d4c5 100644 }; static const struct of_device_id stm32_adc_of_match[] = { -@@ -1996,6 +2970,7 @@ static struct platform_driver stm32_adc_driver = { +@@ -1887,6 +2818,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc", .of_match_table = stm32_adc_of_match, @@ -3902,11 +3930,14 @@ index 3784118..e82d4c5 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..ae6b166 100644 +index f5586dd..034f919 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c -@@ -12,6 +12,11 @@ +@@ -10,8 +10,14 @@ + #include + #include #include ++#include #include #include +#include @@ -3917,7 +3948,7 @@ index fcd4a1c..ae6b166 100644 #include #include #include -@@ -34,9 +39,21 @@ +@@ -34,9 +40,21 @@ #define DFSDM_MAX_INT_OVERSAMPLING 256 #define DFSDM_MAX_FL_OVERSAMPLING 1024 @@ -3942,7 +3973,18 @@ index fcd4a1c..ae6b166 100644 enum sd_converter_type { DFSDM_AUDIO, -@@ -54,6 +71,8 @@ struct stm32_dfsdm_adc { +@@ -50,16 +68,26 @@ struct stm32_dfsdm_dev_data { + const struct regmap_config *regmap_cfg; + }; + ++struct stm32_dfsdm_sd_chan_info { ++ int scale_val; ++ int scale_val2; ++ int offset; ++ unsigned int differential; ++}; ++ + struct stm32_dfsdm_adc { struct stm32_dfsdm *dfsdm; const struct stm32_dfsdm_dev_data *dev_data; unsigned int fl_id; @@ -3951,7 +3993,14 @@ index fcd4a1c..ae6b166 100644 /* ADC specific */ unsigned int oversamp; -@@ -114,14 +133,70 @@ static int stm32_dfsdm_str2val(const char *str, + struct iio_hw_consumer *hwc; + struct completion completion; + u32 *buffer; ++ struct stm32_dfsdm_sd_chan_info *sd_chan; + + /* Audio specific */ + unsigned int spi_freq; /* SPI bus clock frequency */ +@@ -114,14 +142,70 @@ static int stm32_dfsdm_str2val(const char *str, return -EINVAL; } @@ -4026,7 +4075,7 @@ index fcd4a1c..ae6b166 100644 pr_debug("%s: Requested oversampling: %d\n", __func__, oversamp); /* -@@ -140,11 +215,8 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, +@@ -140,11 +224,8 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, /* * Look for filter and integrator oversampling ratios which allows @@ -4039,7 +4088,7 @@ index fcd4a1c..ae6b166 100644 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, +@@ -169,50 +250,128 @@ static int stm32_dfsdm_set_osrs(struct stm32_dfsdm_filter *fl, res = fosr; for (i = p - 1; i > 0; i--) { res = res * (u64)fosr; @@ -4193,7 +4242,7 @@ index fcd4a1c..ae6b166 100644 } static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, -@@ -237,9 +387,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, +@@ -237,9 +396,11 @@ static int stm32_dfsdm_chan_configure(struct stm32_dfsdm *dfsdm, DFSDM_CHCFGR1_CHINSEL(ch->alt_si)); } @@ -4207,7 +4256,7 @@ index fcd4a1c..ae6b166 100644 int ret; /* Enable filter */ -@@ -248,7 +400,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, +@@ -248,7 +409,11 @@ static int stm32_dfsdm_start_filter(struct stm32_dfsdm *dfsdm, if (ret < 0) return ret; @@ -4220,7 +4269,7 @@ index fcd4a1c..ae6b166 100644 return regmap_update_bits(dfsdm->regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RSWSTART_MASK, DFSDM_CR1_RSWSTART(1)); -@@ -262,22 +418,101 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, +@@ -262,22 +427,101 @@ static void stm32_dfsdm_stop_filter(struct stm32_dfsdm *dfsdm, DFSDM_CR1_DFEN_MASK, DFSDM_CR1_DFEN(0)); } @@ -4328,7 +4377,7 @@ index fcd4a1c..ae6b166 100644 if (ret) return ret; -@@ -286,15 +521,74 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, +@@ -286,15 +530,74 @@ static int stm32_dfsdm_filter_configure(struct stm32_dfsdm *dfsdm, if (ret) return ret; @@ -4336,18 +4385,18 @@ index fcd4a1c..ae6b166 100644 - ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), DFSDM_CR1_RCH_MASK, - DFSDM_CR1_RCH(ch_id)); + ret = stm32_dfsdm_filter_set_trig(adc, fl_id, trig); ++ if (ret) ++ return ret; ++ ++ ret = regmap_update_bits(regmap, DFSDM_CR1(fl_id), ++ DFSDM_CR1_FAST_MASK, ++ DFSDM_CR1_FAST(fl->fast)); if (ret) return ret; - return regmap_update_bits(regmap, DFSDM_CR1(fl_id), - DFSDM_CR1_RSYNC_MASK, - DFSDM_CR1_RSYNC(fl->sync_mode)); -+ 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 + * ---------------------------------------------------------------- @@ -4409,7 +4458,7 @@ index fcd4a1c..ae6b166 100644 } static int stm32_dfsdm_channel_parse_of(struct stm32_dfsdm *dfsdm, -@@ -378,13 +672,36 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, +@@ -378,13 +681,36 @@ static ssize_t dfsdm_adc_audio_get_spiclk(struct iio_dev *indio_dev, return snprintf(buf, PAGE_SIZE, "%d\n", adc->spi_freq); } @@ -4447,7 +4496,7 @@ index fcd4a1c..ae6b166 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 +720,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, +@@ -403,17 +729,9 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, return -EINVAL; if (sample_freq) { @@ -4467,7 +4516,7 @@ index fcd4a1c..ae6b166 100644 } adc->spi_freq = spi_freq; -@@ -421,72 +730,48 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, +@@ -421,72 +739,48 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev, } static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, @@ -4519,11 +4568,11 @@ index fcd4a1c..ae6b166 100644 return 0; -stop_channels: -- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RDMAEN_MASK, 0); -- +filter_unconfigure: regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), +- DFSDM_CR1_RDMAEN_MASK, 0); +- +- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), - DFSDM_CR1_RCONT_MASK, 0); - stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); + DFSDM_CR1_CFG_MASK, 0); @@ -4542,19 +4591,19 @@ index fcd4a1c..ae6b166 100644 stm32_dfsdm_stop_filter(adc->dfsdm, adc->fl_id); - /* Clean conversion options */ -- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RDMAEN_MASK, 0); -- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), -- DFSDM_CR1_RCONT_MASK, 0); +- DFSDM_CR1_RDMAEN_MASK, 0); + DFSDM_CR1_CFG_MASK, 0); +- regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id), +- DFSDM_CR1_RCONT_MASK, 0); +- - stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel); + stm32_dfsdm_stop_channel(adc); } static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, -@@ -494,6 +779,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, +@@ -494,6 +788,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); unsigned int watermark = DFSDM_DMA_BUFFER_SIZE / 2; @@ -4562,7 +4611,7 @@ index fcd4a1c..ae6b166 100644 /* * DMA cyclic transfers are used, buffer is split into two periods. -@@ -502,7 +788,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, +@@ -502,7 +797,7 @@ static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev, * - one buffer (period) driver pushed to ASoC side. */ watermark = min(watermark, val * (unsigned int)(sizeof(u32))); @@ -4571,7 +4620,7 @@ index fcd4a1c..ae6b166 100644 return 0; } -@@ -532,13 +818,67 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) +@@ -532,13 +827,67 @@ static unsigned int stm32_dfsdm_adc_dma_residue(struct stm32_dfsdm_adc *adc) return 0; } @@ -4640,7 +4689,7 @@ index fcd4a1c..ae6b166 100644 /* * FIXME: In Kernel interface does not support cyclic DMA buffer,and * offers only an interface to push data samples per samples. -@@ -553,10 +893,10 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) +@@ -553,10 +902,10 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) old_pos = adc->bufi; while (available >= indio_dev->scan_bytes) { @@ -4654,7 +4703,7 @@ index fcd4a1c..ae6b166 100644 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) +@@ -566,6 +915,9 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) adc->bufi = 0; old_pos = 0; } @@ -4664,7 +4713,7 @@ index fcd4a1c..ae6b166 100644 } if (adc->cb) adc->cb(&adc->rx_buf[old_pos], adc->bufi - old_pos, -@@ -575,6 +918,15 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) +@@ -575,6 +927,15 @@ static void stm32_dfsdm_audio_dma_buffer_done(void *data) static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -4680,7 +4729,7 @@ index fcd4a1c..ae6b166 100644 struct dma_async_tx_descriptor *desc; dma_cookie_t cookie; int ret; -@@ -585,6 +937,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) +@@ -585,6 +946,14 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__, adc->buf_sz, adc->buf_sz / 2); @@ -4695,7 +4744,7 @@ index fcd4a1c..ae6b166 100644 /* Prepare a DMA cyclic transaction */ desc = dmaengine_prep_dma_cyclic(adc->dma_chan, adc->dma_buf, -@@ -594,71 +954,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) +@@ -594,71 +963,154 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev) if (!desc) return -EBUSY; @@ -4873,7 +4922,7 @@ index fcd4a1c..ae6b166 100644 return 0; } -@@ -736,7 +1179,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, +@@ -736,7 +1188,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, if (ret < 0) goto stop_dfsdm; @@ -4884,7 +4933,7 @@ index fcd4a1c..ae6b166 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 +1202,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, +@@ -757,7 +1211,9 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev, else ret = IIO_VAL_INT; @@ -4895,7 +4944,7 @@ index fcd4a1c..ae6b166 100644 stop_dfsdm: stm32_dfsdm_stop_dfsdm(adc->dfsdm); -@@ -770,23 +1217,29 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, +@@ -770,49 +1226,50 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, int val, int val2, long mask) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -4904,16 +4953,35 @@ index fcd4a1c..ae6b166 100644 unsigned int spi_freq; int ret = -EINVAL; ++ switch (ch->src) { ++ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: ++ spi_freq = adc->dfsdm->spi_master_freq; ++ break; ++ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING: ++ case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING: ++ spi_freq = adc->dfsdm->spi_master_freq / 2; ++ break; ++ default: ++ spi_freq = adc->spi_freq; ++ } ++ switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: - ret = stm32_dfsdm_set_osrs(fl, 0, val); +- if (!ret) +- adc->oversamp = val; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = stm32_dfsdm_compute_all_osrs(indio_dev, val); - if (!ret) - adc->oversamp = val; -- ++ if (!ret) { ++ dev_dbg(&indio_dev->dev, ++ "Sampling rate changed from (%u) to (%u)\n", ++ adc->sample_freq, spi_freq / val); ++ adc->oversamp = val; ++ adc->sample_freq = spi_freq / val; ++ } + iio_device_release_direct_mode(indio_dev); return ret; @@ -4921,17 +4989,18 @@ index fcd4a1c..ae6b166 100644 if (!val) return -EINVAL; -+ ret = iio_device_claim_direct_mode(indio_dev); -+ if (ret) -+ return ret; -+ - switch (ch->src) { - case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: - spi_freq = adc->dfsdm->spi_master_freq; -@@ -799,20 +1252,9 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev, - spi_freq = adc->spi_freq; - } - +- switch (ch->src) { +- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL: +- spi_freq = adc->dfsdm->spi_master_freq; +- break; +- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING: +- case DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING: +- spi_freq = adc->dfsdm->spi_master_freq / 2; +- break; +- default: +- spi_freq = adc->spi_freq; +- } +- - if (spi_freq % val) - dev_warn(&indio_dev->dev, - "Sampling rate not accurate (%d)\n", @@ -4941,10 +5010,12 @@ index fcd4a1c..ae6b166 100644 - if (ret < 0) { - dev_err(&indio_dev->dev, - "Not able to find parameter that match!\n"); -- return ret; ++ ret = iio_device_claim_direct_mode(indio_dev); ++ if (ret) + return ret; - } - adc->sample_freq = val; -- + - return 0; + ret = dfsdm_adc_set_samp_freq(indio_dev, val, spi_freq); + iio_device_release_direct_mode(indio_dev); @@ -4952,7 +5023,15 @@ index fcd4a1c..ae6b166 100644 } return -EINVAL; -@@ -827,11 +1269,15 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -823,15 +1280,22 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, + int *val2, long mask) + { + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); +- int ret; ++ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id]; ++ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; ++ u32 max = flo->max << (flo->lshift - chan->scan_type.shift); ++ int ret, idx = chan->scan_index; switch (mask) { case IIO_CHAN_INFO_RAW: @@ -4968,7 +5047,7 @@ index fcd4a1c..ae6b166 100644 return ret; } ret = stm32_dfsdm_single_conv(indio_dev, chan, val); -@@ -840,8 +1286,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -840,8 +1304,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, dev_err(&indio_dev->dev, "%s: Conversion failed (channel %d)\n", __func__, chan->channel); @@ -4979,7 +5058,45 @@ index fcd4a1c..ae6b166 100644 return IIO_VAL_INT; case IIO_CHAN_INFO_OVERSAMPLING_RATIO: -@@ -858,15 +1306,25 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -853,20 +1319,63 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, + *val = adc->sample_freq; + + return IIO_VAL_INT; ++ ++ case IIO_CHAN_INFO_SCALE: ++ /* ++ * Scale is expressed in mV. ++ * When fast mode is disabled, actual resolution may be lower ++ * than 2^n, where n=realbits-1. ++ * This leads to underestimating input voltage. To ++ * compensate this deviation, the voltage reference can be ++ * corrected with a factor = realbits resolution / actual max ++ */ ++ *val = div_u64((u64)adc->sd_chan[idx].scale_val * ++ (u64)BIT(DFSDM_DATA_RES - 1), max); ++ *val2 = chan->scan_type.realbits; ++ if (adc->sd_chan[idx].differential) ++ *val *= 2; ++ return IIO_VAL_FRACTIONAL_LOG2; ++ ++ case IIO_CHAN_INFO_OFFSET: ++ /* ++ * DFSDM output data are in the range [-2^n,2^n-1], ++ * with n=realbits-1. ++ * - Differential modulator: ++ * Offset correspond to SD modulator offset. ++ * - Single ended modulator: ++ * Input is in [0V,Vref] range, where 0V corresponds to -2^n. ++ * Add 2^n to offset. (i.e. middle of input range) ++ * offset = offset(sd) * vref / res(sd) * max / vref. ++ */ ++ *val = div_u64((u64)max * adc->sd_chan[idx].offset, ++ BIT(adc->sd_chan[idx].scale_val2 - 1)); ++ if (!adc->sd_chan[idx].differential) ++ *val += max; ++ return IIO_VAL_INT; + } + return -EINVAL; } @@ -5005,7 +5122,7 @@ index fcd4a1c..ae6b166 100644 }; static irqreturn_t stm32_dfsdm_irq(int irq, void *arg) -@@ -926,12 +1384,6 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) +@@ -926,12 +1435,6 @@ static void stm32_dfsdm_dma_release(struct iio_dev *indio_dev) static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -5018,7 +5135,7 @@ index fcd4a1c..ae6b166 100644 adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); if (!adc->dma_chan) -@@ -941,23 +1393,14 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) +@@ -941,23 +1444,14 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) DFSDM_DMA_BUFFER_SIZE, &adc->dma_buf, GFP_KERNEL); if (!adc->rx_buf) { @@ -5046,26 +5163,30 @@ index fcd4a1c..ae6b166 100644 } 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, +@@ -977,8 +1471,11 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, + * IIO_CHAN_INFO_RAW: used to compute regular conversion * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling */ - ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); +- ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); - ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO); ++ ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | ++ BIT(IIO_CHAN_INFO_SCALE) | ++ BIT(IIO_CHAN_INFO_OFFSET); + ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | + BIT(IIO_CHAN_INFO_SAMP_FREQ); if (adc->dev_data->type == DFSDM_AUDIO) { -- ch->scan_type.sign = 's'; ch->ext_info = dfsdm_adc_audio_ext_info; - } else { -- ch->scan_type.sign = 'u'; -+ ch->scan_type.shift = 8; +@@ -986,7 +1483,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, + ch->scan_type.shift = 8; } -+ ch->scan_type.sign = 's'; - ch->scan_type.realbits = 24; + ch->scan_type.sign = 's'; +- ch->scan_type.realbits = 24; ++ ch->scan_type.realbits = DFSDM_DATA_RES; ch->scan_type.storagebits = 32; -@@ -1000,9 +1444,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) + return stm32_dfsdm_chan_configure(adc->dfsdm, +@@ -1000,9 +1497,6 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev) struct stm32_dfsdm_channel *d_ch; int ret; @@ -5075,8 +5196,15 @@ index fcd4a1c..ae6b166 100644 ch = devm_kzalloc(&indio_dev->dev, sizeof(*ch), GFP_KERNEL); if (!ch) return -ENOMEM; -@@ -1034,8 +1475,7 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) - int ret, chan_idx; +@@ -1030,12 +1524,13 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + { + struct iio_chan_spec *ch; + struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); ++ struct iio_channel *channels, *chan; ++ struct stm32_dfsdm_sd_chan_info *sd_chan; + int num_ch; +- int ret, chan_idx; ++ int ret, chan_idx, val2; adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; - ret = stm32_dfsdm_set_osrs(&adc->dfsdm->fl_list[adc->fl_id], 0, @@ -5085,7 +5213,68 @@ index fcd4a1c..ae6b166 100644 if (ret < 0) return ret; -@@ -1070,6 +1510,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) +@@ -1056,6 +1551,21 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + if (!ch) + return -ENOMEM; + ++ /* Get SD modulator channels */ ++ channels = iio_channel_get_all(&indio_dev->dev); ++ if (IS_ERR(channels)) { ++ dev_err(&indio_dev->dev, "Failed to get channel %ld\n", ++ PTR_ERR(channels)); ++ return PTR_ERR(channels); ++ } ++ chan = &channels[0]; ++ ++ adc->sd_chan = devm_kzalloc(&indio_dev->dev, ++ sizeof(*adc->sd_chan) * num_ch, GFP_KERNEL); ++ if (!adc->sd_chan) ++ return -ENOMEM; ++ sd_chan = adc->sd_chan; ++ + for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { + ch[chan_idx].scan_index = chan_idx; + ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]); +@@ -1063,6 +1573,38 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) + dev_err(&indio_dev->dev, "Channels init failed\n"); + return ret; + } ++ ++ if (!chan->indio_dev) ++ return -EINVAL; ++ ++ ret = iio_read_channel_scale(chan, &sd_chan->scale_val, ++ &sd_chan->scale_val2); ++ if (ret < 0) { ++ dev_err(&indio_dev->dev, ++ "Failed to get channel %d scale\n", chan_idx); ++ return ret; ++ } ++ ++ if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_OFFSET)) { ++ ret = iio_read_channel_offset(chan, &sd_chan->offset, ++ &val2); ++ if (ret < 0) { ++ dev_err(&indio_dev->dev, ++ "Failed to get channel %d offset\n", ++ chan_idx); ++ return ret; ++ } ++ } ++ ++ sd_chan->differential = chan->channel->differential; ++ ++ dev_dbg(&indio_dev->dev, "Channel %d %s scale ref=%d offset=%d", ++ chan_idx, chan->channel->differential ? ++ "differential" : "single-ended", ++ sd_chan->scale_val, sd_chan->offset); ++ ++ chan++; ++ sd_chan++; + } + + indio_dev->num_channels = num_ch; +@@ -1070,6 +1612,25 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) init_completion(&adc->completion); @@ -5111,7 +5300,7 @@ index fcd4a1c..ae6b166 100644 return 0; } -@@ -1117,7 +1576,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) +@@ -1117,7 +1678,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev) iio->dev.parent = dev; iio->dev.of_node = np; @@ -5120,20 +5309,7 @@ index fcd4a1c..ae6b166 100644 platform_set_drvdata(pdev, adc); -@@ -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) +@@ -1209,10 +1770,48 @@ static int stm32_dfsdm_adc_remove(struct platform_device *pdev) return 0; } @@ -5183,7 +5359,7 @@ index fcd4a1c..ae6b166 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..9609515 100644 +index 9416306..9609515 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -12,6 +12,8 @@ @@ -5319,29 +5495,7 @@ index bf089f5..9609515 100644 } dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, atomic_read(&priv->n_active_ch)); -@@ -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, +@@ -247,13 +267,18 @@ static int stm32_dfsdm_parse_of(struct platform_device *pdev, return 0; } @@ -5362,7 +5516,7 @@ index bf089f5..9609515 100644 if (rem) { dev_warn(&pdev->dev, "SPI clock not accurate\n"); -@@ -318,14 +347,115 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) +@@ -322,14 +347,115 @@ static int stm32_dfsdm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dfsdm); @@ -5392,8 +5546,8 @@ index bf089f5..9609515 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); @@ -5423,8 +5577,8 @@ index bf089f5..9609515 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); 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.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch similarity index 76% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0011-ARM-stm32mp1-r2-INPUT-IRQ-Mailbox.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch index 520ebea..4ef2646 100644 --- 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.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch @@ -1,18 +1,20 @@ -From a7a3aa42479bf82ba9ed31d2960ad299a5bb214b Mon Sep 17 00:00:00 2001 +From b9a72771779e960b3ddf14d372ed6484cba99cbc 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 +Date: Fri, 8 Nov 2019 16:52:41 +0100 +Subject: [PATCH 12/31] ARM stm32mp1 r3 INPUT IRQ Mailbox --- drivers/input/misc/Kconfig | 11 ++ drivers/input/misc/Makefile | 2 + - drivers/input/misc/stpmic1_onkey.c | 197 +++++++++++++++++++ - drivers/input/touchscreen/edt-ft5x06.c | 8 +- - drivers/input/touchscreen/goodix.c | 9 + + drivers/input/misc/stpmic1_onkey.c | 198 +++++++++++++++++++ + drivers/input/touchscreen/edt-ft5x06.c | 24 ++- + drivers/input/touchscreen/goodix.c | 24 +++ drivers/irqchip/irq-stm32-exti.c | 339 +++++++++++++++++++++++++++------ - drivers/mailbox/mailbox-test.c | 26 +-- - drivers/mailbox/stm32-ipcc.c | 54 ++++-- - 8 files changed, 555 insertions(+), 91 deletions(-) + drivers/mailbox/mailbox-test.c | 12 +- + drivers/mailbox/stm32-ipcc.c | 4 +- + kernel/irq/internals.h | 4 - + kernel/irq/manage.c | 75 ++------ + 10 files changed, 563 insertions(+), 130 deletions(-) create mode 100644 drivers/input/misc/stpmic1_onkey.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig @@ -54,10 +56,10 @@ index 9d0f9d1..1b44202 100644 + diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c new file mode 100644 -index 0000000..6a7f08b +index 0000000..7b49c99 --- /dev/null +++ b/drivers/input/misc/stpmic1_onkey.c -@@ -0,0 +1,197 @@ +@@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet for STMicroelectronics. @@ -135,7 +137,7 @@ index 0000000..6a7f08b + } + + if (!device_property_read_u32(dev, "power-off-time-sec", &val)) { -+ if ((val > 0) && (val <= 16)) { ++ 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); @@ -160,7 +162,8 @@ index 0000000..6a7f08b + PONKEY_PU_INACTIVE, + PONKEY_PU_INACTIVE); + if (error) { -+ dev_err(dev, "ONKEY Pads configuration failed: %d\n", error); ++ dev_err(dev, "ONKEY Pads configuration failed: %d\n", ++ error); + return error; + } + } @@ -256,10 +259,28 @@ index 0000000..6a7f08b +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 +index 1e18ca0..745da4c 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, +@@ -39,6 +39,8 @@ + #include + #include + #include ++#include ++ + + #define WORK_REGISTER_THRESHOLD 0x00 + #define WORK_REGISTER_REPORT_RATE 0x08 +@@ -968,6 +970,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, + { + const struct edt_i2c_chip_data *chip_data; + struct edt_ft5x06_ts_data *tsdata; ++ struct mipi_dsi_device *panel; ++ struct device_node *np; + struct input_dev *input; + unsigned long irq_flags; + int error; +@@ -1033,7 +1037,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, error = edt_ft5x06_ts_identify(client, tsdata, fw_version); if (error) { @@ -268,7 +289,26 @@ index 1e18ca0..c1c6f2a 100644 return error; } -@@ -1152,11 +1152,16 @@ static const struct edt_i2c_chip_data edt_ft6236_data = { +@@ -1105,6 +1109,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, + tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1, + tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); + ++ np = of_parse_phandle(client->dev.of_node, "panel", 0); ++ if (np) { ++ panel = of_find_mipi_dsi_device_by_node(np); ++ of_node_put(np); ++ if (!panel) ++ return -ENOENT; ++ ++ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | ++ DL_FLAG_AUTOREMOVE_SUPPLIER); ++ put_device(&panel->dev); ++ } ++ + return 0; + } + +@@ -1152,11 +1168,16 @@ static const struct edt_i2c_chip_data edt_ft6236_data = { .max_support_points = 2, }; @@ -285,7 +325,7 @@ index 1e18ca0..c1c6f2a 100644 { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id); -@@ -1169,6 +1174,7 @@ static const struct of_device_id edt_ft5x06_of_match[] = { +@@ -1169,6 +1190,7 @@ static const struct of_device_id edt_ft5x06_of_match[] = { { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data }, /* Note focaltech vendor prefix for compatibility with ft6236.c */ { .compatible = "focaltech,ft6236", .data = &edt_ft6236_data }, @@ -294,18 +334,21 @@ index 1e18ca0..c1c6f2a 100644 }; 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 +index b20ba65..c196423 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c -@@ -27,6 +27,7 @@ +@@ -25,8 +25,10 @@ + #include + #include #include ++#include #include #include +#include #include #include #include -@@ -357,6 +358,13 @@ static void goodix_free_irq(struct goodix_ts_data *ts) +@@ -366,6 +368,13 @@ static void goodix_free_irq(struct goodix_ts_data *ts) static int goodix_request_irq(struct goodix_ts_data *ts) { @@ -319,7 +362,42 @@ index f2d9c2c..9ce8db4 100644 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[] = { +@@ -774,6 +783,8 @@ static int goodix_ts_probe(struct i2c_client *client, + const struct i2c_device_id *id) + { + struct goodix_ts_data *ts; ++ struct mipi_dsi_device *panel; ++ struct device_node *np; + int error; + + dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); +@@ -842,6 +853,17 @@ static int goodix_ts_probe(struct i2c_client *client, + return error; + } + ++ np = of_parse_phandle(client->dev.of_node, "panel", 0); ++ if (np) { ++ panel = of_find_mipi_dsi_device_by_node(np); ++ of_node_put(np); ++ if (!panel) ++ return -ENOENT; ++ device_link_add(&client->dev, &panel->dev, DL_FLAG_STATELESS | ++ DL_FLAG_AUTOREMOVE_SUPPLIER); ++ put_device(&panel->dev); ++ } ++ + return 0; + } + +@@ -896,6 +918,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) + * sooner, delay 58ms here. + */ + msleep(58); ++ + return 0; + } + +@@ -958,6 +981,7 @@ static const struct of_device_id goodix_of_match[] = { { .compatible = "goodix,gt9271" }, { .compatible = "goodix,gt928" }, { .compatible = "goodix,gt967" }, @@ -856,7 +934,7 @@ index 97b27f3..8e5a31b 100644 - -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 +index 129b365..4e4ac4b 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -31,7 +31,6 @@ @@ -896,38 +974,7 @@ index 58bfafc..4e4ac4b 100644 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) +@@ -418,7 +418,7 @@ static int mbox_test_remove(struct platform_device *pdev) { struct mbox_test_device *tdev = platform_get_drvdata(pdev); @@ -937,153 +984,10 @@ index 58bfafc..4e4ac4b 100644 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 +index e313222..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) +@@ -296,8 +296,8 @@ static int stm32_ipcc_probe(struct platform_device *pdev) dev_err(dev, "Failed to set wake up irq\n"); goto err_init_wkp; } @@ -1094,6 +998,169 @@ index 533b0da..eaf4ea4 100644 } /* mailbox controller */ +diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h +index ea57f3d..c119aa1 100644 +--- a/kernel/irq/internals.h ++++ b/kernel/irq/internals.h +@@ -95,10 +95,6 @@ static inline void irq_mark_irq(unsigned int irq) { } + extern void irq_mark_irq(unsigned int irq); + #endif + +-extern int __irq_get_irqchip_state(struct irq_data *data, +- enum irqchip_irq_state which, +- bool *state); +- + extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); + + irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags); +diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c +index 23bcfa7..f8214bb 100644 +--- a/kernel/irq/manage.c ++++ b/kernel/irq/manage.c +@@ -35,9 +35,8 @@ static int __init setup_forced_irqthreads(char *arg) + early_param("threadirqs", setup_forced_irqthreads); + #endif + +-static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip) ++static void __synchronize_hardirq(struct irq_desc *desc) + { +- struct irq_data *irqd = irq_desc_get_irq_data(desc); + bool inprogress; + + do { +@@ -53,20 +52,6 @@ static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip) + /* Ok, that indicated we're done: double-check carefully. */ + raw_spin_lock_irqsave(&desc->lock, flags); + inprogress = irqd_irq_inprogress(&desc->irq_data); +- +- /* +- * If requested and supported, check at the chip whether it +- * is in flight at the hardware level, i.e. already pending +- * in a CPU and waiting for service and acknowledge. +- */ +- if (!inprogress && sync_chip) { +- /* +- * Ignore the return code. inprogress is only updated +- * when the chip supports it. +- */ +- __irq_get_irqchip_state(irqd, IRQCHIP_STATE_ACTIVE, +- &inprogress); +- } + raw_spin_unlock_irqrestore(&desc->lock, flags); + + /* Oops, that failed? */ +@@ -89,18 +74,13 @@ static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip) + * Returns: false if a threaded handler is active. + * + * This function may be called - with care - from IRQ context. +- * +- * It does not check whether there is an interrupt in flight at the +- * hardware level, but not serviced yet, as this might deadlock when +- * called with interrupts disabled and the target CPU of the interrupt +- * is the current CPU. + */ + bool synchronize_hardirq(unsigned int irq) + { + struct irq_desc *desc = irq_to_desc(irq); + + if (desc) { +- __synchronize_hardirq(desc, false); ++ __synchronize_hardirq(desc); + return !atomic_read(&desc->threads_active); + } + +@@ -118,17 +98,13 @@ EXPORT_SYMBOL(synchronize_hardirq); + * + * Can only be called from preemptible code as it might sleep when + * an interrupt thread is associated to @irq. +- * +- * It optionally makes sure (when the irq chip supports that method) +- * that the interrupt is not pending in any CPU and waiting for +- * service. + */ + void synchronize_irq(unsigned int irq) + { + struct irq_desc *desc = irq_to_desc(irq); + + if (desc) { +- __synchronize_hardirq(desc, true); ++ __synchronize_hardirq(desc); + /* + * We made sure that no hardirq handler is + * running. Now verify that no threaded handlers are +@@ -1674,12 +1650,8 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id) + + unregister_handler_proc(irq, action); + +- /* +- * Make sure it's not being used on another CPU and if the chip +- * supports it also make sure that there is no (not yet serviced) +- * interrupt in flight at the hardware level. +- */ +- __synchronize_hardirq(desc, true); ++ /* Make sure it's not being used on another CPU: */ ++ synchronize_hardirq(irq); + + #ifdef CONFIG_DEBUG_SHIRQ + /* +@@ -2212,28 +2184,6 @@ int __request_percpu_irq(unsigned int irq, irq_handler_t handler, + } + EXPORT_SYMBOL_GPL(__request_percpu_irq); + +-int __irq_get_irqchip_state(struct irq_data *data, enum irqchip_irq_state which, +- bool *state) +-{ +- struct irq_chip *chip; +- int err = -EINVAL; +- +- do { +- chip = irq_data_get_irq_chip(data); +- if (chip->irq_get_irqchip_state) +- break; +-#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY +- data = data->parent_data; +-#else +- data = NULL; +-#endif +- } while (data); +- +- if (data) +- err = chip->irq_get_irqchip_state(data, which, state); +- return err; +-} +- + /** + * irq_get_irqchip_state - returns the irqchip state of a interrupt. + * @irq: Interrupt line that is forwarded to a VM +@@ -2252,6 +2202,7 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, + { + struct irq_desc *desc; + struct irq_data *data; ++ struct irq_chip *chip; + unsigned long flags; + int err = -EINVAL; + +@@ -2261,7 +2212,19 @@ int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, + + data = irq_desc_get_irq_data(desc); + +- err = __irq_get_irqchip_state(data, which, state); ++ do { ++ chip = irq_data_get_irq_chip(data); ++ if (chip->irq_get_irqchip_state) ++ break; ++#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY ++ data = data->parent_data; ++#else ++ data = NULL; ++#endif ++ } while (data); ++ ++ if (data) ++ err = chip->irq_get_irqchip_state(data, which, state); + + irq_put_desc_busunlock(desc, flags); + return err; -- 2.7.4 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0012-ARM-stm32mp1-r2-MEDIA.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch similarity index 52% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0012-ARM-stm32mp1-r2-MEDIA.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch index 67562c9..a4553cc 100644 --- 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.94/0013-ARM-stm32mp1-r3-MEDIA.patch @@ -1,20 +1,180 @@ -From c26e518bb565acef9af071733f60227f67a048ee Mon Sep 17 00:00:00 2001 +From 8e40238bdd44bb0088d19c053ab2261523c81637 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 +Date: Fri, 8 Nov 2019 16:52:41 +0100 +Subject: [PATCH 13/31] ARM stm32mp1 r3 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(-) + Documentation/media/uapi/v4l/subdev-formats.rst | 107 +++ + drivers/media/i2c/Kconfig | 13 + + drivers/media/i2c/Makefile | 1 + + drivers/media/i2c/ov5640.c | 1000 +++++++++++++-------- + drivers/media/i2c/st-mipid02.c | 1076 +++++++++++++++++++++++ + drivers/media/platform/Kconfig | 2 +- + drivers/media/platform/stm32/stm32-cec.c | 96 +- + drivers/media/platform/stm32/stm32-dcmi.c | 366 ++++++-- + drivers/media/usb/uvc/uvc_queue.c | 15 +- + drivers/media/usb/uvc/uvc_v4l2.c | 11 +- + drivers/media/usb/uvc/uvcvideo.h | 2 + + drivers/media/v4l2-core/v4l2-fwnode.c | 3 + + include/uapi/linux/media-bus-format.h | 3 +- + 13 files changed, 2266 insertions(+), 429 deletions(-) + create mode 100644 drivers/media/i2c/st-mipid02.c +diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst +index 8e73fcf..44f427c 100644 +--- a/Documentation/media/uapi/v4l/subdev-formats.rst ++++ b/Documentation/media/uapi/v4l/subdev-formats.rst +@@ -973,6 +973,113 @@ The following tables list existing packed RGB formats. + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` ++ * .. _MEDIA-BUS-FMT-BGR888-3X8: ++ ++ - MEDIA_BUS_FMT_BGR888_3X8 ++ - 0x101b ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - b\ :sub:`7` ++ - b\ :sub:`6` ++ - b\ :sub:`5` ++ - b\ :sub:`4` ++ - b\ :sub:`3` ++ - b\ :sub:`2` ++ - b\ :sub:`1` ++ - b\ :sub:`0` ++ * - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - g\ :sub:`7` ++ - g\ :sub:`6` ++ - g\ :sub:`5` ++ - g\ :sub:`4` ++ - g\ :sub:`3` ++ - g\ :sub:`2` ++ - g\ :sub:`1` ++ - g\ :sub:`0` ++ * - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - ++ - r\ :sub:`7` ++ - r\ :sub:`6` ++ - r\ :sub:`5` ++ - r\ :sub:`4` ++ - r\ :sub:`3` ++ - r\ :sub:`2` ++ - r\ :sub:`1` ++ - r\ :sub:`0` + * .. _MEDIA-BUS-FMT-GBR888-1X24: + + - MEDIA_BUS_FMT_GBR888_1X24 +diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig +index 8b1ae1d..6a8e58d 100644 +--- a/drivers/media/i2c/Kconfig ++++ b/drivers/media/i2c/Kconfig +@@ -1068,6 +1068,19 @@ config VIDEO_I2C + To compile this driver as a module, choose M here: the + module will be called video-i2c + ++config VIDEO_ST_MIPID02 ++ tristate "STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge" ++ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API ++ depends on MEDIA_CAMERA_SUPPORT ++ select V4L2_FWNODE ++ help ++ Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge. ++ It is used to allow usage of CSI-2 sensor with PARALLEL port ++ controller. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called st-mipid02. ++ + endmenu + + menu "Sensors used on soc_camera driver" +diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile +index 520b3c3..051c68e 100644 +--- a/drivers/media/i2c/Makefile ++++ b/drivers/media/i2c/Makefile +@@ -108,5 +108,6 @@ obj-$(CONFIG_VIDEO_OV2659) += ov2659.o + obj-$(CONFIG_VIDEO_TC358743) += tc358743.o + obj-$(CONFIG_VIDEO_IMX258) += imx258.o + obj-$(CONFIG_VIDEO_IMX274) += imx274.o ++obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o + + obj-$(CONFIG_SDR_MAX2175) += max2175.o diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index d5c0ffc..4432188 100644 +index 2023df1..62269ac 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -66,6 +66,7 @@ @@ -84,7 +244,15 @@ index d5c0ffc..4432188 100644 }; /* regulator supplies */ -@@ -261,8 +277,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +@@ -202,6 +218,7 @@ struct ov5640_ctrls { + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; ++ struct v4l2_ctrl *link_freq; + }; + + struct ov5640_dev { +@@ -261,8 +278,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0}, {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0}, @@ -94,7 +262,7 @@ index d5c0ffc..4432188 100644 {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[] = { +@@ -289,7 +305,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x3000, 0x00, 0, 0}, {0x3002, 0x1c, 0, 0}, {0x3004, 0xff, 0, 0}, {0x3006, 0xc3, 0, 0}, {0x302e, 0x08, 0, 0}, {0x4300, 0x3f, 0, 0}, @@ -103,7 +271,7 @@ index d5c0ffc..4432188 100644 {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[] = { +@@ -344,66 +360,8 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = { {0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300}, }; @@ -128,23 +296,23 @@ index d5c0ffc..4432188 100644 - -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}, +- {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}, -+ {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}, @@ -167,12 +335,12 @@ index d5c0ffc..4432188 100644 - -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[] = { ++static const struct reg_value ov5640_setting_VGA_640_480[] = { + {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -416,13 +392,12 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { +@@ -416,13 +374,13 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, @@ -180,17 +348,18 @@ index d5c0ffc..4432188 100644 - {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}, ++ {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[] = { ++static const struct reg_value ov5640_setting_XGA_1024_768[] = { + {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -435,13 +410,12 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { +@@ -435,13 +393,12 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, @@ -203,12 +372,12 @@ index d5c0ffc..4432188 100644 -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[] = { ++static const struct reg_value ov5640_setting_QVGA_320_240[] = { + {0x3c07, 0x08, 0, 0}, {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, {0x3814, 0x31, 0, 0}, {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, -@@ -454,70 +428,12 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { +@@ -454,13 +411,12 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, @@ -221,23 +390,22 @@ index d5c0ffc..4432188 100644 -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}, ++static const struct reg_value ov5640_setting_QCIF_176_144[] = { ++ {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, +@@ -473,32 +429,12 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = { + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, --}; -- ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + -static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = { - {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, @@ -259,6 +427,24 @@ index d5c0ffc..4432188 100644 - -static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { - {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++static const struct reg_value ov5640_setting_NTSC_720_480[] = { ++ {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x31, 0, 0}, + {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, +@@ -511,32 +447,12 @@ static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = { + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, +- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + +-static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { +- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, @@ -276,24 +462,26 @@ index d5c0ffc..4432188 100644 - {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[] = { +-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}, -@@ -530,32 +446,12 @@ static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = { +@@ -549,33 +465,12 @@ static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, --}; -- --static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = { -- {0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, ++ {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, ++ {0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0}, + }; + +-static const struct reg_value ov5640_setting_15fps_PAL_720_576[] = { +- {0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x31, 0, 0}, - {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, @@ -309,28 +497,8 @@ index d5c0ffc..4432188 100644 - {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}, @@ -339,7 +507,7 @@ index d5c0ffc..4432188 100644 {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[] = { +@@ -588,34 +483,13 @@ static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = { {0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0}, {0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0}, @@ -378,7 +546,7 @@ index d5c0ffc..4432188 100644 {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[] = { +@@ -628,10 +502,10 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, @@ -393,7 +561,7 @@ index d5c0ffc..4432188 100644 {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[] = { +@@ -640,46 +514,12 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = { {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, @@ -402,38 +570,10 @@ index d5c0ffc..4432188 100644 + {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[] = { +-static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = { +- {0x3008, 0x42, 0, 0}, - {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, - {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, - {0x3814, 0x11, 0, 0}, @@ -449,6 +589,34 @@ index d5c0ffc..4432188 100644 - {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, - {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, - {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, +- {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0}, +- {0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0}, +- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, +- {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0}, +- {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0}, +- {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, +- {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0}, +- {0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0}, +- {0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0}, +- {0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0}, +- {0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0}, +- {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0}, +- {0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0}, + }; + +-static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { +- {0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0}, ++static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = { ++ {0x3c07, 0x08, 0, 0}, + {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0}, + {0x3814, 0x11, 0, 0}, + {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0}, +@@ -692,9 +532,9 @@ static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = { + {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0}, + {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0}, + {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0}, +- {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0}, +- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0}, - {0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70}, + {0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, + {0x4407, 0x04, 0, 0}, @@ -456,7 +624,7 @@ index d5c0ffc..4432188 100644 }; /* power-on sensor init reg table */ -@@ -705,79 +544,43 @@ static const struct ov5640_mode_info ov5640_mode_init_data = { +@@ -705,79 +545,43 @@ static const struct ov5640_mode_info ov5640_mode_init_data = { }; static const struct ov5640_mode_info @@ -573,7 +741,7 @@ index d5c0ffc..4432188 100644 }; 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, +@@ -909,27 +713,389 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg, return ov5640_write_reg(sensor, reg, val); } @@ -939,6 +1107,7 @@ index d5c0ffc..4432188 100644 + (ilog2(pclk_div) << 4)); +} + ++#if 0 +/* set JPEG framing sizes */ +static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor, + const struct ov5640_mode_info *mode) @@ -964,12 +1133,13 @@ index d5c0ffc..4432188 100644 - return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot); + return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact); } ++#endif +/* download ov5640 settings to sensor through i2c */ static int ov5640_load_regs(struct ov5640_dev *sensor, const struct ov5640_mode_info *mode) { -@@ -957,7 +1120,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, +@@ -957,7 +1123,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor, usleep_range(1000 * delay_ms, 1000 * delay_ms + 100); } @@ -978,7 +1148,7 @@ index d5c0ffc..4432188 100644 } 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) +@@ -1062,16 +1228,6 @@ static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) if (on) { /* @@ -995,7 +1165,7 @@ index d5c0ffc..4432188 100644 * configure parallel port control lines polarity * * POLARITY CTRL0 -@@ -1438,14 +1591,44 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) +@@ -1438,14 +1594,44 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor) return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp); } @@ -1003,13 +1173,13 @@ index d5c0ffc..4432188 100644 + const struct ov5640_mode_info *mode) +{ + int ret; -+ ++#if 0 + if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) { + ret = ov5640_set_jpeg_timings(sensor, mode); + if (ret < 0) + return ret; + } -+ ++#endif + ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact); + if (ret < 0) + return ret; @@ -1042,7 +1212,7 @@ index d5c0ffc..4432188 100644 hact, vact, width, height); -@@ -1453,6 +1636,11 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, +@@ -1453,6 +1639,11 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr, (!nearest && (mode->hact != width || mode->vact != height))) return NULL; @@ -1054,7 +1224,7 @@ index d5c0ffc..4432188 100644 return mode; } -@@ -1637,8 +1825,12 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) +@@ -1637,8 +1828,12 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) enum ov5640_downsize_mode dn_mode, orig_dn_mode; bool auto_gain = sensor->ctrls.auto_gain->val == 1; bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO; @@ -1067,7 +1237,7 @@ index d5c0ffc..4432188 100644 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) +@@ -1655,6 +1850,23 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) goto restore_auto_gain; } @@ -1091,7 +1261,7 @@ index d5c0ffc..4432188 100644 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) +@@ -1678,6 +1890,10 @@ static int ov5640_set_mode(struct ov5640_dev *sensor) if (auto_exp) ov5640_set_autoexposure(sensor, true); @@ -1102,7 +1272,7 @@ index d5c0ffc..4432188 100644 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) +@@ -1724,8 +1940,8 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) sensor->last_mode = &ov5640_mode_init_data; ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f, @@ -1113,7 +1283,7 @@ index d5c0ffc..4432188 100644 if (ret) return ret; -@@ -1925,34 +2138,39 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, +@@ -1925,34 +2141,39 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor, u32 width, u32 height) { const struct ov5640_mode_info *mode; @@ -1170,7 +1340,18 @@ index d5c0ffc..4432188 100644 } static int ov5640_get_fmt(struct v4l2_subdev *sd, -@@ -2061,46 +2279,67 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, +@@ -2013,6 +2234,10 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, + return 0; + } + ++static const s64 link_freq_menu_items[] = { ++ 384000000, ++}; ++ + static int ov5640_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +@@ -2061,46 +2286,67 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, struct v4l2_mbus_framefmt *format) { int ret = 0; @@ -1250,7 +1431,7 @@ index d5c0ffc..4432188 100644 if (ret) return ret; -@@ -2268,10 +2507,41 @@ static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) +@@ -2268,10 +2514,41 @@ static int ov5640_set_ctrl_gain(struct ov5640_dev *sensor, bool auto_gain) return ret; } @@ -1294,7 +1475,16 @@ index d5c0ffc..4432188 100644 } 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 = { +@@ -2399,6 +2676,8 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) + case V4L2_CID_VFLIP: + ret = ov5640_set_ctrl_vflip(sensor, ctrl->val); + break; ++ case V4L2_CID_LINK_FREQ: ++ return 0; + default: + ret = -EINVAL; + break; +@@ -2412,11 +2691,6 @@ static const struct v4l2_ctrl_ops ov5640_ctrl_ops = { .s_ctrl = ov5640_s_ctrl, }; @@ -1306,7 +1496,17 @@ index d5c0ffc..4432188 100644 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, +@@ -2471,6 +2745,9 @@ static int ov5640_init_controls(struct ov5640_dev *sensor) + V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0, + V4L2_CID_POWER_LINE_FREQUENCY_50HZ); + ++ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops, V4L2_CID_LINK_FREQ, ++ 0, 0, link_freq_menu_items); ++ + if (hdl->error) { + ret = hdl->error; + goto free_ctrls; +@@ -2501,10 +2778,10 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd, return -EINVAL; fse->min_width = @@ -1319,7 +1519,7 @@ index d5c0ffc..4432188 100644 fse->max_height = fse->min_height; return 0; -@@ -2569,11 +2834,12 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, +@@ -2569,8 +2846,11 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd, frame_rate = ov5640_try_frame_interval(sensor, &fi->interval, mode->hact, mode->vact); @@ -1331,24 +1531,9 @@ index d5c0ffc..4432188 100644 + 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, +@@ -2735,7 +3015,7 @@ static int ov5640_probe(struct i2c_client *client, sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS]; sensor->current_fr = OV5640_30_FPS; sensor->current_mode = @@ -1357,6 +1542,1101 @@ index d5c0ffc..4432188 100644 sensor->last_mode = sensor->current_mode; sensor->ae_target = 52; +diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c +new file mode 100644 +index 0000000..7751960 +--- /dev/null ++++ b/drivers/media/i2c/st-mipid02.c +@@ -0,0 +1,1076 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Driver for ST MIPID02 CSI-2 to PARALLEL bridge ++ * ++ * Copyright (C) STMicroelectronics SA 2019 ++ * Authors: Mickael Guene ++ * for STMicroelectronics. ++ * ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define V4L2_MBUS_CSI2_DPHY V4L2_MBUS_CSI2 ++ ++#define MIPID02_CLK_LANE_WR_REG1 0x01 ++#define MIPID02_CLK_LANE_REG1 0x02 ++#define MIPID02_CLK_LANE_REG3 0x04 ++#define MIPID02_DATA_LANE0_REG1 0x05 ++#define MIPID02_DATA_LANE0_REG2 0x06 ++#define MIPID02_DATA_LANE1_REG1 0x09 ++#define MIPID02_DATA_LANE1_REG2 0x0a ++#define MIPID02_MODE_REG1 0x14 ++#define MIPID02_MODE_REG2 0x15 ++#define MIPID02_DATA_ID_RREG 0x17 ++#define MIPID02_DATA_SELECTION_CTRL 0x19 ++#define MIPID02_PIX_WIDTH_CTRL 0x1e ++#define MIPID02_PIX_WIDTH_CTRL_EMB 0x1f ++ ++/* Bits definition for MIPID02_CLK_LANE_REG1 */ ++#define CLK_ENABLE BIT(0) ++/* Bits definition for MIPID02_CLK_LANE_REG3 */ ++#define CLK_MIPI_CSI BIT(1) ++/* Bits definition for MIPID02_DATA_LANE0_REG1 */ ++#define DATA_ENABLE BIT(0) ++/* Bits definition for MIPID02_DATA_LANEx_REG2 */ ++#define DATA_MIPI_CSI BIT(0) ++/* Bits definition for MIPID02_MODE_REG1 */ ++#define MODE_DATA_SWAP BIT(2) ++#define MODE_NO_BYPASS BIT(6) ++/* Bits definition for MIPID02_MODE_REG2 */ ++#define MODE_HSYNC_ACTIVE_HIGH BIT(1) ++#define MODE_VSYNC_ACTIVE_HIGH BIT(2) ++/* Bits definition for MIPID02_DATA_SELECTION_CTRL */ ++#define SELECTION_MANUAL_DATA BIT(2) ++#define SELECTION_MANUAL_WIDTH BIT(3) ++ ++static const u32 mipid02_supported_fmt_codes[] = { ++ MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, ++ MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, ++ MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, ++ MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, ++ MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, ++ MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, ++ MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24, ++ MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, ++ MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, ++ MEDIA_BUS_FMT_JPEG_1X8 ++}; ++ ++/* regulator supplies */ ++static const char * const mipid02_supply_name[] = { ++ "VDDE", /* 1.8V digital I/O supply */ ++ "VDDIN", /* 1V8 voltage regulator supply */ ++}; ++ ++#define MIPID02_NUM_SUPPLIES ARRAY_SIZE(mipid02_supply_name) ++ ++#define MIPID02_SINK_0 0 ++#define MIPID02_SINK_1 1 ++#define MIPID02_SOURCE 2 ++#define MIPID02_PAD_NB 3 ++ ++struct mipid02_dev { ++ struct i2c_client *i2c_client; ++ struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES]; ++ struct v4l2_subdev sd; ++ struct media_pad pad[MIPID02_PAD_NB]; ++ struct clk *xclk; ++ struct gpio_desc *reset_gpio; ++ /* endpoints info */ ++ struct v4l2_fwnode_endpoint rx; ++ u64 link_frequency; ++ struct v4l2_fwnode_endpoint tx; ++ /* remote source */ ++ struct v4l2_async_subdev asd; ++ struct v4l2_async_notifier notifier; ++ struct v4l2_subdev *s_subdev; ++ /* registers */ ++ struct { ++ u8 clk_lane_reg1; ++ u8 data_lane0_reg1; ++ u8 data_lane1_reg1; ++ u8 mode_reg1; ++ u8 mode_reg2; ++ u8 data_selection_ctrl; ++ u8 data_id_rreg; ++ u8 pix_width_ctrl; ++ u8 pix_width_ctrl_emb; ++ } r; ++ /* lock to protect all members below */ ++ struct mutex lock; ++ bool streaming; ++ struct v4l2_mbus_framefmt fmt; ++}; ++ ++static int bpp_from_code(__u32 code) ++{ ++ switch (code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ return 8; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ return 10; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ return 12; ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ case MEDIA_BUS_FMT_RGB565_2X8_BE: ++ return 16; ++ case MEDIA_BUS_FMT_BGR888_1X24: ++ return 24; ++ default: ++ return 0; ++ } ++} ++ ++static u8 data_type_from_code(__u32 code) ++{ ++ switch (code) { ++ case MEDIA_BUS_FMT_SBGGR8_1X8: ++ case MEDIA_BUS_FMT_SGBRG8_1X8: ++ case MEDIA_BUS_FMT_SGRBG8_1X8: ++ case MEDIA_BUS_FMT_SRGGB8_1X8: ++ return 0x2a; ++ case MEDIA_BUS_FMT_SBGGR10_1X10: ++ case MEDIA_BUS_FMT_SGBRG10_1X10: ++ case MEDIA_BUS_FMT_SGRBG10_1X10: ++ case MEDIA_BUS_FMT_SRGGB10_1X10: ++ return 0x2b; ++ case MEDIA_BUS_FMT_SBGGR12_1X12: ++ case MEDIA_BUS_FMT_SGBRG12_1X12: ++ case MEDIA_BUS_FMT_SGRBG12_1X12: ++ case MEDIA_BUS_FMT_SRGGB12_1X12: ++ return 0x2c; ++ case MEDIA_BUS_FMT_UYVY8_1X16: ++ case MEDIA_BUS_FMT_YUYV8_2X8: ++ case MEDIA_BUS_FMT_UYVY8_2X8: ++ return 0x1e; ++ case MEDIA_BUS_FMT_BGR888_1X24: ++ return 0x24; ++ case MEDIA_BUS_FMT_RGB565_2X8_LE: ++ case MEDIA_BUS_FMT_RGB565_2X8_BE: ++ return 0x22; ++ default: ++ return 0; ++ } ++} ++ ++static void init_format(struct v4l2_mbus_framefmt *fmt) ++{ ++ fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; ++ fmt->field = V4L2_FIELD_NONE; ++ fmt->colorspace = V4L2_COLORSPACE_SRGB; ++ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); ++ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; ++ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); ++ fmt->width = 640; ++ fmt->height = 480; ++} ++ ++static __u32 get_fmt_code(__u32 code) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < ARRAY_SIZE(mipid02_supported_fmt_codes); i++) { ++ if (code == mipid02_supported_fmt_codes[i]) ++ return code; ++ } ++ ++ return mipid02_supported_fmt_codes[0]; ++} ++ ++static __u32 serial_to_parallel_code(__u32 serial) ++{ ++ if (serial == MEDIA_BUS_FMT_UYVY8_1X16) ++ return MEDIA_BUS_FMT_UYVY8_2X8; ++ if (serial == MEDIA_BUS_FMT_BGR888_1X24) ++ return MEDIA_BUS_FMT_BGR888_3X8; ++ ++ return serial; ++} ++ ++static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd) ++{ ++ return container_of(sd, struct mipid02_dev, sd); ++} ++ ++static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val) ++{ ++ struct i2c_client *client = bridge->i2c_client; ++ struct i2c_msg msg[2]; ++ u8 buf[2]; ++ int ret; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ ++ msg[0].addr = client->addr; ++ msg[0].flags = client->flags; ++ msg[0].buf = buf; ++ msg[0].len = sizeof(buf); ++ ++ msg[1].addr = client->addr; ++ msg[1].flags = client->flags | I2C_M_RD; ++ msg[1].buf = val; ++ msg[1].len = 1; ++ ++ ret = i2c_transfer(client->adapter, msg, 2); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", ++ __func__, client->addr, reg, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val) ++{ ++ struct i2c_client *client = bridge->i2c_client; ++ struct i2c_msg msg; ++ u8 buf[3]; ++ int ret; ++ ++ buf[0] = reg >> 8; ++ buf[1] = reg & 0xff; ++ buf[2] = val; ++ ++ msg.addr = client->addr; ++ msg.flags = client->flags; ++ msg.buf = buf; ++ msg.len = sizeof(buf); ++ ++ ret = i2c_transfer(client->adapter, &msg, 1); ++ if (ret < 0) { ++ dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", ++ __func__, reg, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int mipid02_get_regulators(struct mipid02_dev *bridge) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < MIPID02_NUM_SUPPLIES; i++) ++ bridge->supplies[i].supply = mipid02_supply_name[i]; ++ ++ return devm_regulator_bulk_get(&bridge->i2c_client->dev, ++ MIPID02_NUM_SUPPLIES, ++ bridge->supplies); ++} ++ ++static void mipid02_apply_reset(struct mipid02_dev *bridge) ++{ ++ gpiod_set_value_cansleep(bridge->reset_gpio, 0); ++ usleep_range(5000, 10000); ++ gpiod_set_value_cansleep(bridge->reset_gpio, 1); ++ usleep_range(5000, 10000); ++ gpiod_set_value_cansleep(bridge->reset_gpio, 0); ++ usleep_range(5000, 10000); ++} ++ ++static int mipid02_set_power_on(struct mipid02_dev *bridge) ++{ ++ struct i2c_client *client = bridge->i2c_client; ++ int ret; ++ ++ ret = clk_prepare_enable(bridge->xclk); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable clock\n", __func__); ++ return ret; ++ } ++ ++ ret = regulator_bulk_enable(MIPID02_NUM_SUPPLIES, ++ bridge->supplies); ++ if (ret) { ++ dev_err(&client->dev, "%s: failed to enable regulators\n", ++ __func__); ++ goto xclk_off; ++ } ++ ++ if (bridge->reset_gpio) { ++ dev_dbg(&client->dev, "apply reset"); ++ mipid02_apply_reset(bridge); ++ } else { ++ dev_dbg(&client->dev, "don't apply reset"); ++ usleep_range(5000, 10000); ++ } ++ ++ return 0; ++ ++xclk_off: ++ clk_disable_unprepare(bridge->xclk); ++ return ret; ++} ++ ++static void mipid02_set_power_off(struct mipid02_dev *bridge) ++{ ++ regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies); ++ clk_disable_unprepare(bridge->xclk); ++} ++ ++static int mipid02_detect(struct mipid02_dev *bridge) ++{ ++ u8 reg; ++ ++ /* ++ * There is no version registers. Just try to read register ++ * MIPID02_CLK_LANE_WR_REG1. ++ */ ++ return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); ++} ++ ++static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge, ++ struct v4l2_subdev *subdev) ++{ ++ struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, }; ++ struct v4l2_ctrl *ctrl; ++ int ret; ++ ++ ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ); ++ if (!ctrl) ++ return 0; ++ qm.index = v4l2_ctrl_g_ctrl(ctrl); ++ ++ ret = v4l2_querymenu(subdev->ctrl_handler, &qm); ++ if (ret) ++ return 0; ++ ++ return qm.value; ++} ++ ++static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, ++ struct v4l2_subdev *subdev) ++{ ++ struct v4l2_fwnode_endpoint *ep = &bridge->rx; ++ struct v4l2_ctrl *ctrl; ++ u32 pixel_clock; ++ u32 bpp = bpp_from_code(bridge->fmt.code); ++ ++ ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); ++ if (!ctrl) ++ return 0; ++ pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); ++ ++ return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes); ++} ++ ++/* ++ * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency ++ * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel ++ * and number of lanes. ++ */ ++static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) ++{ ++ struct i2c_client *client = bridge->i2c_client; ++ struct v4l2_subdev *subdev = bridge->s_subdev; ++ u32 link_freq; ++ ++ link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev); ++ if (!link_freq) { ++ link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, ++ subdev); ++ if (!link_freq) { ++ dev_err(&client->dev, "Failed to get link frequency"); ++ return -EINVAL; ++ } ++ } ++ ++ dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); ++ bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2; ++ ++ return 0; ++} ++ ++static int mipid02_configure_clk_lane(struct mipid02_dev *bridge) ++{ ++ struct i2c_client *client = bridge->i2c_client; ++ struct v4l2_fwnode_endpoint *ep = &bridge->rx; ++ bool *polarities = ep->bus.mipi_csi2.lane_polarities; ++ ++ /* midid02 doesn't support clock lane remapping */ ++ if (ep->bus.mipi_csi2.clock_lane != 0) { ++ dev_err(&client->dev, "clk lane must be map to lane 0\n"); ++ return -EINVAL; ++ } ++ bridge->r.clk_lane_reg1 |= (polarities[0] << 1) | CLK_ENABLE; ++ ++ return 0; ++} ++ ++static int mipid02_configure_data0_lane(struct mipid02_dev *bridge, int nb, ++ bool are_lanes_swap, bool *polarities) ++{ ++ bool are_pin_swap = are_lanes_swap ? polarities[2] : polarities[1]; ++ ++ if (nb == 1 && are_lanes_swap) ++ return 0; ++ ++ /* ++ * data lane 0 as pin swap polarity reversed compared to clock and ++ * data lane 1 ++ */ ++ if (!are_pin_swap) ++ bridge->r.data_lane0_reg1 = 1 << 1; ++ bridge->r.data_lane0_reg1 |= DATA_ENABLE; ++ ++ return 0; ++} ++ ++static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb, ++ bool are_lanes_swap, bool *polarities) ++{ ++ bool are_pin_swap = are_lanes_swap ? polarities[1] : polarities[2]; ++ ++ if (nb == 1 && !are_lanes_swap) ++ return 0; ++ ++ if (are_pin_swap) ++ bridge->r.data_lane1_reg1 = 1 << 1; ++ bridge->r.data_lane1_reg1 |= DATA_ENABLE; ++ ++ return 0; ++} ++ ++static int mipid02_configure_from_rx(struct mipid02_dev *bridge) ++{ ++ struct v4l2_fwnode_endpoint *ep = &bridge->rx; ++ bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2; ++ bool *polarities = ep->bus.mipi_csi2.lane_polarities; ++ int nb = ep->bus.mipi_csi2.num_data_lanes; ++ int ret; ++ ++ ret = mipid02_configure_clk_lane(bridge); ++ if (ret) ++ return ret; ++ ++ ret = mipid02_configure_data0_lane(bridge, nb, are_lanes_swap, ++ polarities); ++ if (ret) ++ return ret; ++ ++ ret = mipid02_configure_data1_lane(bridge, nb, are_lanes_swap, ++ polarities); ++ if (ret) ++ return ret; ++ ++ bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0; ++ bridge->r.mode_reg1 |= (nb - 1) << 1; ++ ++ return mipid02_configure_from_rx_speed(bridge); ++} ++ ++static int mipid02_configure_from_tx(struct mipid02_dev *bridge) ++{ ++ struct v4l2_fwnode_endpoint *ep = &bridge->tx; ++ ++ bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH; ++ bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; ++ bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; ++ if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) ++ bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH; ++ if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) ++ bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH; ++ ++ return 0; ++} ++ ++static int mipid02_configure_from_code(struct mipid02_dev *bridge) ++{ ++ u8 data_type; ++ ++ bridge->r.data_id_rreg = 0; ++ ++ if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) { ++ bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA; ++ ++ data_type = data_type_from_code(bridge->fmt.code); ++ if (!data_type) ++ return -EINVAL; ++ bridge->r.data_id_rreg = data_type; ++ } ++ ++ return 0; ++} ++ ++static int mipid02_stream_disable(struct mipid02_dev *bridge) ++{ ++ struct i2c_client *client = bridge->i2c_client; ++ int ret; ++ ++ /* Disable all lanes */ ++ ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0); ++ if (ret) ++ goto error; ++error: ++ if (ret) ++ dev_err(&client->dev, "failed to stream off %d", ret); ++ ++ return ret; ++} ++ ++static int mipid02_stream_enable(struct mipid02_dev *bridge) ++{ ++ struct i2c_client *client = bridge->i2c_client; ++ int ret = -EINVAL; ++ ++ if (!bridge->s_subdev) ++ goto error; ++ ++ memset(&bridge->r, 0, sizeof(bridge->r)); ++ /* build registers content */ ++ ret = mipid02_configure_from_rx(bridge); ++ if (ret) ++ goto error; ++ ret = mipid02_configure_from_tx(bridge); ++ if (ret) ++ goto error; ++ ret = mipid02_configure_from_code(bridge); ++ if (ret) ++ goto error; ++ ++ /* write mipi registers */ ++ ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, ++ bridge->r.clk_lane_reg1); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, ++ bridge->r.data_lane0_reg1); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2, ++ DATA_MIPI_CSI); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, ++ bridge->r.data_lane1_reg1); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2, ++ DATA_MIPI_CSI); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1, ++ MODE_NO_BYPASS | bridge->r.mode_reg1); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2, ++ bridge->r.mode_reg2); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG, ++ bridge->r.data_id_rreg); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, ++ bridge->r.data_selection_ctrl); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, ++ bridge->r.pix_width_ctrl); ++ if (ret) ++ goto error; ++ ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB, ++ bridge->r.pix_width_ctrl_emb); ++ if (ret) ++ goto error; ++ ++ return 0; ++ ++error: ++ dev_err(&client->dev, "failed to stream on %d", ret); ++ mipid02_stream_disable(bridge); ++ ++ return ret; ++} ++ ++static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ struct mipid02_dev *bridge = to_mipid02_dev(sd); ++ struct i2c_client *client = bridge->i2c_client; ++ int ret = 0; ++ ++ dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__, ++ enable, bridge->streaming); ++ mutex_lock(&bridge->lock); ++ ++ if (bridge->streaming == enable) ++ goto out; ++ ++ ret = enable ? mipid02_stream_enable(bridge) : ++ mipid02_stream_disable(bridge); ++ if (!ret) ++ bridge->streaming = enable; ++ ++out: ++ dev_dbg(&client->dev, "%s current now = %d / %d", __func__, ++ bridge->streaming, ret); ++ mutex_unlock(&bridge->lock); ++ ++ return ret; ++} ++ ++static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) ++{ ++ struct mipid02_dev *bridge = to_mipid02_dev(sd); ++ int ret = 0; ++ ++ switch (code->pad) { ++ case MIPID02_SINK_0: ++ if (code->index >= ARRAY_SIZE(mipid02_supported_fmt_codes)) ++ ret = -EINVAL; ++ else ++ code->code = mipid02_supported_fmt_codes[code->index]; ++ break; ++ case MIPID02_SOURCE: ++ if (code->index == 0) ++ code->code = serial_to_parallel_code(bridge->fmt.code); ++ else ++ ret = -EINVAL; ++ break; ++ default: ++ ret = -EINVAL; ++ } ++ ++ return ret; ++} ++ ++static int mipid02_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mbus_fmt = &format->format; ++ struct mipid02_dev *bridge = to_mipid02_dev(sd); ++ struct i2c_client *client = bridge->i2c_client; ++ struct v4l2_mbus_framefmt *fmt; ++ ++ dev_dbg(&client->dev, "%s probe %d", __func__, format->pad); ++ ++ if (format->pad >= MIPID02_PAD_NB) ++ return -EINVAL; ++ /* second CSI-2 pad not yet supported */ ++ if (format->pad == MIPID02_SINK_1) ++ return -EINVAL; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ fmt = v4l2_subdev_get_try_format(&bridge->sd, cfg, format->pad); ++ else ++ fmt = &bridge->fmt; ++ ++ mutex_lock(&bridge->lock); ++ ++ *mbus_fmt = *fmt; ++ /* code may need to be converted for source */ ++ if (format->pad == MIPID02_SOURCE) ++ mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code); ++ ++ mutex_unlock(&bridge->lock); ++ ++ return 0; ++} ++ ++static void mipid02_set_fmt_source(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct mipid02_dev *bridge = to_mipid02_dev(sd); ++ ++ /* source pad mirror active sink pad */ ++ format->format = bridge->fmt; ++ /* but code may need to be converted */ ++ format->format.code = serial_to_parallel_code(format->format.code); ++ ++ /* only apply format for V4L2_SUBDEV_FORMAT_TRY case */ ++ if (format->which != V4L2_SUBDEV_FORMAT_TRY) ++ return; ++ ++ *v4l2_subdev_get_try_format(sd, cfg, format->pad) = format->format; ++} ++ ++static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct mipid02_dev *bridge = to_mipid02_dev(sd); ++ struct v4l2_mbus_framefmt *fmt; ++ ++ format->format.code = get_fmt_code(format->format.code); ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); ++ else ++ fmt = &bridge->fmt; ++ ++ *fmt = format->format; ++} ++ ++static int mipid02_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct mipid02_dev *bridge = to_mipid02_dev(sd); ++ struct i2c_client *client = bridge->i2c_client; ++ int ret = 0; ++ ++ dev_dbg(&client->dev, "%s for %d", __func__, format->pad); ++ ++ if (format->pad >= MIPID02_PAD_NB) ++ return -EINVAL; ++ /* second CSI-2 pad not yet supported */ ++ if (format->pad == MIPID02_SINK_1) ++ return -EINVAL; ++ ++ mutex_lock(&bridge->lock); ++ ++ if (bridge->streaming) { ++ ret = -EBUSY; ++ goto error; ++ } ++ ++ if (format->pad == MIPID02_SOURCE) ++ mipid02_set_fmt_source(sd, cfg, format); ++ else ++ mipid02_set_fmt_sink(sd, cfg, format); ++ ++error: ++ mutex_unlock(&bridge->lock); ++ ++ return ret; ++} ++ ++static const struct v4l2_subdev_video_ops mipid02_video_ops = { ++ .s_stream = mipid02_s_stream, ++}; ++ ++static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { ++ .enum_mbus_code = mipid02_enum_mbus_code, ++ .get_fmt = mipid02_get_fmt, ++ .set_fmt = mipid02_set_fmt, ++}; ++ ++static const struct v4l2_subdev_ops mipid02_subdev_ops = { ++ .video = &mipid02_video_ops, ++ .pad = &mipid02_pad_ops, ++}; ++ ++static const struct media_entity_operations mipid02_subdev_entity_ops = { ++ .link_validate = v4l2_subdev_link_validate, ++}; ++ ++static int mipid02_async_bound(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *s_subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); ++ struct i2c_client *client = bridge->i2c_client; ++ int source_pad; ++ int ret; ++ ++ dev_dbg(&client->dev, "sensor_async_bound call %p", s_subdev); ++ ++ source_pad = media_entity_get_fwnode_pad(&s_subdev->entity, ++ s_subdev->fwnode, ++ MEDIA_PAD_FL_SOURCE); ++ if (source_pad < 0) { ++ dev_err(&client->dev, "Couldn't find output pad for subdev %s\n", ++ s_subdev->name); ++ return source_pad; ++ } ++ ++ ret = media_create_pad_link(&s_subdev->entity, source_pad, ++ &bridge->sd.entity, 0, ++ MEDIA_LNK_FL_ENABLED | ++ MEDIA_LNK_FL_IMMUTABLE); ++ if (ret) { ++ dev_err(&client->dev, "Couldn't create media link %d", ret); ++ return ret; ++ } ++ ++ bridge->s_subdev = s_subdev; ++ ++ return 0; ++} ++ ++static void mipid02_async_unbind(struct v4l2_async_notifier *notifier, ++ struct v4l2_subdev *s_subdev, ++ struct v4l2_async_subdev *asd) ++{ ++ struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); ++ ++ bridge->s_subdev = NULL; ++} ++ ++static const struct v4l2_async_notifier_operations mipid02_notifier_ops = { ++ .bound = mipid02_async_bound, ++ .unbind = mipid02_async_unbind, ++}; ++ ++static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) ++{ ++ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; ++ struct i2c_client *client = bridge->i2c_client; ++ struct device_node *ep_node; ++ int ret; ++ ++ /* parse rx (endpoint 0) */ ++ ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, ++ 0, 0); ++ if (!ep_node) { ++ dev_err(&client->dev, "unable to find port0 ep"); ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); ++ if (ret) { ++ dev_err(&client->dev, "Could not parse v4l2 endpoint %d\n", ++ ret); ++ goto error_of_node_put; ++ } ++ ++ /* do some sanity checks */ ++ if (ep.bus.mipi_csi2.num_data_lanes > 2) { ++ dev_err(&client->dev, "max supported data lanes is 2 / got %d", ++ ep.bus.mipi_csi2.num_data_lanes); ++ ret = -EINVAL; ++ goto error_of_node_put; ++ } ++ ++ /* register it for later use */ ++ bridge->rx = ep; ++ ++ /* register async notifier so we get noticed when sensor is connected */ ++ bridge->asd.match.fwnode = ++ fwnode_graph_get_remote_port_parent(of_fwnode_handle(ep_node)); ++ bridge->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; ++ of_node_put(ep_node); ++ bridge->notifier.subdevs = ++ devm_kzalloc(&bridge->i2c_client->dev, ++ sizeof(*bridge->notifier.subdevs), ++ GFP_KERNEL); ++ if (!bridge->notifier.subdevs) ++ return -ENOMEM; ++ bridge->notifier.subdevs[0] = &bridge->asd; ++ bridge->notifier.num_subdevs = 1; ++ bridge->notifier.ops = &mipid02_notifier_ops; ++ ++ ret = v4l2_async_subdev_notifier_register(&bridge->sd, ++ &bridge->notifier); ++ if (ret) ++ v4l2_async_notifier_cleanup(&bridge->notifier); ++ ++ return ret; ++ ++error_of_node_put: ++ of_node_put(ep_node); ++error: ++ ++ return ret; ++} ++ ++static int mipid02_parse_tx_ep(struct mipid02_dev *bridge) ++{ ++ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_PARALLEL }; ++ struct i2c_client *client = bridge->i2c_client; ++ struct device_node *ep_node; ++ int ret; ++ ++ /* parse tx (endpoint 2) */ ++ ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, ++ 2, 0); ++ if (!ep_node) { ++ dev_err(&client->dev, "unable to find port1 ep"); ++ ret = -EINVAL; ++ goto error; ++ } ++ ++ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); ++ if (ret) { ++ dev_err(&client->dev, "Could not parse v4l2 endpoint\n"); ++ goto error_of_node_put; ++ } ++ ++ of_node_put(ep_node); ++ bridge->tx = ep; ++ ++ return 0; ++ ++error_of_node_put: ++ of_node_put(ep_node); ++error: ++ ++ return -EINVAL; ++} ++ ++static int mipid02_probe(struct i2c_client *client) ++{ ++ struct device *dev = &client->dev; ++ struct mipid02_dev *bridge; ++ u32 clk_freq; ++ int ret; ++ ++ bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); ++ if (!bridge) ++ return -ENOMEM; ++ ++ init_format(&bridge->fmt); ++ ++ bridge->i2c_client = client; ++ v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops); ++ ++ /* got and check clock */ ++ bridge->xclk = devm_clk_get(dev, "xclk"); ++ if (IS_ERR(bridge->xclk)) { ++ dev_err(dev, "failed to get xclk\n"); ++ return PTR_ERR(bridge->xclk); ++ } ++ ++ clk_freq = clk_get_rate(bridge->xclk); ++ if (clk_freq < 6000000 || clk_freq > 27000000) { ++ dev_err(dev, "xclk freq must be in 6-27 Mhz range. got %d Hz\n", ++ clk_freq); ++ return -EINVAL; ++ } ++ ++ bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset", ++ GPIOD_OUT_HIGH); ++ ++ ret = mipid02_get_regulators(bridge); ++ if (ret) { ++ dev_err(dev, "failed to get regulators %d", ret); ++ return ret; ++ } ++ ++ mutex_init(&bridge->lock); ++ bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ++ bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; ++ bridge->sd.entity.ops = &mipid02_subdev_entity_ops; ++ bridge->pad[0].flags = MEDIA_PAD_FL_SINK; ++ bridge->pad[1].flags = MEDIA_PAD_FL_SINK; ++ bridge->pad[2].flags = MEDIA_PAD_FL_SOURCE; ++ ret = media_entity_pads_init(&bridge->sd.entity, MIPID02_PAD_NB, ++ bridge->pad); ++ if (ret) { ++ dev_err(&client->dev, "pads init failed %d", ret); ++ goto mutex_cleanup; ++ } ++ ++ /* enable clock, power and reset device if available */ ++ ret = mipid02_set_power_on(bridge); ++ if (ret) ++ goto entity_cleanup; ++ ++ ret = mipid02_detect(bridge); ++ if (ret) { ++ dev_err(&client->dev, "failed to detect mipid02 %d", ret); ++ goto power_off; ++ } ++ ++ ret = mipid02_parse_tx_ep(bridge); ++ if (ret) { ++ dev_err(&client->dev, "failed to parse tx %d", ret); ++ goto power_off; ++ } ++ ++ ret = mipid02_parse_rx_ep(bridge); ++ if (ret) { ++ dev_err(&client->dev, "failed to parse rx %d", ret); ++ goto power_off; ++ } ++ ++ ret = v4l2_async_register_subdev(&bridge->sd); ++ if (ret < 0) { ++ dev_err(&client->dev, "v4l2_async_register_subdev failed %d", ++ ret); ++ goto unregister_notifier; ++ } ++ ++ dev_info(&client->dev, "mipid02 device probe successfully"); ++ ++ return 0; ++ ++unregister_notifier: ++ v4l2_async_notifier_unregister(&bridge->notifier); ++ v4l2_async_notifier_cleanup(&bridge->notifier); ++power_off: ++ mipid02_set_power_off(bridge); ++entity_cleanup: ++ media_entity_cleanup(&bridge->sd.entity); ++mutex_cleanup: ++ mutex_destroy(&bridge->lock); ++ ++ return ret; ++} ++ ++static int mipid02_remove(struct i2c_client *client) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(client); ++ struct mipid02_dev *bridge = to_mipid02_dev(sd); ++ ++ v4l2_async_notifier_unregister(&bridge->notifier); ++ v4l2_async_notifier_cleanup(&bridge->notifier); ++ v4l2_async_unregister_subdev(&bridge->sd); ++ mipid02_set_power_off(bridge); ++ media_entity_cleanup(&bridge->sd.entity); ++ mutex_destroy(&bridge->lock); ++ ++ return 0; ++} ++ ++static const struct of_device_id mipid02_dt_ids[] = { ++ { .compatible = "st,st-mipid02" }, ++ { /* sentinel */ } ++}; ++MODULE_DEVICE_TABLE(of, mipid02_dt_ids); ++ ++static struct i2c_driver mipid02_i2c_driver = { ++ .driver = { ++ .name = "st-mipid02", ++ .of_match_table = mipid02_dt_ids, ++ }, ++ .probe_new = mipid02_probe, ++ .remove = mipid02_remove, ++}; ++ ++module_i2c_driver(mipid02_i2c_driver); ++ ++MODULE_AUTHOR("Mickael Guene "); ++MODULE_DESCRIPTION("STMicroelectronics MIPID02 CSI-2 bridge driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig +index 54fe90a..6f0721e 100644 +--- a/drivers/media/platform/Kconfig ++++ b/drivers/media/platform/Kconfig +@@ -111,7 +111,7 @@ config VIDEO_S3C_CAMIF + + config VIDEO_STM32_DCMI + tristate "STM32 Digital Camera Memory Interface (DCMI) support" +- depends on VIDEO_V4L2 && OF ++ depends on VIDEO_V4L2 && OF && MEDIA_CONTROLLER + depends on ARCH_STM32 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c index 7c496bc..1e657fe 100644 --- a/drivers/media/platform/stm32/stm32-cec.c @@ -1523,10 +2803,10 @@ index 7c496bc..1e657fe 100644 }; diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c -index d386822..1737892 100644 +index 18d0b56..0a59f44 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c -@@ -95,8 +95,13 @@ enum state { +@@ -95,13 +95,18 @@ enum state { #define MIN_HEIGHT 16U #define MAX_HEIGHT 2592U @@ -1535,57 +2815,31 @@ index d386822..1737892 100644 + #define TIMEOUT_MS 1000 +-struct dcmi_graph_entity { +- struct device_node *node; +#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; ++struct dcmi_graph_entity { + struct v4l2_async_subdev asd; +- struct v4l2_subdev *subdev; + -+ /* Ensure DMA operations atomicity */ -+ struct mutex dma_lock; ++ struct device_node *remote_node; ++ struct v4l2_subdev *source; + }; + + struct dcmi_format { +@@ -167,6 +172,10 @@ struct stm32_dcmi { + + /* Ensure DMA operations atomicity */ + struct mutex dma_lock; ++ ++ struct media_device mdev; ++ struct media_pad vid_cap_pad; ++ struct media_pipeline pipeline; }; static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) -@@ -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) +@@ -446,11 +455,13 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) spin_lock_irq(&dcmi->irqlock); @@ -1603,20 +2857,175 @@ index d386822..1737892 100644 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; +@@ -576,6 +587,144 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) + spin_unlock_irq(&dcmi->irqlock); + } - 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); ++static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi) ++{ ++ struct media_entity *entity = &dcmi->vdev->entity; ++ struct media_pad *pad; ++ ++ /* Walk searching for entity having no sink */ ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ ++ entity = pad->entity; ++ } ++ ++ return entity; ++} ++ ++static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi, ++ struct v4l2_subdev_pad_config *pad_cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct media_entity *entity = &dcmi->entity.source->entity; ++ struct v4l2_subdev *subdev; ++ struct media_pad *sink_pad = NULL; ++ struct media_pad *src_pad = NULL; ++ struct media_pad *pad = NULL; ++ struct v4l2_subdev_format fmt = *format; ++ bool found = false; ++ int ret; ++ ++ /* ++ * Starting from sensor subdevice, walk within ++ * pipeline and set format on each subdevice ++ */ ++ while (1) { ++ unsigned int i; ++ ++ /* Search if current entity has a source pad */ ++ for (i = 0; i < entity->num_pads; i++) { ++ pad = &entity->pads[i]; ++ if (pad->flags & MEDIA_PAD_FL_SOURCE) { ++ src_pad = pad; ++ found = true; ++ break; ++ } ++ } ++ if (!found) ++ break; ++ ++ subdev = media_entity_to_v4l2_subdev(entity); ++ ++ /* Propagate format on sink pad if any, otherwise source pad */ ++ if (sink_pad) ++ pad = sink_pad; ++ ++ dev_dbg(dcmi->dev, "\"%s\":%d pad format set to 0x%x %ux%u\n", ++ subdev->name, pad->index, format->format.code, ++ format->format.width, format->format.height); ++ ++ fmt.pad = pad->index; ++ ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt); ++ if (ret < 0) { ++ dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n", ++ __func__, format->format.code, ++ format->format.width, format->format.height, ++ subdev->name, pad->index, ret); ++ return ret; ++ } ++ ++ if (fmt.format.code != format->format.code || ++ fmt.format.width != format->format.width || ++ fmt.format.height != format->format.height) { ++ dev_dbg(dcmi->dev, "\"%s\":%d pad format has been changed to 0x%x %ux%u\n", ++ subdev->name, pad->index, fmt.format.code, ++ fmt.format.width, fmt.format.height); ++ } ++ ++ /* Walk to next entity */ ++ sink_pad = media_entity_remote_pad(src_pad); ++ if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity)) ++ break; ++ ++ entity = sink_pad->entity; ++ } ++ *format = fmt; ++ ++ return 0; ++} ++ ++static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state) ++{ ++ struct media_entity *entity = &dcmi->vdev->entity; ++ struct v4l2_subdev *subdev; ++ struct media_pad *pad; ++ int ret; ++ ++ /* Start/stop all entities within pipeline */ ++ while (1) { ++ pad = &entity->pads[0]; ++ if (!(pad->flags & MEDIA_PAD_FL_SINK)) ++ break; ++ ++ pad = media_entity_remote_pad(pad); ++ if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) ++ break; ++ ++ entity = pad->entity; ++ subdev = media_entity_to_v4l2_subdev(entity); ++ ++ ret = v4l2_subdev_call(subdev, video, s_stream, state); ++ if (ret < 0 && ret != -ENOIOCTLCMD) { ++ dev_err(dcmi->dev, "%s: \"%s\" failed to %s streaming (%d)\n", ++ __func__, subdev->name, ++ state ? "start" : "stop", ret); ++ return ret; ++ } ++ ++ dev_dbg(dcmi->dev, "\"%s\" is %s\n", ++ subdev->name, state ? "started" : "stopped"); ++ } ++ ++ return 0; ++} ++ ++static int dcmi_pipeline_start(struct stm32_dcmi *dcmi) ++{ ++ return dcmi_pipeline_s_stream(dcmi, 1); ++} ++ ++static void dcmi_pipeline_stop(struct stm32_dcmi *dcmi) ++{ ++ dcmi_pipeline_s_stream(dcmi, 0); ++} ++ + static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) + { + struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); +@@ -590,14 +739,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) goto err_release_buffers; } -@@ -621,8 +642,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) +- /* Enable stream on the sub device */ +- ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 1); +- if (ret && ret != -ENOIOCTLCMD) { +- dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error", +- __func__); ++ ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); ++ if (ret < 0) { ++ dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n", ++ __func__, ret); + goto err_pm_put; + } + ++ ret = dcmi_pipeline_start(dcmi); ++ if (ret) ++ goto err_media_pipeline_stop; ++ + spin_lock_irq(&dcmi->irqlock); + + /* Set bus width */ +@@ -635,8 +787,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dcmi_set_crop(dcmi); /* Enable jpeg capture */ @@ -1629,7 +3038,7 @@ index d386822..1737892 100644 + }; + struct v4l2_fract frame_interval = {1, 30}; + -+ ret = v4l2_g_parm_cap(dcmi->vdev, dcmi->entity.subdev, &p); ++ ret = v4l2_g_parm_cap(dcmi->vdev, dcmi->entity.source, &p); + if (!ret) + frame_interval = p.parm.capture.timeperframe; + @@ -1650,7 +3059,12 @@ index d386822..1737892 100644 /* 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) +@@ -669,16 +844,22 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) + if (ret) { + dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", + __func__); +- goto err_subdev_streamoff; ++ goto err_pipeline_stop; } /* Enable interruptions */ @@ -1662,23 +3076,373 @@ index d386822..1737892 100644 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); +-err_subdev_streamoff: +- v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); ++err_pipeline_stop: ++ dcmi_pipeline_stop(dcmi); ++ ++err_media_pipeline_stop: ++ media_pipeline_stop(&dcmi->vdev->entity); + err_pm_put: pm_runtime_put(dcmi->dev); +@@ -703,13 +884,10 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) + { + struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq); + struct dcmi_buf *buf, *node; +- int ret; -@@ -1719,6 +1768,7 @@ static int dcmi_probe(struct platform_device *pdev) +- /* Disable stream on the sub device */ +- ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); +- if (ret && ret != -ENOIOCTLCMD) +- dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", +- __func__, ret); ++ dcmi_pipeline_stop(dcmi); ++ ++ media_pipeline_stop(&dcmi->vdev->entity); - spin_lock_init(&dcmi->irqlock); - mutex_init(&dcmi->lock); -+ mutex_init(&dcmi->dma_lock); - init_completion(&dcmi->complete); - INIT_LIST_HEAD(&dcmi->buffers); + spin_lock_irq(&dcmi->irqlock); + +@@ -850,7 +1028,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, + } + + v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); +- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, ++ ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, + &pad_cfg, &format); + if (ret < 0) + return ret; +@@ -927,8 +1105,7 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) + mf->width = sd_framesize.width; + mf->height = sd_framesize.height; + +- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, +- set_fmt, NULL, &format); ++ ret = dcmi_pipeline_s_fmt(dcmi, NULL, &format); + if (ret < 0) + return ret; + +@@ -984,7 +1161,7 @@ static int dcmi_get_sensor_format(struct stm32_dcmi *dcmi, + }; + int ret; + +- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_fmt, NULL, &fmt); ++ ret = v4l2_subdev_call(dcmi->entity.source, pad, get_fmt, NULL, &fmt); + if (ret) + return ret; + +@@ -1013,7 +1190,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, + } + + v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code); +- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt, ++ ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt, + &pad_cfg, &format); + if (ret < 0) + return ret; +@@ -1036,7 +1213,7 @@ static int dcmi_get_sensor_bounds(struct stm32_dcmi *dcmi, + /* + * Get sensor bounds first + */ +- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_selection, ++ ret = v4l2_subdev_call(dcmi->entity.source, pad, get_selection, + NULL, &bounds); + if (!ret) + *r = bounds.r; +@@ -1217,7 +1394,7 @@ static int dcmi_enum_framesizes(struct file *file, void *fh, + + fse.code = sd_fmt->mbus_code; + +- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_size, ++ ret = v4l2_subdev_call(dcmi->entity.source, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; +@@ -1234,7 +1411,7 @@ static int dcmi_g_parm(struct file *file, void *priv, + { + struct stm32_dcmi *dcmi = video_drvdata(file); + +- return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p); ++ return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.source, p); + } + + static int dcmi_s_parm(struct file *file, void *priv, +@@ -1242,7 +1419,7 @@ static int dcmi_s_parm(struct file *file, void *priv, + { + struct stm32_dcmi *dcmi = video_drvdata(file); + +- return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p); ++ return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.source, p); + } + + static int dcmi_enum_frameintervals(struct file *file, void *fh, +@@ -1264,7 +1441,7 @@ static int dcmi_enum_frameintervals(struct file *file, void *fh, + + fie.code = sd_fmt->mbus_code; + +- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, ++ ret = v4l2_subdev_call(dcmi->entity.source, pad, + enum_frame_interval, NULL, &fie); + if (ret) + return ret; +@@ -1284,7 +1461,7 @@ MODULE_DEVICE_TABLE(of, stm32_dcmi_of_match); + static int dcmi_open(struct file *file) + { + struct stm32_dcmi *dcmi = video_drvdata(file); +- struct v4l2_subdev *sd = dcmi->entity.subdev; ++ struct v4l2_subdev *sd = dcmi->entity.source; + int ret; + + if (mutex_lock_interruptible(&dcmi->lock)) +@@ -1315,7 +1492,7 @@ static int dcmi_open(struct file *file) + static int dcmi_release(struct file *file) + { + struct stm32_dcmi *dcmi = video_drvdata(file); +- struct v4l2_subdev *sd = dcmi->entity.subdev; ++ struct v4l2_subdev *sd = dcmi->entity.source; + bool fh_singular; + int ret; + +@@ -1402,6 +1579,12 @@ static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi) + return 0; + } + ++/* ++ * FIXME: For the time being we only support subdevices ++ * which expose RGB & YUV "parallel form" mbus code (_2X8). ++ * Nevertheless, this allows to support serial source subdevices ++ * and serial to parallel bridges which conform to this. ++ */ + static const struct dcmi_format dcmi_formats[] = { + { + .fourcc = V4L2_PIX_FMT_RGB565, +@@ -1426,7 +1609,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) + { + const struct dcmi_format *sd_fmts[ARRAY_SIZE(dcmi_formats)]; + unsigned int num_fmts = 0, i, j; +- struct v4l2_subdev *subdev = dcmi->entity.subdev; ++ struct v4l2_subdev *subdev = dcmi->entity.source; + struct v4l2_subdev_mbus_code_enum mbus_code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; +@@ -1440,12 +1623,20 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) + /* Code supported, have we got this fourcc yet? */ + for (j = 0; j < num_fmts; j++) + if (sd_fmts[j]->fourcc == +- dcmi_formats[i].fourcc) ++ dcmi_formats[i].fourcc) { + /* Already available */ ++ dev_dbg(dcmi->dev, "Skipping fourcc/code: %4.4s/0x%x\n", ++ (char *)&sd_fmts[j]->fourcc, ++ mbus_code.code); + break; +- if (j == num_fmts) ++ } ++ if (j == num_fmts) { + /* New */ + sd_fmts[num_fmts++] = dcmi_formats + i; ++ dev_dbg(dcmi->dev, "Supported fourcc/code: %4.4s/0x%x\n", ++ (char *)&sd_fmts[num_fmts - 1]->fourcc, ++ sd_fmts[num_fmts - 1]->mbus_code); ++ } + } + mbus_code.index++; + } +@@ -1472,7 +1663,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) + static int dcmi_framesizes_init(struct stm32_dcmi *dcmi) + { + unsigned int num_fsize = 0; +- struct v4l2_subdev *subdev = dcmi->entity.subdev; ++ struct v4l2_subdev *subdev = dcmi->entity.source; + struct v4l2_subdev_frame_size_enum fse = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .code = dcmi->sd_format->mbus_code, +@@ -1519,7 +1710,20 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) + struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); + int ret; + +- dcmi->vdev->ctrl_handler = dcmi->entity.subdev->ctrl_handler; ++ /* ++ * Now that the graph is complete, ++ * we search for the source subdevice ++ * in order to expose it through V4L2 interface ++ */ ++ dcmi->entity.source = ++ media_entity_to_v4l2_subdev(dcmi_find_source(dcmi)); ++ if (!dcmi->entity.source) { ++ dev_err(dcmi->dev, "Source subdevice not found\n"); ++ return -ENODEV; ++ } ++ ++ dcmi->vdev->ctrl_handler = dcmi->entity.source->ctrl_handler; ++ + ret = dcmi_formats_init(dcmi); + if (ret) { + dev_err(dcmi->dev, "No supported mediabus format found\n"); +@@ -1544,14 +1748,6 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier) + return ret; + } + +- ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); +- if (ret) { +- dev_err(dcmi->dev, "Failed to register video device\n"); +- return ret; +- } +- +- dev_dbg(dcmi->dev, "Device registered as %s\n", +- video_device_node_name(dcmi->vdev)); + return 0; + } + +@@ -1572,12 +1768,31 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_async_subdev *asd) + { + struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); ++ unsigned int ret; ++ int src_pad; + +- dev_dbg(dcmi->dev, "Subdev %s bound\n", subdev->name); ++ dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); + +- dcmi->entity.subdev = subdev; ++ /* ++ * Link this sub-device to DCMI, it could be ++ * a parallel camera sensor or a bridge ++ */ ++ src_pad = media_entity_get_fwnode_pad(&subdev->entity, ++ subdev->fwnode, ++ MEDIA_PAD_FL_SOURCE); ++ ++ ret = media_create_pad_link(&subdev->entity, src_pad, ++ &dcmi->vdev->entity, 0, ++ MEDIA_LNK_FL_IMMUTABLE | ++ MEDIA_LNK_FL_ENABLED); ++ if (ret) ++ dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n", ++ subdev->name); ++ else ++ dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", ++ subdev->name); + +- return 0; ++ return ret; + } + + static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { +@@ -1601,7 +1816,7 @@ static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node) + return -EINVAL; + + /* Remote node to connect */ +- dcmi->entity.node = remote; ++ dcmi->entity.remote_node = remote; + dcmi->entity.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + dcmi->entity.asd.match.fwnode = of_fwnode_handle(remote); + return 0; +@@ -1622,7 +1837,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) + /* Register the subdevices notifier. */ + subdevs = devm_kzalloc(dcmi->dev, sizeof(*subdevs), GFP_KERNEL); + if (!subdevs) { +- of_node_put(dcmi->entity.node); ++ of_node_put(dcmi->entity.remote_node); + return -ENOMEM; + } + +@@ -1635,7 +1850,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) + ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); + if (ret < 0) { + dev_err(dcmi->dev, "Notifier registration failed\n"); +- of_node_put(dcmi->entity.node); ++ of_node_put(dcmi->entity.remote_node); + return ret; + } + +@@ -1746,10 +1961,19 @@ static int dcmi_probe(struct platform_device *pdev) + + q = &dcmi->queue; + ++ dcmi->v4l2_dev.mdev = &dcmi->mdev; ++ ++ /* Initialize media device */ ++ strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model)); ++ snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info), ++ "platform:%s", DRV_NAME); ++ dcmi->mdev.dev = &pdev->dev; ++ media_device_init(&dcmi->mdev); ++ + /* Initialize the top-level structure */ + ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev); + if (ret) +- goto err_dma_release; ++ goto err_media_device_cleanup; + + dcmi->vdev = video_device_alloc(); + if (!dcmi->vdev) { +@@ -1769,6 +1993,25 @@ static int dcmi_probe(struct platform_device *pdev) + V4L2_CAP_READWRITE; + video_set_drvdata(dcmi->vdev, dcmi); + ++ /* Media entity pads */ ++ dcmi->vid_cap_pad.flags = MEDIA_PAD_FL_SINK; ++ ret = media_entity_pads_init(&dcmi->vdev->entity, ++ 1, &dcmi->vid_cap_pad); ++ if (ret) { ++ dev_err(dcmi->dev, "Failed to init media entity pad\n"); ++ goto err_device_release; ++ } ++ dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; ++ ++ ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1); ++ if (ret) { ++ dev_err(dcmi->dev, "Failed to register video device\n"); ++ goto err_media_entity_cleanup; ++ } ++ ++ dev_dbg(dcmi->dev, "Device registered as %s\n", ++ video_device_node_name(dcmi->vdev)); ++ + /* Buffer queue */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; +@@ -1784,12 +2027,12 @@ static int dcmi_probe(struct platform_device *pdev) + ret = vb2_queue_init(q); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to initialize vb2 queue\n"); +- goto err_device_release; ++ goto err_media_entity_cleanup; + } + + ret = dcmi_graph_init(dcmi); + if (ret < 0) +- goto err_device_release; ++ goto err_media_entity_cleanup; + + /* Reset device */ + ret = reset_control_assert(dcmi->rstc); +@@ -1814,11 +2057,14 @@ static int dcmi_probe(struct platform_device *pdev) + + return 0; + ++err_media_entity_cleanup: ++ media_entity_cleanup(&dcmi->vdev->entity); + err_device_release: + video_device_release(dcmi->vdev); + err_device_unregister: + v4l2_device_unregister(&dcmi->v4l2_dev); +-err_dma_release: ++err_media_device_cleanup: ++ media_device_cleanup(&dcmi->mdev); + dma_release_channel(dcmi->dma_chan); + + return ret; +@@ -1831,7 +2077,9 @@ static int dcmi_remove(struct platform_device *pdev) + pm_runtime_disable(&pdev->dev); + + v4l2_async_notifier_unregister(&dcmi->notifier); ++ media_entity_cleanup(&dcmi->vdev->entity); + v4l2_device_unregister(&dcmi->v4l2_dev); ++ media_device_cleanup(&dcmi->mdev); + + dma_release_channel(dcmi->dma_chan); diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index fecccb5..89a7839 100644 @@ -1769,6 +3533,27 @@ index 169bdbb..505338e 100644 bus->flags = flags; } +diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h +index d6a5a3b..2a6b253 100644 +--- a/include/uapi/linux/media-bus-format.h ++++ b/include/uapi/linux/media-bus-format.h +@@ -34,7 +34,7 @@ + + #define MEDIA_BUS_FMT_FIXED 0x0001 + +-/* RGB - next is 0x101b */ ++/* RGB - next is 0x101c */ + #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 + #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 + #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 +@@ -50,6 +50,7 @@ + #define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 + #define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 + #define MEDIA_BUS_FMT_BGR888_1X24 0x1013 ++#define MEDIA_BUS_FMT_BGR888_3X8 0x101b + #define MEDIA_BUS_FMT_GBR888_1X24 0x1014 + #define MEDIA_BUS_FMT_RGB888_1X24 0x100a + #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b -- 2.7.4 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0013-ARM-stm32mp1-r2-MFD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch similarity index 74% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0013-ARM-stm32mp1-r2-MFD.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch index e6af02a..84e0ea9 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0013-ARM-stm32mp1-r2-MFD.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch @@ -1,21 +1,21 @@ -From 1e1b3d357ac9971d70631b624301524294ea5d3c Mon Sep 17 00:00:00 2001 +From f37dea894c9913b5d35a7dc0258fddb735d1b007 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 +Date: Fri, 8 Nov 2019 16:52:42 +0100 +Subject: [PATCH 14/31] ARM stm32mp1 r3 MFD --- - drivers/mfd/Kconfig | 31 ++ + drivers/mfd/Kconfig | 34 +++ drivers/mfd/Makefile | 4 +- - drivers/mfd/stm32-pwr.c | 400 ++++++++++++++++++++++ - drivers/mfd/stmfx.c | 626 +++++++++++++++++++++++++++++++++++ - drivers/mfd/stpmic1.c | 409 +++++++++++++++++++++++ + drivers/mfd/stm32-pwr.c | 400 +++++++++++++++++++++++++ + drivers/mfd/stmfx.c | 545 +++++++++++++++++++++++++++++++++++ + drivers/mfd/stpmic1.c | 219 ++++++++++++++ drivers/mfd/syscon.c | 19 ++ drivers/mfd/wm8994-core.c | 21 ++ - include/dt-bindings/mfd/st,stpmic1.h | 46 +++ - include/linux/mfd/stmfx.h | 27 ++ - include/linux/mfd/stpmic1.h | 212 ++++++++++++ + include/dt-bindings/mfd/st,stpmic1.h | 50 ++++ + include/linux/mfd/stmfx.h | 123 ++++++++ + include/linux/mfd/stpmic1.h | 212 ++++++++++++++ include/linux/mfd/wm8994/pdata.h | 6 + - 11 files changed, 1800 insertions(+), 1 deletion(-) + 11 files changed, 1632 insertions(+), 1 deletion(-) create mode 100644 drivers/mfd/stm32-pwr.c create mode 100644 drivers/mfd/stmfx.c create mode 100644 drivers/mfd/stpmic1.c @@ -24,10 +24,10 @@ Subject: [PATCH 13/30] ARM stm32mp1 r2 MFD create mode 100644 include/linux/mfd/stpmic1.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 11841f4..cc25a19 100644 +index dd938a5..2930188 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig -@@ -1855,6 +1855,37 @@ config MFD_STM32_TIMERS +@@ -1855,6 +1855,40 @@ config MFD_STM32_TIMERS for PWM and IIO Timer. This driver allow to share the registers between the others drivers. @@ -56,8 +56,11 @@ index 11841f4..cc25a19 100644 + select REGMAP_IRQ + select MFD_CORE + help -+ Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 MFD driver is -+ the core driver for STPMIC1 component that mainly handles interrupts. ++ Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 has power on ++ key, watchdog and regulator functionalities which are supported via ++ the relevant subsystems. This driver provides core support for the ++ STPMIC1. In order to use the actual functionaltiy of the device other ++ drivers must be enabled. + + To compile this driver as a module, choose M here: the + module will be called stpmic1. @@ -493,15 +496,15 @@ index 0000000..92744bf +module_exit(stm32_pwr_exit); diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c new file mode 100644 -index 0000000..cfd4fca +index 0000000..857991c --- /dev/null +++ b/drivers/mfd/stmfx.c -@@ -0,0 +1,626 @@ +@@ -0,0 +1,545 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STMicroelectronics Multi-Function eXpander (STMFX) core + * -+ * Copyright (C) 2018 STMicroelectronics ++ * Copyright (C) 2019 STMicroelectronics + * Author(s): Amelie Delaunay . + */ +#include @@ -513,85 +516,84 @@ index 0000000..cfd4fca +#include +#include + -+/* General */ -+#define STMFX_REG_CHIP_ID 0x00 /* R */ -+#define STMFX_REG_FW_VERSION_MSB 0x01 /* R */ -+#define STMFX_REG_FW_VERSION_LSB 0x02 /* R */ -+#define STMFX_REG_SYS_CTRL 0x40 /* RW */ -+/* IRQ output management */ -+#define STMFX_REG_IRQ_OUT_PIN 0x41 /* RW */ -+#define STMFX_REG_IRQ_SRC_EN 0x42 /* RW */ -+#define STMFX_REG_IRQ_PENDING 0x08 /* R */ -+#define STMFX_REG_IRQ_ACK 0x44 /* RW */ -+/* GPIO management */ -+#define STMFX_REG_IRQ_GPI_PENDING1 0x0C /* R */ -+#define STMFX_REG_IRQ_GPI_PENDING2 0x0D /* R */ -+#define STMFX_REG_IRQ_GPI_PENDING3 0x0E /* R */ -+#define STMFX_REG_GPIO_STATE1 0x10 /* R */ -+#define STMFX_REG_GPIO_STATE2 0x11 /* R */ -+#define STMFX_REG_GPIO_STATE3 0x12 /* R */ -+#define STMFX_REG_IRQ_GPI_SRC1 0x48 /* RW */ -+#define STMFX_REG_IRQ_GPI_SRC2 0x49 /* RW */ -+#define STMFX_REG_IRQ_GPI_SRC3 0x4A /* RW */ -+#define STMFX_REG_GPO_SET1 0x6C /* RW */ -+#define STMFX_REG_GPO_SET2 0x6D /* RW */ -+#define STMFX_REG_GPO_SET3 0x6E /* RW */ -+#define STMFX_REG_GPO_CLR1 0x70 /* RW */ -+#define STMFX_REG_GPO_CLR2 0x71 /* RW */ -+#define STMFX_REG_GPO_CLR3 0x72 /* RW */ ++static bool stmfx_reg_volatile(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case STMFX_REG_SYS_CTRL: ++ case STMFX_REG_IRQ_SRC_EN: ++ case STMFX_REG_IRQ_PENDING: ++ case STMFX_REG_IRQ_GPI_PENDING1: ++ case STMFX_REG_IRQ_GPI_PENDING2: ++ case STMFX_REG_IRQ_GPI_PENDING3: ++ case STMFX_REG_GPIO_STATE1: ++ case STMFX_REG_GPIO_STATE2: ++ case STMFX_REG_GPIO_STATE3: ++ case STMFX_REG_IRQ_GPI_SRC1: ++ case STMFX_REG_IRQ_GPI_SRC2: ++ case STMFX_REG_IRQ_GPI_SRC3: ++ case STMFX_REG_GPO_SET1: ++ case STMFX_REG_GPO_SET2: ++ case STMFX_REG_GPO_SET3: ++ case STMFX_REG_GPO_CLR1: ++ case STMFX_REG_GPO_CLR2: ++ case STMFX_REG_GPO_CLR3: ++ return true; ++ default: ++ return false; ++ } ++} + -+#define STMFX_REG_MAX 0xB0 ++static bool stmfx_reg_writeable(struct device *dev, unsigned int reg) ++{ ++ return (reg >= STMFX_REG_SYS_CTRL); ++} + -+/* MFX boot time is around 10ms, so after reset, we have to wait this delay */ -+#define STMFX_BOOT_TIME_MS 10 -+ -+/* STMFX_REG_CHIP_ID bitfields */ -+#define STMFX_REG_CHIP_ID_MASK GENMASK(7, 0) -+ -+/* STMFX_REG_SYS_CTRL bitfields */ -+#define STMFX_REG_SYS_CTRL_GPIO_EN BIT(0) -+#define STMFX_REG_SYS_CTRL_TS_EN BIT(1) -+#define STMFX_REG_SYS_CTRL_IDD_EN BIT(2) -+#define STMFX_REG_SYS_CTRL_ALTGPIO_EN BIT(3) -+#define STMFX_REG_SYS_CTRL_SWRST BIT(7) -+ -+/* STMFX_REG_IRQ_OUT_PIN bitfields */ -+#define STMFX_REG_IRQ_OUT_PIN_TYPE BIT(0) /* 0-OD 1-PP */ -+#define STMFX_REG_IRQ_OUT_PIN_POL BIT(1) /* 0-active LOW 1-active HIGH */ -+ -+/* STMFX_REG_IRQ_(SRC_EN/PENDING/ACK) bit shift */ -+enum stmfx_irqs { -+ STMFX_REG_IRQ_SRC_EN_GPIO = 0, -+ STMFX_REG_IRQ_SRC_EN_IDD, -+ STMFX_REG_IRQ_SRC_EN_ERROR, -+ STMFX_REG_IRQ_SRC_EN_TS_DET, -+ STMFX_REG_IRQ_SRC_EN_TS_NE, -+ STMFX_REG_IRQ_SRC_EN_TS_TH, -+ STMFX_REG_IRQ_SRC_EN_TS_FULL, -+ STMFX_REG_IRQ_SRC_EN_TS_OVF, -+ STMFX_REG_IRQ_SRC_MAX, ++static const struct regmap_config stmfx_regmap_config = { ++ .reg_bits = 8, ++ .reg_stride = 1, ++ .val_bits = 8, ++ .max_register = STMFX_REG_MAX, ++ .volatile_reg = stmfx_reg_volatile, ++ .writeable_reg = stmfx_reg_writeable, ++ .cache_type = REGCACHE_RBTREE, +}; + -+/** -+ * struct stmfx_ddata - STMFX MFD private structure -+ * @stmfx: state holder with device for logs and register map -+ * @vdd: STMFX power supply -+ * @irq_domain: IRQ domain -+ * @lock: IRQ bus lock -+ * @irq_src: cache of IRQ_SRC_EN register for bus_lock -+ * @bkp_sysctrl: backup of SYS_CTRL register for suspend/resume -+ * @bkp_irqoutpin: backup of IRQ_OUT_PIN register for suspend/resume -+ */ -+struct stmfx_ddata { -+ struct stmfx *stmfx; -+ struct regulator *vdd; -+ struct irq_domain *irq_domain; -+ struct mutex lock; /* IRQ bus lock */ -+ u8 irq_src; -+#ifdef CONFIG_PM -+ u8 bkp_sysctrl; -+ u8 bkp_irqoutpin; -+#endif ++static const struct resource stmfx_pinctrl_resources[] = { ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_GPIO), ++}; ++ ++static const struct resource stmfx_idd_resources[] = { ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_IDD), ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_ERROR), ++}; ++ ++static const struct resource stmfx_ts_resources[] = { ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_DET), ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_NE), ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_TH), ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_FULL), ++ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_OVF), ++}; ++ ++static struct mfd_cell stmfx_cells[] = { ++ { ++ .of_compatible = "st,stmfx-0300-pinctrl", ++ .name = "stmfx-pinctrl", ++ .resources = stmfx_pinctrl_resources, ++ .num_resources = ARRAY_SIZE(stmfx_pinctrl_resources), ++ }, ++ { ++ .of_compatible = "st,stmfx-0300-idd", ++ .name = "stmfx-idd", ++ .resources = stmfx_idd_resources, ++ .num_resources = ARRAY_SIZE(stmfx_idd_resources), ++ }, ++ { ++ .of_compatible = "st,stmfx-0300-ts", ++ .name = "stmfx-ts", ++ .resources = stmfx_ts_resources, ++ .num_resources = ARRAY_SIZE(stmfx_ts_resources), ++ }, +}; + +static u8 stmfx_func_to_mask(u32 func) @@ -665,32 +667,32 @@ index 0000000..cfd4fca + +static void stmfx_irq_bus_lock(struct irq_data *data) +{ -+ struct stmfx_ddata *ddata = irq_data_get_irq_chip_data(data); ++ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); + -+ mutex_lock(&ddata->lock); ++ mutex_lock(&stmfx->lock); +} + +static void stmfx_irq_bus_sync_unlock(struct irq_data *data) +{ -+ struct stmfx_ddata *ddata = irq_data_get_irq_chip_data(data); ++ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); + -+ regmap_write(ddata->stmfx->map, STMFX_REG_IRQ_SRC_EN, ddata->irq_src); ++ regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, stmfx->irq_src); + -+ mutex_unlock(&ddata->lock); ++ mutex_unlock(&stmfx->lock); +} + +static void stmfx_irq_mask(struct irq_data *data) +{ -+ struct stmfx_ddata *ddata = irq_data_get_irq_chip_data(data); ++ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); + -+ ddata->irq_src &= ~BIT(data->hwirq % 8); ++ stmfx->irq_src &= ~BIT(data->hwirq % 8); +} + +static void stmfx_irq_unmask(struct irq_data *data) +{ -+ struct stmfx_ddata *ddata = irq_data_get_irq_chip_data(data); ++ struct stmfx *stmfx = irq_data_get_irq_chip_data(data); + -+ ddata->irq_src |= BIT(data->hwirq % 8); ++ stmfx->irq_src |= BIT(data->hwirq % 8); +} + +static struct irq_chip stmfx_irq_chip = { @@ -703,13 +705,12 @@ index 0000000..cfd4fca + +static irqreturn_t stmfx_irq_handler(int irq, void *data) +{ -+ struct stmfx_ddata *ddata = data; -+ unsigned long n, pending; -+ u32 ack; -+ int ret; ++ struct stmfx *stmfx = data; ++ unsigned long bits; ++ u32 pending, ack; ++ int n, ret; + -+ ret = regmap_read(ddata->stmfx->map, STMFX_REG_IRQ_PENDING, -+ (u32 *)&pending); ++ ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, &pending); + if (ret) + return IRQ_NONE; + @@ -719,13 +720,14 @@ index 0000000..cfd4fca + */ + ack = pending & ~BIT(STMFX_REG_IRQ_SRC_EN_GPIO); + if (ack) { -+ ret = regmap_write(ddata->stmfx->map, STMFX_REG_IRQ_ACK, ack); ++ ret = regmap_write(stmfx->map, STMFX_REG_IRQ_ACK, ack); + if (ret) + return IRQ_NONE; + } + -+ for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX) -+ handle_nested_irq(irq_find_mapping(ddata->irq_domain, n)); ++ bits = pending; ++ for_each_set_bit(n, &bits, STMFX_REG_IRQ_SRC_MAX) ++ handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n)); + + return IRQ_HANDLED; +} @@ -752,55 +754,58 @@ index 0000000..cfd4fca + .unmap = stmfx_irq_unmap, +}; + -+static void stmfx_irq_exit(struct stmfx_ddata *ddata) ++static void stmfx_irq_exit(struct i2c_client *client) +{ ++ struct stmfx *stmfx = i2c_get_clientdata(client); + int hwirq; + + for (hwirq = 0; hwirq < STMFX_REG_IRQ_SRC_MAX; hwirq++) -+ irq_dispose_mapping(irq_find_mapping(ddata->irq_domain, hwirq)); -+ irq_domain_remove(ddata->irq_domain); ++ irq_dispose_mapping(irq_find_mapping(stmfx->irq_domain, hwirq)); ++ ++ irq_domain_remove(stmfx->irq_domain); +} + -+static int stmfx_irq_init(struct stmfx_ddata *ddata, int irq) ++static int stmfx_irq_init(struct i2c_client *client) +{ -+ struct device *dev = ddata->stmfx->dev; ++ struct stmfx *stmfx = i2c_get_clientdata(client); + u32 irqoutpin = 0, irqtrigger; + int ret; + -+ ddata->irq_domain = irq_domain_add_simple(dev->of_node, ++ stmfx->irq_domain = irq_domain_add_simple(stmfx->dev->of_node, + STMFX_REG_IRQ_SRC_MAX, 0, -+ &stmfx_irq_ops, ddata); -+ if (!ddata->irq_domain) { -+ dev_err(dev, "failed to create irq domain\n"); ++ &stmfx_irq_ops, stmfx); ++ if (!stmfx->irq_domain) { ++ dev_err(stmfx->dev, "Failed to create IRQ domain\n"); + return -EINVAL; + } + -+ if (!of_property_read_bool(dev->of_node, "drive-open-drain")) ++ if (!of_property_read_bool(stmfx->dev->of_node, "drive-open-drain")) + irqoutpin |= STMFX_REG_IRQ_OUT_PIN_TYPE; + -+ irqtrigger = irq_get_trigger_type(irq); ++ irqtrigger = irq_get_trigger_type(client->irq); + if ((irqtrigger & IRQ_TYPE_EDGE_RISING) || + (irqtrigger & IRQ_TYPE_LEVEL_HIGH)) + irqoutpin |= STMFX_REG_IRQ_OUT_PIN_POL; + -+ ret = regmap_write(ddata->stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin); ++ ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin); + if (ret) + return ret; + -+ ret = devm_request_threaded_irq(dev, irq, NULL, stmfx_irq_handler, ++ ret = devm_request_threaded_irq(stmfx->dev, client->irq, ++ NULL, stmfx_irq_handler, + irqtrigger | IRQF_ONESHOT, -+ "stmfx", ddata); ++ "stmfx", stmfx); + if (ret) -+ stmfx_irq_exit(ddata); ++ stmfx_irq_exit(client); + + return ret; +} + -+static int stmfx_chip_reset(struct stmfx_ddata *ddata) ++static int stmfx_chip_reset(struct stmfx *stmfx) +{ + int ret; + -+ ret = regmap_write(ddata->stmfx->map, STMFX_REG_SYS_CTRL, ++ ret = regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, + STMFX_REG_SYS_CTRL_SWRST); + if (ret) + return ret; @@ -810,34 +815,35 @@ index 0000000..cfd4fca + return ret; +} + -+static int stmfx_chip_init(struct stmfx_ddata *ddata, struct i2c_client *client) ++static int stmfx_chip_init(struct i2c_client *client) +{ ++ struct stmfx *stmfx = i2c_get_clientdata(client); + u32 id; + u8 version[2]; + int ret; + -+ ddata->vdd = devm_regulator_get_optional(&client->dev, "vdd"); -+ if (IS_ERR(ddata->vdd)) { -+ ret = PTR_ERR(ddata->vdd); -+ if (ret != -ENODEV) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(&client->dev, -+ "no vdd regulator found:%d\n", ret); -+ return ret; -+ } ++ stmfx->vdd = devm_regulator_get_optional(&client->dev, "vdd"); ++ ret = PTR_ERR_OR_ZERO(stmfx->vdd); ++ if (ret == -ENODEV) { ++ stmfx->vdd = NULL; ++ } else if (ret == -EPROBE_DEFER) { ++ return ret; ++ } else if (ret) { ++ dev_err(&client->dev, "Failed to get VDD regulator: %d\n", ret); ++ return ret; + } + -+ if (!IS_ERR(ddata->vdd)) { -+ ret = regulator_enable(ddata->vdd); ++ if (stmfx->vdd) { ++ ret = regulator_enable(stmfx->vdd); + if (ret) { -+ dev_err(&client->dev, "vdd enable failed: %d\n", ret); ++ dev_err(&client->dev, "VDD enable failed: %d\n", ret); + return ret; + } + } + -+ ret = regmap_read(ddata->stmfx->map, STMFX_REG_CHIP_ID, &id); ++ ret = regmap_read(stmfx->map, STMFX_REG_CHIP_ID, &id); + if (ret) { -+ dev_err(&client->dev, "error reading chip id: %d\n", ret); ++ dev_err(&client->dev, "Error reading chip ID: %d\n", ret); + goto err; + } + @@ -853,125 +859,74 @@ index 0000000..cfd4fca + * 1 | b: 1000 011x h:0x86 | 0x43 + */ + if (FIELD_GET(STMFX_REG_CHIP_ID_MASK, ~id) != (client->addr << 1)) { -+ dev_err(&client->dev, "unknown chip id: %#x\n", id); ++ dev_err(&client->dev, "Unknown chip ID: %#x\n", id); + ret = -EINVAL; + goto err; + } + -+ ret = regmap_bulk_read(ddata->stmfx->map, STMFX_REG_FW_VERSION_MSB, ++ ret = regmap_bulk_read(stmfx->map, STMFX_REG_FW_VERSION_MSB, + version, ARRAY_SIZE(version)); + if (ret) { -+ dev_err(&client->dev, "error reading fw version: %d\n", ret); ++ dev_err(&client->dev, "Error reading FW version: %d\n", ret); + goto err; + } + + dev_info(&client->dev, "STMFX id: %#x, fw version: %x.%02x\n", + id, version[0], version[1]); + -+ return stmfx_chip_reset(ddata); ++ ret = stmfx_chip_reset(stmfx); ++ if (ret) { ++ dev_err(&client->dev, "Failed to reset chip: %d\n", ret); ++ goto err; ++ } ++ ++ return 0; + +err: -+ if (!IS_ERR(ddata->vdd)) -+ return regulator_disable(ddata->vdd); ++ if (stmfx->vdd) ++ return regulator_disable(stmfx->vdd); + + return ret; +} + -+static int stmfx_chip_exit(struct stmfx_ddata *ddata) ++static int stmfx_chip_exit(struct i2c_client *client) +{ -+ regmap_write(ddata->stmfx->map, STMFX_REG_IRQ_SRC_EN, 0); -+ regmap_write(ddata->stmfx->map, STMFX_REG_SYS_CTRL, 0); ++ struct stmfx *stmfx = i2c_get_clientdata(client); + -+ if (!IS_ERR(ddata->vdd)) -+ return regulator_disable(ddata->vdd); ++ regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, 0); ++ regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, 0); ++ ++ if (stmfx->vdd) ++ return regulator_disable(stmfx->vdd); + + return 0; +} + -+static const struct resource stmfx_pinctrl_resources[] = { -+ DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_GPIO), -+}; -+ -+static struct mfd_cell stmfx_cells[] = { -+ { -+ .of_compatible = "st,stmfx-0300-pinctrl", -+ .name = "stmfx-pinctrl", -+ .resources = stmfx_pinctrl_resources, -+ .num_resources = ARRAY_SIZE(stmfx_pinctrl_resources), -+ } -+}; -+ -+static bool stmfx_reg_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case STMFX_REG_SYS_CTRL: -+ case STMFX_REG_IRQ_SRC_EN: -+ case STMFX_REG_IRQ_PENDING: -+ case STMFX_REG_IRQ_GPI_PENDING1: -+ case STMFX_REG_IRQ_GPI_PENDING2: -+ case STMFX_REG_IRQ_GPI_PENDING3: -+ case STMFX_REG_GPIO_STATE1: -+ case STMFX_REG_GPIO_STATE2: -+ case STMFX_REG_GPIO_STATE3: -+ case STMFX_REG_IRQ_GPI_SRC1: -+ case STMFX_REG_IRQ_GPI_SRC2: -+ case STMFX_REG_IRQ_GPI_SRC3: -+ case STMFX_REG_GPO_SET1: -+ case STMFX_REG_GPO_SET2: -+ case STMFX_REG_GPO_SET3: -+ case STMFX_REG_GPO_CLR1: -+ case STMFX_REG_GPO_CLR2: -+ case STMFX_REG_GPO_CLR3: -+ return true; -+ default: -+ return false; -+ } -+} -+ -+static bool stmfx_reg_writeable(struct device *dev, unsigned int reg) -+{ -+ return (reg >= STMFX_REG_SYS_CTRL); -+} -+ -+static const struct regmap_config stmfx_regmap_config = { -+ .reg_bits = 8, -+ .reg_stride = 1, -+ .val_bits = 8, -+ .max_register = STMFX_REG_MAX, -+ .volatile_reg = stmfx_reg_volatile, -+ .writeable_reg = stmfx_reg_writeable, -+ .cache_type = REGCACHE_RBTREE, -+}; -+ +static int stmfx_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; -+ struct stmfx_ddata *ddata; -+ int i, ret; ++ struct stmfx *stmfx; ++ int ret; + -+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); -+ if (!ddata) -+ return -ENOMEM; -+ /* State holder */ -+ ddata->stmfx = devm_kzalloc(dev, sizeof(*ddata->stmfx), GFP_KERNEL); -+ if (!ddata->stmfx) ++ stmfx = devm_kzalloc(dev, sizeof(*stmfx), GFP_KERNEL); ++ if (!stmfx) + return -ENOMEM; + -+ i2c_set_clientdata(client, ddata); ++ i2c_set_clientdata(client, stmfx); + -+ ddata->stmfx->dev = dev; ++ stmfx->dev = dev; + -+ ddata->stmfx->map = devm_regmap_init_i2c(client, &stmfx_regmap_config); -+ if (IS_ERR(ddata->stmfx->map)) { -+ ret = PTR_ERR(ddata->stmfx->map); -+ dev_err(dev, "failed to allocate register map: %d\n", ret); ++ stmfx->map = devm_regmap_init_i2c(client, &stmfx_regmap_config); ++ if (IS_ERR(stmfx->map)) { ++ ret = PTR_ERR(stmfx->map); ++ dev_err(dev, "Failed to allocate register map: %d\n", ret); + return ret; + } + -+ mutex_init(&ddata->lock); ++ mutex_init(&stmfx->lock); + -+ ret = stmfx_chip_init(ddata, client); ++ ret = stmfx_chip_init(client); + if (ret) { + if (ret == -ETIMEDOUT) + return -EPROBE_DEFER; @@ -979,123 +934,90 @@ index 0000000..cfd4fca + } + + if (client->irq < 0) { -+ dev_err(dev, "failed to get irq: %d\n", client->irq); ++ dev_err(dev, "Failed to get IRQ: %d\n", client->irq); + ret = client->irq; + goto err_chip_exit; + } + -+ ret = stmfx_irq_init(ddata, client->irq); ++ ret = stmfx_irq_init(client); + if (ret) + goto err_chip_exit; + -+ for (i = 0; i < ARRAY_SIZE(stmfx_cells); i++) { -+ stmfx_cells[i].platform_data = ddata->stmfx; -+ stmfx_cells[i].pdata_size = sizeof(struct stmfx); -+ } -+ + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, + stmfx_cells, ARRAY_SIZE(stmfx_cells), NULL, -+ 0, ddata->irq_domain); ++ 0, stmfx->irq_domain); + if (ret) + goto err_irq_exit; + + return 0; + +err_irq_exit: -+ stmfx_irq_exit(ddata); ++ stmfx_irq_exit(client); +err_chip_exit: -+ stmfx_chip_exit(ddata); ++ stmfx_chip_exit(client); + + return ret; +} + +static int stmfx_remove(struct i2c_client *client) +{ -+ struct stmfx_ddata *ddata = i2c_get_clientdata(client); ++ stmfx_irq_exit(client); + -+ stmfx_irq_exit(ddata); -+ -+ return stmfx_chip_exit(ddata); ++ return stmfx_chip_exit(client); +} + +#ifdef CONFIG_PM_SLEEP -+static int stmfx_backup_regs(struct stmfx_ddata *ddata) -+{ -+ int ret; -+ -+ ret = regmap_raw_read(ddata->stmfx->map, STMFX_REG_SYS_CTRL, -+ &ddata->bkp_sysctrl, sizeof(ddata->bkp_sysctrl)); -+ if (ret) -+ return ret; -+ ret = regmap_raw_read(ddata->stmfx->map, STMFX_REG_IRQ_OUT_PIN, -+ &ddata->bkp_irqoutpin, -+ sizeof(ddata->bkp_irqoutpin)); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ -+static int stmfx_restore_regs(struct stmfx_ddata *ddata) -+{ -+ int ret; -+ -+ ret = regmap_raw_write(ddata->stmfx->map, STMFX_REG_SYS_CTRL, -+ &ddata->bkp_sysctrl, sizeof(ddata->bkp_sysctrl)); -+ if (ret) -+ return ret; -+ ret = regmap_raw_write(ddata->stmfx->map, STMFX_REG_IRQ_OUT_PIN, -+ &ddata->bkp_irqoutpin, -+ sizeof(ddata->bkp_irqoutpin)); -+ if (ret) -+ return ret; -+ ret = regmap_raw_write(ddata->stmfx->map, STMFX_REG_IRQ_SRC_EN, -+ &ddata->irq_src, sizeof(ddata->irq_src)); -+ if (ret) -+ return ret; -+ -+ return 0; -+} -+ +static int stmfx_suspend(struct device *dev) +{ -+ struct stmfx_ddata *ddata = dev_get_drvdata(dev); ++ struct stmfx *stmfx = dev_get_drvdata(dev); + int ret; + -+ ret = stmfx_backup_regs(ddata); -+ if (ret) { -+ dev_err(ddata->stmfx->dev, "registers backup failure\n"); ++ ret = regmap_raw_read(stmfx->map, STMFX_REG_SYS_CTRL, ++ &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); ++ if (ret) + return ret; -+ } + -+ if (!IS_ERR(ddata->vdd)) { -+ ret = regulator_disable(ddata->vdd); -+ if (ret) -+ return ret; -+ } ++ ret = regmap_raw_read(stmfx->map, STMFX_REG_IRQ_OUT_PIN, ++ &stmfx->bkp_irqoutpin, ++ sizeof(stmfx->bkp_irqoutpin)); ++ if (ret) ++ return ret; ++ ++ if (stmfx->vdd) ++ return regulator_disable(stmfx->vdd); + + return 0; +} + +static int stmfx_resume(struct device *dev) +{ -+ struct stmfx_ddata *ddata = dev_get_drvdata(dev); ++ struct stmfx *stmfx = dev_get_drvdata(dev); + int ret; + -+ if (!IS_ERR(ddata->vdd)) { -+ ret = regulator_enable(ddata->vdd); ++ if (stmfx->vdd) { ++ ret = regulator_enable(stmfx->vdd); + if (ret) { -+ dev_err(ddata->stmfx->dev, -+ "vdd enable failed: %d\n", ret); ++ dev_err(stmfx->dev, ++ "VDD enable failed: %d\n", ret); + return ret; + } + } + -+ ret = stmfx_restore_regs(ddata); -+ if (ret) { -+ dev_err(ddata->stmfx->dev, "registers restoration failure\n"); ++ ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL, ++ &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, ++ &stmfx->bkp_irqoutpin, ++ sizeof(stmfx->bkp_irqoutpin)); ++ if (ret) ++ return ret; ++ ++ ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, ++ &stmfx->irq_src, sizeof(stmfx->irq_src)); ++ if (ret) + return ret; -+ } + + return 0; +} @@ -1125,10 +1047,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..648315d +index 0000000..766c321 --- /dev/null +++ b/drivers/mfd/stpmic1.c -@@ -0,0 +1,409 @@ +@@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet @@ -1147,219 +1069,93 @@ index 0000000..648315d +#include + +#define STPMIC1_MAIN_IRQ 0 -+#define STPMIC1_WAKEUP_IRQ 1 + -+static bool stpmic1_reg_readable(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case TURN_ON_SR: -+ case TURN_OFF_SR: -+ case ICC_LDO_TURN_OFF_SR: -+ case ICC_BUCK_TURN_OFF_SR: -+ case RREQ_STATE_SR: -+ case VERSION_SR: -+ case SWOFF_PWRCTRL_CR: -+ case PADS_PULL_CR: -+ case BUCKS_PD_CR: -+ case LDO14_PD_CR: -+ case LDO56_VREF_PD_CR: -+ case VBUS_DET_VIN_CR: -+ case PKEY_TURNOFF_CR: -+ case BUCKS_MASK_RANK_CR: -+ case BUCKS_MASK_RESET_CR: -+ case LDOS_MASK_RANK_CR: -+ case LDOS_MASK_RESET_CR: -+ case WCHDG_CR: -+ case WCHDG_TIMER_CR: -+ case BUCKS_ICCTO_CR: -+ case LDOS_ICCTO_CR: -+ case BUCK1_ACTIVE_CR: -+ case BUCK2_ACTIVE_CR: -+ case BUCK3_ACTIVE_CR: -+ case BUCK4_ACTIVE_CR: -+ case VREF_DDR_ACTIVE_CR: -+ case LDO1_ACTIVE_CR: -+ case LDO2_ACTIVE_CR: -+ case LDO3_ACTIVE_CR: -+ case LDO4_ACTIVE_CR: -+ case LDO5_ACTIVE_CR: -+ case LDO6_ACTIVE_CR: -+ case BUCK1_STDBY_CR: -+ case BUCK2_STDBY_CR: -+ case BUCK3_STDBY_CR: -+ case BUCK4_STDBY_CR: -+ case VREF_DDR_STDBY_CR: -+ case LDO1_STDBY_CR: -+ case LDO2_STDBY_CR: -+ case LDO3_STDBY_CR: -+ case LDO4_STDBY_CR: -+ case LDO5_STDBY_CR: -+ case LDO6_STDBY_CR: -+ case BST_SW_CR: -+ case INT_PENDING_R1: -+ case INT_PENDING_R2: -+ case INT_PENDING_R3: -+ case INT_PENDING_R4: -+ case INT_DBG_LATCH_R1: -+ case INT_DBG_LATCH_R2: -+ case INT_DBG_LATCH_R3: -+ case INT_DBG_LATCH_R4: -+ case INT_CLEAR_R1: -+ case INT_CLEAR_R2: -+ case INT_CLEAR_R3: -+ case INT_CLEAR_R4: -+ case INT_MASK_R1: -+ case INT_MASK_R2: -+ case INT_MASK_R3: -+ case INT_MASK_R4: -+ case INT_SET_MASK_R1: -+ case INT_SET_MASK_R2: -+ case INT_SET_MASK_R3: -+ case INT_SET_MASK_R4: -+ case INT_CLEAR_MASK_R1: -+ case INT_CLEAR_MASK_R2: -+ case INT_CLEAR_MASK_R3: -+ case INT_CLEAR_MASK_R4: -+ case INT_SRC_R1: -+ case INT_SRC_R2: -+ case INT_SRC_R3: -+ case INT_SRC_R4: -+ return true; -+ default: -+ return false; -+ } -+} ++static const struct regmap_range stpmic1_readable_ranges[] = { ++ regmap_reg_range(TURN_ON_SR, VERSION_SR), ++ regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), ++ regmap_reg_range(BST_SW_CR, BST_SW_CR), ++ regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4), ++ regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), ++ regmap_reg_range(INT_MASK_R1, INT_MASK_R4), ++ regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4), ++ regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4), ++ regmap_reg_range(INT_SRC_R1, INT_SRC_R1), ++}; + -+static bool stpmic1_reg_writeable(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case SWOFF_PWRCTRL_CR: -+ case PADS_PULL_CR: -+ case BUCKS_PD_CR: -+ case LDO14_PD_CR: -+ case LDO56_VREF_PD_CR: -+ case VBUS_DET_VIN_CR: -+ case PKEY_TURNOFF_CR: -+ case BUCKS_MASK_RANK_CR: -+ case BUCKS_MASK_RESET_CR: -+ case LDOS_MASK_RANK_CR: -+ case LDOS_MASK_RESET_CR: -+ case WCHDG_CR: -+ case WCHDG_TIMER_CR: -+ case BUCKS_ICCTO_CR: -+ case LDOS_ICCTO_CR: -+ case BUCK1_ACTIVE_CR: -+ case BUCK2_ACTIVE_CR: -+ case BUCK3_ACTIVE_CR: -+ case BUCK4_ACTIVE_CR: -+ case VREF_DDR_ACTIVE_CR: -+ case LDO1_ACTIVE_CR: -+ case LDO2_ACTIVE_CR: -+ case LDO3_ACTIVE_CR: -+ case LDO4_ACTIVE_CR: -+ case LDO5_ACTIVE_CR: -+ case LDO6_ACTIVE_CR: -+ case BUCK1_STDBY_CR: -+ case BUCK2_STDBY_CR: -+ case BUCK3_STDBY_CR: -+ case BUCK4_STDBY_CR: -+ case VREF_DDR_STDBY_CR: -+ case LDO1_STDBY_CR: -+ case LDO2_STDBY_CR: -+ case LDO3_STDBY_CR: -+ case LDO4_STDBY_CR: -+ case LDO5_STDBY_CR: -+ case LDO6_STDBY_CR: -+ case BST_SW_CR: -+ case INT_DBG_LATCH_R1: -+ case INT_DBG_LATCH_R2: -+ case INT_DBG_LATCH_R3: -+ case INT_DBG_LATCH_R4: -+ case INT_CLEAR_R1: -+ case INT_CLEAR_R2: -+ case INT_CLEAR_R3: -+ case INT_CLEAR_R4: -+ case INT_SET_MASK_R1: -+ case INT_SET_MASK_R2: -+ case INT_SET_MASK_R3: -+ case INT_SET_MASK_R4: -+ case INT_CLEAR_MASK_R1: -+ case INT_CLEAR_MASK_R2: -+ case INT_CLEAR_MASK_R3: -+ case INT_CLEAR_MASK_R4: -+ return true; -+ default: -+ return false; -+ } -+} ++static const struct regmap_range stpmic1_writeable_ranges[] = { ++ regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR), ++ regmap_reg_range(BST_SW_CR, BST_SW_CR), ++ regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4), ++ regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4), ++ regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4), ++}; + -+static bool stpmic1_reg_volatile(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case TURN_ON_SR: -+ case TURN_OFF_SR: -+ case ICC_LDO_TURN_OFF_SR: -+ case ICC_BUCK_TURN_OFF_SR: -+ case RREQ_STATE_SR: -+ case INT_PENDING_R1: -+ case INT_PENDING_R2: -+ case INT_PENDING_R3: -+ case INT_PENDING_R4: -+ case INT_SRC_R1: -+ case INT_SRC_R2: -+ case INT_SRC_R3: -+ case INT_SRC_R4: -+ case WCHDG_CR: -+ return true; -+ default: -+ return false; -+ } -+} ++static const struct regmap_range stpmic1_volatile_ranges[] = { ++ regmap_reg_range(TURN_ON_SR, VERSION_SR), ++ regmap_reg_range(WCHDG_CR, WCHDG_CR), ++ regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4), ++ regmap_reg_range(INT_SRC_R1, INT_SRC_R4), ++}; ++ ++static const struct regmap_access_table stpmic1_readable_table = { ++ .yes_ranges = stpmic1_readable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(stpmic1_readable_ranges), ++}; ++ ++static const struct regmap_access_table stpmic1_writeable_table = { ++ .yes_ranges = stpmic1_writeable_ranges, ++ .n_yes_ranges = ARRAY_SIZE(stpmic1_writeable_ranges), ++}; ++ ++static const struct regmap_access_table stpmic1_volatile_table = { ++ .yes_ranges = stpmic1_volatile_ranges, ++ .n_yes_ranges = ARRAY_SIZE(stpmic1_volatile_ranges), ++}; + +const struct regmap_config stpmic1_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = PMIC_MAX_REGISTER_ADDRESS, -+ .readable_reg = stpmic1_reg_readable, -+ .writeable_reg = stpmic1_reg_writeable, -+ .volatile_reg = stpmic1_reg_volatile, ++ .rd_table = &stpmic1_readable_table, ++ .wr_table = &stpmic1_writeable_table, ++ .volatile_table = &stpmic1_volatile_table, +}; + +static const struct regmap_irq stpmic1_irqs[] = { -+ [IT_PONKEY_F] = { .mask = 0x01 }, -+ [IT_PONKEY_R] = { .mask = 0x02 }, -+ [IT_WAKEUP_F] = { .mask = 0x04 }, -+ [IT_WAKEUP_R] = { .mask = 0x08 }, -+ [IT_VBUS_OTG_F] = { .mask = 0x10 }, -+ [IT_VBUS_OTG_R] = { .mask = 0x20 }, -+ [IT_SWOUT_F] = { .mask = 0x40 }, -+ [IT_SWOUT_R] = { .mask = 0x80 }, ++ REGMAP_IRQ_REG(IT_PONKEY_F, 0, 0x01), ++ REGMAP_IRQ_REG(IT_PONKEY_R, 0, 0x02), ++ REGMAP_IRQ_REG(IT_WAKEUP_F, 0, 0x04), ++ REGMAP_IRQ_REG(IT_WAKEUP_R, 0, 0x08), ++ REGMAP_IRQ_REG(IT_VBUS_OTG_F, 0, 0x10), ++ REGMAP_IRQ_REG(IT_VBUS_OTG_R, 0, 0x20), ++ REGMAP_IRQ_REG(IT_SWOUT_F, 0, 0x40), ++ REGMAP_IRQ_REG(IT_SWOUT_R, 0, 0x80), + -+ [IT_CURLIM_BUCK1] = { .reg_offset = 1, .mask = 0x01 }, -+ [IT_CURLIM_BUCK2] = { .reg_offset = 1, .mask = 0x02 }, -+ [IT_CURLIM_BUCK3] = { .reg_offset = 1, .mask = 0x04 }, -+ [IT_CURLIM_BUCK4] = { .reg_offset = 1, .mask = 0x08 }, -+ [IT_OCP_OTG] = { .reg_offset = 1, .mask = 0x10 }, -+ [IT_OCP_SWOUT] = { .reg_offset = 1, .mask = 0x20 }, -+ [IT_OCP_BOOST] = { .reg_offset = 1, .mask = 0x40 }, -+ [IT_OVP_BOOST] = { .reg_offset = 1, .mask = 0x80 }, ++ REGMAP_IRQ_REG(IT_CURLIM_BUCK1, 1, 0x01), ++ REGMAP_IRQ_REG(IT_CURLIM_BUCK2, 1, 0x02), ++ REGMAP_IRQ_REG(IT_CURLIM_BUCK3, 1, 0x04), ++ REGMAP_IRQ_REG(IT_CURLIM_BUCK4, 1, 0x08), ++ REGMAP_IRQ_REG(IT_OCP_OTG, 1, 0x10), ++ REGMAP_IRQ_REG(IT_OCP_SWOUT, 1, 0x20), ++ REGMAP_IRQ_REG(IT_OCP_BOOST, 1, 0x40), ++ REGMAP_IRQ_REG(IT_OVP_BOOST, 1, 0x80), + -+ [IT_CURLIM_LDO1] = { .reg_offset = 2, .mask = 0x01 }, -+ [IT_CURLIM_LDO2] = { .reg_offset = 2, .mask = 0x02 }, -+ [IT_CURLIM_LDO3] = { .reg_offset = 2, .mask = 0x04 }, -+ [IT_CURLIM_LDO4] = { .reg_offset = 2, .mask = 0x08 }, -+ [IT_CURLIM_LDO5] = { .reg_offset = 2, .mask = 0x10 }, -+ [IT_CURLIM_LDO6] = { .reg_offset = 2, .mask = 0x20 }, -+ [IT_SHORT_SWOTG] = { .reg_offset = 2, .mask = 0x40 }, -+ [IT_SHORT_SWOUT] = { .reg_offset = 2, .mask = 0x80 }, ++ REGMAP_IRQ_REG(IT_CURLIM_LDO1, 2, 0x01), ++ REGMAP_IRQ_REG(IT_CURLIM_LDO2, 2, 0x02), ++ REGMAP_IRQ_REG(IT_CURLIM_LDO3, 2, 0x04), ++ REGMAP_IRQ_REG(IT_CURLIM_LDO4, 2, 0x08), ++ REGMAP_IRQ_REG(IT_CURLIM_LDO5, 2, 0x10), ++ REGMAP_IRQ_REG(IT_CURLIM_LDO6, 2, 0x20), ++ REGMAP_IRQ_REG(IT_SHORT_SWOTG, 2, 0x40), ++ REGMAP_IRQ_REG(IT_SHORT_SWOUT, 2, 0x80), + -+ [IT_TWARN_F] = { .reg_offset = 3, .mask = 0x01 }, -+ [IT_TWARN_R] = { .reg_offset = 3, .mask = 0x02 }, -+ [IT_VINLOW_F] = { .reg_offset = 3, .mask = 0x04 }, -+ [IT_VINLOW_R] = { .reg_offset = 3, .mask = 0x08 }, -+ [IT_SWIN_F] = { .reg_offset = 3, .mask = 0x40 }, -+ [IT_SWIN_R] = { .reg_offset = 3, .mask = 0x80 }, ++ REGMAP_IRQ_REG(IT_TWARN_F, 3, 0x01), ++ REGMAP_IRQ_REG(IT_TWARN_R, 3, 0x02), ++ REGMAP_IRQ_REG(IT_VINLOW_F, 3, 0x04), ++ REGMAP_IRQ_REG(IT_VINLOW_R, 3, 0x08), ++ REGMAP_IRQ_REG(IT_SWIN_F, 3, 0x40), ++ REGMAP_IRQ_REG(IT_SWIN_R, 3, 0x80), +}; + +static const struct regmap_irq_chip stpmic1_regmap_irq_chip = { @@ -1399,78 +1195,14 @@ index 0000000..648315d + return ddata->irq; + } + -+ if (of_property_read_bool(np, "wakeup-source")) -+ device_init_wakeup(dev, true); -+ -+ if (!of_property_read_u32(np, "st,main-control-register", ®)) { -+ ret = regmap_update_bits(ddata->regmap, -+ SWOFF_PWRCTRL_CR, -+ PWRCTRL_POLARITY_HIGH | -+ PWRCTRL_PIN_VALID | -+ RESTART_REQUEST_ENABLED, -+ reg); -+ if (ret) { -+ dev_err(dev, -+ "Failed to update main control register: %d\n", -+ ret); -+ return ret; -+ } -+ } -+ -+ /* Read Version ID */ + ret = regmap_read(ddata->regmap, VERSION_SR, ®); + if (ret) { -+ dev_err(dev, "Unable to read pmic version\n"); ++ dev_err(dev, "Unable to read PMIC version\n"); + return ret; + } + dev_info(dev, "PMIC Chip Version: 0x%x\n", reg); + -+ if (!of_property_read_u32(np, "st,pads-pull-register", ®)) { -+ ret = regmap_update_bits(ddata->regmap, -+ PADS_PULL_CR, -+ WAKEUP_DETECTOR_DISABLED | -+ PWRCTRL_PD_ACTIVE | -+ PWRCTRL_PU_ACTIVE | -+ WAKEUP_PD_ACTIVE, -+ reg); -+ if (ret) { -+ dev_err(dev, -+ "Failed to update pads control register: %d\n", -+ ret); -+ return ret; -+ } -+ } -+ -+ if (!of_property_read_u32(np, "st,vin-control-register", ®)) { -+ ret = regmap_update_bits(ddata->regmap, -+ VBUS_DET_VIN_CR, -+ VINLOW_CTRL_REG_MASK, -+ reg); -+ if (ret) { -+ dev_err(dev, -+ "Failed to update vin control register: %d\n", -+ ret); -+ return ret; -+ } -+ } -+ -+ if (!of_property_read_u32(np, "st,usb-control-register", ®)) { -+ ret = regmap_update_bits(ddata->regmap, BST_SW_CR, -+ BOOST_OVP_DISABLED | -+ VBUS_OTG_DETECTION_DISABLED | -+ SW_OUT_DISCHARGE | -+ VBUS_OTG_DISCHARGE | -+ OCP_LIMIT_HIGH, -+ reg); -+ if (ret) { -+ dev_err(dev, -+ "Failed to update usb control register: %d\n", -+ ret); -+ return ret; -+ } -+ } -+ -+ /* Initialize PMIC IRQ Chip & IRQ domains associated */ ++ /* Initialize PMIC IRQ Chip & associated IRQ domains */ + ret = devm_regmap_add_irq_chip(dev, ddata->regmap, ddata->irq, + IRQF_ONESHOT | IRQF_SHARED, + 0, &stpmic1_regmap_irq_chip, @@ -1483,13 +1215,6 @@ index 0000000..648315d + return devm_of_platform_populate(dev); +} + -+static const struct i2c_device_id stpmic1_id[] = { -+ { "stpmic1"}, -+ {} -+}; -+ -+MODULE_DEVICE_TABLE(i2c, stpmic1_id); -+ +#ifdef CONFIG_PM_SLEEP +static int stpmic1_suspend(struct device *dev) +{ @@ -1497,6 +1222,7 @@ index 0000000..648315d + struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c); + + disable_irq(pmic_dev->irq); ++ + if (device_may_wakeup(dev)) + enable_irq_wake(pmic_dev->irq); + @@ -1524,13 +1250,19 @@ index 0000000..648315d + +static SIMPLE_DEV_PM_OPS(stpmic1_pm, stpmic1_suspend, stpmic1_resume); + ++static const struct of_device_id stpmic1_of_match[] = { ++ { .compatible = "st,stpmic1", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, stpmic1_of_match); ++ +static struct i2c_driver stpmic1_driver = { + .driver = { + .name = "stpmic1", ++ .of_match_table = of_match_ptr(stpmic1_of_match), + .pm = &stpmic1_pm, + }, + .probe = stpmic1_probe, -+ .id_table = stpmic1_id, +}; + +module_i2c_driver(stpmic1_driver); @@ -1637,10 +1369,10 @@ index 22bd652..ab8f1d4 100644 #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 +index 0000000..321cd087 --- /dev/null +++ b/include/dt-bindings/mfd/st,stpmic1.h -@@ -0,0 +1,46 @@ +@@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -1686,24 +1418,105 @@ index 0000000..b2d6c83 +#define IT_SWIN_F 30 +#define IT_SWIN_R 31 + ++/* BUCK MODES definitions */ ++#define STPMIC1_BUCK_MODE_NORMAL 0 ++#define STPMIC1_BUCK_MODE_LP 2 ++ +#endif /* __DT_BINDINGS_STPMIC1_H__ */ diff --git a/include/linux/mfd/stmfx.h b/include/linux/mfd/stmfx.h new file mode 100644 -index 0000000..35c3d42 +index 0000000..3c67983 --- /dev/null +++ b/include/linux/mfd/stmfx.h -@@ -0,0 +1,27 @@ +@@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* -+ * Copyright (C) 2018 STMicroelectronics ++ * Copyright (C) 2019 STMicroelectronics + * Author(s): Amelie Delaunay . + */ + +#ifndef MFD_STMFX_H -+#define MFX_STMFX_H ++#define MFD_STMFX_H + +#include + ++/* General */ ++#define STMFX_REG_CHIP_ID 0x00 /* R */ ++#define STMFX_REG_FW_VERSION_MSB 0x01 /* R */ ++#define STMFX_REG_FW_VERSION_LSB 0x02 /* R */ ++#define STMFX_REG_SYS_CTRL 0x40 /* RW */ ++/* IRQ output management */ ++#define STMFX_REG_IRQ_OUT_PIN 0x41 /* RW */ ++#define STMFX_REG_IRQ_SRC_EN 0x42 /* RW */ ++#define STMFX_REG_IRQ_PENDING 0x08 /* R */ ++#define STMFX_REG_IRQ_ACK 0x44 /* RW */ ++/* GPIO management */ ++#define STMFX_REG_IRQ_GPI_PENDING1 0x0C /* R */ ++#define STMFX_REG_IRQ_GPI_PENDING2 0x0D /* R */ ++#define STMFX_REG_IRQ_GPI_PENDING3 0x0E /* R */ ++#define STMFX_REG_GPIO_STATE1 0x10 /* R */ ++#define STMFX_REG_GPIO_STATE2 0x11 /* R */ ++#define STMFX_REG_GPIO_STATE3 0x12 /* R */ ++#define STMFX_REG_IRQ_GPI_SRC1 0x48 /* RW */ ++#define STMFX_REG_IRQ_GPI_SRC2 0x49 /* RW */ ++#define STMFX_REG_IRQ_GPI_SRC3 0x4A /* RW */ ++#define STMFX_REG_IRQ_GPI_EVT1 0x4C /* RW */ ++#define STMFX_REG_IRQ_GPI_EVT2 0x4D /* RW */ ++#define STMFX_REG_IRQ_GPI_EVT3 0x4E /* RW */ ++#define STMFX_REG_IRQ_GPI_TYPE1 0x50 /* RW */ ++#define STMFX_REG_IRQ_GPI_TYPE2 0x51 /* RW */ ++#define STMFX_REG_IRQ_GPI_TYPE3 0x52 /* RW */ ++#define STMFX_REG_IRQ_GPI_ACK1 0x54 /* RW */ ++#define STMFX_REG_IRQ_GPI_ACK2 0x55 /* RW */ ++#define STMFX_REG_IRQ_GPI_ACK3 0x56 /* RW */ ++#define STMFX_REG_GPIO_DIR1 0x60 /* RW */ ++#define STMFX_REG_GPIO_DIR2 0x61 /* RW */ ++#define STMFX_REG_GPIO_DIR3 0x62 /* RW */ ++#define STMFX_REG_GPIO_TYPE1 0x64 /* RW */ ++#define STMFX_REG_GPIO_TYPE2 0x65 /* RW */ ++#define STMFX_REG_GPIO_TYPE3 0x66 /* RW */ ++#define STMFX_REG_GPIO_PUPD1 0x68 /* RW */ ++#define STMFX_REG_GPIO_PUPD2 0x69 /* RW */ ++#define STMFX_REG_GPIO_PUPD3 0x6A /* RW */ ++#define STMFX_REG_GPO_SET1 0x6C /* RW */ ++#define STMFX_REG_GPO_SET2 0x6D /* RW */ ++#define STMFX_REG_GPO_SET3 0x6E /* RW */ ++#define STMFX_REG_GPO_CLR1 0x70 /* RW */ ++#define STMFX_REG_GPO_CLR2 0x71 /* RW */ ++#define STMFX_REG_GPO_CLR3 0x72 /* RW */ ++ ++#define STMFX_REG_MAX 0xB0 ++ ++/* MFX boot time is around 10ms, so after reset, we have to wait this delay */ ++#define STMFX_BOOT_TIME_MS 10 ++ ++/* STMFX_REG_CHIP_ID bitfields */ ++#define STMFX_REG_CHIP_ID_MASK GENMASK(7, 0) ++ ++/* STMFX_REG_SYS_CTRL bitfields */ ++#define STMFX_REG_SYS_CTRL_GPIO_EN BIT(0) ++#define STMFX_REG_SYS_CTRL_TS_EN BIT(1) ++#define STMFX_REG_SYS_CTRL_IDD_EN BIT(2) ++#define STMFX_REG_SYS_CTRL_ALTGPIO_EN BIT(3) ++#define STMFX_REG_SYS_CTRL_SWRST BIT(7) ++ ++/* STMFX_REG_IRQ_OUT_PIN bitfields */ ++#define STMFX_REG_IRQ_OUT_PIN_TYPE BIT(0) /* 0-OD 1-PP */ ++#define STMFX_REG_IRQ_OUT_PIN_POL BIT(1) /* 0-active LOW 1-active HIGH */ ++ ++/* STMFX_REG_IRQ_(SRC_EN/PENDING/ACK) bit shift */ ++enum stmfx_irqs { ++ STMFX_REG_IRQ_SRC_EN_GPIO = 0, ++ STMFX_REG_IRQ_SRC_EN_IDD, ++ STMFX_REG_IRQ_SRC_EN_ERROR, ++ STMFX_REG_IRQ_SRC_EN_TS_DET, ++ STMFX_REG_IRQ_SRC_EN_TS_NE, ++ STMFX_REG_IRQ_SRC_EN_TS_TH, ++ STMFX_REG_IRQ_SRC_EN_TS_FULL, ++ STMFX_REG_IRQ_SRC_EN_TS_OVF, ++ STMFX_REG_IRQ_SRC_MAX, ++}; ++ +enum stmfx_functions { + STMFX_FUNC_GPIO = BIT(0), /* GPIO[15:0] */ + STMFX_FUNC_ALTGPIO_LOW = BIT(1), /* aGPIO[3:0] */ @@ -1712,9 +1525,28 @@ index 0000000..35c3d42 + STMFX_FUNC_IDD = BIT(4), +}; + ++/** ++ * struct stmfx_ddata - STMFX MFD structure ++ * @device: device reference used for logs ++ * @map: register map ++ * @vdd: STMFX power supply ++ * @irq_domain: IRQ domain ++ * @lock: IRQ bus lock ++ * @irq_src: cache of IRQ_SRC_EN register for bus_lock ++ * @bkp_sysctrl: backup of SYS_CTRL register for suspend/resume ++ * @bkp_irqoutpin: backup of IRQ_OUT_PIN register for suspend/resume ++ */ +struct stmfx { + struct device *dev; + struct regmap *map; ++ struct regulator *vdd; ++ struct irq_domain *irq_domain; ++ struct mutex lock; /* IRQ bus lock */ ++ u8 irq_src; ++#ifdef CONFIG_PM ++ u8 bkp_sysctrl; ++ u8 bkp_irqoutpin; ++#endif +}; + +int stmfx_function_enable(struct stmfx *stmfx, u32 func); diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0014-ARM-stm32mp1-r2-MMC-MTD.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0014-ARM-stm32mp1-r2-MMC-MTD.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch index 2f1cc29..22202c4 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0014-ARM-stm32mp1-r2-MMC-MTD.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch @@ -1,22 +1,22 @@ -From ae70b2603fb4622389c5b26d5214a2f6879714e9 Mon Sep 17 00:00:00 2001 +From 1549511bd55cdcfccdaded1d1e1b0e7e68adc8bb 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 +Date: Fri, 8 Nov 2019 16:52:42 +0100 +Subject: [PATCH 15/31] ARM stm32mp1 r3 MMC MTD --- drivers/mmc/host/Kconfig | 10 + drivers/mmc/host/Makefile | 1 + - drivers/mmc/host/mmci.c | 900 ++++++++++---- - drivers/mmc/host/mmci.h | 195 +++- + drivers/mmc/host/mmci.c | 862 ++++++++++---- + drivers/mmc/host/mmci.h | 189 ++- drivers/mmc/host/mmci_qcom_dml.c | 17 +- drivers/mmc/host/mmci_stm32_sdmmc.c | 429 +++++++ drivers/mtd/nand/raw/Kconfig | 9 + drivers/mtd/nand/raw/Makefile | 1 + - drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2005 ++++++++++++++++++++++++++++++++ + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2041 ++++++++++++++++++++++++++++++++ drivers/mtd/spi-nor/Kconfig | 7 - drivers/mtd/spi-nor/Makefile | 1 - - drivers/mtd/spi-nor/stm32-quadspi.c | 720 ------------ - 12 files changed, 3277 insertions(+), 1018 deletions(-) + drivers/mtd/spi-nor/stm32-quadspi.c | 720 ----------- + 12 files changed, 3285 insertions(+), 1002 deletions(-) create mode 100644 drivers/mmc/host/mmci_stm32_sdmmc.c create mode 100644 drivers/mtd/nand/raw/stm32_fmc2_nand.c delete mode 100644 drivers/mtd/spi-nor/stm32-quadspi.c @@ -55,7 +55,7 @@ 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..0b7b607 100644 +index fa6268c..1c6b5d0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -14,6 +14,7 @@ @@ -619,17 +619,17 @@ index 1841d250..0b7b607 100644 { const char *rxname, *txname; + struct mmci_dmae_priv *dmae; - -- host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); -- host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); ++ + dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL); + if (!dmae) + return -ENOMEM; +- host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); +- host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); ++ host->dma_priv = dmae; + - /* initialize pre request cookie */ - host->next_data.cookie = 1; -+ host->dma_priv = dmae; -+ + dmae->rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), + "rx"); + dmae->tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), @@ -740,7 +740,7 @@ index 1841d250..0b7b607 100644 -static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +void mmci_dmae_error(struct mmci_host *host) -+{ + { + struct mmci_dmae_priv *dmae = host->dma_priv; + + if (!dma_inprogress(host)) @@ -757,7 +757,7 @@ index 1841d250..0b7b607 100644 +} + +void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data) - { ++{ + struct mmci_dmae_priv *dmae = host->dma_priv; u32 status; int i; @@ -844,20 +844,20 @@ index 1841d250..0b7b607 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 int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +-static inline int mmci_dma_prep_next(struct mmci_host *host, +- struct mmc_data *data) +int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) { +- struct mmci_host_next *nd = &host->next_data; +- return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc); +-} +- +-static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +-{ - int ret; + struct mmci_dmae_priv *dmae = host->dma_priv; struct mmc_data *data = host->data; @@ -1149,25 +1149,7 @@ index 1841d250..0b7b607 100644 if (/*interrupt*/0) c |= MCI_CPSM_INTERRUPT; -@@ -895,21 +1215,22 @@ static void - mmci_data_irq(struct mmci_host *host, struct mmc_data *data, - unsigned int status) - { -+ unsigned int status_err; -+ - /* Make sure we have data to handle */ - if (!data) - return; - - /* First check for errors */ -- if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | -- host->variant->start_err | -- MCI_TXUNDERRUN | MCI_RXOVERRUN)) { -+ status_err = status & (host->variant->start_err | -+ MCI_DATACRCFAIL | MCI_DATATIMEOUT | -+ MCI_TXUNDERRUN | MCI_RXOVERRUN); -+ -+ if (status_err) { +@@ -910,10 +1230,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, u32 remain, success; /* Terminate the DMA transfer */ @@ -1179,7 +1161,7 @@ index 1841d250..0b7b607 100644 /* * Calculate how far we are into the transfer. Note that -@@ -918,22 +1239,26 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, +@@ -922,8 +1239,12 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, * can be as much as a FIFO-worth of data ahead. This * matters for FIFO overruns only. */ @@ -1193,28 +1175,8 @@ index 1841d250..0b7b607 100644 + } dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n", -- status, success); -- if (status & MCI_DATACRCFAIL) { -+ status_err, success); -+ if (status_err & MCI_DATACRCFAIL) { - /* Last block was not successful */ - success -= 1; - data->error = -EILSEQ; -- } else if (status & MCI_DATATIMEOUT) { -+ } else if (status_err & MCI_DATATIMEOUT) { - data->error = -ETIMEDOUT; -- } else if (status & MCI_STARTBITERR) { -+ } else if (status_err & MCI_STARTBITERR) { - data->error = -ECOMM; -- } else if (status & MCI_TXUNDERRUN) { -+ } else if (status_err & MCI_TXUNDERRUN) { - data->error = -EIO; -- } else if (status & MCI_RXOVERRUN) { -+ } else if (status_err & MCI_RXOVERRUN) { - if (success > host->variant->fifosize) - success -= host->variant->fifosize; - else -@@ -947,19 +1272,18 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, + status_err, success); +@@ -951,19 +1272,18 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); if (status & MCI_DATAEND || data->error) { @@ -1238,7 +1200,7 @@ index 1841d250..0b7b607 100644 } } -@@ -968,11 +1292,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -972,11 +1292,13 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, unsigned int status) { void __iomem *base = host->base; @@ -1253,7 +1215,7 @@ index 1841d250..0b7b607 100644 sbc = (cmd == host->mrq->sbc); /* -@@ -980,18 +1306,21 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -984,18 +1306,21 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, * handling. Note that we tag on any latent IRQs postponed * due to waiting for busy status. */ @@ -1279,7 +1241,7 @@ index 1841d250..0b7b607 100644 (status & host->variant->busy_detect_flag)) return; -@@ -1001,9 +1330,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -1005,9 +1330,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, * that the special busy status bit is still set before * proceeding. */ @@ -1292,7 +1254,7 @@ index 1841d250..0b7b607 100644 /* Clear the busy start IRQ */ writel(host->variant->busy_detect_mask, -@@ -1045,6 +1374,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -1049,6 +1374,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, cmd->error = -ETIMEDOUT; } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { cmd->error = -EILSEQ; @@ -1302,7 +1264,7 @@ index 1841d250..0b7b607 100644 } else { cmd->resp[0] = readl(base + MMCIRESPONSE0); cmd->resp[1] = readl(base + MMCIRESPONSE1); -@@ -1055,16 +1387,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, +@@ -1059,16 +1387,15 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, if ((!sbc && !cmd->data) || cmd->error) { if (host->data) { /* Terminate the DMA transfer */ @@ -1323,22 +1285,7 @@ index 1841d250..0b7b607 100644 mmci_start_data(host, cmd->data); } } -@@ -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) +@@ -1268,7 +1595,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) if (status & host->mask1_reg) mmci_pio_irq(irq, dev_id); @@ -1347,7 +1294,7 @@ index 1841d250..0b7b607 100644 } /* -@@ -1277,7 +1611,8 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) +@@ -1281,7 +1608,8 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) * to make sure that both start and end interrupts are always * cleared one after the other. */ @@ -1357,26 +1304,7 @@ index 1841d250..0b7b607 100644 if (host->variant->busy_detect) writel(status & ~host->variant->busy_detect_mask, host->base + MMCICLEAR); -@@ -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; -+ - } while (status); - - spin_unlock(&host->lock); -@@ -1328,7 +1667,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) +@@ -1333,7 +1661,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) if (mrq->data) mmci_get_next_data(host, mrq->data); @@ -1386,7 +1314,7 @@ index 1841d250..0b7b607 100644 mmci_start_data(host, mrq->data); if (mrq->sbc) -@@ -1438,8 +1778,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +@@ -1443,8 +1772,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); @@ -1405,7 +1333,7 @@ index 1841d250..0b7b607 100644 mmci_reg_delay(host); spin_unlock_irqrestore(&host->lock, flags); -@@ -1462,6 +1810,8 @@ static int mmci_get_cd(struct mmc_host *mmc) +@@ -1467,6 +1804,8 @@ static int mmci_get_cd(struct mmc_host *mmc) static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -1414,7 +1342,7 @@ index 1841d250..0b7b607 100644 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) +@@ -1479,6 +1818,28 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) case MMC_SIGNAL_VOLTAGE_180: ret = regulator_set_voltage(mmc->supply.vqmmc, 1700000, 1950000); @@ -1443,7 +1371,7 @@ index 1841d250..0b7b607 100644 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) +@@ -1493,6 +1854,16 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) return ret; } @@ -1460,7 +1388,7 @@ index 1841d250..0b7b607 100644 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 = { +@@ -1501,6 +1872,7 @@ static struct mmc_host_ops mmci_ops = { .get_ro = mmc_gpio_get_ro, .get_cd = mmci_get_cd, .start_signal_voltage_switch = mmci_sig_volt_switch, @@ -1468,7 +1396,7 @@ index 1841d250..0b7b607 100644 }; 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) +@@ -1523,6 +1895,12 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) host->pwr_reg_add |= MCI_ST_CMDDIREN; if (of_get_property(np, "st,sig-pin-fbclk", NULL)) host->pwr_reg_add |= MCI_ST_FBCLKEN; @@ -1481,7 +1409,7 @@ index 1841d250..0b7b607 100644 if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) mmc->caps |= MMC_CAP_MMC_HIGHSPEED; -@@ -1644,6 +2033,8 @@ static int mmci_probe(struct amba_device *dev, +@@ -1649,6 +2027,8 @@ static int mmci_probe(struct amba_device *dev, */ if (variant->st_clkdiv) mmc->f_min = DIV_ROUND_UP(host->mclk, 257); @@ -1490,7 +1418,7 @@ index 1841d250..0b7b607 100644 else if (variant->explicit_mclk_control) mmc->f_min = clk_round_rate(host->clk, 100000); else -@@ -1665,6 +2056,12 @@ static int mmci_probe(struct amba_device *dev, +@@ -1670,6 +2050,12 @@ static int mmci_probe(struct amba_device *dev, dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); @@ -1503,7 +1431,7 @@ index 1841d250..0b7b607 100644 /* Get regulators and the supported OCR mask */ ret = mmc_regulator_get_supply(mmc); if (ret) -@@ -1675,12 +2072,7 @@ static int mmci_probe(struct amba_device *dev, +@@ -1680,12 +2066,7 @@ static int mmci_probe(struct amba_device *dev, else if (plat->ocr_mask) dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); @@ -1517,7 +1445,7 @@ index 1841d250..0b7b607 100644 /* We support these capabilities. */ mmc->caps |= MMC_CAP_CMD23; -@@ -1689,6 +2081,8 @@ static int mmci_probe(struct amba_device *dev, +@@ -1694,6 +2075,8 @@ static int mmci_probe(struct amba_device *dev, * Enable busy detection. */ if (variant->busy_detect) { @@ -1526,7 +1454,7 @@ index 1841d250..0b7b607 100644 mmci_ops.card_busy = mmci_card_busy; /* * Not all variants have a flag to enable busy detection -@@ -1698,7 +2092,18 @@ static int mmci_probe(struct amba_device *dev, +@@ -1703,7 +2086,18 @@ static int mmci_probe(struct amba_device *dev, mmci_write_datactrlreg(host, host->variant->busy_dpsm_flag); mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; @@ -1546,7 +1474,7 @@ index 1841d250..0b7b607 100644 } mmc->ops = &mmci_ops; -@@ -1727,13 +2132,13 @@ static int mmci_probe(struct amba_device *dev, +@@ -1732,13 +2126,13 @@ static int mmci_probe(struct amba_device *dev, /* * Block size can be up to 2048 bytes, but must be a power of two. */ @@ -1562,7 +1490,7 @@ index 1841d250..0b7b607 100644 spin_lock_init(&host->lock); -@@ -1749,30 +2154,16 @@ static int mmci_probe(struct amba_device *dev, +@@ -1754,30 +2148,16 @@ static int mmci_probe(struct amba_device *dev, * - not using DT but using a descriptor table, or * - using a table of descriptors ALONGSIDE DT, or * look up these descriptors named "cd" and "wp" right here, fail @@ -1598,26 +1526,7 @@ index 1841d250..0b7b607 100644 } ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED, -@@ -1789,7 +2180,7 @@ static int mmci_probe(struct amba_device *dev, - goto clk_disable; - } - -- writel(MCI_IRQENABLE, host->base + MMCIMASK0); -+ writel(MCI_IRQENABLE | variant->start_err, host->base + MMCIMASK0); - - amba_set_drvdata(dev, mmc); - -@@ -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); - } -- writel(MCI_IRQENABLE, host->base + MMCIMASK0); -+ writel(MCI_IRQENABLE | host->variant->start_err, -+ host->base + MMCIMASK0); - mmci_reg_delay(host); - - spin_unlock_irqrestore(&host->lock, flags); -@@ -1971,6 +2363,16 @@ static const struct amba_id mmci_ids[] = { +@@ -1977,6 +2357,16 @@ static const struct amba_id mmci_ids[] = { .mask = 0x00ffffff, .data = &variant_stm32, }, @@ -1635,7 +1544,7 @@ index 1841d250..0b7b607 100644 { .id = 0x00051180, diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h -index 517591d..e10093e 100644 +index 613d37a..e10093e 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -23,6 +23,14 @@ @@ -1745,12 +1654,9 @@ index 517591d..e10093e 100644 +#define MMCI_STM32_IDMABAR 0x68 + #define MCI_IRQENABLE \ -- (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \ -- MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \ -- MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK) -+ (MCI_CMDCRCFAILMASK | MCI_DATACRCFAILMASK | MCI_CMDTIMEOUTMASK | \ -+ MCI_DATATIMEOUTMASK | MCI_TXUNDERRUNMASK | MCI_RXOVERRUNMASK | \ -+ MCI_CMDRESPENDMASK | MCI_CMDSENTMASK) + (MCI_CMDCRCFAILMASK | MCI_DATACRCFAILMASK | MCI_CMDTIMEOUTMASK | \ + MCI_DATATIMEOUTMASK | MCI_TXUNDERRUNMASK | MCI_RXOVERRUNMASK | \ + MCI_CMDRESPENDMASK | MCI_CMDSENTMASK) /* These interrupts are directed to IRQ1 when two IRQ lines are available */ -#define MCI_IRQ1MASK \ @@ -2486,10 +2392,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..aaaad34 +index 0000000..ce1a15a --- /dev/null +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c -@@ -0,0 +1,2005 @@ +@@ -0,0 +1,2041 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 @@ -2543,6 +2449,8 @@ index 0000000..aaaad34 +#define FMC2_PMEM 0x88 +#define FMC2_PATT 0x8c +#define FMC2_HECCR 0x94 ++#define FMC2_ISR 0x184 ++#define FMC2_ICR 0x188 +#define FMC2_CSQCR 0x200 +#define FMC2_CSQCFGR1 0x204 +#define FMC2_CSQCFGR2 0x208 @@ -2608,6 +2516,12 @@ index 0000000..aaaad34 +#define FMC2_PATT_ATTHIZ(x) (((x) & 0xff) << 24) +#define FMC2_PATT_DEFAULT 0x0a0a0a0a + ++/* Register: FMC2_ISR */ ++#define FMC2_ISR_IHLF BIT(1) ++ ++/* Register: FMC2_ICR */ ++#define FMC2_ICR_CIHLF BIT(1) ++ +/* Register: FMC2_CSQCR */ +#define FMC2_CSQCR_CSQSTART BIT(0) + @@ -3653,6 +3567,34 @@ index 0000000..aaaad34 + stm32_fmc2_set_buswidth_16(fmc2, true); +} + ++static int stm32_fmc2_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) ++{ ++ struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ const struct nand_sdr_timings *timings; ++ int ret; ++ u32 isr, sr; ++ ++ /* Check if there is no pending requests to the NAND flash */ ++ ret = readl_relaxed_poll_timeout(fmc2->io_base + FMC2_SR, ++ sr, sr & FMC2_SR_NWRF, 1, 1000); ++ if (ret) { ++ dev_err(fmc2->dev, "Waitrdy timeout\n"); ++ return ret; ++ } ++ ++ /* Wait tWB before R/B# signal is low */ ++ timings = nand_get_sdr_timings(&chip->data_interface); ++ ndelay(PSEC_TO_NSEC(timings->tWB_max)); ++ ++ /* R/B# signal is low, clear high level flag */ ++ writel_relaxed(FMC2_ICR_CIHLF, fmc2->io_base + FMC2_ICR); ++ ++ /* Wait R/B# signal is high */ ++ return readl_relaxed_poll_timeout(fmc2->io_base + FMC2_ISR, ++ isr, isr & FMC2_ISR_IHLF, ++ 1, 1000 * timeout_ms); ++} ++ +static int stm32_fmc2_exec_op(struct nand_chip *chip, + const struct nand_operation *op, + bool check_only) @@ -3693,8 +3635,8 @@ index 0000000..aaaad34 + break; + + case NAND_OP_WAITRDY_INSTR: -+ ret = nand_soft_waitrdy(chip, -+ instr->ctx.waitrdy.timeout_ms); ++ ret = stm32_fmc2_waitrdy(chip, ++ instr->ctx.waitrdy.timeout_ms); + break; + } + } 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.94/0016-ARM-stm32mp1-r3-NET.patch similarity index 91% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0015-ARM-stm32mp1-r2-NET.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0016-ARM-stm32mp1-r3-NET.patch index 090ba56..ac1b651 100644 --- 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.94/0016-ARM-stm32mp1-r3-NET.patch @@ -1,20 +1,34 @@ -From edca8bc73b6a7e2057b821cc41e68fe3d7c0bb03 Mon Sep 17 00:00:00 2001 +From 61b384e5eaed6c1ef9342e7216ffd2376e0f611d 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 +Date: Fri, 8 Nov 2019 16:52:43 +0100 +Subject: [PATCH 16/31] ARM stm32mp1 r3 NET --- - drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 166 +++++++++++++++++---- + drivers/net/ethernet/stmicro/stmmac/common.h | 2 +- + drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c | 167 +++++++++++++++++---- drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 45 +++++- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 3 + .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 + .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 5 + .../net/wireless/broadcom/brcm80211/brcmutil/d11.c | 3 - - 7 files changed, 189 insertions(+), 41 deletions(-) + 8 files changed, 191 insertions(+), 42 deletions(-) +diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h +index b069b3a..272b9ca6 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/common.h ++++ b/drivers/net/ethernet/stmicro/stmmac/common.h +@@ -261,7 +261,7 @@ struct stmmac_safety_stats { + #define STMMAC_COAL_TX_TIMER 1000 + #define STMMAC_MAX_COAL_TX_TICK 100000 + #define STMMAC_TX_MAX_FRAMES 256 +-#define STMMAC_TX_FRAMES 1 ++#define STMMAC_TX_FRAMES 25 + + /* Packets types */ + enum packets_types { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -index 7e2e79d..6e260e9 100644 +index 7e2e79d..dd45026 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -25,9 +25,24 @@ @@ -178,13 +192,13 @@ index 7e2e79d..6e260e9 100644 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, +@@ -232,35 +304,65 @@ static int stm32_dwmac_parse_data(struct stm32_dwmac *dwmac, static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct device_node *np = dev->of_node; -+ int err = 0; ++ int err; - dwmac->int_phyclk = of_property_read_bool(np, "st,int-phyclk"); + /* Gigabit Ethernet 125MHz clock selection. */ @@ -231,6 +245,7 @@ index 7e2e79d..6e260e9 100644 } - return 0; ++ err = 0; + /* Get IRQ information early to have an ability to ask for deferred + * probe if needed before we went too far with resource allocation. + */ @@ -257,7 +272,7 @@ index 7e2e79d..6e260e9 100644 } static int stm32_dwmac_probe(struct platform_device *pdev) -@@ -326,9 +427,15 @@ static int stm32_dwmac_remove(struct platform_device *pdev) +@@ -326,9 +428,15 @@ static int stm32_dwmac_remove(struct platform_device *pdev) struct net_device *ndev = platform_get_drvdata(pdev); struct stmmac_priv *priv = netdev_priv(ndev); int ret = stmmac_dvr_remove(&pdev->dev); @@ -273,7 +288,7 @@ index 7e2e79d..6e260e9 100644 return ret; } -@@ -341,8 +448,9 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac) +@@ -341,8 +449,9 @@ static int stm32mp1_suspend(struct stm32_dwmac *dwmac) return ret; clk_disable_unprepare(dwmac->clk_tx); @@ -299,7 +314,7 @@ index 49f5687..5b35071 100644 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 +index 014fe93..ccb512f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2713,6 +2713,8 @@ static int stmmac_release(struct net_device *dev) @@ -320,7 +335,7 @@ index 50c0082..1df9027 100644 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) +@@ -4501,14 +4501,13 @@ int stmmac_suspend(struct device *dev) if (!ndev || !netif_running(ndev)) return 0; @@ -337,7 +352,7 @@ index 50c0082..1df9027 100644 stmmac_disable_all_queues(priv); /* Stop TX/RX DMA */ -@@ -4514,6 +4513,10 @@ int stmmac_suspend(struct device *dev) +@@ -4532,6 +4531,10 @@ int stmmac_suspend(struct device *dev) priv->oldlink = false; priv->speed = SPEED_UNKNOWN; priv->oldduplex = DUPLEX_UNKNOWN; @@ -348,7 +363,7 @@ index 50c0082..1df9027 100644 return 0; } EXPORT_SYMBOL_GPL(stmmac_suspend); -@@ -4554,6 +4557,7 @@ int stmmac_resume(struct device *dev) +@@ -4572,6 +4575,7 @@ int stmmac_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct stmmac_priv *priv = netdev_priv(ndev); @@ -356,7 +371,14 @@ index 50c0082..1df9027 100644 if (!netif_running(ndev)) return 0; -@@ -4585,7 +4589,28 @@ int stmmac_resume(struct device *dev) +@@ -4601,11 +4605,32 @@ int stmmac_resume(struct device *dev) + + netif_device_attach(ndev); + ++ if (ndev->phydev) ++ phy_start(ndev->phydev); ++ + mutex_lock(&priv->lock); stmmac_reset_queues_param(priv); @@ -380,13 +402,10 @@ index 50c0082..1df9027 100644 + __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) +@@ -4617,10 +4642,14 @@ int stmmac_resume(struct device *dev) mutex_unlock(&priv->lock); diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0016-ARM-stm32mp1-r2-NVMEM.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch similarity index 85% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0016-ARM-stm32mp1-r2-NVMEM.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch index a6049dc..266f60f 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0016-ARM-stm32mp1-r2-NVMEM.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch @@ -1,15 +1,15 @@ -From 7a1e0bedb3066a32ff522e25daacd490d306ea40 Mon Sep 17 00:00:00 2001 +From a658fa1ee69e4b233cde37442c25523238b0d001 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 +Date: Fri, 8 Nov 2019 16:52:43 +0100 +Subject: [PATCH 17/31] ARM stm32mp1 r3 NVMEM --- drivers/nvmem/Kconfig | 10 ++ drivers/nvmem/Makefile | 2 + - drivers/nvmem/core.c | 37 ++++++++ + drivers/nvmem/core.c | 74 +++++++++++++++ drivers/nvmem/stm32-romem.c | 203 +++++++++++++++++++++++++++++++++++++++++ - include/linux/nvmem-consumer.h | 7 ++ - 5 files changed, 259 insertions(+) + include/linux/nvmem-consumer.h | 14 +++ + 5 files changed, 303 insertions(+) create mode 100644 drivers/nvmem/stm32-romem.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig @@ -47,10 +47,10 @@ index 4e8c616..e85c946 100644 obj-$(CONFIG_UNIPHIER_EFUSE) += nvmem-uniphier-efuse.o nvmem-uniphier-efuse-y := uniphier-efuse.o diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c -index 7c530c8..60dacd7 100644 +index 30c0407..e5808b8f 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c -@@ -1234,6 +1234,43 @@ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) +@@ -1246,6 +1246,80 @@ int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); /** @@ -90,6 +90,43 @@ index 7c530c8..60dacd7 100644 +} +EXPORT_SYMBOL_GPL(nvmem_cell_read_u16); + ++/** ++ * nvmem_cell_read_u8() - Read a cell value as an u8 ++ * ++ * @dev: Device that requests the nvmem cell. ++ * @cell_id: Name of nvmem cell to read. ++ * @val: pointer to output value. ++ * ++ * Return: 0 on success or negative errno. ++ */ ++int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val) ++{ ++ struct nvmem_cell *cell; ++ void *buf; ++ size_t len; ++ ++ cell = nvmem_cell_get(dev, cell_id); ++ if (IS_ERR(cell)) ++ return PTR_ERR(cell); ++ ++ buf = nvmem_cell_read(cell, &len); ++ if (IS_ERR(buf)) { ++ nvmem_cell_put(cell); ++ return PTR_ERR(buf); ++ } ++ if (len != sizeof(*val)) { ++ kfree(buf); ++ nvmem_cell_put(cell); ++ return -EINVAL; ++ } ++ memcpy(val, buf, sizeof(*val)); ++ kfree(buf); ++ nvmem_cell_put(cell); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nvmem_cell_read_u8); ++ +/** * nvmem_device_cell_read() - Read a given nvmem device and cell * @@ -304,18 +341,19 @@ index 0000000..34b388c +MODULE_ALIAS("platform:nvmem-stm32-romem"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h -index 4e85447..f303008 100644 +index 4e85447..c97f1e9 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h -@@ -39,6 +39,7 @@ void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); +@@ -39,6 +39,8 @@ void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val); +int nvmem_cell_read_u16(struct device *dev, const char *cell_id, u16 *val); ++int nvmem_cell_read_u8(struct device *dev, const char *cell_id, u8 *val); /* direct nvmem device read/write interface */ struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); -@@ -95,6 +96,12 @@ static inline int nvmem_cell_read_u32(struct device *dev, +@@ -95,6 +97,18 @@ static inline int nvmem_cell_read_u32(struct device *dev, return -ENOSYS; } @@ -324,6 +362,12 @@ index 4e85447..f303008 100644 +{ + return -ENOSYS; +} ++ ++static inline int nvmem_cell_read_u8(struct device *dev, ++ const char *cell_id, u8 *val) ++{ ++ return -EOPNOTSUPP; ++} + static inline struct nvmem_device *nvmem_device_get(struct device *dev, const char *name) 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.94/0018-ARM-stm32mp1-r3-PERF.patch similarity index 98% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0017-ARM-stm32mp1-r2-PERF.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch index 2590c9f..74c1af4 100644 --- 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.94/0018-ARM-stm32mp1-r3-PERF.patch @@ -1,7 +1,7 @@ -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 +From 6b4eeb6fe243c0c077a9b9ce4f631a5310f7b058 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Fri, 8 Nov 2019 16:52:43 +0100 +Subject: [PATCH 18/31] ARM stm32mp1 r3 PERF --- Documentation/perf/stm32-ddr-pmu.txt | 41 +++ diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0018-ARM-stm32mp1-r2-PHY-PINCTRL-PWM.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0018-ARM-stm32mp1-r2-PHY-PINCTRL-PWM.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch index 1640815..636541d 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0018-ARM-stm32mp1-r2-PHY-PINCTRL-PWM.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch @@ -1,23 +1,23 @@ -From 6c5c0debff2505c77c0d9545da09ac4b311619d4 Mon Sep 17 00:00:00 2001 +From 65b46b4c2bf2b5d86f210f337e1ca8471034019c 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 +Date: Fri, 8 Nov 2019 16:52:44 +0100 +Subject: [PATCH 19/31] ARM stm32mp1 r3 PHY PINCTRL PWM --- drivers/phy/st/phy-stm32-usbphyc.c | 451 +++++++++-- - drivers/pinctrl/Kconfig | 12 + + drivers/pinctrl/Kconfig | 14 + drivers/pinctrl/Makefile | 1 + 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/pinctrl-stmfx.c | 858 +++++++++++++++++++++ + drivers/pinctrl/stm32/pinctrl-stm32.c | 435 +++++++++-- + drivers/pinctrl/stm32/pinctrl-stm32.h | 53 +- drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1095 ++++++++++++++++----------- - drivers/pwm/pwm-stm32-lp.c | 44 ++ + drivers/pwm/pwm-stm32-lp.c | 38 + drivers/pwm/pwm-stm32.c | 105 ++- - drivers/pwm/sysfs.c | 12 +- - include/dt-bindings/pinctrl/stm32-pinfunc.h | 6 + + drivers/pwm/sysfs.c | 11 + + include/dt-bindings/pinctrl/stm32-pinfunc.h | 7 + include/linux/pinctrl/pinctrl.h | 7 + - 13 files changed, 2481 insertions(+), 616 deletions(-) + 13 files changed, 2498 insertions(+), 605 deletions(-) create mode 100644 drivers/pinctrl/pinctrl-stmfx.c diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c @@ -636,15 +636,17 @@ index 1255cd1..c9c3c3e 100644 }; module_platform_driver(stm32_usbphyc_driver); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig -index e86752b..bbd3908 100644 +index e86752b..70ea304 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig -@@ -244,6 +244,18 @@ config PINCTRL_ST +@@ -244,6 +244,20 @@ config PINCTRL_ST select PINCONF select GPIOLIB_IRQCHIP +config PINCTRL_STMFX + tristate "STMicroelectronics STMFX GPIO expander pinctrl driver" ++ depends on I2C ++ depends on OF_GPIO + select GENERIC_PINCONF + select GPIOLIB_IRQCHIP + select MFD_STMFX @@ -735,15 +737,15 @@ index c6ff4d5..7e747ac 100644 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..327c00d +index 0000000..b4c232a --- /dev/null +++ b/drivers/pinctrl/pinctrl-stmfx.c -@@ -0,0 +1,832 @@ +@@ -0,0 +1,858 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander + * -+ * Copyright (C) 2018 STMicroelectronics ++ * Copyright (C) 2019 STMicroelectronics + * Author(s): Amelie Delaunay . + */ +#include @@ -759,30 +761,27 @@ index 0000000..327c00d + +/* GPIOs expander */ +/* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */ -+#define STMFX_REG_GPIO_STATE 0x10 /* R */ ++#define STMFX_REG_GPIO_STATE STMFX_REG_GPIO_STATE1 /* R */ +/* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */ -+#define STMFX_REG_GPIO_DIR 0x60 /* RW */ ++#define STMFX_REG_GPIO_DIR STMFX_REG_GPIO_DIR1 /* RW */ +/* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */ -+#define STMFX_REG_GPIO_TYPE 0x64 /* RW */ ++#define STMFX_REG_GPIO_TYPE STMFX_REG_GPIO_TYPE1 /* RW */ +/* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */ -+#define STMFX_REG_GPIO_PUPD 0x68 /* RW */ ++#define STMFX_REG_GPIO_PUPD STMFX_REG_GPIO_PUPD1 /* RW */ +/* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */ -+#define STMFX_REG_GPO_SET 0x6C /* RW */ ++#define STMFX_REG_GPO_SET STMFX_REG_GPO_SET1 /* RW */ +/* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */ -+#define STMFX_REG_GPO_CLR 0x70 /* RW */ ++#define STMFX_REG_GPO_CLR STMFX_REG_GPO_CLR1 /* RW */ +/* IRQ_GPI_SRC1 0x48, IRQ_GPI_SRC2 0x49, IRQ_GPI_SRC3 0x4A */ -+#define STMFX_REG_IRQ_GPI_SRC 0x48 /* RW */ ++#define STMFX_REG_IRQ_GPI_SRC STMFX_REG_IRQ_GPI_SRC1 /* RW */ +/* IRQ_GPI_EVT1 0x4C, IRQ_GPI_EVT2 0x4D, IRQ_GPI_EVT3 0x4E */ -+#define STMFX_REG_IRQ_GPI_EVT 0x4C /* RW */ ++#define STMFX_REG_IRQ_GPI_EVT STMFX_REG_IRQ_GPI_EVT1 /* RW */ +/* IRQ_GPI_TYPE1 0x50, IRQ_GPI_TYPE2 0x51, IRQ_GPI_TYPE3 0x52 */ -+#define STMFX_REG_IRQ_GPI_TYPE 0x50 /* RW */ ++#define STMFX_REG_IRQ_GPI_TYPE STMFX_REG_IRQ_GPI_TYPE1 /* RW */ +/* IRQ_GPI_PENDING1 0x0C, IRQ_GPI_PENDING2 0x0D, IRQ_GPI_PENDING3 0x0E*/ -+#define STMFX_REG_IRQ_GPI_PENDING 0x0C /* R */ ++#define STMFX_REG_IRQ_GPI_PENDING STMFX_REG_IRQ_GPI_PENDING1 /* R */ +/* IRQ_GPI_ACK1 0x54, IRQ_GPI_ACK2 0x55, IRQ_GPI_ACK3 0x56 */ -+#define STMFX_REG_IRQ_GPI_ACK 0x54 /* RW */ -+ -+/* STMFX_REG_IRQ_PENDING bitfields */ -+#define STMFX_REG_IRQ_PENDING_GPIO BIT(0) ++#define STMFX_REG_IRQ_GPI_ACK STMFX_REG_IRQ_GPI_ACK1 /* RW */ + +#define NR_GPIO_REGS 3 +#define NR_GPIOS_PER_REG 8 @@ -957,9 +956,8 @@ index 0000000..327c00d + struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + u32 param = pinconf_to_config_param(*config); + struct pinctrl_gpio_range *range; -+ int dir, type, pupd; + u32 arg = 0; -+ int ret; ++ int ret, dir, type, pupd; + + range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); + if (!range) @@ -1182,7 +1180,7 @@ index 0000000..327c00d + u32 reg = get_reg(data->hwirq); + u32 mask = get_mask(data->hwirq); + -+ if (type & IRQ_TYPE_NONE) ++ if (type == IRQ_TYPE_NONE) + return -EINVAL; + + if (type & IRQ_TYPE_EDGE_BOTH) { @@ -1250,6 +1248,34 @@ index 0000000..327c00d + mutex_unlock(&pctl->lock); +} + ++static int stmfx_gpio_irq_request_resources(struct irq_data *data) ++{ ++ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); ++ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); ++ int ret; ++ ++ ret = stmfx_gpio_direction_input(&pctl->gpio_chip, data->hwirq); ++ if (ret) ++ return ret; ++ ++ ret = gpiochip_lock_as_irq(&pctl->gpio_chip, data->hwirq); ++ if (ret) { ++ dev_err(pctl->dev, "Unable to lock gpio %lu as IRQ: %d\n", ++ data->hwirq, ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static void stmfx_gpio_irq_release_resources(struct irq_data *data) ++{ ++ struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); ++ struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); ++ ++ gpiochip_unlock_as_irq(&pctl->gpio_chip, data->hwirq); ++} ++ +static void stmfx_pinctrl_irq_toggle_trigger(struct stmfx_pinctrl *pctl, + unsigned int offset) +{ @@ -1332,7 +1358,7 @@ index 0000000..327c00d + +static int stmfx_pinctrl_probe(struct platform_device *pdev) +{ -+ struct stmfx *stmfx = dev_get_platdata(&pdev->dev); ++ struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent); + struct device_node *np = pdev->dev.of_node; + struct stmfx_pinctrl *pctl; + u32 n; @@ -1421,6 +1447,8 @@ index 0000000..327c00d + pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type; + pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock; + pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock; ++ pctl->irq_chip.irq_request_resources = stmfx_gpio_irq_request_resources; ++ pctl->irq_chip.irq_release_resources = stmfx_gpio_irq_release_resources; + for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio) + clear_bit(n, pctl->gpio_chip.valid_mask); + @@ -1450,7 +1478,7 @@ index 0000000..327c00d + +static int stmfx_pinctrl_remove(struct platform_device *pdev) +{ -+ struct stmfx *stmfx = dev_get_platdata(&pdev->dev); ++ struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent); + + return stmfx_function_disable(stmfx, + STMFX_FUNC_GPIO | @@ -1572,7 +1600,7 @@ index 0000000..327c00d +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..5b71c97 100644 +index 14dfbbd..4f2676b 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -7,7 +7,9 @@ @@ -1622,7 +1650,15 @@ index a9bec6e..5b71c97 100644 static const char * const stm32_gpio_functions[] = { "gpio", "af0", "af1", "af2", "af3", "af4", -@@ -76,6 +94,9 @@ struct stm32_gpio_bank { +@@ -58,6 +76,7 @@ static const char * const stm32_gpio_functions[] = { + "af8", "af9", "af10", + "af11", "af12", "af13", + "af14", "af15", "analog", ++ "reserved", + }; + + struct stm32_pinctrl_group { +@@ -76,6 +95,9 @@ struct stm32_gpio_bank { struct irq_domain *domain; u32 bank_nr; u32 bank_ioport_nr; @@ -1632,7 +1668,7 @@ index a9bec6e..5b71c97 100644 }; struct stm32_pinctrl { -@@ -91,6 +112,13 @@ struct stm32_pinctrl { +@@ -91,6 +113,13 @@ struct stm32_pinctrl { struct irq_domain *domain; struct regmap *regmap; struct regmap_field *irqmux[STM32_GPIO_PINS_PER_BANK]; @@ -1646,7 +1682,7 @@ index a9bec6e..5b71c97 100644 }; static inline int stm32_gpio_pin(int gpio) -@@ -126,11 +154,33 @@ static inline u32 stm32_gpio_get_alt(u32 function) +@@ -126,11 +155,33 @@ static inline u32 stm32_gpio_get_alt(u32 function) return 0; } @@ -1680,7 +1716,7 @@ index a9bec6e..5b71c97 100644 if (!value) offset += STM32_GPIO_PINS_PER_BANK; -@@ -300,9 +350,40 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, +@@ -300,9 +351,40 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, { struct stm32_gpio_bank *bank = d->host_data; struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); @@ -1722,7 +1758,7 @@ index a9bec6e..5b71c97 100644 } static int stm32_gpio_domain_alloc(struct irq_domain *d, -@@ -331,6 +412,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = { +@@ -331,6 +413,7 @@ static const struct irq_domain_ops stm32_gpio_domain_ops = { .alloc = stm32_gpio_domain_alloc, .free = irq_domain_free_irqs_common, .activate = stm32_gpio_domain_activate, @@ -1730,7 +1766,7 @@ index a9bec6e..5b71c97 100644 }; /* Pinctrl functions */ -@@ -352,16 +434,16 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) +@@ -352,16 +435,19 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, u32 pin_num, u32 fnum) { @@ -1747,89 +1783,14 @@ index a9bec6e..5b71c97 100644 continue; - while (func && func->name) { ++ if (fnum == STM32_PIN_RSVD) ++ return true; ++ + for (k = 0; k < STM32_CONFIG_NUM; k++) { if (func->num == fnum) return true; func++; -@@ -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, +@@ -579,17 +665,27 @@ static int stm32_pmx_get_func_groups(struct pinctrl_dev *pctldev, return 0; } @@ -1859,7 +1820,7 @@ index a9bec6e..5b71c97 100644 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, +@@ -600,8 +696,15 @@ static void stm32_pmx_set_mode(struct stm32_gpio_bank *bank, val |= mode << (pin * 2); writel_relaxed(val, bank->base + STM32_GPIO_MODER); @@ -1875,7 +1836,18 @@ index a9bec6e..5b71c97 100644 } 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, +@@ -652,15 +755,18 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, + return -EINVAL; + } + ++ if (function == STM32_PIN_RSVD) { ++ dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n"); ++ return 0; ++ } ++ + bank = gpiochip_get_data(range->gc); + pin = stm32_gpio_pin(g->pin); + mode = stm32_gpio_get_mode(function); alt = stm32_gpio_get_alt(function); @@ -1886,7 +1858,7 @@ index a9bec6e..5b71c97 100644 } 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, +@@ -670,9 +776,7 @@ static int stm32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, struct stm32_gpio_bank *bank = gpiochip_get_data(range->gc); int pin = stm32_gpio_pin(gpio); @@ -1897,7 +1869,7 @@ index a9bec6e..5b71c97 100644 } static const struct pinmux_ops stm32_pmx_ops = { -@@ -680,22 +781,39 @@ static const struct pinmux_ops stm32_pmx_ops = { +@@ -686,22 +790,39 @@ static const struct pinmux_ops stm32_pmx_ops = { /* Pinconf functions */ @@ -1939,7 +1911,7 @@ index a9bec6e..5b71c97 100644 } 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, +@@ -722,22 +843,39 @@ static u32 stm32_pconf_get_driving(struct stm32_gpio_bank *bank, return (val >> offset); } @@ -1981,7 +1953,7 @@ index a9bec6e..5b71c97 100644 } 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, +@@ -758,22 +896,39 @@ static u32 stm32_pconf_get_speed(struct stm32_gpio_bank *bank, return (val >> (offset * 2)); } @@ -2023,7 +1995,7 @@ index a9bec6e..5b71c97 100644 } 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, +@@ -836,22 +991,22 @@ static int stm32_pconf_parse_conf(struct pinctrl_dev *pctldev, switch (param) { case PIN_CONFIG_DRIVE_PUSH_PULL: @@ -2052,7 +2024,7 @@ index a9bec6e..5b71c97 100644 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, +@@ -899,6 +1054,8 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned int pin) { @@ -2061,7 +2033,7 @@ index a9bec6e..5b71c97 100644 struct pinctrl_gpio_range *range; struct stm32_gpio_bank *bank; int offset; -@@ -942,7 +1096,9 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, +@@ -948,7 +1105,9 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, case 2: drive = stm32_pconf_get_driving(bank, offset); speed = stm32_pconf_get_speed(bank, offset); @@ -2072,7 +2044,7 @@ index a9bec6e..5b71c97 100644 drive ? "open drain" : "push pull", biasing[bias], speeds[speed], "speed"); -@@ -1049,23 +1205,35 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, +@@ -1055,23 +1214,35 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, return 0; } @@ -2117,7 +2089,7 @@ index a9bec6e..5b71c97 100644 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) +@@ -1111,7 +1282,7 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) struct stm32_pinctrl *pctl = platform_get_drvdata(pdev); int i; @@ -2126,7 +2098,7 @@ index a9bec6e..5b71c97 100644 /* Allocate groups */ pctl->groups = devm_kcalloc(&pdev->dev, pctl->ngroups, -@@ -1119,19 +1287,51 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) +@@ -1125,19 +1296,51 @@ static int stm32_pctrl_build_state(struct platform_device *pdev) if (!pctl->grp_names) return -ENOMEM; @@ -2181,7 +2153,7 @@ index a9bec6e..5b71c97 100644 int stm32_pctl_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; -@@ -1140,7 +1340,7 @@ int stm32_pctl_probe(struct platform_device *pdev) +@@ -1146,7 +1349,7 @@ int stm32_pctl_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct stm32_pinctrl *pctl; struct pinctrl_pin_desc *pins; @@ -2190,7 +2162,7 @@ index a9bec6e..5b71c97 100644 if (!np) return -EINVAL; -@@ -1160,36 +1360,66 @@ int stm32_pctl_probe(struct platform_device *pdev) +@@ -1166,36 +1369,66 @@ int stm32_pctl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pctl); @@ -2262,7 +2234,7 @@ index a9bec6e..5b71c97 100644 pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, pctl); -@@ -1227,3 +1457,115 @@ int stm32_pctl_probe(struct platform_device *pdev) +@@ -1233,3 +1466,115 @@ int stm32_pctl_probe(struct platform_device *pdev) return 0; } @@ -2379,14 +2351,15 @@ index a9bec6e..5b71c97 100644 +} +#endif /* CONFIG_PM */ diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h -index 473a623..eb6ed85 100644 +index 473a623..bc77a58 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.h +++ b/drivers/pinctrl/stm32/pinctrl-stm32.h -@@ -17,6 +17,15 @@ +@@ -17,6 +17,16 @@ #define STM32_PIN_GPIO 0 #define STM32_PIN_AF(x) ((x) + 1) #define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1) -+#define STM32_CONFIG_NUM 18 ++#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1) ++#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1) + +/* package information */ +#define STM32MP157CAA BIT(0) @@ -2398,7 +2371,7 @@ index 473a623..eb6ed85 100644 struct stm32_desc_function { const char *name; -@@ -25,7 +34,8 @@ struct stm32_desc_function { +@@ -25,7 +35,8 @@ struct stm32_desc_function { struct stm32_desc_pin { struct pinctrl_pin_desc pin; @@ -2408,7 +2381,7 @@ index 473a623..eb6ed85 100644 }; #define STM32_PIN(_pin, ...) \ -@@ -35,8 +45,15 @@ struct stm32_desc_pin { +@@ -35,8 +46,15 @@ struct stm32_desc_pin { __VA_ARGS__, { } }, \ } @@ -2425,7 +2398,7 @@ index 473a623..eb6ed85 100644 .num = _num, \ .name = _name, \ } -@@ -44,6 +61,7 @@ struct stm32_desc_pin { +@@ -44,6 +62,7 @@ struct stm32_desc_pin { struct stm32_pinctrl_match_data { const struct stm32_desc_pin *pins; const unsigned int npins; @@ -2433,7 +2406,7 @@ index 473a623..eb6ed85 100644 }; struct stm32_gpio_bank; -@@ -51,5 +69,35 @@ struct stm32_gpio_bank; +@@ -51,5 +70,35 @@ struct stm32_gpio_bank; int stm32_pctl_probe(struct platform_device *pdev); void stm32_pmx_get_mode(struct stm32_gpio_bank *bank, int pin, u32 *mode, u32 *alt); @@ -5199,7 +5172,7 @@ index 7c7d628..e1a8a89 100644 }; diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c -index 0059b24c..322df1f 100644 +index 28e1f64..b461412 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -13,6 +13,7 @@ @@ -5219,20 +5192,7 @@ index 0059b24c..322df1f 100644 }; static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip) -@@ -58,6 +61,12 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, - /* Calculate the period and prescaler value */ - div = (unsigned long long)clk_get_rate(priv->clk) * state->period; - do_div(div, NSEC_PER_SEC); -+ if (!div) { -+ /* Fall here in case source clock < period */ -+ dev_err(priv->chip.dev, "Can't reach expected period\n"); -+ return -EINVAL; -+ } -+ - prd = div; - while (div > STM32_LPTIM_MAX_ARR) { - presc++; -@@ -223,6 +232,40 @@ static int stm32_pwm_lp_remove(struct platform_device *pdev) +@@ -229,6 +232,40 @@ static int stm32_pwm_lp_remove(struct platform_device *pdev) return pwmchip_remove(&priv->chip); } @@ -5273,7 +5233,7 @@ index 0059b24c..322df1f 100644 static const struct of_device_id stm32_pwm_lp_of_match[] = { { .compatible = "st,stm32-pwm-lp", }, {}, -@@ -235,6 +278,7 @@ static struct platform_driver stm32_pwm_lp_driver = { +@@ -241,6 +278,7 @@ static struct platform_driver stm32_pwm_lp_driver = { .driver = { .name = "stm32-pwm-lp", .of_match_table = of_match_ptr(stm32_pwm_lp_of_match), @@ -5471,7 +5431,7 @@ index 4f84255..4688425 100644 }; module_platform_driver(stm32_pwm_driver); diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c -index 7c71cdb..ceb233d 100644 +index 72bdda4..13d9bd5 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -249,6 +249,7 @@ static void pwm_export_release(struct device *child) @@ -5482,15 +5442,7 @@ index 7c71cdb..ceb233d 100644 int ret; if (test_and_set_bit(PWMF_EXPORTED, &pwm->flags)) -@@ -263,7 +264,6 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm) - export->pwm = pwm; - mutex_init(&export->lock); - -- export->child.class = parent->class; - export->child.release = pwm_export_release; - export->child.parent = parent; - export->child.devt = MKDEV(0, 0); -@@ -277,6 +277,10 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm) +@@ -276,6 +277,10 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm) export = NULL; return ret; } @@ -5501,7 +5453,7 @@ index 7c71cdb..ceb233d 100644 return 0; } -@@ -289,6 +293,7 @@ static int pwm_unexport_match(struct device *child, void *data) +@@ -288,6 +293,7 @@ static int pwm_unexport_match(struct device *child, void *data) static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) { struct device *child; @@ -5509,7 +5461,7 @@ index 7c71cdb..ceb233d 100644 if (!test_and_clear_bit(PWMF_EXPORTED, &pwm->flags)) return -ENODEV; -@@ -297,6 +302,11 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) +@@ -296,6 +302,11 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm) if (!child) return -ENODEV; @@ -5522,10 +5474,17 @@ index 7c71cdb..ceb233d 100644 put_device(child); device_unregister(child); diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h -index b5a2174..e928aea 100644 +index b5a2174..e3b45a8 100644 --- a/include/dt-bindings/pinctrl/stm32-pinfunc.h +++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h -@@ -32,5 +32,11 @@ +@@ -26,11 +26,18 @@ + #define AF14 0xf + #define AF15 0x10 + #define ANALOG 0x11 ++#define RSVD 0x12 + + /* define Pins number*/ + #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) #define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode)) 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.94/0020-ARM-stm32mp1-r3-REGULATOR.patch similarity index 81% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0019-ARM-stm32mp1-r2-REGULATOR.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch index 2da94d9..7aa58c6 100644 --- 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.94/0020-ARM-stm32mp1-r3-REGULATOR.patch @@ -1,15 +1,17 @@ -From c26270a4d76f20b3ee1af133269ac67e60185e8c Mon Sep 17 00:00:00 2001 +From 099f59a43431770a338d464c59e26d9e4a2b30eb 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 +Date: Fri, 8 Nov 2019 16:52:44 +0100 +Subject: [PATCH 20/31] ARM stm32mp1 r3 REGULATOR --- drivers/regulator/Kconfig | 19 + drivers/regulator/Makefile | 2 + + drivers/regulator/core.c | 6 + drivers/regulator/stm32-pwr.c | 245 +++++++++++++ - drivers/regulator/stm32-vrefbuf.c | 123 ++++++- - drivers/regulator/stpmic1_regulator.c | 663 ++++++++++++++++++++++++++++++++++ - 5 files changed, 1045 insertions(+), 7 deletions(-) + drivers/regulator/stm32-vrefbuf.c | 126 ++++++- + drivers/regulator/stpmic1_regulator.c | 632 ++++++++++++++++++++++++++++++++++ + include/linux/regulator/driver.h | 1 + + 7 files changed, 1023 insertions(+), 8 deletions(-) create mode 100644 drivers/regulator/stm32-pwr.c create mode 100644 drivers/regulator/stpmic1_regulator.c @@ -44,7 +46,7 @@ index 329cdd3..9ecafba 100644 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 +index bba9c48..a818c5d 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -101,6 +101,8 @@ obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o @@ -56,6 +58,23 @@ index 801d9a3..3506ec2 100644 obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index f312764..1a40a4a 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -4605,6 +4605,12 @@ struct device *rdev_get_dev(struct regulator_dev *rdev) + } + EXPORT_SYMBOL_GPL(rdev_get_dev); + ++struct regmap *rdev_get_regmap(struct regulator_dev *rdev) ++{ ++ return rdev->regmap; ++} ++EXPORT_SYMBOL_GPL(rdev_get_regmap); ++ + void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) + { + return reg_init_data->driver_data; diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c new file mode 100644 index 0000000..e6f41eb @@ -308,7 +327,7 @@ index 0000000..e6f41eb +} +subsys_initcall(stm32_pwr_regulator_init); diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c -index e0a9c44..29cca32 100644 +index e0a9c44..a74dffe 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -15,6 +15,7 @@ @@ -367,6 +386,7 @@ index e0a9c44..29cca32 100644 + u32 val; + int ret; +- val = (val & ~STM32_ENVR) | STM32_HIZ; + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); @@ -374,7 +394,7 @@ index e0a9c44..29cca32 100644 + } + + val = readl_relaxed(priv->base + STM32_VREFBUF_CSR); - val = (val & ~STM32_ENVR) | STM32_HIZ; ++ val &= ~STM32_ENVR; writel_relaxed(val, priv->base + STM32_VREFBUF_CSR); + pm_runtime_mark_last_busy(priv->dev); @@ -451,7 +471,15 @@ index e0a9c44..29cca32 100644 } static const struct regulator_ops stm32_vrefbuf_volt_ops = { -@@ -130,6 +191,7 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) +@@ -115,6 +176,7 @@ static const struct regulator_desc stm32_vrefbuf_regu = { + .volt_table = stm32_vrefbuf_voltages, + .n_voltages = ARRAY_SIZE(stm32_vrefbuf_voltages), + .ops = &stm32_vrefbuf_volt_ops, ++ .off_on_delay = 1000, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }; +@@ -130,6 +192,7 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -459,7 +487,7 @@ index e0a9c44..29cca32 100644 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) +@@ -140,10 +203,17 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); @@ -478,7 +506,7 @@ index e0a9c44..29cca32 100644 } config.dev = &pdev->dev; -@@ -161,10 +230,17 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) +@@ -161,10 +231,17 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, rdev); @@ -496,7 +524,7 @@ index e0a9c44..29cca32 100644 return ret; } -@@ -174,12 +250,44 @@ static int stm32_vrefbuf_remove(struct platform_device *pdev) +@@ -174,12 +251,44 @@ static int stm32_vrefbuf_remove(struct platform_device *pdev) struct regulator_dev *rdev = platform_get_drvdata(pdev); struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev); @@ -541,7 +569,7 @@ index e0a9c44..29cca32 100644 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 = { +@@ -192,6 +301,7 @@ static struct platform_driver stm32_vrefbuf_driver = { .driver = { .name = "stm32-vrefbuf", .of_match_table = of_match_ptr(stm32_vrefbuf_of_match), @@ -551,10 +579,10 @@ index e0a9c44..29cca32 100644 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 +index 0000000..29f1584 --- /dev/null +++ b/drivers/regulator/stpmic1_regulator.c -@@ -0,0 +1,663 @@ +@@ -0,0 +1,632 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet for STMicroelectronics. @@ -569,8 +597,10 @@ index 0000000..31c960c +#include +#include + ++#include ++ +/** -+ * stpmic1 regulator description ++ * stpmic1 regulator description: this structure is used as driver data + * @desc: regulator framework description + * @mask_reset_reg: mask reset register address + * @mask_reset_mask: mask rank and mask reset register mask @@ -585,28 +615,9 @@ index 0000000..31c960c + 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 { @@ -629,16 +640,13 @@ index 0000000..31c960c +/* 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[] = { ++static const struct regulator_linear_range buck1_ranges[] = { + REGULATOR_LINEAR_RANGE(725000, 0, 4, 0), + REGULATOR_LINEAR_RANGE(725000, 5, 36, 25000), + REGULATOR_LINEAR_RANGE(1500000, 37, 63, 0), +}; + -+struct regulator_linear_range buck2_ranges[] = { ++static const struct regulator_linear_range buck2_ranges[] = { + REGULATOR_LINEAR_RANGE(1000000, 0, 17, 0), + REGULATOR_LINEAR_RANGE(1050000, 18, 19, 0), + REGULATOR_LINEAR_RANGE(1100000, 20, 21, 0), @@ -652,7 +660,7 @@ index 0000000..31c960c + REGULATOR_LINEAR_RANGE(1500000, 36, 63, 0), +}; + -+struct regulator_linear_range buck3_ranges[] = { ++static const struct regulator_linear_range buck3_ranges[] = { + REGULATOR_LINEAR_RANGE(1000000, 0, 19, 0), + REGULATOR_LINEAR_RANGE(1100000, 20, 23, 0), + REGULATOR_LINEAR_RANGE(1200000, 24, 27, 0), @@ -660,10 +668,9 @@ index 0000000..31c960c + 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[] = { ++static const struct regulator_linear_range buck4_ranges[] = { + REGULATOR_LINEAR_RANGE(600000, 0, 27, 25000), + REGULATOR_LINEAR_RANGE(1300000, 28, 29, 0), + REGULATOR_LINEAR_RANGE(1350000, 30, 31, 0), @@ -671,24 +678,21 @@ index 0000000..31c960c + 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[] = { ++static const struct regulator_linear_range ldo1_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), + REGULATOR_LINEAR_RANGE(3300000, 25, 31, 0), -+ +}; + -+struct regulator_linear_range ldo2_ranges[] = { ++static const struct regulator_linear_range ldo2_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), + REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), -+ +}; + -+struct regulator_linear_range ldo3_ranges[] = { ++static const struct regulator_linear_range ldo3_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 24, 100000), + REGULATOR_LINEAR_RANGE(3300000, 25, 30, 0), @@ -696,18 +700,18 @@ index 0000000..31c960c + REGULATOR_LINEAR_RANGE(500000, 31, 31, 0), +}; + -+struct regulator_linear_range ldo5_ranges[] = { ++static const struct regulator_linear_range ldo5_ranges[] = { + REGULATOR_LINEAR_RANGE(1700000, 0, 7, 0), + REGULATOR_LINEAR_RANGE(1700000, 8, 30, 100000), + REGULATOR_LINEAR_RANGE(3900000, 31, 31, 0), +}; + -+struct regulator_linear_range ldo6_ranges[] = { ++static const 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 = { ++static const struct regulator_ops stpmic1_ldo_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, @@ -718,7 +722,7 @@ index 0000000..31c960c + .set_over_current_protection = stpmic1_set_icc, +}; + -+static struct regulator_ops stpmic1_ldo3_ops = { ++static const struct regulator_ops stpmic1_ldo3_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_iterate, + .is_enabled = regulator_is_enabled_regmap, @@ -731,14 +735,14 @@ index 0000000..31c960c + .set_over_current_protection = stpmic1_set_icc, +}; + -+static struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { ++static const struct regulator_ops stpmic1_ldo4_fixed_regul_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_over_current_protection = stpmic1_set_icc, +}; + -+static struct regulator_ops stpmic1_buck_ops = { ++static const struct regulator_ops stpmic1_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .is_enabled = regulator_is_enabled_regmap, @@ -752,19 +756,27 @@ index 0000000..31c960c + .set_over_current_protection = stpmic1_set_icc, +}; + -+static struct regulator_ops stpmic1_vref_ddr_ops = { ++static const 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 = { ++static const struct regulator_ops stpmic1_boost_regul_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_over_current_protection = stpmic1_set_icc, +}; + ++static const struct regulator_ops stpmic1_switch_regul_ops = { ++ .is_enabled = regulator_is_enabled_regmap, ++ .enable = regulator_enable_regmap, ++ .disable = regulator_disable_regmap, ++ .set_over_current_protection = stpmic1_set_icc, ++ .set_active_discharge = regulator_set_active_discharge_regmap, ++}; ++ +#define REG_LDO(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ @@ -863,7 +875,24 @@ index 0000000..31c960c + .supply_name = #base, \ +} + -+#define REG_SWITCH(ids, base, reg, mask, val) { \ ++#define REG_BOOST(ids, base) { \ ++ .name = #ids, \ ++ .id = STPMIC1_##ids, \ ++ .n_voltages = 1, \ ++ .ops = &stpmic1_boost_regul_ops, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE, \ ++ .min_uV = 0, \ ++ .fixed_uV = 5000000, \ ++ .enable_reg = BST_SW_CR, \ ++ .enable_mask = BOOST_ENABLED, \ ++ .enable_val = BOOST_ENABLED, \ ++ .disable_val = 0, \ ++ .enable_time = PMIC_ENABLE_TIME_US, \ ++ .supply_name = #base, \ ++} ++ ++#define REG_VBUS_OTG(ids, base) { \ + .name = #ids, \ + .id = STPMIC1_##ids, \ + .n_voltages = 1, \ @@ -872,15 +901,38 @@ index 0000000..31c960c + .owner = THIS_MODULE, \ + .min_uV = 0, \ + .fixed_uV = 5000000, \ -+ .enable_reg = (reg), \ -+ .enable_mask = (mask), \ -+ .enable_val = (val), \ ++ .enable_reg = BST_SW_CR, \ ++ .enable_mask = USBSW_OTG_SWITCH_ENABLED, \ ++ .enable_val = USBSW_OTG_SWITCH_ENABLED, \ + .disable_val = 0, \ + .enable_time = PMIC_ENABLE_TIME_US, \ + .supply_name = #base, \ ++ .active_discharge_reg = BST_SW_CR, \ ++ .active_discharge_mask = VBUS_OTG_DISCHARGE, \ ++ .active_discharge_on = VBUS_OTG_DISCHARGE, \ +} + -+struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = { ++#define REG_SW_OUT(ids, base) { \ ++ .name = #ids, \ ++ .id = STPMIC1_##ids, \ ++ .n_voltages = 1, \ ++ .ops = &stpmic1_switch_regul_ops, \ ++ .type = REGULATOR_VOLTAGE, \ ++ .owner = THIS_MODULE, \ ++ .min_uV = 0, \ ++ .fixed_uV = 5000000, \ ++ .enable_reg = BST_SW_CR, \ ++ .enable_mask = SWIN_SWOUT_ENABLED, \ ++ .enable_val = SWIN_SWOUT_ENABLED, \ ++ .disable_val = 0, \ ++ .enable_time = PMIC_ENABLE_TIME_US, \ ++ .supply_name = #base, \ ++ .active_discharge_reg = BST_SW_CR, \ ++ .active_discharge_mask = SW_OUT_DISCHARGE, \ ++ .active_discharge_on = SW_OUT_DISCHARGE, \ ++} ++ ++static const struct stpmic1_regulator_cfg stpmic1_regulator_cfgs[] = { + [STPMIC1_BUCK1] = { + .desc = REG_BUCK(BUCK1, buck1), + .icc_reg = BUCKS_ICCTO_CR, @@ -957,23 +1009,17 @@ index 0000000..31c960c + .mask_reset_mask = BIT(6), + }, + [STPMIC1_BOOST] = { -+ .desc = REG_SWITCH(BOOST, boost, BST_SW_CR, -+ BOOST_ENABLED, -+ BOOST_ENABLED), ++ .desc = REG_BOOST(BOOST, boost), + .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), ++ .desc = REG_VBUS_OTG(VBUS_OTG, pwr_sw1), + .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), ++ .desc = REG_SW_OUT(SW_OUT, pwr_sw2), + .icc_reg = BUCKS_ICCTO_CR, + .icc_mask = BIT(5), + }, @@ -987,15 +1033,16 @@ index 0000000..31c960c + case STPMIC1_BUCK_MODE_LP: + return REGULATOR_MODE_STANDBY; + default: -+ return -EINVAL; ++ return REGULATOR_MODE_INVALID; + } +} + +static unsigned int stpmic1_get_mode(struct regulator_dev *rdev) +{ + int value; ++ struct regmap *regmap = rdev_get_regmap(rdev); + -+ regmap_read(rdev->regmap, rdev->desc->enable_reg, &value); ++ regmap_read(regmap, rdev->desc->enable_reg, &value); + + if (value & STPMIC1_BUCK_MODE_LP) + return REGULATOR_MODE_STANDBY; @@ -1006,6 +1053,7 @@ index 0000000..31c960c +static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + int value; ++ struct regmap *regmap = rdev_get_regmap(rdev); + + switch (mode) { + case REGULATOR_MODE_NORMAL: @@ -1018,17 +1066,18 @@ index 0000000..31c960c + return -EINVAL; + } + -+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, ++ return regmap_update_bits(regmap, rdev->desc->enable_reg, + STPMIC1_BUCK_MODE_LP, value); +} + +static int stpmic1_set_icc(struct regulator_dev *rdev) +{ -+ struct stpmic1_regulator *regul = rdev_get_drvdata(rdev); ++ struct stpmic1_regulator_cfg *cfg = rdev_get_drvdata(rdev); ++ struct regmap *regmap = rdev_get_regmap(rdev); + + /* enable switch off in case of over current */ -+ return regmap_update_bits(regul->regmap, regul->cfg->icc_reg, -+ regul->cfg->icc_mask, regul->cfg->icc_mask); ++ return regmap_update_bits(regmap, cfg->icc_reg, cfg->icc_mask, ++ cfg->icc_mask); +} + +static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) @@ -1047,46 +1096,13 @@ index 0000000..31c960c + 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[] = { ++static struct of_regulator_match stpmic1_matches[] = { + MATCH(buck1, BUCK1), + MATCH(buck2, BUCK2), + MATCH(buck3, BUCK3), @@ -1103,94 +1119,75 @@ index 0000000..31c960c + 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) ++static int stpmic1_regulator_register(struct platform_device *pdev, int id, ++ struct of_regulator_match *match, ++ const struct stpmic1_regulator_cfg *cfg) +{ + struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); + struct regulator_dev *rdev; + struct regulator_config config = {}; ++ int ret = 0; ++ int irq; + + config.dev = &pdev->dev; -+ config.init_data = init_data; -+ config.of_node = stpmic1_regulators_matches[id].of_node; ++ config.init_data = match->init_data; ++ config.of_node = match->of_node; + config.regmap = pmic_dev->regmap; -+ config.driver_data = regul; ++ config.driver_data = (void *)cfg; + -+ 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); ++ rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s regulator\n", -+ regul->cfg->desc.name); ++ cfg->desc.name); ++ return PTR_ERR(rdev); + } + -+ return rdev; ++ /* set mask reset */ ++ if (of_get_property(config.of_node, "st,mask-reset", NULL) && ++ cfg->mask_reset_reg != 0) { ++ ret = regmap_update_bits(pmic_dev->regmap, ++ cfg->mask_reset_reg, ++ cfg->mask_reset_mask, ++ cfg->mask_reset_mask); ++ if (ret) { ++ dev_err(&pdev->dev, "set mask reset failed\n"); ++ return ret; ++ } ++ } ++ ++ /* setup an irq handler for over-current detection */ ++ irq = of_irq_get(config.of_node, 0); ++ if (irq > 0) { ++ ret = devm_request_threaded_irq(&pdev->dev, ++ irq, NULL, ++ stpmic1_curlim_irq_handler, ++ IRQF_ONESHOT | IRQF_SHARED, ++ pdev->name, rdev); ++ if (ret) { ++ dev_err(&pdev->dev, "Request IRQ failed\n"); ++ return ret; ++ } ++ } ++ return 0; +} + +static int stpmic1_regulator_probe(struct platform_device *pdev) +{ -+ 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)); ++ ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, ++ ARRAY_SIZE(stpmic1_matches)); + if (ret < 0) { + dev_err(&pdev->dev, + "Error in PMIC regulator device tree node"); + return ret; + } + -+ 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); ++ ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], ++ &stpmic1_regulator_cfgs[i]); ++ if (ret < 0) + return ret; -+ } -+ -+ regul++; + } + + dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); @@ -1218,6 +1215,18 @@ index 0000000..31c960c +MODULE_DESCRIPTION("STPMIC1 PMIC voltage regulator driver"); +MODULE_AUTHOR("Pascal Paillet "); +MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h +index 0fd8fbb..85c5427 100644 +--- a/include/linux/regulator/driver.h ++++ b/include/linux/regulator/driver.h +@@ -492,6 +492,7 @@ int regulator_notifier_call_chain(struct regulator_dev *rdev, + + void *rdev_get_drvdata(struct regulator_dev *rdev); + struct device *rdev_get_dev(struct regulator_dev *rdev); ++struct regmap *rdev_get_regmap(struct regulator_dev *rdev); + int rdev_get_id(struct regulator_dev *rdev); + + int regulator_mode_to_status(unsigned int); -- 2.7.4 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0020-ARM-stm32mp1-r2-REMOTEPROC-RPMSG-RESET.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0020-ARM-stm32mp1-r2-REMOTEPROC-RPMSG-RESET.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch index 3ce9100..0294aab 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0020-ARM-stm32mp1-r2-REMOTEPROC-RPMSG-RESET.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch @@ -1,7 +1,7 @@ -From 0feaf56c6535420b9c89752e55353887e8266959 Mon Sep 17 00:00:00 2001 +From b1e1c0d118b5f460f13d08f7a4f25210aaa88641 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 +Date: Fri, 8 Nov 2019 16:52:45 +0100 +Subject: [PATCH 21/31] ARM stm32mp1 r3 REMOTEPROC RPMSG RESET --- drivers/remoteproc/Kconfig | 36 ++ @@ -12,18 +12,18 @@ Subject: [PATCH 20/30] ARM stm32mp1 r2 REMOTEPROC RPMSG RESET 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/remoteproc/rproc_srm_dev.c | 744 +++++++++++++++++++++++++++ + drivers/remoteproc/stm32_rproc.c | 858 +++++++++++++++++++++++++++++++ drivers/reset/reset-stm32mp1.c | 48 ++ drivers/rpmsg/Kconfig | 9 + drivers/rpmsg/Makefile | 1 + drivers/rpmsg/rpmsg_core.c | 19 + drivers/rpmsg/rpmsg_internal.h | 2 + - drivers/rpmsg/rpmsg_tty.c | 305 +++++++++++ + drivers/rpmsg/rpmsg_tty.c | 310 +++++++++++ drivers/rpmsg/virtio_rpmsg_bus.c | 17 +- include/linux/remoteproc.h | 38 +- include/linux/rpmsg.h | 9 + - 19 files changed, 3200 insertions(+), 149 deletions(-) + 19 files changed, 3127 insertions(+), 149 deletions(-) create mode 100644 drivers/remoteproc/rproc_srm_core.c create mode 100644 drivers/remoteproc/rproc_srm_core.h create mode 100644 drivers/remoteproc/rproc_srm_dev.c @@ -1699,10 +1699,10 @@ index 0000000..7dffdb38 +#endif diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c new file mode 100644 -index 0000000..7dc99c5 +index 0000000..6b164da --- /dev/null +++ b/drivers/remoteproc/rproc_srm_dev.c -@@ -0,0 +1,833 @@ +@@ -0,0 +1,744 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -1717,7 +1717,6 @@ index 0000000..7dc99c5 +#include +#include +#include -+#include +#include +#include +#include @@ -1732,12 +1731,6 @@ index 0000000..7dc99c5 + bool parent_enabled; +}; + -+struct rproc_srm_pin_info { -+ struct list_head list; -+ unsigned int index; -+ char *name; -+}; -+ +struct rproc_srm_regu_info { + struct list_head list; + unsigned int index; @@ -1758,12 +1751,10 @@ index 0000000..7dc99c5 + struct device *dev; + struct rproc_srm_core *core; + struct notifier_block nb; -+ struct pinctrl *pctrl; + bool early_boot; + + struct list_head clk_list_head; + struct list_head regu_list_head; -+ struct list_head pin_list_head; + struct list_head irq_list_head; +}; + @@ -2247,79 +2238,6 @@ index 0000000..7dc99c5 + return ret; +} + -+/* Pins */ -+static void rproc_srm_dev_pins_put(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct rproc_srm_pin_info *p, *tmp; -+ -+ list_for_each_entry_safe(p, tmp, &rproc_srm_dev->pin_list_head, list) { -+ devm_kfree(dev, p->name); -+ devm_kfree(dev, p); -+ dev_dbg(dev, "remove pin cfg %d (%s)\n", p->index, p->name); -+ list_del(&p->list); -+ } -+ -+ if (!IS_ERR_OR_NULL(rproc_srm_dev->pctrl)) { -+ devm_pinctrl_put(rproc_srm_dev->pctrl); -+ rproc_srm_dev->pctrl = NULL; -+ } -+} -+ -+static int rproc_srm_dev_pins_get(struct rproc_srm_dev *rproc_srm_dev) -+{ -+ struct device *dev = rproc_srm_dev->dev; -+ struct device_node *np = dev->of_node; -+ struct rproc_srm_pin_info *p; -+ int ret, nb_p; -+ unsigned int i; -+ const char *name; -+ -+ if (!np) -+ return 0; -+ -+ rproc_srm_dev->pctrl = devm_pinctrl_get(dev); -+ if (IS_ERR(rproc_srm_dev->pctrl)) -+ return 0; -+ -+ nb_p = of_property_count_strings(np, "pinctrl-names"); -+ if (nb_p <= 0) { -+ dev_err(dev, "pinctrl-names not defined\n"); -+ ret = -EINVAL; -+ goto err; -+ } -+ -+ for (i = 0; i < nb_p; i++) { -+ p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); -+ if (!p) { -+ ret = -ENOMEM; -+ goto err; -+ } -+ -+ if (of_property_read_string_index(np, "pinctrl-names", i, -+ &name)) { -+ dev_err(dev, "no pinctrl-names (pin %d)\n", i); -+ ret = -EINVAL; -+ goto err; -+ } -+ p->name = devm_kstrdup(dev, name, GFP_KERNEL); -+ -+ /* 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; -+ -+ list_add_tail(&p->list, &rproc_srm_dev->pin_list_head); -+ dev_dbg(dev, "found pin cfg %d (%s)\n", p->index, p->name); -+ } -+ return 0; -+ -+err: -+ rproc_srm_dev_pins_put(rproc_srm_dev); -+ return ret; -+} -+ +/* Core */ +static int rproc_srm_dev_notify_cb(struct notifier_block *nb, unsigned long evt, + void *data) @@ -2405,7 +2323,7 @@ index 0000000..7dc99c5 + rproc_srm_dev_regus_unsetup(rproc_srm_dev); + rproc_srm_dev_clocks_unsetup(rproc_srm_dev); + -+ /* For pins and IRQs: nothing to unsetup */ ++ /* For IRQs: nothing to unsetup */ +} + +static int @@ -2424,7 +2342,7 @@ index 0000000..7dc99c5 + if (ret) + return ret; + -+ /* For pins and IRQs: nothing to setup */ ++ /* For IRQs: nothing to setup */ + return 0; +} + @@ -2453,11 +2371,10 @@ index 0000000..7dc99c5 + rproc_srm_dev->core = dev_get_drvdata(dev->parent); + + INIT_LIST_HEAD(&rproc_srm_dev->clk_list_head); -+ INIT_LIST_HEAD(&rproc_srm_dev->pin_list_head); + INIT_LIST_HEAD(&rproc_srm_dev->regu_list_head); + INIT_LIST_HEAD(&rproc_srm_dev->irq_list_head); + -+ /* Get clocks, regu, irqs and pinctrl */ ++ /* Get clocks, regu and irqs */ + ret = rproc_srm_dev_clocks_get(rproc_srm_dev); + if (ret) + return ret; @@ -2466,10 +2383,6 @@ index 0000000..7dc99c5 + if (ret) + goto err_get; + -+ ret = rproc_srm_dev_pins_get(rproc_srm_dev); -+ if (ret) -+ goto err_get; -+ + ret = rproc_srm_dev_irqs_get(rproc_srm_dev); + if (ret) + goto err_get; @@ -2489,7 +2402,6 @@ index 0000000..7dc99c5 + &rproc_srm_dev->nb); +err_get: + rproc_srm_dev_irqs_put(rproc_srm_dev); -+ rproc_srm_dev_pins_put(rproc_srm_dev); + rproc_srm_dev_regus_put(rproc_srm_dev); + rproc_srm_dev_clocks_put(rproc_srm_dev); + return ret; @@ -2509,7 +2421,6 @@ index 0000000..7dc99c5 + + rproc_srm_dev_irqs_put(rproc_srm_dev); + rproc_srm_dev_regus_put(rproc_srm_dev); -+ rproc_srm_dev_pins_put(rproc_srm_dev); + rproc_srm_dev_clocks_put(rproc_srm_dev); + + return 0; @@ -2538,10 +2449,10 @@ index 0000000..7dc99c5 +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c new file mode 100644 -index 0000000..6533503 +index 0000000..21a569a --- /dev/null +++ b/drivers/remoteproc/stm32_rproc.c -@@ -0,0 +1,847 @@ +@@ -0,0 +1,858 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -2580,6 +2491,8 @@ index 0000000..6533503 +#define STM32_MBX_VQ1_ID 1 +#define STM32_MBX_SHUTDOWN "shutdown" + ++#define RSC_TBL_SIZE (1024) ++ +struct stm32_syscon { + struct regmap *map; + u32 reg; @@ -2619,7 +2532,6 @@ index 0000000..6533503 + struct workqueue_struct *workqueue; + bool secured_soc; + void __iomem *rsc_va; -+ u32 rsc_len; +}; + +static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) @@ -2772,7 +2684,6 @@ index 0000000..6533503 + int status; + struct resource_table *table = NULL; + struct stm32_rproc *ddata = rproc->priv; -+ size_t tablesz = 0; + + if (!rproc->early_boot) { + status = rproc_elf_load_rsc_table(rproc, fw); @@ -2783,14 +2694,14 @@ index 0000000..6533503 + } + + if (ddata->rsc_va) { -+ tablesz = ddata->rsc_len; + table = (struct resource_table *)ddata->rsc_va; -+ rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL); ++ /* Assuming that the resource table fits in 1kB is fair */ ++ rproc->cached_table = kmemdup(table, RSC_TBL_SIZE, GFP_KERNEL); + if (!rproc->cached_table) + return -ENOMEM; + + rproc->table_ptr = rproc->cached_table; -+ rproc->table_sz = tablesz; ++ rproc->table_sz = RSC_TBL_SIZE; + return 0; + } + @@ -2799,7 +2710,7 @@ index 0000000..6533503 + rproc->table_sz = 0; + +no_rsc_table: -+ dev_warn(&rproc->dev, "not resource table found for this firmware\n"); ++ dev_warn(&rproc->dev, "no resource table found for this firmware\n"); + return 0; +} + @@ -2956,7 +2867,7 @@ index 0000000..6533503 + } +}; + -+static void stm32_rproc_request_mbox(struct rproc *rproc) ++static int stm32_rproc_request_mbox(struct rproc *rproc) +{ + struct stm32_rproc *ddata = rproc->priv; + struct device *dev = &rproc->dev; @@ -2974,7 +2885,9 @@ index 0000000..6533503 + cl->dev = dev->parent; + + ddata->mb[i].chan = mbox_request_channel_byname(cl, name); -+ if (IS_ERR(ddata->mb[i].chan)) { ++ if (PTR_ERR(ddata->mb[i].chan) == -EPROBE_DEFER) { ++ return -EPROBE_DEFER; ++ } else if (IS_ERR(ddata->mb[i].chan)) { + dev_warn(dev, "cannot get %s mbox\n", name); + ddata->mb[i].chan = NULL; + } @@ -2983,6 +2896,8 @@ index 0000000..6533503 + stm32_rproc_mb_vq_work); + } + } ++ ++ return 0; +} + +static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) @@ -3171,7 +3086,7 @@ index 0000000..6533503 + struct device_node *np = dev->of_node; + struct rproc *rproc = platform_get_drvdata(pdev); + struct stm32_rproc *ddata = rproc->priv; -+ struct stm32_syscon tz; ++ struct stm32_syscon tz, rsctbl; + phys_addr_t rsc_pa; + u32 rsc_da; + unsigned int tzen; @@ -3232,7 +3147,7 @@ index 0000000..6533503 + + err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); + if (err) -+ dev_warn(dev, "failed to get pdds\n"); ++ dev_warn(dev, "pdds not supported\n"); + + + rproc->auto_boot = of_property_read_bool(np, "auto_boot"); @@ -3244,30 +3159,35 @@ index 0000000..6533503 + + 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-size", &ddata->rsc_len); ++ if (stm32_rproc_get_syscon(np, "st,syscfg-rsc-tbl", &rsctbl)) { ++ /* no rsc table syscon (optional) */ ++ dev_warn(dev, "rsc tbl syscon not supported\n"); ++ goto bail; ++ } ++ ++ err = regmap_read(rsctbl.map, rsctbl.reg, &rsc_da); + if (err) { -+ dev_err(dev, "resource table size required as address defined\n"); ++ dev_err(&rproc->dev, "failed to read rsc tbl addr\n"); + return err; + } ++ if (!rsc_da) ++ /* no rsc table */ ++ goto bail; + + err = stm32_rproc_da_to_pa(rproc, rsc_da, &rsc_pa); + if (err) + return err; + -+ ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, ddata->rsc_len); ++ ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); + if (IS_ERR_OR_NULL(ddata->rsc_va)) { + dev_err(dev, "Unable to map memory region: %pa+%zx\n", -+ &rsc_pa, ddata->rsc_len); ++ &rsc_pa, RSC_TBL_SIZE); + ddata->rsc_va = NULL; + return -ENOMEM; + } + } -+ ++bail: + return 0; +} + @@ -3301,10 +3221,12 @@ index 0000000..6533503 + if (!rproc->early_boot) { + ret = stm32_rproc_stop(rproc); + if (ret) -+ goto free_rproc; ++ goto free_wkq; + } + -+ stm32_rproc_request_mbox(rproc); ++ ret = stm32_rproc_request_mbox(rproc); ++ if (ret) ++ goto free_wkq; + + ret = rproc_add(rproc); + if (ret) @@ -3560,10 +3482,10 @@ 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..26814d3 +index 0000000..5776389 --- /dev/null +++ b/drivers/rpmsg/rpmsg_tty.c -@@ -0,0 +1,305 @@ +@@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -3838,6 +3760,11 @@ index 0000000..26814d3 + + tty_set_operations(rpmsg_tty_driver, &rpmsg_tty_ops); + ++ /* Disable unused mode by default */ ++ rpmsg_tty_driver->init_termios = tty_std_termios; ++ rpmsg_tty_driver->init_termios.c_lflag &= ~(ECHO | ICANON); ++ rpmsg_tty_driver->init_termios.c_oflag &= ~(OPOST | ONLCR); ++ + err = tty_register_driver(rpmsg_tty_driver); + if (err < 0) { + pr_err("Couldn't install rpmsg tty driver: err %d\n", err); 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.94/0022-ARM-stm32mp1-r3-RTC.patch similarity index 98% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0021-ARM-stm32mp1-r2-RTC.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch index f1b05eb..c50aaaf 100644 --- 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.94/0022-ARM-stm32mp1-r3-RTC.patch @@ -1,7 +1,7 @@ -From dbec0d5fe9520a172a3cba71781d9e19e659f43a Mon Sep 17 00:00:00 2001 +From eb8e18ef550744ca51256b8cd1dc3cf09b7596e4 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 +Date: Fri, 8 Nov 2019 16:52:45 +0100 +Subject: [PATCH 22/31] ARM stm32mp1 r3 RTC --- drivers/rtc/Kconfig | 1 + 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.94/0023-ARM-stm32mp1-r3-SOC.patch similarity index 98% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0022-ARM-stm32mp1-r2-SOC.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch index 5011fd8..3498c9f 100644 --- 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.94/0023-ARM-stm32mp1-r3-SOC.patch @@ -1,7 +1,7 @@ -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 +From 62a47162dba55286160a68ac2b46d405142b2830 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Mon, 9 Dec 2019 12:26:14 +0100 +Subject: [PATCH 23/31] ARM stm32mp1 r3 SOC --- drivers/soc/Kconfig | 1 + @@ -31,7 +31,7 @@ index c07b4a8..f2bd1ce 100644 source "drivers/soc/tegra/Kconfig" source "drivers/soc/ti/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile -index 113e884..a16f673 100644 +index f0d46b1..d2c3147 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -18,6 +18,7 @@ obj-y += qcom/ 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.94/0024-ARM-stm32mp1-r3-SPI.patch similarity index 99% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0023-ARM-stm32mp1-r2-SPI.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch index fb63c97..068759f 100644 --- 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.94/0024-ARM-stm32mp1-r3-SPI.patch @@ -1,7 +1,7 @@ -From 7e96d3b92f935af4c9b85bbc25cc3e63323fd5bc Mon Sep 17 00:00:00 2001 +From b40db75218cb1808125643c8e76b364d26ae2479 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 +Date: Fri, 8 Nov 2019 16:52:46 +0100 +Subject: [PATCH 24/31] ARM stm32mp1 r3 SPI --- drivers/spi/Kconfig | 9 + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0024-ARM-stm32mp1-r2-THERMAL.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch similarity index 99% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0024-ARM-stm32mp1-r2-THERMAL.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch index e1aa5f2..caafc4a 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0024-ARM-stm32mp1-r2-THERMAL.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch @@ -1,7 +1,7 @@ -From acf08f1eb571f76ff42e343efa928f9b3c6112c5 Mon Sep 17 00:00:00 2001 +From 69f90684b9d271fe91b53862b3a760d91b0fe7e4 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 +Date: Fri, 8 Nov 2019 16:52:46 +0100 +Subject: [PATCH 25/31] ARM stm32mp1 r3 THERMAL --- drivers/thermal/Kconfig | 2 +- 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.94/0026-ARM-stm32mp1-r3-TTY-USB.patch similarity index 84% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0025-ARM-stm32mp1-r2-TTY-USB.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch index 781930c..a3a6140 100644 --- 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.94/0026-ARM-stm32mp1-r3-TTY-USB.patch @@ -1,33 +1,34 @@ -From 8b909622c1d507518a617c58d5fe42470bc7f73a Mon Sep 17 00:00:00 2001 +From 6e8d34490963467552ebe1a996e0ad78b4e560ba 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 +Date: Fri, 8 Nov 2019 16:52:47 +0100 +Subject: [PATCH 26/31] ARM stm32mp1 r3 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(-) + drivers/tty/serial/stm32-usart.c | 758 ++++++++++++++++++++------- + drivers/tty/serial/stm32-usart.h | 48 +- + drivers/usb/dwc2/Makefile | 2 +- + drivers/usb/dwc2/core.c | 123 +++-- + drivers/usb/dwc2/core.h | 50 ++ + drivers/usb/dwc2/debugfs.c | 1 + + drivers/usb/dwc2/drd.c | 191 +++++++ + drivers/usb/dwc2/gadget.c | 99 +++- + drivers/usb/dwc2/hcd.c | 36 +- + drivers/usb/dwc2/hw.h | 25 + + drivers/usb/dwc2/params.c | 40 ++ + drivers/usb/dwc2/platform.c | 166 +++++- + drivers/usb/gadget/function/u_serial.c | 35 +- + drivers/usb/host/ehci-platform.c | 59 +++ + drivers/usb/typec/Kconfig | 9 + + drivers/usb/typec/Makefile | 1 + + drivers/usb/typec/class.c | 15 + + drivers/usb/typec/typec_stusb.c | 918 +++++++++++++++++++++++++++++++++ + include/linux/usb/typec.h | 1 + + 19 files changed, 2265 insertions(+), 312 deletions(-) create mode 100644 drivers/usb/dwc2/drd.c create mode 100644 drivers/usb/typec/typec_stusb.c diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c -index e8d7a7b..fdcc214 100644 +index e8d7a7b..c6acbcf 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -24,6 +24,8 @@ @@ -57,77 +58,86 @@ index e8d7a7b..fdcc214 100644 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); +@@ -169,101 +168,193 @@ static int stm32_init_rs485(struct uart_port *port, + return 0; + } - if (threaded && stm32_port->rx_ch) { -+ if (stm32_port->rx_dma_cb == CALLBACK_CALLED) +-static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, +- bool threaded) ++/* Returns 1 when data is pending in pio mode and 0 when no data is pending. */ ++static int stm32_pending_rx_pio(struct uart_port *port, u32 *sr) + { + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- enum dma_status status; +- struct dma_tx_state state; + + *sr = readl_relaxed(port->membase + ofs->isr); ++ /* Get pending characters in RDR or FIFO */ ++ if (*sr & USART_SR_RXNE) { ++ /* ++ * Get all pending characters from the RDR or the FIFO when ++ * using interrupts ++ */ ++ if (!stm32_port->rx_ch) + return 1; - status = dmaengine_tx_status(stm32_port->rx_ch, - stm32_port->rx_ch->cookie, - &state); - if ((status == DMA_IN_PROGRESS) && + +- if (threaded && stm32_port->rx_ch) { +- status = dmaengine_tx_status(stm32_port->rx_ch, +- stm32_port->rx_ch->cookie, +- &state); +- if ((status == DMA_IN_PROGRESS) && - (*last_res != state.residue)) -+ (*last_res != state.residue)) { -+ stm32_port->rx_dma_cb = CALLBACK_IGNORED; ++ /* Handle only RX data errors when using dma */ ++ if (*sr & USART_SR_ERR_MASK) return 1; - else -+ } else { - return 0; -+ } - } else if (*sr & USART_SR_RXNE) { - return 1; +- 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) ++static unsigned long stm32_get_char_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -203,12 +206,18 @@ stm32_get_char(struct uart_port *port, u32 *sr, int *last_res) + unsigned long c; - if (stm32_port->rx_ch) { - c = stm32_port->rx_buf[RX_BUF_L - (*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; +- *last_res = RX_BUF_L; - return c; -+ if (stm32_port->rx_dma_cb == CALLBACK_CALLED) -+ stm32_port->rx_dma_cb = CALLBACK_NOT_CALLED; -+ } - } else { +- } else { - return readl_relaxed(port->membase + ofs->rdr); -+ c = readl_relaxed(port->membase + ofs->rdr); -+ /* apply RDR data mask */ -+ c &= stm32_port->rdr_mask; - } +- } ++ c = readl_relaxed(port->membase + ofs->rdr); ++ /* Apply RDR data mask */ ++ c &= stm32_port->rdr_mask; + + return c; } - static void stm32_receive_chars(struct uart_port *port, bool threaded) -@@ -216,44 +225,65 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) - struct tty_port *tport = &port->state->port; +-static void stm32_receive_chars(struct uart_port *port, bool threaded) ++static void stm32_receive_chars_pio(struct uart_port *port) + { +- struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -- unsigned long c; -+ unsigned long c, flags; + unsigned long c; u32 sr; char flag; - if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) - pm_wakeup_event(tport->tty->dev, 0); - -+ if (threaded) -+ spin_lock_irqsave(&port->lock, flags); -+ else -+ spin_lock(&port->lock); -+ - while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { +- if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) +- pm_wakeup_event(tport->tty->dev, 0); +- +- while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { ++ while (stm32_pending_rx_pio(port, &sr)) { sr |= USART_SR_DUMMY_RX; - c = stm32_get_char(port, &sr, &stm32_port->last_res); flag = TTY_NORMAL; @@ -148,7 +158,7 @@ index e8d7a7b..fdcc214 100644 + writel_relaxed(sr & USART_SR_ERR_MASK, + port->membase + ofs->icr); + -+ c = stm32_get_char(port, &sr, &stm32_port->last_res); ++ c = stm32_get_char_pio(port); + port->icount.rx++; if (sr & USART_SR_ERR_MASK) { - if (sr & USART_SR_LBD) { @@ -177,7 +187,7 @@ index e8d7a7b..fdcc214 100644 } sr &= port->read_status_mask; - +- - if (sr & USART_SR_LBD) - flag = TTY_BREAK; - else if (sr & USART_SR_PE) @@ -194,22 +204,105 @@ index e8d7a7b..fdcc214 100644 } if (uart_handle_sysrq_char(port, c)) -@@ -261,9 +291,12 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) + continue; uart_insert_char(port, sr, USART_SR_ORE, c, flag); } ++} ++ ++static void stm32_push_buffer_dma(struct uart_port *port, ++ unsigned int dma_size) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct tty_port *ttyport = &stm32_port->port.state->port; ++ unsigned char *dma_start; ++ int dma_count; ++ ++ dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); ++ dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); ++ port->icount.rx += dma_count; ++ stm32_port->last_res -= dma_count; ++ if (stm32_port->last_res == 0) ++ stm32_port->last_res = RX_BUF_L; ++} ++ ++static void stm32_receive_chars_dma(struct uart_port *port) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ unsigned int dma_size; ++ ++ /* ++ * DMA buffer is configured in cyclic mode and handles the rollback of ++ * the buffer. ++ */ ++ if (stm32_port->state.residue > stm32_port->last_res) { ++ /* Conditional first part: from last_res to end of dma buffer */ ++ dma_size = stm32_port->last_res; ++ stm32_push_buffer_dma(port, dma_size); ++ } - spin_unlock(&port->lock); ++ dma_size = stm32_port->last_res - stm32_port->state.residue; ++ stm32_push_buffer_dma(port, dma_size); ++} ++ ++static void stm32_receive_chars(struct uart_port *port, bool threaded) ++{ ++ struct tty_port *tport = &port->state->port; ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ unsigned long flags = 0; ++ u32 sr; ++ ++ if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) ++ pm_wakeup_event(tport->tty->dev, 0); ++ ++ if (threaded) ++ spin_lock_irqsave(&port->lock, flags); ++ else ++ spin_lock(&port->lock); ++ ++ if (stm32_port->rx_ch) { ++ stm32_port->status = ++ dmaengine_tx_status(stm32_port->rx_ch, ++ stm32_port->rx_ch->cookie, ++ &stm32_port->state); ++ if (stm32_port->status == DMA_IN_PROGRESS) { ++ /* Empty DMA buffer */ ++ stm32_receive_chars_dma(port); ++ sr = readl_relaxed(port->membase + ofs->isr); ++ if (sr & USART_SR_ERR_MASK) { ++ /* Disable DMA request line */ ++ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ ++ /* Switch to PIO mode handle the errors */ ++ stm32_receive_chars_pio(port); ++ ++ /* Switch back to DMA mode */ ++ stm32_set_bits(port, ofs->cr3, USART_CR3_DMAR); ++ } ++ } else { ++ /* Disable rx DMA */ ++ dmaengine_terminate_async(stm32_port->rx_ch); ++ stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ /* fall back to interrupt mode */ ++ dev_dbg(port->dev, ++ "DMA error, fallback to irq mode\n"); ++ stm32_receive_chars_pio(port); ++ } ++ } else { ++ stm32_receive_chars_pio(port); ++ } ++ + if (threaded) + spin_unlock_irqrestore(&port->lock, flags); + else + spin_unlock(&port->lock); -+ tty_flip_buffer_push(tport); - spin_lock(&port->lock); } static void stm32_tx_dma_complete(void *arg) -@@ -271,27 +304,39 @@ static void stm32_tx_dma_complete(void *arg) +@@ -271,27 +362,23 @@ static void stm32_tx_dma_complete(void *arg) struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32port->info->ofs; @@ -243,28 +336,12 @@ index e8d7a7b..fdcc214 100644 +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); ++ stm32_receive_chars(port, true); } static void stm32_transmit_chars_pio(struct uart_port *port) -@@ -299,27 +344,30 @@ static void stm32_transmit_chars_pio(struct uart_port *port) +@@ -299,27 +386,30 @@ static void stm32_transmit_chars_pio(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; @@ -309,7 +386,7 @@ index e8d7a7b..fdcc214 100644 } static void stm32_transmit_chars_dma(struct uart_port *port) -@@ -377,7 +425,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port) +@@ -377,7 +467,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port) /* Issue pending DMA TX requests */ dma_async_issue_pending(stm32port->tx_ch); @@ -317,7 +394,7 @@ index e8d7a7b..fdcc214 100644 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) +@@ -401,15 +490,18 @@ static void stm32_transmit_chars(struct uart_port *port) return; } @@ -342,7 +419,7 @@ index e8d7a7b..fdcc214 100644 if (stm32_port->tx_ch) stm32_transmit_chars_dma(port); -@@ -419,8 +469,12 @@ static void stm32_transmit_chars(struct uart_port *port) +@@ -419,8 +511,12 @@ static void stm32_transmit_chars(struct uart_port *port) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -357,7 +434,7 @@ index e8d7a7b..fdcc214 100644 } static irqreturn_t stm32_interrupt(int irq, void *ptr) -@@ -430,10 +484,12 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) +@@ -430,21 +526,30 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; @@ -372,8 +449,15 @@ index e8d7a7b..fdcc214 100644 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)) + +- if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) ++ /* ++ * rx errors in dma mode has to be handled ASAP to avoid overrun as the ++ * DMA request line has been masked by HW and rx data are stacking in ++ * FIFO. ++ */ ++ if (((sr & USART_SR_RXNE) && !stm32_port->rx_ch) || ++ ((sr & USART_SR_ERR_MASK) && stm32_port->rx_ch)) stm32_receive_chars(port, false); - if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) @@ -387,37 +471,24 @@ index e8d7a7b..fdcc214 100644 if (stm32_port->rx_ch) return IRQ_WAKE_THREAD; -@@ -456,13 +513,24 @@ static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) +@@ -455,14 +560,9 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) + static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; - struct stm32_port *stm32_port = to_stm32_port(port); -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -+ unsigned long flags; +- struct stm32_port *stm32_port = to_stm32_port(port); - 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); +- 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); -+ } ++ /* Receiver timeout irq for dma rx */ ++ stm32_receive_chars(port, true); return IRQ_HANDLED; } -@@ -472,7 +540,10 @@ static unsigned int stm32_tx_empty(struct uart_port *port) +@@ -472,7 +572,10 @@ static unsigned int stm32_tx_empty(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; @@ -429,7 +500,7 @@ index e8d7a7b..fdcc214 100644 } 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) +@@ -498,7 +601,15 @@ static void stm32_stop_tx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; @@ -446,7 +517,7 @@ index e8d7a7b..fdcc214 100644 } /* There are probably characters waiting to be transmitted. */ -@@ -512,6 +591,22 @@ static void stm32_start_tx(struct uart_port *port) +@@ -512,6 +623,23 @@ static void stm32_start_tx(struct uart_port *port) stm32_transmit_chars(port); } @@ -457,9 +528,10 @@ index e8d7a7b..fdcc214 100644 + 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); ++ /* Avoid deadlock with the DMA engine callback */ + spin_unlock(&port->lock); ++ dmaengine_terminate_async(stm32_port->tx_ch); ++ spin_lock(&port->lock); + + stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_port->tx_dma_busy = false; @@ -469,7 +541,7 @@ index e8d7a7b..fdcc214 100644 /* 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) +@@ -520,7 +648,10 @@ static void stm32_throttle(struct uart_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -481,7 +553,7 @@ index e8d7a7b..fdcc214 100644 spin_unlock_irqrestore(&port->lock, flags); } -@@ -532,7 +630,10 @@ static void stm32_unthrottle(struct uart_port *port) +@@ -532,7 +663,10 @@ static void stm32_unthrottle(struct uart_port *port) unsigned long flags; spin_lock_irqsave(&port->lock, flags); @@ -493,7 +565,7 @@ index e8d7a7b..fdcc214 100644 spin_unlock_irqrestore(&port->lock, flags); } -@@ -542,7 +643,10 @@ static void stm32_stop_rx(struct uart_port *port) +@@ -542,7 +676,10 @@ static void stm32_stop_rx(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; @@ -505,15 +577,18 @@ index e8d7a7b..fdcc214 100644 } /* Handle breaks - ignored by us */ -@@ -554,7 +658,6 @@ static int stm32_startup(struct uart_port *port) +@@ -554,8 +691,9 @@ static int stm32_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; ++ struct dma_async_tx_descriptor *desc = NULL; ++ dma_cookie_t cookie; u32 val; int ret; -@@ -565,18 +668,12 @@ static int stm32_startup(struct uart_port *port) + +@@ -565,18 +703,35 @@ static int stm32_startup(struct uart_port *port) if (ret) return ret; @@ -523,11 +598,32 @@ index e8d7a7b..fdcc214 100644 - if (ret) { - free_irq(port->irq, port); - return ret; -- } -- } + /* RX FIFO Flush */ + if (ofs->rqr != UNDEF_REG) + stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ); ++ ++ if (stm32_port->rx_ch) { ++ stm32_port->last_res = RX_BUF_L; ++ /* Prepare a DMA cyclic transaction */ ++ desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, ++ stm32_port->rx_dma_buf, ++ RX_BUF_L, RX_BUF_P, ++ DMA_DEV_TO_MEM, ++ DMA_PREP_INTERRUPT); ++ if (!desc) { ++ dev_err(port->dev, "rx dma prep cyclic failed\n"); ++ return -ENODEV; + } ++ ++ desc->callback = stm32_rx_dma_complete; ++ desc->callback_param = port; ++ ++ /* Push current DMA transaction in the pending queue */ ++ cookie = dmaengine_submit(desc); ++ ++ /* Issue pending DMA requests */ ++ dma_async_issue_pending(stm32_port->rx_ch); + } - val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; - if (stm32_port->fifoen) @@ -537,7 +633,7 @@ index e8d7a7b..fdcc214 100644 stm32_set_bits(port, ofs->cr1, val); return 0; -@@ -587,18 +684,62 @@ static void stm32_shutdown(struct uart_port *port) +@@ -587,18 +742,65 @@ static void stm32_shutdown(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; @@ -566,6 +662,9 @@ index e8d7a7b..fdcc214 100644 + if (stm32_port->fifoen) + stm32_clr_bits(port, ofs->cr3, + USART_CR3_TXFTIE | USART_CR3_RXFTIE); ++ ++ if (stm32_port->rx_ch) ++ dmaengine_terminate_async(stm32_port->rx_ch); + free_irq(port->irq, port); } @@ -603,7 +702,7 @@ index e8d7a7b..fdcc214 100644 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, +@@ -606,11 +808,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; struct serial_rs485 *rs485conf = &port->rs485; @@ -618,7 +717,7 @@ index e8d7a7b..fdcc214 100644 if (!stm32_port->hw_flow_control) cflag &= ~CRTSCTS; -@@ -619,29 +761,80 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -619,29 +822,80 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, spin_lock_irqsave(&port->lock, flags); @@ -707,7 +806,7 @@ index e8d7a7b..fdcc214 100644 if (cflag & PARODD) cr1 |= USART_CR1_PS; -@@ -679,14 +872,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -679,14 +933,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (termios->c_iflag & INPCK) port->read_status_mask |= USART_SR_PE | USART_SR_FE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) @@ -724,7 +823,25 @@ index e8d7a7b..fdcc214 100644 /* * 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, +@@ -699,8 +953,16 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= USART_SR_DUMMY_RX; + +- if (stm32_port->rx_ch) ++ if (stm32_port->rx_ch) { ++ /* ++ * Setup DMA to collect only valid data and enable error irqs. ++ * This also enables break reception when using dma. ++ */ ++ cr1 |= USART_CR1_PEIE; ++ cr3 |= USART_CR3_EIE; + cr3 |= USART_CR3_DMAR; ++ cr3 |= USART_CR3_DDRE; ++ } + + if (rs485conf->flags & SER_RS485_ENABLED) { + stm32_config_reg_rs485(&cr1, &cr3, +@@ -715,8 +977,10 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, } } else { @@ -737,7 +854,7 @@ index e8d7a7b..fdcc214 100644 } writel_relaxed(cr3, port->membase + ofs->cr3); -@@ -765,13 +960,13 @@ static void stm32_pm(struct uart_port *port, unsigned int state, +@@ -765,13 +1029,13 @@ static void stm32_pm(struct uart_port *port, unsigned int state, switch (state) { case UART_PM_STATE_ON: @@ -753,7 +870,7 @@ index e8d7a7b..fdcc214 100644 break; } } -@@ -788,6 +983,7 @@ static const struct uart_ops stm32_uart_ops = { +@@ -788,6 +1052,7 @@ static const struct uart_ops stm32_uart_ops = { .break_ctl = stm32_break_ctl, .startup = stm32_startup, .shutdown = stm32_shutdown, @@ -761,7 +878,7 @@ index e8d7a7b..fdcc214 100644 .set_termios = stm32_set_termios, .pm = stm32_pm, .type = stm32_type, -@@ -802,20 +998,60 @@ static int stm32_init_port(struct stm32_port *stm32port, +@@ -802,20 +1067,60 @@ static int stm32_init_port(struct stm32_port *stm32port, { struct uart_port *port = &stm32port->port; struct resource *res; @@ -825,7 +942,7 @@ index e8d7a7b..fdcc214 100644 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) +@@ -862,7 +1167,11 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) stm32_ports[id].hw_flow_control = of_property_read_bool(np, "st,hw-flow-ctrl"); stm32_ports[id].port.line = id; @@ -837,43 +954,75 @@ index e8d7a7b..fdcc214 100644 return &stm32_ports[id]; } -@@ -890,10 +1130,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, +@@ -884,15 +1193,15 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, + struct uart_port *port = &stm32port->port; + struct device *dev = &pdev->dev; + struct dma_slave_config config; +- struct dma_async_tx_descriptor *desc = NULL; +- dma_cookie_t cookie; + int ret; /* Request DMA RX channel */ - stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); +- 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; -- } +- return -ENODEV; ++ stm32port->rx_ch = dma_request_chan_linked(dev, "rx"); ++ if (IS_ERR(stm32port->rx_ch)) { ++ ret = PTR_ERR(stm32port->rx_ch); ++ stm32port->rx_ch = NULL; ++ dev_dbg(dev, "cannot get the DMA channel.\n"); ++ return ret; + } stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, &stm32port->rx_dma_buf, - GFP_KERNEL); -@@ -925,9 +1163,8 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, +@@ -914,27 +1223,6 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, goto config_err; } +- /* Prepare a DMA cyclic transaction */ +- desc = dmaengine_prep_dma_cyclic(stm32port->rx_ch, +- stm32port->rx_dma_buf, +- RX_BUF_L, RX_BUF_P, DMA_DEV_TO_MEM, +- DMA_PREP_INTERRUPT); +- if (!desc) { +- dev_err(dev, "rx dma prep cyclic failed\n"); +- ret = -ENODEV; +- goto config_err; +- } +- - /* No callback as dma buffer is drained on usart interrupt */ - desc->callback = NULL; - desc->callback_param = NULL; -+ desc->callback = stm32_rx_dma_complete; -+ desc->callback_param = port; +- +- /* Push current DMA transaction in the pending queue */ +- cookie = dmaengine_submit(desc); +- +- /* Issue pending DMA requests */ +- dma_async_issue_pending(stm32port->rx_ch); +- + return 0; - /* 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, + config_err: +@@ -943,7 +1231,7 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, + stm32port->rx_dma_buf); + alloc_err: +- dma_release_channel(stm32port->rx_ch); ++ dma_release_chan_linked(dev, stm32port->rx_ch); + stm32port->rx_ch = NULL; + + return ret; +@@ -963,7 +1251,7 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, /* Request DMA TX channel */ stm32port->tx_ch = dma_request_slave_channel(dev, "tx"); -- if (!stm32port->tx_ch) { + if (!stm32port->tx_ch) { - dev_info(dev, "tx dma alloc failed\n"); -+ if (!stm32port->tx_ch) ++ dev_dbg(dev, "cannot get the DMA channel.\n"); 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) +@@ -1020,15 +1308,18 @@ static int stm32_serial_probe(struct platform_device *pdev) if (ret) return ret; @@ -882,26 +1031,29 @@ index e8d7a7b..fdcc214 100644 ret = device_init_wakeup(&pdev->dev, true); if (ret) goto err_uninit; -+ +- } + +- ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); +- if (ret) +- goto err_nowup; + ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, + stm32port->wakeirq); + if (ret) + goto err_nowup; + + device_set_wakeup_enable(&pdev->dev, false); - } - - ret = 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) +@@ -1040,10 +1331,41 @@ static int stm32_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &stm32port->port); ++ ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); ++ if (ret) ++ goto err_dma; ++ + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); @@ -909,7 +1061,25 @@ index e8d7a7b..fdcc214 100644 + return 0; -+err_wirq: ++err_dma: ++ if (stm32port->rx_ch) ++ dma_release_chan_linked(&pdev->dev, stm32port->rx_ch); ++ ++ if (stm32port->rx_dma_buf) ++ dma_free_coherent(&pdev->dev, ++ RX_BUF_L, stm32port->rx_buf, ++ stm32port->rx_dma_buf); ++ ++ if (stm32port->tx_ch) { ++ dmaengine_terminate_async(stm32port->tx_ch); ++ dma_release_channel(stm32port->tx_ch); ++ } ++ ++ if (stm32port->tx_dma_buf) ++ dma_free_coherent(&pdev->dev, ++ TX_BUF_L, stm32port->tx_buf, ++ stm32port->tx_dma_buf); ++ + if (stm32port->wakeirq > 0) + dev_pm_clear_wake_irq(&pdev->dev); + @@ -919,26 +1089,33 @@ index e8d7a7b..fdcc214 100644 device_init_wakeup(&pdev->dev, false); err_uninit: -@@ -1057,12 +1308,16 @@ static int stm32_serial_remove(struct platform_device *pdev) +@@ -1057,12 +1379,22 @@ static int stm32_serial_remove(struct platform_device *pdev) struct uart_port *port = platform_get_drvdata(pdev); struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; + int err; -+ ++ u32 cr3; + +- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + pm_runtime_get_sync(&pdev->dev); ++ ++ err = uart_remove_one_port(&stm32_usart_driver, port); ++ ++ stm32_clr_bits(port, ofs->cr1, USART_CR1_PEIE); ++ cr3 = readl_relaxed(port->membase + ofs->cr3); ++ cr3 &= ~USART_CR3_EIE; ++ cr3 &= ~USART_CR3_DMAR; ++ cr3 &= ~USART_CR3_DDRE; ++ writel_relaxed(cr3, port->membase + ofs->cr3); - 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_ch) +- dma_release_channel(stm32_port->rx_ch); ++ dma_release_chan_linked(&pdev->dev, stm32_port->rx_ch); if (stm32_port->rx_dma_buf) dma_free_coherent(&pdev->dev, -@@ -1071,20 +1326,29 @@ static int stm32_serial_remove(struct platform_device *pdev) +@@ -1071,20 +1403,27 @@ static int stm32_serial_remove(struct platform_device *pdev) stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); @@ -962,8 +1139,6 @@ index e8d7a7b..fdcc214 100644 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); + @@ -971,7 +1146,7 @@ index e8d7a7b..fdcc214 100644 } -@@ -1195,7 +1459,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) +@@ -1195,7 +1534,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) struct stm32_usart_config *cfg = &stm32_port->info->cfg; u32 val; @@ -980,7 +1155,7 @@ index e8d7a7b..fdcc214 100644 return; if (enable) { -@@ -1207,21 +1471,36 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) +@@ -1207,21 +1546,36 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE; writel_relaxed(val, port->membase + ofs->cr3); stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); @@ -1021,7 +1196,7 @@ index e8d7a7b..fdcc214 100644 return 0; } -@@ -1230,14 +1509,40 @@ static int stm32_serial_resume(struct device *dev) +@@ -1230,14 +1584,40 @@ static int stm32_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); @@ -1064,7 +1239,7 @@ index e8d7a7b..fdcc214 100644 }; diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h -index 6f294e2..2a68bc4 100644 +index 6f294e2..ddd87c9 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -27,6 +27,7 @@ struct stm32_usart_config { @@ -1091,7 +1266,7 @@ index 6f294e2..2a68bc4 100644 } }; -@@ -96,6 +99,7 @@ struct stm32_usart_info stm32h7_info = { +@@ -96,19 +99,19 @@ struct stm32_usart_info stm32h7_info = { .has_7bits_data = true, .has_wakeup = true, .has_fifo = true, @@ -1099,7 +1274,13 @@ index 6f294e2..2a68bc4 100644 } }; -@@ -108,7 +112,6 @@ struct stm32_usart_info stm32h7_info = { + /* USART_SR (F4) / USART_ISR (F7) */ + #define USART_SR_PE BIT(0) + #define USART_SR_FE BIT(1) +-#define USART_SR_NF BIT(2) ++#define USART_SR_NE BIT(2) /* F7 (NF for F4) */ + #define USART_SR_ORE BIT(3) + #define USART_SR_IDLE BIT(4) #define USART_SR_RXNE BIT(5) #define USART_SR_TC BIT(6) #define USART_SR_TXE BIT(7) @@ -1107,13 +1288,14 @@ index 6f294e2..2a68bc4 100644 #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 = { +@@ -120,14 +123,11 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ -#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ - USART_SR_FE | USART_SR_PE) -+#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE) ++#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_NE | USART_SR_FE\ ++ | USART_SR_PE) /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) @@ -1123,7 +1305,7 @@ index 6f294e2..2a68bc4 100644 /* USART_DR */ #define USART_DR_MASK GENMASK(8, 0) -@@ -151,8 +150,7 @@ struct stm32_usart_info stm32h7_info = { +@@ -151,8 +151,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR1_PS BIT(9) #define USART_CR1_PCE BIT(10) #define USART_CR1_WAKE BIT(11) @@ -1133,7 +1315,7 @@ index 6f294e2..2a68bc4 100644 #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 = { +@@ -169,8 +168,6 @@ struct stm32_usart_info stm32h7_info = { /* USART_CR2 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ #define USART_CR2_ADDM7 BIT(4) /* F7 */ @@ -1142,7 +1324,7 @@ index 6f294e2..2a68bc4 100644 #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 = { +@@ -209,6 +206,19 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR3_WUS_MASK GENMASK(21, 20) /* H7 */ #define USART_CR3_WUS_START_BIT BIT(21) /* H7 */ #define USART_CR3_WUFIE BIT(22) /* H7 */ @@ -1162,7 +1344,7 @@ index 6f294e2..2a68bc4 100644 /* USART_GTPR */ #define USART_GTPR_PSC_MASK GENMASK(7, 0) -@@ -227,12 +236,10 @@ struct stm32_usart_info stm32h7_info = { +@@ -227,12 +237,10 @@ struct stm32_usart_info stm32h7_info = { /* USART_ICR */ #define USART_ICR_PECF BIT(0) /* F7 */ @@ -1176,38 +1358,34 @@ index 6f294e2..2a68bc4 100644 #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 = { +@@ -242,9 +250,9 @@ struct stm32_usart_info stm32h7_info = { #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 -#define RX_BUF_L 200 /* dma rx buffer length */ -+#define RX_BUF_L 160 /* dma rx buffer length */ - #define RX_BUF_P RX_BUF_L /* dma rx buffer period */ +-#define RX_BUF_P RX_BUF_L /* dma rx buffer period */ -#define TX_BUF_L 200 /* dma tx buffer length */ ++#define RX_BUF_L 4096 /* dma rx buffer length */ ++#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ +#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ -+ -+enum dma_cb { -+ CALLBACK_NOT_CALLED, -+ CALLBACK_CALLED, -+ CALLBACK_IGNORED, -+}; struct stm32_port { struct uart_port port; -@@ -256,11 +269,16 @@ struct stm32_port { +@@ -256,11 +264,17 @@ struct stm32_port { struct dma_chan *tx_ch; /* dma tx channel */ dma_addr_t tx_dma_buf; /* dma tx buffer bus address */ unsigned char *tx_buf; /* dma tx buffer cpu address */ + u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */ + u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; -+ 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 */ ++ struct dma_tx_state state; ++ enum dma_status status; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; @@ -1225,7 +1403,7 @@ index 440320c..2bcd694 100644 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 +index 633ba01..8ad88d2 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -83,6 +83,7 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) @@ -1811,7 +1989,7 @@ index 0000000..7d812b7 + return 0; +} diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c -index 03614ef..3ebd5dd 100644 +index 3f68edd..3ebd5dd 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -123,6 +123,24 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep) @@ -1891,48 +2069,7 @@ index 03614ef..3ebd5dd 100644 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, +@@ -3322,6 +3378,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK); } @@ -1943,7 +2080,7 @@ index 03614ef..3ebd5dd 100644 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, +@@ -3378,6 +3438,10 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, /* configure the core to support LPM */ dwc2_gadget_init_lpm(hsotg); @@ -1954,7 +2091,7 @@ index 03614ef..3ebd5dd 100644 /* 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, +@@ -3390,7 +3454,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, dwc2_readl(hsotg, DOEPCTL0)); } @@ -1963,7 +2100,7 @@ index 03614ef..3ebd5dd 100644 { /* 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) +@@ -3399,7 +3463,8 @@ static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) { /* remove the soft-disconnect and let's go */ @@ -1973,7 +2110,7 @@ index 03614ef..3ebd5dd 100644 } /** -@@ -3674,6 +3751,10 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) +@@ -3686,6 +3751,10 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) goto irq_retry; @@ -1984,84 +2121,16 @@ index 03614ef..3ebd5dd 100644 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) +@@ -4795,7 +4864,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) hsotg->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock_irqrestore(&hsotg->lock, flags); - for (ep = 0; ep < hsotg->num_of_eps; ep++) { + for (ep = 1; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) -- dwc2_hsotg_ep_disable(&hsotg->eps_in[ep]->ep); -+ dwc2_hsotg_ep_disable_lock(&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) +@@ -4966,8 +5035,32 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; @@ -2095,7 +2164,7 @@ index 03614ef..3ebd5dd 100644 /** diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c -index 260010a..7f128b1 100644 +index a5c8329..67bbf94 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -125,7 +125,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) @@ -2162,113 +2231,26 @@ index 260010a..7f128b1 100644 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; +@@ -1934,7 +1912,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) + * release_channel_ddma(), which is called from ep_disable when + * device disconnects + */ +- channel->qh = NULL; ++ if (hsotg->params.host_dma && hsotg->params.dma_desc_enable) ++ channel->qh = NULL; + } + /* All channels have been freed, mark them available */ + if (hsotg->params.uframe_sched) { +@@ -3804,7 +3783,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) + goto error; - 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); - } +- if (!hsotg->flags.b.port_connect_status) { ++ if (!hsotg->flags.b.port_connect_status && ++ !dwc2_is_host_mode(hsotg)) { + /* + * The port is disconnected, which means the core is + * either in device mode or it soon will be. Just diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 0ca8e7b..7500954 100644 --- a/drivers/usb/dwc2/hw.h @@ -2341,18 +2323,10 @@ index 0ca8e7b..7500954 100644 #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 +index a93415f..8af461c 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) +@@ -152,6 +152,36 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) p->host_perio_tx_fifo_size = 256; } @@ -2370,6 +2344,7 @@ index dff2c6e..ce4657c 100644 + p->i2c_enable = false; + p->activate_stm_fs_transceiver = true; + p->activate_stm_id_vb_detection = true; ++ p->power_down = DWC2_POWER_DOWN_PARAM_NONE; +} + +static void dwc2_set_stm32mp1_hsotg_params(struct dwc2_hsotg *hsotg) @@ -2388,7 +2363,7 @@ index dff2c6e..ce4657c 100644 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[] = { +@@ -173,6 +203,10 @@ const struct of_device_id dwc2_of_match_table[] = { { .compatible = "st,stm32f4x9-hsotg" }, { .compatible = "st,stm32f7-hsotg", .data = dwc2_set_stm32f7_hsotg_params }, @@ -2399,7 +2374,7 @@ index dff2c6e..ce4657c 100644 {}, }; MODULE_DEVICE_TABLE(of, dwc2_of_match_table); -@@ -308,9 +342,12 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) +@@ -309,9 +343,12 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) p->hird_threshold_en = true; p->hird_threshold = 4; p->ipg_isoc_en = false; @@ -2412,7 +2387,7 @@ index dff2c6e..ce4657c 100644 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) +@@ -602,6 +639,7 @@ static void dwc2_check_params(struct dwc2_hsotg *hsotg) CHECK_BOOL(besl, (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a)); CHECK_BOOL(hird_threshold_en, hsotg->params.lpm); CHECK_RANGE(hird_threshold, 0, hsotg->params.besl ? 12 : 7, 0); @@ -2420,7 +2395,7 @@ index dff2c6e..ce4657c 100644 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) +@@ -790,6 +828,8 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; hw->acg_enable = !!(hwcfg4 & GHWCFG4_ACG_SUPPORTED); hw->ipg_isoc_en = !!(hwcfg4 & GHWCFG4_IPG_ISOC_SUPPORTED); @@ -2674,6 +2649,112 @@ index 5776428..3d61100 100644 if (dwc2_is_device_mode(dwc2)) ret = dwc2_hsotg_resume(dwc2); +diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c +index d4d317d..bb1e2e1 100644 +--- a/drivers/usb/gadget/function/u_serial.c ++++ b/drivers/usb/gadget/function/u_serial.c +@@ -16,7 +16,6 @@ + + #include + #include +-#include + #include + #include + #include +@@ -26,6 +25,7 @@ + #include + #include + #include ++#include + #include + + #include "u_serial.h" +@@ -110,7 +110,7 @@ struct gs_port { + int read_allocated; + struct list_head read_queue; + unsigned n_read; +- struct tasklet_struct push; ++ struct delayed_work push; + + struct list_head write_pool; + int write_started; +@@ -352,9 +352,10 @@ __acquires(&port->port_lock) + * So QUEUE_SIZE packets plus however many the FIFO holds (usually two) + * can be buffered before the TTY layer's buffers (currently 64 KB). + */ +-static void gs_rx_push(unsigned long _port) ++static void gs_rx_push(struct work_struct *work) + { +- struct gs_port *port = (void *)_port; ++ struct delayed_work *w = to_delayed_work(work); ++ struct gs_port *port = container_of(w, struct gs_port, push); + struct tty_struct *tty; + struct list_head *queue = &port->read_queue; + bool disconnect = false; +@@ -429,21 +430,13 @@ static void gs_rx_push(unsigned long _port) + + /* We want our data queue to become empty ASAP, keeping data + * in the tty and ldisc (not here). If we couldn't push any +- * this time around, there may be trouble unless there's an +- * implicit tty_unthrottle() call on its way... ++ * this time around, RX may be starved, so wait until next jiffy. + * +- * REVISIT we should probably add a timer to keep the tasklet +- * from starving ... but it's not clear that case ever happens. ++ * We may leave non-empty queue only when there is a tty, and ++ * either it is throttled or there is no more room in flip buffer. + */ +- if (!list_empty(queue) && tty) { +- if (!tty_throttled(tty)) { +- if (do_push) +- tasklet_schedule(&port->push); +- else +- pr_warn("ttyGS%d: RX not scheduled?\n", +- port->port_num); +- } +- } ++ if (!list_empty(queue) && !tty_throttled(tty)) ++ schedule_delayed_work(&port->push, 1); + + /* If we're still connected, refill the USB RX queue. */ + if (!disconnect && port->port_usb) +@@ -459,7 +452,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req) + /* Queue all received data until the tty layer is ready for it. */ + spin_lock(&port->port_lock); + list_add_tail(&req->list, &port->read_queue); +- tasklet_schedule(&port->push); ++ schedule_delayed_work(&port->push, 0); + spin_unlock(&port->port_lock); + } + +@@ -854,8 +847,8 @@ static void gs_unthrottle(struct tty_struct *tty) + * rts/cts, or other handshaking with the host, but if the + * read queue backs up enough we'll be NAKing OUT packets. + */ +- tasklet_schedule(&port->push); + pr_vdebug("ttyGS%d: unthrottle\n", port->port_num); ++ schedule_delayed_work(&port->push, 0); + } + spin_unlock_irqrestore(&port->port_lock, flags); + } +@@ -1159,7 +1152,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) + init_waitqueue_head(&port->drain_wait); + init_waitqueue_head(&port->close_wait); + +- tasklet_init(&port->push, gs_rx_push, (unsigned long) port); ++ INIT_DELAYED_WORK(&port->push, gs_rx_push); + + INIT_LIST_HEAD(&port->read_pool); + INIT_LIST_HEAD(&port->read_queue); +@@ -1186,7 +1179,7 @@ static int gs_closed(struct gs_port *port) + + static void gserial_free_port(struct gs_port *port) + { +- tasklet_kill(&port->push); ++ cancel_delayed_work_sync(&port->push); + /* wait for old opens to finish */ + wait_event(port->close_wait, gs_closed(port)); + WARN_ON(port->port_usb != NULL); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 4c306fb..b915c0f 100644 --- a/drivers/usb/host/ehci-platform.c @@ -2842,7 +2923,7 @@ index 45b0aef..aedb153 100644 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 +index 1916ee1..df4cadd 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1382,6 +1382,21 @@ void typec_set_pwr_opmode(struct typec_port *port, diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0026-ARM-stm32mp1-r2-WATCHDOG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch similarity index 84% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0026-ARM-stm32mp1-r2-WATCHDOG.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch index c02913e..e98714d 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0026-ARM-stm32mp1-r2-WATCHDOG.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch @@ -1,18 +1,18 @@ -From cbd843990c118aaf21b72565d68b852bea8cae1b Mon Sep 17 00:00:00 2001 +From 918e6c75e00bcae7481c4560ebbca237d991b2c0 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 +Date: Fri, 8 Nov 2019 16:52:48 +0100 +Subject: [PATCH 27/31] ARM stm32mp1 r3 WATCHDOG --- drivers/watchdog/Kconfig | 12 ++++ drivers/watchdog/Makefile | 1 + - drivers/watchdog/stm32_iwdg.c | 65 +++++++++++-------- - drivers/watchdog/stpmic1_wdt.c | 139 +++++++++++++++++++++++++++++++++++++++++ - 4 files changed, 192 insertions(+), 25 deletions(-) + drivers/watchdog/stm32_iwdg.c | 83 ++++++++++++++++-------- + drivers/watchdog/stpmic1_wdt.c | 140 +++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 211 insertions(+), 25 deletions(-) create mode 100644 drivers/watchdog/stpmic1_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 5ea8909..6d2ffef 100644 +index b165c46..9790eca 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -806,6 +806,18 @@ config STM32_WATCHDOG @@ -44,7 +44,7 @@ index bf92e7b..2649cf3 100644 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 +index e00e3b3..56a3ffd 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -34,18 +34,10 @@ @@ -185,12 +185,37 @@ index e00e3b3..2208e8c 100644 wdd->parent = &pdev->dev; watchdog_set_drvdata(wdd, wdt); +@@ -243,6 +258,24 @@ static int stm32_iwdg_probe(struct platform_device *pdev) + dev_warn(&pdev->dev, + "unable to set timeout value, using default\n"); + ++ /* ++ * In case of CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is set ++ * (Means U-Boot/bootloaders leaves the watchdog running) ++ * When we get here we should make a decision to prevent ++ * any side effects before user space daemon will take care of it. ++ * The best option, taking into consideration that there is no ++ * way to read values back from hardware, is to enforce watchdog ++ * being run with deterministic values. ++ */ ++ if (IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) { ++ ret = stm32_iwdg_start(wdd); ++ if (ret) ++ return ret; ++ ++ /* Make sure the watchdog is serviced */ ++ set_bit(WDOG_HW_RUNNING, &wdd->status); ++ } ++ + ret = watchdog_register_device(wdd); + if (ret) { + dev_err(&pdev->dev, "failed to register watchdog device\n"); diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c new file mode 100644 -index 0000000..a6cbc27 +index 0000000..45d0c54 --- /dev/null +++ b/drivers/watchdog/stpmic1_wdt.c -@@ -0,0 +1,139 @@ +@@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet for STMicroelectronics. @@ -217,9 +242,8 @@ index 0000000..a6cbc27 + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); -+MODULE_PARM_DESC(nowayout, -+ "Watchdog cannot be stopped once started (default=" -+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); ++MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" ++ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +struct stpmic1_wdt { + struct stpmic1 *pmic; @@ -275,18 +299,19 @@ index 0000000..a6cbc27 + +static int pmic_wdt_probe(struct platform_device *pdev) +{ ++ struct device *dev = &pdev->dev; + int ret; + struct stpmic1 *pmic; + struct stpmic1_wdt *wdt; + -+ if (!pdev->dev.parent) ++ if (!dev->parent) + return -EINVAL; + -+ pmic = dev_get_drvdata(pdev->dev.parent); ++ pmic = dev_get_drvdata(dev->parent); + if (!pmic) + return -EINVAL; + -+ wdt = devm_kzalloc(&pdev->dev, sizeof(struct stpmic1_wdt), GFP_KERNEL); ++ wdt = devm_kzalloc(dev, sizeof(struct stpmic1_wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + @@ -296,14 +321,15 @@ index 0000000..a6cbc27 + wdt->wdtdev.ops = &pmic_watchdog_ops; + wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT; + wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT; ++ wdt->wdtdev.parent = dev; + + wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT; -+ watchdog_init_timeout(&wdt->wdtdev, 0, &pdev->dev); ++ watchdog_init_timeout(&wdt->wdtdev, 0, dev); + + watchdog_set_nowayout(&wdt->wdtdev, nowayout); + watchdog_set_drvdata(&wdt->wdtdev, wdt); + -+ ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev); ++ ret = devm_watchdog_register_device(dev, &wdt->wdtdev); + if (ret) + return ret; + diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0027-ARM-stm32mp1-r2-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch similarity index 76% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0027-ARM-stm32mp1-r2-SOUND.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch index c4eccb9..24e1f9b 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0027-ARM-stm32mp1-r2-SOUND.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch @@ -1,22 +1,22 @@ -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 +From f3a6e1e545c6a1810b2560ea821a3ed61b751d60 Mon Sep 17 00:00:00 2001 +From: Romuald JEANNE +Date: Mon, 20 Jan 2020 18:09:29 +0100 +Subject: [PATCH 28/31] ARM stm32mp1 r3 SOUND --- sound/soc/codecs/Kconfig | 4 +- - sound/soc/codecs/cs42l51-i2c.c | 34 +++- - sound/soc/codecs/cs42l51.c | 231 +++++++++++++++++++++-- - sound/soc/codecs/cs42l51.h | 21 +++ - sound/soc/codecs/wm8994.c | 80 +++++++- + sound/soc/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(-) + sound/soc/stm/stm32_adfsdm.c | 52 +++- + sound/soc/stm/stm32_i2s.c | 186 +++++++++----- + sound/soc/stm/stm32_sai.c | 134 ++++++++-- + sound/soc/stm/stm32_sai.h | 59 ++++- + sound/soc/stm/stm32_sai_sub.c | 562 +++++++++++++++++++++++++++++++++-------- + sound/soc/stm/stm32_spdifrx.c | 132 ++++++++-- + 12 files changed, 1245 insertions(+), 251 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efb095d..58161d1 100644 @@ -502,7 +502,7 @@ index 0ca8054..a086f7e 100644 #endif diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c -index 14f1b0c..c83ae39 100644 +index 01acb8d..c902ac7 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -11,6 +11,7 @@ @@ -513,7 +513,7 @@ index 14f1b0c..c83ae39 100644 #include #include #include -@@ -839,6 +840,42 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, +@@ -844,6 +845,42 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w, return 0; } @@ -556,7 +556,7 @@ index 14f1b0c..c83ae39 100644 static void vmid_reference(struct snd_soc_component *component) { struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); -@@ -1156,7 +1193,6 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, +@@ -1161,7 +1198,6 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, else adc = WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA; @@ -564,7 +564,7 @@ index 14f1b0c..c83ae39 100644 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[] = { +@@ -1780,6 +1816,16 @@ static const struct snd_soc_dapm_widget wm8994_specific_dapm_widgets[] = { SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux), }; @@ -581,7 +581,7 @@ index 14f1b0c..c83ae39 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 +2045,10 @@ static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { +@@ -2004,10 +2050,10 @@ static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { }; static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { @@ -596,7 +596,7 @@ index 14f1b0c..c83ae39 100644 { "MICBIAS1", NULL, "CLK_SYS" }, { "MICBIAS1", NULL, "MICBIAS Supply" }, { "MICBIAS2", NULL, "CLK_SYS" }, -@@ -2376,11 +2422,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, +@@ -2381,11 +2427,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, { struct snd_soc_component *component = dai->component; struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); @@ -623,7 +623,7 @@ index 14f1b0c..c83ae39 100644 break; default: -@@ -3990,6 +4051,7 @@ static int wm8994_component_probe(struct snd_soc_component *component) +@@ -3995,6 +4056,7 @@ static int wm8994_component_probe(struct snd_soc_component *component) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct wm8994 *control = dev_get_drvdata(component->dev->parent); @@ -631,8 +631,8 @@ index 14f1b0c..c83ae39 100644 struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component); unsigned int reg; int ret, i; -@@ -4271,6 +4333,14 @@ static int wm8994_component_probe(struct snd_soc_component *component) - case WM8994: +@@ -4278,6 +4340,14 @@ static int wm8994_component_probe(struct snd_soc_component *component) + ARRAY_SIZE(wm8994_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, ARRAY_SIZE(wm8994_specific_dapm_widgets)); + if (pdata->mclk1) @@ -659,7 +659,7 @@ 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 24948b9..3a4d2c8 100644 +index 24948b95..33de130 100644 --- a/sound/soc/stm/stm32_adfsdm.c +++ b/sound/soc/stm/stm32_adfsdm.c @@ -18,6 +18,7 @@ @@ -695,13 +695,13 @@ index 24948b9..3a4d2c8 100644 .name = "stm32_dfsdm_audio", }; -+void memcpy_32to16(void *dest, const void *src, size_t n) ++void stm32_memcpy_32to16(void *dest, const void *src, size_t n) +{ + unsigned int i = 0; + u16 *d = (u16 *)dest, *s = (u16 *)src; + + s++; -+ for (i = n; i > 0; i--) { ++ for (i = n >> 1; i > 0; i--) { + *d++ = *s++; + s++; + } @@ -734,8 +734,8 @@ index 24948b9..3a4d2c8 100644 - 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); ++ stm32_memcpy_32to16(&pcm_buff[priv->pos], src_buff, ++ buff_size - priv->pos); + else + memcpy(&pcm_buff[priv->pos], src_buff, + buff_size - priv->pos); @@ -745,8 +745,8 @@ index 24948b9..3a4d2c8 100644 - 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); ++ stm32_memcpy_32to16(&pcm_buff[priv->pos], ++ &src_buff[src_size - cur_size], cur_size); + else + memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size], + cur_size); @@ -759,7 +759,7 @@ index 24948b9..3a4d2c8 100644 return 0; diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c -index 6d0bf78..490352c 100644 +index aa2b119..490352c 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -16,6 +16,7 @@ @@ -841,17 +841,6 @@ index 6d0bf78..490352c 100644 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; - } - -- regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, -- I2S_IFCR_MASK, flags); -+ regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, -+ I2S_IFCR_MASK, flags); - - if (flags & I2S_SR_OVR) { - dev_dbg(&pdev->dev, "Overrun\n"); @@ -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"); @@ -864,11 +853,10 @@ index 6d0bf78..490352c 100644 return IRQ_HANDLED; } -@@ -276,10 +299,12 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) +@@ -276,9 +299,12 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) case STM32_I2S_CFG2_REG: case STM32_I2S_IER_REG: case STM32_I2S_SR_REG: -- case STM32_I2S_IFCR_REG: - case STM32_I2S_TXDR_REG: case STM32_I2S_RXDR_REG: case STM32_I2S_CGFR_REG: @@ -879,7 +867,7 @@ index 6d0bf78..490352c 100644 return true; default: return false; -@@ -289,7 +314,7 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) +@@ -288,7 +314,7 @@ static bool stm32_i2s_readable_reg(struct device *dev, unsigned int reg) static bool stm32_i2s_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -888,12 +876,7 @@ index 6d0bf78..490352c 100644 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); -- u32 cfgr, cfgr_mask, cfg1, cfg1_mask; -+ u32 cfgr, cfgr_mask, cfg1; +@@ -491,12 +517,6 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, unsigned int fthlv; int ret; @@ -906,29 +889,7 @@ index 6d0bf78..490352c 100644 switch (format) { case 16: cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_16); -- cfgr_mask = I2S_CGFR_DATLEN_MASK; -+ cfgr_mask = I2S_CGFR_DATLEN_MASK | I2S_CGFR_CHLEN; - break; - case 32: - cfgr = I2S_CGFR_DATLEN_SET(I2S_I2SMOD_DATLEN_32) | -@@ -529,30 +548,36 @@ static int stm32_i2s_configure(struct snd_soc_dai *cpu_dai, - if (ret < 0) - return ret; - -- cfg1 = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; -- cfg1_mask = cfg1; -- - fthlv = STM32_I2S_FIFO_SIZE * I2S_FIFO_TH_ONE_QUARTER / 4; -- cfg1 |= I2S_CFG1_FTHVL_SET(fthlv - 1); -- cfg1_mask |= I2S_CFG1_FTHVL_MASK; -+ cfg1 = I2S_CFG1_FTHVL_SET(fthlv - 1); - - return regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, -- cfg1_mask, cfg1); -+ I2S_CFG1_FTHVL_MASK, cfg1); - } - - static int stm32_i2s_startup(struct snd_pcm_substream *substream, +@@ -539,12 +559,22 @@ static int stm32_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); @@ -945,35 +906,26 @@ index 6d0bf78..490352c 100644 + 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_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 +612,12 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + return regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); +@@ -582,7 +612,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* Enable i2s */ - dev_dbg(cpu_dai->dev, "start I2S\n"); + dev_dbg(cpu_dai->dev, "start I2S %s\n", + playback_flg ? "playback" : "capture"); -+ -+ cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; -+ regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, -+ cfg1_mask, cfg1_mask); - ret = regmap_update_bits(i2s->regmap, STM32_I2S_CR1_REG, - I2S_CR1_SPE, I2S_CR1_SPE); -@@ -596,28 +626,29 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; + regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, +@@ -595,8 +626,8 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, return ret; } @@ -984,12 +936,9 @@ index 6d0bf78..490352c 100644 if (ret < 0) { dev_err(cpu_dai->dev, "Error %d starting I2S\n", ret); return ret; - } - -- regmap_update_bits(i2s->regmap, STM32_I2S_IFCR_REG, -- I2S_IFCR_MASK, I2S_IFCR_MASK); -+ regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, -+ I2S_IFCR_MASK, I2S_IFCR_MASK); +@@ -605,18 +636,19 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + regmap_write_bits(i2s->regmap, STM32_I2S_IFCR_REG, + I2S_IFCR_MASK, I2S_IFCR_MASK); + spin_lock(&i2s->lock_fd); + i2s->refcount++; @@ -1011,7 +960,7 @@ index 6d0bf78..490352c 100644 if (STM32_I2S_IS_SLAVE(i2s)) ier |= I2S_IER_TIFREIE; -@@ -627,6 +658,9 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, +@@ -626,6 +658,9 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -1021,7 +970,7 @@ index 6d0bf78..490352c 100644 if (playback_flg) regmap_update_bits(i2s->regmap, STM32_I2S_IER_REG, I2S_IER_UDRIE, -@@ -642,16 +676,15 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, +@@ -641,16 +676,15 @@ static int stm32_i2s_trigger(struct snd_pcm_substream *substream, int cmd, spin_unlock(&i2s->lock_fd); break; } @@ -1040,7 +989,7 @@ index 6d0bf78..490352c 100644 cfg1_mask = I2S_CFG1_RXDMAEN | I2S_CFG1_TXDMAEN; regmap_update_bits(i2s->regmap, STM32_I2S_CFG1_REG, -@@ -668,11 +701,16 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, +@@ -667,11 +701,16 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); @@ -1059,7 +1008,7 @@ index 6d0bf78..490352c 100644 } static int stm32_i2s_dai_probe(struct snd_soc_dai *cpu_dai) -@@ -698,11 +736,13 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { +@@ -697,11 +736,13 @@ static const struct regmap_config stm32_h7_i2s_regmap_conf = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -1074,7 +1023,7 @@ index 6d0bf78..490352c 100644 }; 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 = { +@@ -716,7 +757,8 @@ static const struct snd_soc_dai_ops stm32_i2s_pcm_dai_ops = { static const struct snd_pcm_hardware stm32_i2s_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, .buffer_bytes_max = 8 * PAGE_SIZE, @@ -1084,7 +1033,7 @@ index 6d0bf78..490352c 100644 .periods_min = 2, .periods_max = 8, }; -@@ -753,12 +794,8 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, +@@ -752,12 +794,8 @@ static int stm32_i2s_dais_init(struct platform_device *pdev, if (!dai_ptr) return -ENOMEM; @@ -1097,7 +1046,7 @@ index 6d0bf78..490352c 100644 dai_ptr->id = 1; stm32_i2s_dai_init(&dai_ptr->playback, "playback"); stm32_i2s_dai_init(&dai_ptr->capture, "capture"); -@@ -828,8 +865,9 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, +@@ -827,8 +865,9 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, /* Get irqs */ irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -1109,7 +1058,7 @@ index 6d0bf78..490352c 100644 } 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, +@@ -852,6 +891,7 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, static int stm32_i2s_probe(struct platform_device *pdev) { struct stm32_i2s_data *i2s; @@ -1117,7 +1066,7 @@ index 6d0bf78..490352c 100644 int ret; i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); -@@ -866,76 +905,94 @@ static int stm32_i2s_probe(struct platform_device *pdev) +@@ -865,76 +905,94 @@ static int stm32_i2s_probe(struct platform_device *pdev) i2s->pdev = pdev; i2s->ms_flg = I2S_MS_NOT_SET; spin_lock_init(&i2s->lock_fd); @@ -1241,7 +1190,7 @@ index 6d0bf78..490352c 100644 module_platform_driver(stm32_i2s_driver); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c -index f226542..d6763a1 100644 +index 540c4a0..d6763a1 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -21,6 +21,8 @@ @@ -1284,7 +1233,7 @@ index f226542..d6763a1 100644 -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); @@ -1293,7 +1242,7 @@ index f226542..d6763a1 100644 +} + +static int stm32_sai_pclk_enable(struct device *dev) - { ++{ + struct stm32_sai_data *sai = dev_get_drvdata(dev); int ret; @@ -1353,33 +1302,31 @@ index f226542..d6763a1 100644 return 0; } -@@ -112,16 +138,22 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, - if (!sai_provider) { +@@ -113,19 +139,20 @@ static int stm32_sai_set_sync(struct stm32_sai_data *sai_client, dev_err(&sai_client->pdev->dev, "SAI sync provider data not found\n"); -- return -EINVAL; -+ ret = -EINVAL; + ret = -EINVAL; +- goto out_put_dev; + goto error; } /* Configure sync client */ ret = stm32_sai_sync_conf_client(sai_client, synci); if (ret < 0) -- return ret; +- goto out_put_dev; + goto error; /* Configure sync provider */ -- return stm32_sai_sync_conf_provider(sai_provider, synco); -+ ret = stm32_sai_sync_conf_provider(sai_provider, synco); -+ + ret = stm32_sai_sync_conf_provider(sai_provider, synco); + +-out_put_dev: +error: -+ put_device(&pdev->dev); + put_device(&pdev->dev); + of_node_put(np_provider); -+ return ret; + return ret; } - static int stm32_sai_probe(struct platform_device *pdev) -@@ -130,6 +162,8 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -135,6 +162,8 @@ static int stm32_sai_probe(struct platform_device *pdev) struct reset_control *rst; struct resource *res; const struct of_device_id *of_id; @@ -1388,7 +1335,7 @@ index f226542..d6763a1 100644 sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); if (!sai) -@@ -142,7 +176,8 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -147,7 +176,8 @@ static int stm32_sai_probe(struct platform_device *pdev) of_id = of_match_device(stm32_sai_ids, &pdev->dev); if (of_id) @@ -1398,7 +1345,7 @@ index f226542..d6763a1 100644 else return -EINVAL; -@@ -181,6 +216,30 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -186,6 +216,30 @@ static int stm32_sai_probe(struct platform_device *pdev) reset_control_deassert(rst); } @@ -1429,7 +1376,7 @@ index f226542..d6763a1 100644 sai->pdev = pdev; sai->set_sync = &stm32_sai_set_sync; platform_set_drvdata(pdev, sai); -@@ -188,12 +247,54 @@ static int stm32_sai_probe(struct platform_device *pdev) +@@ -193,12 +247,54 @@ static int stm32_sai_probe(struct platform_device *pdev) return devm_of_platform_populate(&pdev->dev); } @@ -1605,7 +1552,7 @@ index f254221..158c73f 100644 + u32 gcr; }; diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c -index 2fb2b91..24f13ea 100644 +index 6c2e69e..8225665 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -17,6 +17,7 @@ @@ -1700,7 +1647,64 @@ index 2fb2b91..24f13ea 100644 case STM_SAI_CLRFR_REGX: case STM_SAI_DR_REGX: case STM_SAI_PDMCR_REGX: -@@ -195,6 +206,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { +@@ -186,6 +197,56 @@ static bool stm32_sai_sub_writeable_reg(struct device *dev, unsigned int reg) + } + } + ++static int stm32_sai_sub_reg_up(struct stm32_sai_sub_data *sai, ++ unsigned int reg, unsigned int mask, ++ unsigned int val) ++{ ++ int ret; ++ ++ ret = clk_enable(sai->pdata->pclk); ++ if (ret < 0) ++ return ret; ++ ++ ret = regmap_update_bits(sai->regmap, reg, mask, val); ++ ++ clk_disable(sai->pdata->pclk); ++ ++ return ret; ++} ++ ++static int stm32_sai_sub_reg_wr(struct stm32_sai_sub_data *sai, ++ unsigned int reg, unsigned int mask, ++ unsigned int val) ++{ ++ int ret; ++ ++ ret = clk_enable(sai->pdata->pclk); ++ if (ret < 0) ++ return ret; ++ ++ ret = regmap_write_bits(sai->regmap, reg, mask, val); ++ ++ clk_disable(sai->pdata->pclk); ++ ++ return ret; ++} ++ ++static int stm32_sai_sub_reg_rd(struct stm32_sai_sub_data *sai, ++ unsigned int reg, unsigned int *val) ++{ ++ int ret; ++ ++ ret = clk_enable(sai->pdata->pclk); ++ if (ret < 0) ++ return ret; ++ ++ ret = regmap_read(sai->regmap, reg, val); ++ ++ clk_disable(sai->pdata->pclk); ++ ++ return ret; ++} ++ + static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { + .reg_bits = 32, + .reg_stride = 4, +@@ -195,6 +256,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_f4 = { .volatile_reg = stm32_sai_sub_volatile_reg, .writeable_reg = stm32_sai_sub_writeable_reg, .fast_io = true, @@ -1708,7 +1712,7 @@ index 2fb2b91..24f13ea 100644 }; 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 = { +@@ -206,6 +268,7 @@ static const struct regmap_config stm32_sai_sub_regmap_config_h7 = { .volatile_reg = stm32_sai_sub_volatile_reg, .writeable_reg = stm32_sai_sub_writeable_reg, .fast_io = true, @@ -1716,7 +1720,7 @@ index 2fb2b91..24f13ea 100644 }; static int snd_pcm_iec958_info(struct snd_kcontrol *kcontrol, -@@ -251,6 +264,194 @@ static const struct snd_kcontrol_new iec958_ctls = { +@@ -251,6 +314,194 @@ static const struct snd_kcontrol_new iec958_ctls = { .put = snd_pcm_iec958_put, }; @@ -1764,7 +1768,7 @@ index 2fb2b91..24f13ea 100644 + + mask = SAI_XCR1_MCKDIV_MASK(SAI_XCR1_MCKDIV_WIDTH(version)); + cr1 = SAI_XCR1_MCKDIV_SET(div); -+ ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, mask, cr1); ++ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, mask, cr1); + if (ret < 0) + dev_err(&sai->pdev->dev, "Failed to update CR1 register\n"); + @@ -1841,8 +1845,8 @@ index 2fb2b91..24f13ea 100644 + + dev_dbg(&sai->pdev->dev, "Enable master clock\n"); + -+ return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, -+ SAI_XCR1_MCKEN, SAI_XCR1_MCKEN); ++ return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, ++ SAI_XCR1_MCKEN, SAI_XCR1_MCKEN); +} + +static void stm32_sai_mclk_disable(struct clk_hw *hw) @@ -1852,7 +1856,7 @@ index 2fb2b91..24f13ea 100644 + + dev_dbg(&sai->pdev->dev, "Disable master clock\n"); + -+ regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0); ++ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, SAI_XCR1_MCKEN, 0); +} + +static const struct clk_ops mclk_ops = { @@ -1911,18 +1915,27 @@ index 2fb2b91..24f13ea 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 +466,8 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) +@@ -258,15 +509,15 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) + unsigned int sr, imr, flags; + snd_pcm_state_t status = SNDRV_PCM_STATE_RUNNING; + +- regmap_read(sai->regmap, STM_SAI_IMR_REGX, &imr); +- regmap_read(sai->regmap, STM_SAI_SR_REGX, &sr); ++ stm32_sai_sub_reg_rd(sai, STM_SAI_IMR_REGX, &imr); ++ stm32_sai_sub_reg_rd(sai, STM_SAI_SR_REGX, &sr); + + flags = sr & imr; if (!flags) return IRQ_NONE; - regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, - SAI_XCLRFR_MASK); -+ regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, -+ SAI_XCLRFR_MASK); ++ stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX, SAI_XCLRFR_MASK, ++ SAI_XCLRFR_MASK); if (!sai->substream) { dev_err(&pdev->dev, "Device stopped. Spurious IRQ 0x%x\n", sr); -@@ -300,8 +501,10 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) +@@ -300,8 +551,10 @@ static irqreturn_t stm32_sai_isr(int irq, void *devid) status = SNDRV_PCM_STATE_XRUN; } @@ -1934,15 +1947,18 @@ index 2fb2b91..24f13ea 100644 return IRQ_HANDLED; } -@@ -312,15 +515,29 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, +@@ -312,15 +565,29 @@ static int stm32_sai_set_sysclk(struct snd_soc_dai *cpu_dai, struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int ret; - if ((dir == SND_SOC_CLOCK_OUT) && sai->master) { +- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, +- SAI_XCR1_NODIV, +- (unsigned int)~SAI_XCR1_NODIV); + if (dir == SND_SOC_CLOCK_OUT && sai->sai_mclk) { - ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, - SAI_XCR1_NODIV, - (unsigned int)~SAI_XCR1_NODIV); ++ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, ++ SAI_XCR1_NODIV, ++ (unsigned int)~SAI_XCR1_NODIV); if (ret < 0) return ret; @@ -1966,7 +1982,34 @@ index 2fb2b91..24f13ea 100644 } return 0; -@@ -495,8 +712,11 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, +@@ -369,7 +636,7 @@ static int stm32_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, + + slotr_mask |= SAI_XSLOTR_SLOTEN_MASK; + +- regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, slotr_mask, slotr); ++ stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, slotr_mask, slotr); + + sai->slot_width = slot_width; + sai->slots = slots; +@@ -451,7 +718,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) + cr1_mask |= SAI_XCR1_CKSTR; + frcr_mask |= SAI_XFRCR_FSPOL; + +- regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); ++ stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr); + + /* DAI clock master masks */ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { +@@ -479,7 +746,7 @@ static int stm32_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) + cr1_mask |= SAI_XCR1_SLAVE; + + conf_update: +- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); ++ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1); + if (ret < 0) { + dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); + return ret; +@@ -495,8 +762,11 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); int imr, cr2, ret; @@ -1978,19 +2021,35 @@ index 2fb2b91..24f13ea 100644 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, +@@ -513,13 +783,12 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, } /* Enable ITs */ - - regmap_update_bits(sai->regmap, STM_SAI_CLRFR_REGX, - SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); -+ regmap_write_bits(sai->regmap, STM_SAI_CLRFR_REGX, -+ SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); ++ stm32_sai_sub_reg_wr(sai, STM_SAI_CLRFR_REGX, ++ SAI_XCLRFR_MASK, SAI_XCLRFR_MASK); imr = SAI_XIMR_OVRUDRIE; if (STM_SAI_IS_CAPTURE(sai)) { -@@ -547,10 +766,10 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, +- regmap_read(sai->regmap, STM_SAI_CR2_REGX, &cr2); ++ stm32_sai_sub_reg_rd(sai, STM_SAI_CR2_REGX, &cr2); + if (cr2 & SAI_XCR2_MUTECNT_MASK) + imr |= SAI_XIMR_MUTEDETIE; + } +@@ -529,8 +798,8 @@ static int stm32_sai_startup(struct snd_pcm_substream *substream, + else + imr |= SAI_XIMR_AFSDETIE | SAI_XIMR_LFSDETIE; + +- regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, +- SAI_XIMR_MASK, imr); ++ stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, ++ SAI_XIMR_MASK, imr); + + return 0; + } +@@ -547,10 +816,10 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, * SAI fifo threshold is set to half fifo, to keep enough space * for DMA incoming bursts. */ @@ -1998,14 +2057,74 @@ index 2fb2b91..24f13ea 100644 - SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, - SAI_XCR2_FFLUSH | - SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); -+ regmap_write_bits(sai->regmap, STM_SAI_CR2_REGX, -+ SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, -+ SAI_XCR2_FFLUSH | -+ SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); ++ stm32_sai_sub_reg_wr(sai, STM_SAI_CR2_REGX, ++ SAI_XCR2_FFLUSH | SAI_XCR2_FTH_MASK, ++ SAI_XCR2_FFLUSH | ++ SAI_XCR2_FTH_SET(STM_SAI_FIFO_TH_HALF)); /* DS bits in CR1 not set for SPDIF (size forced to 24 bits).*/ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { -@@ -722,31 +941,35 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -579,7 +848,7 @@ static int stm32_sai_set_config(struct snd_soc_dai *cpu_dai, + if ((sai->slots == 2) && (params_channels(params) == 1)) + cr1 |= SAI_XCR1_MONO; + +- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); ++ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1); + if (ret < 0) { + dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); + return ret; +@@ -593,7 +862,7 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai) + struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); + int slotr, slot_sz; + +- regmap_read(sai->regmap, STM_SAI_SLOTR_REGX, &slotr); ++ stm32_sai_sub_reg_rd(sai, STM_SAI_SLOTR_REGX, &slotr); + + /* + * If SLOTSZ is set to auto in SLOTR, align slot width on data size +@@ -615,16 +884,16 @@ static int stm32_sai_set_slots(struct snd_soc_dai *cpu_dai) + sai->slots = 2; + + /* The number of slots in the audio frame is equal to NBSLOT[3:0] + 1*/ +- regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, +- SAI_XSLOTR_NBSLOT_MASK, +- SAI_XSLOTR_NBSLOT_SET((sai->slots - 1))); ++ stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, ++ SAI_XSLOTR_NBSLOT_MASK, ++ SAI_XSLOTR_NBSLOT_SET((sai->slots - 1))); + + /* Set default slots mask if not already set from DT */ + if (!(slotr & SAI_XSLOTR_SLOTEN_MASK)) { + sai->slot_mask = (1 << sai->slots) - 1; +- regmap_update_bits(sai->regmap, +- STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK, +- SAI_XSLOTR_SLOTEN_SET(sai->slot_mask)); ++ stm32_sai_sub_reg_up(sai, ++ STM_SAI_SLOTR_REGX, SAI_XSLOTR_SLOTEN_MASK, ++ SAI_XSLOTR_SLOTEN_SET(sai->slot_mask)); + } + + dev_dbg(cpu_dai->dev, "Slots %d, slot width %d\n", +@@ -654,14 +923,14 @@ static void stm32_sai_set_frame(struct snd_soc_dai *cpu_dai) + dev_dbg(cpu_dai->dev, "Frame length %d, frame active %d\n", + sai->fs_length, fs_active); + +- regmap_update_bits(sai->regmap, STM_SAI_FRCR_REGX, frcr_mask, frcr); ++ stm32_sai_sub_reg_up(sai, STM_SAI_FRCR_REGX, frcr_mask, frcr); + + if ((sai->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_LSB) { + offset = sai->slot_width - sai->data_size; + +- regmap_update_bits(sai->regmap, STM_SAI_SLOTR_REGX, +- SAI_XSLOTR_FBOFF_MASK, +- SAI_XSLOTR_FBOFF_SET(offset)); ++ stm32_sai_sub_reg_up(sai, STM_SAI_SLOTR_REGX, ++ SAI_XSLOTR_FBOFF_MASK, ++ SAI_XSLOTR_FBOFF_SET(offset)); + } + } + +@@ -722,31 +991,35 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, struct snd_pcm_hw_params *params) { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); @@ -2059,7 +2178,7 @@ index 2fb2b91..24f13ea 100644 } else { /* * TDM mode : -@@ -758,13 +981,14 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -758,13 +1031,14 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, * Note: NOMCK/NODIV correspond to same bit. */ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) { @@ -2077,16 +2196,16 @@ index 2fb2b91..24f13ea 100644 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, +@@ -772,31 +1046,27 @@ static int stm32_sai_configure_clock(struct snd_soc_dai *cpu_dai, mclk_ratio); return -EINVAL; } - div = DIV_ROUND_CLOSEST(sai_clk_rate, - sai->mclk_rate); + -+ regmap_update_bits(sai->regmap, -+ STM_SAI_CR1_REGX, -+ SAI_XCR1_OSR, cr1); ++ stm32_sai_sub_reg_up(sai, ++ STM_SAI_CR1_REGX, ++ SAI_XCR1_OSR, cr1); + + div = stm32_sai_get_clk_div(sai, sai_clk_rate, + sai->mclk_rate); @@ -2123,23 +2242,68 @@ index 2fb2b91..24f13ea 100644 } static int stm32_sai_hw_params(struct snd_pcm_substream *substream, -@@ -882,14 +1102,24 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, +@@ -841,12 +1111,12 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dev_dbg(cpu_dai->dev, "Enable DMA and SAI\n"); + +- regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, +- SAI_XCR1_DMAEN, SAI_XCR1_DMAEN); ++ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, ++ SAI_XCR1_DMAEN, SAI_XCR1_DMAEN); + + /* Enable SAI */ +- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, +- SAI_XCR1_SAIEN, SAI_XCR1_SAIEN); ++ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, ++ SAI_XCR1_SAIEN, SAI_XCR1_SAIEN); + if (ret < 0) + dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); + break; +@@ -855,16 +1125,16 @@ static int stm32_sai_trigger(struct snd_pcm_substream *substream, int cmd, + case SNDRV_PCM_TRIGGER_STOP: + dev_dbg(cpu_dai->dev, "Disable DMA and SAI\n"); + +- regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, +- SAI_XIMR_MASK, 0); ++ stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, ++ SAI_XIMR_MASK, 0); + +- regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, +- SAI_XCR1_SAIEN, +- (unsigned int)~SAI_XCR1_SAIEN); ++ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, ++ SAI_XCR1_SAIEN, ++ (unsigned int)~SAI_XCR1_SAIEN); + +- ret = regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, +- SAI_XCR1_DMAEN, +- (unsigned int)~SAI_XCR1_DMAEN); ++ ret = stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, ++ SAI_XCR1_DMAEN, ++ (unsigned int)~SAI_XCR1_DMAEN); + if (ret < 0) + dev_err(cpu_dai->dev, "Failed to update CR1 register\n"); + +@@ -882,14 +1152,24 @@ static void stm32_sai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct stm32_sai_sub_data *sai = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; ++ ++ stm32_sai_sub_reg_up(sai, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); - regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); - - regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, - SAI_XCR1_NODIV); +- regmap_update_bits(sai->regmap, STM_SAI_IMR_REGX, SAI_XIMR_MASK, 0); ++ stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, ++ SAI_XCR1_NODIV); +- regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, SAI_XCR1_NODIV, +- SAI_XCR1_NODIV); + /* Release mclk rate only if rate was actually set */ + if (sai->mclk_rate) { + clk_rate_exclusive_put(sai->sai_mclk); + sai->mclk_rate = 0; + } -+ + clk_disable_unprepare(sai->sai_ck); + + spin_lock_irqsave(&sai->irq_lock, flags); @@ -2148,7 +2312,7 @@ index 2fb2b91..24f13ea 100644 } 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, +@@ -910,7 +1190,9 @@ static int stm32_sai_pcm_new(struct snd_soc_pcm_runtime *rtd, static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) { struct stm32_sai_sub_data *sai = dev_get_drvdata(cpu_dai->dev); @@ -2159,7 +2323,7 @@ index 2fb2b91..24f13ea 100644 sai->dma_params.addr = (dma_addr_t)(sai->phys_addr + STM_SAI_DR_REGX); /* -@@ -919,6 +1151,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) +@@ -919,6 +1201,8 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) * constraints). */ sai->dma_params.maxburst = 4; @@ -2168,7 +2332,7 @@ index 2fb2b91..24f13ea 100644 /* Buswidth will be set by framework at runtime */ sai->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; -@@ -938,8 +1172,10 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) +@@ -938,14 +1222,16 @@ static int stm32_sai_dai_probe(struct snd_soc_dai *cpu_dai) /* Configure synchronization */ if (sai->sync == SAI_SYNC_EXTERNAL) { /* Configure synchro client and provider */ @@ -2181,33 +2345,14 @@ index 2fb2b91..24f13ea 100644 } cr1_mask |= SAI_XCR1_SYNCEN_MASK; -@@ -994,6 +1230,16 @@ static int stm32_sai_pcm_process_spdif(struct snd_pcm_substream *substream, - return 0; + cr1 |= SAI_XCR1_SYNCEN_SET(sai->sync); + +- return regmap_update_bits(sai->regmap, STM_SAI_CR1_REGX, cr1_mask, cr1); ++ return stm32_sai_sub_reg_up(sai, STM_SAI_CR1_REGX, cr1_mask, cr1); } -+/* 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, + static const struct snd_soc_dai_ops stm32_sai_pcm_dai_ops = { +@@ -1099,11 +1385,16 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, sai->regmap_config = &stm32_sai_sub_regmap_config_f4; /* Note: PDM registers not available for H7 sub-block B */ @@ -2215,11 +2360,26 @@ index 2fb2b91..24f13ea 100644 + if (STM_SAI_HAS_PDM(sai) && STM_SAI_IS_SUB_A(sai)) sai->regmap_config = &stm32_sai_sub_regmap_config_h7; - sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", -@@ -1191,6 +1437,23 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, +- sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "sai_ck", +- base, sai->regmap_config); ++ /* ++ * Do not manage peripheral clock through regmap framework as this ++ * can lead to circular locking issue with sai master clock provider. ++ * Manage peripheral clock directly in driver instead. ++ */ ++ sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, ++ sai->regmap_config); + if (IS_ERR(sai->regmap)) { + dev_err(&pdev->dev, "Failed to initialize MMIO\n"); + return PTR_ERR(sai->regmap); +@@ -1201,6 +1492,27 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, return PTR_ERR(sai->sai_ck); } ++ ret = clk_prepare(sai->pdata->pclk); ++ if (ret < 0) ++ return ret; ++ + if (STM_SAI_IS_F4(sai->pdata)) + return 0; + @@ -2240,7 +2400,7 @@ index 2fb2b91..24f13ea 100644 return 0; } -@@ -1235,6 +1498,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) +@@ -1245,6 +1557,7 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) sai->pdev = pdev; mutex_init(&sai->ctrl_lock); @@ -2248,26 +2408,52 @@ index 2fb2b91..24f13ea 100644 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) +@@ -1285,12 +1598,63 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) return 0; } ++static int stm32_sai_sub_remove(struct platform_device *pdev) ++{ ++ struct stm32_sai_sub_data *sai = dev_get_drvdata(&pdev->dev); ++ ++ clk_unprepare(sai->pdata->pclk); ++ ++ return 0; ++} ++ +#ifdef CONFIG_PM_SLEEP +static int stm32_sai_sub_suspend(struct device *dev) +{ + struct stm32_sai_sub_data *sai = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_enable(sai->pdata->pclk); ++ if (ret < 0) ++ return ret; + + regcache_cache_only(sai->regmap, true); + regcache_mark_dirty(sai->regmap); ++ ++ clk_disable(sai->pdata->pclk); ++ + return 0; +} + +static int stm32_sai_sub_resume(struct device *dev) +{ + struct stm32_sai_sub_data *sai = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = clk_enable(sai->pdata->pclk); ++ if (ret < 0) ++ return ret; + + regcache_cache_only(sai->regmap, false); -+ return regcache_sync(sai->regmap); ++ ret = regcache_sync(sai->regmap); ++ ++ clk_disable(sai->pdata->pclk); ++ ++ return ret; +} +#endif /* CONFIG_PM_SLEEP */ + @@ -2282,12 +2468,15 @@ index 2fb2b91..24f13ea 100644 + .pm = &stm32_sai_sub_pm_ops, }, .probe = stm32_sai_sub_probe, ++ .remove = stm32_sai_sub_remove, }; + + module_platform_driver(stm32_sai_sub_driver); diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c -index 373df4f..ac3cd15 100644 +index 373df4f..5a5094e 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c -@@ -16,11 +16,13 @@ +@@ -16,6 +16,7 @@ * details. */ @@ -2295,13 +2484,7 @@ index 373df4f..ac3cd15 100644 #include #include #include - #include - #include -+#include - #include - #include - -@@ -35,6 +37,9 @@ +@@ -35,6 +36,9 @@ #define STM32_SPDIFRX_DR 0x10 #define STM32_SPDIFRX_CSR 0x14 #define STM32_SPDIFRX_DIR 0x18 @@ -2311,7 +2494,7 @@ index 373df4f..ac3cd15 100644 /* Bit definition for SPDIF_CR register */ #define SPDIFRX_CR_SPDIFEN_SHIFT 0 -@@ -168,6 +173,18 @@ +@@ -168,6 +172,18 @@ #define SPDIFRX_SPDIFEN_SYNC 0x1 #define SPDIFRX_SPDIFEN_ENABLE 0x3 @@ -2330,16 +2513,82 @@ index 373df4f..ac3cd15 100644 #define SPDIFRX_IN1 0x1 #define SPDIFRX_IN2 0x2 #define SPDIFRX_IN3 0x3 -@@ -471,6 +488,8 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) - memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB); - memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB); +@@ -213,6 +229,7 @@ + * @slave_config: dma slave channel runtime config pointer + * @phys_addr: SPDIFRX registers physical base address + * @lock: synchronization enabling lock ++ * @irq_lock: prevent race condition with IRQ on stream state + * @cs: channel status buffer + * @ub: user data buffer + * @irq: SPDIFRX interrupt line +@@ -233,6 +250,7 @@ struct stm32_spdifrx_data { + struct dma_slave_config slave_config; + dma_addr_t phys_addr; + spinlock_t lock; /* Sync enabling lock */ ++ spinlock_t irq_lock; /* Prevent race condition on stream state */ + unsigned char cs[SPDIFRX_CS_BYTES_NB]; + unsigned char ub[SPDIFRX_UB_BYTES_NB]; + int irq; +@@ -313,6 +331,7 @@ static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) + static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) + { + int cr, cr_mask, imr, ret; ++ unsigned long flags; -+ pinctrl_pm_select_default_state(&spdifrx->pdev->dev); -+ - ret = stm32_spdifrx_dma_ctrl_start(spdifrx); - if (ret < 0) + /* Enable IRQs */ + imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; +@@ -320,7 +339,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) + if (ret) return ret; -@@ -493,7 +512,7 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) + +- spin_lock(&spdifrx->lock); ++ spin_lock_irqsave(&spdifrx->lock, flags); + + spdifrx->refcount++; + +@@ -344,6 +363,8 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) + SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; + cr_mask = cr; + ++ cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63); ++ cr_mask |= SPDIFRX_CR_NBTR_MASK; + cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); + cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; + ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, +@@ -353,7 +374,7 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) + "Failed to start synchronization\n"); + } + +- spin_unlock(&spdifrx->lock); ++ spin_unlock_irqrestore(&spdifrx->lock, flags); + + return ret; + } +@@ -361,11 +382,12 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) + static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) + { + int cr, cr_mask, reg; ++ unsigned long flags; + +- spin_lock(&spdifrx->lock); ++ spin_lock_irqsave(&spdifrx->lock, flags); + + if (--spdifrx->refcount) { +- spin_unlock(&spdifrx->lock); ++ spin_unlock_irqrestore(&spdifrx->lock, flags); + return; + } + +@@ -384,7 +406,7 @@ static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) + regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); + regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); + +- spin_unlock(&spdifrx->lock); ++ spin_unlock_irqrestore(&spdifrx->lock, flags); + } + + static int stm32_spdifrx_dma_ctrl_register(struct device *dev, +@@ -493,7 +515,7 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, msecs_to_jiffies(100)) <= 0) { @@ -2348,15 +2597,7 @@ index 373df4f..ac3cd15 100644 ret = -EAGAIN; } -@@ -502,6 +521,7 @@ static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) - - end: - clk_disable_unprepare(spdifrx->kclk); -+ pinctrl_pm_select_sleep_state(&spdifrx->pdev->dev); - - return ret; - } -@@ -603,6 +623,9 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) +@@ -603,6 +625,9 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) case STM32_SPDIFRX_DR: case STM32_SPDIFRX_CSR: case STM32_SPDIFRX_DIR: @@ -2366,7 +2607,7 @@ index 373df4f..ac3cd15 100644 return true; default: return false; -@@ -611,10 +634,15 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) +@@ -611,10 +636,15 @@ static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) { @@ -2385,7 +2626,7 @@ index 373df4f..ac3cd15 100644 } static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) -@@ -633,11 +661,13 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { +@@ -633,20 +663,21 @@ static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -2400,7 +2641,85 @@ index 373df4f..ac3cd15 100644 }; static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) -@@ -835,7 +865,8 @@ static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { + { + struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; +- struct snd_pcm_substream *substream = spdifrx->substream; + struct platform_device *pdev = spdifrx->pdev; + unsigned int cr, mask, sr, imr; +- unsigned int flags; ++ unsigned int flags, sync_state; + int err = 0, err_xrun = 0; + + regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); +@@ -706,19 +737,36 @@ static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) + } + + if (err) { +- /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */ ++ regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); ++ sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) && ++ SPDIFRX_SPDIFEN_SYNC; ++ ++ /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */ + cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); + regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, + SPDIFRX_CR_SPDIFEN_MASK, cr); + +- if (substream) +- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); ++ /* If SPDIFRX was in STATE_SYNC, retry synchro */ ++ if (sync_state) { ++ cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); ++ regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, ++ SPDIFRX_CR_SPDIFEN_MASK, cr); ++ return IRQ_HANDLED; ++ } ++ ++ spin_lock(&spdifrx->irq_lock); ++ if (spdifrx->substream) ++ snd_pcm_stop(spdifrx->substream, ++ SNDRV_PCM_STATE_DISCONNECTED); ++ spin_unlock(&spdifrx->irq_lock); + + return IRQ_HANDLED; + } + +- if (err_xrun && substream) +- snd_pcm_stop_xrun(substream); ++ spin_lock(&spdifrx->irq_lock); ++ if (err_xrun && spdifrx->substream) ++ snd_pcm_stop_xrun(spdifrx->substream); ++ spin_unlock(&spdifrx->irq_lock); + + return IRQ_HANDLED; + } +@@ -727,9 +775,12 @@ static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) + { + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); ++ unsigned long flags; + int ret; + ++ spin_lock_irqsave(&spdifrx->irq_lock, flags); + spdifrx->substream = substream; ++ spin_unlock_irqrestore(&spdifrx->irq_lock, flags); + + ret = clk_prepare_enable(spdifrx->kclk); + if (ret) +@@ -805,8 +856,12 @@ static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) + { + struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); ++ unsigned long flags; + ++ spin_lock_irqsave(&spdifrx->irq_lock, flags); + spdifrx->substream = NULL; ++ spin_unlock_irqrestore(&spdifrx->irq_lock, flags); ++ + clk_disable_unprepare(spdifrx->kclk); + } + +@@ -835,7 +890,8 @@ static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, .buffer_bytes_max = 8 * PAGE_SIZE, @@ -2410,7 +2729,7 @@ index 373df4f..ac3cd15 100644 .periods_min = 2, .periods_max = 8, }; -@@ -901,6 +932,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) +@@ -901,6 +957,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) struct stm32_spdifrx_data *spdifrx; struct reset_control *rst; const struct snd_dmaengine_pcm_config *pcm_config = NULL; @@ -2418,7 +2737,15 @@ index 373df4f..ac3cd15 100644 int ret; spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); -@@ -957,7 +989,19 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) +@@ -910,6 +967,7 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) + spdifrx->pdev = pdev; + init_completion(&spdifrx->cs_completion); + spin_lock_init(&spdifrx->lock); ++ spin_lock_init(&spdifrx->irq_lock); + + platform_set_drvdata(pdev, spdifrx); + +@@ -957,7 +1015,19 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) goto error; } @@ -2439,7 +2766,7 @@ index 373df4f..ac3cd15 100644 error: if (!IS_ERR(spdifrx->ctrl_chan)) -@@ -983,10 +1027,34 @@ static int stm32_spdifrx_remove(struct platform_device *pdev) +@@ -983,10 +1053,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.94/0029-ARM-stm32mp1-r2.4-MISC.patch similarity index 95% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0028-ARM-stm32mp1-r2-MISC.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch index 7b9d2d4..d39b544 100644 --- 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.94/0029-ARM-stm32mp1-r2.4-MISC.patch @@ -1,7 +1,7 @@ -From a3c9e0d977420d451f6e13873a4a0921d8a9b88f Mon Sep 17 00:00:00 2001 +From 9166e19abab21450a32288379f5fb55f44e7a340 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 +Date: Fri, 8 Nov 2019 16:52:49 +0100 +Subject: [PATCH 29/31] ARM stm32mp1 r2.4 MISC --- Documentation/remoteproc.txt | 23 ++++++++++++++++++++ @@ -45,10 +45,10 @@ index 77fb03a..bec2177 100644 +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 +index bee0ba1..b402db6 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug -@@ -1184,6 +1184,42 @@ choice +@@ -1191,6 +1191,42 @@ choice If unsure, say N. @@ -91,7 +91,7 @@ index f6fcb8a..88849c1 100644 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 +@@ -1475,6 +1511,10 @@ config DEBUG_STI_UART bool depends on ARCH_STI @@ -102,7 +102,7 @@ index f6fcb8a..88849c1 100644 config DEBUG_SIRFSOC_UART bool depends on ARCH_SIRF -@@ -1517,6 +1557,7 @@ config DEBUG_LL_INCLUDE +@@ -1524,6 +1564,7 @@ config DEBUG_LL_INCLUDE default "debug/s5pv210.S" if DEBUG_S5PV210_UART default "debug/sirf.S" if DEBUG_SIRFSOC_UART default "debug/sti.S" if DEBUG_STI_UART @@ -110,7 +110,7 @@ index f6fcb8a..88849c1 100644 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 +@@ -1587,6 +1628,8 @@ config DEBUG_UART_PHYS default 0x3e000000 if DEBUG_BCM_KONA_UART default 0x3f201000 if DEBUG_BCM2836 default 0x4000e400 if DEBUG_LL_UART_EFM32 @@ -119,7 +119,7 @@ index f6fcb8a..88849c1 100644 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 +@@ -1681,10 +1724,12 @@ config DEBUG_UART_PHYS DEBUG_S3C64XX_UART || \ DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \ @@ -133,7 +133,7 @@ index f6fcb8a..88849c1 100644 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 +@@ -1797,7 +1842,7 @@ config DEBUG_UART_VIRT DEBUG_S3C64XX_UART || \ DEBUG_BCM63XX_UART || DEBUG_ASM9260_UART || \ DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \ diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0029-ARM-stm32mp1-r2-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch similarity index 87% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0029-ARM-stm32mp1-r2-DEVICETREE.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch index f9beb9c..eff795c 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0029-ARM-stm32mp1-r2-DEVICETREE.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch @@ -1,17 +1,19 @@ -From 3c9063e4da42c0fdc9a0e6a5dc9b0707cdb0f22a Mon Sep 17 00:00:00 2001 +From b7da07cd38a5e6c19c7a45c422d0da01b6069e8c 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 +Date: Fri, 8 Nov 2019 16:52:53 +0100 +Subject: [PATCH 30/31] ARM stm32mp1 r3 DEVICETREE --- .../bindings/connector/usb-connector.txt | 2 + + .../devicetree/bindings/cpufreq/stm32-cpufreq.txt | 61 + .../devicetree/bindings/display/bridge/sii902x.txt | 9 + - .../devicetree/bindings/dma/stm32-dma.txt | 32 +- + .../devicetree/bindings/dma/stm32-dma.txt | 36 +- .../devicetree/bindings/dma/stm32-dmamux.txt | 5 +- - .../devicetree/bindings/dma/stm32-mdma.txt | 22 +- + .../devicetree/bindings/dma/stm32-mdma.txt | 66 +- Documentation/devicetree/bindings/gpio/gpio.txt | 12 + .../bindings/hwlock/st,stm32-hwspinlock.txt | 23 + - .../devicetree/bindings/i2c/i2c-stm32.txt | 85 +- + .../devicetree/bindings/i2c/i2c-stm32.txt | 88 +- + .../bindings/iio/adc/sigma-delta-modulator.txt | 3 + .../devicetree/bindings/iio/adc/st,stm32-adc.txt | 98 +- .../bindings/iio/counter/stm32-lptimer-cnt.txt | 8 +- .../bindings/iio/timer/stm32-timer-trigger.txt | 9 + @@ -19,7 +21,7 @@ Subject: [PATCH 29/30] ARM stm32mp1 r2 DEVICETREE .../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 +++ + .../devicetree/bindings/mfd/st,stpmic1.txt | 61 + Documentation/devicetree/bindings/mfd/stmfx.txt | 28 + Documentation/devicetree/bindings/mfd/syscon.txt | 1 + Documentation/devicetree/bindings/mmc/mmci.txt | 13 + @@ -29,13 +31,13 @@ Subject: [PATCH 29/30] ARM stm32mp1 r2 DEVICETREE .../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 + + .../bindings/pinctrl/st,stm32-pinctrl.txt | 12 + .../devicetree/bindings/pwm/pwm-stm32-lp.txt | 9 +- .../devicetree/bindings/pwm/pwm-stm32.txt | 11 +- .../bindings/regulator/st,stm32mp1-pwr-reg.txt | 42 + - .../bindings/regulator/st,stpmic1-regulator.txt | 68 ++ - .../devicetree/bindings/remoteproc/rproc-srm.txt | 61 + - .../devicetree/bindings/remoteproc/stm32-rproc.txt | 80 ++ + .../bindings/regulator/st,stpmic1-regulator.txt | 69 ++ + .../devicetree/bindings/remoteproc/rproc-srm.txt | 58 + + .../devicetree/bindings/remoteproc/stm32-rproc.txt | 85 ++ .../devicetree/bindings/rtc/st,stm32-rtc.txt | 10 +- .../devicetree/bindings/serial/st,stm32-usart.txt | 41 +- .../devicetree/bindings/soc/stm32/stm32_hdp.txt | 39 + @@ -47,21 +49,22 @@ Subject: [PATCH 29/30] ARM stm32mp1 r2 DEVICETREE .../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/stm32mp157a-dk1.dts | 767 +++++++++++++ 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-dk2-m4-examples.dts | 129 +++ + arch/arm/boot/dts/stm32mp157c-dk2.dts | 147 +++ + arch/arm/boot/dts/stm32mp157c-ed1.dts | 385 ++++++- arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts | 33 + - arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts | 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/stm32mp157c-ev1-m4-examples.dts | 146 +++ + arch/arm/boot/dts/stm32mp157c-ev1.dts | 566 +++++++++- + arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi | 961 ++++++++++++++++ + arch/arm/boot/dts/stm32mp157c.dtsi | 1071 +++++++++++++++++- arch/arm/boot/dts/stm32mp157caa-pinctrl.dtsi | 90 ++ arch/arm/boot/dts/stm32mp157cab-pinctrl.dtsi | 62 + arch/arm/boot/dts/stm32mp157cac-pinctrl.dtsi | 78 ++ arch/arm/boot/dts/stm32mp157cad-pinctrl.dtsi | 62 + - 57 files changed, 6444 insertions(+), 204 deletions(-) + 59 files changed, 6970 insertions(+), 228 deletions(-) + create mode 100644 Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt create mode 100644 Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt create mode 100644 Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt @@ -105,6 +108,73 @@ index 8855bfc..bf43ee9 100644 - try-power-role: preferred power role if "dual"(DRP) can support Try.SNK or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC. - data-role: should be one of "host", "device", "dual"(DRD) if typec +diff --git a/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt +new file mode 100644 +index 0000000..1292eb2 +--- /dev/null ++++ b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt +@@ -0,0 +1,61 @@ ++STM32 CPUFreq and OPP bindings ++============================== ++ ++STM32 CPUFreq driver needs to read chip information from the SoC to list ++available OPPs. Then it depends on cpufreq-dt bindings. ++ ++Required properties: ++-------------------- ++- clocks: Phandle to the cpu clock "cpu". ++- clocks-name: Should contain "cpu". ++- nvmem-cells: Phandle to nvmem cell that contains "part_number". ++- nvmem-cell-names: Must be "part_number". ++- operating-points-v2: Phandle to operating points table. See ../power/opp.txt ++ for more details. ++ ++Optional properties: ++-------------------- ++See cpufreq-dt.txt for optional properties. ++ ++Examples: ++--------- ++ cpus { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ cpu0: cpu@0 { ++ compatible = "arm,cortex-a7"; ++ device_type = "cpu"; ++ reg = <0>; ++ clocks = <&rcc CK_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; ++ nvmem-cells = <&part_number_otp>; ++ nvmem-cell-names = "part_number"; ++ }; ++ ++ cpu1: cpu@1 { ++ compatible = "arm,cortex-a7"; ++ device_type = "cpu"; ++ reg = <1>; ++ clocks = <&rcc CK_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; ++ }; ++ }; ++ ++ cpu0_opp_table: cpu0-opp-table { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-650000000 { ++ opp-hz = /bits/ 64 <650000000>; ++ opp-microvolt = <1200000>; ++ opp-supported-hw = <0x1>; ++ }; ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt = <1350000>; ++ opp-supported-hw = <0x2>; ++ }; ++ }; diff --git a/Documentation/devicetree/bindings/display/bridge/sii902x.txt b/Documentation/devicetree/bindings/display/bridge/sii902x.txt index 72d2dc6..00e9e88 100644 --- a/Documentation/devicetree/bindings/display/bridge/sii902x.txt @@ -132,7 +202,7 @@ index 72d2dc6..00e9e88 100644 }; }; diff --git a/Documentation/devicetree/bindings/dma/stm32-dma.txt b/Documentation/devicetree/bindings/dma/stm32-dma.txt -index c5f5190..163be09 100644 +index c5f5190..0982c574 100644 --- a/Documentation/devicetree/bindings/dma/stm32-dma.txt +++ b/Documentation/devicetree/bindings/dma/stm32-dma.txt @@ -17,6 +17,12 @@ Optional properties: @@ -165,7 +235,7 @@ index c5f5190..163be09 100644 }; * DMA client -@@ -62,13 +78,21 @@ channel: a phandle to the DMA controller plus the following four integer cells: +@@ -62,13 +78,25 @@ channel: a phandle to the DMA controller plus the following four integer cells: 0x1: medium 0x2: high 0x3: very high @@ -186,10 +256,14 @@ index c5f5190..163be09 100644 + For cyclic, whether Intermediate M2M transfer is chosen, any value can + be set: SRAM buffer size will rely on period size and not on this DT + value. ++ -bit 5: DMA direct mode ++ 0: FIFO mode: with threshold level selectable with bit 0-1 ++ 1: Direct mode: each DMA request immediately initiates a transfer ++ from/to the memory. Example: -@@ -77,7 +101,7 @@ Example: +@@ -77,7 +105,7 @@ Example: reg = <0x40011000 0x400>; interrupts = <37>; clocks = <&clk_pclk2>; @@ -223,7 +297,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..1810f876 100644 +index d18772d..077c819a 100644 --- a/Documentation/devicetree/bindings/dma/stm32-mdma.txt +++ b/Documentation/devicetree/bindings/dma/stm32-mdma.txt @@ -10,7 +10,7 @@ Required properties: @@ -244,7 +318,7 @@ index d18772d..1810f876 100644 dma-channels = <16>; dma-requests = <32>; st,ahb-addr-masks = <0x20000000>, <0x00000000>; -@@ -35,8 +35,8 @@ Example: +@@ -35,60 +35,64 @@ Example: * DMA client DMA clients connected to the STM32 MDMA controller must use the format @@ -255,7 +329,61 @@ index d18772d..1810f876 100644 1. The request line number 2. The priority level -@@ -76,19 +76,23 @@ a phandle to the MDMA controller plus the following five integer cells: +- 0x00: Low +- 0x01: Medium +- 0x10: High +- 0x11: Very high ++ 0x0: Low ++ 0x1: Medium ++ 0x2: High ++ 0x3: Very high + 3. A 32bit mask specifying the DMA channel configuration + -bit 0-1: Source increment mode +- 0x00: Source address pointer is fixed +- 0x10: Source address pointer is incremented after each data transfer +- 0x11: Source address pointer is decremented after each data transfer ++ 0x0: Source address pointer is fixed ++ 0x2: Source address pointer is incremented after each data transfer ++ 0x3: Source address pointer is decremented after each data transfer + -bit 2-3: Destination increment mode +- 0x00: Destination address pointer is fixed +- 0x10: Destination address pointer is incremented after each data ++ 0x0: Destination address pointer is fixed ++ 0x2: Destination address pointer is incremented after each data + transfer +- 0x11: Destination address pointer is decremented after each data ++ 0x3: Destination address pointer is decremented after each data + transfer + -bit 8-9: Source increment offset size +- 0x00: byte (8bit) +- 0x01: half-word (16bit) +- 0x10: word (32bit) +- 0x11: double-word (64bit) ++ 0x0: byte (8bit) ++ 0x1: half-word (16bit) ++ 0x2: word (32bit) ++ 0x3: double-word (64bit) + -bit 10-11: Destination increment offset size +- 0x00: byte (8bit) +- 0x01: half-word (16bit) +- 0x10: word (32bit) +- 0x11: double-word (64bit) ++ 0x0: byte (8bit) ++ 0x1: half-word (16bit) ++ 0x2: word (32bit) ++ 0x3: double-word (64bit) + -bit 25-18: The number of bytes to be transferred in a single transfer + (min = 1 byte, max = 128 bytes) + -bit 29:28: Trigger Mode +- 0x00: Each MDMA request triggers a buffer transfer (max 128 bytes) +- 0x01: Each MDMA request triggers a block transfer (max 64K bytes) +- 0x10: Each MDMA request triggers a repeated block transfer +- 0x11: Each MDMA request triggers a linked list transfer ++ 0x0: Each MDMA request triggers a buffer transfer (max 128 bytes) ++ 0x1: Each MDMA request triggers a block transfer (max 64K bytes) ++ 0x2: Each MDMA request triggers a repeated block transfer ++ 0x3: Each MDMA request triggers a linked list transfer + 4. A 32bit value specifying the register to be used to acknowledge the request if no HW ack signal is used by the MDMA client 5. A 32bit mask specifying the value to be written to acknowledge the request if no HW ack signal is used by the MDMA client @@ -337,10 +465,10 @@ index 0000000..adf4f000 + clock-names = "hsem"; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt -index 3b54899..94cd4bd 100644 +index 3b54899..f5194b4 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt -@@ -1,33 +1,49 @@ +@@ -1,33 +1,52 @@ * I2C controller embedded in STMicroelectronics STM32 I2C platform -Required properties : @@ -355,6 +483,7 @@ index 3b54899..94cd4bd 100644 +- interrupts: Must contain the interrupt id for I2C event and then the interrupt id for I2C error. + Optionnaly a wakeup interrupt may be specified. ++- interrupt-names: Must be "event", "error" and optionnaly "wakeup". - resets: Must contain the phandle to the reset controller. - clocks: Must contain the input clock of the I2C instance. - A pinctrl state named "default" must be defined to set pins in mode of @@ -398,13 +527,15 @@ index 3b54899..94cd4bd 100644 + 2nd cell: clear register offset within SYSCFG + 3rd cell: register bitmask for FMP clear bit + For STM32MP1 family only. ++- st,smbus-alert: enable the SMBus Alert feature ++- st,smbus-host-notify: enable the SMBus Host-Notify feature -Example : +Example: i2c@40005400 { compatible = "st,stm32f4-i2c"; -@@ -52,5 +68,44 @@ Example : +@@ -52,5 +71,44 @@ Example : resets = <&rcc STM32F7_APB1_RESET(I2C1)>; clocks = <&rcc 1 CLK_I2C1>; pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>; @@ -450,6 +581,20 @@ index 3b54899..94cd4bd 100644 + reg = <0x3c>; + }; }; +diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt +index 59b92cd..fa70fda 100644 +--- a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt ++++ b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt +@@ -5,6 +5,9 @@ Required properties: + as a generic SD modulator if modulator not specified in compatible list. + - #io-channel-cells = <0>: See the IIO bindings section "IIO consumers". + ++Optional properties: ++- vref-supply: Phandle to the vref input analog reference voltage. ++ + Example node: + + ads1202: adc { diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt index 8346bcb..a6aa796 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt @@ -800,93 +945,20 @@ index 0000000..eb62238 + diff --git a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt new file mode 100644 -index 0000000..0fab08a +index 0000000..afd45c0 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt -@@ -0,0 +1,132 @@ +@@ -0,0 +1,61 @@ +* STMicroelectronics STPMIC1 Power Management IC + -+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. -+- #interrupt-cells: Should be 2. -+- interrupt-controller: Describes the STPMIC1 as an interrupt -+ controller (has its own domain). Interrupt number are the following: -+ /* Interrupt Register 1 (0x50 for latch) */ -+ IT_SWOUT_R=0 -+ IT_SWOUT_F=1 -+ IT_VBUS_OTG_R=2 -+ IT_VBUS_OTG_F=3 -+ IT_WAKEUP_R=4 -+ IT_WAKEUP_F=5 -+ IT_PONKEY_R=6 -+ IT_PONKEY_F=7 -+ /* Interrupt Register 2 (0x51 for latch) */ -+ IT_OVP_BOOST=8 -+ IT_OCP_BOOST=9 -+ IT_OCP_SWOUT=10 -+ IT_OCP_OTG=11 -+ IT_CURLIM_BUCK4=12 -+ IT_CURLIM_BUCK3=13 -+ IT_CURLIM_BUCK2=14 -+ IT_CURLIM_BUCK1=15 -+ /* Interrupt Register 3 (0x52 for latch) */ -+ IT_SHORT_SWOUT=16 -+ IT_SHORT_SWOTG=17 -+ IT_CURLIM_LDO6=18 -+ IT_CURLIM_LDO5=19 -+ IT_CURLIM_LDO4=20 -+ IT_CURLIM_LDO3=21 -+ IT_CURLIM_LDO2=22 -+ IT_CURLIM_LDO1=23 -+ /* Interrupt Register 3 (0x52 for latch) */ -+ IT_SWIN_R=24 -+ IT_SWIN_F=25 -+ IT_RESERVED_1=26 -+ IT_RESERVED_2=27 -+ IT_VINLOW_R=28 -+ IT_VINLOW_F=29 -+ IT_TWARN_R=30 -+ IT_TWARN_F=31 -+ -+Optional parent device properties: -+- st,main-control-register: -+ -bit 1: Power cycling will be performed on turn OFF condition -+ -bit 2: PWRCTRL is functional -+ -bit 3: PWRCTRL active high -+- st,pads-pull-register: -+ -bit 1: WAKEUP pull down is not active -+ -bit 2: PWRCTRL pull up is active -+ -bit 3: PWRCTRL pull down is active -+ -bit 4: WAKEUP detector is disabled -+- st,vin-control-register: -+ -bit 0: VINLOW monitoring is enabled -+ -bit [1...3]: VINLOW rising threshold -+ 000 VINOK_f + 50mV -+ 001 VINOK_f + 100mV -+ 010 VINOK_f + 150mV -+ 011 VINOK_f + 200mV -+ 100 VINOK_f + 250mV -+ 101 VINOK_f + 300mV -+ 110 VINOK_f + 350mV -+ 111 VINOK_f + 400mV -+ -bit [4...5]: VINLOW hyst -+ 00 100mV -+ 01 200mV -+ 10 300mV -+ 11 400mV -+ -bit 6: SW_OUT detector is disabled -+ -bit 7: SW_IN detector is enabled. -+- st,usb-control-register: -+ -bit 3: SW_OUT current limit -+ 0: 600mA -+ 1: 1.1A -+ -bit 4: VBUS_OTG discharge is enabled -+ -bit 5: SW_OUT discharge is enabled -+ -bit 6: VBUS_OTG detection is enabled -+ -bit 7: BOOST_OVP is disabled -+- wakeup-source: bool flag to indicate this device has wakeup capabilities ++Required properties: ++- compatible: : "st,stpmic1" ++- reg: : The I2C slave address for the STPMIC1 chip. ++- interrupts: : The interrupt line the device is connected to. ++- #interrupt-cells: : Should be 1. ++- interrupt-controller: : Marks the device node as an interrupt controller. ++ Interrupt numbers are defined at ++ dt-bindings/mfd/st,stpmic1.h. + +STPMIC1 consists in a varied group of sub-devices. +Each sub-device binding is be described in own documentation file. @@ -899,12 +971,14 @@ index 0000000..0fab08a + +Example: + ++#include ++ +pmic: pmic@33 { + compatible = "st,stpmic1"; + reg = <0x33>; + interrupt-parent = <&gpioa>; + interrupts = <0 2>; -+ st,main-control-register=<0x0c>; ++ + interrupt-controller; + #interrupt-cells = <2>; + @@ -1400,7 +1474,7 @@ 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..1a5d1e2 100644 +index ef4f2ff..793e428 100644 --- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt @@ -56,6 +56,9 @@ Optional properties: @@ -1413,6 +1487,34 @@ index ef4f2ff..1a5d1e2 100644 Example 1: #include +@@ -146,11 +149,16 @@ Required properties: + * ... + * 16 : Alternate Function 15 + * 17 : Analog ++ * 18 : Reserved + + To simplify the usage, macro is available to generate "pinmux" field. + This macro is available here: + - include/dt-bindings/pinctrl/stm32-pinfunc.h + ++ Setting the pinmux's function to the Reserved (RSVD) value is used to inform ++ the driver that it shall not apply the mux setting. This can be used to ++ reserve some pins, for example to a co-processor not running Linux. ++ + Some examples of using macro: + /* GPIO A9 set as alernate function 2 */ + ... { +@@ -164,6 +172,10 @@ Required properties: + ... { + pinmux = ; + }; ++ /* GPIO A9 reserved for co-processor */ ++ ... { ++ pinmux = ; ++ }; + + Optional properties: + - GENERIC_PINCONFIG: is the generic pinconfig options to use. diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt index bd23302..6521bc4 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-stm32-lp.txt @@ -1521,10 +1623,10 @@ index 0000000..12acf9d + }; diff --git a/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt b/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt new file mode 100644 -index 0000000..a3f4762 +index 0000000..0a57e40 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/st,stpmic1-regulator.txt -@@ -0,0 +1,68 @@ +@@ -0,0 +1,69 @@ +STMicroelectronics STPMIC1 Voltage regulators + +Regulator Nodes are optional depending on needs. @@ -1560,6 +1662,7 @@ index 0000000..a3f4762 +- interrupts: index of current limit detection interrupt +- -supply: phandle to the parent supply/regulator node + each regulator supply can be described except vref_ddr. ++- regulator-active-discharge: can be used on pwr_sw1 and pwr_sw2. + +Example: +regulators { @@ -1595,10 +1698,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..19a5255 +index 0000000..66fccd5 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -@@ -0,0 +1,61 @@ +@@ -0,0 +1,58 @@ +Remoteproc System Resource Manager +---------------------------------- + @@ -1623,12 +1726,10 @@ index 0000000..19a5255 +- reg: register base address and length +- clocks: clocks required by the coprocessor +- clock-names: see clock-bindings.txt -+- pinctrl-x: pins configurations required by the coprocessor ++- pinctrl-0: pins configurations required by the coprocessor. + The SRM reserves the pins for the coprocessor, which prevents the local + processor to use them. -+- pinctrl-names: 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. ++- pinctrl-names: must be "default". +- x-supply: power supplies required by the coprocessor +- interrupts: external interrupts configurations required by the coprocessor. + This is optional since the configuration is done by the coprocessor. @@ -1644,9 +1745,8 @@ index 0000000..19a5255 + mmc0: sdhci@09060000 { + compatible = "rproc-srm-dev"; + reg = <0x09060000 0x100>; -+ pinctrl-names = "rproc_default", "rproc_idle"; -+ pinctrl-0 = <&pinctrl_mmc0>; -+ pinctrl-1 = <&pinctrl_mmc1>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&pinctrl_mmc0_m4>; + clock-names = "mmc", "icn"; + clocks = <&clk_s_c0_flexgen CLK_MMC_0>, + <&clk_s_c0_flexgen CLK_RX_ICN_HVA>; @@ -1662,10 +1762,10 @@ index 0000000..19a5255 + }; diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt new file mode 100644 -index 0000000..957adcd +index 0000000..3960ce9 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -@@ -0,0 +1,80 @@ +@@ -0,0 +1,85 @@ +STMicroelectronics STM32 Remoteproc +----------------------------------- +This document defines the binding for the remoteproc component that loads and @@ -1722,6 +1822,11 @@ index 0000000..957adcd + 1st cell: phandle to syscon block + 2nd cell: register offset containing the deep sleep setting + 3rd cell: register bitmask for the deep sleep bit ++- st,syscfg-rsc-tbl: Reference to the system configuration controlling the ++ resource table address loaded by the bootloader ++ 1st cell: phandle to syscon block ++ 2nd cell: register offset containing the resource table address ++ 3rd cell: register bitmask for the resource table address +- auto_boot: If defined, when remoteproc is probed, it looks for a default + firmware and if it finds some, it loads the firmware and starts + the remote processor. @@ -3551,10 +3656,10 @@ index c485127..dd796ec 100644 }; diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts new file mode 100644 -index 0000000..2b01a01 +index 0000000..9ec45de --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts -@@ -0,0 +1,756 @@ +@@ -0,0 +1,767 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -3564,8 +3669,8 @@ index 0000000..2b01a01 +/dts-v1/; + +#include "stm32mp157c.dtsi" -+#include "stm32mp157c-m4-srm.dtsi" +#include "stm32mp157cac-pinctrl.dtsi" ++#include "stm32mp157c-m4-srm.dtsi" +#include +#include + @@ -3719,6 +3824,14 @@ index 0000000..2b01a01 + status = "okay"; +}; + ++&cpu0{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ +&dma1 { + sram = <&dma_pool>; +}; @@ -3809,9 +3922,6 @@ index 0000000..2b01a01 + 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 { @@ -3841,6 +3951,7 @@ index 0000000..2b01a01 + pinctrl-1 = <&i2c4_pins_sleep_a>; + i2c-scl-rising-time-ns = <185>; + i2c-scl-falling-time-ns = <20>; ++ clock-frequency = <400000>; + status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; @@ -3869,10 +3980,7 @@ index 0000000..2b01a01 + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; -+ -+ st,main-control-register = <0x04>; -+ st,vin-control-register = <0xc0>; -+ st,usb-control-register = <0x20>; ++ wakeup-source; + + regulators { + compatible = "st,stpmic1-regulators"; @@ -3984,20 +4092,20 @@ index 0000000..2b01a01 + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + interrupts = ; -+ regulator-active-discharge; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + interrupts = ; -+ regulator-active-discharge; ++ regulator-active-discharge = <1>; + }; + }; + + onkey { + compatible = "st,stpmic1-onkey"; -+ interrupts = , ; ++ interrupts = , ; + interrupt-names = "onkey-falling", "onkey-rising"; ++ power-off-time-sec = <10>; + status = "okay"; + }; + @@ -4044,6 +4152,9 @@ index 0000000..2b01a01 +}; + +<dc { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <<dc_pins_a>; ++ pinctrl-1 = <<dc_pins_sleep_a>; + status = "okay"; + + port { @@ -4260,6 +4371,8 @@ index 0000000..2b01a01 + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + pinctrl-3 = <&uart4_pins_a>; ++ /delete-property/dmas; ++ /delete-property/dma-names; + status = "okay"; +}; + @@ -4268,6 +4381,8 @@ index 0000000..2b01a01 + pinctrl-0 = <&uart7_pins_a>; + pinctrl-1 = <&uart7_sleep_pins_a>; + pinctrl-2 = <&uart7_idle_pins_a>; ++ /delete-property/dmas; ++ /delete-property/dma-names; + status = "disabled"; +}; + @@ -4276,6 +4391,7 @@ index 0000000..2b01a01 + pinctrl-0 = <&usart3_pins_b>; + pinctrl-1 = <&usart3_sleep_pins_b>; + pinctrl-2 = <&usart3_idle_pins_b>; ++ st,hw-flow-ctrl; + status = "disabled"; +}; + @@ -4333,10 +4449,10 @@ index 0000000..9c89733 +}; 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 +index 0000000..14eac74 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts -@@ -0,0 +1,157 @@ +@@ -0,0 +1,129 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -4396,8 +4512,8 @@ index 0000000..15c0c91 +}; + +&m4_i2c5 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&i2c5_pins_a>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_i2c5_pins_a>; + status = "okay"; +}; + @@ -4419,74 +4535,46 @@ index 0000000..15c0c91 + + 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>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_leds_orange_pins>; + status = "okay"; + }; + }; +}; + +&m4_spi4 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&spi4_pins_a>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_spi4_pins_a>; + status = "okay"; +}; + + +&m4_timers2 { -+ pinctrl-names = "rproc_default"; + status = "okay"; +}; + +&m4_timers1 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&timer1_pins>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pwm1_pins_a_ch1>; + status = "okay"; +}; + +&m4_uart7 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&uart7_pins>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_uart7_pins_a>; + 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; ++ m4_leds_orange_pins: m4-leds-orange-0 { ++ pins { ++ pinmux = ; + }; + }; + -+ timer1_pins: pwm1-test-0 { ++ m4_pwm1_pins_a_ch1: m4-pwm1-0-ch1 { + 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 = ; ++ pinmux = ; + }; + }; +}; @@ -4496,10 +4584,10 @@ index 0000000..15c0c91 +}; diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts new file mode 100644 -index 0000000..d11fbb8 +index 0000000..5523dc3 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -0,0 +1,145 @@ +@@ -0,0 +1,147 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -4549,7 +4637,7 @@ index 0000000..d11fbb8 + }; + }; + -+ panel@0 { ++ panel: panel@0 { + compatible = "orisetech,otm8009a"; + reg = <0>; + reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; @@ -4573,6 +4661,7 @@ index 0000000..d11fbb8 + interrupt-controller; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; ++ panel = <&panel>; + status = "okay"; + }; + touchscreen@38 { @@ -4583,6 +4672,7 @@ index 0000000..d11fbb8 + interrupt-controller; + touchscreen-size-x = <480>; + touchscreen-size-y = <800>; ++ panel = <&panel>; + status = "okay"; + }; +}; @@ -4646,7 +4736,7 @@ index 0000000..d11fbb8 + }; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index f77bea4..c9eabc1 100644 +index f77bea4..f5e685d 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -6,7 +6,9 @@ @@ -4654,13 +4744,13 @@ index f77bea4..c9eabc1 100644 #include "stm32mp157c.dtsi" -#include "stm32mp157-pinctrl.dtsi" -+#include "stm32mp157c-m4-srm.dtsi" +#include "stm32mp157caa-pinctrl.dtsi" ++#include "stm32mp157c-m4-srm.dtsi" +#include / { model = "STMicroelectronics STM32MP157C eval daughter"; -@@ -20,41 +22,305 @@ +@@ -20,40 +22,309 @@ reg = <0xC0000000 0x40000000>; }; @@ -4796,6 +4886,14 @@ index f77bea4..c9eabc1 100644 }; -&i2c4 { ++&cpu0{ ++ cpu-supply = <&vddcore>; ++}; ++ ++&cpu1{ ++ cpu-supply = <&vddcore>; ++}; ++ +&dac { pinctrl-names = "default"; + pinctrl-0 = <&dac_ch1_pins_a &dac_ch2_pins_a>; @@ -4832,7 +4930,8 @@ index f77bea4..c9eabc1 100644 + pinctrl-1 = <&i2c4_pins_sleep_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; - status = "okay"; ++ clock-frequency = <400000>; ++ status = "okay"; + /delete-property/dmas; + /delete-property/dma-names; + @@ -4843,14 +4942,10 @@ index f77bea4..c9eabc1 100644 + interrupt-controller; + #interrupt-cells = <2>; + status = "okay"; -+ -+ st,main-control-register = <0x04>; -+ st,vin-control-register = <0xc0>; -+ st,usb-control-register = <0x20>; ++ wakeup-source; + + regulators { + compatible = "st,stpmic1-regulators"; -+ + ldo1-supply = <&v3v3>; + ldo2-supply = <&v3v3>; + ldo3-supply = <&vdd_ddr>; @@ -4954,20 +5049,20 @@ index f77bea4..c9eabc1 100644 + vbus_otg: pwr_sw1 { + regulator-name = "vbus_otg"; + interrupts = ; -+ regulator-active-discharge; + }; + + vbus_sw: pwr_sw2 { + regulator-name = "vbus_sw"; + interrupts = ; -+ regulator-active-discharge; ++ regulator-active-discharge = <1>; + }; + }; + + onkey { + compatible = "st,stpmic1-onkey"; -+ interrupts = , ; ++ interrupts = , ; + interrupt-names = "onkey-falling", "onkey-rising"; ++ power-off-time-sec = <10>; + status = "okay"; + }; + @@ -4979,11 +5074,10 @@ index f77bea4..c9eabc1 100644 +}; + +&ipcc { -+ status = "okay"; + status = "okay"; }; - &iwdg2 { -@@ -62,6 +328,26 @@ +@@ -62,6 +333,26 @@ status = "okay"; }; @@ -5010,7 +5104,7 @@ index f77bea4..c9eabc1 100644 &rng1 { status = "okay"; }; -@@ -70,27 +356,65 @@ +@@ -70,27 +361,67 @@ status = "okay"; }; @@ -5067,6 +5161,8 @@ index f77bea4..c9eabc1 100644 + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; + pinctrl-3 = <&uart4_pins_a>; ++ /delete-property/dmas; ++ /delete-property/dma-names; status = "okay"; }; @@ -5126,10 +5222,10 @@ index 0000000..a927b00 +}; 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 +index 0000000..8edcb4f --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts -@@ -0,0 +1,162 @@ +@@ -0,0 +1,146 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -5201,14 +5297,15 @@ index 0000000..50c274f +}; + +&m4_i2c5 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&i2c5_pins_a>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_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>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_qspi_clk_pins_a &m4_qspi_bk1_pins_a ++ &m4_qspi_bk2_pins_a>; + status = "okay"; +}; + @@ -5226,9 +5323,8 @@ index 0000000..50c274f + + 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>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_leds_orange_pins>; + status = "okay"; + }; + }; @@ -5239,44 +5335,28 @@ index 0000000..50c274f +}; + +&m4_spi1 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&spi1_pins_a>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_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>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pwm2_pins_a>; + status = "okay"; +}; + +&m4_usart3 { -+ pinctrl-names = "rproc_default"; -+ pinctrl-0 = <&usart3_pins_a>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_usart3_pins_a>; + status = "okay"; +}; + +&pinctrl { -+ leds_orange_pins: leds_orange_test-0 { ++ m4_leds_orange_pins: m4-leds-orange-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 = ; ++ pinmux = ; + }; + }; +}; @@ -5293,19 +5373,20 @@ index 0000000..50c274f + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts -index 372bc2e..559b9b9 100644 +index 063ee8a..7323f40 100644 --- a/arch/arm/boot/dts/stm32mp157c-ev1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts -@@ -6,6 +6,8 @@ +@@ -6,7 +6,8 @@ /dts-v1/; #include "stm32mp157c-ed1.dts" +-#include +#include +#include / { model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; -@@ -16,9 +18,327 @@ +@@ -17,22 +18,287 @@ }; aliases { @@ -5313,7 +5394,7 @@ index 372bc2e..559b9b9 100644 + serial1 = &usart3; ethernet0 = ðernet0; }; -+ + + clocks { + clk_ext_camera: clk-ext-camera { + #clock-cells = <0>; @@ -5359,12 +5440,12 @@ index 372bc2e..559b9b9 100644 + }; + }; + -+ panel_backlight: panel-backlight { -+ compatible = "gpio-backlight"; -+ gpios = <&gpiod 13 GPIO_ACTIVE_LOW>; -+ default-on; -+ status = "okay"; -+ }; + 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>; @@ -5390,7 +5471,7 @@ index 372bc2e..559b9b9 100644 + }; + }; + -+ sound { ++ sound: sound { + compatible = "audio-graph-card"; + label = "STM32MP1-EV"; + routing = @@ -5462,11 +5543,12 @@ index 372bc2e..559b9b9 100644 + st,hs-rx-offset = <2>; + st,no-lsfs-sc; + }; -+}; -+ -+&cec { + }; + + &cec { +- pinctrl-names = "default"; + pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <&cec_pins_a>; + pinctrl-0 = <&cec_pins_a>; + pinctrl-1 = <&cec_pins_sleep_a>; +}; + @@ -5498,7 +5580,7 @@ index 372bc2e..559b9b9 100644 + + clocks = <&rcc DFSDM_K>, <&rcc ADFSDM_K>; + clock-names = "dfsdm", "audio"; -+ status = "okay"; + status = "okay"; + + dfsdm0: filter@0 { + compatible = "st,stm32-dfsdm-dmic"; @@ -5590,51 +5672,24 @@ index 372bc2e..559b9b9 100644 + }; + }; + }; -+ }; -+}; -+ -+&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 { -@@ -26,7 +346,7 @@ + &dsi { +@@ -59,10 +325,11 @@ + }; + }; + +- panel-dsi@0 { ++ panel_dsi: panel-dsi@0 { + compatible = "raydium,rm68200"; + reg = <0>; + reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; ++ power-supply = <&v3v3>; + backlight = <&panel_backlight>; + status = "okay"; + +@@ -79,7 +346,7 @@ pinctrl-0 = <ðernet0_rgmii_pins_a>; pinctrl-1 = <ðernet0_rgmii_pins_sleep_a>; pinctrl-names = "default", "sleep"; @@ -5643,18 +5698,15 @@ index 372bc2e..559b9b9 100644 max-speed = <1000>; phy-handle = <&phy0>; -@@ -40,43 +360,200 @@ +@@ -93,20 +360,167 @@ }; }; --&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>; + @@ -5675,8 +5727,8 @@ index 372bc2e..559b9b9 100644 + 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"; @@ -5786,6 +5838,7 @@ index 372bc2e..559b9b9 100644 + gt9147: goodix_ts@5d { + compatible = "goodix,gt9147"; + reg = <0x5d>; ++ panel = <&panel_dsi>; + status = "okay"; + + irq-gpios = <&stmfx_pinctrl 14 GPIO_ACTIVE_HIGH>; @@ -5810,22 +5863,13 @@ index 372bc2e..559b9b9 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>; -+ }; -+ }; + }; + + <dc { +@@ -124,20 +538,23 @@ }; &m_can1 { @@ -5851,7 +5895,7 @@ index 372bc2e..559b9b9 100644 reg = <0>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; -@@ -85,6 +562,7 @@ +@@ -146,6 +563,7 @@ }; flash1: mx66l51235l@1 { @@ -5859,7 +5903,7 @@ index 372bc2e..559b9b9 100644 reg = <1>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; -@@ -93,17 +571,110 @@ +@@ -154,17 +572,110 @@ }; }; @@ -5941,7 +5985,7 @@ index 372bc2e..559b9b9 100644 +&spdifrx { + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&spdifrx_pins_a>; -+ pinctrl-1 = <&spdifrx_sleep_pins_a>; ++ pinctrl-1 = <&spdifrx_pins_a>; + status = "okay"; + + spdifrx_port: port { @@ -5972,7 +6016,7 @@ index 372bc2e..559b9b9 100644 status = "okay"; }; timer@1 { -@@ -113,9 +684,12 @@ +@@ -174,9 +685,12 @@ &timers8 { status = "disabled"; @@ -5986,7 +6030,7 @@ index 372bc2e..559b9b9 100644 status = "okay"; }; timer@7 { -@@ -125,9 +699,12 @@ +@@ -186,9 +700,12 @@ &timers12 { status = "disabled"; @@ -6000,7 +6044,7 @@ index 372bc2e..559b9b9 100644 status = "okay"; }; timer@11 { -@@ -135,14 +712,24 @@ +@@ -196,14 +713,25 @@ }; }; @@ -6009,6 +6053,7 @@ index 372bc2e..559b9b9 100644 + pinctrl-0 = <&usart3_pins_a>; + pinctrl-1 = <&usart3_sleep_pins_a>; + pinctrl-2 = <&usart3_idle_pins_a>; ++ st,hw-flow-ctrl; + status = "disabled"; +}; + @@ -6026,7 +6071,7 @@ index 372bc2e..559b9b9 100644 phys = <&usbphyc_port1 0>; phy-names = "usb2-phy"; status = "okay"; -@@ -151,3 +738,11 @@ +@@ -212,3 +740,11 @@ &usbphyc { status = "okay"; }; @@ -6040,10 +6085,535 @@ index 372bc2e..559b9b9 100644 +}; 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..9ea9736 +index 0000000..4d641a9 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-m4-srm.dtsi -@@ -0,0 +1,436 @@ +@@ -0,0 +1,961 @@ ++// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Author: Fabien Dessenne for STMicroelectronics. ++ */ ++ ++&pinctrl { ++ m4_adc1_in6_pins_a: m4-adc1-in6 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_adc12_ain_pins_a: m4-adc12-ain-0 { ++ pins { ++ pinmux = , /* ADC1 in13 */ ++ , /* ADC1 in6 */ ++ , /* ADC2 in2 */ ++ ; /* ADC2 in6 */ ++ }; ++ }; ++ ++ m4_adc12_usb_pwr_pins_a: m4-adc12-usb-pwr-pins-0 { ++ pins { ++ pinmux = , /* ADC12 in18 */ ++ ; /* ADC12 in19 */ ++ }; ++ }; ++ ++ m4_cec_pins_a: m4-cec-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_cec_pins_b: m4-cec-1 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_dac_ch1_pins_a: m4-dac-ch1 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_dac_ch2_pins_a: m4-dac-ch2 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_dcmi_pins_a: m4-dcmi-0 { ++ pins { ++ pinmux = ,/* DCMI_HSYNC */ ++ ,/* DCMI_VSYNC */ ++ ,/* DCMI_PIXCLK */ ++ ,/* DCMI_D0 */ ++ ,/* DCMI_D1 */ ++ ,/* DCMI_D2 */ ++ ,/* DCMI_D3 */ ++ ,/* DCMI_D4 */ ++ ,/* DCMI_D5 */ ++ ,/* DCMI_D6 */ ++ ,/* DCMI_D7 */ ++ ,/* DCMI_D8 */ ++ ,/* DCMI_D9 */ ++ ,/* DCMI_D10 */ ++ ;/* DCMI_D11 */ ++ }; ++ }; ++ ++ m4_dfsdm_clkout_pins_a: m4-dfsdm-clkout-pins-0 { ++ pins { ++ pinmux = ; /* DFSDM_CKOUT */ ++ }; ++ }; ++ ++ m4_dfsdm_data1_pins_a: m4-dfsdm-data1-pins-0 { ++ pins { ++ pinmux = ; /* DFSDM_DATA1 */ ++ }; ++ }; ++ ++ m4_dfsdm_data3_pins_a: m4-dfsdm-data3-pins-0 { ++ pins { ++ pinmux = ; /* DFSDM_DATA3 */ ++ }; ++ }; ++ ++ m4_ethernet0_rgmii_pins_a: m4-rgmii-0 { ++ pins { ++ pinmux = , /* ETH_RGMII_CLK125 */ ++ , /* ETH_RGMII_GTX_CLK */ ++ , /* ETH_RGMII_TXD0 */ ++ , /* ETH_RGMII_TXD1 */ ++ , /* ETH_RGMII_TXD2 */ ++ , /* ETH_RGMII_TXD3 */ ++ , /* ETH_RGMII_TX_CTL */ ++ , /* ETH_MDC */ ++ , /* ETH_MDIO */ ++ , /* ETH_RGMII_RXD0 */ ++ , /* ETH_RGMII_RXD1 */ ++ , /* ETH_RGMII_RXD2 */ ++ , /* ETH_RGMII_RXD3 */ ++ , /* ETH_RGMII_RX_CLK */ ++ ; /* ETH_RGMII_RX_CTL */ ++ }; ++ }; ++ ++ m4_fmc_pins_a: m4-fmc-0 { ++ pins { ++ pinmux = , /* FMC_NOE */ ++ , /* FMC_NWE */ ++ , /* FMC_A16_FMC_CLE */ ++ , /* FMC_A17_FMC_ALE */ ++ , /* FMC_D0 */ ++ , /* FMC_D1 */ ++ , /* FMC_D2 */ ++ , /* FMC_D3 */ ++ , /* FMC_D4 */ ++ , /* FMC_D5 */ ++ , /* FMC_D6 */ ++ , /* FMC_D7 */ ++ , /* FMC_NE2_FMC_NCE */ ++ ; /* FMC_NWAIT */ ++ }; ++ }; ++ ++ m4_hdp0_pins_a: m4-hdp0-0 { ++ pins { ++ pinmux = ; /* HDP0 */ ++ }; ++ }; ++ ++ m4_hdp6_pins_a: m4-hdp6-0 { ++ pins { ++ pinmux = ; /* HDP6 */ ++ }; ++ }; ++ ++ m4_hdp7_pins_a: m4-hdp7-0 { ++ pins { ++ pinmux = ; /* HDP7 */ ++ }; ++ }; ++ ++ m4_i2c1_pins_a: m4-i2c1-0 { ++ pins { ++ pinmux = , /* I2C1_SCL */ ++ ; /* I2C1_SDA */ ++ }; ++ }; ++ ++ m4_i2c2_pins_a: m4-i2c2-0 { ++ pins { ++ pinmux = , /* I2C2_SCL */ ++ ; /* I2C2_SDA */ ++ }; ++ }; ++ ++ m4_i2c5_pins_a: m4-i2c5-0 { ++ pins { ++ pinmux = , /* I2C5_SCL */ ++ ; /* I2C5_SDA */ ++ }; ++ }; ++ ++ m4_i2s2_pins_a: m4-i2s2-0 { ++ pins { ++ pinmux = , /* I2S2_SDO */ ++ , /* I2S2_WS */ ++ ; /* I2S2_CK */ ++ }; ++ }; ++ ++ m4_ltdc_pins_a: m4-ltdc-a-0 { ++ pins { ++ pinmux = , /* LCD_CLK */ ++ , /* LCD_HSYNC */ ++ , /* LCD_VSYNC */ ++ , /* LCD_DE */ ++ , /* LCD_R0 */ ++ , /* LCD_R1 */ ++ , /* LCD_R2 */ ++ , /* LCD_R3 */ ++ , /* LCD_R4 */ ++ , /* LCD_R5 */ ++ , /* LCD_R6 */ ++ , /* LCD_R7 */ ++ , /* LCD_G0 */ ++ , /* LCD_G1 */ ++ , /* LCD_G2 */ ++ , /* LCD_G3 */ ++ , /* LCD_G4 */ ++ , /* LCD_G5 */ ++ , /* LCD_G6 */ ++ , /* LCD_G7 */ ++ , /* LCD_B0 */ ++ , /* LCD_B1 */ ++ , /* LCD_B2 */ ++ , /* LCD_B3 */ ++ , /* LCD_B4 */ ++ , /* LCD_B5 */ ++ , /* LCD_B6 */ ++ ; /* LCD_B7 */ ++ }; ++ }; ++ ++ m4_ltdc_pins_b: m4-ltdc-b-0 { ++ pins { ++ pinmux = , /* LCD_CLK */ ++ , /* LCD_HSYNC */ ++ , /* LCD_VSYNC */ ++ , /* LCD_DE */ ++ , /* LCD_R0 */ ++ , /* LCD_R1 */ ++ , /* LCD_R2 */ ++ , /* LCD_R3 */ ++ , /* LCD_R4 */ ++ , /* LCD_R5 */ ++ , /* LCD_R6 */ ++ , /* LCD_R7 */ ++ , /* LCD_G0 */ ++ , /* LCD_G1 */ ++ , /* LCD_G2 */ ++ , /* LCD_G3 */ ++ , /* LCD_G4 */ ++ , /* LCD_G5 */ ++ , /* LCD_G6 */ ++ , /* LCD_G7 */ ++ , /* LCD_B0 */ ++ , /* LCD_B1 */ ++ , /* LCD_B2 */ ++ , /* LCD_B3 */ ++ , /* LCD_B4 */ ++ , /* LCD_B5 */ ++ , /* LCD_B6 */ ++ ; /* LCD_B7 */ ++ }; ++ }; ++ ++ m4_m_can1_pins_a: m4-m-can1-0 { ++ pins { ++ pinmux = , /* CAN1_TX */ ++ ; /* CAN1_RX */ ++ }; ++ }; ++ ++ m4_pwm1_pins_a: m4-pwm1-0 { ++ pins { ++ pinmux = , /* TIM1_CH1 */ ++ , /* TIM1_CH2 */ ++ ; /* TIM1_CH4 */ ++ }; ++ }; ++ ++ m4_pwm2_pins_a: m4-pwm2-0 { ++ pins { ++ pinmux = ; /* TIM2_CH4 */ ++ }; ++ }; ++ ++ m4_pwm3_pins_a: m4-pwm3-0 { ++ pins { ++ pinmux = ; /* TIM3_CH2 */ ++ }; ++ }; ++ ++ m4_pwm4_pins_a: m4-pwm4-0 { ++ pins { ++ pinmux = , /* TIM4_CH3 */ ++ ; /* TIM4_CH4 */ ++ }; ++ }; ++ ++ m4_pwm4_pins_b: m4-pwm4-1 { ++ pins { ++ pinmux = ; /* TIM4_CH2 */ ++ }; ++ }; ++ ++ m4_pwm5_pins_a: m4-pwm5-0 { ++ pins { ++ pinmux = ; /* TIM5_CH2 */ ++ }; ++ }; ++ ++ m4_pwm8_pins_a: m4-pwm8-0 { ++ pins { ++ pinmux = ; /* TIM8_CH4 */ ++ }; ++ }; ++ ++ m4_pwm12_pins_a: m4-pwm12-0 { ++ pins { ++ pinmux = ; /* TIM12_CH1 */ ++ }; ++ }; ++ ++ m4_qspi_bk1_pins_a: m4-qspi-bk1-0 { ++ pins { ++ pinmux = , /* QSPI_BK1_IO0 */ ++ , /* QSPI_BK1_IO1 */ ++ , /* QSPI_BK1_IO2 */ ++ , /* QSPI_BK1_IO3 */ ++ ; /* QSPI_BK1_NCS */ ++ }; ++ }; ++ ++ m4_qspi_bk2_pins_a: m4-qspi-bk2-0 { ++ pins { ++ pinmux = , /* QSPI_BK2_IO0 */ ++ , /* QSPI_BK2_IO1 */ ++ , /* QSPI_BK2_IO2 */ ++ , /* QSPI_BK2_IO3 */ ++ ; /* QSPI_BK2_NCS */ ++ }; ++ }; ++ ++ m4_qspi_clk_pins_a: m4-qspi-clk-0 { ++ pins { ++ pinmux = ; /* QSPI_CLK */ ++ }; ++ }; ++ ++ m4_rtc_out2_rmp_pins_a: m4-rtc-out2-rmp-pins-0 { ++ pins { ++ pinmux = ; /* RTC_OUT2_RMP */ ++ }; ++ }; ++ ++ m4_sai2a_pins_a: m4-sai2a-0 { ++ pins { ++ pinmux = , /* SAI2_SCK_A */ ++ , /* SAI2_SD_A */ ++ , /* SAI2_FS_A */ ++ ; /* SAI2_MCLK_A */ ++ }; ++ }; ++ ++ m4_sai2b_pins_a: m4-sai2b-0 { ++ pins { ++ pinmux = , /* SAI2_SCK_B */ ++ , /* SAI2_FS_B */ ++ , /* SAI2_MCLK_B */ ++ ; /* SAI2_SD_B */ ++ }; ++ }; ++ ++ m4_sai2b_pins_b: m4-sai2b-2 { ++ pins { ++ pinmux = ; /* SAI2_SD_B */ ++ }; ++ }; ++ ++ m4_sai4a_pins_a: m4-sai4a-0 { ++ pins { ++ pinmux = ; /* SAI4_SD_A */ ++ }; ++ }; ++ ++ m4_sdmmc1_b4_pins_a: m4-sdmmc1-b4-0 { ++ pins { ++ pinmux = , /* SDMMC1_D0 */ ++ , /* SDMMC1_D1 */ ++ , /* SDMMC1_D2 */ ++ , /* SDMMC1_D3 */ ++ , /* SDMMC1_CMD */ ++ ; /* SDMMC1_CK */ ++ }; ++ }; ++ ++ m4_sdmmc1_dir_pins_a: m4-sdmmc1-dir-0 { ++ pins { ++ pinmux = , /* SDMMC1_D0DIR */ ++ , /* SDMMC1_D123DIR */ ++ , /* SDMMC1_CDIR */ ++ ; /* SDMMC1_CKIN */ ++ }; ++ }; ++ ++ m4_sdmmc2_b4_pins_a: m4-sdmmc2-b4-0 { ++ pins { ++ pinmux = , /* SDMMC2_D0 */ ++ , /* SDMMC2_D1 */ ++ , /* SDMMC2_D2 */ ++ , /* SDMMC2_D3 */ ++ , /* SDMMC2_CMD */ ++ ; /* SDMMC2_CK */ ++ }; ++ }; ++ ++ m4_sdmmc2_b4_pins_b: m4-sdmmc2-b4-1 { ++ pins { ++ pinmux = , /* SDMMC2_D0 */ ++ , /* SDMMC2_D1 */ ++ , /* SDMMC2_D2 */ ++ , /* SDMMC2_D3 */ ++ , /* SDMMC2_CMD */ ++ ; /* SDMMC2_CK */ ++ }; ++ }; ++ ++ m4_sdmmc2_d47_pins_a: m4-sdmmc2-d47-0 { ++ pins { ++ pinmux = , /* SDMMC2_D4 */ ++ , /* SDMMC2_D5 */ ++ , /* SDMMC2_D6 */ ++ ; /* SDMMC2_D7 */ ++ }; ++ }; ++ ++ m4_sdmmc3_b4_pins_a: m4-sdmmc3-b4-0 { ++ pins { ++ pinmux = , /* SDMMC3_D0 */ ++ , /* SDMMC3_D1 */ ++ , /* SDMMC3_D2 */ ++ , /* SDMMC3_D3 */ ++ , /* SDMMC3_CMD */ ++ ; /* SDMMC3_CK */ ++ }; ++ }; ++ ++ m4_spdifrx_pins_a: m4-spdifrx-0 { ++ pins { ++ pinmux = ; /* SPDIF_IN1 */ ++ }; ++ }; ++ ++ m4_spi4_pins_a: m4-spi4-0 { ++ pins { ++ pinmux = , /* SPI4_SCK */ ++ , /* SPI4_MOSI */ ++ ; /* SPI4_MISO */ ++ }; ++ }; ++ ++ m4_spi5_pins_a: m4-spi5-0 { ++ pins { ++ pinmux = , /* SPI5_SCK */ ++ , /* SPI5_MOSI */ ++ ; /* SPI5_MISO */ ++ }; ++ }; ++ ++ m4_stusb1600_pins_a: m4-stusb1600-0 { ++ pins { ++ pinmux = ; ++ }; ++ }; ++ ++ m4_uart4_pins_a: m4-uart4-0 { ++ pins { ++ pinmux = , /* UART4_TX */ ++ ; /* UART4_RX */ ++ }; ++ }; ++ ++ m4_uart7_pins_a: m4-uart7-0 { ++ pins { ++ pinmux = , /* USART7_TX */ ++ ; /* USART7_RX */ ++ }; ++ }; ++ ++ m4_usart2_pins_a: m4-usart2-0 { ++ pins { ++ pinmux = , /* USART2_TX */ ++ , /* USART2_RTS */ ++ , /* USART2_RX */ ++ ; /* USART2_CTS_NSS */ ++ }; ++ }; ++ ++ m4_usart3_pins_a: m4-usart3-0 { ++ pins { ++ pinmux = , /* USART3_TX */ ++ , /* USART3_RTS */ ++ , /* USART3_RX */ ++ ; /* USART3_CTS_NSS */ ++ }; ++ }; ++ ++ m4_usart3_pins_b: m4-usart3-1 { ++ pins { ++ pinmux = , /* USART3_TX */ ++ , /* USART3_RTS */ ++ , /* USART3_RX */ ++ ; /* USART3_CTS_NSS */ ++ }; ++ }; ++ ++ m4_usbotg_hs_pins_a: m4-usbotg_hs-0 { ++ pins { ++ pinmux = ; /* OTG_ID */ ++ }; ++ }; ++ ++ m4_usbotg_fs_dp_dm_pins_a: m4-usbotg-fs-dp-dm-0 { ++ pins { ++ pinmux = , /* OTG_FS_DM */ ++ ; /* OTG_FS_DP */ ++ }; ++ }; ++}; ++ ++&pinctrl_z { ++ m4_i2c4_pins_a: m4-i2c4-0 { ++ pins { ++ pinmux = , /* I2C4_SCL */ ++ ; /* I2C4_SDA */ ++ }; ++ }; ++ ++ m4_spi1_pins_a: m4-spi1-0 { ++ pins { ++ pinmux = , /* SPI1_SCK */ ++ , /* SPI1_MOSI */ ++ ; /* SPI1_MISO */ ++ }; ++ }; ++}; ++ +&m4_rproc { + m4_system_resources { + #address-cells = <1>; @@ -6481,7 +7051,7 @@ index 0000000..9ea9736 +}; + diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi -index 185541a..e8f995a 100644 +index c50c36b..d56e0f9 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp157c.dtsi @@ -5,6 +5,7 @@ @@ -6492,21 +7062,43 @@ index 185541a..e8f995a 100644 #include / { -@@ -19,20 +20,28 @@ +@@ -19,20 +20,50 @@ compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; -+ clock-frequency = <650000000>; ++ clocks = <&rcc CK_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; ++ nvmem-cells = <&part_number_otp>; ++ nvmem-cell-names = "part_number"; }; cpu1: cpu@1 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <1>; -+ clock-frequency = <650000000>; ++ clocks = <&rcc CK_MPU>; ++ clock-names = "cpu"; ++ operating-points-v2 = <&cpu0_opp_table>; }; }; ++ cpu0_opp_table: cpu0-opp-table { ++ compatible = "operating-points-v2"; ++ opp-shared; ++ ++ opp-650000000 { ++ opp-hz = /bits/ 64 <650000000>; ++ opp-microvolt = <1200000>; ++ opp-supported-hw = <0x1>; ++ }; ++ opp-800000000 { ++ opp-hz = /bits/ 64 <800000000>; ++ opp-microvolt = <1350000>; ++ opp-supported-hw = <0x2>; ++ }; ++ }; ++ + arm-pmu { + compatible = "arm,cortex-a7-pmu"; + interrupts = , @@ -6524,7 +7116,7 @@ index 185541a..e8f995a 100644 }; intc: interrupt-controller@a0021000 { -@@ -50,6 +59,7 @@ +@@ -50,6 +81,7 @@ , ; interrupt-parent = <&intc>; @@ -6532,7 +7124,7 @@ index 185541a..e8f995a 100644 }; clocks { -@@ -82,6 +92,87 @@ +@@ -82,6 +114,87 @@ compatible = "fixed-clock"; clock-frequency = <4000000>; }; @@ -6620,7 +7212,7 @@ index 185541a..e8f995a 100644 }; soc { -@@ -98,10 +189,17 @@ +@@ -98,10 +211,17 @@ reg = <0x40000000 0x400>; clocks = <&rcc TIM2_K>; clock-names = "int"; @@ -6638,7 +7230,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -119,10 +217,18 @@ +@@ -119,10 +239,18 @@ reg = <0x40001000 0x400>; clocks = <&rcc TIM3_K>; clock-names = "int"; @@ -6657,7 +7249,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -140,10 +246,16 @@ +@@ -140,10 +268,16 @@ reg = <0x40002000 0x400>; clocks = <&rcc TIM4_K>; clock-names = "int"; @@ -6674,7 +7266,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -161,10 +273,18 @@ +@@ -161,10 +295,18 @@ reg = <0x40003000 0x400>; clocks = <&rcc TIM5_K>; clock-names = "int"; @@ -6693,7 +7285,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -182,6 +302,8 @@ +@@ -182,6 +324,8 @@ reg = <0x40004000 0x400>; clocks = <&rcc TIM6_K>; clock-names = "int"; @@ -6702,7 +7294,7 @@ index 185541a..e8f995a 100644 status = "disabled"; timer@5 { -@@ -198,6 +320,8 @@ +@@ -198,6 +342,8 @@ reg = <0x40005000 0x400>; clocks = <&rcc TIM7_K>; clock-names = "int"; @@ -6711,7 +7303,7 @@ index 185541a..e8f995a 100644 status = "disabled"; timer@6 { -@@ -218,6 +342,7 @@ +@@ -218,6 +364,7 @@ pwm { compatible = "st,stm32-pwm"; @@ -6719,7 +7311,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -239,6 +364,7 @@ +@@ -239,6 +386,7 @@ pwm { compatible = "st,stm32-pwm"; @@ -6727,7 +7319,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -260,6 +386,7 @@ +@@ -260,6 +408,7 @@ pwm { compatible = "st,stm32-pwm"; @@ -6735,7 +7327,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -277,6 +404,7 @@ +@@ -277,6 +426,7 @@ reg = <0x40009000 0x400>; clocks = <&rcc LPTIM1_K>; clock-names = "mux"; @@ -6743,7 +7335,7 @@ index 185541a..e8f995a 100644 status = "disabled"; pwm { -@@ -305,8 +433,20 @@ +@@ -305,8 +455,20 @@ interrupts = ; clocks = <&rcc SPI2_K>; resets = <&rcc SPI2_R>; @@ -6766,7 +7358,7 @@ index 185541a..e8f995a 100644 dma-names = "rx", "tx"; status = "disabled"; }; -@@ -319,93 +459,166 @@ +@@ -319,93 +481,178 @@ interrupts = ; clocks = <&rcc SPI3_K>; resets = <&rcc SPI3_R>; @@ -6814,6 +7406,9 @@ index 185541a..e8f995a 100644 + resets = <&rcc USART2_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 43 0x400 0x21>, ++ <&dmamux1 44 0x400 0x1>; ++ dma-names = "rx", "tx"; status = "disabled"; }; @@ -6828,6 +7423,9 @@ index 185541a..e8f995a 100644 + resets = <&rcc USART3_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 45 0x400 0x21>, ++ <&dmamux1 46 0x400 0x1>; ++ dma-names = "rx", "tx"; status = "disabled"; }; @@ -6842,6 +7440,9 @@ index 185541a..e8f995a 100644 + resets = <&rcc UART4_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 63 0x400 0x21>, ++ <&dmamux1 64 0x400 0x1>; ++ dma-names = "rx", "tx"; status = "disabled"; }; @@ -6856,6 +7457,9 @@ index 185541a..e8f995a 100644 + resets = <&rcc UART5_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 65 0x400 0x21>, ++ <&dmamux1 66 0x400 0x1>; ++ dma-names = "rx", "tx"; status = "disabled"; }; @@ -6951,7 +7555,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -413,8 +626,9 @@ +@@ -413,8 +660,9 @@ compatible = "st,stm32-cec"; reg = <0x40016000 0x400>; interrupts = ; @@ -6962,7 +7566,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -445,16 +659,26 @@ +@@ -445,16 +693,32 @@ uart7: serial@40018000 { compatible = "st,stm32h7-uart"; reg = <0x40018000 0x400>; @@ -6974,6 +7578,9 @@ index 185541a..e8f995a 100644 + resets = <&rcc UART7_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 79 0x400 0x21>, ++ <&dmamux1 80 0x400 0x1>; ++ dma-names = "rx", "tx"; status = "disabled"; }; @@ -6988,10 +7595,13 @@ index 185541a..e8f995a 100644 + resets = <&rcc UART8_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 81 0x400 0x21>, ++ <&dmamux1 82 0x400 0x1>; ++ dma-names = "rx", "tx"; status = "disabled"; }; -@@ -465,10 +689,20 @@ +@@ -465,10 +729,20 @@ reg = <0x44000000 0x400>; clocks = <&rcc TIM1_K>; clock-names = "int"; @@ -7012,7 +7622,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -486,10 +720,20 @@ +@@ -486,10 +760,20 @@ reg = <0x44001000 0x400>; clocks = <&rcc TIM8_K>; clock-names = "int"; @@ -7033,7 +7643,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -503,8 +747,13 @@ +@@ -503,8 +787,16 @@ usart6: serial@44003000 { compatible = "st,stm32h7-uart"; reg = <0x44003000 0x400>; @@ -7045,10 +7655,13 @@ index 185541a..e8f995a 100644 + resets = <&rcc USART6_R>; + wakeup-source; + power-domains = <&pd_core>; ++ dmas = <&dmamux1 71 0x400 0x21>, ++ <&dmamux1 72 0x400 0x1>; ++ dma-names = "rx", "tx"; status = "disabled"; }; -@@ -516,8 +765,20 @@ +@@ -516,8 +808,20 @@ interrupts = ; clocks = <&rcc SPI1_K>; resets = <&rcc SPI1_R>; @@ -7071,7 +7684,7 @@ index 185541a..e8f995a 100644 dma-names = "rx", "tx"; status = "disabled"; }; -@@ -530,9 +791,10 @@ +@@ -530,9 +834,10 @@ interrupts = ; clocks = <&rcc SPI4_K>; resets = <&rcc SPI4_R>; @@ -7084,7 +7697,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -543,10 +805,16 @@ +@@ -543,10 +848,16 @@ reg = <0x44006000 0x400>; clocks = <&rcc TIM15_K>; clock-names = "int"; @@ -7101,7 +7714,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -564,10 +832,14 @@ +@@ -564,10 +875,14 @@ reg = <0x44007000 0x400>; clocks = <&rcc TIM16_K>; clock-names = "int"; @@ -7116,7 +7729,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; timer@15 { -@@ -584,10 +856,14 @@ +@@ -584,10 +899,14 @@ reg = <0x44008000 0x400>; clocks = <&rcc TIM17_K>; clock-names = "int"; @@ -7131,7 +7744,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -606,10 +882,105 @@ +@@ -606,12 +925,107 @@ interrupts = ; clocks = <&rcc SPI5_K>; resets = <&rcc SPI5_R>; @@ -7141,9 +7754,9 @@ index 185541a..e8f995a 100644 + <&dmamux1 86 0x400 0x01>; dma-names = "rx", "tx"; + power-domains = <&pd_core>; -+ status = "disabled"; -+ }; -+ + status = "disabled"; + }; + + sai1: sai@4400a000 { + compatible = "st,stm32h7-sai"; + #address-cells = <1>; @@ -7184,7 +7797,7 @@ index 185541a..e8f995a 100644 + reg = <0x4400b000 0x4>; + interrupts = ; + resets = <&rcc SAI2_R>; - status = "disabled"; ++ status = "disabled"; + + sai2a: audio-controller@4400b004 { + #sound-dai-cells = <0>; @@ -7236,10 +7849,12 @@ index 185541a..e8f995a 100644 + dmas = <&dmamux1 114 0x400 0x01>; + status = "disabled"; + }; - }; - ++ }; ++ dfsdm: dfsdm@4400d000 { -@@ -684,12 +1055,12 @@ + compatible = "st,stm32mp1-dfsdm"; + reg = <0x4400d000 0x800>; +@@ -684,12 +1098,12 @@ m_can1: can@4400e000 { compatible = "bosch,m_can"; @@ -7254,7 +7869,7 @@ index 185541a..e8f995a 100644 clock-names = "hclk", "cclk"; bosch,mram-cfg = <0x0 0 0 32 0 0 2 2>; status = "disabled"; -@@ -702,9 +1073,9 @@ +@@ -702,9 +1116,9 @@ interrupts = , ; interrupt-names = "int0", "int1"; @@ -7266,7 +7881,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -720,9 +1091,19 @@ +@@ -720,9 +1134,19 @@ , ; clocks = <&rcc DMA1>; @@ -7274,19 +7889,19 @@ index 185541a..e8f995a 100644 #dma-cells = <4>; st,mem2mem; dma-requests = <8>; -+ dmas = <&mdma1 0 0x11 0x1200000a 0x48000008 0x00000020 1>, -+ <&mdma1 1 0x11 0x1200000a 0x48000008 0x00000800 1>, -+ <&mdma1 2 0x11 0x1200000a 0x48000008 0x00200000 1>, -+ <&mdma1 3 0x11 0x1200000a 0x48000008 0x08000000 1>, -+ <&mdma1 4 0x11 0x1200000a 0x4800000C 0x00000020 1>, -+ <&mdma1 5 0x11 0x1200000a 0x4800000C 0x00000800 1>, -+ <&mdma1 6 0x11 0x1200000a 0x4800000C 0x00200000 1>, -+ <&mdma1 7 0x11 0x1200000a 0x4800000C 0x08000000 1>; ++ dmas = <&mdma1 0 0x3 0x1200000a 0x48000008 0x00000020 1>, ++ <&mdma1 1 0x3 0x1200000a 0x48000008 0x00000800 1>, ++ <&mdma1 2 0x3 0x1200000a 0x48000008 0x00200000 1>, ++ <&mdma1 3 0x3 0x1200000a 0x48000008 0x08000000 1>, ++ <&mdma1 4 0x3 0x1200000a 0x4800000C 0x00000020 1>, ++ <&mdma1 5 0x3 0x1200000a 0x4800000C 0x00000800 1>, ++ <&mdma1 6 0x3 0x1200000a 0x4800000C 0x00200000 1>, ++ <&mdma1 7 0x3 0x1200000a 0x4800000C 0x08000000 1>; + dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; }; dma2: dma@48001000 { -@@ -737,9 +1118,19 @@ +@@ -737,9 +1161,19 @@ , ; clocks = <&rcc DMA2>; @@ -7294,19 +7909,19 @@ index 185541a..e8f995a 100644 #dma-cells = <4>; st,mem2mem; dma-requests = <8>; -+ dmas = <&mdma1 8 0x11 0x1200000a 0x48001008 0x00000020 1>, -+ <&mdma1 9 0x11 0x1200000a 0x48001008 0x00000800 1>, -+ <&mdma1 10 0x11 0x1200000a 0x48001008 0x00200000 1>, -+ <&mdma1 11 0x11 0x1200000a 0x48001008 0x08000000 1>, -+ <&mdma1 12 0x11 0x1200000a 0x4800100C 0x00000020 1>, -+ <&mdma1 13 0x11 0x1200000a 0x4800100C 0x00000800 1>, -+ <&mdma1 14 0x11 0x1200000a 0x4800100C 0x00200000 1>, -+ <&mdma1 15 0x11 0x1200000a 0x4800100C 0x08000000 1>; ++ dmas = <&mdma1 8 0x3 0x1200000a 0x48001008 0x00000020 1>, ++ <&mdma1 9 0x3 0x1200000a 0x48001008 0x00000800 1>, ++ <&mdma1 10 0x3 0x1200000a 0x48001008 0x00200000 1>, ++ <&mdma1 11 0x3 0x1200000a 0x48001008 0x08000000 1>, ++ <&mdma1 12 0x3 0x1200000a 0x4800100C 0x00000020 1>, ++ <&mdma1 13 0x3 0x1200000a 0x4800100C 0x00000800 1>, ++ <&mdma1 14 0x3 0x1200000a 0x4800100C 0x00200000 1>, ++ <&mdma1 15 0x3 0x1200000a 0x4800100C 0x08000000 1>; + dma-names = "ch0", "ch1", "ch2", "ch3", "ch4", "ch5", "ch6", "ch7"; }; dmamux1: dma-router@48002000 { -@@ -750,6 +1141,7 @@ +@@ -750,6 +1184,7 @@ dma-masters = <&dma1 &dma2>; dma-channels = <16>; clocks = <&rcc DMAMUX>; @@ -7314,7 +7929,7 @@ index 185541a..e8f995a 100644 }; adc: adc@48003000 { -@@ -760,6 +1152,10 @@ +@@ -760,6 +1195,10 @@ clocks = <&rcc ADC12>, <&rcc ADC12_K>; clock-names = "bus", "adc"; interrupt-controller; @@ -7325,7 +7940,7 @@ index 185541a..e8f995a 100644 #interrupt-cells = <1>; #address-cells = <1>; #size-cells = <0>; -@@ -771,7 +1167,7 @@ +@@ -771,7 +1210,7 @@ reg = <0x0>; interrupt-parent = <&adc>; interrupts = <0>; @@ -7334,7 +7949,7 @@ index 185541a..e8f995a 100644 dma-names = "rx"; status = "disabled"; }; -@@ -782,24 +1178,117 @@ +@@ -782,24 +1221,117 @@ reg = <0x100>; interrupt-parent = <&adc>; interrupts = <1>; @@ -7455,7 +8070,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -808,6 +1297,47 @@ +@@ -808,6 +1340,47 @@ reg = <0x50000000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; @@ -7503,7 +8118,7 @@ index 185541a..e8f995a 100644 }; exti: interrupt-controller@5000d000 { -@@ -815,11 +1345,24 @@ +@@ -815,11 +1388,24 @@ interrupt-controller; #interrupt-cells = <2>; reg = <0x5000d000 0x400>; @@ -7528,7 +8143,7 @@ index 185541a..e8f995a 100644 }; lptimer2: timer@50021000 { -@@ -829,6 +1372,7 @@ +@@ -829,6 +1415,7 @@ reg = <0x50021000 0x400>; clocks = <&rcc LPTIM2_K>; clock-names = "mux"; @@ -7536,7 +8151,7 @@ index 185541a..e8f995a 100644 status = "disabled"; pwm { -@@ -856,6 +1400,7 @@ +@@ -856,6 +1443,7 @@ reg = <0x50022000 0x400>; clocks = <&rcc LPTIM3_K>; clock-names = "mux"; @@ -7544,7 +8159,7 @@ index 185541a..e8f995a 100644 status = "disabled"; pwm { -@@ -876,6 +1421,7 @@ +@@ -876,6 +1464,7 @@ reg = <0x50023000 0x400>; clocks = <&rcc LPTIM4_K>; clock-names = "mux"; @@ -7552,7 +8167,7 @@ index 185541a..e8f995a 100644 status = "disabled"; pwm { -@@ -890,6 +1436,7 @@ +@@ -890,6 +1479,7 @@ reg = <0x50024000 0x400>; clocks = <&rcc LPTIM5_K>; clock-names = "mux"; @@ -7560,7 +8175,7 @@ index 185541a..e8f995a 100644 status = "disabled"; pwm { -@@ -908,6 +1455,198 @@ +@@ -908,6 +1498,198 @@ status = "disabled"; }; @@ -7759,7 +8374,16 @@ index 185541a..e8f995a 100644 cryp1: cryp@54001000 { compatible = "st,stm32mp1-cryp"; reg = <0x54001000 0x400>; -@@ -942,21 +1681,74 @@ +@@ -923,7 +1705,7 @@ + interrupts = ; + clocks = <&rcc HASH1>; + resets = <&rcc HASH1_R>; +- dmas = <&mdma1 31 0x10 0x1000A02 0x0 0x0 0x0>; ++ dmas = <&mdma1 31 0x2 0x1000A02 0x0 0x0 0x0>; + dma-names = "in"; + dma-maxburst = <2>; + status = "disabled"; +@@ -942,21 +1724,74 @@ reg = <0x58000000 0x1000>; interrupts = ; clocks = <&rcc MDMA>; @@ -7780,22 +8404,22 @@ index 185541a..e8f995a 100644 + <0x89010000 0x1000>, + <0x89020000 0x1000>; + interrupts = ; -+ dmas = <&mdma1 20 0x10 0x12000A02 0x0 0x0 0>, -+ <&mdma1 20 0x10 0x12000A08 0x0 0x0 0>, -+ <&mdma1 21 0x10 0x12000A0A 0x0 0x0 0>; ++ dmas = <&mdma1 20 0x2 0x12000A02 0x0 0x0 0>, ++ <&mdma1 20 0x2 0x12000A08 0x0 0x0 0>, ++ <&mdma1 21 0x2 0x12000A0A 0x0 0x0 0>; + dma-names = "tx", "rx", "ecc"; + clocks = <&rcc FMC_K>; + resets = <&rcc FMC_R>; + status = "disabled"; + }; + - qspi: qspi@58003000 { + qspi: spi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; -+ dmas = <&mdma1 22 0x10 0x100002 0x0 0x0 0x0>, -+ <&mdma1 22 0x10 0x100008 0x0 0x0 0x0>; ++ dmas = <&mdma1 22 0x2 0x100002 0x0 0x0 0x0>, ++ <&mdma1 22 0x2 0x100008 0x0 0x0 0x0>; + dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; @@ -7835,7 +8459,7 @@ index 185541a..e8f995a 100644 crc1: crc@58009000 { compatible = "st,stm32f7-crc"; reg = <0x58009000 0x400>; -@@ -974,23 +1766,27 @@ +@@ -974,23 +1809,27 @@ compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; reg = <0x5800a000 0x2000>; reg-names = "stmmaceth"; @@ -7869,7 +8493,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -1008,8 +1804,22 @@ +@@ -1008,8 +1847,22 @@ reg = <0x5800d000 0x1000>; clocks = <&rcc USBH>; resets = <&rcc USBH_R>; @@ -7893,7 +8517,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -1020,6 +1830,7 @@ +@@ -1020,6 +1873,7 @@ clock-names = "pclk", "ref", "px_clk"; resets = <&rcc DSI_R>; reset-names = "apb"; @@ -7901,7 +8525,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -1045,10 +1856,13 @@ +@@ -1045,10 +1899,13 @@ usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; @@ -7915,7 +8539,7 @@ index 185541a..e8f995a 100644 status = "disabled"; usbphyc_port0: usb-phy@0 { -@@ -1062,11 +1876,25 @@ +@@ -1062,11 +1919,25 @@ }; }; @@ -7942,7 +8566,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -1078,22 +1906,30 @@ +@@ -1078,22 +1949,30 @@ interrupts = ; clocks = <&rcc SPI6_K>; resets = <&rcc SPI6_R>; @@ -7978,7 +8602,7 @@ index 185541a..e8f995a 100644 status = "disabled"; }; -@@ -1102,21 +1938,88 @@ +@@ -1102,21 +1981,93 @@ reg = <0x5c004000 0x400>; clocks = <&rcc RTCAPB>, <&rcc RTC>; clock-names = "pclk", "rtc_ck"; @@ -7993,6 +8617,10 @@ index 185541a..e8f995a 100644 + reg = <0x5c005000 0x400>; + #address-cells = <1>; + #size-cells = <1>; ++ ++ part_number_otp: part_number_otp@4 { ++ reg = <0x4 0x1>; ++ }; + ts_cal1: calib@5c { + reg = <0x5c 0x2>; + }; @@ -8021,8 +8649,8 @@ index 185541a..e8f995a 100644 + power-domains = <&pd_core>; + st,syscfg-fmp = <&syscfg 0x4 0x20>; + st,syscfg-fmp-clr = <&syscfg 0x44 0x20>; - status = "disabled"; - }; ++ status = "disabled"; ++ }; + + tamp: tamp@5c00a000 { + compatible = "simple-bus", "syscon", "simple-mfd"; @@ -8056,20 +8684,21 @@ index 185541a..e8f995a 100644 + st,syscfg-pdds = <&pwr 0x014 0x1>; + st,syscfg-holdboot = <&rcc 0x10C 0x1>; + st,syscfg-tz = <&rcc 0x000 0x1>; ++ st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>; + status = "disabled"; + + m4_system_resources { + compatible = "rproc-srm-core"; -+ status = "disabled"; -+ }; -+ }; + 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 diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0030-ARM-stm32mp1-r2-DEFCONFIG.patch b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0030-ARM-stm32mp1-r2-DEFCONFIG.patch rename to recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch index a249780..fce739b 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/4.19.49/0030-ARM-stm32mp1-r2-DEFCONFIG.patch +++ b/recipes-kernel/linux/linux-stm32mp/4.19/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch @@ -1,13 +1,13 @@ -From 8352ebfd1953c5dc6514c0be878f7c8a47e33fa7 Mon Sep 17 00:00:00 2001 +From 62cd375deb0762da00fbfce0f211a02404f5ab54 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 +Date: Fri, 8 Nov 2019 16:52:53 +0100 +Subject: [PATCH 31/31] ARM stm32mp1 r3 DEFCONFIG --- .../arm/configs/fragment-01-multiv7_cleanup.config | 69 +++ - arch/arm/configs/fragment-02-multiv7_addons.config | 509 +++++++++++++++++++++ + arch/arm/configs/fragment-02-multiv7_addons.config | 508 +++++++++++++++++++++ arch/arm/configs/multi_v7_defconfig | 1 + - 3 files changed, 579 insertions(+) + 3 files changed, 578 insertions(+) create mode 100644 arch/arm/configs/fragment-01-multiv7_cleanup.config create mode 100644 arch/arm/configs/fragment-02-multiv7_addons.config @@ -88,10 +88,10 @@ 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..7ba8387 +index 0000000..e68bb1e --- /dev/null +++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -0,0 +1,509 @@ +@@ -0,0 +1,508 @@ +# +# General setup +# @@ -133,6 +133,7 @@ index 0000000..7ba8387 +# +# Kernel Features +# ++CONFIG_SCHED_MC=y +CONFIG_MCPM=y +CONFIG_NR_CPUS=4 +# CONFIG_PREEMPT_NONE is not set @@ -153,11 +154,8 @@ index 0000000..7ba8387 +# +# CPU Power Management +# -+ +# -+# CPU Frequency scaling -+# -+# CONFIG_CPU_FREQ is not set ++CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y + +# +# CPU Idle @@ -416,6 +414,7 @@ index 0000000..7ba8387 +# +# USB Device Class drivers +# ++CONFIG_USB_ACM=y + +# +# also be needed; see USB_STORAGE Help for more info diff --git a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-modules.config b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-modules.config index e9b3cf5..d15f1c7 100644 --- a/recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-modules.config +++ b/recipes-kernel/linux/linux-stm32mp/4.19/fragment-05-modules.config @@ -11,3 +11,5 @@ CONFIG_IIO_ST_PRESS=m CONFIG_IIO_ST_LSM6DSX=m CONFIG_IIO_ST_LSM6DSX_I2C=m +# support of event emulation +CONFIG_INPUT_UINPUT=m diff --git a/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt b/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt index 719f2ce..3baf91f 100644 --- a/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt +++ b/recipes-kernel/linux/linux-stm32mp/README.HOW_TO.txt @@ -218,7 +218,10 @@ Please refer to User guide for more details. ------------------------ * kernel + devicetree $> cd /install_artifact - $> ssh root@ mount /boot + if bootfs are not monted on target, mount it + $> ssh root@ df to see if there is a partition mounted on /boot + else + $> ssh root@ mount /boot $> scp -r boot/* root@:/boot/ $> ssh root@ umount /boot diff --git a/recipes-kernel/linux/linux-stm32mp_4.19.bb b/recipes-kernel/linux/linux-stm32mp_4.19.bb index f10c6e4..7d7bf8f 100644 --- a/recipes-kernel/linux/linux-stm32mp_4.19.bb +++ b/recipes-kernel/linux/linux-stm32mp_4.19.bb @@ -5,48 +5,49 @@ 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.49.tar.xz" -SRC_URI[md5sum] = "0cb9baf0f5ed8f56d42cccc508d841b0" -SRC_URI[sha256sum] = "92d920b3973c0dbca5516271afa405be6e5822a9b831df8c085f9c9eb838bbcd" +SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.94.tar.xz" +SRC_URI[md5sum] = "3f5621e9b463a3574618f3edfe438e4a" +SRC_URI[sha256sum] = "c62a10a75a7c4213e41287040e7c7509b7d42117d6830feb7dfe505949fa7467" SRC_URI += " \ - file://${LINUX_VERSION}/4.19.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 \ + file://${LINUX_VERSION}/4.19.94/0001-ARM-stm32mp1-r3-MACHINE.patch \ + file://${LINUX_VERSION}/4.19.94/0002-ARM-stm32mp1-r3-CPUFREQ.patch \ + file://${LINUX_VERSION}/4.19.94/0003-ARM-stm32mp1-r3-CRYPTO.patch \ + file://${LINUX_VERSION}/4.19.94/0004-ARM-stm32mp1-r3-BLUETOOTH-CHAR.patch \ + file://${LINUX_VERSION}/4.19.94/0005-ARM-stm32mp1-r3-CLOCK.patch \ + file://${LINUX_VERSION}/4.19.94/0006-ARM-stm32mp1-r3-DMA.patch \ + file://${LINUX_VERSION}/4.19.94/0007-ARM-stm32mp1-r3-DRM.patch \ + file://${LINUX_VERSION}/4.19.94/0008-ARM-stm32mp1-r3-GPIO.patch \ + file://${LINUX_VERSION}/4.19.94/0009-ARM-stm32mp1-r3-HWSPINLOCK.patch \ + file://${LINUX_VERSION}/4.19.94/0010-ARM-stm32mp1-r3-HWTRACING-I2C.patch \ + file://${LINUX_VERSION}/4.19.94/0011-ARM-stm32mp1-r3-IIO.patch \ + file://${LINUX_VERSION}/4.19.94/0012-ARM-stm32mp1-r3-INPUT-IRQ-Mailbox.patch \ + file://${LINUX_VERSION}/4.19.94/0013-ARM-stm32mp1-r3-MEDIA.patch \ + file://${LINUX_VERSION}/4.19.94/0014-ARM-stm32mp1-r3-MFD.patch \ + file://${LINUX_VERSION}/4.19.94/0015-ARM-stm32mp1-r3-MMC-MTD.patch \ + file://${LINUX_VERSION}/4.19.94/0016-ARM-stm32mp1-r3-NET.patch \ + file://${LINUX_VERSION}/4.19.94/0017-ARM-stm32mp1-r3-NVMEM.patch \ + file://${LINUX_VERSION}/4.19.94/0018-ARM-stm32mp1-r3-PERF.patch \ + file://${LINUX_VERSION}/4.19.94/0019-ARM-stm32mp1-r3-PHY-PINCTRL-PWM.patch \ + file://${LINUX_VERSION}/4.19.94/0020-ARM-stm32mp1-r3-REGULATOR.patch \ + file://${LINUX_VERSION}/4.19.94/0021-ARM-stm32mp1-r3-REMOTEPROC-RPMSG-RESET.patch \ + file://${LINUX_VERSION}/4.19.94/0022-ARM-stm32mp1-r3-RTC.patch \ + file://${LINUX_VERSION}/4.19.94/0023-ARM-stm32mp1-r3-SOC.patch \ + file://${LINUX_VERSION}/4.19.94/0024-ARM-stm32mp1-r3-SPI.patch \ + file://${LINUX_VERSION}/4.19.94/0025-ARM-stm32mp1-r3-THERMAL.patch \ + file://${LINUX_VERSION}/4.19.94/0026-ARM-stm32mp1-r3-TTY-USB.patch \ + file://${LINUX_VERSION}/4.19.94/0027-ARM-stm32mp1-r3-WATCHDOG.patch \ + file://${LINUX_VERSION}/4.19.94/0028-ARM-stm32mp1-r3-SOUND.patch \ + file://${LINUX_VERSION}/4.19.94/0029-ARM-stm32mp1-r2.4-MISC.patch \ + file://${LINUX_VERSION}/4.19.94/0030-ARM-stm32mp1-r3-DEVICETREE.patch \ + file://${LINUX_VERSION}/4.19.94/0031-ARM-stm32mp1-r3-DEFCONFIG.patch \ " LINUX_VERSION = "4.19" PV = "${LINUX_VERSION}" -S = "${WORKDIR}/linux-4.19.49" +S = "${WORKDIR}/linux-4.19.94" # --------------------------------- # Configure devupstream class usage @@ -54,7 +55,7 @@ S = "${WORKDIR}/linux-4.19.49" 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 = "9cc80ff80f5ea5f1ff35122f61afaa7b11ad22ae" +SRCREV_class-devupstream = "1cb30cb5ffc29a53ec2031b6a29878ddd266516c" SRCREV_FORMAT_class-devupstream = "linux" PV_class-devupstream = "${LINUX_VERSION}+github+${SRCPV}" diff --git a/recipes-kernel/make-mod-scripts/make-mod-scripts_1.0.bbappend b/recipes-kernel/make-mod-scripts/make-mod-scripts_1.0.bbappend new file mode 100644 index 0000000..2b9fb0c --- /dev/null +++ b/recipes-kernel/make-mod-scripts/make-mod-scripts_1.0.bbappend @@ -0,0 +1,3 @@ +# make-mode-scripts package -dev and -dbg are empty so don't generate them +ALLOW_EMPTY_${PN}-dev = "0" +ALLOW_EMPTY_${PN}-dbg = "0"