Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/8] Add STM32MP25 SPI NOR support
@ 2025-02-10 13:18 patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
                   ` (8 more replies)
  0 siblings, 9 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

This series adds SPI NOR support for STM32MP25 SoCs from STMicroelectronics,
for that it adds support for:
  - Octo Memory Manager driver.
  - Octo SPI driver.
  - yaml schema for Octo Memory Manager and Octo SPI drivers.

The device tree files adds Octo Memory Manager and associated Octo SPI instances
in stm32mp251.dtsi and adds SPI NOR support in stm32mp257f-ev1 board.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>

Changes in v3:
  - Squash defconfig patches 8 and 9.
  - Update STM32 Octo Memory Manager controller bindings.
  - Rename st,stm32-omm.yaml to st,stm32mp25-omm.yaml.
  - Update STM32 OSPI controller bindings.
  - Reorder DT properties in .dtsi and .dts files.
  - Replace devm_reset_control_get_optional() by devm_reset_control_get_optional_exclusive() in stm32_omm.c.
  - Reintroduce region-memory-names management in stm32_omm.c.
  - Rename stm32_ospi_tx_poll() to stm32_ospi_poll() in spi-stm32-ospi.c.
  - Set SPI_CONTROLLER_HALF_DUPLEX in controller flags in spi-stm32-ospi.c.

Changes in v2:
  - Move STM32 Octo Memory Manager controller driver and bindings from
    misc to memory-controllers.
  - Update STM32 OSPI controller bindings.
  - Update STM32 Octo Memory Manager controller bindings.
  - Update STM32 Octo Memory Manager driver to match bindings update.
  - Update DT to match bindings update.



Patrice Chotard (8):
  dt-bindings: spi: Add STM32 OSPI controller
  spi: stm32: Add OSPI driver
  dt-bindings: memory-controllers: Add STM32 Octo Memory Manager
    controller
  memory: Add STM32 Octo Memory Manager driver
  arm64: dts: st: Add OMM node on stm32mp251
  arm64: dts: st: Add ospi port1 pinctrl entries in
    stm32mp25-pinctrl.dtsi
  arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
  arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver

 .../memory-controllers/st,stm32mp25-omm.yaml  |  201 ++++
 .../bindings/spi/st,stm32mp25-ospi.yaml       |  105 ++
 arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi |   51 +
 arch/arm64/boot/dts/st/stm32mp251.dtsi        |   48 +
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts    |   32 +
 arch/arm64/configs/defconfig                  |    2 +
 drivers/memory/Kconfig                        |   17 +
 drivers/memory/Makefile                       |    1 +
 drivers/memory/stm32_omm.c                    |  520 ++++++++
 drivers/spi/Kconfig                           |   10 +
 drivers/spi/Makefile                          |    1 +
 drivers/spi/spi-stm32-ospi.c                  | 1065 +++++++++++++++++
 12 files changed, 2053 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
 create mode 100644 Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
 create mode 100644 drivers/memory/stm32_omm.c
 create mode 100644 drivers/spi/spi-stm32-ospi.c

-- 
2.25.1



^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-13  7:57   ` Krzysztof Kozlowski
  2025-02-17  9:17   ` Philipp Zabel
  2025-02-10 13:18 ` [PATCH v3 2/8] spi: stm32: Add OSPI driver patrice.chotard
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Add device tree bindings for the STM32 OSPI controller.

Main features of the Octo-SPI controller :
  - support sNOR / sNAND / HyperRAM™ and HyperFlash™ devices.
  - Three functional modes: indirect, automatic-status polling,
    memory-mapped.
  - Up to 4 Gbytes of external memory can be addressed in indirect
    mode (per physical port and per CS), and up to 256 Mbytes in
    memory-mapped mode (combined for both physical ports and per CS).
  - Single-, dual-, quad-, and octal-SPI communication.
  - Dual-quad communication.
  - Single data rate (SDR) and double transfer rate (DTR).
  - Maximum target frequency is 133 MHz for SDR and 133 MHz for DTR.
  - Data strobe support.
  - DMA channel for indirect mode.
  - Double CS mapping that allows two external flash devices to be
    addressed with a single OCTOSPI controller mapped on a single
    OCTOSPI port.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
 .../bindings/spi/st,stm32mp25-ospi.yaml       | 105 ++++++++++++++++++
 1 file changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml

diff --git a/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
new file mode 100644
index 000000000000..5f276f27dc4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
@@ -0,0 +1,105 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/st,stm32mp25-ospi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STMicroelectronics STM32 Octal Serial Peripheral Interface (OSPI)
+
+maintainers:
+  - Patrice Chotard <patrice.chotard@foss.st.com>
+
+allOf:
+  - $ref: spi-controller.yaml#
+
+properties:
+  compatible:
+    const: st,stm32mp25-ospi
+
+  reg:
+    maxItems: 1
+
+  memory-region:
+    description:
+      Memory region to be used for memory-map read access.
+      In memory-mapped mode, read access are performed from the memory
+      device using the direct mapping.
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  resets:
+    items:
+      - description: phandle to OSPI block reset
+      - description: phandle to delay block reset
+
+  dmas:
+    maxItems: 2
+
+  dma-names:
+    items:
+      - const: tx
+      - const: rx
+
+  st,syscfg-dlyb:
+    description: configure OCTOSPI delay block.
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    items:
+      - description: phandle to syscfg
+      - description: register offset within syscfg
+
+  access-controllers:
+    description: phandle to the rifsc device to check access right
+      and in some cases, an additional phandle to the rcc device for
+      secure clock control.
+    items:
+      - description: phandle to bus controller
+      - description: phandle to clock controller
+    minItems: 1
+
+  power-domains:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - interrupts
+  - st,syscfg-dlyb
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/st,stm32mp25-rcc.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/reset/st,stm32mp25-rcc.h>
+
+    spi@40430000 {
+      compatible = "st,stm32mp25-ospi";
+      reg = <0x40430000 0x400>;
+      memory-region = <&mm_ospi1>;
+      interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+      dmas = <&hpdma 2 0x62 0x00003121 0x0>,
+             <&hpdma 2 0x42 0x00003112 0x0>;
+      dma-names = "tx", "rx";
+      clocks = <&scmi_clk CK_SCMI_OSPI1>;
+      resets = <&scmi_reset RST_SCMI_OSPI1>, <&scmi_reset RST_SCMI_OSPI1DLL>;
+      access-controllers = <&rifsc 74>;
+      power-domains = <&CLUSTER_PD>;
+      st,syscfg-dlyb = <&syscfg 0x1000>;
+
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      flash@0 {
+        compatible = "jedec,spi-nor";
+        reg = <0>;
+        spi-rx-bus-width = <4>;
+        spi-max-frequency = <108000000>;
+      };
+    };
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 2/8] spi: stm32: Add OSPI driver
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 3/8] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller patrice.chotard
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Add STM32 OSPI driver, it supports :
  - support sNOR / sNAND devices.
  - Three functional modes: indirect, automatic-status polling,
    memory-mapped.
  - Single-, dual-, quad-, and octal-SPI communication.
  - Dual-quad communication.
  - Single data rate (SDR).
  - DMA channel for indirect mode.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
 drivers/spi/Kconfig          |   10 +
 drivers/spi/Makefile         |    1 +
 drivers/spi/spi-stm32-ospi.c | 1065 ++++++++++++++++++++++++++++++++++
 3 files changed, 1076 insertions(+)
 create mode 100644 drivers/spi/spi-stm32-ospi.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index ea8a31032927..256a3e23639a 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -1045,6 +1045,16 @@ config SPI_STM32
 	  is not available, the driver automatically falls back to
 	  PIO mode.
 
+config SPI_STM32_OSPI
+	tristate "STMicroelectronics STM32 OCTO SPI controller"
+	depends on ARCH_STM32 || COMPILE_TEST
+	depends on OF
+	depends on SPI_MEM
+	help
+	  This enables support for the Octo SPI controller in master mode.
+	  This driver does not support generic SPI. The implementation only
+	  supports spi-mem interface.
+
 config SPI_STM32_QSPI
 	tristate "STMicroelectronics STM32 QUAD SPI controller"
 	depends on ARCH_STM32 || COMPILE_TEST
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 9db7554c1864..41cbd6df048f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -137,6 +137,7 @@ obj-$(CONFIG_SPI_SN_F_OSPI)		+= spi-sn-f-ospi.o
 obj-$(CONFIG_SPI_SPRD)			+= spi-sprd.o
 obj-$(CONFIG_SPI_SPRD_ADI)		+= spi-sprd-adi.o
 obj-$(CONFIG_SPI_STM32) 		+= spi-stm32.o
+obj-$(CONFIG_SPI_STM32_OSPI) 		+= spi-stm32-ospi.o
 obj-$(CONFIG_SPI_STM32_QSPI) 		+= spi-stm32-qspi.o
 obj-$(CONFIG_SPI_ST_SSC4)		+= spi-st-ssc4.o
 obj-$(CONFIG_SPI_SUN4I)			+= spi-sun4i.o
diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
new file mode 100644
index 000000000000..8eadcb64f34a
--- /dev/null
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -0,0 +1,1065 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2025 - All Rights Reserved
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/sizes.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/types.h>
+
+#define OSPI_CR			0x00
+#define CR_EN			BIT(0)
+#define CR_ABORT		BIT(1)
+#define CR_DMAEN		BIT(2)
+#define CR_FTHRES_SHIFT		8
+#define CR_TEIE			BIT(16)
+#define CR_TCIE			BIT(17)
+#define CR_SMIE			BIT(19)
+#define CR_APMS			BIT(22)
+#define CR_CSSEL		BIT(24)
+#define CR_FMODE_MASK		GENMASK(29, 28)
+#define CR_FMODE_INDW		(0U)
+#define CR_FMODE_INDR		(1U)
+#define CR_FMODE_APM		(2U)
+#define CR_FMODE_MM		(3U)
+
+#define OSPI_DCR1		0x08
+#define DCR1_DLYBYP		BIT(3)
+#define DCR1_DEVSIZE_MASK	GENMASK(20, 16)
+#define DCR1_MTYP_MASK		GENMASK(26, 24)
+#define DCR1_MTYP_MX_MODE	1
+#define DCR1_MTYP_HP_MEMMODE	4
+
+#define OSPI_DCR2		0x0c
+#define DCR2_PRESC_MASK		GENMASK(7, 0)
+
+#define OSPI_SR			0x20
+#define SR_TEF			BIT(0)
+#define SR_TCF			BIT(1)
+#define SR_FTF			BIT(2)
+#define SR_SMF			BIT(3)
+#define SR_BUSY			BIT(5)
+
+#define OSPI_FCR		0x24
+#define FCR_CTEF		BIT(0)
+#define FCR_CTCF		BIT(1)
+#define FCR_CSMF		BIT(3)
+
+#define OSPI_DLR		0x40
+#define OSPI_AR			0x48
+#define OSPI_DR			0x50
+#define OSPI_PSMKR		0x80
+#define OSPI_PSMAR		0x88
+
+#define OSPI_CCR		0x100
+#define CCR_IMODE_MASK		GENMASK(2, 0)
+#define CCR_IDTR		BIT(3)
+#define CCR_ISIZE_MASK		GENMASK(5, 4)
+#define CCR_ADMODE_MASK		GENMASK(10, 8)
+#define CCR_ADMODE_8LINES	4
+#define CCR_ADDTR		BIT(11)
+#define CCR_ADSIZE_MASK		GENMASK(13, 12)
+#define CCR_ADSIZE_32BITS	3
+#define CCR_DMODE_MASK		GENMASK(26, 24)
+#define CCR_DMODE_8LINES	4
+#define CCR_DQSE		BIT(29)
+#define CCR_DDTR		BIT(27)
+#define CCR_BUSWIDTH_0		0x0
+#define CCR_BUSWIDTH_1		0x1
+#define CCR_BUSWIDTH_2		0x2
+#define CCR_BUSWIDTH_4		0x3
+#define CCR_BUSWIDTH_8		0x4
+
+#define OSPI_TCR		0x108
+#define TCR_DCYC_MASK		GENMASK(4, 0)
+#define TCR_DHQC		BIT(28)
+#define TCR_SSHIFT		BIT(30)
+
+#define OSPI_IR			0x110
+
+#define STM32_OSPI_MAX_MMAP_SZ	SZ_256M
+#define STM32_OSPI_MAX_NORCHIP	2
+
+#define STM32_FIFO_TIMEOUT_US		30000
+#define STM32_ABT_TIMEOUT_US		100000
+#define STM32_COMP_TIMEOUT_MS		5000
+#define STM32_BUSY_TIMEOUT_US		100000
+
+
+#define STM32_AUTOSUSPEND_DELAY -1
+
+struct stm32_ospi {
+	struct device *dev;
+	struct spi_controller *ctrl;
+	struct clk *clk;
+	struct reset_control *rstc;
+
+	struct completion data_completion;
+	struct completion match_completion;
+
+	struct dma_chan *dma_chtx;
+	struct dma_chan *dma_chrx;
+	struct completion dma_completion;
+
+	void __iomem *regs_base;
+	void __iomem *mm_base;
+	phys_addr_t regs_phys_base;
+	resource_size_t mm_size;
+	u32 clk_rate;
+	u32 fmode;
+	u32 cr_reg;
+	u32 dcr_reg;
+	u32 flash_presc[STM32_OSPI_MAX_NORCHIP];
+	int irq;
+	unsigned long status_timeout;
+
+	/*
+	 * To protect device configuration, could be different between
+	 * 2 flash access
+	 */
+	struct mutex lock;
+};
+
+static void stm32_ospi_read_fifo(u8 *val, void __iomem *addr)
+{
+	*val = readb_relaxed(addr);
+}
+
+static void stm32_ospi_write_fifo(u8 *val, void __iomem *addr)
+{
+	writeb_relaxed(*val, addr);
+}
+
+static int stm32_ospi_abort(struct stm32_ospi *ospi)
+{
+	void __iomem *regs_base = ospi->regs_base;
+	u32 cr;
+	int timeout;
+
+	cr = readl_relaxed(regs_base + OSPI_CR) | CR_ABORT;
+	writel_relaxed(cr, regs_base + OSPI_CR);
+
+	/* wait clear of abort bit by hw */
+	timeout = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_CR,
+						    cr, !(cr & CR_ABORT), 1,
+						    STM32_ABT_TIMEOUT_US);
+
+	if (timeout)
+		dev_err(ospi->dev, "%s abort timeout:%d\n", __func__, timeout);
+
+	return timeout;
+}
+
+static int stm32_ospi_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
+{
+	void __iomem *regs_base = ospi->regs_base;
+	void (*fifo)(u8 *val, void __iomem *addr);
+	u32 sr;
+	int ret;
+
+	if (read)
+		fifo = stm32_ospi_read_fifo;
+	else
+		fifo = stm32_ospi_write_fifo;
+
+	while (len--) {
+		ret = readl_relaxed_poll_timeout_atomic(regs_base + OSPI_SR,
+							sr, sr & SR_FTF, 1,
+							STM32_FIFO_TIMEOUT_US);
+		if (ret) {
+			dev_err(ospi->dev, "fifo timeout (len:%d stat:%#x)\n",
+				len, sr);
+			return ret;
+		}
+		fifo(buf++, regs_base + OSPI_DR);
+	}
+
+	return 0;
+}
+
+static int stm32_ospi_wait_nobusy(struct stm32_ospi *ospi)
+{
+	u32 sr;
+
+	return readl_relaxed_poll_timeout_atomic(ospi->regs_base + OSPI_SR,
+						 sr, !(sr & SR_BUSY), 1,
+						 STM32_BUSY_TIMEOUT_US);
+}
+
+static int stm32_ospi_wait_cmd(struct stm32_ospi *ospi)
+{
+	void __iomem *regs_base = ospi->regs_base;
+	u32 cr, sr;
+	int err = 0;
+
+	if ((readl_relaxed(regs_base + OSPI_SR) & SR_TCF) ||
+	    ospi->fmode == CR_FMODE_APM)
+		goto out;
+
+	reinit_completion(&ospi->data_completion);
+	cr = readl_relaxed(regs_base + OSPI_CR);
+	writel_relaxed(cr | CR_TCIE | CR_TEIE, regs_base + OSPI_CR);
+
+	if (!wait_for_completion_timeout(&ospi->data_completion,
+				msecs_to_jiffies(STM32_COMP_TIMEOUT_MS)))
+		err = -ETIMEDOUT;
+
+	sr = readl_relaxed(regs_base + OSPI_SR);
+	if (sr & SR_TCF)
+		/* avoid false timeout */
+		err = 0;
+	if (sr & SR_TEF)
+		err = -EIO;
+
+out:
+	/* clear flags */
+	writel_relaxed(FCR_CTCF | FCR_CTEF, regs_base + OSPI_FCR);
+
+	if (!err)
+		err = stm32_ospi_wait_nobusy(ospi);
+
+	return err;
+}
+
+static void stm32_ospi_dma_callback(void *arg)
+{
+	struct completion *dma_completion = arg;
+
+	complete(dma_completion);
+}
+
+static irqreturn_t stm32_ospi_irq(int irq, void *dev_id)
+{
+	struct stm32_ospi *ospi = (struct stm32_ospi *)dev_id;
+	void __iomem *regs_base = ospi->regs_base;
+	u32 cr, sr;
+
+	cr = readl_relaxed(regs_base + OSPI_CR);
+	sr = readl_relaxed(regs_base + OSPI_SR);
+
+	if (cr & CR_SMIE && sr & SR_SMF) {
+		/* disable irq */
+		cr &= ~CR_SMIE;
+		writel_relaxed(cr, regs_base + OSPI_CR);
+		complete(&ospi->match_completion);
+
+		return IRQ_HANDLED;
+	}
+
+	if (sr & (SR_TEF | SR_TCF)) {
+		/* disable irq */
+		cr &= ~CR_TCIE & ~CR_TEIE;
+		writel_relaxed(cr, regs_base + OSPI_CR);
+		complete(&ospi->data_completion);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void stm32_ospi_dma_setup(struct stm32_ospi *ospi,
+			 struct dma_slave_config *dma_cfg)
+{
+	if (dma_cfg && ospi->dma_chrx) {
+		if (dmaengine_slave_config(ospi->dma_chrx, dma_cfg)) {
+			dev_err(ospi->dev, "dma rx config failed\n");
+			dma_release_channel(ospi->dma_chrx);
+			ospi->dma_chrx = NULL;
+		}
+	}
+
+	if (dma_cfg && ospi->dma_chtx) {
+		if (dmaengine_slave_config(ospi->dma_chtx, dma_cfg)) {
+			dev_err(ospi->dev, "dma tx config failed\n");
+			dma_release_channel(ospi->dma_chtx);
+			ospi->dma_chtx = NULL;
+		}
+	}
+
+	init_completion(&ospi->dma_completion);
+}
+
+static int stm32_ospi_tx_mm(struct stm32_ospi *ospi,
+			    const struct spi_mem_op *op)
+{
+	memcpy_fromio(op->data.buf.in, ospi->mm_base + op->addr.val,
+		      op->data.nbytes);
+	return 0;
+}
+
+static int stm32_ospi_tx_dma(struct stm32_ospi *ospi,
+			     const struct spi_mem_op *op)
+{
+	struct dma_async_tx_descriptor *desc;
+	void __iomem *regs_base = ospi->regs_base;
+	enum dma_transfer_direction dma_dir;
+	struct dma_chan *dma_ch;
+	struct sg_table sgt;
+	dma_cookie_t cookie;
+	u32 cr, t_out;
+	int err;
+
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		dma_dir = DMA_DEV_TO_MEM;
+		dma_ch = ospi->dma_chrx;
+	} else {
+		dma_dir = DMA_MEM_TO_DEV;
+		dma_ch = ospi->dma_chtx;
+	}
+
+	/*
+	 * Spi_map_buf return -EINVAL if the buffer is not DMA-able
+	 * (DMA-able: in vmalloc | kmap | virt_addr_valid)
+	 */
+	err = spi_controller_dma_map_mem_op_data(ospi->ctrl, op, &sgt);
+	if (err)
+		return err;
+
+	desc = dmaengine_prep_slave_sg(dma_ch, sgt.sgl, sgt.nents,
+				       dma_dir, DMA_PREP_INTERRUPT);
+	if (!desc) {
+		err = -ENOMEM;
+		goto out_unmap;
+	}
+
+	cr = readl_relaxed(regs_base + OSPI_CR);
+
+	reinit_completion(&ospi->dma_completion);
+	desc->callback = stm32_ospi_dma_callback;
+	desc->callback_param = &ospi->dma_completion;
+	cookie = dmaengine_submit(desc);
+	err = dma_submit_error(cookie);
+	if (err)
+		goto out;
+
+	dma_async_issue_pending(dma_ch);
+
+	writel_relaxed(cr | CR_DMAEN, regs_base + OSPI_CR);
+
+	t_out = sgt.nents * STM32_COMP_TIMEOUT_MS;
+	if (!wait_for_completion_timeout(&ospi->dma_completion,
+					 msecs_to_jiffies(t_out)))
+		err = -ETIMEDOUT;
+
+	if (err)
+		dmaengine_terminate_all(dma_ch);
+
+out:
+	writel_relaxed(cr & ~CR_DMAEN, regs_base + OSPI_CR);
+out_unmap:
+	spi_controller_dma_unmap_mem_op_data(ospi->ctrl, op, &sgt);
+
+	return err;
+}
+
+static int stm32_ospi_xfer(struct stm32_ospi *ospi, const struct spi_mem_op *op)
+{
+	u8 *buf;
+
+	if (!op->data.nbytes)
+		return 0;
+
+	if (ospi->fmode == CR_FMODE_MM)
+		return stm32_ospi_tx_mm(ospi, op);
+	else if (((op->data.dir == SPI_MEM_DATA_IN && ospi->dma_chrx) ||
+		 (op->data.dir == SPI_MEM_DATA_OUT && ospi->dma_chtx)) &&
+		  op->data.nbytes > 8)
+		if (!stm32_ospi_tx_dma(ospi, op))
+			return 0;
+
+	if (op->data.dir == SPI_MEM_DATA_IN)
+		buf = op->data.buf.in;
+	else
+		buf = (u8 *)op->data.buf.out;
+
+	return stm32_ospi_poll(ospi, buf, op->data.nbytes,
+			       op->data.dir == SPI_MEM_DATA_IN);
+}
+
+static int stm32_ospi_wait_poll_status(struct stm32_ospi *ospi,
+				       const struct spi_mem_op *op)
+{
+	void __iomem *regs_base = ospi->regs_base;
+	u32 cr;
+
+	reinit_completion(&ospi->match_completion);
+	cr = readl_relaxed(regs_base + OSPI_CR);
+	writel_relaxed(cr | CR_SMIE, regs_base + OSPI_CR);
+
+	if (!wait_for_completion_timeout(&ospi->match_completion,
+					 msecs_to_jiffies(ospi->status_timeout))) {
+		u32 sr = readl_relaxed(regs_base + OSPI_SR);
+
+		/* Avoid false timeout */
+		if (!(sr & SR_SMF))
+			return -ETIMEDOUT;
+	}
+
+	writel_relaxed(FCR_CSMF, regs_base + OSPI_FCR);
+
+	return 0;
+}
+
+static int stm32_ospi_get_mode(u8 buswidth)
+{
+	switch (buswidth) {
+	case 8:
+		return CCR_BUSWIDTH_8;
+	case 4:
+		return CCR_BUSWIDTH_4;
+	default:
+		return buswidth;
+	}
+}
+
+static int stm32_ospi_send(struct spi_device *spi, const struct spi_mem_op *op)
+{
+	struct stm32_ospi *ospi = spi_controller_get_devdata(spi->controller);
+	void __iomem *regs_base = ospi->regs_base;
+	u32 ccr, cr, dcr2, tcr;
+	int timeout, err = 0, err_poll_status = 0;
+	u8 cs = spi->chip_select[ffs(spi->cs_index_mask) - 1];
+
+	dev_dbg(ospi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n",
+		op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+		op->dummy.buswidth, op->data.buswidth,
+		op->addr.val, op->data.nbytes);
+
+	cr = readl_relaxed(ospi->regs_base + OSPI_CR);
+	cr &= ~CR_CSSEL;
+	cr |= FIELD_PREP(CR_CSSEL, cs);
+	cr &= ~CR_FMODE_MASK;
+	cr |= FIELD_PREP(CR_FMODE_MASK, ospi->fmode);
+	writel_relaxed(cr, regs_base + OSPI_CR);
+
+	if (op->data.nbytes)
+		writel_relaxed(op->data.nbytes - 1, regs_base + OSPI_DLR);
+
+	/* set prescaler */
+	dcr2 = readl_relaxed(regs_base + OSPI_DCR2);
+	dcr2 |= FIELD_PREP(DCR2_PRESC_MASK, ospi->flash_presc[cs]);
+	writel_relaxed(dcr2, regs_base + OSPI_DCR2);
+
+	ccr = FIELD_PREP(CCR_IMODE_MASK, stm32_ospi_get_mode(op->cmd.buswidth));
+
+	if (op->addr.nbytes) {
+		ccr |= FIELD_PREP(CCR_ADMODE_MASK,
+				  stm32_ospi_get_mode(op->addr.buswidth));
+		ccr |= FIELD_PREP(CCR_ADSIZE_MASK, op->addr.nbytes - 1);
+	}
+
+	tcr = TCR_SSHIFT;
+	if (op->dummy.buswidth && op->dummy.nbytes) {
+		tcr |= FIELD_PREP(TCR_DCYC_MASK,
+				  op->dummy.nbytes * 8 / op->dummy.buswidth);
+	}
+	writel_relaxed(tcr, regs_base + OSPI_TCR);
+
+	if (op->data.nbytes) {
+		ccr |= FIELD_PREP(CCR_DMODE_MASK,
+				  stm32_ospi_get_mode(op->data.buswidth));
+	}
+
+	writel_relaxed(ccr, regs_base + OSPI_CCR);
+
+	/* set instruction, must be set after ccr register update */
+	writel_relaxed(op->cmd.opcode, regs_base + OSPI_IR);
+
+	if (op->addr.nbytes && ospi->fmode != CR_FMODE_MM)
+		writel_relaxed(op->addr.val, regs_base + OSPI_AR);
+
+	if (ospi->fmode == CR_FMODE_APM)
+		err_poll_status = stm32_ospi_wait_poll_status(ospi, op);
+
+	err = stm32_ospi_xfer(ospi, op);
+
+	/*
+	 * Abort in:
+	 * -error case
+	 * -read memory map: prefetching must be stopped if we read the last
+	 *  byte of device (device size - fifo size). like device size is not
+	 *  knows, the prefetching is always stop.
+	 */
+	if (err || err_poll_status || ospi->fmode == CR_FMODE_MM)
+		goto abort;
+
+	/* Wait end of tx in indirect mode */
+	err = stm32_ospi_wait_cmd(ospi);
+	if (err)
+		goto abort;
+
+	return 0;
+
+abort:
+	timeout = stm32_ospi_abort(ospi);
+	writel_relaxed(FCR_CTCF | FCR_CSMF, regs_base + OSPI_FCR);
+
+	if (err || err_poll_status || timeout)
+		dev_err(ospi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n",
+			__func__, err, err_poll_status, timeout);
+
+	return err;
+}
+
+static int stm32_ospi_poll_status(struct spi_mem *mem,
+				  const struct spi_mem_op *op,
+				  u16 mask, u16 match,
+				  unsigned long initial_delay_us,
+				  unsigned long polling_rate_us,
+				  unsigned long timeout_ms)
+{
+	struct stm32_ospi *ospi = spi_controller_get_devdata(mem->spi->controller);
+	void __iomem *regs_base = ospi->regs_base;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&ospi->lock);
+
+	writel_relaxed(mask, regs_base + OSPI_PSMKR);
+	writel_relaxed(match, regs_base + OSPI_PSMAR);
+	ospi->fmode = CR_FMODE_APM;
+	ospi->status_timeout = timeout_ms;
+
+	ret = stm32_ospi_send(mem->spi, op);
+	mutex_unlock(&ospi->lock);
+
+	pm_runtime_mark_last_busy(ospi->dev);
+	pm_runtime_put_autosuspend(ospi->dev);
+
+	return ret;
+}
+
+static int stm32_ospi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+	struct stm32_ospi *ospi = spi_controller_get_devdata(mem->spi->controller);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&ospi->lock);
+	if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes)
+		ospi->fmode = CR_FMODE_INDR;
+	else
+		ospi->fmode = CR_FMODE_INDW;
+
+	ret = stm32_ospi_send(mem->spi, op);
+	mutex_unlock(&ospi->lock);
+
+	pm_runtime_mark_last_busy(ospi->dev);
+	pm_runtime_put_autosuspend(ospi->dev);
+
+	return ret;
+}
+
+static int stm32_ospi_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+	struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller);
+
+	if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT)
+		return -EOPNOTSUPP;
+
+	/* Should never happen, as mm_base == null is an error probe exit condition */
+	if (!ospi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN)
+		return -EOPNOTSUPP;
+
+	if (!ospi->mm_size)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static ssize_t stm32_ospi_dirmap_read(struct spi_mem_dirmap_desc *desc,
+				      u64 offs, size_t len, void *buf)
+{
+	struct stm32_ospi *ospi = spi_controller_get_devdata(desc->mem->spi->controller);
+	struct spi_mem_op op;
+	u32 addr_max;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&ospi->lock);
+	/*
+	 * Make a local copy of desc op_tmpl and complete dirmap rdesc
+	 * spi_mem_op template with offs, len and *buf in  order to get
+	 * all needed transfer information into struct spi_mem_op
+	 */
+	memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op));
+	dev_dbg(ospi->dev, "%s len = 0x%zx offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf);
+
+	op.data.nbytes = len;
+	op.addr.val = desc->info.offset + offs;
+	op.data.buf.in = buf;
+
+	addr_max = op.addr.val + op.data.nbytes + 1;
+	if (addr_max < ospi->mm_size && op.addr.buswidth)
+		ospi->fmode = CR_FMODE_MM;
+	else
+		ospi->fmode = CR_FMODE_INDR;
+
+	ret = stm32_ospi_send(desc->mem->spi, &op);
+	mutex_unlock(&ospi->lock);
+
+	pm_runtime_mark_last_busy(ospi->dev);
+	pm_runtime_put_autosuspend(ospi->dev);
+
+	return ret ?: len;
+}
+
+static int stm32_ospi_transfer_one_message(struct spi_controller *ctrl,
+					   struct spi_message *msg)
+{
+	struct stm32_ospi *ospi = spi_controller_get_devdata(ctrl);
+	struct spi_transfer *transfer;
+	struct spi_device *spi = msg->spi;
+	struct spi_mem_op op;
+	struct gpio_desc *cs_gpiod = spi->cs_gpiod[ffs(spi->cs_index_mask) - 1];
+	int ret = 0;
+
+	if (!cs_gpiod)
+		return -EOPNOTSUPP;
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&ospi->lock);
+
+	gpiod_set_value_cansleep(cs_gpiod, true);
+
+	list_for_each_entry(transfer, &msg->transfers, transfer_list) {
+		u8 dummy_bytes = 0;
+
+		memset(&op, 0, sizeof(op));
+
+		dev_dbg(ospi->dev, "tx_buf:%p tx_nbits:%d rx_buf:%p rx_nbits:%d len:%d dummy_data:%d\n",
+			transfer->tx_buf, transfer->tx_nbits,
+			transfer->rx_buf, transfer->rx_nbits,
+			transfer->len, transfer->dummy_data);
+
+		/*
+		 * OSPI hardware supports dummy bytes transfer.
+		 * If current transfer is dummy byte, merge it with the next
+		 * transfer in order to take into account OSPI block constraint
+		 */
+		if (transfer->dummy_data) {
+			op.dummy.buswidth = transfer->tx_nbits;
+			op.dummy.nbytes = transfer->len;
+			dummy_bytes = transfer->len;
+
+			/* If happens, means that message is not correctly built */
+			if (list_is_last(&transfer->transfer_list, &msg->transfers)) {
+				ret = -EINVAL;
+				goto end_of_transfer;
+			}
+
+			transfer = list_next_entry(transfer, transfer_list);
+		}
+
+		op.data.nbytes = transfer->len;
+
+		if (transfer->rx_buf) {
+			ospi->fmode = CR_FMODE_INDR;
+			op.data.buswidth = transfer->rx_nbits;
+			op.data.dir = SPI_MEM_DATA_IN;
+			op.data.buf.in = transfer->rx_buf;
+		} else {
+			ospi->fmode = CR_FMODE_INDW;
+			op.data.buswidth = transfer->tx_nbits;
+			op.data.dir = SPI_MEM_DATA_OUT;
+			op.data.buf.out = transfer->tx_buf;
+		}
+
+		ret = stm32_ospi_send(spi, &op);
+		if (ret)
+			goto end_of_transfer;
+
+		msg->actual_length += transfer->len + dummy_bytes;
+	}
+
+end_of_transfer:
+	gpiod_set_value_cansleep(cs_gpiod, false);
+
+	mutex_unlock(&ospi->lock);
+
+	msg->status = ret;
+	spi_finalize_current_message(ctrl);
+
+	pm_runtime_mark_last_busy(ospi->dev);
+	pm_runtime_put_autosuspend(ospi->dev);
+
+	return ret;
+}
+
+static int stm32_ospi_setup(struct spi_device *spi)
+{
+	struct spi_controller *ctrl = spi->controller;
+	struct stm32_ospi *ospi = spi_controller_get_devdata(ctrl);
+	void __iomem *regs_base = ospi->regs_base;
+	int ret;
+	u8 cs = spi->chip_select[ffs(spi->cs_index_mask) - 1];
+
+	if (ctrl->busy)
+		return -EBUSY;
+
+	if (!spi->max_speed_hz)
+		return -EINVAL;
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		return ret;
+
+	ospi->flash_presc[cs] = DIV_ROUND_UP(ospi->clk_rate, spi->max_speed_hz) - 1;
+
+	mutex_lock(&ospi->lock);
+
+	ospi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_EN;
+	writel_relaxed(ospi->cr_reg, regs_base + OSPI_CR);
+
+	/* set dcr fsize to max address */
+	ospi->dcr_reg = DCR1_DEVSIZE_MASK | DCR1_DLYBYP;
+	writel_relaxed(ospi->dcr_reg, regs_base + OSPI_DCR1);
+
+	mutex_unlock(&ospi->lock);
+
+	pm_runtime_mark_last_busy(ospi->dev);
+	pm_runtime_put_autosuspend(ospi->dev);
+
+	return 0;
+}
+
+/*
+ * No special host constraint, so use default spi_mem_default_supports_op
+ * to check supported mode.
+ */
+static const struct spi_controller_mem_ops stm32_ospi_mem_ops = {
+	.exec_op	= stm32_ospi_exec_op,
+	.dirmap_create	= stm32_ospi_dirmap_create,
+	.dirmap_read	= stm32_ospi_dirmap_read,
+	.poll_status	= stm32_ospi_poll_status,
+};
+
+static int stm32_ospi_get_resources(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct stm32_ospi *ospi = platform_get_drvdata(pdev);
+	struct resource *res;
+	struct reserved_mem *rmem = NULL;
+	struct device_node *node;
+	int ret;
+
+	ospi->regs_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(ospi->regs_base))
+		return PTR_ERR(ospi->regs_base);
+
+	ospi->regs_phys_base = res->start;
+
+	ospi->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(ospi->clk))
+		return dev_err_probe(dev, PTR_ERR(ospi->clk),
+				     "Can't get clock\n");
+
+	ospi->clk_rate = clk_get_rate(ospi->clk);
+	if (!ospi->clk_rate) {
+		dev_err(dev, "Invalid clock rate\n");
+		return -EINVAL;
+	}
+
+	ospi->irq = platform_get_irq(pdev, 0);
+	if (ospi->irq < 0) {
+		dev_err(dev, "Can't get irq %d\n", ospi->irq);
+		return ospi->irq;
+	}
+
+	ret = devm_request_irq(dev, ospi->irq, stm32_ospi_irq, 0,
+			       dev_name(dev), ospi);
+	if (ret) {
+		dev_err(dev, "Failed to request irq\n");
+		return ret;
+	}
+
+	ospi->rstc = devm_reset_control_array_get_optional_exclusive(dev);
+	if (IS_ERR(ospi->rstc))
+		return dev_err_probe(dev, PTR_ERR(ospi->rstc),
+				     "Can't get reset\n");
+
+	ospi->dma_chrx = dma_request_chan(dev, "rx");
+	if (IS_ERR(ospi->dma_chrx)) {
+		ret = PTR_ERR(ospi->dma_chrx);
+		ospi->dma_chrx = NULL;
+		if (ret == -EPROBE_DEFER)
+			goto err_dma;
+	}
+
+	ospi->dma_chtx = dma_request_chan(dev, "tx");
+	if (IS_ERR(ospi->dma_chtx)) {
+		ret = PTR_ERR(ospi->dma_chtx);
+		ospi->dma_chtx = NULL;
+		if (ret == -EPROBE_DEFER)
+			goto err_dma;
+	}
+
+	node = of_parse_phandle(dev->of_node, "memory-region", 0);
+	if (node)
+		rmem = of_reserved_mem_lookup(node);
+	of_node_put(node);
+
+	if (rmem) {
+		ospi->mm_size = rmem->size;
+		ospi->mm_base = devm_ioremap(dev, rmem->base, rmem->size);
+		if (IS_ERR(ospi->mm_base)) {
+			dev_err(dev, "unable to map memory region: %pa+%pa\n",
+				&rmem->base, &rmem->size);
+			ret = PTR_ERR(ospi->mm_base);
+			goto err_dma;
+		}
+
+		if (ospi->mm_size > STM32_OSPI_MAX_MMAP_SZ) {
+			dev_err(dev, "Memory map size outsize bounds\n");
+			ret = -EINVAL;
+			goto err_dma;
+		}
+	} else {
+		dev_info(dev, "No memory-map region found\n");
+	}
+
+	init_completion(&ospi->data_completion);
+	init_completion(&ospi->match_completion);
+
+	return 0;
+
+err_dma:
+	dev_info(dev, "Can't get all resources (%d)\n", ret);
+
+	if (ospi->dma_chtx)
+		dma_release_channel(ospi->dma_chtx);
+	if (ospi->dma_chrx)
+		dma_release_channel(ospi->dma_chrx);
+
+	return ret;
+};
+
+static int stm32_ospi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct spi_controller *ctrl;
+	struct stm32_ospi *ospi;
+	struct dma_slave_config dma_cfg;
+	struct device_node *child;
+	int ret;
+	u8 spi_flash_count = 0;
+
+	/*
+	 * Flash subnodes sanity check:
+	 *        1 or 2 spi-nand/spi-nor flashes		=> supported
+	 *	  All other flash node configuration		=> not supported
+	 */
+	for_each_available_child_of_node(dev->of_node, child) {
+		if (of_device_is_compatible(child, "jedec,spi-nor") ||
+		    of_device_is_compatible(child, "spi-nand"))
+			spi_flash_count++;
+	}
+
+	if (spi_flash_count == 0 || spi_flash_count > 2) {
+		dev_err(dev, "Incorrect DT flash node\n");
+		return -ENODEV;
+	}
+
+	ctrl = devm_spi_alloc_host(dev, sizeof(*ospi));
+	if (!ctrl)
+		return -ENOMEM;
+
+	ospi = spi_controller_get_devdata(ctrl);
+	ospi->ctrl = ctrl;
+
+	ospi->dev = &pdev->dev;
+	platform_set_drvdata(pdev, ospi);
+
+	ret = stm32_ospi_get_resources(pdev);
+	if (ret)
+		return ret;
+
+	memset(&dma_cfg, 0, sizeof(dma_cfg));
+	dma_cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_cfg.src_addr = ospi->regs_phys_base + OSPI_DR;
+	dma_cfg.dst_addr = ospi->regs_phys_base + OSPI_DR;
+	dma_cfg.src_maxburst = 4;
+	dma_cfg.dst_maxburst = 4;
+	stm32_ospi_dma_setup(ospi, &dma_cfg);
+
+	mutex_init(&ospi->lock);
+
+	ctrl->mode_bits = SPI_RX_DUAL | SPI_RX_QUAD |
+			  SPI_TX_DUAL | SPI_TX_QUAD |
+			  SPI_TX_OCTAL | SPI_RX_OCTAL;
+	ctrl->flags = SPI_CONTROLLER_HALF_DUPLEX;
+	ctrl->setup = stm32_ospi_setup;
+	ctrl->bus_num = -1;
+	ctrl->mem_ops = &stm32_ospi_mem_ops;
+	ctrl->use_gpio_descriptors = true;
+	ctrl->transfer_one_message = stm32_ospi_transfer_one_message;
+	ctrl->num_chipselect = STM32_OSPI_MAX_NORCHIP;
+	ctrl->dev.of_node = dev->of_node;
+
+	pm_runtime_enable(ospi->dev);
+	pm_runtime_set_autosuspend_delay(ospi->dev, STM32_AUTOSUSPEND_DELAY);
+	pm_runtime_use_autosuspend(ospi->dev);
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		goto err_pm_enable;
+
+	if (ospi->rstc) {
+		reset_control_assert(ospi->rstc);
+		udelay(2);
+		reset_control_deassert(ospi->rstc);
+	}
+
+	ret = spi_register_controller(ctrl);
+	if (ret) {
+		/* Disable ospi */
+		writel_relaxed(0, ospi->regs_base + OSPI_CR);
+		goto err_pm_resume;
+	}
+
+	pm_runtime_mark_last_busy(ospi->dev);
+	pm_runtime_put_autosuspend(ospi->dev);
+
+	return 0;
+
+err_pm_resume:
+	pm_runtime_put_sync_suspend(ospi->dev);
+
+err_pm_enable:
+	pm_runtime_force_suspend(ospi->dev);
+	mutex_destroy(&ospi->lock);
+
+	return ret;
+}
+
+static void stm32_ospi_remove(struct platform_device *pdev)
+{
+	struct stm32_ospi *ospi = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		return;
+
+	spi_unregister_controller(ospi->ctrl);
+	/* Disable ospi */
+	writel_relaxed(0, ospi->regs_base + OSPI_CR);
+	mutex_destroy(&ospi->lock);
+
+	if (ospi->dma_chtx)
+		dma_release_channel(ospi->dma_chtx);
+	if (ospi->dma_chrx)
+		dma_release_channel(ospi->dma_chrx);
+
+	pm_runtime_put_sync_suspend(ospi->dev);
+	pm_runtime_force_suspend(ospi->dev);
+}
+
+static int __maybe_unused stm32_ospi_suspend(struct device *dev)
+{
+	struct stm32_ospi *ospi = dev_get_drvdata(dev);
+
+	pinctrl_pm_select_sleep_state(dev);
+
+	return pm_runtime_force_suspend(ospi->dev);
+}
+
+static int __maybe_unused stm32_ospi_resume(struct device *dev)
+{
+	struct stm32_ospi *ospi = dev_get_drvdata(dev);
+	void __iomem *regs_base = ospi->regs_base;
+	int ret;
+
+	ret = pm_runtime_force_resume(ospi->dev);
+	if (ret < 0)
+		return ret;
+
+	pinctrl_pm_select_default_state(dev);
+
+	ret = pm_runtime_resume_and_get(ospi->dev);
+	if (ret < 0)
+		return ret;
+
+	writel_relaxed(ospi->cr_reg, regs_base + OSPI_CR);
+	writel_relaxed(ospi->dcr_reg, regs_base + OSPI_DCR1);
+	pm_runtime_mark_last_busy(ospi->dev);
+	pm_runtime_put_autosuspend(ospi->dev);
+
+	return 0;
+}
+
+static int __maybe_unused stm32_ospi_runtime_suspend(struct device *dev)
+{
+	struct stm32_ospi *ospi = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(ospi->clk);
+
+	return 0;
+}
+
+static int __maybe_unused stm32_ospi_runtime_resume(struct device *dev)
+{
+	struct stm32_ospi *ospi = dev_get_drvdata(dev);
+
+	return clk_prepare_enable(ospi->clk);
+}
+
+static const struct dev_pm_ops stm32_ospi_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(stm32_ospi_suspend, stm32_ospi_resume)
+	SET_RUNTIME_PM_OPS(stm32_ospi_runtime_suspend,
+			   stm32_ospi_runtime_resume, NULL)
+};
+
+static const struct of_device_id stm32_ospi_of_match[] = {
+	{ .compatible = "st,stm32mp25-ospi" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_ospi_of_match);
+
+static struct platform_driver stm32_ospi_driver = {
+	.probe	= stm32_ospi_probe,
+	.remove	= stm32_ospi_remove,
+	.driver	= {
+		.name = "stm32-ospi",
+		.pm = &stm32_ospi_pm_ops,
+		.of_match_table = stm32_ospi_of_match,
+	},
+};
+module_platform_driver(stm32_ospi_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 OCTO SPI driver");
+MODULE_LICENSE("GPL");
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 3/8] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 2/8] spi: stm32: Add OSPI driver patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-13  8:00   ` Krzysztof Kozlowski
  2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Add bindings for STM32 Octo Memory Manager (OMM) controller.

OMM manages:
  - the muxing between 2 OSPI busses and 2 output ports.
    There are 4 possible muxing configurations:
      - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
        output is on port 2
      - OSPI1 and OSPI2 are multiplexed over the same output port 1
      - swapped mode (no multiplexing), OSPI1 output is on port 2,
        OSPI2 output is on port 1
      - OSPI1 and OSPI2 are multiplexed over the same output port 2
  - the split of the memory area shared between the 2 OSPI instances.
  - chip select selection override.
  - the time between 2 transactions in multiplexed mode.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
 .../memory-controllers/st,stm32mp25-omm.yaml  | 201 ++++++++++++++++++
 1 file changed, 201 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml

diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
new file mode 100644
index 000000000000..c897e6bf490d
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
@@ -0,0 +1,201 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/st,stm32mp25-omm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32 Octo Memory Manager (OMM)
+
+maintainers:
+  - Patrice Chotard <patrice.chotard@foss.st.com>
+
+description: |
+  The STM32 Octo Memory Manager is a low-level interface that enables an
+  efficient OCTOSPI pin assignment with a full I/O matrix (before alternate
+  function map) and multiplex of single/dual/quad/octal SPI interfaces over
+  the same bus. It Supports up to:
+    - Two single/dual/quad/octal SPI interfaces
+    - Two ports for pin assignment
+
+properties:
+  compatible:
+    const: st,stm32mp25-omm
+
+  "#address-cells":
+    const: 2
+
+  "#size-cells":
+    const: 1
+
+  ranges:
+    description: |
+      Reflects the memory layout with four integer values per OSPI instance.
+      Format:
+      <chip-select> 0 <registers base address> <size>
+    minItems: 2
+    maxItems: 2
+
+  reg:
+    items:
+      - description: OMM registers
+      - description: OMM memory map area
+
+  reg-names:
+    items:
+      - const: regs
+      - const: memory_map
+
+  memory-region:
+    description: |
+      Memory region shared between the 2 OCTOSPI instance.
+      One or two phandle to a node describing a memory mapped region
+      depending of child number.
+    minItems: 1
+    maxItems: 2
+
+  memory-region-names:
+    description: |
+      OCTOSPI instance's name to which memory region is associated
+    items:
+      enum: [ospi1, ospi2]
+    minItems: 1
+    maxItems: 2
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  access-controllers:
+    maxItems: 1
+
+  st,syscfg-amcr:
+    $ref: /schemas/types.yaml#/definitions/phandle-array
+    description: |
+      The Address Mapping Control Register (AMCR) is used to split the 256MB
+      memory map area shared between the 2 OSPI instance. The Octo Memory
+      Manager sets the AMCR depending of the memory-region configuration.
+      The memory split bitmask description is:
+        - 000: OCTOSPI1 (256 Mbytes), OCTOSPI2 unmapped
+        - 001: OCTOSPI1 (192 Mbytes), OCTOSPI2 (64 Mbytes)
+        - 010: OCTOSPI1 (128 Mbytes), OCTOSPI2 (128 Mbytes)
+        - 011: OCTOSPI1 (64 Mbytes), OCTOSPI2 (192 Mbytes)
+        - 1xx: OCTOSPI1 unmapped, OCTOSPI2 (256 Mbytes)
+    items:
+      - description: phandle to syscfg
+      - description: register offset within syscfg
+      - description: register bitmask for memory split
+
+  st,omm-req2ack-ns:
+    description: |
+      In multiplexed mode (MUXEN = 1), this field defines the time in
+      nanoseconds between two transactions.
+
+  st,omm-cssel-ovr:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      Configure the chip select selector override for the 2 OCTOSPIs.
+      - 0: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS1
+      - 1: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS1
+      - 2: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS2
+      - 3: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS2
+    minimum: 0
+    maximum: 3
+
+  st,omm-mux:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description: |
+      Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
+      - 0: direct mode, default
+      - 1: mux OCTOSPI1 and OCTOSPI2 to port 1
+      - 2: swapped mode
+      - 3: mux OCTOSPI1 and OCTOSPI2 to port 2
+    minimum: 0
+    maximum: 3
+
+  power-domains:
+    maxItems: 1
+
+patternProperties:
+  ^spi@[a-f0-9]+$:
+    type: object
+    $ref: /schemas/spi/st,stm32mp25-ospi.yaml#
+    description: Required spi child node
+
+required:
+  - compatible
+  - reg
+  - "#address-cells"
+  - "#size-cells"
+  - clocks
+  - st,syscfg-amcr
+  - ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/st,stm32mp25-rcc.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/reset/st,stm32mp25-rcc.h>
+    ommanager@40500000 {
+      compatible = "st,stm32mp25-omm";
+      reg = <0x40500000 0x400>, <0x60000000 0x10000000>;
+      reg-names = "regs", "memory_map";
+      ranges = <0 0 0x40430000 0x400>,
+               <1 0 0x40440000 0x400>;
+      memory-region = <&mm_ospi1>, <&mm_ospi2>;
+      memory-region-names = "ospi1", "ospi2";
+      pinctrl-0 = <&ospi_port1_clk_pins_a
+                   &ospi_port1_io03_pins_a
+                   &ospi_port1_cs0_pins_a>;
+      pinctrl-1 = <&ospi_port1_clk_sleep_pins_a
+                   &ospi_port1_io03_sleep_pins_a
+                   &ospi_port1_cs0_sleep_pins_a>;
+      pinctrl-names = "default", "sleep";
+      clocks = <&rcc CK_BUS_OSPIIOM>;
+      resets = <&rcc OSPIIOM_R>;
+      access-controllers = <&rifsc 111>;
+      power-domains = <&CLUSTER_PD>;
+      #address-cells = <2>;
+      #size-cells = <1>;
+      st,syscfg-amcr = <&syscfg 0x2c00 0x7>;
+      st,omm-req2ack-ns = <0>;
+      st,omm-mux = <0>;
+      st,omm-cssel-ovr = <0>;
+
+      spi@40430000 {
+        compatible = "st,stm32mp25-ospi";
+        reg = <0 0 0x400>;
+        memory-region = <&mm_ospi1>;
+        interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+        dmas = <&hpdma 2 0x62 0x00003121 0x0>,
+               <&hpdma 2 0x42 0x00003112 0x0>;
+        dma-names = "tx", "rx";
+        clocks = <&scmi_clk CK_SCMI_OSPI1>;
+        resets = <&scmi_reset RST_SCMI_OSPI1>, <&scmi_reset RST_SCMI_OSPI1DLL>;
+        access-controllers = <&rifsc 74>;
+        power-domains = <&CLUSTER_PD>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        st,syscfg-dlyb = <&syscfg 0x1000>;
+      };
+
+      spi@40440000 {
+        compatible = "st,stm32mp25-ospi";
+        reg = <1 0 0x400>;
+        memory-region = <&mm_ospi1>;
+        interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+        dmas = <&hpdma 3 0x62 0x00003121 0x0>,
+               <&hpdma 3 0x42 0x00003112 0x0>;
+        dma-names = "tx", "rx";
+        clocks = <&scmi_clk CK_KER_OSPI2>;
+        resets = <&scmi_reset RST_SCMI_OSPI2>, <&scmi_reset RST_SCMI_OSPI1DLL>;
+        access-controllers = <&rifsc 75>;
+        power-domains = <&CLUSTER_PD>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        st,syscfg-dlyb = <&syscfg 0x1000>;
+      };
+    };
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
                   ` (2 preceding siblings ...)
  2025-02-10 13:18 ` [PATCH v3 3/8] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-11 17:04   ` kernel test robot
                     ` (4 more replies)
  2025-02-10 13:18 ` [PATCH v3 5/8] arm64: dts: st: Add OMM node on stm32mp251 patrice.chotard
                   ` (4 subsequent siblings)
  8 siblings, 5 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Octo Memory Manager driver (OMM) manages:
  - the muxing between 2 OSPI busses and 2 output ports.
    There are 4 possible muxing configurations:
      - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
        output is on port 2
      - OSPI1 and OSPI2 are multiplexed over the same output port 1
      - swapped mode (no multiplexing), OSPI1 output is on port 2,
        OSPI2 output is on port 1
      - OSPI1 and OSPI2 are multiplexed over the same output port 2
  - the split of the memory area shared between the 2 OSPI instances.
  - chip select selection override.
  - the time between 2 transactions in multiplexed mode.
  - check firewall access.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
Signed-off-by: Christophe Kerello <christophe.kerello@foss.st.com>
---
 drivers/memory/Kconfig     |  17 ++
 drivers/memory/Makefile    |   1 +
 drivers/memory/stm32_omm.c | 520 +++++++++++++++++++++++++++++++++++++
 3 files changed, 538 insertions(+)
 create mode 100644 drivers/memory/stm32_omm.c

diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c82d8d8a16ea..80c44a6d5bdb 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -225,6 +225,23 @@ config STM32_FMC2_EBI
 	  devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on
 	  SOCs containing the FMC2 External Bus Interface.
 
+config STM32_OMM
+	tristate "STM32 Octo Memory Manager"
+	depends on SPI_STM32_OSPI || TEST_COMPILE
+	help
+	  This driver manages the muxing between the 2 OSPI busses and
+	  the 2 output ports. There are 4 possible muxing configurations:
+	  - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
+	       output is on port 2
+	  - OSPI1 and OSPI2 are multiplexed over the same output port 1
+	  - swapped mode (no multiplexing), OSPI1 output is on port 2,
+	       OSPI2 output is on port 1
+	  - OSPI1 and OSPI2 are multiplexed over the same output port 2
+	  It also manages :
+	    - the split of the memory area shared between the 2 OSPI instances.
+	    - chip select selection override.
+	    - the time between 2 transactions in multiplexed mode.
+
 source "drivers/memory/samsung/Kconfig"
 source "drivers/memory/tegra/Kconfig"
 
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index d2e6ca9abbe0..c1959661bf63 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_DA8XX_DDRCTL)	+= da8xx-ddrctl.o
 obj-$(CONFIG_PL353_SMC)		+= pl353-smc.o
 obj-$(CONFIG_RENESAS_RPCIF)	+= renesas-rpc-if.o
 obj-$(CONFIG_STM32_FMC2_EBI)	+= stm32-fmc2-ebi.o
+obj-$(CONFIG_STM32_OMM)		+= stm32_omm.o
 
 obj-$(CONFIG_SAMSUNG_MC)	+= samsung/
 obj-$(CONFIG_TEGRA_MC)		+= tegra/
diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c
new file mode 100644
index 000000000000..af69137bfba2
--- /dev/null
+++ b/drivers/memory/stm32_omm.c
@@ -0,0 +1,520 @@
+// SPDX-License-Identifier: GPL
+/*
+ * Copyright (C) STMicroelectronics 2024 - All Rights Reserved
+ * Author(s): Patrice Chotard <patrice.chotard@foss.st.com> for STMicroelectronics.
+ */
+
+#include <linux/bus/stm32_firewall_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define OMM_CR			0
+#define CR_MUXEN		BIT(0)
+#define CR_MUXENMODE_MASK	GENMASK(1, 0)
+#define CR_CSSEL_OVR_EN		BIT(4)
+#define CR_CSSEL_OVR_MASK	GENMASK(6, 5)
+#define CR_REQ2ACK_MASK		GENMASK(23, 16)
+
+#define OMM_CHILD_NB		2
+
+struct ospi_child {
+	struct device *dev;
+	struct device_node *node;
+	struct clk *clk;
+};
+
+struct stm32_omm {
+	struct ospi_child child[OMM_CHILD_NB];
+	struct resource *mm_res;
+	struct clk *clk;
+	void __iomem *io_base;
+	u32 cr;
+	u8 nb_child;
+	bool restore_omm;
+};
+
+static int stm32_omm_set_amcr(struct device *dev, bool set)
+{
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+	struct regmap *syscfg_regmap;
+	struct device_node *node;
+	struct resource res, res1;
+	resource_size_t mm_ospi2_size = 0;
+	static const char * const mm_name[] = { "ospi1", "ospi2" };
+	u32 amcr_base, amcr_mask;
+	int ret, i, idx;
+	unsigned int amcr, read_amcr;
+
+	for (i = 0; i < omm->nb_child; i++) {
+		idx = of_property_match_string(dev->of_node,
+					       "memory-region-names",
+					       mm_name[i]);
+		if (idx < 0)
+			continue;
+
+		/* res1 only used on second loop iteration */
+		res1.start = res.start;
+		res1.end = res.end;
+
+		node = of_parse_phandle(dev->of_node, "memory-region", idx);
+		if (!node)
+			continue;
+
+		ret = of_address_to_resource(node, 0, &res);
+		if (ret) {
+			dev_err(dev, "unable to resolve memory region\n");
+			return ret;
+		}
+
+		/* check that memory region fits inside OMM memory map area */
+		if (!resource_contains(omm->mm_res, &res)) {
+			dev_err(dev, "%s doesn't fit inside OMM memory map area\n",
+				mm_name[i]);
+			dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
+				res.start, res.end,
+				omm->mm_res->start, omm->mm_res->end);
+
+			return -EFAULT;
+		}
+
+		if (i == 1) {
+			mm_ospi2_size = resource_size(&res);
+
+			/* check that OMM memory region 1 doesn't overlap memory region 2 */
+			if (resource_overlaps(&res, &res1)) {
+				dev_err(dev, "OMM memory-region %s overlaps memory region %s\n",
+					mm_name[0], mm_name[1]);
+				dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
+					res1.start, res1.end, res.start, res.end);
+
+				return -EFAULT;
+			}
+		}
+	}
+
+	syscfg_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "st,syscfg-amcr");
+	if (IS_ERR(syscfg_regmap)) {
+		dev_err(dev, "Failed to get st,syscfg-amcr property\n");
+		return PTR_ERR(syscfg_regmap);
+	}
+
+	ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 1,
+					 &amcr_base);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 2,
+					 &amcr_mask);
+	if (ret)
+		return ret;
+
+	amcr = mm_ospi2_size / SZ_64M;
+
+	if (set)
+		regmap_update_bits(syscfg_regmap, amcr_base, amcr_mask, amcr);
+
+	/* read AMCR and check coherency with memory-map areas defined in DT */
+	regmap_read(syscfg_regmap, amcr_base, &read_amcr);
+	read_amcr = read_amcr >> (ffs(amcr_mask) - 1);
+
+	if (amcr != read_amcr) {
+		dev_err(dev, "AMCR value not coherent with DT memory-map areas\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int stm32_omm_enable_child_clock(struct device *dev, bool enable)
+{
+	/* As there is only 2 children, remember first child in case of error */
+	struct clk *first_child_clk = NULL;
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+	u8 i;
+	int ret;
+
+	for (i = 0; i < omm->nb_child; i++) {
+		if (enable) {
+			ret = clk_prepare_enable(omm->child[i].clk);
+			if (ret) {
+				if (first_child_clk)
+					clk_disable_unprepare(first_child_clk);
+
+				dev_err(dev, "Can not enable clock\n");
+				return ret;
+			}
+		} else {
+			clk_disable_unprepare(omm->child[i].clk);
+		}
+
+		first_child_clk = omm->child[i].clk;
+	}
+
+	return 0;
+}
+
+static int stm32_omm_configure(struct device *dev)
+{
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+	struct reset_control *rstc;
+	unsigned long clk_rate, clk_rate_max = 0;
+	int ret;
+	u8 i;
+	u32 mux = 0;
+	u32 cssel_ovr = 0;
+	u32 req2ack = 0;
+
+	omm->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(omm->clk)) {
+		dev_err(dev, "Failed to get OMM clock (%ld)\n",
+			PTR_ERR(omm->clk));
+
+		return PTR_ERR(omm->clk);
+	}
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret < 0)
+		return ret;
+
+	/* parse children's clock */
+	for (i = 0; i < omm->nb_child; i++) {
+		clk_rate = clk_get_rate(omm->child[i].clk);
+		if (!clk_rate) {
+			dev_err(dev, "Invalid clock rate\n");
+			goto err_clk_disable;
+		}
+
+		if (clk_rate > clk_rate_max)
+			clk_rate_max = clk_rate;
+	}
+
+	rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
+	if (IS_ERR(rstc)) {
+		ret = dev_err_probe(dev, PTR_ERR(rstc), "reset get failed\n");
+		goto err_clk_disable;
+	}
+
+	reset_control_assert(rstc);
+	udelay(2);
+	reset_control_deassert(rstc);
+
+	omm->cr = readl_relaxed(omm->io_base + OMM_CR);
+	/* optional */
+	ret = of_property_read_u32(dev->of_node, "st,omm-mux", &mux);
+	if (!ret) {
+		if (mux & CR_MUXEN) {
+			ret = of_property_read_u32(dev->of_node, "st,omm-req2ack-ns",
+						   &req2ack);
+			if (!ret && !req2ack) {
+				req2ack = DIV_ROUND_UP(req2ack, NSEC_PER_SEC / clk_rate_max) - 1;
+
+				if (req2ack > 256)
+					req2ack = 256;
+			}
+
+			req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
+
+			omm->cr &= ~CR_REQ2ACK_MASK;
+			omm->cr |= FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
+
+			/*
+			 * If the mux is enabled, the 2 OSPI clocks have to be
+			 * always enabled
+			 */
+			ret = stm32_omm_enable_child_clock(dev, true);
+			if (ret)
+				goto err_clk_disable;
+		}
+
+		omm->cr &= ~CR_MUXENMODE_MASK;
+		omm->cr |= FIELD_PREP(CR_MUXENMODE_MASK, mux);
+	}
+
+	/* optional */
+	ret = of_property_read_u32(dev->of_node, "st,omm-cssel-ovr", &cssel_ovr);
+	if (!ret) {
+		omm->cr &= ~CR_CSSEL_OVR_MASK;
+		omm->cr |= FIELD_PREP(CR_CSSEL_OVR_MASK, cssel_ovr);
+		omm->cr |= CR_CSSEL_OVR_EN;
+	}
+
+	omm->restore_omm = true;
+	writel_relaxed(omm->cr, omm->io_base + OMM_CR);
+
+	ret = stm32_omm_set_amcr(dev, true);
+
+err_clk_disable:
+	pm_runtime_put_sync_suspend(dev);
+
+	return ret;
+}
+
+static int stm32_omm_check_access(struct device *dev, struct device_node *np)
+{
+	struct stm32_firewall firewall;
+	int ret;
+
+	ret = stm32_firewall_get_firewall(np, &firewall, 1);
+	if (ret)
+		return ret;
+
+	return stm32_firewall_grant_access(&firewall);
+}
+
+static int stm32_omm_disable_child(struct device *dev)
+{
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+	struct reset_control *reset;
+	int ret;
+	u8 i;
+
+	for (i = 0; i < omm->nb_child; i++) {
+		ret = clk_prepare_enable(omm->child[i].clk);
+		if (ret) {
+			dev_err(dev, "Can not enable clock\n");
+			return ret;
+		}
+
+		reset = of_reset_control_get_exclusive(omm->child[i].node, 0);
+		if (IS_ERR(reset)) {
+			dev_err(dev, "Can't get child reset\n");
+			return PTR_ERR(reset);
+		};
+
+		/* reset OSPI to ensure CR_EN bit is set to 0 */
+		reset_control_assert(reset);
+		udelay(2);
+		reset_control_deassert(reset);
+
+		reset_control_put(reset);
+		clk_disable_unprepare(omm->child[i].clk);
+	}
+
+	return 0;
+}
+
+static int stm32_omm_probe(struct platform_device *pdev)
+{
+	struct platform_device *vdev;
+	struct device *dev = &pdev->dev;
+	struct stm32_omm *omm;
+	struct clk *clk;
+	int ret;
+	u8 child_access_granted = 0;
+	u8 i, j;
+	bool child_access[OMM_CHILD_NB];
+
+	omm = devm_kzalloc(dev, sizeof(*omm), GFP_KERNEL);
+	if (!omm)
+		return -ENOMEM;
+
+	omm->io_base = devm_platform_ioremap_resource_byname(pdev, "regs");
+	if (IS_ERR(omm->io_base))
+		return PTR_ERR(omm->io_base);
+
+	omm->mm_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory_map");
+	if (IS_ERR(omm->mm_res))
+		return PTR_ERR(omm->mm_res);
+
+	/* check child's access */
+	for_each_child_of_node_scoped(dev->of_node, child) {
+		if (omm->nb_child >= OMM_CHILD_NB) {
+			dev_err(dev, "Bad DT, found too much children\n");
+			ret = -E2BIG;
+			goto err_clk_release;
+		}
+
+		if (!of_device_is_compatible(child, "st,stm32mp25-ospi")) {
+			ret = -EINVAL;
+			goto err_clk_release;
+		}
+
+		ret = stm32_omm_check_access(dev, child);
+		if (ret < 0 && ret != -EACCES)
+			goto err_clk_release;
+
+		child_access[omm->nb_child] = false;
+		if (!ret) {
+			child_access_granted++;
+			child_access[omm->nb_child] = true;
+		}
+
+		omm->child[omm->nb_child].node = child;
+
+		clk = of_clk_get(child, 0);
+		if (IS_ERR(clk)) {
+			dev_err(dev, "Can't get child clock\n");
+			ret = PTR_ERR(clk);
+			goto err_clk_release;
+		};
+
+		omm->child[omm->nb_child].clk = clk;
+		omm->nb_child++;
+	}
+
+	if (omm->nb_child != OMM_CHILD_NB) {
+		ret = -EINVAL;
+		goto err_clk_release;
+	}
+
+	platform_set_drvdata(pdev, omm);
+
+	pm_runtime_enable(dev);
+
+	/* check if OMM's resource access is granted */
+	ret = stm32_omm_check_access(dev, dev->of_node);
+	if (ret < 0 && ret != -EACCES)
+		goto err_clk_release;
+
+	if (!ret && child_access_granted == OMM_CHILD_NB) {
+		/* Ensure both OSPI instance are disabled before configuring OMM */
+		ret = stm32_omm_disable_child(dev);
+		if (ret)
+			goto err_clk_release;
+
+		ret = stm32_omm_configure(dev);
+		if (ret)
+			goto err_clk_release;
+	} else {
+		dev_dbg(dev, "Octo Memory Manager resource's access not granted\n");
+		/*
+		 * AMCR can't be set, so check if current value is coherent
+		 * with memory-map areas defined in DT
+		 */
+		ret = stm32_omm_set_amcr(dev, false);
+		if (ret)
+			goto err_clk_release;
+	}
+
+	/* for each child, if resource access is granted and status "okay", probe it */
+	for (i = 0; i < omm->nb_child; i++) {
+		if (!child_access[i] || !of_device_is_available(omm->child[i].node))
+			continue;
+
+		vdev = of_platform_device_create(omm->child[i].node, NULL, NULL);
+		if (!vdev) {
+			dev_err(dev, "Failed to create Octo Memory Manager child\n");
+			for (j = i; j > 0; --j) {
+				if (omm->child[j].dev)
+					of_platform_device_destroy(omm->child[j].dev, NULL);
+			}
+
+			ret = -EINVAL;
+			goto err_clk_release;
+		}
+		omm->child[i].dev = &vdev->dev;
+	}
+
+err_clk_release:
+	for (i = 0; i < omm->nb_child; i++)
+		clk_put(omm->child[i].clk);
+
+	return ret;
+}
+
+static void stm32_omm_remove(struct platform_device *pdev)
+{
+	struct stm32_omm *omm = platform_get_drvdata(pdev);
+	int i;
+
+	for (i = 0; i < omm->nb_child; i++)
+		if (omm->child[i].dev)
+			of_platform_device_destroy(omm->child[i].dev, NULL);
+
+	if (omm->cr & CR_MUXEN)
+		stm32_omm_enable_child_clock(&pdev->dev, false);
+
+	pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id stm32_omm_of_match[] = {
+	{ .compatible = "st,stm32mp25-omm", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_omm_of_match);
+
+static int __maybe_unused stm32_omm_runtime_suspend(struct device *dev)
+{
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(omm->clk);
+
+	return 0;
+}
+
+static int __maybe_unused stm32_omm_runtime_resume(struct device *dev)
+{
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+
+	return clk_prepare_enable(omm->clk);
+}
+
+static int __maybe_unused stm32_omm_suspend(struct device *dev)
+{
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+
+	if (omm->restore_omm && omm->cr & CR_MUXEN)
+		stm32_omm_enable_child_clock(dev, false);
+
+	return pinctrl_pm_select_sleep_state(dev);
+}
+
+static int __maybe_unused stm32_omm_resume(struct device *dev)
+{
+	struct stm32_omm *omm = dev_get_drvdata(dev);
+	int ret;
+
+	pinctrl_pm_select_default_state(dev);
+
+	if (!omm->restore_omm)
+		return 0;
+
+	/* Ensure both OSPI instance are disabled before configuring OMM */
+	ret = stm32_omm_disable_child(dev);
+	if (ret)
+		return ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret < 0)
+		return ret;
+
+	writel_relaxed(omm->cr, omm->io_base + OMM_CR);
+	ret = stm32_omm_set_amcr(dev, true);
+	pm_runtime_put_sync_suspend(dev);
+	if (ret)
+		return ret;
+
+	if (omm->cr & CR_MUXEN)
+		ret = stm32_omm_enable_child_clock(dev, true);
+
+	return ret;
+}
+
+static const struct dev_pm_ops stm32_omm_pm_ops = {
+	SET_RUNTIME_PM_OPS(stm32_omm_runtime_suspend,
+			   stm32_omm_runtime_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(stm32_omm_suspend, stm32_omm_resume)
+};
+
+static struct platform_driver stm32_omm_driver = {
+	.probe	= stm32_omm_probe,
+	.remove = stm32_omm_remove,
+	.driver	= {
+		.name = "stm32-omm",
+		.of_match_table = stm32_omm_of_match,
+		.pm = &stm32_omm_pm_ops,
+	},
+};
+module_platform_driver(stm32_omm_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics Octo Memory Manager driver");
+MODULE_LICENSE("GPL");
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 5/8] arm64: dts: st: Add OMM node on stm32mp251
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
                   ` (3 preceding siblings ...)
  2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 6/8] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi patrice.chotard
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Add Octo Memory Manager (OMM) entry on stm32mp251 and its two
OSPI instance.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp251.dtsi | 48 ++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index f3c6cdfd7008..2565236e369f 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -768,6 +768,54 @@ rng: rng@42020000 {
 				status = "disabled";
 			};
 
