* [PATCH 0/9] Add STM32MP25 SPI NOR support
@ 2025-01-22 14:10 patrice.chotard
2025-01-22 14:10 ` [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
` (8 more replies)
0 siblings, 9 replies; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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>
Patrice Chotard (9):
dt-bindings: spi: Add STM32 OSPI controller
spi: stm32: Add OSPI driver
dt-bindings: misc: Add STM32 Octo Memory Manager controller
misc: 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 driver
arm64: defconfig: Enable STM32 OctoSPI driver
.../bindings/misc/st,stm32-omm.yaml | 194 +++
.../bindings/spi/st,stm32-ospi.yaml | 109 ++
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 | 33 +
arch/arm64/configs/defconfig | 2 +
drivers/misc/Kconfig | 17 +
drivers/misc/Makefile | 1 +
drivers/misc/stm32_omm.c | 510 ++++++++
drivers/spi/Kconfig | 10 +
drivers/spi/Makefile | 1 +
drivers/spi/spi-stm32-ospi.c | 1064 +++++++++++++++++
12 files changed, 2040 insertions(+)
create mode 100644 Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
create mode 100644 Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
create mode 100644 drivers/misc/stm32_omm.c
create mode 100644 drivers/spi/spi-stm32-ospi.c
--
2.25.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 15:18 ` Krzysztof Kozlowski
2025-01-22 14:10 ` [PATCH 2/9] spi: stm32: Add OSPI driver patrice.chotard
` (7 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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,stm32-ospi.yaml | 109 ++++++++++++++++++
1 file changed, 109 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
diff --git a/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
new file mode 100644
index 000000000000..bf16252f85fa
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
@@ -0,0 +1,109 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/st,stm32-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:
+ description: registers
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ memory-region:
+ maxItems: 1
+ description: Phandle to a node describing memory-map region to be used
+
+ clocks:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ resets:
+ maxItems: 2
+
+ dmas:
+ items:
+ - description: tx DMA channel
+ - description: rx DMA channel
+
+ dma-names:
+ items:
+ - const: tx
+ - const: rx
+
+ st,syscfg-dlyb:
+ description: |
+ Use to set the OSPI delay block within SYSCFG to:
+ Tune the phase of the RX sampling clock (or DQS) in order
+ to sample the data in their valid window.
+ Tune the phase of the TX launch clock in order to meet setup
+ and hold constraints of TX signals versus the memory clock.
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ items:
+ minItems: 2
+ maxItems: 2
+
+ access-controllers:
+ minItems: 1
+ maxItems: 2
+
+ power-domains:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - 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] 16+ messages in thread
* [PATCH 2/9] spi: stm32: Add OSPI driver
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
2025-01-22 14:10 ` [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 14:10 ` [PATCH 3/9] dt-bindings: misc: Add STM32 Octo Memory Manager controller patrice.chotard
` (6 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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 | 1064 ++++++++++++++++++++++++++++++++++
3 files changed, 1075 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..65e0804ebb3a 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -138,6 +138,7 @@ 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_QSPI) += spi-stm32-qspi.o
+obj-$(CONFIG_SPI_STM32_OSPI) += spi-stm32-ospi.o
obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c
new file mode 100644
index 000000000000..131266a7c5fe
--- /dev/null
+++ b/drivers/spi/spi-stm32-ospi.c
@@ -0,0 +1,1064 @@
+// 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_tx_poll(struct stm32_ospi *ospi, u8 *buf, u32 len, bool read)
+{
+ void __iomem *regs_base = ospi->regs_base;
+ void (*tx_fifo)(u8 *val, void __iomem *addr);
+ u32 sr;
+ int ret;
+
+ if (read)
+ tx_fifo = stm32_ospi_read_fifo;
+ else
+ tx_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;
+ }
+ tx_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_tx(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_tx_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_tx(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->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] 16+ messages in thread
* [PATCH 3/9] dt-bindings: misc: Add STM32 Octo Memory Manager controller
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
2025-01-22 14:10 ` [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
2025-01-22 14:10 ` [PATCH 2/9] spi: stm32: Add OSPI driver patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 15:22 ` Krzysztof Kozlowski
2025-01-22 14:10 ` [PATCH 4/9] misc: Add STM32 Octo Memory Manager driver patrice.chotard
` (5 subsequent siblings)
8 siblings, 1 reply; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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>
---
.../bindings/misc/st,stm32-omm.yaml | 194 ++++++++++++++++++
1 file changed, 194 insertions(+)
create mode 100644 Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
diff --git a/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml b/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
new file mode 100644
index 000000000000..ef8f5d2c526c
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
@@ -0,0 +1,194 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/st,stm32-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>
+
+ reg:
+ items:
+ - description: registers
+ - description: memory mapping
+
+ reg-names:
+ items:
+ - const: omm
+ - const: omm_mm
+
+ memory-region:
+ description: Phandle to a node describing memory-map region to be used.
+
+ memory-region-names:
+ minItems: 1
+ items:
+ - const: mm_ospi1
+ - const: mm_ospi2
+
+ clocks:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ access-controllers:
+ minItems: 1
+ maxItems: 2
+
+ 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.
+ Format is phandle to syscfg / register offset within syscfg / memory split
+ bitmask.
+ 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:
+ minItems: 3
+ maxItems: 3
+
+ 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.
+ The 2 bits mask muxing description is:
+ -bit 0: Chip select selector override setting for OCTOSPI1
+ 0x0: the chip select signal from OCTOSPI1 is sent to NCS1
+ 0x1: the chip select signal from OCTOSPI1 is sent to NCS2
+ -bit 1: Chip select selector override setting for OCTOSPI2
+ 0x0: the chip select signal from OCTOSPI2 is sent to NCS1
+ 0x1: the chip select signal from OCTOSPI2 is sent to NCS2
+
+ st,omm-mux:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
+ The muxing 2 bits mask description is:
+ - 0x0: direct mode, default
+ - 0x1: mux OCTOSPI1 and OCTOSPI2 to port 1
+ - 0x2: swapped mode
+ - 0x3: mux OCTOSPI1 and OCTOSPI2 to port 2
+
+ power-domains:
+ maxItems: 1
+
+patternProperties:
+ "^spi@[a-f0-9]+$":
+ type: object
+ $ref: "/schemas/spi/st,stm32-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 = "omm", "omm_mm";
+ memory-region = <&mm_ospi1>, <&mm_ospi2>;
+ memory-region-names = "mm_ospi1", "mm_ospi2";
+ pinctrl-names = "default", "sleep";
+ 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>;
+ clocks = <&rcc CK_BUS_OSPIIOM>;
+ resets = <&rcc OSPIIOM_R>;
+ st,syscfg-amcr = <&syscfg 0x2c00 0x7>;
+ st,omm-req2ack-ns = <0x0>;
+ st,omm-mux = <0x0>;
+ st,omm-cssel-ovr = <0x0>;
+ access-controllers = <&rifsc 111>;
+ power-domains = <&CLUSTER_PD>;
+
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ ranges = <0 0 0x40430000 0x400>,
+ <1 0 0x40440000 0x400>;
+
+ spi@40430000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32mp25-ospi";
+ reg = <0 0 0x400>;
+ 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>;
+ };
+
+ spi@40440000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32mp25-ospi";
+ reg = <1 0 0x400>;
+ 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>;
+ st,syscfg-dlyb = <&syscfg 0x1000>;
+ };
+ };
--
2.25.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 4/9] misc: Add STM32 Octo Memory Manager driver
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
` (2 preceding siblings ...)
2025-01-22 14:10 ` [PATCH 3/9] dt-bindings: misc: Add STM32 Octo Memory Manager controller patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 14:10 ` [PATCH 5/9] arm64: dts: st: Add OMM node on stm32mp251 patrice.chotard
` (4 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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/misc/Kconfig | 17 ++
drivers/misc/Makefile | 1 +
drivers/misc/stm32_omm.c | 510 +++++++++++++++++++++++++++++++++++++++
3 files changed, 528 insertions(+)
create mode 100644 drivers/misc/stm32_omm.c
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 56bc72c7ce4a..a6be09505ee5 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -467,6 +467,23 @@ config DW_XDATA_PCIE
If unsure, say N.
+config STM32_OMM
+ bool "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.
+
config PCI_ENDPOINT_TEST
depends on PCI
select CRC32
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 545aad06d088..a20c1cb6e663 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -75,3 +75,4 @@ lan966x-pci-objs := lan966x_pci.o
lan966x-pci-objs += lan966x_pci.dtbo.o
obj-$(CONFIG_MCHP_LAN966X_PCI) += lan966x-pci.o
obj-y += keba/
+obj-$(CONFIG_STM32_OMM) += stm32_omm.o
diff --git a/drivers/misc/stm32_omm.c b/drivers/misc/stm32_omm.c
new file mode 100644
index 000000000000..3a064c4b30f1
--- /dev/null
+++ b/drivers/misc/stm32_omm.c
@@ -0,0 +1,510 @@
+// 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 reset_control *reset;
+};
+
+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[] = { "mm_ospi1", "mm_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);
+ 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(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);
+ u8 i;
+ int ret;
+
+ 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 OSPI to ensure CR_EN bit is set to 0 */
+ reset_control_assert(omm->child[i].reset);
+ udelay(2);
+ reset_control_deassert(omm->child[i].reset);
+
+ reset_control_put(omm->child[i].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;
+ 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, "omm");
+ if (IS_ERR(omm->io_base))
+ return PTR_ERR(omm->io_base);
+
+ omm->mm_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "omm_mm");
+
+ /* 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;
+ omm->child[omm->nb_child].clk = of_clk_get(child, 0);
+ omm->child[omm->nb_child].reset = of_reset_control_get_exclusive(child, 0);
+ 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;
+ }
+
+ return 0;
+
+err_clk_release:
+ for (i = 0; i < omm->nb_child; i++) {
+ clk_put(omm->child[i].clk);
+ reset_control_put(omm->child[i].reset);
+ }
+
+ 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);
+
+ for (i = 0; i < omm->nb_child; i++) {
+ clk_put(omm->child[i].clk);
+ reset_control_put(omm->child[i].reset);
+ };
+
+ 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] 16+ messages in thread
* [PATCH 5/9] arm64: dts: st: Add OMM node on stm32mp251
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
` (3 preceding siblings ...)
2025-01-22 14:10 ` [PATCH 4/9] misc: Add STM32 Octo Memory Manager driver patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 14:10 ` [PATCH 6/9] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi patrice.chotard
` (3 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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..7d23a0beb154 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 = "omm", "omm_mm";
+ ranges = <0 0 0x40430000 0x400>,
+ <1 0 0x40440000 0x400>;
+ clocks = <&rcc CK_BUS_OSPIIOM>;
+ resets = <&rcc OSPIIOM_R>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ st,syscfg-amcr = <&syscfg 0x2c00 0x7>;
+ access-controllers = <&rifsc 111>;
+ power-domains = <&CLUSTER_PD>;
+ 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";
+ st,syscfg-dlyb = <&syscfg 0x1000>;
+ 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>;
+ 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";
+ st,syscfg-dlyb = <&syscfg 0x1400>;
+ 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>;
+ status = "disabled";
+ };
+ };
+
spi8: spi@46020000 {
#address-cells = <1>;
#size-cells = <0>;
--
2.25.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 6/9] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
` (4 preceding siblings ...)
2025-01-22 14:10 ` [PATCH 5/9] arm64: dts: st: Add OMM node on stm32mp251 patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 14:10 ` [PATCH 7/9] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board patrice.chotard
` (2 subsequent siblings)
8 siblings, 0 replies; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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] 16+ messages in thread
* [PATCH 7/9] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
` (5 preceding siblings ...)
2025-01-22 14:10 ` [PATCH 6/9] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 14:10 ` [PATCH 8/9] arm64: defconfig: Enable STM32 Octo Memory Manager driver patrice.chotard
2025-01-22 14:10 ` [PATCH 9/9] arm64: defconfig: Enable STM32 OctoSPI driver patrice.chotard
8 siblings, 0 replies; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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 | 33 ++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index 1b88485a62a1..fe5577fff4d3 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,34 @@ &i2c8 {
status = "disabled";
};
+&ommanager {
+ memory-region = <&mm_ospi1>;
+ memory-region-names = "mm_ospi1";
+ pinctrl-names = "default", "sleep";
+ 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>;
+ 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] 16+ messages in thread
* [PATCH 8/9] arm64: defconfig: Enable STM32 Octo Memory Manager driver
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
` (6 preceding siblings ...)
2025-01-22 14:10 ` [PATCH 7/9] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
2025-01-22 15:23 ` Krzysztof Kozlowski
2025-01-22 14:10 ` [PATCH 9/9] arm64: defconfig: Enable STM32 OctoSPI driver patrice.chotard
8 siblings, 1 reply; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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 Octo Memory Manager (OMM) driver which is needed
for OSPI usage on STM32 platforms.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 246a13412bf0..28df37d1baa6 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -294,6 +294,7 @@ CONFIG_BLK_DEV_NVME=m
CONFIG_QCOM_COINCELL=m
CONFIG_QCOM_FASTRPC=m
CONFIG_SRAM=y
+CONFIG_STM32_OMM=m
CONFIG_PCI_ENDPOINT_TEST=m
CONFIG_EEPROM_AT24=m
CONFIG_EEPROM_AT25=m
--
2.25.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 9/9] arm64: defconfig: Enable STM32 OctoSPI driver
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
` (7 preceding siblings ...)
2025-01-22 14:10 ` [PATCH 8/9] arm64: defconfig: Enable STM32 Octo Memory Manager driver patrice.chotard
@ 2025-01-22 14:10 ` patrice.chotard
8 siblings, 0 replies; 16+ messages in thread
From: patrice.chotard @ 2025-01-22 14:10 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 the STM32 OctoSPI driver.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 28df37d1baa6..dbd8ed3bbd7d 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -578,6 +578,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
--
2.25.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller
2025-01-22 14:10 ` [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
@ 2025-01-22 15:18 ` Krzysztof Kozlowski
2025-01-24 15:53 ` Patrice CHOTARD
0 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-22 15:18 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: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, christophe.kerello
On 22/01/2025 15:10, patrice.chotard@foss.st.com wrote:
> ---
> .../bindings/spi/st,stm32-ospi.yaml | 109 ++++++++++++++++++
> 1 file changed, 109 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
>
> diff --git a/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
> new file mode 100644
> index 000000000000..bf16252f85fa
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
Use compatible as filename.
> @@ -0,0 +1,109 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/spi/st,stm32-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:
> + description: registers
That's not helping. Please take a look how other bindings do it.
maxItems instead or you need to list the items with meaningful description.
> +
> + "#address-cells":
> + const: 1
> +
> + "#size-cells":
> + const: 0
Drop *cells.
> +
> + memory-region:
> + maxItems: 1
> + description: Phandle to a node describing memory-map region to be used
Drop description, redundant. Say something useful - the purpose - or
just maxItems if purpose is obvious.
> +
> + clocks:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + resets:
> + maxItems: 2
You need to list and describe the items.
> +
> + dmas:
> + items:
> + - description: tx DMA channel
> + - description: rx DMA channel
maxItems: 2 is enough, because names define what these are
> +
> + dma-names:
> + items:
> + - const: tx
> + - const: rx
> +
> + st,syscfg-dlyb:
> + description: |
> + Use to set the OSPI delay block within SYSCFG to:
Phandles to what? Describe also the destination device.
> + Tune the phase of the RX sampling clock (or DQS) in order
Unneeded indentation.
> + to sample the data in their valid window.
> + Tune the phase of the TX launch clock in order to meet setup
> + and hold constraints of TX signals versus the memory clock.
> + $ref: /schemas/types.yaml#/definitions/phandle-array
> + items:
> + minItems: 2
> + maxItems: 2
Your example has only one item, so probably you wanted one more items
with description. Now you miss one of matrix constraints.
git grep -C 8 phandle-array
(e.g. some sram or syscon examples)
> +
> + access-controllers:
> + minItems: 1
> + maxItems: 2
List the items.
> +
> + power-domains:
> + maxItems: 1
> +
> +required:
> + - compatible
> + - reg
> + - "#address-cells"
> + - "#size-cells"
Drop cells
> + - clocks
> + - interrupts
> + - st,syscfg-dlyb
> +
> +unevaluatedProperties: false
> +
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 3/9] dt-bindings: misc: Add STM32 Octo Memory Manager controller
2025-01-22 14:10 ` [PATCH 3/9] dt-bindings: misc: Add STM32 Octo Memory Manager controller patrice.chotard
@ 2025-01-22 15:22 ` Krzysztof Kozlowski
2025-01-24 15:53 ` Patrice CHOTARD
0 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-22 15:22 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: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, christophe.kerello
On 22/01/2025 15:10, 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>
> ---
> .../bindings/misc/st,stm32-omm.yaml | 194 ++++++++++++++++++
> 1 file changed, 194 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
All my other comments apply.
Also:
This cannot be misc. Depending what this is, either dedicated subsystem
like memory or soc.
>
> diff --git a/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml b/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
> new file mode 100644
> index 000000000000..ef8f5d2c526c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
> @@ -0,0 +1,194 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/misc/st,stm32-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>
> +
> + reg:
> + items:
> + - description: registers
Well, why here is entirely different syntax? Anyway, useless
description. Say something useful
> + - description: memory mapping
This is a bit better but still confusing. Memory mapping of what?
Virtual memory? This is vague to me.
> +
> + reg-names:
> + items:
> + - const: omm
> + - const: omm_mm
Not useful names. Drop prefixes and then you end up with empty first
entry :/
> +
> + memory-region:
> + description: Phandle to a node describing memory-map region to be used.
Constraints.
> +
> + memory-region-names:
> + minItems: 1
Nope, you just said one phandle?
> + items:
> + - const: mm_ospi1
> + - const: mm_ospi2
Drop redundant parts. If name is just 1 or 2, then just drop xxx-names
> +
> + clocks:
> + maxItems: 1
> +
> + resets:
> + maxItems: 1
> +
> + access-controllers:
> + minItems: 1
> + maxItems: 2
> +
> + 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.
> + Format is phandle to syscfg / register offset within syscfg / memory split
> + bitmask.
> + 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:
> + minItems: 3
> + maxItems: 3
> +
> + 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.
> + The 2 bits mask muxing description is:
> + -bit 0: Chip select selector override setting for OCTOSPI1
> + 0x0: the chip select signal from OCTOSPI1 is sent to NCS1
> + 0x1: the chip select signal from OCTOSPI1 is sent to NCS2
> + -bit 1: Chip select selector override setting for OCTOSPI2
> + 0x0: the chip select signal from OCTOSPI2 is sent to NCS1
> + 0x1: the chip select signal from OCTOSPI2 is sent to NCS2
> +
> + st,omm-mux:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: |
> + Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
> + The muxing 2 bits mask description is:
> + - 0x0: direct mode, default
> + - 0x1: mux OCTOSPI1 and OCTOSPI2 to port 1
> + - 0x2: swapped mode
> + - 0x3: mux OCTOSPI1 and OCTOSPI2 to port 2
> +
> + power-domains:
> + maxItems: 1
> +
> +patternProperties:
> + "^spi@[a-f0-9]+$":
> + type: object
> + $ref: "/schemas/spi/st,stm32-ospi.yaml#"
Drop quotes.
Look at your other $ref and keep things consistent.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 8/9] arm64: defconfig: Enable STM32 Octo Memory Manager driver
2025-01-22 14:10 ` [PATCH 8/9] arm64: defconfig: Enable STM32 Octo Memory Manager driver patrice.chotard
@ 2025-01-22 15:23 ` Krzysztof Kozlowski
2025-01-24 15:53 ` Patrice CHOTARD
0 siblings, 1 reply; 16+ messages in thread
From: Krzysztof Kozlowski @ 2025-01-22 15:23 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: linux-spi, devicetree, linux-stm32, linux-arm-kernel,
linux-kernel, christophe.kerello
On 22/01/2025 15:10, patrice.chotard@foss.st.com wrote:
> From: Patrice Chotard <patrice.chotard@foss.st.com>
>
> Enable STM32 Octo Memory Manager (OMM) driver which is needed
> for OSPI usage on STM32 platforms.
... And which upstream boards need it?
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller
2025-01-22 15:18 ` Krzysztof Kozlowski
@ 2025-01-24 15:53 ` Patrice CHOTARD
0 siblings, 0 replies; 16+ messages in thread
From: Patrice CHOTARD @ 2025-01-24 15:53 UTC (permalink / raw)
To: Krzysztof Kozlowski, 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
On 1/22/25 16:18, Krzysztof Kozlowski wrote:
> On 22/01/2025 15:10, patrice.chotard@foss.st.com wrote:
>> ---
>> .../bindings/spi/st,stm32-ospi.yaml | 109 ++++++++++++++++++
>> 1 file changed, 109 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml b/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
>> new file mode 100644
>> index 000000000000..bf16252f85fa
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/spi/st,stm32-ospi.yaml
>
>
> Use compatible as filename.
Ok
>
>> @@ -0,0 +1,109 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/spi/st,stm32-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:
>> + description: registers
>
> That's not helping. Please take a look how other bindings do it.
> maxItems instead or you need to list the items with meaningful description.
ok, will use maxItems
>
>> +
>> + "#address-cells":
>> + const: 1
>> +
>> + "#size-cells":
>> + const: 0
>
> Drop *cells.
ok
>> +
>> + memory-region:
>> + maxItems: 1
>> + description: Phandle to a node describing memory-map region to be used
>
> Drop description, redundant. Say something useful - the purpose - or
> just maxItems if purpose is obvious.
ok, i will add
- description: phandle to OSPI block reset
- description: phandle to delay block reset
>
>> +
>> + clocks:
>> + maxItems: 1
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + resets:
>> + maxItems: 2
>
> You need to list and describe the items.
ok
>
>> +
>> + dmas:
>> + items:
>> + - description: tx DMA channel
>> + - description: rx DMA channel
>
> maxItems: 2 is enough, because names define what these are
ok
>
>> +
>> + dma-names:
>> + items:
>> + - const: tx
>> + - const: rx
>> +
>> + st,syscfg-dlyb:
>> + description: |
>> + Use to set the OSPI delay block within SYSCFG to:
>
> Phandles to what? Describe also the destination device.
>
>> + Tune the phase of the RX sampling clock (or DQS) in order
>
> Unneeded indentation.
>
>> + to sample the data in their valid window.
>> + Tune the phase of the TX launch clock in order to meet setup
>> + and hold constraints of TX signals versus the memory clock.
>> + $ref: /schemas/types.yaml#/definitions/phandle-array
>> + items:
>> + minItems: 2
>> + maxItems: 2
>
> Your example has only one item, so probably you wanted one more items
> with description. Now you miss one of matrix constraints.
My fault, only one item is required.
>
> git grep -C 8 phandle-array
> (e.g. some sram or syscon examples)
>
>
>
>> +
>> + access-controllers:
>> + minItems: 1
>> + maxItems: 2
>
> List the items.
i will update as following:
access-controllers:
- description: phandle to the rifsc device to check access right.
- description: phandle to the rcc device for secure clock control
minItems: 1
maxItems: 2
>
>> +
>> + power-domains:
>> + maxItems: 1
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - "#address-cells"
>> + - "#size-cells"
>
> Drop cells
ok
>
>> + - clocks
>> + - interrupts
>> + - st,syscfg-dlyb
>> +
>> +unevaluatedProperties: false
>> +
>
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 3/9] dt-bindings: misc: Add STM32 Octo Memory Manager controller
2025-01-22 15:22 ` Krzysztof Kozlowski
@ 2025-01-24 15:53 ` Patrice CHOTARD
0 siblings, 0 replies; 16+ messages in thread
From: Patrice CHOTARD @ 2025-01-24 15:53 UTC (permalink / raw)
To: Krzysztof Kozlowski, 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
On 1/22/25 16:22, Krzysztof Kozlowski wrote:
> On 22/01/2025 15:10, 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>
>> ---
>> .../bindings/misc/st,stm32-omm.yaml | 194 ++++++++++++++++++
>> 1 file changed, 194 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
>
>
> All my other comments apply.
>
> Also:
> This cannot be misc. Depending what this is, either dedicated subsystem
> like memory or soc.
>
Ok i will migrate it to memory
>
>>
>> diff --git a/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml b/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
>> new file mode 100644
>> index 000000000000..ef8f5d2c526c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/misc/st,stm32-omm.yaml
>
>
>> @@ -0,0 +1,194 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/misc/st,stm32-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>
>> +
>> + reg:
>> + items:
>> + - description: registers
>
> Well, why here is entirely different syntax? Anyway, useless
> description. Say something useful
ok
>
>> + - description: memory mapping
>
> This is a bit better but still confusing. Memory mapping of what?
> Virtual memory? This is vague to me.
It's a memory map area, i will update to :
reg:
items:
- description: OMM registers
- description: OMM memory map area
>
>> +
>> + reg-names:
>> + items:
>> + - const: omm
>> + - const: omm_mm
>
> Not useful names. Drop prefixes and then you end up with empty first
> entry :/
Will replace by
reg-names:
items:
- const: regs
- const: memory_map
>
>> +
>> + memory-region:
>> + description: Phandle to a node describing memory-map region to be used.
>
> Constraints.
>
>> +
>> + memory-region-names:
>> + minItems: 1
>
> Nope, you just said one phandle?
I made an error, it's not mandatory and can be up to 2 phandle.
will update as following:
memory-region:
description: Phandle to a node describing memory-map region to be used.
maxItems: 2
>
>> + items:
>> + - const: mm_ospi1
>> + - const: mm_ospi2
>
> Drop redundant parts. If name is just 1 or 2, then just drop xxx-names
I will remove the memory-regions-names properties (a driver update is needed accordingly)
>
>> +
>> + clocks:
>> + maxItems: 1
>> +
>> + resets:
>> + maxItems: 1
>> +
>> + access-controllers:
>> + minItems: 1
>> + maxItems: 2
>> +
>> + 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.
>> + Format is phandle to syscfg / register offset within syscfg / memory split
>> + bitmask.
>> + 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:
>> + minItems: 3
>> + maxItems: 3
>> +
>> + 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.
>> + The 2 bits mask muxing description is:
>> + -bit 0: Chip select selector override setting for OCTOSPI1
>> + 0x0: the chip select signal from OCTOSPI1 is sent to NCS1
>> + 0x1: the chip select signal from OCTOSPI1 is sent to NCS2
>> + -bit 1: Chip select selector override setting for OCTOSPI2
>> + 0x0: the chip select signal from OCTOSPI2 is sent to NCS1
>> + 0x1: the chip select signal from OCTOSPI2 is sent to NCS2
>> +
>> + st,omm-mux:
>> + $ref: /schemas/types.yaml#/definitions/uint32
>> + description: |
>> + Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
>> + The muxing 2 bits mask description is:
>> + - 0x0: direct mode, default
>> + - 0x1: mux OCTOSPI1 and OCTOSPI2 to port 1
>> + - 0x2: swapped mode
>> + - 0x3: mux OCTOSPI1 and OCTOSPI2 to port 2
>> +
>> + power-domains:
>> + maxItems: 1
>> +
>> +patternProperties:
>> + "^spi@[a-f0-9]+$":
>> + type: object
>> + $ref: "/schemas/spi/st,stm32-ospi.yaml#"
>
> Drop quotes.
>
> Look at your other $ref and keep things consistent.
ok
Thanks
Patrice
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 8/9] arm64: defconfig: Enable STM32 Octo Memory Manager driver
2025-01-22 15:23 ` Krzysztof Kozlowski
@ 2025-01-24 15:53 ` Patrice CHOTARD
0 siblings, 0 replies; 16+ messages in thread
From: Patrice CHOTARD @ 2025-01-24 15:53 UTC (permalink / raw)
To: Krzysztof Kozlowski, 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
On 1/22/25 16:23, Krzysztof Kozlowski wrote:
> On 22/01/2025 15:10, patrice.chotard@foss.st.com wrote:
>> From: Patrice Chotard <patrice.chotard@foss.st.com>
>>
>> Enable STM32 Octo Memory Manager (OMM) driver which is needed
>> for OSPI usage on STM32 platforms.
> ... And which upstream boards need it?
Right, i will add that is needed for stm32mp257f-ev1 board
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2025-01-24 15:56 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-22 14:10 [PATCH 0/9] Add STM32MP25 SPI NOR support patrice.chotard
2025-01-22 14:10 ` [PATCH 1/9] dt-bindings: spi: Add STM32 OSPI controller patrice.chotard
2025-01-22 15:18 ` Krzysztof Kozlowski
2025-01-24 15:53 ` Patrice CHOTARD
2025-01-22 14:10 ` [PATCH 2/9] spi: stm32: Add OSPI driver patrice.chotard
2025-01-22 14:10 ` [PATCH 3/9] dt-bindings: misc: Add STM32 Octo Memory Manager controller patrice.chotard
2025-01-22 15:22 ` Krzysztof Kozlowski
2025-01-24 15:53 ` Patrice CHOTARD
2025-01-22 14:10 ` [PATCH 4/9] misc: Add STM32 Octo Memory Manager driver patrice.chotard
2025-01-22 14:10 ` [PATCH 5/9] arm64: dts: st: Add OMM node on stm32mp251 patrice.chotard
2025-01-22 14:10 ` [PATCH 6/9] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi patrice.chotard
2025-01-22 14:10 ` [PATCH 7/9] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board patrice.chotard
2025-01-22 14:10 ` [PATCH 8/9] arm64: defconfig: Enable STM32 Octo Memory Manager driver patrice.chotard
2025-01-22 15:23 ` Krzysztof Kozlowski
2025-01-24 15:53 ` Patrice CHOTARD
2025-01-22 14:10 ` [PATCH 9/9] arm64: defconfig: Enable STM32 OctoSPI driver patrice.chotard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).