From 0d2f843602bc63ec44992e2fa41db10d65fd568f Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Tue, 27 Oct 2020 12:21:11 +0100 Subject: [PATCH] LINUX-STM32MP: update to v5.4-stm32mp-r2 Kernel 5.4.56 Change-Id: I1b6874b20f23a72b572794013ac879d50da0ecd4 --- recipes-kernel/linux/linux-stm32mp.inc | 1 + .../0014-ARM-stm32mp1-r1-MMC-NAND.patch | 1187 ------ .../5.4.31/0019-ARM-stm32mp1-r1-MISC.patch | 213 -- .../5.4.31/0022-ARM-stm32mp1-r1-POWER.patch | 24 - .../0001-ARM-stm32mp1-r2-MACHINE.patch} | 14 +- .../0002-ARM-stm32mp1-r2-CPUFREQ.patch} | 27 +- .../0003-ARM-stm32mp1-r2-CRYPTO.patch} | 296 +- ...004-ARM-stm32mp1-r2-RNG-DEBUG-NVMEM.patch} | 18 +- .../0005-ARM-stm32mp1-r2-CLOCK.patch} | 691 +++- .../0006-ARM-stm32mp1-r2-DMA.patch} | 108 +- .../0007-ARM-stm32mp1-r2-DRM.patch} | 380 +- .../0008-ARM-stm32mp1-r2-HWSPINLOCK.patch} | 124 +- ...009-ARM-stm32mp1-r2-I2C-IIO-IRQCHIP.patch} | 772 ++-- ...tm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch} | 1249 ++++++- ...-ARM-stm32mp1-r2-RESET-RTC-WATCHDOG.patch} | 165 +- ...2-ARM-stm32mp1-r2-MEDIA-SOC-THERMAL.patch} | 356 +- .../0013-ARM-stm32mp1-r2-MFD.patch} | 403 +- .../0014-ARM-stm32mp1-r2-MMC-NAND.patch | 3318 +++++++++++++++++ .../0015-ARM-stm32mp1-r2-NET-TTY.patch} | 745 +++- .../0016-ARM-stm32mp1-r2-PHY-USB.patch} | 625 +++- ...m32mp1-r2-PINCTRL-REGULATOR-SPI-PWM.patch} | 457 ++- .../0018-ARM-stm32mp1-r2-SOUND.patch} | 687 +++- ...0019-ARM-stm32mp1-r2-MISC-CPUIDLE-MM.patch | 1943 ++++++++++ .../0020-ARM-stm32mp1-r2-DEVICETREE.patch} | 1732 +++------ .../0021-ARM-stm32mp1-r2-CONFIG.patch} | 42 +- .../0022-ARM-stm32mp1-r2-PERF.patch} | 16 +- recipes-kernel/linux/linux-stm32mp_5.4.bb | 51 +- 27 files changed, 11099 insertions(+), 4545 deletions(-) delete mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch delete mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch => 5.4.56/0001-ARM-stm32mp1-r2-MACHINE.patch} (80%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch => 5.4.56/0002-ARM-stm32mp1-r2-CPUFREQ.patch} (88%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch => 5.4.56/0003-ARM-stm32mp1-r2-CRYPTO.patch} (80%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch => 5.4.56/0004-ARM-stm32mp1-r2-RNG-DEBUG-NVMEM.patch} (94%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch => 5.4.56/0005-ARM-stm32mp1-r2-CLOCK.patch} (71%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0006-ARM-stm32mp1-r1-DMA.patch => 5.4.56/0006-ARM-stm32mp1-r2-DMA.patch} (95%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0007-ARM-stm32mp1-r1-DRM.patch => 5.4.56/0007-ARM-stm32mp1-r2-DRM.patch} (79%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch => 5.4.56/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch} (68%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch => 5.4.56/0009-ARM-stm32mp1-r2-I2C-IIO-IRQCHIP.patch} (86%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch => 5.4.56/0010-ARM-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch} (67%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch => 5.4.56/0011-ARM-stm32mp1-r2-RESET-RTC-WATCHDOG.patch} (70%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch => 5.4.56/0012-ARM-stm32mp1-r2-MEDIA-SOC-THERMAL.patch} (79%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0013-ARM-stm32mp1-r1-MFD.patch => 5.4.56/0013-ARM-stm32mp1-r2-MFD.patch} (64%) create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0014-ARM-stm32mp1-r2-MMC-NAND.patch rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch => 5.4.56/0015-ARM-stm32mp1-r2-NET-TTY.patch} (75%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch => 5.4.56/0016-ARM-stm32mp1-r2-PHY-USB.patch} (82%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch => 5.4.56/0017-ARM-stm32mp1-r2-PINCTRL-REGULATOR-SPI-PWM.patch} (87%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch => 5.4.56/0018-ARM-stm32mp1-r2-SOUND.patch} (51%) create mode 100644 recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0019-ARM-stm32mp1-r2-MISC-CPUIDLE-MM.patch rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch => 5.4.56/0020-ARM-stm32mp1-r2-DEVICETREE.patch} (87%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch => 5.4.56/0021-ARM-stm32mp1-r2-CONFIG.patch} (93%) rename recipes-kernel/linux/linux-stm32mp/5.4/{5.4.31/0023-ARM-stm32mp1-r1-PERF.patch => 5.4.56/0022-ARM-stm32mp1-r2-PERF.patch} (98%) diff --git a/recipes-kernel/linux/linux-stm32mp.inc b/recipes-kernel/linux/linux-stm32mp.inc index 20ef807..90d39d0 100644 --- a/recipes-kernel/linux/linux-stm32mp.inc +++ b/recipes-kernel/linux/linux-stm32mp.inc @@ -1,6 +1,7 @@ COMPATIBLE_MACHINE = "(stm32mpcommon)" inherit kernel +inherit kernel-fitimage DEPENDS += "openssl-native util-linux-native libyaml-native" diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch deleted file mode 100644 index 8ebd040..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0014-ARM-stm32mp1-r1-MMC-NAND.patch +++ /dev/null @@ -1,1187 +0,0 @@ -From 157e4fd4d369ee81ded975d5ccd3d7c56cb045d0 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:45:40 +0200 -Subject: [PATCH 14/23] ARM-stm32mp1-r1-MMC-NAND - ---- - drivers/mmc/core/block.c | 11 + - drivers/mmc/core/core.c | 31 ++- - drivers/mmc/host/mmci.c | 281 +++++++++++++++++-------- - drivers/mmc/host/mmci.h | 17 +- - drivers/mmc/host/mmci_stm32_sdmmc.c | 259 +++++++++++++++++++++-- - drivers/mtd/nand/raw/nand_base.c | 2 + - drivers/mtd/nand/raw/stm32_fmc2_nand.c | 46 +++- - include/linux/mmc/core.h | 1 + - include/linux/mmc/host.h | 6 + - 9 files changed, 537 insertions(+), 117 deletions(-) - -diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c -index 95b41c089..d6a7cc042 100644 ---- a/drivers/mmc/core/block.c -+++ b/drivers/mmc/core/block.c -@@ -1762,6 +1762,17 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req) - u32 blocks; - int err; - -+ /* -+ * the host is in a bad state, and can't sent a new command -+ * without be unstuck -+ */ -+ if (brq->sbc.error == -EDEADLK || brq->cmd.error == -EDEADLK || -+ brq->stop.error == -EDEADLK || brq->data.error == -EDEADLK) { -+ pr_err("%s: host is in bad state, must be unstuck\n", -+ req->rq_disk->disk_name); -+ mmc_hw_unstuck(card->host); -+ } -+ - /* - * Some errors the host driver might not have seen. Set the number of - * bytes transferred to zero in that case. -diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c -index 26644b7ec..6d00eed17 100644 ---- a/drivers/mmc/core/core.c -+++ b/drivers/mmc/core/core.c -@@ -397,6 +397,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) - void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) - { - struct mmc_command *cmd; -+ int sbc_err, stop_err, data_err; - - while (1) { - wait_for_completion(&mrq->completion); -@@ -420,8 +421,20 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) - mmc_hostname(host), __func__); - } - } -- if (!cmd->error || !cmd->retries || -- mmc_card_removed(host->card)) -+ -+ sbc_err = mrq->sbc ? mrq->sbc->error : 0; -+ stop_err = mrq->stop ? mrq->stop->error : 0; -+ data_err = mrq->data ? mrq->data->error : 0; -+ -+ if (cmd->error == -EDEADLK || sbc_err == -EDEADLK || -+ stop_err == -EDEADLK || data_err == -EDEADLK) { -+ pr_debug("%s: host is in bad state, must be unstuck\n", -+ mmc_hostname(host)); -+ mmc_hw_unstuck(host); -+ } -+ -+ if ((!cmd->error && !sbc_err && !stop_err && !data_err) || -+ !cmd->retries || mmc_card_removed(host->card)) - break; - - mmc_retune_recheck(host); -@@ -430,6 +443,12 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) - mmc_hostname(host), cmd->opcode, cmd->error); - cmd->retries--; - cmd->error = 0; -+ if (mrq->sbc) -+ mrq->sbc->error = 0; -+ if (mrq->stop) -+ mrq->stop->error = 0; -+ if (mrq->data) -+ mrq->data->error = 0; - __mmc_start_request(host, mrq); - } - -@@ -2163,6 +2182,14 @@ int mmc_sw_reset(struct mmc_host *host) - } - EXPORT_SYMBOL(mmc_sw_reset); - -+void mmc_hw_unstuck(struct mmc_host *host) -+{ -+ if (!host->ops->hw_unstuck) -+ return; -+ host->ops->hw_unstuck(host); -+} -+EXPORT_SYMBOL(mmc_hw_unstuck); -+ - static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) - { - host->f_init = freq; -diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index c37e70dbe..d4b7880fc 100644 ---- a/drivers/mmc/host/mmci.c -+++ b/drivers/mmc/host/mmci.c -@@ -22,6 +22,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -44,6 +45,7 @@ - #define DRIVER_NAME "mmci-pl18x" - - static void mmci_variant_init(struct mmci_host *host); -+static void ux500_variant_init(struct mmci_host *host); - static void ux500v2_variant_init(struct mmci_host *host); - - static unsigned int fmax = 515633; -@@ -175,7 +177,6 @@ static struct variant_data variant_ux500 = { - .f_max = 100000000, - .signal_direction = true, - .pwrreg_clkgate = true, -- .busy_detect = true, - .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, - .busy_detect_flag = MCI_ST_CARDBUSY, - .busy_detect_mask = MCI_ST_BUSYENDMASK, -@@ -184,7 +185,7 @@ static struct variant_data variant_ux500 = { - .irq_pio_mask = MCI_IRQ_PIO_MASK, - .start_err = MCI_STARTBITERR, - .opendrain = MCI_OD, -- .init = mmci_variant_init, -+ .init = ux500_variant_init, - }; - - static struct variant_data variant_ux500v2 = { -@@ -208,7 +209,6 @@ static struct variant_data variant_ux500v2 = { - .f_max = 100000000, - .signal_direction = true, - .pwrreg_clkgate = true, -- .busy_detect = true, - .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, - .busy_detect_flag = MCI_ST_CARDBUSY, - .busy_detect_mask = MCI_ST_BUSYENDMASK, -@@ -260,7 +260,38 @@ static struct variant_data variant_stm32_sdmmc = { - .datacnt_useless = true, - .datalength_bits = 25, - .datactrl_blocksz = 14, -+ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, -+ .pwrreg_nopower = true, - .stm32_idmabsize_mask = GENMASK(12, 5), -+ .busy_timeout = true, -+ .busy_detect_flag = MCI_STM32_BUSYD0, -+ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, -+ .init = sdmmc_variant_init, -+}; -+ -+static struct variant_data variant_stm32_sdmmcv2 = { -+ .fifosize = 16 * 4, -+ .fifohalfsize = 8 * 4, -+ .f_max = 208000000, -+ .stm32_clkdiv = true, -+ .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, -+ .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, -+ .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, -+ .cmdreg_srsp = MCI_CPSM_STM32_SRSP, -+ .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, -+ .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, -+ .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, -+ .datactrl_first = true, -+ .datacnt_useless = true, -+ .datalength_bits = 25, -+ .datactrl_blocksz = 14, -+ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, -+ .pwrreg_nopower = true, -+ .stm32_idmabsize_mask = GENMASK(16, 5), -+ .dma_lli = true, -+ .busy_timeout = true, -+ .busy_detect_flag = MCI_STM32_BUSYD0, -+ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, - .init = sdmmc_variant_init, - }; - -@@ -357,6 +388,24 @@ static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) - } - } - -+static void mmci_restore(struct mmci_host *host) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&host->lock, flags); -+ -+ if (host->variant->pwrreg_nopower) { -+ writel(host->clk_reg, host->base + MMCICLOCK); -+ writel(host->datactrl_reg, host->base + MMCIDATACTRL); -+ writel(host->pwr_reg, host->base + MMCIPOWER); -+ } -+ writel(MCI_IRQENABLE | host->variant->start_err, -+ host->base + MMCIMASK0); -+ mmci_reg_delay(host); -+ -+ spin_unlock_irqrestore(&host->lock, flags); -+} -+ - /* - * This must be called with host->lock held - */ -@@ -450,7 +499,8 @@ static int mmci_validate_data(struct mmci_host *host, - if (!data) - return 0; - -- if (!is_power_of_2(data->blksz)) { -+ if ((host->mmc->card && !mmc_card_sdio(host->mmc->card)) && -+ !is_power_of_2(data->blksz)) { - dev_err(mmc_dev(host->mmc), - "unsupported block size (%d bytes)\n", data->blksz); - return -EINVAL; -@@ -610,6 +660,67 @@ static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) - return MCI_DPSM_ENABLE | (host->data->blksz << 16); - } - -+static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) -+{ -+ void __iomem *base = host->base; -+ -+ /* -+ * Before unmasking for the busy end IRQ, confirm that the -+ * command was sent successfully. To keep track of having a -+ * command in-progress, waiting for busy signaling to end, -+ * store the status in host->busy_status. -+ * -+ * Note that, the card may need a couple of clock cycles before -+ * it starts signaling busy on DAT0, hence re-read the -+ * MMCISTATUS register here, to allow the busy bit to be set. -+ * Potentially we may even need to poll the register for a -+ * while, to allow it to be set, but tests indicates that it -+ * isn't needed. -+ */ -+ if (!host->busy_status && !(status & err_msk) && -+ (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { -+ writel(readl(base + MMCIMASK0) | -+ host->variant->busy_detect_mask, -+ base + MMCIMASK0); -+ -+ host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND); -+ return false; -+ } -+ -+ /* -+ * If there is a command in-progress that has been successfully -+ * sent, then bail out if busy status is set and wait for the -+ * busy end IRQ. -+ * -+ * Note that, the HW triggers an IRQ on both edges while -+ * monitoring DAT0 for busy completion, but there is only one -+ * status bit in MMCISTATUS for the busy state. Therefore -+ * both the start and the end interrupts needs to be cleared, -+ * one after the other. So, clear the busy start IRQ here. -+ */ -+ if (host->busy_status && -+ (status & host->variant->busy_detect_flag)) { -+ writel(host->variant->busy_detect_mask, base + MMCICLEAR); -+ return false; -+ } -+ -+ /* -+ * If there is a command in-progress that has been successfully -+ * sent and the busy bit isn't set, it means we have received -+ * the busy end IRQ. Clear and mask the IRQ, then continue to -+ * process the command. -+ */ -+ if (host->busy_status) { -+ writel(host->variant->busy_detect_mask, base + MMCICLEAR); -+ -+ writel(readl(base + MMCIMASK0) & -+ ~host->variant->busy_detect_mask, base + MMCIMASK0); -+ host->busy_status = 0; -+ } -+ -+ return true; -+} -+ - /* - * All the DMA operation mode stuff goes inside this ifdef. - * This assumes that you have a generic DMA device interface, -@@ -953,9 +1064,16 @@ void mmci_variant_init(struct mmci_host *host) - host->ops = &mmci_variant_ops; - } - -+void ux500_variant_init(struct mmci_host *host) -+{ -+ host->ops = &mmci_variant_ops; -+ host->ops->busy_complete = ux500_busy_complete; -+} -+ - void ux500v2_variant_init(struct mmci_host *host) - { - host->ops = &mmci_variant_ops; -+ host->ops->busy_complete = ux500_busy_complete; - host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; - } - -@@ -1075,6 +1193,7 @@ static void - mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) - { - void __iomem *base = host->base; -+ unsigned long long clks; - - dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", - cmd->opcode, cmd->arg, cmd->flags); -@@ -1097,6 +1216,19 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) - else - c |= host->variant->cmdreg_srsp; - } -+ -+ if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) { -+ if (!cmd->busy_timeout) -+ cmd->busy_timeout = 1000; -+ -+ clks = (unsigned long long)cmd->busy_timeout * host->cclk; -+ do_div(clks, MSEC_PER_SEC); -+ writel_relaxed(clks, host->base + MMCIDATATIMER); -+ } -+ -+ if (host->ops->prep_volt_switch && cmd->opcode == SD_SWITCH_VOLTAGE) -+ host->ops->prep_volt_switch(host); -+ - if (/*interrupt*/0) - c |= MCI_CPSM_INTERRUPT; - -@@ -1201,6 +1333,7 @@ static void - mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - unsigned int status) - { -+ u32 err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT; - void __iomem *base = host->base; - bool sbc, busy_resp; - -@@ -1215,74 +1348,17 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - * handling. Note that we tag on any latent IRQs postponed - * due to waiting for busy status. - */ -- if (!((status|host->busy_status) & -- (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND))) -+ if (host->variant->busy_timeout && busy_resp) -+ err_msk |= MCI_DATATIMEOUT; -+ -+ if (!((status | host->busy_status) & -+ (err_msk | MCI_CMDSENT | MCI_CMDRESPEND))) - return; - - /* Handle busy detection on DAT0 if the variant supports it. */ -- if (busy_resp && host->variant->busy_detect) { -- -- /* -- * Before unmasking for the busy end IRQ, confirm that the -- * command was sent successfully. To keep track of having a -- * command in-progress, waiting for busy signaling to end, -- * store the status in host->busy_status. -- * -- * Note that, the card may need a couple of clock cycles before -- * it starts signaling busy on DAT0, hence re-read the -- * MMCISTATUS register here, to allow the busy bit to be set. -- * Potentially we may even need to poll the register for a -- * while, to allow it to be set, but tests indicates that it -- * isn't needed. -- */ -- if (!host->busy_status && -- !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && -- (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { -- -- writel(readl(base + MMCIMASK0) | -- host->variant->busy_detect_mask, -- base + MMCIMASK0); -- -- host->busy_status = -- status & (MCI_CMDSENT|MCI_CMDRESPEND); -+ if (busy_resp && host->ops->busy_complete) -+ if (!host->ops->busy_complete(host, status, err_msk)) - return; -- } -- -- /* -- * If there is a command in-progress that has been successfully -- * sent, then bail out if busy status is set and wait for the -- * busy end IRQ. -- * -- * Note that, the HW triggers an IRQ on both edges while -- * monitoring DAT0 for busy completion, but there is only one -- * status bit in MMCISTATUS for the busy state. Therefore -- * both the start and the end interrupts needs to be cleared, -- * one after the other. So, clear the busy start IRQ here. -- */ -- if (host->busy_status && -- (status & host->variant->busy_detect_flag)) { -- writel(host->variant->busy_detect_mask, -- host->base + MMCICLEAR); -- return; -- } -- -- /* -- * If there is a command in-progress that has been successfully -- * sent and the busy bit isn't set, it means we have received -- * the busy end IRQ. Clear and mask the IRQ, then continue to -- * process the command. -- */ -- if (host->busy_status) { -- -- writel(host->variant->busy_detect_mask, -- host->base + MMCICLEAR); -- -- writel(readl(base + MMCIMASK0) & -- ~host->variant->busy_detect_mask, -- base + MMCIMASK0); -- host->busy_status = 0; -- } -- } - - host->cmd = NULL; - -@@ -1290,6 +1366,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - cmd->error = -ETIMEDOUT; - } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { - cmd->error = -EILSEQ; -+ } else if (host->variant->busy_timeout && busy_resp && -+ status & MCI_DATATIMEOUT) { -+ cmd->error = -EDEADLK; - } else { - cmd->resp[0] = readl(base + MMCIRESPONSE0); - cmd->resp[1] = readl(base + MMCIRESPONSE1); -@@ -1301,7 +1380,6 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, - if (host->data) { - /* Terminate the DMA transfer */ - mmci_dma_error(host); -- - mmci_stop_data(host); - if (host->variant->cmdreg_stop && cmd->error) { - mmci_stop_command(host); -@@ -1520,7 +1598,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) - * clear the corresponding IRQ. - */ - status &= readl(host->base + MMCIMASK0); -- if (host->variant->busy_detect) -+ if (host->ops->busy_complete) - writel(status & ~host->variant->busy_detect_mask, - host->base + MMCICLEAR); - else -@@ -1583,6 +1661,20 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) - spin_unlock_irqrestore(&host->lock, flags); - } - -+static void mmci_set_max_busy_timeout(struct mmc_host *mmc) -+{ -+ struct mmci_host *host = mmc_priv(mmc); -+ u32 max_busy_timeout = 0; -+ -+ if (!host->ops->busy_complete) -+ return; -+ -+ if (host->variant->busy_timeout && mmc->actual_clock) -+ max_busy_timeout = ~0UL / (mmc->actual_clock / MSEC_PER_SEC); -+ -+ mmc->max_busy_timeout = max_busy_timeout; -+} -+ - static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - { - struct mmci_host *host = mmc_priv(mmc); -@@ -1687,6 +1779,8 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) - else - mmci_set_clkreg(host, ios->clock); - -+ mmci_set_max_busy_timeout(mmc); -+ - if (host->ops && host->ops->set_pwrreg) - host->ops->set_pwrreg(host, pwr); - else -@@ -1714,6 +1808,7 @@ static int mmci_get_cd(struct mmc_host *mmc) - - static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) - { -+ struct mmci_host *host = mmc_priv(mmc); - int ret = 0; - - if (!IS_ERR(mmc->supply.vqmmc)) { -@@ -1733,6 +1828,9 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) - break; - } - -+ if (!ret && host->ops && host->ops->volt_switch) -+ ret = host->ops->volt_switch(host, ios); -+ - if (ret) - dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); - } -@@ -1740,6 +1838,19 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) - return ret; - } - -+static void mmci_hw_unstuck(struct mmc_host *mmc) -+{ -+ struct mmci_host *host = mmc_priv(mmc); -+ -+ if (host->rst) { -+ reset_control_assert(host->rst); -+ udelay(2); -+ reset_control_deassert(host->rst); -+ } -+ -+ mmci_restore(host); -+} -+ - static struct mmc_host_ops mmci_ops = { - .request = mmci_request, - .pre_req = mmci_pre_request, -@@ -1748,6 +1859,7 @@ static struct mmc_host_ops mmci_ops = { - .get_ro = mmc_gpio_get_ro, - .get_cd = mmci_get_cd, - .start_signal_voltage_switch = mmci_sig_volt_switch, -+ .hw_unstuck = mmci_hw_unstuck, - }; - - static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) -@@ -1817,6 +1929,7 @@ static int mmci_probe(struct amba_device *dev, - - host = mmc_priv(mmc); - host->mmc = mmc; -+ host->mmc_ops = &mmci_ops; - - /* - * Some variant (STM32) doesn't have opendrain bit, nevertheless -@@ -1941,13 +2054,15 @@ static int mmci_probe(struct amba_device *dev, - else if (plat->ocr_mask) - dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); - -+ host->pwr_reg = readl_relaxed(host->base + MMCIPOWER); -+ - /* We support these capabilities. */ - mmc->caps |= MMC_CAP_CMD23; - - /* - * Enable busy detection. - */ -- if (variant->busy_detect) { -+ if (host->ops->busy_complete) { - mmci_ops.card_busy = mmci_card_busy; - /* - * Not all variants have a flag to enable busy detection -@@ -1957,7 +2072,6 @@ static int mmci_probe(struct amba_device *dev, - mmci_write_datactrlreg(host, - host->variant->busy_dpsm_flag); - mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; -- mmc->max_busy_timeout = 0; - } - - /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ -@@ -2115,24 +2229,6 @@ static void mmci_save(struct mmci_host *host) - spin_unlock_irqrestore(&host->lock, flags); - } - --static void mmci_restore(struct mmci_host *host) --{ -- unsigned long flags; -- -- spin_lock_irqsave(&host->lock, flags); -- -- if (host->variant->pwrreg_nopower) { -- writel(host->clk_reg, host->base + MMCICLOCK); -- writel(host->datactrl_reg, host->base + MMCIDATACTRL); -- writel(host->pwr_reg, host->base + MMCIPOWER); -- } -- writel(MCI_IRQENABLE | host->variant->start_err, -- host->base + MMCIMASK0); -- mmci_reg_delay(host); -- -- spin_unlock_irqrestore(&host->lock, flags); --} -- - static int mmci_runtime_suspend(struct device *dev) - { - struct amba_device *adev = to_amba_device(dev); -@@ -2227,6 +2323,11 @@ static const struct amba_id mmci_ids[] = { - .mask = 0xf0ffffff, - .data = &variant_stm32_sdmmc, - }, -+ { -+ .id = 0x00253180, -+ .mask = 0xf0ffffff, -+ .data = &variant_stm32_sdmmcv2, -+ }, - /* Qualcomm variants */ - { - .id = 0x00051180, -diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h -index 833236ecb..ed12592cc 100644 ---- a/drivers/mmc/host/mmci.h -+++ b/drivers/mmc/host/mmci.h -@@ -133,6 +133,8 @@ - #define MCI_DPSM_STM32_MODE_SDIO (1 << 2) - #define MCI_DPSM_STM32_MODE_STREAM (2 << 2) - #define MCI_DPSM_STM32_MODE_BLOCK_STOP (3 << 2) -+#define MCI_DPSM_STM32_SDIOEN BIT(11) -+ - - #define MMCIDATACNT 0x030 - #define MMCISTATUS 0x034 -@@ -164,6 +166,8 @@ - #define MCI_ST_CARDBUSY (1 << 24) - /* Extended status bits for the STM32 variants */ - #define MCI_STM32_BUSYD0 BIT(20) -+#define MCI_STM32_BUSYD0END BIT(21) -+#define MCI_STM32_VSWEND BIT(25) - - #define MMCICLEAR 0x038 - #define MCI_CMDCRCFAILCLR (1 << 0) -@@ -181,6 +185,9 @@ - #define MCI_ST_SDIOITC (1 << 22) - #define MCI_ST_CEATAENDC (1 << 23) - #define MCI_ST_BUSYENDC (1 << 24) -+/* Extended clear bits for the STM32 variants */ -+#define MCI_STM32_VSWENDC (1 << 25) -+#define MCI_STM32_CKSTOPC (1 << 26) - - #define MMCIMASK0 0x03c - #define MCI_CMDCRCFAILMASK (1 << 0) -@@ -286,7 +293,8 @@ struct mmci_host; - * @f_max: maximum clk frequency supported by the controller. - * @signal_direction: input/out direction of bus signals can be indicated - * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock -- * @busy_detect: true if the variant supports busy detection on DAT0. -+ * @busy_timeout: true if the variant starts data timer when the DPSM -+ * enter in Wait_R or Busy state. - * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM - * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register - * indicating that the card is busy -@@ -332,7 +340,7 @@ struct variant_data { - u32 f_max; - u8 signal_direction:1; - u8 pwrreg_clkgate:1; -- u8 busy_detect:1; -+ u8 busy_timeout:1; - u32 busy_dpsm_flag; - u32 busy_detect_flag; - u32 busy_detect_mask; -@@ -366,6 +374,9 @@ struct mmci_host_ops { - void (*dma_error)(struct mmci_host *host); - void (*set_clkreg)(struct mmci_host *host, unsigned int desired); - void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); -+ bool (*busy_complete)(struct mmci_host *host, u32 status, u32 err_msk); -+ void (*prep_volt_switch)(struct mmci_host *host); -+ int (*volt_switch)(struct mmci_host *host, struct mmc_ios *ios); - }; - - struct mmci_host { -@@ -396,8 +407,10 @@ struct mmci_host { - u32 mask1_reg; - u8 vqmmc_enabled:1; - struct mmci_platform_data *plat; -+ struct mmc_host_ops *mmc_ops; - struct mmci_host_ops *ops; - struct variant_data *variant; -+ void *variant_priv; - struct pinctrl *pinctrl; - struct pinctrl_state *pins_default; - struct pinctrl_state *pins_opendrain; -diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c -index 8e83ae692..7c6ba518b 100644 ---- a/drivers/mmc/host/mmci_stm32_sdmmc.c -+++ b/drivers/mmc/host/mmci_stm32_sdmmc.c -@@ -3,10 +3,13 @@ - * Copyright (C) STMicroelectronics 2018 - All Rights Reserved - * Author: Ludovic.barre@st.com for STMicroelectronics. - */ -+#include - #include - #include -+#include - #include - #include -+#include - #include - #include - #include "mmci.h" -@@ -14,17 +17,36 @@ - #define SDMMC_LLI_BUF_LEN PAGE_SIZE - #define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT) - -+#define DLYB_CR 0x0 -+#define DLYB_CR_DEN BIT(0) -+#define DLYB_CR_SEN BIT(1) -+ -+#define DLYB_CFGR 0x4 -+#define DLYB_CFGR_SEL_MASK GENMASK(3, 0) -+#define DLYB_CFGR_UNIT_MASK GENMASK(14, 8) -+#define DLYB_CFGR_LNG_MASK GENMASK(27, 16) -+#define DLYB_CFGR_LNGF BIT(31) -+ -+#define DLYB_CFGR_SEL_MAX 12 -+#define DLYB_CFGR_UNIT_MAX 127 -+ - struct sdmmc_lli_desc { - u32 idmalar; - u32 idmabase; - u32 idmasize; - }; - --struct sdmmc_priv { -+struct sdmmc_idma { - dma_addr_t sg_dma; - void *sg_cpu; - }; - -+struct sdmmc_dlyb { -+ void __iomem *base; -+ u32 unit; -+ u32 max; -+}; -+ - int sdmmc_idma_validate_data(struct mmci_host *host, - struct mmc_data *data) - { -@@ -36,8 +58,8 @@ int sdmmc_idma_validate_data(struct mmci_host *host, - * excepted the last element which has no constraint on idmasize - */ - for_each_sg(data->sg, sg, data->sg_len - 1, i) { -- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) || -- !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) { -+ if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) || -+ !IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) { - dev_err(mmc_dev(host->mmc), - "unaligned scatterlist: ofst:%x length:%d\n", - data->sg->offset, data->sg->length); -@@ -45,7 +67,7 @@ int sdmmc_idma_validate_data(struct mmci_host *host, - } - } - -- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) { -+ if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) { - dev_err(mmc_dev(host->mmc), - "unaligned last scatterlist: ofst:%x length:%d\n", - data->sg->offset, data->sg->length); -@@ -92,21 +114,21 @@ static void sdmmc_idma_unprep_data(struct mmci_host *host, - - static int sdmmc_idma_setup(struct mmci_host *host) - { -- struct sdmmc_priv *idma; -+ struct sdmmc_idma *idma; -+ struct device *dev = mmc_dev(host->mmc); - -- idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); -- if (!idma) -+ idma = devm_kzalloc(dev, sizeof(*idma), GFP_KERNEL); -+ dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); -+ if (!idma || !dev->dma_parms) - return -ENOMEM; - - host->dma_priv = idma; - - if (host->variant->dma_lli) { -- idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc), -- SDMMC_LLI_BUF_LEN, -+ idma->sg_cpu = dmam_alloc_coherent(dev, SDMMC_LLI_BUF_LEN, - &idma->sg_dma, GFP_KERNEL); - if (!idma->sg_cpu) { -- dev_err(mmc_dev(host->mmc), -- "Failed to alloc IDMA descriptor\n"); -+ dev_err(dev, "Failed to alloc IDMA descriptor\n"); - return -ENOMEM; - } - host->mmc->max_segs = SDMMC_LLI_BUF_LEN / -@@ -117,13 +139,15 @@ static int sdmmc_idma_setup(struct mmci_host *host) - host->mmc->max_seg_size = host->mmc->max_req_size; - } - -+ dma_set_max_seg_size(dev, host->mmc->max_seg_size); -+ - return 0; - } - - static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) - - { -- struct sdmmc_priv *idma = host->dma_priv; -+ struct sdmmc_idma *idma = host->dma_priv; - struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu; - struct mmc_data *data = host->data; - struct scatterlist *sg; -@@ -162,6 +186,9 @@ static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) - static void sdmmc_idma_finalize(struct mmci_host *host, struct mmc_data *data) - { - writel_relaxed(0, host->base + MMCI_STM32_IDMACTRLR); -+ -+ if (!data->host_cookie) -+ sdmmc_idma_unprep_data(host, data, 0); - } - - static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) -@@ -226,12 +253,25 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) - mmci_write_clkreg(host, clk); - } - -+static void sdmmc_dlyb_input_ck(struct sdmmc_dlyb *dlyb) -+{ -+ if (!dlyb || !dlyb->base) -+ return; -+ -+ /* Output clock = Input clock */ -+ writel_relaxed(0, dlyb->base + DLYB_CR); -+} -+ - static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) - { - struct mmc_ios ios = host->mmc->ios; -+ struct sdmmc_dlyb *dlyb = host->variant_priv; - -+ /* adds OF options */ - pwr = host->pwr_reg_add; - -+ sdmmc_dlyb_input_ck(dlyb); -+ - if (ios.power_mode == MMC_POWER_OFF) { - /* Only a reset could power-off sdmmc */ - reset_control_assert(host->rst); -@@ -254,6 +294,10 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) - writel(MCI_IRQENABLE | host->variant->start_err, - host->base + MMCIMASK0); - -+ /* preserves voltage switch bits */ -+ pwr |= host->pwr_reg & (MCI_STM32_VSWITCHEN | -+ MCI_STM32_VSWITCH); -+ - /* - * After a power-cycle state, we must set the SDMMC in - * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are -@@ -282,6 +326,178 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) - return datactrl; - } - -+bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) -+{ -+ void __iomem *base = host->base; -+ u32 busy_d0, busy_d0end, mask; -+ -+ mask = readl_relaxed(base + MMCIMASK0); -+ busy_d0end = readl_relaxed(base + MMCISTATUS) & MCI_STM32_BUSYD0END; -+ busy_d0 = readl_relaxed(base + MMCISTATUS) & MCI_STM32_BUSYD0; -+ -+ /* complete if there is an error or busy_d0end */ -+ if ((status & err_msk) || busy_d0end) -+ goto complete; -+ -+ /* -+ * On response the busy signaling is reflected in the BUSYD0 flag. -+ * if busy_d0 is in-progress we must activate busyd0end interrupt -+ * to wait this completion. Else this request has no busy step. -+ */ -+ if (busy_d0) { -+ if (!host->busy_status) { -+ writel_relaxed(mask | host->variant->busy_detect_mask, -+ base + MMCIMASK0); -+ host->busy_status = status & -+ (MCI_CMDSENT | MCI_CMDRESPEND); -+ } -+ return false; -+ } -+ -+complete: -+ writel_relaxed(mask & ~host->variant->busy_detect_mask, -+ base + MMCIMASK0); -+ writel_relaxed(host->variant->busy_detect_mask, base + MMCICLEAR); -+ host->busy_status = 0; -+ -+ return true; -+} -+ -+static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb, -+ int unit, int phase, bool sampler) -+{ -+ u32 cfgr; -+ -+ writel_relaxed(DLYB_CR_SEN | DLYB_CR_DEN, dlyb->base + DLYB_CR); -+ -+ cfgr = FIELD_PREP(DLYB_CFGR_UNIT_MASK, unit) | -+ FIELD_PREP(DLYB_CFGR_SEL_MASK, phase); -+ writel_relaxed(cfgr, dlyb->base + DLYB_CFGR); -+ -+ if (!sampler) -+ writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR); -+} -+ -+static int sdmmc_dlyb_lng_tuning(struct mmci_host *host) -+{ -+ struct sdmmc_dlyb *dlyb = host->variant_priv; -+ u32 cfgr; -+ int i, lng, ret; -+ -+ for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) { -+ sdmmc_dlyb_set_cfgr(dlyb, i, DLYB_CFGR_SEL_MAX, true); -+ -+ ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr, -+ (cfgr & DLYB_CFGR_LNGF), -+ 1, 1000); -+ if (ret) { -+ dev_warn(mmc_dev(host->mmc), -+ "delay line cfg timeout unit:%d cfgr:%d\n", -+ i, cfgr); -+ continue; -+ } -+ -+ lng = FIELD_GET(DLYB_CFGR_LNG_MASK, cfgr); -+ if (lng < (BIT(11) | BIT(10)) && (lng & ~BIT(11)) > 0) -+ break; -+ } -+ -+ if (i > DLYB_CFGR_UNIT_MAX) -+ return -EINVAL; -+ -+ dlyb->unit = i; -+ dlyb->max = __fls(lng & ~BIT(11)); -+ -+ return 0; -+} -+ -+static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) -+{ -+ struct sdmmc_dlyb *dlyb = host->variant_priv; -+ int cur_len = 0, max_len = 0, end_of_len = 0; -+ int phase; -+ -+ for (phase = 0; phase <= dlyb->max; phase++) { -+ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); -+ -+ if (mmc_send_tuning(host->mmc, opcode, NULL)) { -+ cur_len = 0; -+ } else { -+ cur_len++; -+ if (cur_len > max_len) { -+ max_len = cur_len; -+ end_of_len = phase; -+ } -+ } -+ } -+ -+ if (!max_len) { -+ dev_err(mmc_dev(host->mmc), "no tuning point found\n"); -+ return -EINVAL; -+ } -+ -+ writel_relaxed(0, dlyb->base + DLYB_CR); -+ -+ phase = end_of_len - max_len / 2; -+ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); -+ -+ dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n", -+ dlyb->unit, dlyb->max, phase); -+ -+ return 0; -+} -+ -+static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) -+{ -+ struct mmci_host *host = mmc_priv(mmc); -+ struct sdmmc_dlyb *dlyb = host->variant_priv; -+ -+ if (!dlyb || !dlyb->base) -+ return -EINVAL; -+ -+ if (sdmmc_dlyb_lng_tuning(host)) -+ return -EINVAL; -+ -+ return sdmmc_dlyb_phase_tuning(host, opcode); -+} -+ -+static void sdmmc_prep_vswitch(struct mmci_host *host) -+{ -+ /* clear the voltage switch completion flag */ -+ writel_relaxed(MCI_STM32_VSWENDC, host->base + MMCICLEAR); -+ /* enable Voltage switch procedure */ -+ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN); -+} -+ -+static int sdmmc_vswitch(struct mmci_host *host, struct mmc_ios *ios) -+{ -+ unsigned long flags; -+ u32 status; -+ int ret = 0; -+ -+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { -+ spin_lock_irqsave(&host->lock, flags); -+ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH); -+ spin_unlock_irqrestore(&host->lock, flags); -+ -+ /* wait voltage switch completion while 10ms */ -+ ret = readl_relaxed_poll_timeout(host->base + MMCISTATUS, -+ status, -+ (status & MCI_STM32_VSWEND), -+ 10, 10000); -+ -+ writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC, -+ host->base + MMCICLEAR); -+ -+ spin_lock_irqsave(&host->lock, flags); -+ mmci_write_pwrreg(host, host->pwr_reg & -+ ~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH)); -+ spin_unlock_irqrestore(&host->lock, flags); -+ } -+ -+ return ret; -+} -+ - static struct mmci_host_ops sdmmc_variant_ops = { - .validate_data = sdmmc_idma_validate_data, - .prep_data = sdmmc_idma_prep_data, -@@ -292,9 +508,28 @@ static struct mmci_host_ops sdmmc_variant_ops = { - .dma_finalize = sdmmc_idma_finalize, - .set_clkreg = mmci_sdmmc_set_clkreg, - .set_pwrreg = mmci_sdmmc_set_pwrreg, -+ .busy_complete = sdmmc_busy_complete, -+ .prep_volt_switch = sdmmc_prep_vswitch, -+ .volt_switch = sdmmc_vswitch, - }; - - void sdmmc_variant_init(struct mmci_host *host) - { -+ struct device_node *np = host->mmc->parent->of_node; -+ void __iomem *base_dlyb; -+ struct sdmmc_dlyb *dlyb; -+ - host->ops = &sdmmc_variant_ops; -+ -+ base_dlyb = devm_of_iomap(mmc_dev(host->mmc), np, 1, NULL); -+ if (IS_ERR(base_dlyb)) -+ return; -+ -+ dlyb = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dlyb), GFP_KERNEL); -+ if (!dlyb) -+ return; -+ -+ dlyb->base = base_dlyb; -+ host->variant_priv = dlyb; -+ host->mmc_ops->execute_tuning = sdmmc_execute_tuning; - } -diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c -index f64e3b660..47c63968f 100644 ---- a/drivers/mtd/nand/raw/nand_base.c -+++ b/drivers/mtd/nand/raw/nand_base.c -@@ -5907,6 +5907,8 @@ void nand_cleanup(struct nand_chip *chip) - chip->ecc.algo == NAND_ECC_BCH) - nand_bch_free((struct nand_bch_control *)chip->ecc.priv); - -+ nanddev_cleanup(&chip->base); -+ - /* Free bad block table memory */ - kfree(chip->bbt); - kfree(chip->data_buf); -diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c -index 5c06e0b4d..982b1935d 100644 ---- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c -+++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c -@@ -1606,17 +1606,36 @@ static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr, - /* DMA configuration */ - static int stm32_fmc2_dma_setup(struct stm32_fmc2_nfc *fmc2) - { -- int ret; -+ struct dma_chan *rx, *tx, *ecc; -+ int ret = 0; - -- fmc2->dma_tx_ch = dma_request_slave_channel(fmc2->dev, "tx"); -- fmc2->dma_rx_ch = dma_request_slave_channel(fmc2->dev, "rx"); -- fmc2->dma_ecc_ch = dma_request_slave_channel(fmc2->dev, "ecc"); -+ tx = dma_request_chan(fmc2->dev, "tx"); -+ rx = dma_request_chan(fmc2->dev, "rx"); -+ ecc = dma_request_chan(fmc2->dev, "ecc"); - -- if (!fmc2->dma_tx_ch || !fmc2->dma_rx_ch || !fmc2->dma_ecc_ch) { -- dev_warn(fmc2->dev, "DMAs not defined in the device tree, polling mode is used\n"); -- return 0; -+ /* DMAs are not mandatory but at least wait for them to be probeb */ -+ if (PTR_ERR(tx) == -EPROBE_DEFER || PTR_ERR(rx) == -EPROBE_DEFER || -+ PTR_ERR(ecc) == -EPROBE_DEFER) -+ ret = -EPROBE_DEFER; -+ -+ if (IS_ERR(tx) || IS_ERR(rx) || IS_ERR(ecc)) { -+ if (!IS_ERR(tx)) -+ dma_release_channel(tx); -+ if (!IS_ERR(rx)) -+ dma_release_channel(rx); -+ if (!IS_ERR(ecc)) -+ dma_release_channel(ecc); -+ -+ if (ret != -EPROBE_DEFER) -+ dev_warn(fmc2->dev, "DMAs missing, use polling mode\n"); -+ -+ return ret; - } - -+ fmc2->dma_tx_ch = tx; -+ fmc2->dma_rx_ch = rx; -+ fmc2->dma_ecc_ch = ecc; -+ - ret = sg_alloc_table(&fmc2->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL); - if (ret) - return ret; -@@ -1940,7 +1959,11 @@ static int stm32_fmc2_probe(struct platform_device *pdev) - } - - rstc = devm_reset_control_get(dev, NULL); -- if (!IS_ERR(rstc)) { -+ if (IS_ERR(rstc)) { -+ ret = PTR_ERR(rstc); -+ if (ret == -EPROBE_DEFER) -+ goto err_clk_disable; -+ } else { - reset_control_assert(rstc); - reset_control_deassert(rstc); - } -@@ -1948,7 +1971,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) - /* DMA setup */ - ret = stm32_fmc2_dma_setup(fmc2); - if (ret) -- return ret; -+ goto err_dma_setup; - - /* FMC2 init routine */ - stm32_fmc2_init(fmc2); -@@ -1970,7 +1993,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) - /* Scan to find existence of the device */ - ret = nand_scan(chip, nand->ncs); - if (ret) -- goto err_scan; -+ goto err_dma_setup; - - ret = mtd_device_register(mtd, NULL, 0); - if (ret) -@@ -1983,7 +2006,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) - err_device_register: - nand_cleanup(chip); - --err_scan: -+err_dma_setup: - if (fmc2->dma_ecc_ch) - dma_release_channel(fmc2->dma_ecc_ch); - if (fmc2->dma_tx_ch) -@@ -1994,6 +2017,7 @@ static int stm32_fmc2_probe(struct platform_device *pdev) - sg_free_table(&fmc2->dma_data_sg); - sg_free_table(&fmc2->dma_ecc_sg); - -+err_clk_disable: - clk_disable_unprepare(fmc2->clk); - - return ret; -diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h -index b7ba8810a..eb10b8194 100644 ---- a/include/linux/mmc/core.h -+++ b/include/linux/mmc/core.h -@@ -173,6 +173,7 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq); - int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, - int retries); - -+void mmc_hw_unstuck(struct mmc_host *host); - int mmc_hw_reset(struct mmc_host *host); - int mmc_sw_reset(struct mmc_host *host); - void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card); -diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h -index 4c5eb3aa8..feac3431b 100644 ---- a/include/linux/mmc/host.h -+++ b/include/linux/mmc/host.h -@@ -163,6 +163,12 @@ struct mmc_host_ops { - void (*hw_reset)(struct mmc_host *host); - void (*card_event)(struct mmc_host *host); - -+ /* -+ * Optional callback, if your host is in deadlock after a command and -+ * must done specific action before sent new command. -+ */ -+ void (*hw_unstuck)(struct mmc_host *host); -+ - /* - * Optional callback to support controllers with HW issues for multiple - * I/O. Returns the number of supported blocks for the request. --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch deleted file mode 100644 index a12e2fd..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0019-ARM-stm32mp1-r1-MISC.patch +++ /dev/null @@ -1,213 +0,0 @@ -From 21d34047c11667042371bf23d89f168be4eb607d Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:48:07 +0200 -Subject: [PATCH 19/23] ARM-stm32mp1-r1-MISC - ---- - CONTRIBUTING.md | 30 ++++++++++++++++++++++++ - drivers/block/loop.c | 49 ++++++++++++++++++++++++++++----------- - include/linux/pm_wakeup.h | 10 ++++++++ - tools/perf/util/srcline.c | 16 ++++++++++++- - 4 files changed, 91 insertions(+), 14 deletions(-) - create mode 100644 CONTRIBUTING.md - -diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md -new file mode 100644 -index 000000000..3d1bacd78 ---- /dev/null -+++ b/CONTRIBUTING.md -@@ -0,0 +1,30 @@ -+# Contributing guide -+ -+This document serves as a checklist before contributing to this repository. It includes links to read up on if topics are unclear to you. -+ -+This guide mainly focuses on the proper use of Git. -+ -+## 1. Issues -+ -+STM32MPU projects do not activate "Github issues" feature for the time being. If you need to report an issue or question about this project deliverables, you can report them using [ ST Support Center ](https://my.st.com/ols#/ols/newrequest) or [ ST Community MPU Forum ](https://community.st.com/s/topic/0TO0X0000003u2AWAQ/stm32-mpus). -+ -+## 2. Pull Requests -+ -+STMicrolectronics is happy to receive contributions from the community, based on an initial Contributor License Agreement (CLA) procedure. -+ -+* If you are an individual writing original source code and you are sure **you own the intellectual property**, then you need to sign an Individual CLA (https://cla.st.com). -+* If you work for a company that wants also to allow you to contribute with your work, your company needs to provide a Corporate CLA (https://cla.st.com) mentioning your GitHub account name. -+* If you are not sure that a CLA (Individual or Corporate) has been signed for your GitHub account you can check here (https://cla.st.com). -+ -+Please note that: -+* The Corporate CLA will always take precedence over the Individual CLA. -+* One CLA submission is sufficient, for any project proposed by STMicroelectronics. -+ -+__How to proceed__ -+ -+* We recommend to fork the project in your GitHub account to further develop your contribution. Please use the latest commit version. -+* Please, submit one Pull Request for one new feature or proposal. This will ease the analysis and final merge if accepted. -+ -+__Note__ -+ -+Merge will not be done directly in GitHub but it will need first to follow internal integration process before public deliver in a standard release. The Pull request will stay open until it is merged and delivered. -diff --git a/drivers/block/loop.c b/drivers/block/loop.c -index ef6e25185..6831ab725 100644 ---- a/drivers/block/loop.c -+++ b/drivers/block/loop.c -@@ -427,11 +427,12 @@ static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos, - * information. - */ - struct file *file = lo->lo_backing_file; -+ struct request_queue *q = lo->lo_queue; - int ret; - - mode |= FALLOC_FL_KEEP_SIZE; - -- if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) { -+ if (!blk_queue_discard(q)) { - ret = -EOPNOTSUPP; - goto out; - } -@@ -461,7 +462,7 @@ static void lo_complete_rq(struct request *rq) - if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) || - req_op(rq) != REQ_OP_READ) { - if (cmd->ret < 0) -- ret = BLK_STS_IOERR; -+ ret = errno_to_blk_status(cmd->ret); - goto end_io; - } - -@@ -863,28 +864,47 @@ static void loop_config_discard(struct loop_device *lo) - struct inode *inode = file->f_mapping->host; - struct request_queue *q = lo->lo_queue; - -+ /* -+ * If the backing device is a block device, mirror its zeroing -+ * capability. Set the discard sectors to the block device's zeroing -+ * capabilities because loop discards result in blkdev_issue_zeroout(), -+ * not blkdev_issue_discard(). This maintains consistent behavior with -+ * file-backed loop devices: discarded regions read back as zero. -+ */ -+ if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) { -+ struct request_queue *backingq; -+ -+ backingq = bdev_get_queue(inode->i_bdev); -+ blk_queue_max_discard_sectors(q, -+ backingq->limits.max_write_zeroes_sectors); -+ -+ blk_queue_max_write_zeroes_sectors(q, -+ backingq->limits.max_write_zeroes_sectors); -+ - /* - * We use punch hole to reclaim the free space used by the - * image a.k.a. discard. However we do not support discard if - * encryption is enabled, because it may give an attacker - * useful information. - */ -- if ((!file->f_op->fallocate) || -- lo->lo_encrypt_key_size) { -+ } else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) { - q->limits.discard_granularity = 0; - q->limits.discard_alignment = 0; - blk_queue_max_discard_sectors(q, 0); - blk_queue_max_write_zeroes_sectors(q, 0); -- blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); -- return; -- } - -- q->limits.discard_granularity = inode->i_sb->s_blocksize; -- q->limits.discard_alignment = 0; -+ } else { -+ q->limits.discard_granularity = inode->i_sb->s_blocksize; -+ q->limits.discard_alignment = 0; -+ -+ blk_queue_max_discard_sectors(q, UINT_MAX >> 9); -+ blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9); -+ } - -- blk_queue_max_discard_sectors(q, UINT_MAX >> 9); -- blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9); -- blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); -+ if (q->limits.max_write_zeroes_sectors) -+ blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); -+ else -+ blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); - } - - static void loop_unprepare_queue(struct loop_device *lo) -@@ -1950,7 +1970,10 @@ static void loop_handle_cmd(struct loop_cmd *cmd) - failed: - /* complete non-aio request */ - if (!cmd->use_aio || ret) { -- cmd->ret = ret ? -EIO : 0; -+ if (ret == -EOPNOTSUPP) -+ cmd->ret = ret; -+ else -+ cmd->ret = ret ? -EIO : 0; - blk_mq_complete_request(rq); - } - } -diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h -index 661efa029..faee74f36 100644 ---- a/include/linux/pm_wakeup.h -+++ b/include/linux/pm_wakeup.h -@@ -79,6 +79,11 @@ static inline bool device_may_wakeup(struct device *dev) - return dev->power.can_wakeup && !!dev->power.wakeup; - } - -+static inline bool device_wakeup_path(struct device *dev) -+{ -+ return !!dev->power.wakeup_path; -+} -+ - static inline void device_set_wakeup_path(struct device *dev) - { - dev->power.wakeup_path = true; -@@ -165,6 +170,11 @@ static inline bool device_may_wakeup(struct device *dev) - return dev->power.can_wakeup && dev->power.should_wakeup; - } - -+static inline bool device_wakeup_path(struct device *dev) -+{ -+ return false; -+} -+ - static inline void device_set_wakeup_path(struct device *dev) {} - - static inline void __pm_stay_awake(struct wakeup_source *ws) {} -diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c -index 6ccf6f6d0..5b7d6c16d 100644 ---- a/tools/perf/util/srcline.c -+++ b/tools/perf/util/srcline.c -@@ -193,16 +193,30 @@ static void find_address_in_section(bfd *abfd, asection *section, void *data) - bfd_vma pc, vma; - bfd_size_type size; - struct a2l_data *a2l = data; -+ flagword flags; - - if (a2l->found) - return; - -- if ((bfd_get_section_flags(abfd, section) & SEC_ALLOC) == 0) -+#ifdef bfd_get_section_flags -+ flags = bfd_get_section_flags(abfd, section); -+#else -+ flags = bfd_section_flags(section); -+#endif -+ if ((flags & SEC_ALLOC) == 0) - return; - - pc = a2l->addr; -+#ifdef bfd_get_section_vma - vma = bfd_get_section_vma(abfd, section); -+#else -+ vma = bfd_section_vma(section); -+#endif -+#ifdef bfd_get_section_size - size = bfd_get_section_size(section); -+#else -+ size = bfd_section_size(section); -+#endif - - if (pc < vma || pc >= vma + size) - return; --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch deleted file mode 100644 index d9e6f94..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0022-ARM-stm32mp1-r1-POWER.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 65ad7ed110b25b333679e5084fb82db0d5a15a6c Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:50:46 +0200 -Subject: [PATCH 22/23] ARM-stm32mp1-r1-POWER - ---- - kernel/power/suspend.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c -index 27f149f5d..4581702e8 100644 ---- a/kernel/power/suspend.c -+++ b/kernel/power/suspend.c -@@ -34,7 +34,6 @@ - #include "power.h" - - const char * const pm_labels[] = { -- [PM_SUSPEND_TO_IDLE] = "freeze", - [PM_SUSPEND_STANDBY] = "standby", - [PM_SUSPEND_MEM] = "mem", - }; --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0001-ARM-stm32mp1-r2-MACHINE.patch similarity index 80% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0001-ARM-stm32mp1-r2-MACHINE.patch index 8b8171f..ac148b7 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0001-ARM-stm32mp1-r1-MACHINE.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0001-ARM-stm32mp1-r2-MACHINE.patch @@ -1,7 +1,7 @@ -From fda596ab13299af0f9cebfa8f9bde2827b02a2b3 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:36:29 +0200 -Subject: [PATCH 01/23] ARM-stm32mp1-r1-MACHINE +From 4556074b66971918536ed27d52f5f4f6337f0646 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:40 +0200 +Subject: [PATCH 01/22] ARM-stm32mp1-r2-rc8-MACHINE --- arch/arm/kernel/time.c | 2 ++ @@ -10,7 +10,7 @@ Subject: [PATCH 01/23] ARM-stm32mp1-r1-MACHINE 3 files changed, 5 insertions(+) diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c -index b996b2cf0..dddc7ebf4 100644 +index b996b2cf07038..dddc7ebf4db44 100644 --- a/arch/arm/kernel/time.c +++ b/arch/arm/kernel/time.c @@ -9,6 +9,7 @@ @@ -29,7 +29,7 @@ index b996b2cf0..dddc7ebf4 100644 } } diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig -index 57699bd8f..8f9fd1da9 100644 +index 57699bd8f1075..8f9fd1da9ea05 100644 --- a/arch/arm/mach-stm32/Kconfig +++ b/arch/arm/mach-stm32/Kconfig @@ -46,6 +46,7 @@ if ARCH_MULTI_V7 @@ -41,7 +41,7 @@ index 57699bd8f..8f9fd1da9 100644 endif # ARMv7-A diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c -index 011d57b48..8e06a9442 100644 +index 011d57b488c2e..8e06a94421d9b 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -17,6 +17,8 @@ static const char *const stm32_compat[] __initconst = { diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0002-ARM-stm32mp1-r2-CPUFREQ.patch similarity index 88% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0002-ARM-stm32mp1-r2-CPUFREQ.patch index 440b21e..4a15358 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0002-ARM-stm32mp1-r1-CPUFREQ.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0002-ARM-stm32mp1-r2-CPUFREQ.patch @@ -1,19 +1,19 @@ -From 14bcead6b5ca532f85cffadab2753cc044002f86 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:37:04 +0200 -Subject: [PATCH 02/23] ARM-stm32mp1-r1-CPUFREQ +From 458e623d9cf01cde1dc2404da5377064b3136389 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:41 +0200 +Subject: [PATCH 02/22] ARM-stm32mp1-r2-rc8-CPUFREQ --- drivers/cpufreq/Kconfig.arm | 7 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/cpufreq-dt-platdev.c | 1 + drivers/cpufreq/stm32-cpufreq.c | 101 +++++++++++++++++++++++++++ - drivers/opp/core.c | 11 ++- - 5 files changed, 120 insertions(+), 1 deletion(-) + drivers/opp/core.c | 12 +++- + 5 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 drivers/cpufreq/stm32-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm -index a905796f7..b2beb1708 100644 +index a905796f7f856..b2beb170840be 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -295,6 +295,13 @@ config ARM_STI_CPUFREQ @@ -31,7 +31,7 @@ index a905796f7..b2beb1708 100644 bool depends on CPUFREQ_DT && ARCH_TANGO diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index 9a9f5ccd1..6139d2aeb 100644 +index 9a9f5ccd13d98..6139d2aebea40 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o @@ -43,7 +43,7 @@ index 9a9f5ccd1..6139d2aeb 100644 obj-$(CONFIG_ARM_TANGO_CPUFREQ) += tango-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c -index bca8d1f47..7ac5715e4 100644 +index bca8d1f47fd2c..7ac5715e43597 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -131,6 +131,7 @@ static const struct of_device_id blacklist[] __initconst = { @@ -56,7 +56,7 @@ index bca8d1f47..7ac5715e4 100644 diff --git a/drivers/cpufreq/stm32-cpufreq.c b/drivers/cpufreq/stm32-cpufreq.c new file mode 100644 -index 000000000..35fb3520d +index 0000000000000..35fb3520d48df --- /dev/null +++ b/drivers/cpufreq/stm32-cpufreq.c @@ -0,0 +1,101 @@ @@ -162,10 +162,10 @@ index 000000000..35fb3520d +MODULE_AUTHOR("Alexandre Torgue "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/opp/core.c b/drivers/opp/core.c -index 9ff0538ee..1974bf21f 100644 +index 9ff0538ee83a0..ec692884c170f 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c -@@ -980,9 +980,14 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index) +@@ -980,9 +980,15 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index) opp_table->clk = clk_get(dev, NULL); if (IS_ERR(opp_table->clk)) { ret = PTR_ERR(opp_table->clk); @@ -175,13 +175,14 @@ index 9ff0538ee..1974bf21f 100644 ret); + } + else { ++ _remove_opp_dev(opp_dev, opp_table); + kfree(opp_table); + return ERR_PTR(-EPROBE_DEFER); + } } BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head); -@@ -1443,6 +1448,10 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, +@@ -1443,6 +1449,10 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, struct opp_table *opp_table; opp_table = dev_pm_opp_get_opp_table(dev); diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0003-ARM-stm32mp1-r2-CRYPTO.patch similarity index 80% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0003-ARM-stm32mp1-r2-CRYPTO.patch index 1ff660e..cc7fdf0 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0003-ARM-stm32mp1-r1-CRYPTO.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0003-ARM-stm32mp1-r2-CRYPTO.patch @@ -1,28 +1,41 @@ -From ad399098098fb0ed48ccab85bbc70e15de7777c0 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:38:03 +0200 -Subject: [PATCH 03/23] ARM-stm32mp1-r1-CRYPTO +From 0f32661351778c6c282c9509defdcec61abf7fab Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:41 +0200 +Subject: [PATCH 03/22] ARM-stm32mp1-r2-rc8-CRYPTO --- - drivers/crypto/stm32/stm32-crc32.c | 228 +++++++++++++++------- + drivers/crypto/stm32/Kconfig | 2 + + drivers/crypto/stm32/stm32-crc32.c | 99 +++++++++- drivers/crypto/stm32/stm32-cryp.c | 300 +++++++++++++++++++++-------- drivers/crypto/stm32/stm32-hash.c | 57 ++++-- - 3 files changed, 417 insertions(+), 168 deletions(-) + 4 files changed, 348 insertions(+), 110 deletions(-) +diff --git a/drivers/crypto/stm32/Kconfig b/drivers/crypto/stm32/Kconfig +index 1aba9372cd232..425c68d42a5fe 100644 +--- a/drivers/crypto/stm32/Kconfig ++++ b/drivers/crypto/stm32/Kconfig +@@ -3,6 +3,8 @@ config CRYPTO_DEV_STM32_CRC + tristate "Support for STM32 crc accelerators" + depends on ARCH_STM32 + select CRYPTO_HASH ++ select CRYPTO_CRC32 ++ select CRYPTO_CRC32C + help + This enables support for the CRC32 hw accelerator which can be found + on STMicroelectronics STM32 SOC. diff --git a/drivers/crypto/stm32/stm32-crc32.c b/drivers/crypto/stm32/stm32-crc32.c -index 9e11c3480..892d5b6eb 100644 +index e68b856d03b6e..22b301c684f09 100644 --- a/drivers/crypto/stm32/stm32-crc32.c +++ b/drivers/crypto/stm32/stm32-crc32.c -@@ -28,18 +28,23 @@ +@@ -6,6 +6,7 @@ - /* Registers values */ - #define CRC_CR_RESET BIT(0) --#define CRC_CR_REVERSE (BIT(7) | BIT(6) | BIT(5)) --#define CRC_INIT_DEFAULT 0xFFFFFFFF -+#define CRC_CR_REV_IN_WORD (BIT(6) | BIT(5)) -+#define CRC_CR_REV_IN_BYTE BIT(5) -+#define CRC_CR_REV_OUT BIT(7) -+#define CRC32C_INIT_DEFAULT 0xFFFFFFFF + #include + #include ++#include + #include + #include + #include +@@ -35,11 +36,16 @@ #define CRC_AUTOSUSPEND_DELAY 50 @@ -35,96 +48,35 @@ index 9e11c3480..892d5b6eb 100644 struct device *dev; void __iomem *regs; struct clk *clk; -- u8 pending_data[sizeof(u32)]; -- size_t nb_pending_bytes; + spinlock_t lock; }; struct stm32_crc_list { -@@ -59,14 +64,13 @@ struct stm32_crc_ctx { - - struct stm32_crc_desc_ctx { - u32 partial; /* crc32c: partial in first 4 bytes of that struct */ -- struct stm32_crc *crc; - }; - - static int stm32_crc32_cra_init(struct crypto_tfm *tfm) - { - struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); - -- mctx->key = CRC_INIT_DEFAULT; -+ mctx->key = 0; - mctx->poly = CRC32_POLY_LE; - return 0; - } -@@ -75,7 +79,7 @@ static int stm32_crc32c_cra_init(struct crypto_tfm *tfm) - { - struct stm32_crc_ctx *mctx = crypto_tfm_ctx(tfm); - -- mctx->key = CRC_INIT_DEFAULT; -+ mctx->key = CRC32C_INIT_DEFAULT; - mctx->poly = CRC32C_POLY_LE; - return 0; - } -@@ -94,87 +98,135 @@ static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key, - return 0; - } - -+static struct stm32_crc *stm32_crc_get_next_crc(void) -+{ -+ struct stm32_crc *crc; -+ -+ spin_lock_bh(&crc_list.lock); -+ crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); -+ if (crc) -+ list_move_tail(&crc->list, &crc_list.dev_list); -+ spin_unlock_bh(&crc_list.lock); -+ -+ return crc; -+} -+ - static int stm32_crc_init(struct shash_desc *desc) - { +@@ -111,6 +117,7 @@ static int stm32_crc_init(struct shash_desc *desc) struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); struct stm32_crc *crc; + unsigned long flags; -- spin_lock_bh(&crc_list.lock); -- list_for_each_entry(crc, &crc_list.dev_list, list) { -- ctx->crc = crc; -- break; -- } -- spin_unlock_bh(&crc_list.lock); -+ crc = stm32_crc_get_next_crc(); -+ if (!crc) -+ return -ENODEV; -+ -+ pm_runtime_get_sync(crc->dev); + crc = stm32_crc_get_next_crc(); + if (!crc) +@@ -118,6 +125,8 @@ static int stm32_crc_init(struct shash_desc *desc) + + pm_runtime_get_sync(crc->dev); -- pm_runtime_get_sync(ctx->crc->dev); + spin_lock_irqsave(&crc->lock, flags); - ++ /* Reset, set key, poly and configure in bit reverse mode */ -- writel_relaxed(bitrev32(mctx->key), ctx->crc->regs + CRC_INIT); -- writel_relaxed(bitrev32(mctx->poly), ctx->crc->regs + CRC_POL); -- writel_relaxed(CRC_CR_RESET | CRC_CR_REVERSE, ctx->crc->regs + CRC_CR); -+ writel_relaxed(bitrev32(mctx->key), crc->regs + CRC_INIT); -+ writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); -+ writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, -+ crc->regs + CRC_CR); - + writel_relaxed(bitrev32(mctx->key), crc->regs + CRC_INIT); + writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); +@@ -127,14 +136,16 @@ static int stm32_crc_init(struct shash_desc *desc) /* Store partial result */ -- ctx->partial = readl_relaxed(ctx->crc->regs + CRC_DR); -- ctx->crc->nb_pending_bytes = 0; -+ ctx->partial = readl_relaxed(crc->regs + CRC_DR); + ctx->partial = readl_relaxed(crc->regs + CRC_DR); -- pm_runtime_mark_last_busy(ctx->crc->dev); -- pm_runtime_put_autosuspend(ctx->crc->dev); + spin_unlock_irqrestore(&crc->lock, flags); + -+ pm_runtime_mark_last_busy(crc->dev); -+ pm_runtime_put_autosuspend(crc->dev); + pm_runtime_mark_last_busy(crc->dev); + pm_runtime_put_autosuspend(crc->dev); return 0; } @@ -135,91 +87,37 @@ index 9e11c3480..892d5b6eb 100644 + size_t length) { struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); -- struct stm32_crc *crc = ctx->crc; -- u32 *d32; -- unsigned int i; -+ struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); -+ struct stm32_crc *crc; -+ unsigned long flags; -+ -+ crc = stm32_crc_get_next_crc(); -+ if (!crc) -+ return -ENODEV; + struct stm32_crc_ctx *mctx = crypto_shash_ctx(desc->tfm); +@@ -146,6 +157,16 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, pm_runtime_get_sync(crc->dev); -- if (unlikely(crc->nb_pending_bytes)) { -- while (crc->nb_pending_bytes != sizeof(u32) && length) { -- /* Fill in pending data */ -- crc->pending_data[crc->nb_pending_bytes++] = *(d8++); -+ spin_lock_irqsave(&crc->lock, flags); ++ if (!spin_trylock(&crc->lock)) { ++ /* Hardware is busy, calculate crc32 by software */ ++ if (mctx->poly == CRC32_POLY_LE) ++ ctx->partial = crc32_le(ctx->partial, d8, length); ++ else ++ ctx->partial = __crc32c_le(ctx->partial, d8, length); + -+ /* -+ * Restore previously calculated CRC for this context as init value -+ * Restore polynomial configuration -+ * Configure in register for word input data, -+ * Configure out register in reversed bit mode data. -+ */ -+ writel_relaxed(bitrev32(ctx->partial), crc->regs + CRC_INIT); -+ writel_relaxed(bitrev32(mctx->poly), crc->regs + CRC_POL); -+ writel_relaxed(CRC_CR_RESET | CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, -+ crc->regs + CRC_CR); -+ -+ if (d8 != PTR_ALIGN(d8, sizeof(u32))) { -+ /* Configure for byte data */ -+ writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, -+ crc->regs + CRC_CR); -+ while (d8 != PTR_ALIGN(d8, sizeof(u32)) && length) { -+ writeb_relaxed(*d8++, crc->regs + CRC_DR); - length--; - } -- -- if (crc->nb_pending_bytes == sizeof(u32)) { -- /* Process completed pending data */ -- writel_relaxed(*(u32 *)crc->pending_data, -- crc->regs + CRC_DR); -- crc->nb_pending_bytes = 0; -- } -+ /* Configure for word data */ -+ writel_relaxed(CRC_CR_REV_IN_WORD | CRC_CR_REV_OUT, -+ crc->regs + CRC_CR); - } - -- d32 = (u32 *)d8; -- for (i = 0; i < length >> 2; i++) -- /* Process 32 bits data */ -- writel_relaxed(*(d32++), crc->regs + CRC_DR); -+ for (; length >= sizeof(u32); d8 += sizeof(u32), length -= sizeof(u32)) -+ writel_relaxed(*((u32 *)d8), crc->regs + CRC_DR); -+ -+ if (length) { -+ /* Configure for byte data */ -+ writel_relaxed(CRC_CR_REV_IN_BYTE | CRC_CR_REV_OUT, -+ crc->regs + CRC_CR); -+ while (length--) -+ writeb_relaxed(*d8++, crc->regs + CRC_DR); ++ goto pm_out; + } - ++ + /* + * Restore previously calculated CRC for this context as init value + * Restore polynomial configuration +@@ -184,12 +205,41 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, /* Store partial result */ ctx->partial = readl_relaxed(crc->regs + CRC_DR); -+ spin_unlock_irqrestore(&crc->lock, flags); ++ spin_unlock(&crc->lock); + ++pm_out: pm_runtime_mark_last_busy(crc->dev); pm_runtime_put_autosuspend(crc->dev); -- /* Check for pending data (non 32 bits) */ -- length &= 3; -- if (likely(!length)) -- return 0; -+ return 0; -+} + return 0; + } -- if ((crc->nb_pending_bytes + length) >= sizeof(u32)) { -- /* Shall not happen */ -- dev_err(crc->dev, "Pending data overflow\n"); -- return -EINVAL; -- } +static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, + unsigned int length) +{ @@ -228,11 +126,7 @@ index 9e11c3480..892d5b6eb 100644 + const u8 *cur; + size_t size; + int ret; - -- d8 = (const u8 *)d32; -- for (i = 0; i < length; i++) -- /* Store pending data */ -- crc->pending_data[crc->nb_pending_bytes++] = *(d8++); ++ + if (!burst_sz) + return burst_update(desc, d8, length); + @@ -246,19 +140,14 @@ index 9e11c3480..892d5b6eb 100644 + if (ret) + return ret; + } - - return 0; - } -@@ -204,6 +256,8 @@ static int stm32_crc_digest(struct shash_desc *desc, const u8 *data, - return stm32_crc_init(desc) ?: stm32_crc_finup(desc, data, length, out); - } - -+static unsigned int refcnt; -+static DEFINE_MUTEX(refcnt_lock); - static struct shash_alg algs[] = { - /* CRC-32 */ - { -@@ -271,7 +325,9 @@ static int stm32_crc_probe(struct platform_device *pdev) ++ ++ return 0; ++} ++ + static int stm32_crc_final(struct shash_desc *desc, u8 *out) + { + struct stm32_crc_desc_ctx *ctx = shash_desc_ctx(desc); +@@ -284,7 +334,9 @@ static int stm32_crc_probe(struct platform_device *pdev) crc->clk = devm_clk_get(dev, NULL); if (IS_ERR(crc->clk)) { @@ -269,7 +158,7 @@ index 9e11c3480..892d5b6eb 100644 return PTR_ERR(crc->clk); } -@@ -286,20 +342,29 @@ static int stm32_crc_probe(struct platform_device *pdev) +@@ -299,8 +351,11 @@ static int stm32_crc_probe(struct platform_device *pdev) pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); @@ -281,42 +170,7 @@ index 9e11c3480..892d5b6eb 100644 platform_set_drvdata(pdev, crc); spin_lock(&crc_list.lock); - list_add(&crc->list, &crc_list.dev_list); - spin_unlock(&crc_list.lock); - -- ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); -- if (ret) { -- dev_err(dev, "Failed to register\n"); -- clk_disable_unprepare(crc->clk); -- return ret; -+ mutex_lock(&refcnt_lock); -+ if (!refcnt) { -+ ret = crypto_register_shashes(algs, ARRAY_SIZE(algs)); -+ if (ret) { -+ mutex_unlock(&refcnt_lock); -+ dev_err(dev, "Failed to register\n"); -+ clk_disable_unprepare(crc->clk); -+ return ret; -+ } - } -+ refcnt++; -+ mutex_unlock(&refcnt_lock); - - dev_info(dev, "Initialized\n"); - -@@ -320,7 +385,10 @@ static int stm32_crc_remove(struct platform_device *pdev) - list_del(&crc->list); - spin_unlock(&crc_list.lock); - -- crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); -+ mutex_lock(&refcnt_lock); -+ if (!--refcnt) -+ crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); -+ mutex_unlock(&refcnt_lock); - - pm_runtime_disable(crc->dev); - pm_runtime_put_noidle(crc->dev); -@@ -331,11 +399,39 @@ static int stm32_crc_remove(struct platform_device *pdev) +@@ -353,11 +408,39 @@ static int stm32_crc_remove(struct platform_device *pdev) } #ifdef CONFIG_PM @@ -357,7 +211,7 @@ index 9e11c3480..892d5b6eb 100644 return 0; } -@@ -345,9 +441,9 @@ static int stm32_crc_runtime_resume(struct device *dev) +@@ -367,9 +450,9 @@ static int stm32_crc_runtime_resume(struct device *dev) struct stm32_crc *crc = dev_get_drvdata(dev); int ret; @@ -369,7 +223,7 @@ index 9e11c3480..892d5b6eb 100644 return ret; } -@@ -356,8 +452,8 @@ static int stm32_crc_runtime_resume(struct device *dev) +@@ -378,8 +461,8 @@ static int stm32_crc_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops stm32_crc_pm_ops = { @@ -381,7 +235,7 @@ index 9e11c3480..892d5b6eb 100644 stm32_crc_runtime_resume, NULL) }; diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c -index ba5ea6434..fbf522dc3 100644 +index ba5ea6434f9ca..fbf522dc3d63f 100644 --- a/drivers/crypto/stm32/stm32-cryp.c +++ b/drivers/crypto/stm32/stm32-cryp.c @@ -143,10 +143,10 @@ struct stm32_cryp { @@ -1105,7 +959,7 @@ index ba5ea6434..fbf522dc3 100644 pm_runtime_put_noidle(dev); pm_runtime_disable(dev); diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c -index cfc8e0e37..f8b0e1b28 100644 +index cfc8e0e37beec..f8b0e1b28971e 100644 --- a/drivers/crypto/stm32/stm32-hash.c +++ b/drivers/crypto/stm32/stm32-hash.c @@ -507,6 +507,7 @@ static int stm32_hash_hmac_dma_send(struct stm32_hash_dev *hdev) diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0004-ARM-stm32mp1-r2-RNG-DEBUG-NVMEM.patch similarity index 94% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0004-ARM-stm32mp1-r2-RNG-DEBUG-NVMEM.patch index a24c2a3..ce1aa9a 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0004-ARM-stm32mp1-r2-RNG-DEBUG-NVMEM.patch @@ -1,7 +1,7 @@ -From 31ac3e358c9c6303d58c3f24fe33b6924a56bddd Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:39:52 +0200 -Subject: [PATCH 04/23] ARM-stm32mp1-r1-RNG-DEBUG-NVMEM +From bfe89db1821d391733d9410f1102f456de687474 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:41 +0200 +Subject: [PATCH 04/22] ARM-stm32mp1-r2-rc8-RNG-DEBUG-NVMEM --- arch/arm/Kconfig.debug | 42 +++++++++++++++++++++++++----- @@ -12,7 +12,7 @@ Subject: [PATCH 04/23] ARM-stm32mp1-r1-RNG-DEBUG-NVMEM 5 files changed, 88 insertions(+), 12 deletions(-) diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index 8bcbd0cd7..3357e294a 100644 +index 8bcbd0cd739b5..3357e294a7cc0 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -1201,23 +1201,49 @@ choice @@ -106,7 +106,7 @@ index 8bcbd0cd7..3357e294a 100644 config DEBUG_UART_8250_SHIFT int "Register offset shift for the 8250 debug UART" diff --git a/arch/arm/include/debug/stm32.S b/arch/arm/include/debug/stm32.S -index 1abb32f68..6446e4692 100644 +index 1abb32f685fdb..6446e4692025d 100644 --- a/arch/arm/include/debug/stm32.S +++ b/arch/arm/include/debug/stm32.S @@ -4,14 +4,13 @@ @@ -138,7 +138,7 @@ index 1abb32f68..6446e4692 100644 .macro senduart,rd,rx diff --git a/drivers/char/hw_random/stm32-rng.c b/drivers/char/hw_random/stm32-rng.c -index 38324c2dd..a25c4b5c3 100644 +index 38324c2ddda10..a25c4b5c3d1bc 100644 --- a/drivers/char/hw_random/stm32-rng.c +++ b/drivers/char/hw_random/stm32-rng.c @@ -135,7 +135,10 @@ static int stm32_rng_probe(struct platform_device *ofdev) @@ -154,7 +154,7 @@ index 38324c2dd..a25c4b5c3 100644 udelay(2); reset_control_deassert(priv->rst); diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c -index 960542dea..8105fe423 100644 +index 960542dea5adb..8105fe4230cc5 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -1080,6 +1080,43 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) @@ -202,7 +202,7 @@ index 960542dea..8105fe423 100644 * nvmem_cell_read_u16() - Read a cell value as an u16 * diff --git a/include/linux/nvmem-consumer.h b/include/linux/nvmem-consumer.h -index 5c17cb733..c3c53a63e 100644 +index 5c17cb7332241..c3c53a63e358a 100644 --- a/include/linux/nvmem-consumer.h +++ b/include/linux/nvmem-consumer.h @@ -61,6 +61,7 @@ void nvmem_cell_put(struct nvmem_cell *cell); diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0005-ARM-stm32mp1-r2-CLOCK.patch similarity index 71% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0005-ARM-stm32mp1-r2-CLOCK.patch index 87dfb55..631d8ac 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0005-ARM-stm32mp1-r1-CLOCK.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0005-ARM-stm32mp1-r2-CLOCK.patch @@ -1,17 +1,56 @@ -From 8e898b8cdce1f6bfb91ce5720946d4cbece59da6 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:40:17 +0200 -Subject: [PATCH 05/23] ARM-stm32mp1-r1-CLOCK +From 791f0dfb6aaf584e1a73c0aca77cb95d8dae8070 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:42 +0200 +Subject: [PATCH 05/22] ARM-stm32mp1-r2-rc8-CLOCK --- - drivers/clk/clk-stm32mp1.c | 875 ++++++++++++++++++++-------- - drivers/clk/clk.c | 7 +- - drivers/counter/stm32-lptimer-cnt.c | 2 +- - drivers/counter/stm32-timer-cnt.c | 68 ++- - 4 files changed, 700 insertions(+), 252 deletions(-) + drivers/clk/clk-composite.c | 15 + + drivers/clk/clk-stm32mp1.c | 933 ++++++++++++++++------ + drivers/clk/clk.c | 7 +- + drivers/clocksource/Kconfig | 4 + + drivers/clocksource/Makefile | 1 + + drivers/clocksource/timer-stm32-lp.c | 221 +++++ + drivers/counter/stm32-lptimer-cnt.c | 2 +- + drivers/counter/stm32-timer-cnt.c | 68 +- + include/dt-bindings/clock/stm32mp1-clks.h | 33 + + 9 files changed, 1026 insertions(+), 258 deletions(-) + create mode 100644 drivers/clocksource/timer-stm32-lp.c +diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c +index 4f13a681ddfcd..853558156bda1 100644 +--- a/drivers/clk/clk-composite.c ++++ b/drivers/clk/clk-composite.c +@@ -41,6 +41,18 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, + return rate_ops->recalc_rate(rate_hw, parent_rate); + } + ++static int clk_composite_get_duty_cycle(struct clk_hw *hw, ++ struct clk_duty *duty) ++{ ++ struct clk_composite *composite = to_clk_composite(hw); ++ const struct clk_ops *rate_ops = composite->rate_ops; ++ struct clk_hw *rate_hw = composite->rate_hw; ++ ++ __clk_hw_set_clk(rate_hw, hw); ++ ++ return rate_ops->get_duty_cycle(rate_hw, duty); ++} ++ + static int clk_composite_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) + { +@@ -246,6 +258,9 @@ struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, + } + clk_composite_ops->recalc_rate = clk_composite_recalc_rate; + ++ if (rate_ops->get_duty_cycle) ++ clk_composite_ops->get_duty_cycle = clk_composite_get_duty_cycle; ++ + if (rate_ops->determine_rate) + clk_composite_ops->determine_rate = + clk_composite_determine_rate; diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index a875649df..4a282bfd2 100644 +index a875649df8b8f..2a1de15cd9813 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -5,15 +5,26 @@ @@ -81,16 +120,15 @@ index a875649df..4a282bfd2 100644 }; static const char * const mco1_src[] = { -@@ -291,6 +307,8 @@ static const struct clk_div_table ck_trace_div_table[] = { +@@ -291,6 +307,7 @@ static const struct clk_div_table ck_trace_div_table[] = { struct stm32_mmux { u8 nbr_clk; struct clk_hw *hws[MAX_MUX_CLK]; + u8 saved_parent; -+ u8 enable_count; }; struct stm32_clk_mmux { -@@ -323,7 +341,7 @@ struct clock_config { +@@ -323,7 +340,7 @@ struct clock_config { const struct clock_config *cfg); }; @@ -99,7 +137,7 @@ index a875649df..4a282bfd2 100644 struct gate_cfg { u32 reg_off; -@@ -469,7 +487,7 @@ static const struct clk_ops mp1_gate_clk_ops = { +@@ -469,7 +486,7 @@ static const struct clk_ops mp1_gate_clk_ops = { .is_enabled = clk_gate_is_enabled, }; @@ -108,7 +146,7 @@ index a875649df..4a282bfd2 100644 const struct stm32_mux_cfg *cfg, spinlock_t *lock) { -@@ -478,7 +496,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, +@@ -478,7 +495,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, struct clk_hw *mux_hw; if (cfg->mmux) { @@ -117,7 +155,7 @@ index a875649df..4a282bfd2 100644 if (!mmux) return ERR_PTR(-ENOMEM); -@@ -493,7 +511,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, +@@ -493,7 +510,7 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, cfg->mmux->hws[cfg->mmux->nbr_clk++] = mux_hw; } else { @@ -126,7 +164,7 @@ index a875649df..4a282bfd2 100644 if (!mux) return ERR_PTR(-ENOMEM); -@@ -509,13 +527,13 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, +@@ -509,13 +526,13 @@ static struct clk_hw *_get_stm32_mux(void __iomem *base, return mux_hw; } @@ -142,7 +180,7 @@ index a875649df..4a282bfd2 100644 if (!div) return ERR_PTR(-ENOMEM); -@@ -530,16 +548,16 @@ static struct clk_hw *_get_stm32_div(void __iomem *base, +@@ -530,16 +547,16 @@ static struct clk_hw *_get_stm32_div(void __iomem *base, return &div->hw; } @@ -163,7 +201,7 @@ index a875649df..4a282bfd2 100644 if (!mgate) return ERR_PTR(-ENOMEM); -@@ -554,7 +572,7 @@ _get_stm32_gate(void __iomem *base, +@@ -554,7 +571,7 @@ _get_stm32_gate(void __iomem *base, gate_hw = &mgate->gate.hw; } else { @@ -172,7 +210,7 @@ index a875649df..4a282bfd2 100644 if (!gate) return ERR_PTR(-ENOMEM); -@@ -592,7 +610,7 @@ clk_stm32_register_gate_ops(struct device *dev, +@@ -592,7 +609,7 @@ clk_stm32_register_gate_ops(struct device *dev, if (cfg->ops) init.ops = cfg->ops; @@ -181,7 +219,7 @@ index a875649df..4a282bfd2 100644 if (IS_ERR(hw)) return ERR_PTR(-ENOMEM); -@@ -623,7 +641,7 @@ clk_stm32_register_composite(struct device *dev, +@@ -623,7 +640,7 @@ clk_stm32_register_composite(struct device *dev, gate_ops = NULL; if (cfg->mux) { @@ -190,7 +228,7 @@ index a875649df..4a282bfd2 100644 if (!IS_ERR(mux_hw)) { mux_ops = &clk_mux_ops; -@@ -634,7 +652,7 @@ clk_stm32_register_composite(struct device *dev, +@@ -634,7 +651,7 @@ clk_stm32_register_composite(struct device *dev, } if (cfg->div) { @@ -199,7 +237,7 @@ index a875649df..4a282bfd2 100644 if (!IS_ERR(div_hw)) { div_ops = &clk_divider_ops; -@@ -645,7 +663,7 @@ clk_stm32_register_composite(struct device *dev, +@@ -645,7 +662,7 @@ clk_stm32_register_composite(struct device *dev, } if (cfg->gate) { @@ -208,7 +246,7 @@ index a875649df..4a282bfd2 100644 if (!IS_ERR(gate_hw)) { gate_ops = &clk_gate_ops; -@@ -714,7 +732,7 @@ static int clk_mmux_set_parent(struct clk_hw *hw, u8 index) +@@ -714,7 +731,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) @@ -217,7 +255,7 @@ index a875649df..4a282bfd2 100644 return 0; } -@@ -725,178 +743,260 @@ static const struct clk_ops clk_mmux_ops = { +@@ -725,178 +742,266 @@ static const struct clk_ops clk_mmux_ops = { .determine_rate = __clk_mux_determine_rate, }; @@ -228,15 +266,21 @@ index a875649df..4a282bfd2 100644 - void __iomem *reg; - struct clk_hw hw; -}; -+#define MMUX_SAFE_POSITION 0 - --#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) -+static int clk_mmux_set_safe_position(struct clk_hw *hw) ++static bool is_all_clk_on_switch_are_off(struct clk_hw *hw) +{ + struct clk_composite *composite = to_clk_composite(hw); + struct clk_hw *mux_hw = composite->mux_hw; + struct clk_mux *mux = to_clk_mux(mux_hw); + struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); ++ int i = 0; ++ ++ for (i = 0; i < clk_mmux->mmux->nbr_clk; i++) ++ if (__clk_is_enabled(clk_mmux->mmux->hws[i]->clk)) ++ return false; + +-#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) ++ return true; ++} -#define PLL_ON BIT(0) -#define PLL_RDY BIT(1) @@ -248,16 +292,10 @@ index a875649df..4a282bfd2 100644 -#define FRAC_MASK 0x1FFF -#define FRAC_SHIFT 3 -#define FRACLE BIT(16) -+ if (--clk_mmux->mmux->enable_count == 0) { -+ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(mux_hw); -+ clk_mux_ops.set_parent(mux_hw, MMUX_SAFE_POSITION); -+ } ++#define MMUX_SAFE_POSITION 0 -static int __pll_is_enabled(struct clk_hw *hw) -+ return 0; -+} -+ -+static int clk_mmux_restore_parent(struct clk_hw *hw) ++static int clk_mmux_set_safe_position(struct clk_hw *hw) { - struct stm32_pll_obj *clk_elem = to_pll(hw); + struct clk_composite *composite = to_clk_composite(hw); @@ -267,44 +305,41 @@ index a875649df..4a282bfd2 100644 - return readl_relaxed(clk_elem->reg) & PLL_ON; -} -+ if (clk_mmux->mmux->enable_count == 0) -+ clk_mux_ops.set_parent(mux_hw, clk_mmux->mmux->saved_parent); ++ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(mux_hw); ++ clk_mux_ops.set_parent(mux_hw, MMUX_SAFE_POSITION); -#define TIMEOUT 5 -+ clk_mmux->mmux->enable_count++; - --static int pll_enable(struct clk_hw *hw) + return 0; +} -+ -+static u8 clk_mmux_get_parent_safe(struct clk_hw *hw) + +-static int pll_enable(struct clk_hw *hw) ++static int clk_mmux_restore_parent(struct clk_hw *hw) { - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - unsigned long flags = 0; - unsigned int timeout = TIMEOUT; - int bit_status = 0; -+ struct clk_mux *mux = to_clk_mux(hw); ++ struct clk_composite *composite = to_clk_composite(hw); ++ struct clk_hw *mux_hw = composite->mux_hw; ++ struct clk_mux *mux = to_clk_mux(mux_hw); + struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - spin_lock_irqsave(clk_elem->lock, flags); -+ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(hw); ++ clk_mux_ops.set_parent(mux_hw, clk_mmux->mmux->saved_parent); - if (__pll_is_enabled(hw)) - goto unlock; -+ return clk_mmux->mmux->saved_parent; ++ return 0; +} -+ -+static int clk_mmux_set_parent_safe(struct clk_hw *hw, u8 index) -+{ -+ struct clk_mux *mux = to_clk_mux(hw); -+ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - reg = readl_relaxed(clk_elem->reg); - reg |= PLL_ON; - writel_relaxed(reg, clk_elem->reg); -+ clk_mmux_set_parent(hw, index); -+ clk_mmux->mmux->saved_parent = index; ++static u8 clk_mmux_get_parent_safe(struct clk_hw *hw) ++{ ++ struct clk_mux *mux = to_clk_mux(hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); - /* We can't use readl_poll_timeout() because we can be blocked if - * someone enables this clock before clocksource changes. @@ -313,53 +348,61 @@ index a875649df..4a282bfd2 100644 - */ - do { - bit_status = !(readl_relaxed(clk_elem->reg) & PLL_RDY); -+ return 0; -+} ++ clk_mmux->mmux->saved_parent = clk_mmux_get_parent(hw); - if (bit_status) - udelay(120); ++ return clk_mmux->mmux->saved_parent; ++} + +- } while (bit_status && --timeout); ++static int clk_mmux_set_parent_safe(struct clk_hw *hw, u8 index) ++{ ++ struct clk_mux *mux = to_clk_mux(hw); ++ struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + +-unlock: +- spin_unlock_irqrestore(clk_elem->lock, flags); ++ clk_mmux_set_parent(hw, index); ++ clk_mmux->mmux->saved_parent = index; + +- return bit_status; ++ return 0; + } + +-static void pll_disable(struct clk_hw *hw) +static const struct clk_ops clk_mmux_safe_ops = { + .get_parent = clk_mmux_get_parent_safe, + .set_parent = clk_mmux_set_parent_safe, + .determine_rate = __clk_mux_determine_rate, +}; - -- } while (bit_status && --timeout); ++ +static int mp1_mgate_clk_enable_safe(struct clk_hw *hw) -+{ -+ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); - --unlock: -- spin_unlock_irqrestore(clk_elem->lock, flags); -+ clk_mmux_restore_parent(composite_hw); -+ mp1_mgate_clk_enable(hw); - -- return bit_status; -+ return 0; - } - --static void pll_disable(struct clk_hw *hw) -+static void mp1_mgate_clk_disable_safe(struct clk_hw *hw) { - struct stm32_pll_obj *clk_elem = to_pll(hw); - u32 reg; - unsigned long flags = 0; -- ++ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); + - spin_lock_irqsave(clk_elem->lock, flags); -+ struct clk_gate *gate = to_clk_gate(hw); -+ struct stm32_clk_mgate *clk_mgate = to_clk_mgate(gate); ++ clk_mmux_restore_parent(composite_hw); ++ mp1_mgate_clk_enable(hw); ++ ++ return 0; ++} ++ ++static void mp1_mgate_clk_disable_safe(struct clk_hw *hw) ++{ + struct clk_hw *composite_hw = __clk_get_hw(hw->clk); - reg = readl_relaxed(clk_elem->reg); - reg &= ~PLL_ON; - writel_relaxed(reg, clk_elem->reg); -+ clk_mgate->mgate->flag &= ~clk_mgate->mask; ++ mp1_mgate_clk_disable(hw); - spin_unlock_irqrestore(clk_elem->lock, flags); -+ if (clk_mgate->mgate->flag == 0) { ++ if (is_all_clk_on_switch_are_off(composite_hw)) + clk_mmux_set_safe_position(composite_hw); -+ mp1_gate_clk_disable(hw); -+ } } -static u32 pll_frac_val(struct clk_hw *hw) @@ -463,28 +506,28 @@ index a875649df..4a282bfd2 100644 + struct clk_gate *gate = to_clk_gate(hw); + u32 timeout = TIMEOUT; + int bit_status = 0; -+ -+ if (clk_gate_ops.is_enabled(hw)) -+ return 0; - reg = readl_relaxed(clk_elem->reg + 4); -+ clk_gate_ops.enable(hw); ++ if (clk_gate_ops.is_enabled(hw)) ++ return 0; - divm = ((reg >> DIVM_SHIFT) & DIVM_MASK) + 1; - divn = ((reg >> DIVN_SHIFT) & DIVN_MASK) + 1; - rate = (u64)parent_rate * divn; -+ do { -+ bit_status = !(readl_relaxed(gate->reg) & BIT(PLL_BIT_RDY)); ++ clk_gate_ops.enable(hw); - do_div(rate, divm); -+ if (bit_status) -+ udelay(120); ++ do { ++ bit_status = !(readl_relaxed(gate->reg) & BIT(PLL_BIT_RDY)); - frac = pll_frac_val(hw); - if (frac) { - rate_frac = (u64)parent_rate * (u64)frac; - do_div(rate_frac, (divm * 8192)); - } ++ if (bit_status) ++ udelay(120); ++ + } while (bit_status && --timeout); - return rate + rate_frac; @@ -594,7 +637,7 @@ index a875649df..4a282bfd2 100644 } /* Kernel Timer */ -@@ -1005,7 +1105,7 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, +@@ -1005,7 +1110,7 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, struct clk_hw *hw; int err; @@ -603,7 +646,7 @@ index a875649df..4a282bfd2 100644 if (!tim_ker) return ERR_PTR(-ENOMEM); -@@ -1023,16 +1123,51 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, +@@ -1023,16 +1128,90 @@ static struct clk_hw *clk_register_cktim(struct device *dev, const char *name, hw = &tim_ker->hw; err = clk_hw_register(dev, hw); @@ -645,11 +688,50 @@ index a875649df..4a282bfd2 100644 + return parent_rate; +} + ++static int clk_div_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty) ++{ ++ struct clk_divider *divider = to_clk_divider(hw); ++ unsigned int val; ++ ++ val = readl(divider->reg) >> divider->shift; ++ val &= clk_div_mask(divider->width); ++ ++ duty->num = (val + 1) / 2; ++ duty->den = (val + 1); ++ ++ return 0; ++} ++ +static const struct clk_ops rtc_div_clk_ops = { + .recalc_rate = clk_divider_rtc_recalc_rate, + .round_rate = clk_divider_rtc_round_rate, + .set_rate = clk_divider_rtc_set_rate, +}; ++ ++static unsigned long clk_div_duty_cycle_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ return clk_divider_ops.recalc_rate(hw, parent_rate); ++} ++ ++static long clk_div_duty_cycle_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ return clk_divider_ops.round_rate(hw, rate, prate); ++} ++ ++static int clk_div_duty_cycle_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ return clk_divider_ops.set_rate(hw, rate, parent_rate); ++} ++ ++static const struct clk_ops div_dc_clk_ops = { ++ .recalc_rate = clk_div_duty_cycle_recalc_rate, ++ .round_rate = clk_div_duty_cycle_round_rate, ++ .set_rate = clk_div_duty_cycle_set_rate, ++ .get_duty_cycle = clk_div_get_duty_cycle, ++}; + struct stm32_pll_cfg { u32 offset; @@ -658,7 +740,7 @@ index a875649df..4a282bfd2 100644 }; static struct clk_hw *_clk_register_pll(struct device *dev, -@@ -1042,8 +1177,11 @@ static struct clk_hw *_clk_register_pll(struct device *dev, +@@ -1042,8 +1221,11 @@ static struct clk_hw *_clk_register_pll(struct device *dev, { struct stm32_pll_cfg *stm_pll_cfg = cfg->cfg; @@ -672,7 +754,7 @@ index a875649df..4a282bfd2 100644 } struct stm32_cktim_cfg { -@@ -1153,14 +1291,16 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1153,14 +1335,16 @@ _clk_stm32_register_composite(struct device *dev, .func = _clk_hw_register_mux,\ } @@ -693,7 +775,7 @@ index a875649df..4a282bfd2 100644 },\ .func = _clk_register_pll,\ } -@@ -1216,7 +1356,7 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1216,7 +1400,7 @@ _clk_stm32_register_composite(struct device *dev, NULL, &mp1_gate_clk_ops)\ #define _MGATE_MP1(_mgate)\ @@ -702,7 +784,7 @@ index a875649df..4a282bfd2 100644 #define GATE_MP1(_id, _name, _parent, _flags, _offset, _bit_idx, _gate_flags)\ STM32_GATE(_id, _name, _parent, _flags,\ -@@ -1228,7 +1368,7 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1228,7 +1412,7 @@ _clk_stm32_register_composite(struct device *dev, #define _STM32_DIV(_div_offset, _div_shift, _div_width,\ _div_flags, _div_table, _ops)\ @@ -711,7 +793,7 @@ index a875649df..4a282bfd2 100644 &(struct div_cfg) {\ .reg_off = _div_offset,\ .shift = _div_shift,\ -@@ -1237,14 +1377,18 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1237,14 +1421,23 @@ _clk_stm32_register_composite(struct device *dev, .table = _div_table,\ },\ .ops = _ops,\ @@ -723,6 +805,11 @@ index a875649df..4a282bfd2 100644 - _div_flags, _div_table, NULL)\ + _div_flags, _div_table, NULL) + ++#define _DIV_DUTY_CYCLE(_div_offset, _div_shift, _div_width, _div_flags,\ ++ _div_table)\ ++ _STM32_DIV(_div_offset, _div_shift, _div_width,\ ++ _div_flags, _div_table, &div_dc_clk_ops) ++ +#define _DIV_RTC(_div_offset, _div_shift, _div_width, _div_flags, _div_table)\ + _STM32_DIV(_div_offset, _div_shift, _div_width,\ + _div_flags, _div_table, &rtc_div_clk_ops) @@ -733,7 +820,7 @@ index a875649df..4a282bfd2 100644 &(struct mux_cfg) {\ .reg_off = _offset,\ .shift = _shift,\ -@@ -1254,18 +1398,18 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1254,18 +1447,18 @@ _clk_stm32_register_composite(struct device *dev, },\ .mmux = _mmux,\ .ops = _ops,\ @@ -759,7 +846,7 @@ index a875649df..4a282bfd2 100644 #define COMPOSITE(_id, _name, _parents, _flags, _gate, _mux, _div)\ {\ -@@ -1275,9 +1419,9 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1275,9 +1468,9 @@ _clk_stm32_register_composite(struct device *dev, .num_parents = ARRAY_SIZE(_parents),\ .flags = _flags,\ .cfg = &(struct stm32_composite_cfg) {\ @@ -772,7 +859,7 @@ index a875649df..4a282bfd2 100644 },\ .func = _clk_stm32_register_composite,\ } -@@ -1292,6 +1436,11 @@ _clk_stm32_register_composite(struct device *dev, +@@ -1292,6 +1485,11 @@ _clk_stm32_register_composite(struct device *dev, _MMUX(_mmux),\ _NO_DIV) @@ -784,7 +871,7 @@ index a875649df..4a282bfd2 100644 enum { G_SAI1, G_SAI2, -@@ -1409,8 +1558,7 @@ enum { +@@ -1409,8 +1607,7 @@ enum { static struct stm32_mgate mp1_mgate[G_LAST]; @@ -794,7 +881,7 @@ index a875649df..4a282bfd2 100644 [_id] = {\ &(struct gate_cfg) {\ .reg_off = _gate_offset,\ -@@ -1429,6 +1577,10 @@ static struct stm32_mgate mp1_mgate[G_LAST]; +@@ -1429,6 +1626,10 @@ static struct stm32_mgate mp1_mgate[G_LAST]; _K_GATE(_id, _gate_offset, _gate_bit_idx, _gate_flags,\ &mp1_mgate[_id], &mp1_mgate_clk_ops) @@ -805,7 +892,7 @@ index a875649df..4a282bfd2 100644 /* Peripheral gates */ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { /* Multi gates */ -@@ -1540,16 +1692,19 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { +@@ -1540,16 +1741,19 @@ static struct stm32_gate_cfg per_gate_cfg[G_LAST] = { K_GATE(G_USBH, RCC_AHB6ENSETR, 24, 0), K_GATE(G_CRC1, RCC_AHB6ENSETR, 20, 0), @@ -829,7 +916,7 @@ index a875649df..4a282bfd2 100644 K_GATE(G_ETHSTP, RCC_AHB6LPENSETR, 11, 0), }; -@@ -1615,9 +1770,13 @@ static struct stm32_mmux ker_mux[M_LAST]; +@@ -1615,9 +1819,13 @@ static struct stm32_mmux ker_mux[M_LAST]; _K_MUX(_id, _offset, _shift, _width, _mux_flags,\ &ker_mux[_id], &clk_mmux_ops) @@ -844,7 +931,7 @@ index a875649df..4a282bfd2 100644 K_MMUX(M_SPI23, RCC_SPI2S23CKSELR, 0, 3, 0), K_MMUX(M_SPI45, RCC_SPI2S45CKSELR, 0, 3, 0), K_MMUX(M_I2C12, RCC_I2C12CKSELR, 0, 3, 0), -@@ -1634,8 +1793,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { +@@ -1634,8 +1842,8 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { /* Kernel simple mux */ K_MUX(M_RNG2, RCC_RNG2CKSELR, 0, 2, 0), K_MUX(M_SDMMC3, RCC_SDMMC3CKSELR, 0, 3, 0), @@ -855,7 +942,7 @@ index a875649df..4a282bfd2 100644 K_MUX(M_USBPHY, RCC_USBCKSELR, 0, 2, 0), K_MUX(M_USBO, RCC_USBCKSELR, 4, 1, 0), K_MUX(M_SPDIF, RCC_SPDIFCKSELR, 0, 2, 0), -@@ -1656,40 +1815,43 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { +@@ -1656,40 +1864,43 @@ static const struct stm32_mux_cfg ker_mux_cfg[M_LAST] = { K_MUX(M_SPI6, RCC_SPI6CKSELR, 0, 3, 0), }; @@ -923,7 +1010,23 @@ index a875649df..4a282bfd2 100644 _GATE(RCC_PLL1CR, 4, 0), _NO_MUX, _DIV(RCC_PLL1CFGR2, 0, 7, 0, NULL)), -@@ -1743,34 +1905,36 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1717,7 +1928,7 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + COMPOSITE(PLL3_Q, "pll3_q", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 5, 0), + _NO_MUX, +- _DIV(RCC_PLL3CFGR2, 8, 7, 0, NULL)), ++ _DIV_DUTY_CYCLE(RCC_PLL3CFGR2, 8, 7, 0, NULL)), + + COMPOSITE(PLL3_R, "pll3_r", PARENT("pll3"), 0, + _GATE(RCC_PLL3CR, 6, 0), +@@ -1737,40 +1948,42 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + COMPOSITE(PLL4_R, "pll4_r", PARENT("pll4"), 0, + _GATE(RCC_PLL4CR, 6, 0), + _NO_MUX, +- _DIV(RCC_PLL4CFGR2, 16, 7, 0, NULL)), ++ _DIV_DUTY_CYCLE(RCC_PLL4CFGR2, 16, 7, 0, NULL)), + + /* MUX system clocks */ MUX(CK_PER, "ck_per", per_src, CLK_OPS_PARENT_ENABLE, RCC_CPERCKSELR, 0, 2, 0), @@ -977,7 +1080,7 @@ index a875649df..4a282bfd2 100644 3, CLK_DIVIDER_READ_ONLY, apb_div_table), /* Kernel Timers */ -@@ -1852,8 +2016,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1852,8 +2065,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { PCLK(I2C4, "i2c4", "pclk5", 0, G_I2C4), PCLK(I2C6, "i2c6", "pclk5", 0, G_I2C6), PCLK(USART1, "usart1", "pclk5", 0, G_USART1), @@ -988,7 +1091,7 @@ index a875649df..4a282bfd2 100644 PCLK(TZC1, "tzc1", "ck_axi", CLK_IGNORE_UNUSED, G_TZC1), PCLK(TZC2, "tzc2", "ck_axi", CLK_IGNORE_UNUSED, G_TZC2), PCLK(TZPC, "tzpc", "pclk5", CLK_IGNORE_UNUSED, G_TZPC), -@@ -1888,7 +2052,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1888,16 +2101,13 @@ static const struct clock_config stm32mp1_clock_cfg[] = { PCLK(CRYP1, "cryp1", "ck_axi", CLK_IGNORE_UNUSED, G_CRYP1), PCLK(HASH1, "hash1", "ck_axi", CLK_IGNORE_UNUSED, G_HASH1), PCLK(RNG1, "rng1", "ck_axi", 0, G_RNG1), @@ -998,7 +1101,16 @@ index a875649df..4a282bfd2 100644 PCLK(MDMA, "mdma", "ck_axi", 0, G_MDMA), PCLK(GPU, "gpu", "ck_axi", 0, G_GPU), PCLK(ETHTX, "ethtx", "ck_axi", 0, G_ETHTX), -@@ -1912,7 +2077,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + PCLK(ETHRX, "ethrx", "ck_axi", 0, G_ETHRX), + PCLK(ETHMAC, "ethmac", "ck_axi", 0, G_ETHMAC), +- PCLK(FMC, "fmc", "ck_axi", CLK_IGNORE_UNUSED, G_FMC), +- PCLK(QSPI, "qspi", "ck_axi", CLK_IGNORE_UNUSED, G_QSPI), +- PCLK(SDMMC1, "sdmmc1", "ck_axi", 0, G_SDMMC1), +- PCLK(SDMMC2, "sdmmc2", "ck_axi", 0, G_SDMMC2), + PCLK(CRC1, "crc1", "ck_axi", 0, G_CRC1), + PCLK(USBH, "usbh", "ck_axi", 0, G_USBH), + PCLK(ETHSTP, "ethstp", "ck_axi", 0, G_ETHSTP), +@@ -1912,7 +2122,8 @@ static const struct clock_config stm32mp1_clock_cfg[] = { KCLK(RNG1_K, "rng1_k", rng_src, 0, G_RNG1, M_RNG1), KCLK(RNG2_K, "rng2_k", rng_src, 0, G_RNG2, M_RNG2), KCLK(USBPHY_K, "usbphy_k", usbphy_src, 0, G_USBPHY, M_USBPHY), @@ -1008,7 +1120,7 @@ index a875649df..4a282bfd2 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), -@@ -1965,23 +2131,21 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1965,23 +2176,21 @@ static const struct clock_config stm32mp1_clock_cfg[] = { _DIV(RCC_ETHCKSELR, 4, 4, 0, NULL)), /* RTC clock */ @@ -1039,7 +1151,15 @@ index a875649df..4a282bfd2 100644 _GATE(RCC_MCO2CFGR, 12, 0), _MUX(RCC_MCO2CFGR, 0, 3, 0), _DIV(RCC_MCO2CFGR, 4, 4, 0, NULL)), -@@ -1996,10 +2160,60 @@ static const struct clock_config stm32mp1_clock_cfg[] = { +@@ -1990,16 +2199,67 @@ static const struct clock_config stm32mp1_clock_cfg[] = { + GATE(CK_DBG, "ck_sys_dbg", "ck_axi", CLK_IGNORE_UNUSED, + RCC_DBGCFGR, 8, 0), + +- COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, CLK_OPS_PARENT_ENABLE, ++ COMPOSITE(CK_TRACE, "ck_trace", ck_trace_src, ++ CLK_OPS_PARENT_ENABLE | CLK_IGNORE_UNUSED, + _GATE(RCC_DBGCFGR, 9, 0), + _NO_MUX, _DIV(RCC_DBGCFGR, 0, 3, 0, ck_trace_div_table)), }; @@ -1100,7 +1220,7 @@ index a875649df..4a282bfd2 100644 }; static struct stm32_clock_match_data stm32mp1_data = { -@@ -2008,13 +2222,25 @@ static struct stm32_clock_match_data stm32mp1_data = { +@@ -2008,13 +2268,25 @@ static struct stm32_clock_match_data stm32mp1_data = { .maxbinding = STM32MP1_LAST_CLK, }; @@ -1126,7 +1246,7 @@ index a875649df..4a282bfd2 100644 static int stm32_register_hw_clk(struct device *dev, struct clk_hw_onecell_data *clk_data, -@@ -2040,8 +2266,7 @@ static int stm32_register_hw_clk(struct device *dev, +@@ -2040,8 +2312,7 @@ static int stm32_register_hw_clk(struct device *dev, return 0; } @@ -1136,7 +1256,7 @@ index a875649df..4a282bfd2 100644 const struct of_device_id *match_data) { struct clk_hw_onecell_data *clk_data; -@@ -2050,9 +2275,9 @@ static int stm32_rcc_init(struct device_node *np, +@@ -2050,9 +2321,9 @@ static int stm32_rcc_init(struct device_node *np, const struct stm32_clock_match_data *data; int err, n, max_binding; @@ -1148,7 +1268,7 @@ index a875649df..4a282bfd2 100644 return -ENODEV; } -@@ -2060,8 +2285,8 @@ static int stm32_rcc_init(struct device_node *np, +@@ -2060,8 +2331,8 @@ static int stm32_rcc_init(struct device_node *np, max_binding = data->maxbinding; @@ -1159,7 +1279,7 @@ index a875649df..4a282bfd2 100644 if (!clk_data) return -ENOMEM; -@@ -2073,36 +2298,194 @@ static int stm32_rcc_init(struct device_node *np, +@@ -2073,36 +2344,194 @@ static int stm32_rcc_init(struct device_node *np, hws[n] = ERR_PTR(-ENOENT); for (n = 0; n < data->num; n++) { @@ -1204,8 +1324,11 @@ index a875649df..4a282bfd2 100644 + if (!rcc_base) { + dev_err(dev, "%pOFn: unable to map resource", dev_of_node(dev)); + goto out; -+ } -+ + } + +- if (stm32_rcc_init(np, base, stm32mp1_match_data)) { +- iounmap(base); +- of_node_put(np); + ret = stm32_rcc_init(dev, rcc_base, stm32mp1_match_data); + if (ret) + goto out; @@ -1219,7 +1342,7 @@ index a875649df..4a282bfd2 100644 + rcc_base = NULL; + + of_node_put(dev_of_node(dev)); -+ } + } + + return ret; +} @@ -1267,8 +1390,9 @@ index a875649df..4a282bfd2 100644 + SMC(STM32_SVC_RCC, STM32_WRITE, RCC_CIFR, RCC_IRQ_FLAGS_MASK); + + return IRQ_HANDLED; -+} -+ + } + +-CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); +static struct irqaction rcc_irq = { + .name = "rcc irq", + .flags = IRQF_ONESHOT, @@ -1286,16 +1410,13 @@ index a875649df..4a282bfd2 100644 + if (irq <= 0) { + pr_err("%s: failed to get RCC generic IRQ\n", __func__); + return irq ? irq : -ENXIO; - } - -- if (stm32_rcc_init(np, base, stm32mp1_match_data)) { -- iounmap(base); -- of_node_put(np); ++ } ++ + ret = setup_irq(irq, &rcc_irq); + if (ret) { + pr_err("%s: failed to register generic IRQ\n", __func__); + return ret; - } ++ } + + /* Configure LPEN static table */ + for (i = 0; i < ARRAY_SIZE(lp_table); i++) @@ -1332,9 +1453,8 @@ index a875649df..4a282bfd2 100644 + } + + return 0; - } - --CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); ++} ++ +static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; @@ -1372,10 +1492,10 @@ index a875649df..4a282bfd2 100644 +} +core_initcall(stm32mp1_clocks_init); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c -index 62d0fc486..815067c28 100644 +index 36e9f38a38824..b986c72a497a0 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c -@@ -1713,6 +1713,7 @@ static void clk_reparent(struct clk_core *core, struct clk_core *new_parent) +@@ -1717,6 +1717,7 @@ static void clk_reparent(struct clk_core *core, struct clk_core *new_parent) core->parent = new_parent; } @@ -1383,7 +1503,7 @@ index 62d0fc486..815067c28 100644 static struct clk_core *__clk_set_parent_before(struct clk_core *core, struct clk_core *parent) { -@@ -1741,7 +1742,8 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core, +@@ -1745,7 +1746,8 @@ static struct clk_core *__clk_set_parent_before(struct clk_core *core, /* enable old_parent & parent if CLK_OPS_PARENT_ENABLE is set */ if (core->flags & CLK_OPS_PARENT_ENABLE) { @@ -1393,7 +1513,7 @@ index 62d0fc486..815067c28 100644 clk_core_prepare_enable(parent); } -@@ -1775,7 +1777,8 @@ static void __clk_set_parent_after(struct clk_core *core, +@@ -1779,7 +1781,8 @@ static void __clk_set_parent_after(struct clk_core *core, /* re-balance ref counting if CLK_OPS_PARENT_ENABLE is set */ if (core->flags & CLK_OPS_PARENT_ENABLE) { clk_core_disable_unprepare(parent); @@ -1403,8 +1523,262 @@ index 62d0fc486..815067c28 100644 } } +diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig +index f35a53ce8988a..19ec0a78a316a 100644 +--- a/drivers/clocksource/Kconfig ++++ b/drivers/clocksource/Kconfig +@@ -292,6 +292,10 @@ config CLKSRC_STM32 + select CLKSRC_MMIO + select TIMER_OF + ++config CLKSRC_STM32_LP ++ bool "Low power clocksource for STM32 SoCs" ++ depends on MFD_STM32_LPTIMER || COMPILE_TEST ++ + config CLKSRC_MPS2 + bool "Clocksource for MPS2 SoCs" if COMPILE_TEST + depends on GENERIC_SCHED_CLOCK +diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile +index 4dfe4225ece78..c6eef37be9ccc 100644 +--- a/drivers/clocksource/Makefile ++++ b/drivers/clocksource/Makefile +@@ -44,6 +44,7 @@ obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o + obj-$(CONFIG_CADENCE_TTC_TIMER) += timer-cadence-ttc.o + obj-$(CONFIG_CLKSRC_EFM32) += timer-efm32.o + obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o ++obj-$(CONFIG_CLKSRC_STM32_LP) += timer-stm32-lp.o + obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o + obj-$(CONFIG_CLKSRC_LPC32XX) += timer-lpc32xx.o + obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o +diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c +new file mode 100644 +index 0000000000000..db2841d0beb81 +--- /dev/null ++++ b/drivers/clocksource/timer-stm32-lp.c +@@ -0,0 +1,221 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2019 - All Rights Reserved ++ * Authors: Benjamin Gaignard for STMicroelectronics. ++ * Pascal Paillet for STMicroelectronics. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define CFGR_PSC_OFFSET 9 ++#define STM32_LP_RATING 1000 ++#define STM32_TARGET_CLKRATE (32000 * HZ) ++#define STM32_LP_MAX_PSC 7 ++ ++struct stm32_lp_private { ++ struct regmap *reg; ++ struct clock_event_device clkevt; ++ unsigned long period; ++ struct device *dev; ++}; ++ ++static struct stm32_lp_private* ++to_priv(struct clock_event_device *clkevt) ++{ ++ return container_of(clkevt, struct stm32_lp_private, clkevt); ++} ++ ++static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt) ++{ ++ struct stm32_lp_private *priv = to_priv(clkevt); ++ ++ regmap_write(priv->reg, STM32_LPTIM_CR, 0); ++ regmap_write(priv->reg, STM32_LPTIM_IER, 0); ++ /* clear pending flags */ ++ regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF); ++ ++ return 0; ++} ++ ++static int stm32_clkevent_lp_set_timer(unsigned long evt, ++ struct clock_event_device *clkevt, ++ int is_periodic) ++{ ++ struct stm32_lp_private *priv = to_priv(clkevt); ++ ++ /* disable LPTIMER to be able to write into IER register*/ ++ regmap_write(priv->reg, STM32_LPTIM_CR, 0); ++ /* enable ARR interrupt */ ++ regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE); ++ /* enable LPTIMER to be able to write into ARR register */ ++ regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE); ++ /* set next event counter */ ++ regmap_write(priv->reg, STM32_LPTIM_ARR, evt); ++ ++ /* start counter */ ++ if (is_periodic) ++ regmap_write(priv->reg, STM32_LPTIM_CR, ++ STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE); ++ else ++ regmap_write(priv->reg, STM32_LPTIM_CR, ++ STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE); ++ ++ return 0; ++} ++ ++static int stm32_clkevent_lp_set_next_event(unsigned long evt, ++ struct clock_event_device *clkevt) ++{ ++ return stm32_clkevent_lp_set_timer(evt, clkevt, ++ clockevent_state_periodic(clkevt)); ++} ++ ++static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt) ++{ ++ struct stm32_lp_private *priv = to_priv(clkevt); ++ ++ return stm32_clkevent_lp_set_timer(priv->period, clkevt, true); ++} ++ ++static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt) ++{ ++ struct stm32_lp_private *priv = to_priv(clkevt); ++ ++ return stm32_clkevent_lp_set_timer(priv->period, clkevt, false); ++} ++ ++static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id) ++{ ++ struct clock_event_device *clkevt = (struct clock_event_device *)dev_id; ++ struct stm32_lp_private *priv = to_priv(clkevt); ++ ++ regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF); ++ ++ if (clkevt->event_handler) ++ clkevt->event_handler(clkevt); ++ ++ return IRQ_HANDLED; ++} ++ ++static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv, ++ unsigned long *rate) ++{ ++ int i; ++ ++ for (i = 0; i <= STM32_LP_MAX_PSC; i++) { ++ if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE) ++ break; ++ } ++ ++ regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET); ++ ++ /* Adjust rate and period given the prescaler value */ ++ *rate = DIV_ROUND_CLOSEST(*rate, (1 << i)); ++ priv->period = DIV_ROUND_UP(*rate, HZ); ++} ++ ++static void stm32_clkevent_lp_init(struct stm32_lp_private *priv, ++ struct device_node *np, unsigned long rate) ++{ ++ priv->clkevt.name = np->full_name; ++ priv->clkevt.cpumask = cpu_possible_mask; ++ priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | ++ CLOCK_EVT_FEAT_ONESHOT; ++ priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown; ++ priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic; ++ priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot; ++ priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event; ++ priv->clkevt.rating = STM32_LP_RATING; ++ ++ clockevents_config_and_register(&priv->clkevt, rate, 0x1, ++ STM32_LPTIM_MAX_ARR); ++} ++ ++static int stm32_clkevent_lp_probe(struct platform_device *pdev) ++{ ++ struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent); ++ struct stm32_lp_private *priv; ++ unsigned long rate; ++ int ret, irq; ++ ++ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ priv->reg = ddata->regmap; ++ ret = clk_prepare_enable(ddata->clk); ++ if (ret) ++ return -EINVAL; ++ ++ rate = clk_get_rate(ddata->clk); ++ if (!rate) { ++ ret = -EINVAL; ++ goto out_clk_disable; ++ } ++ ++ irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0); ++ if (irq <= 0) { ++ ret = irq; ++ goto out_clk_disable; ++ } ++ ++ if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) { ++ ret = device_init_wakeup(&pdev->dev, true); ++ if (ret) ++ goto out_clk_disable; ++ ++ ret = dev_pm_set_wake_irq(&pdev->dev, irq); ++ if (ret) ++ goto out_clk_disable; ++ } ++ ++ ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler, ++ IRQF_TIMER, pdev->name, &priv->clkevt); ++ if (ret) ++ goto out_clk_disable; ++ ++ stm32_clkevent_lp_set_prescaler(priv, &rate); ++ ++ stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate); ++ ++ priv->dev = &pdev->dev; ++ ++ return 0; ++ ++out_clk_disable: ++ clk_disable_unprepare(ddata->clk); ++ return ret; ++} ++ ++static int stm32_clkevent_lp_remove(struct platform_device *pdev) ++{ ++ return -EBUSY; /* cannot unregister clockevent */ ++} ++ ++static const struct of_device_id stm32_clkevent_lp_of_match[] = { ++ { .compatible = "st,stm32-lptimer-timer", }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match); ++ ++static struct platform_driver stm32_clkevent_lp_driver = { ++ .probe = stm32_clkevent_lp_probe, ++ .remove = stm32_clkevent_lp_remove, ++ .driver = { ++ .name = "stm32-lptimer-timer", ++ .of_match_table = of_match_ptr(stm32_clkevent_lp_of_match), ++ }, ++}; ++module_platform_driver(stm32_clkevent_lp_driver); ++ ++MODULE_ALIAS("platform:stm32-lptimer-timer"); ++MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c -index bbc930a59..28b63645c 100644 +index bbc930a5962c6..28b63645c4118 100644 --- a/drivers/counter/stm32-lptimer-cnt.c +++ b/drivers/counter/stm32-lptimer-cnt.c @@ -347,7 +347,7 @@ static const struct iio_chan_spec stm32_lptim_cnt_channels = { @@ -1417,7 +1791,7 @@ index bbc930a59..28b63645c 100644 * @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) */ diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c -index 644ba18a7..6c51ff2cf 100644 +index 644ba18a72ad5..6c51ff2cf5758 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -8,10 +8,10 @@ @@ -1537,6 +1911,55 @@ index 644ba18a7..6c51ff2cf 100644 }, }; module_platform_driver(stm32_timer_cnt_driver); +diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h +index 4cdaf135829c6..ec7b1a93200fa 100644 +--- a/include/dt-bindings/clock/stm32mp1-clks.h ++++ b/include/dt-bindings/clock/stm32mp1-clks.h +@@ -179,6 +179,12 @@ + #define DAC12_K 168 + #define ETHPTP_K 169 + ++#define PCLK1 170 ++#define PCLK2 171 ++#define PCLK3 172 ++#define PCLK4 173 ++#define PCLK5 174 ++ + /* PLL */ + #define PLL1 176 + #define PLL2 177 +@@ -248,4 +254,31 @@ + + #define STM32MP1_LAST_CLK 232 + ++/* SCMI clock identifiers */ ++#define CK_SCMI0_HSE 0 ++#define CK_SCMI0_HSI 1 ++#define CK_SCMI0_CSI 2 ++#define CK_SCMI0_LSE 3 ++#define CK_SCMI0_LSI 4 ++#define CK_SCMI0_PLL2_Q 5 ++#define CK_SCMI0_PLL2_R 6 ++#define CK_SCMI0_MPU 7 ++#define CK_SCMI0_AXI 8 ++#define CK_SCMI0_BSEC 9 ++#define CK_SCMI0_CRYP1 10 ++#define CK_SCMI0_GPIOZ 11 ++#define CK_SCMI0_HASH1 12 ++#define CK_SCMI0_I2C4 13 ++#define CK_SCMI0_I2C6 14 ++#define CK_SCMI0_IWDG1 15 ++#define CK_SCMI0_RNG1 16 ++#define CK_SCMI0_RTC 17 ++#define CK_SCMI0_RTCAPB 18 ++#define CK_SCMI0_SPI6 19 ++#define CK_SCMI0_USART1 20 ++ ++#define CK_SCMI1_PLL3_Q 0 ++#define CK_SCMI1_PLL3_R 1 ++#define CK_SCMI1_MCU 2 ++ + #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0006-ARM-stm32mp1-r1-DMA.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0006-ARM-stm32mp1-r2-DMA.patch similarity index 95% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0006-ARM-stm32mp1-r1-DMA.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0006-ARM-stm32mp1-r2-DMA.patch index 3088f33..39d5330 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0006-ARM-stm32mp1-r1-DMA.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0006-ARM-stm32mp1-r2-DMA.patch @@ -1,18 +1,18 @@ -From ec7780453caf21817873becfdb8efb2a99cad0d5 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:40:57 +0200 -Subject: [PATCH 06/23] ARM-stm32mp1-r1-DMA +From ea9107d1f4dde411886c614bfa5f7403e28c4d0b Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:42 +0200 +Subject: [PATCH 06/22] ARM-stm32mp1-r2-rc8-DMA --- drivers/dma/dmaengine.c | 113 +++- - drivers/dma/stm32-dma.c | 1118 +++++++++++++++++++++++++++++++----- + drivers/dma/stm32-dma.c | 1119 +++++++++++++++++++++++++++++++----- drivers/dma/stm32-dmamux.c | 95 ++- drivers/dma/stm32-mdma.c | 273 +++++++-- include/linux/dmaengine.h | 18 + - 5 files changed, 1379 insertions(+), 238 deletions(-) + 5 files changed, 1380 insertions(+), 238 deletions(-) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c -index 4b604086b..3db3f8e36 100644 +index 4b604086b1b3a..3db3f8e36dea0 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -58,6 +58,65 @@ static DEFINE_IDA(dma_ida); @@ -172,7 +172,7 @@ index 4b604086b..3db3f8e36 100644 arch_initcall(dma_bus_init); diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index 5989b0893..9ebcaadf4 100644 +index 5989b08935211..e8bedbad125c3 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -14,11 +14,14 @@ @@ -272,7 +272,7 @@ index 5989b0893..9ebcaadf4 100644 }; static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) -@@ -260,6 +295,7 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan, +@@ -260,9 +295,11 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan, } static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, @@ -280,17 +280,21 @@ index 5989b0893..9ebcaadf4 100644 u32 threshold) { enum dma_slave_buswidth max_width; -@@ -273,6 +309,9 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, ++ u64 addr = buf_addr; + + if (threshold == STM32_DMA_FIFO_THRESHOLD_FULL) + max_width = DMA_SLAVE_BUSWIDTH_4_BYTES; +@@ -273,6 +310,9 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, max_width > DMA_SLAVE_BUSWIDTH_1_BYTE) max_width = max_width >> 1; -+ if (buf_addr % max_width) ++ if (do_div(addr, max_width)) + max_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + return max_width; } -@@ -281,6 +320,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, +@@ -281,6 +321,9 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, { u32 remaining; @@ -300,7 +304,7 @@ index 5989b0893..9ebcaadf4 100644 if (width != DMA_SLAVE_BUSWIDTH_UNDEFINED) { if (burst != 0) { /* -@@ -302,6 +344,10 @@ static bool stm32_dma_fifo_threshold_is_allowed(u32 burst, u32 threshold, +@@ -302,6 +345,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) { @@ -311,7 +315,7 @@ index 5989b0893..9ebcaadf4 100644 /* * Buffer or period length has to be aligned on FIFO depth. * Otherwise bytes may be stuck within FIFO at buffer or period -@@ -422,29 +468,19 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) +@@ -422,29 +469,19 @@ static void stm32_dma_irq_clear(struct stm32_dma_chan *chan, u32 flags) static int stm32_dma_disable_chan(struct stm32_dma_chan *chan) { struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); @@ -348,7 +352,7 @@ index 5989b0893..9ebcaadf4 100644 } return 0; -@@ -483,13 +519,22 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) +@@ -483,13 +520,22 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) static int stm32_dma_terminate_all(struct dma_chan *c) { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); @@ -374,7 +378,7 @@ index 5989b0893..9ebcaadf4 100644 chan->desc = NULL; } -@@ -500,9 +545,103 @@ static int stm32_dma_terminate_all(struct dma_chan *c) +@@ -500,9 +546,103 @@ static int stm32_dma_terminate_all(struct dma_chan *c) return 0; } @@ -478,7 +482,7 @@ index 5989b0893..9ebcaadf4 100644 vchan_synchronize(&chan->vchan); } -@@ -525,62 +664,213 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) +@@ -525,62 +665,213 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); } @@ -729,7 +733,7 @@ index 5989b0893..9ebcaadf4 100644 } static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) -@@ -612,23 +902,134 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) +@@ -612,23 +903,134 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) } } @@ -875,7 +879,7 @@ index 5989b0893..9ebcaadf4 100644 } static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) -@@ -643,26 +1044,37 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) +@@ -643,26 +1045,37 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); @@ -923,7 +927,7 @@ index 5989b0893..9ebcaadf4 100644 if (status) { stm32_dma_irq_clear(chan, status); dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); -@@ -680,31 +1092,37 @@ static void stm32_dma_issue_pending(struct dma_chan *c) +@@ -680,31 +1093,37 @@ static void stm32_dma_issue_pending(struct dma_chan *c) struct stm32_dma_chan *chan = to_stm32_dma_chan(c); unsigned long flags; @@ -965,7 +969,7 @@ index 5989b0893..9ebcaadf4 100644 switch (direction) { case DMA_MEM_TO_DEV: -@@ -716,7 +1134,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -716,7 +1135,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, @@ -974,7 +978,7 @@ index 5989b0893..9ebcaadf4 100644 dst_addr_width); dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); -@@ -724,7 +1142,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -724,7 +1143,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, return dst_burst_size; /* Set memory data size */ @@ -984,7 +988,7 @@ index 5989b0893..9ebcaadf4 100644 chan->mem_width = src_addr_width; src_bus_width = stm32_dma_get_width(chan, src_addr_width); if (src_bus_width < 0) -@@ -734,7 +1153,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -734,7 +1154,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, @@ -993,7 +997,7 @@ index 5989b0893..9ebcaadf4 100644 src_addr_width); src_burst_size = stm32_dma_get_burst(chan, src_best_burst); if (src_burst_size < 0) -@@ -748,7 +1167,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -748,7 +1168,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; @@ -1003,7 +1007,7 @@ index 5989b0893..9ebcaadf4 100644 /* Set peripheral address */ chan->chan_reg.dma_spar = chan->dma_sconfig.dst_addr; -@@ -764,7 +1184,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -764,7 +1185,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, @@ -1012,7 +1016,7 @@ index 5989b0893..9ebcaadf4 100644 src_addr_width); chan->mem_burst = src_best_burst; src_burst_size = stm32_dma_get_burst(chan, src_best_burst); -@@ -772,7 +1192,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -772,7 +1193,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, return src_burst_size; /* Set memory data size */ @@ -1022,7 +1026,7 @@ index 5989b0893..9ebcaadf4 100644 chan->mem_width = dst_addr_width; dst_bus_width = stm32_dma_get_width(chan, dst_addr_width); if (dst_bus_width < 0) -@@ -782,7 +1203,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -782,7 +1204,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, @@ -1031,7 +1035,7 @@ index 5989b0893..9ebcaadf4 100644 dst_addr_width); chan->mem_burst = dst_best_burst; dst_burst_size = stm32_dma_get_burst(chan, dst_best_burst); -@@ -797,7 +1218,8 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -797,7 +1219,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; @@ -1041,7 +1045,7 @@ index 5989b0893..9ebcaadf4 100644 /* Set peripheral address */ chan->chan_reg.dma_spar = chan->dma_sconfig.src_addr; -@@ -825,6 +1247,162 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) +@@ -825,6 +1248,162 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); } @@ -1204,7 +1208,7 @@ index 5989b0893..9ebcaadf4 100644 static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( struct dma_chan *c, struct scatterlist *sgl, u32 sg_len, enum dma_transfer_direction direction, -@@ -832,9 +1410,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -832,9 +1411,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); struct stm32_dma_desc *desc; @@ -1214,7 +1218,7 @@ index 5989b0893..9ebcaadf4 100644 int i, ret; if (!chan->config_init) { -@@ -857,48 +1432,140 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -857,48 +1433,140 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( else chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -1375,7 +1379,7 @@ index 5989b0893..9ebcaadf4 100644 int i, ret; if (!buf_len || !period_len) { -@@ -927,7 +1594,8 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -927,7 +1595,8 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( return NULL; } @@ -1385,7 +1389,7 @@ index 5989b0893..9ebcaadf4 100644 if (ret < 0) return NULL; -@@ -946,28 +1614,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -946,28 +1615,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; @@ -1447,7 +1451,7 @@ index 5989b0893..9ebcaadf4 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -@@ -1008,13 +1697,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1008,13 +1698,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( STM32_DMA_SCR_PINC | STM32_DMA_SCR_TCIE | STM32_DMA_SCR_TEIE; @@ -1463,7 +1467,7 @@ index 5989b0893..9ebcaadf4 100644 } desc->num_sgs = num_sgs; -@@ -1023,18 +1712,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1023,18 +1713,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } @@ -1482,7 +1486,7 @@ index 5989b0893..9ebcaadf4 100644 /** * stm32_dma_is_current_sg - check that expected sg_req is currently transferred * @chan: dma channel -@@ -1081,6 +1758,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1081,6 +1759,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; int i; @@ -1493,7 +1497,7 @@ index 5989b0893..9ebcaadf4 100644 /* * Calculate the residue means compute the descriptors * information: -@@ -1112,7 +1793,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1112,7 +1794,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, n_sg++; if (n_sg == chan->desc->num_sgs) n_sg = 0; @@ -1502,7 +1506,7 @@ index 5989b0893..9ebcaadf4 100644 } /* -@@ -1124,7 +1805,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1124,7 +1806,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, */ if (!chan->desc->cyclic || n_sg != 0) for (i = n_sg; i < desc->num_sgs; i++) @@ -1511,7 +1515,7 @@ index 5989b0893..9ebcaadf4 100644 if (!chan->mem_burst) return residue; -@@ -1142,11 +1823,23 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, +@@ -1142,11 +1824,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); @@ -1535,7 +1539,7 @@ index 5989b0893..9ebcaadf4 100644 status = dma_cookie_status(c, cookie, state); if (status == DMA_COMPLETE || !state) return status; -@@ -1203,25 +1896,51 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) +@@ -1203,25 +1897,51 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) pm_runtime_put(dmadev->ddev.dev); vchan_free_chan_resources(to_virt_chan(c)); @@ -1592,7 +1596,7 @@ index 5989b0893..9ebcaadf4 100644 } static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, -@@ -1259,6 +1978,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1259,6 +1979,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, stm32_dma_set_config(chan, &cfg); @@ -1602,7 +1606,7 @@ index 5989b0893..9ebcaadf4 100644 return c; } -@@ -1271,10 +1993,13 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); +@@ -1271,10 +1994,13 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); static int stm32_dma_probe(struct platform_device *pdev) { struct stm32_dma_chan *chan; @@ -1616,7 +1620,7 @@ index 5989b0893..9ebcaadf4 100644 int i, ret; match = of_match_device(stm32_dma_of_match, &pdev->dev); -@@ -1296,8 +2021,10 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1296,8 +2022,10 @@ static int stm32_dma_probe(struct platform_device *pdev) dmadev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dmadev->clk)) { @@ -1629,7 +1633,7 @@ index 5989b0893..9ebcaadf4 100644 } ret = clk_prepare_enable(dmadev->clk); -@@ -1309,13 +2036,26 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1309,13 +2037,26 @@ static int stm32_dma_probe(struct platform_device *pdev) dmadev->mem2mem = of_property_read_bool(pdev->dev.of_node, "st,mem2mem"); @@ -1660,7 +1664,7 @@ index 5989b0893..9ebcaadf4 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); -@@ -1336,7 +2076,9 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1336,7 +2077,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; @@ -1670,7 +1674,7 @@ index 5989b0893..9ebcaadf4 100644 dd->dev = &pdev->dev; INIT_LIST_HEAD(&dd->channels); -@@ -1351,11 +2093,27 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1351,11 +2094,27 @@ static int stm32_dma_probe(struct platform_device *pdev) chan->id = i; chan->vchan.desc_free = stm32_dma_desc_free; vchan_init(&chan->vchan, dd); @@ -1699,7 +1703,7 @@ index 5989b0893..9ebcaadf4 100644 for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; -@@ -1396,7 +2154,11 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1396,7 +2155,11 @@ static int stm32_dma_probe(struct platform_device *pdev) err_unregister: dma_async_device_unregister(dd); @@ -1712,7 +1716,7 @@ index 5989b0893..9ebcaadf4 100644 clk_disable_unprepare(dmadev->clk); return ret; -@@ -1427,7 +2189,44 @@ static int stm32_dma_runtime_resume(struct device *dev) +@@ -1427,7 +2190,44 @@ static int stm32_dma_runtime_resume(struct device *dev) } #endif @@ -1757,7 +1761,7 @@ index 5989b0893..9ebcaadf4 100644 SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, stm32_dma_runtime_resume, NULL) }; -@@ -1438,10 +2237,11 @@ static struct platform_driver stm32_dma_driver = { +@@ -1438,10 +2238,11 @@ static struct platform_driver stm32_dma_driver = { .of_match_table = stm32_dma_of_match, .pm = &stm32_dma_pm_ops, }, @@ -1772,7 +1776,7 @@ index 5989b0893..9ebcaadf4 100644 -subsys_initcall(stm32_dma_init); +device_initcall(stm32_dma_init); diff --git a/drivers/dma/stm32-dmamux.c b/drivers/dma/stm32-dmamux.c -index 3c89bd39e..bbfa14100 100644 +index 3c89bd39e0968..bbfa141004cdf 100644 --- a/drivers/dma/stm32-dmamux.c +++ b/drivers/dma/stm32-dmamux.c @@ -35,12 +35,14 @@ struct stm32_dmamux { @@ -1924,7 +1928,7 @@ index 3c89bd39e..bbfa14100 100644 stm32_dmamux_runtime_resume, NULL) }; diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c -index 5838311cf..856421335 100644 +index 5838311cf9900..85642133554eb 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -199,7 +199,9 @@ @@ -2498,7 +2502,7 @@ index 5838311cf..856421335 100644 stm32_mdma_runtime_resume, NULL) }; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h -index 801356275..07f6e1136 100644 +index 8013562751a50..07f6e1136dbf8 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -258,6 +258,9 @@ struct dma_chan { diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0007-ARM-stm32mp1-r2-DRM.patch similarity index 79% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0007-ARM-stm32mp1-r2-DRM.patch index b3fb45f..d36e404 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0007-ARM-stm32mp1-r1-DRM.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0007-ARM-stm32mp1-r2-DRM.patch @@ -1,11 +1,15 @@ -From 29a46aadaab8285eafc89b86fb6db1b092979589 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:41:19 +0200 -Subject: [PATCH 07/23] ARM-stm32mp1-r1-DRM +From 8cfec718ba7f8e1e8e004d7033b4f48b901b2779 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:43 +0200 +Subject: [PATCH 07/22] ARM-stm32mp1-r2-rc8-DRM --- + .../display/panel/orisetech,otm8009a.txt | 23 -- + .../display/panel/orisetech,otm8009a.yaml | 53 ++++ + .../display/panel/raydium,rm68200.txt | 25 -- + .../display/panel/raydium,rm68200.yaml | 52 ++++ drivers/gpu/drm/bridge/sii902x.c | 145 +++++++++- - drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 160 +++++++++-- + drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 212 ++++++++++---- drivers/gpu/drm/drm_modes.c | 19 +- .../gpu/drm/panel/panel-orisetech-otm8009a.c | 20 +- drivers/gpu/drm/panel/panel-raydium-rm68200.c | 14 +- @@ -15,10 +19,191 @@ Subject: [PATCH 07/23] ARM-stm32mp1-r1-DRM drivers/input/touchscreen/edt-ft5x06.c | 18 +- drivers/input/touchscreen/goodix.c | 16 ++ include/uapi/drm/drm_mode.h | 6 + - 11 files changed, 512 insertions(+), 166 deletions(-) + 15 files changed, 648 insertions(+), 235 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt + create mode 100644 Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml + delete mode 100644 Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt + create mode 100644 Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml +diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt +deleted file mode 100644 +index 203b03eefb688..0000000000000 +--- a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt ++++ /dev/null +@@ -1,23 +0,0 @@ +-Orise Tech OTM8009A 3.97" 480x800 TFT LCD panel (MIPI-DSI video mode) +- +-The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using +-a MIPI-DSI video interface. Its backlight is managed through the DSI link. +- +-Required properties: +- - compatible: "orisetech,otm8009a" +- - reg: the virtual channel number of a DSI peripheral +- +-Optional properties: +- - reset-gpios: a GPIO spec for the reset pin (active low). +- - power-supply: phandle of the regulator that provides the supply voltage. +- +-Example: +-&dsi { +- ... +- panel@0 { +- compatible = "orisetech,otm8009a"; +- reg = <0>; +- reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; +- power-supply = <&v1v8>; +- }; +-}; +diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml +new file mode 100644 +index 0000000000000..6eda24035c9eb +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml +@@ -0,0 +1,53 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/orisetech,otm8009a.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Orise Tech OTM8009A 3.97" 480x800 panel ++ ++maintainers: ++ - Yannick Fertre ++ ++description: ++ The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using ++ a MIPI-DSI video interface. Its backlight is managed through the DSI link. ++ ++properties: ++ compatible: ++ const: orisetech,otm8009a ++ ++ power-supply: true ++ reset-gpios: true ++ backlight: true ++ port: true ++ reg: true ++ ++required: ++ - compatible ++ - reg ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ display1: display { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ panel { ++ compatible = "orisetech,otm8009a"; ++ reg = <0>; ++ reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; ++ power-supply = <&v1v8>; ++ ++ port { ++ panel_in_dsi: endpoint { ++ remote-endpoint = <&controller_out_dsi>; ++ }; ++ }; ++ }; ++ }; ++ ++... +diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt +deleted file mode 100644 +index cbb79ef3bfc98..0000000000000 +--- a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt ++++ /dev/null +@@ -1,25 +0,0 @@ +-Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel +- +-The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD +-panel connected using a MIPI-DSI video interface. +- +-Required properties: +- - compatible: "raydium,rm68200" +- - reg: the virtual channel number of a DSI peripheral +- +-Optional properties: +- - reset-gpios: a GPIO spec for the reset pin (active low). +- - power-supply: phandle of the regulator that provides the supply voltage. +- - backlight: phandle of the backlight device attached to the panel. +- +-Example: +-&dsi { +- ... +- panel@0 { +- compatible = "raydium,rm68200"; +- reg = <0>; +- reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; +- power-supply = <&v1v8>; +- backlight = <&pwm_backlight>; +- }; +-}; +diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml +new file mode 100644 +index 0000000000000..2bbd4a0cb5da8 +--- /dev/null ++++ b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml +@@ -0,0 +1,52 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/display/panel/raydium,rm68200.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Raydium RM68200 5.5" 720x1280 panel ++ ++maintainers: ++ - Yannick Fertre ++ ++description: ++ The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD ++ panel connected using a MIPI-DSI video interface. ++ ++properties: ++ compatible: ++ const: raydium,rm68200 ++ ++ power-supply: true ++ reset-gpios: true ++ backlight: true ++ port: true ++ reg: true ++ ++required: ++ - compatible ++ - reg ++ - port ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ display0: display { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ panel { ++ compatible = "raydium,rm68200"; ++ reg = <0>; ++ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; ++ power-supply = <&v1v8>; ++ port { ++ panel_in_dsi: endpoint { ++ remote-endpoint = <&controller_out_dsi>; ++ }; ++ }; ++ }; ++ }; ++ ++... diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c -index 38f75ac58..92299884f 100644 +index 38f75ac580df4..92299884f6cb9 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -16,8 +16,10 @@ @@ -291,7 +476,7 @@ index 38f75ac58..92299884f 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 675442bfc..1389bbfa0 100644 +index 675442bfc1bd7..34a9569e28f6d 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -90,6 +90,7 @@ @@ -323,41 +508,51 @@ index 675442bfc..1389bbfa0 100644 #define DSI_INT_MSK0 0xc4 #define DSI_INT_MSK1 0xc8 -@@ -297,7 +312,13 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, +@@ -295,9 +310,7 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, + { + struct dw_mipi_dsi *dsi = host_to_dsi(host); const struct dw_mipi_dsi_plat_data *pdata = dsi->plat_data; - struct drm_bridge *bridge; - struct drm_panel *panel; +- struct drm_bridge *bridge; +- struct drm_panel *panel; - int ret; -+ int i, nb_endpoints; + int ret = -ENODEV; -+ -+ /* Get number of endpoints */ -+ nb_endpoints = of_graph_get_endpoint_count(host->dev->of_node); -+ if (!nb_endpoints) -+ return -ENODEV; if (device->lanes > dsi->plat_data->max_data_lanes) { dev_err(dsi->dev, "the number of data lanes(%u) is too many\n", -@@ -310,8 +331,16 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, +@@ -310,21 +323,6 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host, dsi->format = device->format; dsi->mode_flags = device->mode_flags; - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, - &panel, &bridge); -+ for (i = 1; i < nb_endpoints; i++) { -+ ret = drm_of_find_panel_or_bridge(host->dev->of_node, i, 0, -+ &panel, &bridge); -+ if (!ret) -+ break; -+ else if (ret == -EPROBE_DEFER) -+ return ret; -+ } -+ -+ /* check if an error is returned >> no panel or bridge detected */ - if (ret) - return ret; +- if (ret) +- return ret; +- +- if (panel) { +- bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI); +- if (IS_ERR(bridge)) +- return PTR_ERR(bridge); +- } +- +- dsi->panel_bridge = bridge; +- +- drm_bridge_add(&dsi->bridge); +- + if (pdata->host_ops && pdata->host_ops->attach) { + ret = pdata->host_ops->attach(pdata->priv_data, device); + if (ret < 0) +@@ -347,10 +345,6 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, + return ret; + } -@@ -360,13 +389,32 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, +- drm_of_panel_bridge_remove(host->dev->of_node, 1, 0); +- +- drm_bridge_remove(&dsi->bridge); +- + return 0; + } + +@@ -360,13 +354,32 @@ static void dw_mipi_message_config(struct dw_mipi_dsi *dsi, bool lpm = msg->flags & MIPI_DSI_MSG_USE_LPM; u32 val = 0; @@ -391,7 +586,7 @@ index 675442bfc..1389bbfa0 100644 } static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) -@@ -396,6 +444,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) +@@ -396,6 +409,42 @@ static int dw_mipi_dsi_gen_pkt_hdr_write(struct dw_mipi_dsi *dsi, u32 hdr_val) return 0; } @@ -434,7 +629,7 @@ index 675442bfc..1389bbfa0 100644 static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, const struct mipi_dsi_packet *packet) { -@@ -425,6 +509,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, +@@ -425,6 +474,12 @@ static int dw_mipi_dsi_write(struct dw_mipi_dsi *dsi, "failed to get available write payload FIFO\n"); return ret; } @@ -447,7 +642,7 @@ index 675442bfc..1389bbfa0 100644 } word = 0; -@@ -458,6 +548,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, +@@ -458,6 +513,12 @@ static int dw_mipi_dsi_read(struct dw_mipi_dsi *dsi, return ret; } @@ -460,7 +655,7 @@ index 675442bfc..1389bbfa0 100644 val = dsi_read(dsi, DSI_GEN_PLD_DATA); for (j = 0; j < 4 && j + i < len; j++) buf[i + j] = val >> (8 * j); -@@ -472,6 +568,7 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, +@@ -472,6 +533,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; @@ -468,7 +663,7 @@ index 675442bfc..1389bbfa0 100644 ret = mipi_dsi_create_packet(&packet, msg); if (ret) { -@@ -483,24 +580,32 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, +@@ -483,24 +545,32 @@ static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, if (dsi->slave) dw_mipi_message_config(dsi->slave, msg); @@ -515,7 +710,7 @@ index 675442bfc..1389bbfa0 100644 return nb_bytes; } -@@ -541,16 +646,22 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) +@@ -541,16 +611,22 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) static void dw_mipi_dsi_set_mode(struct dw_mipi_dsi *dsi, unsigned long mode_flags) { @@ -539,7 +734,7 @@ index 675442bfc..1389bbfa0 100644 dsi_write(dsi, DSI_PWR_UP, POWERUP); } -@@ -611,14 +722,6 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, +@@ -611,14 +687,6 @@ static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, dsi_write(dsi, DSI_DPI_VCID, DPI_VCID(dsi->channel)); dsi_write(dsi, DSI_DPI_COLOR_CODING, color); dsi_write(dsi, DSI_DPI_CFG_POL, val); @@ -554,7 +749,7 @@ index 675442bfc..1389bbfa0 100644 } static void dw_mipi_dsi_packet_handler_config(struct dw_mipi_dsi *dsi) -@@ -814,7 +917,8 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) +@@ -814,7 +882,8 @@ static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) * This needs to be fixed in the drm_bridge framework and the API * needs to be updated to manage our own call chains... */ @@ -564,8 +759,83 @@ index 675442bfc..1389bbfa0 100644 if (dsi->slave) { dw_mipi_dsi_disable(dsi->slave); +@@ -982,6 +1051,9 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, + struct reset_control *apb_rst; + struct dw_mipi_dsi *dsi; + struct resource *res; ++ struct drm_bridge *bridge; ++ struct drm_panel *panel; ++ int i, nb_endpoints; + int ret; + + dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL); +@@ -1052,8 +1124,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, + ret = mipi_dsi_host_register(&dsi->dsi_host); + if (ret) { + dev_err(dev, "Failed to register MIPI host: %d\n", ret); +- dw_mipi_dsi_debugfs_remove(dsi); +- return ERR_PTR(ret); ++ goto err_pmr_enable; + } + + dsi->bridge.driver_private = dsi; +@@ -1062,11 +1133,54 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, + dsi->bridge.of_node = pdev->dev.of_node; + #endif + ++ /* Get number of endpoints */ ++ nb_endpoints = of_graph_get_endpoint_count(pdev->dev.of_node); ++ if (!nb_endpoints) { ++ ret = -ENODEV; ++ goto err_host_reg; ++ } ++ ++ for (i = 1; i < nb_endpoints; i++) { ++ ret = drm_of_find_panel_or_bridge(pdev->dev.of_node, i, 0, ++ &panel, &bridge); ++ if (!ret) ++ break; ++ else if (ret == -EPROBE_DEFER) ++ goto err_host_reg; ++ } ++ ++ /* check if an error is returned >> no panel or bridge detected */ ++ if (ret) ++ goto err_host_reg; ++ ++ if (panel) { ++ bridge = drm_panel_bridge_add(panel, DRM_MODE_CONNECTOR_DSI); ++ if (IS_ERR(bridge)) { ++ ret = PTR_ERR(bridge); ++ goto err_host_reg; ++ } ++ } ++ ++ dsi->panel_bridge = bridge; ++ ++ drm_bridge_add(&dsi->bridge); ++ + return dsi; ++ ++err_host_reg: ++ mipi_dsi_host_unregister(&dsi->dsi_host); ++ ++err_pmr_enable: ++ pm_runtime_disable(dev); ++ dw_mipi_dsi_debugfs_remove(dsi); ++ ++ return ERR_PTR(ret); + } + + static void __dw_mipi_dsi_remove(struct dw_mipi_dsi *dsi) + { ++ drm_bridge_remove(&dsi->bridge); ++ drm_panel_bridge_remove(dsi->panel_bridge); + mipi_dsi_host_unregister(&dsi->dsi_host); + + pm_runtime_disable(dsi->dev); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c -index 3fd35e6b9..80de2fb7e 100644 +index 3fd35e6b9d535..80de2fb7ed817 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -127,7 +127,7 @@ EXPORT_SYMBOL(drm_mode_probed_add); @@ -609,7 +879,7 @@ index 3fd35e6b9..80de2fb7e 100644 EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -index c7b48df88..2fdf9d183 100644 +index c7b48df8869a1..2fdf9d183d239 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -101,20 +101,6 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, @@ -661,7 +931,7 @@ index c7b48df88..2fdf9d183 100644 drm_panel_init(&ctx->panel); ctx->panel.dev = dev; diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c -index ba889625a..b20e26666 100644 +index ba889625ad435..b20e26666c7cb 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -84,15 +84,15 @@ struct rm68200 { @@ -696,7 +966,7 @@ index ba889625a..b20e26666 100644 drm_panel_init(&ctx->panel); ctx->panel.dev = dev; diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -index a03a642c1..d1689758f 100644 +index a03a642c147cc..d1689758fea0d 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -260,8 +260,11 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, @@ -724,7 +994,7 @@ index a03a642c1..d1689758f 100644 } diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c -index 3ab4fbf8e..1f7836be2 100644 +index 3ab4fbf8eb0d1..1f7836be2e6a9 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -15,6 +15,7 @@ @@ -1176,7 +1446,7 @@ index 3ab4fbf8e..1f7836be2 100644 pm_runtime_disable(ddev->dev); diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h -index a1ad0ae3b..310e87f06 100644 +index a1ad0ae3b0068..310e87f0667c2 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -19,6 +19,7 @@ struct ltdc_caps { @@ -1188,7 +1458,7 @@ index a1ad0ae3b..310e87f06 100644 #define LTDC_MAX_LAYER 4 diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c -index 240e8de24..66f790de8 100644 +index b41b97c962edc..fd21d31b64644 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -28,6 +28,8 @@ @@ -1200,7 +1470,7 @@ index 240e8de24..66f790de8 100644 #define WORK_REGISTER_THRESHOLD 0x00 #define WORK_REGISTER_REPORT_RATE 0x08 -@@ -1042,6 +1044,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, +@@ -1048,6 +1050,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; u8 buf[2] = { 0xfc, 0x00 }; @@ -1209,7 +1479,7 @@ index 240e8de24..66f790de8 100644 struct input_dev *input; unsigned long irq_flags; int error; -@@ -1107,7 +1111,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, +@@ -1113,7 +1117,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, error = edt_ft5x06_ts_identify(client, tsdata, fw_version); if (error) { @@ -1218,7 +1488,7 @@ index 240e8de24..66f790de8 100644 return error; } -@@ -1176,6 +1180,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, +@@ -1182,6 +1186,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, if (error) return error; @@ -1238,7 +1508,7 @@ index 240e8de24..66f790de8 100644 device_init_wakeup(&client->dev, 1); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c -index 0403102e8..8816f2cd4 100644 +index 37b35ab97beb2..ed63c343ba423 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -21,6 +21,7 @@ @@ -1249,7 +1519,7 @@ index 0403102e8..8816f2cd4 100644 #include #include #include -@@ -844,6 +845,8 @@ static int goodix_ts_probe(struct i2c_client *client, +@@ -866,6 +867,8 @@ static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct goodix_ts_data *ts; @@ -1258,7 +1528,7 @@ index 0403102e8..8816f2cd4 100644 int error; dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); -@@ -936,6 +939,17 @@ static int goodix_ts_probe(struct i2c_client *client, +@@ -958,6 +961,17 @@ static int goodix_ts_probe(struct i2c_client *client, return error; } @@ -1276,7 +1546,7 @@ index 0403102e8..8816f2cd4 100644 return 0; } -@@ -990,6 +1004,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) +@@ -1012,6 +1026,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) * sooner, delay 58ms here. */ msleep(58); @@ -1284,7 +1554,7 @@ index 0403102e8..8816f2cd4 100644 return 0; } -@@ -1054,6 +1069,7 @@ static const struct of_device_id goodix_of_match[] = { +@@ -1076,6 +1091,7 @@ static const struct of_device_id goodix_of_match[] = { { .compatible = "goodix,gt9271" }, { .compatible = "goodix,gt928" }, { .compatible = "goodix,gt967" }, @@ -1293,7 +1563,7 @@ index 0403102e8..8816f2cd4 100644 }; MODULE_DEVICE_TABLE(of, goodix_of_match); diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h -index 735c8cfda..28a9ea94e 100644 +index 735c8cfdaaa14..28a9ea94ea2ed 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -97,6 +97,12 @@ extern "C" { diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch similarity index 68% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch index 584ccd6..1f21fa7 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch @@ -1,16 +1,17 @@ -From 9e9f45cd3d4887d9af58da15e627443838da1645 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:41:46 +0200 -Subject: [PATCH 08/23] ARM-stm32mp1-r1-HWSPINLOCK +From 10e0333454dbd6ccecb67ad303eae3aef707ce0b Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:43 +0200 +Subject: [PATCH 08/22] ARM-stm32mp1-r2-rc8-HWSPINLOCK --- Documentation/hwspinlock.txt | 10 ++- drivers/hwspinlock/hwspinlock_core.c | 82 ++++++++++++++++++------ drivers/hwspinlock/hwspinlock_internal.h | 2 + - 3 files changed, 73 insertions(+), 21 deletions(-) + drivers/hwspinlock/stm32_hwspinlock.c | 62 +++++++++++------- + 4 files changed, 112 insertions(+), 44 deletions(-) diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt -index 6f03713b7..605bd2dc8 100644 +index 6f03713b70039..605bd2dc8a03e 100644 --- a/Documentation/hwspinlock.txt +++ b/Documentation/hwspinlock.txt @@ -54,9 +54,11 @@ Should be called from a process context (might sleep). @@ -43,7 +44,7 @@ index 6f03713b7..605bd2dc8 100644 }; diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c -index 8862445aa..ac76631c7 100644 +index 8862445aa8580..ac76631c7059b 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -29,6 +29,8 @@ @@ -231,7 +232,7 @@ index 8862445aa..ac76631c7 100644 return ret; } diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h -index 9eb6bd020..c808e116c 100644 +index 9eb6bd020dc70..c808e116ce3fe 100644 --- a/drivers/hwspinlock/hwspinlock_internal.h +++ b/drivers/hwspinlock/hwspinlock_internal.h @@ -35,11 +35,13 @@ struct hwspinlock_ops { @@ -248,6 +249,113 @@ index 9eb6bd020..c808e116c 100644 void *priv; }; +diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c +index c8eacf4f9692b..c7c8c4cc2c5fa 100644 +--- a/drivers/hwspinlock/stm32_hwspinlock.c ++++ b/drivers/hwspinlock/stm32_hwspinlock.c +@@ -54,8 +54,23 @@ static const struct hwspinlock_ops stm32_hwspinlock_ops = { + .relax = stm32_hwspinlock_relax, + }; + ++static void stm32_hwspinlock_disable_clk(void *data) ++{ ++ struct platform_device *pdev = data; ++ struct stm32_hwspinlock *hw = platform_get_drvdata(pdev); ++ struct device *dev = &pdev->dev; ++ ++ pm_runtime_get_sync(dev); ++ pm_runtime_disable(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_put_noidle(dev); ++ ++ clk_disable_unprepare(hw->clk); ++} ++ + static int stm32_hwspinlock_probe(struct platform_device *pdev) + { ++ struct device *dev = &pdev->dev; + struct stm32_hwspinlock *hw; + void __iomem *io_base; + struct resource *res; +@@ -63,46 +78,48 @@ static int stm32_hwspinlock_probe(struct platform_device *pdev) + int i, ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- io_base = devm_ioremap_resource(&pdev->dev, res); ++ io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + array_size = STM32_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); +- hw = devm_kzalloc(&pdev->dev, sizeof(*hw) + array_size, GFP_KERNEL); ++ hw = devm_kzalloc(dev, sizeof(*hw) + array_size, GFP_KERNEL); + if (!hw) + return -ENOMEM; + +- hw->clk = devm_clk_get(&pdev->dev, "hsem"); ++ hw->clk = devm_clk_get(dev, "hsem"); + if (IS_ERR(hw->clk)) + return PTR_ERR(hw->clk); + +- for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++) +- hw->bank.lock[i].priv = io_base + i * sizeof(u32); ++ ret = clk_prepare_enable(hw->clk); ++ if (ret) { ++ dev_err(dev, "Failed to prepare_enable clock\n"); ++ return ret; ++ } ++ ++ pm_runtime_get_noresume(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_put(dev); + + platform_set_drvdata(pdev, hw); +- pm_runtime_enable(&pdev->dev); + +- ret = hwspin_lock_register(&hw->bank, &pdev->dev, &stm32_hwspinlock_ops, +- 0, STM32_MUTEX_NUM_LOCKS); ++ ret = devm_add_action_or_reset(dev, stm32_hwspinlock_disable_clk, pdev); ++ if (ret) { ++ dev_err(dev, "Failed to register action\n"); ++ return ret; ++ } + +- if (ret) +- pm_runtime_disable(&pdev->dev); +- +- return ret; +-} ++ for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++) ++ hw->bank.lock[i].priv = io_base + i * sizeof(u32); + +-static int stm32_hwspinlock_remove(struct platform_device *pdev) +-{ +- struct stm32_hwspinlock *hw = platform_get_drvdata(pdev); +- int ret; ++ ret = devm_hwspin_lock_register(dev, &hw->bank, &stm32_hwspinlock_ops, ++ 0, STM32_MUTEX_NUM_LOCKS); + +- ret = hwspin_lock_unregister(&hw->bank); + if (ret) +- dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); +- +- pm_runtime_disable(&pdev->dev); ++ dev_err(dev, "Failed to register hwspinlock\n"); + +- return 0; ++ return ret; + } + + static int __maybe_unused stm32_hwspinlock_runtime_suspend(struct device *dev) +@@ -137,7 +154,6 @@ MODULE_DEVICE_TABLE(of, stm32_hwpinlock_ids); + + static struct platform_driver stm32_hwspinlock_driver = { + .probe = stm32_hwspinlock_probe, +- .remove = stm32_hwspinlock_remove, + .driver = { + .name = "stm32_hwspinlock", + .of_match_table = stm32_hwpinlock_ids, -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0009-ARM-stm32mp1-r2-I2C-IIO-IRQCHIP.patch similarity index 86% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0009-ARM-stm32mp1-r2-I2C-IIO-IRQCHIP.patch index b221098..471a787 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0009-ARM-stm32mp1-r2-I2C-IIO-IRQCHIP.patch @@ -1,26 +1,26 @@ -From 60d0b197857cc6e26cc8521986b4a85d912fd201 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:42:27 +0200 -Subject: [PATCH 09/23] ARM-stm32mp1-r1-I2C-IIO-IRQCHIP +From 7d5ade3a72ec6ff24276380a84c15c2b048a5c16 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:44 +0200 +Subject: [PATCH 09/22] ARM-stm32mp1-r2-rc8-I2C-IIO-IRQCHIP --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-stm32.c | 19 +- drivers/i2c/busses/i2c-stm32f4.c | 4 +- - drivers/i2c/busses/i2c-stm32f7.c | 644 ++++++++++++++++++---- + drivers/i2c/busses/i2c-stm32f7.c | 623 ++++++++++++++++++---- drivers/iio/adc/sd_adc_modulator.c | 84 ++- - drivers/iio/adc/stm32-adc-core.c | 84 +-- + drivers/iio/adc/stm32-adc-core.c | 97 ++-- drivers/iio/adc/stm32-adc-core.h | 9 + - drivers/iio/adc/stm32-adc.c | 129 ++++- - drivers/iio/adc/stm32-dfsdm-adc.c | 157 +++++- - drivers/iio/dac/stm32-dac-core.c | 153 +++-- + drivers/iio/adc/stm32-adc.c | 146 +++-- + drivers/iio/adc/stm32-dfsdm-adc.c | 136 ++++- + drivers/iio/dac/stm32-dac-core.c | 153 ++++-- drivers/iio/dac/stm32-dac.c | 94 +++- drivers/iio/trigger/stm32-timer-trigger.c | 164 +++++- - drivers/irqchip/irq-stm32-exti.c | 255 ++++++--- - 13 files changed, 1464 insertions(+), 333 deletions(-) + drivers/irqchip/irq-stm32-exti.c | 274 +++++++--- + 13 files changed, 1461 insertions(+), 343 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index 146ce40d8..19f05c44f 100644 +index 146ce40d8e0aa..19f05c44f6f91 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1008,6 +1008,7 @@ config I2C_STM32F7 @@ -32,7 +32,7 @@ index 146ce40d8..19f05c44f 100644 Enable this option to add support for STM32 I2C controller embedded in STM32F7 SoCs. diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c -index 1da347e6a..448c0df71 100644 +index 1da347e6a3586..448c0df71eab9 100644 --- a/drivers/i2c/busses/i2c-stm32.c +++ b/drivers/i2c/busses/i2c-stm32.c @@ -25,9 +25,11 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, @@ -92,7 +92,7 @@ index 1da347e6a..448c0df71 100644 return ERR_PTR(ret); } diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c -index ba600d77a..1b8cad506 100644 +index ba600d77a3f88..1b8cad506ad75 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -797,8 +797,10 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) @@ -108,7 +108,7 @@ index ba600d77a..1b8cad506 100644 } reset_control_assert(rst); diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index b2634afe0..8a82e331e 100644 +index b2634afe066d3..f59c45a4f61b2 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -18,6 +18,7 @@ @@ -1090,7 +1090,7 @@ index b2634afe0..8a82e331e 100644 pm_runtime_put_noidle(i2c_dev->dev); pm_runtime_disable(i2c_dev->dev); pm_runtime_set_suspended(i2c_dev->dev); -@@ -2022,13 +2369,14 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) +@@ -2022,23 +2369,60 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) i2c_dev->dma = NULL; } @@ -1103,55 +1103,21 @@ index b2634afe0..8a82e331e 100644 -#ifdef CONFIG_PM -static int stm32f7_i2c_runtime_suspend(struct device *dev) -+static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) - { - struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); - -@@ -2038,7 +2386,7 @@ static int stm32f7_i2c_runtime_suspend(struct device *dev) - return 0; - } - --static int stm32f7_i2c_runtime_resume(struct device *dev) -+static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) - { - struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); - int ret; -@@ -2053,15 +2401,125 @@ static int stm32f7_i2c_runtime_resume(struct device *dev) - - return 0; - } --#endif -+ -+static int __maybe_unused ++static void __maybe_unused +stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) +{ -+ int ret; -+ -+ ret = pm_runtime_get_sync(i2c_dev->dev); -+ if (ret < 0) -+ return ret; -+ + i2c_dev->regs.cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); + i2c_dev->regs.cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); + i2c_dev->regs.oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); + i2c_dev->regs.oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); + i2c_dev->regs.tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR); + stm32f7_i2c_write_fm_plus_bits(i2c_dev, 0); -+ -+ pm_runtime_put_sync(i2c_dev->dev); -+ -+ return ret; +} + -+static int __maybe_unused ++static void __maybe_unused +stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) +{ + u32 cr1; -+ int ret; -+ -+ ret = pm_runtime_get_sync(i2c_dev->dev); -+ if (ret < 0) -+ return ret; + + cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); + if (cr1 & STM32F7_I2C_CR1_PE) @@ -1168,10 +1134,33 @@ index b2634afe0..8a82e331e 100644 + writel_relaxed(i2c_dev->regs.oar1, i2c_dev->base + STM32F7_I2C_OAR1); + writel_relaxed(i2c_dev->regs.oar2, i2c_dev->base + STM32F7_I2C_OAR2); + stm32f7_i2c_write_fm_plus_bits(i2c_dev, 1); ++} + -+ pm_runtime_put_sync(i2c_dev->dev); + -+ return ret; ++static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) + { + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); + ++ stm32f7_i2c_regs_backup(i2c_dev); ++ + if (!stm32f7_i2c_is_slave_registered(i2c_dev)) + clk_disable_unprepare(i2c_dev->clk); + + return 0; + } + +-static int stm32f7_i2c_runtime_resume(struct device *dev) ++static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) + { + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); + int ret; +@@ -2051,17 +2435,70 @@ static int stm32f7_i2c_runtime_resume(struct device *dev) + } + } + ++ stm32f7_i2c_regs_restore(i2c_dev); ++ ++ return 0; +} + +static void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev, @@ -1196,17 +1185,13 @@ index b2634afe0..8a82e331e 100644 +static int __maybe_unused stm32f7_i2c_suspend(struct device *dev) +{ + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); -+ int ret; + + i2c_mark_adapter_suspended(&i2c_dev->adap); -+ ret = stm32f7_i2c_regs_backup(i2c_dev); -+ if (ret < 0) -+ return ret; + -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { ++ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) + pinctrl_pm_select_sleep_state(dev); -+ pm_runtime_force_suspend(dev); -+ } ++ ++ pm_runtime_force_suspend(dev); + + return 0; +} @@ -1216,20 +1201,18 @@ index b2634afe0..8a82e331e 100644 + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); + int ret; + -+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { -+ ret = pm_runtime_force_resume(dev); -+ if (ret < 0) -+ return ret; -+ pinctrl_pm_select_default_state(dev); -+ } -+ -+ ret = stm32f7_i2c_regs_restore(i2c_dev); ++ ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; ++ ++ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) ++ pinctrl_pm_select_default_state(dev); ++ + i2c_mark_adapter_resumed(&i2c_dev->adap); + -+ return 0; -+} + return 0; + } +-#endif static const struct dev_pm_ops stm32f7_i2c_pm_ops = { SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend, @@ -1244,7 +1227,7 @@ index b2634afe0..8a82e331e 100644 }; MODULE_DEVICE_TABLE(of, stm32f7_i2c_match); diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c -index 560d8c7d9..c0a6e89cd 100644 +index 560d8c7d9d862..c0a6e89cd77a3 100644 --- a/drivers/iio/adc/sd_adc_modulator.c +++ b/drivers/iio/adc/sd_adc_modulator.c @@ -10,8 +10,7 @@ @@ -1367,10 +1350,10 @@ index 560d8c7d9..c0a6e89cd 100644 static struct platform_driver iio_sd_mod_adc = { diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index 93a096a91..0e2068ec0 100644 +index 74f3a2be17a64..614d774438b98 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c -@@ -38,12 +38,12 @@ +@@ -38,21 +38,19 @@ #define HAS_ANASWVDD BIT(1) /** @@ -1381,13 +1364,23 @@ index 93a096a91..0e2068ec0 100644 - * @eoc1: adc1 end of conversion flag in @csr - * @eoc2: adc2 end of conversion flag in @csr - * @eoc3: adc3 end of conversion flag in @csr -+ * @eoc1_msk: adc1 end of conversion flag in @csr -+ * @eoc2_msk: adc2 end of conversion flag in @csr -+ * @eoc3_msk: adc3 end of conversion flag in @csr ++ * @eoc_msk: array of eoc (end of conversion flag) masks in csr for adc1..n ++ * @ovr_msk: array of ovr (overrun flag) masks in csr for adc1..n * @ier: interrupt enable register offset for each adc * @eocie_msk: end of conversion interrupt enable mask in @ier */ -@@ -60,17 +60,19 @@ struct stm32_adc_common_regs { + struct stm32_adc_common_regs { + u32 csr; + u32 ccr; +- u32 eoc1_msk; +- u32 eoc2_msk; +- u32 eoc3_msk; ++ u32 eoc_msk[STM32_ADC_MAX_ADCS]; ++ u32 ovr_msk[STM32_ADC_MAX_ADCS]; + u32 ier; + u32 eocie_msk; + }; +@@ -60,7 +58,7 @@ struct stm32_adc_common_regs { struct stm32_adc_priv; /** @@ -1396,19 +1389,7 @@ index 93a096a91..0e2068ec0 100644 * @regs: common registers for all instances * @clk_sel: clock selection routine * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) - * @has_syscfg: SYSCFG capability flags -+ * @num_irqs: number of interrupt lines - */ - struct stm32_adc_priv_cfg { - const struct stm32_adc_common_regs *regs; - int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); - u32 max_clk_rate_hz; - unsigned int has_syscfg; -+ unsigned int num_irqs; - }; - - /** -@@ -79,6 +81,7 @@ struct stm32_adc_priv_cfg { +@@ -81,6 +79,7 @@ struct stm32_adc_priv_cfg { * @domain: irq domain reference * @aclk: clock reference for the analog circuitry * @bclk: bus clock common for all ADCs, depends on part used @@ -1416,7 +1397,7 @@ index 93a096a91..0e2068ec0 100644 * @booster: booster supply reference * @vdd: vdd supply reference * @vdda: vdda analog supply reference -@@ -95,6 +98,7 @@ struct stm32_adc_priv { +@@ -97,6 +96,7 @@ struct stm32_adc_priv { struct irq_domain *domain; struct clk *aclk; struct clk *bclk; @@ -1424,7 +1405,7 @@ index 93a096a91..0e2068ec0 100644 struct regulator *booster; struct regulator *vdd; struct regulator *vdda; -@@ -117,6 +121,7 @@ static int stm32f4_pclk_div[] = {2, 4, 6, 8}; +@@ -119,6 +119,7 @@ static int stm32f4_pclk_div[] = {2, 4, 6, 8}; /** * stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler @@ -1432,7 +1413,7 @@ index 93a096a91..0e2068ec0 100644 * @priv: stm32 ADC core private data * Select clock prescaler used for analog conversions, before using ADC. */ -@@ -140,7 +145,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, +@@ -142,7 +143,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, } for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { @@ -1441,107 +1422,122 @@ index 93a096a91..0e2068ec0 100644 break; } if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { -@@ -229,7 +234,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -199,7 +200,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, + { + u32 ckmode, presc, val; + unsigned long rate; +- int i, div; ++ int i, div, duty; + + /* stm32h7 bus clock is common for all ADC instances (mandatory) */ + if (!priv->bclk) { +@@ -223,6 +224,11 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, + return -EINVAL; + } + ++ /* If duty is an error, kindly use at least /2 divider */ ++ duty = clk_get_scaled_duty_cycle(priv->aclk, 100); ++ if (duty < 0) ++ dev_warn(&pdev->dev, "adc clock duty: %d\n", duty); ++ + for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { + ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; + presc = stm32h7_adc_ckmodes_spec[i].presc; +@@ -231,7 +237,14 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (ckmode) continue; - if ((rate / div) <= priv->cfg->max_clk_rate_hz) ++ /* ++ * For proper operation, clock duty cycle range is 49% ++ * to 51%. Apply at least /2 prescaler otherwise. ++ */ ++ if (div == 1 && (duty < 49 || duty > 51)) ++ continue; ++ + if ((rate / div) <= priv->max_clk_rate) goto out; } } -@@ -249,7 +254,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -243,6 +256,10 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, + return -EINVAL; + } + ++ duty = clk_get_scaled_duty_cycle(priv->bclk, 100); ++ if (duty < 0) ++ dev_warn(&pdev->dev, "bus clock duty: %d\n", duty); ++ + for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { + ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; + presc = stm32h7_adc_ckmodes_spec[i].presc; +@@ -251,7 +268,10 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (!ckmode) continue; - if ((rate / div) <= priv->cfg->max_clk_rate_hz) ++ if (div == 1 && (duty < 49 || duty > 51)) ++ continue; ++ + if ((rate / div) <= priv->max_clk_rate) goto out; } -@@ -277,21 +282,21 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, +@@ -279,9 +299,8 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { .csr = STM32F4_ADC_CSR, .ccr = STM32F4_ADC_CCR, - .eoc1_msk = STM32F4_EOC1, - .eoc2_msk = STM32F4_EOC2, - .eoc3_msk = STM32F4_EOC3, -+ .eoc1_msk = STM32F4_EOC1 | STM32F4_OVR1, -+ .eoc2_msk = STM32F4_EOC2 | STM32F4_OVR2, -+ .eoc3_msk = STM32F4_EOC3 | STM32F4_OVR3, ++ .eoc_msk = { STM32F4_EOC1, STM32F4_EOC2, STM32F4_EOC3}, ++ .ovr_msk = { STM32F4_OVR1, STM32F4_OVR2, STM32F4_OVR3}, .ier = STM32F4_ADC_CR1, -- .eocie_msk = STM32F4_EOCIE, -+ .eocie_msk = STM32F4_EOCIE | STM32F4_OVRIE, + .eocie_msk = STM32F4_EOCIE, }; - - /* STM32H7 common registers definitions */ +@@ -290,8 +309,8 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { static const struct stm32_adc_common_regs stm32h7_adc_common_regs = { .csr = STM32H7_ADC_CSR, .ccr = STM32H7_ADC_CCR, - .eoc1_msk = STM32H7_EOC_MST, - .eoc2_msk = STM32H7_EOC_SLV, -+ .eoc1_msk = STM32H7_EOC_MST | STM32H7_OVR_MST, -+ .eoc2_msk = STM32H7_EOC_SLV | STM32H7_OVR_SLV, ++ .eoc_msk = { STM32H7_EOC_MST, STM32H7_EOC_SLV}, ++ .ovr_msk = { STM32H7_OVR_MST, STM32H7_OVR_SLV}, .ier = STM32H7_ADC_IER, -- .eocie_msk = STM32H7_EOCIE, -+ .eocie_msk = STM32H7_EOCIE | STM32H7_OVRIE, + .eocie_msk = STM32H7_EOCIE, }; +@@ -315,6 +334,7 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) + { + struct stm32_adc_priv *priv = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); ++ int i; + u32 status; - static const unsigned int stm32_adc_offset[STM32_ADC_MAX_ADCS] = { -@@ -372,21 +377,15 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, - struct device_node *np = pdev->dev.of_node; - unsigned int i; - -- for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { -+ /* -+ * Interrupt(s) must be provided, depending on the compatible: -+ * - stm32f4/h7 shares a common interrupt line. -+ * - stm32mp1, has one line per ADC -+ */ -+ for (i = 0; i < priv->cfg->num_irqs; i++) { - priv->irq[i] = platform_get_irq(pdev, i); -- if (priv->irq[i] < 0) { -- /* -- * At least one interrupt must be provided, make others -- * optional: -- * - stm32f4/h7 shares a common interrupt. -- * - stm32mp1, has one line per ADC (either for ADC1, -- * ADC2 or both). -- */ -- if (i && priv->irq[i] == -ENXIO) -- continue; + chained_irq_enter(chip, desc); +@@ -332,17 +352,12 @@ static void stm32_adc_irq_handler(struct irq_desc *desc) + * 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 (priv->irq[i] < 0) - return priv->irq[i]; -- } - } - - priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0, -@@ -397,9 +396,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, - return -ENOMEM; - } - -- for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { -- if (priv->irq[i] < 0) -- continue; +- 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 && +- stm32_adc_eoc_enabled(priv, 2)) +- generic_handle_irq(irq_find_mapping(priv->domain, 2)); + for (i = 0; i < priv->cfg->num_irqs; i++) { - irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler); - irq_set_handler_data(priv->irq[i], priv); - } -@@ -417,11 +414,8 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, - irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); - irq_domain_remove(priv->domain); ++ if ((status & priv->cfg->regs->eoc_msk[i] && ++ stm32_adc_eoc_enabled(priv, i)) || ++ (status & priv->cfg->regs->ovr_msk[i])) ++ generic_handle_irq(irq_find_mapping(priv->domain, i)); ++ } -- for (i = 0; i < STM32_ADC_MAX_ADCS; i++) { -- if (priv->irq[i] < 0) -- continue; -+ for (i = 0; i < priv->cfg->num_irqs; i++) - irq_set_chained_handler(priv->irq[i], NULL); -- } - } - - static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv, -@@ -654,6 +648,7 @@ static int stm32_adc_probe(struct platform_device *pdev) + chained_irq_exit(chip, desc); + }; +@@ -645,6 +660,7 @@ static int stm32_adc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; struct resource *res; @@ -1549,7 +1545,7 @@ index 93a096a91..0e2068ec0 100644 int ret; if (!pdev->dev.of_node) -@@ -684,7 +679,8 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -675,7 +691,8 @@ static int stm32_adc_probe(struct platform_device *pdev) priv->vref = devm_regulator_get(&pdev->dev, "vref"); if (IS_ERR(priv->vref)) { ret = PTR_ERR(priv->vref); @@ -1559,7 +1555,7 @@ index 93a096a91..0e2068ec0 100644 return ret; } -@@ -692,7 +688,8 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -683,7 +700,8 @@ static int stm32_adc_probe(struct platform_device *pdev) if (IS_ERR(priv->aclk)) { ret = PTR_ERR(priv->aclk); if (ret != -ENOENT) { @@ -1569,7 +1565,7 @@ index 93a096a91..0e2068ec0 100644 return ret; } priv->aclk = NULL; -@@ -702,7 +699,8 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -693,7 +711,8 @@ static int stm32_adc_probe(struct platform_device *pdev) if (IS_ERR(priv->bclk)) { ret = PTR_ERR(priv->bclk); if (ret != -ENOENT) { @@ -1579,7 +1575,7 @@ index 93a096a91..0e2068ec0 100644 return ret; } priv->bclk = NULL; -@@ -730,6 +728,13 @@ static int stm32_adc_probe(struct platform_device *pdev) +@@ -721,6 +740,13 @@ static int stm32_adc_probe(struct platform_device *pdev) priv->common.vref_mv = ret / 1000; dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); @@ -1593,32 +1589,31 @@ index 93a096a91..0e2068ec0 100644 ret = priv->cfg->clk_sel(pdev, priv); if (ret < 0) goto err_hw_stop; -@@ -803,6 +808,7 @@ static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { - .regs = &stm32f4_adc_common_regs, - .clk_sel = stm32f4_adc_clk_sel, - .max_clk_rate_hz = 36000000, -+ .num_irqs = 1, +@@ -780,6 +806,13 @@ static int stm32_adc_core_runtime_resume(struct device *dev) + { + return stm32_adc_core_hw_start(dev); + } ++ ++static int stm32_adc_core_runtime_idle(struct device *dev) ++{ ++ pm_runtime_mark_last_busy(dev); ++ ++ return 0; ++} + #endif + + static const struct dev_pm_ops stm32_adc_core_pm_ops = { +@@ -787,7 +820,7 @@ static const struct dev_pm_ops stm32_adc_core_pm_ops = { + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend, + stm32_adc_core_runtime_resume, +- NULL) ++ stm32_adc_core_runtime_idle) }; - static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { -@@ -810,6 +816,7 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { - .clk_sel = stm32h7_adc_clk_sel, - .max_clk_rate_hz = 36000000, - .has_syscfg = HAS_VBOOSTER, -+ .num_irqs = 1, - }; - - static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { -@@ -817,6 +824,7 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { - .clk_sel = stm32h7_adc_clk_sel, - .max_clk_rate_hz = 40000000, - .has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD, -+ .num_irqs = 2, - }; - - static const struct of_device_id stm32_adc_of_match[] = { + static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h -index 2579d514c..2322809bf 100644 +index 2579d514c2a34..2322809bfd2f7 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h @@ -51,10 +51,12 @@ @@ -1670,7 +1665,7 @@ index 2579d514c..2322809bf 100644 /* STM32H7_ADC_CCR - bit fields */ diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c -index 73aee5949..de0ecad66 100644 +index 94fde39d9ff7a..cd1bbecd54921 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -102,7 +102,7 @@ struct stm32_adc_calib { @@ -1715,7 +1710,23 @@ index 73aee5949..de0ecad66 100644 * @regs: registers descriptions * @adc_info: per instance input channels definitions * @trigs: external trigger sources -@@ -183,8 +187,8 @@ struct stm32_adc_cfg { +@@ -150,6 +154,7 @@ struct stm32_adc; + * @start_conv: routine to start conversions + * @stop_conv: routine to stop conversions + * @unprepare: optional unprepare routine (disable, power-down) ++ * @irq_clear: routine to clear irqs + * @smp_cycles: programmable sampling time (ADC clock cycles) + */ + struct stm32_adc_cfg { +@@ -162,6 +167,7 @@ struct stm32_adc_cfg { + void (*start_conv)(struct stm32_adc *, bool dma); + void (*stop_conv)(struct stm32_adc *); + void (*unprepare)(struct stm32_adc *); ++ void (*irq_clear)(struct stm32_adc *adc, u32 msk); + const unsigned int *smp_cycles; + }; + +@@ -183,8 +189,8 @@ struct stm32_adc_cfg { * @rx_buf: dma rx buffer cpu address * @rx_dma_buf: dma rx buffer bus address * @rx_buf_sz: dma rx buffer size @@ -1726,7 +1737,7 @@ index 73aee5949..de0ecad66 100644 * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) * @cal: optional calibration data on some devices * @chan_name: channel name array -@@ -254,7 +258,7 @@ static const struct stm32_adc_info stm32h7_adc_info = { +@@ -254,7 +260,7 @@ static const struct stm32_adc_info stm32h7_adc_info = { .num_res = ARRAY_SIZE(stm32h7_adc_resolutions), }; @@ -1735,7 +1746,7 @@ index 73aee5949..de0ecad66 100644 * stm32f4_sq - describe regular sequence registers * - L: sequence len (register & bit field) * - SQ1..SQ16: sequence entries (register & bit field) -@@ -301,7 +305,7 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { +@@ -301,7 +307,7 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { {}, /* sentinel */ }; @@ -1744,7 +1755,7 @@ index 73aee5949..de0ecad66 100644 * stm32f4_smp_bits[] - describe sampling time register index & bit fields * Sorted so it can be indexed by channel number. */ -@@ -337,7 +341,9 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { +@@ -337,7 +343,9 @@ static const unsigned int stm32f4_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { static const struct stm32_adc_regspec stm32f4_adc_regspec = { .dr = STM32F4_ADC_DR, .ier_eoc = { STM32F4_ADC_CR1, STM32F4_EOCIE }, @@ -1754,7 +1765,7 @@ index 73aee5949..de0ecad66 100644 .sqr = stm32f4_sq, .exten = { STM32F4_ADC_CR2, STM32F4_EXTEN_MASK, STM32F4_EXTEN_SHIFT }, .extsel = { STM32F4_ADC_CR2, STM32F4_EXTSEL_MASK, -@@ -392,7 +398,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { +@@ -392,7 +400,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { {}, }; @@ -1763,7 +1774,7 @@ index 73aee5949..de0ecad66 100644 * stm32h7_smp_bits - describe sampling time register index & bit fields * Sorted so it can be indexed by channel number. */ -@@ -429,7 +435,9 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { +@@ -429,7 +437,9 @@ static const unsigned int stm32h7_adc_smp_cycles[STM32_ADC_MAX_SMP + 1] = { static const struct stm32_adc_regspec stm32h7_adc_regspec = { .dr = STM32H7_ADC_DR, .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE }, @@ -1773,7 +1784,7 @@ index 73aee5949..de0ecad66 100644 .sqr = stm32h7_sq, .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT }, .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK, -@@ -506,6 +514,18 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) +@@ -506,6 +516,18 @@ static void stm32_adc_conv_irq_disable(struct stm32_adc *adc) adc->cfg->regs->ier_eoc.mask); } @@ -1792,7 +1803,32 @@ index 73aee5949..de0ecad66 100644 static void stm32_adc_set_res(struct stm32_adc *adc) { const struct stm32_adc_regs *res = &adc->cfg->regs->res; -@@ -994,6 +1014,7 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, +@@ -595,6 +617,11 @@ static void stm32f4_adc_stop_conv(struct stm32_adc *adc) + STM32F4_ADON | STM32F4_DMA | STM32F4_DDS); + } + ++static void stm32f4_adc_irq_clear(struct stm32_adc *adc, u32 msk) ++{ ++ stm32_adc_clr_bits(adc, adc->cfg->regs->isr_eoc.reg, msk); ++} ++ + static void stm32h7_adc_start_conv(struct stm32_adc *adc, bool dma) + { + enum stm32h7_adc_dmngt dmngt; +@@ -632,6 +659,12 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) + stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK); + } + ++static void stm32h7_adc_irq_clear(struct stm32_adc *adc, u32 msk) ++{ ++ /* On STM32H7 IRQs are cleared by writing 1 into ISR register */ ++ stm32_adc_set_bits(adc, adc->cfg->regs->isr_eoc.reg, msk); ++} ++ + static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) + { + struct iio_dev *indio_dev = iio_priv_to_dev(adc); +@@ -994,6 +1027,7 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, /** * stm32_adc_get_trig_extsel() - Get external trigger selection @@ -1800,38 +1836,55 @@ index 73aee5949..de0ecad66 100644 * @trig: trigger * * Returns trigger extsel value, if trig matches, -EINVAL otherwise. -@@ -1156,6 +1177,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, - - stm32_adc_conv_irq_disable(adc); - -+ pm_runtime_mark_last_busy(dev->parent); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - -@@ -1204,6 +1226,19 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, +@@ -1204,12 +1238,63 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, } } ++static void stm32_adc_irq_clear(struct stm32_adc *adc, u32 msk) ++{ ++ adc->cfg->irq_clear(adc, msk); ++} ++ +static irqreturn_t stm32_adc_threaded_isr(int irq, void *data) +{ + struct stm32_adc *adc = data; + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + const struct stm32_adc_regspec *regs = adc->cfg->regs; + u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg); ++ u32 mask = stm32_adc_readl(adc, regs->ier_eoc.reg); + -+ if (status & regs->isr_ovr.mask) ++ /* Check ovr status right now, as ovr mask should be already disabled */ ++ if (status & regs->isr_ovr.mask) { ++ /* ++ * Clear ovr bit to avoid subsequent calls to IRQ handler. ++ * This requires to stop ADC first. OVR bit state in ISR, ++ * is propaged to CSR register by hardware. ++ */ ++ adc->cfg->stop_conv(adc); ++ stm32_adc_irq_clear(adc, regs->isr_ovr.mask); + dev_err(&indio_dev->dev, "Overrun, stopping: restart needed\n"); ++ return IRQ_HANDLED; ++ } + -+ return IRQ_HANDLED; ++ if (!(status & mask)) ++ dev_err_ratelimited(&indio_dev->dev, ++ "Unexpected IRQ: IER=0x%08x, ISR=0x%08x\n", ++ mask, status); ++ ++ return IRQ_NONE; +} + static irqreturn_t stm32_adc_isr(int irq, void *data) { struct stm32_adc *adc = data; -@@ -1211,6 +1246,19 @@ static irqreturn_t stm32_adc_isr(int irq, void *data) + struct iio_dev *indio_dev = iio_priv_to_dev(adc); const struct stm32_adc_regspec *regs = adc->cfg->regs; u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg); - ++ u32 mask = stm32_adc_readl(adc, regs->ier_eoc.reg); ++ ++ if (!(status & mask)) ++ return IRQ_WAKE_THREAD; ++ + if (status & regs->isr_ovr.mask) { + /* + * Overrun occurred on regular conversions: data for wrong @@ -1844,19 +1897,19 @@ index 73aee5949..de0ecad66 100644 + stm32_adc_conv_irq_disable(adc); + return IRQ_WAKE_THREAD; + } -+ + if (status & regs->isr_eoc.mask) { /* Reading DR also clears EOC status flag */ - adc->buffer[adc->bufi] = stm32_adc_readw(adc, regs->dr); -@@ -1277,6 +1325,7 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, - adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength); - - ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask); -+ pm_runtime_mark_last_busy(dev->parent); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - -@@ -1297,6 +1346,10 @@ static int stm32_adc_of_xlate(struct iio_dev *indio_dev, +@@ -1253,7 +1338,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) + * dma cyclic transfers are used, buffer is split into two periods. + * There should be : + * - always one buffer (period) dma is working on +- * - one buffer (period) driver can push with iio_trigger_poll(). ++ * - one buffer (period) driver can push data. + */ + watermark = min(watermark, val * (unsigned)(sizeof(u16))); + adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv); +@@ -1297,6 +1382,10 @@ static int stm32_adc_of_xlate(struct iio_dev *indio_dev, /** * stm32_adc_debugfs_reg_access - read or write register value @@ -1867,47 +1920,7 @@ index 73aee5949..de0ecad66 100644 * * To read a value from an ADC register: * echo [ADC reg offset] > direct_reg_access -@@ -1324,6 +1377,7 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, - else - *readval = stm32_adc_readl(adc, reg); - -+ pm_runtime_mark_last_busy(dev->parent); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - -@@ -1367,8 +1421,30 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc) - static void stm32_adc_dma_buffer_done(void *data) - { - struct iio_dev *indio_dev = data; -+ struct stm32_adc *adc = iio_priv(indio_dev); -+ int residue = stm32_adc_dma_residue(adc); -+ -+ /* -+ * In DMA mode the trigger services of IIO are not used -+ * (e.g. no call to iio_trigger_poll). -+ * Calling irq handler associated to the hardware trigger is not -+ * relevant as the conversions have already been done. Data -+ * transfers are performed directly in DMA callback instead. -+ * This implementation avoids to call trigger irq handler that -+ * may sleep, in an atomic context (DMA irq handler context). -+ */ -+ dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); -+ -+ while (residue >= indio_dev->scan_bytes) { -+ u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi]; -+ -+ iio_push_to_buffers(indio_dev, buffer); - -- iio_trigger_poll_chained(indio_dev->trig); -+ residue -= indio_dev->scan_bytes; -+ adc->bufi += indio_dev->scan_bytes; -+ if (adc->bufi >= adc->rx_buf_sz) -+ adc->bufi = 0; -+ } - } - - static int stm32_adc_dma_start(struct iio_dev *indio_dev) -@@ -1436,6 +1512,8 @@ static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev) +@@ -1458,6 +1547,8 @@ static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev) /* Reset adc buffer index */ adc->bufi = 0; @@ -1916,15 +1929,7 @@ index 73aee5949..de0ecad66 100644 if (!adc->dma_chan) stm32_adc_conv_irq_enable(adc); -@@ -1446,6 +1524,7 @@ static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev) - err_clr_trig: - stm32_adc_set_trig(indio_dev, NULL); - err_pm_put: -+ pm_runtime_mark_last_busy(dev->parent); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - -@@ -1476,12 +1555,15 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev) +@@ -1498,6 +1589,8 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev) if (!adc->dma_chan) stm32_adc_conv_irq_disable(adc); @@ -1933,46 +1938,44 @@ index 73aee5949..de0ecad66 100644 if (adc->dma_chan) dmaengine_terminate_sync(adc->dma_chan); - if (stm32_adc_set_trig(indio_dev, NULL)) - dev_err(&indio_dev->dev, "Can't clear trigger\n"); +@@ -1534,31 +1627,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p) -+ pm_runtime_mark_last_busy(dev->parent); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - } -@@ -1741,9 +1823,21 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev) - struct dma_slave_config config; - int ret; + dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); -- adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); +- if (!adc->dma_chan) { +- /* reset buffer index */ +- adc->bufi = 0; +- iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, +- pf->timestamp); +- } else { +- int residue = stm32_adc_dma_residue(adc); +- +- while (residue >= indio_dev->scan_bytes) { +- u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi]; +- +- iio_push_to_buffers_with_timestamp(indio_dev, buffer, +- pf->timestamp); +- residue -= indio_dev->scan_bytes; +- adc->bufi += indio_dev->scan_bytes; +- if (adc->bufi >= adc->rx_buf_sz) +- adc->bufi = 0; +- } +- } +- ++ /* reset buffer index */ ++ adc->bufi = 0; ++ iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, ++ pf->timestamp); + iio_trigger_notify_done(indio_dev->trig); + + /* re-enable eoc irq */ - if (!adc->dma_chan) -+ adc->dma_chan = dma_request_chan(&indio_dev->dev, "rx"); -+ if (IS_ERR(adc->dma_chan)) { -+ ret = PTR_ERR(adc->dma_chan); -+ if (ret != -ENODEV) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(&indio_dev->dev, -+ "DMA channel request failed with %d\n", -+ ret); -+ return ret; -+ } -+ -+ /* DMA is optional: fall back to IRQ mode */ -+ adc->dma_chan = NULL; - return 0; -+ } +- stm32_adc_conv_irq_enable(adc); ++ stm32_adc_conv_irq_enable(adc); - adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev, - STM32_DMA_BUFFER_SIZE, -@@ -1778,6 +1872,7 @@ static int stm32_adc_probe(struct platform_device *pdev) - { - struct iio_dev *indio_dev; - struct device *dev = &pdev->dev; -+ irqreturn_t (*handler)(int irq, void *p) = NULL; - struct stm32_adc *adc; - int ret; - -@@ -1813,8 +1908,9 @@ static int stm32_adc_probe(struct platform_device *pdev) + return IRQ_HANDLED; + } +@@ -1848,8 +1924,9 @@ static int stm32_adc_probe(struct platform_device *pdev) if (adc->irq < 0) return adc->irq; @@ -1984,30 +1987,32 @@ index 73aee5949..de0ecad66 100644 if (ret) { dev_err(&pdev->dev, "failed to request IRQ\n"); return ret; -@@ -1843,9 +1939,11 @@ static int stm32_adc_probe(struct platform_device *pdev) - if (ret < 0) - return ret; +@@ -2013,6 +2090,7 @@ 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, ++ .irq_clear = stm32f4_adc_irq_clear, + }; -+ if (!adc->dma_chan) -+ handler = &stm32_adc_trigger_handler; -+ - ret = iio_triggered_buffer_setup(indio_dev, -- &iio_pollfunc_store_time, -- &stm32_adc_trigger_handler, -+ &iio_pollfunc_store_time, handler, - &stm32_adc_buffer_setup_ops); - if (ret) { - dev_err(&pdev->dev, "buffer setup failed\n"); -@@ -1869,6 +1967,7 @@ static int stm32_adc_probe(struct platform_device *pdev) - goto err_hw_stop; - } + static const struct stm32_adc_cfg stm32h7_adc_cfg = { +@@ -2024,6 +2102,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { + .prepare = stm32h7_adc_prepare, + .unprepare = stm32h7_adc_unprepare, + .smp_cycles = stm32h7_adc_smp_cycles, ++ .irq_clear = stm32h7_adc_irq_clear, + }; -+ pm_runtime_mark_last_busy(dev->parent); - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); + static const struct stm32_adc_cfg stm32mp1_adc_cfg = { +@@ -2036,6 +2115,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { + .prepare = stm32h7_adc_prepare, + .unprepare = stm32h7_adc_unprepare, + .smp_cycles = stm32h7_adc_smp_cycles, ++ .irq_clear = stm32h7_adc_irq_clear, + }; + static const struct of_device_id stm32_adc_of_match[] = { diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c -index 3ae0366a7..160d952c2 100644 +index c2948defa7853..b9a536a6c24f2 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -10,6 +10,7 @@ @@ -2145,24 +2150,7 @@ index 3ae0366a7..160d952c2 100644 } return -EINVAL; -@@ -1363,9 +1414,13 @@ static int stm32_dfsdm_dma_request(struct iio_dev *indio_dev) - { - struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); - -- adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx"); -- if (!adc->dma_chan) -- return -EINVAL; -+ adc->dma_chan = dma_request_chan(&indio_dev->dev, "rx"); -+ if (IS_ERR(adc->dma_chan)) { -+ int ret = PTR_ERR(adc->dma_chan); -+ -+ adc->dma_chan = NULL; -+ return ret; -+ } - - adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev, - DFSDM_DMA_BUFFER_SIZE, -@@ -1398,7 +1453,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -1403,7 +1454,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, * IIO_CHAN_INFO_RAW: used to compute regular conversion * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling */ @@ -2173,7 +2161,7 @@ index 3ae0366a7..160d952c2 100644 ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | BIT(IIO_CHAN_INFO_SAMP_FREQ); -@@ -1408,7 +1465,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -1413,7 +1466,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, ch->scan_type.shift = 8; } ch->scan_type.sign = 's'; @@ -2182,7 +2170,7 @@ index 3ae0366a7..160d952c2 100644 ch->scan_type.storagebits = 32; return stm32_dfsdm_chan_configure(adc->dfsdm, -@@ -1449,8 +1506,10 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) +@@ -1454,8 +1507,10 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) { struct iio_chan_spec *ch; struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -2194,7 +2182,7 @@ index 3ae0366a7..160d952c2 100644 adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp); -@@ -1474,6 +1533,21 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) +@@ -1479,6 +1534,21 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) if (!ch) return -ENOMEM; @@ -2216,7 +2204,7 @@ index 3ae0366a7..160d952c2 100644 for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { ch[chan_idx].scan_index = chan_idx; ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]); -@@ -1481,6 +1555,38 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) +@@ -1486,6 +1556,38 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) dev_err(&indio_dev->dev, "Channels init failed\n"); return ret; } @@ -2255,26 +2243,8 @@ index 3ae0366a7..160d952c2 100644 } indio_dev->num_channels = num_ch; -@@ -1489,7 +1595,16 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev) - init_completion(&adc->completion); - - /* Optionally request DMA */ -- if (stm32_dfsdm_dma_request(indio_dev)) { -+ ret = stm32_dfsdm_dma_request(indio_dev); -+ if (ret) { -+ if (ret != -ENODEV) { -+ if (ret != -EPROBE_DEFER) -+ dev_err(&indio_dev->dev, -+ "DMA channel request failed with %d\n", -+ ret); -+ return ret; -+ } -+ - dev_dbg(&indio_dev->dev, "No DMA support\n"); - return 0; - } diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c -index d0fb3124d..7e5809ba0 100644 +index d0fb3124de076..7e5809ba0dee1 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -11,6 +11,7 @@ @@ -2536,7 +2506,7 @@ index d0fb3124d..7e5809ba0 100644 }; module_platform_driver(stm32_dac_driver); diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c -index cce26a3a6..f22c1d912 100644 +index cce26a3a6627c..f22c1d9129b28 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -13,6 +13,7 @@ @@ -2697,7 +2667,7 @@ index cce26a3a6..f22c1d912 100644 }; module_platform_driver(stm32_dac_driver); diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c -index f98510c71..7d8962d65 100644 +index f98510c714b57..7d8962d6566a1 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -75,14 +75,27 @@ static const void *stm32h7_valids_table[][MAX_VALIDS] = { @@ -3012,7 +2982,7 @@ index f98510c71..7d8962d65 100644 }; module_platform_driver(stm32_timer_trigger_driver); diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index e00f2fa27..af4b0d690 100644 +index e00f2fa27f00e..0337c71d7b625 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -25,7 +25,6 @@ @@ -3031,7 +3001,7 @@ index e00f2fa27..af4b0d690 100644 }; struct stm32_exti_drv_data { -@@ -166,27 +166,49 @@ static const struct stm32_exti_bank *stm32mp1_exti_banks[] = { +@@ -166,27 +166,54 @@ static const struct stm32_exti_bank *stm32mp1_exti_banks[] = { &stm32mp1_exti_b3, }; @@ -3092,6 +3062,11 @@ index e00f2fa27..af4b0d690 100644 + { .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct }, + { .exti = 43, .irq_parent = 75, .chip = &stm32_exti_h_chip_direct }, + { .exti = 44, .irq_parent = 98, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 52, .irq_parent = 140, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 53, .irq_parent = 141, .chip = &stm32_exti_h_chip_direct }, + { .exti = 54, .irq_parent = 135, .chip = &stm32_exti_h_chip_direct }, + { .exti = 61, .irq_parent = 100, .chip = &stm32_exti_h_chip_direct }, + { .exti = 65, .irq_parent = 144, .chip = &stm32_exti_h_chip }, @@ -3101,7 +3076,7 @@ index e00f2fa27..af4b0d690 100644 }; static const struct stm32_exti_drv_data stm32mp1_drv_data = { -@@ -196,22 +218,23 @@ static const struct stm32_exti_drv_data stm32mp1_drv_data = { +@@ -196,22 +223,23 @@ static const struct stm32_exti_drv_data stm32mp1_drv_data = { .irq_nr = ARRAY_SIZE(stm32mp1_desc_irq), }; @@ -3133,7 +3108,7 @@ index e00f2fa27..af4b0d690 100644 } static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) -@@ -277,55 +300,24 @@ static int stm32_exti_set_type(struct irq_data *d, +@@ -277,55 +305,24 @@ static int stm32_exti_set_type(struct irq_data *d, return 0; } @@ -3197,7 +3172,7 @@ index e00f2fa27..af4b0d690 100644 rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); -@@ -338,7 +330,8 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type) +@@ -338,7 +335,8 @@ static int stm32_irq_set_type(struct irq_data *d, unsigned int type) irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); unspinlock: @@ -3207,7 +3182,36 @@ index e00f2fa27..af4b0d690 100644 unlock: irq_gc_unlock(gc); -@@ -504,15 +497,20 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) +@@ -431,6 +429,16 @@ static void stm32_irq_ack(struct irq_data *d) + irq_gc_unlock(gc); + } + ++/* directly set the target bit without reading first. */ ++static inline void stm32_exti_write_bit(struct irq_data *d, u32 reg) ++{ ++ struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); ++ void __iomem *base = chip_data->host_data->base; ++ u32 val = BIT(d->hwirq % IRQS_PER_BANK); ++ ++ writel_relaxed(val, base + reg); ++} ++ + static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg) + { + struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); +@@ -464,9 +472,9 @@ static void stm32_exti_h_eoi(struct irq_data *d) + + raw_spin_lock(&chip_data->rlock); + +- stm32_exti_set_bit(d, stm32_bank->rpr_ofst); ++ stm32_exti_write_bit(d, stm32_bank->rpr_ofst); + if (stm32_bank->fpr_ofst != UNDEF_REG) +- stm32_exti_set_bit(d, stm32_bank->fpr_ofst); ++ stm32_exti_write_bit(d, stm32_bank->fpr_ofst); + + raw_spin_unlock(&chip_data->rlock); + +@@ -504,15 +512,20 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) { struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d); const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank; @@ -3231,7 +3235,7 @@ index e00f2fa27..af4b0d690 100644 rtsr = readl_relaxed(base + stm32_bank->rtsr_ofst); ftsr = readl_relaxed(base + stm32_bank->ftsr_ofst); -@@ -525,10 +523,14 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) +@@ -525,10 +538,14 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) writel_relaxed(ftsr, base + stm32_bank->ftsr_ofst); unspinlock: @@ -3247,7 +3251,7 @@ index e00f2fa27..af4b0d690 100644 return err; } -@@ -546,6 +548,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) +@@ -546,6 +563,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) raw_spin_unlock(&chip_data->rlock); @@ -3257,7 +3261,7 @@ index e00f2fa27..af4b0d690 100644 return 0; } -@@ -555,7 +560,13 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, +@@ -555,7 +575,13 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, if (d->parent_data->chip) return irq_chip_set_affinity_parent(d, dest, force); @@ -3272,7 +3276,7 @@ index e00f2fa27..af4b0d690 100644 } static int __maybe_unused stm32_exti_h_suspend(void) -@@ -604,45 +615,90 @@ static void stm32_exti_h_syscore_deinit(void) +@@ -604,45 +630,90 @@ static void stm32_exti_h_syscore_deinit(void) unregister_syscore_ops(&stm32_exti_h_syscore_ops); } @@ -3306,8 +3310,8 @@ index e00f2fa27..af4b0d690 100644 + .name = "stm32-exti-h-direct", + .irq_eoi = irq_chip_eoi_parent, + .irq_ack = irq_chip_ack_parent, -+ .irq_mask = irq_chip_mask_parent, -+ .irq_unmask = irq_chip_unmask_parent, ++ .irq_mask = stm32_exti_h_mask, ++ .irq_unmask = stm32_exti_h_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = irq_chip_set_type_parent, + .irq_set_wake = stm32_exti_h_set_wake, @@ -3360,7 +3364,7 @@ index e00f2fa27..af4b0d690 100644 return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec); + } else { -+ if (desc->irq_parent >= 0) { ++ if (desc->irq_parent) { + p_fwspec.fwnode = dm->parent->fwnode; + p_fwspec.param_count = 3; + p_fwspec.param[0] = GIC_SPI; @@ -3373,7 +3377,7 @@ index e00f2fa27..af4b0d690 100644 } return 0; -@@ -807,11 +863,12 @@ static int stm32_exti_probe(struct platform_device *pdev) +@@ -807,11 +878,12 @@ static int stm32_exti_probe(struct platform_device *pdev) { int ret, i; struct device *dev = &pdev->dev; @@ -3387,7 +3391,7 @@ index e00f2fa27..af4b0d690 100644 host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); if (!host_data) -@@ -879,6 +936,34 @@ static int stm32_exti_probe(struct platform_device *pdev) +@@ -879,6 +951,34 @@ static int stm32_exti_probe(struct platform_device *pdev) if (ret) return ret; diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0010-ARM-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch similarity index 67% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0010-ARM-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch index cac772b..5f27021 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0010-ARM-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch @@ -1,40 +1,197 @@ -From e0c91ba2bc4702d8ed587f7e200591cf135ade14 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:43:27 +0200 -Subject: [PATCH 10/23] ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG +From 16dc56ebda804f047d718c7531cb65fbb5176f99 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:45 +0200 +Subject: [PATCH 10/22] ARM-stm32mp1-r2-rc8-MAILBOX-REMOTEPROC-RPMSG --- - Documentation/remoteproc.txt | 22 + - drivers/mailbox/Kconfig | 7 + - drivers/mailbox/Makefile | 2 + - drivers/mailbox/arm-smc-mailbox.c | 166 ++++++ - drivers/mailbox/stm32-ipcc.c | 36 +- - drivers/remoteproc/Kconfig | 21 + - drivers/remoteproc/Makefile | 2 + - drivers/remoteproc/remoteproc_core.c | 55 +- - drivers/remoteproc/rproc_srm_core.c | 303 ++++++++++ - drivers/remoteproc/rproc_srm_core.h | 98 ++++ - drivers/remoteproc/rproc_srm_dev.c | 744 +++++++++++++++++++++++++ - drivers/remoteproc/stm32_rproc.c | 314 ++++++++++- - drivers/rpmsg/Kconfig | 9 + - drivers/rpmsg/Makefile | 1 + - drivers/rpmsg/rpmsg_core.c | 19 + - drivers/rpmsg/rpmsg_internal.h | 2 + - drivers/rpmsg/rpmsg_tty.c | 310 +++++++++++ - drivers/rpmsg/virtio_rpmsg_bus.c | 11 + - include/linux/mailbox/arm-smccc-mbox.h | 20 + - include/linux/remoteproc.h | 2 + - include/linux/rpmsg.h | 9 + - 21 files changed, 2093 insertions(+), 60 deletions(-) + .../bindings/mailbox/stm32-ipcc.txt | 4 +- + .../bindings/remoteproc/rproc-srm.txt | 58 ++ + .../bindings/remoteproc/stm32-rproc.txt | 41 +- + Documentation/remoteproc.txt | 22 + + drivers/mailbox/Kconfig | 7 + + drivers/mailbox/Makefile | 2 + + drivers/mailbox/arm-smc-mailbox.c | 166 ++++ + drivers/mailbox/stm32-ipcc.c | 36 +- + drivers/remoteproc/Kconfig | 30 + + drivers/remoteproc/Makefile | 3 + + drivers/remoteproc/remoteproc_core.c | 55 +- + drivers/remoteproc/rproc_srm_core.c | 303 +++++++ + drivers/remoteproc/rproc_srm_core.h | 98 +++ + drivers/remoteproc/rproc_srm_dev.c | 744 ++++++++++++++++++ + drivers/remoteproc/stm32_rproc.c | 543 +++++++++++-- + drivers/remoteproc/tee_remoteproc.c | 379 +++++++++ + 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 | 339 ++++++++ + drivers/rpmsg/virtio_rpmsg_bus.c | 11 + + include/linux/mailbox/arm-smccc-mbox.h | 20 + + include/linux/remoteproc.h | 2 + + include/linux/rpmsg.h | 9 + + include/linux/tee_remoteproc.h | 106 +++ + 26 files changed, 2878 insertions(+), 131 deletions(-) + create mode 100644 Documentation/devicetree/bindings/remoteproc/rproc-srm.txt create mode 100644 drivers/mailbox/arm-smc-mailbox.c create mode 100644 drivers/remoteproc/rproc_srm_core.c create mode 100644 drivers/remoteproc/rproc_srm_core.h create mode 100644 drivers/remoteproc/rproc_srm_dev.c + create mode 100644 drivers/remoteproc/tee_remoteproc.c create mode 100644 drivers/rpmsg/rpmsg_tty.c create mode 100644 include/linux/mailbox/arm-smccc-mbox.h + create mode 100644 include/linux/tee_remoteproc.h +diff --git a/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt b/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt +index 1d2b7fee7b853..139c06a94b006 100644 +--- a/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt ++++ b/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt +@@ -14,9 +14,9 @@ Required properties: + property. Must contain the following entries: + - "rx" + - "tx" +- - "wakeup" + - interrupts: Interrupt specifiers for "rx channel occupied", "tx channel +- free" and "system wakeup". ++ free". If "wakeup-source" is set the rx interrupt is the ++ one used to wake up the system. + - #mbox-cells: Number of cells required for the mailbox specifier. Must be 1. + The data contained in the mbox specifier of the "mboxes" + property in the client node is the mailbox channel index. +diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt +new file mode 100644 +index 0000000000000..baa6e8e135e11 +--- /dev/null ++++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt +@@ -0,0 +1,58 @@ ++Remoteproc System Resource Manager ++---------------------------------- ++ ++The remoteproc SRM (System Resource Manager) handles resources allocated ++to remote processors. ++This makes it possible for remote proc to reserve and initialize system ++resources for a peripheral assigned to a coprocessor. ++ ++The devices are grouped in a core node ++ ++Core ++==== ++Required properties: ++- compatible: should be "rproc-srm-core" ++ ++Dev ++=== ++Required properties: ++- compatible: should be "rproc-srm-dev" ++ ++Optional properties: ++- reg: register base address and length ++- clocks: clocks required by the coprocessor ++- clock-names: see clock-bindings.txt ++- pinctrl-0: pins configurations required by the coprocessor ++ The SRM reserves the pins for the coprocessor, which prevents the local ++ processor to use them. ++- pinctrl-names: must be "default". ++- x-supply: power supplies required by the coprocessor ++- interrupts: external interrupts configurations required by the coprocessor. ++ This is optional since the configuration is done by the coprocessor. ++ When defined, the SRM (over)writes the configuration which allows the ++ interrupt controller to check for configuration conflicts. ++- interrupt-parent: see interrupts.txt ++- interrupt-names: see interrupts.txt ++ ++Example: ++ system_resources { ++ compatible = "rproc-srm-core"; ++ ++ mmc0: sdhci@09060000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x09060000 0x100>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&m4_pinctrl_mmc0>; ++ clock-names = "mmc", "icn"; ++ clocks = <&clk_s_c0_flexgen CLK_MMC_0>, ++ <&clk_s_c0_flexgen CLK_RX_ICN_HVA>; ++ vdda-supply = <&vdda>; ++ }; ++ ++ button { ++ compatible = "rproc-srm-dev"; ++ interrupt-parent = <&gpioa>; ++ interrupts = <5 1>; ++ interrupt-names = "gpio_key"; ++ }; ++ }; +diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt +index 5fa915a4b7360..4cea56fbded56 100644 +--- a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt ++++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt +@@ -4,23 +4,24 @@ This document defines the binding for the remoteproc component that loads and + boots firmwares on the ST32MP family chipset. + + Required properties: +-- compatible: Must be "st,stm32mp1-m4" ++- compatible: Should be one of the following, ++ "st,stm32mp1-m4": for non-authenticated remote processor firmware. ++ "st,stm32mp1-m4_optee": for OP-TEE authenticated remote processor ++ firmware. + - reg: Address ranges of the RETRAM and MCU SRAM memories used by the + remote processor. +-- resets: Reference to a reset controller asserting the remote processor. +-- st,syscfg-holdboot: Reference to the system configuration which holds the +- remote processor reset hold boot +- 1st cell: phandle of syscon block +- 2nd cell: register offset containing the hold boot setting +- 3rd cell: register bitmask for the hold boot field +-- st,syscfg-tz: Reference to the system configuration which holds the RCC trust +- zone mode +- 1st cell: phandle to syscon block +- 2nd cell: register offset containing the RCC trust zone mode setting +- 3rd cell: register bitmask for the RCC trust zone mode bit ++- resets: Reference to resets asserting: ++ - the remote processor ++ - the remote processor reset hold boot ++- reset-names: Name of the MCU reset ++ - must be "mcu_rst" for the remote processor reset ++ - must be "hold_boot" for the remote processor hold boot + + Optional properties: + - interrupts: Should contain the watchdog interrupt ++- wakeup-source: Flag indicating whether remoteproc can wake up the system by ++ the watchdog interrupt. Only meaningful if the "interrupts" ++ property is defined. + - mboxes: This property is required only if the rpmsg/virtio functionality + is used. List of phandle and mailbox channel specifiers: + - a channel (a) used to communicate through virtqueues with the +@@ -48,6 +49,16 @@ Optional properties: + 1st cell: phandle to syscon block + 2nd cell: register offset containing the deep sleep setting + 3rd cell: register bitmask for the deep sleep bit ++- st,syscfg-rsc-tbl: Reference to the system configuration controlling the ++ resource table address loaded by the bootloader ++ 1st cell: phandle to syscon block ++ 2nd cell: register offset containing the resource table address ++ 3rd cell: register bitmask for the resource table address ++- st,syscfg-copro-state: Reference to the system configuration which returns the ++ coprocessor state. ++ 1st cell: phandle to syscon block ++ 2nd cell: register offset containing the coprocessor state ++ 3rd cell: register bitmask for the coprocessor state + - st,auto-boot: If defined, when remoteproc is probed, it loads the default + firmware and starts the remote processor. + +@@ -57,7 +68,7 @@ Example: + reg = <0x10000000 0x40000>, + <0x30000000 0x40000>, + <0x38000000 0x10000>; +- resets = <&rcc MCU_R>; +- st,syscfg-holdboot = <&rcc 0x10C 0x1>; +- st,syscfg-tz = <&rcc 0x000 0x1>; ++ resets = <&scmi0_reset RST_SCMI0_MCU>, ++ <&scmi0_reset RST_SCMI0_MCU_HOLD_BOOT>; ++ reset-names = "mcu_rst", "hold_boot"; + }; diff --git a/Documentation/remoteproc.txt b/Documentation/remoteproc.txt -index 03c3d2e56..5b217887b 100644 +index 03c3d2e568b04..5b217887b99c6 100644 --- a/Documentation/remoteproc.txt +++ b/Documentation/remoteproc.txt @@ -357,3 +357,25 @@ Of course, RSC_VDEV resource entries are only good enough for static @@ -64,7 +221,7 @@ index 03c3d2e56..5b217887b 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/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig -index ab4eb750b..7707ee262 100644 +index ab4eb750bbddc..7707ee26251a4 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -16,6 +16,13 @@ config ARM_MHU @@ -82,7 +239,7 @@ index ab4eb750b..7707ee262 100644 tristate "i.MX Mailbox" depends on ARCH_MXC || COMPILE_TEST diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile -index c22fad6f6..93918a84c 100644 +index c22fad6f696b7..93918a84c91b6 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o @@ -96,7 +253,7 @@ index c22fad6f6..93918a84c 100644 obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o diff --git a/drivers/mailbox/arm-smc-mailbox.c b/drivers/mailbox/arm-smc-mailbox.c new file mode 100644 -index 000000000..a6ec56f41 +index 0000000000000..a6ec56f41f7f8 --- /dev/null +++ b/drivers/mailbox/arm-smc-mailbox.c @@ -0,0 +1,166 @@ @@ -267,7 +424,7 @@ index 000000000..a6ec56f41 +MODULE_DESCRIPTION("Generic ARM smc mailbox driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c -index 5c2d1e1f9..ef966887a 100644 +index 5c2d1e1f988b8..ef966887aa151 100644 --- a/drivers/mailbox/stm32-ipcc.c +++ b/drivers/mailbox/stm32-ipcc.c @@ -52,7 +52,6 @@ struct stm32_ipcc { @@ -360,7 +517,7 @@ index 5c2d1e1f9..ef966887a 100644 writel_relaxed(ipcc->xcr, ipcc->reg_proc + IPCC_XCR); diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig -index 94afdde4b..9d1436ddf 100644 +index 94afdde4bc9f1..626c1e4502f32 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -14,6 +14,25 @@ config REMOTEPROC @@ -398,11 +555,27 @@ index 94afdde4b..9d1436ddf 100644 help Say y here to support STM32 MCU processors via the remote processor framework. +@@ -214,6 +235,15 @@ config STM32_RPROC + + This can be either built-in or a loadable module. + ++ ++config TEE_REMOTEPROC ++ tristate "trusted firmware Support by a Trusted Application" ++ depends on OPTEE ++ help ++ Support for trusted remote processors firmware. The firmware ++ authentication and/or decryption are managed by a trusted application. ++ This can be either built-in or a loadable module. ++ + endif # REMOTEPROC + + endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile -index 00f09e658..0e8bad12b 100644 +index 00f09e658cb34..692a9a85963b5 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile -@@ -9,6 +9,8 @@ remoteproc-y += remoteproc_debugfs.o +@@ -9,11 +9,14 @@ remoteproc-y += remoteproc_debugfs.o remoteproc-y += remoteproc_sysfs.o remoteproc-y += remoteproc_virtio.o remoteproc-y += remoteproc_elf_loader.o @@ -411,8 +584,14 @@ index 00f09e658..0e8bad12b 100644 obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o obj-$(CONFIG_OMAP_REMOTEPROC) += omap_remoteproc.o obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o + obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o + obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o ++obj-$(CONFIG_TEE_REMOTEPROC) += tee_remoteproc.o + obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o + obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o + obj-$(CONFIG_QCOM_Q6V5_ADSP) += qcom_q6v5_adsp.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c -index b542debbc..cdbec7fc3 100644 +index ce92ae227aa10..e71a27dbe5cc2 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -34,6 +34,7 @@ @@ -517,7 +696,7 @@ index b542debbc..cdbec7fc3 100644 ret = rproc_trigger_auto_boot(rproc); if (ret < 0) return ret; -@@ -2144,6 +2179,8 @@ int rproc_del(struct rproc *rproc) +@@ -2143,6 +2178,8 @@ int rproc_del(struct rproc *rproc) list_del(&rproc->node); mutex_unlock(&rproc_list_mutex); @@ -528,7 +707,7 @@ index b542debbc..cdbec7fc3 100644 return 0; diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c new file mode 100644 -index 000000000..fc61e8b35 +index 0000000000000..fc61e8b35686b --- /dev/null +++ b/drivers/remoteproc/rproc_srm_core.c @@ -0,0 +1,303 @@ @@ -837,7 +1016,7 @@ index 000000000..fc61e8b35 +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h new file mode 100644 -index 000000000..7dffdb38f +index 0000000000000..7dffdb38f4d46 --- /dev/null +++ b/drivers/remoteproc/rproc_srm_core.h @@ -0,0 +1,98 @@ @@ -941,7 +1120,7 @@ index 000000000..7dffdb38f +#endif diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c new file mode 100644 -index 000000000..6b164dad5 +index 0000000000000..6b164dad53ca1 --- /dev/null +++ b/drivers/remoteproc/rproc_srm_dev.c @@ -0,0 +1,744 @@ @@ -1690,10 +1869,10 @@ index 000000000..6b164dad5 +MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - dev"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index 2cf4b2992..061562405 100644 +index 2cf4b2992bfcd..9ff1d416761b7 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c -@@ -15,9 +15,11 @@ +@@ -15,15 +15,15 @@ #include #include #include @@ -1701,11 +1880,18 @@ index 2cf4b2992..061562405 100644 #include #include #include ++#include +#include #include "remoteproc_internal.h" -@@ -31,9 +33,20 @@ +-#define HOLD_BOOT 0 +-#define RELEASE_BOOT 1 +- + #define MBOX_NB_VQ 2 + #define MBOX_NB_MBX 3 + +@@ -31,9 +31,27 @@ #define STM32_SMC_REG_WRITE 0x1 #define STM32_MBX_VQ0 "vq0" @@ -1722,11 +1908,18 @@ index 2cf4b2992..061562405 100644 +#define COPRO_STATE_CSTOP 3 +#define COPRO_STATE_STANDBY 4 +#define COPRO_STATE_CRASH 5 ++ ++/* ++ * Define a default index in future may come a global list of ++ * firmwares which list platforms and associated firmware(s) ++ */ ++ ++#define STM32_MP1_FW_ID 0 + struct stm32_syscon { struct regmap *map; u32 reg; -@@ -58,6 +71,7 @@ struct stm32_mbox { +@@ -58,17 +76,29 @@ struct stm32_mbox { const unsigned char name[10]; struct mbox_chan *chan; struct mbox_client client; @@ -1734,22 +1927,31 @@ index 2cf4b2992..061562405 100644 int vq_id; }; -@@ -65,10 +79,14 @@ struct stm32_rproc { + struct stm32_rproc { struct reset_control *rst; - struct stm32_syscon hold_boot; +- struct stm32_syscon hold_boot; ++ struct reset_control *hold_boot; struct stm32_syscon pdds; + struct stm32_syscon copro_state; + int wdg_irq; u32 nb_rmems; struct stm32_rproc_mem *rmems; struct stm32_mbox mb[MBOX_NB_MBX]; +- bool secured_soc; + struct workqueue_struct *workqueue; - bool secured_soc; ++ bool secured_fw; ++ bool fw_loaded; ++ struct tee_rproc *trproc; + void __iomem *rsc_va; ++}; ++ ++struct stm32_rproc_conf { ++ bool secured_fw; ++ struct rproc_ops *ops; }; static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) -@@ -91,6 +109,28 @@ static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) +@@ -91,6 +121,28 @@ static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) return -EINVAL; } @@ -1778,7 +1980,7 @@ index 2cf4b2992..061562405 100644 static int stm32_rproc_mem_alloc(struct rproc *rproc, struct rproc_mem_entry *mem) { -@@ -120,6 +160,15 @@ static int stm32_rproc_mem_release(struct rproc *rproc, +@@ -120,6 +172,15 @@ static int stm32_rproc_mem_release(struct rproc *rproc, return 0; } @@ -1794,7 +1996,102 @@ index 2cf4b2992..061562405 100644 static int stm32_rproc_of_memory_translations(struct rproc *rproc) { struct device *parent, *dev = rproc->dev.parent; -@@ -190,9 +239,34 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) +@@ -187,12 +248,135 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) + return -EINVAL; + } + ++static int stm32_rproc_tee_elf_sanity_check(struct rproc *rproc, ++ const struct firmware *fw) ++{ ++ struct stm32_rproc *ddata = rproc->priv; ++ unsigned int ret = 0; ++ ++ if (!rproc->early_boot) { ++ ret = tee_rproc_load_fw(ddata->trproc, fw); ++ if (!ret) ++ ddata->fw_loaded = true; ++ } ++ ++ return ret; ++} ++ ++static int stm32_rproc_tee_elf_load(struct rproc *rproc, ++ const struct firmware *fw) ++{ ++ struct stm32_rproc *ddata = rproc->priv; ++ unsigned int ret; ++ ++ /* ++ * This function can be called by remote proc for recovery ++ * without the sanity check. In this case we need to load the firmware ++ * else nothing done here as the firmware has been preloaded for the ++ * sanity check to be able to parse it for the resource table ++ */ ++ if (!ddata->fw_loaded && !rproc->early_boot) { ++ ret = tee_rproc_load_fw(ddata->trproc, fw); ++ if (ret) ++ return ret; ++ /* update the resource table parameters */ ++ if (rproc_tee_get_rsc_table(ddata->trproc)) { ++ /* no resource table: reset the related fields */ ++ rproc->cached_table = NULL; ++ rproc->table_ptr = NULL; ++ rproc->table_sz = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++static struct resource_table * ++stm32_rproc_tee_elf_find_loaded_rsc_table(struct rproc *rproc, ++ const struct firmware *fw) ++{ ++ struct stm32_rproc *ddata = rproc->priv; ++ ++ return tee_rproc_get_loaded_rsc_table(ddata->trproc); ++} ++ ++static int stm32_rproc_tee_start(struct rproc *rproc) ++{ ++ struct stm32_rproc *ddata = rproc->priv; ++ ++ if (!rproc->early_boot) { ++ return tee_rproc_start(ddata->trproc); ++ } ++ ++ return 0; ++} ++ ++static int stm32_rproc_tee_stop(struct rproc *rproc) ++{ ++ struct stm32_rproc *ddata = rproc->priv; ++ int err, dummy_data, idx; ++ ++ /* request shutdown of the remote processor */ ++ if (rproc->state != RPROC_OFFLINE) { ++ idx = stm32_rproc_mbox_idx(rproc, STM32_MBX_SHUTDOWN); ++ if (idx >= 0 && ddata->mb[idx].chan) { ++ /* a dummy data is sent to allow to block on transmit */ ++ err = mbox_send_message(ddata->mb[idx].chan, ++ &dummy_data); ++ if (err < 0) ++ dev_warn(&rproc->dev, "warning: remote FW shutdown without ack\n"); ++ } ++ } ++ ++ err = tee_rproc_stop(ddata->trproc); ++ if (err) ++ return err; ++ ++ ddata->fw_loaded = false; ++ ++ /* Reset early_boot state as we stop the co-processor */ ++ rproc->early_boot = false; ++ ++ return 0; ++} ++ static int stm32_rproc_elf_load_rsc_table(struct rproc *rproc, const struct firmware *fw) { @@ -1802,6 +2099,12 @@ index 2cf4b2992..061562405 100644 - dev_warn(&rproc->dev, "no resource table found for this firmware\n"); + struct resource_table *table = NULL; + struct stm32_rproc *ddata = rproc->priv; + ++ if (ddata->trproc) { ++ if (rproc_tee_get_rsc_table(ddata->trproc)) ++ goto no_rsc_table; ++ return 0; ++ } + + if (!rproc->early_boot) { + if (rproc_elf_load_rsc_table(rproc, fw)) @@ -1822,16 +2125,16 @@ index 2cf4b2992..061562405 100644 + return 0; + } + ++no_rsc_table: + rproc->cached_table = NULL; + rproc->table_ptr = NULL; + rproc->table_sz = 0; - -+no_rsc_table: ++ + dev_warn(&rproc->dev, "no resource table found for this firmware\n"); return 0; } -@@ -252,6 +326,36 @@ static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) +@@ -252,6 +436,36 @@ static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) return stm32_rproc_elf_load_rsc_table(rproc, fw); } @@ -1850,10 +2153,10 @@ index 2cf4b2992..061562405 100644 +static int stm32_rproc_elf_sanity_check(struct rproc *rproc, + const struct firmware *fw) +{ -+ if (!rproc->early_boot) -+ return rproc_elf_sanity_check(rproc, fw); ++ if (rproc->early_boot) ++ return 0; + -+ return 0; ++ return rproc_elf_sanity_check(rproc, fw); +} + +static u32 stm32_rproc_elf_get_boot_addr(struct rproc *rproc, @@ -1868,7 +2171,7 @@ index 2cf4b2992..061562405 100644 static irqreturn_t stm32_rproc_wdg(int irq, void *data) { struct rproc *rproc = data; -@@ -261,13 +365,22 @@ static irqreturn_t stm32_rproc_wdg(int irq, void *data) +@@ -261,13 +475,22 @@ static irqreturn_t stm32_rproc_wdg(int irq, void *data) return IRQ_HANDLED; } @@ -1893,7 +2196,7 @@ index 2cf4b2992..061562405 100644 } static void stm32_rproc_free_mbox(struct rproc *rproc) -@@ -285,7 +398,7 @@ static void stm32_rproc_free_mbox(struct rproc *rproc) +@@ -285,7 +508,7 @@ static void stm32_rproc_free_mbox(struct rproc *rproc) static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { { .name = STM32_MBX_VQ0, @@ -1902,7 +2205,7 @@ index 2cf4b2992..061562405 100644 .client = { .rx_callback = stm32_rproc_mb_callback, .tx_block = false, -@@ -293,7 +406,7 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { +@@ -293,7 +516,7 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { }, { .name = STM32_MBX_VQ1, @@ -1911,7 +2214,7 @@ index 2cf4b2992..061562405 100644 .client = { .rx_callback = stm32_rproc_mb_callback, .tx_block = false, -@@ -310,7 +423,7 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { +@@ -310,7 +533,7 @@ static const struct stm32_mbox stm32_rproc_mbox[MBOX_NB_MBX] = { } }; @@ -1920,7 +2223,7 @@ index 2cf4b2992..061562405 100644 { struct stm32_rproc *ddata = rproc->priv; struct device *dev = &rproc->dev; -@@ -329,10 +442,18 @@ static void stm32_rproc_request_mbox(struct rproc *rproc) +@@ -329,34 +552,18 @@ static void stm32_rproc_request_mbox(struct rproc *rproc) ddata->mb[i].chan = mbox_request_channel_byname(cl, name); if (IS_ERR(ddata->mb[i].chan)) { @@ -1934,12 +2237,35 @@ index 2cf4b2992..061562405 100644 + stm32_rproc_mb_vq_work); + } } -+ +-} +- +-static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) +-{ +- struct stm32_rproc *ddata = rproc->priv; +- struct stm32_syscon hold_boot = ddata->hold_boot; +- struct arm_smccc_res smc_res; +- int val, err; +- +- val = hold ? HOLD_BOOT : RELEASE_BOOT; +- +- if (IS_ENABLED(CONFIG_HAVE_ARM_SMCCC) && ddata->secured_soc) { +- arm_smccc_smc(STM32_SMC_RCC, STM32_SMC_REG_WRITE, +- hold_boot.reg, val, 0, 0, 0, 0, &smc_res); +- err = smc_res.a0; +- } else { +- err = regmap_update_bits(hold_boot.map, hold_boot.reg, +- hold_boot.mask, val); +- } +- +- if (err) +- dev_err(&rproc->dev, "failed to set hold boot\n"); + +- return err; + return 0; } - static int stm32_rproc_set_hold_boot(struct rproc *rproc, bool hold) -@@ -389,7 +510,7 @@ static int stm32_rproc_start(struct rproc *rproc) + static void stm32_rproc_add_coredump_trace(struct rproc *rproc) +@@ -389,7 +596,7 @@ static int stm32_rproc_start(struct rproc *rproc) stm32_rproc_add_coredump_trace(rproc); /* clear remote proc Deep Sleep */ @@ -1948,7 +2274,7 @@ index 2cf4b2992..061562405 100644 err = regmap_update_bits(ddata->pdds.map, ddata->pdds.reg, ddata->pdds.mask, 0); if (err) { -@@ -398,9 +519,15 @@ static int stm32_rproc_start(struct rproc *rproc) +@@ -398,11 +605,17 @@ static int stm32_rproc_start(struct rproc *rproc) } } @@ -1960,14 +2286,31 @@ index 2cf4b2992..061562405 100644 + * is set to catch any crash. + */ + if (!rproc->early_boot) { -+ err = stm32_rproc_set_hold_boot(rproc, false); ++ err = reset_control_deassert(ddata->hold_boot); + if (err) + return err; + } - return stm32_rproc_set_hold_boot(rproc, true); +- return stm32_rproc_set_hold_boot(rproc, true); ++ return reset_control_assert(ddata->hold_boot); } -@@ -442,6 +569,21 @@ static int stm32_rproc_stop(struct rproc *rproc) + + static int stm32_rproc_stop(struct rproc *rproc) +@@ -422,9 +635,11 @@ static int stm32_rproc_stop(struct rproc *rproc) + } + } + +- err = stm32_rproc_set_hold_boot(rproc, true); +- if (err) ++ err = reset_control_assert(ddata->hold_boot); ++ if (err) { ++ dev_err(&rproc->dev, "failed to assert the hold boot\n"); + return err; ++ } + + err = reset_control_assert(ddata->rst); + if (err) { +@@ -442,6 +657,21 @@ static int stm32_rproc_stop(struct rproc *rproc) } } @@ -1989,7 +2332,7 @@ index 2cf4b2992..061562405 100644 return 0; } -@@ -471,11 +613,11 @@ static struct rproc_ops st_rproc_ops = { +@@ -471,15 +701,42 @@ static struct rproc_ops st_rproc_ops = { .start = stm32_rproc_start, .stop = stm32_rproc_stop, .kick = stm32_rproc_kick, @@ -2002,23 +2345,55 @@ index 2cf4b2992..061562405 100644 + .find_loaded_rsc_table = stm32_rproc_elf_find_loaded_rsc_table, + .sanity_check = stm32_rproc_elf_sanity_check, + .get_boot_addr = stm32_rproc_elf_get_boot_addr, ++}; ++ ++static struct rproc_ops st_rproc_tee_ops = { ++ .start = stm32_rproc_tee_start, ++ .stop = stm32_rproc_tee_stop, ++ .kick = stm32_rproc_kick, ++ .parse_fw = stm32_rproc_parse_fw, ++ .find_loaded_rsc_table = stm32_rproc_tee_elf_find_loaded_rsc_table, ++ .sanity_check = stm32_rproc_tee_elf_sanity_check, ++ .load = stm32_rproc_tee_elf_load, ++}; ++ ++static const struct stm32_rproc_conf stm32_rproc_default_conf = { ++ .secured_fw = false, ++ .ops = &st_rproc_ops, ++}; ++ ++static const struct stm32_rproc_conf stm32_rproc_tee_conf = { ++ .secured_fw = true, ++ .ops = &st_rproc_tee_ops, }; static const struct of_device_id stm32_rproc_match[] = { -@@ -512,8 +654,10 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) +- { .compatible = "st,stm32mp1-m4" }, ++ { ++ .compatible = "st,stm32mp1-m4", ++ .data = &stm32_rproc_default_conf, ++ }, ++ { ++ .compatible = "st,stm32mp1-m4_optee", ++ .data = &stm32_rproc_tee_conf, ++ }, + {}, + }; + MODULE_DEVICE_TABLE(of, stm32_rproc_match); +@@ -512,8 +769,10 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) struct device_node *np = dev->of_node; struct rproc *rproc = platform_get_drvdata(pdev); struct stm32_rproc *ddata = rproc->priv; - struct stm32_syscon tz; - unsigned int tzen; -+ struct stm32_syscon tz, rsctbl; ++ struct stm32_syscon rsctbl; + phys_addr_t rsc_pa; + u32 rsc_da; -+ unsigned int tzen, state; ++ unsigned int state; int err, irq; irq = platform_get_irq(pdev, 0); -@@ -528,12 +672,21 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) +@@ -528,47 +787,90 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) return err; } @@ -2032,7 +2407,8 @@ index 2cf4b2992..061562405 100644 dev_info(dev, "wdg irq registered\n"); } - ddata->rst = devm_reset_control_get_by_index(dev, 0); +- ddata->rst = devm_reset_control_get_by_index(dev, 0); ++ ddata->rst = devm_reset_control_get(dev, "mcu_rst"); if (IS_ERR(ddata->rst)) { - dev_err(dev, "failed to get mcu reset\n"); + if (PTR_ERR(ddata->rst) != -EPROBE_DEFER) @@ -2041,19 +2417,35 @@ index 2cf4b2992..061562405 100644 return PTR_ERR(ddata->rst); } -@@ -564,11 +717,62 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev) +- /* +- * if platform is secured the hold boot bit must be written by +- * smc call and read normally. +- * if not secure the hold boot bit could be read/write normally +- */ +- err = stm32_rproc_get_syscon(np, "st,syscfg-tz", &tz); +- if (err) { +- dev_err(dev, "failed to get tz syscfg\n"); +- return err; ++ ddata->hold_boot = devm_reset_control_get(dev, "hold_boot"); ++ if (IS_ERR(ddata->hold_boot)) { ++ if (PTR_ERR(ddata->hold_boot) != -EPROBE_DEFER) ++ dev_err(dev, "failed to get mcu reset\n"); ++ ++ return PTR_ERR(ddata->hold_boot); + } - err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); - if (err) -- dev_warn(dev, "failed to get pdds\n"); +- err = regmap_read(tz.map, tz.reg, &tzen); +- if (err) { +- dev_err(&rproc->dev, "failed to read tzen\n"); ++ err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); ++ if (err) + dev_warn(dev, "pdds not supported\n"); - - rproc->auto_boot = of_property_read_bool(np, "st,auto-boot"); - -- return stm32_rproc_of_memory_translations(rproc); ++ ++ rproc->auto_boot = of_property_read_bool(np, "st,auto-boot"); ++ + err = stm32_rproc_of_memory_translations(rproc); + if (err) -+ return err; + return err; + + /* check if the coprocessor has been started from the bootloader */ + err = stm32_rproc_get_syscon(np, "st,syscfg-copro-state", @@ -2062,24 +2454,33 @@ index 2cf4b2992..061562405 100644 + /* no copro_state syscon (optional) */ + dev_warn(dev, "copro_state not supported\n"); + goto bail; -+ } -+ + } +- ddata->secured_soc = tzen & tz.mask; + +- err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot", +- &ddata->hold_boot); + err = regmap_read(ddata->copro_state.map, ddata->copro_state.reg, + &state); -+ if (err) { + if (err) { +- dev_err(dev, "failed to get hold boot\n"); + dev_err(&rproc->dev, "failed to read copro state\n"); -+ return err; -+ } -+ + return err; + } + +- err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); +- if (err) +- dev_warn(dev, "failed to get pdds\n"); + if (state == COPRO_STATE_CRUN) { + rproc->early_boot = true; -+ + +- rproc->auto_boot = of_property_read_bool(np, "st,auto-boot"); + 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; + } -+ + +- return stm32_rproc_of_memory_translations(rproc); + err = regmap_read(rsctbl.map, rsctbl.reg, &rsc_da); + if (err) { + dev_err(&rproc->dev, "failed to read rsc tbl addr\n"); @@ -2106,10 +2507,33 @@ index 2cf4b2992..061562405 100644 } static int stm32_rproc_probe(struct platform_device *pdev) -@@ -589,14 +793,28 @@ static int stm32_rproc_probe(struct platform_device *pdev) +@@ -576,6 +878,8 @@ static int stm32_rproc_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct stm32_rproc *ddata; + struct device_node *np = dev->of_node; ++ const struct of_device_id *of_id; ++ const struct stm32_rproc_conf *conf; + struct rproc *rproc; + int ret; + +@@ -583,30 +887,69 @@ static int stm32_rproc_probe(struct platform_device *pdev) + if (ret) + return ret; + +- rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); ++ of_id = of_match_device(stm32_rproc_match, &pdev->dev); ++ if (of_id) ++ conf = (const struct stm32_rproc_conf *)of_id->data; ++ else ++ return -EINVAL; ++ ++ rproc = rproc_alloc(dev, np->name, conf->ops, NULL, sizeof(*ddata)); + if (!rproc) + return -ENOMEM; rproc->has_iommu = false; ddata = rproc->priv; ++ ddata->secured_fw = conf->secured_fw; + ddata->workqueue = create_workqueue(dev_name(dev)); + if (!ddata->workqueue) { + dev_err(dev, "cannot create workqueue\n"); @@ -2123,22 +2547,37 @@ index 2cf4b2992..061562405 100644 if (ret) - goto free_rproc; + goto free_wkq; - -- stm32_rproc_request_mbox(rproc); -+ if (!rproc->early_boot) { ++ ++ if (!rproc->early_boot && !ddata->secured_fw) { + ret = stm32_rproc_stop(rproc); + if (ret) + goto free_wkq; + } -+ + +- stm32_rproc_request_mbox(rproc); + ret = stm32_rproc_request_mbox(rproc); + if (ret) + goto free_wkq; ++ ++ if (ddata->secured_fw) { ++ ddata->trproc = tee_rproc_register(dev, rproc, ++ STM32_MP1_FW_ID); ++ if (IS_ERR_OR_NULL(ddata->trproc)) { ++ ret = -EPROBE_DEFER; ++ goto free_mb; ++ } ++ } ret = rproc_add(rproc); if (ret) -@@ -606,7 +824,13 @@ static int stm32_rproc_probe(struct platform_device *pdev) +- goto free_mb; ++ goto free_tee; + return 0; + ++free_tee: ++ if (ddata->trproc) ++ tee_rproc_unregister(ddata->trproc); free_mb: stm32_rproc_free_mbox(rproc); +free_wkq: @@ -2151,7 +2590,7 @@ index 2cf4b2992..061562405 100644 rproc_free(rproc); return ret; } -@@ -614,22 +838,68 @@ static int stm32_rproc_probe(struct platform_device *pdev) +@@ -614,22 +957,70 @@ static int stm32_rproc_probe(struct platform_device *pdev) static int stm32_rproc_remove(struct platform_device *pdev) { struct rproc *rproc = platform_get_drvdata(pdev); @@ -2162,6 +2601,8 @@ index 2cf4b2992..061562405 100644 rproc_shutdown(rproc); rproc_del(rproc); ++ if (ddata->trproc) ++ tee_rproc_unregister(ddata->trproc); stm32_rproc_free_mbox(rproc); + destroy_workqueue(ddata->workqueue); + @@ -2220,8 +2661,393 @@ index 2cf4b2992..061562405 100644 .of_match_table = of_match_ptr(stm32_rproc_match), }, }; +diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c +new file mode 100644 +index 0000000000000..e48887d3de7c0 +--- /dev/null ++++ b/drivers/remoteproc/tee_remoteproc.c +@@ -0,0 +1,379 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Copyright (C) STMicroelectronics 2020 - All Rights Reserved ++ * Authors: Arnaud Pouliquen ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "remoteproc_internal.h" ++ ++#define MAX_TEE_PARAM_ARRY_MEMBER 4 ++ ++/* ++ * Authentication of the firmware and load in the remote processor memory ++ * ++ * [in] params[0].value.a: unique 32bit identifier of the firmware ++ * [in] params[1].memref: buffer containing the image of the buffer ++ */ ++#define TA_RPROC_FW_CMD_LOAD_FW 1 ++ ++/* ++ * start the remote processor ++ * ++ * [in] params[0].value.a: unique 32bit identifier of the firmware ++ */ ++#define TA_RPROC_FW_CMD_START_FW 2 ++ ++/* ++ * stop the remote processor ++ * ++ * [in] params[0].value.a: unique 32bit identifier of the firmware ++ */ ++#define TA_RPROC_FW_CMD_STOP_FW 3 ++ ++/* ++ * return the address of the resource table, or 0 if not found ++ * No chech is done to verify that the address returned is accessible by ++ * the non secure context. If the resource table is loaded in a protected ++ * memory the acces by the non secure context will lead to a data abort. ++ * ++ * [in] params[0].value.a: unique 32bit identifier of the firmware ++ * [out] params[1].value.a: 32bit LSB resource table memory address ++ * [out] params[1].value.b: 32bit MSB resource table memory address ++ * [out] params[2].value.a: 32bit LSB resource table memory size ++ * [out] params[2].value.b: 32bit MSB resource table memory size ++ */ ++#define TA_RPROC_FW_CMD_GET_RSC_TABLE 4 ++ ++/* ++ * return the address of the core dump ++ * ++ * [in] params[0].value.a: unique 32bit identifier of the firmware ++ * [out] params[1].memref: address of the core dump image if exist, ++ * else return Null ++ */ ++#define TA_RPROC_FW_CMD_GET_COREDUMP 5 ++ ++struct tee_rproc_mem { ++ char name[20]; ++ void __iomem *cpu_addr; ++ phys_addr_t bus_addr; ++ u32 dev_addr; ++ size_t size; ++}; ++ ++struct tee_rproc_context { ++ struct list_head sessions; ++ struct tee_context *ctx; ++ struct device *dev; ++}; ++ ++struct tee_rproc_context pvt_data; ++ ++static void prepare_args(struct tee_rproc *trproc, int cmd, ++ struct tee_ioctl_invoke_arg *arg, ++ struct tee_param *param, unsigned int num_params) ++{ ++ memset(arg, 0, sizeof(*arg)); ++ memset(param, 0, MAX_TEE_PARAM_ARRY_MEMBER * sizeof(*param)); ++ ++ arg->func = cmd; ++ arg->session = trproc->session_id; ++ arg->num_params = num_params + 1; ++ ++ param[0] = (struct tee_param) { ++ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, ++ .u.value.a = trproc->fw_id, ++ }; ++} ++ ++int tee_rproc_load_fw(struct tee_rproc *trproc, const struct firmware *fw) ++{ ++ struct tee_ioctl_invoke_arg arg; ++ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; ++ struct tee_shm *fw_shm; ++ int ret; ++ ++ /* ++ * useless copy waiting that tee_shm_register and tee well support ++ * kernel buffers registration ++ */ ++ ++ fw_shm = tee_shm_alloc(pvt_data.ctx, fw->size, ++ TEE_SHM_MAPPED | TEE_SHM_DMA_BUF); ++ if (IS_ERR(fw_shm)) ++ return PTR_ERR(fw_shm); ++ ++ memcpy(tee_shm_get_va(fw_shm, 0), fw->data, fw->size); ++ ++ prepare_args(trproc, TA_RPROC_FW_CMD_LOAD_FW, &arg, param, 1); ++ ++ /* provide the address of the firmware image */ ++ param[1] = (struct tee_param) { ++ .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT, ++ .u.memref = { ++ .shm = fw_shm, ++ .size = fw->size, ++ .shm_offs = 0, ++ }, ++ }; ++ ++ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); ++ if (ret < 0 || arg.ret != 0) { ++ dev_err(pvt_data.dev, ++ "TA_RPROC_FW_CMD_LOAD_FW invoke failed TEE err: %x, ret:%x\n", ++ arg.ret, ret); ++ if (!ret) ++ ret = -EIO; ++ } ++ ++ tee_shm_free(fw_shm); ++ ++ return ret; ++} ++EXPORT_SYMBOL(tee_rproc_load_fw); ++ ++int rproc_tee_get_rsc_table(struct tee_rproc *trproc) ++{ ++ struct tee_ioctl_invoke_arg arg; ++ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; ++ struct rproc *rproc = trproc->rproc; ++ size_t rsc_size; ++ int ret; ++ ++ prepare_args(trproc, TA_RPROC_FW_CMD_GET_RSC_TABLE, &arg, param, 2); ++ ++ param[1].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ++ param[2].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT; ++ ++ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); ++ if (ret < 0 || arg.ret != 0) { ++ dev_err(pvt_data.dev, ++ "TA_RPROC_FW_CMD_GET_RSC_TABLE invoke failed TEE err: %x, ret:%x\n", ++ arg.ret, ret); ++ return -EIO; ++ } ++ ++ rsc_size = param[2].u.value.a; ++ ++ /* ++ * Store the resource table address that would be updated by the remote ++ * core and the virtio. ++ */ ++ trproc->rsc_va = ioremap_wc(param[1].u.value.a, rsc_size); ++ if (IS_ERR_OR_NULL(trproc->rsc_va)) { ++ dev_err(pvt_data.dev, "Unable to map memory region: %lld+%zx\n", ++ param[1].u.value.a, rsc_size); ++ trproc->rsc_va = NULL; ++ return -ENOMEM; ++ } ++ ++ /* ++ * A cached table is requested as the physical address is not mapped yet ++ * but remoteproc need to parse the table for resources. ++ */ ++ rproc->cached_table = kmemdup(trproc->rsc_va, rsc_size, GFP_KERNEL); ++ if (!rproc->cached_table) ++ return -ENOMEM; ++ ++ rproc->table_ptr = rproc->cached_table; ++ rproc->table_sz = rsc_size; ++ ++ return 0; ++} ++EXPORT_SYMBOL(rproc_tee_get_rsc_table); ++ ++struct resource_table *tee_rproc_get_loaded_rsc_table(struct tee_rproc *trproc) ++{ ++ return (struct resource_table *)trproc->rsc_va; ++} ++EXPORT_SYMBOL(tee_rproc_get_loaded_rsc_table); ++ ++int tee_rproc_start(struct tee_rproc *trproc) ++{ ++ struct tee_ioctl_invoke_arg arg; ++ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; ++ int ret; ++ ++ prepare_args(trproc, TA_RPROC_FW_CMD_START_FW, &arg, param, 0); ++ ++ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); ++ if (ret < 0 || arg.ret != 0) { ++ dev_err(pvt_data.dev, ++ "TA_RPROC_FW_CMD_START_FW invoke failed TEE err: %x, ret:%x\n", ++ arg.ret, ret); ++ if (!ret) ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL(tee_rproc_start); ++ ++int tee_rproc_stop(struct tee_rproc *trproc) ++{ ++ struct tee_ioctl_invoke_arg arg; ++ struct tee_param param[MAX_TEE_PARAM_ARRY_MEMBER]; ++ int ret; ++ ++ prepare_args(trproc, TA_RPROC_FW_CMD_STOP_FW, &arg, param, 0); ++ ++ ret = tee_client_invoke_func(pvt_data.ctx, &arg, param); ++ if (ret < 0 || arg.ret != 0) { ++ dev_err(pvt_data.dev, ++ "TA_RPROC_FW_CMD_STOP_FW invoke failed TEE err: %x, ret:%x\n", ++ arg.ret, ret); ++ if (!ret) ++ ret = -EIO; ++ } ++ if (trproc->rsc_va) ++ iounmap(trproc->rsc_va); ++ trproc->rsc_va = NULL; ++ ++ return ret; ++} ++EXPORT_SYMBOL(tee_rproc_stop); ++ ++static const struct tee_client_device_id stm32_tee_fw_id_table[] = { ++ {UUID_INIT(0x80a4c275, 0x0a47, 0x4905, ++ 0x82, 0x85, 0x14, 0x86, 0xa9, 0x77, 0x1a, 0x08)}, ++ {} ++}; ++ ++struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, ++ unsigned int fw_id) ++{ ++ struct tee_client_device *rproc_tee_device; ++ struct tee_ioctl_open_session_arg sess_arg; ++ struct tee_rproc *trproc; ++ int ret; ++ ++ if (!pvt_data.ctx) ++ return ERR_PTR(-ENODEV); ++ ++ trproc = devm_kzalloc(dev, sizeof(*trproc), GFP_KERNEL); ++ if (!trproc) ++ return ERR_PTR(-ENOMEM); ++ ++ rproc_tee_device = to_tee_client_device(pvt_data.dev); ++ memset(&sess_arg, 0, sizeof(sess_arg)); ++ ++ /* Open session with rproc_tee load Trusted App */ ++ memcpy(sess_arg.uuid, rproc_tee_device->id.uuid.b, TEE_IOCTL_UUID_LEN); ++ ++ /* ++ * TODO: should we replace TEE_IOCTL_LOGIN_PUBLIC by ++ * TEE_IOCTL_LOGIN_REE_KERNEL? ++ */ ++ sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC; ++ sess_arg.num_params = 0; ++ ++ ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL); ++ if (ret < 0 || sess_arg.ret != 0) { ++ dev_err(dev, "tee_client_open_session failed, err: %x\n", ++ sess_arg.ret); ++ return ERR_PTR(ret); ++ } ++ ++ trproc->rproc = rproc; ++ trproc->parent = dev; ++ trproc->fw_id = fw_id; ++ trproc->session_id = sess_arg.session; ++ ++ list_add_tail(&trproc->node, &pvt_data.sessions); ++ ++ return trproc; ++} ++EXPORT_SYMBOL(tee_rproc_register); ++ ++int tee_rproc_unregister(struct tee_rproc *trproc) ++{ ++ int ret; ++ ++ if (!pvt_data.ctx) ++ return -ENODEV; ++ ++ ret = tee_client_close_session(pvt_data.ctx, trproc->session_id); ++ if (ret < 0) { ++ dev_err(trproc->parent, ++ "tee_client_close_session failed, err: %x\n", ret); ++ } ++ ++ list_del(&trproc->node); ++ ++ return ret; ++} ++EXPORT_SYMBOL(tee_rproc_unregister); ++ ++static int tee_ctx_match(struct tee_ioctl_version_data *ver, const void *data) ++{ ++ /* Today we support only the OP-TEE, could be extend to other tees */ ++ return (ver->impl_id == TEE_IMPL_ID_OPTEE); ++} ++ ++static int tee_rproc_probe(struct device *dev) ++{ ++ /* Open context with TEE driver */ ++ pvt_data.ctx = tee_client_open_context(NULL, tee_ctx_match, NULL, ++ NULL); ++ if (IS_ERR(pvt_data.ctx)) ++ return -ENODEV; ++ ++ pvt_data.dev = dev; ++ INIT_LIST_HEAD(&pvt_data.sessions); ++ ++ return 0; ++} ++ ++static int tee_rproc_remove(struct device *dev) ++{ ++ struct tee_rproc *entry, *tmp; ++ ++ list_for_each_entry_safe(entry, tmp, &pvt_data.sessions, node) { ++ tee_client_close_session(pvt_data.ctx, entry->session_id); ++ list_del(&entry->node); ++ kfree(entry); ++ } ++ ++ tee_client_close_context(pvt_data.ctx); ++ return 0; ++} ++ ++MODULE_DEVICE_TABLE(tee, stm32_tee_fw_id_table); ++ ++static struct tee_client_driver tee_rproc_fw_driver = { ++ .id_table = stm32_tee_fw_id_table, ++ .driver = { ++ .name = KBUILD_MODNAME, ++ .bus = &tee_bus_type, ++ .probe = tee_rproc_probe, ++ .remove = tee_rproc_remove, ++ }, ++}; ++ ++static int __init tee_rproc_fw_mod_init(void) ++{ ++ return driver_register(&tee_rproc_fw_driver.driver); ++} ++ ++static void __exit tee_rproc_fw_mod_exit(void) ++{ ++ driver_unregister(&tee_rproc_fw_driver.driver); ++} ++ ++module_init(tee_rproc_fw_mod_init); ++module_exit(tee_rproc_fw_mod_exit); ++ ++MODULE_DESCRIPTION("secure remote processor control driver"); ++MODULE_AUTHOR("Arnaud Pouliquen "); ++MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig -index d0322b41e..88759a4c9 100644 +index d0322b41eca54..88759a4c90e43 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -55,4 +55,13 @@ config RPMSG_VIRTIO @@ -2239,7 +3065,7 @@ index d0322b41e..88759a4c9 100644 + endmenu diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile -index 9aa859502..107145c63 100644 +index 9aa859502d275..107145c6316b0 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK_RPM) += qcom_glink_rpm.o @@ -2249,7 +3075,7 @@ index 9aa859502..107145c63 100644 +obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c -index e330ec4df..48f24503f 100644 +index e330ec4dfc337..48f24503fb34e 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -283,6 +283,25 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, @@ -2279,7 +3105,7 @@ index e330ec4df..48f24503f 100644 * match an rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h -index 3fc83cd50..244292540 100644 +index 3fc83cd50e98f..244292540e583 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -47,6 +47,7 @@ struct rpmsg_device_ops { @@ -2300,10 +3126,10 @@ index 3fc83cd50..244292540 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 000000000..57763898e +index 0000000000000..d1cccdff8ed1e --- /dev/null +++ b/drivers/rpmsg/rpmsg_tty.c -@@ -0,0 +1,310 @@ +@@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved @@ -2328,7 +3154,7 @@ index 000000000..57763898e +static struct tty_port_operations rpmsg_tty_port_ops = { }; + +struct rpmsg_tty_port { -+ struct tty_port port; /* TTY port data */ ++ struct tty_port *port; /* TTY port data */ + struct list_head list; /* TTY device list */ + u32 id; /* tty rpmsg index */ + spinlock_t rx_lock; /* message reception lock */ @@ -2352,7 +3178,7 @@ index 000000000..57763898e + true); + + spin_lock(&cport->rx_lock); -+ space = tty_prepare_flip_string(&cport->port, &cbuf, len); ++ space = tty_prepare_flip_string(cport->port, &cbuf, len); + if (space <= 0) { + dev_err(&rpdev->dev, "No memory for tty_prepare_flip_string\n"); + spin_unlock(&cport->rx_lock); @@ -2364,7 +3190,7 @@ index 000000000..57763898e + len, space); + + memcpy(cbuf, data, space); -+ tty_flip_buffer_push(&cport->port); ++ tty_flip_buffer_push(cport->port); + spin_unlock(&cport->rx_lock); + + return 0; @@ -2376,7 +3202,7 @@ index 000000000..57763898e + + mutex_lock(&rpmsg_tty_lock); + list_for_each_entry(cport, &rpmsg_tty_list, list) { -+ if (index == cport->id) { ++ if (index == cport->id) { + mutex_unlock(&rpmsg_tty_lock); + return cport; + } @@ -2393,7 +3219,7 @@ index 000000000..57763898e + if (!cport) + return -ENODEV; + -+ return tty_port_install(&cport->port, driver, tty); ++ return tty_port_install(cport->port, driver, tty); +} + +static int rpmsg_tty_open(struct tty_struct *tty, struct file *filp) @@ -2408,11 +3234,7 @@ index 000000000..57763898e + +static void rpmsg_tty_close(struct tty_struct *tty, struct file *filp) +{ -+ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); -+ -+ if (!cport) -+ return; -+ return tty_port_close(tty->port, tty, filp); ++ tty_port_close(tty->port, tty, filp); +} + +static int rpmsg_tty_write(struct tty_struct *tty, const unsigned char *buf, @@ -2420,8 +3242,8 @@ index 000000000..57763898e +{ + int count, ret = 0; + const unsigned char *tbuf; -+ struct rpmsg_tty_port *cport = container_of(tty->port, -+ struct rpmsg_tty_port, port); ++ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); ++ + struct rpmsg_device *rpdev = cport->rpdev; + int msg_size; + @@ -2461,8 +3283,7 @@ index 000000000..57763898e + +static int rpmsg_tty_write_room(struct tty_struct *tty) +{ -+ struct rpmsg_tty_port *cport = container_of(tty->port, -+ struct rpmsg_tty_port, port); ++ struct rpmsg_tty_port *cport = rpmsg_tty_get(tty->index); + struct rpmsg_device *rpdev = cport->rpdev; + + /* report the space in the rpmsg buffer */ @@ -2482,26 +3303,20 @@ index 000000000..57763898e + struct rpmsg_tty_port *cport, *tmp; + unsigned int index; + struct device *tty_dev; ++ int ret = 0; + + cport = devm_kzalloc(&rpdev->dev, sizeof(*cport), GFP_KERNEL); + if (!cport) + return -ENOMEM; + -+ tty_port_init(&cport->port); -+ cport->port.ops = &rpmsg_tty_port_ops; -+ spin_lock_init(&cport->rx_lock); -+ -+ cport->port.low_latency = cport->port.flags | ASYNC_LOW_LATENCY; -+ -+ cport->rpdev = rpdev; -+ -+ /* get free index */ + mutex_lock(&rpmsg_tty_lock); ++ ++ /* Get free index */ + for (index = 0; index < MAX_TTY_RPMSG_INDEX; index++) { + bool id_found = false; + + list_for_each_entry(tmp, &rpmsg_tty_list, list) { -+ if (index == tmp->id) { ++ if (index == tmp->id) { + id_found = true; + break; + } @@ -2510,35 +3325,69 @@ index 000000000..57763898e + break; + } + -+ tty_dev = tty_port_register_device(&cport->port, rpmsg_tty_driver, ++ if (index >= MAX_TTY_RPMSG_INDEX) { ++ ret = -ENOSPC; ++ goto end_probe; ++ } ++ ++ /* ++ * the tty port allocation has to be independent from the tty device ++ * The reason is that it can be use after device removing, for instance ++ * if a user has opened it. ++ * So it is not possible to release the port on device remove. ++ * A solution is to store the port in the driver structure. The port ++ * structure is reused on next probe to save memory. ++ */ ++ if (!rpmsg_tty_driver->ports[index]) { ++ /* first allocation of the port associated to the index */ ++ rpmsg_tty_driver->ports[index] = kzalloc(sizeof(*cport->port), ++ GFP_KERNEL); ++ if (!rpmsg_tty_driver->ports[index]) { ++ ret = -ENOMEM; ++ goto end_probe; ++ } ++ } ++ ++ cport->port = rpmsg_tty_driver->ports[index]; ++ tty_port_init(cport->port); ++ cport->port->ops = &rpmsg_tty_port_ops; ++ ++ spin_lock_init(&cport->rx_lock); ++ cport->port->low_latency = cport->port->flags | ASYNC_LOW_LATENCY; ++ cport->rpdev = rpdev; ++ ++ tty_dev = tty_port_register_device(cport->port, rpmsg_tty_driver, + index, &rpdev->dev); + if (IS_ERR(tty_dev)) { + dev_err(&rpdev->dev, "failed to register tty port\n"); -+ tty_port_destroy(&cport->port); -+ mutex_unlock(&rpmsg_tty_lock); -+ return PTR_ERR(tty_dev); ++ tty_port_destroy(cport->port); ++ ret = PTR_ERR(tty_dev); ++ goto end_probe; + } + + cport->id = index; + list_add_tail(&cport->list, &rpmsg_tty_list); -+ mutex_unlock(&rpmsg_tty_lock); + dev_set_drvdata(&rpdev->dev, cport); + + dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x : ttyRPMSG%d\n", + rpdev->src, rpdev->dst, index); ++end_probe: ++ mutex_unlock(&rpmsg_tty_lock); + -+ return 0; ++ return ret; +} + +static void rpmsg_tty_remove(struct rpmsg_device *rpdev) +{ + struct rpmsg_tty_port *cport = dev_get_drvdata(&rpdev->dev); ++ struct tty_struct *tty; + -+ /* User hang up to release the tty */ -+ if (tty_port_initialized(&cport->port)) -+ tty_port_tty_hangup(&cport->port, false); -+ tty_port_destroy(&cport->port); + tty_unregister_device(rpmsg_tty_driver, cport->id); ++ tty = tty_port_tty_get(cport->port); ++ if (tty) { ++ tty_vhangup(cport->port->tty); ++ tty_kref_put(tty); ++ } + list_del(&cport->list); + + dev_info(&rpdev->dev, "rpmsg tty device %d is removed\n", cport->id); @@ -2603,8 +3452,14 @@ index 000000000..57763898e + +static void __exit rpmsg_tty_exit(void) +{ ++ unsigned int index; ++ + unregister_rpmsg_driver(&rpmsg_tty_rmpsg_drv); + tty_unregister_driver(rpmsg_tty_driver); ++ ++ /* release port allocations */ ++ for (index = 0; index < MAX_TTY_RPMSG_INDEX; index++) ++ kfree(rpmsg_tty_driver->ports[index]); + put_tty_driver(rpmsg_tty_driver); +} + @@ -2615,7 +3470,7 @@ index 000000000..57763898e +MODULE_DESCRIPTION("virtio remote processor messaging tty driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c -index 376ebbf88..31b6d053f 100644 +index 376ebbf880d66..31b6d053f8ff0 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -175,6 +175,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, @@ -2652,7 +3507,7 @@ index 376ebbf88..31b6d053f 100644 { diff --git a/include/linux/mailbox/arm-smccc-mbox.h b/include/linux/mailbox/arm-smccc-mbox.h new file mode 100644 -index 000000000..d35fb89a7 +index 0000000000000..d35fb89a77f52 --- /dev/null +++ b/include/linux/mailbox/arm-smccc-mbox.h @@ -0,0 +1,20 @@ @@ -2677,7 +3532,7 @@ index 000000000..d35fb89a7 + +#endif /* _LINUX_ARM_SMCCC_MBOX_H_ */ diff --git a/include/linux/remoteproc.h b/include/linux/remoteproc.h -index 16ad66683..221f98b73 100644 +index 16ad66683ad0a..221f98b73b09c 100644 --- a/include/linux/remoteproc.h +++ b/include/linux/remoteproc.h @@ -481,6 +481,7 @@ struct rproc_dump_segment { @@ -2697,7 +3552,7 @@ index 16ad66683..221f98b73 100644 /** diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h -index 9fe156d1c..2af767403 100644 +index 9fe156d1c018e..2af7674035aa7 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -135,6 +135,7 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, @@ -2723,6 +3578,118 @@ index 9fe156d1c..2af767403 100644 #endif /* IS_ENABLED(CONFIG_RPMSG) */ /* use a macro to avoid include chaining to get THIS_MODULE */ +diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h +new file mode 100644 +index 0000000000000..5d2d6ae492d0d +--- /dev/null ++++ b/include/linux/tee_remoteproc.h +@@ -0,0 +1,106 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Copyright(c) 2020 STMicroelectronics 2020 ++ */ ++ ++#ifndef TEE_REMOTEPROC_H ++#define TEE_REMOTEPROC_H ++ ++#include ++#include ++ ++/** ++ * struct tee_rproc - TEE remoteproc structure ++ * @node: Reference in list ++ * @rproc: Remoteproc reference ++ * @parent: Parent device ++ * @fw_id: Identifier of the target firmware ++ * @session_id: TEE session identifier ++ * @rsc_va: Resource table virtual address. ++ */ ++struct tee_rproc { ++ struct list_head node; ++ ++ struct rproc *rproc; ++ struct device *parent; ++ u32 fw_id; ++ u32 session_id; ++ void *rsc_va; ++}; ++ ++#if IS_ENABLED(CONFIG_TEE_REMOTEPROC) ++ ++struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, ++ unsigned int fw_id); ++int tee_rproc_unregister(struct tee_rproc *trproc); ++ ++int tee_rproc_load_fw(struct tee_rproc *trproc, const struct firmware *fw); ++int rproc_tee_get_rsc_table(struct tee_rproc *trproc); ++struct resource_table *tee_rproc_get_loaded_rsc_table(struct tee_rproc *trproc); ++int tee_rproc_start(struct tee_rproc *trproc); ++int tee_rproc_stop(struct tee_rproc *trproc); ++ ++#else ++ ++static inline struct tee_rproc *tee_rproc_register(struct device *dev, ++ struct rproc *rproc, ++ unsigned int fw_id) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return NULL; ++} ++ ++static inline int tee_rproc_unregister(struct tee_rproc *trproc) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return 0; ++} ++ ++static inline int tee_rproc_load_fw(struct tee_rproc *trproc, ++ const struct firmware *fw) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return 0; ++} ++ ++static inline int tee_rproc_start(struct tee_rproc *trproc) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return 0; ++} ++ ++static inline int tee_rproc_stop(struct tee_rproc *trproc) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return 0; ++} ++ ++static inline int rproc_tee_get_rsc_table(struct tee_rproc *trproc) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return 0; ++} ++ ++static inline struct resource_table * ++ tee_rproc_get_loaded_rsc_table(struct tee_rproc *trproc) ++{ ++ /* This shouldn't be possible */ ++ WARN_ON(1); ++ ++ return NULL; ++} ++ ++#endif /* CONFIG_TEE_REMOTEPROC */ ++#endif /* TEE_REMOTEPROC_H */ -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0011-ARM-stm32mp1-r2-RESET-RTC-WATCHDOG.patch similarity index 70% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0011-ARM-stm32mp1-r2-RESET-RTC-WATCHDOG.patch index 858673c..a7af3aa 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0011-ARM-stm32mp1-r2-RESET-RTC-WATCHDOG.patch @@ -1,17 +1,49 @@ -From 835fe45ed0a3c0ef8cb2b74a900d227a124b4761 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:44:22 +0200 -Subject: [PATCH 11/23] ARM-stm32mp1-r1-RESET-RTC-WATCHDOG +From 60ca74ac3c89a476b38d4f41c3bea3745779587e Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:46 +0200 +Subject: [PATCH 11/22] ARM-stm32mp1-r2-rc8-RESET-RTC-WATCHDOG --- - drivers/reset/reset-stm32mp1.c | 83 +++++++++++------ - drivers/rtc/Kconfig | 1 + - drivers/rtc/rtc-stm32.c | 159 +++++++++++++++++++++++++++------ - drivers/watchdog/stm32_iwdg.c | 6 +- - 4 files changed, 192 insertions(+), 57 deletions(-) + .../devicetree/bindings/rtc/st,stm32-rtc.txt | 10 +- + drivers/reset/reset-stm32mp1.c | 83 +++++--- + drivers/rtc/Kconfig | 1 + + drivers/rtc/rtc-stm32.c | 180 +++++++++++++++--- + drivers/watchdog/stm32_iwdg.c | 6 +- + include/dt-bindings/reset/stm32mp1-resets.h | 15 ++ + include/dt-bindings/rtc/rtc-stm32.h | 13 ++ + 7 files changed, 246 insertions(+), 62 deletions(-) + create mode 100644 include/dt-bindings/rtc/rtc-stm32.h +diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt +index 130ca5b982538..bab0df81af2cc 100644 +--- a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt ++++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt +@@ -21,9 +21,14 @@ Required properties: + domain (RTC registers) write protection. + It is required on stm32(f4/f7/h7). + +-Optional properties (to override default rtc_ck parent clock on stm32(f4/f7/h7): ++Optional properties: ++* to override default rtc_ck parent clock on stm32(f4/f7/h7): + - assigned-clocks: reference to the rtc_ck clock entry. + - assigned-clock-parents: phandle of the new parent clock of rtc_ck. ++* to select and enable RTC Low Speed Clock Output on stm32mp1: ++- st,lsco: defines the RTC output on which RTC Low-Speed Clock is Output. The ++ valid output values are defined in . ++- pinctrl state named "default" may be defined to reserve pin for RTC output. + + Example: + +@@ -58,4 +63,7 @@ Example: + clock-names = "pclk", "rtc_ck"; + interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_NONE>, + <&exti 19 1>; ++ st,lsco = ; ++ pinctrl-0 = <&rtc_out2_rmp_pins_a>; ++ pinctrl-names = "default"; + }; diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c -index b221a2804..daf0e26b2 100644 +index b221a28041fa0..daf0e26b27a8d 100644 --- a/drivers/reset/reset-stm32mp1.c +++ b/drivers/reset/reset-stm32mp1.c @@ -4,14 +4,21 @@ @@ -123,7 +155,7 @@ index b221a2804..daf0e26b2 100644 +} +OF_DECLARE_1(clk, stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_reset_of_init_drv); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index c5b980414..d590b4205 100644 +index c5b9804140860..d590b420525ce 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1862,6 +1862,7 @@ config RTC_DRV_R7301 @@ -135,7 +167,7 @@ index c5b980414..d590b4205 100644 help If you say yes here you get support for the STM32 On-Chip diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c -index 2999e33a7..5bfe655c5 100644 +index 2999e33a7e376..3cf51497681a4 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -6,6 +6,8 @@ @@ -189,16 +221,17 @@ index 2999e33a7..5bfe655c5 100644 u16 verr; }; -@@ -114,7 +130,7 @@ struct stm32_rtc_data { +@@ -114,7 +130,8 @@ struct stm32_rtc_data { void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags); bool has_pclk; bool need_dbp; - bool has_wakeirq; + bool has_lsco; ++ bool need_accuracy; }; struct stm32_rtc { -@@ -127,9 +143,87 @@ struct stm32_rtc { +@@ -127,9 +144,87 @@ struct stm32_rtc { struct clk *rtc_ck; const struct stm32_rtc_data *data; int irq_alarm; @@ -287,16 +320,17 @@ index 2999e33a7..5bfe655c5 100644 static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) { const struct stm32_rtc_registers *regs = &rtc->data->regs; -@@ -547,7 +641,7 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, +@@ -547,7 +642,8 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32_rtc_data = { .has_pclk = false, .need_dbp = true, - .has_wakeirq = false, + .has_lsco = false, ++ .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, -@@ -558,6 +652,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { +@@ -558,6 +654,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { .wpr = 0x24, .sr = 0x0C, /* set to ISR offset to ease alarm management */ .scr = UNDEF_REG, @@ -304,16 +338,17 @@ index 2999e33a7..5bfe655c5 100644 .verr = UNDEF_REG, }, .events = { -@@ -569,7 +664,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { +@@ -569,7 +666,8 @@ static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = { .has_pclk = true, .need_dbp = true, - .has_wakeirq = false, + .has_lsco = false, ++ .need_accuracy = false, .regs = { .tr = 0x00, .dr = 0x04, -@@ -580,6 +675,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { +@@ -580,6 +678,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { .wpr = 0x24, .sr = 0x0C, /* set to ISR offset to ease alarm management */ .scr = UNDEF_REG, @@ -321,16 +356,17 @@ index 2999e33a7..5bfe655c5 100644 .verr = UNDEF_REG, }, .events = { -@@ -600,7 +696,7 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, +@@ -600,7 +699,8 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32mp1_data = { .has_pclk = true, .need_dbp = false, - .has_wakeirq = true, + .has_lsco = true, ++ .need_accuracy = true, .regs = { .tr = 0x00, .dr = 0x04, -@@ -611,6 +707,7 @@ static const struct stm32_rtc_data stm32mp1_data = { +@@ -611,6 +711,7 @@ static const struct stm32_rtc_data stm32mp1_data = { .wpr = 0x24, .sr = 0x50, .scr = 0x5C, @@ -338,7 +374,32 @@ index 2999e33a7..5bfe655c5 100644 .verr = 0x3F4, }, .events = { -@@ -738,13 +835,15 @@ static int stm32_rtc_probe(struct platform_device *pdev) +@@ -641,11 +742,20 @@ static int stm32_rtc_init(struct platform_device *pdev, + pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; + pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; + +- for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { +- pred_s = (rate / (pred_a + 1)) - 1; ++ if (rtc->data->need_accuracy) { ++ for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { ++ pred_s = (rate / (pred_a + 1)) - 1; ++ ++ if (((pred_s + 1) * (pred_a + 1)) == rate) ++ break; ++ } ++ } else { ++ for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { ++ pred_s = (rate / (pred_a + 1)) - 1; + +- if (((pred_s + 1) * (pred_a + 1)) == rate) +- break; ++ if (((pred_s + 1) * (pred_a + 1)) == rate) ++ break; ++ } + } + + /* +@@ -738,13 +848,15 @@ static int stm32_rtc_probe(struct platform_device *pdev) } else { rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(rtc->pclk)) { @@ -356,7 +417,7 @@ index 2999e33a7..5bfe655c5 100644 return PTR_ERR(rtc->rtc_ck); } -@@ -781,19 +880,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) +@@ -781,19 +893,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) } ret = device_init_wakeup(&pdev->dev, true); @@ -381,7 +442,7 @@ index 2999e33a7..5bfe655c5 100644 platform_set_drvdata(pdev, rtc); -@@ -816,6 +908,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) +@@ -816,6 +921,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) goto err; } @@ -403,7 +464,7 @@ index 2999e33a7..5bfe655c5 100644 /* * If INITS flag is reset (calendar year field set to 0x00), calendar * must be initialized -@@ -852,6 +959,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) +@@ -852,6 +972,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) const struct stm32_rtc_registers *regs = &rtc->data->regs; unsigned int cr; @@ -413,7 +474,7 @@ index 2999e33a7..5bfe655c5 100644 /* Disable interrupts */ stm32_rtc_wpr_unlock(rtc); cr = readl_relaxed(rtc->base + regs->cr); -@@ -881,9 +991,6 @@ static int stm32_rtc_suspend(struct device *dev) +@@ -881,9 +1004,6 @@ static int stm32_rtc_suspend(struct device *dev) if (rtc->data->has_pclk) clk_disable_unprepare(rtc->pclk); @@ -423,7 +484,7 @@ index 2999e33a7..5bfe655c5 100644 return 0; } -@@ -902,15 +1009,13 @@ static int stm32_rtc_resume(struct device *dev) +@@ -902,15 +1022,13 @@ static int stm32_rtc_resume(struct device *dev) if (ret < 0) return ret; @@ -443,7 +504,7 @@ index 2999e33a7..5bfe655c5 100644 static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c -index 25188d6bb..1b71c205c 100644 +index 25188d6bbe152..1b71c205cee0e 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -163,7 +163,8 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, @@ -466,6 +527,56 @@ index 25188d6bb..1b71c205c 100644 return PTR_ERR(wdt->clk_pclk); } +diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h +index f0c3aaef67a0a..f3a0ed3178356 100644 +--- a/include/dt-bindings/reset/stm32mp1-resets.h ++++ b/include/dt-bindings/reset/stm32mp1-resets.h +@@ -7,6 +7,7 @@ + #ifndef _DT_BINDINGS_STM32MP1_RESET_H_ + #define _DT_BINDINGS_STM32MP1_RESET_H_ + ++#define MCU_HOLD_BOOT_R 2144 + #define LTDC_R 3072 + #define DSI_R 3076 + #define DDRPERFM_R 3080 +@@ -105,4 +106,18 @@ + #define GPIOJ_R 19785 + #define GPIOK_R 19786 + ++/* SCMI reset domain identifiers */ ++#define RST_SCMI0_SPI6 0 ++#define RST_SCMI0_I2C4 1 ++#define RST_SCMI0_I2C6 2 ++#define RST_SCMI0_USART1 3 ++#define RST_SCMI0_STGEN 4 ++#define RST_SCMI0_GPIOZ 5 ++#define RST_SCMI0_CRYP1 6 ++#define RST_SCMI0_HASH1 7 ++#define RST_SCMI0_RNG1 8 ++#define RST_SCMI0_MDMA 9 ++#define RST_SCMI0_MCU 10 ++#define RST_SCMI0_MCU_HOLD_BOOT 11 ++ + #endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ +diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h +new file mode 100644 +index 0000000000000..4373c4dea5879 +--- /dev/null ++++ b/include/dt-bindings/rtc/rtc-stm32.h +@@ -0,0 +1,13 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * This header provides constants for STM32_RTC bindings. ++ */ ++ ++#ifndef _DT_BINDINGS_RTC_RTC_STM32_H ++#define _DT_BINDINGS_RTC_RTC_STM32_H ++ ++#define RTC_OUT1 0 ++#define RTC_OUT2 1 ++#define RTC_OUT2_RMP 2 ++ ++#endif -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0012-ARM-stm32mp1-r2-MEDIA-SOC-THERMAL.patch similarity index 79% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0012-ARM-stm32mp1-r2-MEDIA-SOC-THERMAL.patch index 109f19f..aa9a109 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0012-ARM-stm32mp1-r2-MEDIA-SOC-THERMAL.patch @@ -1,29 +1,92 @@ -From 3da66d9a5ce2cb975d8ee48f47d497de85d79ccc Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:44:58 +0200 -Subject: [PATCH 12/23] ARM-stm32mp1-r1-MEDIA-SOC-THERMAL +From 1d34419db80914e8fcd39e622a56c3fdf0b2fe30 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:46 +0200 +Subject: [PATCH 12/22] ARM-stm32mp1-r2-rc8-MEDIA-SOC-THERMAL --- - drivers/media/i2c/ov5640.c | 77 +++-- - drivers/media/platform/stm32/stm32-cec.c | 10 +- - drivers/media/platform/stm32/stm32-dcmi.c | 51 ++- - drivers/media/v4l2-core/v4l2-fwnode.c | 3 + - drivers/soc/Kconfig | 1 + - drivers/soc/Makefile | 1 + - drivers/soc/st/Kconfig | 17 + - drivers/soc/st/Makefile | 2 + - drivers/soc/st/stm32_hdp.c | 242 ++++++++++++++ - drivers/soc/st/stm32_pm_domain.c | 212 ++++++++++++ - drivers/thermal/st/stm_thermal.c | 383 +++++++--------------- - include/media/v4l2-fwnode.h | 2 + - 12 files changed, 699 insertions(+), 302 deletions(-) + .../bindings/media/video-interfaces.txt | 2 + + .../bindings/soc/stm32/stm32_hdp.txt | 39 ++ + drivers/media/i2c/ov5640.c | 77 +++- + drivers/media/platform/stm32/stm32-cec.c | 10 +- + drivers/media/platform/stm32/stm32-dcmi.c | 100 +++-- + drivers/media/v4l2-core/v4l2-fwnode.c | 3 + + drivers/soc/Kconfig | 1 + + drivers/soc/Makefile | 1 + + drivers/soc/st/Kconfig | 17 + + drivers/soc/st/Makefile | 2 + + drivers/soc/st/stm32_hdp.c | 242 +++++++++++ + drivers/soc/st/stm32_pm_domain.c | 212 ++++++++++ + drivers/thermal/st/stm_thermal.c | 383 ++++++------------ + include/dt-bindings/soc/stm32-hdp.h | 108 +++++ + include/media/v4l2-fwnode.h | 2 + + 15 files changed, 882 insertions(+), 317 deletions(-) + create mode 100644 Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt create mode 100644 drivers/soc/st/Kconfig create mode 100644 drivers/soc/st/Makefile create mode 100644 drivers/soc/st/stm32_hdp.c create mode 100644 drivers/soc/st/stm32_pm_domain.c + create mode 100644 include/dt-bindings/soc/stm32-hdp.h +diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt +index f884ada0bffc8..aff685a25aca9 100644 +--- a/Documentation/devicetree/bindings/media/video-interfaces.txt ++++ b/Documentation/devicetree/bindings/media/video-interfaces.txt +@@ -149,6 +149,8 @@ Optional endpoint properties + as 0 (normal). This property is valid for serial busses only. + - strobe: Whether the clock signal is used as clock (0) or strobe (1). Used + with CCP2, for instance. ++- pclk-max-frequency: maximum pixel clock frequency admissible by video ++ host interface. + + Example + ------- +diff --git a/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt +new file mode 100644 +index 0000000000000..e2bd82f4980eb +--- /dev/null ++++ b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt +@@ -0,0 +1,39 @@ ++STM32 - STM32MP1- HDP Pin configuration for STM32MP1 ++======================================================= ++ ++The Hardware Debug Port (HDP) allows the observation of internal signals. By using multiplexers, ++up to 16 signals for each of 8-bit output can be observed. ++ ++Required Properties: ++ ++ - compatible: Must be "st,stm32mp1-hdp" ++ - muxing-hdp: Indicates for each HDP pins selected which HDP output among the 16 available signals you want ++ ++For each HDP pins you can select one of 16 signals which will be described in file : include/dt-bindings/soc/stm32-hdp.h ++ ++Example ++------- ++ ++In common dtsi file: ++ ++hdp: hdp@5002a000 { ++ compatible = "st,stm32mp1-hdp"; ++ reg = <0x5002a000 0x400>; ++ clocks = <&rcc HDP>; ++ clock-names = "hdp"; ++}; ++ ++In board-specific file: ++ ++In this example I've selected HDP0, HDP6 and HDP7, and for HDP0 the output signal is HDP0_GPOVAL_0, ++for HDP6 is HDP6_GPOVAL_6, and for HDP7 is HDP7_GPOVAL_7. ++ ++&hdp { ++ pinctrl-names = "default", "sleep"; ++ pinctrl-0 = <&hdp0_pins_a &hdp6_pins_a &hdp7_pins_a>; ++ pinctrl-1 = <&hdp0_pins_sleep_a &hdp6_pins_sleep_a &hdp7_pins_sleep_a>; ++ ++ muxing-hdp = <(STM32_HDP(0, HDP0_GPOVAL_0) | ++ STM32_HDP(6, HDP6_GPOVAL_6) | ++ STM32_HDP(7, HDP7_GPOVAL_7))>; ++}; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index a398ea81e..3bee8eed7 100644 +index 266e947572c1e..6a1b50bec7c84 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -63,6 +63,7 @@ @@ -244,7 +307,7 @@ index a398ea81e..3bee8eed7 100644 ret = hdl->error; goto free_ctrls; diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c -index 8a86b2cc2..108f83c26 100644 +index 8a86b2cc22fab..108f83c264f84 100644 --- a/drivers/media/platform/stm32/stm32-cec.c +++ b/drivers/media/platform/stm32/stm32-cec.c @@ -291,7 +291,9 @@ static int stm32_cec_probe(struct platform_device *pdev) @@ -275,7 +338,7 @@ index 8a86b2cc2..108f83c26 100644 } } diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c -index 9392e3409..2e78facd0 100644 +index 9392e3409fba0..7c8256441db33 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -95,6 +95,9 @@ enum state { @@ -306,6 +369,15 @@ index 9392e3409..2e78facd0 100644 /* Restart capture */ if (dcmi_restart_capture(dcmi)) +@@ -733,7 +736,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) + if (ret < 0) { + dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n", + __func__, ret); +- goto err_release_buffers; ++ goto err_pm_put; + } + + ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline); @@ -784,8 +787,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dcmi_set_crop(dcmi); @@ -340,7 +412,16 @@ index 9392e3409..2e78facd0 100644 /* Enable dcmi */ reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); -@@ -884,7 +910,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) +@@ -837,8 +863,6 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) + + err_pm_put: + pm_runtime_put(dcmi->dev); +- +-err_release_buffers: + spin_lock_irq(&dcmi->irqlock); + /* + * Return all buffers to vb2 in QUEUED state. +@@ -884,7 +908,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) /* Stop all pending DMA operations */ mutex_lock(&dcmi->dma_lock); @@ -349,7 +430,60 @@ index 9392e3409..2e78facd0 100644 mutex_unlock(&dcmi->dma_lock); pm_runtime_put(dcmi->dev); -@@ -1853,7 +1879,9 @@ static int dcmi_probe(struct platform_device *pdev) +@@ -1576,6 +1600,22 @@ static const struct dcmi_format dcmi_formats[] = { + .fourcc = V4L2_PIX_FMT_JPEG, + .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, + .bpp = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SBGGR8, ++ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, ++ .bpp = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGBRG8, ++ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, ++ .bpp = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SGRBG8, ++ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, ++ .bpp = 1, ++ }, { ++ .fourcc = V4L2_PIX_FMT_SRGGB8, ++ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, ++ .bpp = 1, + }, + }; + +@@ -1747,6 +1787,15 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, + + dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); + ++ 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)); ++ + /* + * Link this sub-device to DCMI, it could be + * a parallel camera sensor or a bridge +@@ -1759,10 +1808,11 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, + &dcmi->vdev->entity, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); +- if (ret) ++ if (ret) { + dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n", + subdev->name); +- else ++ video_unregister_device(dcmi->vdev); ++ } else + dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", + subdev->name); + +@@ -1853,7 +1903,9 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(dcmi->rstc)) { @@ -360,7 +494,7 @@ index 9392e3409..2e78facd0 100644 return PTR_ERR(dcmi->rstc); } -@@ -1910,10 +1938,13 @@ static int dcmi_probe(struct platform_device *pdev) +@@ -1910,10 +1962,13 @@ static int dcmi_probe(struct platform_device *pdev) return PTR_ERR(mclk); } @@ -378,8 +512,52 @@ index 9392e3409..2e78facd0 100644 } spin_lock_init(&dcmi->irqlock); +@@ -1971,15 +2026,6 @@ static int dcmi_probe(struct platform_device *pdev) + } + 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; +@@ -2000,7 +2046,7 @@ static int dcmi_probe(struct platform_device *pdev) + + ret = dcmi_graph_init(dcmi); + if (ret < 0) +- goto err_media_entity_cleanup; ++ goto err_vb2_queue_release; + + /* Reset device */ + ret = reset_control_assert(dcmi->rstc); +@@ -2026,7 +2072,10 @@ static int dcmi_probe(struct platform_device *pdev) + return 0; + + err_cleanup: ++ v4l2_async_notifier_unregister(&dcmi->notifier); + v4l2_async_notifier_cleanup(&dcmi->notifier); ++err_vb2_queue_release: ++ vb2_queue_release(q); + err_media_entity_cleanup: + media_entity_cleanup(&dcmi->vdev->entity); + err_device_release: +@@ -2048,6 +2097,7 @@ static int dcmi_remove(struct platform_device *pdev) + + v4l2_async_notifier_unregister(&dcmi->notifier); + v4l2_async_notifier_cleanup(&dcmi->notifier); ++ vb2_queue_release(&dcmi->queue); + media_entity_cleanup(&dcmi->vdev->entity); + v4l2_device_unregister(&dcmi->v4l2_dev); + media_device_cleanup(&dcmi->mdev); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index 3bd188878..7f370d6b7 100644 +index 3bd1888787eb3..7f370d6b7a143 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -356,6 +356,9 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode, @@ -393,7 +571,7 @@ index 3bd188878..7f370d6b7 100644 default: bus->flags = flags; diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig -index 833e04a78..4ad5724f5 100644 +index 833e04a7835c5..4ad5724f5cefd 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -14,6 +14,7 @@ source "drivers/soc/qcom/Kconfig" @@ -405,7 +583,7 @@ index 833e04a78..4ad5724f5 100644 source "drivers/soc/tegra/Kconfig" source "drivers/soc/ti/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile -index 2ec355003..30d3dcabf 100644 +index 2ec3550035243..30d3dcabf3bb0 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -20,6 +20,7 @@ obj-y += qcom/ @@ -418,7 +596,7 @@ index 2ec355003..30d3dcabf 100644 obj-y += ti/ diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig new file mode 100644 -index 000000000..59db03150 +index 0000000000000..59db031505522 --- /dev/null +++ b/drivers/soc/st/Kconfig @@ -0,0 +1,17 @@ @@ -441,7 +619,7 @@ index 000000000..59db03150 +endif # ARCH_STM32 diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile new file mode 100644 -index 000000000..0fce1db16 +index 0000000000000..0fce1db166421 --- /dev/null +++ b/drivers/soc/st/Makefile @@ -0,0 +1,2 @@ @@ -449,7 +627,7 @@ index 000000000..0fce1db16 +obj-$(CONFIG_STM32_PM_DOMAINS) += stm32_pm_domain.o diff --git a/drivers/soc/st/stm32_hdp.c b/drivers/soc/st/stm32_hdp.c new file mode 100644 -index 000000000..6408ac68c +index 0000000000000..6408ac68ca5f8 --- /dev/null +++ b/drivers/soc/st/stm32_hdp.c @@ -0,0 +1,242 @@ @@ -697,7 +875,7 @@ index 000000000..6408ac68c +module_platform_driver(hdp_driver); diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c new file mode 100644 -index 000000000..0386624c2 +index 0000000000000..0386624c20f2f --- /dev/null +++ b/drivers/soc/st/stm32_pm_domain.c @@ -0,0 +1,212 @@ @@ -914,7 +1092,7 @@ index 000000000..0386624c2 +} +core_initcall(stm32_pm_domains_init); diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c -index cf9ddc52f..1cecf9544 100644 +index cf9ddc52f30e1..1cecf95449c3e 100644 --- a/drivers/thermal/st/stm_thermal.c +++ b/drivers/thermal/st/stm_thermal.c @@ -30,7 +30,7 @@ @@ -1533,8 +1711,122 @@ index cf9ddc52f..1cecf9544 100644 dev_info(&pdev->dev, "%s: Driver initialized successfully\n", __func__); +diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h +new file mode 100644 +index 0000000000000..d98665327281b +--- /dev/null ++++ b/include/dt-bindings/soc/stm32-hdp.h +@@ -0,0 +1,108 @@ ++/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ ++/* ++ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved ++ * Author: Roullier Christophe ++ * for STMicroelectronics. ++ */ ++ ++#ifndef _DT_BINDINGS_STM32_HDP_H ++#define _DT_BINDINGS_STM32_HDP_H ++ ++#define STM32_HDP(port, value) ((value) << ((port) * 4)) ++ ++/* define HDP Pins number*/ ++#define HDP0_PWR_PWRWAKE_SYS 0 ++#define HDP0_CM4_SLEEPDEEP 1 ++#define HDP0_PWR_STDBY_WKUP 2 ++#define HDP0_PWR_ENCOMP_VDDCORE 3 ++#define HDP0_BSEC_OUT_SEC_NIDEN 4 ++#define HDP0_RCC_CM4_SLEEPDEEP 6 ++#define HDP0_GPU_DBG7 7 ++#define HDP0_DDRCTRL_LP_REQ 8 ++#define HDP0_PWR_DDR_RET_ENABLE_N 9 ++#define HDP0_GPOVAL_0 15 ++ ++#define HDP1_PWR_PWRWAKE_MCU 0 ++#define HDP1_CM4_HALTED 1 ++#define HDP1_CA7_NAXIERRIRQ 2 ++#define HDP1_PWR_OKIN_MR 3 ++#define HDP1_BSEC_OUT_SEC_DBGEN 4 ++#define HDP1_EXTI_SYS_WAKEUP 5 ++#define HDP1_RCC_PWRDS_MPU 6 ++#define HDP1_GPU_DBG6 7 ++#define HDP1_DDRCTRL_DFI_CTRLUPD_REQ 8 ++#define HDP1_DDRCTRL_CACTIVE_DDRC_ASR 9 ++#define HDP1_GPOVAL_1 15 ++ ++#define HDP2_PWR_PWRWAKE_MPU 0 ++#define HDP2_CM4_RXEV 1 ++#define HDP2_CA7_NPMUIRQ1 2 ++#define HDP2_CA7_NFIQOUT1 3 ++#define HDP2_BSEC_IN_RSTCORE_N 4 ++#define HDP2_EXTI_C2_WAKEUP 5 ++#define HDP2_RCC_PWRDS_MCU 6 ++#define HDP2_GPU_DBG5 7 ++#define HDP2_DDRCTRL_DFI_INIT_COMPLETE 8 ++#define HDP2_DDRCTRL_PERF_OP_IS_REFRESH 9 ++#define HDP2_DDRCTRL_GSKP_DFI_LP_REQ 10 ++#define HDP2_GPOVAL_2 15 ++ ++#define HDP3_PWR_SEL_VTH_VDD_CORE 0 ++#define HDP3_CM4_TXEV 1 ++#define HDP3_CA7_NPMUIRQ0 2 ++#define HDP3_CA7_NFIQOUT0 3 ++#define HDP3_BSEC_OUT_SEC_DFTLOCK 4 ++#define HDP3_EXTI_C1_WAKEUP 5 ++#define HDP3_RCC_PWRDS_SYS 6 ++#define HDP3_GPU_DBG4 7 ++#define HDP3_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE0 8 ++#define HDP3_DDRCTRL_CACTIVE_1 9 ++#define HDP3_GPOVAL_3 15 ++ ++#define HDP4_PWR_PDDS 0 ++#define HDP4_CM4_SLEEPING 1 ++#define HDP4_CA7_NRESET1 2 ++#define HDP4_CA7_NIRQOUT1 3 ++#define HDP4_BSEC_OUT_SEC_DFTEN 4 ++#define HDP4_BSEC_OUT_SEC_DBGSWENABLE 5 ++#define HDP4_ETH_OUT_PMT_INTR_O 6 ++#define HDP4_GPU_DBG3 7 ++#define HDP4_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE1 8 ++#define HDP4_DDRCTRL_CACTIVE_0 9 ++#define HDP4_GPOVAL_4 15 ++ ++#define HDP5_CA7_STANDBYWFIL2 0 ++#define HDP5_PWR_VTH_VDDCORE_ACK 1 ++#define HDP5_CA7_NRESET0 2 ++#define HDP5_CA7_NIRQOUT0 3 ++#define HDP5_BSEC_IN_PWROK 4 ++#define HDP5_BSEC_OUT_SEC_DEVICEEN 5 ++#define HDP5_ETH_OUT_LPI_INTR_O 6 ++#define HDP5_GPU_DBG2 7 ++#define HDP5_DDRCTRL_CACTIVE_DDRC 8 ++#define HDP5_DDRCTRL_WR_CREDIT_CNT 9 ++#define HDP5_GPOVAL_5 15 ++ ++#define HDP6_CA7_STANDBYWFI1 0 ++#define HDP6_CA7_STANDBYWFE1 1 ++#define HDP6_CA7_EVENT0 2 ++#define HDP6_CA7_DBGACK1 3 ++#define HDP6_BSEC_OUT_SEC_SPNIDEN 5 ++#define HDP6_ETH_OUT_MAC_SPEED_O1 6 ++#define HDP6_GPU_DBG1 7 ++#define HDP6_DDRCTRL_CSYSACK_DDRC 8 ++#define HDP6_DDRCTRL_LPR_CREDIT_CNT 9 ++#define HDP6_GPOVAL_6 15 ++ ++#define HDP7_CA7_STANDBYWFI0 0 ++#define HDP7_CA7_STANDBYWFE0 1 ++#define HDP7_CA7_DBGACK0 3 ++#define HDP7_BSEC_OUT_FUSE_OK 4 ++#define HDP7_BSEC_OUT_SEC_SPIDEN 5 ++#define HDP7_ETH_OUT_MAC_SPEED_O0 6 ++#define HDP7_GPU_DBG0 7 ++#define HDP7_DDRCTRL_CSYSREQ_DDRC 8 ++#define HDP7_DDRCTRL_HPR_CREDIT_CNT 9 ++#define HDP7_GPOVAL_7 15 ++ ++#endif /* _DT_BINDINGS_STM32_HDP_H */ diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h -index f6a7bcd13..c3dd47f14 100644 +index f6a7bcd131977..c3dd47f14c1ac 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -50,11 +50,13 @@ struct v4l2_fwnode_bus_mipi_csi2 { diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0013-ARM-stm32mp1-r2-MFD.patch similarity index 64% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0013-ARM-stm32mp1-r2-MFD.patch index 7e5757a..0002c9f 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0013-ARM-stm32mp1-r1-MFD.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0013-ARM-stm32mp1-r2-MFD.patch @@ -1,24 +1,265 @@ -From f811efe3cbe842a78d98740c0a0a8e1b7c0181b0 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:45:15 +0200 -Subject: [PATCH 13/23] ARM-stm32mp1-r1-MFD +From c37d67ecd03c14eabef9d8cde67913bdfe497ae8 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:47 +0200 +Subject: [PATCH 13/22] ARM-stm32mp1-r2-rc8-MFD --- - drivers/mfd/Kconfig | 10 + - drivers/mfd/Makefile | 1 + - drivers/mfd/stm32-pwr.c | 400 +++++++++++++++++++++++++++++++ - drivers/mfd/stm32-timers.c | 36 ++- - drivers/mfd/stmfx.c | 22 +- - drivers/mfd/stpmic1.c | 6 + - drivers/mfd/wm8994-core.c | 21 ++ - include/linux/mfd/stm32-timers.h | 12 +- - include/linux/mfd/stmfx.h | 1 + - include/linux/mfd/wm8994/pdata.h | 6 + - 10 files changed, 494 insertions(+), 21 deletions(-) + .../bindings/mfd/st,stm32mp1-pwr.txt | 57 +++ + .../devicetree/bindings/mfd/stm32-lptimer.txt | 10 + + .../bindings/mtd/st,stm32-fmc2-nand.yaml | 129 ++++++ + drivers/mfd/Kconfig | 10 + + drivers/mfd/Makefile | 1 + + drivers/mfd/stm32-lptimer.c | 1 + + drivers/mfd/stm32-pwr.c | 400 ++++++++++++++++++ + drivers/mfd/stm32-timers.c | 36 +- + drivers/mfd/stpmic1.c | 6 + + drivers/mfd/wm8994-core.c | 21 + + include/dt-bindings/mfd/stm32f4-rcc.h | 1 - + include/linux/mfd/stm32-lptimer.h | 5 + + include/linux/mfd/stm32-timers.h | 12 +- + include/linux/mfd/wm8994/pdata.h | 6 + + 14 files changed, 675 insertions(+), 20 deletions(-) + create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt + create mode 100644 Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml create mode 100644 drivers/mfd/stm32-pwr.c +diff --git a/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt +new file mode 100644 +index 0000000000000..eb622387bb651 +--- /dev/null ++++ b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt +@@ -0,0 +1,57 @@ ++STMicroelectronics STM32MP1 Power Management Controller ++======================================================= ++ ++The PWR IP is responsible for handling the power related resources such as ++clocks, power supplies and resets. It provides 6 wake-up pins that are handled ++by an interrupt-controller. Wake-up pin can be used to wake-up from STANDBY SoC state. ++ ++Required properties: ++- compatible should be: "st,stm32mp1-pwr" ++- reg: should be register base and length as documented in the ++ datasheet ++- interrupts: contains the reference to the gic wake-up pin interrupt ++- interrupt-controller; Enable interrupt controller for wake-up pins. ++- #interrupt-cells = <3> ++- wakeup-gpios: contains a list of GPIO spec describing each wake-up pin. ++ ++Optional Properties: ++- pwr-supply: main soc power supply ++ ++Interrupt consumers have to specify 3 cells: ++ - cell 1: wake-up pin id from 0 to 5 ++ - cell 2: IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_RISING ++ - cell 3: Pull config: 0 = No Pull, 1=Pull Up, 2=Pull Down ++ ++ ++Example: ++ ++ pwr: pwr@50001000 { ++ compatible = "st,stm32mp1-pwr", "simple-mfd"; ++ reg = <0x50001000 0x400>; ++ interrupts = ; ++ interrupt-controller; ++ #interrupt-cells = <3>; ++ ++ wakeup-gpios = <&gpioa 0 0>, <&gpioa 2 0>, ++ <&gpioc 13 0>, <&gpioi 8 0>, ++ <&gpioi 11 0>, <&gpioc 1 0>; ++ ++ pwr-supply = <&vdd>; ++ }; ++ ++ ++Example of interrupt user: ++gpio_keys { ++ compatible = "gpio-keys"; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ button@4 { ++ label = "WakeUp4"; ++ linux,code = ; ++ interrupt-parent = <&pwr>; ++ interrupts = <3 IRQ_TYPE_EDGE_FALLING 1>; ++ wakeup-source; ++ }; ++}; ++ +diff --git a/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt b/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt +index fb54e4dad5b3e..ef3b795b5d9f0 100644 +--- a/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt ++++ b/Documentation/devicetree/bindings/mfd/stm32-lptimer.txt +@@ -14,10 +14,15 @@ Required properties: + - #address-cells: Should be '<1>'. + - #size-cells: Should be '<0>'. + ++Optional properties: ++- interrupts: Interrupt line for the LP timer. ++ + Optional subnodes: + - pwm: See ../pwm/pwm-stm32-lp.txt + - counter: See ../counter/stm32-lptimer-cnt.txt + - trigger: See ../iio/timer/stm32-lptimer-trigger.txt ++- timer: Must contain "st,stm32-lptimer-timer" compatible ++ property. + + Example: + +@@ -26,6 +31,7 @@ Example: + reg = <0x40002400 0x400>; + clocks = <&timer_clk>; + clock-names = "mux"; ++ interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + +@@ -45,4 +51,8 @@ Example: + pinctrl-names = "default"; + pinctrl-0 = <&lptim1_in_pins>; + }; ++ ++ timer { ++ compatible = "st,stm32-lptimer-timer"; ++ }; + }; +diff --git a/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml +new file mode 100644 +index 0000000000000..6ae7de15d172f +--- /dev/null ++++ b/Documentation/devicetree/bindings/mtd/st,stm32-fmc2-nand.yaml +@@ -0,0 +1,129 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/mtd/st,stm32-fmc2-nand.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: STMicroelectronics Flexible Memory Controller 2 (FMC2) Bindings ++ ++maintainers: ++ - Christophe Kerello ++ ++properties: ++ compatible: ++ enum: ++ - st,stm32mp15-fmc2 ++ - st,stm32mp1-fmc2-nfc ++ ++ reg: ++ minItems: 6 ++ maxItems: 7 ++ ++ interrupts: ++ maxItems: 1 ++ ++ dmas: ++ items: ++ - description: tx DMA channel ++ - description: rx DMA channel ++ - description: ecc DMA channel ++ ++ dma-names: ++ items: ++ - const: tx ++ - const: rx ++ - const: ecc ++ ++patternProperties: ++ "^nand@[a-f0-9]$": ++ type: object ++ properties: ++ nand-ecc-step-size: ++ const: 512 ++ ++ nand-ecc-strength: ++ enum: [1, 4 ,8 ] ++ ++allOf: ++ - $ref: "nand-controller.yaml#" ++ ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: st,stm32mp15-fmc2 ++ then: ++ properties: ++ reg: ++ items: ++ - description: Registers ++ - description: Chip select 0 data ++ - description: Chip select 0 command ++ - description: Chip select 0 address space ++ - description: Chip select 1 data ++ - description: Chip select 1 command ++ - description: Chip select 1 address space ++ ++ clocks: ++ maxItems: 1 ++ ++ resets: ++ maxItems: 1 ++ ++ required: ++ - clocks ++ ++ - if: ++ properties: ++ compatible: ++ contains: ++ const: st,stm32mp1-fmc2-nfc ++ then: ++ properties: ++ reg: ++ items: ++ - description: Chip select 0 data ++ - description: Chip select 0 command ++ - description: Chip select 0 address space ++ - description: Chip select 1 data ++ - description: Chip select 1 command ++ - description: Chip select 1 address space ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ ++examples: ++ - | ++ #include ++ #include ++ #include ++ nand-controller@58002000 { ++ compatible = "st,stm32mp15-fmc2"; ++ reg = <0x58002000 0x1000>, ++ <0x80000000 0x1000>, ++ <0x88010000 0x1000>, ++ <0x88020000 0x1000>, ++ <0x81000000 0x1000>, ++ <0x89010000 0x1000>, ++ <0x89020000 0x1000>; ++ interrupts = ; ++ dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>, ++ <&mdma1 20 0x2 0x12000a08 0x0 0x0>, ++ <&mdma1 21 0x2 0x12000a0a 0x0 0x0>; ++ dma-names = "tx", "rx", "ecc"; ++ clocks = <&rcc FMC_K>; ++ resets = <&rcc FMC_R>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ nand@0 { ++ reg = <0>; ++ nand-on-flash-bbt; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ }; ++ ++... diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 43169f25d..48ef1822a 100644 +index 43169f25da1fd..48ef1822ab1ce 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1955,6 +1955,16 @@ config MFD_STPMIC1 @@ -39,7 +280,7 @@ index 43169f25d..48ef1822a 100644 tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index c1067ea46..11acfa1bf 100644 +index c1067ea462046..11acfa1bf8160 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -249,6 +249,7 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o @@ -50,9 +291,21 @@ index c1067ea46..11acfa1bf 100644 obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o +diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c +index a00f99f365595..746e51a17cc8e 100644 +--- a/drivers/mfd/stm32-lptimer.c ++++ b/drivers/mfd/stm32-lptimer.c +@@ -17,6 +17,7 @@ static const struct regmap_config stm32_lptimer_regmap_cfg = { + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = STM32_LPTIM_MAX_REGISTER, ++ .fast_io = true, + }; + + static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata) diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c new file mode 100644 -index 000000000..48ca8b474 +index 0000000000000..48ca8b4745d34 --- /dev/null +++ b/drivers/mfd/stm32-pwr.c @@ -0,0 +1,400 @@ @@ -457,7 +710,7 @@ index 000000000..48ca8b474 +arch_initcall(stm32_pwr_init); +module_exit(stm32_pwr_exit); diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c -index efcd4b980..65a160a26 100644 +index efcd4b980c94c..65a160a264555 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -167,26 +167,36 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata) @@ -520,68 +773,8 @@ index efcd4b980..65a160a26 100644 platform_set_drvdata(pdev, ddata); -diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c -index 857991cb3..711979afd 100644 ---- a/drivers/mfd/stmfx.c -+++ b/drivers/mfd/stmfx.c -@@ -287,14 +287,21 @@ static int stmfx_irq_init(struct i2c_client *client) - - ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin); - if (ret) -- return ret; -+ goto irq_exit; - - ret = devm_request_threaded_irq(stmfx->dev, client->irq, - NULL, stmfx_irq_handler, - irqtrigger | IRQF_ONESHOT, - "stmfx", stmfx); - if (ret) -- stmfx_irq_exit(client); -+ goto irq_exit; -+ -+ stmfx->irq = client->irq; -+ -+ return 0; -+ -+irq_exit: -+ stmfx_irq_exit(client); - - return ret; - } -@@ -481,6 +488,8 @@ static int stmfx_suspend(struct device *dev) - if (ret) - return ret; - -+ disable_irq(stmfx->irq); -+ - if (stmfx->vdd) - return regulator_disable(stmfx->vdd); - -@@ -501,6 +510,13 @@ static int stmfx_resume(struct device *dev) - } - } - -+ /* Reset STMFX - supply has been stopped during suspend */ -+ ret = stmfx_chip_reset(stmfx); -+ if (ret) { -+ dev_err(stmfx->dev, "Failed to reset chip: %d\n", ret); -+ return ret; -+ } -+ - ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL, - &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); - if (ret) -@@ -517,6 +533,8 @@ static int stmfx_resume(struct device *dev) - if (ret) - return ret; - -+ enable_irq(stmfx->irq); -+ - return 0; - } - #endif diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c -index 7dfbe8906..766c3217f 100644 +index 7dfbe8906cb86..766c3217f30ed 100644 --- a/drivers/mfd/stpmic1.c +++ b/drivers/mfd/stpmic1.c @@ -170,6 +170,9 @@ static int stpmic1_suspend(struct device *dev) @@ -605,7 +798,7 @@ index 7dfbe8906..766c3217f 100644 return 0; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c -index 1e9fe7d92..b110c8ac1 100644 +index 737dede4a95c3..8161ee16c2f86 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -7,6 +7,7 @@ @@ -650,8 +843,40 @@ index 1e9fe7d92..b110c8ac1 100644 return 0; } #else +diff --git a/include/dt-bindings/mfd/stm32f4-rcc.h b/include/dt-bindings/mfd/stm32f4-rcc.h +index 309e8c79f27b1..36448a5619a12 100644 +--- a/include/dt-bindings/mfd/stm32f4-rcc.h ++++ b/include/dt-bindings/mfd/stm32f4-rcc.h +@@ -34,7 +34,6 @@ + #define STM32F4_AHB1_RESET(bit) (STM32F4_RCC_AHB1_##bit + (0x10 * 8)) + #define STM32F4_AHB1_CLOCK(bit) (STM32F4_RCC_AHB1_##bit) + +- + /* AHB2 */ + #define STM32F4_RCC_AHB2_DCMI 0 + #define STM32F4_RCC_AHB2_CRYP 4 +diff --git a/include/linux/mfd/stm32-lptimer.h b/include/linux/mfd/stm32-lptimer.h +index 605f622648258..90b20550c1c8b 100644 +--- a/include/linux/mfd/stm32-lptimer.h ++++ b/include/linux/mfd/stm32-lptimer.h +@@ -27,10 +27,15 @@ + #define STM32_LPTIM_CMPOK BIT(3) + + /* STM32_LPTIM_ICR - bit fields */ ++#define STM32_LPTIM_ARRMCF BIT(1) + #define STM32_LPTIM_CMPOKCF_ARROKCF GENMASK(4, 3) + ++/* STM32_LPTIM_IER - bit flieds */ ++#define STM32_LPTIM_ARRMIE BIT(1) ++ + /* STM32_LPTIM_CR - bit fields */ + #define STM32_LPTIM_CNTSTRT BIT(2) ++#define STM32_LPTIM_SNGSTRT BIT(1) + #define STM32_LPTIM_ENABLE BIT(0) + + /* STM32_LPTIM_CFGR - bit fields */ diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h -index 067d14655..f8db83aed 100644 +index 067d14655c28b..f8db83aedb2b5 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -70,14 +70,11 @@ @@ -682,20 +907,8 @@ index 067d14655..f8db83aed 100644 enum stm32_timers_dmas { STM32_TIMERS_DMA_CH1, -diff --git a/include/linux/mfd/stmfx.h b/include/linux/mfd/stmfx.h -index 3c6798367..744dce639 100644 ---- a/include/linux/mfd/stmfx.h -+++ b/include/linux/mfd/stmfx.h -@@ -109,6 +109,7 @@ struct stmfx { - struct device *dev; - struct regmap *map; - struct regulator *vdd; -+ int irq; - struct irq_domain *irq_domain; - struct mutex lock; /* IRQ bus lock */ - u8 irq_src; diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h -index 81e7dcbd9..addb2fede 100644 +index 81e7dcbd94dfb..addb2fede83d8 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h @@ -231,6 +231,12 @@ struct wm8994_pdata { diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0014-ARM-stm32mp1-r2-MMC-NAND.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0014-ARM-stm32mp1-r2-MMC-NAND.patch new file mode 100644 index 0000000..07a9623 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0014-ARM-stm32mp1-r2-MMC-NAND.patch @@ -0,0 +1,3318 @@ +From 207470b1f44164f76939b25ebb0d50fb81375777 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:48 +0200 +Subject: [PATCH 14/22] ARM-stm32mp1-r2-rc8-MMC-NAND + +--- + .../devicetree/bindings/mmc/mmci.txt | 2 + + .../bindings/mtd/stm32-fmc2-nand.txt | 61 - + drivers/mmc/core/block.c | 11 + + drivers/mmc/core/core.c | 31 +- + drivers/mmc/host/mmci.c | 285 ++-- + drivers/mmc/host/mmci.h | 17 +- + drivers/mmc/host/mmci_stm32_sdmmc.c | 256 +++- + drivers/mtd/nand/raw/Kconfig | 1 + + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 1185 ++++++++--------- + include/linux/mmc/core.h | 1 + + include/linux/mmc/host.h | 6 + + 11 files changed, 1089 insertions(+), 767 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt + +diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt +index 6d3c626e017d2..4ec921e4bf344 100644 +--- a/Documentation/devicetree/bindings/mmc/mmci.txt ++++ b/Documentation/devicetree/bindings/mmc/mmci.txt +@@ -28,6 +28,8 @@ specific for ux500 variant: + - st,sig-pin-fbclk : feedback clock signal pin used. + + specific for sdmmc variant: ++- reg : a second base register may be defined if a delay ++ block is present and used for tuning. + - st,sig-dir : signal direction polarity used for cmd, dat0 dat123. + - st,neg-edge : data & command phase relation, generated on + sd clock falling edge. +diff --git a/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt b/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt +deleted file mode 100644 +index e55895e8dae44..0000000000000 +--- a/Documentation/devicetree/bindings/mtd/stm32-fmc2-nand.txt ++++ /dev/null +@@ -1,61 +0,0 @@ +-STMicroelectronics Flexible Memory Controller 2 (FMC2) +-NAND Interface +- +-Required properties: +-- compatible: Should be one of: +- * st,stm32mp15-fmc2 +-- reg: NAND flash controller memory areas. +- First region contains the register location. +- Regions 2 to 4 respectively contain the data, command, +- and address space for CS0. +- Regions 5 to 7 contain the same areas for CS1. +-- interrupts: The interrupt number +-- pinctrl-0: Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt) +-- clocks: The clock needed by the NAND flash controller +- +-Optional properties: +-- resets: Reference to a reset controller asserting the FMC controller +-- dmas: DMA specifiers (see: dma/stm32-mdma.txt) +-- dma-names: Must be "tx", "rx" and "ecc" +- +-* NAND device bindings: +- +-Required properties: +-- reg: describes the CS lines assigned to the NAND device. +- +-Optional properties: +-- nand-on-flash-bbt: see nand-controller.yaml +-- nand-ecc-strength: see nand-controller.yaml +-- nand-ecc-step-size: see nand-controller.yaml +- +-The following ECC strength and step size are currently supported: +- - nand-ecc-strength = <1>, nand-ecc-step-size = <512> (Hamming) +- - nand-ecc-strength = <4>, nand-ecc-step-size = <512> (BCH4) +- - nand-ecc-strength = <8>, nand-ecc-step-size = <512> (BCH8) (default) +- +-Example: +- +- fmc: nand-controller@58002000 { +- compatible = "st,stm32mp15-fmc2"; +- reg = <0x58002000 0x1000>, +- <0x80000000 0x1000>, +- <0x88010000 0x1000>, +- <0x88020000 0x1000>, +- <0x81000000 0x1000>, +- <0x89010000 0x1000>, +- <0x89020000 0x1000>; +- interrupts = ; +- clocks = <&rcc FMC_K>; +- resets = <&rcc FMC_R>; +- pinctrl-names = "default"; +- pinctrl-0 = <&fmc_pins_a>; +- #address-cells = <1>; +- #size-cells = <0>; +- +- nand@0 { +- reg = <0>; +- nand-on-flash-bbt; +- #address-cells = <1>; +- #size-cells = <1>; +- }; +- }; +diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c +index 7f480c6b19810..4ac7a07d87cc6 100644 +--- a/drivers/mmc/core/block.c ++++ b/drivers/mmc/core/block.c +@@ -1763,6 +1763,17 @@ static void mmc_blk_mq_rw_recovery(struct mmc_queue *mq, struct request *req) + u32 blocks; + int err; + ++ /* ++ * the host is in a bad state, and can't sent a new command ++ * without be unstuck ++ */ ++ if (brq->sbc.error == -EDEADLK || brq->cmd.error == -EDEADLK || ++ brq->stop.error == -EDEADLK || brq->data.error == -EDEADLK) { ++ pr_err("%s: host is in bad state, must be unstuck\n", ++ req->rq_disk->disk_name); ++ mmc_hw_unstuck(card->host); ++ } ++ + /* + * Some errors the host driver might not have seen. Set the number of + * bytes transferred to zero in that case. +diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c +index 26644b7ec13e3..6d00eed17738e 100644 +--- a/drivers/mmc/core/core.c ++++ b/drivers/mmc/core/core.c +@@ -397,6 +397,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) + void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) + { + struct mmc_command *cmd; ++ int sbc_err, stop_err, data_err; + + while (1) { + wait_for_completion(&mrq->completion); +@@ -420,8 +421,20 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) + mmc_hostname(host), __func__); + } + } +- if (!cmd->error || !cmd->retries || +- mmc_card_removed(host->card)) ++ ++ sbc_err = mrq->sbc ? mrq->sbc->error : 0; ++ stop_err = mrq->stop ? mrq->stop->error : 0; ++ data_err = mrq->data ? mrq->data->error : 0; ++ ++ if (cmd->error == -EDEADLK || sbc_err == -EDEADLK || ++ stop_err == -EDEADLK || data_err == -EDEADLK) { ++ pr_debug("%s: host is in bad state, must be unstuck\n", ++ mmc_hostname(host)); ++ mmc_hw_unstuck(host); ++ } ++ ++ if ((!cmd->error && !sbc_err && !stop_err && !data_err) || ++ !cmd->retries || mmc_card_removed(host->card)) + break; + + mmc_retune_recheck(host); +@@ -430,6 +443,12 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq) + mmc_hostname(host), cmd->opcode, cmd->error); + cmd->retries--; + cmd->error = 0; ++ if (mrq->sbc) ++ mrq->sbc->error = 0; ++ if (mrq->stop) ++ mrq->stop->error = 0; ++ if (mrq->data) ++ mrq->data->error = 0; + __mmc_start_request(host, mrq); + } + +@@ -2163,6 +2182,14 @@ int mmc_sw_reset(struct mmc_host *host) + } + EXPORT_SYMBOL(mmc_sw_reset); + ++void mmc_hw_unstuck(struct mmc_host *host) ++{ ++ if (!host->ops->hw_unstuck) ++ return; ++ host->ops->hw_unstuck(host); ++} ++EXPORT_SYMBOL(mmc_hw_unstuck); ++ + static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) + { + host->f_init = freq; +diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c +index 7e4bc9124efde..f2e74aa3d7274 100644 +--- a/drivers/mmc/host/mmci.c ++++ b/drivers/mmc/host/mmci.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -44,6 +45,7 @@ + #define DRIVER_NAME "mmci-pl18x" + + static void mmci_variant_init(struct mmci_host *host); ++static void ux500_variant_init(struct mmci_host *host); + static void ux500v2_variant_init(struct mmci_host *host); + + static unsigned int fmax = 515633; +@@ -177,7 +179,6 @@ static struct variant_data variant_ux500 = { + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, +- .busy_detect = true, + .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, + .busy_detect_flag = MCI_ST_CARDBUSY, + .busy_detect_mask = MCI_ST_BUSYENDMASK, +@@ -186,7 +187,7 @@ static struct variant_data variant_ux500 = { + .irq_pio_mask = MCI_IRQ_PIO_MASK, + .start_err = MCI_STARTBITERR, + .opendrain = MCI_OD, +- .init = mmci_variant_init, ++ .init = ux500_variant_init, + }; + + static struct variant_data variant_ux500v2 = { +@@ -212,7 +213,6 @@ static struct variant_data variant_ux500v2 = { + .f_max = 100000000, + .signal_direction = true, + .pwrreg_clkgate = true, +- .busy_detect = true, + .busy_dpsm_flag = MCI_DPSM_ST_BUSYMODE, + .busy_detect_flag = MCI_ST_CARDBUSY, + .busy_detect_mask = MCI_ST_BUSYENDMASK, +@@ -264,8 +264,38 @@ static struct variant_data variant_stm32_sdmmc = { + .datacnt_useless = true, + .datalength_bits = 25, + .datactrl_blocksz = 14, +- .datactrl_any_blocksz = true, ++ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, ++ .pwrreg_nopower = true, + .stm32_idmabsize_mask = GENMASK(12, 5), ++ .busy_timeout = true, ++ .busy_detect_flag = MCI_STM32_BUSYD0, ++ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, ++ .init = sdmmc_variant_init, ++}; ++ ++static struct variant_data variant_stm32_sdmmcv2 = { ++ .fifosize = 16 * 4, ++ .fifohalfsize = 8 * 4, ++ .f_max = 208000000, ++ .stm32_clkdiv = true, ++ .cmdreg_cpsm_enable = MCI_CPSM_STM32_ENABLE, ++ .cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC, ++ .cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC, ++ .cmdreg_srsp = MCI_CPSM_STM32_SRSP, ++ .cmdreg_stop = MCI_CPSM_STM32_CMDSTOP, ++ .data_cmd_enable = MCI_CPSM_STM32_CMDTRANS, ++ .irq_pio_mask = MCI_IRQ_PIO_STM32_MASK, ++ .datactrl_first = true, ++ .datacnt_useless = true, ++ .datalength_bits = 25, ++ .datactrl_blocksz = 14, ++ .datactrl_mask_sdio = MCI_DPSM_STM32_SDIOEN, ++ .pwrreg_nopower = true, ++ .stm32_idmabsize_mask = GENMASK(16, 5), ++ .dma_lli = true, ++ .busy_timeout = true, ++ .busy_detect_flag = MCI_STM32_BUSYD0, ++ .busy_detect_mask = MCI_STM32_BUSYD0ENDMASK, + .init = sdmmc_variant_init, + }; + +@@ -363,6 +393,24 @@ static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) + } + } + ++static void mmci_restore(struct mmci_host *host) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&host->lock, flags); ++ ++ if (host->variant->pwrreg_nopower) { ++ writel(host->clk_reg, host->base + MMCICLOCK); ++ writel(host->datactrl_reg, host->base + MMCIDATACTRL); ++ writel(host->pwr_reg, host->base + MMCIPOWER); ++ } ++ writel(MCI_IRQENABLE | host->variant->start_err, ++ host->base + MMCIMASK0); ++ mmci_reg_delay(host); ++ ++ spin_unlock_irqrestore(&host->lock, flags); ++} ++ + /* + * This must be called with host->lock held + */ +@@ -453,11 +501,11 @@ void mmci_dma_setup(struct mmci_host *host) + static int mmci_validate_data(struct mmci_host *host, + struct mmc_data *data) + { +- struct variant_data *variant = host->variant; +- + if (!data) + return 0; +- if (!is_power_of_2(data->blksz) && !variant->datactrl_any_blocksz) { ++ ++ if ((host->mmc->card && !mmc_card_sdio(host->mmc->card)) && ++ !is_power_of_2(data->blksz)) { + dev_err(mmc_dev(host->mmc), + "unsupported block size (%d bytes)\n", data->blksz); + return -EINVAL; +@@ -619,6 +667,67 @@ static u32 ux500v2_get_dctrl_cfg(struct mmci_host *host) + return MCI_DPSM_ENABLE | (host->data->blksz << 16); + } + ++static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) ++{ ++ void __iomem *base = host->base; ++ ++ /* ++ * Before unmasking for the busy end IRQ, confirm that the ++ * command was sent successfully. To keep track of having a ++ * command in-progress, waiting for busy signaling to end, ++ * store the status in host->busy_status. ++ * ++ * Note that, the card may need a couple of clock cycles before ++ * it starts signaling busy on DAT0, hence re-read the ++ * MMCISTATUS register here, to allow the busy bit to be set. ++ * Potentially we may even need to poll the register for a ++ * while, to allow it to be set, but tests indicates that it ++ * isn't needed. ++ */ ++ if (!host->busy_status && !(status & err_msk) && ++ (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { ++ writel(readl(base + MMCIMASK0) | ++ host->variant->busy_detect_mask, ++ base + MMCIMASK0); ++ ++ host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND); ++ return false; ++ } ++ ++ /* ++ * If there is a command in-progress that has been successfully ++ * sent, then bail out if busy status is set and wait for the ++ * busy end IRQ. ++ * ++ * Note that, the HW triggers an IRQ on both edges while ++ * monitoring DAT0 for busy completion, but there is only one ++ * status bit in MMCISTATUS for the busy state. Therefore ++ * both the start and the end interrupts needs to be cleared, ++ * one after the other. So, clear the busy start IRQ here. ++ */ ++ if (host->busy_status && ++ (status & host->variant->busy_detect_flag)) { ++ writel(host->variant->busy_detect_mask, base + MMCICLEAR); ++ return false; ++ } ++ ++ /* ++ * If there is a command in-progress that has been successfully ++ * sent and the busy bit isn't set, it means we have received ++ * the busy end IRQ. Clear and mask the IRQ, then continue to ++ * process the command. ++ */ ++ if (host->busy_status) { ++ writel(host->variant->busy_detect_mask, base + MMCICLEAR); ++ ++ writel(readl(base + MMCIMASK0) & ++ ~host->variant->busy_detect_mask, base + MMCIMASK0); ++ host->busy_status = 0; ++ } ++ ++ return true; ++} ++ + /* + * All the DMA operation mode stuff goes inside this ifdef. + * This assumes that you have a generic DMA device interface, +@@ -979,9 +1088,16 @@ void mmci_variant_init(struct mmci_host *host) + host->ops = &mmci_variant_ops; + } + ++void ux500_variant_init(struct mmci_host *host) ++{ ++ host->ops = &mmci_variant_ops; ++ host->ops->busy_complete = ux500_busy_complete; ++} ++ + void ux500v2_variant_init(struct mmci_host *host) + { + host->ops = &mmci_variant_ops; ++ host->ops->busy_complete = ux500_busy_complete; + host->ops->get_datactrl_cfg = ux500v2_get_dctrl_cfg; + } + +@@ -1101,6 +1217,7 @@ static void + mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) + { + void __iomem *base = host->base; ++ unsigned long long clks; + + dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n", + cmd->opcode, cmd->arg, cmd->flags); +@@ -1123,6 +1240,19 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) + else + c |= host->variant->cmdreg_srsp; + } ++ ++ if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) { ++ if (!cmd->busy_timeout) ++ cmd->busy_timeout = 1000; ++ ++ clks = (unsigned long long)cmd->busy_timeout * host->cclk; ++ do_div(clks, MSEC_PER_SEC); ++ writel_relaxed(clks, host->base + MMCIDATATIMER); ++ } ++ ++ if (host->ops->prep_volt_switch && cmd->opcode == SD_SWITCH_VOLTAGE) ++ host->ops->prep_volt_switch(host); ++ + if (/*interrupt*/0) + c |= MCI_CPSM_INTERRUPT; + +@@ -1227,6 +1357,7 @@ static void + mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + unsigned int status) + { ++ u32 err_msk = MCI_CMDCRCFAIL | MCI_CMDTIMEOUT; + void __iomem *base = host->base; + bool sbc, busy_resp; + +@@ -1241,74 +1372,17 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + * handling. Note that we tag on any latent IRQs postponed + * due to waiting for busy status. + */ +- if (!((status|host->busy_status) & +- (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND))) ++ if (host->variant->busy_timeout && busy_resp) ++ err_msk |= MCI_DATATIMEOUT; ++ ++ if (!((status | host->busy_status) & ++ (err_msk | MCI_CMDSENT | MCI_CMDRESPEND))) + return; + + /* Handle busy detection on DAT0 if the variant supports it. */ +- if (busy_resp && host->variant->busy_detect) { +- +- /* +- * Before unmasking for the busy end IRQ, confirm that the +- * command was sent successfully. To keep track of having a +- * command in-progress, waiting for busy signaling to end, +- * store the status in host->busy_status. +- * +- * Note that, the card may need a couple of clock cycles before +- * it starts signaling busy on DAT0, hence re-read the +- * MMCISTATUS register here, to allow the busy bit to be set. +- * Potentially we may even need to poll the register for a +- * while, to allow it to be set, but tests indicates that it +- * isn't needed. +- */ +- if (!host->busy_status && +- !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && +- (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { +- +- writel(readl(base + MMCIMASK0) | +- host->variant->busy_detect_mask, +- base + MMCIMASK0); +- +- host->busy_status = +- status & (MCI_CMDSENT|MCI_CMDRESPEND); +- return; +- } +- +- /* +- * If there is a command in-progress that has been successfully +- * sent, then bail out if busy status is set and wait for the +- * busy end IRQ. +- * +- * Note that, the HW triggers an IRQ on both edges while +- * monitoring DAT0 for busy completion, but there is only one +- * status bit in MMCISTATUS for the busy state. Therefore +- * both the start and the end interrupts needs to be cleared, +- * one after the other. So, clear the busy start IRQ here. +- */ +- if (host->busy_status && +- (status & host->variant->busy_detect_flag)) { +- writel(host->variant->busy_detect_mask, +- host->base + MMCICLEAR); ++ if (busy_resp && host->ops->busy_complete) ++ if (!host->ops->busy_complete(host, status, err_msk)) + return; +- } +- +- /* +- * If there is a command in-progress that has been successfully +- * sent and the busy bit isn't set, it means we have received +- * the busy end IRQ. Clear and mask the IRQ, then continue to +- * process the command. +- */ +- if (host->busy_status) { +- +- writel(host->variant->busy_detect_mask, +- host->base + MMCICLEAR); +- +- writel(readl(base + MMCIMASK0) & +- ~host->variant->busy_detect_mask, +- base + MMCIMASK0); +- host->busy_status = 0; +- } +- } + + host->cmd = NULL; + +@@ -1316,6 +1390,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + cmd->error = -ETIMEDOUT; + } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) { + cmd->error = -EILSEQ; ++ } else if (host->variant->busy_timeout && busy_resp && ++ status & MCI_DATATIMEOUT) { ++ cmd->error = -EDEADLK; + } else { + cmd->resp[0] = readl(base + MMCIRESPONSE0); + cmd->resp[1] = readl(base + MMCIRESPONSE1); +@@ -1327,7 +1404,6 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, + if (host->data) { + /* Terminate the DMA transfer */ + mmci_dma_error(host); +- + mmci_stop_data(host); + if (host->variant->cmdreg_stop && cmd->error) { + mmci_stop_command(host); +@@ -1546,7 +1622,7 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) + * clear the corresponding IRQ. + */ + status &= readl(host->base + MMCIMASK0); +- if (host->variant->busy_detect) ++ if (host->ops->busy_complete) + writel(status & ~host->variant->busy_detect_mask, + host->base + MMCICLEAR); + else +@@ -1609,6 +1685,20 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) + spin_unlock_irqrestore(&host->lock, flags); + } + ++static void mmci_set_max_busy_timeout(struct mmc_host *mmc) ++{ ++ struct mmci_host *host = mmc_priv(mmc); ++ u32 max_busy_timeout = 0; ++ ++ if (!host->ops->busy_complete) ++ return; ++ ++ if (host->variant->busy_timeout && mmc->actual_clock) ++ max_busy_timeout = ~0UL / (mmc->actual_clock / MSEC_PER_SEC); ++ ++ mmc->max_busy_timeout = max_busy_timeout; ++} ++ + static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + { + struct mmci_host *host = mmc_priv(mmc); +@@ -1713,6 +1803,8 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) + else + mmci_set_clkreg(host, ios->clock); + ++ mmci_set_max_busy_timeout(mmc); ++ + if (host->ops && host->ops->set_pwrreg) + host->ops->set_pwrreg(host, pwr); + else +@@ -1740,6 +1832,7 @@ static int mmci_get_cd(struct mmc_host *mmc) + + static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) + { ++ struct mmci_host *host = mmc_priv(mmc); + int ret = 0; + + if (!IS_ERR(mmc->supply.vqmmc)) { +@@ -1759,6 +1852,9 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) + break; + } + ++ if (!ret && host->ops && host->ops->volt_switch) ++ ret = host->ops->volt_switch(host, ios); ++ + if (ret) + dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); + } +@@ -1766,6 +1862,19 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) + return ret; + } + ++static void mmci_hw_unstuck(struct mmc_host *mmc) ++{ ++ struct mmci_host *host = mmc_priv(mmc); ++ ++ if (host->rst) { ++ reset_control_assert(host->rst); ++ udelay(2); ++ reset_control_deassert(host->rst); ++ } ++ ++ mmci_restore(host); ++} ++ + static struct mmc_host_ops mmci_ops = { + .request = mmci_request, + .pre_req = mmci_pre_request, +@@ -1774,6 +1883,7 @@ static struct mmc_host_ops mmci_ops = { + .get_ro = mmc_gpio_get_ro, + .get_cd = mmci_get_cd, + .start_signal_voltage_switch = mmci_sig_volt_switch, ++ .hw_unstuck = mmci_hw_unstuck, + }; + + static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) +@@ -1843,6 +1953,7 @@ static int mmci_probe(struct amba_device *dev, + + host = mmc_priv(mmc); + host->mmc = mmc; ++ host->mmc_ops = &mmci_ops; + + /* + * Some variant (STM32) doesn't have opendrain bit, nevertheless +@@ -1967,13 +2078,15 @@ static int mmci_probe(struct amba_device *dev, + else if (plat->ocr_mask) + dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); + ++ host->pwr_reg = readl_relaxed(host->base + MMCIPOWER); ++ + /* We support these capabilities. */ + mmc->caps |= MMC_CAP_CMD23; + + /* + * Enable busy detection. + */ +- if (variant->busy_detect) { ++ if (host->ops->busy_complete) { + mmci_ops.card_busy = mmci_card_busy; + /* + * Not all variants have a flag to enable busy detection +@@ -1983,7 +2096,6 @@ static int mmci_probe(struct amba_device *dev, + mmci_write_datactrlreg(host, + host->variant->busy_dpsm_flag); + mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; +- mmc->max_busy_timeout = 0; + } + + /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ +@@ -2141,24 +2253,6 @@ static void mmci_save(struct mmci_host *host) + spin_unlock_irqrestore(&host->lock, flags); + } + +-static void mmci_restore(struct mmci_host *host) +-{ +- unsigned long flags; +- +- spin_lock_irqsave(&host->lock, flags); +- +- if (host->variant->pwrreg_nopower) { +- writel(host->clk_reg, host->base + MMCICLOCK); +- writel(host->datactrl_reg, host->base + MMCIDATACTRL); +- writel(host->pwr_reg, host->base + MMCIPOWER); +- } +- writel(MCI_IRQENABLE | host->variant->start_err, +- host->base + MMCIMASK0); +- mmci_reg_delay(host); +- +- spin_unlock_irqrestore(&host->lock, flags); +-} +- + static int mmci_runtime_suspend(struct device *dev) + { + struct amba_device *adev = to_amba_device(dev); +@@ -2253,6 +2347,11 @@ static const struct amba_id mmci_ids[] = { + .mask = 0xf0ffffff, + .data = &variant_stm32_sdmmc, + }, ++ { ++ .id = 0x00253180, ++ .mask = 0xf0ffffff, ++ .data = &variant_stm32_sdmmcv2, ++ }, + /* Qualcomm variants */ + { + .id = 0x00051180, +diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h +index 89ab73343cf30..a94f384bb1ff5 100644 +--- a/drivers/mmc/host/mmci.h ++++ b/drivers/mmc/host/mmci.h +@@ -133,6 +133,8 @@ + #define MCI_DPSM_STM32_MODE_SDIO (1 << 2) + #define MCI_DPSM_STM32_MODE_STREAM (2 << 2) + #define MCI_DPSM_STM32_MODE_BLOCK_STOP (3 << 2) ++#define MCI_DPSM_STM32_SDIOEN BIT(11) ++ + + #define MMCIDATACNT 0x030 + #define MMCISTATUS 0x034 +@@ -164,6 +166,8 @@ + #define MCI_ST_CARDBUSY (1 << 24) + /* Extended status bits for the STM32 variants */ + #define MCI_STM32_BUSYD0 BIT(20) ++#define MCI_STM32_BUSYD0END BIT(21) ++#define MCI_STM32_VSWEND BIT(25) + + #define MMCICLEAR 0x038 + #define MCI_CMDCRCFAILCLR (1 << 0) +@@ -181,6 +185,9 @@ + #define MCI_ST_SDIOITC (1 << 22) + #define MCI_ST_CEATAENDC (1 << 23) + #define MCI_ST_BUSYENDC (1 << 24) ++/* Extended clear bits for the STM32 variants */ ++#define MCI_STM32_VSWENDC (1 << 25) ++#define MCI_STM32_CKSTOPC (1 << 26) + + #define MMCIMASK0 0x03c + #define MCI_CMDCRCFAILMASK (1 << 0) +@@ -290,7 +297,8 @@ struct mmci_host; + * @f_max: maximum clk frequency supported by the controller. + * @signal_direction: input/out direction of bus signals can be indicated + * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock +- * @busy_detect: true if the variant supports busy detection on DAT0. ++ * @busy_timeout: true if the variant starts data timer when the DPSM ++ * enter in Wait_R or Busy state. + * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM + * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register + * indicating that the card is busy +@@ -338,7 +346,7 @@ struct variant_data { + u32 f_max; + u8 signal_direction:1; + u8 pwrreg_clkgate:1; +- u8 busy_detect:1; ++ u8 busy_timeout:1; + u32 busy_dpsm_flag; + u32 busy_detect_flag; + u32 busy_detect_mask; +@@ -372,6 +380,9 @@ struct mmci_host_ops { + void (*dma_error)(struct mmci_host *host); + void (*set_clkreg)(struct mmci_host *host, unsigned int desired); + void (*set_pwrreg)(struct mmci_host *host, unsigned int pwr); ++ bool (*busy_complete)(struct mmci_host *host, u32 status, u32 err_msk); ++ void (*prep_volt_switch)(struct mmci_host *host); ++ int (*volt_switch)(struct mmci_host *host, struct mmc_ios *ios); + }; + + struct mmci_host { +@@ -402,8 +413,10 @@ struct mmci_host { + u32 mask1_reg; + u8 vqmmc_enabled:1; + struct mmci_platform_data *plat; ++ struct mmc_host_ops *mmc_ops; + struct mmci_host_ops *ops; + struct variant_data *variant; ++ void *variant_priv; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_opendrain; +diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c +index 0953bd8a4f79d..7c6ba518bc08e 100644 +--- a/drivers/mmc/host/mmci_stm32_sdmmc.c ++++ b/drivers/mmc/host/mmci_stm32_sdmmc.c +@@ -3,10 +3,13 @@ + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: Ludovic.barre@st.com for STMicroelectronics. + */ ++#include + #include + #include ++#include + #include + #include ++#include + #include + #include + #include "mmci.h" +@@ -14,17 +17,36 @@ + #define SDMMC_LLI_BUF_LEN PAGE_SIZE + #define SDMMC_IDMA_BURST BIT(MMCI_STM32_IDMABNDT_SHIFT) + ++#define DLYB_CR 0x0 ++#define DLYB_CR_DEN BIT(0) ++#define DLYB_CR_SEN BIT(1) ++ ++#define DLYB_CFGR 0x4 ++#define DLYB_CFGR_SEL_MASK GENMASK(3, 0) ++#define DLYB_CFGR_UNIT_MASK GENMASK(14, 8) ++#define DLYB_CFGR_LNG_MASK GENMASK(27, 16) ++#define DLYB_CFGR_LNGF BIT(31) ++ ++#define DLYB_CFGR_SEL_MAX 12 ++#define DLYB_CFGR_UNIT_MAX 127 ++ + struct sdmmc_lli_desc { + u32 idmalar; + u32 idmabase; + u32 idmasize; + }; + +-struct sdmmc_priv { ++struct sdmmc_idma { + dma_addr_t sg_dma; + void *sg_cpu; + }; + ++struct sdmmc_dlyb { ++ void __iomem *base; ++ u32 unit; ++ u32 max; ++}; ++ + int sdmmc_idma_validate_data(struct mmci_host *host, + struct mmc_data *data) + { +@@ -36,8 +58,8 @@ int sdmmc_idma_validate_data(struct mmci_host *host, + * excepted the last element which has no constraint on idmasize + */ + for_each_sg(data->sg, sg, data->sg_len - 1, i) { +- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32)) || +- !IS_ALIGNED(sg_dma_len(data->sg), SDMMC_IDMA_BURST)) { ++ if (!IS_ALIGNED(data->sg->offset, sizeof(u32)) || ++ !IS_ALIGNED(data->sg->length, SDMMC_IDMA_BURST)) { + dev_err(mmc_dev(host->mmc), + "unaligned scatterlist: ofst:%x length:%d\n", + data->sg->offset, data->sg->length); +@@ -45,7 +67,7 @@ int sdmmc_idma_validate_data(struct mmci_host *host, + } + } + +- if (!IS_ALIGNED(sg_dma_address(data->sg), sizeof(u32))) { ++ if (!IS_ALIGNED(data->sg->offset, sizeof(u32))) { + dev_err(mmc_dev(host->mmc), + "unaligned last scatterlist: ofst:%x length:%d\n", + data->sg->offset, data->sg->length); +@@ -92,21 +114,21 @@ static void sdmmc_idma_unprep_data(struct mmci_host *host, + + static int sdmmc_idma_setup(struct mmci_host *host) + { +- struct sdmmc_priv *idma; ++ struct sdmmc_idma *idma; ++ struct device *dev = mmc_dev(host->mmc); + +- idma = devm_kzalloc(mmc_dev(host->mmc), sizeof(*idma), GFP_KERNEL); +- if (!idma) ++ idma = devm_kzalloc(dev, sizeof(*idma), GFP_KERNEL); ++ dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); ++ if (!idma || !dev->dma_parms) + return -ENOMEM; + + host->dma_priv = idma; + + if (host->variant->dma_lli) { +- idma->sg_cpu = dmam_alloc_coherent(mmc_dev(host->mmc), +- SDMMC_LLI_BUF_LEN, ++ idma->sg_cpu = dmam_alloc_coherent(dev, SDMMC_LLI_BUF_LEN, + &idma->sg_dma, GFP_KERNEL); + if (!idma->sg_cpu) { +- dev_err(mmc_dev(host->mmc), +- "Failed to alloc IDMA descriptor\n"); ++ dev_err(dev, "Failed to alloc IDMA descriptor\n"); + return -ENOMEM; + } + host->mmc->max_segs = SDMMC_LLI_BUF_LEN / +@@ -117,13 +139,15 @@ static int sdmmc_idma_setup(struct mmci_host *host) + host->mmc->max_seg_size = host->mmc->max_req_size; + } + ++ dma_set_max_seg_size(dev, host->mmc->max_seg_size); ++ + return 0; + } + + static int sdmmc_idma_start(struct mmci_host *host, unsigned int *datactrl) + + { +- struct sdmmc_priv *idma = host->dma_priv; ++ struct sdmmc_idma *idma = host->dma_priv; + struct sdmmc_lli_desc *desc = (struct sdmmc_lli_desc *)idma->sg_cpu; + struct mmc_data *data = host->data; + struct scatterlist *sg; +@@ -229,12 +253,25 @@ static void mmci_sdmmc_set_clkreg(struct mmci_host *host, unsigned int desired) + mmci_write_clkreg(host, clk); + } + ++static void sdmmc_dlyb_input_ck(struct sdmmc_dlyb *dlyb) ++{ ++ if (!dlyb || !dlyb->base) ++ return; ++ ++ /* Output clock = Input clock */ ++ writel_relaxed(0, dlyb->base + DLYB_CR); ++} ++ + static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) + { + struct mmc_ios ios = host->mmc->ios; ++ struct sdmmc_dlyb *dlyb = host->variant_priv; + ++ /* adds OF options */ + pwr = host->pwr_reg_add; + ++ sdmmc_dlyb_input_ck(dlyb); ++ + if (ios.power_mode == MMC_POWER_OFF) { + /* Only a reset could power-off sdmmc */ + reset_control_assert(host->rst); +@@ -257,6 +294,10 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr) + writel(MCI_IRQENABLE | host->variant->start_err, + host->base + MMCIMASK0); + ++ /* preserves voltage switch bits */ ++ pwr |= host->pwr_reg & (MCI_STM32_VSWITCHEN | ++ MCI_STM32_VSWITCH); ++ + /* + * After a power-cycle state, we must set the SDMMC in + * Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are +@@ -285,6 +326,178 @@ static u32 sdmmc_get_dctrl_cfg(struct mmci_host *host) + return datactrl; + } + ++bool sdmmc_busy_complete(struct mmci_host *host, u32 status, u32 err_msk) ++{ ++ void __iomem *base = host->base; ++ u32 busy_d0, busy_d0end, mask; ++ ++ mask = readl_relaxed(base + MMCIMASK0); ++ busy_d0end = readl_relaxed(base + MMCISTATUS) & MCI_STM32_BUSYD0END; ++ busy_d0 = readl_relaxed(base + MMCISTATUS) & MCI_STM32_BUSYD0; ++ ++ /* complete if there is an error or busy_d0end */ ++ if ((status & err_msk) || busy_d0end) ++ goto complete; ++ ++ /* ++ * On response the busy signaling is reflected in the BUSYD0 flag. ++ * if busy_d0 is in-progress we must activate busyd0end interrupt ++ * to wait this completion. Else this request has no busy step. ++ */ ++ if (busy_d0) { ++ if (!host->busy_status) { ++ writel_relaxed(mask | host->variant->busy_detect_mask, ++ base + MMCIMASK0); ++ host->busy_status = status & ++ (MCI_CMDSENT | MCI_CMDRESPEND); ++ } ++ return false; ++ } ++ ++complete: ++ writel_relaxed(mask & ~host->variant->busy_detect_mask, ++ base + MMCIMASK0); ++ writel_relaxed(host->variant->busy_detect_mask, base + MMCICLEAR); ++ host->busy_status = 0; ++ ++ return true; ++} ++ ++static void sdmmc_dlyb_set_cfgr(struct sdmmc_dlyb *dlyb, ++ int unit, int phase, bool sampler) ++{ ++ u32 cfgr; ++ ++ writel_relaxed(DLYB_CR_SEN | DLYB_CR_DEN, dlyb->base + DLYB_CR); ++ ++ cfgr = FIELD_PREP(DLYB_CFGR_UNIT_MASK, unit) | ++ FIELD_PREP(DLYB_CFGR_SEL_MASK, phase); ++ writel_relaxed(cfgr, dlyb->base + DLYB_CFGR); ++ ++ if (!sampler) ++ writel_relaxed(DLYB_CR_DEN, dlyb->base + DLYB_CR); ++} ++ ++static int sdmmc_dlyb_lng_tuning(struct mmci_host *host) ++{ ++ struct sdmmc_dlyb *dlyb = host->variant_priv; ++ u32 cfgr; ++ int i, lng, ret; ++ ++ for (i = 0; i <= DLYB_CFGR_UNIT_MAX; i++) { ++ sdmmc_dlyb_set_cfgr(dlyb, i, DLYB_CFGR_SEL_MAX, true); ++ ++ ret = readl_relaxed_poll_timeout(dlyb->base + DLYB_CFGR, cfgr, ++ (cfgr & DLYB_CFGR_LNGF), ++ 1, 1000); ++ if (ret) { ++ dev_warn(mmc_dev(host->mmc), ++ "delay line cfg timeout unit:%d cfgr:%d\n", ++ i, cfgr); ++ continue; ++ } ++ ++ lng = FIELD_GET(DLYB_CFGR_LNG_MASK, cfgr); ++ if (lng < (BIT(11) | BIT(10)) && (lng & ~BIT(11)) > 0) ++ break; ++ } ++ ++ if (i > DLYB_CFGR_UNIT_MAX) ++ return -EINVAL; ++ ++ dlyb->unit = i; ++ dlyb->max = __fls(lng & ~BIT(11)); ++ ++ return 0; ++} ++ ++static int sdmmc_dlyb_phase_tuning(struct mmci_host *host, u32 opcode) ++{ ++ struct sdmmc_dlyb *dlyb = host->variant_priv; ++ int cur_len = 0, max_len = 0, end_of_len = 0; ++ int phase; ++ ++ for (phase = 0; phase <= dlyb->max; phase++) { ++ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); ++ ++ if (mmc_send_tuning(host->mmc, opcode, NULL)) { ++ cur_len = 0; ++ } else { ++ cur_len++; ++ if (cur_len > max_len) { ++ max_len = cur_len; ++ end_of_len = phase; ++ } ++ } ++ } ++ ++ if (!max_len) { ++ dev_err(mmc_dev(host->mmc), "no tuning point found\n"); ++ return -EINVAL; ++ } ++ ++ writel_relaxed(0, dlyb->base + DLYB_CR); ++ ++ phase = end_of_len - max_len / 2; ++ sdmmc_dlyb_set_cfgr(dlyb, dlyb->unit, phase, false); ++ ++ dev_dbg(mmc_dev(host->mmc), "unit:%d max_dly:%d phase:%d\n", ++ dlyb->unit, dlyb->max, phase); ++ ++ return 0; ++} ++ ++static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) ++{ ++ struct mmci_host *host = mmc_priv(mmc); ++ struct sdmmc_dlyb *dlyb = host->variant_priv; ++ ++ if (!dlyb || !dlyb->base) ++ return -EINVAL; ++ ++ if (sdmmc_dlyb_lng_tuning(host)) ++ return -EINVAL; ++ ++ return sdmmc_dlyb_phase_tuning(host, opcode); ++} ++ ++static void sdmmc_prep_vswitch(struct mmci_host *host) ++{ ++ /* clear the voltage switch completion flag */ ++ writel_relaxed(MCI_STM32_VSWENDC, host->base + MMCICLEAR); ++ /* enable Voltage switch procedure */ ++ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN); ++} ++ ++static int sdmmc_vswitch(struct mmci_host *host, struct mmc_ios *ios) ++{ ++ unsigned long flags; ++ u32 status; ++ int ret = 0; ++ ++ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { ++ spin_lock_irqsave(&host->lock, flags); ++ mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH); ++ spin_unlock_irqrestore(&host->lock, flags); ++ ++ /* wait voltage switch completion while 10ms */ ++ ret = readl_relaxed_poll_timeout(host->base + MMCISTATUS, ++ status, ++ (status & MCI_STM32_VSWEND), ++ 10, 10000); ++ ++ writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC, ++ host->base + MMCICLEAR); ++ ++ spin_lock_irqsave(&host->lock, flags); ++ mmci_write_pwrreg(host, host->pwr_reg & ++ ~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH)); ++ spin_unlock_irqrestore(&host->lock, flags); ++ } ++ ++ return ret; ++} ++ + static struct mmci_host_ops sdmmc_variant_ops = { + .validate_data = sdmmc_idma_validate_data, + .prep_data = sdmmc_idma_prep_data, +@@ -295,9 +508,28 @@ static struct mmci_host_ops sdmmc_variant_ops = { + .dma_finalize = sdmmc_idma_finalize, + .set_clkreg = mmci_sdmmc_set_clkreg, + .set_pwrreg = mmci_sdmmc_set_pwrreg, ++ .busy_complete = sdmmc_busy_complete, ++ .prep_volt_switch = sdmmc_prep_vswitch, ++ .volt_switch = sdmmc_vswitch, + }; + + void sdmmc_variant_init(struct mmci_host *host) + { ++ struct device_node *np = host->mmc->parent->of_node; ++ void __iomem *base_dlyb; ++ struct sdmmc_dlyb *dlyb; ++ + host->ops = &sdmmc_variant_ops; ++ ++ base_dlyb = devm_of_iomap(mmc_dev(host->mmc), np, 1, NULL); ++ if (IS_ERR(base_dlyb)) ++ return; ++ ++ dlyb = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dlyb), GFP_KERNEL); ++ if (!dlyb) ++ return; ++ ++ dlyb->base = base_dlyb; ++ host->variant_priv = dlyb; ++ host->mmc_ops->execute_tuning = sdmmc_execute_tuning; + } +diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig +index e59de3f60cf6b..1b549d58787c2 100644 +--- a/drivers/mtd/nand/raw/Kconfig ++++ b/drivers/mtd/nand/raw/Kconfig +@@ -419,6 +419,7 @@ config MTD_NAND_TEGRA + config MTD_NAND_STM32_FMC2 + tristate "Support for NAND controller on STM32MP SoCs" + depends on MACH_STM32MP157 || COMPILE_TEST ++ select MFD_SYSCON + help + Enables support for NAND Flash chips on SoCs containing the FMC2 + NAND controller. This controller is found on STM32MP SoCs. +diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c +index 5c06e0b4d4ef3..9553702d7a46d 100644 +--- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c ++++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c +@@ -4,16 +4,20 @@ + * Author: Christophe Kerello + */ + ++#include + #include + #include + #include + #include + #include + #include ++#include + #include + #include ++#include + #include + #include ++#include + #include + + /* Bad block marker length */ +@@ -37,8 +41,7 @@ + /* Max ECC buffer length */ + #define FMC2_MAX_ECC_BUF_LEN (FMC2_BCHDSRS_LEN * FMC2_MAX_SG) + +-#define FMC2_TIMEOUT_US 1000 +-#define FMC2_TIMEOUT_MS 1000 ++#define FMC2_TIMEOUT_MS 5000 + + /* Timings */ + #define FMC2_THIZ 1 +@@ -85,20 +88,16 @@ + /* Register: FMC2_PCR */ + #define FMC2_PCR_PWAITEN BIT(1) + #define FMC2_PCR_PBKEN BIT(2) +-#define FMC2_PCR_PWID_MASK GENMASK(5, 4) +-#define FMC2_PCR_PWID(x) (((x) & 0x3) << 4) ++#define FMC2_PCR_PWID GENMASK(5, 4) + #define FMC2_PCR_PWID_BUSWIDTH_8 0 + #define FMC2_PCR_PWID_BUSWIDTH_16 1 + #define FMC2_PCR_ECCEN BIT(6) + #define FMC2_PCR_ECCALG BIT(8) +-#define FMC2_PCR_TCLR_MASK GENMASK(12, 9) +-#define FMC2_PCR_TCLR(x) (((x) & 0xf) << 9) ++#define FMC2_PCR_TCLR GENMASK(12, 9) + #define FMC2_PCR_TCLR_DEFAULT 0xf +-#define FMC2_PCR_TAR_MASK GENMASK(16, 13) +-#define FMC2_PCR_TAR(x) (((x) & 0xf) << 13) ++#define FMC2_PCR_TAR GENMASK(16, 13) + #define FMC2_PCR_TAR_DEFAULT 0xf +-#define FMC2_PCR_ECCSS_MASK GENMASK(19, 17) +-#define FMC2_PCR_ECCSS(x) (((x) & 0x7) << 17) ++#define FMC2_PCR_ECCSS GENMASK(19, 17) + #define FMC2_PCR_ECCSS_512 1 + #define FMC2_PCR_ECCSS_2048 3 + #define FMC2_PCR_BCHECC BIT(24) +@@ -108,17 +107,17 @@ + #define FMC2_SR_NWRF BIT(6) + + /* Register: FMC2_PMEM */ +-#define FMC2_PMEM_MEMSET(x) (((x) & 0xff) << 0) +-#define FMC2_PMEM_MEMWAIT(x) (((x) & 0xff) << 8) +-#define FMC2_PMEM_MEMHOLD(x) (((x) & 0xff) << 16) +-#define FMC2_PMEM_MEMHIZ(x) (((x) & 0xff) << 24) ++#define FMC2_PMEM_MEMSET GENMASK(7, 0) ++#define FMC2_PMEM_MEMWAIT GENMASK(15, 8) ++#define FMC2_PMEM_MEMHOLD GENMASK(23, 16) ++#define FMC2_PMEM_MEMHIZ GENMASK(31, 24) + #define FMC2_PMEM_DEFAULT 0x0a0a0a0a + + /* Register: FMC2_PATT */ +-#define FMC2_PATT_ATTSET(x) (((x) & 0xff) << 0) +-#define FMC2_PATT_ATTWAIT(x) (((x) & 0xff) << 8) +-#define FMC2_PATT_ATTHOLD(x) (((x) & 0xff) << 16) +-#define FMC2_PATT_ATTHIZ(x) (((x) & 0xff) << 24) ++#define FMC2_PATT_ATTSET GENMASK(7, 0) ++#define FMC2_PATT_ATTWAIT GENMASK(15, 8) ++#define FMC2_PATT_ATTHOLD GENMASK(23, 16) ++#define FMC2_PATT_ATTHIZ GENMASK(31, 24) + #define FMC2_PATT_DEFAULT 0x0a0a0a0a + + /* Register: FMC2_ISR */ +@@ -133,9 +132,9 @@ + /* Register: FMC2_CSQCFGR1 */ + #define FMC2_CSQCFGR1_CMD2EN BIT(1) + #define FMC2_CSQCFGR1_DMADEN BIT(2) +-#define FMC2_CSQCFGR1_ACYNBR(x) (((x) & 0x7) << 4) +-#define FMC2_CSQCFGR1_CMD1(x) (((x) & 0xff) << 8) +-#define FMC2_CSQCFGR1_CMD2(x) (((x) & 0xff) << 16) ++#define FMC2_CSQCFGR1_ACYNBR GENMASK(6, 4) ++#define FMC2_CSQCFGR1_CMD1 GENMASK(15, 8) ++#define FMC2_CSQCFGR1_CMD2 GENMASK(23, 16) + #define FMC2_CSQCFGR1_CMD1T BIT(24) + #define FMC2_CSQCFGR1_CMD2T BIT(25) + +@@ -143,13 +142,13 @@ + #define FMC2_CSQCFGR2_SQSDTEN BIT(0) + #define FMC2_CSQCFGR2_RCMD2EN BIT(1) + #define FMC2_CSQCFGR2_DMASEN BIT(2) +-#define FMC2_CSQCFGR2_RCMD1(x) (((x) & 0xff) << 8) +-#define FMC2_CSQCFGR2_RCMD2(x) (((x) & 0xff) << 16) ++#define FMC2_CSQCFGR2_RCMD1 GENMASK(15, 8) ++#define FMC2_CSQCFGR2_RCMD2 GENMASK(23, 16) + #define FMC2_CSQCFGR2_RCMD1T BIT(24) + #define FMC2_CSQCFGR2_RCMD2T BIT(25) + + /* Register: FMC2_CSQCFGR3 */ +-#define FMC2_CSQCFGR3_SNBR(x) (((x) & 0x1f) << 8) ++#define FMC2_CSQCFGR3_SNBR GENMASK(13, 8) + #define FMC2_CSQCFGR3_AC1T BIT(16) + #define FMC2_CSQCFGR3_AC2T BIT(17) + #define FMC2_CSQCFGR3_AC3T BIT(18) +@@ -160,15 +159,15 @@ + #define FMC2_CSQCFGR3_RAC2T BIT(23) + + /* Register: FMC2_CSQCAR1 */ +-#define FMC2_CSQCAR1_ADDC1(x) (((x) & 0xff) << 0) +-#define FMC2_CSQCAR1_ADDC2(x) (((x) & 0xff) << 8) +-#define FMC2_CSQCAR1_ADDC3(x) (((x) & 0xff) << 16) +-#define FMC2_CSQCAR1_ADDC4(x) (((x) & 0xff) << 24) ++#define FMC2_CSQCAR1_ADDC1 GENMASK(7, 0) ++#define FMC2_CSQCAR1_ADDC2 GENMASK(15, 8) ++#define FMC2_CSQCAR1_ADDC3 GENMASK(23, 16) ++#define FMC2_CSQCAR1_ADDC4 GENMASK(31, 24) + + /* Register: FMC2_CSQCAR2 */ +-#define FMC2_CSQCAR2_ADDC5(x) (((x) & 0xff) << 0) +-#define FMC2_CSQCAR2_NANDCEN(x) (((x) & 0x3) << 10) +-#define FMC2_CSQCAR2_SAO(x) (((x) & 0xffff) << 16) ++#define FMC2_CSQCAR2_ADDC5 GENMASK(7, 0) ++#define FMC2_CSQCAR2_NANDCEN GENMASK(11, 10) ++#define FMC2_CSQCAR2_SAO GENMASK(31, 16) + + /* Register: FMC2_CSQIER */ + #define FMC2_CSQIER_TCIE BIT(0) +@@ -189,28 +188,23 @@ + /* Register: FMC2_BCHDSR0 */ + #define FMC2_BCHDSR0_DUE BIT(0) + #define FMC2_BCHDSR0_DEF BIT(1) +-#define FMC2_BCHDSR0_DEN_MASK GENMASK(7, 4) +-#define FMC2_BCHDSR0_DEN_SHIFT 4 ++#define FMC2_BCHDSR0_DEN GENMASK(7, 4) + + /* Register: FMC2_BCHDSR1 */ +-#define FMC2_BCHDSR1_EBP1_MASK GENMASK(12, 0) +-#define FMC2_BCHDSR1_EBP2_MASK GENMASK(28, 16) +-#define FMC2_BCHDSR1_EBP2_SHIFT 16 ++#define FMC2_BCHDSR1_EBP1 GENMASK(12, 0) ++#define FMC2_BCHDSR1_EBP2 GENMASK(28, 16) + + /* Register: FMC2_BCHDSR2 */ +-#define FMC2_BCHDSR2_EBP3_MASK GENMASK(12, 0) +-#define FMC2_BCHDSR2_EBP4_MASK GENMASK(28, 16) +-#define FMC2_BCHDSR2_EBP4_SHIFT 16 ++#define FMC2_BCHDSR2_EBP3 GENMASK(12, 0) ++#define FMC2_BCHDSR2_EBP4 GENMASK(28, 16) + + /* Register: FMC2_BCHDSR3 */ +-#define FMC2_BCHDSR3_EBP5_MASK GENMASK(12, 0) +-#define FMC2_BCHDSR3_EBP6_MASK GENMASK(28, 16) +-#define FMC2_BCHDSR3_EBP6_SHIFT 16 ++#define FMC2_BCHDSR3_EBP5 GENMASK(12, 0) ++#define FMC2_BCHDSR3_EBP6 GENMASK(28, 16) + + /* Register: FMC2_BCHDSR4 */ +-#define FMC2_BCHDSR4_EBP7_MASK GENMASK(12, 0) +-#define FMC2_BCHDSR4_EBP8_MASK GENMASK(28, 16) +-#define FMC2_BCHDSR4_EBP8_SHIFT 16 ++#define FMC2_BCHDSR4_EBP7 GENMASK(12, 0) ++#define FMC2_BCHDSR4_EBP8 GENMASK(28, 16) + + enum stm32_fmc2_ecc { + FMC2_ECC_HAM = 1, +@@ -251,7 +245,8 @@ struct stm32_fmc2_nfc { + struct nand_controller base; + struct stm32_fmc2_nand nand; + struct device *dev; +- void __iomem *io_base; ++ struct device *cdev; ++ struct regmap *regmap; + void __iomem *data_base[FMC2_MAX_CE]; + void __iomem *cmd_base[FMC2_MAX_CE]; + void __iomem *addr_base[FMC2_MAX_CE]; +@@ -281,47 +276,42 @@ static inline struct stm32_fmc2_nfc *to_stm32_nfc(struct nand_controller *base) + return container_of(base, struct stm32_fmc2_nfc, base); + } + +-/* Timings configuration */ +-static void stm32_fmc2_timings_init(struct nand_chip *chip) ++static void stm32_fmc2_nfc_timings_init(struct nand_chip *chip) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); + struct stm32_fmc2_timings *timings = &nand->timings; +- u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); + u32 pmem, patt; + + /* Set tclr/tar timings */ +- pcr &= ~FMC2_PCR_TCLR_MASK; +- pcr |= FMC2_PCR_TCLR(timings->tclr); +- pcr &= ~FMC2_PCR_TAR_MASK; +- pcr |= FMC2_PCR_TAR(timings->tar); ++ regmap_update_bits(nfc->regmap, FMC2_PCR, ++ FMC2_PCR_TCLR | FMC2_PCR_TAR, ++ FIELD_PREP(FMC2_PCR_TCLR, timings->tclr) | ++ FIELD_PREP(FMC2_PCR_TAR, timings->tar)); + + /* Set tset/twait/thold/thiz timings in common bank */ +- pmem = FMC2_PMEM_MEMSET(timings->tset_mem); +- pmem |= FMC2_PMEM_MEMWAIT(timings->twait); +- pmem |= FMC2_PMEM_MEMHOLD(timings->thold_mem); +- pmem |= FMC2_PMEM_MEMHIZ(timings->thiz); ++ pmem = FIELD_PREP(FMC2_PMEM_MEMSET, timings->tset_mem); ++ pmem |= FIELD_PREP(FMC2_PMEM_MEMWAIT, timings->twait); ++ pmem |= FIELD_PREP(FMC2_PMEM_MEMHOLD, timings->thold_mem); ++ pmem |= FIELD_PREP(FMC2_PMEM_MEMHIZ, timings->thiz); ++ regmap_write(nfc->regmap, FMC2_PMEM, pmem); + + /* Set tset/twait/thold/thiz timings in attribut bank */ +- patt = FMC2_PATT_ATTSET(timings->tset_att); +- patt |= FMC2_PATT_ATTWAIT(timings->twait); +- patt |= FMC2_PATT_ATTHOLD(timings->thold_att); +- patt |= FMC2_PATT_ATTHIZ(timings->thiz); +- +- writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); +- writel_relaxed(pmem, fmc2->io_base + FMC2_PMEM); +- writel_relaxed(patt, fmc2->io_base + FMC2_PATT); ++ patt = FIELD_PREP(FMC2_PATT_ATTSET, timings->tset_att); ++ patt |= FIELD_PREP(FMC2_PATT_ATTWAIT, timings->twait); ++ patt |= FIELD_PREP(FMC2_PATT_ATTHOLD, timings->thold_att); ++ patt |= FIELD_PREP(FMC2_PATT_ATTHIZ, timings->thiz); ++ regmap_write(nfc->regmap, FMC2_PATT, patt); + } + +-/* Controller configuration */ +-static void stm32_fmc2_setup(struct nand_chip *chip) ++static void stm32_fmc2_nfc_setup(struct nand_chip *chip) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); +- u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); ++ u32 pcr = 0, pcr_mask; + + /* Configure ECC algorithm (default configuration is Hamming) */ +- pcr &= ~FMC2_PCR_ECCALG; +- pcr &= ~FMC2_PCR_BCHECC; ++ pcr_mask = FMC2_PCR_ECCALG; ++ pcr_mask |= FMC2_PCR_BCHECC; + if (chip->ecc.strength == FMC2_ECC_BCH8) { + pcr |= FMC2_PCR_ECCALG; + pcr |= FMC2_PCR_BCHECC; +@@ -330,195 +320,159 @@ static void stm32_fmc2_setup(struct nand_chip *chip) + } + + /* Set buswidth */ +- pcr &= ~FMC2_PCR_PWID_MASK; ++ pcr_mask |= FMC2_PCR_PWID; + if (chip->options & NAND_BUSWIDTH_16) +- pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16); ++ pcr |= FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16); + + /* Set ECC sector size */ +- pcr &= ~FMC2_PCR_ECCSS_MASK; +- pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_512); ++ pcr_mask |= FMC2_PCR_ECCSS; ++ pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_512); + +- writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); ++ regmap_update_bits(nfc->regmap, FMC2_PCR, pcr_mask, pcr); + } + +-/* Select target */ +-static int stm32_fmc2_select_chip(struct nand_chip *chip, int chipnr) ++static int stm32_fmc2_nfc_select_chip(struct nand_chip *chip, int chipnr) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); + struct dma_slave_config dma_cfg; + int ret; + +- if (nand->cs_used[chipnr] == fmc2->cs_sel) ++ if (nand->cs_used[chipnr] == nfc->cs_sel) + return 0; + +- fmc2->cs_sel = nand->cs_used[chipnr]; +- +- /* FMC2 setup routine */ +- stm32_fmc2_setup(chip); ++ nfc->cs_sel = nand->cs_used[chipnr]; ++ stm32_fmc2_nfc_setup(chip); ++ stm32_fmc2_nfc_timings_init(chip); + +- /* Apply timings */ +- stm32_fmc2_timings_init(chip); +- +- if (fmc2->dma_tx_ch && fmc2->dma_rx_ch) { ++ if (nfc->dma_tx_ch && nfc->dma_rx_ch) { + memset(&dma_cfg, 0, sizeof(dma_cfg)); +- dma_cfg.src_addr = fmc2->data_phys_addr[fmc2->cs_sel]; +- dma_cfg.dst_addr = fmc2->data_phys_addr[fmc2->cs_sel]; ++ dma_cfg.src_addr = nfc->data_phys_addr[nfc->cs_sel]; ++ dma_cfg.dst_addr = nfc->data_phys_addr[nfc->cs_sel]; + dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma_cfg.src_maxburst = 32; + dma_cfg.dst_maxburst = 32; + +- ret = dmaengine_slave_config(fmc2->dma_tx_ch, &dma_cfg); ++ ret = dmaengine_slave_config(nfc->dma_tx_ch, &dma_cfg); + if (ret) { +- dev_err(fmc2->dev, "tx DMA engine slave config failed\n"); ++ dev_err(nfc->dev, "tx DMA engine slave config failed\n"); + return ret; + } + +- ret = dmaengine_slave_config(fmc2->dma_rx_ch, &dma_cfg); ++ ret = dmaengine_slave_config(nfc->dma_rx_ch, &dma_cfg); + if (ret) { +- dev_err(fmc2->dev, "rx DMA engine slave config failed\n"); ++ dev_err(nfc->dev, "rx DMA engine slave config failed\n"); + return ret; + } + } + +- if (fmc2->dma_ecc_ch) { ++ if (nfc->dma_ecc_ch) { + /* + * Hamming: we read HECCR register + * BCH4/BCH8: we read BCHDSRSx registers + */ + memset(&dma_cfg, 0, sizeof(dma_cfg)); +- dma_cfg.src_addr = fmc2->io_phys_addr; ++ dma_cfg.src_addr = nfc->io_phys_addr; + dma_cfg.src_addr += chip->ecc.strength == FMC2_ECC_HAM ? + FMC2_HECCR : FMC2_BCHDSR0; + dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + +- ret = dmaengine_slave_config(fmc2->dma_ecc_ch, &dma_cfg); ++ ret = dmaengine_slave_config(nfc->dma_ecc_ch, &dma_cfg); + if (ret) { +- dev_err(fmc2->dev, "ECC DMA engine slave config failed\n"); ++ dev_err(nfc->dev, "ECC DMA engine slave config failed\n"); + return ret; + } + + /* Calculate ECC length needed for one sector */ +- fmc2->dma_ecc_len = chip->ecc.strength == FMC2_ECC_HAM ? +- FMC2_HECCR_LEN : FMC2_BCHDSRS_LEN; ++ nfc->dma_ecc_len = chip->ecc.strength == FMC2_ECC_HAM ? ++ FMC2_HECCR_LEN : FMC2_BCHDSRS_LEN; + } + + return 0; + } + +-/* Set bus width to 16-bit or 8-bit */ +-static void stm32_fmc2_set_buswidth_16(struct stm32_fmc2_nfc *fmc2, bool set) ++static void stm32_fmc2_nfc_set_buswidth_16(struct stm32_fmc2_nfc *nfc, bool set) + { +- u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); ++ u32 pcr; ++ ++ pcr = set ? FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_16) : ++ FIELD_PREP(FMC2_PCR_PWID, FMC2_PCR_PWID_BUSWIDTH_8); + +- pcr &= ~FMC2_PCR_PWID_MASK; +- if (set) +- pcr |= FMC2_PCR_PWID(FMC2_PCR_PWID_BUSWIDTH_16); +- writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); ++ regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_PWID, pcr); + } + +-/* Enable/disable ECC */ +-static void stm32_fmc2_set_ecc(struct stm32_fmc2_nfc *fmc2, bool enable) ++static void stm32_fmc2_nfc_set_ecc(struct stm32_fmc2_nfc *nfc, bool enable) + { +- u32 pcr = readl(fmc2->io_base + FMC2_PCR); +- +- pcr &= ~FMC2_PCR_ECCEN; +- if (enable) +- pcr |= FMC2_PCR_ECCEN; +- writel(pcr, fmc2->io_base + FMC2_PCR); ++ regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_ECCEN, ++ enable ? FMC2_PCR_ECCEN : 0); + } + +-/* Enable irq sources in case of the sequencer is used */ +-static inline void stm32_fmc2_enable_seq_irq(struct stm32_fmc2_nfc *fmc2) ++static void stm32_fmc2_nfc_enable_seq_irq(struct stm32_fmc2_nfc *nfc) + { +- u32 csqier = readl_relaxed(fmc2->io_base + FMC2_CSQIER); +- +- csqier |= FMC2_CSQIER_TCIE; +- +- fmc2->irq_state = FMC2_IRQ_SEQ; ++ nfc->irq_state = FMC2_IRQ_SEQ; + +- writel_relaxed(csqier, fmc2->io_base + FMC2_CSQIER); ++ regmap_update_bits(nfc->regmap, FMC2_CSQIER, ++ FMC2_CSQIER_TCIE, FMC2_CSQIER_TCIE); + } + +-/* Disable irq sources in case of the sequencer is used */ +-static inline void stm32_fmc2_disable_seq_irq(struct stm32_fmc2_nfc *fmc2) ++static void stm32_fmc2_nfc_disable_seq_irq(struct stm32_fmc2_nfc *nfc) + { +- u32 csqier = readl_relaxed(fmc2->io_base + FMC2_CSQIER); ++ regmap_update_bits(nfc->regmap, FMC2_CSQIER, FMC2_CSQIER_TCIE, 0); + +- csqier &= ~FMC2_CSQIER_TCIE; +- +- writel_relaxed(csqier, fmc2->io_base + FMC2_CSQIER); +- +- fmc2->irq_state = FMC2_IRQ_UNKNOWN; ++ nfc->irq_state = FMC2_IRQ_UNKNOWN; + } + +-/* Clear irq sources in case of the sequencer is used */ +-static inline void stm32_fmc2_clear_seq_irq(struct stm32_fmc2_nfc *fmc2) ++static void stm32_fmc2_nfc_clear_seq_irq(struct stm32_fmc2_nfc *nfc) + { +- writel_relaxed(FMC2_CSQICR_CLEAR_IRQ, fmc2->io_base + FMC2_CSQICR); ++ regmap_write(nfc->regmap, FMC2_CSQICR, FMC2_CSQICR_CLEAR_IRQ); + } + +-/* Enable irq sources in case of bch is used */ +-static inline void stm32_fmc2_enable_bch_irq(struct stm32_fmc2_nfc *fmc2, +- int mode) ++static void stm32_fmc2_nfc_enable_bch_irq(struct stm32_fmc2_nfc *nfc, int mode) + { +- u32 bchier = readl_relaxed(fmc2->io_base + FMC2_BCHIER); ++ nfc->irq_state = FMC2_IRQ_BCH; + + if (mode == NAND_ECC_WRITE) +- bchier |= FMC2_BCHIER_EPBRIE; ++ regmap_update_bits(nfc->regmap, FMC2_BCHIER, ++ FMC2_BCHIER_EPBRIE, FMC2_BCHIER_EPBRIE); + else +- bchier |= FMC2_BCHIER_DERIE; +- +- fmc2->irq_state = FMC2_IRQ_BCH; +- +- writel_relaxed(bchier, fmc2->io_base + FMC2_BCHIER); ++ regmap_update_bits(nfc->regmap, FMC2_BCHIER, ++ FMC2_BCHIER_DERIE, FMC2_BCHIER_DERIE); + } + +-/* Disable irq sources in case of bch is used */ +-static inline void stm32_fmc2_disable_bch_irq(struct stm32_fmc2_nfc *fmc2) ++static void stm32_fmc2_nfc_disable_bch_irq(struct stm32_fmc2_nfc *nfc) + { +- u32 bchier = readl_relaxed(fmc2->io_base + FMC2_BCHIER); ++ regmap_update_bits(nfc->regmap, FMC2_BCHIER, ++ FMC2_BCHIER_DERIE | FMC2_BCHIER_EPBRIE, 0); + +- bchier &= ~FMC2_BCHIER_DERIE; +- bchier &= ~FMC2_BCHIER_EPBRIE; +- +- writel_relaxed(bchier, fmc2->io_base + FMC2_BCHIER); +- +- fmc2->irq_state = FMC2_IRQ_UNKNOWN; ++ nfc->irq_state = FMC2_IRQ_UNKNOWN; + } + +-/* Clear irq sources in case of bch is used */ +-static inline void stm32_fmc2_clear_bch_irq(struct stm32_fmc2_nfc *fmc2) ++static void stm32_fmc2_nfc_clear_bch_irq(struct stm32_fmc2_nfc *nfc) + { +- writel_relaxed(FMC2_BCHICR_CLEAR_IRQ, fmc2->io_base + FMC2_BCHICR); ++ regmap_write(nfc->regmap, FMC2_BCHICR, FMC2_BCHICR_CLEAR_IRQ); + } + + /* + * Enable ECC logic and reset syndrome/parity bits previously calculated + * Syndrome/parity bits is cleared by setting the ECCEN bit to 0 + */ +-static void stm32_fmc2_hwctl(struct nand_chip *chip, int mode) ++static void stm32_fmc2_nfc_hwctl(struct nand_chip *chip, int mode) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + +- stm32_fmc2_set_ecc(fmc2, false); ++ stm32_fmc2_nfc_set_ecc(nfc, false); + + if (chip->ecc.strength != FMC2_ECC_HAM) { +- u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); +- +- if (mode == NAND_ECC_WRITE) +- pcr |= FMC2_PCR_WEN; +- else +- pcr &= ~FMC2_PCR_WEN; +- writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); ++ regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, ++ mode == NAND_ECC_WRITE ? FMC2_PCR_WEN : 0); + +- reinit_completion(&fmc2->complete); +- stm32_fmc2_clear_bch_irq(fmc2); +- stm32_fmc2_enable_bch_irq(fmc2, mode); ++ reinit_completion(&nfc->complete); ++ stm32_fmc2_nfc_clear_bch_irq(nfc); ++ stm32_fmc2_nfc_enable_bch_irq(nfc, mode); + } + +- stm32_fmc2_set_ecc(fmc2, true); ++ stm32_fmc2_nfc_set_ecc(nfc, true); + } + + /* +@@ -526,40 +480,37 @@ static void stm32_fmc2_hwctl(struct nand_chip *chip, int mode) + * ECC is 3 bytes for 512 bytes of data (supports error correction up to + * max of 1-bit) + */ +-static inline void stm32_fmc2_ham_set_ecc(const u32 ecc_sta, u8 *ecc) ++static void stm32_fmc2_nfc_ham_set_ecc(const u32 ecc_sta, u8 *ecc) + { + ecc[0] = ecc_sta; + ecc[1] = ecc_sta >> 8; + ecc[2] = ecc_sta >> 16; + } + +-static int stm32_fmc2_ham_calculate(struct nand_chip *chip, const u8 *data, +- u8 *ecc) ++static int stm32_fmc2_nfc_ham_calculate(struct nand_chip *chip, const u8 *data, ++ u8 *ecc) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + u32 sr, heccr; + int ret; + +- ret = readl_relaxed_poll_timeout(fmc2->io_base + FMC2_SR, +- sr, sr & FMC2_SR_NWRF, 10, +- FMC2_TIMEOUT_MS); ++ ret = regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, ++ sr & FMC2_SR_NWRF, 1, ++ 1000 * FMC2_TIMEOUT_MS); + if (ret) { +- dev_err(fmc2->dev, "ham timeout\n"); ++ dev_err(nfc->dev, "ham timeout\n"); + return ret; + } + +- heccr = readl_relaxed(fmc2->io_base + FMC2_HECCR); +- +- stm32_fmc2_ham_set_ecc(heccr, ecc); +- +- /* Disable ECC */ +- stm32_fmc2_set_ecc(fmc2, false); ++ regmap_read(nfc->regmap, FMC2_HECCR, &heccr); ++ stm32_fmc2_nfc_ham_set_ecc(heccr, ecc); ++ stm32_fmc2_nfc_set_ecc(nfc, false); + + return 0; + } + +-static int stm32_fmc2_ham_correct(struct nand_chip *chip, u8 *dat, +- u8 *read_ecc, u8 *calc_ecc) ++static int stm32_fmc2_nfc_ham_correct(struct nand_chip *chip, u8 *dat, ++ u8 *read_ecc, u8 *calc_ecc) + { + u8 bit_position = 0, b0, b1, b2; + u32 byte_addr = 0, b; +@@ -615,28 +566,28 @@ static int stm32_fmc2_ham_correct(struct nand_chip *chip, u8 *dat, + * ECC is 7/13 bytes for 512 bytes of data (supports error correction up to + * max of 4-bit/8-bit) + */ +-static int stm32_fmc2_bch_calculate(struct nand_chip *chip, const u8 *data, +- u8 *ecc) ++static int stm32_fmc2_nfc_bch_calculate(struct nand_chip *chip, const u8 *data, ++ u8 *ecc) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + u32 bchpbr; + + /* Wait until the BCH code is ready */ +- if (!wait_for_completion_timeout(&fmc2->complete, ++ if (!wait_for_completion_timeout(&nfc->complete, + msecs_to_jiffies(FMC2_TIMEOUT_MS))) { +- dev_err(fmc2->dev, "bch timeout\n"); +- stm32_fmc2_disable_bch_irq(fmc2); ++ dev_err(nfc->dev, "bch timeout\n"); ++ stm32_fmc2_nfc_disable_bch_irq(nfc); + return -ETIMEDOUT; + } + + /* Read parity bits */ +- bchpbr = readl_relaxed(fmc2->io_base + FMC2_BCHPBR1); ++ regmap_read(nfc->regmap, FMC2_BCHPBR1, &bchpbr); + ecc[0] = bchpbr; + ecc[1] = bchpbr >> 8; + ecc[2] = bchpbr >> 16; + ecc[3] = bchpbr >> 24; + +- bchpbr = readl_relaxed(fmc2->io_base + FMC2_BCHPBR2); ++ regmap_read(nfc->regmap, FMC2_BCHPBR2, &bchpbr); + ecc[4] = bchpbr; + ecc[5] = bchpbr >> 8; + ecc[6] = bchpbr >> 16; +@@ -644,24 +595,22 @@ static int stm32_fmc2_bch_calculate(struct nand_chip *chip, const u8 *data, + if (chip->ecc.strength == FMC2_ECC_BCH8) { + ecc[7] = bchpbr >> 24; + +- bchpbr = readl_relaxed(fmc2->io_base + FMC2_BCHPBR3); ++ regmap_read(nfc->regmap, FMC2_BCHPBR3, &bchpbr); + ecc[8] = bchpbr; + ecc[9] = bchpbr >> 8; + ecc[10] = bchpbr >> 16; + ecc[11] = bchpbr >> 24; + +- bchpbr = readl_relaxed(fmc2->io_base + FMC2_BCHPBR4); ++ regmap_read(nfc->regmap, FMC2_BCHPBR4, &bchpbr); + ecc[12] = bchpbr; + } + +- /* Disable ECC */ +- stm32_fmc2_set_ecc(fmc2, false); ++ stm32_fmc2_nfc_set_ecc(nfc, false); + + return 0; + } + +-/* BCH algorithm correction */ +-static int stm32_fmc2_bch_decode(int eccsize, u8 *dat, u32 *ecc_sta) ++static int stm32_fmc2_nfc_bch_decode(int eccsize, u8 *dat, u32 *ecc_sta) + { + u32 bchdsr0 = ecc_sta[0]; + u32 bchdsr1 = ecc_sta[1]; +@@ -680,16 +629,16 @@ static int stm32_fmc2_bch_decode(int eccsize, u8 *dat, u32 *ecc_sta) + if (unlikely(bchdsr0 & FMC2_BCHDSR0_DUE)) + return -EBADMSG; + +- pos[0] = bchdsr1 & FMC2_BCHDSR1_EBP1_MASK; +- pos[1] = (bchdsr1 & FMC2_BCHDSR1_EBP2_MASK) >> FMC2_BCHDSR1_EBP2_SHIFT; +- pos[2] = bchdsr2 & FMC2_BCHDSR2_EBP3_MASK; +- pos[3] = (bchdsr2 & FMC2_BCHDSR2_EBP4_MASK) >> FMC2_BCHDSR2_EBP4_SHIFT; +- pos[4] = bchdsr3 & FMC2_BCHDSR3_EBP5_MASK; +- pos[5] = (bchdsr3 & FMC2_BCHDSR3_EBP6_MASK) >> FMC2_BCHDSR3_EBP6_SHIFT; +- pos[6] = bchdsr4 & FMC2_BCHDSR4_EBP7_MASK; +- pos[7] = (bchdsr4 & FMC2_BCHDSR4_EBP8_MASK) >> FMC2_BCHDSR4_EBP8_SHIFT; ++ pos[0] = FIELD_GET(FMC2_BCHDSR1_EBP1, bchdsr1); ++ pos[1] = FIELD_GET(FMC2_BCHDSR1_EBP2, bchdsr1); ++ pos[2] = FIELD_GET(FMC2_BCHDSR2_EBP3, bchdsr2); ++ pos[3] = FIELD_GET(FMC2_BCHDSR2_EBP4, bchdsr2); ++ pos[4] = FIELD_GET(FMC2_BCHDSR3_EBP5, bchdsr3); ++ pos[5] = FIELD_GET(FMC2_BCHDSR3_EBP6, bchdsr3); ++ pos[6] = FIELD_GET(FMC2_BCHDSR4_EBP7, bchdsr4); ++ pos[7] = FIELD_GET(FMC2_BCHDSR4_EBP8, bchdsr4); + +- den = (bchdsr0 & FMC2_BCHDSR0_DEN_MASK) >> FMC2_BCHDSR0_DEN_SHIFT; ++ den = FIELD_GET(FMC2_BCHDSR0_DEN, bchdsr0); + for (i = 0; i < den; i++) { + if (pos[i] < eccsize * 8) { + change_bit(pos[i], (unsigned long *)dat); +@@ -700,34 +649,29 @@ static int stm32_fmc2_bch_decode(int eccsize, u8 *dat, u32 *ecc_sta) + return nb_errs; + } + +-static int stm32_fmc2_bch_correct(struct nand_chip *chip, u8 *dat, +- u8 *read_ecc, u8 *calc_ecc) ++static int stm32_fmc2_nfc_bch_correct(struct nand_chip *chip, u8 *dat, ++ u8 *read_ecc, u8 *calc_ecc) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + u32 ecc_sta[5]; + + /* Wait until the decoding error is ready */ +- if (!wait_for_completion_timeout(&fmc2->complete, ++ if (!wait_for_completion_timeout(&nfc->complete, + msecs_to_jiffies(FMC2_TIMEOUT_MS))) { +- dev_err(fmc2->dev, "bch timeout\n"); +- stm32_fmc2_disable_bch_irq(fmc2); ++ dev_err(nfc->dev, "bch timeout\n"); ++ stm32_fmc2_nfc_disable_bch_irq(nfc); + return -ETIMEDOUT; + } + +- ecc_sta[0] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR0); +- ecc_sta[1] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR1); +- ecc_sta[2] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR2); +- ecc_sta[3] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR3); +- ecc_sta[4] = readl_relaxed(fmc2->io_base + FMC2_BCHDSR4); ++ regmap_bulk_read(nfc->regmap, FMC2_BCHDSR0, ecc_sta, 5); + +- /* Disable ECC */ +- stm32_fmc2_set_ecc(fmc2, false); ++ stm32_fmc2_nfc_set_ecc(nfc, false); + +- return stm32_fmc2_bch_decode(chip->ecc.size, dat, ecc_sta); ++ return stm32_fmc2_nfc_bch_decode(chip->ecc.size, dat, ecc_sta); + } + +-static int stm32_fmc2_read_page(struct nand_chip *chip, u8 *buf, +- int oob_required, int page) ++static int stm32_fmc2_nfc_read_page(struct nand_chip *chip, u8 *buf, ++ int oob_required, int page) + { + struct mtd_info *mtd = nand_to_mtd(chip); + int ret, i, s, stat, eccsize = chip->ecc.size; +@@ -789,35 +733,34 @@ static int stm32_fmc2_read_page(struct nand_chip *chip, u8 *buf, + } + + /* Sequencer read/write configuration */ +-static void stm32_fmc2_rw_page_init(struct nand_chip *chip, int page, +- int raw, bool write_data) ++static void stm32_fmc2_nfc_rw_page_init(struct nand_chip *chip, int page, ++ int raw, bool write_data) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct mtd_info *mtd = nand_to_mtd(chip); +- u32 csqcfgr1, csqcfgr2, csqcfgr3; +- u32 csqar1, csqar2; + u32 ecc_offset = mtd->writesize + FMC2_BBM_LEN; +- u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); ++ /* ++ * cfg[0] => csqcfgr1, cfg[1] => csqcfgr2, cfg[2] => csqcfgr3 ++ * cfg[3] => csqar1, cfg[4] => csqar2 ++ */ ++ u32 cfg[5]; + +- if (write_data) +- pcr |= FMC2_PCR_WEN; +- else +- pcr &= ~FMC2_PCR_WEN; +- writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); ++ regmap_update_bits(nfc->regmap, FMC2_PCR, FMC2_PCR_WEN, ++ write_data ? FMC2_PCR_WEN : 0); + + /* + * - Set Program Page/Page Read command + * - Enable DMA request data + * - Set timings + */ +- csqcfgr1 = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T; ++ cfg[0] = FMC2_CSQCFGR1_DMADEN | FMC2_CSQCFGR1_CMD1T; + if (write_data) +- csqcfgr1 |= FMC2_CSQCFGR1_CMD1(NAND_CMD_SEQIN); ++ cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_SEQIN); + else +- csqcfgr1 |= FMC2_CSQCFGR1_CMD1(NAND_CMD_READ0) | +- FMC2_CSQCFGR1_CMD2EN | +- FMC2_CSQCFGR1_CMD2(NAND_CMD_READSTART) | +- FMC2_CSQCFGR1_CMD2T; ++ cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_CMD1, NAND_CMD_READ0) | ++ FMC2_CSQCFGR1_CMD2EN | ++ FIELD_PREP(FMC2_CSQCFGR1_CMD2, NAND_CMD_READSTART) | ++ FMC2_CSQCFGR1_CMD2T; + + /* + * - Set Random Data Input/Random Data Read command +@@ -826,29 +769,29 @@ static void stm32_fmc2_rw_page_init(struct nand_chip *chip, int page, + * - Set timings + */ + if (write_data) +- csqcfgr2 = FMC2_CSQCFGR2_RCMD1(NAND_CMD_RNDIN); ++ cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDIN); + else +- csqcfgr2 = FMC2_CSQCFGR2_RCMD1(NAND_CMD_RNDOUT) | +- FMC2_CSQCFGR2_RCMD2EN | +- FMC2_CSQCFGR2_RCMD2(NAND_CMD_RNDOUTSTART) | +- FMC2_CSQCFGR2_RCMD1T | +- FMC2_CSQCFGR2_RCMD2T; ++ cfg[1] = FIELD_PREP(FMC2_CSQCFGR2_RCMD1, NAND_CMD_RNDOUT) | ++ FMC2_CSQCFGR2_RCMD2EN | ++ FIELD_PREP(FMC2_CSQCFGR2_RCMD2, NAND_CMD_RNDOUTSTART) | ++ FMC2_CSQCFGR2_RCMD1T | ++ FMC2_CSQCFGR2_RCMD2T; + if (!raw) { +- csqcfgr2 |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN; +- csqcfgr2 |= FMC2_CSQCFGR2_SQSDTEN; ++ cfg[1] |= write_data ? 0 : FMC2_CSQCFGR2_DMASEN; ++ cfg[1] |= FMC2_CSQCFGR2_SQSDTEN; + } + + /* + * - Set the number of sectors to be written + * - Set timings + */ +- csqcfgr3 = FMC2_CSQCFGR3_SNBR(chip->ecc.steps - 1); ++ cfg[2] = FIELD_PREP(FMC2_CSQCFGR3_SNBR, chip->ecc.steps - 1); + if (write_data) { +- csqcfgr3 |= FMC2_CSQCFGR3_RAC2T; ++ cfg[2] |= FMC2_CSQCFGR3_RAC2T; + if (chip->options & NAND_ROW_ADDR_3) +- csqcfgr3 |= FMC2_CSQCFGR3_AC5T; ++ cfg[2] |= FMC2_CSQCFGR3_AC5T; + else +- csqcfgr3 |= FMC2_CSQCFGR3_AC4T; ++ cfg[2] |= FMC2_CSQCFGR3_AC4T; + } + + /* +@@ -856,8 +799,8 @@ static void stm32_fmc2_rw_page_init(struct nand_chip *chip, int page, + * Byte 1 and byte 2 => column, we start at 0x0 + * Byte 3 and byte 4 => page + */ +- csqar1 = FMC2_CSQCAR1_ADDC3(page); +- csqar1 |= FMC2_CSQCAR1_ADDC4(page >> 8); ++ cfg[3] = FIELD_PREP(FMC2_CSQCAR1_ADDC3, page); ++ cfg[3] |= FIELD_PREP(FMC2_CSQCAR1_ADDC4, page >> 8); + + /* + * - Set chip enable number +@@ -865,43 +808,39 @@ static void stm32_fmc2_rw_page_init(struct nand_chip *chip, int page, + * - Calculate the number of address cycles to be issued + * - Set byte 5 of address cycle if needed + */ +- csqar2 = FMC2_CSQCAR2_NANDCEN(fmc2->cs_sel); ++ cfg[4] = FIELD_PREP(FMC2_CSQCAR2_NANDCEN, nfc->cs_sel); + if (chip->options & NAND_BUSWIDTH_16) +- csqar2 |= FMC2_CSQCAR2_SAO(ecc_offset >> 1); ++ cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset >> 1); + else +- csqar2 |= FMC2_CSQCAR2_SAO(ecc_offset); ++ cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_SAO, ecc_offset); + if (chip->options & NAND_ROW_ADDR_3) { +- csqcfgr1 |= FMC2_CSQCFGR1_ACYNBR(5); +- csqar2 |= FMC2_CSQCAR2_ADDC5(page >> 16); ++ cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 5); ++ cfg[4] |= FIELD_PREP(FMC2_CSQCAR2_ADDC5, page >> 16); + } else { +- csqcfgr1 |= FMC2_CSQCFGR1_ACYNBR(4); ++ cfg[0] |= FIELD_PREP(FMC2_CSQCFGR1_ACYNBR, 4); + } + +- writel_relaxed(csqcfgr1, fmc2->io_base + FMC2_CSQCFGR1); +- writel_relaxed(csqcfgr2, fmc2->io_base + FMC2_CSQCFGR2); +- writel_relaxed(csqcfgr3, fmc2->io_base + FMC2_CSQCFGR3); +- writel_relaxed(csqar1, fmc2->io_base + FMC2_CSQAR1); +- writel_relaxed(csqar2, fmc2->io_base + FMC2_CSQAR2); ++ regmap_bulk_write(nfc->regmap, FMC2_CSQCFGR1, cfg, 5); + } + +-static void stm32_fmc2_dma_callback(void *arg) ++static void stm32_fmc2_nfc_dma_callback(void *arg) + { + complete((struct completion *)arg); + } + + /* Read/write data from/to a page */ +-static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, +- int raw, bool write_data) ++static int stm32_fmc2_nfc_xfer(struct nand_chip *chip, const u8 *buf, ++ int raw, bool write_data) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct dma_async_tx_descriptor *desc_data, *desc_ecc; + struct scatterlist *sg; +- struct dma_chan *dma_ch = fmc2->dma_rx_ch; ++ struct dma_chan *dma_ch = nfc->dma_rx_ch; + enum dma_data_direction dma_data_dir = DMA_FROM_DEVICE; + enum dma_transfer_direction dma_transfer_dir = DMA_DEV_TO_MEM; +- u32 csqcr = readl_relaxed(fmc2->io_base + FMC2_CSQCR); + int eccsteps = chip->ecc.steps; + int eccsize = chip->ecc.size; ++ unsigned long timeout = msecs_to_jiffies(FMC2_TIMEOUT_MS); + const u8 *p = buf; + int s, ret; + +@@ -909,20 +848,20 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, + if (write_data) { + dma_data_dir = DMA_TO_DEVICE; + dma_transfer_dir = DMA_MEM_TO_DEV; +- dma_ch = fmc2->dma_tx_ch; ++ dma_ch = nfc->dma_tx_ch; + } + +- for_each_sg(fmc2->dma_data_sg.sgl, sg, eccsteps, s) { ++ for_each_sg(nfc->dma_data_sg.sgl, sg, eccsteps, s) { + sg_set_buf(sg, p, eccsize); + p += eccsize; + } + +- ret = dma_map_sg(fmc2->dev, fmc2->dma_data_sg.sgl, ++ ret = dma_map_sg(nfc->dev, nfc->dma_data_sg.sgl, + eccsteps, dma_data_dir); + if (ret < 0) + return ret; + +- desc_data = dmaengine_prep_slave_sg(dma_ch, fmc2->dma_data_sg.sgl, ++ desc_data = dmaengine_prep_slave_sg(dma_ch, nfc->dma_data_sg.sgl, + eccsteps, dma_transfer_dir, + DMA_PREP_INTERRUPT); + if (!desc_data) { +@@ -930,10 +869,10 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, + goto err_unmap_data; + } + +- reinit_completion(&fmc2->dma_data_complete); +- reinit_completion(&fmc2->complete); +- desc_data->callback = stm32_fmc2_dma_callback; +- desc_data->callback_param = &fmc2->dma_data_complete; ++ reinit_completion(&nfc->dma_data_complete); ++ reinit_completion(&nfc->complete); ++ desc_data->callback = stm32_fmc2_nfc_dma_callback; ++ desc_data->callback_param = &nfc->dma_data_complete; + ret = dma_submit_error(dmaengine_submit(desc_data)); + if (ret) + goto err_unmap_data; +@@ -942,19 +881,19 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, + + if (!write_data && !raw) { + /* Configure DMA ECC status */ +- p = fmc2->ecc_buf; +- for_each_sg(fmc2->dma_ecc_sg.sgl, sg, eccsteps, s) { +- sg_set_buf(sg, p, fmc2->dma_ecc_len); +- p += fmc2->dma_ecc_len; ++ p = nfc->ecc_buf; ++ for_each_sg(nfc->dma_ecc_sg.sgl, sg, eccsteps, s) { ++ sg_set_buf(sg, p, nfc->dma_ecc_len); ++ p += nfc->dma_ecc_len; + } + +- ret = dma_map_sg(fmc2->dev, fmc2->dma_ecc_sg.sgl, ++ ret = dma_map_sg(nfc->dev, nfc->dma_ecc_sg.sgl, + eccsteps, dma_data_dir); + if (ret < 0) + goto err_unmap_data; + +- desc_ecc = dmaengine_prep_slave_sg(fmc2->dma_ecc_ch, +- fmc2->dma_ecc_sg.sgl, ++ desc_ecc = dmaengine_prep_slave_sg(nfc->dma_ecc_ch, ++ nfc->dma_ecc_sg.sgl, + eccsteps, dma_transfer_dir, + DMA_PREP_INTERRUPT); + if (!desc_ecc) { +@@ -962,76 +901,73 @@ static int stm32_fmc2_xfer(struct nand_chip *chip, const u8 *buf, + goto err_unmap_ecc; + } + +- reinit_completion(&fmc2->dma_ecc_complete); +- desc_ecc->callback = stm32_fmc2_dma_callback; +- desc_ecc->callback_param = &fmc2->dma_ecc_complete; ++ reinit_completion(&nfc->dma_ecc_complete); ++ desc_ecc->callback = stm32_fmc2_nfc_dma_callback; ++ desc_ecc->callback_param = &nfc->dma_ecc_complete; + ret = dma_submit_error(dmaengine_submit(desc_ecc)); + if (ret) + goto err_unmap_ecc; + +- dma_async_issue_pending(fmc2->dma_ecc_ch); ++ dma_async_issue_pending(nfc->dma_ecc_ch); + } + +- stm32_fmc2_clear_seq_irq(fmc2); +- stm32_fmc2_enable_seq_irq(fmc2); ++ stm32_fmc2_nfc_clear_seq_irq(nfc); ++ stm32_fmc2_nfc_enable_seq_irq(nfc); + + /* Start the transfer */ +- csqcr |= FMC2_CSQCR_CSQSTART; +- writel_relaxed(csqcr, fmc2->io_base + FMC2_CSQCR); ++ regmap_update_bits(nfc->regmap, FMC2_CSQCR, ++ FMC2_CSQCR_CSQSTART, FMC2_CSQCR_CSQSTART); + + /* Wait end of sequencer transfer */ +- if (!wait_for_completion_timeout(&fmc2->complete, +- msecs_to_jiffies(FMC2_TIMEOUT_MS))) { +- dev_err(fmc2->dev, "seq timeout\n"); +- stm32_fmc2_disable_seq_irq(fmc2); ++ if (!wait_for_completion_timeout(&nfc->complete, timeout)) { ++ dev_err(nfc->dev, "seq timeout\n"); ++ stm32_fmc2_nfc_disable_seq_irq(nfc); + dmaengine_terminate_all(dma_ch); + if (!write_data && !raw) +- dmaengine_terminate_all(fmc2->dma_ecc_ch); ++ dmaengine_terminate_all(nfc->dma_ecc_ch); + ret = -ETIMEDOUT; + goto err_unmap_ecc; + } + + /* Wait DMA data transfer completion */ +- if (!wait_for_completion_timeout(&fmc2->dma_data_complete, +- msecs_to_jiffies(FMC2_TIMEOUT_MS))) { +- dev_err(fmc2->dev, "data DMA timeout\n"); ++ if (!wait_for_completion_timeout(&nfc->dma_data_complete, timeout)) { ++ dev_err(nfc->dev, "data DMA timeout\n"); + dmaengine_terminate_all(dma_ch); + ret = -ETIMEDOUT; + } + + /* Wait DMA ECC transfer completion */ + if (!write_data && !raw) { +- if (!wait_for_completion_timeout(&fmc2->dma_ecc_complete, +- msecs_to_jiffies(FMC2_TIMEOUT_MS))) { +- dev_err(fmc2->dev, "ECC DMA timeout\n"); +- dmaengine_terminate_all(fmc2->dma_ecc_ch); ++ if (!wait_for_completion_timeout(&nfc->dma_ecc_complete, ++ timeout)) { ++ dev_err(nfc->dev, "ECC DMA timeout\n"); ++ dmaengine_terminate_all(nfc->dma_ecc_ch); + ret = -ETIMEDOUT; + } + } + + err_unmap_ecc: + if (!write_data && !raw) +- dma_unmap_sg(fmc2->dev, fmc2->dma_ecc_sg.sgl, ++ dma_unmap_sg(nfc->dev, nfc->dma_ecc_sg.sgl, + eccsteps, dma_data_dir); + + err_unmap_data: +- dma_unmap_sg(fmc2->dev, fmc2->dma_data_sg.sgl, eccsteps, dma_data_dir); ++ dma_unmap_sg(nfc->dev, nfc->dma_data_sg.sgl, eccsteps, dma_data_dir); + + return ret; + } + +-static int stm32_fmc2_sequencer_write(struct nand_chip *chip, +- const u8 *buf, int oob_required, +- int page, int raw) ++static int stm32_fmc2_nfc_seq_write(struct nand_chip *chip, const u8 *buf, ++ int oob_required, int page, int raw) + { + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + + /* Configure the sequencer */ +- stm32_fmc2_rw_page_init(chip, page, raw, true); ++ stm32_fmc2_nfc_rw_page_init(chip, page, raw, true); + + /* Write the page */ +- ret = stm32_fmc2_xfer(chip, buf, raw, true); ++ ret = stm32_fmc2_nfc_xfer(chip, buf, raw, true); + if (ret) + return ret; + +@@ -1047,55 +983,52 @@ static int stm32_fmc2_sequencer_write(struct nand_chip *chip, + return nand_prog_page_end_op(chip); + } + +-static int stm32_fmc2_sequencer_write_page(struct nand_chip *chip, +- const u8 *buf, +- int oob_required, +- int page) ++static int stm32_fmc2_nfc_seq_write_page(struct nand_chip *chip, const u8 *buf, ++ int oob_required, int page) + { + int ret; + +- /* Select the target */ +- ret = stm32_fmc2_select_chip(chip, chip->cur_cs); ++ ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); + if (ret) + return ret; + +- return stm32_fmc2_sequencer_write(chip, buf, oob_required, page, false); ++ return stm32_fmc2_nfc_seq_write(chip, buf, oob_required, page, false); + } + +-static int stm32_fmc2_sequencer_write_page_raw(struct nand_chip *chip, +- const u8 *buf, +- int oob_required, +- int page) ++static int stm32_fmc2_nfc_seq_write_page_raw(struct nand_chip *chip, ++ const u8 *buf, int oob_required, ++ int page) + { + int ret; + +- /* Select the target */ +- ret = stm32_fmc2_select_chip(chip, chip->cur_cs); ++ ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); + if (ret) + return ret; + +- return stm32_fmc2_sequencer_write(chip, buf, oob_required, page, true); ++ return stm32_fmc2_nfc_seq_write(chip, buf, oob_required, page, true); + } + + /* Get a status indicating which sectors have errors */ +-static inline u16 stm32_fmc2_get_mapping_status(struct stm32_fmc2_nfc *fmc2) ++static u16 stm32_fmc2_nfc_get_mapping_status(struct stm32_fmc2_nfc *nfc) + { +- u32 csqemsr = readl_relaxed(fmc2->io_base + FMC2_CSQEMSR); ++ u32 csqemsr; + +- return csqemsr & FMC2_CSQEMSR_SEM; ++ regmap_read(nfc->regmap, FMC2_CSQEMSR, &csqemsr); ++ ++ return FIELD_GET(FMC2_CSQEMSR_SEM, csqemsr); + } + +-static int stm32_fmc2_sequencer_correct(struct nand_chip *chip, u8 *dat, +- u8 *read_ecc, u8 *calc_ecc) ++static int stm32_fmc2_nfc_seq_correct(struct nand_chip *chip, u8 *dat, ++ u8 *read_ecc, u8 *calc_ecc) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + int eccbytes = chip->ecc.bytes; + int eccsteps = chip->ecc.steps; + int eccstrength = chip->ecc.strength; + int i, s, eccsize = chip->ecc.size; +- u32 *ecc_sta = (u32 *)fmc2->ecc_buf; +- u16 sta_map = stm32_fmc2_get_mapping_status(fmc2); ++ u32 *ecc_sta = (u32 *)nfc->ecc_buf; ++ u16 sta_map = stm32_fmc2_nfc_get_mapping_status(nfc); + unsigned int max_bitflips = 0; + + for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, dat += eccsize) { +@@ -1104,10 +1037,11 @@ static int stm32_fmc2_sequencer_correct(struct nand_chip *chip, u8 *dat, + if (eccstrength == FMC2_ECC_HAM) { + /* Ecc_sta = FMC2_HECCR */ + if (sta_map & BIT(s)) { +- stm32_fmc2_ham_set_ecc(*ecc_sta, &calc_ecc[i]); +- stat = stm32_fmc2_ham_correct(chip, dat, +- &read_ecc[i], +- &calc_ecc[i]); ++ stm32_fmc2_nfc_ham_set_ecc(*ecc_sta, ++ &calc_ecc[i]); ++ stat = stm32_fmc2_nfc_ham_correct(chip, dat, ++ &read_ecc[i], ++ &calc_ecc[i]); + } + ecc_sta++; + } else { +@@ -1119,8 +1053,8 @@ static int stm32_fmc2_sequencer_correct(struct nand_chip *chip, u8 *dat, + * Ecc_sta[4] = FMC2_BCHDSR4 + */ + if (sta_map & BIT(s)) +- stat = stm32_fmc2_bch_decode(eccsize, dat, +- ecc_sta); ++ stat = stm32_fmc2_nfc_bch_decode(eccsize, dat, ++ ecc_sta); + ecc_sta += 5; + } + +@@ -1143,30 +1077,29 @@ static int stm32_fmc2_sequencer_correct(struct nand_chip *chip, u8 *dat, + return max_bitflips; + } + +-static int stm32_fmc2_sequencer_read_page(struct nand_chip *chip, u8 *buf, +- int oob_required, int page) ++static int stm32_fmc2_nfc_seq_read_page(struct nand_chip *chip, u8 *buf, ++ int oob_required, int page) + { + struct mtd_info *mtd = nand_to_mtd(chip); +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + u8 *ecc_calc = chip->ecc.calc_buf; + u8 *ecc_code = chip->ecc.code_buf; + u16 sta_map; + int ret; + +- /* Select the target */ +- ret = stm32_fmc2_select_chip(chip, chip->cur_cs); ++ ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); + if (ret) + return ret; + + /* Configure the sequencer */ +- stm32_fmc2_rw_page_init(chip, page, 0, false); ++ stm32_fmc2_nfc_rw_page_init(chip, page, 0, false); + + /* Read the page */ +- ret = stm32_fmc2_xfer(chip, buf, 0, false); ++ ret = stm32_fmc2_nfc_xfer(chip, buf, 0, false); + if (ret) + return ret; + +- sta_map = stm32_fmc2_get_mapping_status(fmc2); ++ sta_map = stm32_fmc2_nfc_get_mapping_status(nfc); + + /* Check if errors happen */ + if (likely(!sta_map)) { +@@ -1193,22 +1126,21 @@ static int stm32_fmc2_sequencer_read_page(struct nand_chip *chip, u8 *buf, + return chip->ecc.correct(chip, buf, ecc_code, ecc_calc); + } + +-static int stm32_fmc2_sequencer_read_page_raw(struct nand_chip *chip, u8 *buf, +- int oob_required, int page) ++static int stm32_fmc2_nfc_seq_read_page_raw(struct nand_chip *chip, u8 *buf, ++ int oob_required, int page) + { + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + +- /* Select the target */ +- ret = stm32_fmc2_select_chip(chip, chip->cur_cs); ++ ret = stm32_fmc2_nfc_select_chip(chip, chip->cur_cs); + if (ret) + return ret; + + /* Configure the sequencer */ +- stm32_fmc2_rw_page_init(chip, page, 1, false); ++ stm32_fmc2_nfc_rw_page_init(chip, page, 1, false); + + /* Read the page */ +- ret = stm32_fmc2_xfer(chip, buf, 1, false); ++ ret = stm32_fmc2_nfc_xfer(chip, buf, 1, false); + if (ret) + return ret; + +@@ -1221,31 +1153,31 @@ static int stm32_fmc2_sequencer_read_page_raw(struct nand_chip *chip, u8 *buf, + return 0; + } + +-static irqreturn_t stm32_fmc2_irq(int irq, void *dev_id) ++static irqreturn_t stm32_fmc2_nfc_irq(int irq, void *dev_id) + { +- struct stm32_fmc2_nfc *fmc2 = (struct stm32_fmc2_nfc *)dev_id; ++ struct stm32_fmc2_nfc *nfc = (struct stm32_fmc2_nfc *)dev_id; + +- if (fmc2->irq_state == FMC2_IRQ_SEQ) ++ if (nfc->irq_state == FMC2_IRQ_SEQ) + /* Sequencer is used */ +- stm32_fmc2_disable_seq_irq(fmc2); +- else if (fmc2->irq_state == FMC2_IRQ_BCH) ++ stm32_fmc2_nfc_disable_seq_irq(nfc); ++ else if (nfc->irq_state == FMC2_IRQ_BCH) + /* BCH is used */ +- stm32_fmc2_disable_bch_irq(fmc2); ++ stm32_fmc2_nfc_disable_bch_irq(nfc); + +- complete(&fmc2->complete); ++ complete(&nfc->complete); + + return IRQ_HANDLED; + } + +-static void stm32_fmc2_read_data(struct nand_chip *chip, void *buf, +- unsigned int len, bool force_8bit) ++static void stm32_fmc2_nfc_read_data(struct nand_chip *chip, void *buf, ++ unsigned int len, bool force_8bit) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); +- void __iomem *io_addr_r = fmc2->data_base[fmc2->cs_sel]; ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); ++ void __iomem *io_addr_r = nfc->data_base[nfc->cs_sel]; + + if (force_8bit && chip->options & NAND_BUSWIDTH_16) + /* Reconfigure bus width to 8-bit */ +- stm32_fmc2_set_buswidth_16(fmc2, false); ++ stm32_fmc2_nfc_set_buswidth_16(nfc, false); + + if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) { + if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16)) && len) { +@@ -1281,18 +1213,18 @@ static void stm32_fmc2_read_data(struct nand_chip *chip, void *buf, + + if (force_8bit && chip->options & NAND_BUSWIDTH_16) + /* Reconfigure bus width to 16-bit */ +- stm32_fmc2_set_buswidth_16(fmc2, true); ++ stm32_fmc2_nfc_set_buswidth_16(nfc, true); + } + +-static void stm32_fmc2_write_data(struct nand_chip *chip, const void *buf, +- unsigned int len, bool force_8bit) ++static void stm32_fmc2_nfc_write_data(struct nand_chip *chip, const void *buf, ++ unsigned int len, bool force_8bit) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); +- void __iomem *io_addr_w = fmc2->data_base[fmc2->cs_sel]; ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); ++ void __iomem *io_addr_w = nfc->data_base[nfc->cs_sel]; + + if (force_8bit && chip->options & NAND_BUSWIDTH_16) + /* Reconfigure bus width to 8-bit */ +- stm32_fmc2_set_buswidth_16(fmc2, false); ++ stm32_fmc2_nfc_set_buswidth_16(nfc, false); + + if (!IS_ALIGNED((uintptr_t)buf, sizeof(u32))) { + if (!IS_ALIGNED((uintptr_t)buf, sizeof(u16)) && len) { +@@ -1328,44 +1260,45 @@ static void stm32_fmc2_write_data(struct nand_chip *chip, const void *buf, + + if (force_8bit && chip->options & NAND_BUSWIDTH_16) + /* Reconfigure bus width to 16-bit */ +- stm32_fmc2_set_buswidth_16(fmc2, true); ++ stm32_fmc2_nfc_set_buswidth_16(nfc, true); + } + +-static int stm32_fmc2_waitrdy(struct nand_chip *chip, unsigned long timeout_ms) ++static int stm32_fmc2_nfc_waitrdy(struct nand_chip *chip, ++ unsigned long timeout_ms) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + const struct nand_sdr_timings *timings; + u32 isr, sr; + + /* Check if there is no pending requests to the NAND flash */ +- if (readl_relaxed_poll_timeout_atomic(fmc2->io_base + FMC2_SR, sr, +- sr & FMC2_SR_NWRF, 1, +- FMC2_TIMEOUT_US)) +- dev_warn(fmc2->dev, "Waitrdy timeout\n"); ++ if (regmap_read_poll_timeout(nfc->regmap, FMC2_SR, sr, ++ sr & FMC2_SR_NWRF, 1, ++ 1000 * FMC2_TIMEOUT_MS)) ++ dev_warn(nfc->dev, "Waitrdy timeout\n"); + + /* 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); ++ regmap_write(nfc->regmap, FMC2_ICR, FMC2_ICR_CIHLF); + + /* Wait R/B# signal is high */ +- return readl_relaxed_poll_timeout_atomic(fmc2->io_base + FMC2_ISR, +- isr, isr & FMC2_ISR_IHLF, +- 5, 1000 * timeout_ms); ++ return regmap_read_poll_timeout(nfc->regmap, FMC2_ISR, isr, ++ isr & FMC2_ISR_IHLF, 5, ++ 1000 * FMC2_TIMEOUT_MS); + } + +-static int stm32_fmc2_exec_op(struct nand_chip *chip, +- const struct nand_operation *op, +- bool check_only) ++static int stm32_fmc2_nfc_exec_op(struct nand_chip *chip, ++ const struct nand_operation *op, ++ bool check_only) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + const struct nand_op_instr *instr = NULL; +- unsigned int op_id, i; ++ unsigned int op_id, i, timeout; + int ret; + +- ret = stm32_fmc2_select_chip(chip, op->cs); ++ ret = stm32_fmc2_nfc_select_chip(chip, op->cs); + if (ret) + return ret; + +@@ -1378,30 +1311,30 @@ static int stm32_fmc2_exec_op(struct nand_chip *chip, + switch (instr->type) { + case NAND_OP_CMD_INSTR: + writeb_relaxed(instr->ctx.cmd.opcode, +- fmc2->cmd_base[fmc2->cs_sel]); ++ nfc->cmd_base[nfc->cs_sel]); + break; + + case NAND_OP_ADDR_INSTR: + for (i = 0; i < instr->ctx.addr.naddrs; i++) + writeb_relaxed(instr->ctx.addr.addrs[i], +- fmc2->addr_base[fmc2->cs_sel]); ++ nfc->addr_base[nfc->cs_sel]); + break; + + case NAND_OP_DATA_IN_INSTR: +- stm32_fmc2_read_data(chip, instr->ctx.data.buf.in, +- instr->ctx.data.len, +- instr->ctx.data.force_8bit); ++ stm32_fmc2_nfc_read_data(chip, instr->ctx.data.buf.in, ++ instr->ctx.data.len, ++ instr->ctx.data.force_8bit); + break; + + case NAND_OP_DATA_OUT_INSTR: +- stm32_fmc2_write_data(chip, instr->ctx.data.buf.out, +- instr->ctx.data.len, +- instr->ctx.data.force_8bit); ++ stm32_fmc2_nfc_write_data(chip, instr->ctx.data.buf.out, ++ instr->ctx.data.len, ++ instr->ctx.data.force_8bit); + break; + + case NAND_OP_WAITRDY_INSTR: +- ret = stm32_fmc2_waitrdy(chip, +- instr->ctx.waitrdy.timeout_ms); ++ timeout = instr->ctx.waitrdy.timeout_ms; ++ ret = stm32_fmc2_nfc_waitrdy(chip, timeout); + break; + } + } +@@ -1409,21 +1342,21 @@ static int stm32_fmc2_exec_op(struct nand_chip *chip, + return ret; + } + +-/* Controller initialization */ +-static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2) ++static void stm32_fmc2_nfc_init(struct stm32_fmc2_nfc *nfc) + { +- u32 pcr = readl_relaxed(fmc2->io_base + FMC2_PCR); +- u32 bcr1 = readl_relaxed(fmc2->io_base + FMC2_BCR1); ++ u32 pcr; ++ ++ regmap_read(nfc->regmap, FMC2_PCR, &pcr); + + /* Set CS used to undefined */ +- fmc2->cs_sel = -1; ++ nfc->cs_sel = -1; + + /* Enable wait feature and nand flash memory bank */ + pcr |= FMC2_PCR_PWAITEN; + pcr |= FMC2_PCR_PBKEN; + + /* Set buswidth to 8 bits mode for identification */ +- pcr &= ~FMC2_PCR_PWID_MASK; ++ pcr &= ~FMC2_PCR_PWID; + + /* ECC logic is disabled */ + pcr &= ~FMC2_PCR_ECCEN; +@@ -1434,32 +1367,32 @@ static void stm32_fmc2_init(struct stm32_fmc2_nfc *fmc2) + pcr &= ~FMC2_PCR_WEN; + + /* Set default ECC sector size */ +- pcr &= ~FMC2_PCR_ECCSS_MASK; +- pcr |= FMC2_PCR_ECCSS(FMC2_PCR_ECCSS_2048); ++ pcr &= ~FMC2_PCR_ECCSS; ++ pcr |= FIELD_PREP(FMC2_PCR_ECCSS, FMC2_PCR_ECCSS_2048); + + /* Set default tclr/tar timings */ +- pcr &= ~FMC2_PCR_TCLR_MASK; +- pcr |= FMC2_PCR_TCLR(FMC2_PCR_TCLR_DEFAULT); +- pcr &= ~FMC2_PCR_TAR_MASK; +- pcr |= FMC2_PCR_TAR(FMC2_PCR_TAR_DEFAULT); ++ pcr &= ~FMC2_PCR_TCLR; ++ pcr |= FIELD_PREP(FMC2_PCR_TCLR, FMC2_PCR_TCLR_DEFAULT); ++ pcr &= ~FMC2_PCR_TAR; ++ pcr |= FIELD_PREP(FMC2_PCR_TAR, FMC2_PCR_TAR_DEFAULT); + + /* Enable FMC2 controller */ +- bcr1 |= FMC2_BCR1_FMC2EN; ++ if (nfc->dev == nfc->cdev) ++ regmap_update_bits(nfc->regmap, FMC2_BCR1, ++ FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); + +- writel_relaxed(bcr1, fmc2->io_base + FMC2_BCR1); +- writel_relaxed(pcr, fmc2->io_base + FMC2_PCR); +- writel_relaxed(FMC2_PMEM_DEFAULT, fmc2->io_base + FMC2_PMEM); +- writel_relaxed(FMC2_PATT_DEFAULT, fmc2->io_base + FMC2_PATT); ++ regmap_write(nfc->regmap, FMC2_PCR, pcr); ++ regmap_write(nfc->regmap, FMC2_PMEM, FMC2_PMEM_DEFAULT); ++ regmap_write(nfc->regmap, FMC2_PATT, FMC2_PATT_DEFAULT); + } + +-/* Controller timings */ +-static void stm32_fmc2_calc_timings(struct nand_chip *chip, +- const struct nand_sdr_timings *sdrt) ++static void stm32_fmc2_nfc_calc_timings(struct nand_chip *chip, ++ const struct nand_sdr_timings *sdrt) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct stm32_fmc2_nand *nand = to_fmc2_nand(chip); + struct stm32_fmc2_timings *tims = &nand->timings; +- unsigned long hclk = clk_get_rate(fmc2->clk); ++ unsigned long hclk = clk_get_rate(nfc->clk); + unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000); + unsigned long timing, tar, tclr, thiz, twait; + unsigned long tset_mem, tset_att, thold_mem, thold_att; +@@ -1583,8 +1516,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, + tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); + } + +-static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr, +- const struct nand_data_interface *conf) ++static int stm32_fmc2_nfc_setup_interface(struct nand_chip *chip, int chipnr, ++ const struct nand_data_interface *conf) + { + const struct nand_sdr_timings *sdrt; + +@@ -1595,77 +1528,102 @@ static int stm32_fmc2_setup_interface(struct nand_chip *chip, int chipnr, + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) + return 0; + +- stm32_fmc2_calc_timings(chip, sdrt); +- +- /* Apply timings */ +- stm32_fmc2_timings_init(chip); ++ stm32_fmc2_nfc_calc_timings(chip, sdrt); ++ stm32_fmc2_nfc_timings_init(chip); + + return 0; + } + +-/* DMA configuration */ +-static int stm32_fmc2_dma_setup(struct stm32_fmc2_nfc *fmc2) ++static int stm32_fmc2_nfc_dma_setup(struct stm32_fmc2_nfc *nfc) + { +- int ret; ++ int ret = 0; + +- fmc2->dma_tx_ch = dma_request_slave_channel(fmc2->dev, "tx"); +- fmc2->dma_rx_ch = dma_request_slave_channel(fmc2->dev, "rx"); +- fmc2->dma_ecc_ch = dma_request_slave_channel(fmc2->dev, "ecc"); ++ nfc->dma_tx_ch = dma_request_chan(nfc->dev, "tx"); ++ if (IS_ERR(nfc->dma_tx_ch)) { ++ ret = PTR_ERR(nfc->dma_tx_ch); ++ if (ret != -ENODEV && ret != -EPROBE_DEFER) ++ dev_err(nfc->dev, ++ "failed to request tx DMA channel: %d\n", ret); ++ nfc->dma_tx_ch = NULL; ++ goto err_dma; ++ } + +- if (!fmc2->dma_tx_ch || !fmc2->dma_rx_ch || !fmc2->dma_ecc_ch) { +- dev_warn(fmc2->dev, "DMAs not defined in the device tree, polling mode is used\n"); +- return 0; ++ nfc->dma_rx_ch = dma_request_chan(nfc->dev, "rx"); ++ if (IS_ERR(nfc->dma_rx_ch)) { ++ ret = PTR_ERR(nfc->dma_rx_ch); ++ if (ret != -ENODEV && ret != -EPROBE_DEFER) ++ dev_err(nfc->dev, ++ "failed to request rx DMA channel: %d\n", ret); ++ nfc->dma_rx_ch = NULL; ++ goto err_dma; + } + +- ret = sg_alloc_table(&fmc2->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL); ++ nfc->dma_ecc_ch = dma_request_chan(nfc->dev, "ecc"); ++ if (IS_ERR(nfc->dma_ecc_ch)) { ++ ret = PTR_ERR(nfc->dma_ecc_ch); ++ if (ret != -ENODEV && ret != -EPROBE_DEFER) ++ dev_err(nfc->dev, ++ "failed to request ecc DMA channel: %d\n", ret); ++ nfc->dma_ecc_ch = NULL; ++ goto err_dma; ++ } ++ ++ ret = sg_alloc_table(&nfc->dma_ecc_sg, FMC2_MAX_SG, GFP_KERNEL); + if (ret) + return ret; + + /* Allocate a buffer to store ECC status registers */ +- fmc2->ecc_buf = devm_kzalloc(fmc2->dev, FMC2_MAX_ECC_BUF_LEN, +- GFP_KERNEL); +- if (!fmc2->ecc_buf) ++ nfc->ecc_buf = devm_kzalloc(nfc->dev, FMC2_MAX_ECC_BUF_LEN, GFP_KERNEL); ++ if (!nfc->ecc_buf) + return -ENOMEM; + +- ret = sg_alloc_table(&fmc2->dma_data_sg, FMC2_MAX_SG, GFP_KERNEL); ++ ret = sg_alloc_table(&nfc->dma_data_sg, FMC2_MAX_SG, GFP_KERNEL); + if (ret) + return ret; + +- init_completion(&fmc2->dma_data_complete); +- init_completion(&fmc2->dma_ecc_complete); ++ init_completion(&nfc->dma_data_complete); ++ init_completion(&nfc->dma_ecc_complete); + + return 0; ++ ++err_dma: ++ if (ret == -ENODEV) { ++ dev_warn(nfc->dev, ++ "DMAs not defined in the DT, polling mode is used\n"); ++ ret = 0; ++ } ++ ++ return ret; + } + +-/* NAND callbacks setup */ +-static void stm32_fmc2_nand_callbacks_setup(struct nand_chip *chip) ++static void stm32_fmc2_nfc_nand_callbacks_setup(struct nand_chip *chip) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + + /* + * Specific callbacks to read/write a page depending on + * the mode (polling/sequencer) and the algo used (Hamming, BCH). + */ +- if (fmc2->dma_tx_ch && fmc2->dma_rx_ch && fmc2->dma_ecc_ch) { ++ if (nfc->dma_tx_ch && nfc->dma_rx_ch && nfc->dma_ecc_ch) { + /* DMA => use sequencer mode callbacks */ +- chip->ecc.correct = stm32_fmc2_sequencer_correct; +- chip->ecc.write_page = stm32_fmc2_sequencer_write_page; +- chip->ecc.read_page = stm32_fmc2_sequencer_read_page; +- chip->ecc.write_page_raw = stm32_fmc2_sequencer_write_page_raw; +- chip->ecc.read_page_raw = stm32_fmc2_sequencer_read_page_raw; ++ chip->ecc.correct = stm32_fmc2_nfc_seq_correct; ++ chip->ecc.write_page = stm32_fmc2_nfc_seq_write_page; ++ chip->ecc.read_page = stm32_fmc2_nfc_seq_read_page; ++ chip->ecc.write_page_raw = stm32_fmc2_nfc_seq_write_page_raw; ++ chip->ecc.read_page_raw = stm32_fmc2_nfc_seq_read_page_raw; + } else { + /* No DMA => use polling mode callbacks */ +- chip->ecc.hwctl = stm32_fmc2_hwctl; ++ chip->ecc.hwctl = stm32_fmc2_nfc_hwctl; + if (chip->ecc.strength == FMC2_ECC_HAM) { + /* Hamming is used */ +- chip->ecc.calculate = stm32_fmc2_ham_calculate; +- chip->ecc.correct = stm32_fmc2_ham_correct; ++ chip->ecc.calculate = stm32_fmc2_nfc_ham_calculate; ++ chip->ecc.correct = stm32_fmc2_nfc_ham_correct; + chip->ecc.options |= NAND_ECC_GENERIC_ERASED_CHECK; + } else { + /* BCH is used */ +- chip->ecc.calculate = stm32_fmc2_bch_calculate; +- chip->ecc.correct = stm32_fmc2_bch_correct; +- chip->ecc.read_page = stm32_fmc2_read_page; ++ chip->ecc.calculate = stm32_fmc2_nfc_bch_calculate; ++ chip->ecc.correct = stm32_fmc2_nfc_bch_correct; ++ chip->ecc.read_page = stm32_fmc2_nfc_read_page; + } + } + +@@ -1678,9 +1636,8 @@ static void stm32_fmc2_nand_callbacks_setup(struct nand_chip *chip) + chip->ecc.bytes = chip->options & NAND_BUSWIDTH_16 ? 8 : 7; + } + +-/* FMC2 layout */ +-static int stm32_fmc2_nand_ooblayout_ecc(struct mtd_info *mtd, int section, +- struct mtd_oob_region *oobregion) ++static int stm32_fmc2_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) + { + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; +@@ -1694,8 +1651,8 @@ static int stm32_fmc2_nand_ooblayout_ecc(struct mtd_info *mtd, int section, + return 0; + } + +-static int stm32_fmc2_nand_ooblayout_free(struct mtd_info *mtd, int section, +- struct mtd_oob_region *oobregion) ++static int stm32_fmc2_nfc_ooblayout_free(struct mtd_info *mtd, int section, ++ struct mtd_oob_region *oobregion) + { + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; +@@ -1709,13 +1666,12 @@ static int stm32_fmc2_nand_ooblayout_free(struct mtd_info *mtd, int section, + return 0; + } + +-static const struct mtd_ooblayout_ops stm32_fmc2_nand_ooblayout_ops = { +- .ecc = stm32_fmc2_nand_ooblayout_ecc, +- .free = stm32_fmc2_nand_ooblayout_free, ++static const struct mtd_ooblayout_ops stm32_fmc2_nfc_ooblayout_ops = { ++ .ecc = stm32_fmc2_nfc_ooblayout_ecc, ++ .free = stm32_fmc2_nfc_ooblayout_free, + }; + +-/* FMC2 caps */ +-static int stm32_fmc2_calc_ecc_bytes(int step_size, int strength) ++static int stm32_fmc2_nfc_calc_ecc_bytes(int step_size, int strength) + { + /* Hamming */ + if (strength == FMC2_ECC_HAM) +@@ -1729,14 +1685,13 @@ static int stm32_fmc2_calc_ecc_bytes(int step_size, int strength) + return 8; + } + +-NAND_ECC_CAPS_SINGLE(stm32_fmc2_ecc_caps, stm32_fmc2_calc_ecc_bytes, ++NAND_ECC_CAPS_SINGLE(stm32_fmc2_nfc_ecc_caps, stm32_fmc2_nfc_calc_ecc_bytes, + FMC2_ECC_STEP_SIZE, + FMC2_ECC_HAM, FMC2_ECC_BCH4, FMC2_ECC_BCH8); + +-/* FMC2 controller ops */ +-static int stm32_fmc2_attach_chip(struct nand_chip *chip) ++static int stm32_fmc2_nfc_attach_chip(struct nand_chip *chip) + { +- struct stm32_fmc2_nfc *fmc2 = to_stm32_nfc(chip->controller); ++ struct stm32_fmc2_nfc *nfc = to_stm32_nfc(chip->controller); + struct mtd_info *mtd = nand_to_mtd(chip); + int ret; + +@@ -1748,49 +1703,45 @@ static int stm32_fmc2_attach_chip(struct nand_chip *chip) + * ECC sector size = 512 + */ + if (chip->ecc.mode != NAND_ECC_HW) { +- dev_err(fmc2->dev, "nand_ecc_mode is not well defined in the DT\n"); ++ dev_err(nfc->dev, "nand_ecc_mode is not well defined in the DT\n"); + return -EINVAL; + } + +- ret = nand_ecc_choose_conf(chip, &stm32_fmc2_ecc_caps, ++ ret = nand_ecc_choose_conf(chip, &stm32_fmc2_nfc_ecc_caps, + mtd->oobsize - FMC2_BBM_LEN); + if (ret) { +- dev_err(fmc2->dev, "no valid ECC settings set\n"); ++ dev_err(nfc->dev, "no valid ECC settings set\n"); + return ret; + } + + if (mtd->writesize / chip->ecc.size > FMC2_MAX_SG) { +- dev_err(fmc2->dev, "nand page size is not supported\n"); ++ dev_err(nfc->dev, "nand page size is not supported\n"); + return -EINVAL; + } + + if (chip->bbt_options & NAND_BBT_USE_FLASH) + chip->bbt_options |= NAND_BBT_NO_OOB; + +- /* NAND callbacks setup */ +- stm32_fmc2_nand_callbacks_setup(chip); ++ stm32_fmc2_nfc_nand_callbacks_setup(chip); + +- /* Define ECC layout */ +- mtd_set_ooblayout(mtd, &stm32_fmc2_nand_ooblayout_ops); ++ mtd_set_ooblayout(mtd, &stm32_fmc2_nfc_ooblayout_ops); + +- /* Configure bus width to 16-bit */ + if (chip->options & NAND_BUSWIDTH_16) +- stm32_fmc2_set_buswidth_16(fmc2, true); ++ stm32_fmc2_nfc_set_buswidth_16(nfc, true); + + return 0; + } + +-static const struct nand_controller_ops stm32_fmc2_nand_controller_ops = { +- .attach_chip = stm32_fmc2_attach_chip, +- .exec_op = stm32_fmc2_exec_op, +- .setup_data_interface = stm32_fmc2_setup_interface, ++static const struct nand_controller_ops stm32_fmc2_nfc_controller_ops = { ++ .attach_chip = stm32_fmc2_nfc_attach_chip, ++ .exec_op = stm32_fmc2_nfc_exec_op, ++ .setup_data_interface = stm32_fmc2_nfc_setup_interface, + }; + +-/* FMC2 probe */ +-static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2, +- struct device_node *dn) ++static int stm32_fmc2_nfc_parse_child(struct stm32_fmc2_nfc *nfc, ++ struct device_node *dn) + { +- struct stm32_fmc2_nand *nand = &fmc2->nand; ++ struct stm32_fmc2_nand *nand = &nfc->nand; + u32 cs; + int ret, i; + +@@ -1799,29 +1750,29 @@ static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2, + + nand->ncs /= sizeof(u32); + if (!nand->ncs) { +- dev_err(fmc2->dev, "invalid reg property size\n"); ++ dev_err(nfc->dev, "invalid reg property size\n"); + return -EINVAL; + } + + for (i = 0; i < nand->ncs; i++) { + ret = of_property_read_u32_index(dn, "reg", i, &cs); + if (ret) { +- dev_err(fmc2->dev, "could not retrieve reg property: %d\n", ++ dev_err(nfc->dev, "could not retrieve reg property: %d\n", + ret); + return ret; + } + + if (cs > FMC2_MAX_CE) { +- dev_err(fmc2->dev, "invalid reg value: %d\n", cs); ++ dev_err(nfc->dev, "invalid reg value: %d\n", cs); + return -EINVAL; + } + +- if (fmc2->cs_assigned & BIT(cs)) { +- dev_err(fmc2->dev, "cs already assigned: %d\n", cs); ++ if (nfc->cs_assigned & BIT(cs)) { ++ dev_err(nfc->dev, "cs already assigned: %d\n", cs); + return -EINVAL; + } + +- fmc2->cs_assigned |= BIT(cs); ++ nfc->cs_assigned |= BIT(cs); + nand->cs_used[i] = cs; + } + +@@ -1830,25 +1781,25 @@ static int stm32_fmc2_parse_child(struct stm32_fmc2_nfc *fmc2, + return 0; + } + +-static int stm32_fmc2_parse_dt(struct stm32_fmc2_nfc *fmc2) ++static int stm32_fmc2_nfc_parse_dt(struct stm32_fmc2_nfc *nfc) + { +- struct device_node *dn = fmc2->dev->of_node; ++ struct device_node *dn = nfc->dev->of_node; + struct device_node *child; + int nchips = of_get_child_count(dn); + int ret = 0; + + if (!nchips) { +- dev_err(fmc2->dev, "NAND chip not defined\n"); ++ dev_err(nfc->dev, "NAND chip not defined\n"); + return -EINVAL; + } + + if (nchips > 1) { +- dev_err(fmc2->dev, "too many NAND chips defined\n"); ++ dev_err(nfc->dev, "too many NAND chips defined\n"); + return -EINVAL; + } + + for_each_child_of_node(dn, child) { +- ret = stm32_fmc2_parse_child(fmc2, child); ++ ret = stm32_fmc2_nfc_parse_child(nfc, child); + if (ret < 0) { + of_node_put(child); + return ret; +@@ -1858,107 +1809,145 @@ static int stm32_fmc2_parse_dt(struct stm32_fmc2_nfc *fmc2) + return ret; + } + +-static int stm32_fmc2_probe(struct platform_device *pdev) ++static int stm32_fmc2_nfc_set_cdev(struct stm32_fmc2_nfc *nfc) ++{ ++ struct device *dev = nfc->dev; ++ bool ebi_found = false; ++ ++ if (dev->parent && of_device_is_compatible(dev->parent->of_node, ++ "st,stm32mp1-fmc2-ebi")) ++ ebi_found = true; ++ ++ if (of_device_is_compatible(dev->of_node, "st,stm32mp1-fmc2-nfc")) { ++ if (ebi_found) { ++ nfc->cdev = dev->parent; ++ ++ return 0; ++ } ++ ++ return -EINVAL; ++ } ++ ++ if (ebi_found) ++ return -EINVAL; ++ ++ nfc->cdev = dev; ++ ++ return 0; ++} ++ ++static int stm32_fmc2_nfc_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; + struct reset_control *rstc; +- struct stm32_fmc2_nfc *fmc2; ++ struct stm32_fmc2_nfc *nfc; + struct stm32_fmc2_nand *nand; + struct resource *res; + struct mtd_info *mtd; + struct nand_chip *chip; ++ struct resource cres; + int chip_cs, mem_region, ret, irq; ++ int start_region = 0; + +- fmc2 = devm_kzalloc(dev, sizeof(*fmc2), GFP_KERNEL); +- if (!fmc2) ++ nfc = devm_kzalloc(dev, sizeof(*nfc), GFP_KERNEL); ++ if (!nfc) + return -ENOMEM; + +- fmc2->dev = dev; +- nand_controller_init(&fmc2->base); +- fmc2->base.ops = &stm32_fmc2_nand_controller_ops; ++ nfc->dev = dev; ++ nand_controller_init(&nfc->base); ++ nfc->base.ops = &stm32_fmc2_nfc_controller_ops; ++ ++ ret = stm32_fmc2_nfc_set_cdev(nfc); ++ if (ret) ++ return ret; ++ ++ ret = stm32_fmc2_nfc_parse_dt(nfc); ++ if (ret) ++ return ret; + +- ret = stm32_fmc2_parse_dt(fmc2); ++ ret = of_address_to_resource(nfc->cdev->of_node, 0, &cres); + if (ret) + return ret; + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- fmc2->io_base = devm_ioremap_resource(dev, res); +- if (IS_ERR(fmc2->io_base)) +- return PTR_ERR(fmc2->io_base); ++ nfc->io_phys_addr = cres.start; + +- fmc2->io_phys_addr = res->start; ++ nfc->regmap = device_node_to_regmap(nfc->cdev->of_node); ++ if (IS_ERR(nfc->regmap)) ++ return PTR_ERR(nfc->regmap); + +- for (chip_cs = 0, mem_region = 1; chip_cs < FMC2_MAX_CE; ++ if (nfc->dev == nfc->cdev) ++ start_region = 1; ++ ++ for (chip_cs = 0, mem_region = start_region; chip_cs < FMC2_MAX_CE; + chip_cs++, mem_region += 3) { +- if (!(fmc2->cs_assigned & BIT(chip_cs))) ++ if (!(nfc->cs_assigned & BIT(chip_cs))) + continue; + + res = platform_get_resource(pdev, IORESOURCE_MEM, mem_region); +- fmc2->data_base[chip_cs] = devm_ioremap_resource(dev, res); +- if (IS_ERR(fmc2->data_base[chip_cs])) +- return PTR_ERR(fmc2->data_base[chip_cs]); ++ nfc->data_base[chip_cs] = devm_ioremap_resource(dev, res); ++ if (IS_ERR(nfc->data_base[chip_cs])) ++ return PTR_ERR(nfc->data_base[chip_cs]); + +- fmc2->data_phys_addr[chip_cs] = res->start; ++ nfc->data_phys_addr[chip_cs] = res->start; + + res = platform_get_resource(pdev, IORESOURCE_MEM, + mem_region + 1); +- fmc2->cmd_base[chip_cs] = devm_ioremap_resource(dev, res); +- if (IS_ERR(fmc2->cmd_base[chip_cs])) +- return PTR_ERR(fmc2->cmd_base[chip_cs]); ++ nfc->cmd_base[chip_cs] = devm_ioremap_resource(dev, res); ++ if (IS_ERR(nfc->cmd_base[chip_cs])) ++ return PTR_ERR(nfc->cmd_base[chip_cs]); + + res = platform_get_resource(pdev, IORESOURCE_MEM, + mem_region + 2); +- fmc2->addr_base[chip_cs] = devm_ioremap_resource(dev, res); +- if (IS_ERR(fmc2->addr_base[chip_cs])) +- return PTR_ERR(fmc2->addr_base[chip_cs]); ++ nfc->addr_base[chip_cs] = devm_ioremap_resource(dev, res); ++ if (IS_ERR(nfc->addr_base[chip_cs])) ++ return PTR_ERR(nfc->addr_base[chip_cs]); + } + + irq = platform_get_irq(pdev, 0); +- if (irq < 0) { +- if (irq != -EPROBE_DEFER) +- dev_err(dev, "IRQ error missing or invalid\n"); ++ if (irq < 0) + return irq; +- } + +- ret = devm_request_irq(dev, irq, stm32_fmc2_irq, 0, +- dev_name(dev), fmc2); ++ ret = devm_request_irq(dev, irq, stm32_fmc2_nfc_irq, 0, ++ dev_name(dev), nfc); + if (ret) { + dev_err(dev, "failed to request irq\n"); + return ret; + } + +- init_completion(&fmc2->complete); ++ init_completion(&nfc->complete); + +- fmc2->clk = devm_clk_get(dev, NULL); +- if (IS_ERR(fmc2->clk)) +- return PTR_ERR(fmc2->clk); ++ nfc->clk = devm_clk_get(nfc->cdev, NULL); ++ if (IS_ERR(nfc->clk)) ++ return PTR_ERR(nfc->clk); + +- ret = clk_prepare_enable(fmc2->clk); ++ ret = clk_prepare_enable(nfc->clk); + if (ret) { + dev_err(dev, "can not enable the clock\n"); + return ret; + } + + rstc = devm_reset_control_get(dev, NULL); +- if (!IS_ERR(rstc)) { ++ if (IS_ERR(rstc)) { ++ ret = PTR_ERR(rstc); ++ if (ret == -EPROBE_DEFER) ++ goto err_clk_disable; ++ } else { + reset_control_assert(rstc); + reset_control_deassert(rstc); + } + +- /* DMA setup */ +- ret = stm32_fmc2_dma_setup(fmc2); ++ ret = stm32_fmc2_nfc_dma_setup(nfc); + if (ret) +- return ret; ++ goto err_release_dma; + +- /* FMC2 init routine */ +- stm32_fmc2_init(fmc2); ++ stm32_fmc2_nfc_init(nfc); + +- nand = &fmc2->nand; ++ nand = &nfc->nand; + chip = &nand->chip; + mtd = nand_to_mtd(chip); + mtd->dev.parent = dev; + +- chip->controller = &fmc2->base; ++ chip->controller = &nfc->base; + chip->options |= NAND_BUSWIDTH_AUTO | NAND_NO_SUBPAGE_WRITE | + NAND_USE_BOUNCE_BUFFER; + +@@ -1970,86 +1959,87 @@ static int stm32_fmc2_probe(struct platform_device *pdev) + /* Scan to find existence of the device */ + ret = nand_scan(chip, nand->ncs); + if (ret) +- goto err_scan; ++ goto err_release_dma; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) +- goto err_device_register; ++ goto err_nand_cleanup; + +- platform_set_drvdata(pdev, fmc2); ++ platform_set_drvdata(pdev, nfc); + + return 0; + +-err_device_register: ++err_nand_cleanup: + nand_cleanup(chip); + +-err_scan: +- if (fmc2->dma_ecc_ch) +- dma_release_channel(fmc2->dma_ecc_ch); +- if (fmc2->dma_tx_ch) +- dma_release_channel(fmc2->dma_tx_ch); +- if (fmc2->dma_rx_ch) +- dma_release_channel(fmc2->dma_rx_ch); ++err_release_dma: ++ if (nfc->dma_ecc_ch) ++ dma_release_channel(nfc->dma_ecc_ch); ++ if (nfc->dma_tx_ch) ++ dma_release_channel(nfc->dma_tx_ch); ++ if (nfc->dma_rx_ch) ++ dma_release_channel(nfc->dma_rx_ch); + +- sg_free_table(&fmc2->dma_data_sg); +- sg_free_table(&fmc2->dma_ecc_sg); ++ sg_free_table(&nfc->dma_data_sg); ++ sg_free_table(&nfc->dma_ecc_sg); + +- clk_disable_unprepare(fmc2->clk); ++err_clk_disable: ++ clk_disable_unprepare(nfc->clk); + + return ret; + } + +-static int stm32_fmc2_remove(struct platform_device *pdev) ++static int stm32_fmc2_nfc_remove(struct platform_device *pdev) + { +- struct stm32_fmc2_nfc *fmc2 = platform_get_drvdata(pdev); +- struct stm32_fmc2_nand *nand = &fmc2->nand; ++ struct stm32_fmc2_nfc *nfc = platform_get_drvdata(pdev); ++ struct stm32_fmc2_nand *nand = &nfc->nand; + + nand_release(&nand->chip); + +- if (fmc2->dma_ecc_ch) +- dma_release_channel(fmc2->dma_ecc_ch); +- if (fmc2->dma_tx_ch) +- dma_release_channel(fmc2->dma_tx_ch); +- if (fmc2->dma_rx_ch) +- dma_release_channel(fmc2->dma_rx_ch); ++ if (nfc->dma_ecc_ch) ++ dma_release_channel(nfc->dma_ecc_ch); ++ if (nfc->dma_tx_ch) ++ dma_release_channel(nfc->dma_tx_ch); ++ if (nfc->dma_rx_ch) ++ dma_release_channel(nfc->dma_rx_ch); + +- sg_free_table(&fmc2->dma_data_sg); +- sg_free_table(&fmc2->dma_ecc_sg); ++ sg_free_table(&nfc->dma_data_sg); ++ sg_free_table(&nfc->dma_ecc_sg); + +- clk_disable_unprepare(fmc2->clk); ++ clk_disable_unprepare(nfc->clk); + + return 0; + } + +-static int __maybe_unused stm32_fmc2_suspend(struct device *dev) ++static int __maybe_unused stm32_fmc2_nfc_suspend(struct device *dev) + { +- struct stm32_fmc2_nfc *fmc2 = dev_get_drvdata(dev); ++ struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev); + +- clk_disable_unprepare(fmc2->clk); ++ clk_disable_unprepare(nfc->clk); + + pinctrl_pm_select_sleep_state(dev); + + return 0; + } + +-static int __maybe_unused stm32_fmc2_resume(struct device *dev) ++static int __maybe_unused stm32_fmc2_nfc_resume(struct device *dev) + { +- struct stm32_fmc2_nfc *fmc2 = dev_get_drvdata(dev); +- struct stm32_fmc2_nand *nand = &fmc2->nand; ++ struct stm32_fmc2_nfc *nfc = dev_get_drvdata(dev); ++ struct stm32_fmc2_nand *nand = &nfc->nand; + int chip_cs, ret; + + pinctrl_pm_select_default_state(dev); + +- ret = clk_prepare_enable(fmc2->clk); ++ ret = clk_prepare_enable(nfc->clk); + if (ret) { + dev_err(dev, "can not enable the clock\n"); + return ret; + } + +- stm32_fmc2_init(fmc2); ++ stm32_fmc2_nfc_init(nfc); + + for (chip_cs = 0; chip_cs < FMC2_MAX_CE; chip_cs++) { +- if (!(fmc2->cs_assigned & BIT(chip_cs))) ++ if (!(nfc->cs_assigned & BIT(chip_cs))) + continue; + + nand_reset(&nand->chip, chip_cs); +@@ -2058,27 +2048,28 @@ static int __maybe_unused stm32_fmc2_resume(struct device *dev) + return 0; + } + +-static SIMPLE_DEV_PM_OPS(stm32_fmc2_pm_ops, stm32_fmc2_suspend, +- stm32_fmc2_resume); ++static SIMPLE_DEV_PM_OPS(stm32_fmc2_nfc_pm_ops, stm32_fmc2_nfc_suspend, ++ stm32_fmc2_nfc_resume); + +-static const struct of_device_id stm32_fmc2_match[] = { ++static const struct of_device_id stm32_fmc2_nfc_match[] = { + {.compatible = "st,stm32mp15-fmc2"}, ++ {.compatible = "st,stm32mp1-fmc2-nfc"}, + {} + }; +-MODULE_DEVICE_TABLE(of, stm32_fmc2_match); ++MODULE_DEVICE_TABLE(of, stm32_fmc2_nfc_match); + +-static struct platform_driver stm32_fmc2_driver = { +- .probe = stm32_fmc2_probe, +- .remove = stm32_fmc2_remove, ++static struct platform_driver stm32_fmc2_nfc_driver = { ++ .probe = stm32_fmc2_nfc_probe, ++ .remove = stm32_fmc2_nfc_remove, + .driver = { +- .name = "stm32_fmc2_nand", +- .of_match_table = stm32_fmc2_match, +- .pm = &stm32_fmc2_pm_ops, ++ .name = "stm32_fmc2_nfc", ++ .of_match_table = stm32_fmc2_nfc_match, ++ .pm = &stm32_fmc2_nfc_pm_ops, + }, + }; +-module_platform_driver(stm32_fmc2_driver); ++module_platform_driver(stm32_fmc2_nfc_driver); + +-MODULE_ALIAS("platform:stm32_fmc2_nand"); ++MODULE_ALIAS("platform:stm32_fmc2_nfc"); + MODULE_AUTHOR("Christophe Kerello "); +-MODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 nand driver"); ++MODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 NFC driver"); + MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h +index b7ba8810a3b53..eb10b8194073e 100644 +--- a/include/linux/mmc/core.h ++++ b/include/linux/mmc/core.h +@@ -173,6 +173,7 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq); + int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, + int retries); + ++void mmc_hw_unstuck(struct mmc_host *host); + int mmc_hw_reset(struct mmc_host *host); + int mmc_sw_reset(struct mmc_host *host); + void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card); +diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h +index 4c5eb3aa8e723..feac3431be49a 100644 +--- a/include/linux/mmc/host.h ++++ b/include/linux/mmc/host.h +@@ -163,6 +163,12 @@ struct mmc_host_ops { + void (*hw_reset)(struct mmc_host *host); + void (*card_event)(struct mmc_host *host); + ++ /* ++ * Optional callback, if your host is in deadlock after a command and ++ * must done specific action before sent new command. ++ */ ++ void (*hw_unstuck)(struct mmc_host *host); ++ + /* + * Optional callback to support controllers with HW issues for multiple + * I/O. Returns the number of supported blocks for the request. +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0015-ARM-stm32mp1-r2-NET-TTY.patch similarity index 75% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0015-ARM-stm32mp1-r2-NET-TTY.patch index b60eb20..60b9f51 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0015-ARM-stm32mp1-r1-NET-TTY.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0015-ARM-stm32mp1-r2-NET-TTY.patch @@ -1,22 +1,27 @@ -From d367a94623ae3c7e9707fe10e25ab06a8b0ea00b Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:46:34 +0200 -Subject: [PATCH 15/23] ARM-stm32mp1-r1-NET-TTY +From e7d39044a73d9ca89178dad8abd1477c31e4a163 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:48 +0200 +Subject: [PATCH 15/22] ARM-stm32mp1-r2-rc8-NET-TTY --- - .../net/ethernet/stmicro/stmmac/dwmac-stm32.c | 98 +- - .../net/ethernet/stmicro/stmmac/dwmac4_lib.c | 2 +- - .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 +- - .../net/ethernet/stmicro/stmmac/stmmac_main.c | 29 +- - .../ethernet/stmicro/stmmac/stmmac_platform.c | 4 +- - drivers/net/phy/realtek.c | 5 + - .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 + - drivers/tty/serial/stm32-usart.c | 996 +++++++++++------- - drivers/tty/serial/stm32-usart.h | 20 +- - 9 files changed, 728 insertions(+), 434 deletions(-) + .../net/ethernet/stmicro/stmmac/dwmac-stm32.c | 98 +- + .../net/ethernet/stmicro/stmmac/dwmac4_lib.c | 2 +- + .../ethernet/stmicro/stmmac/stmmac_ethtool.c | 2 +- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 29 +- + .../ethernet/stmicro/stmmac/stmmac_platform.c | 2 +- + drivers/net/phy/realtek.c | 5 + + .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 + + drivers/tty/serial/Kconfig | 1 + + drivers/tty/serial/serial_core.c | 10 + + drivers/tty/serial/serial_mctrl_gpio.c | 38 + + drivers/tty/serial/serial_mctrl_gpio.h | 18 + + drivers/tty/serial/stm32-usart.c | 1238 +++++++++++------ + drivers/tty/serial/stm32-usart.h | 30 +- + include/uapi/linux/serial.h | 2 + + 14 files changed, 1013 insertions(+), 468 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -index 4ef041bdf..f67842bfc 100644 +index 4ef041bdf6a1c..f67842bfcd5d3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -95,7 +95,6 @@ struct stm32_dwmac { @@ -209,7 +214,7 @@ index 4ef041bdf..f67842bfc 100644 clk_disable_unprepare(dwmac->clk_eth_ck); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c -index f2a29a90e..2df6705cd 100644 +index f2a29a90e0854..2df6705cde6c8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c @@ -19,7 +19,7 @@ int dwmac4_dma_reset(void __iomem *ioaddr) @@ -222,7 +227,7 @@ index f2a29a90e..2df6705cd 100644 if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) break; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c -index 1a768837c..43532e207 100644 +index 1a768837ca728..43532e20749e8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -706,7 +706,7 @@ static u32 stmmac_riwt2usec(u32 riwt, struct stmmac_priv *priv) @@ -235,10 +240,10 @@ index 1a768837c..43532e207 100644 static int stmmac_get_coalesce(struct net_device *dev, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -index 89a6ae2b1..413b6f234 100644 +index 982be75fde833..3c99b960f660d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -4846,6 +4846,7 @@ int stmmac_resume(struct device *dev) +@@ -4842,6 +4842,7 @@ int stmmac_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct stmmac_priv *priv = netdev_priv(ndev); @@ -246,7 +251,7 @@ index 89a6ae2b1..413b6f234 100644 if (!netif_running(ndev)) return 0; -@@ -4879,7 +4880,25 @@ int stmmac_resume(struct device *dev) +@@ -4875,7 +4876,25 @@ int stmmac_resume(struct device *dev) stmmac_reset_queues_param(priv); @@ -273,7 +278,7 @@ index 89a6ae2b1..413b6f234 100644 stmmac_hw_setup(ndev, false); stmmac_init_coalesce(priv); -@@ -4900,6 +4919,14 @@ int stmmac_resume(struct device *dev) +@@ -4896,6 +4915,14 @@ int stmmac_resume(struct device *dev) phylink_mac_change(priv->phylink, true); return 0; @@ -289,7 +294,7 @@ index 89a6ae2b1..413b6f234 100644 EXPORT_SYMBOL_GPL(stmmac_resume); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -index 5150551c2..a6225534a 100644 +index 508325cc105d5..e5d1ce84a3554 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -588,7 +588,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) @@ -301,17 +306,8 @@ index 5150551c2..a6225534a 100644 } else { plat->clk_ptp_rate = clk_get_rate(plat->clk_ptp_ref); dev_dbg(&pdev->dev, "PTP rate %d\n", plat->clk_ptp_rate); -@@ -670,7 +670,7 @@ int stmmac_get_platform_resources(struct platform_device *pdev, - stmmac_res->wol_irq = stmmac_res->irq; - } - -- stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); -+ stmmac_res->lpi_irq = platform_get_irq_byname_optional(pdev, "eth_lpi"); - if (stmmac_res->lpi_irq == -EPROBE_DEFER) - return -EPROBE_DEFER; - diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c -index c76df51dd..45a112016 100644 +index 879ca37c85081..fe26438500fcf 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -175,6 +175,11 @@ static int rtl8211f_config_init(struct phy_device *phydev) @@ -327,7 +323,7 @@ index c76df51dd..45a112016 100644 * rgmii-rxid. The RX-delay can be enabled by the external RXDLY pin. */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c -index fc12598b2..041a215aa 100644 +index fc12598b2dd3f..041a215aa13ed 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -1128,7 +1128,10 @@ static int brcmf_ops_sdio_suspend(struct device *dev) @@ -351,8 +347,124 @@ index fc12598b2..041a215aa 100644 brcmf_sdiod_freezer_off(sdiodev); return 0; } +diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig +index 67a9eb3f94cec..af3ebf79674fd 100644 +--- a/drivers/tty/serial/Kconfig ++++ b/drivers/tty/serial/Kconfig +@@ -1472,6 +1472,7 @@ config SERIAL_STM32 + tristate "STMicroelectronics STM32 serial port support" + select SERIAL_CORE + depends on ARCH_STM32 || COMPILE_TEST ++ select SERIAL_MCTRL_GPIO if GPIOLIB + help + This driver is for the on-chip Serial Controller on + STMicroelectronics STM32 MCUs. +diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +index 7c27827857363..ce7944fa3576d 100644 +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -3102,6 +3102,16 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) + u32 rs485_delay[2]; + int ret; + ++ ret = device_property_read_u32_array(dev, "rs485-rts-delay-ns", ++ rs485_delay, 2); ++ if (!ret) { ++ rs485conf->delay_rts_before_send_ns = rs485_delay[0]; ++ rs485conf->delay_rts_after_send_ns = rs485_delay[1]; ++ } else { ++ rs485conf->delay_rts_before_send_ns = 0; ++ rs485conf->delay_rts_after_send_ns = 0; ++ } ++ + ret = device_property_read_u32_array(dev, "rs485-rts-delay", + rs485_delay, 2); + if (!ret) { +diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c +index fb4781292d409..1fc2f704769e7 100644 +--- a/drivers/tty/serial/serial_mctrl_gpio.c ++++ b/drivers/tty/serial/serial_mctrl_gpio.c +@@ -299,4 +299,42 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) + } + EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms); + ++void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) ++{ ++ enum mctrl_gpio_idx i; ++ ++ if (!gpios) ++ return; ++ ++ if (!gpios->mctrl_on) ++ return; ++ ++ for (i = 0; i < UART_GPIO_MAX; ++i) { ++ if (!gpios->irq[i]) ++ continue; ++ ++ enable_irq_wake(gpios->irq[i]); ++ } ++} ++EXPORT_SYMBOL_GPL(mctrl_gpio_enable_irq_wake); ++ ++void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) ++{ ++ enum mctrl_gpio_idx i; ++ ++ if (!gpios) ++ return; ++ ++ if (!gpios->mctrl_on) ++ return; ++ ++ for (i = 0; i < UART_GPIO_MAX; ++i) { ++ if (!gpios->irq[i]) ++ continue; ++ ++ disable_irq_wake(gpios->irq[i]); ++ } ++} ++EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake); ++ + MODULE_LICENSE("GPL"); +diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h +index 1b2ff503b2c24..f2e4760ac2de1 100644 +--- a/drivers/tty/serial/serial_mctrl_gpio.h ++++ b/drivers/tty/serial/serial_mctrl_gpio.h +@@ -91,6 +91,16 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); + */ + void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios); + ++/* ++ * Enable gpio wakeup interrupts to enable wake up source. ++ */ ++void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios); ++ ++/* ++ * Disable gpio wakeup interrupts to enable wake up source. ++ */ ++void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios); ++ + #else /* GPIOLIB */ + + static inline +@@ -142,6 +152,14 @@ static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) + { + } + ++static inline void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios) ++{ ++} ++ ++static inline void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios) ++{ ++} ++ + #endif /* GPIOLIB */ + + #endif diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c -index 2f72514d6..6592e5cdb 100644 +index 2f72514d63edd..231fbb3684d8a 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -4,6 +4,7 @@ @@ -363,14 +475,18 @@ index 2f72514d6..6592e5cdb 100644 * * Inspired by st-asc.c from STMicroelectronics (c) */ -@@ -37,15 +38,15 @@ +@@ -35,17 +36,19 @@ + #include + #include ++#include "serial_mctrl_gpio.h" #include "stm32-usart.h" -static void stm32_stop_tx(struct uart_port *port); -static void stm32_transmit_chars(struct uart_port *port); +static void stm32_usart_stop_tx(struct uart_port *port); +static void stm32_usart_transmit_chars(struct uart_port *port); ++static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port); static inline struct stm32_port *to_stm32_port(struct uart_port *port) { @@ -382,7 +498,7 @@ index 2f72514d6..6592e5cdb 100644 { u32 val; -@@ -54,7 +55,7 @@ static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) +@@ -54,7 +57,7 @@ static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } @@ -391,18 +507,92 @@ index 2f72514d6..6592e5cdb 100644 { u32 val; -@@ -63,8 +64,8 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) +@@ -63,43 +66,70 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } -static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, - u32 delay_DDE, u32 baud) -+static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, -+ u32 delay_DDE, u32 baud) ++static u32 stm32_usart_config_delay_rs485(u32 *cr1, u32 delay, u32 baud, ++ bool over8, u32 rs485_deat_dedt_max, ++ struct serial_rs485 *rs485conf) { - u32 rs485_deat_dedt; +- u32 rs485_deat_dedt; ++ u64 tmp; ++ ++ /* ++ * Compute (de)assertion time by using the delay (in ns), the baud rate ++ * (in bits/s) and the oversampling (in 1/8 or 1/16 bit) ++ */ ++ tmp = (u64)delay * (u64)baud * 8ULL; ++ ++ /* Handle oversampling 16 */ ++ if (!over8) ++ tmp = tmp * 2ULL; ++ ++ tmp = DIV_ROUND_CLOSEST_ULL(tmp, NSEC_PER_SEC); ++ ++ /* Set delay to max value if result is higher than max value */ ++ tmp = tmp > rs485_deat_dedt_max ? rs485_deat_dedt_max : tmp; ++ ++ return tmp; ++} ++ ++static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 baud, ++ struct serial_rs485 *rs485conf) ++{ ++ u32 delay_ADE, delay_DDE, rs485_deat_dedt; u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT); -@@ -98,8 +99,8 @@ static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, + bool over8; ++ u32 tmp; ++ ++ /* ++ * Assertion and deassertion delays (in ns) are computed by the ++ * selection of rs485-rts-delay-ns (in ns) or rs485-rts-delay (in ms) ++ * provided by device tree ++ */ ++ if (rs485conf->delay_rts_before_send_ns != 0 || ++ rs485conf->delay_rts_after_send_ns != 0) { ++ delay_ADE = rs485conf->delay_rts_before_send_ns; ++ delay_DDE = rs485conf->delay_rts_after_send_ns; ++ } else { ++ delay_ADE = rs485conf->delay_rts_before_send * NSEC_PER_MSEC; ++ delay_DDE = rs485conf->delay_rts_after_send * NSEC_PER_MSEC; ++ } + + *cr3 |= USART_CR3_DEM; + over8 = *cr1 & USART_CR1_OVER8; + +- if (over8) +- rs485_deat_dedt = delay_ADE * baud * 8; +- else +- rs485_deat_dedt = delay_ADE * baud * 16; +- +- rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); +- rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? +- rs485_deat_dedt_max : rs485_deat_dedt; +- rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEAT_SHIFT) & +- USART_CR1_DEAT_MASK; ++ /* Assertion time */ ++ tmp = stm32_usart_config_delay_rs485(cr1, delay_ADE, baud, over8, ++ rs485_deat_dedt_max, rs485conf); ++ rs485_deat_dedt = (tmp << USART_CR1_DEAT_SHIFT) & USART_CR1_DEAT_MASK; + *cr1 |= rs485_deat_dedt; + +- if (over8) +- rs485_deat_dedt = delay_DDE * baud * 8; +- else +- rs485_deat_dedt = delay_DDE * baud * 16; +- +- rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); +- rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? +- rs485_deat_dedt_max : rs485_deat_dedt; +- rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEDT_SHIFT) & +- USART_CR1_DEDT_MASK; ++ /* Deassertion time */ ++ tmp = stm32_usart_config_delay_rs485(cr1, delay_DDE, baud, over8, ++ rs485_deat_dedt_max, rs485conf); ++ rs485_deat_dedt = (tmp << USART_CR1_DEDT_SHIFT) & USART_CR1_DEDT_MASK; *cr1 |= rs485_deat_dedt; } @@ -413,7 +603,7 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -107,7 +108,7 @@ static int stm32_config_rs485(struct uart_port *port, +@@ -107,7 +137,7 @@ static int stm32_config_rs485(struct uart_port *port, u32 usartdiv, baud, cr1, cr3; bool over8; @@ -422,21 +612,18 @@ index 2f72514d6..6592e5cdb 100644 port->rs485 = *rs485conf; -@@ -125,9 +126,10 @@ static int stm32_config_rs485(struct uart_port *port, +@@ -125,9 +155,7 @@ static int stm32_config_rs485(struct uart_port *port, << USART_BRR_04_R_SHIFT; baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); - stm32_config_reg_rs485(&cr1, &cr3, - rs485conf->delay_rts_before_send, - rs485conf->delay_rts_after_send, baud); -+ stm32_usart_config_reg_rs485(&cr1, &cr3, -+ rs485conf->delay_rts_before_send, -+ rs485conf->delay_rts_after_send, -+ baud); ++ stm32_usart_config_reg_rs485(&cr1, &cr3, baud, rs485conf); if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; -@@ -140,18 +142,19 @@ static int stm32_config_rs485(struct uart_port *port, +@@ -140,18 +168,19 @@ static int stm32_config_rs485(struct uart_port *port, writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr1, port->membase + ofs->cr1); } else { @@ -462,7 +649,7 @@ index 2f72514d6..6592e5cdb 100644 { struct serial_rs485 *rs485conf = &port->rs485; -@@ -167,64 +170,66 @@ static int stm32_init_rs485(struct uart_port *port, +@@ -167,64 +196,67 @@ static int stm32_init_rs485(struct uart_port *port, return 0; } @@ -545,12 +732,13 @@ index 2f72514d6..6592e5cdb 100644 } -static void stm32_receive_chars(struct uart_port *port, bool threaded) -+static void stm32_usart_receive_chars_pio(struct uart_port *port) ++static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; ++ unsigned int size = 0; u32 sr; char flag; @@ -562,19 +750,25 @@ index 2f72514d6..6592e5cdb 100644 sr |= USART_SR_DUMMY_RX; flag = TTY_NORMAL; -@@ -243,7 +248,7 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) +@@ -243,8 +275,9 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) writel_relaxed(sr & USART_SR_ERR_MASK, port->membase + ofs->icr); - c = stm32_get_char(port, &sr, &stm32_port->last_res); + c = stm32_usart_get_char_pio(port); port->icount.rx++; ++ size++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { -@@ -277,26 +282,116 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) - continue; + port->icount.overrun++; +@@ -278,25 +311,115 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) uart_insert_char(port, sr, USART_SR_ORE, c, flag); } + +- spin_unlock(&port->lock); +- tty_flip_buffer_push(tport); +- spin_lock(&port->lock); ++ return size; +} + +static void stm32_usart_push_buffer_dma(struct uart_port *port, @@ -588,15 +782,17 @@ index 2f72514d6..6592e5cdb 100644 + 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; ++ if (dma_count != dma_size) ++ port->icount.buf_overrun++; + stm32_port->last_res -= dma_count; + if (stm32_port->last_res == 0) + stm32_port->last_res = RX_BUF_L; +} + -+static void stm32_usart_receive_chars_dma(struct uart_port *port) ++static unsigned int stm32_usart_receive_chars_dma(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); -+ unsigned int dma_size; ++ unsigned int dma_size, size = 0; + + /* + * DMA buffer is configured in cyclic mode and handles the rollback of @@ -606,33 +802,33 @@ index 2f72514d6..6592e5cdb 100644 + /* Conditional first part: from last_res to end of DMA buffer */ + dma_size = stm32_port->last_res; + stm32_usart_push_buffer_dma(port, dma_size); ++ size = dma_size; + } + + dma_size = stm32_port->last_res - stm32_port->state.residue; + stm32_usart_push_buffer_dma(port, dma_size); ++ size += dma_size; ++ ++ return size; +} + -+static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) ++static void stm32_usart_receive_chars(struct uart_port *port, ++ bool force_dma_flush) +{ + 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; ++ unsigned int size; + -+ if (threaded) -+ spin_lock_irqsave(&port->lock, flags); -+ else -+ spin_lock(&port->lock); -+ -+ if (stm32_usart_rx_dma_enabled(port)) { ++ if (stm32_usart_rx_dma_enabled(port) || force_dma_flush) { + stm32_port->status = + dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &stm32_port->state); + if (stm32_port->status == DMA_IN_PROGRESS) { + /* Empty DMA buffer */ -+ stm32_usart_receive_chars_dma(port); ++ size = stm32_usart_receive_chars_dma(port); + sr = readl_relaxed(port->membase + ofs->isr); + if (sr & USART_SR_ERR_MASK) { + /* Disable DMA request line */ @@ -640,7 +836,7 @@ index 2f72514d6..6592e5cdb 100644 + USART_CR3_DMAR); + + /* Switch to PIO mode to handle the errors */ -+ stm32_usart_receive_chars_pio(port); ++ size += stm32_usart_receive_chars_pio(port); + + /* Switch back to DMA mode */ + stm32_usart_set_bits(port, ofs->cr3, @@ -653,20 +849,14 @@ index 2f72514d6..6592e5cdb 100644 + /* Fall back to interrupt mode */ + dev_dbg(port->dev, + "DMA error, fallback to irq mode\n"); -+ stm32_usart_receive_chars_pio(port); ++ size = stm32_usart_receive_chars_pio(port); + } + } else { -+ stm32_usart_receive_chars_pio(port); ++ size = stm32_usart_receive_chars_pio(port); + } + -+ if (threaded) -+ spin_unlock_irqrestore(&port->lock, flags); -+ else -+ spin_unlock(&port->lock); - -- spin_unlock(&port->lock); - tty_flip_buffer_push(tport); -- spin_lock(&port->lock); ++ if (size) ++ tty_flip_buffer_push(tport); } -static void stm32_tx_dma_complete(void *arg) @@ -694,11 +884,13 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -306,30 +401,37 @@ static void stm32_tx_interrupt_enable(struct uart_port *port) +@@ -305,31 +428,41 @@ static void stm32_tx_interrupt_enable(struct uart_port *port) + * Enables TX FIFO threashold irq when FIFO is enabled, * or TX empty irq when FIFO is disabled */ - if (stm32_port->fifoen) +- if (stm32_port->fifoen) - stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); ++ if (stm32_port->fifoen && stm32_port->txftcfg >= 0) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); else - stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); @@ -708,8 +900,11 @@ index 2f72514d6..6592e5cdb 100644 +static void stm32_usart_rx_dma_complete(void *arg) +{ + struct uart_port *port = arg; ++ unsigned long flags; + -+ stm32_usart_receive_chars(port, true); ++ spin_lock_irqsave(&port->lock, flags); ++ stm32_usart_receive_chars(port, false); ++ spin_unlock_irqrestore(&port->lock, flags); } -static void stm32_tx_interrupt_disable(struct uart_port *port) @@ -718,8 +913,9 @@ index 2f72514d6..6592e5cdb 100644 struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - if (stm32_port->fifoen) +- if (stm32_port->fifoen) - stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); ++ if (stm32_port->fifoen && stm32_port->txftcfg >= 0) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); else - stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); @@ -739,7 +935,7 @@ index 2f72514d6..6592e5cdb 100644 stm32_port->tx_dma_busy = false; } -@@ -344,19 +446,19 @@ static void stm32_transmit_chars_pio(struct uart_port *port) +@@ -344,19 +477,19 @@ static void stm32_transmit_chars_pio(struct uart_port *port) /* rely on TXE irq (mask or unmask) for sending remaining data */ if (uart_circ_empty(xmit)) @@ -763,7 +959,7 @@ index 2f72514d6..6592e5cdb 100644 if (stm32port->tx_dma_busy) return; -@@ -389,28 +491,36 @@ static void stm32_transmit_chars_dma(struct uart_port *port) +@@ -389,28 +522,36 @@ static void stm32_transmit_chars_dma(struct uart_port *port) DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); @@ -808,7 +1004,7 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -418,211 +528,276 @@ static void stm32_transmit_chars(struct uart_port *port) +@@ -418,211 +559,330 @@ static void stm32_transmit_chars(struct uart_port *port) if (port->x_char) { if (stm32_port->tx_dma_busy) @@ -887,9 +1083,13 @@ index 2f72514d6..6592e5cdb 100644 + * DMA request line has been masked by HW and rx data are stacking in + * FIFO. + */ -+ if (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || -+ ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port))) ++ if (!stm32_port->throttled && ++ (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || ++ ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port)))) { ++ spin_lock(&port->lock); + stm32_usart_receive_chars(port, false); ++ spin_unlock(&port->lock); ++ } - spin_unlock(&port->lock); + if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { @@ -915,10 +1115,13 @@ index 2f72514d6..6592e5cdb 100644 - - if (stm32_port->rx_ch) - stm32_receive_chars(port, true); ++ unsigned long flags; - spin_unlock(&port->lock); ++ spin_lock_irqsave(&port->lock, flags); + /* Receiver timeout irq for DMA RX */ -+ stm32_usart_receive_chars(port, true); ++ stm32_usart_receive_chars(port, false); ++ spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; } @@ -948,13 +1151,31 @@ index 2f72514d6..6592e5cdb 100644 else - stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_RTSE); ++ ++ mctrl_gpio_set(stm32_port->gpios, mctrl); } -static unsigned int stm32_get_mctrl(struct uart_port *port) +static unsigned int stm32_usart_get_mctrl(struct uart_port *port) { ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ unsigned int ret; ++ /* This routine is used to get signals of: DCD, DSR, RI, and CTS */ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +- return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; ++ ret = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; ++ ++ return mctrl_gpio_get(stm32_port->gpios, &ret); ++} ++ ++static void stm32_usart_enable_ms(struct uart_port *port) ++{ ++ mctrl_gpio_enable_ms(to_stm32_port(port)->gpios); ++} ++ ++static void stm32_usart_disable_ms(struct uart_port *port) ++{ ++ mctrl_gpio_disable_ms(to_stm32_port(port)->gpios); } /* Transmit stop */ @@ -1012,11 +1233,21 @@ index 2f72514d6..6592e5cdb 100644 spin_lock_irqsave(&port->lock, flags); - stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); ++ ++ /* ++ * Disable DMA request line if enabled, so the RX data gets queued ++ * into the FIFO. ++ * Hardware flow control is triggered when RX FIFO is full. ++ */ ++ if (stm32_usart_rx_dma_enabled(port)) ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) - stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); ++ stm32_port->throttled = true; spin_unlock_irqrestore(&port->lock, flags); } @@ -1035,6 +1266,14 @@ index 2f72514d6..6592e5cdb 100644 - stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); ++ /* ++ * Switch back to DMA mode (re-enable DMA request line). ++ * Hardware flow control is stopped when FIFO is not full any more. ++ */ ++ if (stm32_port->rx_ch) ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); ++ ++ stm32_port->throttled = false; spin_unlock_irqrestore(&port->lock, flags); } @@ -1046,21 +1285,28 @@ index 2f72514d6..6592e5cdb 100644 struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); -+ stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); - if (stm32_port->cr3_irq) +- if (stm32_port->cr3_irq) - stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); -- ++ /* Disable DMA request line and RX DMA. */ ++ if (stm32_port->rx_ch) { ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ dmaengine_terminate_sync(stm32_port->rx_ch); ++ } + ++ stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); ++ if (stm32_port->cr3_irq) + stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); } /* Handle breaks - ignored by us */ -static void stm32_break_ctl(struct uart_port *port, int break_state) +static void stm32_usart_break_ctl(struct uart_port *port, int break_state) -+{ -+} -+ -+static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port) { + } + +-static int stm32_startup(struct uart_port *port) ++static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port) ++{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct dma_async_tx_descriptor *desc; @@ -1090,12 +1336,17 @@ index 2f72514d6..6592e5cdb 100644 + + /* Issue pending DMA requests */ + dma_async_issue_pending(stm32_port->rx_ch); -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); ++ ++ /* ++ * DMA request line not re-enabled at resume when port is throttled. ++ * It will be re-enabled by unthrottle ops. ++ */ ++ if (!stm32_port->throttled) ++ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); + + return 0; - } - --static int stm32_startup(struct uart_port *port) ++} ++ +static int stm32_usart_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); @@ -1150,17 +1401,35 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -643,12 +818,17 @@ static void stm32_shutdown(struct uart_port *port) - if (ret) +@@ -630,6 +890,9 @@ static void stm32_shutdown(struct uart_port *port) + u32 val, isr; + int ret; + ++ /* Disable modem control interrupts */ ++ stm32_usart_disable_ms(port); ++ + val = USART_CR1_TXEIE | USART_CR1_TE; + val |= stm32_port->cr1_irq | USART_CR1_RE; + val |= BIT(cfg->uart_enable_bit); +@@ -640,15 +903,24 @@ static void stm32_shutdown(struct uart_port *port) + isr, (isr & USART_SR_TC), + 10, 100000); + +- if (ret) ++ /* ++ * Send the TC error message only when ISR_TC is not set and ++ * data stored in TDR / TX FIFO. ++ */ ++ if (ret && !(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) dev_err(port->dev, "transmission complete not set\n"); - stm32_clr_bits(port, ofs->cr1, val); -+ stm32_usart_clr_bits(port, ofs->cr1, val); ++ /* flush RX & TX FIFO */ ++ if (ofs->rqr != UNDEF_REG) ++ stm32_usart_set_bits(port, ofs->rqr, ++ USART_RQR_TXFRQ | USART_RQR_RXFRQ); + -+ if (stm32_port->rx_ch) { -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); -+ dmaengine_terminate_sync(stm32_port->rx_ch); -+ } ++ stm32_usart_clr_bits(port, ofs->cr1, val); free_irq(port->irq, port); } @@ -1170,7 +1439,7 @@ index 2f72514d6..6592e5cdb 100644 { unsigned int bits; -@@ -678,8 +858,9 @@ static unsigned int stm32_get_databits(struct ktermios *termios) +@@ -678,8 +950,9 @@ static unsigned int stm32_get_databits(struct ktermios *termios) return bits; } @@ -1182,7 +1451,7 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -688,8 +869,9 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -688,8 +961,9 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int baud, bits; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; @@ -1193,7 +1462,7 @@ index 2f72514d6..6592e5cdb 100644 if (!stm32_port->hw_flow_control) cflag &= ~CRTSCTS; -@@ -698,26 +880,39 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -698,26 +972,45 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, spin_lock_irqsave(&port->lock, flags); @@ -1202,7 +1471,11 @@ index 2f72514d6..6592e5cdb 100644 + (isr & USART_SR_TC), + 10, 100000); + -+ if (ret) ++ /* ++ * Send the TC error message only when ISR_TC is not set and ++ * data stored in TDR / TX FIFO. ++ */ ++ if (ret && !(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) + dev_err(port->dev, "transmission complete not set\n"); + /* Stop serial port and reset value */ @@ -1226,8 +1499,10 @@ index 2f72514d6..6592e5cdb 100644 - | USART_CR3_TXFTCFG_MASK; + cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; + if (stm32_port->fifoen) { -+ cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; -+ cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; ++ if (stm32_port->txftcfg >= 0) ++ cr3 |= stm32_port->txftcfg << USART_CR3_TXFTCFG_SHIFT; ++ if (stm32_port->rxftcfg >= 0) ++ cr3 |= stm32_port->rxftcfg << USART_CR3_RXFTCFG_SHIFT; + } if (cflag & CSTOPB) @@ -1238,7 +1513,17 @@ index 2f72514d6..6592e5cdb 100644 stm32_port->rdr_mask = (BIT(bits) - 1); if (cflag & PARENB) { -@@ -751,9 +946,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -741,7 +1034,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + , bits); + + if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || +- stm32_port->fifoen)) { ++ (stm32_port->fifoen && ++ stm32_port->rxftcfg >= 0))) { + if (cflag & CSTOPB) + bits = bits + 3; /* 1 start bit + 2 stop bits */ + else +@@ -751,9 +1045,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, stm32_port->cr1_irq = USART_CR1_RTOIE; writel_relaxed(bits, port->membase + ofs->rtor); cr2 |= USART_CR2_RTOEN; @@ -1254,7 +1539,7 @@ index 2f72514d6..6592e5cdb 100644 } cr1 |= stm32_port->cr1_irq; -@@ -779,11 +977,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -779,11 +1076,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (usartdiv < 16) { oversampling = 8; cr1 |= USART_CR1_OVER8; @@ -1268,7 +1553,7 @@ index 2f72514d6..6592e5cdb 100644 } mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; -@@ -816,13 +1014,22 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -816,13 +1113,19 @@ 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; @@ -1288,14 +1573,11 @@ index 2f72514d6..6592e5cdb 100644 - stm32_config_reg_rs485(&cr1, &cr3, - rs485conf->delay_rts_before_send, - rs485conf->delay_rts_after_send, baud); -+ stm32_usart_config_reg_rs485(&cr1, &cr3, -+ rs485conf->delay_rts_before_send, -+ rs485conf->delay_rts_after_send, -+ baud); ++ stm32_usart_config_reg_rs485(&cr1, &cr3, baud, rs485conf); if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; -@@ -836,43 +1043,49 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -836,43 +1139,55 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); } @@ -1312,6 +1594,12 @@ index 2f72514d6..6592e5cdb 100644 - stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); ++ ++ /* Handle modem control interrupts */ ++ if (UART_ENABLE_MS(port, termios->c_cflag)) ++ stm32_usart_enable_ms(port); ++ else ++ stm32_usart_disable_ms(port); } -static const char *stm32_type(struct uart_port *port) @@ -1353,7 +1641,7 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32port = container_of(port, struct stm32_port, port); -@@ -886,7 +1099,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state, +@@ -886,7 +1201,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state, break; case UART_PM_STATE_OFF: spin_lock_irqsave(&port->lock, flags); @@ -1362,7 +1650,7 @@ index 2f72514d6..6592e5cdb 100644 spin_unlock_irqrestore(&port->lock, flags); pm_runtime_put_sync(port->dev); break; -@@ -894,53 +1107,56 @@ static void stm32_pm(struct uart_port *port, unsigned int state, +@@ -894,55 +1209,98 @@ static void stm32_pm(struct uart_port *port, unsigned int state, } static const struct uart_ops stm32_uart_ops = { @@ -1392,6 +1680,7 @@ index 2f72514d6..6592e5cdb 100644 + .throttle = stm32_usart_throttle, + .unthrottle = stm32_usart_unthrottle, + .stop_rx = stm32_usart_stop_rx, ++ .enable_ms = stm32_usart_enable_ms, + .break_ctl = stm32_usart_break_ctl, + .startup = stm32_usart_startup, + .shutdown = stm32_usart_shutdown, @@ -1407,6 +1696,39 @@ index 2f72514d6..6592e5cdb 100644 -static int stm32_init_port(struct stm32_port *stm32port, - struct platform_device *pdev) ++/* ++ * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG) ++ * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case, ++ * RXNEIE / TXEIE can be used instead of threshold irqs: RXFTIE / TXFTIE. ++ * So, RXFTCFG / TXFTCFG bitfields values are encoded as array index + 1. ++ */ ++static const u32 stm32h7_usart_fifo_thresh_cfg[] = { 1, 2, 4, 8, 12, 14, 16 }; ++ ++static void stm32_usart_get_ftcfg(struct platform_device *pdev, const char *p, ++ int *ftcfg) ++{ ++ u32 bytes, i; ++ ++ /* DT option to get RX & TX FIFO threshold (default to 8 bytes) */ ++ if (of_property_read_u32(pdev->dev.of_node, p, &bytes)) ++ bytes = 8; ++ ++ for (i = 0; i < ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg); i++) ++ if (stm32h7_usart_fifo_thresh_cfg[i] >= bytes) ++ break; ++ if (i >= ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg)) ++ i = ARRAY_SIZE(stm32h7_usart_fifo_thresh_cfg) - 1; ++ ++ dev_dbg(&pdev->dev, "%s set to %d bytes\n", p, ++ stm32h7_usart_fifo_thresh_cfg[i]); ++ ++ /* Provide FIFO threshold ftcfg (1 is invalid: threshold irq unused) */ ++ if (i) ++ *ftcfg = i - 1; ++ else ++ *ftcfg = -EINVAL; ++} ++ +static void stm32_usart_deinit_port(struct stm32_port *stm32port) +{ + clk_disable_unprepare(stm32port->clk); @@ -1450,8 +1772,48 @@ index 2f72514d6..6592e5cdb 100644 + "wakeup-source"); stm32port->fifoen = stm32port->info->cfg.has_fifo; ++ if (stm32port->fifoen) { ++ stm32_usart_get_ftcfg(pdev, "st,rx-fifo-threshold-bytes", ++ &stm32port->rxftcfg); ++ stm32_usart_get_ftcfg(pdev, "st,tx-fifo-threshold-bytes", ++ &stm32port->txftcfg); ++ } -@@ -970,7 +1186,7 @@ static int stm32_init_port(struct stm32_port *stm32port, + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + port->membase = devm_ioremap_resource(&pdev->dev, res); +@@ -963,14 +1321,38 @@ static int stm32_init_port(struct stm32_port *stm32port, + + stm32port->port.uartclk = clk_get_rate(stm32port->clk); + if (!stm32port->port.uartclk) { +- clk_disable_unprepare(stm32port->clk); + ret = -EINVAL; ++ goto err_clk; ++ } ++ ++ stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0); ++ if (IS_ERR(stm32port->gpios)) { ++ ret = PTR_ERR(stm32port->gpios); ++ goto err_clk; + } + ++ /* ++ * Both CTS/RTS gpios and "st,hw-flow-ctrl" (deprecated) or "uart-has-rtscts" ++ * properties should not be specified. ++ */ ++ if (stm32port->hw_flow_control) { ++ if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) || ++ mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) { ++ dev_err(&pdev->dev, "Conflicting RTS/CTS config\n"); ++ ret = -EINVAL; ++ goto err_clk; ++ } ++ } ++ ++ return ret; ++ ++err_clk: ++ clk_disable_unprepare(stm32port->clk); ++ return ret; } @@ -1460,7 +1822,7 @@ index 2f72514d6..6592e5cdb 100644 { struct device_node *np = pdev->dev.of_node; int id; -@@ -987,12 +1203,14 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) +@@ -987,12 +1369,14 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) if (WARN_ON(id >= STM32_MAX_PORTS)) return NULL; @@ -1477,7 +1839,7 @@ index 2f72514d6..6592e5cdb 100644 return &stm32_ports[id]; } -@@ -1007,30 +1225,28 @@ static const struct of_device_id stm32_match[] = { +@@ -1007,30 +1391,28 @@ static const struct of_device_id stm32_match[] = { MODULE_DEVICE_TABLE(of, stm32_match); #endif @@ -1522,7 +1884,7 @@ index 2f72514d6..6592e5cdb 100644 /* Configure DMA channel */ memset(&config, 0, sizeof(config)); -@@ -1040,47 +1256,23 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, +@@ -1040,47 +1422,23 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->rx_ch, &config); if (ret < 0) { dev_err(dev, "rx dma channel config failed\n"); @@ -1581,7 +1943,7 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct uart_port *port = &stm32port->port; -@@ -1090,19 +1282,11 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, +@@ -1090,19 +1448,11 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, stm32port->tx_dma_busy = false; @@ -1605,7 +1967,7 @@ index 2f72514d6..6592e5cdb 100644 /* Configure DMA channel */ memset(&config, 0, sizeof(config)); -@@ -1112,31 +1296,20 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, +@@ -1112,31 +1462,20 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->tx_ch, &config); if (ret < 0) { dev_err(dev, "tx dma channel config failed\n"); @@ -1641,7 +2003,7 @@ index 2f72514d6..6592e5cdb 100644 if (!stm32port) return -ENODEV; -@@ -1146,105 +1319,145 @@ static int stm32_serial_probe(struct platform_device *pdev) +@@ -1146,105 +1485,145 @@ static int stm32_serial_probe(struct platform_device *pdev) else return -EINVAL; @@ -1840,7 +2202,7 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -1255,7 +1468,8 @@ static void stm32_console_putchar(struct uart_port *port, int ch) +@@ -1255,7 +1634,8 @@ static void stm32_console_putchar(struct uart_port *port, int ch) writel_relaxed(ch, port->membase + ofs->tdr); } @@ -1850,7 +2212,7 @@ index 2f72514d6..6592e5cdb 100644 { struct uart_port *port = &stm32_ports[co->index].port; struct stm32_port *stm32_port = to_stm32_port(port); -@@ -1279,7 +1493,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) +@@ -1279,7 +1659,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) new_cr1 |= USART_CR1_TE | BIT(cfg->uart_enable_bit); writel_relaxed(new_cr1, port->membase + ofs->cr1); @@ -1859,7 +2221,7 @@ index 2f72514d6..6592e5cdb 100644 /* Restore interrupt state */ writel_relaxed(old_cr1, port->membase + ofs->cr1); -@@ -1289,7 +1503,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) +@@ -1289,7 +1669,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) local_irq_restore(flags); } @@ -1868,7 +2230,7 @@ index 2f72514d6..6592e5cdb 100644 { struct stm32_port *stm32port; int baud = 9600; -@@ -1308,7 +1522,7 @@ static int stm32_console_setup(struct console *co, char *options) +@@ -1308,7 +1688,7 @@ static int stm32_console_setup(struct console *co, char *options) * this to be called during the uart port registration when the * driver gets probed and the port should be mapped at that point. */ @@ -1877,7 +2239,7 @@ index 2f72514d6..6592e5cdb 100644 return -ENXIO; if (options) -@@ -1320,8 +1534,8 @@ static int stm32_console_setup(struct console *co, char *options) +@@ -1320,8 +1700,8 @@ static int stm32_console_setup(struct console *co, char *options) static struct console stm32_console = { .name = STM32_SERIAL_NAME, .device = uart_console_device, @@ -1888,23 +2250,27 @@ index 2f72514d6..6592e5cdb 100644 .flags = CON_PRINTBUFFER, .index = -1, .data = &stm32_usart_driver, -@@ -1342,60 +1556,89 @@ static struct uart_driver stm32_usart_driver = { +@@ -1342,60 +1722,107 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; -static void __maybe_unused stm32_serial_enable_wakeup(struct uart_port *port, - bool enable) -+static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, -+ bool enable) ++static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, ++ bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - struct stm32_usart_config *cfg = &stm32_port->info->cfg; - u32 val; ++ struct tty_port *tport = &port->state->port; ++ unsigned long flags; ++ int ret; - if (stm32_port->wakeirq <= 0) -+ if (!stm32_port->wakeup_src) - return; +- return; ++ if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) ++ return 0; + /* + * Enable low-power wake-up and wake-up irq if argument is set to @@ -1921,20 +2287,48 @@ index 2f72514d6..6592e5cdb 100644 - stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); ++ mctrl_gpio_enable_irq_wake(stm32_port->gpios); ++ ++ /* ++ * When DMA is used for reception, it must be disabled before ++ * entering low-power mode and re-enabled when exiting from ++ * low-power mode. ++ */ ++ if (stm32_port->rx_ch) { ++ /* Avoid race with RX IRQ when DMAR is cleared */ ++ spin_lock_irqsave(&port->lock, flags); ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ /* Poll data from DMA RX buffer if any */ ++ stm32_usart_receive_chars(port, true); ++ dmaengine_terminate_async(stm32_port->rx_ch); ++ spin_unlock_irqrestore(&port->lock, flags); ++ } ++ ++ spin_lock_irqsave(&port->lock, flags); ++ /* Poll data from RX FIFO if any */ ++ stm32_usart_receive_chars(port, false); ++ spin_unlock_irqrestore(&port->lock, flags); } else { - stm32_clr_bits(port, ofs->cr1, USART_CR1_UESM); ++ if (stm32_port->rx_ch) { ++ ret = stm32_usart_start_rx_dma_cyclic(port); ++ if (ret) ++ return ret; ++ } ++ ++ mctrl_gpio_disable_irq_wake(stm32_port->gpios); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } ++ ++ return 0; } -static int __maybe_unused stm32_serial_suspend(struct device *dev) +static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -+ struct tty_port *tport = &port->state->port; ++ int ret; uart_suspend_port(&stm32_usart_driver, port); @@ -1943,16 +2337,9 @@ index 2f72514d6..6592e5cdb 100644 - else - stm32_serial_enable_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { -+ stm32_usart_serial_en_wakeup(port, true); -+ /* -+ * DMA can't suspend while DMA channels are still active. -+ * Terminate DMA transfer at suspend, and then restart a new -+ * DMA transfer at resume. -+ */ -+ if (stm32_port->rx_ch && tty_port_initialized(tport)) { -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); -+ dmaengine_terminate_sync(stm32_port->rx_ch); -+ } ++ ret = stm32_usart_serial_en_wakeup(port, true); ++ if (ret) ++ return ret; + } - pinctrl_pm_select_sleep_state(dev); @@ -1976,8 +2363,6 @@ index 2f72514d6..6592e5cdb 100644 +static int __maybe_unused stm32_usart_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ struct tty_port *tport = &port->state->port; + int ret; pinctrl_pm_select_default_state(dev); @@ -1985,13 +2370,9 @@ index 2f72514d6..6592e5cdb 100644 - if (device_may_wakeup(dev)) - stm32_serial_enable_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { -+ stm32_usart_serial_en_wakeup(port, false); -+ -+ if (stm32_port->rx_ch && tty_port_initialized(tport)) { -+ ret = stm32_usart_start_rx_dma_cyclic(port); -+ if (ret) -+ return ret; -+ } ++ ret = stm32_usart_serial_en_wakeup(port, false); ++ if (ret) ++ return ret; + } return uart_resume_port(&stm32_usart_driver, port); @@ -2002,7 +2383,7 @@ index 2f72514d6..6592e5cdb 100644 { struct uart_port *port = dev_get_drvdata(dev); struct stm32_port *stm32port = container_of(port, -@@ -1406,7 +1649,7 @@ static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) +@@ -1406,7 +1833,7 @@ static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) return 0; } @@ -2011,7 +2392,7 @@ index 2f72514d6..6592e5cdb 100644 { struct uart_port *port = dev_get_drvdata(dev); struct stm32_port *stm32port = container_of(port, -@@ -1416,14 +1659,15 @@ static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) +@@ -1416,14 +1843,15 @@ static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) } static const struct dev_pm_ops stm32_serial_pm_ops = { @@ -2032,7 +2413,7 @@ index 2f72514d6..6592e5cdb 100644 .driver = { .name = DRIVER_NAME, .pm = &stm32_serial_pm_ops, -@@ -1431,7 +1675,7 @@ static struct platform_driver stm32_serial_driver = { +@@ -1431,7 +1859,7 @@ static struct platform_driver stm32_serial_driver = { }, }; @@ -2041,7 +2422,7 @@ index 2f72514d6..6592e5cdb 100644 { static char banner[] __initdata = "STM32 USART driver initialized"; int ret; -@@ -1449,14 +1693,14 @@ static int __init usart_init(void) +@@ -1449,14 +1877,14 @@ static int __init usart_init(void) return ret; } @@ -2060,7 +2441,7 @@ index 2f72514d6..6592e5cdb 100644 MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver"); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h -index a175c1094..969b0c6dd 100644 +index a175c1094dc8d..6961cd9855f68 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -1,4 +1,4 @@ @@ -2094,7 +2475,20 @@ index a175c1094..969b0c6dd 100644 /* USART_DR */ #define USART_DR_MASK GENMASK(8, 0) -@@ -252,9 +250,9 @@ struct stm32_usart_info stm32h7_info = { +@@ -216,12 +214,6 @@ struct stm32_usart_info stm32h7_info = { + #define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */ + #define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */ + +-/* TX FIFO threashold set to half of its depth */ +-#define USART_CR3_TXFTCFG_HALF 0x2 +- +-/* RX FIFO threashold set to half of its depth */ +-#define USART_CR3_RXFTCFG_HALF 0x2 +- + /* USART_GTPR */ + #define USART_GTPR_PSC_MASK GENMASK(7, 0) + #define USART_GTPR_GT_MASK GENMASK(15, 8) +@@ -252,9 +244,9 @@ struct stm32_usart_info stm32h7_info = { #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 @@ -2107,18 +2501,37 @@ index a175c1094..969b0c6dd 100644 struct stm32_port { struct uart_port port; -@@ -272,8 +270,10 @@ struct stm32_port { +@@ -270,10 +262,16 @@ struct stm32_port { + u32 cr3_irq; /* USART_CR3_RXFTIE */ + int last_res; bool tx_dma_busy; /* dma tx busy */ ++ bool throttled; /* port throttled */ bool hw_flow_control; bool fifoen; - int wakeirq; ++ int rxftcfg; /* RX FIFO threshold CFG */ ++ int txftcfg; /* TX FIFO threshold CFG */ + bool wakeup_src; int rdr_mask; /* receive data register mask */ ++ struct mctrl_gpios *gpios; /* modem control gpios */ + struct dma_tx_state state; + enum dma_status status; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; +diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h +index 93eb3c496ff1e..2d98e65d2a783 100644 +--- a/include/uapi/linux/serial.h ++++ b/include/uapi/linux/serial.h +@@ -128,6 +128,8 @@ struct serial_rs485 { + (if supported) */ + __u32 delay_rts_before_send; /* Delay before send (milliseconds) */ + __u32 delay_rts_after_send; /* Delay after send (milliseconds) */ ++ __u32 delay_rts_before_send_ns; /* Delay (nanoseconds) */ ++ __u32 delay_rts_after_send_ns; /* Delay (nanoseconds) */ + __u32 padding[5]; /* Memory is cheap, new structs + are a royal PITA .. */ + }; -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0016-ARM-stm32mp1-r2-PHY-USB.patch similarity index 82% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0016-ARM-stm32mp1-r2-PHY-USB.patch index 67f61c6..3a148c3 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0016-ARM-stm32mp1-r1-PHY-USB.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0016-ARM-stm32mp1-r2-PHY-USB.patch @@ -1,41 +1,262 @@ -From cad7f0ae4c464edf0d139218f06c9d46e18fb62b Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:47:01 +0200 -Subject: [PATCH 16/23] ARM-stm32mp1-r1-PHY-USB +From 95aafdb42d1f3aa59f114a7f076949abac53c38d Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:50 +0200 +Subject: [PATCH 16/22] ARM-stm32mp1-r2-rc8-PHY-USB --- - drivers/phy/phy-core.c | 48 +- - drivers/phy/st/phy-stm32-usbphyc.c | 485 ++++++++++--- - drivers/usb/dwc2/Kconfig | 1 + - drivers/usb/dwc2/Makefile | 2 +- - drivers/usb/dwc2/core.c | 123 ++-- - drivers/usb/dwc2/core.h | 20 + - drivers/usb/dwc2/core_intr.c | 7 +- - drivers/usb/dwc2/drd.c | 189 +++++ - drivers/usb/dwc2/gadget.c | 7 +- - drivers/usb/dwc2/hcd.c | 6 +- - drivers/usb/dwc2/hw.h | 8 + - drivers/usb/dwc2/params.c | 39 ++ - drivers/usb/dwc2/platform.c | 134 +++- - drivers/usb/gadget/function/f_acm.c | 16 + - drivers/usb/gadget/function/f_serial.c | 16 + - drivers/usb/gadget/function/u_serial.c | 53 +- - drivers/usb/gadget/function/u_serial.h | 2 + - drivers/usb/host/ehci-platform.c | 7 + - drivers/usb/renesas_usbhs/rcar2.c | 2 +- - drivers/usb/renesas_usbhs/rza2.c | 2 +- - drivers/usb/typec/Kconfig | 9 + - drivers/usb/typec/Makefile | 1 + - drivers/usb/typec/class.c | 15 + - drivers/usb/typec/typec_stusb.c | 910 +++++++++++++++++++++++++ - include/linux/phy/phy.h | 9 +- - include/linux/usb/typec.h | 1 + - 26 files changed, 1959 insertions(+), 153 deletions(-) + .../bindings/connector/usb-connector.txt | 2 + + .../bindings/phy/phy-stm32-usbphyc.txt | 60 +- + .../devicetree/bindings/usb/dwc2.txt | 8 + + .../devicetree/bindings/usb/generic-ehci.yaml | 5 + + .../bindings/usb/st,typec-stusb.txt | 48 + + drivers/phy/phy-core.c | 48 +- + drivers/phy/st/phy-stm32-usbphyc.c | 497 ++++++++-- + drivers/usb/dwc2/Kconfig | 1 + + drivers/usb/dwc2/Makefile | 2 +- + drivers/usb/dwc2/core.c | 123 ++- + drivers/usb/dwc2/core.h | 21 + + drivers/usb/dwc2/drd.c | 196 ++++ + drivers/usb/dwc2/gadget.c | 7 +- + drivers/usb/dwc2/hcd.c | 6 +- + drivers/usb/dwc2/hw.h | 8 + + drivers/usb/dwc2/params.c | 43 + + drivers/usb/dwc2/platform.c | 131 ++- + drivers/usb/gadget/function/f_acm.c | 16 + + drivers/usb/gadget/function/f_serial.c | 16 + + drivers/usb/gadget/function/u_serial.c | 53 +- + drivers/usb/gadget/function/u_serial.h | 2 + + drivers/usb/host/ehci-platform.c | 7 + + drivers/usb/renesas_usbhs/rcar2.c | 2 +- + drivers/usb/renesas_usbhs/rza2.c | 2 +- + drivers/usb/typec/Kconfig | 9 + + drivers/usb/typec/Makefile | 1 + + drivers/usb/typec/class.c | 15 + + drivers/usb/typec/typec_stusb.c | 910 ++++++++++++++++++ + include/linux/phy/phy.h | 9 +- + include/linux/usb/typec.h | 1 + + 30 files changed, 2102 insertions(+), 147 deletions(-) + create mode 100644 Documentation/devicetree/bindings/usb/st,typec-stusb.txt create mode 100644 drivers/usb/dwc2/drd.c create mode 100644 drivers/usb/typec/typec_stusb.c +diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt +index d357987181ee0..5c0bb0395bc92 100644 +--- a/Documentation/devicetree/bindings/connector/usb-connector.txt ++++ b/Documentation/devicetree/bindings/connector/usb-connector.txt +@@ -34,6 +34,8 @@ Optional properties for usb-b-connector: + Optional properties for usb-c-connector: + - power-role: should be one of "source", "sink" or "dual"(DRP) if typec + connector has power support. ++- power-opmode: should be one of "default", "1.5A", "3.0A" or ++ "usb_power_delivery" if typec connector has power support. + - try-power-role: preferred power role if "dual"(DRP) can support Try.SNK + or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC. + - data-role: should be one of "host", "device", "dual"(DRD) if typec +diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt +index 725ae71ae6535..3953489e3a6bb 100644 +--- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt ++++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt +@@ -23,8 +23,11 @@ Required properties: + - compatible: must be "st,stm32mp1-usbphyc" + - reg: address and length of the usb phy control register set + - clocks: phandle + clock specifier for the PLL phy clock ++- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY ++- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY + - #address-cells: number of address cells for phys sub-nodes, must be <1> + - #size-cells: number of size cells for phys sub-nodes, must be <0> ++- #clock-cells: number of clock cells for ck_usbo_48m consumer, must be <0> + + Optional properties: + - assigned-clocks: phandle + clock specifier for the PLL phy clock +@@ -34,40 +37,83 @@ Optional properties: + Required nodes: one sub-node per port the controller provides. + + Phy sub-nodes +-============== ++============= + + Required properties: + - reg: phy port index + - phy-supply: phandle to the regulator providing 3V3 power to the PHY, + see phy-bindings.txt in the same directory. +-- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY +-- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY + - #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY + port#1 and must be <1> for PHY port#2, to select USB controller + ++Optional properties: ++- st,phy-tuning : phandle to the usb phy tuning node, see Phy tuning node below ++- vbus-supply: phandle to the regulator providing 5V vbus to the USB connector ++ ++Phy tuning node ++=============== ++ ++It may be necessary to adjust the phy settings to compensate parasitics, which ++can be due to USB connector/receptacle, routing, ESD protection component, ... ++ ++Here is the list of all optional parameters to tune the interface of the phy ++(HS for High-Speed, FS for Full-Speed, LS for Low-Speed) ++ ++Optional properties: ++- st,current-boost: <1> current boosting of 1mA ++ <2> current boosting of 2mA ++- st,no-lsfs-fb-cap: disables the LS/FS feedback capacitor ++- st,hs-slew-ctrl: slows the HS driver slew rate by 10% ++- st,hs-dc-level: <0> decreases the HS driver DC level by 5 to 7mV ++ <1> increases the HS driver DC level by 5 to 7mV ++ <2> increases the HS driver DC level by 10 to 14mV ++- st,fs-rftime-tuning: enables the FS rise/fall tuning option ++- st,hs-rftime-reduction: enables the HS rise/fall reduction feature ++- st,hs-current-trim: controls HS driver current trimming for choke ++- st,hs-impedance-trim: controls HS driver impedance tuning for choke ++- st,squelch-level: adjusts the squelch DC threshold value ++- st,hs-rx-gain-eq: enables the HS Rx gain equalizer ++- st,hs-rx-offset: adjusts the HS Rx offset ++- st,no-hs-ftime-ctrl: disables the HS fall time control of single ++ ended signals during pre-emphasis ++- st,no-lsfs-sc: disables the short circuit protection in LS/FS driver ++- st,hs-tx-staggering: enables the basic staggering in HS Tx mode ++ + + Example: ++ usb_phy_tuning: usb-phy-tuning { ++ st,current-boost = <2>; ++ st,no-lfs-fb-cap; ++ st,hs-dc-level = <2>; ++ st,hs-rftime-reduction; ++ st,hs-current-trim = <5>; ++ st,hs-impedance-trim = <0>; ++ st,squelch-level = <1>; ++ st,no-hs-ftime-ctrl; ++ st,hs-tx-staggering; ++ }; ++ + usbphyc: usb-phy@5a006000 { + compatible = "st,stm32mp1-usbphyc"; + reg = <0x5a006000 0x1000>; + clocks = <&rcc_clk USBPHY_K>; + resets = <&rcc_rst USBPHY_R>; ++ vdda1v1-supply = <®11>; ++ vdda1v8-supply = <®18>; + #address-cells = <1>; + #size-cells = <0>; ++ #clock-cells = <0>; + + usbphyc_port0: usb-phy@0 { + reg = <0>; + phy-supply = <&vdd_usb>; +- vdda1v1-supply = <®11>; +- vdda1v8-supply = <®18> + #phy-cells = <0>; + }; + + usbphyc_port1: usb-phy@1 { + reg = <1>; + phy-supply = <&vdd_usb>; +- vdda1v1-supply = <®11>; +- vdda1v8-supply = <®18> + #phy-cells = <1>; ++ st,phy-tuning = <&usb_phy_tuning>; + }; + }; +diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt +index aafff3a6904d0..1a65303d0ca5c 100644 +--- a/Documentation/devicetree/bindings/usb/dwc2.txt ++++ b/Documentation/devicetree/bindings/usb/dwc2.txt +@@ -23,6 +23,9 @@ Required properties: + configured in HS mode; + - "st,stm32f7-hsotg": The DWC2 USB HS controller instance in STM32F7 SoCs + configured in HS mode; ++ - "st,stm32mp1-fsotg": The DWC2 USB controller instance in STM32MP1 SoCs, ++ configured in FS mode (using dedicated FS transceiver). ++ - "st,stm32mp1-hsotg": The DWC2 USB controller instance in STM32MP1 SoCs; + - reg : Should contain 1 register range (address and length) + - interrupts : Should contain 1 interrupt + - clocks: clock provider specifier +@@ -46,6 +49,11 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties + on for remote wakeup during suspend. + - snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when + we detect a wakeup. This is due to a hardware errata. ++- usb33d-supply: external VBUS and ID sensing comparators supply, in order to ++ perform OTG operation, used on STM32MP1 SoCs. ++- usb-role-switch: use USB Role Switch to support dynamic dual role switch. ++ Refer to usb/generic.txt ++- wakeup-source: bool flag to indicate this device has wakeup capabilities + + Deprecated properties: + - g-use-dma: gadget DMA mode is automatically detected +diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml +index 1ca64c85191aa..b71c15dc8c11f 100644 +--- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml ++++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml +@@ -69,6 +69,11 @@ properties: + phy-names: + const: usb + ++ wakeup-source: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: ++ Indicate this device has wakeup capabilities. ++ + required: + - compatible + - reg +diff --git a/Documentation/devicetree/bindings/usb/st,typec-stusb.txt b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt +new file mode 100644 +index 0000000000000..415e14e1409ea +--- /dev/null ++++ b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt +@@ -0,0 +1,48 @@ ++STMicroelectronics STUSB Type-C Controller family ++ ++Required properties: ++ - compatible: should be "st,stusb1600". ++ - reg: I2C slave address of the device. ++ ++Optional properties: ++ - vdd-supply: main power supply [4.1V;22V]. ++ - vsys-supply: low power supply [3.0V;5.5V]. ++ - vconn-supply: power supply [2.7;5.5V] used to supply VConn on CC pin in ++ source or dual power role. ++ - interrupts: interrupt specifier triggered by ALERT# signal. ++ Please refer to ../interrupt-controller/interrupt.txt ++ - pinctrl state named "default" may be defined to configure pin for #ALERT ++ signal ++ ++USB-C connector attached to STUSB Type-C port controller can be described in ++an optional connector sub-node. Refer to ../connector/usb-connector.txt. ++In case role switch can be used, an optional port sub-node can be added. Refer ++to ../graph.txt. ++ ++Example : ++ ++ typec: stusb1600@28 { ++ compatible = "st,stusb1600"; ++ reg = <0x28>; ++ vdd-supply = <&vbus_drd>; ++ vsys-supply = <&vdd_usb>; ++ interrupts = <11 IRQ_TYPE_EDGE_FALLING>; ++ interrupt-parent = <&gpioi>; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&stusb1600_pins_a>; ++ ++ usb_con: connector { ++ compatible = "usb-c-connector"; ++ label = "USB-C"; ++ power-role = "dual"; ++ power-opmode = "1.5A"; ++ data-role = "dual"; ++ ++ port { ++ con_usbotg_hs_ep: endpoint { ++ remote-endpoint = <&usbotg_hs_ep>; ++ }; ++ }; ++ }; ++ }; ++ diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c -index b04f4fe85..8dfb4868c 100644 +index b04f4fe85ac2d..8dfb4868c8c3d 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -29,7 +29,7 @@ static void devm_phy_release(struct device *dev, void *res) @@ -152,7 +373,7 @@ index b04f4fe85..8dfb4868c 100644 } EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index); diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c -index 56bdea4b0..4e029c008 100644 +index 56bdea4b0bd90..0eb699344c071 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -7,8 +7,9 @@ @@ -220,10 +441,7 @@ index 56bdea4b0..4e029c008 100644 + DC_PLUS_10_TO_14_MV, + DC_MAX, +}; - --static const char * const supplies_names[] = { -- "vdda1v1", /* 1V1 */ -- "vdda1v8", /* 1V8 */ ++ +enum current_trim { + CUR_NOMINAL, + CUR_PLUS_1_56_PCT, @@ -242,9 +460,8 @@ index 56bdea4b0..4e029c008 100644 + CUR_PLUS_22_16_PCT, + CUR_PLUS_23_73_PCT, + CUR_MAX, - }; - --#define NUM_SUPPLIES ARRAY_SIZE(supplies_names) ++}; ++ +enum impedance_trim { + IMP_NOMINAL, + IMP_MINUS_2_OHMS, @@ -260,15 +477,19 @@ index 56bdea4b0..4e029c008 100644 + SQLCH_PLUS_14_MV, + SQLCH_MAX, +}; -+ + +-static const char * const supplies_names[] = { +- "vdda1v1", /* 1V1 */ +- "vdda1v8", /* 1V8 */ +enum rx_offset { + NO_RX_OFFSET, + RX_OFFSET_PLUS_5_MV, + RX_OFFSET_PLUS_10_MV, + RX_OFFSET_MINUS_5_MV, + RX_OFFSET_MAX, -+}; -+ + }; + +-#define NUM_SUPPLIES ARRAY_SIZE(supplies_names) +/* STM32_USBPHYC_VERSION bit fields */ +#define MINREV GENMASK(3, 0) +#define MAJREV GENMASK(7, 4) @@ -278,15 +499,16 @@ index 56bdea4b0..4e029c008 100644 #define PLL_FVCO_MHZ 2880 #define PLL_INFF_MIN_RATE_HZ 19200000 #define PLL_INFF_MAX_RATE_HZ 38400000 -@@ -58,7 +135,6 @@ struct pll_params { +@@ -58,7 +135,7 @@ struct pll_params { struct stm32_usbphyc_phy { struct phy *phy; struct stm32_usbphyc *usbphyc; - struct regulator_bulk_data supplies[NUM_SUPPLIES]; ++ struct regulator *vbus; u32 index; bool active; }; -@@ -70,6 +146,10 @@ struct stm32_usbphyc { +@@ -70,6 +147,10 @@ struct stm32_usbphyc { struct reset_control *rst; struct stm32_usbphyc_phy **phys; int nphys; @@ -297,7 +519,7 @@ index 56bdea4b0..4e029c008 100644 int switch_setup; }; -@@ -83,6 +163,41 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) +@@ -83,6 +164,41 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) writel_relaxed(readl_relaxed(reg) & ~bits, reg); } @@ -339,7 +561,7 @@ index 56bdea4b0..4e029c008 100644 static void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) { -@@ -142,83 +257,106 @@ static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) +@@ -142,83 +258,106 @@ static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) return 0; } @@ -354,12 +576,12 @@ index 56bdea4b0..4e029c008 100644 - if (usbphyc->phys[i]->active) - return true; + stm32_usbphyc_clr_bits(pll_reg, PLLEN); -+ + +- return false; + /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ + if (readl_relaxed_poll_timeout(pll_reg, pllen, !(pllen & PLLEN), 5, 50)) + dev_err(usbphyc->dev, "PLL not reset\n"); - -- return false; ++ + return stm32_usbphyc_regulators_disable(usbphyc); +} + @@ -424,12 +646,10 @@ index 56bdea4b0..4e029c008 100644 - return 0; -} - +- -static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) -{ - void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -+reg_disable: -+ stm32_usbphyc_regulators_disable(usbphyc); - /* Check if other phy port active */ - if (stm32_usbphyc_has_one_phy_active(usbphyc)) @@ -438,7 +658,9 @@ index 56bdea4b0..4e029c008 100644 - stm32_usbphyc_clr_bits(pll_reg, PLLEN); - /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ - udelay(PLL_PWR_DOWN_TIME_US); -- ++reg_disable: ++ stm32_usbphyc_regulators_disable(usbphyc); + - if (readl_relaxed(pll_reg) & PLLEN) { - dev_err(usbphyc->dev, "PLL not reset\n"); - return -EIO; @@ -484,44 +706,49 @@ index 56bdea4b0..4e029c008 100644 } static int stm32_usbphyc_phy_exit(struct phy *phy) -@@ -231,28 +369,168 @@ static int stm32_usbphyc_phy_exit(struct phy *phy) - return stm32_usbphyc_pll_disable(usbphyc); - } - --static int stm32_usbphyc_phy_power_on(struct phy *phy) -+static const struct phy_ops stm32_usbphyc_phy_ops = { -+ .init = stm32_usbphyc_phy_init, -+ .exit = stm32_usbphyc_phy_exit, -+ .owner = THIS_MODULE, -+}; -+ -+static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) +@@ -235,14 +374,20 @@ static int stm32_usbphyc_phy_power_on(struct phy *phy) { -- struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); -+ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, -+ clk48_hw); + struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); - return regulator_bulk_enable(NUM_SUPPLIES, usbphyc_phy->supplies); -+ return stm32_usbphyc_pll_enable(usbphyc); ++ if (usbphyc_phy->vbus) ++ return regulator_enable(usbphyc_phy->vbus); ++ ++ return 0; } --static int stm32_usbphyc_phy_power_off(struct phy *phy) -+static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) + static int stm32_usbphyc_phy_power_off(struct phy *phy) { -- struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); -+ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, -+ clk48_hw); + struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); - return regulator_bulk_disable(NUM_SUPPLIES, usbphyc_phy->supplies); -+ stm32_usbphyc_pll_disable(usbphyc); ++ if (usbphyc_phy->vbus) ++ return regulator_disable(usbphyc_phy->vbus); ++ ++ return 0; } --static const struct phy_ops stm32_usbphyc_phy_ops = { -- .init = stm32_usbphyc_phy_init, -- .exit = stm32_usbphyc_phy_exit, -- .power_on = stm32_usbphyc_phy_power_on, -- .power_off = stm32_usbphyc_phy_power_off, -- .owner = THIS_MODULE, + static const struct phy_ops stm32_usbphyc_phy_ops = { +@@ -253,6 +398,163 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { + .owner = THIS_MODULE, + }; + ++static int stm32_usbphyc_clk48_prepare(struct clk_hw *hw) ++{ ++ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, ++ clk48_hw); ++ ++ return stm32_usbphyc_pll_enable(usbphyc); ++} ++ ++static void stm32_usbphyc_clk48_unprepare(struct clk_hw *hw) ++{ ++ struct stm32_usbphyc *usbphyc = container_of(hw, struct stm32_usbphyc, ++ clk48_hw); ++ ++ stm32_usbphyc_pll_disable(usbphyc); ++} ++ +static unsigned long stm32_usbphyc_clk48_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ @@ -532,8 +759,8 @@ index 56bdea4b0..4e029c008 100644 + .prepare = stm32_usbphyc_clk48_prepare, + .unprepare = stm32_usbphyc_clk48_unprepare, + .recalc_rate = stm32_usbphyc_clk48_recalc_rate, - }; - ++}; ++ +static void stm32_usbphyc_clk48_unregister(void *data) +{ + struct stm32_usbphyc *usbphyc = data; @@ -550,6 +777,7 @@ index 56bdea4b0..4e029c008 100644 + + init.name = "ck_usbo_48m"; + init.ops = &usbphyc_clk48_ops; ++ init.flags = CLK_IGNORE_UNUSED | CLK_IS_CRITICAL; + + usbphyc->clk48_hw.init = &init; + @@ -665,7 +893,7 @@ index 56bdea4b0..4e029c008 100644 static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, u32 utmi_switch) { -@@ -313,7 +591,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -313,7 +615,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) struct device_node *child, *np = dev->of_node; struct resource *res; struct phy_provider *phy_provider; @@ -674,7 +902,7 @@ index 56bdea4b0..4e029c008 100644 int ret, port = 0; usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL); -@@ -330,7 +608,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -330,7 +632,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) usbphyc->clk = devm_clk_get(dev, 0); if (IS_ERR(usbphyc->clk)) { ret = PTR_ERR(usbphyc->clk); @@ -684,7 +912,7 @@ index 56bdea4b0..4e029c008 100644 return ret; } -@@ -345,6 +624,24 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -345,6 +648,24 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) reset_control_assert(usbphyc->rst); udelay(2); reset_control_deassert(usbphyc->rst); @@ -709,7 +937,7 @@ index 56bdea4b0..4e029c008 100644 } usbphyc->switch_setup = -EINVAL; -@@ -356,11 +653,26 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -356,11 +677,26 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto clk_disable; } @@ -737,7 +965,7 @@ index 56bdea4b0..4e029c008 100644 phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops); if (IS_ERR(phy)) { -@@ -378,24 +690,15 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -378,24 +714,15 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto put_child; } @@ -765,7 +993,22 @@ index 56bdea4b0..4e029c008 100644 usbphyc->phys[port] = usbphyc_phy; phy_set_bus_width(phy, 8); phy_set_drvdata(phy, usbphyc_phy); -@@ -416,6 +719,13 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -405,6 +732,14 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) + usbphyc->phys[port]->index = index; + usbphyc->phys[port]->active = false; + ++ usbphyc->phys[port]->vbus = devm_regulator_get_optional(&phy->dev, "vbus"); ++ if (IS_ERR(usbphyc->phys[port]->vbus)) { ++ ret = PTR_ERR(usbphyc->phys[port]->vbus); ++ if (ret == -EPROBE_DEFER) ++ goto put_child; ++ usbphyc->phys[port]->vbus = NULL; ++ } ++ + port++; + } + +@@ -416,6 +751,13 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto clk_disable; } @@ -779,7 +1022,7 @@ index 56bdea4b0..4e029c008 100644 version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); dev_info(dev, "registered rev:%lu.%lu\n", FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); -@@ -433,12 +743,34 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -433,12 +775,34 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) static int stm32_usbphyc_remove(struct platform_device *pdev) { struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev); @@ -814,7 +1057,7 @@ index 56bdea4b0..4e029c008 100644 static const struct of_device_id stm32_usbphyc_of_match[] = { { .compatible = "st,stm32mp1-usbphyc", }, { }, -@@ -451,6 +783,7 @@ static struct platform_driver stm32_usbphyc_driver = { +@@ -451,6 +815,7 @@ static struct platform_driver stm32_usbphyc_driver = { .driver = { .of_match_table = stm32_usbphyc_of_match, .name = "stm32-usbphyc", @@ -823,19 +1066,19 @@ index 56bdea4b0..4e029c008 100644 }; module_platform_driver(stm32_usbphyc_driver); diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig -index 16e1aa304..dceb8f324 100644 +index 16e1aa304edc4..c131719367eca 100644 --- a/drivers/usb/dwc2/Kconfig +++ b/drivers/usb/dwc2/Kconfig -@@ -47,6 +47,7 @@ config USB_DWC2_PERIPHERAL - config USB_DWC2_DUAL_ROLE - bool "Dual Role mode" - depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET) +@@ -5,6 +5,7 @@ config USB_DWC2 + depends on HAS_DMA + depends on USB || USB_GADGET + depends on HAS_IOMEM + select USB_ROLE_SWITCH help - Select this option if you want the driver to work in a dual-role - mode. In this mode both host and gadget features are enabled, and + Say Y here if your system has a Dual Role Hi-Speed USB + controller based on the DesignWare HSOTG IP Core. diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile -index 440320cc2..2bcd6945d 100644 +index 440320cc20a47..2bcd6945df461 100644 --- a/drivers/usb/dwc2/Makefile +++ b/drivers/usb/dwc2/Makefile @@ -3,7 +3,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG @@ -848,7 +1091,7 @@ index 440320cc2..2bcd6945d 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 78a4925aa..d1c6a8a9d 100644 +index 78a4925aa1185..d1c6a8a9d9789 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) @@ -1036,7 +1279,7 @@ index 78a4925aa..d1c6a8a9d 100644 /** diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index d08d070a0..ab67c2127 100644 +index d08d070a0fb6f..04d6b4937d769 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -411,6 +411,10 @@ enum dwc2_ep0_state { @@ -1136,32 +1379,20 @@ index d08d070a0..ab67c2127 100644 void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); -diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c -index 6af6add3d..6272b4ae4 100644 ---- a/drivers/usb/dwc2/core_intr.c -+++ b/drivers/usb/dwc2/core_intr.c -@@ -421,10 +421,13 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) - if (ret && (ret != -ENOTSUPP)) - dev_err(hsotg->dev, "exit power_down failed\n"); - -+ /* Change to L0 state */ -+ hsotg->lx_state = DWC2_L0; - call_gadget(hsotg, resume); -+ } else { -+ /* Change to L0 state */ -+ hsotg->lx_state = DWC2_L0; - } -- /* Change to L0 state */ -- hsotg->lx_state = DWC2_L0; - } else { - if (hsotg->params.power_down) - return; +@@ -1405,6 +1425,7 @@ static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg) + { return 0; } + static inline void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, + bool reset) {} ++static inline void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) {} + static inline void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) {} + static inline void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2) {} + static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c new file mode 100644 -index 000000000..8de90d7b2 +index 0000000000000..728ca64450960 --- /dev/null +++ b/drivers/usb/dwc2/drd.c -@@ -0,0 +1,189 @@ +@@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * drd.c - DesignWare USB2 DRD Controller Dual-role support @@ -1171,6 +1402,7 @@ index 000000000..8de90d7b2 + * Author(s): Amelie Delaunay + */ + ++#include +#include +#include +#include @@ -1189,9 +1421,9 @@ index 000000000..8de90d7b2 + gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); + dwc2_writel(hsotg, gotgctl, GOTGCTL); + -+ dwc2_force_mode(hsotg, false); -+ + spin_unlock_irqrestore(&hsotg->lock, flags); ++ ++ dwc2_force_mode(hsotg, (hsotg->dr_mode == USB_DR_MODE_HOST)); +} + +static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) @@ -1234,56 +1466,62 @@ index 000000000..8de90d7b2 +{ + struct dwc2_hsotg *hsotg = dev_get_drvdata(dev); + unsigned long flags; ++ int already = 0; + + /* Skip session not in line with dr_mode */ + if ((role == USB_ROLE_DEVICE && hsotg->dr_mode == USB_DR_MODE_HOST) || + (role == USB_ROLE_HOST && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) + return -EINVAL; + ++#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ ++ IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) + /* Skip session if core is in test mode */ + if (role == USB_ROLE_NONE && hsotg->test_mode) { + dev_dbg(hsotg->dev, "Core is in test mode\n"); + return -EBUSY; + } ++#endif ++ ++ /* ++ * In case of USB_DR_MODE_PERIPHERAL, clock is disabled at the end of ++ * the probe and enabled on udc_start. ++ * If role-switch set is called before the udc_start, we need to enable ++ * the clock to read/write GOTGCTL and GUSBCFG registers to override ++ * mode and sessions. It is the case if cable is plugged at boot. ++ */ ++ if (!hsotg->ll_hw_enabled && hsotg->clk) { ++ int ret = clk_prepare_enable(hsotg->clk); ++ if (ret) ++ return ret; ++ } + + spin_lock_irqsave(&hsotg->lock, flags); + + if (role == USB_ROLE_HOST) { -+ if (dwc2_ovr_avalid(hsotg, true)) -+ goto unlock; -+ -+ if (hsotg->dr_mode == USB_DR_MODE_OTG) -+ /* -+ * This will raise a Connector ID Status Change -+ * Interrupt - connID A -+ */ -+ dwc2_force_mode(hsotg, true); ++ already = dwc2_ovr_avalid(hsotg, true); + } else if (role == USB_ROLE_DEVICE) { -+ if (dwc2_ovr_bvalid(hsotg, true)) -+ goto unlock; -+ -+ if (hsotg->dr_mode == USB_DR_MODE_OTG) -+ /* -+ * This will raise a Connector ID Status Change -+ * Interrupt - connID B -+ */ -+ dwc2_force_mode(hsotg, false); -+ ++ already = dwc2_ovr_bvalid(hsotg, true); + /* This clear DCTL.SFTDISCON bit */ + dwc2_hsotg_core_connect(hsotg); + } else { + if (dwc2_is_device_mode(hsotg)) { -+ if (!dwc2_ovr_bvalid(hsotg, false)) -+ /* This set DCTL.SFTDISCON bit */ -+ dwc2_hsotg_core_disconnect(hsotg); ++ if (!dwc2_ovr_bvalid(hsotg, false)) ++ /* This set DCTL.SFTDISCON bit */ ++ dwc2_hsotg_core_disconnect(hsotg); + } else { + dwc2_ovr_avalid(hsotg, false); + } + } + -+unlock: + spin_unlock_irqrestore(&hsotg->lock, flags); + ++ if (!already && hsotg->dr_mode == USB_DR_MODE_OTG) ++ /* This will raise a Connector ID Status Change Interrupt */ ++ dwc2_force_mode(hsotg, role == USB_ROLE_HOST); ++ ++ if (!hsotg->ll_hw_enabled && hsotg->clk) ++ clk_disable_unprepare(hsotg->clk); ++ + dev_dbg(hsotg->dev, "%s-session valid\n", + role == USB_ROLE_NONE ? "No" : + role == USB_ROLE_HOST ? "A" : "B"); @@ -1352,7 +1590,7 @@ index 000000000..8de90d7b2 + usb_role_switch_unregister(hsotg->role_sw); +} diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c -index 7fd0900a9..f1e8323c0 100644 +index f7528f732b2aa..8e448e8b1fe4b 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3531,7 +3531,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, @@ -1374,7 +1612,7 @@ index 7fd0900a9..f1e8323c0 100644 } /** -@@ -4930,7 +4931,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) +@@ -4924,7 +4925,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) hsotg->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock_irqrestore(&hsotg->lock, flags); @@ -1384,7 +1622,7 @@ index 7fd0900a9..f1e8323c0 100644 dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); if (hsotg->eps_out[ep]) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c -index 81afe553a..f89e6d003 100644 +index 81afe553aa666..f89e6d003ec8b 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -1735,7 +1735,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) @@ -1408,7 +1646,7 @@ index 81afe553a..f89e6d003 100644 * The port is disconnected, which means the core is * either in device mode or it soon will be. Just diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h -index 510e87ec0..c4027bbce 100644 +index 510e87ec0be84..c4027bbcedec4 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -54,6 +54,12 @@ @@ -1434,10 +1672,10 @@ index 510e87ec0..c4027bbce 100644 #define GUID HSOTG_REG(0x003c) #define GSNPSID HSOTG_REG(0x0040) diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c -index 31e090ac9..f7c947cdc 100644 +index 31e090ac9f1ec..b4cff8b079ec2 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c -@@ -163,6 +163,41 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) +@@ -163,6 +163,45 @@ static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg) p->host_perio_tx_fifo_size = 256; } @@ -1474,12 +1712,16 @@ index 31e090ac9..f7c947cdc 100644 + p->host_perio_tx_fifo_size = 256; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; + p->power_down = DWC2_POWER_DOWN_PARAM_NONE; ++ p->lpm = false; ++ p->lpm_clock_gating = false; ++ p->besl = false; ++ p->hird_threshold_en = false; +} + const struct of_device_id dwc2_of_match_table[] = { { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, -@@ -186,6 +221,10 @@ const struct of_device_id dwc2_of_match_table[] = { +@@ -186,6 +225,10 @@ const struct of_device_id dwc2_of_match_table[] = { { .compatible = "st,stm32f4x9-hsotg" }, { .compatible = "st,stm32f7-hsotg", .data = dwc2_set_stm32f7_hsotg_params }, @@ -1491,35 +1733,22 @@ index 31e090ac9..f7c947cdc 100644 }; MODULE_DEVICE_TABLE(of, dwc2_of_match_table); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index 3c6ce09a6..5691d8281 100644 +index 4e14c4f7fed7a..0acbf58020ea8 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -312,6 +312,11 @@ static int dwc2_driver_remove(struct platform_device *dev) if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); ++ dwc2_drd_exit(hsotg); ++ + if (hsotg->params.activate_stm_id_vb_detection) + regulator_disable(hsotg->usb33d); -+ -+ dwc2_drd_exit(hsotg); + if (hsotg->ll_hw_enabled) dwc2_lowlevel_hw_disable(hsotg); -@@ -445,8 +450,11 @@ static int dwc2_driver_probe(struct platform_device *dev) - * reset value form registers. - */ - retval = dwc2_core_reset(hsotg, false); -- if (retval) -+ if (retval) { -+ /* TEMPORARY WORKAROUND */ -+ retval = -EPROBE_DEFER; - goto error; -+ } - - /* Detect config values from hardware */ - retval = dwc2_get_hwparams(hsotg); -@@ -464,10 +472,40 @@ static int dwc2_driver_probe(struct platform_device *dev) +@@ -465,10 +470,40 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) goto error; @@ -1557,30 +1786,32 @@ index 3c6ce09a6..5691d8281 100644 retval = dwc2_gadget_init(hsotg); if (retval) - goto error; -+ goto error_init; ++ goto error_drd; hsotg->gadget_enabled = 1; } -@@ -493,7 +531,7 @@ static int dwc2_driver_probe(struct platform_device *dev) +@@ -494,7 +529,7 @@ static int dwc2_driver_probe(struct platform_device *dev) if (retval) { if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); - goto error; -+ goto error_init; ++ goto error_drd; } hsotg->hcd_enabled = 1; } -@@ -509,6 +547,9 @@ static int dwc2_driver_probe(struct platform_device *dev) - +@@ -521,6 +556,11 @@ static int dwc2_driver_probe(struct platform_device *dev) + #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ return 0; ++error_drd: ++ dwc2_drd_exit(hsotg); +error_init: + if (hsotg->params.activate_stm_id_vb_detection) + regulator_disable(hsotg->usb33d); error: dwc2_lowlevel_hw_disable(hsotg); return retval; -@@ -523,12 +564,61 @@ static int __maybe_unused dwc2_suspend(struct device *dev) +@@ -535,12 +575,61 @@ static int __maybe_unused dwc2_suspend(struct device *dev) if (is_device_mode) dwc2_hsotg_suspend(dwc2); @@ -1642,7 +1873,7 @@ index 3c6ce09a6..5691d8281 100644 return ret; } -@@ -537,6 +627,9 @@ static int __maybe_unused dwc2_resume(struct device *dev) +@@ -549,6 +638,9 @@ static int __maybe_unused dwc2_resume(struct device *dev) struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev); int ret = 0; @@ -1652,7 +1883,7 @@ index 3c6ce09a6..5691d8281 100644 if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) { ret = __dwc2_lowlevel_hw_enable(dwc2); if (ret) -@@ -544,6 +637,41 @@ static int __maybe_unused dwc2_resume(struct device *dev) +@@ -556,6 +648,41 @@ static int __maybe_unused dwc2_resume(struct device *dev) } dwc2->phy_off_for_suspend = false; @@ -1695,7 +1926,7 @@ index 3c6ce09a6..5691d8281 100644 ret = dwc2_hsotg_resume(dwc2); diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c -index 9fc98de83..780059373 100644 +index 9fc98de836249..7800593735659 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -723,6 +723,20 @@ static void acm_free_func(struct usb_function *f) @@ -1729,7 +1960,7 @@ index 9fc98de83..780059373 100644 return &acm->port.func; } diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c -index c860f30a0..b2fb6b742 100644 +index c860f30a0ea2b..b2fb6b7424e98 100644 --- a/drivers/usb/gadget/function/f_serial.c +++ b/drivers/usb/gadget/function/f_serial.c @@ -327,6 +327,20 @@ static void gser_unbind(struct usb_configuration *c, struct usb_function *f) @@ -1763,7 +1994,7 @@ index c860f30a0..b2fb6b742 100644 return &gser->port.func; } diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c -index 038c445a4..3c144621a 100644 +index 038c445a4e9b5..3c144621ad935 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -119,6 +119,8 @@ struct gs_port { @@ -1857,7 +2088,7 @@ index 038c445a4..3c144621a 100644 { unsigned i; diff --git a/drivers/usb/gadget/function/u_serial.h b/drivers/usb/gadget/function/u_serial.h -index 9acaac1cb..223a4be05 100644 +index 9acaac1cbb75a..223a4be05afe7 100644 --- a/drivers/usb/gadget/function/u_serial.h +++ b/drivers/usb/gadget/function/u_serial.h @@ -60,6 +60,8 @@ void gserial_free_line(unsigned char port_line); @@ -1870,10 +2101,10 @@ index 9acaac1cb..223a4be05 100644 /* functions are bound to configurations by a config or gadget driver */ int gser_bind_config(struct usb_configuration *c, u8 port_num); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c -index 769749ca5..a356b227e 100644 +index e4fc3f66d43bf..db436d432e723 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c -@@ -33,6 +33,7 @@ +@@ -35,6 +35,7 @@ #include #include #include @@ -1881,7 +2112,7 @@ index 769749ca5..a356b227e 100644 #include "ehci.h" -@@ -307,6 +308,9 @@ static int ehci_platform_suspend(struct device *dev) +@@ -430,6 +431,9 @@ static int ehci_platform_suspend(struct device *dev) if (pdata->power_suspend) pdata->power_suspend(pdev); @@ -1891,7 +2122,7 @@ index 769749ca5..a356b227e 100644 return ret; } -@@ -318,6 +322,9 @@ static int ehci_platform_resume(struct device *dev) +@@ -441,6 +445,9 @@ static int ehci_platform_resume(struct device *dev) struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); struct device *companion_dev; @@ -1902,7 +2133,7 @@ index 769749ca5..a356b227e 100644 int err = pdata->power_on(pdev); if (err < 0) diff --git a/drivers/usb/renesas_usbhs/rcar2.c b/drivers/usb/renesas_usbhs/rcar2.c -index 440d213e1..791908f8c 100644 +index 440d213e1749d..791908f8cf73e 100644 --- a/drivers/usb/renesas_usbhs/rcar2.c +++ b/drivers/usb/renesas_usbhs/rcar2.c @@ -34,7 +34,7 @@ static int usbhs_rcar2_hardware_exit(struct platform_device *pdev) @@ -1915,7 +2146,7 @@ index 440d213e1..791908f8c 100644 } diff --git a/drivers/usb/renesas_usbhs/rza2.c b/drivers/usb/renesas_usbhs/rza2.c -index 021749594..3eed3334a 100644 +index 021749594389e..3eed3334a17f1 100644 --- a/drivers/usb/renesas_usbhs/rza2.c +++ b/drivers/usb/renesas_usbhs/rza2.c @@ -29,7 +29,7 @@ static int usbhs_rza2_hardware_exit(struct platform_device *pdev) @@ -1928,7 +2159,7 @@ index 021749594..3eed3334a 100644 return 0; diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig -index 895e2418d..3a1ee89be 100644 +index 895e2418de53b..3a1ee89be74e4 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -61,6 +61,15 @@ config TYPEC_TPS6598X @@ -1948,7 +2179,7 @@ index 895e2418d..3a1ee89be 100644 source "drivers/usb/typec/altmodes/Kconfig" diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile -index 6696b7263..c9136020e 100644 +index 6696b7263d61a..c9136020e4f3e 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -5,4 +5,5 @@ obj-$(CONFIG_TYPEC) += altmodes/ @@ -1958,7 +2189,7 @@ index 6696b7263..c9136020e 100644 +obj-$(CONFIG_TYPEC_STUSB) += typec_stusb.o obj-$(CONFIG_TYPEC) += mux/ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c -index a400b65cf..6391d0101 100644 +index a400b65cf17bb..6391d01015d17 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -1387,6 +1387,21 @@ void typec_set_pwr_opmode(struct typec_port *port, @@ -1985,7 +2216,7 @@ index a400b65cf..6391d0101 100644 * @name: port power capability string diff --git a/drivers/usb/typec/typec_stusb.c b/drivers/usb/typec/typec_stusb.c new file mode 100644 -index 000000000..e760ba304 +index 0000000000000..e760ba304f854 --- /dev/null +++ b/drivers/usb/typec/typec_stusb.c @@ -0,0 +1,910 @@ @@ -2900,7 +3131,7 @@ index 000000000..e760ba304 +MODULE_DESCRIPTION("STMicroelectronics STUSB Type-C controller driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h -index 15032f145..99ec370a6 100644 +index 15032f1450631..99ec370a6ff50 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h @@ -233,7 +233,8 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np, @@ -2927,7 +3158,7 @@ index 15032f145..99ec370a6 100644 } diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h -index 7df4ecabc..2671776a1 100644 +index 7df4ecabc78a2..2671776a1f8ea 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -241,6 +241,7 @@ int typec_set_orientation(struct typec_port *port, diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0017-ARM-stm32mp1-r2-PINCTRL-REGULATOR-SPI-PWM.patch similarity index 87% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0017-ARM-stm32mp1-r2-PINCTRL-REGULATOR-SPI-PWM.patch index e02a3b6..d51755d 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0017-ARM-stm32mp1-r2-PINCTRL-REGULATOR-SPI-PWM.patch @@ -1,22 +1,80 @@ -From 479f8a903c863085c2bc680c71ae0f7fea166aa8 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:47:29 +0200 -Subject: [PATCH 17/23] ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM +From a3294658232852248461b79c8c0a532956974568 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:51 +0200 +Subject: [PATCH 17/22] ARM-stm32mp1-r2-rc8-PINCTRL-REGULATOR-SPI-PWM --- - drivers/pinctrl/pinctrl-stmfx.c | 36 +- - drivers/pinctrl/stm32/pinctrl-stm32.c | 250 +++++++--- - drivers/pinctrl/stm32/pinctrl-stm32.h | 17 +- - drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1 + - drivers/pwm/pwm-stm32.c | 116 +++-- - drivers/regulator/stm32-pwr.c | 85 +++- - drivers/regulator/stpmic1_regulator.c | 203 +++++++- - drivers/spi/spi-stm32-qspi.c | 127 ++++- - drivers/spi/spi-stm32.c | 511 +++++++++++++-------- - 9 files changed, 990 insertions(+), 356 deletions(-) + .../bindings/pinctrl/st,stm32-pinctrl.yaml | 8 + + .../devicetree/bindings/pwm/pwm-stm32.txt | 8 +- + drivers/pinctrl/pinctrl-stmfx.c | 36 +- + drivers/pinctrl/stm32/pinctrl-stm32.c | 268 +++++++--- + drivers/pinctrl/stm32/pinctrl-stm32.h | 17 +- + drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1 + + drivers/pwm/pwm-stm32.c | 116 ++-- + drivers/regulator/stm32-pwr.c | 85 ++- + drivers/regulator/stpmic1_regulator.c | 203 ++++++- + drivers/spi/spi-stm32-qspi.c | 155 ++++-- + drivers/spi/spi-stm32.c | 495 ++++++++++-------- + include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + + 12 files changed, 1019 insertions(+), 374 deletions(-) +diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +index 400df2da018a3..4e24a8e863475 100644 +--- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml ++++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +@@ -144,9 +144,13 @@ patternProperties: + * ... + * 16 : Alternate Function 15 + * 17 : Analog ++ * 18 : Reserved + To simplify the usage, macro is available to generate "pinmux" field. + This macro is available here: + - include/dt-bindings/pinctrl/stm32-pinfunc.h ++ Setting the pinmux's function to the Reserved (RSVD) value is used to inform ++ the driver that it shall not apply the mux setting. This can be used to ++ reserve some pins, for example to a co-processor not running Linux. + Some examples of using macro: + /* GPIO A9 set as alernate function 2 */ + ... { +@@ -160,6 +164,10 @@ patternProperties: + ... { + pinmux = ; + }; ++ /* GPIO A9 reserved for co-processor */ ++ ... { ++ pinmux = ; ++ }; + + bias-disable: + type: boolean +diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt +index a8690bfa5e1fa..f1620c1feebfc 100644 +--- a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt ++++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt +@@ -5,8 +5,9 @@ See ../mfd/stm32-timers.txt for details about the parent node. + + Required parameters: + - compatible: Must be "st,stm32-pwm". +-- pinctrl-names: Set to "default". +-- pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module. ++- pinctrl-names: Set to "default". An additional "sleep" state can be ++ defined to set pins in sleep state when in low power. ++- pinctrl-n: List of phandles pointing to pin configuration nodes for PWM module. + For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt + - #pwm-cells: Should be set to 3. This PWM chip uses the default 3 cells + bindings defined in pwm.txt. +@@ -32,7 +33,8 @@ Example: + compatible = "st,stm32-pwm"; + #pwm-cells = <3>; + pinctrl-0 = <&pwm1_pins>; +- pinctrl-names = "default"; ++ pinctrl-1 = <&pwm1_sleep_pins>; ++ pinctrl-names = "default", "sleep"; + st,breakinput = <0 1 5>; + }; + }; diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c -index ccdf0bb21..f7958eece 100644 +index ccdf0bb214149..f7958eece5e0e 100644 --- a/drivers/pinctrl/pinctrl-stmfx.c +++ b/drivers/pinctrl/pinctrl-stmfx.c @@ -277,7 +277,7 @@ static int stmfx_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, @@ -84,7 +142,7 @@ index ccdf0bb21..f7958eece 100644 ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip, 0, handle_bad_irq, IRQ_TYPE_NONE); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c -index 2d5e0435a..1d52cbeab 100644 +index 2d5e0435af0a4..ef3b081d27983 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32.c @@ -64,7 +64,7 @@ @@ -448,7 +506,7 @@ index 2d5e0435a..1d52cbeab 100644 if (ret < 0) return ret; -@@ -1070,10 +1141,36 @@ static int stm32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, +@@ -1070,10 +1141,51 @@ static int stm32_pconf_group_set(struct pinctrl_dev *pctldev, unsigned group, return 0; } @@ -475,6 +533,21 @@ index 2d5e0435a..1d52cbeab 100644 + + return 0; +} ++ ++static struct stm32_desc_pin * ++stm32_pconf_get_pin_desc_by_pin_number(struct stm32_pinctrl *pctl, ++ unsigned int pin_number) ++{ ++ struct stm32_desc_pin *pins = pctl->pins; ++ int i; ++ ++ for (i = 0; i < pctl->npins; i++) { ++ if (pins->pin.number == pin_number) ++ return pins; ++ pins++; ++ } ++ return NULL; ++} + static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, @@ -485,18 +558,21 @@ index 2d5e0435a..1d52cbeab 100644 struct pinctrl_gpio_range *range; struct stm32_gpio_bank *bank; int offset; -@@ -1123,7 +1220,9 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, +@@ -1123,7 +1235,12 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, case 2: drive = stm32_pconf_get_driving(bank, offset); speed = stm32_pconf_get_speed(bank, offset); - seq_printf(s, "%d - %s - %s - %s %s", alt, -+ pin_desc = pctl->pins + (pin - pctl->pin_base_shift); ++ pin_desc = stm32_pconf_get_pin_desc_by_pin_number(pctl, pin); ++ if (!pin_desc) ++ return; ++ + seq_printf(s, "%d (%s) - %s - %s - %s %s", alt, + pin_desc->functions[alt + 1].name, drive ? "open drain" : "push pull", biasing[bias], speeds[speed], "speed"); -@@ -1140,6 +1239,7 @@ static const struct pinconf_ops stm32_pconf_ops = { +@@ -1140,6 +1257,7 @@ static const struct pinconf_ops stm32_pconf_ops = { .pin_config_group_get = stm32_pconf_group_get, .pin_config_group_set = stm32_pconf_group_set, .pin_config_dbg_show = stm32_pconf_dbg_show, @@ -504,7 +580,7 @@ index 2d5e0435a..1d52cbeab 100644 }; static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, -@@ -1151,13 +1251,11 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, +@@ -1151,13 +1269,11 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct of_phandle_args args; struct device *dev = pctl->dev; struct resource res; @@ -520,7 +596,7 @@ index 2d5e0435a..1d52cbeab 100644 if (of_address_to_resource(np, 0, &res)) return -ENODEV; -@@ -1166,12 +1264,6 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, +@@ -1166,12 +1282,6 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, if (IS_ERR(bank->base)) return PTR_ERR(bank->base); @@ -533,7 +609,7 @@ index 2d5e0435a..1d52cbeab 100644 err = clk_prepare(bank->clk); if (err) { dev_err(dev, "failed to prepare clk (%d)\n", err); -@@ -1335,7 +1427,8 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, +@@ -1335,7 +1445,8 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, if (pctl->pkg && !(pctl->pkg & p->pkg)) continue; pins->pin = p->pin; @@ -543,7 +619,7 @@ index 2d5e0435a..1d52cbeab 100644 pins++; nb_pins_available++; } -@@ -1444,6 +1537,7 @@ int stm32_pctl_probe(struct platform_device *pdev) +@@ -1444,6 +1555,7 @@ int stm32_pctl_probe(struct platform_device *pdev) pctl->pctl_desc.pctlops = &stm32_pctrl_ops; pctl->pctl_desc.pmxops = &stm32_pmx_ops; pctl->dev = &pdev->dev; @@ -551,7 +627,7 @@ index 2d5e0435a..1d52cbeab 100644 pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, pctl); -@@ -1466,6 +1560,28 @@ int stm32_pctl_probe(struct platform_device *pdev) +@@ -1466,6 +1578,28 @@ int stm32_pctl_probe(struct platform_device *pdev) if (!pctl->banks) return -ENOMEM; @@ -581,7 +657,7 @@ index 2d5e0435a..1d52cbeab 100644 if (of_property_read_bool(child, "gpio-controller")) { ret = stm32_gpiolib_register_bank(pctl, child); diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h -index ec0d34c33..b11a223f3 100644 +index ec0d34c339031..b11a223f3504c 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32.h +++ b/drivers/pinctrl/stm32/pinctrl-stm32.h @@ -17,6 +17,8 @@ @@ -644,7 +720,7 @@ index ec0d34c33..b11a223f3 100644 struct stm32_gpio_bank; diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -index 2ccb99d64..86fe6d5ac 100644 +index 2ccb99d64df83..86fe6d5ac54d6 100644 --- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c +++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c @@ -2328,6 +2328,7 @@ static struct stm32_pinctrl_match_data stm32mp157_match_data = { @@ -656,7 +732,7 @@ index 2ccb99d64..86fe6d5ac 100644 static const struct of_device_id stm32mp157_pctrl_match[] = { diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c -index 359b08596..d3be944f2 100644 +index 359b08596d9e3..d3be944f2ae96 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -12,6 +12,7 @@ @@ -861,7 +937,7 @@ index 359b08596..d3be944f2 100644 }; module_platform_driver(stm32_pwm_driver); diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c -index e0e627b01..373d83797 100644 +index e0e627b0106e0..373d83797ea86 100644 --- a/drivers/regulator/stm32-pwr.c +++ b/drivers/regulator/stm32-pwr.c @@ -3,12 +3,15 @@ @@ -1021,7 +1097,7 @@ index e0e627b01..373d83797 100644 priv->ready_mask = ready_mask_table[i]; config.driver_data = priv; diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c -index f09061473..4537e3ab1 100644 +index f09061473613c..4537e3ab143ca 100644 --- a/drivers/regulator/stpmic1_regulator.c +++ b/drivers/regulator/stpmic1_regulator.c @@ -2,7 +2,9 @@ @@ -1339,7 +1415,7 @@ index f09061473..4537e3ab1 100644 dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c -index 4e726929b..02f110b10 100644 +index 4e726929bb4f5..77c1da13a3f05 100644 --- a/drivers/spi/spi-stm32-qspi.c +++ b/drivers/spi/spi-stm32-qspi.c @@ -16,6 +16,7 @@ @@ -1458,22 +1534,23 @@ index 4e726929b..02f110b10 100644 } static void stm32_qspi_dma_free(struct stm32_qspi *qspi) -@@ -524,9 +556,14 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { - static void stm32_qspi_release(struct stm32_qspi *qspi) - { - /* disable qspi */ -+ pm_runtime_get_sync(qspi->dev); - writel_relaxed(0, qspi->io_base + QSPI_CR); - stm32_qspi_dma_free(qspi); - mutex_destroy(&qspi->lock); -+ pm_runtime_put_noidle(qspi->dev); -+ pm_runtime_disable(qspi->dev); -+ pm_runtime_set_suspended(qspi->dev); -+ pm_runtime_dont_use_autosuspend(qspi->dev); - clk_disable_unprepare(qspi->clk); - } +@@ -521,15 +553,6 @@ static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { + .exec_op = stm32_qspi_exec_op, + }; -@@ -550,7 +587,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) +-static void stm32_qspi_release(struct stm32_qspi *qspi) +-{ +- /* disable qspi */ +- writel_relaxed(0, qspi->io_base + QSPI_CR); +- stm32_qspi_dma_free(qspi); +- mutex_destroy(&qspi->lock); +- clk_disable_unprepare(qspi->clk); +-} +- + static int stm32_qspi_probe(struct platform_device *pdev) + { + struct device *dev = &pdev->dev; +@@ -550,7 +573,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->io_base = devm_ioremap_resource(dev, res); if (IS_ERR(qspi->io_base)) { ret = PTR_ERR(qspi->io_base); @@ -1482,7 +1559,7 @@ index 4e726929b..02f110b10 100644 } qspi->phys_base = res->start; -@@ -559,24 +596,26 @@ static int stm32_qspi_probe(struct platform_device *pdev) +@@ -559,24 +582,26 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->mm_base = devm_ioremap_resource(dev, res); if (IS_ERR(qspi->mm_base)) { ret = PTR_ERR(qspi->mm_base); @@ -1514,7 +1591,7 @@ index 4e726929b..02f110b10 100644 } init_completion(&qspi->data_completion); -@@ -584,23 +623,27 @@ static int stm32_qspi_probe(struct platform_device *pdev) +@@ -584,23 +609,27 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->clk = devm_clk_get(dev, NULL); if (IS_ERR(qspi->clk)) { ret = PTR_ERR(qspi->clk); @@ -1541,24 +1618,24 @@ index 4e726929b..02f110b10 100644 + if (IS_ERR(rstc)) { + ret = PTR_ERR(rstc); + if (ret == -EPROBE_DEFER) -+ goto err_qspi_release; ++ goto err_clk_disable; + } else { reset_control_assert(rstc); udelay(2); reset_control_deassert(rstc); -@@ -608,7 +651,10 @@ static int stm32_qspi_probe(struct platform_device *pdev) +@@ -608,7 +637,10 @@ static int stm32_qspi_probe(struct platform_device *pdev) qspi->dev = dev; platform_set_drvdata(pdev, qspi); - stm32_qspi_dma_setup(qspi); + ret = stm32_qspi_dma_setup(qspi); + if (ret) -+ goto err_qspi_release; ++ goto err_dma_free; + mutex_init(&qspi->lock); ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD -@@ -619,12 +665,24 @@ static int stm32_qspi_probe(struct platform_device *pdev) +@@ -619,12 +651,35 @@ static int stm32_qspi_probe(struct platform_device *pdev) ctrl->num_chipselect = STM32_QSPI_MAX_NORCHIP; ctrl->dev.of_node = dev->of_node; @@ -1572,7 +1649,7 @@ index 4e726929b..02f110b10 100644 - if (!ret) - return 0; + if (ret) -+ goto err_qspi_release; ++ goto err_pm_runtime_free; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); @@ -1580,16 +1657,39 @@ index 4e726929b..02f110b10 100644 + return 0; -err: -+err_qspi_release: - stm32_qspi_release(qspi); +- stm32_qspi_release(qspi); ++err_pm_runtime_free: ++ pm_runtime_get_sync(qspi->dev); ++ /* disable qspi */ ++ writel_relaxed(0, qspi->io_base + QSPI_CR); ++ mutex_destroy(&qspi->lock); ++ pm_runtime_put_noidle(qspi->dev); ++ pm_runtime_disable(qspi->dev); ++ pm_runtime_set_suspended(qspi->dev); ++ pm_runtime_dont_use_autosuspend(qspi->dev); ++err_dma_free: ++ stm32_qspi_dma_free(qspi); ++err_clk_disable: ++ clk_disable_unprepare(qspi->clk); +err_master_put: spi_master_put(qspi->ctrl); return ret; -@@ -635,14 +693,28 @@ static int stm32_qspi_remove(struct platform_device *pdev) +@@ -634,15 +689,38 @@ static int stm32_qspi_remove(struct platform_device *pdev) + { struct stm32_qspi *qspi = platform_get_drvdata(pdev); - stm32_qspi_release(qspi); +- stm32_qspi_release(qspi); ++ pm_runtime_get_sync(qspi->dev); ++ /* disable qspi */ ++ writel_relaxed(0, qspi->io_base + QSPI_CR); ++ stm32_qspi_dma_free(qspi); ++ mutex_destroy(&qspi->lock); ++ pm_runtime_put_noidle(qspi->dev); ++ pm_runtime_disable(qspi->dev); ++ pm_runtime_set_suspended(qspi->dev); ++ pm_runtime_dont_use_autosuspend(qspi->dev); ++ clk_disable_unprepare(qspi->clk); + return 0; } @@ -1616,7 +1716,7 @@ index 4e726929b..02f110b10 100644 pinctrl_pm_select_sleep_state(dev); return 0; -@@ -651,17 +723,28 @@ static int __maybe_unused stm32_qspi_suspend(struct device *dev) +@@ -651,17 +729,28 @@ static int __maybe_unused stm32_qspi_suspend(struct device *dev) static int __maybe_unused stm32_qspi_resume(struct device *dev) { struct stm32_qspi *qspi = dev_get_drvdata(dev); @@ -1648,7 +1748,7 @@ index 4e726929b..02f110b10 100644 static const struct of_device_id stm32_qspi_match[] = { {.compatible = "st,stm32f469-qspi"}, diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c -index b222ce8d0..df98a6925 100644 +index b222ce8d083ef..feed9206323be 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -5,6 +5,7 @@ @@ -1677,15 +1777,13 @@ index b222ce8d0..df98a6925 100644 #define STM32F4_SPI_CR1_SPE BIT(6) #define STM32F4_SPI_CR1_LSBFRST BIT(7) #define STM32F4_SPI_CR1_SSI BIT(8) -@@ -94,27 +96,24 @@ +@@ -94,27 +96,22 @@ #define STM32H7_SPI_CR1_SSI BIT(12) /* STM32H7_SPI_CR2 bit fields */ -#define STM32H7_SPI_CR2_TSIZE_SHIFT 0 #define STM32H7_SPI_CR2_TSIZE GENMASK(15, 0) -+#define STM32H7_SPI_CR2_TSER GENMASK(31, 16) +#define STM32H7_SPI_TSIZE_MAX GENMASK(15, 0) -+#define STM32H7_SPI_TSER_MAX (GENMASK(31, 16) >> 16) /* STM32H7_SPI_CFG1 bit fields */ -#define STM32H7_SPI_CFG1_DSIZE_SHIFT 0 @@ -1709,27 +1807,19 @@ index b222ce8d0..df98a6925 100644 #define STM32H7_SPI_CFG2_SP GENMASK(21, 19) #define STM32H7_SPI_CFG2_MASTER BIT(22) #define STM32H7_SPI_CFG2_LSBFRST BIT(23) -@@ -131,16 +130,18 @@ - #define STM32H7_SPI_IER_TXTFIE BIT(4) - #define STM32H7_SPI_IER_OVRIE BIT(6) - #define STM32H7_SPI_IER_MODFIE BIT(9) -+#define STM32H7_SPI_IER_TSERFIE BIT(10) - #define STM32H7_SPI_IER_ALL GENMASK(10, 0) - - /* STM32H7_SPI_SR bit fields */ +@@ -137,10 +134,10 @@ #define STM32H7_SPI_SR_RXP BIT(0) #define STM32H7_SPI_SR_TXP BIT(1) #define STM32H7_SPI_SR_EOT BIT(3) +#define STM32H7_SPI_SR_TXTF BIT(4) #define STM32H7_SPI_SR_OVR BIT(6) #define STM32H7_SPI_SR_MODF BIT(9) -+#define STM32H7_SPI_SR_TSERF BIT(10) #define STM32H7_SPI_SR_SUSP BIT(11) -#define STM32H7_SPI_SR_RXPLVL_SHIFT 13 #define STM32H7_SPI_SR_RXPLVL GENMASK(14, 13) #define STM32H7_SPI_SR_RXWNE BIT(15) -@@ -167,8 +168,6 @@ +@@ -167,8 +164,6 @@ #define SPI_3WIRE_TX 3 #define SPI_3WIRE_RX 4 @@ -1738,7 +1828,7 @@ index b222ce8d0..df98a6925 100644 /* * use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers * without fifo buffers. -@@ -249,7 +248,7 @@ struct stm32_spi_cfg { +@@ -249,7 +244,7 @@ struct stm32_spi_cfg { int (*set_mode)(struct stm32_spi *spi, unsigned int comm_type); void (*set_data_idleness)(struct stm32_spi *spi, u32 length); int (*set_number_of_data)(struct stm32_spi *spi, u32 length); @@ -1747,7 +1837,7 @@ index b222ce8d0..df98a6925 100644 void (*dma_rx_cb)(void *data); void (*dma_tx_cb)(void *data); int (*transfer_one_irq)(struct stm32_spi *spi); -@@ -268,7 +267,6 @@ struct stm32_spi_cfg { +@@ -268,7 +263,6 @@ struct stm32_spi_cfg { * @base: virtual memory area * @clk: hw kernel clock feeding the SPI clock generator * @clk_rate: rate of the hw kernel clock feeding the SPI clock generator @@ -1755,15 +1845,7 @@ index b222ce8d0..df98a6925 100644 * @lock: prevent I/O concurrent access * @irq: SPI controller interrupt line * @fifo_size: size of the embedded fifo in bytes -@@ -278,6 +276,7 @@ struct stm32_spi_cfg { - * @cur_fthlv: fifo threshold level (data frames in a single data packet) - * @cur_comm: SPI communication mode - * @cur_xferlen: current transfer length in bytes -+ * @cur_reload: current transfer remaining bytes to be loaded - * @cur_usedma: boolean to know if dma is used in current transfer - * @tx_buf: data to be written, or NULL - * @rx_buf: data to be read, or NULL -@@ -294,7 +293,6 @@ struct stm32_spi { +@@ -294,7 +288,6 @@ struct stm32_spi { void __iomem *base; struct clk *clk; u32 clk_rate; @@ -1771,15 +1853,7 @@ index b222ce8d0..df98a6925 100644 spinlock_t lock; /* prevent I/O concurrent access */ int irq; unsigned int fifo_size; -@@ -305,6 +303,7 @@ struct stm32_spi { - unsigned int cur_fthlv; - unsigned int cur_comm; - unsigned int cur_xferlen; -+ unsigned int cur_reload; - bool cur_usedma; - - const void *tx_buf; -@@ -313,7 +312,10 @@ struct stm32_spi { +@@ -313,7 +306,10 @@ struct stm32_spi { int rx_len; struct dma_chan *dma_tx; struct dma_chan *dma_rx; @@ -1790,7 +1864,7 @@ index b222ce8d0..df98a6925 100644 }; static const struct stm32_spi_regspec stm32f4_spi_regspec = { -@@ -417,9 +419,7 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi) +@@ -417,9 +413,7 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi) stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_DSIZE); cfg1 = readl_relaxed(spi->base + STM32H7_SPI_CFG1); @@ -1801,7 +1875,7 @@ index b222ce8d0..df98a6925 100644 spin_unlock_irqrestore(&spi->lock, flags); -@@ -442,7 +442,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, +@@ -442,7 +436,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, { u32 div, mbrdiv; @@ -1811,7 +1885,7 @@ index b222ce8d0..df98a6925 100644 /* * SPI framework set xfer->speed_hz to master->max_speed_hz if -@@ -469,19 +470,22 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, +@@ -469,19 +464,22 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, * stm32h7_spi_prepare_fthlv - Determine FIFO threshold level * @spi: pointer to the spi controller data structure */ @@ -1839,7 +1913,7 @@ index b222ce8d0..df98a6925 100644 /* align packet size with data registers access */ if (spi->cur_bpw > 8) -@@ -489,9 +493,29 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) +@@ -489,6 +487,9 @@ static u32 stm32h7_spi_prepare_fthlv(struct stm32_spi *spi) else fthlv -= (fthlv % 4); /* multiple of 4 */ @@ -1849,27 +1923,7 @@ index b222ce8d0..df98a6925 100644 return fthlv; } -+static void stm32h7_spi_transfer_extension(struct stm32_spi *spi) -+{ -+ if (spi->cur_reload > 0) { -+ u32 cr2 = readl_relaxed(spi->base + STM32H7_SPI_CR2); -+ u32 tsize = FIELD_GET(STM32H7_SPI_CR2_TSIZE, cr2); -+ u32 tser = STM32H7_SPI_TSER_MAX; -+ -+ tser -= (STM32H7_SPI_TSER_MAX % spi->cur_fthlv); -+ tser = min(spi->cur_reload, tser); -+ -+ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSER, tser) | -+ FIELD_PREP(STM32H7_SPI_CR2_TSIZE, tsize), -+ spi->base + STM32H7_SPI_CR2); -+ spi->cur_reload -= tser; -+ } -+} -+ - /** - * stm32f4_spi_write_tx - Write bytes to Transmit Data Register - * @spi: pointer to the spi controller data structure -@@ -592,25 +616,26 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) +@@ -592,25 +593,26 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) * Write in rx_buf depends on remaining bytes to avoid to write beyond * rx_buf end. */ @@ -1902,7 +1956,7 @@ index b222ce8d0..df98a6925 100644 u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); *rx_buf16 = readw_relaxed(spi->base + STM32H7_SPI_RXDR); -@@ -623,12 +648,11 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) +@@ -623,12 +625,11 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) } sr = readl_relaxed(spi->base + STM32H7_SPI_SR); @@ -1918,7 +1972,7 @@ index b222ce8d0..df98a6925 100644 } /** -@@ -696,12 +720,7 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) +@@ -696,12 +697,7 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) * @spi: pointer to the spi controller data structure * * RX-Fifo is flushed when SPI controller is disabled. To prevent any data @@ -1932,7 +1986,7 @@ index b222ce8d0..df98a6925 100644 */ static void stm32h7_spi_disable(struct stm32_spi *spi) { -@@ -736,7 +755,7 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) +@@ -736,7 +732,7 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) } if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) @@ -1941,7 +1995,7 @@ index b222ce8d0..df98a6925 100644 if (spi->cur_usedma && spi->dma_tx) dmaengine_terminate_all(spi->dma_tx); -@@ -891,7 +910,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) +@@ -891,7 +887,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) { struct spi_master *master = dev_id; struct stm32_spi *spi = spi_master_get_devdata(master); @@ -1950,7 +2004,7 @@ index b222ce8d0..df98a6925 100644 unsigned long flags; bool end = false; -@@ -899,77 +918,82 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) +@@ -899,77 +895,77 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) sr = readl_relaxed(spi->base + STM32H7_SPI_SR); ier = readl_relaxed(spi->base + STM32H7_SPI_IER); @@ -1989,11 +2043,6 @@ index b222ce8d0..df98a6925 100644 - if (sr & STM32H7_SPI_SR_SUSP) { - dev_warn(spi->dev, "Communication suspended\n"); -+ if (mask & STM32H7_SPI_SR_TSERF) { -+ stm32h7_spi_transfer_extension(spi); -+ ifcr |= STM32H7_SPI_SR_TSERF; -+ } -+ + if (mask & STM32H7_SPI_SR_SUSP) { + dev_warn_once(spi->dev, + "System too slow is limiting data throughput\n"); @@ -2075,7 +2124,42 @@ index b222ce8d0..df98a6925 100644 return IRQ_HANDLED; } -@@ -1079,25 +1103,18 @@ static void stm32f4_spi_dma_rx_cb(void *data) +@@ -980,11 +976,8 @@ static int stm32_spi_setup(struct spi_device *spi_dev) + { + int ret = 0; + +- if (!gpio_is_valid(spi_dev->cs_gpio)) { +- dev_err(&spi_dev->dev, "%d is not a valid gpio\n", +- spi_dev->cs_gpio); +- return -EINVAL; +- } ++ if (!gpio_is_valid(spi_dev->cs_gpio)) ++ return 0; + + dev_dbg(&spi_dev->dev, "%s: set gpio%d output %s\n", __func__, + spi_dev->cs_gpio, +@@ -1034,6 +1027,20 @@ static int stm32_spi_prepare_msg(struct spi_master *master, + spi_dev->mode & SPI_LSB_FIRST, + spi_dev->mode & SPI_CS_HIGH); + ++ /* On STM32H7, messages should not exceed a maximum size setted ++ * afterward via the set_number_of_data function. In order to ++ * ensure that, split large messages into several messages ++ */ ++ if (spi->cfg->set_number_of_data) { ++ int ret; ++ ++ ret = spi_split_transfers_maxsize(master, msg, ++ STM32H7_SPI_TSIZE_MAX, ++ GFP_KERNEL | GFP_DMA); ++ if (ret) ++ return ret; ++ } ++ + spin_lock_irqsave(&spi->lock, flags); + + /* CPOL, CPHA and LSB FIRST bits have common register */ +@@ -1079,25 +1086,18 @@ static void stm32f4_spi_dma_rx_cb(void *data) /** * stm32h7_spi_dma_cb - dma callback * @@ -2103,7 +2187,7 @@ index b222ce8d0..df98a6925 100644 } /** -@@ -1190,9 +1207,6 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) +@@ -1190,9 +1190,6 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) /** * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using * interrupts @@ -2113,18 +2197,16 @@ index b222ce8d0..df98a6925 100644 */ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) { -@@ -1209,7 +1223,9 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) +@@ -1209,7 +1206,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) /* Enable the interrupts relative to the end of transfer */ ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | - STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; + STM32H7_SPI_IER_OVRIE; -+ /* Enable the interrupt relative to transfer extension */ -+ ier |= STM32H7_SPI_IER_TSERFIE; spin_lock_irqsave(&spi->lock, flags); -@@ -1225,15 +1241,19 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) +@@ -1225,15 +1222,19 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) spin_unlock_irqrestore(&spi->lock, flags); @@ -2146,7 +2228,7 @@ index b222ce8d0..df98a6925 100644 /* In DMA mode end of transfer is handled by DMA TX or RX callback. */ if (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_3WIRE_RX || spi->cur_comm == SPI_FULL_DUPLEX) { -@@ -1246,40 +1266,58 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) +@@ -1246,40 +1247,56 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) } stm32_spi_enable(spi); @@ -2170,10 +2252,9 @@ index b222ce8d0..df98a6925 100644 /* Enable the interrupts relative to the end of transfer */ stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | - STM32H7_SPI_IER_OVRIE | +- STM32H7_SPI_IER_OVRIE | - STM32H7_SPI_IER_MODFIE); -+ /* transfer extension */ -+ STM32H7_SPI_IER_TSERFIE); ++ STM32H7_SPI_IER_OVRIE); stm32_spi_enable(spi); @@ -2210,7 +2291,7 @@ index b222ce8d0..df98a6925 100644 rx_dma_desc = NULL; if (spi->rx_buf && spi->dma_rx) { stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM); -@@ -1316,7 +1354,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, +@@ -1316,7 +1333,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, goto dma_desc_error; if (rx_dma_desc) { @@ -2219,7 +2300,7 @@ index b222ce8d0..df98a6925 100644 rx_dma_desc->callback_param = spi; if (dma_submit_error(dmaengine_submit(rx_dma_desc))) { -@@ -1330,7 +1368,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, +@@ -1330,7 +1347,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, if (tx_dma_desc) { if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) { @@ -2228,7 +2309,7 @@ index b222ce8d0..df98a6925 100644 tx_dma_desc->callback_param = spi; } -@@ -1345,12 +1383,9 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, +@@ -1345,12 +1362,9 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, stm32_spi_set_bits(spi, spi->cfg->regs->dma_tx_en.reg, spi->cfg->regs->dma_tx_en.mask); } @@ -2242,7 +2323,7 @@ index b222ce8d0..df98a6925 100644 dma_submit_error: if (spi->dma_rx) -@@ -1392,15 +1427,13 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi) +@@ -1392,15 +1406,13 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi) bpw = spi->cur_bpw - 1; cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; @@ -2261,7 +2342,7 @@ index b222ce8d0..df98a6925 100644 writel_relaxed( (readl_relaxed(spi->base + STM32H7_SPI_CFG1) & -@@ -1418,8 +1451,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) +@@ -1418,8 +1430,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) u32 clrb = 0, setb = 0; clrb |= spi->cfg->regs->br.mask; @@ -2271,7 +2352,7 @@ index b222ce8d0..df98a6925 100644 writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) & ~clrb) | setb, -@@ -1504,8 +1536,7 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) +@@ -1504,8 +1515,7 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) } cfg2_clrb |= STM32H7_SPI_CFG2_COMM; @@ -2281,7 +2362,7 @@ index b222ce8d0..df98a6925 100644 writel_relaxed( (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & -@@ -1527,15 +1558,15 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) +@@ -1527,15 +1537,15 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) cfg2_clrb |= STM32H7_SPI_CFG2_MIDI; if ((len > 1) && (spi->cur_midi > 0)) { @@ -2303,7 +2384,7 @@ index b222ce8d0..df98a6925 100644 } writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & -@@ -1550,19 +1581,23 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) +@@ -1550,14 +1560,8 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) */ static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) { @@ -2315,29 +2396,12 @@ index b222ce8d0..df98a6925 100644 - cr2_setb = nb_words << STM32H7_SPI_CR2_TSIZE_SHIFT; - writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CR2) & - ~cr2_clrb) | cr2_setb, -- spi->base + STM32H7_SPI_CR2); -+ u32 tsize; -+ + if (nb_words <= STM32H7_SPI_TSIZE_MAX) { -+ tsize = nb_words; -+ spi->cur_reload = 0; ++ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, nb_words), + spi->base + STM32H7_SPI_CR2); } else { -- return -EMSGSIZE; -+ tsize = STM32H7_SPI_TSIZE_MAX; -+ tsize -= (STM32H7_SPI_TSIZE_MAX % spi->cur_fthlv); -+ spi->cur_reload = nb_words - tsize; - } - -+ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, tsize), -+ spi->base + STM32H7_SPI_CR2); -+ -+ if (spi->cur_reload > 0) -+ stm32h7_spi_transfer_extension(spi); -+ - return 0; - } - -@@ -1578,39 +1613,33 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, + return -EMSGSIZE; +@@ -1578,39 +1582,33 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, unsigned long flags; unsigned int comm_type; int nb_words, ret = 0; @@ -2349,10 +2413,12 @@ index b222ce8d0..df98a6925 100644 - spi->cur_bpw = transfer->bits_per_word; - spi->cfg->set_bpw(spi); - } -- ++ spi->cur_xferlen = transfer->len; + - if (spi->cur_speed != transfer->speed_hz) { - int mbr; -+ spi->cur_xferlen = transfer->len; ++ spi->cur_bpw = transfer->bits_per_word; ++ spi->cfg->set_bpw(spi); - /* Update spi->cur_speed with real clock speed */ - mbr = stm32_spi_prepare_mbr(spi, transfer->speed_hz, @@ -2362,9 +2428,7 @@ index b222ce8d0..df98a6925 100644 - ret = mbr; - goto out; - } -+ spi->cur_bpw = transfer->bits_per_word; -+ spi->cfg->set_bpw(spi); - +- - transfer->speed_hz = spi->cur_speed; - stm32_spi_set_mbr(spi, mbr); + /* Update spi->cur_speed with real clock speed */ @@ -2395,7 +2459,7 @@ index b222ce8d0..df98a6925 100644 if (spi->cfg->set_data_idleness) spi->cfg->set_data_idleness(spi, transfer->len); -@@ -1628,8 +1657,6 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, +@@ -1628,8 +1626,6 @@ static int stm32_spi_transfer_one_setup(struct stm32_spi *spi, goto out; } @@ -2404,7 +2468,7 @@ index b222ce8d0..df98a6925 100644 dev_dbg(spi->dev, "transfer communication mode set to %d\n", spi->cur_comm); dev_dbg(spi->dev, -@@ -1658,6 +1685,8 @@ static int stm32_spi_transfer_one(struct spi_master *master, +@@ -1658,8 +1654,16 @@ static int stm32_spi_transfer_one(struct spi_master *master, struct spi_transfer *transfer) { struct stm32_spi *spi = spi_master_get_devdata(master); @@ -2412,8 +2476,16 @@ index b222ce8d0..df98a6925 100644 + unsigned long timeout; int ret; ++ /* Don't do anything on 0 bytes transfers */ ++ if (transfer->len == 0) { ++ spi->xfer_status = 0; ++ goto finalize; ++ } ++ spi->tx_buf = transfer->tx_buf; -@@ -1674,10 +1703,39 @@ static int stm32_spi_transfer_one(struct spi_master *master, + spi->rx_buf = transfer->rx_buf; + spi->tx_len = spi->tx_buf ? transfer->len : 0; +@@ -1674,10 +1678,40 @@ static int stm32_spi_transfer_one(struct spi_master *master, return ret; } @@ -2449,13 +2521,14 @@ index b222ce8d0..df98a6925 100644 + + spi->cfg->disable(spi); + ++finalize: + spi_finalize_current_transfer(master); + + return spi->xfer_status; } /** -@@ -1810,7 +1868,8 @@ static int stm32_spi_probe(struct platform_device *pdev) +@@ -1810,7 +1844,8 @@ static int stm32_spi_probe(struct platform_device *pdev) struct spi_master *master; struct stm32_spi *spi; struct resource *res; @@ -2465,7 +2538,7 @@ index b222ce8d0..df98a6925 100644 master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); if (!master) { -@@ -1823,6 +1882,8 @@ static int stm32_spi_probe(struct platform_device *pdev) +@@ -1823,6 +1858,8 @@ static int stm32_spi_probe(struct platform_device *pdev) spi->dev = &pdev->dev; spi->master = master; spin_lock_init(&spi->lock); @@ -2474,7 +2547,7 @@ index b222ce8d0..df98a6925 100644 spi->cfg = (const struct stm32_spi_cfg *) of_match_device(pdev->dev.driver->of_match_table, -@@ -1873,11 +1934,20 @@ static int stm32_spi_probe(struct platform_device *pdev) +@@ -1873,11 +1910,20 @@ static int stm32_spi_probe(struct platform_device *pdev) goto err_clk_disable; } @@ -2499,7 +2572,7 @@ index b222ce8d0..df98a6925 100644 } if (spi->cfg->has_fifo) -@@ -1903,17 +1973,29 @@ static int stm32_spi_probe(struct platform_device *pdev) +@@ -1903,17 +1949,29 @@ static int stm32_spi_probe(struct platform_device *pdev) master->transfer_one = stm32_spi_transfer_one; master->unprepare_message = stm32_spi_unprepare_msg; @@ -2539,7 +2612,7 @@ index b222ce8d0..df98a6925 100644 if (spi->dma_tx || spi->dma_rx) master->can_dma = stm32_spi_can_dma; -@@ -1921,36 +2003,33 @@ static int stm32_spi_probe(struct platform_device *pdev) +@@ -1921,36 +1979,33 @@ static int stm32_spi_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -2549,14 +2622,14 @@ index b222ce8d0..df98a6925 100644 - ret); - goto err_dma_release; - } -- ++ num_cs = of_gpio_named_count(pdev->dev.of_node, "cs-gpios"); + - if (!master->cs_gpios) { - dev_err(&pdev->dev, "no CS gpios available\n"); - ret = -EINVAL; - goto err_dma_release; - } -+ num_cs = of_gpio_named_count(pdev->dev.of_node, "cs-gpios"); - +- - for (i = 0; i < master->num_chipselect; i++) { - if (!gpio_is_valid(master->cs_gpios[i])) { - dev_err(&pdev->dev, "%i is not a valid gpio\n", @@ -2596,7 +2669,7 @@ index b222ce8d0..df98a6925 100644 dev_info(&pdev->dev, "driver initialized\n"); return 0; -@@ -1975,6 +2054,9 @@ static int stm32_spi_remove(struct platform_device *pdev) +@@ -1975,6 +2030,9 @@ static int stm32_spi_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct stm32_spi *spi = spi_master_get_devdata(master); @@ -2606,7 +2679,7 @@ index b222ce8d0..df98a6925 100644 spi->cfg->disable(spi); if (master->dma_tx) -@@ -1984,7 +2066,12 @@ static int stm32_spi_remove(struct platform_device *pdev) +@@ -1984,7 +2042,12 @@ static int stm32_spi_remove(struct platform_device *pdev) clk_disable_unprepare(spi->clk); @@ -2619,7 +2692,7 @@ index b222ce8d0..df98a6925 100644 return 0; } -@@ -1997,13 +2084,18 @@ static int stm32_spi_runtime_suspend(struct device *dev) +@@ -1997,13 +2060,18 @@ static int stm32_spi_runtime_suspend(struct device *dev) clk_disable_unprepare(spi->clk); @@ -2639,7 +2712,7 @@ index b222ce8d0..df98a6925 100644 return clk_prepare_enable(spi->clk); } -@@ -2033,10 +2125,23 @@ static int stm32_spi_resume(struct device *dev) +@@ -2033,10 +2101,23 @@ static int stm32_spi_resume(struct device *dev) return ret; ret = spi_master_resume(master); @@ -2665,6 +2738,18 @@ index b222ce8d0..df98a6925 100644 } #endif +diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h +index e6fb8ada3f4d3..370a25a9366cc 100644 +--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h ++++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h +@@ -26,6 +26,7 @@ + #define AF14 0xf + #define AF15 0x10 + #define ANALOG 0x11 ++#define RSVD 0x12 + + /* define Pins number*/ + #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0018-ARM-stm32mp1-r2-SOUND.patch similarity index 51% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0018-ARM-stm32mp1-r2-SOUND.patch index a74bad6..e309def 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0018-ARM-stm32mp1-r1-SOUND.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0018-ARM-stm32mp1-r2-SOUND.patch @@ -1,20 +1,189 @@ -From 9ce7cf9f5ce6b3fe1370be07d989eabaf0afb25a Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:47:45 +0200 -Subject: [PATCH 18/23] ARM-stm32mp1-r1-SOUND +From 69629ada3651978075924c825648de57ad2dab11 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:51 +0200 +Subject: [PATCH 18/22] ARM-stm32mp1-r2-rc8-SOUND --- - sound/soc/codecs/Kconfig | 2 +- - sound/soc/codecs/cs42l51.c | 17 ++++-- - sound/soc/codecs/wm8994.c | 80 +++++++++++++++++++++++-- - sound/soc/stm/stm32_i2s.c | 75 +++++++++++++++++------- - sound/soc/stm/stm32_sai.c | 26 ++++++--- - sound/soc/stm/stm32_sai_sub.c | 21 ++++--- - sound/soc/stm/stm32_spdifrx.c | 107 +++++++++++++++++++++------------- - 7 files changed, 241 insertions(+), 87 deletions(-) + .../bindings/sound/st,stm32-i2s.txt | 62 --- + .../bindings/sound/st,stm32-i2s.yaml | 91 +++++ + sound/soc/codecs/Kconfig | 2 +- + sound/soc/codecs/cs42l51.c | 17 +- + sound/soc/codecs/wm8994.c | 80 +++- + sound/soc/stm/stm32_i2s.c | 385 +++++++++++++++--- + sound/soc/stm/stm32_sai.c | 26 +- + sound/soc/stm/stm32_sai_sub.c | 21 +- + sound/soc/stm/stm32_spdifrx.c | 105 +++-- + 9 files changed, 599 insertions(+), 190 deletions(-) + delete mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.txt + create mode 100644 Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml +diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt b/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt +deleted file mode 100644 +index cbf24bcd1b8d3..0000000000000 +--- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.txt ++++ /dev/null +@@ -1,62 +0,0 @@ +-STMicroelectronics STM32 SPI/I2S Controller +- +-The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. +-Only some SPI instances support I2S. +- +-Required properties: +- - compatible: Must be "st,stm32h7-i2s" +- - reg: Offset and length of the device's register set. +- - interrupts: Must contain the interrupt line id. +- - clocks: Must contain phandle and clock specifier pairs for each entry +- in clock-names. +- - clock-names: Must contain "i2sclk", "pclk", "x8k" and "x11k". +- "i2sclk": clock which feeds the internal clock generator +- "pclk": clock which feeds the peripheral bus interface +- "x8k": I2S parent clock for sampling rates multiple of 8kHz. +- "x11k": I2S parent clock for sampling rates multiple of 11.025kHz. +- - dmas: DMA specifiers for tx and rx dma. +- See Documentation/devicetree/bindings/dma/stm32-dma.txt. +- - dma-names: Identifier for each DMA request line. Must be "tx" and "rx". +- - pinctrl-names: should contain only value "default" +- - pinctrl-0: see Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +- +-Optional properties: +- - resets: Reference to a reset controller asserting the reset controller +- +-The device node should contain one 'port' child node with one child 'endpoint' +-node, according to the bindings defined in Documentation/devicetree/bindings/ +-graph.txt. +- +-Example: +-sound_card { +- compatible = "audio-graph-card"; +- dais = <&i2s2_port>; +-}; +- +-i2s2: audio-controller@40003800 { +- compatible = "st,stm32h7-i2s"; +- reg = <0x40003800 0x400>; +- interrupts = <36>; +- clocks = <&rcc PCLK1>, <&rcc SPI2_CK>, <&rcc PLL1_Q>, <&rcc PLL2_P>; +- clock-names = "pclk", "i2sclk", "x8k", "x11k"; +- dmas = <&dmamux2 2 39 0x400 0x1>, +- <&dmamux2 3 40 0x400 0x1>; +- dma-names = "rx", "tx"; +- pinctrl-names = "default"; +- pinctrl-0 = <&pinctrl_i2s2>; +- +- i2s2_port: port@0 { +- cpu_endpoint: endpoint { +- remote-endpoint = <&codec_endpoint>; +- format = "i2s"; +- }; +- }; +-}; +- +-audio-codec { +- codec_port: port@0 { +- codec_endpoint: endpoint { +- remote-endpoint = <&cpu_endpoint>; +- }; +- }; +-}; +diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml +new file mode 100644 +index 0000000000000..6feb5a09c184e +--- /dev/null ++++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml +@@ -0,0 +1,91 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/sound/st,stm32-i2s.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: STMicroelectronics STM32 SPI/I2S Controller ++ ++maintainers: ++ - Olivier Moysan ++ ++description: ++ The SPI/I2S block supports I2S/PCM protocols when configured on I2S mode. ++ Only some SPI instances support I2S. ++ ++properties: ++ compatible: ++ enum: ++ - st,stm32h7-i2s ++ ++ "#sound-dai-cells": ++ const: 0 ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ items: ++ - description: clock feeding the peripheral bus interface. ++ - description: clock feeding the internal clock generator. ++ - description: I2S parent clock for sampling rates multiple of 8kHz. ++ - description: I2S parent clock for sampling rates multiple of 11.025kHz. ++ ++ clock-names: ++ items: ++ - const: pclk ++ - const: i2sclk ++ - const: x8k ++ - const: x11k ++ ++ interrupts: ++ maxItems: 1 ++ ++ dmas: ++ items: ++ - description: audio capture DMA. ++ - description: audio playback DMA. ++ ++ dma-names: ++ items: ++ - const: rx ++ - const: tx ++ ++ resets: ++ maxItems: 1 ++ ++ "#clock-cells": ++ description: Configure the I2S device as MCLK clock provider. ++ const: 0 ++ ++required: ++ - compatible ++ - "#sound-dai-cells" ++ - reg ++ - clocks ++ - clock-names ++ - interrupts ++ - dmas ++ - dma-names ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ i2s2: audio-controller@4000b000 { ++ compatible = "st,stm32h7-i2s"; ++ #sound-dai-cells = <0>; ++ reg = <0x4000b000 0x400>; ++ clocks = <&rcc SPI2>, <&rcc SPI2_K>, <&rcc PLL3_Q>, <&rcc PLL3_R>; ++ clock-names = "pclk", "i2sclk", "x8k", "x11k"; ++ interrupts = ; ++ dmas = <&dmamux1 39 0x400 0x01>, ++ <&dmamux1 40 0x400 0x01>; ++ dma-names = "rx", "tx"; ++ pinctrl-names = "default"; ++ pinctrl-0 = <&i2s2_pins_a>; ++ }; ++ ++... diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 229cc89f8..e5d231a63 100644 +index 229cc89f8c5a5..e5d231a6331b4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1395,7 +1395,7 @@ config SND_SOC_WM8993 @@ -27,7 +196,7 @@ index 229cc89f8..e5d231a63 100644 config SND_SOC_WM8995 tristate diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c -index 55408c8fc..01a4d93e1 100644 +index 55408c8fcb4e3..01a4d93e11dd8 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -174,6 +174,7 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, @@ -69,7 +238,7 @@ index 55408c8fc..01a4d93e1 100644 {"Right ADC", NULL, "Right PGA"}, diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c -index d5fb7f5dd..a166ab1f3 100644 +index d5fb7f5dd551c..a166ab1f34e1e 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -7,6 +7,7 @@ @@ -214,10 +383,395 @@ index d5fb7f5dd..a166ab1f3 100644 snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, ARRAY_SIZE(wm8994_lateclk_revd_widgets)); diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c -index 3e7226a53..7c4d63c33 100644 +index 3e7226a53e53a..7d1672cf78cc5 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c -@@ -831,25 +831,33 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -196,6 +197,9 @@ enum i2s_datlen { + #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER) + #define STM32_I2S_IS_SLAVE(x) ((x)->ms_flg == I2S_MS_SLAVE) + ++#define STM32_I2S_NAME_LEN 32 ++#define STM32_I2S_RATE_11K 11025 ++ + /** + * struct stm32_i2s_data - private data of I2S + * @regmap_conf: I2S register map configuration pointer +@@ -206,6 +210,7 @@ enum i2s_datlen { + * @dma_data_rx: dma configuration data for tx channel + * @substream: PCM substream data pointer + * @i2sclk: kernel clock feeding the I2S clock generator ++ * @i2smclk: master clock from I2S mclk provider + * @pclk: peripheral clock driving bus interface + * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz + * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz +@@ -215,6 +220,9 @@ enum i2s_datlen { + * @irq_lock: prevent race condition with IRQ + * @mclk_rate: master clock frequency (Hz) + * @fmt: DAI protocol ++ * @divider: prescaler division ratio ++ * @div: prescaler div field ++ * @odd: prescaler odd field + * @refcount: keep count of opened streams on I2S + * @ms_flg: master mode flag. + */ +@@ -227,6 +235,7 @@ struct stm32_i2s_data { + struct snd_dmaengine_dai_dma_data dma_data_rx; + struct snd_pcm_substream *substream; + struct clk *i2sclk; ++ struct clk *i2smclk; + struct clk *pclk; + struct clk *x8kclk; + struct clk *x11kclk; +@@ -236,10 +245,210 @@ struct stm32_i2s_data { + spinlock_t irq_lock; /* used to prevent race condition with IRQ */ + unsigned int mclk_rate; + unsigned int fmt; ++ unsigned int divider; ++ unsigned int div; ++ bool odd; + int refcount; + int ms_flg; + }; + ++struct stm32_i2smclk_data { ++ struct clk_hw hw; ++ unsigned long freq; ++ struct stm32_i2s_data *i2s_data; ++}; ++ ++#define to_mclk_data(_hw) container_of(_hw, struct stm32_i2smclk_data, hw) ++ ++static int stm32_i2s_calc_clk_div(struct stm32_i2s_data *i2s, ++ unsigned long input_rate, ++ unsigned long output_rate) ++{ ++ unsigned int ratio, div, divider = 1; ++ bool odd; ++ ++ ratio = DIV_ROUND_CLOSEST(input_rate, output_rate); ++ ++ /* Check the parity of the divider */ ++ odd = ratio & 0x1; ++ ++ /* Compute the div prescaler */ ++ div = ratio >> 1; ++ ++ /* If div is 0 actual divider is 1 */ ++ if (div) { ++ divider = ((2 * div) + odd); ++ dev_dbg(&i2s->pdev->dev, "Divider: 2*%d(div)+%d(odd) = %d\n", ++ div, odd, divider); ++ } ++ ++ /* Division by three is not allowed by I2S prescaler */ ++ if ((div == 1 && odd) || div > I2S_CGFR_I2SDIV_MAX) { ++ dev_err(&i2s->pdev->dev, "Wrong divider setting\n"); ++ return -EINVAL; ++ } ++ ++ if (input_rate % divider) ++ dev_dbg(&i2s->pdev->dev, ++ "Rate not accurate. requested (%ld), actual (%ld)\n", ++ output_rate, input_rate / divider); ++ ++ i2s->div = div; ++ i2s->odd = odd; ++ i2s->divider = divider; ++ ++ return 0; ++} ++ ++static int stm32_i2s_set_clk_div(struct stm32_i2s_data *i2s) ++{ ++ u32 cgfr, cgfr_mask; ++ ++ cgfr = I2S_CGFR_I2SDIV_SET(i2s->div) | (i2s->odd << I2S_CGFR_ODD_SHIFT); ++ cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD; ++ ++ return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, ++ cgfr_mask, cgfr); ++} ++ ++static int stm32_i2s_set_parent_clock(struct stm32_i2s_data *i2s, ++ unsigned int rate) ++{ ++ struct platform_device *pdev = i2s->pdev; ++ struct clk *parent_clk; ++ int ret; ++ ++ if (!(rate % STM32_I2S_RATE_11K)) ++ parent_clk = i2s->x11kclk; ++ else ++ parent_clk = i2s->x8kclk; ++ ++ ret = clk_set_parent(i2s->i2sclk, parent_clk); ++ if (ret) ++ dev_err(&pdev->dev, ++ "Error %d setting i2sclk parent clock\n", ret); ++ ++ return ret; ++} ++ ++static long stm32_i2smclk_round_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long *prate) ++{ ++ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); ++ struct stm32_i2s_data *i2s = mclk->i2s_data; ++ int ret; ++ ++ ret = stm32_i2s_calc_clk_div(i2s, *prate, rate); ++ if (ret) ++ return ret; ++ ++ mclk->freq = *prate / i2s->divider; ++ ++ return mclk->freq; ++} ++ ++static unsigned long stm32_i2smclk_recalc_rate(struct clk_hw *hw, ++ unsigned long parent_rate) ++{ ++ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); ++ ++ return mclk->freq; ++} ++ ++static int stm32_i2smclk_set_rate(struct clk_hw *hw, unsigned long rate, ++ unsigned long parent_rate) ++{ ++ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); ++ struct stm32_i2s_data *i2s = mclk->i2s_data; ++ int ret; ++ ++ ret = stm32_i2s_calc_clk_div(i2s, parent_rate, rate); ++ if (ret) ++ return ret; ++ ++ ret = stm32_i2s_set_clk_div(i2s); ++ if (ret) ++ return ret; ++ ++ mclk->freq = rate; ++ ++ return 0; ++} ++ ++static int stm32_i2smclk_enable(struct clk_hw *hw) ++{ ++ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); ++ struct stm32_i2s_data *i2s = mclk->i2s_data; ++ ++ dev_dbg(&i2s->pdev->dev, "Enable master clock\n"); ++ ++ return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, ++ I2S_CGFR_MCKOE, I2S_CGFR_MCKOE); ++} ++ ++static void stm32_i2smclk_disable(struct clk_hw *hw) ++{ ++ struct stm32_i2smclk_data *mclk = to_mclk_data(hw); ++ struct stm32_i2s_data *i2s = mclk->i2s_data; ++ ++ dev_dbg(&i2s->pdev->dev, "Disable master clock\n"); ++ ++ regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, I2S_CGFR_MCKOE, 0); ++} ++ ++static const struct clk_ops mclk_ops = { ++ .enable = stm32_i2smclk_enable, ++ .disable = stm32_i2smclk_disable, ++ .recalc_rate = stm32_i2smclk_recalc_rate, ++ .round_rate = stm32_i2smclk_round_rate, ++ .set_rate = stm32_i2smclk_set_rate, ++}; ++ ++static int stm32_i2s_add_mclk_provider(struct stm32_i2s_data *i2s) ++{ ++ struct clk_hw *hw; ++ struct stm32_i2smclk_data *mclk; ++ struct device *dev = &i2s->pdev->dev; ++ const char *pname = __clk_get_name(i2s->i2sclk); ++ char *mclk_name, *p, *s = (char *)pname; ++ int ret, i = 0; ++ ++ mclk = devm_kzalloc(dev, sizeof(*mclk), GFP_KERNEL); ++ if (!mclk) ++ return -ENOMEM; ++ ++ mclk_name = devm_kcalloc(dev, sizeof(char), ++ STM32_I2S_NAME_LEN, GFP_KERNEL); ++ if (!mclk_name) ++ return -ENOMEM; ++ ++ /* ++ * Forge mclk clock name from parent clock name and suffix. ++ * String after "_" char is stripped in parent name. ++ */ ++ p = mclk_name; ++ while (*s && *s != '_' && (i < (STM32_I2S_NAME_LEN - 7))) { ++ *p++ = *s++; ++ i++; ++ } ++ strcat(p, "_mclk"); ++ ++ mclk->hw.init = CLK_HW_INIT(mclk_name, pname, &mclk_ops, 0); ++ mclk->i2s_data = i2s; ++ hw = &mclk->hw; ++ ++ dev_dbg(dev, "Register master clock %s\n", mclk_name); ++ ret = devm_clk_hw_register(&i2s->pdev->dev, hw); ++ if (ret) { ++ dev_err(dev, "mclk register fails with error %d\n", ret); ++ return ret; ++ } ++ i2s->i2smclk = hw->clk; ++ ++ /* register mclk provider */ ++ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); ++} ++ + static irqreturn_t stm32_i2s_isr(int irq, void *devid) + { + struct stm32_i2s_data *i2s = (struct stm32_i2s_data *)devid; +@@ -405,18 +614,46 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) + { + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); ++ int ret = 0; + +- dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz\n", freq); ++ dev_dbg(cpu_dai->dev, "I2S MCLK frequency is %uHz. mode: %s, dir: %s\n", ++ freq, STM32_I2S_IS_MASTER(i2s) ? "master" : "slave", ++ dir ? "output" : "input"); + +- if ((dir == SND_SOC_CLOCK_OUT) && STM32_I2S_IS_MASTER(i2s)) { +- i2s->mclk_rate = freq; ++ /* MCLK generation is available only in master mode */ ++ if (dir == SND_SOC_CLOCK_OUT && STM32_I2S_IS_MASTER(i2s)) { ++ if (!i2s->i2smclk) { ++ dev_dbg(cpu_dai->dev, "No MCLK registered\n"); ++ return 0; ++ } + +- /* Enable master clock if master mode and mclk-fs are set */ +- return regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, +- I2S_CGFR_MCKOE, I2S_CGFR_MCKOE); ++ /* Assume shutdown if requested frequency is 0Hz */ ++ if (!freq) { ++ /* Release mclk rate only if rate was actually set */ ++ if (i2s->mclk_rate) { ++ clk_rate_exclusive_put(i2s->i2smclk); ++ i2s->mclk_rate = 0; ++ } ++ return regmap_update_bits(i2s->regmap, ++ STM32_I2S_CGFR_REG, ++ I2S_CGFR_MCKOE, 0); ++ } ++ /* If master clock is used, set parent clock now */ ++ ret = stm32_i2s_set_parent_clock(i2s, freq); ++ if (ret) ++ return ret; ++ ret = clk_set_rate_exclusive(i2s->i2smclk, freq); ++ if (ret) { ++ dev_err(cpu_dai->dev, "Could not set mclk rate\n"); ++ return ret; ++ } ++ ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, ++ I2S_CGFR_MCKOE, I2S_CGFR_MCKOE); ++ if (!ret) ++ i2s->mclk_rate = freq; + } + +- return 0; ++ return ret; + } + + static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -424,11 +661,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, + { + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long i2s_clock_rate; +- unsigned int tmp, div, real_div, nb_bits, frame_len; ++ unsigned int nb_bits, frame_len; + unsigned int rate = params_rate(params); ++ u32 cgfr; + int ret; +- u32 cgfr, cgfr_mask; +- bool odd; + + if (!(rate % 11025)) + clk_set_parent(i2s->i2sclk, i2s->x11kclk); +@@ -449,7 +685,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, + * dsp mode : div = i2s_clk / (nb_bits x ws) + */ + if (i2s->mclk_rate) { +- tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, i2s->mclk_rate); ++ ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate, ++ i2s->mclk_rate); ++ if (ret) ++ return ret; + } else { + frame_len = 32; + if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == +@@ -462,34 +701,13 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, + return ret; + + nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1); +- tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, (nb_bits * rate)); +- } +- +- /* Check the parity of the divider */ +- odd = tmp & 0x1; +- +- /* Compute the div prescaler */ +- div = tmp >> 1; +- +- cgfr = I2S_CGFR_I2SDIV_SET(div) | (odd << I2S_CGFR_ODD_SHIFT); +- cgfr_mask = I2S_CGFR_I2SDIV_MASK | I2S_CGFR_ODD; +- +- real_div = ((2 * div) + odd); +- dev_dbg(cpu_dai->dev, "I2S clk: %ld, SCLK: %d\n", +- i2s_clock_rate, rate); +- dev_dbg(cpu_dai->dev, "Divider: 2*%d(div)+%d(odd) = %d\n", +- div, odd, real_div); +- +- if (((div == 1) && odd) || (div > I2S_CGFR_I2SDIV_MAX)) { +- dev_err(cpu_dai->dev, "Wrong divider setting\n"); +- return -EINVAL; ++ ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate, ++ (nb_bits * rate)); ++ if (ret) ++ return ret; + } + +- if (!div && !odd) +- dev_warn(cpu_dai->dev, "real divider forced to 1\n"); +- +- ret = regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, +- cgfr_mask, cgfr); ++ ret = stm32_i2s_set_clk_div(i2s); + if (ret < 0) + return ret; + +@@ -694,9 +912,6 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, + struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + +- regmap_update_bits(i2s->regmap, STM32_I2S_CGFR_REG, +- I2S_CGFR_MCKOE, (unsigned int)~I2S_CGFR_MCKOE); +- + clk_disable_unprepare(i2s->i2sclk); + + spin_lock_irqsave(&i2s->irq_lock, flags); +@@ -831,28 +1046,43 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, /* Get clocks */ i2s->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(i2s->pclk)) { @@ -255,7 +809,17 @@ index 3e7226a53..7c4d63c33 100644 return PTR_ERR(i2s->x11kclk); } -@@ -866,12 +874,24 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, ++ /* Register mclk provider if requested */ ++ if (of_find_property(np, "#clock-cells", NULL)) { ++ ret = stm32_i2s_add_mclk_provider(i2s); ++ if (ret < 0) ++ return ret; ++ } ++ + /* Get irqs */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) +@@ -866,12 +1096,24 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, } /* Reset */ @@ -285,7 +849,28 @@ index 3e7226a53..7c4d63c33 100644 return 0; } -@@ -903,48 +923,62 @@ static int stm32_i2s_probe(struct platform_device *pdev) +@@ -886,16 +1128,16 @@ static int stm32_i2s_probe(struct platform_device *pdev) + if (!i2s) + return -ENOMEM; + +- ret = stm32_i2s_parse_dt(pdev, i2s); +- if (ret) +- return ret; +- + i2s->pdev = pdev; + i2s->ms_flg = I2S_MS_NOT_SET; + spin_lock_init(&i2s->lock_fd); + spin_lock_init(&i2s->irq_lock); + platform_set_drvdata(pdev, i2s); + ++ ret = stm32_i2s_parse_dt(pdev, i2s); ++ if (ret) ++ return ret; ++ + ret = stm32_i2s_dais_init(pdev, i2s); + if (ret) + return ret; +@@ -903,48 +1145,62 @@ static int stm32_i2s_probe(struct platform_device *pdev) i2s->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "pclk", i2s->base, i2s->regmap_conf); if (IS_ERR(i2s->regmap)) { @@ -359,7 +944,7 @@ index 3e7226a53..7c4d63c33 100644 return ret; } -@@ -981,6 +1015,7 @@ static struct platform_driver stm32_i2s_driver = { +@@ -981,6 +1237,7 @@ static struct platform_driver stm32_i2s_driver = { .pm = &stm32_i2s_pm_ops, }, .probe = stm32_i2s_probe, @@ -368,7 +953,7 @@ index 3e7226a53..7c4d63c33 100644 module_platform_driver(stm32_i2s_driver); diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c -index ef4273361..820ae27e7 100644 +index ef4273361d0d8..820ae27e7e2e9 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -174,20 +174,26 @@ static int stm32_sai_probe(struct platform_device *pdev) @@ -424,10 +1009,18 @@ index ef4273361..820ae27e7 100644 /* Enable peripheral clock to allow register access */ ret = clk_prepare_enable(sai->pclk); diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c -index 10eb4b8e8..be25715b4 100644 +index 7e965848796c3..a7c39d1794a7b 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c -@@ -1380,7 +1380,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -1380,7 +1381,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, sai->regmap_config); if (IS_ERR(sai->regmap)) { @@ -438,7 +1031,7 @@ index 10eb4b8e8..be25715b4 100644 return PTR_ERR(sai->regmap); } -@@ -1471,7 +1473,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, +@@ -1471,7 +1474,9 @@ static int stm32_sai_sub_parse_of(struct platform_device *pdev, of_node_put(args.np); sai->sai_ck = devm_clk_get(&pdev->dev, "sai_ck"); if (IS_ERR(sai->sai_ck)) { @@ -449,13 +1042,8 @@ index 10eb4b8e8..be25715b4 100644 return PTR_ERR(sai->sai_ck); } -@@ -1543,21 +1547,22 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) - return ret; - } +@@ -1548,16 +1553,21 @@ static int stm32_sai_sub_probe(struct platform_device *pdev) -+ if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) -+ conf = &stm32_sai_pcm_config_spdif; -+ ret = snd_dmaengine_pcm_register(&pdev->dev, conf, 0); if (ret) { - dev_err(&pdev->dev, "Could not register pcm dma\n"); @@ -466,20 +1054,29 @@ index 10eb4b8e8..be25715b4 100644 ret = snd_soc_register_component(&pdev->dev, &stm32_component, &sai->cpu_dai_drv, 1); - if (ret) -- return ret; -+ snd_dmaengine_pcm_unregister(&pdev->dev); +- if (ret) ++ if (ret) { + snd_dmaengine_pcm_unregister(&pdev->dev); ++ return ret; ++ } -- if (STM_SAI_PROTOCOL_IS_SPDIF(sai)) -- conf = &stm32_sai_pcm_config_spdif; -- -- return 0; -+ return ret; +- return ret; ++ pm_runtime_enable(&pdev->dev); ++ ++ return 0; } static int stm32_sai_sub_remove(struct platform_device *pdev) +@@ -1567,6 +1577,7 @@ static int stm32_sai_sub_remove(struct platform_device *pdev) + clk_unprepare(sai->pdata->pclk); + snd_dmaengine_pcm_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); + + return 0; + } diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c -index e53fb4bd6..1bfa3b2ba 100644 +index 9fc2a1767eb1d..1bfa3b2ba9744 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -353,6 +353,8 @@ static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) @@ -581,7 +1178,7 @@ index e53fb4bd6..1bfa3b2ba 100644 return PTR_ERR(spdifrx->regmap); } -@@ -964,37 +1000,46 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) +@@ -964,31 +1000,38 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) return ret; } @@ -637,15 +1234,7 @@ index e53fb4bd6..1bfa3b2ba 100644 ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr); if (ret) goto error; - - if (idr == SPDIFRX_IPIDR_NUMBER) { - ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver); -+ if (ret) -+ goto error; - - dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n", - FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver), -@@ -1004,27 +1049,11 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) +@@ -1006,27 +1049,11 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) return ret; error: diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0019-ARM-stm32mp1-r2-MISC-CPUIDLE-MM.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0019-ARM-stm32mp1-r2-MISC-CPUIDLE-MM.patch new file mode 100644 index 0000000..79ae87a --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0019-ARM-stm32mp1-r2-MISC-CPUIDLE-MM.patch @@ -0,0 +1,1943 @@ +From d2f5d4b3ec672e5ded9270780386098a0d34ce89 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:52 +0200 +Subject: [PATCH 19/22] ARM-stm32mp1-r2-rc8-MISC-CPUIDLE-MM + +--- + CONTRIBUTING.md | 30 + + .../memory-controllers/st,stm32-fmc2-ebi.yaml | 252 ++++ + drivers/block/loop.c | 7 +- + drivers/cpuidle/Kconfig.arm | 8 + + drivers/cpuidle/Makefile | 1 + + drivers/cpuidle/cpuidle-stm32.c | 276 ++++ + drivers/memory/Kconfig | 10 + + drivers/memory/Makefile | 1 + + drivers/memory/stm32-fmc2-ebi.c | 1206 +++++++++++++++++ + include/linux/pm_wakeup.h | 10 + + kernel/power/suspend.c | 1 - + 11 files changed, 1799 insertions(+), 3 deletions(-) + create mode 100644 CONTRIBUTING.md + create mode 100644 Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml + create mode 100644 drivers/cpuidle/cpuidle-stm32.c + create mode 100644 drivers/memory/stm32-fmc2-ebi.c + +diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md +new file mode 100644 +index 0000000000000..3d1bacd78a543 +--- /dev/null ++++ b/CONTRIBUTING.md +@@ -0,0 +1,30 @@ ++# Contributing guide ++ ++This document serves as a checklist before contributing to this repository. It includes links to read up on if topics are unclear to you. ++ ++This guide mainly focuses on the proper use of Git. ++ ++## 1. Issues ++ ++STM32MPU projects do not activate "Github issues" feature for the time being. If you need to report an issue or question about this project deliverables, you can report them using [ ST Support Center ](https://my.st.com/ols#/ols/newrequest) or [ ST Community MPU Forum ](https://community.st.com/s/topic/0TO0X0000003u2AWAQ/stm32-mpus). ++ ++## 2. Pull Requests ++ ++STMicrolectronics is happy to receive contributions from the community, based on an initial Contributor License Agreement (CLA) procedure. ++ ++* If you are an individual writing original source code and you are sure **you own the intellectual property**, then you need to sign an Individual CLA (https://cla.st.com). ++* If you work for a company that wants also to allow you to contribute with your work, your company needs to provide a Corporate CLA (https://cla.st.com) mentioning your GitHub account name. ++* If you are not sure that a CLA (Individual or Corporate) has been signed for your GitHub account you can check here (https://cla.st.com). ++ ++Please note that: ++* The Corporate CLA will always take precedence over the Individual CLA. ++* One CLA submission is sufficient, for any project proposed by STMicroelectronics. ++ ++__How to proceed__ ++ ++* We recommend to fork the project in your GitHub account to further develop your contribution. Please use the latest commit version. ++* Please, submit one Pull Request for one new feature or proposal. This will ease the analysis and final merge if accepted. ++ ++__Note__ ++ ++Merge will not be done directly in GitHub but it will need first to follow internal integration process before public deliver in a standard release. The Pull request will stay open until it is merged and delivered. +diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml +new file mode 100644 +index 0000000000000..70eaf739036bc +--- /dev/null ++++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32-fmc2-ebi.yaml +@@ -0,0 +1,252 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/memory-controllers/st,stm32-fmc2-ebi.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: STMicroelectronics Flexible Memory Controller 2 (FMC2) Bindings ++ ++description: | ++ The FMC2 functional block makes the interface with: synchronous and ++ asynchronous static devices (such as PSNOR, PSRAM or other memory-mapped ++ peripherals) and NAND flash memories. ++ Its main purposes are: ++ - to translate AXI transactions into the appropriate external device ++ protocol ++ - to meet the access time requirements of the external devices ++ All external devices share the addresses, data and control signals with the ++ controller. Each external device is accessed by means of a unique Chip ++ Select. The FMC2 performs only one access at a time to an external device. ++ ++maintainers: ++ - Christophe Kerello ++ ++properties: ++ compatible: ++ const: st,stm32mp1-fmc2-ebi ++ ++ reg: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ resets: ++ maxItems: 1 ++ ++ "#address-cells": ++ const: 2 ++ ++ "#size-cells": ++ const: 1 ++ ++ ranges: ++ description: | ++ Reflects the memory layout with four integer values per bank. Format: ++ 0
++ ++patternProperties: ++ "^.*@[0-4],[a-f0-9]+$": ++ type: object ++ ++ properties: ++ reg: ++ description: Bank number, base address and size of the device. ++ ++ st,fmc2-ebi-cs-transaction-type: ++ description: | ++ Select one of the transactions type supported ++ 0: Asynchronous mode 1 SRAM/FRAM. ++ 1: Asynchronous mode 1 PSRAM. ++ 2: Asynchronous mode A SRAM/FRAM. ++ 3: Asynchronous mode A PSRAM. ++ 4: Asynchronous mode 2 NOR. ++ 5: Asynchronous mode B NOR. ++ 6: Asynchronous mode C NOR. ++ 7: Asynchronous mode D NOR. ++ 8: Synchronous read synchronous write PSRAM. ++ 9: Synchronous read asynchronous write PSRAM. ++ 10: Synchronous read synchronous write NOR. ++ 11: Synchronous read asynchronous write NOR. ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ minimum: 0 ++ maximum: 11 ++ ++ st,fmc2-ebi-cs-cclk-enable: ++ description: Continuous clock enable (first bank must be configured ++ in synchronous mode). The FMC_CLK is generated continuously ++ during asynchronous and synchronous access. By default, the ++ FMC_CLK is only generated during synchronous access. ++ $ref: /schemas/types.yaml#/definitions/flag ++ ++ st,fmc2-ebi-cs-mux-enable: ++ description: Address/Data multiplexed on databus (valid only with ++ NOR and PSRAM transactions type). By default, Address/Data ++ are not multiplexed. ++ $ref: /schemas/types.yaml#/definitions/flag ++ ++ st,fmc2-ebi-cs-buswidth: ++ description: Data bus width ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ enum: [ 8, 16 ] ++ default: 16 ++ ++ st,fmc2-ebi-cs-waitpol-high: ++ description: Wait signal polarity (NWAIT signal active high). ++ By default, NWAIT is active low. ++ $ref: /schemas/types.yaml#/definitions/flag ++ ++ st,fmc2-ebi-cs-waitcfg-enable: ++ description: The NWAIT signal indicates wheither the data from the ++ device are valid or if a wait state must be inserted when accessing ++ the device in synchronous mode. By default, the NWAIT signal is ++ active one data cycle before wait state. ++ $ref: /schemas/types.yaml#/definitions/flag ++ ++ st,fmc2-ebi-cs-wait-enable: ++ description: The NWAIT signal is enabled (its level is taken into ++ account after the programmed latency period to insert wait states ++ if asserted). By default, the NWAIT signal is disabled. ++ $ref: /schemas/types.yaml#/definitions/flag ++ ++ st,fmc2-ebi-cs-asyncwait-enable: ++ description: The NWAIT signal is taken into account during asynchronous ++ transactions. By default, the NWAIT signal is not taken into account ++ during asynchronous transactions. ++ $ref: /schemas/types.yaml#/definitions/flag ++ ++ st,fmc2-ebi-cs-cpsize: ++ description: CRAM page size. The controller splits the burst access ++ when the memory page is reached. By default, no burst split when ++ crossing page boundary. ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ enum: [ 0, 128, 256, 512, 1024 ] ++ default: 0 ++ ++ st,fmc2-ebi-cs-byte-lane-setup-ns: ++ description: This property configures the byte lane setup timing ++ defined in nanoseconds from NBLx low to Chip Select NEx low. ++ ++ st,fmc2-ebi-cs-address-setup-ns: ++ description: This property defines the duration of the address setup ++ phase in nanoseconds used for asynchronous read/write transactions. ++ ++ st,fmc2-ebi-cs-address-hold-ns: ++ description: This property defines the duration of the address hold ++ phase in nanoseconds used for asynchronous multiplexed read/write ++ transactions. ++ ++ st,fmc2-ebi-cs-data-setup-ns: ++ description: This property defines the duration of the data setup phase ++ in nanoseconds used for asynchronous read/write transactions. ++ ++ st,fmc2-ebi-cs-bus-turnaround-ns: ++ description: This property defines the delay in nanoseconds between the ++ end of current read/write transaction and the next transaction. ++ ++ st,fmc2-ebi-cs-data-hold-ns: ++ description: This property defines the duration of the data hold phase ++ in nanoseconds used for asynchronous read/write transactions. ++ ++ st,fmc2-ebi-cs-clk-period-ns: ++ description: This property defines the FMC_CLK output signal period in ++ nanoseconds. ++ ++ st,fmc2-ebi-cs-data-latency-ns: ++ description: This property defines the data latency before reading or ++ writing the first data in nanoseconds. ++ ++ st,fmc2_ebi-cs-write-address-setup-ns: ++ description: This property defines the duration of the address setup ++ phase in nanoseconds used for asynchronous write transactions. ++ ++ st,fmc2-ebi-cs-write-address-hold-ns: ++ description: This property defines the duration of the address hold ++ phase in nanoseconds used for asynchronous multiplexed write ++ transactions. ++ ++ st,fmc2-ebi-cs-write-data-setup-ns: ++ description: This property defines the duration of the data setup ++ phase in nanoseconds used for asynchronous write transactions. ++ ++ st,fmc2-ebi-cs-write-bus-turnaround-ns: ++ description: This property defines the delay between the end of current ++ write transaction and the next transaction in nanoseconds. ++ ++ st,fmc2-ebi-cs-write-data-hold-ns: ++ description: This property defines the duration of the data hold phase ++ in nanoseconds used for asynchronous write transactions. ++ ++ st,fmc2-ebi-cs-max-low-pulse-ns: ++ description: This property defines the maximum chip select low pulse ++ duration in nanoseconds for synchronous transactions. When this timing ++ reaches 0, the controller splits the current access, toggles NE to ++ allow device refresh and restarts a new access. ++ ++ required: ++ - reg ++ ++required: ++ - "#address-cells" ++ - "#size-cells" ++ - compatible ++ - reg ++ - clocks ++ - ranges ++ ++examples: ++ - | ++ #include ++ #include ++ #include ++ memory-controller@58002000 { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ compatible = "st,stm32mp1-fmc2-ebi"; ++ reg = <0x58002000 0x1000>; ++ clocks = <&rcc FMC_K>; ++ resets = <&rcc FMC_R>; ++ ++ ranges = <0 0 0x60000000 0x04000000>, /* EBI CS 1 */ ++ <1 0 0x64000000 0x04000000>, /* EBI CS 2 */ ++ <2 0 0x68000000 0x04000000>, /* EBI CS 3 */ ++ <3 0 0x6c000000 0x04000000>, /* EBI CS 4 */ ++ <4 0 0x80000000 0x10000000>; /* NAND */ ++ ++ psram@0,0 { ++ compatible = "mtd-ram"; ++ reg = <0 0x00000000 0x100000>; ++ bank-width = <2>; ++ ++ st,fmc2-ebi-cs-transaction-type = <1>; ++ st,fmc2-ebi-cs-address-setup-ns = <60>; ++ st,fmc2-ebi-cs-data-setup-ns = <30>; ++ st,fmc2-ebi-cs-bus-turnaround-ns = <5>; ++ }; ++ ++ nand-controller@4,0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stm32mp1-fmc2-nfc"; ++ reg = <4 0x00000000 0x1000>, ++ <4 0x08010000 0x1000>, ++ <4 0x08020000 0x1000>, ++ <4 0x01000000 0x1000>, ++ <4 0x09010000 0x1000>, ++ <4 0x09020000 0x1000>; ++ interrupts = ; ++ dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0>, ++ <&mdma1 20 0x2 0x12000a08 0x0 0x0>, ++ <&mdma1 21 0x2 0x12000a0a 0x0 0x0>; ++ dma-names = "tx", "rx", "ecc"; ++ ++ nand@0 { ++ reg = <0>; ++ nand-on-flash-bbt; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; ++ }; ++ }; ++ ++... +diff --git a/drivers/block/loop.c b/drivers/block/loop.c +index 565e35e69f249..d5c969284e42d 100644 +--- a/drivers/block/loop.c ++++ b/drivers/block/loop.c +@@ -462,7 +462,7 @@ static void lo_complete_rq(struct request *rq) + if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) || + req_op(rq) != REQ_OP_READ) { + if (cmd->ret < 0) +- ret = BLK_STS_IOERR; ++ ret = errno_to_blk_status(cmd->ret); + goto end_io; + } + +@@ -1970,7 +1970,10 @@ static void loop_handle_cmd(struct loop_cmd *cmd) + failed: + /* complete non-aio request */ + if (!cmd->use_aio || ret) { +- cmd->ret = ret ? -EIO : 0; ++ if (ret == -EOPNOTSUPP) ++ cmd->ret = ret; ++ else ++ cmd->ret = ret ? -EIO : 0; + blk_mq_complete_request(rq); + } + } +diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm +index d8530475493cb..5e5cdbe7ed3cb 100644 +--- a/drivers/cpuidle/Kconfig.arm ++++ b/drivers/cpuidle/Kconfig.arm +@@ -81,6 +81,14 @@ config ARM_EXYNOS_CPUIDLE + help + Select this to enable cpuidle for Exynos processors + ++config ARM_STM32_CPUIDLE ++ bool "Cpu Idle Driver for the STM32 processors" ++ depends on MACH_STM32MP157 ++ select DT_IDLE_STATES ++ select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP ++ help ++ Select this to enable cpuidle for STM32 processors. ++ + config ARM_MVEBU_V7_CPUIDLE + bool "CPU Idle Driver for mvebu v7 family processors" + depends on ARCH_MVEBU && !ARM64 +diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile +index ee70d5cc5b996..0b198896b61a0 100644 +--- a/drivers/cpuidle/Makefile ++++ b/drivers/cpuidle/Makefile +@@ -22,6 +22,7 @@ obj-$(CONFIG_ARM_AT91_CPUIDLE) += cpuidle-at91.o + obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o + obj-$(CONFIG_ARM_CPUIDLE) += cpuidle-arm.o + obj-$(CONFIG_ARM_PSCI_CPUIDLE) += cpuidle-psci.o ++obj-$(CONFIG_ARM_STM32_CPUIDLE) += cpuidle-stm32.o + + ############################################################################### + # MIPS drivers +diff --git a/drivers/cpuidle/cpuidle-stm32.c b/drivers/cpuidle/cpuidle-stm32.c +new file mode 100644 +index 0000000000000..d3413386cc7fe +--- /dev/null ++++ b/drivers/cpuidle/cpuidle-stm32.c +@@ -0,0 +1,276 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Copyright (C) STMicroelectronics 2019 ++// Author: ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dt_idle_states.h" ++ ++#define SMC_AUTOSTOP() \ ++{ \ ++ struct arm_smccc_res res; \ ++ arm_smccc_smc(0x8200100a, 0, 0, 0, \ ++ 0, 0, 0, 0, &res); \ ++} ++ ++struct stm32_pm_domain { ++ struct device *dev; ++ struct generic_pm_domain genpd; ++ int id; ++}; ++ ++static atomic_t stm_idle_barrier; ++ ++static int stm32_enter_idle(struct cpuidle_device *dev, ++ struct cpuidle_driver *drv, int index) ++{ ++ /* ++ * Call idle CPU PM enter notifier chain so that ++ * VFP and per CPU interrupt context is saved. ++ */ ++ cpu_pm_enter(); ++ ++ /* ++ * be sure that both cpu enter at the same time ++ * normally not needed is the state is declared as coupled ++ */ ++ cpuidle_coupled_parallel_barrier(dev, &stm_idle_barrier); ++ ++ /* Enter broadcast mode for periodic timers */ ++ tick_broadcast_enable(); ++ ++ /* Enter broadcast mode for one-shot timers */ ++ tick_broadcast_enter(); ++ ++ if (dev->cpu == 0) ++ cpu_cluster_pm_enter(); ++ ++ SMC_AUTOSTOP(); ++ ++ if (dev->cpu == 0) ++ cpu_cluster_pm_exit(); ++ ++ tick_broadcast_exit(); ++ ++ cpuidle_coupled_parallel_barrier(dev, &stm_idle_barrier); ++ ++ /* ++ * Call idle CPU PM exit notifier chain to restore ++ * VFP and per CPU IRQ context. ++ */ ++ cpu_pm_exit(); ++ ++ return index; ++} ++ ++static const struct of_device_id stm32_idle_state_match[] __initconst = { ++ { .compatible = "arm,idle-state", ++ .data = stm32_enter_idle }, ++ { }, ++}; ++ ++static struct cpuidle_driver stm32_idle_driver = { ++ .name = "stm32_idle", ++ .states = { ++ ARM_CPUIDLE_WFI_STATE, ++ { ++ .enter = stm32_enter_idle, ++ .exit_latency = 620, ++ .target_residency = 700, ++ .flags = /*CPUIDLE_FLAG_TIMER_STOP | */ ++ CPUIDLE_FLAG_COUPLED, ++ .name = "CStop", ++ .desc = "Clocks off", ++ }, ++ }, ++ .safe_state_index = 0, ++ .state_count = 2, ++}; ++ ++static int stm32_pd_cpuidle_off(struct generic_pm_domain *domain) ++{ ++ struct stm32_pm_domain *priv = container_of(domain, ++ struct stm32_pm_domain, ++ genpd); ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct cpuidle_device *cpuidle_dev = per_cpu(cpuidle_devices, ++ cpu); ++ ++ cpuidle_dev->states_usage[1].disable = false; ++ } ++ ++ dev_dbg(priv->dev, "%s OFF\n", domain->name); ++ ++ return 0; ++} ++ ++static int stm32_pd_cpuidle_on(struct generic_pm_domain *domain) ++{ ++ struct stm32_pm_domain *priv = container_of(domain, ++ struct stm32_pm_domain, ++ genpd); ++ int cpu; ++ ++ for_each_possible_cpu(cpu) { ++ struct cpuidle_device *cpuidle_dev = per_cpu(cpuidle_devices, ++ cpu); ++ ++ cpuidle_dev->states_usage[1].disable = true; ++ } ++ ++ dev_dbg(priv->dev, "%s ON\n", domain->name); ++ ++ return 0; ++} ++ ++static void stm32_cpuidle_domain_remove(struct stm32_pm_domain *domain) ++{ ++ int ret; ++ ++ ret = pm_genpd_remove(&domain->genpd); ++ if (ret) ++ dev_err(domain->dev, "failed to remove PM domain %s: %d\n", ++ domain->genpd.name, ret); ++} ++ ++static int stm32_cpuidle_domain_add(struct stm32_pm_domain *domain, ++ struct device *dev, ++ struct device_node *np) ++{ ++ int ret; ++ ++ domain->dev = dev; ++ domain->genpd.name = np->name; ++ domain->genpd.power_off = stm32_pd_cpuidle_off; ++ domain->genpd.power_on = stm32_pd_cpuidle_on; ++ ++ ret = pm_genpd_init(&domain->genpd, NULL, 0); ++ if (ret < 0) { ++ dev_err(domain->dev, "failed to initialise PM domain %s: %d\n", ++ np->name, ret); ++ return ret; ++ } ++ ++ ret = of_genpd_add_provider_simple(np, &domain->genpd); ++ if (ret < 0) { ++ dev_err(domain->dev, "failed to register PM domain %s: %d\n", ++ np->name, ret); ++ stm32_cpuidle_domain_remove(domain); ++ return ret; ++ } ++ ++ dev_info(domain->dev, "domain %s registered\n", np->name); ++ ++ return 0; ++} ++ ++static int stm32_cpuidle_probe(struct platform_device *pdev) ++{ ++ struct cpuidle_driver *drv; ++ struct stm32_pm_domain *domain; ++ struct device *dev = &pdev->dev; ++ struct device_node *np = dev->of_node; ++ struct of_phandle_args child, parent; ++ struct device_node *np_child; ++ int cpu, ret; ++ ++ drv = devm_kmemdup(dev, &stm32_idle_driver, sizeof(*drv), GFP_KERNEL); ++ if (!drv) ++ return -ENOMEM; ++ ++ /* Start at index 1, index 0 standard WFI */ ++ ret = dt_init_idle_driver(drv, stm32_idle_state_match, 1); ++ if (ret < 0) ++ return ret; ++ ++ /* all the cpus of the system are coupled */ ++ ret = cpuidle_register(drv, cpu_possible_mask); ++ if (ret) ++ return ret; ++ ++ /* Declare cpuidle domain */ ++ domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL); ++ if (!domain) ++ return -ENOMEM; ++ ++ ret = stm32_cpuidle_domain_add(domain, dev, np); ++ if (ret) { ++ devm_kfree(dev, domain); ++ return ret; ++ } ++ ++ /* disable cpu idle */ ++ for_each_possible_cpu(cpu) { ++ struct cpuidle_device *cpuidle_dev = per_cpu(cpuidle_devices, ++ cpu); ++ ++ cpuidle_dev->states_usage[1].disable = true; ++ } ++ ++ /* link main cpuidle domain to consumer domain */ ++ for_each_child_of_node(np, np_child) { ++ if (!of_parse_phandle_with_args(np_child, "power-domains", ++ "#power-domain-cells", ++ 0, &child)) { ++ struct device_node *np_test = child.np; ++ ++ parent.np = np; ++ parent.args_count = 0; ++ ++ ret = of_genpd_add_subdomain(&parent, &child); ++ if (ret < 0) ++ dev_err(dev, "failed to add Sub PM domain %d\n", ++ ret); ++ ++ dev_dbg(dev, "%s, add sub cpuidle of %s, with child %s\n", ++ __func__, np->name, np_test->name); ++ ++ pm_runtime_put(dev); ++ } ++ } ++ ++ dev_info(dev, "cpuidle domain probed\n"); ++ ++ return 0; ++} ++ ++int stm32_cpuidle_remove(struct platform_device *pdev) ++{ ++ cpuidle_unregister(&stm32_idle_driver); ++ return 0; ++} ++ ++static const struct of_device_id stm32_cpuidle_of_match[] = { ++ { ++ .compatible = "stm32,cpuidle", ++ }, ++}; ++ ++static struct platform_driver stm32_cpuidle_driver = { ++ .probe = stm32_cpuidle_probe, ++ .remove = stm32_cpuidle_remove, ++ .driver = { ++ .name = "stm32_cpuidle", ++ .owner = THIS_MODULE, ++ .of_match_table = stm32_cpuidle_of_match, ++ }, ++}; ++ ++module_platform_driver(stm32_cpuidle_driver); ++ ++MODULE_AUTHOR("<>"); ++MODULE_DESCRIPTION("STM32 cpu idle driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig +index 9bddca2923301..c651aaf7d72bc 100644 +--- a/drivers/memory/Kconfig ++++ b/drivers/memory/Kconfig +@@ -163,6 +163,16 @@ config PL353_SMC + This driver is for the ARM PL351/PL353 Static Memory + Controller(SMC) module. + ++config STM32_FMC2_EBI ++ tristate "Support for FMC2 External Bus Interface on STM32MP SoCs" ++ depends on MACH_STM32MP157 || COMPILE_TEST ++ select MFD_SYSCON ++ help ++ Select this option to enable the STM32 FMC2 External Bus Interface ++ controller. This driver configures the transactions with external ++ devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on ++ SOCs containing the FMC2 External Bus Interface. ++ + source "drivers/memory/samsung/Kconfig" + source "drivers/memory/tegra/Kconfig" + +diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile +index 27b493435e61c..c7d36db6a5e9f 100644 +--- a/drivers/memory/Makefile ++++ b/drivers/memory/Makefile +@@ -21,6 +21,7 @@ obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o + obj-$(CONFIG_MTK_SMI) += mtk-smi.o + obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o + obj-$(CONFIG_PL353_SMC) += pl353-smc.o ++obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o + + obj-$(CONFIG_SAMSUNG_MC) += samsung/ + obj-$(CONFIG_TEGRA_MC) += tegra/ +diff --git a/drivers/memory/stm32-fmc2-ebi.c b/drivers/memory/stm32-fmc2-ebi.c +new file mode 100644 +index 0000000000000..4d5758c419c55 +--- /dev/null ++++ b/drivers/memory/stm32-fmc2-ebi.c +@@ -0,0 +1,1206 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) STMicroelectronics 2020 ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* FMC2 Controller Registers */ ++#define FMC2_BCR1 0x0 ++#define FMC2_BTR1 0x4 ++#define FMC2_BCR(x) ((x) * 0x8 + FMC2_BCR1) ++#define FMC2_BTR(x) ((x) * 0x8 + FMC2_BTR1) ++#define FMC2_PCSCNTR 0x20 ++#define FMC2_BWTR1 0x104 ++#define FMC2_BWTR(x) ((x) * 0x8 + FMC2_BWTR1) ++ ++/* Register: FMC2_BCR1 */ ++#define FMC2_BCR1_CCLKEN BIT(20) ++#define FMC2_BCR1_FMC2EN BIT(31) ++ ++/* Register: FMC2_BCRx */ ++#define FMC2_BCR_MBKEN BIT(0) ++#define FMC2_BCR_MUXEN BIT(1) ++#define FMC2_BCR_MTYP GENMASK(3, 2) ++#define FMC2_BCR_MWID GENMASK(5, 4) ++#define FMC2_BCR_FACCEN BIT(6) ++#define FMC2_BCR_BURSTEN BIT(8) ++#define FMC2_BCR_WAITPOL BIT(9) ++#define FMC2_BCR_WAITCFG BIT(11) ++#define FMC2_BCR_WREN BIT(12) ++#define FMC2_BCR_WAITEN BIT(13) ++#define FMC2_BCR_EXTMOD BIT(14) ++#define FMC2_BCR_ASYNCWAIT BIT(15) ++#define FMC2_BCR_CPSIZE GENMASK(18, 16) ++#define FMC2_BCR_CBURSTRW BIT(19) ++#define FMC2_BCR_NBLSET GENMASK(23, 22) ++ ++/* Register: FMC2_BTRx/FMC2_BWTRx */ ++#define FMC2_BXTR_ADDSET GENMASK(3, 0) ++#define FMC2_BXTR_ADDHLD GENMASK(7, 4) ++#define FMC2_BXTR_DATAST GENMASK(15, 8) ++#define FMC2_BXTR_BUSTURN GENMASK(19, 16) ++#define FMC2_BTR_CLKDIV GENMASK(23, 20) ++#define FMC2_BTR_DATLAT GENMASK(27, 24) ++#define FMC2_BXTR_ACCMOD GENMASK(29, 28) ++#define FMC2_BXTR_DATAHLD GENMASK(31, 30) ++ ++/* Register: FMC2_PCSCNTR */ ++#define FMC2_PCSCNTR_CSCOUNT GENMASK(15, 0) ++#define FMC2_PCSCNTR_CNTBEN(x) BIT((x) + 16) ++ ++#define FMC2_MAX_EBI_CE 4 ++#define FMC2_MAX_BANKS 5 ++ ++#define FMC2_BCR_CPSIZE_0 0x0 ++#define FMC2_BCR_CPSIZE_128 0x1 ++#define FMC2_BCR_CPSIZE_256 0x2 ++#define FMC2_BCR_CPSIZE_512 0x3 ++#define FMC2_BCR_CPSIZE_1024 0x4 ++ ++#define FMC2_BCR_MWID_8 0x0 ++#define FMC2_BCR_MWID_16 0x1 ++ ++#define FMC2_BCR_MTYP_SRAM 0x0 ++#define FMC2_BCR_MTYP_PSRAM 0x1 ++#define FMC2_BCR_MTYP_NOR 0x2 ++ ++#define FMC2_BXTR_EXTMOD_A 0x0 ++#define FMC2_BXTR_EXTMOD_B 0x1 ++#define FMC2_BXTR_EXTMOD_C 0x2 ++#define FMC2_BXTR_EXTMOD_D 0x3 ++ ++#define FMC2_BCR_NBLSET_MAX 0x3 ++#define FMC2_BXTR_ADDSET_MAX 0xf ++#define FMC2_BXTR_ADDHLD_MAX 0xf ++#define FMC2_BXTR_DATAST_MAX 0xff ++#define FMC2_BXTR_BUSTURN_MAX 0xf ++#define FMC2_BXTR_DATAHLD_MAX 0x3 ++#define FMC2_BTR_CLKDIV_MAX 0xf ++#define FMC2_BTR_DATLAT_MAX 0xf ++#define FMC2_PCSCNTR_CSCOUNT_MAX 0xff ++ ++enum stm32_fmc2_ebi_bank { ++ FMC2_EBI1 = 0, ++ FMC2_EBI2, ++ FMC2_EBI3, ++ FMC2_EBI4, ++ FMC2_NAND ++}; ++ ++enum stm32_fmc2_ebi_register_type { ++ FMC2_REG_BCR = 1, ++ FMC2_REG_BTR, ++ FMC2_REG_BWTR, ++ FMC2_REG_PCSCNTR ++}; ++ ++enum stm32_fmc2_ebi_transaction_type { ++ FMC2_ASYNC_MODE_1_SRAM = 0, ++ FMC2_ASYNC_MODE_1_PSRAM, ++ FMC2_ASYNC_MODE_A_SRAM, ++ FMC2_ASYNC_MODE_A_PSRAM, ++ FMC2_ASYNC_MODE_2_NOR, ++ FMC2_ASYNC_MODE_B_NOR, ++ FMC2_ASYNC_MODE_C_NOR, ++ FMC2_ASYNC_MODE_D_NOR, ++ FMC2_SYNC_READ_SYNC_WRITE_PSRAM, ++ FMC2_SYNC_READ_ASYNC_WRITE_PSRAM, ++ FMC2_SYNC_READ_SYNC_WRITE_NOR, ++ FMC2_SYNC_READ_ASYNC_WRITE_NOR ++}; ++ ++enum stm32_fmc2_ebi_buswidth { ++ FMC2_BUSWIDTH_8 = 8, ++ FMC2_BUSWIDTH_16 = 16 ++}; ++ ++enum stm32_fmc2_ebi_cpsize { ++ FMC2_CPSIZE_0 = 0, ++ FMC2_CPSIZE_128 = 128, ++ FMC2_CPSIZE_256 = 256, ++ FMC2_CPSIZE_512 = 512, ++ FMC2_CPSIZE_1024 = 1024 ++}; ++ ++struct stm32_fmc2_ebi { ++ struct device *dev; ++ struct clk *clk; ++ struct regmap *regmap; ++ u8 bank_assigned; ++ ++ u32 bcr[FMC2_MAX_EBI_CE]; ++ u32 btr[FMC2_MAX_EBI_CE]; ++ u32 bwtr[FMC2_MAX_EBI_CE]; ++ u32 pcscntr; ++}; ++ ++/* ++ * struct stm32_fmc2_prop - STM32 FMC2 EBI property ++ * @name: the device tree binding name of the property ++ * @bprop: indicate that it is a boolean property ++ * @mprop: indicate that it is a mandatory property ++ * @reg_type: the register that have to be modified ++ * @reg_mask: the bit that have to be modified in the selected register ++ * in case of it is a boolean property ++ * @reset_val: the default value that have to be set in case the property ++ * has not been defined in the device tree ++ * @check: this callback ckecks that the property is compliant with the ++ * transaction type selected ++ * @calculate: this callback is called to calculate for exemple a timing ++ * set in nanoseconds in the device tree in clock cycles or in ++ * clock period ++ * @set: this callback applies the values in the registers ++ */ ++struct stm32_fmc2_prop { ++ const char *name; ++ bool bprop; ++ bool mprop; ++ int reg_type; ++ u32 reg_mask; ++ u32 reset_val; ++ int (*check)(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, int cs); ++ u32 (*calculate)(struct stm32_fmc2_ebi *ebi, int cs, u32 setup); ++ int (*set)(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup); ++}; ++ ++static int stm32_fmc2_ebi_check_mux(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ u32 bcr; ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ ++ if (bcr & FMC2_BCR_MTYP) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int stm32_fmc2_ebi_check_waitcfg(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ ++ if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int stm32_fmc2_ebi_check_sync_trans(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ u32 bcr; ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ ++ if (bcr & FMC2_BCR_BURSTEN) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int stm32_fmc2_ebi_check_async_trans(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ u32 bcr; ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ ++ if (!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int stm32_fmc2_ebi_check_cpsize(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ u32 bcr, val = FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ ++ if ((bcr & FMC2_BCR_MTYP) == val && bcr & FMC2_BCR_BURSTEN) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int stm32_fmc2_ebi_check_address_hold(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ u32 bcr, bxtr, val = FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ if (prop->reg_type == FMC2_REG_BWTR) ++ regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); ++ else ++ regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); ++ ++ if ((!(bcr & FMC2_BCR_BURSTEN) || !(bcr & FMC2_BCR_CBURSTRW)) && ++ ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN)) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int stm32_fmc2_ebi_check_clk_period(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ u32 bcr, bcr1; ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ if (cs) ++ regmap_read(ebi->regmap, FMC2_BCR1, &bcr1); ++ else ++ bcr1 = bcr; ++ ++ if (bcr & FMC2_BCR_BURSTEN && (!cs || !(bcr1 & FMC2_BCR1_CCLKEN))) ++ return 0; ++ ++ return -EINVAL; ++} ++ ++static int stm32_fmc2_ebi_check_cclk(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ if (cs) ++ return -EINVAL; ++ ++ return stm32_fmc2_ebi_check_sync_trans(ebi, prop, cs); ++} ++ ++static u32 stm32_fmc2_ebi_ns_to_clock_cycles(struct stm32_fmc2_ebi *ebi, ++ int cs, u32 setup) ++{ ++ unsigned long hclk = clk_get_rate(ebi->clk); ++ unsigned long hclkp = NSEC_PER_SEC / (hclk / 1000); ++ ++ return DIV_ROUND_UP(setup * 1000, hclkp); ++} ++ ++static u32 stm32_fmc2_ebi_ns_to_clk_period(struct stm32_fmc2_ebi *ebi, ++ int cs, u32 setup) ++{ ++ u32 nb_clk_cycles = stm32_fmc2_ebi_ns_to_clock_cycles(ebi, cs, setup); ++ u32 bcr, btr, clk_period; ++ ++ regmap_read(ebi->regmap, FMC2_BCR1, &bcr); ++ if (bcr & FMC2_BCR1_CCLKEN || !cs) ++ regmap_read(ebi->regmap, FMC2_BTR1, &btr); ++ else ++ regmap_read(ebi->regmap, FMC2_BTR(cs), &btr); ++ ++ clk_period = FIELD_GET(FMC2_BTR_CLKDIV, btr) + 1; ++ ++ return DIV_ROUND_UP(nb_clk_cycles, clk_period); ++} ++ ++static int stm32_fmc2_ebi_get_reg(int reg_type, int cs, u32 *reg) ++{ ++ switch (reg_type) { ++ case FMC2_REG_BCR: ++ *reg = FMC2_BCR(cs); ++ break; ++ case FMC2_REG_BTR: ++ *reg = FMC2_BTR(cs); ++ break; ++ case FMC2_REG_BWTR: ++ *reg = FMC2_BWTR(cs); ++ break; ++ case FMC2_REG_PCSCNTR: ++ *reg = FMC2_PCSCNTR; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_bit_field(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 reg; ++ int ret; ++ ++ ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); ++ if (ret) ++ return ret; ++ ++ regmap_update_bits(ebi->regmap, reg, prop->reg_mask, ++ setup ? prop->reg_mask : 0); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_trans_type(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 bcr_mask, bcr = FMC2_BCR_WREN; ++ u32 btr_mask, btr = 0; ++ u32 bwtr_mask, bwtr = 0; ++ ++ bwtr_mask = FMC2_BXTR_ACCMOD; ++ btr_mask = FMC2_BXTR_ACCMOD; ++ bcr_mask = FMC2_BCR_MUXEN | FMC2_BCR_MTYP | FMC2_BCR_FACCEN | ++ FMC2_BCR_WREN | FMC2_BCR_WAITEN | FMC2_BCR_BURSTEN | ++ FMC2_BCR_EXTMOD | FMC2_BCR_CBURSTRW; ++ ++ switch (setup) { ++ case FMC2_ASYNC_MODE_1_SRAM: ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_SRAM); ++ /* ++ * MUXEN = 0, MTYP = 0, FACCEN = 0, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 ++ */ ++ break; ++ case FMC2_ASYNC_MODE_1_PSRAM: ++ /* ++ * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); ++ break; ++ case FMC2_ASYNC_MODE_A_SRAM: ++ /* ++ * MUXEN = 0, MTYP = 0, FACCEN = 0, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_SRAM); ++ bcr |= FMC2_BCR_EXTMOD; ++ btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); ++ bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); ++ break; ++ case FMC2_ASYNC_MODE_A_PSRAM: ++ /* ++ * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); ++ bcr |= FMC2_BCR_EXTMOD; ++ btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); ++ bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_A); ++ break; ++ case FMC2_ASYNC_MODE_2_NOR: ++ /* ++ * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); ++ bcr |= FMC2_BCR_FACCEN; ++ break; ++ case FMC2_ASYNC_MODE_B_NOR: ++ /* ++ * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 1 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); ++ bcr |= FMC2_BCR_FACCEN | FMC2_BCR_EXTMOD; ++ btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_B); ++ bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_B); ++ break; ++ case FMC2_ASYNC_MODE_C_NOR: ++ /* ++ * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 2 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); ++ bcr |= FMC2_BCR_FACCEN | FMC2_BCR_EXTMOD; ++ btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_C); ++ bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_C); ++ break; ++ case FMC2_ASYNC_MODE_D_NOR: ++ /* ++ * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 0, WAITEN = 0, ++ * WREN = 1, EXTMOD = 1, CBURSTRW = 0, ACCMOD = 3 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); ++ bcr |= FMC2_BCR_FACCEN | FMC2_BCR_EXTMOD; ++ btr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); ++ bwtr |= FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); ++ break; ++ case FMC2_SYNC_READ_SYNC_WRITE_PSRAM: ++ /* ++ * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 1, WAITEN = 0, ++ * WREN = 1, EXTMOD = 0, CBURSTRW = 1, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); ++ bcr |= FMC2_BCR_BURSTEN | FMC2_BCR_CBURSTRW; ++ break; ++ case FMC2_SYNC_READ_ASYNC_WRITE_PSRAM: ++ /* ++ * MUXEN = 0, MTYP = 1, FACCEN = 0, BURSTEN = 1, WAITEN = 0, ++ * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_PSRAM); ++ bcr |= FMC2_BCR_BURSTEN; ++ break; ++ case FMC2_SYNC_READ_SYNC_WRITE_NOR: ++ /* ++ * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 1, WAITEN = 0, ++ * WREN = 1, EXTMOD = 0, CBURSTRW = 1, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); ++ bcr |= FMC2_BCR_FACCEN | FMC2_BCR_BURSTEN | FMC2_BCR_CBURSTRW; ++ break; ++ case FMC2_SYNC_READ_ASYNC_WRITE_NOR: ++ /* ++ * MUXEN = 0, MTYP = 2, FACCEN = 1, BURSTEN = 1, WAITEN = 0, ++ * WREN = 1, EXTMOD = 0, CBURSTRW = 0, ACCMOD = 0 ++ */ ++ bcr |= FIELD_PREP(FMC2_BCR_MTYP, FMC2_BCR_MTYP_NOR); ++ bcr |= FMC2_BCR_FACCEN | FMC2_BCR_BURSTEN; ++ break; ++ default: ++ /* Type of transaction not supported */ ++ return -EINVAL; ++ } ++ ++ if (bcr & FMC2_BCR_EXTMOD) ++ regmap_update_bits(ebi->regmap, FMC2_BWTR(cs), ++ bwtr_mask, bwtr); ++ regmap_update_bits(ebi->regmap, FMC2_BTR(cs), btr_mask, btr); ++ regmap_update_bits(ebi->regmap, FMC2_BCR(cs), bcr_mask, bcr); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_buswidth(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val; ++ ++ switch (setup) { ++ case FMC2_BUSWIDTH_8: ++ val = FIELD_PREP(FMC2_BCR_MWID, FMC2_BCR_MWID_8); ++ break; ++ case FMC2_BUSWIDTH_16: ++ val = FIELD_PREP(FMC2_BCR_MWID, FMC2_BCR_MWID_16); ++ break; ++ default: ++ /* Buswidth not supported */ ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_MWID, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_cpsize(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val; ++ ++ switch (setup) { ++ case FMC2_CPSIZE_0: ++ val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_0); ++ break; ++ case FMC2_CPSIZE_128: ++ val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_128); ++ break; ++ case FMC2_CPSIZE_256: ++ val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_256); ++ break; ++ case FMC2_CPSIZE_512: ++ val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_512); ++ break; ++ case FMC2_CPSIZE_1024: ++ val = FIELD_PREP(FMC2_BCR_CPSIZE, FMC2_BCR_CPSIZE_1024); ++ break; ++ default: ++ /* Cpsize not supported */ ++ return -EINVAL; ++ } ++ ++ regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_CPSIZE, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_bl_setup(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val; ++ ++ val = min_t(u32, setup, FMC2_BCR_NBLSET_MAX); ++ val = FIELD_PREP(FMC2_BCR_NBLSET, val); ++ regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_NBLSET, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_address_setup(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 bcr, bxtr, reg; ++ u32 val = FIELD_PREP(FMC2_BXTR_ACCMOD, FMC2_BXTR_EXTMOD_D); ++ int ret; ++ ++ ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); ++ if (ret) ++ return ret; ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ if (prop->reg_type == FMC2_REG_BWTR) ++ regmap_read(ebi->regmap, FMC2_BWTR(cs), &bxtr); ++ else ++ regmap_read(ebi->regmap, FMC2_BTR(cs), &bxtr); ++ ++ if ((bxtr & FMC2_BXTR_ACCMOD) == val || bcr & FMC2_BCR_MUXEN) ++ val = clamp_val(setup, 1, FMC2_BXTR_ADDSET_MAX); ++ else ++ val = min_t(u32, setup, FMC2_BXTR_ADDSET_MAX); ++ val = FIELD_PREP(FMC2_BXTR_ADDSET, val); ++ regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_ADDSET, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_address_hold(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val, reg; ++ int ret; ++ ++ ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); ++ if (ret) ++ return ret; ++ ++ val = clamp_val(setup, 1, FMC2_BXTR_ADDHLD_MAX); ++ val = FIELD_PREP(FMC2_BXTR_ADDHLD, val); ++ regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_ADDHLD, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_data_setup(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val, reg; ++ int ret; ++ ++ ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); ++ if (ret) ++ return ret; ++ ++ val = clamp_val(setup, 1, FMC2_BXTR_DATAST_MAX); ++ val = FIELD_PREP(FMC2_BXTR_DATAST, val); ++ regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_DATAST, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_bus_turnaround(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val, reg; ++ int ret; ++ ++ ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); ++ if (ret) ++ return ret; ++ ++ val = setup ? min_t(u32, setup - 1, FMC2_BXTR_BUSTURN_MAX) : 0; ++ val = FIELD_PREP(FMC2_BXTR_BUSTURN, val); ++ regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_BUSTURN, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_data_hold(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val, reg; ++ int ret; ++ ++ ret = stm32_fmc2_ebi_get_reg(prop->reg_type, cs, ®); ++ if (ret) ++ return ret; ++ ++ if (prop->reg_type == FMC2_REG_BWTR) ++ val = setup ? min_t(u32, setup - 1, FMC2_BXTR_DATAHLD_MAX) : 0; ++ else ++ val = min_t(u32, setup, FMC2_BXTR_DATAHLD_MAX); ++ val = FIELD_PREP(FMC2_BXTR_DATAHLD, val); ++ regmap_update_bits(ebi->regmap, reg, FMC2_BXTR_DATAHLD, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_clk_period(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val; ++ ++ val = setup ? clamp_val(setup - 1, 1, FMC2_BTR_CLKDIV_MAX) : 1; ++ val = FIELD_PREP(FMC2_BTR_CLKDIV, val); ++ regmap_update_bits(ebi->regmap, FMC2_BTR(cs), FMC2_BTR_CLKDIV, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_data_latency(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 val; ++ ++ val = setup > 1 ? min_t(u32, setup - 2, FMC2_BTR_DATLAT_MAX) : 0; ++ val = FIELD_PREP(FMC2_BTR_DATLAT, val); ++ regmap_update_bits(ebi->regmap, FMC2_BTR(cs), FMC2_BTR_DATLAT, val); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_set_max_low_pulse(struct stm32_fmc2_ebi *ebi, ++ const struct stm32_fmc2_prop *prop, ++ int cs, u32 setup) ++{ ++ u32 old_val, new_val, pcscntr; ++ ++ if (setup < 1) ++ return 0; ++ ++ regmap_read(ebi->regmap, FMC2_PCSCNTR, &pcscntr); ++ ++ /* Enable counter for the bank */ ++ regmap_update_bits(ebi->regmap, FMC2_PCSCNTR, ++ FMC2_PCSCNTR_CNTBEN(cs), ++ FMC2_PCSCNTR_CNTBEN(cs)); ++ ++ new_val = min_t(u32, setup - 1, FMC2_PCSCNTR_CSCOUNT_MAX); ++ old_val = FIELD_GET(FMC2_PCSCNTR_CSCOUNT, pcscntr); ++ if (old_val && new_val > old_val) ++ /* Keep current counter value */ ++ return 0; ++ ++ new_val = FIELD_PREP(FMC2_PCSCNTR_CSCOUNT, new_val); ++ regmap_update_bits(ebi->regmap, FMC2_PCSCNTR, ++ FMC2_PCSCNTR_CSCOUNT, new_val); ++ ++ return 0; ++} ++ ++static const struct stm32_fmc2_prop stm32_fmc2_child_props[] = { ++ /* st,fmc2-ebi-cs-trans-type must be the first property */ ++ { ++ .name = "st,fmc2-ebi-cs-transaction-type", ++ .mprop = true, ++ .set = stm32_fmc2_ebi_set_trans_type, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-cclk-enable", ++ .bprop = true, ++ .reg_type = FMC2_REG_BCR, ++ .reg_mask = FMC2_BCR1_CCLKEN, ++ .check = stm32_fmc2_ebi_check_cclk, ++ .set = stm32_fmc2_ebi_set_bit_field, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-mux-enable", ++ .bprop = true, ++ .reg_type = FMC2_REG_BCR, ++ .reg_mask = FMC2_BCR_MUXEN, ++ .check = stm32_fmc2_ebi_check_mux, ++ .set = stm32_fmc2_ebi_set_bit_field, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-buswidth", ++ .reset_val = FMC2_BUSWIDTH_16, ++ .set = stm32_fmc2_ebi_set_buswidth, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-waitpol-high", ++ .bprop = true, ++ .reg_type = FMC2_REG_BCR, ++ .reg_mask = FMC2_BCR_WAITPOL, ++ .set = stm32_fmc2_ebi_set_bit_field, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-waitcfg-enable", ++ .bprop = true, ++ .reg_type = FMC2_REG_BCR, ++ .reg_mask = FMC2_BCR_WAITCFG, ++ .check = stm32_fmc2_ebi_check_waitcfg, ++ .set = stm32_fmc2_ebi_set_bit_field, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-wait-enable", ++ .bprop = true, ++ .reg_type = FMC2_REG_BCR, ++ .reg_mask = FMC2_BCR_WAITEN, ++ .check = stm32_fmc2_ebi_check_sync_trans, ++ .set = stm32_fmc2_ebi_set_bit_field, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-asyncwait-enable", ++ .bprop = true, ++ .reg_type = FMC2_REG_BCR, ++ .reg_mask = FMC2_BCR_ASYNCWAIT, ++ .check = stm32_fmc2_ebi_check_async_trans, ++ .set = stm32_fmc2_ebi_set_bit_field, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-cpsize", ++ .check = stm32_fmc2_ebi_check_cpsize, ++ .set = stm32_fmc2_ebi_set_cpsize, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-byte-lane-setup-ns", ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_bl_setup, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-address-setup-ns", ++ .reg_type = FMC2_REG_BTR, ++ .reset_val = FMC2_BXTR_ADDSET_MAX, ++ .check = stm32_fmc2_ebi_check_async_trans, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_address_setup, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-address-hold-ns", ++ .reg_type = FMC2_REG_BTR, ++ .reset_val = FMC2_BXTR_ADDHLD_MAX, ++ .check = stm32_fmc2_ebi_check_address_hold, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_address_hold, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-data-setup-ns", ++ .reg_type = FMC2_REG_BTR, ++ .reset_val = FMC2_BXTR_DATAST_MAX, ++ .check = stm32_fmc2_ebi_check_async_trans, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_data_setup, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-bus-turnaround-ns", ++ .reg_type = FMC2_REG_BTR, ++ .reset_val = FMC2_BXTR_BUSTURN_MAX + 1, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_bus_turnaround, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-data-hold-ns", ++ .reg_type = FMC2_REG_BTR, ++ .check = stm32_fmc2_ebi_check_async_trans, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_data_hold, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-clk-period-ns", ++ .reset_val = FMC2_BTR_CLKDIV_MAX + 1, ++ .check = stm32_fmc2_ebi_check_clk_period, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_clk_period, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-data-latency-ns", ++ .check = stm32_fmc2_ebi_check_sync_trans, ++ .calculate = stm32_fmc2_ebi_ns_to_clk_period, ++ .set = stm32_fmc2_ebi_set_data_latency, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-write-address-setup-ns", ++ .reg_type = FMC2_REG_BWTR, ++ .reset_val = FMC2_BXTR_ADDSET_MAX, ++ .check = stm32_fmc2_ebi_check_async_trans, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_address_setup, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-write-address-hold-ns", ++ .reg_type = FMC2_REG_BWTR, ++ .reset_val = FMC2_BXTR_ADDHLD_MAX, ++ .check = stm32_fmc2_ebi_check_address_hold, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_address_hold, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-write-data-setup-ns", ++ .reg_type = FMC2_REG_BWTR, ++ .reset_val = FMC2_BXTR_DATAST_MAX, ++ .check = stm32_fmc2_ebi_check_async_trans, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_data_setup, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-write-bus-turnaround-ns", ++ .reg_type = FMC2_REG_BWTR, ++ .reset_val = FMC2_BXTR_BUSTURN_MAX + 1, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_bus_turnaround, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-write-data-hold-ns", ++ .reg_type = FMC2_REG_BWTR, ++ .check = stm32_fmc2_ebi_check_async_trans, ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_data_hold, ++ }, ++ { ++ .name = "st,fmc2-ebi-cs-max-low-pulse-ns", ++ .calculate = stm32_fmc2_ebi_ns_to_clock_cycles, ++ .set = stm32_fmc2_ebi_set_max_low_pulse, ++ }, ++}; ++ ++static int stm32_fmc2_ebi_parse_prop(struct stm32_fmc2_ebi *ebi, ++ struct device_node *dev_node, ++ const struct stm32_fmc2_prop *prop, ++ int cs) ++{ ++ struct device *dev = ebi->dev; ++ u32 setup = 0; ++ ++ if (!prop->set) { ++ dev_err(dev, "property %s is not well defined\n", prop->name); ++ return -EINVAL; ++ } ++ ++ if (prop->check && prop->check(ebi, prop, cs)) ++ /* Skeep this property */ ++ return 0; ++ ++ if (prop->bprop) { ++ bool bprop; ++ ++ bprop = of_property_read_bool(dev_node, prop->name); ++ if (prop->mprop && !bprop) { ++ dev_err(dev, "mandatory property %s not defined in the device tree\n", ++ prop->name); ++ return -EINVAL; ++ } ++ ++ if (bprop) ++ setup = 1; ++ } else { ++ u32 val; ++ int ret; ++ ++ ret = of_property_read_u32(dev_node, prop->name, &val); ++ if (prop->mprop && ret) { ++ dev_err(dev, "mandatory property %s not defined in the device tree\n", ++ prop->name); ++ return ret; ++ } ++ ++ if (ret) ++ setup = prop->reset_val; ++ else if (prop->calculate) ++ setup = prop->calculate(ebi, cs, val); ++ else ++ setup = val; ++ } ++ ++ return prop->set(ebi, prop, cs, setup); ++} ++ ++static void stm32_fmc2_ebi_enable_bank(struct stm32_fmc2_ebi *ebi, int cs) ++{ ++ regmap_update_bits(ebi->regmap, FMC2_BCR(cs), ++ FMC2_BCR_MBKEN, FMC2_BCR_MBKEN); ++} ++ ++static void stm32_fmc2_ebi_disable_bank(struct stm32_fmc2_ebi *ebi, int cs) ++{ ++ regmap_update_bits(ebi->regmap, FMC2_BCR(cs), FMC2_BCR_MBKEN, 0); ++} ++ ++static void stm32_fmc2_ebi_save_setup(struct stm32_fmc2_ebi *ebi) ++{ ++ unsigned int cs; ++ ++ for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &ebi->bcr[cs]); ++ regmap_read(ebi->regmap, FMC2_BTR(cs), &ebi->btr[cs]); ++ regmap_read(ebi->regmap, FMC2_BWTR(cs), &ebi->bwtr[cs]); ++ } ++ ++ regmap_read(ebi->regmap, FMC2_PCSCNTR, &ebi->pcscntr); ++} ++ ++static void stm32_fmc2_ebi_set_setup(struct stm32_fmc2_ebi *ebi) ++{ ++ unsigned int cs; ++ ++ for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { ++ regmap_write(ebi->regmap, FMC2_BCR(cs), ebi->bcr[cs]); ++ regmap_write(ebi->regmap, FMC2_BTR(cs), ebi->btr[cs]); ++ regmap_write(ebi->regmap, FMC2_BWTR(cs), ebi->bwtr[cs]); ++ } ++ ++ regmap_write(ebi->regmap, FMC2_PCSCNTR, ebi->pcscntr); ++} ++ ++static void stm32_fmc2_ebi_disable_banks(struct stm32_fmc2_ebi *ebi) ++{ ++ unsigned int cs; ++ ++ for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { ++ if (!(ebi->bank_assigned & BIT(cs))) ++ continue; ++ ++ stm32_fmc2_ebi_disable_bank(ebi, cs); ++ } ++} ++ ++/* NWAIT signal can not be connected to EBI controller and NAND controller */ ++static bool stm32_fmc2_ebi_nwait_used_by_ctrls(struct stm32_fmc2_ebi *ebi) ++{ ++ unsigned int cs; ++ u32 bcr; ++ ++ for (cs = 0; cs < FMC2_MAX_EBI_CE; cs++) { ++ if (!(ebi->bank_assigned & BIT(cs))) ++ continue; ++ ++ regmap_read(ebi->regmap, FMC2_BCR(cs), &bcr); ++ if ((bcr & FMC2_BCR_WAITEN || bcr & FMC2_BCR_ASYNCWAIT) && ++ ebi->bank_assigned & BIT(FMC2_NAND)) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void stm32_fmc2_ebi_enable(struct stm32_fmc2_ebi *ebi) ++{ ++ regmap_update_bits(ebi->regmap, FMC2_BCR1, ++ FMC2_BCR1_FMC2EN, FMC2_BCR1_FMC2EN); ++} ++ ++static void stm32_fmc2_ebi_disable(struct stm32_fmc2_ebi *ebi) ++{ ++ regmap_update_bits(ebi->regmap, FMC2_BCR1, FMC2_BCR1_FMC2EN, 0); ++} ++ ++static int stm32_fmc2_ebi_setup_cs(struct stm32_fmc2_ebi *ebi, ++ struct device_node *dev_node, ++ u32 cs) ++{ ++ unsigned int i; ++ int ret; ++ ++ stm32_fmc2_ebi_disable_bank(ebi, cs); ++ ++ for (i = 0; i < ARRAY_SIZE(stm32_fmc2_child_props); i++) { ++ const struct stm32_fmc2_prop *p = &stm32_fmc2_child_props[i]; ++ ++ ret = stm32_fmc2_ebi_parse_prop(ebi, dev_node, p, cs); ++ if (ret) { ++ dev_err(ebi->dev, "property %s could not be set: %d\n", ++ p->name, ret); ++ return ret; ++ } ++ } ++ ++ stm32_fmc2_ebi_enable_bank(ebi, cs); ++ ++ return 0; ++} ++ ++static int stm32_fmc2_ebi_parse_dt(struct stm32_fmc2_ebi *ebi) ++{ ++ struct device *dev = ebi->dev; ++ struct device_node *child; ++ bool child_found = false; ++ u32 bank; ++ int ret; ++ ++ for_each_available_child_of_node(dev->of_node, child) { ++ ret = of_property_read_u32(child, "reg", &bank); ++ if (ret) { ++ dev_err(dev, "could not retrieve reg property: %d\n", ++ ret); ++ return ret; ++ } ++ ++ if (bank >= FMC2_MAX_BANKS) { ++ dev_err(dev, "invalid reg value: %d\n", bank); ++ return -EINVAL; ++ } ++ ++ if (ebi->bank_assigned & BIT(bank)) { ++ dev_err(dev, "bank already assigned: %d\n", bank); ++ return -EINVAL; ++ } ++ ++ if (bank < FMC2_MAX_EBI_CE) { ++ ret = stm32_fmc2_ebi_setup_cs(ebi, child, bank); ++ if (ret) { ++ dev_err(dev, "setup chip select %d failed: %d\n", ++ bank, ret); ++ return ret; ++ } ++ } ++ ++ ebi->bank_assigned |= BIT(bank); ++ child_found = true; ++ } ++ ++ if (!child_found) { ++ dev_warn(dev, "no subnodes found, disable the driver.\n"); ++ return -ENODEV; ++ } ++ ++ if (stm32_fmc2_ebi_nwait_used_by_ctrls(ebi)) { ++ dev_err(dev, "NWAIT signal connected to EBI and NAND controllers\n"); ++ return -EINVAL; ++ } ++ ++ stm32_fmc2_ebi_enable(ebi); ++ ++ return of_platform_populate(dev->of_node, NULL, NULL, dev); ++} ++ ++static int stm32_fmc2_ebi_probe(struct platform_device *pdev) ++{ ++ struct device *dev = &pdev->dev; ++ struct stm32_fmc2_ebi *ebi; ++ struct reset_control *rstc; ++ int ret; ++ ++ ebi = devm_kzalloc(&pdev->dev, sizeof(*ebi), GFP_KERNEL); ++ if (!ebi) ++ return -ENOMEM; ++ ++ ebi->dev = dev; ++ ++ ebi->regmap = device_node_to_regmap(dev->of_node); ++ if (IS_ERR(ebi->regmap)) ++ return PTR_ERR(ebi->regmap); ++ ++ ebi->clk = devm_clk_get(dev, NULL); ++ if (IS_ERR(ebi->clk)) ++ return PTR_ERR(ebi->clk); ++ ++ rstc = devm_reset_control_get(dev, NULL); ++ if (PTR_ERR(rstc) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ ret = clk_prepare_enable(ebi->clk); ++ if (ret) ++ return ret; ++ ++ if (!IS_ERR(rstc)) { ++ reset_control_assert(rstc); ++ reset_control_deassert(rstc); ++ } ++ ++ ret = stm32_fmc2_ebi_parse_dt(ebi); ++ if (ret) ++ goto err_release; ++ ++ stm32_fmc2_ebi_save_setup(ebi); ++ platform_set_drvdata(pdev, ebi); ++ ++ return 0; ++ ++err_release: ++ stm32_fmc2_ebi_disable_banks(ebi); ++ stm32_fmc2_ebi_disable(ebi); ++ clk_disable_unprepare(ebi->clk); ++ ++ return ret; ++} ++ ++static int stm32_fmc2_ebi_remove(struct platform_device *pdev) ++{ ++ struct stm32_fmc2_ebi *ebi = platform_get_drvdata(pdev); ++ ++ of_platform_depopulate(&pdev->dev); ++ stm32_fmc2_ebi_disable_banks(ebi); ++ stm32_fmc2_ebi_disable(ebi); ++ clk_disable_unprepare(ebi->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_fmc2_ebi_suspend(struct device *dev) ++{ ++ struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev); ++ ++ stm32_fmc2_ebi_disable(ebi); ++ clk_disable_unprepare(ebi->clk); ++ pinctrl_pm_select_sleep_state(dev); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_fmc2_ebi_resume(struct device *dev) ++{ ++ struct stm32_fmc2_ebi *ebi = dev_get_drvdata(dev); ++ int ret; ++ ++ pinctrl_pm_select_default_state(dev); ++ ++ ret = clk_prepare_enable(ebi->clk); ++ if (ret) ++ return ret; ++ ++ stm32_fmc2_ebi_set_setup(ebi); ++ stm32_fmc2_ebi_enable(ebi); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(stm32_fmc2_ebi_pm_ops, stm32_fmc2_ebi_suspend, ++ stm32_fmc2_ebi_resume); ++ ++static const struct of_device_id stm32_fmc2_ebi_match[] = { ++ {.compatible = "st,stm32mp1-fmc2-ebi"}, ++ {} ++}; ++MODULE_DEVICE_TABLE(of, stm32_fmc2_ebi_match); ++ ++static struct platform_driver stm32_fmc2_ebi_driver = { ++ .probe = stm32_fmc2_ebi_probe, ++ .remove = stm32_fmc2_ebi_remove, ++ .driver = { ++ .name = "stm32_fmc2_ebi", ++ .of_match_table = stm32_fmc2_ebi_match, ++ .pm = &stm32_fmc2_ebi_pm_ops, ++ }, ++}; ++module_platform_driver(stm32_fmc2_ebi_driver); ++ ++MODULE_ALIAS("platform:stm32_fmc2_ebi"); ++MODULE_AUTHOR("Christophe Kerello "); ++MODULE_DESCRIPTION("STMicroelectronics STM32 FMC2 ebi driver"); ++MODULE_LICENSE("GPL v2"); +diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h +index 661efa029c963..faee74f369e78 100644 +--- a/include/linux/pm_wakeup.h ++++ b/include/linux/pm_wakeup.h +@@ -79,6 +79,11 @@ static inline bool device_may_wakeup(struct device *dev) + return dev->power.can_wakeup && !!dev->power.wakeup; + } + ++static inline bool device_wakeup_path(struct device *dev) ++{ ++ return !!dev->power.wakeup_path; ++} ++ + static inline void device_set_wakeup_path(struct device *dev) + { + dev->power.wakeup_path = true; +@@ -165,6 +170,11 @@ static inline bool device_may_wakeup(struct device *dev) + return dev->power.can_wakeup && dev->power.should_wakeup; + } + ++static inline bool device_wakeup_path(struct device *dev) ++{ ++ return false; ++} ++ + static inline void device_set_wakeup_path(struct device *dev) {} + + static inline void __pm_stay_awake(struct wakeup_source *ws) {} +diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c +index 27f149f5d4a9f..4581702e8cdd2 100644 +--- a/kernel/power/suspend.c ++++ b/kernel/power/suspend.c +@@ -34,7 +34,6 @@ + #include "power.h" + + const char * const pm_labels[] = { +- [PM_SUSPEND_TO_IDLE] = "freeze", + [PM_SUSPEND_STANDBY] = "standby", + [PM_SUSPEND_MEM] = "mem", + }; +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0020-ARM-stm32mp1-r2-DEVICETREE.patch similarity index 87% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0020-ARM-stm32mp1-r2-DEVICETREE.patch index d47d1da..597a203 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0020-ARM-stm32mp1-r1-DEVICETREE.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0020-ARM-stm32mp1-r2-DEVICETREE.patch @@ -1,17 +1,12 @@ -From 52b77d7689df6579e251a92b3911b13b3124d363 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:49:54 +0200 -Subject: [PATCH 20/23] ARM-stm32mp1-r1-DEVICETREE +From 1c76b63cabbc962d7974d624cf41e8e655ce44a9 Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:55 +0200 +Subject: [PATCH 20/22] ARM-stm32mp1-r2-rc8-DEVICETREE --- .../devicetree/bindings/arm/stm32/stm32.yaml | 5 +- .../bindings/clock/st,stm32mp1-rcc.txt | 5 +- - .../bindings/connector/usb-connector.txt | 2 + .../bindings/cpufreq/stm32-cpufreq.txt | 61 + - .../display/panel/orisetech,otm8009a.txt | 23 - - .../display/panel/orisetech,otm8009a.yaml | 53 + - .../display/panel/raydium,rm68200.txt | 25 - - .../display/panel/raydium,rm68200.yaml | 52 + .../devicetree/bindings/dma/stm32-dma.txt | 36 +- .../devicetree/bindings/dma/stm32-dmamux.txt | 5 +- .../devicetree/bindings/dma/stm32-mdma.txt | 66 +- @@ -23,49 +18,36 @@ Subject: [PATCH 20/23] ARM-stm32mp1-r1-DEVICETREE .../iio/timer/stm32-timer-trigger.txt | 9 + .../interrupt-controller/st,stm32-exti.txt | 30 +- .../devicetree/bindings/mailbox/arm-smc.yaml | 96 ++ - .../bindings/mailbox/stm32-ipcc.txt | 4 +- - .../bindings/media/video-interfaces.txt | 2 + - .../bindings/mfd/st,stm32mp1-pwr.txt | 57 + - .../devicetree/bindings/mmc/mmci.txt | 2 + .../bindings/perf/stm32-ddr-pmu.txt | 18 + - .../bindings/phy/phy-stm32-usbphyc.txt | 59 +- - .../bindings/pinctrl/st,stm32-pinctrl.yaml | 8 + - .../devicetree/bindings/pwm/pwm-stm32.txt | 8 +- - .../bindings/remoteproc/rproc-srm.txt | 58 + - .../bindings/remoteproc/stm32-rproc.txt | 13 + - .../devicetree/bindings/rtc/st,stm32-rtc.txt | 10 +- - .../bindings/serial/st,stm32-usart.txt | 46 +- - .../bindings/soc/stm32/stm32_hdp.txt | 39 + - .../devicetree/bindings/usb/dwc2.txt | 8 + - .../devicetree/bindings/usb/generic-ehci.yaml | 5 + - .../bindings/usb/st,typec-stusb.txt | 48 + - arch/arm/boot/dts/Makefile | 19 +- - arch/arm/boot/dts/stm32mp15-no-scmi.dtsi | 157 ++ + .../devicetree/bindings/serial/rs485.txt | 7 + + .../bindings/serial/st,stm32-usart.txt | 64 +- + arch/arm/boot/dts/Makefile | 51 +- + arch/arm/boot/dts/stm32mp15-no-scmi.dtsi | 156 ++ arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 1411 +++++++++++++++++ - .../dts/{stm32mp157c.dtsi => stm32mp151.dtsi} | 941 ++++++++--- + .../dts/{stm32mp157c.dtsi => stm32mp151.dtsi} | 986 +++++++++--- arch/arm/boot/dts/stm32mp153.dtsi | 54 + .../boot/dts/stm32mp157-m4-srm-pinctrl.dtsi | 524 ++++++ arch/arm/boot/dts/stm32mp157-m4-srm.dtsi | 442 ++++++ arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 925 ----------- arch/arm/boot/dts/stm32mp157.dtsi | 32 + arch/arm/boot/dts/stm32mp157a-avenger96.dts | 17 +- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 431 +---- - arch/arm/boot/dts/stm32mp157a-ed1.dts | 52 + + arch/arm/boot/dts/stm32mp157a-dk1.dts | 434 +---- + arch/arm/boot/dts/stm32mp157a-ed1.dts | 43 + arch/arm/boot/dts/stm32mp157a-ev1.dts | 86 + - .../boot/dts/stm32mp157c-dk2-a7-examples.dts | 46 + + .../boot/dts/stm32mp157c-dk2-a7-examples.dts | 60 + .../boot/dts/stm32mp157c-dk2-m4-examples.dts | 129 ++ - arch/arm/boot/dts/stm32mp157c-dk2.dts | 126 +- - arch/arm/boot/dts/stm32mp157c-ed1.dts | 317 +--- - .../boot/dts/stm32mp157c-ev1-a7-examples.dts | 53 + + arch/arm/boot/dts/stm32mp157c-dk2.dts | 113 +- + arch/arm/boot/dts/stm32mp157c-ed1.dts | 320 +--- + .../boot/dts/stm32mp157c-ev1-a7-examples.dts | 57 + .../boot/dts/stm32mp157c-ev1-m4-examples.dts | 146 ++ arch/arm/boot/dts/stm32mp157c-ev1.dts | 293 +--- - arch/arm/boot/dts/stm32mp157d-dk1.dts | 44 + - arch/arm/boot/dts/stm32mp157d-ed1.dts | 52 + + arch/arm/boot/dts/stm32mp157d-dk1.dts | 35 + + arch/arm/boot/dts/stm32mp157d-ed1.dts | 43 + arch/arm/boot/dts/stm32mp157d-ev1.dts | 86 + - .../boot/dts/stm32mp157f-dk2-a7-examples.dts | 46 + + .../boot/dts/stm32mp157f-dk2-a7-examples.dts | 52 + .../boot/dts/stm32mp157f-dk2-m4-examples.dts | 129 ++ - arch/arm/boot/dts/stm32mp157f-dk2.dts | 185 +++ - arch/arm/boot/dts/stm32mp157f-ed1.dts | 56 + + arch/arm/boot/dts/stm32mp157f-dk2.dts | 171 ++ + arch/arm/boot/dts/stm32mp157f-ed1.dts | 47 + .../boot/dts/stm32mp157f-ev1-a7-examples.dts | 53 + .../boot/dts/stm32mp157f-ev1-m4-examples.dts | 146 ++ arch/arm/boot/dts/stm32mp157f-ev1.dts | 86 + @@ -77,34 +59,20 @@ Subject: [PATCH 20/23] ARM-stm32mp1-r1-DEVICETREE arch/arm/boot/dts/stm32mp15xc.dtsi | 20 + arch/arm/boot/dts/stm32mp15xd.dtsi | 42 + arch/arm/boot/dts/stm32mp15xf.dtsi | 20 + - arch/arm/boot/dts/stm32mp15xx-dkx.dtsi | 768 +++++++++ - arch/arm/boot/dts/stm32mp15xx-edx.dtsi | 408 +++++ - arch/arm/boot/dts/stm32mp15xx-evx.dtsi | 680 ++++++++ + arch/arm/boot/dts/stm32mp15xx-dkx.dtsi | 770 +++++++++ + arch/arm/boot/dts/stm32mp15xx-edx.dtsi | 407 +++++ + arch/arm/boot/dts/stm32mp15xx-evx.dtsi | 687 ++++++++ arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi | 85 + arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi | 57 + arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi | 73 + arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi | 57 + - include/dt-bindings/clock/stm32mp1-clks.h | 33 + - include/dt-bindings/mfd/stm32f4-rcc.h | 1 - - include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + - include/dt-bindings/reset/stm32mp1-resets.h | 13 + - include/dt-bindings/rtc/rtc-stm32.h | 13 + - include/dt-bindings/soc/stm32-hdp.h | 108 ++ - 86 files changed, 8088 insertions(+), 2583 deletions(-) + 62 files changed, 7555 insertions(+), 2547 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt - delete mode 100644 Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt - create mode 100644 Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml - delete mode 100644 Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt - create mode 100644 Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml create mode 100644 Documentation/devicetree/bindings/mailbox/arm-smc.yaml - create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt create mode 100644 Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt - create mode 100644 Documentation/devicetree/bindings/remoteproc/rproc-srm.txt - create mode 100644 Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt - create mode 100644 Documentation/devicetree/bindings/usb/st,typec-stusb.txt create mode 100644 arch/arm/boot/dts/stm32mp15-no-scmi.dtsi create mode 100644 arch/arm/boot/dts/stm32mp15-pinctrl.dtsi - rename arch/arm/boot/dts/{stm32mp157c.dtsi => stm32mp151.dtsi} (59%) + rename arch/arm/boot/dts/{stm32mp157c.dtsi => stm32mp151.dtsi} (57%) create mode 100644 arch/arm/boot/dts/stm32mp153.dtsi create mode 100644 arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi create mode 100644 arch/arm/boot/dts/stm32mp157-m4-srm.dtsi @@ -141,11 +109,9 @@ Subject: [PATCH 20/23] ARM-stm32mp1-r1-DEVICETREE create mode 100644 arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi create mode 100644 arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi create mode 100644 arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi - create mode 100644 include/dt-bindings/rtc/rtc-stm32.h - create mode 100644 include/dt-bindings/soc/stm32-hdp.h diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml -index 4d194f1eb..c9d74357b 100644 +index 4d194f1eb03a4..c9d74357b9415 100644 --- a/Documentation/devicetree/bindings/arm/stm32/stm32.yaml +++ b/Documentation/devicetree/bindings/arm/stm32/stm32.yaml @@ -27,5 +27,8 @@ properties: @@ -159,7 +125,7 @@ index 4d194f1eb..c9d74357b 100644 + - st,stm32mp151 ... diff --git a/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt -index fb9495ea5..1f1ec3446 100644 +index fb9495ea582c4..1f1ec3446ca52 100644 --- a/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt +++ b/Documentation/devicetree/bindings/clock/st,stm32mp1-rcc.txt @@ -12,7 +12,7 @@ binding usage. @@ -181,22 +147,9 @@ index fb9495ea5..1f1ec3446 100644 reg = <0x50000000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; -diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt b/Documentation/devicetree/bindings/connector/usb-connector.txt -index d35798718..5c0bb0395 100644 ---- a/Documentation/devicetree/bindings/connector/usb-connector.txt -+++ b/Documentation/devicetree/bindings/connector/usb-connector.txt -@@ -34,6 +34,8 @@ Optional properties for usb-b-connector: - Optional properties for usb-c-connector: - - power-role: should be one of "source", "sink" or "dual"(DRP) if typec - connector has power support. -+- power-opmode: should be one of "default", "1.5A", "3.0A" or -+ "usb_power_delivery" if typec connector has power support. - - try-power-role: preferred power role if "dual"(DRP) can support Try.SNK - or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC. - - data-role: should be one of "host", "device", "dual"(DRD) if typec diff --git a/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt new file mode 100644 -index 000000000..1292eb261 +index 0000000000000..1292eb2612a05 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt @@ -0,0 +1,61 @@ @@ -261,185 +214,8 @@ index 000000000..1292eb261 + opp-supported-hw = <0x2>; + }; + }; -diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt -deleted file mode 100644 -index 203b03eef..000000000 ---- a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.txt -+++ /dev/null -@@ -1,23 +0,0 @@ --Orise Tech OTM8009A 3.97" 480x800 TFT LCD panel (MIPI-DSI video mode) -- --The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using --a MIPI-DSI video interface. Its backlight is managed through the DSI link. -- --Required properties: -- - compatible: "orisetech,otm8009a" -- - reg: the virtual channel number of a DSI peripheral -- --Optional properties: -- - reset-gpios: a GPIO spec for the reset pin (active low). -- - power-supply: phandle of the regulator that provides the supply voltage. -- --Example: --&dsi { -- ... -- panel@0 { -- compatible = "orisetech,otm8009a"; -- reg = <0>; -- reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; -- power-supply = <&v1v8>; -- }; --}; -diff --git a/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml -new file mode 100644 -index 000000000..6eda24035 ---- /dev/null -+++ b/Documentation/devicetree/bindings/display/panel/orisetech,otm8009a.yaml -@@ -0,0 +1,53 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/display/panel/orisetech,otm8009a.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Orise Tech OTM8009A 3.97" 480x800 panel -+ -+maintainers: -+ - Yannick Fertre -+ -+description: -+ The Orise Tech OTM8009A is a 3.97" 480x800 TFT LCD panel connected using -+ a MIPI-DSI video interface. Its backlight is managed through the DSI link. -+ -+properties: -+ compatible: -+ const: orisetech,otm8009a -+ -+ power-supply: true -+ reset-gpios: true -+ backlight: true -+ port: true -+ reg: true -+ -+required: -+ - compatible -+ - reg -+ - port -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ display1: display { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ panel { -+ compatible = "orisetech,otm8009a"; -+ reg = <0>; -+ reset-gpios = <&gpioh 7 GPIO_ACTIVE_LOW>; -+ power-supply = <&v1v8>; -+ -+ port { -+ panel_in_dsi: endpoint { -+ remote-endpoint = <&controller_out_dsi>; -+ }; -+ }; -+ }; -+ }; -+ -+... -diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt -deleted file mode 100644 -index cbb79ef3b..000000000 ---- a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.txt -+++ /dev/null -@@ -1,25 +0,0 @@ --Raydium Semiconductor Corporation RM68200 5.5" 720p MIPI-DSI TFT LCD panel -- --The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD --panel connected using a MIPI-DSI video interface. -- --Required properties: -- - compatible: "raydium,rm68200" -- - reg: the virtual channel number of a DSI peripheral -- --Optional properties: -- - reset-gpios: a GPIO spec for the reset pin (active low). -- - power-supply: phandle of the regulator that provides the supply voltage. -- - backlight: phandle of the backlight device attached to the panel. -- --Example: --&dsi { -- ... -- panel@0 { -- compatible = "raydium,rm68200"; -- reg = <0>; -- reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; -- power-supply = <&v1v8>; -- backlight = <&pwm_backlight>; -- }; --}; -diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml -new file mode 100644 -index 000000000..2bbd4a0cb ---- /dev/null -+++ b/Documentation/devicetree/bindings/display/panel/raydium,rm68200.yaml -@@ -0,0 +1,52 @@ -+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -+%YAML 1.2 -+--- -+$id: http://devicetree.org/schemas/display/panel/raydium,rm68200.yaml# -+$schema: http://devicetree.org/meta-schemas/core.yaml# -+ -+title: Raydium RM68200 5.5" 720x1280 panel -+ -+maintainers: -+ - Yannick Fertre -+ -+description: -+ The Raydium Semiconductor Corporation RM68200 is a 5.5" 720x1280 TFT LCD -+ panel connected using a MIPI-DSI video interface. -+ -+properties: -+ compatible: -+ const: raydium,rm68200 -+ -+ power-supply: true -+ reset-gpios: true -+ backlight: true -+ port: true -+ reg: true -+ -+required: -+ - compatible -+ - reg -+ - port -+ -+additionalProperties: false -+ -+examples: -+ - | -+ #include -+ display0: display { -+ #address-cells = <1>; -+ #size-cells = <0>; -+ panel { -+ compatible = "raydium,rm68200"; -+ reg = <0>; -+ reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; -+ power-supply = <&v1v8>; -+ port { -+ panel_in_dsi: endpoint { -+ remote-endpoint = <&controller_out_dsi>; -+ }; -+ }; -+ }; -+ }; -+ -+... diff --git a/Documentation/devicetree/bindings/dma/stm32-dma.txt b/Documentation/devicetree/bindings/dma/stm32-dma.txt -index c5f519097..11ee1e9f8 100644 +index c5f519097204f..11ee1e9f85cc6 100644 --- a/Documentation/devicetree/bindings/dma/stm32-dma.txt +++ b/Documentation/devicetree/bindings/dma/stm32-dma.txt @@ -17,6 +17,12 @@ Optional properties: @@ -511,7 +287,7 @@ index c5f519097..11ee1e9f8 100644 dma-names = "rx", "tx"; }; diff --git a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt -index 1b893b235..8e092d29b 100644 +index 1b893b2355072..8e092d29b6146 100644 --- a/Documentation/devicetree/bindings/dma/stm32-dmamux.txt +++ b/Documentation/devicetree/bindings/dma/stm32-dmamux.txt @@ -4,9 +4,6 @@ Required properties: @@ -534,7 +310,7 @@ index 1b893b235..8e092d29b 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 d18772d6b..077c819a5 100644 +index d18772d6bc656..077c819a54b0e 100644 --- a/Documentation/devicetree/bindings/dma/stm32-mdma.txt +++ b/Documentation/devicetree/bindings/dma/stm32-mdma.txt @@ -10,7 +10,7 @@ Required properties: @@ -650,7 +426,7 @@ index d18772d6b..077c819a5 100644 status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/hwlock/hwlock.txt b/Documentation/devicetree/bindings/hwlock/hwlock.txt -index 085d1f5c9..e98088a40 100644 +index 085d1f5c916a4..e98088a409bac 100644 --- a/Documentation/devicetree/bindings/hwlock/hwlock.txt +++ b/Documentation/devicetree/bindings/hwlock/hwlock.txt @@ -13,7 +13,7 @@ hwlock providers: @@ -705,7 +481,7 @@ index 085d1f5c9..e98088a40 100644 + }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt -index adf4f000e..60a37163b 100644 +index adf4f000ea3db..60a37163b16dd 100644 --- a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt +++ b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.txt @@ -4,8 +4,8 @@ STM32 Hardware Spinlock Device Binding @@ -729,7 +505,7 @@ index adf4f000e..60a37163b 100644 clocks = <&rcc HSEM>; clock-names = "hsem"; diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt -index ce3df2fff..62ccd03fa 100644 +index ce3df2fff6c88..62ccd03fa549d 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt @@ -4,13 +4,15 @@ Required properties: @@ -771,7 +547,7 @@ index ce3df2fff..62ccd03fa 100644 + st,syscfg-fmp-clr = <&syscfg 0x44 0x1>; }; diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt -index 59b92cd32..fa70fda13 100644 +index 59b92cd325527..fa70fda13bdb9 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: @@ -785,7 +561,7 @@ index 59b92cd32..fa70fda13 100644 ads1202: adc { diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt -index 4c0da8c74..8de933146 100644 +index 4c0da8c74bb2c..8de9331467717 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt @@ -53,6 +53,8 @@ Optional properties: @@ -798,7 +574,7 @@ index 4c0da8c74..8de933146 100644 Contents of a stm32 adc child node: ----------------------------------- diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt -index b8e8c769d..4713ff1f5 100644 +index b8e8c769d4343..4713ff1f55599 100644 --- a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt +++ b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt @@ -9,6 +9,12 @@ Required parameters: @@ -824,7 +600,7 @@ index b8e8c769d..4713ff1f5 100644 }; }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt -index cd01b2292..abcf816d6 100644 +index cd01b2292ec68..abcf816d621c1 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt @@ -18,7 +18,19 @@ Optional properties: @@ -870,7 +646,7 @@ index cd01b2292..abcf816d6 100644 +}; diff --git a/Documentation/devicetree/bindings/mailbox/arm-smc.yaml b/Documentation/devicetree/bindings/mailbox/arm-smc.yaml new file mode 100644 -index 000000000..c165946a6 +index 0000000000000..c165946a64e4e --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/arm-smc.yaml @@ -0,0 +1,96 @@ @@ -970,114 +746,9 @@ index 000000000..c165946a6 + }; + +... -diff --git a/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt b/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt -index 1d2b7fee7..139c06a94 100644 ---- a/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt -+++ b/Documentation/devicetree/bindings/mailbox/stm32-ipcc.txt -@@ -14,9 +14,9 @@ Required properties: - property. Must contain the following entries: - - "rx" - - "tx" -- - "wakeup" - - interrupts: Interrupt specifiers for "rx channel occupied", "tx channel -- free" and "system wakeup". -+ free". If "wakeup-source" is set the rx interrupt is the -+ one used to wake up the system. - - #mbox-cells: Number of cells required for the mailbox specifier. Must be 1. - The data contained in the mbox specifier of the "mboxes" - property in the client node is the mailbox channel index. -diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt -index f884ada0b..aff685a25 100644 ---- a/Documentation/devicetree/bindings/media/video-interfaces.txt -+++ b/Documentation/devicetree/bindings/media/video-interfaces.txt -@@ -149,6 +149,8 @@ Optional endpoint properties - as 0 (normal). This property is valid for serial busses only. - - strobe: Whether the clock signal is used as clock (0) or strobe (1). Used - with CCP2, for instance. -+- pclk-max-frequency: maximum pixel clock frequency admissible by video -+ host interface. - - Example - ------- -diff --git a/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt -new file mode 100644 -index 000000000..eb622387b ---- /dev/null -+++ b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt -@@ -0,0 +1,57 @@ -+STMicroelectronics STM32MP1 Power Management Controller -+======================================================= -+ -+The PWR IP is responsible for handling the power related resources such as -+clocks, power supplies and resets. It provides 6 wake-up pins that are handled -+by an interrupt-controller. Wake-up pin can be used to wake-up from STANDBY SoC state. -+ -+Required properties: -+- compatible should be: "st,stm32mp1-pwr" -+- reg: should be register base and length as documented in the -+ datasheet -+- interrupts: contains the reference to the gic wake-up pin interrupt -+- interrupt-controller; Enable interrupt controller for wake-up pins. -+- #interrupt-cells = <3> -+- wakeup-gpios: contains a list of GPIO spec describing each wake-up pin. -+ -+Optional Properties: -+- pwr-supply: main soc power supply -+ -+Interrupt consumers have to specify 3 cells: -+ - cell 1: wake-up pin id from 0 to 5 -+ - cell 2: IRQ_TYPE_EDGE_FALLING or IRQ_TYPE_EDGE_RISING -+ - cell 3: Pull config: 0 = No Pull, 1=Pull Up, 2=Pull Down -+ -+ -+Example: -+ -+ pwr: pwr@50001000 { -+ compatible = "st,stm32mp1-pwr", "simple-mfd"; -+ reg = <0x50001000 0x400>; -+ interrupts = ; -+ interrupt-controller; -+ #interrupt-cells = <3>; -+ -+ wakeup-gpios = <&gpioa 0 0>, <&gpioa 2 0>, -+ <&gpioc 13 0>, <&gpioi 8 0>, -+ <&gpioi 11 0>, <&gpioc 1 0>; -+ -+ pwr-supply = <&vdd>; -+ }; -+ -+ -+Example of interrupt user: -+gpio_keys { -+ compatible = "gpio-keys"; -+ #address-cells = <1>; -+ #size-cells = <0>; -+ -+ button@4 { -+ label = "WakeUp4"; -+ linux,code = ; -+ interrupt-parent = <&pwr>; -+ interrupts = <3 IRQ_TYPE_EDGE_FALLING 1>; -+ wakeup-source; -+ }; -+}; -+ -diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt -index 6d3c626e0..4ec921e4b 100644 ---- a/Documentation/devicetree/bindings/mmc/mmci.txt -+++ b/Documentation/devicetree/bindings/mmc/mmci.txt -@@ -28,6 +28,8 @@ specific for ux500 variant: - - st,sig-pin-fbclk : feedback clock signal pin used. - - specific for sdmmc variant: -+- reg : a second base register may be defined if a delay -+ block is present and used for tuning. - - st,sig-dir : signal direction polarity used for cmd, dat0 dat123. - - st,neg-edge : data & command phase relation, generated on - sd clock falling edge. diff --git a/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt new file mode 100644 -index 000000000..7533b8964 +index 0000000000000..7533b89646539 --- /dev/null +++ b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.txt @@ -0,0 +1,18 @@ @@ -1099,292 +770,26 @@ index 000000000..7533b8964 + clock-names = "bus", "ddr"; + }; + -diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt -index 725ae71ae..156229b2e 100644 ---- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt -+++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt -@@ -23,8 +23,11 @@ Required properties: - - compatible: must be "st,stm32mp1-usbphyc" - - reg: address and length of the usb phy control register set - - clocks: phandle + clock specifier for the PLL phy clock -+- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY -+- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY - - #address-cells: number of address cells for phys sub-nodes, must be <1> - - #size-cells: number of size cells for phys sub-nodes, must be <0> -+- #clock-cells: number of clock cells for ck_usbo_48m consumer, must be <0> - - Optional properties: - - assigned-clocks: phandle + clock specifier for the PLL phy clock -@@ -34,40 +37,82 @@ Optional properties: - Required nodes: one sub-node per port the controller provides. - - Phy sub-nodes --============== -+============= - - Required properties: - - reg: phy port index - - phy-supply: phandle to the regulator providing 3V3 power to the PHY, - see phy-bindings.txt in the same directory. --- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY --- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY - - #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY - port#1 and must be <1> for PHY port#2, to select USB controller - -+Optional properties: -+- st,phy-tuning : phandle to the usb phy tuning node, see Phy tuning node below -+ -+Phy tuning node -+=============== -+ -+It may be necessary to adjust the phy settings to compensate parasitics, which -+can be due to USB connector/receptacle, routing, ESD protection component, ... -+ -+Here is the list of all optional parameters to tune the interface of the phy -+(HS for High-Speed, FS for Full-Speed, LS for Low-Speed) -+ -+Optional properties: -+- st,current-boost: <1> current boosting of 1mA -+ <2> current boosting of 2mA -+- st,no-lsfs-fb-cap: disables the LS/FS feedback capacitor -+- st,hs-slew-ctrl: slows the HS driver slew rate by 10% -+- st,hs-dc-level: <0> decreases the HS driver DC level by 5 to 7mV -+ <1> increases the HS driver DC level by 5 to 7mV -+ <2> increases the HS driver DC level by 10 to 14mV -+- st,fs-rftime-tuning: enables the FS rise/fall tuning option -+- st,hs-rftime-reduction: enables the HS rise/fall reduction feature -+- st,hs-current-trim: controls HS driver current trimming for choke -+- st,hs-impedance-trim: controls HS driver impedance tuning for choke -+- st,squelch-level: adjusts the squelch DC threshold value -+- st,hs-rx-gain-eq: enables the HS Rx gain equalizer -+- st,hs-rx-offset: adjusts the HS Rx offset -+- st,no-hs-ftime-ctrl: disables the HS fall time control of single -+ ended signals during pre-emphasis -+- st,no-lsfs-sc: disables the short circuit protection in LS/FS driver -+- st,hs-tx-staggering: enables the basic staggering in HS Tx mode -+ - - Example: -+ usb_phy_tuning: usb-phy-tuning { -+ st,current-boost = <2>; -+ st,no-lfs-fb-cap; -+ st,hs-dc-level = <2>; -+ st,hs-rftime-reduction; -+ st,hs-current-trim = <5>; -+ st,hs-impedance-trim = <0>; -+ st,squelch-level = <1>; -+ st,no-hs-ftime-ctrl; -+ st,hs-tx-staggering; -+ }; -+ - usbphyc: usb-phy@5a006000 { - compatible = "st,stm32mp1-usbphyc"; - reg = <0x5a006000 0x1000>; - clocks = <&rcc_clk USBPHY_K>; - resets = <&rcc_rst USBPHY_R>; -+ vdda1v1-supply = <®11>; -+ vdda1v8-supply = <®18>; - #address-cells = <1>; - #size-cells = <0>; -+ #clock-cells = <0>; - - usbphyc_port0: usb-phy@0 { - reg = <0>; - phy-supply = <&vdd_usb>; -- vdda1v1-supply = <®11>; -- vdda1v8-supply = <®18> - #phy-cells = <0>; - }; - - usbphyc_port1: usb-phy@1 { - reg = <1>; - phy-supply = <&vdd_usb>; -- vdda1v1-supply = <®11>; -- vdda1v8-supply = <®18> - #phy-cells = <1>; -+ st,phy-tuning = <&usb_phy_tuning>; - }; - }; -diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml -index 400df2da0..4e24a8e86 100644 ---- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml -+++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml -@@ -144,9 +144,13 @@ patternProperties: - * ... - * 16 : Alternate Function 15 - * 17 : Analog -+ * 18 : Reserved - To simplify the usage, macro is available to generate "pinmux" field. - This macro is available here: - - include/dt-bindings/pinctrl/stm32-pinfunc.h -+ Setting the pinmux's function to the Reserved (RSVD) value is used to inform -+ the driver that it shall not apply the mux setting. This can be used to -+ reserve some pins, for example to a co-processor not running Linux. - Some examples of using macro: - /* GPIO A9 set as alernate function 2 */ - ... { -@@ -160,6 +164,10 @@ patternProperties: - ... { - pinmux = ; - }; -+ /* GPIO A9 reserved for co-processor */ -+ ... { -+ pinmux = ; -+ }; - - bias-disable: - type: boolean -diff --git a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt -index a8690bfa5..f1620c1fe 100644 ---- a/Documentation/devicetree/bindings/pwm/pwm-stm32.txt -+++ b/Documentation/devicetree/bindings/pwm/pwm-stm32.txt -@@ -5,8 +5,9 @@ See ../mfd/stm32-timers.txt for details about the parent node. - - Required parameters: - - compatible: Must be "st,stm32-pwm". --- pinctrl-names: Set to "default". --- pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module. -+- pinctrl-names: Set to "default". An additional "sleep" state can be -+ defined to set pins in sleep state when in low power. -+- pinctrl-n: List of phandles pointing to pin configuration nodes for PWM module. - For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt - - #pwm-cells: Should be set to 3. This PWM chip uses the default 3 cells - bindings defined in pwm.txt. -@@ -32,7 +33,8 @@ Example: - compatible = "st,stm32-pwm"; - #pwm-cells = <3>; - pinctrl-0 = <&pwm1_pins>; -- pinctrl-names = "default"; -+ pinctrl-1 = <&pwm1_sleep_pins>; -+ pinctrl-names = "default", "sleep"; - st,breakinput = <0 1 5>; - }; - }; -diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -new file mode 100644 -index 000000000..baa6e8e13 ---- /dev/null -+++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt -@@ -0,0 +1,58 @@ -+Remoteproc System Resource Manager -+---------------------------------- -+ -+The remoteproc SRM (System Resource Manager) handles resources allocated -+to remote processors. -+This makes it possible for remote proc to reserve and initialize system -+resources for a peripheral assigned to a coprocessor. -+ -+The devices are grouped in a core node -+ -+Core -+==== -+Required properties: -+- compatible: should be "rproc-srm-core" -+ -+Dev -+=== -+Required properties: -+- compatible: should be "rproc-srm-dev" -+ -+Optional properties: -+- reg: register base address and length -+- clocks: clocks required by the coprocessor -+- clock-names: see clock-bindings.txt -+- pinctrl-0: pins configurations required by the coprocessor -+ The SRM reserves the pins for the coprocessor, which prevents the local -+ processor to use them. -+- pinctrl-names: must be "default". -+- x-supply: power supplies required by the coprocessor -+- interrupts: external interrupts configurations required by the coprocessor. -+ This is optional since the configuration is done by the coprocessor. -+ When defined, the SRM (over)writes the configuration which allows the -+ interrupt controller to check for configuration conflicts. -+- interrupt-parent: see interrupts.txt -+- interrupt-names: see interrupts.txt -+ -+Example: -+ system_resources { -+ compatible = "rproc-srm-core"; -+ -+ mmc0: sdhci@09060000 { -+ compatible = "rproc-srm-dev"; -+ reg = <0x09060000 0x100>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&m4_pinctrl_mmc0>; -+ clock-names = "mmc", "icn"; -+ clocks = <&clk_s_c0_flexgen CLK_MMC_0>, -+ <&clk_s_c0_flexgen CLK_RX_ICN_HVA>; -+ vdda-supply = <&vdda>; -+ }; -+ -+ button { -+ compatible = "rproc-srm-dev"; -+ interrupt-parent = <&gpioa>; -+ interrupts = <5 1>; -+ interrupt-names = "gpio_key"; -+ }; -+ }; -diff --git a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -index 5fa915a4b..1188d22bd 100644 ---- a/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -+++ b/Documentation/devicetree/bindings/remoteproc/stm32-rproc.txt -@@ -21,6 +21,9 @@ Required properties: - - Optional properties: - - interrupts: Should contain the watchdog interrupt -+- wakeup-source: Flag indicating whether remoteproc can wake up the system by -+ the watchdog interrupt. Only meaningful if the "interrupts" -+ property is defined. - - mboxes: This property is required only if the rpmsg/virtio functionality - is used. List of phandle and mailbox channel specifiers: - - a channel (a) used to communicate through virtqueues with the -@@ -48,6 +51,16 @@ Optional properties: - 1st cell: phandle to syscon block - 2nd cell: register offset containing the deep sleep setting - 3rd cell: register bitmask for the deep sleep bit -+- st,syscfg-rsc-tbl: Reference to the system configuration controlling the -+ resource table address loaded by the bootloader -+ 1st cell: phandle to syscon block -+ 2nd cell: register offset containing the resource table address -+ 3rd cell: register bitmask for the resource table address -+- st,syscfg-copro-state: Reference to the system configuration which returns the -+ coprocessor state. -+ 1st cell: phandle to syscon block -+ 2nd cell: register offset containing the coprocessor state -+ 3rd cell: register bitmask for the coprocessor state - - st,auto-boot: If defined, when remoteproc is probed, it loads the default - firmware and starts the remote processor. - -diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt -index 130ca5b98..bab0df81a 100644 ---- a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt -+++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt -@@ -21,9 +21,14 @@ Required properties: - domain (RTC registers) write protection. - It is required on stm32(f4/f7/h7). - --Optional properties (to override default rtc_ck parent clock on stm32(f4/f7/h7): -+Optional properties: -+* to override default rtc_ck parent clock on stm32(f4/f7/h7): - - assigned-clocks: reference to the rtc_ck clock entry. - - assigned-clock-parents: phandle of the new parent clock of rtc_ck. -+* to select and enable RTC Low Speed Clock Output on stm32mp1: -+- st,lsco: defines the RTC output on which RTC Low-Speed Clock is Output. The -+ valid output values are defined in . -+- pinctrl state named "default" may be defined to reserve pin for RTC output. - - Example: - -@@ -58,4 +63,7 @@ Example: - clock-names = "pclk", "rtc_ck"; - interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_NONE>, - <&exti 19 1>; -+ st,lsco = ; -+ pinctrl-0 = <&rtc_out2_rmp_pins_a>; -+ pinctrl-names = "default"; - }; +diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt +index b92592dff6dd9..f838439e4fe05 100644 +--- a/Documentation/devicetree/bindings/serial/rs485.txt ++++ b/Documentation/devicetree/bindings/serial/rs485.txt +@@ -12,6 +12,13 @@ Optional properties: + * b is the delay between end of data sent and rts signal in milliseconds + it corresponds to the delay after sending data and actual release of the line. + If this property is not specified, <0 0> is assumed. ++- rs485-rts-delay-ns: prop-encoded-array where: ++ * a is the delay between rts signal and beginning of data sent in nanoseconds. ++ it corresponds to the delay before sending data. ++ * b is the delay between end of data sent and rts signal in nanoseconds ++ it corresponds to the delay after sending data and actual release of the line. ++ If this property is not specified, <0 0> is assumed. ++ This property is used to define delays lower than 1ms. + - rs485-rts-active-low: drive RTS low when sending (default is high). + - linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485 + feature at boot time. It can be disabled later with proper ioctl. diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt -index 8620f7fcb..8b032ac3b 100644 +index 8620f7fcbd50f..6263fe1bb85ce 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt @@ -1,7 +1,7 @@ @@ -1396,7 +801,7 @@ index 8620f7fcb..8b032ac3b 100644 - "st,stm32-uart", - "st,stm32f7-uart", - "st,stm32h7-uart". -@@ -9,22 +9,43 @@ Required properties: +@@ -9,22 +9,59 @@ Required properties: - reg: The address and length of the peripheral registers space - interrupts: - The interrupt line for the USART instance, @@ -1407,15 +812,18 @@ index 8620f7fcb..8b032ac3b 100644 - resets: Must contain the phandle to the reset controller. -- pinctrl: The reference on the pins configuration -- st,hw-flow-ctrl: bool flag to enable hardware flow control. +-- rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, +- linux,rs485-enabled-at-boot-time: see rs485.txt. +-- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt +- pinctrl-names: Set to "default". An additional "sleep" state can be defined + to set pins in sleep state when in low power. In case the device is used as + a wakeup source, "idle" state is defined in order to keep RX pin active. +- pinctrl-n: Phandle(s) pointing to pin configuration nodes. + For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt +- uart-has-rtscts: See description in serial.txt binding. - - rs485-rts-delay, rs485-rx-during-tx, rs485-rts-active-low, -- linux,rs485-enabled-at-boot-time: see rs485.txt. --- dmas: phandle(s) to DMA controller node(s). Refer to stm32-dma.txt ++- cts-gpios: CTS gpios for flow control. ++- rts-gpios: RTS gpios for flow control. ++- rs485-rts-delay, rs485-rts-delay-ns, rs485-rx-during-tx, rs485-rts-active-low, + linux,rs485-enabled-at-boot-time: See rs485.txt. +- dmas: Phandle(s) to DMA controller node(s). Refer to stm32-dma.txt - dma-names: "rx" and/or "tx" @@ -1424,7 +832,21 @@ index 8620f7fcb..8b032ac3b 100644 - - "event": the name for the interrupt line of the USART instance - - "wakeup" the name for the optional wake-up interrupt +- wakeup-source: Bool flag to indicate this device has wakeup capabilities ++- st,rx-fifo-threshold-bytes: RX FIFO threshold configuration in bytes, only ++ available with stm32h7 compatible. ++ Valid values are 1, 2, 4, 8, 12, 14, 16. Default value is 8. If value is ++ set to 1, RX FIFO threshold is disabled. ++- st,tx-fifo-threshold-bytes: TX FIFO threshold configuration in bytes, only ++ available with stm32h7 compatible. ++ Valid values are 1, 2, 4, 8, 12, 14, 16. Default value is 8. If value is ++ set to 1, TX FIFO threshold is disabled. ++Note for cts-gpios and rts-gpios: ++ - These properties can be used instead of 'uart-has-rtscts' or ++ 'st,hw-flow-ctrl' (deprecated) for making use of any gpio pins for flow ++ control instead of dedicated pins. It should be noted that both CTS/RTS ++ and 'uart-has-rtscts' properties cannot co-exist in a design. ++ +Note for dma using: +- "tx" dma can be used without any constraint since it uses single +dma transfers. @@ -1449,7 +871,7 @@ index 8620f7fcb..8b032ac3b 100644 Examples: usart4: serial@40004c00 { -@@ -32,8 +53,11 @@ usart4: serial@40004c00 { +@@ -32,8 +69,11 @@ usart4: serial@40004c00 { reg = <0x40004c00 0x400>; interrupts = <52>; clocks = <&clk_pclk1>; @@ -1462,152 +884,48 @@ index 8620f7fcb..8b032ac3b 100644 }; usart2: serial@40004400 { -diff --git a/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt -new file mode 100644 -index 000000000..e2bd82f49 ---- /dev/null -+++ b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt -@@ -0,0 +1,39 @@ -+STM32 - STM32MP1- HDP Pin configuration for STM32MP1 -+======================================================= -+ -+The Hardware Debug Port (HDP) allows the observation of internal signals. By using multiplexers, -+up to 16 signals for each of 8-bit output can be observed. -+ -+Required Properties: -+ -+ - compatible: Must be "st,stm32mp1-hdp" -+ - muxing-hdp: Indicates for each HDP pins selected which HDP output among the 16 available signals you want -+ -+For each HDP pins you can select one of 16 signals which will be described in file : include/dt-bindings/soc/stm32-hdp.h -+ -+Example -+------- -+ -+In common dtsi file: -+ -+hdp: hdp@5002a000 { -+ compatible = "st,stm32mp1-hdp"; -+ reg = <0x5002a000 0x400>; -+ clocks = <&rcc HDP>; -+ clock-names = "hdp"; -+}; -+ -+In board-specific file: -+ -+In this example I've selected HDP0, HDP6 and HDP7, and for HDP0 the output signal is HDP0_GPOVAL_0, -+for HDP6 is HDP6_GPOVAL_6, and for HDP7 is HDP7_GPOVAL_7. -+ -+&hdp { -+ pinctrl-names = "default", "sleep"; -+ pinctrl-0 = <&hdp0_pins_a &hdp6_pins_a &hdp7_pins_a>; -+ pinctrl-1 = <&hdp0_pins_sleep_a &hdp6_pins_sleep_a &hdp7_pins_sleep_a>; -+ -+ muxing-hdp = <(STM32_HDP(0, HDP0_GPOVAL_0) | -+ STM32_HDP(6, HDP6_GPOVAL_6) | -+ STM32_HDP(7, HDP7_GPOVAL_7))>; -+}; -diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt -index aafff3a69..1a65303d0 100644 ---- a/Documentation/devicetree/bindings/usb/dwc2.txt -+++ b/Documentation/devicetree/bindings/usb/dwc2.txt -@@ -23,6 +23,9 @@ Required properties: - configured in HS mode; - - "st,stm32f7-hsotg": The DWC2 USB HS controller instance in STM32F7 SoCs - configured in HS mode; -+ - "st,stm32mp1-fsotg": The DWC2 USB controller instance in STM32MP1 SoCs, -+ configured in FS mode (using dedicated FS transceiver). -+ - "st,stm32mp1-hsotg": The DWC2 USB controller instance in STM32MP1 SoCs; - - reg : Should contain 1 register range (address and length) - - interrupts : Should contain 1 interrupt - - clocks: clock provider specifier -@@ -46,6 +49,11 @@ Refer to phy/phy-bindings.txt for generic phy consumer properties - on for remote wakeup during suspend. - - snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when - we detect a wakeup. This is due to a hardware errata. -+- usb33d-supply: external VBUS and ID sensing comparators supply, in order to -+ perform OTG operation, used on STM32MP1 SoCs. -+- usb-role-switch: use USB Role Switch to support dynamic dual role switch. -+ Refer to usb/generic.txt -+- wakeup-source: bool flag to indicate this device has wakeup capabilities - - Deprecated properties: - - g-use-dma: gadget DMA mode is automatically detected -diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml -index 1ca64c851..b71c15dc8 100644 ---- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml -+++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml -@@ -69,6 +69,11 @@ properties: - phy-names: - const: usb - -+ wakeup-source: -+ $ref: /schemas/types.yaml#/definitions/flag -+ description: -+ Indicate this device has wakeup capabilities. -+ - required: - - compatible - - reg -diff --git a/Documentation/devicetree/bindings/usb/st,typec-stusb.txt b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt -new file mode 100644 -index 000000000..415e14e14 ---- /dev/null -+++ b/Documentation/devicetree/bindings/usb/st,typec-stusb.txt -@@ -0,0 +1,48 @@ -+STMicroelectronics STUSB Type-C Controller family -+ -+Required properties: -+ - compatible: should be "st,stusb1600". -+ - reg: I2C slave address of the device. -+ -+Optional properties: -+ - vdd-supply: main power supply [4.1V;22V]. -+ - vsys-supply: low power supply [3.0V;5.5V]. -+ - vconn-supply: power supply [2.7;5.5V] used to supply VConn on CC pin in -+ source or dual power role. -+ - interrupts: interrupt specifier triggered by ALERT# signal. -+ Please refer to ../interrupt-controller/interrupt.txt -+ - pinctrl state named "default" may be defined to configure pin for #ALERT -+ signal -+ -+USB-C connector attached to STUSB Type-C port controller can be described in -+an optional connector sub-node. Refer to ../connector/usb-connector.txt. -+In case role switch can be used, an optional port sub-node can be added. Refer -+to ../graph.txt. -+ -+Example : -+ -+ typec: stusb1600@28 { -+ compatible = "st,stusb1600"; -+ reg = <0x28>; -+ vdd-supply = <&vbus_drd>; -+ vsys-supply = <&vdd_usb>; -+ interrupts = <11 IRQ_TYPE_EDGE_FALLING>; -+ interrupt-parent = <&gpioi>; -+ pinctrl-names = "default"; -+ pinctrl-0 = <&stusb1600_pins_a>; -+ -+ usb_con: connector { -+ compatible = "usb-c-connector"; -+ label = "USB-C"; -+ power-role = "dual"; -+ power-opmode = "1.5A"; -+ data-role = "dual"; -+ -+ port { -+ con_usbotg_hs_ep: endpoint { -+ remote-endpoint = <&usbotg_hs_ep>; -+ }; -+ }; -+ }; -+ }; -+ diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index b21b3a646..3f1859094 100644 +index b21b3a64641a7..1c5d5b0278b2d 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile -@@ -989,9 +989,26 @@ dtb-$(CONFIG_ARCH_STM32) += \ +@@ -1,4 +1,36 @@ + # SPDX-License-Identifier: GPL-2.0 ++ ++# board-specific dtc flags ++DTC_FLAGS_stm32mp157c-dk2 += -@ ++DTC_FLAGS_stm32f429-disco += -@ ++DTC_FLAGS_stm32f469-disco += -@ ++DTC_FLAGS_stm32f746-disco += -@ ++DTC_FLAGS_stm32f769-disco += -@ ++DTC_FLAGS_stm32429i-eval += -@ ++DTC_FLAGS_stm32746g-eval += -@ ++DTC_FLAGS_stm32h743i-eval += -@ ++DTC_FLAGS_stm32h743i-disco += -@ ++DTC_FLAGS_stm32mp157a-dk1 += -@ ++DTC_FLAGS_stm32mp157d-dk1 += -@ ++DTC_FLAGS_stm32mp157c-dk2 += -@ ++DTC_FLAGS_stm32mp157f-dk2 += -@ ++DTC_FLAGS_stm32mp157c-dk2-a7-examples += -@ ++DTC_FLAGS_stm32mp157c-dk2-m4-examples += -@ ++DTC_FLAGS_stm32mp157f-dk2-a7-examples += -@ ++DTC_FLAGS_stm32mp157f-dk2-m4-examples += -@ ++DTC_FLAGS_stm32mp157a-ed1 += -@ ++DTC_FLAGS_stm32mp157c-ed1 += -@ ++DTC_FLAGS_stm32mp157d-ed1 += -@ ++DTC_FLAGS_stm32mp157f-ed1 += -@ ++DTC_FLAGS_stm32mp157a-ev1 += -@ ++DTC_FLAGS_stm32mp157c-ev1 += -@ ++DTC_FLAGS_stm32mp157d-ev1 += -@ ++DTC_FLAGS_stm32mp157f-ev1 += -@ ++DTC_FLAGS_stm32mp157c-ev1-a7-examples += -@ ++DTC_FLAGS_stm32mp157c-ev1-m4-examples += -@ ++DTC_FLAGS_stm32mp157f-ev1-a7-examples += -@ ++DTC_FLAGS_stm32mp157f-ev1-m4-examples += -@ ++ + dtb-$(CONFIG_ARCH_ALPINE) += \ + alpine-db.dtb + dtb-$(CONFIG_MACH_ARTPEC6) += \ +@@ -989,9 +1021,26 @@ dtb-$(CONFIG_ARCH_STM32) += \ stm32h743i-disco.dtb \ stm32mp157a-avenger96.dtb \ stm32mp157a-dk1.dtb \ @@ -1637,10 +955,10 @@ index b21b3a646..3f1859094 100644 sun4i-a10-ba10-tvbox.dtb \ diff --git a/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi b/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi new file mode 100644 -index 000000000..3bb96ab8a +index 0000000000000..b58b4b0526a20 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi -@@ -0,0 +1,157 @@ +@@ -0,0 +1,156 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2020 - All Rights Reserved @@ -1704,11 +1022,15 @@ index 000000000..3bb96ab8a + clocks = <&rcc CRYP1>; + resets = <&rcc CRYP1_R>; + }; ++ ++ dsi: dsi@5a000000 { ++ clocks = <&rcc DSI_K>, <&clk_hse>, <&rcc DSI_PX>; ++ }; + }; + + mlahb { + m4_rproc: m4@10000000 { -+ resets = <&rcc MCU_R>; ++ resets = <&rcc MCU_R>, <&rcc MCU_HOLD_BOOT_R>; + + m4_system_resources { + m4_cec: cec@40016000 { @@ -1743,10 +1065,6 @@ index 000000000..3bb96ab8a + clocks = <&rcc DDRPERFM>, <&rcc PLL2_R>; +}; + -+&dsi { -+ clocks = <&rcc DSI_K>, <&clk_hse>, <&rcc DSI_PX>; -+}; -+ +&gpioz { + clocks = <&rcc GPIOZ>; +}; @@ -1796,11 +1114,10 @@ index 000000000..3bb96ab8a + +&usart1 { + clocks = <&rcc USART1_K>; -+ resets = <&rcc USART1_R>; +}; diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi new file mode 100644 -index 000000000..38c792694 +index 0000000000000..8035044b8c399 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi @@ -0,0 +1,1411 @@ @@ -3016,7 +2333,7 @@ index 000000000..38c792694 + }; + pins2 { + pinmux = ; /* USART7_RX */ -+ bias-disable; ++ bias-pull-up; + }; + }; + @@ -3026,7 +2343,7 @@ index 000000000..38c792694 + }; + pins2 { + pinmux = ; /* USART7_RX */ -+ bias-disable; ++ bias-pull-up; + }; + }; + @@ -3120,7 +2437,7 @@ index 000000000..38c792694 + pins2 { + pinmux = , /* USART3_RX */ + ; /* USART3_CTS_NSS */ -+ bias-disable; ++ bias-pull-up; + }; + }; + @@ -3132,7 +2449,7 @@ index 000000000..38c792694 + }; + pins2 { + pinmux = ; /* USART3_RX */ -+ bias-disable; ++ bias-pull-up; + }; + }; + @@ -3216,10 +2533,10 @@ index 000000000..38c792694 + }; +}; diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi -similarity index 59% +similarity index 57% rename from arch/arm/boot/dts/stm32mp157c.dtsi rename to arch/arm/boot/dts/stm32mp151.dtsi -index f98e0370c..c516e2ed0 100644 +index f98e0370c0bce..f0211917bb680 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp151.dtsi @@ -5,7 +5,10 @@ @@ -3233,7 +2550,7 @@ index f98e0370c..c516e2ed0 100644 / { #address-cells = <1>; -@@ -19,20 +22,101 @@ +@@ -19,20 +22,95 @@ compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; @@ -3324,12 +2641,6 @@ index f98e0370c..c516e2ed0 100644 + reg = <0x14>; + #clock-cells = <1>; + }; -+ }; -+ -+ optee: optee { -+ compatible = "linaro,optee-tz"; -+ method = "smc"; -+ status = "disabled"; }; }; @@ -3342,7 +2653,7 @@ index f98e0370c..c516e2ed0 100644 }; intc: interrupt-controller@a0021000 { -@@ -50,38 +134,7 @@ +@@ -50,38 +128,7 @@ , ; interrupt-parent = <&intc>; @@ -3382,7 +2693,7 @@ index f98e0370c..c516e2ed0 100644 }; thermal-zones { -@@ -91,12 +144,6 @@ +@@ -91,12 +138,6 @@ thermal-sensors = <&dts>; trips { @@ -3395,7 +2706,7 @@ index f98e0370c..c516e2ed0 100644 cpu-crit { temperature = <120000>; hysteresis = <0>; -@@ -115,6 +162,33 @@ +@@ -115,6 +156,33 @@ status = "disabled"; }; @@ -3429,7 +2740,7 @@ index f98e0370c..c516e2ed0 100644 soc { compatible = "simple-bus"; #address-cells = <1>; -@@ -122,6 +196,14 @@ +@@ -122,6 +190,14 @@ interrupt-parent = <&intc>; ranges; @@ -3444,7 +2755,7 @@ index f98e0370c..c516e2ed0 100644 timers2: timer@40000000 { #address-cells = <1>; #size-cells = <0>; -@@ -129,11 +211,11 @@ +@@ -129,11 +205,11 @@ reg = <0x40000000 0x400>; clocks = <&rcc TIM2_K>; clock-names = "int"; @@ -3461,7 +2772,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "ch2", "ch3", "ch4", "up"; status = "disabled"; -@@ -148,6 +230,11 @@ +@@ -148,6 +224,11 @@ reg = <1>; status = "disabled"; }; @@ -3473,7 +2784,7 @@ index f98e0370c..c516e2ed0 100644 }; timers3: timer@40001000 { -@@ -157,12 +244,12 @@ +@@ -157,12 +238,12 @@ reg = <0x40001000 0x400>; clocks = <&rcc TIM3_K>; clock-names = "int"; @@ -3492,7 +2803,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; status = "disabled"; -@@ -177,6 +264,11 @@ +@@ -177,6 +258,11 @@ reg = <2>; status = "disabled"; }; @@ -3504,7 +2815,7 @@ index f98e0370c..c516e2ed0 100644 }; timers4: timer@40002000 { -@@ -186,10 +278,10 @@ +@@ -186,10 +272,10 @@ reg = <0x40002000 0x400>; clocks = <&rcc TIM4_K>; clock-names = "int"; @@ -3519,7 +2830,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "ch2", "ch3", "ch4"; status = "disabled"; -@@ -204,6 +296,11 @@ +@@ -204,6 +290,11 @@ reg = <3>; status = "disabled"; }; @@ -3531,7 +2842,7 @@ index f98e0370c..c516e2ed0 100644 }; timers5: timer@40003000 { -@@ -213,12 +310,12 @@ +@@ -213,12 +304,12 @@ reg = <0x40003000 0x400>; clocks = <&rcc TIM5_K>; clock-names = "int"; @@ -3550,7 +2861,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig"; status = "disabled"; -@@ -233,6 +330,11 @@ +@@ -233,6 +324,11 @@ reg = <4>; status = "disabled"; }; @@ -3562,7 +2873,7 @@ index f98e0370c..c516e2ed0 100644 }; timers6: timer@40004000 { -@@ -242,7 +344,7 @@ +@@ -242,7 +338,7 @@ reg = <0x40004000 0x400>; clocks = <&rcc TIM6_K>; clock-names = "int"; @@ -3571,7 +2882,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "up"; status = "disabled"; -@@ -260,7 +362,7 @@ +@@ -260,7 +356,7 @@ reg = <0x40005000 0x400>; clocks = <&rcc TIM7_K>; clock-names = "int"; @@ -3580,7 +2891,19 @@ index f98e0370c..c516e2ed0 100644 dma-names = "up"; status = "disabled"; -@@ -372,9 +474,10 @@ +@@ -342,8 +438,11 @@ + #size-cells = <0>; + compatible = "st,stm32-lptimer"; + reg = <0x40009000 0x400>; ++ interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc LPTIM1_K>; + clock-names = "mux"; ++ power-domains = <&pd_core>; ++ wakeup-source; + status = "disabled"; + + pwm { +@@ -372,9 +471,10 @@ interrupts = ; clocks = <&rcc SPI2_K>; resets = <&rcc SPI2_R>; @@ -3593,7 +2916,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -397,9 +500,10 @@ +@@ -397,9 +497,10 @@ interrupts = ; clocks = <&rcc SPI3_K>; resets = <&rcc SPI3_R>; @@ -3606,14 +2929,13 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -430,84 +534,132 @@ +@@ -430,84 +531,128 @@ usart2: serial@4000e000 { compatible = "st,stm32h7-uart"; reg = <0x4000e000 0x400>; - interrupts = ; + interrupts-extended = <&exti 27 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc USART2_K>; -+ resets = <&rcc USART2_R>; + wakeup-source; + power-domains = <&pd_core>; + dmas = <&dmamux1 43 0x400 0x5>, @@ -3628,7 +2950,6 @@ index f98e0370c..c516e2ed0 100644 - interrupts = ; + interrupts-extended = <&exti 28 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc USART3_K>; -+ resets = <&rcc USART3_R>; + wakeup-source; + power-domains = <&pd_core>; + dmas = <&dmamux1 45 0x400 0x5>, @@ -3643,7 +2964,6 @@ index f98e0370c..c516e2ed0 100644 - interrupts = ; + interrupts-extended = <&exti 30 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART4_K>; -+ resets = <&rcc UART4_R>; + wakeup-source; + power-domains = <&pd_core>; + dmas = <&dmamux1 63 0x400 0x5>, @@ -3658,7 +2978,6 @@ index f98e0370c..c516e2ed0 100644 - interrupts = ; + interrupts-extended = <&exti 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART5_K>; -+ resets = <&rcc UART5_R>; + wakeup-source; + power-domains = <&pd_core>; + dmas = <&dmamux1 65 0x400 0x5>, @@ -3755,7 +3074,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -515,7 +667,7 @@ +@@ -515,7 +660,7 @@ compatible = "st,stm32-cec"; reg = <0x40016000 0x400>; interrupts = ; @@ -3764,7 +3083,7 @@ index f98e0370c..c516e2ed0 100644 clock-names = "cec", "hdmi-cec"; status = "disabled"; }; -@@ -531,14 +683,14 @@ +@@ -531,14 +676,14 @@ dac1: dac@1 { compatible = "st,stm32-dac"; @@ -3781,14 +3100,13 @@ index f98e0370c..c516e2ed0 100644 reg = <2>; status = "disabled"; }; -@@ -547,16 +699,28 @@ +@@ -547,16 +692,26 @@ uart7: serial@40018000 { compatible = "st,stm32h7-uart"; reg = <0x40018000 0x400>; - interrupts = ; + interrupts-extended = <&exti 32 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART7_K>; -+ resets = <&rcc UART7_R>; + wakeup-source; + power-domains = <&pd_core>; + dmas = <&dmamux1 79 0x400 0x5>, @@ -3803,7 +3121,6 @@ index f98e0370c..c516e2ed0 100644 - interrupts = ; + interrupts-extended = <&exti 33 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc UART8_K>; -+ resets = <&rcc UART8_R>; + wakeup-source; + power-domains = <&pd_core>; + dmas = <&dmamux1 81 0x400 0x5>, @@ -3812,7 +3129,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -567,13 +731,13 @@ +@@ -567,13 +722,13 @@ reg = <0x44000000 0x400>; clocks = <&rcc TIM1_K>; clock-names = "int"; @@ -3833,7 +3150,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig", "com"; status = "disabled"; -@@ -589,6 +753,11 @@ +@@ -589,6 +744,11 @@ reg = <0>; status = "disabled"; }; @@ -3845,7 +3162,7 @@ index f98e0370c..c516e2ed0 100644 }; timers8: timer@44001000 { -@@ -598,13 +767,13 @@ +@@ -598,13 +758,13 @@ reg = <0x44001000 0x400>; clocks = <&rcc TIM8_K>; clock-names = "int"; @@ -3866,7 +3183,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "ch2", "ch3", "ch4", "up", "trig", "com"; status = "disabled"; -@@ -620,13 +789,24 @@ +@@ -620,13 +780,23 @@ reg = <7>; status = "disabled"; }; @@ -3883,7 +3200,6 @@ index f98e0370c..c516e2ed0 100644 - interrupts = ; + interrupts-extended = <&exti 29 IRQ_TYPE_LEVEL_HIGH>; clocks = <&rcc USART6_K>; -+ resets = <&rcc USART6_R>; + wakeup-source; + power-domains = <&pd_core>; + dmas = <&dmamux1 71 0x400 0x5>, @@ -3892,7 +3208,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -638,9 +818,10 @@ +@@ -638,9 +808,10 @@ interrupts = ; clocks = <&rcc SPI1_K>; resets = <&rcc SPI1_R>; @@ -3905,7 +3221,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -663,9 +844,10 @@ +@@ -663,9 +834,10 @@ interrupts = ; clocks = <&rcc SPI4_K>; resets = <&rcc SPI4_R>; @@ -3918,7 +3234,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -676,10 +858,10 @@ +@@ -676,10 +848,10 @@ reg = <0x44006000 0x400>; clocks = <&rcc TIM15_K>; clock-names = "int"; @@ -3933,7 +3249,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "up", "trig", "com"; status = "disabled"; -@@ -703,8 +885,8 @@ +@@ -703,8 +875,8 @@ reg = <0x44007000 0x400>; clocks = <&rcc TIM16_K>; clock-names = "int"; @@ -3944,7 +3260,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "up"; status = "disabled"; -@@ -727,8 +909,8 @@ +@@ -727,8 +899,8 @@ reg = <0x44008000 0x400>; clocks = <&rcc TIM17_K>; clock-names = "int"; @@ -3955,7 +3271,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "ch1", "up"; status = "disabled"; -@@ -753,9 +935,10 @@ +@@ -753,9 +925,10 @@ interrupts = ; clocks = <&rcc SPI5_K>; resets = <&rcc SPI5_R>; @@ -3968,7 +3284,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -923,32 +1106,6 @@ +@@ -923,32 +1096,6 @@ }; }; @@ -4001,7 +3317,7 @@ index f98e0370c..c516e2ed0 100644 dma1: dma@48000000 { compatible = "st,stm32-dma"; reg = <0x48000000 0x400>; -@@ -961,9 +1118,19 @@ +@@ -961,9 +1108,19 @@ , ; clocks = <&rcc DMA1>; @@ -4021,7 +3337,7 @@ index f98e0370c..c516e2ed0 100644 }; dma2: dma@48001000 { -@@ -978,19 +1145,30 @@ +@@ -978,19 +1135,30 @@ , ; clocks = <&rcc DMA2>; @@ -4053,7 +3369,7 @@ index f98e0370c..c516e2ed0 100644 }; adc: adc@48003000 { -@@ -1013,7 +1191,7 @@ +@@ -1013,7 +1181,7 @@ reg = <0x0>; interrupt-parent = <&adc>; interrupts = <0>; @@ -4062,7 +3378,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "rx"; status = "disabled"; }; -@@ -1024,39 +1202,65 @@ +@@ -1024,39 +1192,65 @@ reg = <0x100>; interrupt-parent = <&adc>; interrupts = <1>; @@ -4137,7 +3453,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -1067,16 +1271,68 @@ +@@ -1067,16 +1261,68 @@ resets = <&rcc CAMITF_R>; clocks = <&rcc DCMI>; clock-names = "mclk"; @@ -4208,7 +3524,7 @@ index f98e0370c..c516e2ed0 100644 }; exti: interrupt-controller@5000d000 { -@@ -1084,6 +1340,18 @@ +@@ -1084,6 +1330,18 @@ interrupt-controller; #interrupt-cells = <2>; reg = <0x5000d000 0x400>; @@ -4227,7 +3543,55 @@ index f98e0370c..c516e2ed0 100644 }; syscfg: syscon@50020000 { -@@ -1219,12 +1487,11 @@ +@@ -1097,8 +1355,11 @@ + #size-cells = <0>; + compatible = "st,stm32-lptimer"; + reg = <0x50021000 0x400>; ++ interrupts-extended = <&exti 48 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc LPTIM2_K>; + clock-names = "mux"; ++ power-domains = <&pd_core>; ++ wakeup-source; + status = "disabled"; + + pwm { +@@ -1124,8 +1385,11 @@ + #size-cells = <0>; + compatible = "st,stm32-lptimer"; + reg = <0x50022000 0x400>; ++ interrupts-extended = <&exti 50 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc LPTIM3_K>; + clock-names = "mux"; ++ power-domains = <&pd_core>; ++ wakeup-source; + status = "disabled"; + + pwm { +@@ -1144,8 +1408,11 @@ + lptimer4: timer@50023000 { + compatible = "st,stm32-lptimer"; + reg = <0x50023000 0x400>; ++ interrupts-extended = <&exti 52 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc LPTIM4_K>; + clock-names = "mux"; ++ power-domains = <&pd_core>; ++ wakeup-source; + status = "disabled"; + + pwm { +@@ -1158,8 +1425,11 @@ + lptimer5: timer@50024000 { + compatible = "st,stm32-lptimer"; + reg = <0x50024000 0x400>; ++ interrupts-extended = <&exti 53 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&rcc LPTIM5_K>; + clock-names = "mux"; ++ power-domains = <&pd_core>; ++ wakeup-source; + status = "disabled"; + + pwm { +@@ -1219,12 +1489,11 @@ status = "disabled"; }; @@ -4245,7 +3609,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -1232,9 +1499,9 @@ +@@ -1232,9 +1501,9 @@ compatible = "st,stm32f756-hash"; reg = <0x54002000 0x400>; interrupts = ; @@ -4258,7 +3622,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "in"; dma-maxburst = <2>; status = "disabled"; -@@ -1243,8 +1510,8 @@ +@@ -1243,8 +1512,8 @@ rng1: rng@54003000 { compatible = "st,stm32-rng"; reg = <0x54003000 0x400>; @@ -4269,7 +3633,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -1253,7 +1520,8 @@ +@@ -1253,28 +1522,44 @@ reg = <0x58000000 0x1000>; interrupts = ; clocks = <&rcc MDMA>; @@ -4279,20 +3643,57 @@ index f98e0370c..c516e2ed0 100644 dma-channels = <32>; dma-requests = <48>; }; -@@ -1268,9 +1536,9 @@ - <0x89010000 0x1000>, - <0x89020000 0x1000>; - interrupts = ; + +- fmc: nand-controller@58002000 { +- compatible = "st,stm32mp15-fmc2"; +- reg = <0x58002000 0x1000>, +- <0x80000000 0x1000>, +- <0x88010000 0x1000>, +- <0x88020000 0x1000>, +- <0x81000000 0x1000>, +- <0x89010000 0x1000>, +- <0x89020000 0x1000>; +- interrupts = ; - dmas = <&mdma1 20 0x10 0x12000a02 0x0 0x0>, - <&mdma1 20 0x10 0x12000a08 0x0 0x0>, - <&mdma1 21 0x10 0x12000a0a 0x0 0x0>; -+ dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0 0x0>, -+ <&mdma1 20 0x2 0x12000a08 0x0 0x0 0x0>, -+ <&mdma1 21 0x2 0x12000a0a 0x0 0x0 0x0>; - dma-names = "tx", "rx", "ecc"; +- dma-names = "tx", "rx", "ecc"; ++ fmc: memory-controller@58002000 { ++ #address-cells = <2>; ++ #size-cells = <1>; ++ compatible = "st,stm32mp1-fmc2-ebi"; ++ reg = <0x58002000 0x1000>; clocks = <&rcc FMC_K>; resets = <&rcc FMC_R>; -@@ -1282,8 +1550,8 @@ + status = "disabled"; ++ ++ ranges = <0 0 0x60000000 0x04000000>, /* EBI CS 1 */ ++ <1 0 0x64000000 0x04000000>, /* EBI CS 2 */ ++ <2 0 0x68000000 0x04000000>, /* EBI CS 3 */ ++ <3 0 0x6c000000 0x04000000>, /* EBI CS 4 */ ++ <4 0 0x80000000 0x10000000>; /* NAND */ ++ ++ nand-controller@4,0 { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ compatible = "st,stm32mp1-fmc2-nfc"; ++ reg = <4 0x00000000 0x1000>, ++ <4 0x08010000 0x1000>, ++ <4 0x08020000 0x1000>, ++ <4 0x01000000 0x1000>, ++ <4 0x09010000 0x1000>, ++ <4 0x09020000 0x1000>; ++ interrupts = ; ++ dmas = <&mdma1 20 0x2 0x12000a02 0x0 0x0 0x0>, ++ <&mdma1 20 0x2 0x12000a08 0x0 0x0 0x0>, ++ <&mdma1 21 0x2 0x12000a0a 0x0 0x0 0x0>; ++ dma-names = "tx", "rx", "ecc"; ++ status = "disabled"; ++ }; + }; + + qspi: spi@58003000 { +@@ -1282,8 +1567,8 @@ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; @@ -4303,7 +3704,7 @@ index f98e0370c..c516e2ed0 100644 dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; -@@ -1292,16 +1560,32 @@ +@@ -1292,16 +1577,32 @@ sdmmc1: sdmmc@58005000 { compatible = "arm,pl18x", "arm,primecell"; @@ -4339,7 +3740,7 @@ index f98e0370c..c516e2ed0 100644 }; crc1: crc@58009000 { -@@ -1321,23 +1605,25 @@ +@@ -1321,23 +1622,25 @@ compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; reg = <0x5800a000 0x2000>; reg-names = "stmmaceth"; @@ -4371,7 +3772,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -1355,28 +1641,10 @@ +@@ -1355,28 +1658,10 @@ reg = <0x5800d000 0x1000>; clocks = <&rcc USBH>; resets = <&rcc USBH_R>; @@ -4403,7 +3804,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -1394,7 +1662,7 @@ +@@ -1394,7 +1679,7 @@ iwdg2: watchdog@5a002000 { compatible = "st,stm32mp1-iwdg"; reg = <0x5a002000 0x400>; @@ -4412,7 +3813,7 @@ index f98e0370c..c516e2ed0 100644 clock-names = "pclk", "lsi"; status = "disabled"; }; -@@ -1402,10 +1670,13 @@ +@@ -1402,10 +1687,13 @@ usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; @@ -4426,7 +3827,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; usbphyc_port0: usb-phy@0 { -@@ -1419,11 +1690,22 @@ +@@ -1419,11 +1707,21 @@ }; }; @@ -4445,13 +3846,12 @@ index f98e0370c..c516e2ed0 100644 - clocks = <&rcc USART1_K>; + interrupts-extended = <&exti 26 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&scmi0_clk CK_SCMI0_USART1>; -+ resets = <&scmi0_reset RST_SCMI0_USART1>; + wakeup-source; + power-domains = <&pd_core>; status = "disabled"; }; -@@ -1433,33 +1715,41 @@ +@@ -1433,33 +1731,41 @@ compatible = "st,stm32h7-spi"; reg = <0x5c001000 0x400>; interrupts = ; @@ -4504,7 +3904,7 @@ index f98e0370c..c516e2ed0 100644 status = "disabled"; }; -@@ -1468,6 +1758,10 @@ +@@ -1468,26 +1774,216 @@ reg = <0x5c005000 0x400>; #address-cells = <1>; #size-cells = <1>; @@ -4515,7 +3915,12 @@ index f98e0370c..c516e2ed0 100644 ts_cal1: calib@5c { reg = <0x5c 0x2>; }; -@@ -1477,17 +1771,200 @@ + ts_cal2: calib@5e { + reg = <0x5e 0x2>; + }; ++ ethernet_mac_address: mac@e4 { ++ reg = <0xe4 0x6>; ++ }; }; i2c6: i2c@5c009000 { @@ -4721,14 +4126,16 @@ index f98e0370c..c516e2ed0 100644 }; mlahb { -@@ -1503,10 +1980,18 @@ +@@ -1503,10 +1999,18 @@ reg = <0x10000000 0x40000>, <0x30000000 0x40000>, <0x38000000 0x10000>; - resets = <&rcc MCU_R>; -+ resets = <&scmi0_reset RST_SCMI0_MCU>; - st,syscfg-holdboot = <&rcc 0x10C 0x1>; - st,syscfg-tz = <&rcc 0x000 0x1>; +- st,syscfg-holdboot = <&rcc 0x10C 0x1>; +- st,syscfg-tz = <&rcc 0x000 0x1>; ++ resets = <&scmi0_reset RST_SCMI0_MCU>, ++ <&scmi0_reset RST_SCMI0_MCU_HOLD_BOOT>; ++ reset-names = "mcu_rst", "hold_boot"; + st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>; + st,syscfg-copro-state = <&tamp 0x148 0xFFFFFFFF>; + st,syscfg-pdds = <&pwr_mcu 0x0 0x1>; @@ -4743,7 +4150,7 @@ index f98e0370c..c516e2ed0 100644 }; diff --git a/arch/arm/boot/dts/stm32mp153.dtsi b/arch/arm/boot/dts/stm32mp153.dtsi new file mode 100644 -index 000000000..cf16b843c +index 0000000000000..cf16b843c6b55 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp153.dtsi @@ -0,0 +1,54 @@ @@ -4803,7 +4210,7 @@ index 000000000..cf16b843c +}; diff --git a/arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi new file mode 100644 -index 000000000..b4030e5c9 +index 0000000000000..b4030e5c9422b --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157-m4-srm-pinctrl.dtsi @@ -0,0 +1,524 @@ @@ -5333,7 +4740,7 @@ index 000000000..b4030e5c9 +}; diff --git a/arch/arm/boot/dts/stm32mp157-m4-srm.dtsi b/arch/arm/boot/dts/stm32mp157-m4-srm.dtsi new file mode 100644 -index 000000000..60454aee4 +index 0000000000000..60454aee4123f --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157-m4-srm.dtsi @@ -0,0 +1,442 @@ @@ -5781,7 +5188,7 @@ index 000000000..60454aee4 + diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi deleted file mode 100644 -index 0a3a7d667..000000000 +index 0a3a7d66737b6..0000000000000 --- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi +++ /dev/null @@ -1,925 +0,0 @@ @@ -6712,7 +6119,7 @@ index 0a3a7d667..000000000 -}; diff --git a/arch/arm/boot/dts/stm32mp157.dtsi b/arch/arm/boot/dts/stm32mp157.dtsi new file mode 100644 -index 000000000..ce1d83aa7 +index 0000000000000..ce1d83aa7b29e --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157.dtsi @@ -0,0 +1,32 @@ @@ -6749,7 +6156,7 @@ index 000000000..ce1d83aa7 + }; +}; diff --git a/arch/arm/boot/dts/stm32mp157a-avenger96.dts b/arch/arm/boot/dts/stm32mp157a-avenger96.dts -index 2e4742c53..887b76662 100644 +index 7b8c3f25861c9..4479b06a94cf5 100644 --- a/arch/arm/boot/dts/stm32mp157a-avenger96.dts +++ b/arch/arm/boot/dts/stm32mp157a-avenger96.dts @@ -6,9 +6,10 @@ @@ -6766,7 +6173,7 @@ index 2e4742c53..887b76662 100644 #include / { -@@ -252,14 +253,13 @@ +@@ -255,14 +256,13 @@ regulator-name = "vbus_otg"; interrupts = ; interrupt-parent = <&pmic>; @@ -6782,7 +6189,7 @@ index 2e4742c53..887b76662 100644 }; }; -@@ -282,6 +282,11 @@ +@@ -285,6 +285,11 @@ status = "okay"; }; @@ -6794,7 +6201,7 @@ index 2e4742c53..887b76662 100644 &rng1 { status = "okay"; }; -@@ -295,7 +300,7 @@ +@@ -298,7 +303,7 @@ pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; pinctrl-1 = <&sdmmc1_b4_od_pins_a>; pinctrl-2 = <&sdmmc1_b4_sleep_pins_a>; @@ -6804,7 +6211,7 @@ index 2e4742c53..887b76662 100644 st,neg-edge; st,use-ckin; diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -index 0615d1c8a..baff3f694 100644 +index 0615d1c8a6fcf..1f265fed2c5d6 100644 --- a/arch/arm/boot/dts/stm32mp157a-dk1.dts +++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts @@ -6,11 +6,11 @@ @@ -6824,7 +6231,7 @@ index 0615d1c8a..baff3f694 100644 / { model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; -@@ -18,434 +18,27 @@ +@@ -18,434 +18,18 @@ aliases { ethernet0 = ðernet0; serial0 = &uart4; @@ -6866,24 +6273,22 @@ index 0615d1c8a..baff3f694 100644 - vdev0buffer: vdev0buffer@10042000 { - compatible = "shared-dma-pool"; - reg = <0x10042000 0x4000>; -- no-map; -- }; -- -- mcuram: mcuram@30000000 { -- compatible = "shared-dma-pool"; -- reg = <0x30000000 0x40000>; + gpu_reserved: gpu@da000000 { + reg = <0xda000000 0x4000000>; no-map; }; - +- +- mcuram: mcuram@30000000 { +- compatible = "shared-dma-pool"; +- reg = <0x30000000 0x40000>; +- no-map; +- }; +- - retram: retram@38000000 { - compatible = "shared-dma-pool"; - reg = <0x38000000 0x10000>; -+ optee_memory: optee@0xde000000 { -+ reg = <0xde000000 0x02000000>; - no-map; - }; +- no-map; +- }; - - gpu_reserved: gpu@d4000000 { - reg = <0xd4000000 0x4000000>; @@ -6978,7 +6383,7 @@ index 0615d1c8a..baff3f694 100644 - }; - }; - }; -- }; + }; - - cs42l51: cs42l51@4a { - compatible = "cirrus,cs42l51"; @@ -7011,9 +6416,9 @@ index 0615d1c8a..baff3f694 100644 - bitclock-master; - }; - }; - }; - }; - +- }; +-}; +- -&i2c4 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c4_pins_a>; @@ -7263,15 +6668,14 @@ index 0615d1c8a..baff3f694 100644 -&uart4 { - pinctrl-names = "default"; - pinctrl-0 = <&uart4_pins_a>; -+&optee { - status = "okay"; +- status = "okay"; }; diff --git a/arch/arm/boot/dts/stm32mp157a-ed1.dts b/arch/arm/boot/dts/stm32mp157a-ed1.dts new file mode 100644 -index 000000000..5dca95684 +index 0000000000000..e7fad7d39476b --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-ed1.dts -@@ -0,0 +1,52 @@ +@@ -0,0 +1,43 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -7304,11 +6708,6 @@ index 000000000..5dca95684 + reg = <0xf6000000 0x8000000>; + no-map; + }; -+ -+ optee_memory: optee@fe000000 { -+ reg = <0xfe000000 0x02000000>; -+ no-map; -+ }; + }; +}; + @@ -7320,13 +6719,9 @@ index 000000000..5dca95684 + contiguous-area = <&gpu_reserved>; + status = "okay"; +}; -+ -+&optee { -+ status = "okay"; -+}; diff --git a/arch/arm/boot/dts/stm32mp157a-ev1.dts b/arch/arm/boot/dts/stm32mp157a-ev1.dts new file mode 100644 -index 000000000..29ecd15c3 +index 0000000000000..29ecd15c32161 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-ev1.dts @@ -0,0 +1,86 @@ @@ -7418,10 +6813,10 @@ index 000000000..29ecd15c3 +}; diff --git a/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts new file mode 100644 -index 000000000..1bffbc629 +index 0000000000000..372ceb2c71283 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts -@@ -0,0 +1,46 @@ +@@ -0,0 +1,60 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -7439,6 +6834,12 @@ index 000000000..1bffbc629 + +&adc { + status = "okay"; ++ ++ adc2: adc@100 { ++ /* Set IRQ mode as example. DMA is the preferred mode, yet. */ ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ }; +}; + +&i2c5 { @@ -7468,9 +6869,17 @@ index 000000000..1bffbc629 +&timers12 { + status = "okay"; +}; ++ ++&uart7 { ++ status = "okay"; ++}; ++ ++&usart3 { ++ status = "okay"; ++}; diff --git a/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts new file mode 100644 -index 000000000..14eac740d +index 0000000000000..14eac740d4e31 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts @@ -0,0 +1,129 @@ @@ -7604,10 +7013,10 @@ index 000000000..14eac740d + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -index 20ea601a5..a7d5e86a1 100644 +index 20ea601a546dd..ba1d15de2f2c6 100644 --- a/arch/arm/boot/dts/stm32mp157c-dk2.dts +++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -6,26 +6,55 @@ +@@ -6,26 +6,50 @@ /dts-v1/; @@ -7646,11 +7055,6 @@ index 20ea601a5..a7d5e86a1 100644 + reg = <0xda000000 0x4000000>; + no-map; + }; -+ -+ optee_memory: optee@0xde000000 { -+ reg = <0xde000000 0x02000000>; -+ no-map; -+ }; + }; + + wifi_pwrseq: wifi-pwrseq { @@ -7671,7 +7075,7 @@ index 20ea601a5..a7d5e86a1 100644 ports { #address-cells = <1>; -@@ -46,7 +75,7 @@ +@@ -46,7 +70,7 @@ }; }; @@ -7680,7 +7084,7 @@ index 20ea601a5..a7d5e86a1 100644 compatible = "orisetech,otm8009a"; reg = <0>; reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; -@@ -61,6 +90,31 @@ +@@ -61,6 +85,31 @@ }; }; @@ -7712,7 +7116,7 @@ index 20ea601a5..a7d5e86a1 100644 <dc { status = "okay"; -@@ -74,3 +128,57 @@ +@@ -74,3 +123,49 @@ }; }; }; @@ -7762,16 +7166,8 @@ index 20ea601a5..a7d5e86a1 100644 + vddio-supply = <&v3v3>; + }; +}; -+ -+&optee_memory { -+ status = "okay"; -+}; -+ -+&optee { -+ status = "okay"; -+}; diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index 1d426ea8b..bf2d7e7b7 100644 +index 1d426ea8bdafa..16ddc0e9f832e 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -1,14 +1,17 @@ @@ -7798,7 +7194,7 @@ index 1d426ea8b..bf2d7e7b7 100644 / { model = "STMicroelectronics STM32MP157C eval daughter"; -@@ -18,94 +21,29 @@ +@@ -18,314 +21,27 @@ stdout-path = "serial0:115200n8"; }; @@ -7823,11 +7219,9 @@ index 1d426ea8b..bf2d7e7b7 100644 - vdev0vring0: vdev0vring0@10040000 { - compatible = "shared-dma-pool"; - reg = <0x10040000 0x1000>; -+ gpu_reserved: gpu@f6000000 { -+ reg = <0xf6000000 0x8000000>; - no-map; - }; - +- no-map; +- }; +- - vdev0vring1: vdev0vring1@10041000 { - compatible = "shared-dma-pool"; - reg = <0x10041000 0x1000>; @@ -7843,8 +7237,10 @@ index 1d426ea8b..bf2d7e7b7 100644 - mcuram: mcuram@30000000 { - compatible = "shared-dma-pool"; - reg = <0x30000000 0x40000>; -- no-map; -- }; ++ gpu_reserved: gpu@f6000000 { ++ reg = <0xf6000000 0x8000000>; + no-map; + }; - - retram: retram@38000000 { - compatible = "shared-dma-pool"; @@ -7854,17 +7250,15 @@ index 1d426ea8b..bf2d7e7b7 100644 - - gpu_reserved: gpu@e8000000 { - reg = <0xe8000000 0x8000000>; -+ optee_memory: optee@fe000000 { -+ reg = <0xfe000000 0x02000000>; - no-map; - }; +- no-map; +- }; +- }; +- +- aliases { +- serial0 = &uart4; }; +}; -- aliases { -- serial0 = &uart4; -- }; -- - reg11: reg11 { - compatible = "regulator-fixed"; - regulator-name = "reg11"; @@ -7904,17 +7298,16 @@ index 1d426ea8b..bf2d7e7b7 100644 }; &gpu { -@@ -113,219 +51,6 @@ + contiguous-area = <&gpu_reserved>; status = "okay"; }; - +- -&i2c4 { - pinctrl-names = "default"; - pinctrl-0 = <&i2c4_pins_a>; - i2c-scl-rising-time-ns = <185>; - i2c-scl-falling-time-ns = <20>; -+&optee { - status = "okay"; +- status = "okay"; - /* spare dmas for other usage */ - /delete-property/dmas; - /delete-property/dma-names; @@ -8124,13 +7517,13 @@ index 1d426ea8b..bf2d7e7b7 100644 - phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; - }; +-}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts new file mode 100644 -index 000000000..25c9f4f2f +index 0000000000000..8a4eda70d4521 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts -@@ -0,0 +1,53 @@ +@@ -0,0 +1,57 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -8184,9 +7577,13 @@ index 000000000..25c9f4f2f +&timers12 { + status = "okay"; +}; ++ ++&usart3 { ++ status = "okay"; ++}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts new file mode 100644 -index 000000000..b1bb38efb +index 0000000000000..b1bb38efbfa80 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts @@ -0,0 +1,146 @@ @@ -8337,7 +7734,7 @@ index 000000000..b1bb38efb + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts -index 91fc0a315..c60727d9b 100644 +index 91fc0a315c491..c60727d9b1ae0 100644 --- a/arch/arm/boot/dts/stm32mp157c-ev1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts @@ -1,13 +1,14 @@ @@ -8681,10 +8078,10 @@ index 91fc0a315..c60727d9b 100644 -}; diff --git a/arch/arm/boot/dts/stm32mp157d-dk1.dts b/arch/arm/boot/dts/stm32mp157d-dk1.dts new file mode 100644 -index 000000000..c7d65a65e +index 0000000000000..aa98012fd32d8 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157d-dk1.dts -@@ -0,0 +1,44 @@ +@@ -0,0 +1,35 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -8718,23 +8115,14 @@ index 000000000..c7d65a65e + reg = <0xda000000 0x4000000>; + no-map; + }; -+ -+ optee_memory: optee@0xde000000 { -+ reg = <0xde000000 0x02000000>; -+ no-map; -+ }; + }; +}; -+ -+&optee { -+ status = "okay"; -+}; diff --git a/arch/arm/boot/dts/stm32mp157d-ed1.dts b/arch/arm/boot/dts/stm32mp157d-ed1.dts new file mode 100644 -index 000000000..ee55ac8f3 +index 0000000000000..aaf9adf51c55c --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157d-ed1.dts -@@ -0,0 +1,52 @@ +@@ -0,0 +1,43 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -8767,11 +8155,6 @@ index 000000000..ee55ac8f3 + reg = <0xf6000000 0x8000000>; + no-map; + }; -+ -+ optee_memory: optee@fe000000 { -+ reg = <0xfe000000 0x02000000>; -+ no-map; -+ }; + }; +}; + @@ -8783,13 +8166,9 @@ index 000000000..ee55ac8f3 + contiguous-area = <&gpu_reserved>; + status = "okay"; +}; -+ -+&optee { -+ status = "okay"; -+}; diff --git a/arch/arm/boot/dts/stm32mp157d-ev1.dts b/arch/arm/boot/dts/stm32mp157d-ev1.dts new file mode 100644 -index 000000000..a4752c100 +index 0000000000000..a4752c100ef93 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157d-ev1.dts @@ -0,0 +1,86 @@ @@ -8881,10 +8260,10 @@ index 000000000..a4752c100 +}; diff --git a/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts b/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts new file mode 100644 -index 000000000..2a8c46059 +index 0000000000000..339e24b91616b --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts -@@ -0,0 +1,46 @@ +@@ -0,0 +1,52 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -8902,6 +8281,12 @@ index 000000000..2a8c46059 + +&adc { + status = "okay"; ++ ++ adc2: adc@100 { ++ /* Set IRQ mode as example. DMA is the preferred mode, yet. */ ++ /delete-property/dmas; ++ /delete-property/dma-names; ++ }; +}; + +&i2c5 { @@ -8933,7 +8318,7 @@ index 000000000..2a8c46059 +}; diff --git a/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts b/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts new file mode 100644 -index 000000000..726522997 +index 0000000000000..72652299743b9 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts @@ -0,0 +1,129 @@ @@ -9068,10 +8453,10 @@ index 000000000..726522997 +}; diff --git a/arch/arm/boot/dts/stm32mp157f-dk2.dts b/arch/arm/boot/dts/stm32mp157f-dk2.dts new file mode 100644 -index 000000000..b57db3037 +index 0000000000000..1123d0f3ed4a5 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-dk2.dts -@@ -0,0 +1,185 @@ +@@ -0,0 +1,171 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -9108,12 +8493,6 @@ index 000000000..b57db3037 + reg = <0xda000000 0x4000000>; + no-map; + }; -+ -+ optee_memory: optee@0xde000000 { -+ reg = <0xde000000 0x02000000>; -+ no-map; -+ status = "disabled"; -+ }; + }; + + wifi_pwrseq: wifi-pwrseq { @@ -9249,20 +8628,12 @@ index 000000000..b57db3037 + vddio-supply = <&v3v3>; + }; +}; -+ -+&optee_memory { -+ status = "okay"; -+}; -+ -+&optee { -+ status = "okay"; -+}; diff --git a/arch/arm/boot/dts/stm32mp157f-ed1.dts b/arch/arm/boot/dts/stm32mp157f-ed1.dts new file mode 100644 -index 000000000..65380693c +index 0000000000000..7ddb96a0ef5d9 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ed1.dts -@@ -0,0 +1,56 @@ +@@ -0,0 +1,47 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -9295,11 +8666,6 @@ index 000000000..65380693c + reg = <0xf6000000 0x8000000>; + no-map; + }; -+ -+ optee_memory: optee@0xfe000000 { -+ reg = <0xfe000000 0x02000000>; -+ no-map; -+ }; + }; +}; + @@ -9315,13 +8681,9 @@ index 000000000..65380693c + contiguous-area = <&gpu_reserved>; + status = "okay"; +}; -+ -+&optee { -+ status = "okay"; -+}; diff --git a/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts b/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts new file mode 100644 -index 000000000..17d92b7be +index 0000000000000..17d92b7bebdb1 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts @@ -0,0 +1,53 @@ @@ -9380,7 +8742,7 @@ index 000000000..17d92b7be +}; diff --git a/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts b/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts new file mode 100644 -index 000000000..d508be276 +index 0000000000000..d508be27666a5 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts @@ -0,0 +1,146 @@ @@ -9532,7 +8894,7 @@ index 000000000..d508be276 +}; diff --git a/arch/arm/boot/dts/stm32mp157f-ev1.dts b/arch/arm/boot/dts/stm32mp157f-ev1.dts new file mode 100644 -index 000000000..0c18333c0 +index 0000000000000..0c18333c07cf3 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ev1.dts @@ -0,0 +1,86 @@ @@ -9624,7 +8986,7 @@ index 000000000..0c18333c0 +}; diff --git a/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi deleted file mode 100644 -index 875adf5e1..000000000 +index 875adf5e1e303..0000000000000 --- a/arch/arm/boot/dts/stm32mp157xaa-pinctrl.dtsi +++ /dev/null @@ -1,90 +0,0 @@ @@ -9720,7 +9082,7 @@ index 875adf5e1..000000000 -}; diff --git a/arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi deleted file mode 100644 -index 961fa12a5..000000000 +index 961fa12a59c31..0000000000000 --- a/arch/arm/boot/dts/stm32mp157xab-pinctrl.dtsi +++ /dev/null @@ -1,62 +0,0 @@ @@ -9788,7 +9150,7 @@ index 961fa12a5..000000000 -}; diff --git a/arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi deleted file mode 100644 -index 26600f188..000000000 +index 26600f188d251..0000000000000 --- a/arch/arm/boot/dts/stm32mp157xac-pinctrl.dtsi +++ /dev/null @@ -1,78 +0,0 @@ @@ -9872,7 +9234,7 @@ index 26600f188..000000000 -}; diff --git a/arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi deleted file mode 100644 -index 910113f3e..000000000 +index 910113f3e69ae..0000000000000 --- a/arch/arm/boot/dts/stm32mp157xad-pinctrl.dtsi +++ /dev/null @@ -1,62 +0,0 @@ @@ -9940,7 +9302,7 @@ index 910113f3e..000000000 -}; diff --git a/arch/arm/boot/dts/stm32mp15xa.dtsi b/arch/arm/boot/dts/stm32mp15xa.dtsi new file mode 100644 -index 000000000..5ed7e594f +index 0000000000000..5ed7e594f4cd9 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xa.dtsi @@ -0,0 +1,13 @@ @@ -9959,7 +9321,7 @@ index 000000000..5ed7e594f +}; diff --git a/arch/arm/boot/dts/stm32mp15xc.dtsi b/arch/arm/boot/dts/stm32mp15xc.dtsi new file mode 100644 -index 000000000..adc1568a7 +index 0000000000000..adc1568a72850 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xc.dtsi @@ -0,0 +1,20 @@ @@ -9985,7 +9347,7 @@ index 000000000..adc1568a7 +}; diff --git a/arch/arm/boot/dts/stm32mp15xd.dtsi b/arch/arm/boot/dts/stm32mp15xd.dtsi new file mode 100644 -index 000000000..faa039ea2 +index 0000000000000..e2f8b1297c33d --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xd.dtsi @@ -0,0 +1,42 @@ @@ -10018,7 +9380,7 @@ index 000000000..faa039ea2 + }; + + cpu_alert: cpu-alert { -+ temperature = <950000>; ++ temperature = <95000>; + hysteresis = <10000>; + type = "passive"; + }; @@ -10033,7 +9395,7 @@ index 000000000..faa039ea2 +}; diff --git a/arch/arm/boot/dts/stm32mp15xf.dtsi b/arch/arm/boot/dts/stm32mp15xf.dtsi new file mode 100644 -index 000000000..77f50b9bd +index 0000000000000..77f50b9bda64e --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xf.dtsi @@ -0,0 +1,20 @@ @@ -10059,10 +9421,10 @@ index 000000000..77f50b9bd +}; diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi new file mode 100644 -index 000000000..35169385f +index 0000000000000..685a82161cc8e --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi -@@ -0,0 +1,768 @@ +@@ -0,0 +1,770 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -10228,6 +9590,8 @@ index 000000000..35169385f + phy-mode = "rgmii-id"; + max-speed = <1000>; + phy-handle = <&phy0>; ++ nvmem-cells = <ðernet_mac_address>; ++ nvmem-cell-names = "mac-address"; + + mdio0 { + #address-cells = <1>; @@ -10833,10 +10197,10 @@ index 000000000..35169385f +}; diff --git a/arch/arm/boot/dts/stm32mp15xx-edx.dtsi b/arch/arm/boot/dts/stm32mp15xx-edx.dtsi new file mode 100644 -index 000000000..7ed6b14d7 +index 0000000000000..c67d57cc02373 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xx-edx.dtsi -@@ -0,0 +1,408 @@ +@@ -0,0 +1,407 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -11228,7 +10592,6 @@ index 000000000..7ed6b14d7 + pinctrl-0 = <&uart4_pins_a>; + pinctrl-1 = <&uart4_sleep_pins_a>; + pinctrl-2 = <&uart4_idle_pins_a>; -+ pinctrl-3 = <&uart4_pins_a>; + /delete-property/dmas; + /delete-property/dma-names; + status = "okay"; @@ -11247,10 +10610,10 @@ index 000000000..7ed6b14d7 +}; diff --git a/arch/arm/boot/dts/stm32mp15xx-evx.dtsi b/arch/arm/boot/dts/stm32mp15xx-evx.dtsi new file mode 100644 -index 000000000..07cb93db9 +index 0000000000000..1a2b49cadac25 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xx-evx.dtsi -@@ -0,0 +1,680 @@ +@@ -0,0 +1,687 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -11476,11 +10839,12 @@ index 000000000..07cb93db9 + + dfsdm1: filter@1 { + compatible = "st,stm32-dfsdm-dmic"; -+ st,adc-channels = <1>; ++ st,adc-channels = <0>; + st,adc-channel-names = "dmic_u2"; + st,adc-channel-types = "SPI_F"; + st,adc-channel-clk-src = "CLKOUT"; + st,filter-order = <3>; ++ st,adc-alt-channel = <1>; + status = "okay"; + + asoc_pdm1: dfsdm-dai { @@ -11499,10 +10863,11 @@ index 000000000..07cb93db9 + + dfsdm2: filter@2 { + compatible = "st,stm32-dfsdm-dmic"; -+ st,adc-channels = <3>; ++ st,adc-channels = <2>; + st,adc-channel-names = "dmic_u3"; + st,adc-channel-types = "SPI_F"; + st,adc-channel-clk-src = "CLKOUT"; ++ st,adc-alt-channel = <1>; + st,filter-order = <3>; + status = "okay"; + @@ -11552,6 +10917,8 @@ index 000000000..07cb93db9 + phy-mode = "rgmii-id"; + max-speed = <1000>; + phy-handle = <&phy0>; ++ nvmem-cells = <ðernet_mac_address>; ++ nvmem-cell-names = "mac-address"; + + mdio0 { + #address-cells = <1>; @@ -11568,14 +10935,16 @@ index 000000000..07cb93db9 + pinctrl-0 = <&fmc_pins_a>; + pinctrl-1 = <&fmc_sleep_pins_a>; + status = "okay"; -+ #address-cells = <1>; -+ #size-cells = <0>; + -+ nand@0 { -+ reg = <0>; -+ nand-on-flash-bbt; -+ #address-cells = <1>; -+ #size-cells = <1>; ++ nand-controller@4,0 { ++ status = "okay"; ++ ++ nand@0 { ++ reg = <0>; ++ nand-on-flash-bbt; ++ #address-cells = <1>; ++ #size-cells = <1>; ++ }; + }; +}; + @@ -11926,6 +11295,7 @@ index 000000000..07cb93db9 + +&usbphyc_port0 { + st,phy-tuning = <&usb_phy_tuning>; ++ vbus-supply = <&vbus_sw>; +}; + +&usbphyc_port1 { @@ -11933,7 +11303,7 @@ index 000000000..07cb93db9 +}; diff --git a/arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi new file mode 100644 -index 000000000..64e566bf8 +index 0000000000000..64e566bf82f50 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xxaa-pinctrl.dtsi @@ -0,0 +1,85 @@ @@ -12024,7 +11394,7 @@ index 000000000..64e566bf8 +}; diff --git a/arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi new file mode 100644 -index 000000000..d29af8986 +index 0000000000000..d29af8986f2de --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xxab-pinctrl.dtsi @@ -0,0 +1,57 @@ @@ -12087,7 +11457,7 @@ index 000000000..d29af8986 +}; diff --git a/arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi new file mode 100644 -index 000000000..5d8199fd1 +index 0000000000000..5d8199fd19c4b --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xxac-pinctrl.dtsi @@ -0,0 +1,73 @@ @@ -12166,7 +11536,7 @@ index 000000000..5d8199fd1 +}; diff --git a/arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi new file mode 100644 -index 000000000..023f5404c +index 0000000000000..023f5404c4687 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xxad-pinctrl.dtsi @@ -0,0 +1,57 @@ @@ -12227,234 +11597,6 @@ index 000000000..023f5404c + gpio-ranges = <&pinctrl 0 112 2>; + }; +}; -diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h -index 4cdaf1358..ec7b1a932 100644 ---- a/include/dt-bindings/clock/stm32mp1-clks.h -+++ b/include/dt-bindings/clock/stm32mp1-clks.h -@@ -179,6 +179,12 @@ - #define DAC12_K 168 - #define ETHPTP_K 169 - -+#define PCLK1 170 -+#define PCLK2 171 -+#define PCLK3 172 -+#define PCLK4 173 -+#define PCLK5 174 -+ - /* PLL */ - #define PLL1 176 - #define PLL2 177 -@@ -248,4 +254,31 @@ - - #define STM32MP1_LAST_CLK 232 - -+/* SCMI clock identifiers */ -+#define CK_SCMI0_HSE 0 -+#define CK_SCMI0_HSI 1 -+#define CK_SCMI0_CSI 2 -+#define CK_SCMI0_LSE 3 -+#define CK_SCMI0_LSI 4 -+#define CK_SCMI0_PLL2_Q 5 -+#define CK_SCMI0_PLL2_R 6 -+#define CK_SCMI0_MPU 7 -+#define CK_SCMI0_AXI 8 -+#define CK_SCMI0_BSEC 9 -+#define CK_SCMI0_CRYP1 10 -+#define CK_SCMI0_GPIOZ 11 -+#define CK_SCMI0_HASH1 12 -+#define CK_SCMI0_I2C4 13 -+#define CK_SCMI0_I2C6 14 -+#define CK_SCMI0_IWDG1 15 -+#define CK_SCMI0_RNG1 16 -+#define CK_SCMI0_RTC 17 -+#define CK_SCMI0_RTCAPB 18 -+#define CK_SCMI0_SPI6 19 -+#define CK_SCMI0_USART1 20 -+ -+#define CK_SCMI1_PLL3_Q 0 -+#define CK_SCMI1_PLL3_R 1 -+#define CK_SCMI1_MCU 2 -+ - #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ -diff --git a/include/dt-bindings/mfd/stm32f4-rcc.h b/include/dt-bindings/mfd/stm32f4-rcc.h -index 309e8c79f..36448a561 100644 ---- a/include/dt-bindings/mfd/stm32f4-rcc.h -+++ b/include/dt-bindings/mfd/stm32f4-rcc.h -@@ -34,7 +34,6 @@ - #define STM32F4_AHB1_RESET(bit) (STM32F4_RCC_AHB1_##bit + (0x10 * 8)) - #define STM32F4_AHB1_CLOCK(bit) (STM32F4_RCC_AHB1_##bit) - -- - /* AHB2 */ - #define STM32F4_RCC_AHB2_DCMI 0 - #define STM32F4_RCC_AHB2_CRYP 4 -diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h -index e6fb8ada3..370a25a93 100644 ---- a/include/dt-bindings/pinctrl/stm32-pinfunc.h -+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h -@@ -26,6 +26,7 @@ - #define AF14 0xf - #define AF15 0x10 - #define ANALOG 0x11 -+#define RSVD 0x12 - - /* define Pins number*/ - #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) -diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h -index f0c3aaef6..bc71924fa 100644 ---- a/include/dt-bindings/reset/stm32mp1-resets.h -+++ b/include/dt-bindings/reset/stm32mp1-resets.h -@@ -105,4 +105,17 @@ - #define GPIOJ_R 19785 - #define GPIOK_R 19786 - -+/* SCMI reset domain identifiers */ -+#define RST_SCMI0_SPI6 0 -+#define RST_SCMI0_I2C4 1 -+#define RST_SCMI0_I2C6 2 -+#define RST_SCMI0_USART1 3 -+#define RST_SCMI0_STGEN 4 -+#define RST_SCMI0_GPIOZ 5 -+#define RST_SCMI0_CRYP1 6 -+#define RST_SCMI0_HASH1 7 -+#define RST_SCMI0_RNG1 8 -+#define RST_SCMI0_MDMA 9 -+#define RST_SCMI0_MCU 10 -+ - #endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ -diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h -new file mode 100644 -index 000000000..4373c4dea ---- /dev/null -+++ b/include/dt-bindings/rtc/rtc-stm32.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * This header provides constants for STM32_RTC bindings. -+ */ -+ -+#ifndef _DT_BINDINGS_RTC_RTC_STM32_H -+#define _DT_BINDINGS_RTC_RTC_STM32_H -+ -+#define RTC_OUT1 0 -+#define RTC_OUT2 1 -+#define RTC_OUT2_RMP 2 -+ -+#endif -diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h -new file mode 100644 -index 000000000..d98665327 ---- /dev/null -+++ b/include/dt-bindings/soc/stm32-hdp.h -@@ -0,0 +1,108 @@ -+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -+/* -+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved -+ * Author: Roullier Christophe -+ * for STMicroelectronics. -+ */ -+ -+#ifndef _DT_BINDINGS_STM32_HDP_H -+#define _DT_BINDINGS_STM32_HDP_H -+ -+#define STM32_HDP(port, value) ((value) << ((port) * 4)) -+ -+/* define HDP Pins number*/ -+#define HDP0_PWR_PWRWAKE_SYS 0 -+#define HDP0_CM4_SLEEPDEEP 1 -+#define HDP0_PWR_STDBY_WKUP 2 -+#define HDP0_PWR_ENCOMP_VDDCORE 3 -+#define HDP0_BSEC_OUT_SEC_NIDEN 4 -+#define HDP0_RCC_CM4_SLEEPDEEP 6 -+#define HDP0_GPU_DBG7 7 -+#define HDP0_DDRCTRL_LP_REQ 8 -+#define HDP0_PWR_DDR_RET_ENABLE_N 9 -+#define HDP0_GPOVAL_0 15 -+ -+#define HDP1_PWR_PWRWAKE_MCU 0 -+#define HDP1_CM4_HALTED 1 -+#define HDP1_CA7_NAXIERRIRQ 2 -+#define HDP1_PWR_OKIN_MR 3 -+#define HDP1_BSEC_OUT_SEC_DBGEN 4 -+#define HDP1_EXTI_SYS_WAKEUP 5 -+#define HDP1_RCC_PWRDS_MPU 6 -+#define HDP1_GPU_DBG6 7 -+#define HDP1_DDRCTRL_DFI_CTRLUPD_REQ 8 -+#define HDP1_DDRCTRL_CACTIVE_DDRC_ASR 9 -+#define HDP1_GPOVAL_1 15 -+ -+#define HDP2_PWR_PWRWAKE_MPU 0 -+#define HDP2_CM4_RXEV 1 -+#define HDP2_CA7_NPMUIRQ1 2 -+#define HDP2_CA7_NFIQOUT1 3 -+#define HDP2_BSEC_IN_RSTCORE_N 4 -+#define HDP2_EXTI_C2_WAKEUP 5 -+#define HDP2_RCC_PWRDS_MCU 6 -+#define HDP2_GPU_DBG5 7 -+#define HDP2_DDRCTRL_DFI_INIT_COMPLETE 8 -+#define HDP2_DDRCTRL_PERF_OP_IS_REFRESH 9 -+#define HDP2_DDRCTRL_GSKP_DFI_LP_REQ 10 -+#define HDP2_GPOVAL_2 15 -+ -+#define HDP3_PWR_SEL_VTH_VDD_CORE 0 -+#define HDP3_CM4_TXEV 1 -+#define HDP3_CA7_NPMUIRQ0 2 -+#define HDP3_CA7_NFIQOUT0 3 -+#define HDP3_BSEC_OUT_SEC_DFTLOCK 4 -+#define HDP3_EXTI_C1_WAKEUP 5 -+#define HDP3_RCC_PWRDS_SYS 6 -+#define HDP3_GPU_DBG4 7 -+#define HDP3_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE0 8 -+#define HDP3_DDRCTRL_CACTIVE_1 9 -+#define HDP3_GPOVAL_3 15 -+ -+#define HDP4_PWR_PDDS 0 -+#define HDP4_CM4_SLEEPING 1 -+#define HDP4_CA7_NRESET1 2 -+#define HDP4_CA7_NIRQOUT1 3 -+#define HDP4_BSEC_OUT_SEC_DFTEN 4 -+#define HDP4_BSEC_OUT_SEC_DBGSWENABLE 5 -+#define HDP4_ETH_OUT_PMT_INTR_O 6 -+#define HDP4_GPU_DBG3 7 -+#define HDP4_DDRCTRL_STAT_DDRC_REG_SELREF_TYPE1 8 -+#define HDP4_DDRCTRL_CACTIVE_0 9 -+#define HDP4_GPOVAL_4 15 -+ -+#define HDP5_CA7_STANDBYWFIL2 0 -+#define HDP5_PWR_VTH_VDDCORE_ACK 1 -+#define HDP5_CA7_NRESET0 2 -+#define HDP5_CA7_NIRQOUT0 3 -+#define HDP5_BSEC_IN_PWROK 4 -+#define HDP5_BSEC_OUT_SEC_DEVICEEN 5 -+#define HDP5_ETH_OUT_LPI_INTR_O 6 -+#define HDP5_GPU_DBG2 7 -+#define HDP5_DDRCTRL_CACTIVE_DDRC 8 -+#define HDP5_DDRCTRL_WR_CREDIT_CNT 9 -+#define HDP5_GPOVAL_5 15 -+ -+#define HDP6_CA7_STANDBYWFI1 0 -+#define HDP6_CA7_STANDBYWFE1 1 -+#define HDP6_CA7_EVENT0 2 -+#define HDP6_CA7_DBGACK1 3 -+#define HDP6_BSEC_OUT_SEC_SPNIDEN 5 -+#define HDP6_ETH_OUT_MAC_SPEED_O1 6 -+#define HDP6_GPU_DBG1 7 -+#define HDP6_DDRCTRL_CSYSACK_DDRC 8 -+#define HDP6_DDRCTRL_LPR_CREDIT_CNT 9 -+#define HDP6_GPOVAL_6 15 -+ -+#define HDP7_CA7_STANDBYWFI0 0 -+#define HDP7_CA7_STANDBYWFE0 1 -+#define HDP7_CA7_DBGACK0 3 -+#define HDP7_BSEC_OUT_FUSE_OK 4 -+#define HDP7_BSEC_OUT_SEC_SPIDEN 5 -+#define HDP7_ETH_OUT_MAC_SPEED_O0 6 -+#define HDP7_GPU_DBG0 7 -+#define HDP7_DDRCTRL_CSYSREQ_DDRC 8 -+#define HDP7_DDRCTRL_HPR_CREDIT_CNT 9 -+#define HDP7_GPOVAL_7 15 -+ -+#endif /* _DT_BINDINGS_STM32_HDP_H */ -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0021-ARM-stm32mp1-r2-CONFIG.patch similarity index 93% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0021-ARM-stm32mp1-r2-CONFIG.patch index 7bc22da..34dc997 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0021-ARM-stm32mp1-r1-CONFIG.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0021-ARM-stm32mp1-r2-CONFIG.patch @@ -1,22 +1,22 @@ -From c85af400114b9a862a0e9df538d00e1eb42d0028 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Fri, 10 Apr 2020 14:50:29 +0200 -Subject: [PATCH 21/23] ARM-stm32mp1-r1-CONFIG +From 850ec78d02a21c585da6ede580eaff5fbe3db61b Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:55 +0200 +Subject: [PATCH 21/22] ARM-stm32mp1-r2-rc8-CONFIG --- - .../fragment-01-multiv7_cleanup.config | 152 +++++++ - .../configs/fragment-02-multiv7_addons.config | 420 ++++++++++++++++++ + .../fragment-01-multiv7_cleanup.config | 148 ++++++ + .../configs/fragment-02-multiv7_addons.config | 434 ++++++++++++++++++ arch/arm/configs/multi_v7_defconfig | 1 + - 3 files changed, 573 insertions(+) + 3 files changed, 583 insertions(+) create mode 100644 arch/arm/configs/fragment-01-multiv7_cleanup.config create mode 100644 arch/arm/configs/fragment-02-multiv7_addons.config diff --git a/arch/arm/configs/fragment-01-multiv7_cleanup.config b/arch/arm/configs/fragment-01-multiv7_cleanup.config new file mode 100644 -index 000000000..76dd83cf0 +index 0000000000000..3c43593d5665f --- /dev/null +++ b/arch/arm/configs/fragment-01-multiv7_cleanup.config -@@ -0,0 +1,152 @@ +@@ -0,0 +1,148 @@ +# +# CPU Core family selection +# @@ -107,10 +107,6 @@ index 000000000..76dd83cf0 +# CONFIG_EFI is not set + +# -+# CPU Idle -+# -+# CONFIG_CPU_IDLE is not set -+# +# CAN SPI interfaces +# +# CONFIG_CAN_MCP251X is not set @@ -171,10 +167,10 @@ index 000000000..76dd83cf0 +# CONFIG_SCHED_DEBUG is not set diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config new file mode 100644 -index 000000000..62c0de302 +index 0000000000000..5fd995006583f --- /dev/null +++ b/arch/arm/configs/fragment-02-multiv7_addons.config -@@ -0,0 +1,420 @@ +@@ -0,0 +1,434 @@ +# +# General setup +# @@ -567,6 +563,7 @@ index 000000000..62c0de302 +CONFIG_PWM_STM32_LP=y +CONFIG_IIO_STM32_LPTIMER_TRIGGER=y +CONFIG_STM32_LPTIMER_CNT=y ++CONFIG_CLKSRC_STM32_LP=y + +# +# STM32 ADC @@ -595,8 +592,21 @@ index 000000000..62c0de302 +# TTY +# +CONFIG_LEGACY_PTY_COUNT=8 ++ ++# ++# FMC EBI ++# ++CONFIG_MEMORY=y ++CONFIG_STM32_FMC2_EBI=y ++ ++# ++# STM32 CPUIDLE ++# ++CONFIG_CPU_IDLE=y ++CONFIG_ARM_STM32_CPUIDLE=y ++CONFIG_ARM_CPUIDLE=n diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig -index e4c8def9a..4231ad37e 100644 +index e4c8def9a0a57..4231ad37ea3bc 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -1038,6 +1038,7 @@ CONFIG_TI_PIPE3=y diff --git a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0023-ARM-stm32mp1-r1-PERF.patch b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0022-ARM-stm32mp1-r2-PERF.patch similarity index 98% rename from recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0023-ARM-stm32mp1-r1-PERF.patch rename to recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0022-ARM-stm32mp1-r2-PERF.patch index d69e92f..9ca6a36 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.4/5.4.31/0023-ARM-stm32mp1-r1-PERF.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.4/5.4.56/0022-ARM-stm32mp1-r2-PERF.patch @@ -1,7 +1,7 @@ -From cc23b579a850b77f33f331fe854a4d52910ed0d1 Mon Sep 17 00:00:00 2001 -From: Christophe Priouzeau -Date: Tue, 9 Jun 2020 13:06:44 +0200 -Subject: [PATCH 23/23] ARM-stm32mp1-r1-PERF +From 38993f1a9ca823da25a15d8c8b1bc839a0165c0a Mon Sep 17 00:00:00 2001 +From: Lionel VITTE +Date: Mon, 5 Oct 2020 13:19:56 +0200 +Subject: [PATCH 22/22] ARM-stm32mp1-r2-rc8-PERF --- Documentation/perf/stm32-ddr-pmu.txt | 41 +++ @@ -14,7 +14,7 @@ Subject: [PATCH 23/23] ARM-stm32mp1-r1-PERF diff --git a/Documentation/perf/stm32-ddr-pmu.txt b/Documentation/perf/stm32-ddr-pmu.txt new file mode 100644 -index 000000000..d5b35b326 +index 0000000000000..d5b35b3261bdb --- /dev/null +++ b/Documentation/perf/stm32-ddr-pmu.txt @@ -0,0 +1,41 @@ @@ -60,7 +60,7 @@ index 000000000..d5b35b326 + $ cat /sys/bus/event_source/devices/ddrperfm/bandwidth + Read = 403, Write = 239, Read & Write = 642 (MB/s) diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig -index 09ae8a970..2c5041314 100644 +index 09ae8a970880f..2c50413145ab1 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -105,6 +105,12 @@ config QCOM_L3_PMU @@ -77,7 +77,7 @@ index 09ae8a970..2c5041314 100644 tristate "Cavium ThunderX2 SoC PMU UNCORE" depends on ARCH_THUNDER2 && ARM64 && ACPI && NUMA diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile -index 2ebb4de17..fd3368c1b 100644 +index 2ebb4de178151..fd3368c1b4549 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o @@ -90,7 +90,7 @@ index 2ebb4de17..fd3368c1b 100644 obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o diff --git a/drivers/perf/stm32_ddr_pmu.c b/drivers/perf/stm32_ddr_pmu.c new file mode 100644 -index 000000000..4f30f6f8b +index 0000000000000..4f30f6f8be964 --- /dev/null +++ b/drivers/perf/stm32_ddr_pmu.c @@ -0,0 +1,505 @@ diff --git a/recipes-kernel/linux/linux-stm32mp_5.4.bb b/recipes-kernel/linux/linux-stm32mp_5.4.bb index 1d13781..63dbe05 100644 --- a/recipes-kernel/linux/linux-stm32mp_5.4.bb +++ b/recipes-kernel/linux/linux-stm32mp_5.4.bb @@ -6,34 +6,33 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814" include linux-stm32mp.inc LINUX_VERSION = "5.4" -LINUX_SUBVERSION = "31" +LINUX_SUBVERSION = "56" SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-${LINUX_VERSION}.${LINUX_SUBVERSION}.tar.xz;name=kernel" -SRC_URI[kernel.sha256sum] = "a11083f8f809887f6a0f8d4467532385b99418f17998fe6e837807491c276eeb" +SRC_URI[kernel.sha256sum] = "318390b98480ec5663ed8403fca764b07924c5d2d6411de62c4241b4d9c57cad" SRC_URI += " \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0001-ARM-stm32mp1-r1-MACHINE.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0002-ARM-stm32mp1-r1-CPUFREQ.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0003-ARM-stm32mp1-r1-CRYPTO.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0004-ARM-stm32mp1-r1-RNG-DEBUG-NVMEM.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0005-ARM-stm32mp1-r1-CLOCK.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0006-ARM-stm32mp1-r1-DMA.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0007-ARM-stm32mp1-r1-DRM.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0008-ARM-stm32mp1-r1-HWSPINLOCK.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0009-ARM-stm32mp1-r1-I2C-IIO-IRQCHIP.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0010-ARM-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0011-ARM-stm32mp1-r1-RESET-RTC-WATCHDOG.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0012-ARM-stm32mp1-r1-MEDIA-SOC-THERMAL.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0013-ARM-stm32mp1-r1-MFD.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0014-ARM-stm32mp1-r1-MMC-NAND.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0015-ARM-stm32mp1-r1-NET-TTY.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0016-ARM-stm32mp1-r1-PHY-USB.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0017-ARM-stm32mp1-r1-PINCTRL-REGULATOR-SPI-PWM.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0018-ARM-stm32mp1-r1-SOUND.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0019-ARM-stm32mp1-r1-MISC.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0020-ARM-stm32mp1-r1-DEVICETREE.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0021-ARM-stm32mp1-r1-CONFIG.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0022-ARM-stm32mp1-r1-POWER.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0023-ARM-stm32mp1-r1-PERF.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0001-ARM-stm32mp1-r2-MACHINE.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0002-ARM-stm32mp1-r2-CPUFREQ.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0003-ARM-stm32mp1-r2-CRYPTO.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0004-ARM-stm32mp1-r2-RNG-DEBUG-NVMEM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0005-ARM-stm32mp1-r2-CLOCK.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0006-ARM-stm32mp1-r2-DMA.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0007-ARM-stm32mp1-r2-DRM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0008-ARM-stm32mp1-r2-HWSPINLOCK.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0009-ARM-stm32mp1-r2-I2C-IIO-IRQCHIP.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0010-ARM-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0011-ARM-stm32mp1-r2-RESET-RTC-WATCHDOG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0012-ARM-stm32mp1-r2-MEDIA-SOC-THERMAL.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0013-ARM-stm32mp1-r2-MFD.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0014-ARM-stm32mp1-r2-MMC-NAND.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0015-ARM-stm32mp1-r2-NET-TTY.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0016-ARM-stm32mp1-r2-PHY-USB.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0017-ARM-stm32mp1-r2-PINCTRL-REGULATOR-SPI-PWM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0018-ARM-stm32mp1-r2-SOUND.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0019-ARM-stm32mp1-r2-MISC-CPUIDLE-MM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0020-ARM-stm32mp1-r2-DEVICETREE.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0021-ARM-stm32mp1-r2-CONFIG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0022-ARM-stm32mp1-r2-PERF.patch \ " PV = "${LINUX_VERSION}.${LINUX_SUBVERSION}" @@ -46,7 +45,7 @@ S = "${WORKDIR}/linux-${LINUX_VERSION}.${LINUX_SUBVERSION}" BBCLASSEXTEND = "devupstream:target" SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/linux.git;protocol=https;branch=v${LINUX_VERSION}-stm32mp" -SRCREV_class-devupstream = "b8663f5fdb5cfd6f243b72c9fac82c24b2594294" +SRCREV_class-devupstream = "a56628a8ab25734a771086664cc80c215a198438" # --------------------------------- # Configure default preference to manage dynamic selection between tarball and github