+			ommanager: ommanager@40500000 {
+				compatible = "st,stm32mp25-omm";
+				reg = <0x40500000 0x400>, <0x60000000 0x10000000>;
+				reg-names = "regs", "memory_map";
+				ranges = <0 0 0x40430000 0x400>,
+					 <1 0 0x40440000 0x400>;
+				clocks = <&rcc CK_BUS_OSPIIOM>;
+				resets = <&rcc OSPIIOM_R>;
+				access-controllers = <&rifsc 111>;
+				power-domains = <&CLUSTER_PD>;
+				#address-cells = <2>;
+				#size-cells = <1>;
+				st,syscfg-amcr = <&syscfg 0x2c00 0x7>;
+				status = "disabled";
+
+				ospi1: spi@40430000 {
+					compatible = "st,stm32mp25-ospi";
+					reg = <0 0 0x400>;
+					interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&hpdma 2 0x62 0x00003121>,
+					       <&hpdma 2 0x42 0x00003112>;
+					dma-names = "tx", "rx";
+					clocks = <&scmi_clk CK_SCMI_OSPI1>;
+					resets = <&scmi_reset RST_SCMI_OSPI1>,
+						 <&scmi_reset RST_SCMI_OSPI1DLL>;
+					access-controllers = <&rifsc 74>;
+					power-domains = <&CLUSTER_PD>;
+					st,syscfg-dlyb = <&syscfg 0x1000>;
+					status = "disabled";
+				};
+
+				ospi2: spi@40440000 {
+					compatible = "st,stm32mp25-ospi";
+					reg = <1 0 0x400>;
+					interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+					dmas = <&hpdma 3 0x62 0x00003121>,
+					       <&hpdma 3 0x42 0x00003112>;
+					dma-names = "tx", "rx";
+					clocks = <&scmi_clk CK_SCMI_OSPI2>;
+					resets = <&scmi_reset RST_SCMI_OSPI2>,
+						 <&scmi_reset RST_SCMI_OSPI2DLL>;
+					access-controllers = <&rifsc 75>;
+					power-domains = <&CLUSTER_PD>;
+					st,syscfg-dlyb = <&syscfg 0x1400>;
+					status = "disabled";
+				};
+			};
+
 			spi8: spi@46020000 {
 				#address-cells = <1>;
 				#size-cells = <0>;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 6/8] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
                   ` (4 preceding siblings ...)
  2025-02-10 13:18 ` [PATCH v3 5/8] arm64: dts: st: Add OMM node on stm32mp251 patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 7/8] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board patrice.chotard
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Add pinctrl entry related to OSPI's port1 in stm32mp25-pinctrl.dtsi

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi | 51 +++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
index 8fdd5f020425..cf5be316de26 100644
--- a/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi
@@ -101,6 +101,57 @@ pins2 {
 		};
 	};
 
