[PATCH v2 7/9] ARM: dts: stm32: add exti support for stm32h743
From: Ludovic Barre This patch adds support of external interrupt (exti) for stm32h743. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32h743.dtsi | 8 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi index 58ec227..6b2fb4c 100644 --- a/arch/arm/boot/dts/stm32h743.dtsi +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -193,6 +193,14 @@ status = "disabled"; }; }; + + exti: interrupt-controller@5800 { + compatible = "st,stm32h7-exti"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x5800 0x400>; + interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <62>, <76>; + }; }; }; -- 2.7.4
[PATCH v2 6/9] irqchip: stm32: move the wakeup on interrupt mask
From: Ludovic Barre Move irq_set_wake on interrupt mask, needed to wake up from low power mode as the event mask is not able to do so. Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 9715d57..3e4ee25 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -156,16 +156,16 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); const struct stm32_exti_bank *stm32_bank = gc->private; int pin = data->hwirq % IRQS_PER_BANK; - u32 emr; + u32 imr; irq_gc_lock(gc); - emr = irq_reg_readl(gc, stm32_bank->emr_ofst); + imr = irq_reg_readl(gc, stm32_bank->imr_ofst); if (on) - emr |= BIT(pin); + imr |= BIT(pin); else - emr &= ~BIT(pin); - irq_reg_writel(gc, emr, stm32_bank->emr_ofst); + imr &= ~BIT(pin); + irq_reg_writel(gc, imr, stm32_bank->imr_ofst); irq_gc_unlock(gc); -- 2.7.4
[PATCH v2 0/9] irqchip: stm32: add stm32h7 support
From: Ludovic Barre This series adds: -Management of multi-bank of external interrupts stm32h7 has up to 96 inputs (3 banks of 32 inputs). -Fix initial value after cold/hot boot (wakeup issue). Changes v2: -Remove irq_mask and adds const on struct stm32_exti_bank -Add wrapper functions pending and ack -Replace BITS_PER_LONG by IRQS_PER_BANK -Fill commit message on "ARM: dts: stm32: add support of exti on stm32h743" -Add system config bank for stm32h7 Ludovic Barre (9): irqchip: stm32: select GENERIC_IRQ_CHIP irqchip: stm32: add multi-bank management dt-bindings: interrupt-controllers: add compatible string for stm32h7 irqchip: stm32: add stm32h7 support irqchip: stm32: fix initial values irqchip: stm32: move the wakeup on interrupt mask ARM: dts: stm32: add exti support for stm32h743 ARM: dts: stm32: add system config bank node for stm32h743 ARM: dts: stm32: add support of exti on stm32h743 pinctrl .../interrupt-controller/st,stm32-exti.txt | 4 +- arch/arm/boot/dts/stm32h743-pinctrl.dtsi | 24 +++ arch/arm/boot/dts/stm32h743.dtsi | 13 ++ drivers/irqchip/Kconfig| 1 + drivers/irqchip/irq-stm32-exti.c | 208 - 5 files changed, 200 insertions(+), 50 deletions(-) -- 2.7.4
[PATCH v2 2/9] irqchip: stm32: add multi-bank management
From: Ludovic Barre -Prepare to manage multi-bank of external interrupts (N banks of 32 inputs). -Prepare to manage registers offsets by compatible (registers offsets could be different follow per stm32 platform). Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 151 +++ 1 file changed, 105 insertions(+), 46 deletions(-) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 45363ff..6b4109b 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -14,27 +14,66 @@ #include #include -#define EXTI_IMR 0x0 -#define EXTI_EMR 0x4 -#define EXTI_RTSR 0x8 -#define EXTI_FTSR 0xc -#define EXTI_SWIER 0x10 -#define EXTI_PR0x14 +#define IRQS_PER_BANK 32 + +struct stm32_exti_bank { + u32 imr_ofst; + u32 emr_ofst; + u32 rtsr_ofst; + u32 ftsr_ofst; + u32 swier_ofst; + u32 pr_ofst; +}; + +static const struct stm32_exti_bank stm32f4xx_exti_b1 = { + .imr_ofst = 0x00, + .emr_ofst = 0x04, + .rtsr_ofst = 0x08, + .ftsr_ofst = 0x0C, + .swier_ofst = 0x10, + .pr_ofst= 0x14, +}; + +static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { + &stm32f4xx_exti_b1, +}; + +static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + return irq_reg_readl(gc, stm32_bank->pr_ofst); +} + +static void stm32_exti_irq_ack(struct irq_chip_generic *gc, u32 mask) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + irq_reg_writel(gc, mask, stm32_bank->pr_ofst); +} static void stm32_irq_handler(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - struct irq_chip_generic *gc = domain->gc->gc[0]; struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int virq, nbanks = domain->gc->num_chips; + struct irq_chip_generic *gc; + const struct stm32_exti_bank *stm32_bank; unsigned long pending; - int n; + int n, i, irq_base = 0; chained_irq_enter(chip, desc); - while ((pending = irq_reg_readl(gc, EXTI_PR))) { - for_each_set_bit(n, &pending, BITS_PER_LONG) { - generic_handle_irq(irq_find_mapping(domain, n)); - irq_reg_writel(gc, BIT(n), EXTI_PR); + for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) { + gc = irq_get_domain_generic_chip(domain, irq_base); + stm32_bank = gc->private; + + while ((pending = stm32_exti_pending(gc))) { + for_each_set_bit(n, &pending, IRQS_PER_BANK) { + virq = irq_find_mapping(domain, irq_base + n); + generic_handle_irq(virq); + stm32_exti_irq_ack(gc, BIT(n)); + } } } @@ -44,13 +83,14 @@ static void stm32_irq_handler(struct irq_desc *desc) static int stm32_irq_set_type(struct irq_data *data, unsigned int type) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 rtsr, ftsr; irq_gc_lock(gc); - rtsr = irq_reg_readl(gc, EXTI_RTSR); - ftsr = irq_reg_readl(gc, EXTI_FTSR); + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -70,8 +110,8 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) return -EINVAL; } - irq_reg_writel(gc, rtsr, EXTI_RTSR); - irq_reg_writel(gc, ftsr, EXTI_FTSR); + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); + irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); irq_gc_unlock(gc); @@ -81,17 +121,18 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 emr; irq_gc_lock(gc); - emr = irq_reg_readl(gc, EXTI_EMR); + emr = irq_reg_readl(gc, stm32_bank->emr_ofst); if (on) emr |= BIT(pin); else emr &= ~BIT(pin); - irq_reg_writel(gc, emr, EXTI_EMR); + irq_reg_writel(gc, emr, stm32_bank->emr_ofst); irq_gc_unlock(gc); @@ -101,11 +142,12 @@ static int stm32_
[PATCH v2 5/9] irqchip: stm32: fix initial values
From: Ludovic Barre -After cold boot, imr default value depends on hardware configuration. -After hot reboot the registers must be cleared to avoid residue. Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index d872dea..9715d57 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -260,7 +260,16 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); + + /* +* This IP has no reset, so after hot reboot we should +* clear registers to avoid residue +*/ + writel_relaxed(0, base + stm32_bank->imr_ofst); + writel_relaxed(0, base + stm32_bank->emr_ofst); writel_relaxed(0, base + stm32_bank->rtsr_ofst); + writel_relaxed(0, base + stm32_bank->ftsr_ofst); + writel_relaxed(~0UL, base + stm32_bank->pr_ofst); pr_info("%s: bank%d, External IRQs available:%#x\n", node->full_name, i, irqs_mask); -- 2.7.4
[PATCH v2 9/9] ARM: dts: stm32: add support of exti on stm32h743 pinctrl
From: Ludovic Barre This patch adds support of external interrupt (exti) on all gpio ports of stm32h743. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32h743-pinctrl.dtsi | 24 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/stm32h743-pinctrl.dtsi b/arch/arm/boot/dts/stm32h743-pinctrl.dtsi index 76bbd65..df0b441 100644 --- a/arch/arm/boot/dts/stm32h743-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32h743-pinctrl.dtsi @@ -49,6 +49,8 @@ #size-cells = <1>; compatible = "st,stm32h743-pinctrl"; ranges = <0 0x5802 0x3000>; + interrupt-parent = <&exti>; + st,syscfg = <&syscfg 0x8>; pins-are-numbered; gpioa: gpio@5802 { @@ -57,6 +59,8 @@ reg = <0x0 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOA"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiob: gpio@58020400 { @@ -65,6 +69,8 @@ reg = <0x400 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOB"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioc: gpio@58020800 { @@ -73,6 +79,8 @@ reg = <0x800 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOC"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiod: gpio@58020c00 { @@ -81,6 +89,8 @@ reg = <0xc00 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOD"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioe: gpio@58021000 { @@ -89,6 +99,8 @@ reg = <0x1000 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOE"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiof: gpio@58021400 { @@ -97,6 +109,8 @@ reg = <0x1400 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOF"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiog: gpio@58021800 { @@ -105,6 +119,8 @@ reg = <0x1800 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOG"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioh: gpio@58021c00 { @@ -113,6 +129,8 @@ reg = <0x1c00 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOH"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioi: gpio@58022000 { @@ -121,6 +139,8 @@ reg = <0x2000 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOI"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioj: gpio@58022400 { @@ -129,6 +149,8 @@ reg = <0x2400 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOJ"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiok: gpio@58022800 { @@ -137,6 +159,8 @@ reg = <0x2800 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOK"; + interrupt-controller; + #interrupt-cells = <2>; }; usart1_pins: usart1@0 { -- 2.7.4
[PATCH v2 8/9] ARM: dts: stm32: add system config bank node for stm32h743
From: Ludovic Barre This patch adds system config support for stm32h743. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32h743.dtsi | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi index 6b2fb4c..b17aa5c 100644 --- a/arch/arm/boot/dts/stm32h743.dtsi +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -194,6 +194,11 @@ }; }; + syscfg: system-config@58000400 { + compatible = "syscon"; + reg = <0x58000400 0x400>; + }; + exti: interrupt-controller@5800 { compatible = "st,stm32h7-exti"; interrupt-controller; -- 2.7.4
[PATCH v2 3/9] dt-bindings: interrupt-controllers: add compatible string for stm32h7
From: Ludovic Barre This patch updates stm32-exti documentation with stm32h7-exti compatible string. Signed-off-by: Ludovic Barre --- .../devicetree/bindings/interrupt-controller/st,stm32-exti.txt| 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt index 6e7703d..edf03f0 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt @@ -2,7 +2,9 @@ STM32 External Interrupt Controller Required properties: -- compatible: Should be "st,stm32-exti" +- compatible: Should be: +"st,stm32-exti" +"st,stm32h7-exti" - reg: Specifies base physical address and size of the registers - interrupt-controller: Indentifies the node as an interrupt controller - #interrupt-cells: Specifies the number of cells to encode an interrupt -- 2.7.4
[PATCH v2 4/9] irqchip: stm32: add stm32h7 support
From: Ludovic Barre stm32h7 has up to 96 inputs (3 banks of 32 inputs max). Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 42 1 file changed, 42 insertions(+) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 6b4109b..d872dea 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -38,6 +38,39 @@ static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { &stm32f4xx_exti_b1, }; +static const struct stm32_exti_bank stm32h7xx_exti_b1 = { + .imr_ofst = 0x80, + .emr_ofst = 0x84, + .rtsr_ofst = 0x00, + .ftsr_ofst = 0x04, + .swier_ofst = 0x08, + .pr_ofst= 0x88, +}; + +static const struct stm32_exti_bank stm32h7xx_exti_b2 = { + .imr_ofst = 0x90, + .emr_ofst = 0x94, + .rtsr_ofst = 0x20, + .ftsr_ofst = 0x24, + .swier_ofst = 0x28, + .pr_ofst= 0x98, +}; + +static const struct stm32_exti_bank stm32h7xx_exti_b3 = { + .imr_ofst = 0xA0, + .emr_ofst = 0xA4, + .rtsr_ofst = 0x40, + .ftsr_ofst = 0x44, + .swier_ofst = 0x48, + .pr_ofst= 0xA8, +}; + +static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { + &stm32h7xx_exti_b1, + &stm32h7xx_exti_b2, + &stm32h7xx_exti_b3, +}; + static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) { const struct stm32_exti_bank *stm32_bank = gc->private; @@ -258,3 +291,12 @@ static int __init stm32f4_exti_of_init(struct device_node *np, } IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); + +static int __init stm32h7_exti_of_init(struct device_node *np, + struct device_node *parent) +{ + return stm32_exti_init(stm32h7xx_exti_banks, + ARRAY_SIZE(stm32h7xx_exti_banks), np); +} + +IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); -- 2.7.4
[PATCH v2 1/9] irqchip: stm32: select GENERIC_IRQ_CHIP
From: Ludovic Barre This patch adds GENERIC_IRQ_CHIP to stm32 exti config. Signed-off-by: Ludovic Barre --- drivers/irqchip/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 9d8a1dd..c067aae 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -304,6 +304,7 @@ config EZNPS_GIC config STM32_EXTI bool select IRQ_DOMAIN + select GENERIC_IRQ_CHIP config QCOM_IRQ_COMBINER bool "QCOM IRQ combiner support" -- 2.7.4
[PATCH 0/3] mtd: spi-nor: stm32-quadspi: fixes
From: Ludovic Barre This series adds: -Fix: to avoid compilation warning with older compiler versions such as gcc-4.6. This topic has been discussed on 2 threads with Geert and Arnd https://lkml.org/lkml/2017/9/15/70 https://www.spinics.net/lists/arm-kernel/msg606269.html -Fix: abort prefetching in memory-mapped mode as soon prefetching could exceed nor size (not done by fsize limit) -Change license text and Copyright Geert Uytterhoeven (1): mtd: spi-nor: stm32-quadspi: Fix uninitialized error return code Ludovic Barre (2): mtd: spi-nor: stm32-quadspi: fix prefetching outside fsize mtd: spi-nor: stm32-quadspi: change license text drivers/mtd/spi-nor/stm32-quadspi.c | 35 +-- 1 file changed, 29 insertions(+), 6 deletions(-) -- 2.7.4
[PATCH 3/3] mtd: spi-nor: stm32-quadspi: change license text
From: Ludovic Barre -Change the license text with long template. -Change Copyright to STMicroelectronics. Signed-off-by: Ludovic Barre --- drivers/mtd/spi-nor/stm32-quadspi.c | 19 --- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 70710be..b3c7f6a 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -1,9 +1,22 @@ /* - * stm32_quadspi.c + * Driver for stm32 quadspi controller * - * Copyright (C) 2017, Ludovic Barre + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Ludovic Barre author . * - * License terms: GNU General Public License (GPL), version 2 + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * This program. If not, see <http://www.gnu.org/licenses/>. */ #include #include -- 2.7.4
[PATCH 1/3] mtd: spi-nor: stm32-quadspi: Fix uninitialized error return code
From: Geert Uytterhoeven With gcc 4.1.2: drivers/mtd/spi-nor/stm32-quadspi.c: In function ‘stm32_qspi_tx_poll’: drivers/mtd/spi-nor/stm32-quadspi.c:230: warning: ‘ret’ may be used uninitialized in this function Indeed, if stm32_qspi_cmd.len is zero, ret will be uninitialized. This length is passed from outside the driver using the spi_nor.{read,write}{,_reg}() callbacks. Several functions in drivers/mtd/spi-nor/spi-nor.c (e.g. write_enable(), write_disable(), and erase_chip()) call spi_nor.write_reg() with a zero length. Fix this by returning an explicit zero on success. Fixes: 0d43d7ab277a048c ("mtd: spi-nor: add driver for STM32 quad spi flash controller") Signed-off-by: Geert Uytterhoeven Acked-by: Ludovic Barre Signed-off-by: Ludovic Barre --- drivers/mtd/spi-nor/stm32-quadspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 86c0931..ad6a3e1 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -240,12 +240,12 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, STM32_QSPI_FIFO_TIMEOUT_US); if (ret) { dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); - break; + return ret; } tx_fifo(buf++, qspi->io_base + QUADSPI_DR); } - return ret; + return 0; } static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, -- 2.7.4
[PATCH 2/3] mtd: spi-nor: stm32-quadspi: fix prefetching outside fsize
From: Ludovic Barre When memory-mapped mode is used, a prefetching mechanism fully managed by the hardware allows to optimize the read from external the QSPI memory. A 32-bytes FIFO is used for prefetching. When the limit of flash size - fifo size is reached the prefetching mechanism tries to read outside the fsize. The stm32 quadspi hardware become busy and should be aborted. Signed-off-by: Ludovic Barre Reported-by: Bruno Herrera Tested-by: Bruno Herrera --- drivers/mtd/spi-nor/stm32-quadspi.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index ad6a3e1..70710be 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -113,6 +113,7 @@ #define STM32_MAX_MMAP_SZ SZ_256M #define STM32_MAX_NORCHIP 2 +#define STM32_QSPI_FIFO_SZ 32 #define STM32_QSPI_FIFO_TIMEOUT_US 3 #define STM32_QSPI_BUSY_TIMEOUT_US 10 @@ -124,6 +125,7 @@ struct stm32_qspi_flash { u32 presc; u32 read_mode; bool registered; + u32 prefetch_limit; }; struct stm32_qspi { @@ -272,6 +274,7 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, { struct stm32_qspi *qspi = flash->qspi; u32 ccr, dcr, cr; + u32 last_byte; int err; err = stm32_qspi_wait_nobusy(qspi); @@ -314,6 +317,10 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, if (err) goto abort; writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR); + } else { + last_byte = cmd->addr + cmd->len; + if (last_byte > flash->prefetch_limit) + goto abort; } return err; @@ -322,7 +329,9 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT; writel_relaxed(cr, qspi->io_base + QUADSPI_CR); - dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); + if (err) + dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); + return err; } @@ -550,6 +559,7 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi, } flash->fsize = FSIZE_VAL(mtd->size); + flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ; flash->read_mode = CCR_FMODE_MM; if (mtd->size > qspi->mm_size) -- 2.7.4
[PATCH v2 2/3] mtd: spi-nor: stm32-quadspi: fix prefetching outside fsize
From: Ludovic Barre When memory-mapped mode is used, a prefetching mechanism fully managed by the hardware allows to optimize the read from external the QSPI memory. A 32-bytes FIFO is used for prefetching. When the limit of flash size - fifo size is reached the prefetching mechanism tries to read outside the fsize. The stm32 quadspi hardware become busy and should be aborted. Signed-off-by: Ludovic Barre Reported-by: Bruno Herrera Tested-by: Bruno Herrera --- drivers/mtd/spi-nor/stm32-quadspi.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index ad6a3e1..70710be 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -113,6 +113,7 @@ #define STM32_MAX_MMAP_SZ SZ_256M #define STM32_MAX_NORCHIP 2 +#define STM32_QSPI_FIFO_SZ 32 #define STM32_QSPI_FIFO_TIMEOUT_US 3 #define STM32_QSPI_BUSY_TIMEOUT_US 10 @@ -124,6 +125,7 @@ struct stm32_qspi_flash { u32 presc; u32 read_mode; bool registered; + u32 prefetch_limit; }; struct stm32_qspi { @@ -272,6 +274,7 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, { struct stm32_qspi *qspi = flash->qspi; u32 ccr, dcr, cr; + u32 last_byte; int err; err = stm32_qspi_wait_nobusy(qspi); @@ -314,6 +317,10 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, if (err) goto abort; writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR); + } else { + last_byte = cmd->addr + cmd->len; + if (last_byte > flash->prefetch_limit) + goto abort; } return err; @@ -322,7 +329,9 @@ static int stm32_qspi_send(struct stm32_qspi_flash *flash, cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT; writel_relaxed(cr, qspi->io_base + QUADSPI_CR); - dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); + if (err) + dev_err(qspi->dev, "%s abort err:%d\n", __func__, err); + return err; } @@ -550,6 +559,7 @@ static int stm32_qspi_flash_setup(struct stm32_qspi *qspi, } flash->fsize = FSIZE_VAL(mtd->size); + flash->prefetch_limit = mtd->size - STM32_QSPI_FIFO_SZ; flash->read_mode = CCR_FMODE_MM; if (mtd->size > qspi->mm_size) -- 2.7.4
[PATCH v2 0/3] mtd: spi-nor: stm32-quadspi: fixes
From: Ludovic Barre This series adds: -Fix: to avoid compilation warning with older compiler versions such as gcc-4.6. This topic has been discussed on 2 threads with Geert and Arnd https://lkml.org/lkml/2017/9/15/70 https://www.spinics.net/lists/arm-kernel/msg606269.html -Fix: abort prefetching in memory-mapped mode as soon prefetching could exceed nor size (not done by fsize limit) -Change license text and Copyright Changes v2: with the right Cyrille's email (wedev4u.fr) Geert Uytterhoeven (1): mtd: spi-nor: stm32-quadspi: Fix uninitialized error return code Ludovic Barre (2): mtd: spi-nor: stm32-quadspi: fix prefetching outside fsize mtd: spi-nor: stm32-quadspi: change license text drivers/mtd/spi-nor/stm32-quadspi.c | 35 +-- 1 file changed, 29 insertions(+), 6 deletions(-) -- 2.7.4
[PATCH v2 3/3] mtd: spi-nor: stm32-quadspi: change license text
From: Ludovic Barre -Change the license text with long template. -Change Copyright to STMicroelectronics. Signed-off-by: Ludovic Barre --- drivers/mtd/spi-nor/stm32-quadspi.c | 19 --- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 70710be..b3c7f6a 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -1,9 +1,22 @@ /* - * stm32_quadspi.c + * Driver for stm32 quadspi controller * - * Copyright (C) 2017, Ludovic Barre + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved + * Author(s): Ludovic Barre author . * - * License terms: GNU General Public License (GPL), version 2 + * License terms: GPL V2.0. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * This program. If not, see <http://www.gnu.org/licenses/>. */ #include #include -- 2.7.4
[PATCH v2 1/3] mtd: spi-nor: stm32-quadspi: Fix uninitialized error return code
From: Geert Uytterhoeven With gcc 4.1.2: drivers/mtd/spi-nor/stm32-quadspi.c: In function ‘stm32_qspi_tx_poll’: drivers/mtd/spi-nor/stm32-quadspi.c:230: warning: ‘ret’ may be used uninitialized in this function Indeed, if stm32_qspi_cmd.len is zero, ret will be uninitialized. This length is passed from outside the driver using the spi_nor.{read,write}{,_reg}() callbacks. Several functions in drivers/mtd/spi-nor/spi-nor.c (e.g. write_enable(), write_disable(), and erase_chip()) call spi_nor.write_reg() with a zero length. Fix this by returning an explicit zero on success. Fixes: 0d43d7ab277a048c ("mtd: spi-nor: add driver for STM32 quad spi flash controller") Signed-off-by: Geert Uytterhoeven Acked-by: Ludovic Barre Signed-off-by: Ludovic Barre --- drivers/mtd/spi-nor/stm32-quadspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 86c0931..ad6a3e1 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -240,12 +240,12 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, STM32_QSPI_FIFO_TIMEOUT_US); if (ret) { dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); - break; + return ret; } tx_fifo(buf++, qspi->io_base + QUADSPI_DR); } - return ret; + return 0; } static int stm32_qspi_tx_mm(struct stm32_qspi *qspi, -- 2.7.4
[PATCH v3 3/9] dt-bindings: interrupt-controllers: add compatible string for stm32h7
From: Ludovic Barre This patch updates stm32-exti documentation with stm32h7-exti compatible string. Signed-off-by: Ludovic Barre Acked-by: Rob Herring --- .../devicetree/bindings/interrupt-controller/st,stm32-exti.txt| 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt index 6e7703d..edf03f0 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt @@ -2,7 +2,9 @@ STM32 External Interrupt Controller Required properties: -- compatible: Should be "st,stm32-exti" +- compatible: Should be: +"st,stm32-exti" +"st,stm32h7-exti" - reg: Specifies base physical address and size of the registers - interrupt-controller: Indentifies the node as an interrupt controller - #interrupt-cells: Specifies the number of cells to encode an interrupt -- 2.7.4
[PATCH v3 2/9] irqchip: stm32: add multi-bank management
From: Ludovic Barre -Prepare to manage multi-bank of external interrupts (N banks of 32 inputs). -Prepare to manage registers offsets by compatible (registers offsets could be different follow per stm32 platform). Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 149 +++ 1 file changed, 103 insertions(+), 46 deletions(-) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 45363ff..ef37870 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -14,27 +14,66 @@ #include #include -#define EXTI_IMR 0x0 -#define EXTI_EMR 0x4 -#define EXTI_RTSR 0x8 -#define EXTI_FTSR 0xc -#define EXTI_SWIER 0x10 -#define EXTI_PR0x14 +#define IRQS_PER_BANK 32 + +struct stm32_exti_bank { + u32 imr_ofst; + u32 emr_ofst; + u32 rtsr_ofst; + u32 ftsr_ofst; + u32 swier_ofst; + u32 pr_ofst; +}; + +static const struct stm32_exti_bank stm32f4xx_exti_b1 = { + .imr_ofst = 0x00, + .emr_ofst = 0x04, + .rtsr_ofst = 0x08, + .ftsr_ofst = 0x0C, + .swier_ofst = 0x10, + .pr_ofst= 0x14, +}; + +static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { + &stm32f4xx_exti_b1, +}; + +static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + return irq_reg_readl(gc, stm32_bank->pr_ofst); +} + +static void stm32_exti_irq_ack(struct irq_chip_generic *gc, u32 mask) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + irq_reg_writel(gc, mask, stm32_bank->pr_ofst); +} static void stm32_irq_handler(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - struct irq_chip_generic *gc = domain->gc->gc[0]; struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int virq, nbanks = domain->gc->num_chips; + struct irq_chip_generic *gc; + const struct stm32_exti_bank *stm32_bank; unsigned long pending; - int n; + int n, i, irq_base = 0; chained_irq_enter(chip, desc); - while ((pending = irq_reg_readl(gc, EXTI_PR))) { - for_each_set_bit(n, &pending, BITS_PER_LONG) { - generic_handle_irq(irq_find_mapping(domain, n)); - irq_reg_writel(gc, BIT(n), EXTI_PR); + for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) { + gc = irq_get_domain_generic_chip(domain, irq_base); + stm32_bank = gc->private; + + while ((pending = stm32_exti_pending(gc))) { + for_each_set_bit(n, &pending, IRQS_PER_BANK) { + virq = irq_find_mapping(domain, irq_base + n); + generic_handle_irq(virq); + stm32_exti_irq_ack(gc, BIT(n)); + } } } @@ -44,13 +83,14 @@ static void stm32_irq_handler(struct irq_desc *desc) static int stm32_irq_set_type(struct irq_data *data, unsigned int type) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 rtsr, ftsr; irq_gc_lock(gc); - rtsr = irq_reg_readl(gc, EXTI_RTSR); - ftsr = irq_reg_readl(gc, EXTI_FTSR); + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -70,8 +110,8 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) return -EINVAL; } - irq_reg_writel(gc, rtsr, EXTI_RTSR); - irq_reg_writel(gc, ftsr, EXTI_FTSR); + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); + irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); irq_gc_unlock(gc); @@ -81,17 +121,18 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 emr; irq_gc_lock(gc); - emr = irq_reg_readl(gc, EXTI_EMR); + emr = irq_reg_readl(gc, stm32_bank->emr_ofst); if (on) emr |= BIT(pin); else emr &= ~BIT(pin); - irq_reg_writel(gc, emr, EXTI_EMR); + irq_reg_writel(gc, emr, stm32_bank->emr_ofst); irq_gc_unlock(gc); @@ -101,11 +142,12 @@ static int stm32_
[PATCH v3 8/9] ARM: dts: stm32: add system config bank node for stm32h743
From: Ludovic Barre This patch adds system config support for stm32h743. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32h743.dtsi | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi index 6b2fb4c..b17aa5c 100644 --- a/arch/arm/boot/dts/stm32h743.dtsi +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -194,6 +194,11 @@ }; }; + syscfg: system-config@58000400 { + compatible = "syscon"; + reg = <0x58000400 0x400>; + }; + exti: interrupt-controller@5800 { compatible = "st,stm32h7-exti"; interrupt-controller; -- 2.7.4
[PATCH v3 9/9] ARM: dts: stm32: add support of exti on stm32h743 pinctrl
From: Ludovic Barre This patch adds support of external interrupt (exti) on all gpio ports of stm32h743. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32h743-pinctrl.dtsi | 24 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/stm32h743-pinctrl.dtsi b/arch/arm/boot/dts/stm32h743-pinctrl.dtsi index 76bbd65..df0b441 100644 --- a/arch/arm/boot/dts/stm32h743-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32h743-pinctrl.dtsi @@ -49,6 +49,8 @@ #size-cells = <1>; compatible = "st,stm32h743-pinctrl"; ranges = <0 0x5802 0x3000>; + interrupt-parent = <&exti>; + st,syscfg = <&syscfg 0x8>; pins-are-numbered; gpioa: gpio@5802 { @@ -57,6 +59,8 @@ reg = <0x0 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOA"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiob: gpio@58020400 { @@ -65,6 +69,8 @@ reg = <0x400 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOB"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioc: gpio@58020800 { @@ -73,6 +79,8 @@ reg = <0x800 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOC"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiod: gpio@58020c00 { @@ -81,6 +89,8 @@ reg = <0xc00 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOD"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioe: gpio@58021000 { @@ -89,6 +99,8 @@ reg = <0x1000 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOE"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiof: gpio@58021400 { @@ -97,6 +109,8 @@ reg = <0x1400 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOF"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiog: gpio@58021800 { @@ -105,6 +119,8 @@ reg = <0x1800 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOG"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioh: gpio@58021c00 { @@ -113,6 +129,8 @@ reg = <0x1c00 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOH"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioi: gpio@58022000 { @@ -121,6 +139,8 @@ reg = <0x2000 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOI"; + interrupt-controller; + #interrupt-cells = <2>; }; gpioj: gpio@58022400 { @@ -129,6 +149,8 @@ reg = <0x2400 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOJ"; + interrupt-controller; + #interrupt-cells = <2>; }; gpiok: gpio@58022800 { @@ -137,6 +159,8 @@ reg = <0x2800 0x400>; clocks = <&timer_clk>; st,bank-name = "GPIOK"; + interrupt-controller; + #interrupt-cells = <2>; }; usart1_pins: usart1@0 { -- 2.7.4
[PATCH v3 1/9] irqchip: stm32: select GENERIC_IRQ_CHIP
From: Ludovic Barre This patch adds GENERIC_IRQ_CHIP to stm32 exti config. Signed-off-by: Ludovic Barre --- drivers/irqchip/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 9d8a1dd..c067aae 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -304,6 +304,7 @@ config EZNPS_GIC config STM32_EXTI bool select IRQ_DOMAIN + select GENERIC_IRQ_CHIP config QCOM_IRQ_COMBINER bool "QCOM IRQ combiner support" -- 2.7.4
[PATCH v3 4/9] irqchip: stm32: add stm32h7 support
From: Ludovic Barre stm32h7 has up to 96 inputs (3 banks of 32 inputs max). Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 42 1 file changed, 42 insertions(+) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index ef37870..8f409a9 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -38,6 +38,39 @@ static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { &stm32f4xx_exti_b1, }; +static const struct stm32_exti_bank stm32h7xx_exti_b1 = { + .imr_ofst = 0x80, + .emr_ofst = 0x84, + .rtsr_ofst = 0x00, + .ftsr_ofst = 0x04, + .swier_ofst = 0x08, + .pr_ofst= 0x88, +}; + +static const struct stm32_exti_bank stm32h7xx_exti_b2 = { + .imr_ofst = 0x90, + .emr_ofst = 0x94, + .rtsr_ofst = 0x20, + .ftsr_ofst = 0x24, + .swier_ofst = 0x28, + .pr_ofst= 0x98, +}; + +static const struct stm32_exti_bank stm32h7xx_exti_b3 = { + .imr_ofst = 0xA0, + .emr_ofst = 0xA4, + .rtsr_ofst = 0x40, + .ftsr_ofst = 0x44, + .swier_ofst = 0x48, + .pr_ofst= 0xA8, +}; + +static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { + &stm32h7xx_exti_b1, + &stm32h7xx_exti_b2, + &stm32h7xx_exti_b3, +}; + static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) { const struct stm32_exti_bank *stm32_bank = gc->private; @@ -256,3 +289,12 @@ static int __init stm32f4_exti_of_init(struct device_node *np, } IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); + +static int __init stm32h7_exti_of_init(struct device_node *np, + struct device_node *parent) +{ + return stm32_exti_init(stm32h7xx_exti_banks, + ARRAY_SIZE(stm32h7xx_exti_banks), np); +} + +IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); -- 2.7.4
[PATCH v3 5/9] irqchip: stm32: fix initial values
From: Ludovic Barre -After cold boot, imr default value depends on hardware configuration. -After hot reboot the registers must be cleared to avoid residue. Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 9 + 1 file changed, 9 insertions(+) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 8f409a9..477d0fa 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -258,7 +258,16 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); + + /* +* This IP has no reset, so after hot reboot we should +* clear registers to avoid residue +*/ + writel_relaxed(0, base + stm32_bank->imr_ofst); + writel_relaxed(0, base + stm32_bank->emr_ofst); writel_relaxed(0, base + stm32_bank->rtsr_ofst); + writel_relaxed(0, base + stm32_bank->ftsr_ofst); + writel_relaxed(~0UL, base + stm32_bank->pr_ofst); pr_info("%s: bank%d, External IRQs available:%#x\n", node->full_name, i, irqs_mask); -- 2.7.4
[PATCH v3 7/9] ARM: dts: stm32: add exti support for stm32h743
From: Ludovic Barre This patch adds support of external interrupt (exti) for stm32h743. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32h743.dtsi | 8 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi index 58ec227..6b2fb4c 100644 --- a/arch/arm/boot/dts/stm32h743.dtsi +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -193,6 +193,14 @@ status = "disabled"; }; }; + + exti: interrupt-controller@5800 { + compatible = "st,stm32h7-exti"; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x5800 0x400>; + interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>, <10>, <23>, <40>, <41>, <62>, <76>; + }; }; }; -- 2.7.4
[PATCH v3 6/9] irqchip: stm32: move the wakeup on interrupt mask
From: Ludovic Barre Move irq_set_wake on interrupt mask, needed to wake up from low power mode as the event mask is not able to do so. Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 10 +- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 477d0fa..31ab0de 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -156,16 +156,16 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); const struct stm32_exti_bank *stm32_bank = gc->private; int pin = data->hwirq % IRQS_PER_BANK; - u32 emr; + u32 imr; irq_gc_lock(gc); - emr = irq_reg_readl(gc, stm32_bank->emr_ofst); + imr = irq_reg_readl(gc, stm32_bank->imr_ofst); if (on) - emr |= BIT(pin); + imr |= BIT(pin); else - emr &= ~BIT(pin); - irq_reg_writel(gc, emr, stm32_bank->emr_ofst); + imr &= ~BIT(pin); + irq_reg_writel(gc, imr, stm32_bank->imr_ofst); irq_gc_unlock(gc); -- 2.7.4
[PATCH v3 0/9] irqchip: stm32: add stm32h7 support
From: Ludovic Barre This series adds: -Management of multi-bank of external interrupts stm32h7 has up to 96 inputs (3 banks of 32 inputs). -Fix initial value after cold/hot boot (wakeup issue). Changes v3: -remove chip.name and handler, already done by irq_alloc_domain_generic_chips -add Rob ack in dt-bindings commit Changes v2: -Remove irq_mask and adds const on struct stm32_exti_bank -Add wrapper functions pending and ack -Replace BITS_PER_LONG by IRQS_PER_BANK -Fill commit message on "ARM: dts: stm32: add support of exti on stm32h743" -Add system config bank for stm32h7 Ludovic Barre (9): irqchip: stm32: select GENERIC_IRQ_CHIP irqchip: stm32: add multi-bank management dt-bindings: interrupt-controllers: add compatible string for stm32h7 irqchip: stm32: add stm32h7 support irqchip: stm32: fix initial values irqchip: stm32: move the wakeup on interrupt mask ARM: dts: stm32: add exti support for stm32h743 ARM: dts: stm32: add system config bank node for stm32h743 ARM: dts: stm32: add support of exti on stm32h743 pinctrl .../interrupt-controller/st,stm32-exti.txt | 4 +- arch/arm/boot/dts/stm32h743-pinctrl.dtsi | 24 +++ arch/arm/boot/dts/stm32h743.dtsi | 13 ++ drivers/irqchip/Kconfig| 1 + drivers/irqchip/irq-stm32-exti.c | 206 - 5 files changed, 198 insertions(+), 50 deletions(-) -- 2.7.4
Re: [PATCH v2 2/9] irqchip: stm32: add multi-bank management
Hi Julien thank for your review On 10/26/2017 04:36 PM, Julien Thierry wrote: Hi Ludovic, On 25/10/17 18:10, Ludovic Barre wrote: From: Ludovic Barre -Prepare to manage multi-bank of external interrupts (N banks of 32 inputs). -Prepare to manage registers offsets by compatible (registers offsets could be different follow per stm32 platform). Signed-off-by: Ludovic Barre --- drivers/irqchip/irq-stm32-exti.c | 151 +++ 1 file changed, 105 insertions(+), 46 deletions(-) diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 45363ff..6b4109b 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -14,27 +14,66 @@ #include #include -#define EXTI_IMR 0x0 -#define EXTI_EMR 0x4 -#define EXTI_RTSR 0x8 -#define EXTI_FTSR 0xc -#define EXTI_SWIER 0x10 -#define EXTI_PR 0x14 +#define IRQS_PER_BANK 32 + +struct stm32_exti_bank { + u32 imr_ofst; + u32 emr_ofst; + u32 rtsr_ofst; + u32 ftsr_ofst; + u32 swier_ofst; + u32 pr_ofst; +}; + +static const struct stm32_exti_bank stm32f4xx_exti_b1 = { + .imr_ofst = 0x00, + .emr_ofst = 0x04, + .rtsr_ofst = 0x08, + .ftsr_ofst = 0x0C, + .swier_ofst = 0x10, + .pr_ofst = 0x14, +}; + +static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { + &stm32f4xx_exti_b1, +}; + +static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + return irq_reg_readl(gc, stm32_bank->pr_ofst); +} + +static void stm32_exti_irq_ack(struct irq_chip_generic *gc, u32 mask) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + irq_reg_writel(gc, mask, stm32_bank->pr_ofst); +} static void stm32_irq_handler(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - struct irq_chip_generic *gc = domain->gc->gc[0]; struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int virq, nbanks = domain->gc->num_chips; + struct irq_chip_generic *gc; + const struct stm32_exti_bank *stm32_bank; unsigned long pending; - int n; + int n, i, irq_base = 0; chained_irq_enter(chip, desc); - while ((pending = irq_reg_readl(gc, EXTI_PR))) { - for_each_set_bit(n, &pending, BITS_PER_LONG) { - generic_handle_irq(irq_find_mapping(domain, n)); - irq_reg_writel(gc, BIT(n), EXTI_PR); + for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) { + gc = irq_get_domain_generic_chip(domain, irq_base); + stm32_bank = gc->private; + + while ((pending = stm32_exti_pending(gc))) { + for_each_set_bit(n, &pending, IRQS_PER_BANK) { + virq = irq_find_mapping(domain, irq_base + n); + generic_handle_irq(virq); + stm32_exti_irq_ack(gc, BIT(n)); + } } } @@ -44,13 +83,14 @@ static void stm32_irq_handler(struct irq_desc *desc) static int stm32_irq_set_type(struct irq_data *data, unsigned int type) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 rtsr, ftsr; irq_gc_lock(gc); - rtsr = irq_reg_readl(gc, EXTI_RTSR); - ftsr = irq_reg_readl(gc, EXTI_FTSR); + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -70,8 +110,8 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) return -EINVAL; } - irq_reg_writel(gc, rtsr, EXTI_RTSR); - irq_reg_writel(gc, ftsr, EXTI_FTSR); + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); + irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); irq_gc_unlock(gc); @@ -81,17 +121,18 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 emr; irq_gc_lock(gc); - emr = irq_reg_readl(gc, EXTI_EMR); + emr = irq_reg_readl(gc, stm32_bank->emr_ofst); if (on) emr |= BIT(pin); else emr &= ~BIT(pin); - irq_reg_writel(gc, emr, EXTI_EMR); + irq_reg_writel(gc, emr, stm32_bank->emr_ofst); irq_gc_unlock(gc); @@ -101,11 +142,12 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *data) { - struct irq_chip_generic *gc
Re: [PATCH v2 1/3] mtd: spi-nor: stm32-quadspi: Fix uninitialized error return code
thanks Cyrille indeed, the "Signed-off" on Geert'commit was a mistake BR Ludo On 10/29/2017 06:50 PM, Cyrille Pitchen wrote: Hi Ludovic, Le 26/10/2017 à 17:12, Ludovic Barre a écrit : From: Geert Uytterhoeven With gcc 4.1.2: drivers/mtd/spi-nor/stm32-quadspi.c: In function ‘stm32_qspi_tx_poll’: drivers/mtd/spi-nor/stm32-quadspi.c:230: warning: ‘ret’ may be used uninitialized in this function Indeed, if stm32_qspi_cmd.len is zero, ret will be uninitialized. This length is passed from outside the driver using the spi_nor.{read,write}{,_reg}() callbacks. Several functions in drivers/mtd/spi-nor/spi-nor.c (e.g. write_enable(), write_disable(), and erase_chip()) call spi_nor.write_reg() with a zero length. Fix this by returning an explicit zero on success. Fixes: 0d43d7ab277a048c ("mtd: spi-nor: add driver for STM32 quad spi flash controller") Signed-off-by: Geert Uytterhoeven Acked-by: Ludovic Barre Signed-off-by: Ludovic Barre I removed your "Signed-off" because I think this is a mistake but kept your "Acked-by" tag. Applied to the spi-nor/next branch of l2-mtd. Thanks! --- drivers/mtd/spi-nor/stm32-quadspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c index 86c0931..ad6a3e1 100644 --- a/drivers/mtd/spi-nor/stm32-quadspi.c +++ b/drivers/mtd/spi-nor/stm32-quadspi.c @@ -240,12 +240,12 @@ static int stm32_qspi_tx_poll(struct stm32_qspi *qspi, STM32_QSPI_FIFO_TIMEOUT_US); if (ret) { dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr); - break; + return ret; } tx_fifo(buf++, qspi->io_base + QUADSPI_DR); } - return ret; + return 0; } static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
Re: [PATCH V2 1/3] watchdog: stm32: add pclk feature for stm32mp1
On 06/20/2018 03:29 PM, Guenter Roeck wrote: On 06/20/2018 06:24 AM, Ludovic BARRE wrote: On 06/20/2018 11:19 AM, Guenter Roeck wrote: On 06/20/2018 12:53 AM, Ludovic Barre wrote: From: Ludovic Barre This patch adds config data to manage specific properties by compatible. Adds stm32mp1 config which requires pclk clock. Signed-off-by: Ludovic Barre --- .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 21 +++- drivers/watchdog/stm32_iwdg.c | 132 ++--- 2 files changed, 104 insertions(+), 49 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt index cc13b10a..f07f6d89 100644 --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt @@ -2,18 +2,31 @@ STM32 Independent WatchDoG (IWDG) - Required properties: -- compatible: "st,stm32-iwdg" -- reg: physical base address and length of the registers set for the device -- clocks: must contain a single entry describing the clock input +- compatible: Should be either "st,stm32-iwdg" or "st,stm32mp1-iwdg" +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "pclk", "lsi" for st,stm32mp1-iwdg Optional Properties: - timeout-sec: Watchdog timeout value in seconds. -Example: +Examples: iwdg: watchdog@40003000 { compatible = "st,stm32-iwdg"; reg = <0x40003000 0x400>; clocks = <&clk_lsi>; + clock-names = "lsi"; + timeout-sec = <32>; +}; + +iwdg: iwdg@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&clk_lsi>; + clock-names = "pclk", "lsi"; timeout-sec = <32>; }; diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index c97ad56..fc96670 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -11,12 +11,13 @@ #include #include -#include -#include #include #include #include +#include +#include #include +#include #include #include @@ -54,11 +55,17 @@ #define TIMEOUT_US 10 #define SLEEP_US 1000 +struct stm32_iwdg_config { + bool has_pclk; +}; + This data structure is unnecessary. Just assign the boolean directly to .data and ... Ok, I send a v3, with boolean directly to .data like: #define NO_PCLK false #define HAS_PCLK true ... Just use true/false directly. There is no need for those defines. If you want the reader to understand what is defined, I would be ok with #define HAS_PCLK true static const struct of_device_id stm32_iwdg_of_match[] = { { .compatible = "st,stm32-iwdg", .data = (void *) !HAS_PCLK }, { .compatible = "st,stm32mp1-iwdg", .data = (void *) HAS_PCLK }, { /* end node */ } Guenter Ok, thanks static const struct of_device_id stm32_iwdg_of_match[] = { { .compatible = "st,stm32-iwdg", .data = (void *) NO_PCLK }, { .compatible = "st,stm32mp1-iwdg", .data = (void *) HAS_PCLK }, { /* end node */ } }; Note: V3, because I sent my original version with V2 (it's mistake) struct stm32_iwdg { - struct watchdog_device wdd; - void __iomem *regs; - struct clk *clk; - unsigned int rate; + struct watchdog_device wdd; + void __iomem *regs; + struct stm32_iwdg_config *config; declare bool has_pclk here. + struct clk *clk_lsi; + struct clk *clk_pclk; + unsigned int rate; }; static inline u32 reg_read(void __iomem *base, u32 reg) @@ -133,6 +140,44 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, return 0; } +static int stm32_iwdg_clk_init(struct platform_device *pdev, + struct stm32_iwdg *wdt) +{ + u32 ret; + + wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); + if (IS_ERR(wdt->clk_lsi)) { + dev_err(&pdev->dev, "Unable to get lsi clock\n"); + return PTR_ERR(wdt->clk_lsi); + } + + /* optional peripheral clock */ + if (wdt->config->has_pclk) { + wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(wdt->clk_pclk)) { + dev_err(&pdev->dev, "Unable to get pclk clock\n"); + return PTR_ERR(wdt->clk_pclk); + } + + ret = clk_prepare_enable(wdt->clk_pclk); + if (ret) { + dev_err(&am
[PATCH V3 2/3] ARM: dts: stm32: add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch adds independent watchdog support for stm32mp157c. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157c.dtsi | 8 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi index 7d17538..95cc166 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp157c.dtsi @@ -784,6 +784,14 @@ status = "disabled"; }; + iwdg2: watchdog@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&rcc CK_LSI>; + clock-names = "pclk", "lsi"; + status = "disabled"; + }; + usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; -- 2.7.4
[PATCH V3 1/3] watchdog: stm32: add pclk feature for stm32mp1
From: Ludovic Barre This patch adds config data to manage specific properties by compatible. Adds stm32mp1 config which requires pclk clock. Signed-off-by: Ludovic Barre --- .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 21 +++- drivers/watchdog/stm32_iwdg.c | 116 + 2 files changed, 91 insertions(+), 46 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt index cc13b10a..f07f6d89 100644 --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt @@ -2,18 +2,31 @@ STM32 Independent WatchDoG (IWDG) - Required properties: -- compatible: "st,stm32-iwdg" -- reg: physical base address and length of the registers set for the device -- clocks: must contain a single entry describing the clock input +- compatible: Should be either "st,stm32-iwdg" or "st,stm32mp1-iwdg" +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "pclk", "lsi" for st,stm32mp1-iwdg Optional Properties: - timeout-sec: Watchdog timeout value in seconds. -Example: +Examples: iwdg: watchdog@40003000 { compatible = "st,stm32-iwdg"; reg = <0x40003000 0x400>; clocks = <&clk_lsi>; + clock-names = "lsi"; + timeout-sec = <32>; +}; + +iwdg: iwdg@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&clk_lsi>; + clock-names = "pclk", "lsi"; timeout-sec = <32>; }; diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index c97ad56..e00e3b3 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -11,12 +11,13 @@ #include #include -#include -#include #include #include #include +#include +#include #include +#include #include #include @@ -54,11 +55,15 @@ #define TIMEOUT_US 10 #define SLEEP_US 1000 +#define HAS_PCLK true + struct stm32_iwdg { struct watchdog_device wdd; void __iomem*regs; - struct clk *clk; + struct clk *clk_lsi; + struct clk *clk_pclk; unsigned intrate; + boolhas_pclk; }; static inline u32 reg_read(void __iomem *base, u32 reg) @@ -133,6 +138,44 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, return 0; } +static int stm32_iwdg_clk_init(struct platform_device *pdev, + struct stm32_iwdg *wdt) +{ + u32 ret; + + wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); + if (IS_ERR(wdt->clk_lsi)) { + dev_err(&pdev->dev, "Unable to get lsi clock\n"); + return PTR_ERR(wdt->clk_lsi); + } + + /* optional peripheral clock */ + if (wdt->has_pclk) { + wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(wdt->clk_pclk)) { + dev_err(&pdev->dev, "Unable to get pclk clock\n"); + return PTR_ERR(wdt->clk_pclk); + } + + ret = clk_prepare_enable(wdt->clk_pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare pclk clock\n"); + return ret; + } + } + + ret = clk_prepare_enable(wdt->clk_lsi); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare lsi clock\n"); + clk_disable_unprepare(wdt->clk_pclk); + return ret; + } + + wdt->rate = clk_get_rate(wdt->clk_lsi); + + return 0; +} + static const struct watchdog_info stm32_iwdg_info = { .options= WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | @@ -147,49 +190,42 @@ static const struct watchdog_ops stm32_iwdg_ops = { .set_timeout= stm32_iwdg_set_timeout, }; +static const struct of_device_id stm32_iwdg_of_match[] = { + { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK }, + { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK }, + { /* end node */ } +}; +MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); + static int stm32_iwdg_probe(struct platform_device *pdev) { struct watchdog_device *wdd; + const struct of_device_id *ma
[PATCH V3 3/3] ARM: dts: stm32: add iwdg2 support for stm32mp157c-ed1
From: Ludovic Barre This patch activates independent watchdog support for stm32mp157c board. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157c-ed1.dts | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts index ae33653..8af263a 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -68,6 +68,11 @@ status = "okay"; }; +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins_a>; -- 2.7.4
[PATCH V3 0/3] add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch series updates stm32_iwdg driver to manage config by compatible. stm32mp1 config requires a pclk clock. v3: -remove stm32_iwdg_config structure, just assign the boolean directly to .dat Ludovic Barre (3): watchdog: stm32: add pclk feature for stm32mp1 ARM: dts: stm32: add iwdg2 support for stm32mp157c ARM: dts: stm32: add iwdg2 support for stm32mp157c-ed1 .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 21 +++- arch/arm/boot/dts/stm32mp157c-ed1.dts | 5 + arch/arm/boot/dts/stm32mp157c.dtsi | 8 ++ drivers/watchdog/stm32_iwdg.c | 116 + 4 files changed, 104 insertions(+), 46 deletions(-) -- 2.7.4
Re: [PATCH V3 1/3] watchdog: stm32: add pclk feature for stm32mp1
On 06/20/2018 09:14 PM, Rob Herring wrote: On Wed, Jun 20, 2018 at 03:51:36PM +0200, Ludovic Barre wrote: From: Ludovic Barre This patch adds config data to manage specific properties by compatible. Adds stm32mp1 config which requires pclk clock. Signed-off-by: Ludovic Barre --- .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 21 +++- Please split bindings to separate patch. OK drivers/watchdog/stm32_iwdg.c | 116 + 2 files changed, 91 insertions(+), 46 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt index cc13b10a..f07f6d89 100644 --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt @@ -2,18 +2,31 @@ STM32 Independent WatchDoG (IWDG) - Required properties: -- compatible: "st,stm32-iwdg" -- reg: physical base address and length of the registers set for the device -- clocks: must contain a single entry describing the clock input +- compatible: Should be either "st,stm32-iwdg" or "st,stm32mp1-iwdg" Please format one per line. OK +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "pclk", "lsi" for st,stm32mp1-iwdg Put lsi 1st so it is always index 0. OK Optional Properties: - timeout-sec: Watchdog timeout value in seconds. -Example: +Examples: iwdg: watchdog@40003000 { compatible = "st,stm32-iwdg"; reg = <0x40003000 0x400>; clocks = <&clk_lsi>; + clock-names = "lsi"; + timeout-sec = <32>; +}; + +iwdg: iwdg@5a002000 { watchdog@... sorry, I forget this occurrence. Do we really need 2 example just to show 2 clocks? No, I could keep only one + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&clk_lsi>; + clock-names = "pclk", "lsi"; timeout-sec = <32>; };
[PATCH V4 3/4] ARM: dts: stm32: add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch adds independent watchdog support for stm32mp157c. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157c.dtsi | 8 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi index 7d17538..95cc166 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp157c.dtsi @@ -784,6 +784,14 @@ status = "disabled"; }; + iwdg2: watchdog@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&rcc CK_LSI>; + clock-names = "pclk", "lsi"; + status = "disabled"; + }; + usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; -- 2.7.4
[PATCH V4 2/4] watchdog: stm32: add pclk feature for stm32mp1
From: Ludovic Barre This patch adds compatible data to manage pclk clock by compatible. Adds stm32mp1 support which requires pclk clock. Signed-off-by: Ludovic Barre --- drivers/watchdog/stm32_iwdg.c | 116 +++--- 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index c97ad56..e00e3b3 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -11,12 +11,13 @@ #include #include -#include -#include #include #include #include +#include +#include #include +#include #include #include @@ -54,11 +55,15 @@ #define TIMEOUT_US 10 #define SLEEP_US 1000 +#define HAS_PCLK true + struct stm32_iwdg { struct watchdog_device wdd; void __iomem*regs; - struct clk *clk; + struct clk *clk_lsi; + struct clk *clk_pclk; unsigned intrate; + boolhas_pclk; }; static inline u32 reg_read(void __iomem *base, u32 reg) @@ -133,6 +138,44 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, return 0; } +static int stm32_iwdg_clk_init(struct platform_device *pdev, + struct stm32_iwdg *wdt) +{ + u32 ret; + + wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); + if (IS_ERR(wdt->clk_lsi)) { + dev_err(&pdev->dev, "Unable to get lsi clock\n"); + return PTR_ERR(wdt->clk_lsi); + } + + /* optional peripheral clock */ + if (wdt->has_pclk) { + wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(wdt->clk_pclk)) { + dev_err(&pdev->dev, "Unable to get pclk clock\n"); + return PTR_ERR(wdt->clk_pclk); + } + + ret = clk_prepare_enable(wdt->clk_pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare pclk clock\n"); + return ret; + } + } + + ret = clk_prepare_enable(wdt->clk_lsi); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare lsi clock\n"); + clk_disable_unprepare(wdt->clk_pclk); + return ret; + } + + wdt->rate = clk_get_rate(wdt->clk_lsi); + + return 0; +} + static const struct watchdog_info stm32_iwdg_info = { .options= WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | @@ -147,49 +190,42 @@ static const struct watchdog_ops stm32_iwdg_ops = { .set_timeout= stm32_iwdg_set_timeout, }; +static const struct of_device_id stm32_iwdg_of_match[] = { + { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK }, + { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK }, + { /* end node */ } +}; +MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); + static int stm32_iwdg_probe(struct platform_device *pdev) { struct watchdog_device *wdd; + const struct of_device_id *match; struct stm32_iwdg *wdt; struct resource *res; - void __iomem *regs; - struct clk *clk; int ret; + match = of_match_device(stm32_iwdg_of_match, &pdev->dev); + if (!match) + return -ENODEV; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdt->has_pclk = match->data; + /* This is the timer base. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(regs)) { + wdt->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wdt->regs)) { dev_err(&pdev->dev, "Could not get resource\n"); - return PTR_ERR(regs); + return PTR_ERR(wdt->regs); } - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "Unable to get clock\n"); - return PTR_ERR(clk); - } - - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(&pdev->dev, "Unable to prepare clock %p\n", clk); + ret = stm32_iwdg_clk_init(pdev, wdt); + if (ret) return ret; - } - - /* -* Allocate our watchdog driver data, which has the -* struct watchdog_device nested within it. -*/ - wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); - if (!wdt) { - ret = -ENOMEM; - goto err; - } - - /* Initiali
[PATCH V4 0/4] add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch series updates stm32_iwdg driver to manage pclk clock by compatible. stm32mp1 requires a pclk clock. v4: -dt-bindings: split and review v3: -remove stm32_iwdg_config structure, just assign the boolean directly to .dat Ludovic Barre (4): dt-bindings: watchdog: add stm32mp1 support watchdog: stm32: add pclk feature for stm32mp1 ARM: dts: stm32: add iwdg2 support for stm32mp157c ARM: dts: stm32: add iwdg2 support for stm32mp157c-ed1 .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 13 ++- arch/arm/boot/dts/stm32mp157c-ed1.dts | 5 + arch/arm/boot/dts/stm32mp157c.dtsi | 8 ++ drivers/watchdog/stm32_iwdg.c | 116 + 4 files changed, 97 insertions(+), 45 deletions(-) -- 2.7.4
[PATCH V4 4/4] ARM: dts: stm32: add iwdg2 support for stm32mp157c-ed1
From: Ludovic Barre This patch activates independent watchdog support for stm32mp157c board. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157c-ed1.dts | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts index ae33653..8af263a 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -68,6 +68,11 @@ status = "okay"; }; +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins_a>; -- 2.7.4
[PATCH V4 1/4] dt-bindings: watchdog: add stm32mp1 support
From: Ludovic Barre This patch adds support of stm32mp1. stm32mp1 requires 2 clocks lsi and pclk. Signed-off-by: Ludovic Barre --- .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt index cc13b10a..d8f4430 100644 --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt @@ -2,9 +2,15 @@ STM32 Independent WatchDoG (IWDG) - Required properties: -- compatible: "st,stm32-iwdg" -- reg: physical base address and length of the registers set for the device -- clocks: must contain a single entry describing the clock input +- compatible: Should be either: + - "st,stm32-iwdg" + - "st,stm32mp1-iwdg" +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "lsi", "pclk" for st,stm32mp1-iwdg Optional Properties: - timeout-sec: Watchdog timeout value in seconds. @@ -15,5 +21,6 @@ iwdg: watchdog@40003000 { compatible = "st,stm32-iwdg"; reg = <0x40003000 0x400>; clocks = <&clk_lsi>; + clock-names = "lsi"; timeout-sec = <32>; }; -- 2.7.4
Re: [PATCH V4 2/4] watchdog: stm32: add pclk feature for stm32mp1
On 06/21/2018 06:53 PM, Guenter Roeck wrote: On Thu, Jun 21, 2018 at 11:02:15AM +0200, Ludovic Barre wrote: From: Ludovic Barre This patch adds compatible data to manage pclk clock by compatible. Adds stm32mp1 support which requires pclk clock. Signed-off-by: Ludovic Barre --- drivers/watchdog/stm32_iwdg.c | 116 +++--- 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index c97ad56..e00e3b3 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -11,12 +11,13 @@ #include #include -#include -#include #include #include #include +#include +#include #include +#include #include #include @@ -54,11 +55,15 @@ #define TIMEOUT_US10 #define SLEEP_US 1000 +#define HAS_PCLK true + struct stm32_iwdg { struct watchdog_device wdd; void __iomem*regs; - struct clk *clk; + struct clk *clk_lsi; + struct clk *clk_pclk; unsigned intrate; + boolhas_pclk; }; static inline u32 reg_read(void __iomem *base, u32 reg) @@ -133,6 +138,44 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, return 0; } +static int stm32_iwdg_clk_init(struct platform_device *pdev, + struct stm32_iwdg *wdt) +{ + u32 ret; + + wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); I just noticed a subtle difference: This used to be devm_clk_get(&pdev->dev, NULL); which would always get the first clock, no matter how it is named. Can that cause problems with backward compatibility ? You are right Guenter. When there are multiple clocks, I prefer to use name interface. I find it easier to use, and avoid misunderstanding. Today, only one "dtsi" define the watchdog and it's disabled (stm32f429.dtsi). I think it's good moment to move to clock named (before it is used anymore). But you are right I forgot to change stm32f429.dtsi. If I add a commit for stm32f429.dtsi, it's Ok for you ? BR Ludo Thanks, Guenter + if (IS_ERR(wdt->clk_lsi)) { + dev_err(&pdev->dev, "Unable to get lsi clock\n"); + return PTR_ERR(wdt->clk_lsi); + } + + /* optional peripheral clock */ + if (wdt->has_pclk) { + wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(wdt->clk_pclk)) { + dev_err(&pdev->dev, "Unable to get pclk clock\n"); + return PTR_ERR(wdt->clk_pclk); + } + + ret = clk_prepare_enable(wdt->clk_pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare pclk clock\n"); + return ret; + } + } + + ret = clk_prepare_enable(wdt->clk_lsi); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare lsi clock\n"); + clk_disable_unprepare(wdt->clk_pclk); + return ret; + } + + wdt->rate = clk_get_rate(wdt->clk_lsi); + + return 0; +} + static const struct watchdog_info stm32_iwdg_info = { .options= WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | @@ -147,49 +190,42 @@ static const struct watchdog_ops stm32_iwdg_ops = { .set_timeout= stm32_iwdg_set_timeout, }; +static const struct of_device_id stm32_iwdg_of_match[] = { + { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK }, + { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK }, + { /* end node */ } +}; +MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); + static int stm32_iwdg_probe(struct platform_device *pdev) { struct watchdog_device *wdd; + const struct of_device_id *match; struct stm32_iwdg *wdt; struct resource *res; - void __iomem *regs; - struct clk *clk; int ret; + match = of_match_device(stm32_iwdg_of_match, &pdev->dev); + if (!match) + return -ENODEV; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdt->has_pclk = match->data; + /* This is the timer base. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(regs)) { + wdt->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wdt->regs)) { dev_err(&pdev->dev, "Could not get resource\n"); - return PTR_ERR(regs);
[PATCH V5 1/5] dt-bindings: watchdog: add stm32mp1 support
From: Ludovic Barre This patch adds support of stm32mp1. stm32mp1 requires 2 clocks lsi and pclk. Signed-off-by: Ludovic Barre --- .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 13 ++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt index cc13b10a..d8f4430 100644 --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt @@ -2,9 +2,15 @@ STM32 Independent WatchDoG (IWDG) - Required properties: -- compatible: "st,stm32-iwdg" -- reg: physical base address and length of the registers set for the device -- clocks: must contain a single entry describing the clock input +- compatible: Should be either: + - "st,stm32-iwdg" + - "st,stm32mp1-iwdg" +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "lsi", "pclk" for st,stm32mp1-iwdg Optional Properties: - timeout-sec: Watchdog timeout value in seconds. @@ -15,5 +21,6 @@ iwdg: watchdog@40003000 { compatible = "st,stm32-iwdg"; reg = <0x40003000 0x400>; clocks = <&clk_lsi>; + clock-names = "lsi"; timeout-sec = <32>; }; -- 2.7.4
[PATCH V5 0/5] add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch series updates stm32_iwdg driver to manage pclk clock by compatible. stm32mp1 requires a pclk clock. v5: -update stm32f429.dtsi v4: -dt-bindings: split and review v3: -remove stm32_iwdg_config structure, just assign the boolean directly to .dat Ludovic Barre (5): dt-bindings: watchdog: add stm32mp1 support watchdog: stm32: add pclk feature for stm32mp1 ARM: dts: stm32: add iwdg2 support for stm32mp157c ARM: dts: stm32: add iwdg2 support for stm32mp157c-ed1 ARM: dts: stm32: update iwdg with lsi clock name for stm32f429 .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 13 ++- arch/arm/boot/dts/stm32f429.dtsi | 1 + arch/arm/boot/dts/stm32mp157c-ed1.dts | 5 + arch/arm/boot/dts/stm32mp157c.dtsi | 8 ++ drivers/watchdog/stm32_iwdg.c | 116 + 5 files changed, 98 insertions(+), 45 deletions(-) -- 2.7.4
[PATCH V5 2/5] watchdog: stm32: add pclk feature for stm32mp1
From: Ludovic Barre This patch adds compatible data to manage pclk clock by compatible. Adds stm32mp1 support which requires pclk clock. Signed-off-by: Ludovic Barre Acked-by: Alexandre TORGUE --- drivers/watchdog/stm32_iwdg.c | 116 +++--- 1 file changed, 74 insertions(+), 42 deletions(-) diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index c97ad56..e00e3b3 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -11,12 +11,13 @@ #include #include -#include -#include #include #include #include +#include +#include #include +#include #include #include @@ -54,11 +55,15 @@ #define TIMEOUT_US 10 #define SLEEP_US 1000 +#define HAS_PCLK true + struct stm32_iwdg { struct watchdog_device wdd; void __iomem*regs; - struct clk *clk; + struct clk *clk_lsi; + struct clk *clk_pclk; unsigned intrate; + boolhas_pclk; }; static inline u32 reg_read(void __iomem *base, u32 reg) @@ -133,6 +138,44 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, return 0; } +static int stm32_iwdg_clk_init(struct platform_device *pdev, + struct stm32_iwdg *wdt) +{ + u32 ret; + + wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); + if (IS_ERR(wdt->clk_lsi)) { + dev_err(&pdev->dev, "Unable to get lsi clock\n"); + return PTR_ERR(wdt->clk_lsi); + } + + /* optional peripheral clock */ + if (wdt->has_pclk) { + wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(wdt->clk_pclk)) { + dev_err(&pdev->dev, "Unable to get pclk clock\n"); + return PTR_ERR(wdt->clk_pclk); + } + + ret = clk_prepare_enable(wdt->clk_pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare pclk clock\n"); + return ret; + } + } + + ret = clk_prepare_enable(wdt->clk_lsi); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare lsi clock\n"); + clk_disable_unprepare(wdt->clk_pclk); + return ret; + } + + wdt->rate = clk_get_rate(wdt->clk_lsi); + + return 0; +} + static const struct watchdog_info stm32_iwdg_info = { .options= WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | @@ -147,49 +190,42 @@ static const struct watchdog_ops stm32_iwdg_ops = { .set_timeout= stm32_iwdg_set_timeout, }; +static const struct of_device_id stm32_iwdg_of_match[] = { + { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK }, + { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK }, + { /* end node */ } +}; +MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); + static int stm32_iwdg_probe(struct platform_device *pdev) { struct watchdog_device *wdd; + const struct of_device_id *match; struct stm32_iwdg *wdt; struct resource *res; - void __iomem *regs; - struct clk *clk; int ret; + match = of_match_device(stm32_iwdg_of_match, &pdev->dev); + if (!match) + return -ENODEV; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdt->has_pclk = match->data; + /* This is the timer base. */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(regs)) { + wdt->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wdt->regs)) { dev_err(&pdev->dev, "Could not get resource\n"); - return PTR_ERR(regs); + return PTR_ERR(wdt->regs); } - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "Unable to get clock\n"); - return PTR_ERR(clk); - } - - ret = clk_prepare_enable(clk); - if (ret) { - dev_err(&pdev->dev, "Unable to prepare clock %p\n", clk); + ret = stm32_iwdg_clk_init(pdev, wdt); + if (ret) return ret; - } - - /* -* Allocate our watchdog driver data, which has the -* struct watchdog_device nested within it. -*/ - wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); - if (!wdt) { - ret = -ENOMEM; - goto err; - }
[PATCH V5 5/5] ARM: dts: stm32: update iwdg with lsi clock name for stm32f429
From: Ludovic Barre This patch updates iwdg watchdog to use lsi clock name. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32f429.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi index ede77e0..39ea13a 100644 --- a/arch/arm/boot/dts/stm32f429.dtsi +++ b/arch/arm/boot/dts/stm32f429.dtsi @@ -310,6 +310,7 @@ compatible = "st,stm32-iwdg"; reg = <0x40003000 0x400>; clocks = <&clk_lsi>; + clock-names = "lsi"; status = "disabled"; }; -- 2.7.4
[PATCH V5 4/5] ARM: dts: stm32: add iwdg2 support for stm32mp157c-ed1
From: Ludovic Barre This patch activates independent watchdog support for stm32mp157c board. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157c-ed1.dts | 5 + 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts index ae33653..8af263a 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -68,6 +68,11 @@ status = "okay"; }; +&iwdg2 { + timeout-sec = <32>; + status = "okay"; +}; + &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins_a>; -- 2.7.4
[PATCH V5 3/5] ARM: dts: stm32: add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch adds independent watchdog support for stm32mp157c. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157c.dtsi | 8 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi index 7d17538..95cc166 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp157c.dtsi @@ -784,6 +784,14 @@ status = "disabled"; }; + iwdg2: watchdog@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&rcc CK_LSI>; + clock-names = "pclk", "lsi"; + status = "disabled"; + }; + usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; -- 2.7.4
Re: [PATCH] irqchip/stm32: fix init error handling
oh yes, host_data is dereferenced (for kfree into out_free_mem) if stm32_exti_host_init fail thanks Dan BR Ludo On 08/08/2018 02:03 PM, Dan Carpenter wrote: If there are any errors in stm32_exti_host_init() then it leads to a NULL dereference in the callers. The function should clean up after itself. Fixes: f9fc1745501e ("irqchip/stm32: Add host and driver data structures") Signed-off-by: Dan Carpenter Reviewed-by: Ludovic Barre diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 3df527fcf4e1..0a2088e12d96 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -603,17 +603,24 @@ stm32_exti_host_data *stm32_exti_host_init(const struct stm32_exti_drv_data *dd, sizeof(struct stm32_exti_chip_data), GFP_KERNEL); if (!host_data->chips_data) - return NULL; + goto free_host_data; host_data->base = of_iomap(node, 0); if (!host_data->base) { pr_err("%pOF: Unable to map registers\n", node); - return NULL; + goto free_chips_data; } stm32_host_data = host_data; return host_data; + +free_chips_data: + kfree(host_data->chips_data); +free_host_data: + kfree(host_data); + + return NULL; } static struct @@ -665,10 +672,8 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, struct irq_domain *domain; host_data = stm32_exti_host_init(drv_data, node); - if (!host_data) { - ret = -ENOMEM; - goto out_free_mem; - } + if (!host_data) + return -ENOMEM; domain = irq_domain_add_linear(node, drv_data->bank_nr * IRQS_PER_BANK, &irq_exti_domain_ops, NULL); @@ -725,7 +730,6 @@ static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data, irq_domain_remove(domain); out_unmap: iounmap(host_data->base); -out_free_mem: kfree(host_data->chips_data); kfree(host_data); return ret; @@ -752,10 +756,8 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, } host_data = stm32_exti_host_init(drv_data, node); - if (!host_data) { - ret = -ENOMEM; - goto out_free_mem; - } + if (!host_data) + return -ENOMEM; for (i = 0; i < drv_data->bank_nr; i++) stm32_exti_chip_init(host_data, i, node); @@ -777,7 +779,6 @@ __init stm32_exti_hierarchy_init(const struct stm32_exti_drv_data *drv_data, out_unmap: iounmap(host_data->base); -out_free_mem: kfree(host_data->chips_data); kfree(host_data); return ret;
Re: linux-next: manual merge of the pinctrl tree with the devicetree tree
On 07/31/2018 07:42 AM, Stephen Rothwell wrote: Hi all, Today's linux-next merge of the pinctrl tree got a conflict in: Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.txt between commit: 791d3ef2e111 ("dt-bindings: remove 'interrupt-parent' from bindings") from the devicetree tree and commit: de1d08b22974 ("dt-bindings: pinctrl: add syscfg mask parameter") from the pinctrl tree. I fixed it up (see below) and can carry the fix as necessary. This is now fixed as far as linux-next is concerned, but any non trivial conflicts should be mentioned to your upstream maintainer when your tree is submitted for merging. You may also want to consider cooperating with the maintainer of the conflicting tree to minimise any particularly complex conflicts. hi Stephen thanks for the fix conflict, and the fix is OK for me. BR Ludo
[PATCH 10/14] mmc: mmci: add dma_release callback
From: Ludovic Barre This patch adds dma_release callback at mmci_host_ops to allow to call specific variant. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 13 - drivers/mmc/host/mmci.h | 2 ++ drivers/mmc/host/mmci_qcom_dml.c | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ae47d08..177e2e8 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -409,6 +409,12 @@ int mmci_dma_setup(struct mmci_host *host) return host->ops->dma_setup(host); } +void mmci_dma_release(struct mmci_host *host) +{ + if (host->ops && host->ops->dma_release) + host->ops->dma_release(host); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -546,7 +552,7 @@ int mmci_dmae_setup(struct mmci_host *host) * This is used in or so inline it * so it can be discarded. */ -static inline void mmci_dma_release(struct mmci_host *host) +void mmci_dmae_release(struct mmci_host *host) { struct dmaengine_priv *dmae = host->dma_priv; @@ -799,13 +805,10 @@ static struct mmci_host_ops mmci_variant_ops = { .unprepare_data = mmci_dmae_unprepare_data, .get_next_data = mmci_dmae_get_next_data, .dma_setup = mmci_dmae_setup, + .dma_release = mmci_dmae_release, }; #else /* Blank functions if the DMA engine is not available */ -static inline void mmci_dma_release(struct mmci_host *host) -{ -} - static inline void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) { diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index e1b389c..f961f90 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -279,6 +279,7 @@ struct mmci_host_ops { int err); void (*get_next_data)(struct mmci_host *host, struct mmc_data *data); int (*dma_setup)(struct mmci_host *host); + void (*dma_release)(struct mmci_host *host); }; struct mmci_host { @@ -336,3 +337,4 @@ void mmci_dmae_unprepare_data(struct mmci_host *host, struct mmc_data *data, int err); void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data); int mmci_dmae_setup(struct mmci_host *host); +void mmci_dmae_release(struct mmci_host *host); diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index 47abbdd..3c9d32e 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -186,6 +186,7 @@ static struct mmci_host_ops qcom_variant_ops = { .unprepare_data = mmci_dmae_unprepare_data, .get_next_data = mmci_dmae_get_next_data, .dma_setup = qcom_dma_setup, + .dma_release = mmci_dmae_release, }; void qcom_variant_init(struct mmci_host *host) -- 2.7.4
[PATCH 04/14] mmc: mmci: introduce dma_priv pointer to mmci_host
From: Ludovic Barre This patch introduces dma_priv pointer to define specific needs for each dma engine. This patch is needed to prepare sdmmc variant with internal dma which not use dmaengine API. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 165 +-- drivers/mmc/host/mmci.h | 20 + drivers/mmc/host/mmci_qcom_dml.c | 6 +- 3 files changed, 112 insertions(+), 79 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 8144a87..bdc48c3 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -415,31 +415,57 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) * no custom DMA interfaces are supported. */ #ifdef CONFIG_DMA_ENGINE -static void mmci_dma_setup(struct mmci_host *host) +struct dmaengine_next { + struct dma_async_tx_descriptor *dma_desc; + struct dma_chan *dma_chan; + s32 cookie; +}; + +struct dmaengine_priv { + struct dma_chan *dma_current; + struct dma_chan *dma_rx_channel; + struct dma_chan *dma_tx_channel; + struct dma_async_tx_descriptor *dma_desc_current; + struct dmaengine_next next_data; + bool dma_in_progress; +}; + +#define __dmae_inprogress(dmae) ((dmae)->dma_in_progress) + +static int mmci_dma_setup(struct mmci_host *host) { const char *rxname, *txname; + struct dmaengine_priv *dmae; - host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); - host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); + dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL); + if (!dmae) + return -ENOMEM; + + host->dma_priv = dmae; + + dmae->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), +"rx"); + dmae->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), +"tx"); /* initialize pre request cookie */ - host->next_data.cookie = 1; + dmae->next_data.cookie = 1; /* * If only an RX channel is specified, the driver will * attempt to use it bidirectionally, however if it is * is specified but cannot be located, DMA will be disabled. */ - if (host->dma_rx_channel && !host->dma_tx_channel) - host->dma_tx_channel = host->dma_rx_channel; + if (dmae->dma_rx_channel && !dmae->dma_tx_channel) + dmae->dma_tx_channel = dmae->dma_rx_channel; - if (host->dma_rx_channel) - rxname = dma_chan_name(host->dma_rx_channel); + if (dmae->dma_rx_channel) + rxname = dma_chan_name(dmae->dma_rx_channel); else rxname = "none"; - if (host->dma_tx_channel) - txname = dma_chan_name(host->dma_tx_channel); + if (dmae->dma_tx_channel) + txname = dma_chan_name(dmae->dma_tx_channel); else txname = "none"; @@ -450,15 +476,15 @@ static void mmci_dma_setup(struct mmci_host *host) * Limit the maximum segment size in any SG entry according to * the parameters of the DMA engine device. */ - if (host->dma_tx_channel) { - struct device *dev = host->dma_tx_channel->device->dev; + if (dmae->dma_tx_channel) { + struct device *dev = dmae->dma_tx_channel->device->dev; unsigned int max_seg_size = dma_get_max_seg_size(dev); if (max_seg_size < host->mmc->max_seg_size) host->mmc->max_seg_size = max_seg_size; } - if (host->dma_rx_channel) { - struct device *dev = host->dma_rx_channel->device->dev; + if (dmae->dma_rx_channel) { + struct device *dev = dmae->dma_rx_channel->device->dev; unsigned int max_seg_size = dma_get_max_seg_size(dev); if (max_seg_size < host->mmc->max_seg_size) @@ -466,7 +492,9 @@ static void mmci_dma_setup(struct mmci_host *host) } if (host->ops && host->ops->dma_setup) - host->ops->dma_setup(host); + return host->ops->dma_setup(host); + + return 0; } /* @@ -475,21 +503,24 @@ static void mmci_dma_setup(struct mmci_host *host) */ static inline void mmci_dma_release(struct mmci_host *host) { - if (host->dma_rx_channel) - dma_release_channel(host->dma_rx_channel); - if (host->dma_tx_channel) - dma_release_channel(host->dma_tx_channel); - host->dma_rx_channel = host
[PATCH 12/14] mmc: mmci: add dma_finalize callback
From: Ludovic Barre This patch adds dma_finalize callback at mmci_host_ops to allow to call specific variant. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 14 -- drivers/mmc/host/mmci.h | 2 ++ drivers/mmc/host/mmci_qcom_dml.c | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 642ef19..b124a73 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -447,6 +447,12 @@ int mmci_dma_start(struct mmci_host *host, unsigned int datactrl) return 0; } +void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +{ + if (host->ops && host->ops->dma_finalize) + host->ops->dma_finalize(host, data); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -626,7 +632,7 @@ static void mmci_dma_data_error(struct mmci_host *host) __mmci_dmae_unmap(host, host->data); } -static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) +void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data) { struct dmaengine_priv *dmae = host->dma_priv; u32 status; @@ -820,14 +826,10 @@ static struct mmci_host_ops mmci_variant_ops = { .dma_setup = mmci_dmae_setup, .dma_release = mmci_dmae_release, .dma_start = mmci_dmae_start, + .dma_finalize = mmci_dmae_finalize, }; #else /* Blank functions if the DMA engine is not available */ -static inline void mmci_dma_finalize(struct mmci_host *host, -struct mmc_data *data) -{ -} - static inline void mmci_dma_data_error(struct mmci_host *host) { } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 3a200a9..3f482d5 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -281,6 +281,7 @@ struct mmci_host_ops { int (*dma_setup)(struct mmci_host *host); void (*dma_release)(struct mmci_host *host); int (*dma_start)(struct mmci_host *host, unsigned int *datactrl); + void (*dma_finalize)(struct mmci_host *host, struct mmc_data *data); }; struct mmci_host { @@ -340,3 +341,4 @@ void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data); int mmci_dmae_setup(struct mmci_host *host); void mmci_dmae_release(struct mmci_host *host); int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl); +void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data); diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index e6267ad..ba7e311 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -188,6 +188,7 @@ static struct mmci_host_ops qcom_variant_ops = { .dma_setup = qcom_dma_setup, .dma_release = mmci_dmae_release, .dma_start = mmci_dmae_start, + .dma_finalize = mmci_dmae_finalize, }; void qcom_variant_init(struct mmci_host *host) -- 2.7.4
[PATCH 07/14] mmc: mmci: add prepare/unprepare_data callbacks
From: Ludovic Barre This patch adds prepare/unprepare callbacks to mmci_host_ops. Like this mmci_pre/post_request can be generic, mmci_prepare_data and mmci_unprepare_data provide common next_cookie management. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 118 +++ drivers/mmc/host/mmci.h | 10 drivers/mmc/host/mmci_qcom_dml.c | 2 + 3 files changed, 93 insertions(+), 37 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e4d80f1..345aa2e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -58,6 +58,7 @@ static struct variant_data variant_arm = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = mmci_variant_init, }; static struct variant_data variant_arm_extended_fifo = { @@ -69,6 +70,7 @@ static struct variant_data variant_arm_extended_fifo = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = mmci_variant_init, }; static struct variant_data variant_arm_extended_fifo_hwfc = { @@ -81,6 +83,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = mmci_variant_init, }; static struct variant_data variant_u300 = { @@ -99,6 +102,7 @@ static struct variant_data variant_u300 = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_nomadik = { @@ -118,6 +122,7 @@ static struct variant_data variant_nomadik = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_ux500 = { @@ -143,6 +148,7 @@ static struct variant_data variant_ux500 = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_ux500v2 = { @@ -170,6 +176,7 @@ static struct variant_data variant_ux500v2 = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_OD, + .init = mmci_variant_init, }; static struct variant_data variant_stm32 = { @@ -187,6 +194,7 @@ static struct variant_data variant_stm32 = { .f_max = 4800, .pwrreg_clkgate = true, .pwrreg_nopower = true, + .init = mmci_variant_init, }; static struct variant_data variant_qcom = { @@ -357,6 +365,31 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) mmci_write_clkreg(host, clk); } +int mmci_prepare_data(struct mmci_host *host, struct mmc_data *data, bool next) +{ + int err; + + if (!host->ops || !host->ops->prepare_data) + return 0; + + err = host->ops->prepare_data(host, data, next); + + if (next && !err) + data->host_cookie = ++host->next_cookie < 0 ? + 1 : host->next_cookie; + + return err; +} + +void mmci_unprepare_data(struct mmci_host *host, struct mmc_data *data, +int err) +{ + if (host->ops && host->ops->unprepare_data) + host->ops->unprepare_data(host, data, err); + + data->host_cookie = 0; +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -588,9 +621,9 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) } /* prepares DMA channel and DMA descriptor, returns non-zero on failure */ -static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, - struct dma_chan **dma_chan, - struct dma_async_tx_descriptor **dma_desc) +static int __mmci_dmae_prep_data(struct mmci_host *host, struct mmc_data *data, +struct dma_chan **dma_chan, +struct dma_async_tx_descriptor **dma_desc) { struct dmaengine_priv *dmae = host->dma_priv; struct variant_data *variant = host->variant; @@ -651,22 +684,21 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, return -ENOMEM; } -static inline int mmci_dma_prepare_data(struct mmci_host *
[PATCH 09/14] mmc: mmci: modify dma_setup callback
From: Ludovic Barre This patch creates a generic mmci_dma_setup which calls dma_setup callback and manages common next_cookie. This patch is needed for sdmmc variant which has a different dma settings. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 25 + drivers/mmc/host/mmci.h | 1 + drivers/mmc/host/mmci_qcom_dml.c | 2 ++ 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 0193da6..ae47d08 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -398,6 +398,17 @@ void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) host->ops->get_next_data(host, data); } +int mmci_dma_setup(struct mmci_host *host) +{ + if (!host->ops || !host->ops->dma_setup) + return 0; + + /* initialize pre request cookie */ + host->next_cookie = 1; + + return host->ops->dma_setup(host); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -472,7 +483,7 @@ struct dmaengine_priv { #define __dmae_inprogress(dmae) ((dmae)->dma_in_progress) -static int mmci_dma_setup(struct mmci_host *host) +int mmci_dmae_setup(struct mmci_host *host) { const char *rxname, *txname; struct dmaengine_priv *dmae; @@ -488,9 +499,6 @@ static int mmci_dma_setup(struct mmci_host *host) dmae->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); - /* initialize pre request cookie */ - host->next_cookie = 1; - /* * If only an RX channel is specified, the driver will * attempt to use it bidirectionally, however if it is @@ -531,9 +539,6 @@ static int mmci_dma_setup(struct mmci_host *host) host->mmc->max_seg_size = max_seg_size; } - if (host->ops && host->ops->dma_setup) - return host->ops->dma_setup(host); - return 0; } @@ -793,14 +798,10 @@ static struct mmci_host_ops mmci_variant_ops = { .prepare_data = mmci_dmae_prepare_data, .unprepare_data = mmci_dmae_unprepare_data, .get_next_data = mmci_dmae_get_next_data, + .dma_setup = mmci_dmae_setup, }; #else /* Blank functions if the DMA engine is not available */ -static inline int mmci_dma_setup(struct mmci_host *host) -{ - return 0; -} - static inline void mmci_dma_release(struct mmci_host *host) { } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index bb1e4ba..e1b389c 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -335,3 +335,4 @@ int mmci_dmae_prepare_data(struct mmci_host *host, struct mmc_data *data, void mmci_dmae_unprepare_data(struct mmci_host *host, struct mmc_data *data, int err); void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data); +int mmci_dmae_setup(struct mmci_host *host); diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index e4c505a..47abbdd 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -126,6 +126,8 @@ static int qcom_dma_setup(struct mmci_host *host) int consumer_id, producer_id; struct device_node *np = host->mmc->parent->of_node; + mmci_dmae_setup(host); + consumer_id = of_get_dml_pipe_index(np, "tx"); producer_id = of_get_dml_pipe_index(np, "rx"); -- 2.7.4
[PATCH 03/14] mmc: mmci: internalize dma_inprogress into mmci dma functions
From: Ludovic Barre This patch internalizes the dma_inprogress into mmci dma interfaces. This allows to simplify and prepare the next dma callbacks for mmci host ops. __dma_inprogress is called in mmci_dma_data_error and mmci_dma_finalize. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 16 ++-- drivers/mmc/host/mmci.h | 4 +--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index d8fa178..8144a87 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -497,6 +497,9 @@ static void __mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) static void mmci_dma_data_error(struct mmci_host *host) { + if (!__dma_inprogress(host)) + return; + dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); dmaengine_terminate_all(host->dma_current); host->dma_in_progress = false; @@ -512,6 +515,9 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) u32 status; int i; + if (!__dma_inprogress(dmae)) + return; + /* Wait up to 1ms for the DMA to complete */ for (i = 0; ; i++) { status = readl(host->base + MMCISTATUS); @@ -903,8 +909,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, u32 remain, success; /* Terminate the DMA transfer */ - if (dma_inprogress(host)) - mmci_dma_data_error(host); + mmci_dma_data_error(host); /* * Calculate how far we are into the transfer. Note that @@ -942,8 +947,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n"); if (status & MCI_DATAEND || data->error) { - if (dma_inprogress(host)) - mmci_dma_finalize(host, data); + mmci_dma_finalize(host, data); + mmci_stop_data(host); if (!data->error) @@ -1050,8 +1055,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, if ((!sbc && !cmd->data) || cmd->error) { if (host->data) { /* Terminate the DMA transfer */ - if (dma_inprogress(host)) - mmci_dma_data_error(host); + mmci_dma_data_error(host); mmci_stop_data(host); } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 696a066..f1ec066 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -332,9 +332,7 @@ struct mmci_host { struct mmci_host_next next_data; booldma_in_progress; -#define dma_inprogress(host) ((host)->dma_in_progress) -#else -#define dma_inprogress(host) (0) +#define __dma_inprogress(host) ((host)->dma_in_progress) #endif }; -- 2.7.4
[PATCH 06/14] mmc: mmci: merge prepare data functions
From: Ludovic Barre This patch merges the prepare data functions. This allows to define a single access to prepare data service. This prepares integration for mmci host ops. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 22 +- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 5646c2e6..e4d80f1 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -651,11 +651,16 @@ static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data, return -ENOMEM; } -static inline int mmci_dma_prep_data(struct mmci_host *host, -struct mmc_data *data) +static inline int mmci_dma_prepare_data(struct mmci_host *host, + struct mmc_data *data, + bool next) { struct dmaengine_priv *dmae = host->dma_priv; + struct dmaengine_next *nd = &dmae->next_data; + if (next) + return __mmci_dma_prep_data(host, data, &nd->dma_chan, + &nd->dma_desc); /* Check if next job is already prepared. */ if (dmae->dma_current && dmae->dma_desc_current) return 0; @@ -665,22 +670,13 @@ static inline int mmci_dma_prep_data(struct mmci_host *host, &dmae->dma_desc_current); } -static inline int mmci_dma_prep_next(struct mmci_host *host, -struct mmc_data *data) -{ - struct dmaengine_priv *dmae = host->dma_priv; - struct dmaengine_next *nd = &dmae->next_data; - - return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc); -} - static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) { struct dmaengine_priv *dmae = host->dma_priv; struct mmc_data *data = host->data; int ret; - ret = mmci_dma_prep_data(host, host->data); + ret = mmci_dma_prepare_data(host, host->data, false); if (ret) return ret; @@ -737,7 +733,7 @@ static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) if (mmci_validate_data(host, data)) return; - if (!mmci_dma_prep_next(host, data)) + if (!mmci_dma_prepare_data(host, data, true)) data->host_cookie = ++host->next_cookie < 0 ? 1 : host->next_cookie; } -- 2.7.4
[PATCH 02/14] mmc: mmci: internalize dma map/unmap into mmci dma functions
From: Ludovic Barre This patch internalizes the management of dma map/unmap into mmci dma interfaces. This allows to simplify and prepare the next dma callbacks for mmci host ops. mmci_dma_unmap was called in mmci_data_irq & mmci_cmd_irq functions and can be integrated in mmci_dma_data_error. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 44 +++- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 1841d250..d8fa178 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -482,17 +482,7 @@ static inline void mmci_dma_release(struct mmci_host *host) host->dma_rx_channel = host->dma_tx_channel = NULL; } -static void mmci_dma_data_error(struct mmci_host *host) -{ - dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); - dmaengine_terminate_all(host->dma_current); - host->dma_in_progress = false; - host->dma_current = NULL; - host->dma_desc_current = NULL; - host->data->host_cookie = 0; -} - -static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) +static void __mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) { struct dma_chan *chan; @@ -505,6 +495,18 @@ static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) mmc_get_dma_dir(data)); } +static void mmci_dma_data_error(struct mmci_host *host) +{ + dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n"); + dmaengine_terminate_all(host->dma_current); + host->dma_in_progress = false; + host->dma_current = NULL; + host->dma_desc_current = NULL; + host->data->host_cookie = 0; + + __mmci_dma_unmap(host, host->data); +} + static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) { u32 status; @@ -528,11 +530,10 @@ static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) mmci_dma_data_error(host); if (!data->error) data->error = -EIO; + } else if (!data->host_cookie) { + __mmci_dma_unmap(host, data); } - if (!data->host_cookie) - mmci_dma_unmap(host, data); - /* * Use of DMA with scatter-gather is impossible. * Give up with DMA and switch back to PIO mode. @@ -704,7 +705,7 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, if (!data || !data->host_cookie) return; - mmci_dma_unmap(host, data); + __mmci_dma_unmap(host, data); if (err) { struct mmci_host_next *next = &host->next_data; @@ -742,10 +743,6 @@ static inline void mmci_dma_release(struct mmci_host *host) { } -static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data) -{ -} - static inline void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) { @@ -906,10 +903,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, u32 remain, success; /* Terminate the DMA transfer */ - if (dma_inprogress(host)) { + if (dma_inprogress(host)) mmci_dma_data_error(host); - mmci_dma_unmap(host, data); - } /* * Calculate how far we are into the transfer. Note that @@ -1055,10 +1050,9 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, if ((!sbc && !cmd->data) || cmd->error) { if (host->data) { /* Terminate the DMA transfer */ - if (dma_inprogress(host)) { + if (dma_inprogress(host)) mmci_dma_data_error(host); - mmci_dma_unmap(host, host->data); - } + mmci_stop_data(host); } mmci_request_end(host, host->mrq); -- 2.7.4
[PATCH 13/14] mmc: mmci: add dma_error callback
From: Ludovic Barre This patch adds dma_error callback at mmci_host_ops to allow to call specific variant. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 20 +++- drivers/mmc/host/mmci.h | 2 ++ drivers/mmc/host/mmci_qcom_dml.c | 1 + 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index b124a73..d5ca93e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -453,6 +453,12 @@ void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data) host->ops->dma_finalize(host, data); } +void mmci_dma_error(struct mmci_host *host) +{ + if (host->ops && host->ops->dma_error) + host->ops->dma_error(host); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -615,7 +621,7 @@ static void __mmci_dmae_unmap(struct mmci_host *host, struct mmc_data *data) mmc_get_dma_dir(data)); } -static void mmci_dma_data_error(struct mmci_host *host) +void mmci_dmae_error(struct mmci_host *host) { struct dmaengine_priv *dmae = host->dma_priv; @@ -656,7 +662,7 @@ void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data) * contiguous buffers. On TX, we'll get a FIFO underrun error. */ if (status & MCI_RXDATAAVLBLMASK) { - mmci_dma_data_error(host); + mmci_dma_error(host); if (!data->error) data->error = -EIO; } else if (!data->host_cookie) { @@ -827,13 +833,9 @@ static struct mmci_host_ops mmci_variant_ops = { .dma_release = mmci_dmae_release, .dma_start = mmci_dmae_start, .dma_finalize = mmci_dmae_finalize, + .dma_error = mmci_dmae_error, }; #else -/* Blank functions if the DMA engine is not available */ -static inline void mmci_dma_data_error(struct mmci_host *host) -{ -} - static struct mmci_host_ops mmci_variant_ops = {}; #endif @@ -1011,7 +1013,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, u32 remain, success; /* Terminate the DMA transfer */ - mmci_dma_data_error(host); + mmci_dma_error(host); /* * Calculate how far we are into the transfer. Note that @@ -1157,7 +1159,7 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, if ((!sbc && !cmd->data) || cmd->error) { if (host->data) { /* Terminate the DMA transfer */ - mmci_dma_data_error(host); + mmci_dma_error(host); mmci_stop_data(host); } diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 3f482d5..0a4811d 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -282,6 +282,7 @@ struct mmci_host_ops { void (*dma_release)(struct mmci_host *host); int (*dma_start)(struct mmci_host *host, unsigned int *datactrl); void (*dma_finalize)(struct mmci_host *host, struct mmc_data *data); + void (*dma_error)(struct mmci_host *host); }; struct mmci_host { @@ -342,3 +343,4 @@ int mmci_dmae_setup(struct mmci_host *host); void mmci_dmae_release(struct mmci_host *host); int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl); void mmci_dmae_finalize(struct mmci_host *host, struct mmc_data *data); +void mmci_dmae_error(struct mmci_host *host); diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index ba7e311..80701b4 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -189,6 +189,7 @@ static struct mmci_host_ops qcom_variant_ops = { .dma_release = mmci_dmae_release, .dma_start = mmci_dmae_start, .dma_finalize = mmci_dmae_finalize, + .dma_error = mmci_dmae_error, }; void qcom_variant_init(struct mmci_host *host) -- 2.7.4
[PATCH 11/14] mmc: mmci: add dma_start callback
From: Ludovic Barre This patch adds dma_start callback to mmci_host_ops. Create a generic mmci_dma_start function which regroup common action between variant. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 63 +++- drivers/mmc/host/mmci.h | 2 ++ drivers/mmc/host/mmci_qcom_dml.c | 1 + 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 177e2e8..642ef19 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -415,6 +415,38 @@ void mmci_dma_release(struct mmci_host *host) host->ops->dma_release(host); } +int mmci_dma_start(struct mmci_host *host, unsigned int datactrl) +{ + struct mmc_data *data = host->data; + int ret; + + ret = mmci_prepare_data(host, data, false); + if (ret) + return ret; + + if (!host->ops || !host->ops->dma_start) + return -EINVAL; + + /* Okay, go for it. */ + dev_vdbg(mmc_dev(host->mmc), +"Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", +data->sg_len, data->blksz, data->blocks, data->flags); + + host->ops->dma_start(host, &datactrl); + + /* Trigger the DMA transfer */ + mmci_write_datactrlreg(host, datactrl); + + /* +* Let the MMCI say when the data is ended and it's time +* to fire next DMA request. When that happens, MMCI will +* call mmci_data_end() +*/ + writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, + host->base + MMCIMASK0); + return 0; +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -721,20 +753,11 @@ int mmci_dmae_prepare_data(struct mmci_host *host, &dmae->dma_desc_current); } -static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) +int mmci_dmae_start(struct mmci_host *host, unsigned int *datactrl) { struct dmaengine_priv *dmae = host->dma_priv; struct mmc_data *data = host->data; - int ret; - - ret = mmci_prepare_data(host, host->data, false); - if (ret) - return ret; - /* Okay, go for it. */ - dev_vdbg(mmc_dev(host->mmc), -"Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n", -data->sg_len, data->blksz, data->blocks, data->flags); dmae->dma_in_progress = true; dmaengine_submit(dmae->dma_desc_current); dma_async_issue_pending(dmae->dma_current); @@ -742,18 +765,8 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) if (host->variant->qcom_dml) dml_start_xfer(host, data); - datactrl |= MCI_DPSM_DMAENABLE; - - /* Trigger the DMA transfer */ - mmci_write_datactrlreg(host, datactrl); + *datactrl |= MCI_DPSM_DMAENABLE; - /* -* Let the MMCI say when the data is ended and it's time -* to fire next DMA request. When that happens, MMCI will -* call mmci_data_end() -*/ - writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK, - host->base + MMCIMASK0); return 0; } @@ -806,6 +819,7 @@ static struct mmci_host_ops mmci_variant_ops = { .get_next_data = mmci_dmae_get_next_data, .dma_setup = mmci_dmae_setup, .dma_release = mmci_dmae_release, + .dma_start = mmci_dmae_start, }; #else /* Blank functions if the DMA engine is not available */ @@ -818,11 +832,6 @@ static inline void mmci_dma_data_error(struct mmci_host *host) { } -static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) -{ - return -ENOSYS; -} - static struct mmci_host_ops mmci_variant_ops = {}; #endif @@ -925,7 +934,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) * Attempt to use DMA operation mode, if this * should fail, fall back to PIO mode */ - if (!mmci_dma_start_data(host, datactrl)) + if (!mmci_dma_start(host, datactrl)) return; /* IRQ mode, map the SG list for CPU reading/writing */ diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index f961f90..3a200a9 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -280,6 +280,7 @@ struct mmci_host_ops { void (*get_next_data)(struct mmci_host *host, struct mmc_data *data); int (*dma_setup)(struct mmci_host *host); void (*dma_release)(struct mmci_host *host); + int (*dma_start)(struct mmci_host *host, unsigned int *datactrl); }; struct mmci_host { @@ -338,3 +339,4 @@ void mmci_dmae_unprepare_data(struct mmci_host *host, void mmci_dmae_get_next_data(str
[PATCH 14/14] mmc: mmci: add validate_data callback
From: Ludovic Barre This patch adds validate_data callback at mmci_host_ops to check specific constraints of variant. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 39 +-- drivers/mmc/host/mmci.h | 1 + 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index d5ca93e..7ba2f61 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -234,24 +234,6 @@ static int mmci_card_busy(struct mmc_host *mmc) return busy; } -/* - * Validate mmc prerequisites - */ -static int mmci_validate_data(struct mmci_host *host, - struct mmc_data *data) -{ - if (!data) - return 0; - - if (!is_power_of_2(data->blksz)) { - dev_err(mmc_dev(host->mmc), - "unsupported block size (%d bytes)\n", data->blksz); - return -EINVAL; - } - - return 0; -} - static void mmci_reg_delay(struct mmci_host *host) { /* @@ -365,6 +347,27 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) mmci_write_clkreg(host, clk); } +/* + * Validate mmc prerequisites + */ +static int mmci_validate_data(struct mmci_host *host, + struct mmc_data *data) +{ + if (!data) + return 0; + + if (!is_power_of_2(data->blksz)) { + dev_err(mmc_dev(host->mmc), + "unsupported block size (%d bytes)\n", data->blksz); + return -EINVAL; + } + + if (host->ops && host->ops->validate_data) + return host->ops->validate_data(host, data); + + return 0; +} + int mmci_prepare_data(struct mmci_host *host, struct mmc_data *data, bool next) { int err; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 0a4811d..10b71bf 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -273,6 +273,7 @@ struct variant_data { /* mmci variant callbacks */ struct mmci_host_ops { + int (*validate_data)(struct mmci_host *host, struct mmc_data *data); int (*prepare_data)(struct mmci_host *host, struct mmc_data *data, bool next); void (*unprepare_data)(struct mmci_host *host, struct mmc_data *data, -- 2.7.4
[PATCH 08/14] mmc: mmci: add get_next_data callback
From: Ludovic Barre This patch adds get_next_data callback to mmci_host_ops. Generic mmci_get_next_data factorizes next_cookie check and the host ops call. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 16 ++-- drivers/mmc/host/mmci.h | 2 ++ drivers/mmc/host/mmci_qcom_dml.c | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 345aa2e..0193da6 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -390,6 +390,14 @@ void mmci_unprepare_data(struct mmci_host *host, struct mmc_data *data, data->host_cookie = 0; } +void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) +{ + WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); + + if (host->ops && host->ops->get_next_data) + host->ops->get_next_data(host, data); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -738,12 +746,11 @@ static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl) return 0; } -static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) +void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data) { struct dmaengine_priv *dmae = host->dma_priv; struct dmaengine_next *next = &dmae->next_data; - WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan)); dmae->dma_desc_current = next->dma_desc; @@ -785,13 +792,10 @@ void mmci_dmae_unprepare_data(struct mmci_host *host, static struct mmci_host_ops mmci_variant_ops = { .prepare_data = mmci_dmae_prepare_data, .unprepare_data = mmci_dmae_unprepare_data, + .get_next_data = mmci_dmae_get_next_data, }; #else /* Blank functions if the DMA engine is not available */ -static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) -{ -} - static inline int mmci_dma_setup(struct mmci_host *host) { return 0; diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index fa2702b..bb1e4ba 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -277,6 +277,7 @@ struct mmci_host_ops { bool next); void (*unprepare_data)(struct mmci_host *host, struct mmc_data *data, int err); + void (*get_next_data)(struct mmci_host *host, struct mmc_data *data); int (*dma_setup)(struct mmci_host *host); }; @@ -333,3 +334,4 @@ int mmci_dmae_prepare_data(struct mmci_host *host, struct mmc_data *data, bool next); void mmci_dmae_unprepare_data(struct mmci_host *host, struct mmc_data *data, int err); +void mmci_dmae_get_next_data(struct mmci_host *host, struct mmc_data *data); diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index d534fa1..e4c505a 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -182,6 +182,7 @@ static int qcom_dma_setup(struct mmci_host *host) static struct mmci_host_ops qcom_variant_ops = { .prepare_data = mmci_dmae_prepare_data, .unprepare_data = mmci_dmae_unprepare_data, + .get_next_data = mmci_dmae_get_next_data, .dma_setup = qcom_dma_setup, }; -- 2.7.4
[PATCH 01/14] mmc: mmci: fix qcom dma issue during mmci init with new dma_setup callback
From: Ludovic Barre This patch fixes qcom dma issue during mmci init. Like init callback of qcom variant is not set, the qcom dma is not correctly initialized and fail while dma transfer ("buggy DMA detected. Taking evasive action"). Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 1 + drivers/mmc/host/mmci.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 71e9336..1841d250 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -208,6 +208,7 @@ static struct variant_data variant_qcom = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = qcom_variant_init, }; /* Busy detection for the ST Micro variant */ diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 517591d..696a066 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -338,3 +338,4 @@ struct mmci_host { #endif }; +void qcom_variant_init(struct mmci_host *host); -- 2.7.4
[PATCH 00/14] mmc: mmci: prepare dma callbacks with mmci_host_ops
From: Ludovic Barre This patch series prepares and adds callbacks for dma transfert at mmci_host_ops. This series is composed of 3 parts: -Internalize specific needs of legacy dmaengine. -Create and setup dma_priv pointer -Create generic callbacks which share some features (like cookie...) and call specific needs This patch series must be applied on top of "mmc: mmci: Add and implement a ->dma_setup() callback for qcom dml" Ludovic Barre (14): mmc: mmci: fix qcom dma issue during mmci init with new dma_setup callback mmc: mmci: internalize dma map/unmap into mmci dma functions mmc: mmci: internalize dma_inprogress into mmci dma functions mmc: mmci: introduce dma_priv pointer to mmci_host mmc: mmci: move mmci next cookie to mci host mmc: mmci: merge prepare data functions mmc: mmci: add prepare/unprepare_data callbacks mmc: mmci: add get_next_data callback mmc: mmci: modify dma_setup callback mmc: mmci: add dma_release callback mmc: mmci: add dma_start callback mmc: mmci: add dma_finalize callback mmc: mmci: add dma_error callback mmc: mmci: add validate_data callback drivers/mmc/host/mmci.c | 458 --- drivers/mmc/host/mmci.h | 45 ++-- drivers/mmc/host/mmci_qcom_dml.c | 15 +- 3 files changed, 322 insertions(+), 196 deletions(-) -- 2.7.4
[PATCH 05/14] mmc: mmci: move mmci next cookie to mci host
From: Ludovic Barre This patch moves next cookie to mmci host structure to share same cookie management between all variants. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 10 -- drivers/mmc/host/mmci.h | 2 ++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index bdc48c3..5646c2e6 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -418,7 +418,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) struct dmaengine_next { struct dma_async_tx_descriptor *dma_desc; struct dma_chan *dma_chan; - s32 cookie; }; struct dmaengine_priv { @@ -449,7 +448,7 @@ static int mmci_dma_setup(struct mmci_host *host) "tx"); /* initialize pre request cookie */ - dmae->next_data.cookie = 1; + host->next_cookie = 1; /* * If only an RX channel is specified, the driver will @@ -716,7 +715,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) struct dmaengine_priv *dmae = host->dma_priv; struct dmaengine_next *next = &dmae->next_data; - WARN_ON(data->host_cookie && data->host_cookie != next->cookie); + WARN_ON(data->host_cookie && data->host_cookie != host->next_cookie); WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan)); dmae->dma_desc_current = next->dma_desc; @@ -728,9 +727,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) { struct mmci_host *host = mmc_priv(mmc); - struct dmaengine_priv *dmae = host->dma_priv; struct mmc_data *data = mrq->data; - struct dmaengine_next *nd = &dmae->next_data; if (!data) return; @@ -741,7 +738,8 @@ static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq) return; if (!mmci_dma_prep_next(host, data)) - data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie; + data->host_cookie = ++host->next_cookie < 0 ? + 1 : host->next_cookie; } static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 260a1de..d2ec4fd 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -318,6 +318,8 @@ struct mmci_host { int (*get_rx_fifocnt)(struct mmci_host *h, u32 status, int remain); void*dma_priv; + + s32 next_cookie; }; void qcom_variant_init(struct mmci_host *host); -- 2.7.4
Re: [PATCH 01/14] mmc: mmci: fix qcom dma issue during mmci init with new dma_setup callback
On 08/01/2018 12:08 PM, Ulf Hansson wrote: Anyway, we can just drop this patch from your series as I amended the patch causing the problem. I will continue to review the rest. yes, I sent to early. (sorry) BR Ludo
Re: [PATCH 02/19] mmc: mmci: merge qcom dml feature into mmci dma
On 07/05/2018 05:26 PM, Ulf Hansson wrote: On 12 June 2018 at 15:14, Ludovic Barre wrote: From: Ludovic Barre This patch integrates qcom dml feature into mmci_dma file. Qualcomm Data Mover lite/local is already a variant of mmci dmaengine. Signed-off-by: Ludovic Barre --- drivers/mmc/host/Makefile| 1 - drivers/mmc/host/mmci.c | 1 - drivers/mmc/host/mmci.h | 35 drivers/mmc/host/mmci_dma.c | 135 - drivers/mmc/host/mmci_qcom_dml.c | 177 --- drivers/mmc/host/mmci_qcom_dml.h | 31 --- 6 files changed, 169 insertions(+), 211 deletions(-) delete mode 100644 drivers/mmc/host/mmci_qcom_dml.c delete mode 100644 drivers/mmc/host/mmci_qcom_dml.h No, this is not the way to go. Instead I I think there are two options. 1) Keep mmci_qcom_dml.c|h and thus add new files for the stm32 dma variant. 2) Start by renaming mmci_qcom_dml.* to mmc_dma.* and then in the next step add the code for stm32 dma into the renamed files. I guess if there is some overlap in functionality, 2) may be best as it could easier avoid open coding. However, I am fine with whatever option and I expect that you knows what is best. After patch 01 & 05 comments: I will try to define a mmci_ops which contain some functions pointer called by mmci.c (core). A variant defines its mmci_ops. where do you define the specific function: -in a single file, mmci-ops.c or other (for the name, I'm not inspirated) -or in specific file for each variant mmci-qcom.c or mmci-stm32.c following the comment (above), I think we define a single file? Kind regards Uffe diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index daecaa98..608a020 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o armmmci-y := mmci.o mmci_dma.o -armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 8868be0..7a15afd 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -43,7 +43,6 @@ #include "mmci.h" #include "mmci_dma.h" -#include "mmci_qcom_dml.h" #define DRIVER_NAME "mmci-pl18x" diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index a73bb98..f7cba35 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -194,6 +194,41 @@ #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain" +/* QCOM DML Registers */ +#define DML_CONFIG 0x00 +#define PRODUCER_CRCI_MSK GENMASK(1, 0) +#define PRODUCER_CRCI_DISABLE 0 +#define PRODUCER_CRCI_X_SELBIT(0) +#define PRODUCER_CRCI_Y_SELBIT(1) +#define CONSUMER_CRCI_MSK GENMASK(3, 2) +#define CONSUMER_CRCI_DISABLE 0 +#define CONSUMER_CRCI_X_SELBIT(2) +#define CONSUMER_CRCI_Y_SELBIT(3) +#define PRODUCER_TRANS_END_EN BIT(4) +#define BYPASS BIT(16) +#define DIRECT_MODEBIT(17) +#define INFINITE_CONS_TRANSBIT(18) + +#define DML_SW_RESET 0x08 +#define DML_PRODUCER_START 0x0c +#define DML_CONSUMER_START 0x10 +#define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14 +#define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18 +#define DML_PIPE_ID0x1c +#define PRODUCER_PIPE_ID_SHFT 0 +#define PRODUCER_PIPE_ID_MSK GENMASK(4, 0) +#define CONSUMER_PIPE_ID_SHFT 16 +#define CONSUMER_PIPE_ID_MSK GENMASK(20, 16) + +#define DML_PRODUCER_BAM_BLOCK_SIZE0x24 +#define DML_PRODUCER_BAM_TRANS_SIZE0x28 + +/* other definitions */ +#define PRODUCER_PIPE_LOGICAL_SIZE 4096 +#define CONSUMER_PIPE_LOGICAL_SIZE 4096 + +#define DML_OFFSET 0x800 + struct clk; struct dma_chan; diff --git a/drivers/mmc/host/mmci_dma.c b/drivers/mmc/host/mmci_dma.c index 98a542d..dd7dae5 100644 --- a/drivers/mmc/host/mmci_dma.c +++ b/drivers/mmc/host/mmci_dma.c @@ -8,11 +8,11 @@ #include #include #include +#include #include #include "mmci.h" #include "mmci_dma.h" -#include "mmci_qcom_dml.h" int mmci_dma_setup(struct mmci_host *host) { @@ -101,6 +101,139 @@ struct dmaengine_priv { #define dma_inprogress(dmae) ((dmae)->dma_in_progress) +#ifdef CONFIG_MMC_QCOM_DML +void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) +{ + u32 config; + void __iomem *base = host->base + DML_OFFSET; + + if (data->flags & MMC_DATA_READ) { + /* Read operation: configure DML for producer operation */ + /* Set producer CRCI-x and disable consumer CRCI */ +
Re: [PATCH 01/19] mmc: mmci: regroup and define dma operations
On 07/11/2018 02:16 PM, Ulf Hansson wrote: On 11 July 2018 at 11:41, Ludovic BARRE wrote: On 07/05/2018 05:17 PM, Ulf Hansson wrote: On 12 June 2018 at 15:14, Ludovic Barre wrote: From: Ludovic Barre Prepare mmci driver to manage dma interface by new property. This patch defines and regroups dma operations for mmci drivers. mmci_dma_XX prototypes are added to call member of mmci_dma_ops if not null. Based on legacy need, a mmci dma interface has been defined with: -mmci_dma_setup -mmci_dma_release -mmci_dma_pre_req -mmci_dma_start -mmci_dma_finalize -mmci_dma_post_req -mmci_dma_error -mmci_dma_get_next_data As I suggested for one of the other patches, I would rather turn core mmci functions into library functions, which can be either invoked from variant callbacks or assigned directly to them. In other words, I would leave the functions that you move in this patch to stay in mmci.c. Although some needs to be re-factored and we also needs to make some of them available to be called from another file, hence the functions needs to be shared via mmci.h rather than being declared static. In previous exchange mail "STM32MP1 SDMMC driver review" we are said: -dma variant à should fit in Qualcomm implementation, reuse (rename) mmci_qcom_dml.c file and integrate ST dma in. Apologize if I may have lead you in a wrong direction, that was not my intent. However, by looking at $subject patch, your seems to be unnecessarily shuffling code around. I would like to avoid that. stm32 sdmmc has an internal dma, no need to use dmaengine API; So some modifications in mmci (pre/post request, mmci_dma_xx). perhaps should be done with an ops or not. Yes. The Qualcomm variant is also using an internal DMA, hence I thought there may be something we could re-use, or at least have some new common ops for. It's not crystal clear for me. Do you always agree with a dma ops which allow to address different DMA transfer: -with dmaengine API -sdmmc idma, without dmaengine API -... If we can use a mmci ops callback to manage the variant differences, that would be perfect. That combined with making the existing DMA functions in mmci.c converted to "library" functions, which the mmci ops callbacks can call, in order to re-use code. When that isn't really suitable, we may need to add a "quirk" instead, which would be specific for that particular variant. Along the lines of what we already do for variant specifics inside mmci.c. I think we have to decide on case by case basis, what fits best. Hope this makes a better explanation. If not, please tell, and I can take an initial stab and post a patch to show you with code how I mean to move forward. Let me take a concrete example on how I would move forward, hopefully that explains it a bit better. Please see below. [...] -/* - * All the DMA operation mode stuff goes inside this ifdef. - * This assumes that you have a generic DMA device interface, - * no custom DMA interfaces are supported. - */ -#ifdef CONFIG_DMA_ENGINE -static void mmci_dma_setup(struct mmci_host *host) -{ - const char *rxname, *txname; - struct variant_data *variant = host->variant; - - host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); - host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); - - /* initialize pre request cookie */ - host->next_data.cookie = 1; - - /* -* If only an RX channel is specified, the driver will -* attempt to use it bidirectionally, however if it is -* is specified but cannot be located, DMA will be disabled. -*/ - if (host->dma_rx_channel && !host->dma_tx_channel) - host->dma_tx_channel = host->dma_rx_channel; - - if (host->dma_rx_channel) - rxname = dma_chan_name(host->dma_rx_channel); - else - rxname = "none"; - - if (host->dma_tx_channel) - txname = dma_chan_name(host->dma_tx_channel); - else - txname = "none"; - - dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n", -rxname, txname); - - /* -* Limit the maximum segment size in any SG entry according to -* the parameters of the DMA engine device. -*/ - if (host->dma_tx_channel) { - struct device *dev = host->dma_tx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - - if (max_seg_size < host->mmc->max_seg_size) - host->mmc->max_seg_size = max_seg_size; - } - if (host->dma_rx_channel) { - struct device *dev = host->dma_rx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - -
Re: [PATCH 02/19] mmc: mmci: merge qcom dml feature into mmci dma
On 07/13/2018 01:17 PM, Ulf Hansson wrote: On 11 July 2018 at 17:19, Ludovic BARRE wrote: On 07/05/2018 05:26 PM, Ulf Hansson wrote: On 12 June 2018 at 15:14, Ludovic Barre wrote: From: Ludovic Barre This patch integrates qcom dml feature into mmci_dma file. Qualcomm Data Mover lite/local is already a variant of mmci dmaengine. Signed-off-by: Ludovic Barre --- drivers/mmc/host/Makefile| 1 - drivers/mmc/host/mmci.c | 1 - drivers/mmc/host/mmci.h | 35 drivers/mmc/host/mmci_dma.c | 135 - drivers/mmc/host/mmci_qcom_dml.c | 177 --- drivers/mmc/host/mmci_qcom_dml.h | 31 --- 6 files changed, 169 insertions(+), 211 deletions(-) delete mode 100644 drivers/mmc/host/mmci_qcom_dml.c delete mode 100644 drivers/mmc/host/mmci_qcom_dml.h No, this is not the way to go. Instead I I think there are two options. 1) Keep mmci_qcom_dml.c|h and thus add new files for the stm32 dma variant. 2) Start by renaming mmci_qcom_dml.* to mmc_dma.* and then in the next step add the code for stm32 dma into the renamed files. I guess if there is some overlap in functionality, 2) may be best as it could easier avoid open coding. However, I am fine with whatever option and I expect that you knows what is best. After patch 01 & 05 comments: I will try to define a mmci_ops which contain some functions pointer called by mmci.c (core). A variant defines its mmci_ops. where do you define the specific function: -in a single file, mmci-ops.c or other (for the name, I'm not inspirated) -or in specific file for each variant mmci-qcom.c or mmci-stm32.c following the comment (above), I think we define a single file? If I understand the question, the problem is how we should assign the mmc host ops, which corresponds to the probed variant data!? I took a stub at it and posted two patches which I think you should be able to build upon. Please have a look. I review your patch on mmci_host_ops and init, I agree with your series, I was going in the same direction. The comment above was on file organization, what do you prefer? -a single file with: all callback and all mmci_host_ops of each variant -or each variant in specific file (like sdhci): mmci-qcom.c | mmci-stm32.c ... [...] Kind regards Uffe
[PATCH v4 4/7] ARM: stm32: add initial support for STM32MP157
From: Ludovic Barre This patch adds initial support of STM32MP157 microprocessor (MPU) based on Arm Cortex-A7. New Cortex-A infrastructure (gic, timer,...) are selected if ARCH_MULTI_V7 is defined. Signed-off-by: Ludovic Barre --- Documentation/arm/stm32/stm32mp157-overview.rst | 19 +++ arch/arm/mach-stm32/Kconfig | 11 +++ arch/arm/mach-stm32/board-dt.c | 1 + 3 files changed, 31 insertions(+) create mode 100644 Documentation/arm/stm32/stm32mp157-overview.rst diff --git a/Documentation/arm/stm32/stm32mp157-overview.rst b/Documentation/arm/stm32/stm32mp157-overview.rst new file mode 100644 index 000..62e176d --- /dev/null +++ b/Documentation/arm/stm32/stm32mp157-overview.rst @@ -0,0 +1,19 @@ +STM32MP157 Overview +=== + +Introduction + + +The STM32MP157 is a Cortex-A MPU aimed at various applications. +It features: + +- Dual core Cortex-A7 application core +- 2D/3D image composition with GPU +- Standard memories interface support +- Standard connectivity, widely inherited from the STM32 MCU family +- Comprehensive security support + +:Authors: + +- Ludovic Barre +- Gerald Baeza diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig index fb4b8b8..6b65df1 100644 --- a/arch/arm/mach-stm32/Kconfig +++ b/arch/arm/mach-stm32/Kconfig @@ -1,6 +1,9 @@ menuconfig ARCH_STM32 bool "STMicroelectronics STM32 family" if ARM_SINGLE_ARMV7M || ARCH_MULTI_V7 select ARMV7M_SYSTICK if ARM_SINGLE_ARMV7M + select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 + select ARM_GIC if ARCH_MULTI_V7 + select ARM_PSCI if ARCH_MULTI_V7 select ARCH_HAS_RESET_CONTROLLER select CLKSRC_STM32 select PINCTRL @@ -31,4 +34,12 @@ config MACH_STM32H743 endif # ARMv7-M +if ARCH_MULTI_V7 + +config MACH_STM32MP157 + bool "STMicroelectronics STM32MP157" + default y + +endif # ARMv7-A + endif diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c index 4a258eb..d4e58ea 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -12,6 +12,7 @@ static const char *const stm32_compat[] __initconst = { "st,stm32f469", "st,stm32f746", "st,stm32h743", + "st,stm32mp157", NULL }; -- 2.7.4
[PATCH v4 1/7] Documentation: arm: stm32: move to rst format
From: Ludovic Barre This patch rewrites stm32 documentation to rst (ReStructuredText) format. Signed-off-by: Ludovic Barre --- Documentation/arm/stm32/overview.rst | 31 +++ Documentation/arm/stm32/overview.txt | 33 - Documentation/arm/stm32/stm32f429-overview.rst | 26 Documentation/arm/stm32/stm32f429-overview.txt | 22 - Documentation/arm/stm32/stm32f746-overview.rst | 33 + Documentation/arm/stm32/stm32f746-overview.txt | 34 -- Documentation/arm/stm32/stm32h743-overview.rst | 34 ++ Documentation/arm/stm32/stm32h743-overview.txt | 30 --- 8 files changed, 124 insertions(+), 119 deletions(-) create mode 100644 Documentation/arm/stm32/overview.rst delete mode 100644 Documentation/arm/stm32/overview.txt create mode 100644 Documentation/arm/stm32/stm32f429-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f429-overview.txt create mode 100644 Documentation/arm/stm32/stm32f746-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f746-overview.txt create mode 100644 Documentation/arm/stm32/stm32h743-overview.rst delete mode 100644 Documentation/arm/stm32/stm32h743-overview.txt diff --git a/Documentation/arm/stm32/overview.rst b/Documentation/arm/stm32/overview.rst new file mode 100644 index 000..6be6059 --- /dev/null +++ b/Documentation/arm/stm32/overview.rst @@ -0,0 +1,31 @@ + +STM32 ARM Linux Overview + + +Introduction + + +The STMicroelectronics family of Cortex-M based MCUs are supported by the +'STM32' platform of ARM Linux. Currently only the STM32F429 (Cortex-M4) +and STM32F746 (Cortex-M7) are supported. + +Configuration +- + +A generic configuration is provided for STM32 family, and can be used as the +default by +make stm32_defconfig + +Layout +-- + +All the files for multiple machine families are located in the platform code +contained in arch/arm/mach-stm32 + +There is a generic board board-dt.c in the mach folder which support +Flattened Device Tree, which means, it works with any compatible board with +Device Trees. + +:Authors: + +Maxime Coquelin diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt deleted file mode 100644 index a03b035..000 --- a/Documentation/arm/stm32/overview.txt +++ /dev/null @@ -1,33 +0,0 @@ - STM32 ARM Linux Overview - - -Introduction - - - The STMicroelectronics family of Cortex-M based MCUs are supported by the - 'STM32' platform of ARM Linux. Currently only the STM32F429 (Cortex-M4) - and STM32F746 (Cortex-M7) are supported. - - -Configuration -- - - A generic configuration is provided for STM32 family, and can be used as the - default by - make stm32_defconfig - -Layout --- - - All the files for multiple machine families are located in the platform code - contained in arch/arm/mach-stm32 - - There is a generic board board-dt.c in the mach folder which support - Flattened Device Tree, which means, it works with any compatible board with - Device Trees. - - -Document Author - - Maxime Coquelin diff --git a/Documentation/arm/stm32/stm32f429-overview.rst b/Documentation/arm/stm32/stm32f429-overview.rst new file mode 100644 index 000..18feda9 --- /dev/null +++ b/Documentation/arm/stm32/stm32f429-overview.rst @@ -0,0 +1,26 @@ +STM32F429 Overview +== + +Introduction + + +The STM32F429 is a Cortex-M4 MCU aimed at various applications. +It features: + +- ARM Cortex-M4 up to 180MHz with FPU +- 2MB internal Flash Memory +- External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND) +- I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers +- LCD controller & Camera interface +- Cryptographic processor + +Resources +- + +Datasheet and reference manual are publicly available on ST website (STM32F429_). + +.. _STM32F429: http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013 + +:Authors: + +Maxime Coquelin diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt deleted file mode 100644 index 5206822..000 --- a/Documentation/arm/stm32/stm32f429-overview.txt +++ /dev/null @@ -1,22 +0,0 @@ - STM32F429 Overview - == - - Introduction - - The STM32F429 is a Cortex-M4 MCU aimed at various applications. - It features: - - ARM Cortex-M4 up to 180MHz with FPU - - 2MB internal Flash Memory - - External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND) - - I2C, SPI, SAI, CAN, USB OTG, Ethernet c
[PATCH v4 6/7] ARM: dts: stm32: add stm32mp157c initial support
From: Ludovic Barre Add stm32mp157c initial support with: -Dual Cortex-A7 -Arm psci, timer, gic -Pinctrl -Uart Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 172 ++ arch/arm/boot/dts/stm32mp157c.dtsi| 194 ++ 2 files changed, 366 insertions(+) create mode 100644 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi create mode 100644 arch/arm/boot/dts/stm32mp157c.dtsi diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi new file mode 100644 index 000..440276a --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +#include + +/ { + soc { + pinctrl: pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32mp157-pinctrl"; + ranges = <0 0x50002000 0xa400>; + pins-are-numbered; + + gpioa: gpio@50002000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x0 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOA"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@50003000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x1000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOB"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@50004000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x2000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOC"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@50005000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x3000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOD"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@50006000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x4000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOE"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@50007000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x5000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOF"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 80 16>; + }; + + gpiog: gpio@50008000 { +
[PATCH v4 3/7] dt-bindings: stm32: add support of STM32MP157
From: Ludovic Barre This patch adds STM32MP157 SoC bindings. Signed-off-by: Ludovic Barre Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/arm/stm32.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/stm32.txt b/Documentation/devicetree/bindings/arm/stm32.txt index 05762b0..6808ed9 100644 --- a/Documentation/devicetree/bindings/arm/stm32.txt +++ b/Documentation/devicetree/bindings/arm/stm32.txt @@ -7,3 +7,4 @@ using one of the following compatible strings: st,stm32f469 st,stm32f746 st,stm32h743 + st,stm32mp157 -- 2.7.4
[PATCH v4 2/7] ARM: stm32: prepare stm32 family to welcome armv7 architecture
From: Ludovic Barre This patch prepares the STM32 machine for the integration of Cortex-A based microprocessor (MPU), on top of the existing Cortex-M microcontroller family (MCU). Since both MCUs and MPUs are sharing common hardware blocks we can keep using ARCH_STM32 flag for most of them. If a hardware block is specific to one family we can use either ARM_SINGLE_ARMV7M or ARCH_MULTI_V7 flag. Signed-off-by: Ludovic Barre --- Documentation/arm/stm32/overview.rst | 15 +-- arch/arm/mach-stm32/Kconfig | 27 +++ arch/arm/mach-stm32/board-dt.c | 4 +--- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Documentation/arm/stm32/overview.rst b/Documentation/arm/stm32/overview.rst index 6be6059..85cfc84 100644 --- a/Documentation/arm/stm32/overview.rst +++ b/Documentation/arm/stm32/overview.rst @@ -5,16 +5,17 @@ STM32 ARM Linux Overview Introduction -The STMicroelectronics family of Cortex-M based MCUs are supported by the -'STM32' platform of ARM Linux. Currently only the STM32F429 (Cortex-M4) -and STM32F746 (Cortex-M7) are supported. +The STMicroelectronics STM32 family of Cortex-A microprocessors (MPUs) and +Cortex-M microcontrollers (MCUs) are supported by the 'STM32' platform of +ARM Linux. Configuration - -A generic configuration is provided for STM32 family, and can be used as the -default by +For MCUs, use the provided default configuration: make stm32_defconfig +For MPUs, use multi_v7 configuration: +make multi_v7_defconfig Layout -- @@ -28,4 +29,6 @@ Device Trees. :Authors: -Maxime Coquelin +- Maxime Coquelin +- Ludovic Barre +- Gerald Baeza diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig index 0d1889b..fb4b8b8 100644 --- a/arch/arm/mach-stm32/Kconfig +++ b/arch/arm/mach-stm32/Kconfig @@ -1,8 +1,7 @@ -config ARCH_STM32 - bool "STMicrolectronics STM32" - depends on ARM_SINGLE_ARMV7M +menuconfig ARCH_STM32 + bool "STMicroelectronics STM32 family" if ARM_SINGLE_ARMV7M || ARCH_MULTI_V7 + select ARMV7M_SYSTICK if ARM_SINGLE_ARMV7M select ARCH_HAS_RESET_CONTROLLER - select ARMV7M_SYSTICK select CLKSRC_STM32 select PINCTRL select RESET_CONTROLLER @@ -10,22 +9,26 @@ config ARCH_STM32 help Support for STMicroelectronics STM32 processors. +if ARCH_STM32 + +if ARM_SINGLE_ARMV7M + config MACH_STM32F429 - bool "STMicrolectronics STM32F429" - depends on ARCH_STM32 + bool "STMicroelectronics STM32F429" default y config MACH_STM32F469 - bool "STMicrolectronics STM32F469" - depends on ARCH_STM32 + bool "STMicroelectronics STM32F469" default y config MACH_STM32F746 - bool "STMicrolectronics STM32F746" - depends on ARCH_STM32 + bool "STMicroelectronics STM32F746" default y config MACH_STM32H743 - bool "STMicrolectronics STM32H743" - depends on ARCH_STM32 + bool "STMicroelectronics STM32H743" default y + +endif # ARMv7-M + +endif diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c index e918686..4a258eb 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Maxime Coquelin 2015 * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 */ #include -#include #include static const char *const stm32_compat[] __initconst = { @@ -18,5 +17,4 @@ static const char *const stm32_compat[] __initconst = { DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)") .dt_compat = stm32_compat, - .restart = armv7m_restart, MACHINE_END -- 2.7.4
[PATCH v4 7/7] ARM: dts: stm32: add initial support of stm32mp157c eval board
From: Ludovic Barre Add support of stm32mp157c evaluation board (part number: STM32MP157C-EV1) split in 2 elements: -Daughter board (part number: STM32MP157C-ED1) which includes CPU, memory and power supply -Mother board (part number: STM32MP157C-EM1) which includes external peripherals (like display, camera,...) and extension connectors. The daughter board can run alone, this is why the device tree files are split in two layers, for the complete evaluation board (ev1) and for the daughter board alone (ed1). Signed-off-by: Ludovic Barre Signed-off-by: Alexandre Torgue --- arch/arm/boot/dts/Makefile| 6 -- arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 13 + arch/arm/boot/dts/stm32mp157c-ed1.dts | 32 +++ arch/arm/boot/dts/stm32mp157c-ev1.dts | 21 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 arch/arm/boot/dts/stm32mp157c-ed1.dts create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index d0381e9..d72c71c 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -839,7 +839,7 @@ dtb-$(CONFIG_ARCH_STI) += \ stih410-b2120.dtb \ stih410-b2260.dtb \ stih418-b2199.dtb -dtb-$(CONFIG_ARCH_STM32)+= \ +dtb-$(CONFIG_ARCH_STM32) += \ stm32f429-disco.dtb \ stm32f469-disco.dtb \ stm32f746-disco.dtb \ @@ -847,7 +847,9 @@ dtb-$(CONFIG_ARCH_STM32)+= \ stm32429i-eval.dtb \ stm32746g-eval.dtb \ stm32h743i-eval.dtb \ - stm32h743i-disco.dtb + stm32h743i-disco.dtb \ + stm32mp157c-ed1.dtb \ + stm32mp157c-ev1.dtb dtb-$(CONFIG_MACH_SUN4I) += \ sun4i-a10-a1000.dtb \ sun4i-a10-ba10-tvbox.dtb \ diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi index 440276a..7ac65f4 100644 --- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi @@ -145,6 +145,19 @@ ngpios = <8>; gpio-ranges = <&pinctrl 0 160 8>; }; + + uart4_pins_a: uart4@0 { + pins1 { + pinmux = ; /* UART4_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = ; /* UART4_RX */ + bias-disable; + }; + }; }; pinctrl_z: pin-controller-z { diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts new file mode 100644 index 000..f52eba9 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157c.dtsi" +#include "stm32mp157-pinctrl.dtsi" + +/ { + model = "STMicroelectronics STM32MP157C eval daughter"; + compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial3:115200n8"; + }; + + memory { + reg = <0xC000 0x4000>; + }; + + aliases { + serial3 = &uart4; + }; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins_a>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts new file mode 100644 index 000..d7dc9bb --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157c-ed1.dts" + +/ { + model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; + compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial3:115200n8"; + }; + + aliases { + serial3 = &uart4; + }; +}; -- 2.7.4
[PATCH v4 5/7] ARM: configs: multi_v7: add stm32 support
From: Ludovic Barre This patch adds stm32 support to multi_v7_defconfig Signed-off-by: Ludovic Barre --- arch/arm/configs/multi_v7_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 11e648a..a0163e7 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -77,6 +77,7 @@ CONFIG_ARCH_SPEAR13XX=y CONFIG_MACH_SPEAR1310=y CONFIG_MACH_SPEAR1340=y CONFIG_ARCH_STI=y +CONFIG_ARCH_STM32=y CONFIG_ARCH_EXYNOS=y CONFIG_EXYNOS5420_MCPM=y CONFIG_ARCH_RENESAS=y @@ -324,6 +325,8 @@ CONFIG_SERIAL_CONEXANT_DIGICOLOR=y CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE=y CONFIG_SERIAL_ST_ASC=y CONFIG_SERIAL_ST_ASC_CONSOLE=y +CONFIG_SERIAL_STM32=y +CONFIG_SERIAL_STM32_CONSOLE=y CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_ST=y -- 2.7.4
[PATCH v4 0/7] ARM: stm32: add initial STM32MPU support
From: Ludovic Barre This patch series extends the existing STM32 microcontrollers (MCUs) family to microprocessors (MPUs). The MPU platform (based on Arm Cortex-A) is a continuation of the MCU one (based on Arm Cortex-M) in that it shares a wide number of hardware blocks. change v4: -Add all available uarts in stm32mp157c -Move uart aliases to board files change v3: -Remove bootargs -Remove armv7m_restart and Share stm32_compat for mcu/mpu -Modify stm32 kconfig with Arnd template -Remove patch below (Linus W: Patch applied) devicetree: bindings: Document supported STM32 SoC family pinctrl: stm32: Add STM32MP157 MPU support change V2: -Add stm32 documentation in this serie to avoid merge conflict thread: "https://patchwork.kernel.org/patch/10102573/";; -Split bindings (stm32.txt) to separate patches. -Remove ARCH_STM32_MCU/MPU flags -Adopt rst format for Documentation/arm/stm32 files -s/STMicrolectronics/STMicroelectronics/g Ludovic Barre (7): Documentation: arm: stm32: move to rst format ARM: stm32: prepare stm32 family to welcome armv7 architecture dt-bindings: stm32: add support of STM32MP157 ARM: stm32: add initial support for STM32MP157 ARM: configs: multi_v7: add stm32 support ARM: dts: stm32: add stm32mp157c initial support ARM: dts: stm32: add initial support of stm32mp157c eval board Documentation/arm/stm32/overview.rst| 34 + Documentation/arm/stm32/overview.txt| 33 Documentation/arm/stm32/stm32f429-overview.rst | 26 Documentation/arm/stm32/stm32f429-overview.txt | 22 --- Documentation/arm/stm32/stm32f746-overview.rst | 33 Documentation/arm/stm32/stm32f746-overview.txt | 34 - Documentation/arm/stm32/stm32h743-overview.rst | 34 + Documentation/arm/stm32/stm32h743-overview.txt | 30 Documentation/arm/stm32/stm32mp157-overview.rst | 19 +++ Documentation/devicetree/bindings/arm/stm32.txt | 1 + arch/arm/boot/dts/Makefile | 6 +- arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 185 ++ arch/arm/boot/dts/stm32mp157c-ed1.dts | 32 arch/arm/boot/dts/stm32mp157c-ev1.dts | 21 +++ arch/arm/boot/dts/stm32mp157c.dtsi | 194 arch/arm/configs/multi_v7_defconfig | 3 + arch/arm/mach-stm32/Kconfig | 38 +++-- arch/arm/mach-stm32/board-dt.c | 5 +- 18 files changed, 614 insertions(+), 136 deletions(-) create mode 100644 Documentation/arm/stm32/overview.rst delete mode 100644 Documentation/arm/stm32/overview.txt create mode 100644 Documentation/arm/stm32/stm32f429-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f429-overview.txt create mode 100644 Documentation/arm/stm32/stm32f746-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f746-overview.txt create mode 100644 Documentation/arm/stm32/stm32h743-overview.rst delete mode 100644 Documentation/arm/stm32/stm32h743-overview.txt create mode 100644 Documentation/arm/stm32/stm32mp157-overview.rst create mode 100644 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi create mode 100644 arch/arm/boot/dts/stm32mp157c-ed1.dts create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1.dts create mode 100644 arch/arm/boot/dts/stm32mp157c.dtsi -- 2.7.4
Re: [PATCH v4 7/7] ARM: dts: stm32: add initial support of stm32mp157c eval board
On 01/16/2018 03:25 PM, Arnd Bergmann wrote: On Tue, Jan 16, 2018 at 3:12 PM, Ludovic Barre wrote: + + aliases { + serial3 = &uart4; + }; Why 'serial3' ? If you have multiple UARTS on this board, just list all of them, otherwise start with 'serial0'. Arnd sorry, I fix that :-( BR Ludo
[PATCH v5 3/7] dt-bindings: stm32: add support of STM32MP157
From: Ludovic Barre This patch adds STM32MP157 SoC bindings. Signed-off-by: Ludovic Barre Reviewed-by: Rob Herring --- Documentation/devicetree/bindings/arm/stm32.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/stm32.txt b/Documentation/devicetree/bindings/arm/stm32.txt index 05762b0..6808ed9 100644 --- a/Documentation/devicetree/bindings/arm/stm32.txt +++ b/Documentation/devicetree/bindings/arm/stm32.txt @@ -7,3 +7,4 @@ using one of the following compatible strings: st,stm32f469 st,stm32f746 st,stm32h743 + st,stm32mp157 -- 2.7.4
[PATCH v5 6/7] ARM: dts: stm32: add stm32mp157c initial support
From: Ludovic Barre Add stm32mp157c initial support with: -Dual Cortex-A7 -Arm psci, timer, gic -Pinctrl -Uart Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 172 ++ arch/arm/boot/dts/stm32mp157c.dtsi| 194 ++ 2 files changed, 366 insertions(+) create mode 100644 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi create mode 100644 arch/arm/boot/dts/stm32mp157c.dtsi diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi new file mode 100644 index 000..440276a --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +#include + +/ { + soc { + pinctrl: pin-controller { + #address-cells = <1>; + #size-cells = <1>; + compatible = "st,stm32mp157-pinctrl"; + ranges = <0 0x50002000 0xa400>; + pins-are-numbered; + + gpioa: gpio@50002000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x0 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOA"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 0 16>; + }; + + gpiob: gpio@50003000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x1000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOB"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 16 16>; + }; + + gpioc: gpio@50004000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x2000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOC"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 32 16>; + }; + + gpiod: gpio@50005000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x3000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOD"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 48 16>; + }; + + gpioe: gpio@50006000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x4000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOE"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 64 16>; + }; + + gpiof: gpio@50007000 { + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + reg = <0x5000 0x400>; + clocks = <&clk_pll3_p>; + st,bank-name = "GPIOF"; + ngpios = <16>; + gpio-ranges = <&pinctrl 0 80 16>; + }; + + gpiog: gpio@50008000 { +
[PATCH v5 4/7] ARM: stm32: add initial support for STM32MP157
From: Ludovic Barre This patch adds initial support of STM32MP157 microprocessor (MPU) based on Arm Cortex-A7. New Cortex-A infrastructure (gic, timer,...) are selected if ARCH_MULTI_V7 is defined. Signed-off-by: Ludovic Barre --- Documentation/arm/stm32/stm32mp157-overview.rst | 19 +++ arch/arm/mach-stm32/Kconfig | 11 +++ arch/arm/mach-stm32/board-dt.c | 1 + 3 files changed, 31 insertions(+) create mode 100644 Documentation/arm/stm32/stm32mp157-overview.rst diff --git a/Documentation/arm/stm32/stm32mp157-overview.rst b/Documentation/arm/stm32/stm32mp157-overview.rst new file mode 100644 index 000..62e176d --- /dev/null +++ b/Documentation/arm/stm32/stm32mp157-overview.rst @@ -0,0 +1,19 @@ +STM32MP157 Overview +=== + +Introduction + + +The STM32MP157 is a Cortex-A MPU aimed at various applications. +It features: + +- Dual core Cortex-A7 application core +- 2D/3D image composition with GPU +- Standard memories interface support +- Standard connectivity, widely inherited from the STM32 MCU family +- Comprehensive security support + +:Authors: + +- Ludovic Barre +- Gerald Baeza diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig index fb4b8b8..6b65df1 100644 --- a/arch/arm/mach-stm32/Kconfig +++ b/arch/arm/mach-stm32/Kconfig @@ -1,6 +1,9 @@ menuconfig ARCH_STM32 bool "STMicroelectronics STM32 family" if ARM_SINGLE_ARMV7M || ARCH_MULTI_V7 select ARMV7M_SYSTICK if ARM_SINGLE_ARMV7M + select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 + select ARM_GIC if ARCH_MULTI_V7 + select ARM_PSCI if ARCH_MULTI_V7 select ARCH_HAS_RESET_CONTROLLER select CLKSRC_STM32 select PINCTRL @@ -31,4 +34,12 @@ config MACH_STM32H743 endif # ARMv7-M +if ARCH_MULTI_V7 + +config MACH_STM32MP157 + bool "STMicroelectronics STM32MP157" + default y + +endif # ARMv7-A + endif diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c index 4a258eb..d4e58ea 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -12,6 +12,7 @@ static const char *const stm32_compat[] __initconst = { "st,stm32f469", "st,stm32f746", "st,stm32h743", + "st,stm32mp157", NULL }; -- 2.7.4
[PATCH v5 5/7] ARM: configs: multi_v7: add stm32 support
From: Ludovic Barre This patch adds stm32 support to multi_v7_defconfig Signed-off-by: Ludovic Barre --- arch/arm/configs/multi_v7_defconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 11e648a..a0163e7 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -77,6 +77,7 @@ CONFIG_ARCH_SPEAR13XX=y CONFIG_MACH_SPEAR1310=y CONFIG_MACH_SPEAR1340=y CONFIG_ARCH_STI=y +CONFIG_ARCH_STM32=y CONFIG_ARCH_EXYNOS=y CONFIG_EXYNOS5420_MCPM=y CONFIG_ARCH_RENESAS=y @@ -324,6 +325,8 @@ CONFIG_SERIAL_CONEXANT_DIGICOLOR=y CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE=y CONFIG_SERIAL_ST_ASC=y CONFIG_SERIAL_ST_ASC_CONSOLE=y +CONFIG_SERIAL_STM32=y +CONFIG_SERIAL_STM32_CONSOLE=y CONFIG_VIRTIO_CONSOLE=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_ST=y -- 2.7.4
[PATCH v5 1/7] Documentation: arm: stm32: move to rst format
From: Ludovic Barre This patch rewrites stm32 documentation to rst (ReStructuredText) format. Signed-off-by: Ludovic Barre --- Documentation/arm/stm32/overview.rst | 31 +++ Documentation/arm/stm32/overview.txt | 33 - Documentation/arm/stm32/stm32f429-overview.rst | 26 Documentation/arm/stm32/stm32f429-overview.txt | 22 - Documentation/arm/stm32/stm32f746-overview.rst | 33 + Documentation/arm/stm32/stm32f746-overview.txt | 34 -- Documentation/arm/stm32/stm32h743-overview.rst | 34 ++ Documentation/arm/stm32/stm32h743-overview.txt | 30 --- 8 files changed, 124 insertions(+), 119 deletions(-) create mode 100644 Documentation/arm/stm32/overview.rst delete mode 100644 Documentation/arm/stm32/overview.txt create mode 100644 Documentation/arm/stm32/stm32f429-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f429-overview.txt create mode 100644 Documentation/arm/stm32/stm32f746-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f746-overview.txt create mode 100644 Documentation/arm/stm32/stm32h743-overview.rst delete mode 100644 Documentation/arm/stm32/stm32h743-overview.txt diff --git a/Documentation/arm/stm32/overview.rst b/Documentation/arm/stm32/overview.rst new file mode 100644 index 000..6be6059 --- /dev/null +++ b/Documentation/arm/stm32/overview.rst @@ -0,0 +1,31 @@ + +STM32 ARM Linux Overview + + +Introduction + + +The STMicroelectronics family of Cortex-M based MCUs are supported by the +'STM32' platform of ARM Linux. Currently only the STM32F429 (Cortex-M4) +and STM32F746 (Cortex-M7) are supported. + +Configuration +- + +A generic configuration is provided for STM32 family, and can be used as the +default by +make stm32_defconfig + +Layout +-- + +All the files for multiple machine families are located in the platform code +contained in arch/arm/mach-stm32 + +There is a generic board board-dt.c in the mach folder which support +Flattened Device Tree, which means, it works with any compatible board with +Device Trees. + +:Authors: + +Maxime Coquelin diff --git a/Documentation/arm/stm32/overview.txt b/Documentation/arm/stm32/overview.txt deleted file mode 100644 index a03b035..000 --- a/Documentation/arm/stm32/overview.txt +++ /dev/null @@ -1,33 +0,0 @@ - STM32 ARM Linux Overview - - -Introduction - - - The STMicroelectronics family of Cortex-M based MCUs are supported by the - 'STM32' platform of ARM Linux. Currently only the STM32F429 (Cortex-M4) - and STM32F746 (Cortex-M7) are supported. - - -Configuration -- - - A generic configuration is provided for STM32 family, and can be used as the - default by - make stm32_defconfig - -Layout --- - - All the files for multiple machine families are located in the platform code - contained in arch/arm/mach-stm32 - - There is a generic board board-dt.c in the mach folder which support - Flattened Device Tree, which means, it works with any compatible board with - Device Trees. - - -Document Author - - Maxime Coquelin diff --git a/Documentation/arm/stm32/stm32f429-overview.rst b/Documentation/arm/stm32/stm32f429-overview.rst new file mode 100644 index 000..18feda9 --- /dev/null +++ b/Documentation/arm/stm32/stm32f429-overview.rst @@ -0,0 +1,26 @@ +STM32F429 Overview +== + +Introduction + + +The STM32F429 is a Cortex-M4 MCU aimed at various applications. +It features: + +- ARM Cortex-M4 up to 180MHz with FPU +- 2MB internal Flash Memory +- External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND) +- I2C, SPI, SAI, CAN, USB OTG, Ethernet controllers +- LCD controller & Camera interface +- Cryptographic processor + +Resources +- + +Datasheet and reference manual are publicly available on ST website (STM32F429_). + +.. _STM32F429: http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1577/LN1806?ecmp=stm32f429-439_pron_pr-ces2014_nov2013 + +:Authors: + +Maxime Coquelin diff --git a/Documentation/arm/stm32/stm32f429-overview.txt b/Documentation/arm/stm32/stm32f429-overview.txt deleted file mode 100644 index 5206822..000 --- a/Documentation/arm/stm32/stm32f429-overview.txt +++ /dev/null @@ -1,22 +0,0 @@ - STM32F429 Overview - == - - Introduction - - The STM32F429 is a Cortex-M4 MCU aimed at various applications. - It features: - - ARM Cortex-M4 up to 180MHz with FPU - - 2MB internal Flash Memory - - External memory support through FMC controller (PSRAM, SDRAM, NOR, NAND) - - I2C, SPI, SAI, CAN, USB OTG, Ethernet c
[PATCH v5 0/7] ARM: stm32: add initial STM32MPU support
From: Ludovic Barre This patch series extends the existing STM32 microcontrollers (MCUs) family to microprocessors (MPUs). The MPU platform (based on Arm Cortex-A) is a continuation of the MCU one (based on Arm Cortex-M) in that it shares a wide number of hardware blocks. change v5: -fix serial3 aliases by serial0 change v4: -Add all available uarts in stm32mp157c -Move uart aliases to board files change v3: -Remove bootargs -Remove armv7m_restart and Share stm32_compat for mcu/mpu -Modify stm32 kconfig with Arnd template -Remove patch below (Linus W: Patch applied) devicetree: bindings: Document supported STM32 SoC family pinctrl: stm32: Add STM32MP157 MPU support change V2: -Add stm32 documentation in this serie to avoid merge conflict thread: "https://patchwork.kernel.org/patch/10102573/";; -Split bindings (stm32.txt) to separate patches. -Remove ARCH_STM32_MCU/MPU flags -Adopt rst format for Documentation/arm/stm32 files -s/STMicrolectronics/STMicroelectronics/g Ludovic Barre (7): Documentation: arm: stm32: move to rst format ARM: stm32: prepare stm32 family to welcome armv7 architecture dt-bindings: stm32: add support of STM32MP157 ARM: stm32: add initial support for STM32MP157 ARM: configs: multi_v7: add stm32 support ARM: dts: stm32: add stm32mp157c initial support ARM: dts: stm32: add initial support of stm32mp157c eval board Documentation/arm/stm32/overview.rst| 34 + Documentation/arm/stm32/overview.txt| 33 Documentation/arm/stm32/stm32f429-overview.rst | 26 Documentation/arm/stm32/stm32f429-overview.txt | 22 --- Documentation/arm/stm32/stm32f746-overview.rst | 33 Documentation/arm/stm32/stm32f746-overview.txt | 34 - Documentation/arm/stm32/stm32h743-overview.rst | 34 + Documentation/arm/stm32/stm32h743-overview.txt | 30 Documentation/arm/stm32/stm32mp157-overview.rst | 19 +++ Documentation/devicetree/bindings/arm/stm32.txt | 1 + arch/arm/boot/dts/Makefile | 6 +- arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 185 ++ arch/arm/boot/dts/stm32mp157c-ed1.dts | 32 arch/arm/boot/dts/stm32mp157c-ev1.dts | 21 +++ arch/arm/boot/dts/stm32mp157c.dtsi | 194 arch/arm/configs/multi_v7_defconfig | 3 + arch/arm/mach-stm32/Kconfig | 38 +++-- arch/arm/mach-stm32/board-dt.c | 5 +- 18 files changed, 614 insertions(+), 136 deletions(-) create mode 100644 Documentation/arm/stm32/overview.rst delete mode 100644 Documentation/arm/stm32/overview.txt create mode 100644 Documentation/arm/stm32/stm32f429-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f429-overview.txt create mode 100644 Documentation/arm/stm32/stm32f746-overview.rst delete mode 100644 Documentation/arm/stm32/stm32f746-overview.txt create mode 100644 Documentation/arm/stm32/stm32h743-overview.rst delete mode 100644 Documentation/arm/stm32/stm32h743-overview.txt create mode 100644 Documentation/arm/stm32/stm32mp157-overview.rst create mode 100644 arch/arm/boot/dts/stm32mp157-pinctrl.dtsi create mode 100644 arch/arm/boot/dts/stm32mp157c-ed1.dts create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1.dts create mode 100644 arch/arm/boot/dts/stm32mp157c.dtsi -- 2.7.4
[PATCH v5 7/7] ARM: dts: stm32: add initial support of stm32mp157c eval board
From: Ludovic Barre Add support of stm32mp157c evaluation board (part number: STM32MP157C-EV1) split in 2 elements: -Daughter board (part number: STM32MP157C-ED1) which includes CPU, memory and power supply -Mother board (part number: STM32MP157C-EM1) which includes external peripherals (like display, camera,...) and extension connectors. The daughter board can run alone, this is why the device tree files are split in two layers, for the complete evaluation board (ev1) and for the daughter board alone (ed1). Signed-off-by: Ludovic Barre Signed-off-by: Alexandre Torgue --- arch/arm/boot/dts/Makefile| 6 -- arch/arm/boot/dts/stm32mp157-pinctrl.dtsi | 13 + arch/arm/boot/dts/stm32mp157c-ed1.dts | 32 +++ arch/arm/boot/dts/stm32mp157c-ev1.dts | 21 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 arch/arm/boot/dts/stm32mp157c-ed1.dts create mode 100644 arch/arm/boot/dts/stm32mp157c-ev1.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index d0381e9..d72c71c 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -839,7 +839,7 @@ dtb-$(CONFIG_ARCH_STI) += \ stih410-b2120.dtb \ stih410-b2260.dtb \ stih418-b2199.dtb -dtb-$(CONFIG_ARCH_STM32)+= \ +dtb-$(CONFIG_ARCH_STM32) += \ stm32f429-disco.dtb \ stm32f469-disco.dtb \ stm32f746-disco.dtb \ @@ -847,7 +847,9 @@ dtb-$(CONFIG_ARCH_STM32)+= \ stm32429i-eval.dtb \ stm32746g-eval.dtb \ stm32h743i-eval.dtb \ - stm32h743i-disco.dtb + stm32h743i-disco.dtb \ + stm32mp157c-ed1.dtb \ + stm32mp157c-ev1.dtb dtb-$(CONFIG_MACH_SUN4I) += \ sun4i-a10-a1000.dtb \ sun4i-a10-ba10-tvbox.dtb \ diff --git a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi index 440276a..7ac65f4 100644 --- a/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp157-pinctrl.dtsi @@ -145,6 +145,19 @@ ngpios = <8>; gpio-ranges = <&pinctrl 0 160 8>; }; + + uart4_pins_a: uart4@0 { + pins1 { + pinmux = ; /* UART4_TX */ + bias-disable; + drive-push-pull; + slew-rate = <0>; + }; + pins2 { + pinmux = ; /* UART4_RX */ + bias-disable; + }; + }; }; pinctrl_z: pin-controller-z { diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts new file mode 100644 index 000..ee2b17b --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157c.dtsi" +#include "stm32mp157-pinctrl.dtsi" + +/ { + model = "STMicroelectronics STM32MP157C eval daughter"; + compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0xC000 0x4000>; + }; + + aliases { + serial0 = &uart4; + }; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&uart4_pins_a>; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts new file mode 100644 index 000..0723f17 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved + * Author: Ludovic Barre for STMicroelectronics. + */ +/dts-v1/; + +#include "stm32mp157c-ed1.dts" + +/ { + model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; + compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + aliases { + serial0 = &uart4; + }; +}; -- 2.7.4
[PATCH v5 2/7] ARM: stm32: prepare stm32 family to welcome armv7 architecture
From: Ludovic Barre This patch prepares the STM32 machine for the integration of Cortex-A based microprocessor (MPU), on top of the existing Cortex-M microcontroller family (MCU). Since both MCUs and MPUs are sharing common hardware blocks we can keep using ARCH_STM32 flag for most of them. If a hardware block is specific to one family we can use either ARM_SINGLE_ARMV7M or ARCH_MULTI_V7 flag. Signed-off-by: Ludovic Barre --- Documentation/arm/stm32/overview.rst | 15 +-- arch/arm/mach-stm32/Kconfig | 27 +++ arch/arm/mach-stm32/board-dt.c | 4 +--- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Documentation/arm/stm32/overview.rst b/Documentation/arm/stm32/overview.rst index 6be6059..85cfc84 100644 --- a/Documentation/arm/stm32/overview.rst +++ b/Documentation/arm/stm32/overview.rst @@ -5,16 +5,17 @@ STM32 ARM Linux Overview Introduction -The STMicroelectronics family of Cortex-M based MCUs are supported by the -'STM32' platform of ARM Linux. Currently only the STM32F429 (Cortex-M4) -and STM32F746 (Cortex-M7) are supported. +The STMicroelectronics STM32 family of Cortex-A microprocessors (MPUs) and +Cortex-M microcontrollers (MCUs) are supported by the 'STM32' platform of +ARM Linux. Configuration - -A generic configuration is provided for STM32 family, and can be used as the -default by +For MCUs, use the provided default configuration: make stm32_defconfig +For MPUs, use multi_v7 configuration: +make multi_v7_defconfig Layout -- @@ -28,4 +29,6 @@ Device Trees. :Authors: -Maxime Coquelin +- Maxime Coquelin +- Ludovic Barre +- Gerald Baeza diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig index 0d1889b..fb4b8b8 100644 --- a/arch/arm/mach-stm32/Kconfig +++ b/arch/arm/mach-stm32/Kconfig @@ -1,8 +1,7 @@ -config ARCH_STM32 - bool "STMicrolectronics STM32" - depends on ARM_SINGLE_ARMV7M +menuconfig ARCH_STM32 + bool "STMicroelectronics STM32 family" if ARM_SINGLE_ARMV7M || ARCH_MULTI_V7 + select ARMV7M_SYSTICK if ARM_SINGLE_ARMV7M select ARCH_HAS_RESET_CONTROLLER - select ARMV7M_SYSTICK select CLKSRC_STM32 select PINCTRL select RESET_CONTROLLER @@ -10,22 +9,26 @@ config ARCH_STM32 help Support for STMicroelectronics STM32 processors. +if ARCH_STM32 + +if ARM_SINGLE_ARMV7M + config MACH_STM32F429 - bool "STMicrolectronics STM32F429" - depends on ARCH_STM32 + bool "STMicroelectronics STM32F429" default y config MACH_STM32F469 - bool "STMicrolectronics STM32F469" - depends on ARCH_STM32 + bool "STMicroelectronics STM32F469" default y config MACH_STM32F746 - bool "STMicrolectronics STM32F746" - depends on ARCH_STM32 + bool "STMicroelectronics STM32F746" default y config MACH_STM32H743 - bool "STMicrolectronics STM32H743" - depends on ARCH_STM32 + bool "STMicroelectronics STM32H743" default y + +endif # ARMv7-M + +endif diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c index e918686..4a258eb 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) Maxime Coquelin 2015 * Author: Maxime Coquelin - * License terms: GNU General Public License (GPL), version 2 */ #include -#include #include static const char *const stm32_compat[] __initconst = { @@ -18,5 +17,4 @@ static const char *const stm32_compat[] __initconst = { DT_MACHINE_START(STM32DT, "STM32 (Device Tree Support)") .dt_compat = stm32_compat, - .restart = armv7m_restart, MACHINE_END -- 2.7.4
Re: [PATCH V2 2/2] mmc: mmci: add variant property to send stop cmd if a command fail
hi Ulf due to some ST internal works, I will busy the next days. But I will sent the change as soon as possible. On 11/21/18 6:56 PM, Ulf Hansson wrote: On 7 November 2018 at 10:30, Ludovic Barre wrote: From: Ludovic Barre The mmc framework follows the requirement of SD_Specification: the STOP_TRANSMISSION is sent on multiple write/read commands and the stop command (alone), not needed on other ADTC commands. But, if an error happens on command or data transmission, some variants require a stop command "STOP_TRANSMISION" to clear the DPSM "Data Path State Machine". If it's not done the next data command freezes hardware block. Needed to support the STM32 sdmmc variant. May I suggest some re-wording of this changelog, as to make it more clear of why this is needed. Something along the lines of: "The current approach with sending a CMD12 (STOP_TRANSMISSION) to complete a data transfer request, either because of using the open ended transmission type or because of receiving an error during a data transfer, isn't sufficient for the STM32 sdmmc variant. More precisely, for STM32 sdmmc the DPSM ("Data Path State Machine" ) needs to be cleared by sending a CMD12, also for the so called ADTC commands. For this reason, add a new mmci variant property and let the driver send a CMD12 to complete ADTC commands, in case it's set." I will change, it's more accurate and concise, thanks for re-wording Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 33 + drivers/mmc/host/mmci.h | 4 2 files changed, 37 insertions(+) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 13fa640..47b865d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,8 @@ void sdmmc_variant_init(struct mmci_host *host); #else static inline void sdmmc_variant_init(struct mmci_host *host) {} #endif +static void +mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c); static unsigned int fmax = 515633; @@ -274,6 +277,7 @@ static struct variant_data variant_stm32_sdmmc = { .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, @@ -573,6 +577,24 @@ void mmci_dma_error(struct mmci_host *host) static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { + /* +* If an error happens on command or data transmission, some variants +* require a stop command to reinit the DPSM. +* If it's not done the next data command freeze hardware block. +*/ + if (host->variant->cmdreg_stop) { + u32 dpsm; + + dpsm = readl_relaxed(host->base + MMCISTATUS); + dpsm &= MCI_STM32_DPSMACTIVE; + + if (dpsm && ((mrq->cmd && mrq->cmd->error) || +(mrq->data && mrq->data->error))) { + mmci_start_command(host, &host->stop_abort, 0); + return; + } I would rather move this code to a separate function. OK Also, I think you need something else (or additional) than polling the MMCISTATUS register, as in principle you could end up sending CMD12 several times for the same request, which isn't correct. In mmci_request_end, if the DPSM is still enabled, there was no previous "cmd12" sent. So Normally, the regular and special cmd12 can't be sent for the same request. To me the best solution would probably be to make use of the host->data pointer, as it becomes set when DPSM has been enabled. However, host->data is also cleared in mmci_stop_data() which is being called prior mmci_request_end(). In other words, we need to figure under what conditions the new code above should be triggered/called and then also change the conditions for when mmci_request_end() shall be called. In principle look at callers of mmci_request_end() and mmci_stop_data() and update those paths. + } + writel(0, host->base + MMCICOMMAND); BUG_ON(host->data); @@ -1100,6 +1122,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) mmci_reg_delay(host); } + if (host->variant->cmdreg_stop && + cmd->opcode == MMC_STOP_TRANSMISSION) + c |= host->variant->cmdreg_stop; + Hmm. It looks like the above changes, together with the introduction of t
Re: [PATCH V2 1/2] mmc: mmci: send stop command if sbc error issue
On 12/5/18 3:23 PM, Ulf Hansson wrote: On Tue, 20 Nov 2018 at 10:42, Ulf Hansson wrote: On 7 November 2018 at 10:30, Ludovic Barre wrote: From: Ludovic Barre Refer to "4.15 set block count command" of sd specification: Host needs to issue CMD12 if any error is detected in the CMD18 and CMD25 operations. In sbc case, the data->stop is fill by framework. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 82bab35..13fa640 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1190,11 +1190,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, /* The error clause is handled above, success! */ data->bytes_xfered = data->blksz * data->blocks; - if (!data->stop || host->mrq->sbc) { + if (!data->stop || (host->mrq->sbc && !data->error)) mmci_request_end(host, data->mrq); - } else { + else mmci_start_command(host, data->stop, 0); This looks correct to me! Although, just wanted to double check that you tested this for a case where we have host->mrq->sbc set and got an error in data->error? I guess it can be tricky, so I was thinking of manually trying to instruct the code, to set an error in data->error, at some point to trigger this code. That would at least give us some confidence that it works as expected. I did some manual tests to trigger the error path. As far as I can tell, it works as expected and I observes that the core is able to recover and re-send the request. [...] So, I have added my tested-by tag and applied this for next. Thanks! In regards to patch2/2 I am awaiting your update. Kind regards Uffe
Re: [PATCH V2 1/2] mmc: mmci: send stop command if sbc error issue
On 12/5/18 3:23 PM, Ulf Hansson wrote: On Tue, 20 Nov 2018 at 10:42, Ulf Hansson wrote: On 7 November 2018 at 10:30, Ludovic Barre wrote: From: Ludovic Barre Refer to "4.15 set block count command" of sd specification: Host needs to issue CMD12 if any error is detected in the CMD18 and CMD25 operations. In sbc case, the data->stop is fill by framework. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 82bab35..13fa640 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1190,11 +1190,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, /* The error clause is handled above, success! */ data->bytes_xfered = data->blksz * data->blocks; - if (!data->stop || host->mrq->sbc) { + if (!data->stop || (host->mrq->sbc && !data->error)) mmci_request_end(host, data->mrq); - } else { + else mmci_start_command(host, data->stop, 0); This looks correct to me! Although, just wanted to double check that you tested this for a case where we have host->mrq->sbc set and got an error in data->error? I guess it can be tricky, so I was thinking of manually trying to instruct the code, to set an error in data->error, at some point to trigger this code. That would at least give us some confidence that it works as expected. I did some manual tests to trigger the error path. As far as I can tell, it works as expected and I observes that the core is able to recover and re-send the request. Ulf, very thanks for the tests, and sorry for my busy status. I will send as soon as possible the 2/2 with your recommendation (I will more spare time for upstream) [...] So, I have added my tested-by tag and applied this for next. Thanks! In regards to patch2/2 I am awaiting your update. Kind regards Uffe
[PATCH V3 0/2] mmc: mmci: add stop command
From: Ludovic Barre This patch series adds variant property to: -Set cmdstop bit on STOP_TRANSMISSION command. -On command or data error, send a stop command. to clear DPSM if it's yet activated. change v3: -Move the cmdstop bit in separate patch. -Use Ulf re-wording for patch 2/2. -Move specific part in a separate function. Ludovic Barre (2): mmc: mmci: add variant property to set command stop bit mmc: mmci: send stop command to clear the dpsm drivers/mmc/host/mmci.c | 43 +++ drivers/mmc/host/mmci.h | 4 2 files changed, 47 insertions(+) -- 2.7.4
[PATCH V3 1/2] mmc: mmci: add variant property to set command stop bit
From: Ludovic Barre On cmd12 (STOP_TRANSMISSION), STM32 sdmmc variant needs to set cmdstop bit in command register. The CPSM ("Command Path State Machine") treats the command as a Stop Transmission command and signals abort to the DPSM ("Data Path State Machine"). Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 6 ++ drivers/mmc/host/mmci.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 13fa640..e352f5a 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -274,6 +275,7 @@ static struct variant_data variant_stm32_sdmmc = { .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, @@ -1100,6 +1102,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) mmci_reg_delay(host); } + if (host->variant->cmdreg_stop && + cmd->opcode == MMC_STOP_TRANSMISSION) + c |= host->variant->cmdreg_stop; + c |= cmd->opcode | host->variant->cmdreg_cpsm_enable; if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_136) diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 550dd39..2422909 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -264,6 +264,7 @@ struct mmci_host; * @cmdreg_lrsp_crc: enable value for long response with crc * @cmdreg_srsp_crc: enable value for short response with crc * @cmdreg_srsp: enable value for short response without crc + * @cmdreg_stop: enable value for stop and abort transmission * @datalength_bits: number of bits in the MMCIDATALENGTH register * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY * is asserted (likewise for RX) @@ -316,6 +317,7 @@ struct variant_data { unsigned intcmdreg_lrsp_crc; unsigned intcmdreg_srsp_crc; unsigned intcmdreg_srsp; + unsigned intcmdreg_stop; unsigned intdatalength_bits; unsigned intfifosize; unsigned intfifohalfsize; -- 2.7.4
[PATCH V3 2/2] mmc: mmci: send stop command to clear the dpsm
From: Ludovic Barre The current approach with sending a CMD12 (STOP_TRANSMISSION) to complete a data transfer request, either because of using the open ended transmission type or because of receiving an error during a data transfer, isn't sufficient for the STM32 sdmmc variant. More precisely, for STM32 sdmmc the DPSM ("Data Path State Machine") needs to be cleared by sending a CMD12, also for the so called ADTC commands. For this reason, let the driver send a CMD12 to complete ADTC commands, in case it's set (depend of cmdreg_stop variant property). Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 37 + drivers/mmc/host/mmci.h | 2 ++ 2 files changed, 39 insertions(+) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e352f5a..4e5643d 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -58,6 +58,8 @@ void sdmmc_variant_init(struct mmci_host *host); #else static inline void sdmmc_variant_init(struct mmci_host *host) {} #endif +static void +mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c); static unsigned int fmax = 515633; @@ -572,9 +574,37 @@ void mmci_dma_error(struct mmci_host *host) host->ops->dma_error(host); } +static int mmci_stop_command(struct mmci_host *host, struct mmc_request *mrq) +{ + u32 dpsm; + + /* +* If an error happens on command or data transmission +* the DPSM stay enabled. The CPSM required a stop command +* to reinitialize the DPSM. +*/ + dpsm = readl_relaxed(host->base + MMCISTATUS); + dpsm &= MCI_STM32_DPSMACTIVE; + + if (dpsm && ((mrq->cmd && mrq->cmd->error) || +(mrq->data && mrq->data->error))) { + mmci_start_command(host, &host->stop_abort, 0); + return -EBUSY; + } + + return 0; +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { + /* +* For variant with cmdstop bit, a stop command could be needed +* to finish the request. +*/ + if (host->variant->cmdreg_stop && mmci_stop_command(host, mrq)) + return; + writel(0, host->base + MMCICOMMAND); BUG_ON(host->data); @@ -1956,6 +1986,13 @@ static int mmci_probe(struct amba_device *dev, mmc->max_busy_timeout = 0; } + /* prepare the stop command, used to abort and reinitialized the DPSM */ + if (variant->cmdreg_stop) { + host->stop_abort.opcode = MMC_STOP_TRANSMISSION; + host->stop_abort.arg = 0; + host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; + } + mmc->ops = &mmci_ops; /* We support these PM capabilities. */ diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 2422909..35372cd 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -161,6 +161,7 @@ #define MCI_ST_CEATAEND(1 << 23) #define MCI_ST_CARDBUSY(1 << 24) /* Extended status bits for the STM32 variants */ +#define MCI_STM32_DPSMACTIVE BIT(12) #define MCI_STM32_BUSYD0 BIT(20) #define MMCICLEAR 0x038 @@ -377,6 +378,7 @@ struct mmci_host { void __iomem*base; struct mmc_request *mrq; struct mmc_command *cmd; + struct mmc_command stop_abort; struct mmc_data *data; struct mmc_host *mmc; struct clk *clk; -- 2.7.4
Re: [PATCH 00/19] mmc: mmci: add stm32 sdmmc variant
hi Ulf I know that you very busy on other task, but did you have time to look my serie. do you have first feedback ? BR Ludo On 06/12/2018 03:14 PM, Ludovic Barre wrote: From: Ludovic Barre This patch series adapts mmci driver to add support for stm32 sdmmc variant. stm32h7 SoC integrates the first revision of stm32 sdmmc. This series is composed of 3 parts: -Prepare mmci driver to manage dma interfaces by adding property. New mmci dma API is defined according to the legacy needs. -Adapt mmci driver to dedicated constraints of stm32 sdmmc variant, defined under some specific properties. -Add stm32 sdmmc variant. As Internal DMA way satisfies data transfer, the mmci driver hasn't been modified for pio_read/write. Specific adds-ons to stm32 sdmmc: + registers + clk/power functions + idma interface Ludovic Barre (19): mmc: mmci: regroup and define dma operations mmc: mmci: merge qcom dml feature into mmci dma mmc: mmci: add datactrl block size variant property mmc: mmci: expand startbiterr to irqmask and error check mmc: mmci: allow to overwrite clock/power procedure to specific variant mmc: mmci: add variant properties to define cpsm & cmdresp bits mmc: mmci: add variant property to define dpsm bit mmc: mmci: add variant property to define irq pio mask mmc: mmci: add variant property to write datactrl before command mmc: mmci: add variant property to allow remain data mmc: mmci: add variant property to check specific data constraint mmc: mmci: add variant property to request a reset mmc: mmci: send stop cmd if a data command fail mmc: mmci: add clock divider for stm32 sdmmc mmc: mmci: add stm32 sdmmc registers mmc: mmci: add DT bindings for STM32 sdmmc mmc: mmci: add stm32 sdmmc idma support mmc: mmci: add specific clk/pwr procedure for stm32 sdmmc mmc: mmci: add stm32 sdmmc variant Documentation/devicetree/bindings/mmc/mmci.txt | 11 + drivers/mmc/host/Makefile | 3 +- drivers/mmc/host/mmci.c| 846 +++-- drivers/mmc/host/mmci.h| 237 ++- drivers/mmc/host/mmci_dma.c| 780 +++ drivers/mmc/host/mmci_dma.h| 33 + drivers/mmc/host/mmci_qcom_dml.c | 177 -- drivers/mmc/host/mmci_qcom_dml.h | 31 - 8 files changed, 1410 insertions(+), 708 deletions(-) create mode 100644 drivers/mmc/host/mmci_dma.c create mode 100644 drivers/mmc/host/mmci_dma.h delete mode 100644 drivers/mmc/host/mmci_qcom_dml.c delete mode 100644 drivers/mmc/host/mmci_qcom_dml.h
Re: [PATCH 13/19] mmc: mmci: send stop cmd if a data command fail
hi Ulf thanks for review, comments below On 07/04/2018 03:37 PM, Ulf Hansson wrote: On 12 June 2018 at 15:14, Ludovic Barre wrote: From: Ludovic Barre The mmc framework follows the requirement of SD_Specification: the STOP_TRANSMISSION is sent on multiple write/read commands and the stop command (alone), not needed on other ADTC commands. But, some variants require a stop command "STOP_TRANSMISION" to clear the DPSM "Data Path State Machine" if an error happens on command or data step. If it's not done the next data command will freeze hardware block. Needed to support the STM32 sdmmc variant. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 36 +++- drivers/mmc/host/mmci.h | 3 +++ 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 87724e1..9af7db8 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -522,11 +523,28 @@ static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) host->mask1_reg = mask; } -static void mmci_stop_data(struct mmci_host *host) +static int mmci_stop_data(struct mmci_host *host) Let's leave this as void function and instead add a check in mmci_start_command(), to see if the command is a MMC_STOP_TRANSMISSION. If so, then add host->variant->cmdreg_stop to the register that is written in it. In fact: the cmdreg_stop bit (which abort and reinit the DPSM) should have been activated only in error case. But I see a mistake in this piece of code => cmdreg_stop bit is set for all MMC_STOP_TRANSMISSION. So, I read closely the sdmmc datasheet and it seems possible to set cmdreg_stop bit for all MMC_STOP_TRANSMISSION (error or not). So, I will try your proposition to set cmdreg_stop bit in mmci_start_command() if the command is MMC_STOP_TRANSMISSION. And actually, I think this change alone should be a separate patch coming before $subject patch in the series, as it addresses the first problem of two. { + struct mmc_command *stop = &host->stop_abort; + struct mmc_data *data = host->data; + unsigned int cmd = 0; + mmci_write_datactrlreg(host, 0); mmci_set_mask1(host, 0); host->data = NULL; + + if (host->variant->cmdreg_stop) { + cmd |= host->variant->cmdreg_stop; + if (!data->stop) { + memset(stop, 0, sizeof(struct mmc_command)); + stop->opcode = MMC_STOP_TRANSMISSION; + stop->arg = 0; + stop->flags = MMC_RSP_R1B | MMC_CMD_AC; + data->stop = stop; I don't understand why you want the host->stop_abort being present in the mmci host struct? Can we get rid of that? Anyway, re-using the data->stop pointer seems reasonable. In fact mrq->data->stop could be not referenced (NULL). for data command, the stop command is allocated in mmc_blk_request struct mmc_blk_request { struct mmc_command stop; }; struct mmc_data { struct mmc_command *stop; }; struct mmc_request { struct mmc_command *stop; }; in mmc_blk_rw_rq_prep function: if data.blocks > 1 brq->mrq.stop = &brq->stop; else brq->mrq.stop = NULL; in mmc_mrq_prep function: if (mrq->stop) { mrq->data->stop = mrq->stop; Update about this topic: This last week I found a new specific need for sdmmc variant. On response type MMC_RSP_BUSY (example mmc_switch command cmd6, AC command without data): SDMMC needs to set MMCIDATATIMER to define busy_timeout. If timeout expires Datatimeout and DPSM flags occur. So a MMC_STOP_TRANSMISSION with cmdreg_stop bit is required to abort and reinitialize the DPSM. So, I think we could keep "host->stop_abort" which may be used in cmd or data requests. The stop_abort command is always the same, so stop_abort command could be initialized only while probe function (under variant->cmdreg_stop). What do you think about it ? + } + } + + return cmd; } static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) @@ -703,6 +721,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { unsigned int status_err; + unsigned int cmd_reg = 0; /* Make sure we have data to handle */ if (!data) @@ -761,7 +780,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, if (status & MCI_DATAEND || data->error) { mmci_dma_finalize(host, data); - mmci_stop_data(host); + cmd_reg = mmci_stop_data(host); if (!data->error) /* The error clause is handl
Re: [PATCH 01/19] mmc: mmci: regroup and define dma operations
On 07/05/2018 05:17 PM, Ulf Hansson wrote: On 12 June 2018 at 15:14, Ludovic Barre wrote: From: Ludovic Barre Prepare mmci driver to manage dma interface by new property. This patch defines and regroups dma operations for mmci drivers. mmci_dma_XX prototypes are added to call member of mmci_dma_ops if not null. Based on legacy need, a mmci dma interface has been defined with: -mmci_dma_setup -mmci_dma_release -mmci_dma_pre_req -mmci_dma_start -mmci_dma_finalize -mmci_dma_post_req -mmci_dma_error -mmci_dma_get_next_data As I suggested for one of the other patches, I would rather turn core mmci functions into library functions, which can be either invoked from variant callbacks or assigned directly to them. In other words, I would leave the functions that you move in this patch to stay in mmci.c. Although some needs to be re-factored and we also needs to make some of them available to be called from another file, hence the functions needs to be shared via mmci.h rather than being declared static. In previous exchange mail "STM32MP1 SDMMC driver review" we are said: >>> -dma variant à should fit in Qualcomm implementation, reuse (rename) >>> mmci_qcom_dml.c file and integrate ST dma in. >> >> stm32 sdmmc has an internal dma, no need to use dmaengine API; >> So some modifications in mmci (pre/post request, mmci_dma_xx). perhaps >> should be done with an ops or not. > >Yes. > >The Qualcomm variant is also using an internal DMA, hence I thought >there may be something we could re-use, or at least have some new >common ops for. It's not crystal clear for me. Do you always agree with a dma ops which allow to address different DMA transfer: -with dmaengine API -sdmmc idma, without dmaengine API -... Let me take a concrete example on how I would move forward, hopefully that explains it a bit better. Please see below. [...] -/* - * All the DMA operation mode stuff goes inside this ifdef. - * This assumes that you have a generic DMA device interface, - * no custom DMA interfaces are supported. - */ -#ifdef CONFIG_DMA_ENGINE -static void mmci_dma_setup(struct mmci_host *host) -{ - const char *rxname, *txname; - struct variant_data *variant = host->variant; - - host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); - host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); - - /* initialize pre request cookie */ - host->next_data.cookie = 1; - - /* -* If only an RX channel is specified, the driver will -* attempt to use it bidirectionally, however if it is -* is specified but cannot be located, DMA will be disabled. -*/ - if (host->dma_rx_channel && !host->dma_tx_channel) - host->dma_tx_channel = host->dma_rx_channel; - - if (host->dma_rx_channel) - rxname = dma_chan_name(host->dma_rx_channel); - else - rxname = "none"; - - if (host->dma_tx_channel) - txname = dma_chan_name(host->dma_tx_channel); - else - txname = "none"; - - dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n", -rxname, txname); - - /* -* Limit the maximum segment size in any SG entry according to -* the parameters of the DMA engine device. -*/ - if (host->dma_tx_channel) { - struct device *dev = host->dma_tx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - - if (max_seg_size < host->mmc->max_seg_size) - host->mmc->max_seg_size = max_seg_size; - } - if (host->dma_rx_channel) { - struct device *dev = host->dma_rx_channel->device->dev; - unsigned int max_seg_size = dma_get_max_seg_size(dev); - - if (max_seg_size < host->mmc->max_seg_size) - host->mmc->max_seg_size = max_seg_size; - } Everything above shall be left as generic library function, mmci_dma_setup() and I would share it via mmci.h and thus change it from being static. each interfaces mmci_dma_XXX have very different needs depending dma_ops (legacy, sdmmc idma) - - if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel) - if (dml_hw_init(host, host->mmc->parent->of_node)) - variant->qcom_dml = false; This piece of code, should be made specific to the qcom variant and managed though a "mmci_host_ops" callback. The corresponding code in that callback would then start by invoking mmci_dma_setup(), before it continues with the qcom specific operations. For legacy variants, the corresponding callback would be set directly to mmci_dma_setup() and called through the callback from mmci.c when needed. There is no need to have a separate file for DMA for the legacy variants, I think. [...] Kind regards Uffe
Re: [PATCH 05/19] mmc: mmci: allow to overwrite clock/power procedure to specific variant
On 07/05/2018 03:48 PM, Ulf Hansson wrote: On 12 June 2018 at 15:14, Ludovic Barre wrote: From: Ludovic Barre A specific variant could have different power or clock procedures. This patch allows to overwrite the default mmci_set_clkreg and mmci_set_pwrreg for a specific variant. Signed-off-by: Ludovic Barre --- drivers/mmc/host/mmci.c | 96 + drivers/mmc/host/mmci.h | 7 2 files changed, 64 insertions(+), 39 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index ede95b7..801c86b 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -374,6 +374,52 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) mmci_write_clkreg(host, clk); } +static void mmci_set_pwrreg(struct mmci_host *host, unsigned char power_mode, + unsigned int pwr) +{ + struct variant_data *variant = host->variant; + struct mmc_host *mmc = host->mmc; + + switch (power_mode) { + case MMC_POWER_OFF: + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + + if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) { + regulator_disable(mmc->supply.vqmmc); + host->vqmmc_enabled = false; + } + + break; + case MMC_POWER_UP: + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, + mmc->ios.vdd); + + /* +* The ST Micro variant doesn't have the PL180s MCI_PWR_UP +* and instead uses MCI_PWR_ON so apply whatever value is +* configured in the variant data. +*/ + pwr |= variant->pwrreg_powerup; + + break; + case MMC_POWER_ON: + if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { + if (regulator_enable(mmc->supply.vqmmc) < 0) + dev_err(mmc_dev(mmc), + "failed to enable vqmmc regulator\n"); + else + host->vqmmc_enabled = true; + } + + pwr |= MCI_PWR_ON; + break; + } + + mmci_write_pwrreg(host, pwr); +} + static void mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) { @@ -1031,7 +1077,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmci_host *host = mmc_priv(mmc); struct variant_data *variant = host->variant; - u32 pwr = 0; + unsigned int pwr = 0; ? yes not needed rewritten due to re-factoring unsigned long flags; int ret; @@ -1039,42 +1085,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->plat->ios_handler(mmc_dev(mmc), ios)) dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); - switch (ios->power_mode) { - case MMC_POWER_OFF: - if (!IS_ERR(mmc->supply.vmmc)) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - - if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) { - regulator_disable(mmc->supply.vqmmc); - host->vqmmc_enabled = false; - } - - break; - case MMC_POWER_UP: - if (!IS_ERR(mmc->supply.vmmc)) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); - - /* -* The ST Micro variant doesn't have the PL180s MCI_PWR_UP -* and instead uses MCI_PWR_ON so apply whatever value is -* configured in the variant data. -*/ - pwr |= variant->pwrreg_powerup; - - break; - case MMC_POWER_ON: - if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) { - ret = regulator_enable(mmc->supply.vqmmc); - if (ret < 0) - dev_err(mmc_dev(mmc), - "failed to enable vqmmc regulator\n"); - else - host->vqmmc_enabled = true; - } - - pwr |= MCI_PWR_ON; - break; - } This above looks like pure re-factoring. Please make the above change a separate patch. OK if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) { /* @@ -1126,8 +1136,16 @@ static void mmci_set_ios(struct mmc_h
Re: [PATCH 07/11] irqchip: stm32: add stm32mp1 support with hierarchy domain
On 05/04/2018 10:38 PM, Rob Herring wrote: On Thu, May 3, 2018 at 4:55 AM, Ludovic BARRE wrote: On 05/02/2018 07:45 PM, Rob Herring wrote: On Wed, May 2, 2018 at 11:03 AM, Ludovic BARRE wrote: Hi Rob On 05/01/2018 04:56 PM, Rob Herring wrote: On Thu, Apr 26, 2018 at 06:18:30PM +0200, Ludovic Barre wrote: From: Ludovic Barre Exti controller has been differently integrated on stm32mp1 SoC. A parent irq has only one external interrupt. A hierachy domain could be used. Handlers are call by parent, each parent interrupt could be masked and unmasked according to the needs. Signed-off-by: Ludovic Barre --- .../interrupt-controller/st,stm32-exti.txt | 3 + drivers/irqchip/irq-stm32-exti.c | 322 + 2 files changed, 325 insertions(+) diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt index edf03f0..136bd61 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt @@ -5,11 +5,14 @@ Required properties: - compatible: Should be: "st,stm32-exti" "st,stm32h7-exti" +"st,stm32mp1-exti" - reg: Specifies base physical address and size of the registers - interrupt-controller: Indentifies the node as an interrupt controller - #interrupt-cells: Specifies the number of cells to encode an interrupt specifier, shall be 2 - interrupts: interrupts references to primary interrupt controller + (only needed for exti controller with multiple exti under + same parent interrupt: st,stm32-exti and st,stm32h7-exti") Example: diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index b38c655..ebf7146 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c [...] +static const struct stm32_desc_irq stm32mp1_desc_irq[] = { + { .exti = 1, .irq_parent = 7 }, + { .exti = 2, .irq_parent = 8 }, + { .exti = 3, .irq_parent = 9 }, + { .exti = 4, .irq_parent = 10 }, + { .exti = 5, .irq_parent = 23 }, + { .exti = 6, .irq_parent = 64 }, + { .exti = 7, .irq_parent = 65 }, + { .exti = 8, .irq_parent = 66 }, + { .exti = 9, .irq_parent = 67 }, + { .exti = 10, .irq_parent = 40 }, + { .exti = 11, .irq_parent = 42 }, + { .exti = 12, .irq_parent = 76 }, + { .exti = 13, .irq_parent = 77 }, + { .exti = 14, .irq_parent = 121 }, + { .exti = 15, .irq_parent = 127 }, + { .exti = 16, .irq_parent = 1 }, + { .exti = 65, .irq_parent = 144 }, + { .exti = 68, .irq_parent = 143 }, + { .exti = 73, .irq_parent = 129 }, +}; You can use an interrupt-map property rather than put this into the driver. interrupt-map seemed interesting and promising like used in pci host. At first sight this property can't be used into node with "interrupt-controller" property (see in drivers/of/irq.c function: of_irq_parse_raw) because "of_irq_parse_raw" checks if node got it first, and after lookup the interrupt-map. Rob, Thomas, Jason, Marc what do you prefers or the right ways...? I believe the correct thing to do is simply drop "interrupt-controller". Actually, that's not right. if I drop "interrupt-controller" of my node, my driver will not be initialized by "of_irq_init" (start_kernel->init_IRQ->irqchip_init->of_irq_init). Probably, we could replace "IRQCHIP_DECLARE" by a "module_platform_driver" or "postcore_initcall" but I'm not a big fan of this solution. what do you think ? You'd have to parse 'interrupt-map' yourself to extract the data for this to work because interrupt-map currently only works when the translation is transparent (i.e. doesn't need s/w handling). So I guess leave this in the driver. Sorry for the noise. Sorry, I don't know if I've correctly understand the answer. I hesitate between: - keep the code like this, with stm32mp1_desc_irq tab. - parse interrupt-map property into stm32 exti driver. Just to be sure, and avoid misunderstand. BR Ludo Rob
[PATCH V2 2/3] ARM: dts: stm32: add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch adds independent watchdog support for stm32mp157c. Signed-off-by: Ludovic Barre --- arch/arm/boot/dts/stm32mp157c.dtsi | 8 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp157c.dtsi b/arch/arm/boot/dts/stm32mp157c.dtsi index 7d17538..95cc166 100644 --- a/arch/arm/boot/dts/stm32mp157c.dtsi +++ b/arch/arm/boot/dts/stm32mp157c.dtsi @@ -784,6 +784,14 @@ status = "disabled"; }; + iwdg2: watchdog@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&rcc CK_LSI>; + clock-names = "pclk", "lsi"; + status = "disabled"; + }; + usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; -- 2.7.4
[PATCH V2 1/3] watchdog: stm32: add pclk feature for stm32mp1
From: Ludovic Barre This patch adds config data to manage specific properties by compatible. Adds stm32mp1 config which requires pclk clock. Signed-off-by: Ludovic Barre --- .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 21 +++- drivers/watchdog/stm32_iwdg.c | 132 ++--- 2 files changed, 104 insertions(+), 49 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt index cc13b10a..f07f6d89 100644 --- a/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt +++ b/Documentation/devicetree/bindings/watchdog/st,stm32-iwdg.txt @@ -2,18 +2,31 @@ STM32 Independent WatchDoG (IWDG) - Required properties: -- compatible: "st,stm32-iwdg" -- reg: physical base address and length of the registers set for the device -- clocks: must contain a single entry describing the clock input +- compatible: Should be either "st,stm32-iwdg" or "st,stm32mp1-iwdg" +- reg: Physical base address and length of the registers set for the device +- clocks: Reference to the clock entry lsi. Additional pclk clock entry + is required only for st,stm32mp1-iwdg. +- clock-names: Name of the clocks used. + "lsi" for st,stm32-iwdg + "pclk", "lsi" for st,stm32mp1-iwdg Optional Properties: - timeout-sec: Watchdog timeout value in seconds. -Example: +Examples: iwdg: watchdog@40003000 { compatible = "st,stm32-iwdg"; reg = <0x40003000 0x400>; clocks = <&clk_lsi>; + clock-names = "lsi"; + timeout-sec = <32>; +}; + +iwdg: iwdg@5a002000 { + compatible = "st,stm32mp1-iwdg"; + reg = <0x5a002000 0x400>; + clocks = <&rcc IWDG2>, <&clk_lsi>; + clock-names = "pclk", "lsi"; timeout-sec = <32>; }; diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index c97ad56..fc96670 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -11,12 +11,13 @@ #include #include -#include -#include #include #include #include +#include +#include #include +#include #include #include @@ -54,11 +55,17 @@ #define TIMEOUT_US 10 #define SLEEP_US 1000 +struct stm32_iwdg_config { + bool has_pclk; +}; + struct stm32_iwdg { - struct watchdog_device wdd; - void __iomem*regs; - struct clk *clk; - unsigned intrate; + struct watchdog_device wdd; + void __iomem*regs; + struct stm32_iwdg_config*config; + struct clk *clk_lsi; + struct clk *clk_pclk; + unsigned intrate; }; static inline u32 reg_read(void __iomem *base, u32 reg) @@ -133,6 +140,44 @@ static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, return 0; } +static int stm32_iwdg_clk_init(struct platform_device *pdev, + struct stm32_iwdg *wdt) +{ + u32 ret; + + wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); + if (IS_ERR(wdt->clk_lsi)) { + dev_err(&pdev->dev, "Unable to get lsi clock\n"); + return PTR_ERR(wdt->clk_lsi); + } + + /* optional peripheral clock */ + if (wdt->config->has_pclk) { + wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(wdt->clk_pclk)) { + dev_err(&pdev->dev, "Unable to get pclk clock\n"); + return PTR_ERR(wdt->clk_pclk); + } + + ret = clk_prepare_enable(wdt->clk_pclk); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare pclk clock\n"); + return ret; + } + } + + ret = clk_prepare_enable(wdt->clk_lsi); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare lsi clock\n"); + clk_disable_unprepare(wdt->clk_pclk); + return ret; + } + + wdt->rate = clk_get_rate(wdt->clk_lsi); + + return 0; +} + static const struct watchdog_info stm32_iwdg_info = { .options= WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | @@ -147,49 +192,50 @@ static const struct watchdog_ops stm32_iwdg_ops = { .set_timeout= stm32_iwdg_set_timeout, }; +static const struct stm32_iwdg_config stm32_iwdg_cfg = { + .has_pclk = false, +}; + +static const struct stm32_iwdg_config stm32mp1_iwdg_cfg = { + .has_pclk = true, +}; + +static const struct of_device_id stm32_iwdg_of_match
[PATCH V2 0/3] add iwdg2 support for stm32mp157c
From: Ludovic Barre This patch series updates stm32_iwdg driver to manage config by compatible. stm32mp1 config requires a pclk clock. Ludovic Barre (3): watchdog: stm32: add pclk feature for stm32mp1 ARM: dts: stm32: add iwdg2 support for stm32mp157c ARM: dts: stm32: add iwdg2 support for stm32mp157c-ed1 .../devicetree/bindings/watchdog/st,stm32-iwdg.txt | 21 +++- arch/arm/boot/dts/stm32mp157c-ed1.dts | 5 + arch/arm/boot/dts/stm32mp157c.dtsi | 8 ++ drivers/watchdog/stm32_iwdg.c | 132 ++--- 4 files changed, 117 insertions(+), 49 deletions(-) -- 2.7.4