+	ospi_port1_clk_pins_a: ospi-port1-clk-0 {
+		pins {
+			pinmux = <STM32_PINMUX('D', 0, AF10)>; /* OSPI1_CLK */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <2>;
+		};
+	};
+
+	ospi_port1_clk_sleep_pins_a: ospi-port1-clk-sleep-0 {
+		pins {
+			pinmux = <STM32_PINMUX('D', 0, ANALOG)>; /* OSPI1_CLK */
+		};
+	};
+
+	ospi_port1_cs0_pins_a: ospi-port1-cs0-0 {
+		pins {
+			pinmux = <STM32_PINMUX('D', 3, AF10)>; /* OSPI_NCS0 */
+			bias-pull-up;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+	};
+
+	ospi_port1_cs0_sleep_pins_a: ospi-port1-cs0-sleep-0 {
+		pins {
+			pinmux = <STM32_PINMUX('D', 3, ANALOG)>; /* OSPI_NCS0 */
+		};
+	};
+
+	ospi_port1_io03_pins_a: ospi-port1-io03-0 {
+		pins {
+			pinmux = <STM32_PINMUX('D', 4, AF10)>, /* OSPI_IO0 */
+				 <STM32_PINMUX('D', 5, AF10)>, /* OSPI_IO1 */
+				 <STM32_PINMUX('D', 6, AF10)>, /* OSPI_IO2 */
+				 <STM32_PINMUX('D', 7, AF10)>; /* OSPI_IO3 */
+			bias-disable;
+			drive-push-pull;
+			slew-rate = <0>;
+		};
+	};
+
+	ospi_port1_io03_sleep_pins_a: ospi-port1-io03-sleep-0 {
+		pins {
+			pinmux = <STM32_PINMUX('D', 4, ANALOG)>, /* OSPI_IO0 */
+				 <STM32_PINMUX('D', 5, ANALOG)>, /* OSPI_IO1 */
+				 <STM32_PINMUX('D', 6, ANALOG)>, /* OSPI_IO2 */
+				 <STM32_PINMUX('D', 7, ANALOG)>; /* OSPI_IO3 */
+		};
+	};
+
 	sdmmc1_b4_od_pins_a: sdmmc1-b4-od-0 {
 		pins1 {
 			pinmux = <STM32_PINMUX('E', 4, AF10)>, /* SDMMC1_D0 */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 7/8] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
                   ` (5 preceding siblings ...)
  2025-02-10 13:18 ` [PATCH v3 6/8] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-10 13:18 ` [PATCH v3 8/8] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver patrice.chotard
  2025-02-13  7:56 ` [PATCH v3 0/8] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
  8 siblings, 0 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Add SPI NOR flash nor support on stm32mp257f-ev1 board.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index 1b88485a62a1..76970c15e043 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -80,6 +80,11 @@ fw@80000000 {
 			reg = <0x0 0x80000000 0x0 0x4000000>;
 			no-map;
 		};
+
+		mm_ospi1: mm-ospi@60000000 {
+			reg = <0x0 0x60000000 0x0 0x10000000>;
+			no-map;
+		};
 	};
 };
 
@@ -190,6 +195,33 @@ &i2c8 {
 	status = "disabled";
 };
 
+&ommanager {
+	memory-region = <&mm_ospi1>;
+	pinctrl-0 = <&ospi_port1_clk_pins_a
+		     &ospi_port1_io03_pins_a
+		     &ospi_port1_cs0_pins_a>;
+	pinctrl-1 = <&ospi_port1_clk_sleep_pins_a
+		     &ospi_port1_io03_sleep_pins_a
+		     &ospi_port1_cs0_sleep_pins_a>;
+	pinctrl-names = "default", "sleep";
+	status = "okay";
+
+	spi@40430000 {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		memory-region = <&mm_ospi1>;
+		status = "okay";
+
+		flash0: flash@0 {
+			compatible = "jedec,spi-nor";
+			reg = <0>;
+			spi-rx-bus-width = <4>;
+			spi-tx-bus-width = <4>;
+			spi-max-frequency = <50000000>;
+		};
+	};
+};
+
 &rtc {
 	status = "okay";
 };
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 8/8] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
                   ` (6 preceding siblings ...)
  2025-02-10 13:18 ` [PATCH v3 7/8] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board patrice.chotard
@ 2025-02-10 13:18 ` patrice.chotard
  2025-02-13  7:56 ` [PATCH v3 0/8] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
  8 siblings, 0 replies; 23+ messages in thread
From: patrice.chotard @ 2025-02-10 13:18 UTC (permalink / raw)
  To: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello, patrice.chotard

From: Patrice Chotard <patrice.chotard@foss.st.com>

Enable STM32 OctoSPI driver.
Enable STM32 Octo Memory Manager (OMM) driver which is needed
for OSPI usage on STM32MP257F-EV1 board.

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
 arch/arm64/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 246a13412bf0..b089cf4b90a1 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -577,6 +577,7 @@ CONFIG_SPI_QUP=y
 CONFIG_SPI_QCOM_GENI=m
 CONFIG_SPI_S3C64XX=y
 CONFIG_SPI_SH_MSIOF=m
+CONFIG_SPI_STM32_OSPI=m
 CONFIG_SPI_SUN6I=y
 CONFIG_SPI_TEGRA210_QUAD=m
 CONFIG_SPI_TEGRA114=m
@@ -1506,6 +1507,7 @@ CONFIG_EXTCON_USB_GPIO=y
 CONFIG_EXTCON_USBC_CROS_EC=y
 CONFIG_FSL_IFC=y
 CONFIG_RENESAS_RPCIF=m
+CONFIG_STM32_OMM=m
 CONFIG_IIO=y
 CONFIG_EXYNOS_ADC=y
 CONFIG_IMX8QXP_ADC=m
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
@ 2025-02-11 17:04   ` kernel test robot
  2025-02-11 17:56   ` kernel test robot
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 23+ messages in thread
From: kernel test robot @ 2025-02-11 17:04 UTC (permalink / raw)
  To: patrice.chotard, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: oe-kbuild-all, linux-spi, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel, christophe.kerello,
	patrice.chotard

Hi,

kernel test robot noticed the following build warnings:

[auto build test WARNING on broonie-spi/for-next]
[also build test WARNING on atorgue-stm32/stm32-next krzk-mem-ctrl/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/patrice-chotard-foss-st-com/dt-bindings-spi-Add-STM32-OSPI-controller/20250210-212554
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link:    https://lore.kernel.org/r/20250210131826.220318-5-patrice.chotard%40foss.st.com
patch subject: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20250212/202502120005.pznVoB0E-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250212/202502120005.pznVoB0E-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502120005.pznVoB0E-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/linux/device.h:15,
                    from include/linux/platform_device.h:13,
                    from include/linux/bus/stm32_firewall_device.h:10,
                    from drivers/memory/stm32_omm.c:7:
   drivers/memory/stm32_omm.c: In function 'stm32_omm_set_amcr':
>> drivers/memory/stm32_omm.c:82:38: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:82:25: note: in expansion of macro 'dev_err'
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                         ^~~~~~~
   drivers/memory/stm32_omm.c:82:45: note: format string is defined here
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                          ~~~^
         |                                             |
         |                                             long long unsigned int
         |                                          %x
   drivers/memory/stm32_omm.c:82:38: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:82:25: note: in expansion of macro 'dev_err'
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                         ^~~~~~~
   drivers/memory/stm32_omm.c:82:52: note: format string is defined here
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                 ~~~^
         |                                                    |
         |                                                    long long unsigned int
         |                                                 %x
   drivers/memory/stm32_omm.c:82:38: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 5 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:82:25: note: in expansion of macro 'dev_err'
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                         ^~~~~~~
   drivers/memory/stm32_omm.c:82:80: note: format string is defined here
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                                             ~~~^
         |                                                                                |
         |                                                                                long long unsigned int
         |                                                                             %x
   drivers/memory/stm32_omm.c:82:38: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 6 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:82:25: note: in expansion of macro 'dev_err'
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                         ^~~~~~~
   drivers/memory/stm32_omm.c:82:87: note: format string is defined here
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                                                    ~~~^
         |                                                                                       |
         |                                                                                       long long unsigned int
         |                                                                                    %x
   drivers/memory/stm32_omm.c:96:46: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:96:33: note: in expansion of macro 'dev_err'
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                 ^~~~~~~
   drivers/memory/stm32_omm.c:96:53: note: format string is defined here
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                  ~~~^
         |                                                     |
         |                                                     long long unsigned int
         |                                                  %x
   drivers/memory/stm32_omm.c:96:46: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:96:33: note: in expansion of macro 'dev_err'
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",


vim +82 drivers/memory/stm32_omm.c

    44	
    45	static int stm32_omm_set_amcr(struct device *dev, bool set)
    46	{
    47		struct stm32_omm *omm = dev_get_drvdata(dev);
    48		struct regmap *syscfg_regmap;
    49		struct device_node *node;
    50		struct resource res, res1;
    51		resource_size_t mm_ospi2_size = 0;
    52		static const char * const mm_name[] = { "ospi1", "ospi2" };
    53		u32 amcr_base, amcr_mask;
    54		int ret, i, idx;
    55		unsigned int amcr, read_amcr;
    56	
    57		for (i = 0; i < omm->nb_child; i++) {
    58			idx = of_property_match_string(dev->of_node,
    59						       "memory-region-names",
    60						       mm_name[i]);
    61			if (idx < 0)
    62				continue;
    63	
    64			/* res1 only used on second loop iteration */
    65			res1.start = res.start;
    66			res1.end = res.end;
    67	
    68			node = of_parse_phandle(dev->of_node, "memory-region", idx);
    69			if (!node)
    70				continue;
    71	
    72			ret = of_address_to_resource(node, 0, &res);
    73			if (ret) {
    74				dev_err(dev, "unable to resolve memory region\n");
    75				return ret;
    76			}
    77	
    78			/* check that memory region fits inside OMM memory map area */
    79			if (!resource_contains(omm->mm_res, &res)) {
    80				dev_err(dev, "%s doesn't fit inside OMM memory map area\n",
    81					mm_name[i]);
  > 82				dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
    83					res.start, res.end,
    84					omm->mm_res->start, omm->mm_res->end);
    85	
    86				return -EFAULT;
    87			}
    88	
    89			if (i == 1) {
    90				mm_ospi2_size = resource_size(&res);
    91	
    92				/* check that OMM memory region 1 doesn't overlap memory region 2 */
    93				if (resource_overlaps(&res, &res1)) {
    94					dev_err(dev, "OMM memory-region %s overlaps memory region %s\n",
    95						mm_name[0], mm_name[1]);
    96					dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
    97						res1.start, res1.end, res.start, res.end);
    98	
    99					return -EFAULT;
   100				}
   101			}
   102		}
   103	
   104		syscfg_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "st,syscfg-amcr");
   105		if (IS_ERR(syscfg_regmap)) {
   106			dev_err(dev, "Failed to get st,syscfg-amcr property\n");
   107			return PTR_ERR(syscfg_regmap);
   108		}
   109	
   110		ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 1,
   111						 &amcr_base);
   112		if (ret)
   113			return ret;
   114	
   115		ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 2,
   116						 &amcr_mask);
   117		if (ret)
   118			return ret;
   119	
   120		amcr = mm_ospi2_size / SZ_64M;
   121	
   122		if (set)
   123			regmap_update_bits(syscfg_regmap, amcr_base, amcr_mask, amcr);
   124	
   125		/* read AMCR and check coherency with memory-map areas defined in DT */
   126		regmap_read(syscfg_regmap, amcr_base, &read_amcr);
   127		read_amcr = read_amcr >> (ffs(amcr_mask) - 1);
   128	
   129		if (amcr != read_amcr) {
   130			dev_err(dev, "AMCR value not coherent with DT memory-map areas\n");
   131			ret = -EINVAL;
   132		}
   133	
   134		return ret;
   135	}
   136	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
  2025-02-11 17:04   ` kernel test robot
@ 2025-02-11 17:56   ` kernel test robot
  2025-02-11 18:16   ` Christophe JAILLET
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 23+ messages in thread
From: kernel test robot @ 2025-02-11 17:56 UTC (permalink / raw)
  To: patrice.chotard, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: llvm, oe-kbuild-all, linux-spi, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel, christophe.kerello,
	patrice.chotard

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on broonie-spi/for-next]
[also build test ERROR on atorgue-stm32/stm32-next krzk-mem-ctrl/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/patrice-chotard-foss-st-com/dt-bindings-spi-Add-STM32-OSPI-controller/20250210-212554
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link:    https://lore.kernel.org/r/20250210131826.220318-5-patrice.chotard%40foss.st.com
patch subject: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20250212/202502120118.27fjrRqt-lkp@intel.com/config)
compiler: clang version 21.0.0git (https://github.com/llvm/llvm-project 6807164500e9920638e2ab0cdb4bf8321d24f8eb)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250212/202502120118.27fjrRqt-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502120118.27fjrRqt-lkp@intel.com/

All error/warnings (new ones prefixed by >>):

>> drivers/memory/stm32_omm.c:83:5: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                          ~~~~
         |                                          %x
      83 |                                 res.start, res.end,
         |                                 ^~~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/memory/stm32_omm.c:83:16: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                 ~~~~
         |                                                 %x
      83 |                                 res.start, res.end,
         |                                            ^~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/memory/stm32_omm.c:84:5: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                                             ~~~~
         |                                                                             %x
      83 |                                 res.start, res.end,
      84 |                                 omm->mm_res->start, omm->mm_res->end);
         |                                 ^~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/memory/stm32_omm.c:84:25: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                                                    ~~~~
         |                                                                                    %x
      83 |                                 res.start, res.end,
      84 |                                 omm->mm_res->start, omm->mm_res->end);
         |                                                     ^~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/memory/stm32_omm.c:97:6: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                  ~~~~
         |                                                  %x
      97 |                                         res1.start, res1.end, res.start, res.end);
         |                                         ^~~~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/memory/stm32_omm.c:97:18: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                         ~~~~
         |                                                         %x
      97 |                                         res1.start, res1.end, res.start, res.end);
         |                                                     ^~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/memory/stm32_omm.c:97:28: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                                           ~~~~
         |                                                                           %x
      97 |                                         res1.start, res1.end, res.start, res.end);
         |                                                               ^~~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/memory/stm32_omm.c:97:39: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                                                  ~~~~
         |                                                                                  %x
      97 |                                         res1.start, res1.end, res.start, res.end);
         |                                                                          ^~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
>> drivers/memory/stm32_omm.c:224:14: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     224 |                         req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
         |                                   ^
   drivers/memory/stm32_omm.c:239:14: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     239 |                 omm->cr |= FIELD_PREP(CR_MUXENMODE_MASK, mux);
         |                            ^
   drivers/memory/stm32_omm.c:246:14: error: call to undeclared function 'FIELD_PREP'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     246 |                 omm->cr |= FIELD_PREP(CR_CSSEL_OVR_MASK, cssel_ovr);
         |                            ^
   8 warnings and 3 errors generated.


vim +/FIELD_PREP +224 drivers/memory/stm32_omm.c

    44	
    45	static int stm32_omm_set_amcr(struct device *dev, bool set)
    46	{
    47		struct stm32_omm *omm = dev_get_drvdata(dev);
    48		struct regmap *syscfg_regmap;
    49		struct device_node *node;
    50		struct resource res, res1;
    51		resource_size_t mm_ospi2_size = 0;
    52		static const char * const mm_name[] = { "ospi1", "ospi2" };
    53		u32 amcr_base, amcr_mask;
    54		int ret, i, idx;
    55		unsigned int amcr, read_amcr;
    56	
    57		for (i = 0; i < omm->nb_child; i++) {
    58			idx = of_property_match_string(dev->of_node,
    59						       "memory-region-names",
    60						       mm_name[i]);
    61			if (idx < 0)
    62				continue;
    63	
    64			/* res1 only used on second loop iteration */
    65			res1.start = res.start;
    66			res1.end = res.end;
    67	
    68			node = of_parse_phandle(dev->of_node, "memory-region", idx);
    69			if (!node)
    70				continue;
    71	
    72			ret = of_address_to_resource(node, 0, &res);
    73			if (ret) {
    74				dev_err(dev, "unable to resolve memory region\n");
    75				return ret;
    76			}
    77	
    78			/* check that memory region fits inside OMM memory map area */
    79			if (!resource_contains(omm->mm_res, &res)) {
    80				dev_err(dev, "%s doesn't fit inside OMM memory map area\n",
    81					mm_name[i]);
    82				dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
  > 83					res.start, res.end,
    84					omm->mm_res->start, omm->mm_res->end);
    85	
    86				return -EFAULT;
    87			}
    88	
    89			if (i == 1) {
    90				mm_ospi2_size = resource_size(&res);
    91	
    92				/* check that OMM memory region 1 doesn't overlap memory region 2 */
    93				if (resource_overlaps(&res, &res1)) {
    94					dev_err(dev, "OMM memory-region %s overlaps memory region %s\n",
    95						mm_name[0], mm_name[1]);
    96					dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
    97						res1.start, res1.end, res.start, res.end);
    98	
    99					return -EFAULT;
   100				}
   101			}
   102		}
   103	
   104		syscfg_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "st,syscfg-amcr");
   105		if (IS_ERR(syscfg_regmap)) {
   106			dev_err(dev, "Failed to get st,syscfg-amcr property\n");
   107			return PTR_ERR(syscfg_regmap);
   108		}
   109	
   110		ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 1,
   111						 &amcr_base);
   112		if (ret)
   113			return ret;
   114	
   115		ret = of_property_read_u32_index(dev->of_node, "st,syscfg-amcr", 2,
   116						 &amcr_mask);
   117		if (ret)
   118			return ret;
   119	
   120		amcr = mm_ospi2_size / SZ_64M;
   121	
   122		if (set)
   123			regmap_update_bits(syscfg_regmap, amcr_base, amcr_mask, amcr);
   124	
   125		/* read AMCR and check coherency with memory-map areas defined in DT */
   126		regmap_read(syscfg_regmap, amcr_base, &read_amcr);
   127		read_amcr = read_amcr >> (ffs(amcr_mask) - 1);
   128	
   129		if (amcr != read_amcr) {
   130			dev_err(dev, "AMCR value not coherent with DT memory-map areas\n");
   131			ret = -EINVAL;
   132		}
   133	
   134		return ret;
   135	}
   136	
   137	static int stm32_omm_enable_child_clock(struct device *dev, bool enable)
   138	{
   139		/* As there is only 2 children, remember first child in case of error */
   140		struct clk *first_child_clk = NULL;
   141		struct stm32_omm *omm = dev_get_drvdata(dev);
   142		u8 i;
   143		int ret;
   144	
   145		for (i = 0; i < omm->nb_child; i++) {
   146			if (enable) {
   147				ret = clk_prepare_enable(omm->child[i].clk);
   148				if (ret) {
   149					if (first_child_clk)
   150						clk_disable_unprepare(first_child_clk);
   151	
   152					dev_err(dev, "Can not enable clock\n");
   153					return ret;
   154				}
   155			} else {
   156				clk_disable_unprepare(omm->child[i].clk);
   157			}
   158	
   159			first_child_clk = omm->child[i].clk;
   160		}
   161	
   162		return 0;
   163	}
   164	
   165	static int stm32_omm_configure(struct device *dev)
   166	{
   167		struct stm32_omm *omm = dev_get_drvdata(dev);
   168		struct reset_control *rstc;
   169		unsigned long clk_rate, clk_rate_max = 0;
   170		int ret;
   171		u8 i;
   172		u32 mux = 0;
   173		u32 cssel_ovr = 0;
   174		u32 req2ack = 0;
   175	
   176		omm->clk = devm_clk_get(dev, NULL);
   177		if (IS_ERR(omm->clk)) {
   178			dev_err(dev, "Failed to get OMM clock (%ld)\n",
   179				PTR_ERR(omm->clk));
   180	
   181			return PTR_ERR(omm->clk);
   182		}
   183	
   184		ret = pm_runtime_resume_and_get(dev);
   185		if (ret < 0)
   186			return ret;
   187	
   188		/* parse children's clock */
   189		for (i = 0; i < omm->nb_child; i++) {
   190			clk_rate = clk_get_rate(omm->child[i].clk);
   191			if (!clk_rate) {
   192				dev_err(dev, "Invalid clock rate\n");
   193				goto err_clk_disable;
   194			}
   195	
   196			if (clk_rate > clk_rate_max)
   197				clk_rate_max = clk_rate;
   198		}
   199	
   200		rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
   201		if (IS_ERR(rstc)) {
   202			ret = dev_err_probe(dev, PTR_ERR(rstc), "reset get failed\n");
   203			goto err_clk_disable;
   204		}
   205	
   206		reset_control_assert(rstc);
   207		udelay(2);
   208		reset_control_deassert(rstc);
   209	
   210		omm->cr = readl_relaxed(omm->io_base + OMM_CR);
   211		/* optional */
   212		ret = of_property_read_u32(dev->of_node, "st,omm-mux", &mux);
   213		if (!ret) {
   214			if (mux & CR_MUXEN) {
   215				ret = of_property_read_u32(dev->of_node, "st,omm-req2ack-ns",
   216							   &req2ack);
   217				if (!ret && !req2ack) {
   218					req2ack = DIV_ROUND_UP(req2ack, NSEC_PER_SEC / clk_rate_max) - 1;
   219	
   220					if (req2ack > 256)
   221						req2ack = 256;
   222				}
   223	
 > 224				req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
   225	
   226				omm->cr &= ~CR_REQ2ACK_MASK;
   227				omm->cr |= FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
   228	
   229				/*
   230				 * If the mux is enabled, the 2 OSPI clocks have to be
   231				 * always enabled
   232				 */
   233				ret = stm32_omm_enable_child_clock(dev, true);
   234				if (ret)
   235					goto err_clk_disable;
   236			}
   237	
   238			omm->cr &= ~CR_MUXENMODE_MASK;
   239			omm->cr |= FIELD_PREP(CR_MUXENMODE_MASK, mux);
   240		}
   241	
   242		/* optional */
   243		ret = of_property_read_u32(dev->of_node, "st,omm-cssel-ovr", &cssel_ovr);
   244		if (!ret) {
   245			omm->cr &= ~CR_CSSEL_OVR_MASK;
   246			omm->cr |= FIELD_PREP(CR_CSSEL_OVR_MASK, cssel_ovr);
   247			omm->cr |= CR_CSSEL_OVR_EN;
   248		}
   249	
   250		omm->restore_omm = true;
   251		writel_relaxed(omm->cr, omm->io_base + OMM_CR);
   252	
   253		ret = stm32_omm_set_amcr(dev, true);
   254	
   255	err_clk_disable:
   256		pm_runtime_put_sync_suspend(dev);
   257	
   258		return ret;
   259	}
   260	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
  2025-02-11 17:04   ` kernel test robot
  2025-02-11 17:56   ` kernel test robot
@ 2025-02-11 18:16   ` Christophe JAILLET
  2025-02-12 16:17     ` Patrice CHOTARD
  2025-02-12  3:19   ` kernel test robot
  2025-02-12 12:51   ` Geert Uytterhoeven
  4 siblings, 1 reply; 23+ messages in thread
From: Christophe JAILLET @ 2025-02-11 18:16 UTC (permalink / raw)
  To: patrice.chotard
  Cc: alexandre.torgue, arnd, broonie, catalin.marinas,
	christophe.kerello, conor+dt, devicetree, gregkh, krzk+dt,
	linux-arm-kernel, linux-kernel, linux-spi, linux-stm32,
	mcoquelin.stm32, p.zabel, robh, will

Le 10/02/2025 à 14:18, 
patrice.chotard-rj0Iel/JR4NBDgjK7y7TUQ@public.gmane.org a écrit :
> From: Patrice Chotard <patrice.chotard-rj0Iel/JR4NBDgjK7y7TUQ@public.gmane.org>
> 
> Octo Memory Manager driver (OMM) manages:
>    - the muxing between 2 OSPI busses and 2 output ports.
>      There are 4 possible muxing configurations:
>        - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>          output is on port 2
>        - OSPI1 and OSPI2 are multiplexed over the same output port 1
>        - swapped mode (no multiplexing), OSPI1 output is on port 2,
>          OSPI2 output is on port 1
>        - OSPI1 and OSPI2 are multiplexed over the same output port 2
>    - the split of the memory area shared between the 2 OSPI instances.
>    - chip select selection override.
>    - the time between 2 transactions in multiplexed mode.
>    - check firewall access.

...

> diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c
> new file mode 100644
> index 000000000000..af69137bfba2
> --- /dev/null
> +++ b/drivers/memory/stm32_omm.c
> @@ -0,0 +1,520 @@
> +// SPDX-License-Identifier: GPL

Not sure this SPDX-License-Identifier exists.

> +/*
> + * Copyright (C) STMicroelectronics 2024 - All Rights Reserved

...

> +	pm_runtime_enable(dev);
> +
> +	/* check if OMM's resource access is granted */
> +	ret = stm32_omm_check_access(dev, dev->of_node);
> +	if (ret < 0 && ret != -EACCES)
> +		goto err_clk_release;

Should we call, here and below, pm_runtime_disable() in the error 
handling path, as done in the remove function?

> +
> +	if (!ret && child_access_granted == OMM_CHILD_NB) {
> +		/* Ensure both OSPI instance are disabled before configuring OMM */
> +		ret = stm32_omm_disable_child(dev);
> +		if (ret)
> +			goto err_clk_release;
> +
> +		ret = stm32_omm_configure(dev);
> +		if (ret)
> +			goto err_clk_release;
> +	} else {
> +		dev_dbg(dev, "Octo Memory Manager resource's access not granted\n");
> +		/*
> +		 * AMCR can't be set, so check if current value is coherent
> +		 * with memory-map areas defined in DT
> +		 */
> +		ret = stm32_omm_set_amcr(dev, false);
> +		if (ret)
> +			goto err_clk_release;
> +	}
> +
> +	/* for each child, if resource access is granted and status "okay", probe it */
> +	for (i = 0; i < omm->nb_child; i++) {
> +		if (!child_access[i] || !of_device_is_available(omm->child[i].node))
> +			continue;
> +
> +		vdev = of_platform_device_create(omm->child[i].node, NULL, NULL);
> +		if (!vdev) {
> +			dev_err(dev, "Failed to create Octo Memory Manager child\n");
> +			for (j = i; j > 0; --j) {
> +				if (omm->child[j].dev)
> +					of_platform_device_destroy(omm->child[j].dev, NULL);
> +			}
> +
> +			ret = -EINVAL;
> +			goto err_clk_release;
> +		}
> +		omm->child[i].dev = &vdev->dev;
> +	}
> +
> +err_clk_release:
> +	for (i = 0; i < omm->nb_child; i++)
> +		clk_put(omm->child[i].clk);
> +
> +	return ret;
> +}
> +
> +static void stm32_omm_remove(struct platform_device *pdev)
> +{
> +	struct stm32_omm *omm = platform_get_drvdata(pdev);
> +	int i;
> +
> +	for (i = 0; i < omm->nb_child; i++)
> +		if (omm->child[i].dev)
> +			of_platform_device_destroy(omm->child[i].dev, NULL);
> +
> +	if (omm->cr & CR_MUXEN)
> +		stm32_omm_enable_child_clock(&pdev->dev, false);
> +
> +	pm_runtime_disable(&pdev->dev);

Should we have:
	for (i = 0; i < omm->nb_child; i++)
		clk_put(omm->child[i].clk);
as done in the error handling path of the probe?

> +}
> +
> +static const struct of_device_id stm32_omm_of_match[] = {
> +	{ .compatible = "st,stm32mp25-omm", },
> +	{},

Nitpick: Unneeded , after a terminator.

> +};
> +MODULE_DEVICE_TABLE(of, stm32_omm_of_match);

...

CJ





^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
                     ` (2 preceding siblings ...)
  2025-02-11 18:16   ` Christophe JAILLET
@ 2025-02-12  3:19   ` kernel test robot
  2025-02-12 12:51   ` Geert Uytterhoeven
  4 siblings, 0 replies; 23+ messages in thread
From: kernel test robot @ 2025-02-12  3:19 UTC (permalink / raw)
  To: patrice.chotard, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: oe-kbuild-all, linux-spi, devicetree, linux-stm32,
	linux-arm-kernel, linux-kernel, christophe.kerello,
	patrice.chotard

Hi,

kernel test robot noticed the following build errors:

[auto build test ERROR on broonie-spi/for-next]
[also build test ERROR on atorgue-stm32/stm32-next krzk-mem-ctrl/for-next linus/master v6.14-rc2 next-20250210]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/patrice-chotard-foss-st-com/dt-bindings-spi-Add-STM32-OSPI-controller/20250210-212554
base:   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link:    https://lore.kernel.org/r/20250210131826.220318-5-patrice.chotard%40foss.st.com
patch subject: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20250212/202502121131.W1HsUg9j-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250212/202502121131.W1HsUg9j-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502121131.W1HsUg9j-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/memory/stm32_omm.c:82:25: note: in expansion of macro 'dev_err'
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                         ^~~~~~~
   drivers/memory/stm32_omm.c:82:80: note: format string is defined here
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                                             ~~~^
         |                                                                                |
         |                                                                                long long unsigned int
         |                                                                             %x
   drivers/memory/stm32_omm.c:82:38: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 6 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:82:25: note: in expansion of macro 'dev_err'
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                         ^~~~~~~
   drivers/memory/stm32_omm.c:82:87: note: format string is defined here
      82 |                         dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
         |                                                                                    ~~~^
         |                                                                                       |
         |                                                                                       long long unsigned int
         |                                                                                    %x
   drivers/memory/stm32_omm.c:96:46: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 3 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:96:33: note: in expansion of macro 'dev_err'
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                 ^~~~~~~
   drivers/memory/stm32_omm.c:96:53: note: format string is defined here
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                  ~~~^
         |                                                     |
         |                                                     long long unsigned int
         |                                                  %x
   drivers/memory/stm32_omm.c:96:46: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 4 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:96:33: note: in expansion of macro 'dev_err'
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                 ^~~~~~~
   drivers/memory/stm32_omm.c:96:60: note: format string is defined here
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                         ~~~^
         |                                                            |
         |                                                            long long unsigned int
         |                                                         %x
   drivers/memory/stm32_omm.c:96:46: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 5 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:96:33: note: in expansion of macro 'dev_err'
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                 ^~~~~~~
   drivers/memory/stm32_omm.c:96:78: note: format string is defined here
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                                           ~~~^
         |                                                                              |
         |                                                                              long long unsigned int
         |                                                                           %x
   drivers/memory/stm32_omm.c:96:46: warning: format '%llx' expects argument of type 'long long unsigned int', but argument 6 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/memory/stm32_omm.c:96:33: note: in expansion of macro 'dev_err'
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                 ^~~~~~~
   drivers/memory/stm32_omm.c:96:85: note: format string is defined here
      96 |                                 dev_err(dev, "[0x%llx-0x%llx] overlaps [0x%llx-0x%llx]\n",
         |                                                                                  ~~~^
         |                                                                                     |
         |                                                                                     long long unsigned int
         |                                                                                  %x
   drivers/memory/stm32_omm.c: In function 'stm32_omm_configure':
>> drivers/memory/stm32_omm.c:224:35: error: implicit declaration of function 'FIELD_PREP' [-Wimplicit-function-declaration]
     224 |                         req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
         |                                   ^~~~~~~~~~


vim +/FIELD_PREP +224 drivers/memory/stm32_omm.c

   164	
   165	static int stm32_omm_configure(struct device *dev)
   166	{
   167		struct stm32_omm *omm = dev_get_drvdata(dev);
   168		struct reset_control *rstc;
   169		unsigned long clk_rate, clk_rate_max = 0;
   170		int ret;
   171		u8 i;
   172		u32 mux = 0;
   173		u32 cssel_ovr = 0;
   174		u32 req2ack = 0;
   175	
   176		omm->clk = devm_clk_get(dev, NULL);
   177		if (IS_ERR(omm->clk)) {
   178			dev_err(dev, "Failed to get OMM clock (%ld)\n",
   179				PTR_ERR(omm->clk));
   180	
   181			return PTR_ERR(omm->clk);
   182		}
   183	
   184		ret = pm_runtime_resume_and_get(dev);
   185		if (ret < 0)
   186			return ret;
   187	
   188		/* parse children's clock */
   189		for (i = 0; i < omm->nb_child; i++) {
   190			clk_rate = clk_get_rate(omm->child[i].clk);
   191			if (!clk_rate) {
   192				dev_err(dev, "Invalid clock rate\n");
   193				goto err_clk_disable;
   194			}
   195	
   196			if (clk_rate > clk_rate_max)
   197				clk_rate_max = clk_rate;
   198		}
   199	
   200		rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
   201		if (IS_ERR(rstc)) {
   202			ret = dev_err_probe(dev, PTR_ERR(rstc), "reset get failed\n");
   203			goto err_clk_disable;
   204		}
   205	
   206		reset_control_assert(rstc);
   207		udelay(2);
   208		reset_control_deassert(rstc);
   209	
   210		omm->cr = readl_relaxed(omm->io_base + OMM_CR);
   211		/* optional */
   212		ret = of_property_read_u32(dev->of_node, "st,omm-mux", &mux);
   213		if (!ret) {
   214			if (mux & CR_MUXEN) {
   215				ret = of_property_read_u32(dev->of_node, "st,omm-req2ack-ns",
   216							   &req2ack);
   217				if (!ret && !req2ack) {
   218					req2ack = DIV_ROUND_UP(req2ack, NSEC_PER_SEC / clk_rate_max) - 1;
   219	
   220					if (req2ack > 256)
   221						req2ack = 256;
   222				}
   223	
 > 224				req2ack = FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
   225	
   226				omm->cr &= ~CR_REQ2ACK_MASK;
   227				omm->cr |= FIELD_PREP(CR_REQ2ACK_MASK, req2ack);
   228	
   229				/*
   230				 * If the mux is enabled, the 2 OSPI clocks have to be
   231				 * always enabled
   232				 */
   233				ret = stm32_omm_enable_child_clock(dev, true);
   234				if (ret)
   235					goto err_clk_disable;
   236			}
   237	
   238			omm->cr &= ~CR_MUXENMODE_MASK;
   239			omm->cr |= FIELD_PREP(CR_MUXENMODE_MASK, mux);
   240		}
   241	
   242		/* optional */
   243		ret = of_property_read_u32(dev->of_node, "st,omm-cssel-ovr", &cssel_ovr);
   244		if (!ret) {
   245			omm->cr &= ~CR_CSSEL_OVR_MASK;
   246			omm->cr |= FIELD_PREP(CR_CSSEL_OVR_MASK, cssel_ovr);
   247			omm->cr |= CR_CSSEL_OVR_EN;
   248		}
   249	
   250		omm->restore_omm = true;
   251		writel_relaxed(omm->cr, omm->io_base + OMM_CR);
   252	
   253		ret = stm32_omm_set_amcr(dev, true);
   254	
   255	err_clk_disable:
   256		pm_runtime_put_sync_suspend(dev);
   257	
   258		return ret;
   259	}
   260	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
                     ` (3 preceding siblings ...)
  2025-02-12  3:19   ` kernel test robot
@ 2025-02-12 12:51   ` Geert Uytterhoeven
  2025-02-12 16:18     ` Patrice CHOTARD
  4 siblings, 1 reply; 23+ messages in thread
From: Geert Uytterhoeven @ 2025-02-12 12:51 UTC (permalink / raw)
  To: patrice.chotard
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon,
	linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello

Hi Patrice,

On Mon, 10 Feb 2025 at 14:21, <patrice.chotard@foss.st.com> wrote:
> From: Patrice Chotard <patrice.chotard@foss.st.com>
>
> Octo Memory Manager driver (OMM) manages:
>   - the muxing between 2 OSPI busses and 2 output ports.
>     There are 4 possible muxing configurations:
>       - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>         output is on port 2
>       - OSPI1 and OSPI2 are multiplexed over the same output port 1
>       - swapped mode (no multiplexing), OSPI1 output is on port 2,
>         OSPI2 output is on port 1
>       - OSPI1 and OSPI2 are multiplexed over the same output port 2
>   - the split of the memory area shared between the 2 OSPI instances.
>   - chip select selection override.
>   - the time between 2 transactions in multiplexed mode.
>   - check firewall access.
>
> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
> Signed-off-by: Christophe Kerello <christophe.kerello@foss.st.com>

Thanks for your patch!

> --- a/drivers/memory/Kconfig
> +++ b/drivers/memory/Kconfig
> @@ -225,6 +225,23 @@ config STM32_FMC2_EBI
>           devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on
>           SOCs containing the FMC2 External Bus Interface.
>
> +config STM32_OMM
> +       tristate "STM32 Octo Memory Manager"
> +       depends on SPI_STM32_OSPI || TEST_COMPILE

COMPILE_TEST

> +       help
> +         This driver manages the muxing between the 2 OSPI busses and
> +         the 2 output ports. There are 4 possible muxing configurations:
> +         - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
> +              output is on port 2
> +         - OSPI1 and OSPI2 are multiplexed over the same output port 1
> +         - swapped mode (no multiplexing), OSPI1 output is on port 2,
> +              OSPI2 output is on port 1
> +         - OSPI1 and OSPI2 are multiplexed over the same output port 2
> +         It also manages :
> +           - the split of the memory area shared between the 2 OSPI instances.
> +           - chip select selection override.
> +           - the time between 2 transactions in multiplexed mode.
> +
>  source "drivers/memory/samsung/Kconfig"
>  source "drivers/memory/tegra/Kconfig"

> --- /dev/null
> +++ b/drivers/memory/stm32_omm.c

> +static int stm32_omm_set_amcr(struct device *dev, bool set)
> +{
> +       struct stm32_omm *omm = dev_get_drvdata(dev);
> +       struct regmap *syscfg_regmap;
> +       struct device_node *node;
> +       struct resource res, res1;
> +       resource_size_t mm_ospi2_size = 0;
> +       static const char * const mm_name[] = { "ospi1", "ospi2" };
> +       u32 amcr_base, amcr_mask;
> +       int ret, i, idx;

unsigned int i

> +       unsigned int amcr, read_amcr;
> +
> +       for (i = 0; i < omm->nb_child; i++) {
> +               idx = of_property_match_string(dev->of_node,
> +                                              "memory-region-names",
> +                                              mm_name[i]);
> +               if (idx < 0)
> +                       continue;
> +
> +               /* res1 only used on second loop iteration */
> +               res1.start = res.start;
> +               res1.end = res.end;
> +
> +               node = of_parse_phandle(dev->of_node, "memory-region", idx);
> +               if (!node)
> +                       continue;
> +
> +               ret = of_address_to_resource(node, 0, &res);
> +               if (ret) {
> +                       dev_err(dev, "unable to resolve memory region\n");
> +                       return ret;
> +               }
> +
> +               /* check that memory region fits inside OMM memory map area */
> +               if (!resource_contains(omm->mm_res, &res)) {
> +                       dev_err(dev, "%s doesn't fit inside OMM memory map area\n",
> +                               mm_name[i]);
> +                       dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
> +                               res.start, res.end,
> +                               omm->mm_res->start, omm->mm_res->end);

As reported by the kernel test robot, this fails to build when
resource_size_t differs from unsigned long long.  However, you can
easily print the full resource instead:

    dev_err(dev, "%pR doesn't fit inside %pR\n", &res, omm->mm_res);

https://elixir.bootlin.com/linux/v6.13.2/source/Documentation/core-api/printk-formats.rst#L206

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-11 18:16   ` Christophe JAILLET
@ 2025-02-12 16:17     ` Patrice CHOTARD
  0 siblings, 0 replies; 23+ messages in thread
From: Patrice CHOTARD @ 2025-02-12 16:17 UTC (permalink / raw)
  To: Christophe JAILLET
  Cc: alexandre.torgue, arnd, broonie, catalin.marinas,
	christophe.kerello, conor+dt, devicetree, gregkh, krzk+dt,
	linux-arm-kernel, linux-kernel, linux-spi, linux-stm32,
	mcoquelin.stm32, p.zabel, robh, will



On 2/11/25 19:16, Christophe JAILLET wrote:
> Le 10/02/2025 à 14:18, patrice.chotard-rj0Iel/JR4NBDgjK7y7TUQ@public.gmane.org a écrit :
>> From: Patrice Chotard <patrice.chotard-rj0Iel/JR4NBDgjK7y7TUQ@public.gmane.org>
>>
>> Octo Memory Manager driver (OMM) manages:
>>    - the muxing between 2 OSPI busses and 2 output ports.
>>      There are 4 possible muxing configurations:
>>        - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>>          output is on port 2
>>        - OSPI1 and OSPI2 are multiplexed over the same output port 1
>>        - swapped mode (no multiplexing), OSPI1 output is on port 2,
>>          OSPI2 output is on port 1
>>        - OSPI1 and OSPI2 are multiplexed over the same output port 2
>>    - the split of the memory area shared between the 2 OSPI instances.
>>    - chip select selection override.
>>    - the time between 2 transactions in multiplexed mode.
>>    - check firewall access.
> 
> ...
> 
>> diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c
>> new file mode 100644
>> index 000000000000..af69137bfba2
>> --- /dev/null
>> +++ b/drivers/memory/stm32_omm.c
>> @@ -0,0 +1,520 @@
>> +// SPDX-License-Identifier: GPL
> 
> Not sure this SPDX-License-Identifier exists.

Right, i will fix that.

> 
>> +/*
>> + * Copyright (C) STMicroelectronics 2024 - All Rights Reserved
> 
> ...
> 
>> +    pm_runtime_enable(dev);
>> +
>> +    /* check if OMM's resource access is granted */
>> +    ret = stm32_omm_check_access(dev, dev->of_node);
>> +    if (ret < 0 && ret != -EACCES)
>> +        goto err_clk_release;
> 
> Should we call, here and below, pm_runtime_disable() in the error handling path, as done in the remove function?

right, i will add it.

> 
>> +
>> +    if (!ret && child_access_granted == OMM_CHILD_NB) {
>> +        /* Ensure both OSPI instance are disabled before configuring OMM */
>> +        ret = stm32_omm_disable_child(dev);
>> +        if (ret)
>> +            goto err_clk_release;
>> +
>> +        ret = stm32_omm_configure(dev);
>> +        if (ret)
>> +            goto err_clk_release;
>> +    } else {
>> +        dev_dbg(dev, "Octo Memory Manager resource's access not granted\n");
>> +        /*
>> +         * AMCR can't be set, so check if current value is coherent
>> +         * with memory-map areas defined in DT
>> +         */
>> +        ret = stm32_omm_set_amcr(dev, false);
>> +        if (ret)
>> +            goto err_clk_release;
>> +    }
>> +
>> +    /* for each child, if resource access is granted and status "okay", probe it */
>> +    for (i = 0; i < omm->nb_child; i++) {
>> +        if (!child_access[i] || !of_device_is_available(omm->child[i].node))
>> +            continue;
>> +
>> +        vdev = of_platform_device_create(omm->child[i].node, NULL, NULL);
>> +        if (!vdev) {
>> +            dev_err(dev, "Failed to create Octo Memory Manager child\n");
>> +            for (j = i; j > 0; --j) {
>> +                if (omm->child[j].dev)
>> +                    of_platform_device_destroy(omm->child[j].dev, NULL);
>> +            }
>> +
>> +            ret = -EINVAL;
>> +            goto err_clk_release;
>> +        }
>> +        omm->child[i].dev = &vdev->dev;
>> +    }
>> +
>> +err_clk_release:
>> +    for (i = 0; i < omm->nb_child; i++)
>> +        clk_put(omm->child[i].clk);
>> +
>> +    return ret;
>> +}
>> +
>> +static void stm32_omm_remove(struct platform_device *pdev)
>> +{
>> +    struct stm32_omm *omm = platform_get_drvdata(pdev);
>> +    int i;
>> +
>> +    for (i = 0; i < omm->nb_child; i++)
>> +        if (omm->child[i].dev)
>> +            of_platform_device_destroy(omm->child[i].dev, NULL);
>> +
>> +    if (omm->cr & CR_MUXEN)
>> +        stm32_omm_enable_child_clock(&pdev->dev, false);
>> +
>> +    pm_runtime_disable(&pdev->dev);
> 
> Should we have:
>     for (i = 0; i < omm->nb_child; i++)
>         clk_put(omm->child[i].clk);
> as done in the error handling path of the probe?

no need, as child's clock are always freed in stm32_omm_probe() in all cases.

> 
>> +}
>> +
>> +static const struct of_device_id stm32_omm_of_match[] = {
>> +    { .compatible = "st,stm32mp25-omm", },
>> +    {},
> 
> Nitpick: Unneeded , after a terminator.

ok

> 
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32_omm_of_match);
> 
> ...
> 
> CJ
> 
> 
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver
  2025-02-12 12:51   ` Geert Uytterhoeven
@ 2025-02-12 16:18     ` Patrice CHOTARD
  0 siblings, 0 replies; 23+ messages in thread
From: Patrice CHOTARD @ 2025-02-12 16:18 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon,
	linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello



On 2/12/25 13:51, Geert Uytterhoeven wrote:
> Hi Patrice,
> 
> On Mon, 10 Feb 2025 at 14:21, <patrice.chotard@foss.st.com> wrote:
>> From: Patrice Chotard <patrice.chotard@foss.st.com>
>>
>> Octo Memory Manager driver (OMM) manages:
>>   - the muxing between 2 OSPI busses and 2 output ports.
>>     There are 4 possible muxing configurations:
>>       - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>>         output is on port 2
>>       - OSPI1 and OSPI2 are multiplexed over the same output port 1
>>       - swapped mode (no multiplexing), OSPI1 output is on port 2,
>>         OSPI2 output is on port 1
>>       - OSPI1 and OSPI2 are multiplexed over the same output port 2
>>   - the split of the memory area shared between the 2 OSPI instances.
>>   - chip select selection override.
>>   - the time between 2 transactions in multiplexed mode.
>>   - check firewall access.
>>
>> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
>> Signed-off-by: Christophe Kerello <christophe.kerello@foss.st.com>
> 
> Thanks for your patch!
> 
>> --- a/drivers/memory/Kconfig
>> +++ b/drivers/memory/Kconfig
>> @@ -225,6 +225,23 @@ config STM32_FMC2_EBI
>>           devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on
>>           SOCs containing the FMC2 External Bus Interface.
>>
>> +config STM32_OMM
>> +       tristate "STM32 Octo Memory Manager"
>> +       depends on SPI_STM32_OSPI || TEST_COMPILE
> 
> COMPILE_TEST

 good catch 

> 
>> +       help
>> +         This driver manages the muxing between the 2 OSPI busses and
>> +         the 2 output ports. There are 4 possible muxing configurations:
>> +         - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>> +              output is on port 2
>> +         - OSPI1 and OSPI2 are multiplexed over the same output port 1
>> +         - swapped mode (no multiplexing), OSPI1 output is on port 2,
>> +              OSPI2 output is on port 1
>> +         - OSPI1 and OSPI2 are multiplexed over the same output port 2
>> +         It also manages :
>> +           - the split of the memory area shared between the 2 OSPI instances.
>> +           - chip select selection override.
>> +           - the time between 2 transactions in multiplexed mode.
>> +
>>  source "drivers/memory/samsung/Kconfig"
>>  source "drivers/memory/tegra/Kconfig"
> 
>> --- /dev/null
>> +++ b/drivers/memory/stm32_omm.c
> 
>> +static int stm32_omm_set_amcr(struct device *dev, bool set)
>> +{
>> +       struct stm32_omm *omm = dev_get_drvdata(dev);
>> +       struct regmap *syscfg_regmap;
>> +       struct device_node *node;
>> +       struct resource res, res1;
>> +       resource_size_t mm_ospi2_size = 0;
>> +       static const char * const mm_name[] = { "ospi1", "ospi2" };
>> +       u32 amcr_base, amcr_mask;
>> +       int ret, i, idx;
> 
> unsigned int i

ok

> 
>> +       unsigned int amcr, read_amcr;
>> +
>> +       for (i = 0; i < omm->nb_child; i++) {
>> +               idx = of_property_match_string(dev->of_node,
>> +                                              "memory-region-names",
>> +                                              mm_name[i]);
>> +               if (idx < 0)
>> +                       continue;
>> +
>> +               /* res1 only used on second loop iteration */
>> +               res1.start = res.start;
>> +               res1.end = res.end;
>> +
>> +               node = of_parse_phandle(dev->of_node, "memory-region", idx);
>> +               if (!node)
>> +                       continue;
>> +
>> +               ret = of_address_to_resource(node, 0, &res);
>> +               if (ret) {
>> +                       dev_err(dev, "unable to resolve memory region\n");
>> +                       return ret;
>> +               }
>> +
>> +               /* check that memory region fits inside OMM memory map area */
>> +               if (!resource_contains(omm->mm_res, &res)) {
>> +                       dev_err(dev, "%s doesn't fit inside OMM memory map area\n",
>> +                               mm_name[i]);
>> +                       dev_err(dev, "[0x%llx-0x%llx] doesn't fit inside [0x%llx-0x%llx]\n",
>> +                               res.start, res.end,
>> +                               omm->mm_res->start, omm->mm_res->end);
> 
> As reported by the kernel test robot, this fails to build when
> resource_size_t differs from unsigned long long.  However, you can
> easily print the full resource instead:
> 
>     dev_err(dev, "%pR doesn't fit inside %pR\n", &res, omm->mm_res);
> 
> https://elixir.bootlin.com/linux/v6.13.2/source/Documentation/core-api/printk-formats.rst#L206

OK, thanks for this tips

Patrice

> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/8] Add STM32MP25 SPI NOR support
  2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
                   ` (7 preceding siblings ...)
  2025-02-10 13:18 ` [PATCH v3 8/8] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver patrice.chotard
@ 2025-02-13  7:56 ` Krzysztof Kozlowski
  2025-02-18 10:39   ` Patrice CHOTARD
  8 siblings, 1 reply; 23+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-13  7:56 UTC (permalink / raw)
  To: patrice.chotard
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon,
	linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello

On Mon, Feb 10, 2025 at 02:18:18PM +0100, patrice.chotard@foss.st.com wrote:
> From: Patrice Chotard <patrice.chotard@foss.st.com>
> 
> This series adds SPI NOR support for STM32MP25 SoCs from STMicroelectronics,
> for that it adds support for:
>   - Octo Memory Manager driver.
>   - Octo SPI driver.
>   - yaml schema for Octo Memory Manager and Octo SPI drivers.
> 

You combined three different subsystems in one patchset and nothing here
explains why and what is the merging intention. Either split your work
or explain dependencies/merging.

Best regards,
Krzysztof



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller
  2025-02-10 13:18 ` [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
@ 2025-02-13  7:57   ` Krzysztof Kozlowski
  2025-02-17  9:17   ` Philipp Zabel
  1 sibling, 0 replies; 23+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-13  7:57 UTC (permalink / raw)
  To: patrice.chotard
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon,
	linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello

On Mon, Feb 10, 2025 at 02:18:19PM +0100, patrice.chotard@foss.st.com wrote:
> From: Patrice Chotard <patrice.chotard@foss.st.com>
> 
> Add device tree bindings for the STM32 OSPI controller.
> 
> Main features of the Octo-SPI controller :
>   - support sNOR / sNAND / HyperRAM™ and HyperFlash™ devices.
>   - Three functional modes: indirect, automatic-status polling,

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 3/8] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
  2025-02-10 13:18 ` [PATCH v3 3/8] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller patrice.chotard
@ 2025-02-13  8:00   ` Krzysztof Kozlowski
  2025-02-18  9:58     ` Patrice CHOTARD
  0 siblings, 1 reply; 23+ messages in thread
From: Krzysztof Kozlowski @ 2025-02-13  8:00 UTC (permalink / raw)
  To: patrice.chotard
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon,
	linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello

On Mon, Feb 10, 2025 at 02:18:21PM +0100, patrice.chotard@foss.st.com wrote:
> From: Patrice Chotard <patrice.chotard@foss.st.com>
> 
> Add bindings for STM32 Octo Memory Manager (OMM) controller.
> 
> OMM manages:
>   - the muxing between 2 OSPI busses and 2 output ports.
>     There are 4 possible muxing configurations:
>       - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>         output is on port 2
>       - OSPI1 and OSPI2 are multiplexed over the same output port 1
>       - swapped mode (no multiplexing), OSPI1 output is on port 2,
>         OSPI2 output is on port 1
>       - OSPI1 and OSPI2 are multiplexed over the same output port 2
>   - the split of the memory area shared between the 2 OSPI instances.
>   - chip select selection override.
>   - the time between 2 transactions in multiplexed mode.
> 
> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
> ---
>  .../memory-controllers/st,stm32mp25-omm.yaml  | 201 ++++++++++++++++++
>  1 file changed, 201 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
> 
> diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
> new file mode 100644
> index 000000000000..c897e6bf490d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
> @@ -0,0 +1,201 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/memory-controllers/st,stm32mp25-omm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: STM32 Octo Memory Manager (OMM)
> +
> +maintainers:
> +  - Patrice Chotard <patrice.chotard@foss.st.com>
> +
> +description: |
> +  The STM32 Octo Memory Manager is a low-level interface that enables an
> +  efficient OCTOSPI pin assignment with a full I/O matrix (before alternate
> +  function map) and multiplex of single/dual/quad/octal SPI interfaces over
> +  the same bus. It Supports up to:
> +    - Two single/dual/quad/octal SPI interfaces
> +    - Two ports for pin assignment
> +
> +properties:
> +  compatible:
> +    const: st,stm32mp25-omm
> +
> +  "#address-cells":
> +    const: 2
> +
> +  "#size-cells":
> +    const: 1
> +
> +  ranges:
> +    description: |
> +      Reflects the memory layout with four integer values per OSPI instance.
> +      Format:
> +      <chip-select> 0 <registers base address> <size>
> +    minItems: 2
> +    maxItems: 2
> +
> +  reg:
> +    items:
> +      - description: OMM registers
> +      - description: OMM memory map area
> +
> +  reg-names:
> +    items:
> +      - const: regs
> +      - const: memory_map
> +
> +  memory-region:
> +    description: |
> +      Memory region shared between the 2 OCTOSPI instance.
> +      One or two phandle to a node describing a memory mapped region
> +      depending of child number.
> +    minItems: 1
> +    maxItems: 2
> +
> +  memory-region-names:
> +    description: |
> +      OCTOSPI instance's name to which memory region is associated
> +    items:
> +      enum: [ospi1, ospi2]
> +    minItems: 1
> +    maxItems: 2
> +
> +  clocks:
> +    maxItems: 1
> +
> +  resets:
> +    maxItems: 1
> +
> +  access-controllers:
> +    maxItems: 1
> +
> +  st,syscfg-amcr:
> +    $ref: /schemas/types.yaml#/definitions/phandle-array
> +    description: |
> +      The Address Mapping Control Register (AMCR) is used to split the 256MB
> +      memory map area shared between the 2 OSPI instance. The Octo Memory
> +      Manager sets the AMCR depending of the memory-region configuration.
> +      The memory split bitmask description is:
> +        - 000: OCTOSPI1 (256 Mbytes), OCTOSPI2 unmapped
> +        - 001: OCTOSPI1 (192 Mbytes), OCTOSPI2 (64 Mbytes)
> +        - 010: OCTOSPI1 (128 Mbytes), OCTOSPI2 (128 Mbytes)
> +        - 011: OCTOSPI1 (64 Mbytes), OCTOSPI2 (192 Mbytes)
> +        - 1xx: OCTOSPI1 unmapped, OCTOSPI2 (256 Mbytes)
> +    items:
> +      - description: phandle to syscfg
> +      - description: register offset within syscfg
> +      - description: register bitmask for memory split
> +
> +  st,omm-req2ack-ns:
> +    description: |
> +      In multiplexed mode (MUXEN = 1), this field defines the time in
> +      nanoseconds between two transactions.

default: ?

> +
> +  st,omm-cssel-ovr:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: |
> +      Configure the chip select selector override for the 2 OCTOSPIs.
> +      - 0: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS1
> +      - 1: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS1
> +      - 2: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS2
> +      - 3: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS2
> +    minimum: 0
> +    maximum: 3

default: ?

> +
> +  st,omm-mux:
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    description: |
> +      Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
> +      - 0: direct mode, default

Don't repeat constraints in free form text.

> +      - 1: mux OCTOSPI1 and OCTOSPI2 to port 1
> +      - 2: swapped mode
> +      - 3: mux OCTOSPI1 and OCTOSPI2 to port 2
> +    minimum: 0
> +    maximum: 3

default: ?

None of them are required, so usually we expect defaults.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

Best regards,
Krzysztof



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller
  2025-02-10 13:18 ` [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
  2025-02-13  7:57   ` Krzysztof Kozlowski
@ 2025-02-17  9:17   ` Philipp Zabel
  2025-02-18  8:39     ` Patrice CHOTARD
  1 sibling, 1 reply; 23+ messages in thread
From: Philipp Zabel @ 2025-02-17  9:17 UTC (permalink / raw)
  To: patrice.chotard, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Alexandre Torgue, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello

On Mo, 2025-02-10 at 14:18 +0100, patrice.chotard@foss.st.com wrote:
> From: Patrice Chotard <patrice.chotard@foss.st.com>
> 
> Add device tree bindings for the STM32 OSPI controller.
> 
> Main features of the Octo-SPI controller :
>   - support sNOR / sNAND / HyperRAM™ and HyperFlash™ devices.
>   - Three functional modes: indirect, automatic-status polling,
>     memory-mapped.
>   - Up to 4 Gbytes of external memory can be addressed in indirect
>     mode (per physical port and per CS), and up to 256 Mbytes in
>     memory-mapped mode (combined for both physical ports and per CS).
>   - Single-, dual-, quad-, and octal-SPI communication.
>   - Dual-quad communication.
>   - Single data rate (SDR) and double transfer rate (DTR).
>   - Maximum target frequency is 133 MHz for SDR and 133 MHz for DTR.
>   - Data strobe support.
>   - DMA channel for indirect mode.
>   - Double CS mapping that allows two external flash devices to be
>     addressed with a single OCTOSPI controller mapped on a single
>     OCTOSPI port.
> 
> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
> ---
>  .../bindings/spi/st,stm32mp25-ospi.yaml       | 105 ++++++++++++++++++
>  1 file changed, 105 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
> 
> diff --git a/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
> new file mode 100644
> index 000000000000..5f276f27dc4c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
> @@ -0,0 +1,105 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/spi/st,stm32mp25-ospi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: STMicroelectronics STM32 Octal Serial Peripheral Interface (OSPI)
> +
> +maintainers:
> +  - Patrice Chotard <patrice.chotard@foss.st.com>
> +
> +allOf:
> +  - $ref: spi-controller.yaml#
> +
> +properties:
> +  compatible:
> +    const: st,stm32mp25-ospi
> +
> +  reg:
> +    maxItems: 1
> +
> +  memory-region:
> +    description:
> +      Memory region to be used for memory-map read access.
> +      In memory-mapped mode, read access are performed from the memory
> +      device using the direct mapping.
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  resets:
> +    items:
> +      - description: phandle to OSPI block reset
> +      - description: phandle to delay block reset

Are you positive that these will only ever have to be reset together?
Otherwise I'd add a reset-names property just in case.

regards
Philipp


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller
  2025-02-17  9:17   ` Philipp Zabel
@ 2025-02-18  8:39     ` Patrice CHOTARD
  0 siblings, 0 replies; 23+ messages in thread
From: Patrice CHOTARD @ 2025-02-18  8:39 UTC (permalink / raw)
  To: Philipp Zabel, Mark Brown, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Alexandre Torgue, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon
  Cc: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello



On 2/17/25 10:17, Philipp Zabel wrote:
> On Mo, 2025-02-10 at 14:18 +0100, patrice.chotard@foss.st.com wrote:
>> From: Patrice Chotard <patrice.chotard@foss.st.com>
>>
>> Add device tree bindings for the STM32 OSPI controller.
>>
>> Main features of the Octo-SPI controller :
>>   - support sNOR / sNAND / HyperRAM™ and HyperFlash™ devices.
>>   - Three functional modes: indirect, automatic-status polling,
>>     memory-mapped.
>>   - Up to 4 Gbytes of external memory can be addressed in indirect
>>     mode (per physical port and per CS), and up to 256 Mbytes in
>>     memory-mapped mode (combined for both physical ports and per CS).
>>   - Single-, dual-, quad-, and octal-SPI communication.
>>   - Dual-quad communication.
>>   - Single data rate (SDR) and double transfer rate (DTR).
>>   - Maximum target frequency is 133 MHz for SDR and 133 MHz for DTR.
>>   - Data strobe support.
>>   - DMA channel for indirect mode.
>>   - Double CS mapping that allows two external flash devices to be
>>     addressed with a single OCTOSPI controller mapped on a single
>>     OCTOSPI port.
>>
>> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
>> ---
>>  .../bindings/spi/st,stm32mp25-ospi.yaml       | 105 ++++++++++++++++++
>>  1 file changed, 105 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
>> new file mode 100644
>> index 000000000000..5f276f27dc4c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/spi/st,stm32mp25-ospi.yaml
>> @@ -0,0 +1,105 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/spi/st,stm32mp25-ospi.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: STMicroelectronics STM32 Octal Serial Peripheral Interface (OSPI)
>> +
>> +maintainers:
>> +  - Patrice Chotard <patrice.chotard@foss.st.com>
>> +
>> +allOf:
>> +  - $ref: spi-controller.yaml#
>> +
>> +properties:
>> +  compatible:
>> +    const: st,stm32mp25-ospi
>> +
>> +  reg:
>> +    maxItems: 1
>> +
>> +  memory-region:
>> +    description:
>> +      Memory region to be used for memory-map read access.
>> +      In memory-mapped mode, read access are performed from the memory
>> +      device using the direct mapping.
>> +    maxItems: 1
>> +
>> +  clocks:
>> +    maxItems: 1
>> +
>> +  interrupts:
>> +    maxItems: 1
>> +
>> +  resets:
>> +    items:
>> +      - description: phandle to OSPI block reset
>> +      - description: phandle to delay block reset
> 
> Are you positive that these will only ever have to be reset together?
> Otherwise I'd add a reset-names property just in case.

Yes i confirm that these both reset are reset together.

Thanks
Patrice

> 
> regards
> Philipp


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 3/8] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
  2025-02-13  8:00   ` Krzysztof Kozlowski
@ 2025-02-18  9:58     ` Patrice CHOTARD
  0 siblings, 0 replies; 23+ messages in thread
From: Patrice CHOTARD @ 2025-02-18  9:58 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon,
	linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello



On 2/13/25 09:00, Krzysztof Kozlowski wrote:
> On Mon, Feb 10, 2025 at 02:18:21PM +0100, patrice.chotard@foss.st.com wrote:
>> From: Patrice Chotard <patrice.chotard@foss.st.com>
>>
>> Add bindings for STM32 Octo Memory Manager (OMM) controller.
>>
>> OMM manages:
>>   - the muxing between 2 OSPI busses and 2 output ports.
>>     There are 4 possible muxing configurations:
>>       - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>>         output is on port 2
>>       - OSPI1 and OSPI2 are multiplexed over the same output port 1
>>       - swapped mode (no multiplexing), OSPI1 output is on port 2,
>>         OSPI2 output is on port 1
>>       - OSPI1 and OSPI2 are multiplexed over the same output port 2
>>   - the split of the memory area shared between the 2 OSPI instances.
>>   - chip select selection override.
>>   - the time between 2 transactions in multiplexed mode.
>>
>> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
>> ---
>>  .../memory-controllers/st,stm32mp25-omm.yaml  | 201 ++++++++++++++++++
>>  1 file changed, 201 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
>> new file mode 100644
>> index 000000000000..c897e6bf490d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
>> @@ -0,0 +1,201 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/memory-controllers/st,stm32mp25-omm.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: STM32 Octo Memory Manager (OMM)
>> +
>> +maintainers:
>> +  - Patrice Chotard <patrice.chotard@foss.st.com>
>> +
>> +description: |
>> +  The STM32 Octo Memory Manager is a low-level interface that enables an
>> +  efficient OCTOSPI pin assignment with a full I/O matrix (before alternate
>> +  function map) and multiplex of single/dual/quad/octal SPI interfaces over
>> +  the same bus. It Supports up to:
>> +    - Two single/dual/quad/octal SPI interfaces
>> +    - Two ports for pin assignment
>> +
>> +properties:
>> +  compatible:
>> +    const: st,stm32mp25-omm
>> +
>> +  "#address-cells":
>> +    const: 2
>> +
>> +  "#size-cells":
>> +    const: 1
>> +
>> +  ranges:
>> +    description: |
>> +      Reflects the memory layout with four integer values per OSPI instance.
>> +      Format:
>> +      <chip-select> 0 <registers base address> <size>
>> +    minItems: 2
>> +    maxItems: 2
>> +
>> +  reg:
>> +    items:
>> +      - description: OMM registers
>> +      - description: OMM memory map area
>> +
>> +  reg-names:
>> +    items:
>> +      - const: regs
>> +      - const: memory_map
>> +
>> +  memory-region:
>> +    description: |
>> +      Memory region shared between the 2 OCTOSPI instance.
>> +      One or two phandle to a node describing a memory mapped region
>> +      depending of child number.
>> +    minItems: 1
>> +    maxItems: 2
>> +
>> +  memory-region-names:
>> +    description: |
>> +      OCTOSPI instance's name to which memory region is associated
>> +    items:
>> +      enum: [ospi1, ospi2]
>> +    minItems: 1
>> +    maxItems: 2
>> +
>> +  clocks:
>> +    maxItems: 1
>> +
>> +  resets:
>> +    maxItems: 1
>> +
>> +  access-controllers:
>> +    maxItems: 1
>> +
>> +  st,syscfg-amcr:
>> +    $ref: /schemas/types.yaml#/definitions/phandle-array
>> +    description: |
>> +      The Address Mapping Control Register (AMCR) is used to split the 256MB
>> +      memory map area shared between the 2 OSPI instance. The Octo Memory
>> +      Manager sets the AMCR depending of the memory-region configuration.
>> +      The memory split bitmask description is:
>> +        - 000: OCTOSPI1 (256 Mbytes), OCTOSPI2 unmapped
>> +        - 001: OCTOSPI1 (192 Mbytes), OCTOSPI2 (64 Mbytes)
>> +        - 010: OCTOSPI1 (128 Mbytes), OCTOSPI2 (128 Mbytes)
>> +        - 011: OCTOSPI1 (64 Mbytes), OCTOSPI2 (192 Mbytes)
>> +        - 1xx: OCTOSPI1 unmapped, OCTOSPI2 (256 Mbytes)
>> +    items:
>> +      - description: phandle to syscfg
>> +      - description: register offset within syscfg
>> +      - description: register bitmask for memory split
>> +
>> +  st,omm-req2ack-ns:
>> +    description: |
>> +      In multiplexed mode (MUXEN = 1), this field defines the time in
>> +      nanoseconds between two transactions.
> 
> default: ?

Yes, i will add the default value

> 
>> +
>> +  st,omm-cssel-ovr:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    description: |
>> +      Configure the chip select selector override for the 2 OCTOSPIs.
>> +      - 0: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS1
>> +      - 1: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS1
>> +      - 2: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS2
>> +      - 3: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS2
>> +    minimum: 0
>> +    maximum: 3
> 
> default: ?

ditto

> 
>> +
>> +  st,omm-mux:
>> +    $ref: /schemas/types.yaml#/definitions/uint32
>> +    description: |
>> +      Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
>> +      - 0: direct mode, default
> 
> Don't repeat constraints in free form text.
> 
ok

>> +      - 1: mux OCTOSPI1 and OCTOSPI2 to port 1
>> +      - 2: swapped mode
>> +      - 3: mux OCTOSPI1 and OCTOSPI2 to port 2
>> +    minimum: 0
>> +    maximum: 3
> 
> default: ?

i will add the default value as well

Thanks 
Patrice

> 
> None of them are required, so usually we expect defaults.
> 
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> 
> Best regards,
> Krzysztof
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 0/8] Add STM32MP25 SPI NOR support
  2025-02-13  7:56 ` [PATCH v3 0/8] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
@ 2025-02-18 10:39   ` Patrice CHOTARD
  0 siblings, 0 replies; 23+ messages in thread
From: Patrice CHOTARD @ 2025-02-18 10:39 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Mark Brown, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Alexandre Torgue, Philipp Zabel, Maxime Coquelin,
	Greg Kroah-Hartman, Arnd Bergmann, Catalin Marinas, Will Deacon,
	linux-spi, devicetree, linux-stm32, linux-arm-kernel,
	linux-kernel, christophe.kerello



On 2/13/25 08:56, Krzysztof Kozlowski wrote:
> On Mon, Feb 10, 2025 at 02:18:18PM +0100, patrice.chotard@foss.st.com wrote:
>> From: Patrice Chotard <patrice.chotard@foss.st.com>
>>
>> This series adds SPI NOR support for STM32MP25 SoCs from STMicroelectronics,
>> for that it adds support for:
>>   - Octo Memory Manager driver.
>>   - Octo SPI driver.
>>   - yaml schema for Octo Memory Manager and Octo SPI drivers.
>>
> 
> You combined three different subsystems in one patchset and nothing here
> explains why and what is the merging intention. Either split your work
> or explain dependencies/merging.

Ok i will add an explaination about OMM and OSPI relationship.

Thanks
Patrice

> 
> Best regards,
> Krzysztof
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2025-02-18 10:44 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-10 13:18 [PATCH v3 0/8] Add STM32MP25 SPI NOR support patrice.chotard
2025-02-10 13:18 ` [PATCH v3 1/8] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
2025-02-13  7:57   ` Krzysztof Kozlowski
2025-02-17  9:17   ` Philipp Zabel
2025-02-18  8:39     ` Patrice CHOTARD
2025-02-10 13:18 ` [PATCH v3 2/8] spi: stm32: Add OSPI driver patrice.chotard
2025-02-10 13:18 ` [PATCH v3 3/8] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller patrice.chotard
2025-02-13  8:00   ` Krzysztof Kozlowski
2025-02-18  9:58     ` Patrice CHOTARD
2025-02-10 13:18 ` [PATCH v3 4/8] memory: Add STM32 Octo Memory Manager driver patrice.chotard
2025-02-11 17:04   ` kernel test robot
2025-02-11 17:56   ` kernel test robot
2025-02-11 18:16   ` Christophe JAILLET
2025-02-12 16:17     ` Patrice CHOTARD
2025-02-12  3:19   ` kernel test robot
2025-02-12 12:51   ` Geert Uytterhoeven
2025-02-12 16:18     ` Patrice CHOTARD
2025-02-10 13:18 ` [PATCH v3 5/8] arm64: dts: st: Add OMM node on stm32mp251 patrice.chotard
2025-02-10 13:18 ` [PATCH v3 6/8] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi patrice.chotard
2025-02-10 13:18 ` [PATCH v3 7/8] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board patrice.chotard
2025-02-10 13:18 ` [PATCH v3 8/8] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver patrice.chotard
2025-02-13  7:56 ` [PATCH v3 0/8] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
2025-02-18 10:39   ` Patrice CHOTARD

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox