* [PATCH v6 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
2025-03-21 9:32 [PATCH v6 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
@ 2025-03-21 9:32 ` Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller Patrice Chotard
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Patrice Chotard @ 2025-03-21 9:32 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon
Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
linux-arm-kernel, Patrice Chotard
Add myself as STM32 OCTO MEMORY MANAGER maintainer.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b7e1f9c30f3e45fb85b0d0f58b56db84d986061..830245c8d583c422e869dfe4b5a184faaf52b559 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22766,6 +22766,12 @@ L: linux-i2c@vger.kernel.org
S: Maintained
F: drivers/i2c/busses/i2c-stm32*
+ST STM32 OCTO MEMORY MANAGER
+M: Patrice Chotard <patrice.chotard@foss.st.com>
+S: Maintained
+F: Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
+F: drivers/memory/stm32_omm.c
+
ST STM32 SPI DRIVER
M: Alain Volmat <alain.volmat@foss.st.com>
L: linux-spi@vger.kernel.org
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v6 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
2025-03-21 9:32 [PATCH v6 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver Patrice Chotard
@ 2025-03-21 9:32 ` Patrice Chotard
2025-03-21 14:02 ` Rob Herring
2025-03-21 9:32 ` [PATCH v6 3/7] memory: Add STM32 Octo Memory Manager driver Patrice Chotard
` (4 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Patrice Chotard @ 2025-03-21 9:32 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon
Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
linux-arm-kernel, Patrice Chotard
Add bindings for STM32 Octo Memory Manager (OMM) controller.
OMM manages:
- the muxing between 2 OSPI busses and 2 output ports.
There are 4 possible muxing configurations:
- direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
output is on port 2
- OSPI1 and OSPI2 are multiplexed over the same output port 1
- swapped mode (no multiplexing), OSPI1 output is on port 2,
OSPI2 output is on port 1
- OSPI1 and OSPI2 are multiplexed over the same output port 2
- the split of the memory area shared between the 2 OSPI instances.
- chip select selection override.
- the time between 2 transactions in multiplexed mode.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
.../memory-controllers/st,stm32mp25-omm.yaml | 227 +++++++++++++++++++++
1 file changed, 227 insertions(+)
diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2f8fa7569009369ebd077e4c6f4ab409a91838a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
@@ -0,0 +1,227 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/memory-controllers/st,stm32mp25-omm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: STM32 Octo Memory Manager (OMM)
+
+maintainers:
+ - Patrice Chotard <patrice.chotard@foss.st.com>
+
+description: |
+ The STM32 Octo Memory Manager is a low-level interface that enables an
+ efficient OCTOSPI pin assignment with a full I/O matrix (before alternate
+ function map) and multiplex of single/dual/quad/octal SPI interfaces over
+ the same bus. It Supports up to:
+ - Two single/dual/quad/octal SPI interfaces
+ - Two ports for pin assignment
+
+properties:
+ compatible:
+ const: st,stm32mp25-omm
+
+ "#address-cells":
+ const: 2
+
+ "#size-cells":
+ const: 1
+
+ ranges:
+ description: |
+ Reflects the memory layout with four integer values per OSPI instance.
+ Format:
+ <chip-select> 0 <registers base address> <size>
+ minItems: 2
+ maxItems: 2
+
+ reg:
+ items:
+ - description: OMM registers
+ - description: OMM memory map area
+
+ reg-names:
+ items:
+ - const: regs
+ - const: memory_map
+
+ memory-region:
+ description: |
+ Memory region shared between the 2 OCTOSPI instance.
+ One or two phandle to a node describing a memory mapped region
+ depending of child number.
+ minItems: 1
+ maxItems: 2
+
+ memory-region-names:
+ description: |
+ OCTOSPI instance's name to which memory region is associated
+ items:
+ enum: [ospi1, ospi2]
+ minItems: 1
+ maxItems: 2
+
+ clocks:
+ minItems: 3
+ maxItems: 3
+
+ clock-names:
+ items:
+ enum: [omm, ospi1, ospi2]
+ minItems: 3
+ maxItems: 3
+
+ resets:
+ minItems: 3
+ maxItems: 3
+
+ reset-names:
+ items:
+ enum: [omm, ospi1, ospi2]
+ minItems: 3
+ maxItems: 3
+
+ access-controllers:
+ maxItems: 1
+
+ st,syscfg-amcr:
+ $ref: /schemas/types.yaml#/definitions/phandle-array
+ description: |
+ The Address Mapping Control Register (AMCR) is used to split the 256MB
+ memory map area shared between the 2 OSPI instance. The Octo Memory
+ Manager sets the AMCR depending of the memory-region configuration.
+ The memory split bitmask description is:
+ - 000: OCTOSPI1 (256 Mbytes), OCTOSPI2 unmapped
+ - 001: OCTOSPI1 (192 Mbytes), OCTOSPI2 (64 Mbytes)
+ - 010: OCTOSPI1 (128 Mbytes), OCTOSPI2 (128 Mbytes)
+ - 011: OCTOSPI1 (64 Mbytes), OCTOSPI2 (192 Mbytes)
+ - 1xx: OCTOSPI1 unmapped, OCTOSPI2 (256 Mbytes)
+ items:
+ - description: phandle to syscfg
+ - description: register offset within syscfg
+ - description: register bitmask for memory split
+
+ st,omm-req2ack-ns:
+ description: |
+ In multiplexed mode (MUXEN = 1), this field defines the time in
+ nanoseconds between two transactions.
+ default: 0
+
+ st,omm-cssel-ovr:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ Configure the chip select selector override for the 2 OCTOSPIs.
+ - 0: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS1
+ - 1: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS1
+ - 2: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS2
+ - 3: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS2
+ minimum: 0
+ maximum: 3
+ default: 0
+
+ st,omm-mux:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ description: |
+ Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
+ - 0: direct mode
+ - 1: mux OCTOSPI1 and OCTOSPI2 to port 1
+ - 2: swapped mode
+ - 3: mux OCTOSPI1 and OCTOSPI2 to port 2
+ minimum: 0
+ maximum: 3
+ default: 0
+
+ power-domains:
+ maxItems: 1
+
+patternProperties:
+ ^spi@[a-f0-9]+$:
+ type: object
+ $ref: /schemas/spi/st,stm32mp25-ospi.yaml#
+ description: Required spi child node
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - clocks
+ - clock-names
+ - resets
+ - reset-names
+ - st,syscfg-amcr
+ - ranges
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/st,stm32mp25-rcc.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/reset/st,stm32mp25-rcc.h>
+ ommanager@40500000 {
+ compatible = "st,stm32mp25-omm";
+ reg = <0x40500000 0x400>, <0x60000000 0x10000000>;
+ reg-names = "regs", "memory_map";
+ ranges = <0 0 0x40430000 0x400>,
+ <1 0 0x40440000 0x400>;
+ memory-region = <&mm_ospi1>, <&mm_ospi2>;
+ memory-region-names = "ospi1", "ospi2";
+ pinctrl-0 = <&ospi_port1_clk_pins_a
+ &ospi_port1_io03_pins_a
+ &ospi_port1_cs0_pins_a>;
+ pinctrl-1 = <&ospi_port1_clk_sleep_pins_a
+ &ospi_port1_io03_sleep_pins_a
+ &ospi_port1_cs0_sleep_pins_a>;
+ pinctrl-names = "default", "sleep";
+ clocks = <&rcc CK_BUS_OSPIIOM>,
+ <&scmi_clk CK_SCMI_OSPI1>,
+ <&scmi_clk CK_SCMI_OSPI2>;
+ clock-names = "omm", "ospi1", "ospi2";
+ resets = <&rcc OSPIIOM_R>,
+ <&scmi_reset RST_SCMI_OSPI1>,
+ <&scmi_reset RST_SCMI_OSPI2>;
+ reset-names = "omm", "ospi1", "ospi2";
+ access-controllers = <&rifsc 111>;
+ power-domains = <&CLUSTER_PD>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ st,syscfg-amcr = <&syscfg 0x2c00 0x7>;
+ st,omm-req2ack-ns = <0>;
+ st,omm-mux = <0>;
+ st,omm-cssel-ovr = <0>;
+
+ spi@40430000 {
+ compatible = "st,stm32mp25-ospi";
+ reg = <0 0 0x400>;
+ memory-region = <&mm_ospi1>;
+ interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&hpdma 2 0x62 0x00003121 0x0>,
+ <&hpdma 2 0x42 0x00003112 0x0>;
+ dma-names = "tx", "rx";
+ clocks = <&scmi_clk CK_SCMI_OSPI1>;
+ resets = <&scmi_reset RST_SCMI_OSPI1>, <&scmi_reset RST_SCMI_OSPI1DLL>;
+ access-controllers = <&rifsc 74>;
+ power-domains = <&CLUSTER_PD>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-dlyb = <&syscfg 0x1000>;
+ };
+
+ spi@40440000 {
+ compatible = "st,stm32mp25-ospi";
+ reg = <1 0 0x400>;
+ memory-region = <&mm_ospi1>;
+ interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&hpdma 3 0x62 0x00003121 0x0>,
+ <&hpdma 3 0x42 0x00003112 0x0>;
+ dma-names = "tx", "rx";
+ clocks = <&scmi_clk CK_KER_OSPI2>;
+ resets = <&scmi_reset RST_SCMI_OSPI2>, <&scmi_reset RST_SCMI_OSPI1DLL>;
+ access-controllers = <&rifsc 75>;
+ power-domains = <&CLUSTER_PD>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ st,syscfg-dlyb = <&syscfg 0x1000>;
+ };
+ };
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v6 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
2025-03-21 9:32 ` [PATCH v6 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller Patrice Chotard
@ 2025-03-21 14:02 ` Rob Herring
2025-03-24 13:29 ` Patrice CHOTARD
0 siblings, 1 reply; 10+ messages in thread
From: Rob Herring @ 2025-03-21 14:02 UTC (permalink / raw)
To: Patrice Chotard
Cc: Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon, christophe.kerello, linux-kernel,
devicetree, linux-stm32, linux-arm-kernel
On Fri, Mar 21, 2025 at 10:32:22AM +0100, Patrice Chotard wrote:
> Add bindings for STM32 Octo Memory Manager (OMM) controller.
>
> OMM manages:
> - the muxing between 2 OSPI busses and 2 output ports.
> There are 4 possible muxing configurations:
> - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
> output is on port 2
> - OSPI1 and OSPI2 are multiplexed over the same output port 1
> - swapped mode (no multiplexing), OSPI1 output is on port 2,
> OSPI2 output is on port 1
> - OSPI1 and OSPI2 are multiplexed over the same output port 2
> - the split of the memory area shared between the 2 OSPI instances.
> - chip select selection override.
> - the time between 2 transactions in multiplexed mode.
>
> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
> ---
> .../memory-controllers/st,stm32mp25-omm.yaml | 227 +++++++++++++++++++++
> 1 file changed, 227 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..2f8fa7569009369ebd077e4c6f4ab409a91838a5
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
> @@ -0,0 +1,227 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/memory-controllers/st,stm32mp25-omm.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: STM32 Octo Memory Manager (OMM)
> +
> +maintainers:
> + - Patrice Chotard <patrice.chotard@foss.st.com>
> +
> +description: |
> + The STM32 Octo Memory Manager is a low-level interface that enables an
> + efficient OCTOSPI pin assignment with a full I/O matrix (before alternate
> + function map) and multiplex of single/dual/quad/octal SPI interfaces over
> + the same bus. It Supports up to:
> + - Two single/dual/quad/octal SPI interfaces
> + - Two ports for pin assignment
> +
> +properties:
> + compatible:
> + const: st,stm32mp25-omm
> +
> + "#address-cells":
> + const: 2
> +
> + "#size-cells":
> + const: 1
> +
> + ranges:
> + description: |
> + Reflects the memory layout with four integer values per OSPI instance.
You say 4 here...
> + Format:
> + <chip-select> 0 <registers base address> <size>
> + minItems: 2
> + maxItems: 2
And 2 here. I'm confused. From the example it doesn't look like you are
using ranges correctly. If you are parsing it yourself, that's wrong.
More below.
> +
> + reg:
> + items:
> + - description: OMM registers
> + - description: OMM memory map area
> +
> + reg-names:
> + items:
> + - const: regs
> + - const: memory_map
> +
> + memory-region:
> + description: |
> + Memory region shared between the 2 OCTOSPI instance.
> + One or two phandle to a node describing a memory mapped region
> + depending of child number.
> + minItems: 1
> + maxItems: 2
> +
> + memory-region-names:
> + description: |
Don't need '|'.
> + OCTOSPI instance's name to which memory region is associated
That doesn't really tell me anything.
> + items:
> + enum: [ospi1, ospi2]
> + minItems: 1
> + maxItems: 2
> +
> + clocks:
> + minItems: 3
> + maxItems: 3
> +
> + clock-names:
> + items:
> + enum: [omm, ospi1, ospi2]
Define the order.
> + minItems: 3
> + maxItems: 3
> +
> + resets:
> + minItems: 3
> + maxItems: 3
> +
> + reset-names:
> + items:
> + enum: [omm, ospi1, ospi2]
Define the order.
> + minItems: 3
> + maxItems: 3
> +
> + access-controllers:
> + maxItems: 1
> +
> + st,syscfg-amcr:
> + $ref: /schemas/types.yaml#/definitions/phandle-array
> + description: |
> + The Address Mapping Control Register (AMCR) is used to split the 256MB
> + memory map area shared between the 2 OSPI instance. The Octo Memory
> + Manager sets the AMCR depending of the memory-region configuration.
> + The memory split bitmask description is:
> + - 000: OCTOSPI1 (256 Mbytes), OCTOSPI2 unmapped
> + - 001: OCTOSPI1 (192 Mbytes), OCTOSPI2 (64 Mbytes)
> + - 010: OCTOSPI1 (128 Mbytes), OCTOSPI2 (128 Mbytes)
> + - 011: OCTOSPI1 (64 Mbytes), OCTOSPI2 (192 Mbytes)
> + - 1xx: OCTOSPI1 unmapped, OCTOSPI2 (256 Mbytes)
> + items:
> + - description: phandle to syscfg
> + - description: register offset within syscfg
> + - description: register bitmask for memory split
> +
> + st,omm-req2ack-ns:
> + description: |
Don't need '|'.
> + In multiplexed mode (MUXEN = 1), this field defines the time in
> + nanoseconds between two transactions.
> + default: 0
> +
> + st,omm-cssel-ovr:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: |
> + Configure the chip select selector override for the 2 OCTOSPIs.
> + - 0: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS1
> + - 1: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS1
> + - 2: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS2
> + - 3: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS2
> + minimum: 0
> + maximum: 3
> + default: 0
> +
> + st,omm-mux:
> + $ref: /schemas/types.yaml#/definitions/uint32
> + description: |
> + Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
> + - 0: direct mode
> + - 1: mux OCTOSPI1 and OCTOSPI2 to port 1
> + - 2: swapped mode
> + - 3: mux OCTOSPI1 and OCTOSPI2 to port 2
> + minimum: 0
> + maximum: 3
> + default: 0
> +
> + power-domains:
> + maxItems: 1
> +
> +patternProperties:
> + ^spi@[a-f0-9]+$:
> + type: object
> + $ref: /schemas/spi/st,stm32mp25-ospi.yaml#
> + description: Required spi child node
> +
> +required:
> + - compatible
> + - reg
> + - "#address-cells"
> + - "#size-cells"
> + - clocks
> + - clock-names
> + - resets
> + - reset-names
> + - st,syscfg-amcr
> + - ranges
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/st,stm32mp25-rcc.h>
> + #include <dt-bindings/interrupt-controller/arm-gic.h>
> + #include <dt-bindings/reset/st,stm32mp25-rcc.h>
> + ommanager@40500000 {
> + compatible = "st,stm32mp25-omm";
> + reg = <0x40500000 0x400>, <0x60000000 0x10000000>;
> + reg-names = "regs", "memory_map";
> + ranges = <0 0 0x40430000 0x400>,
> + <1 0 0x40440000 0x400>;
> + #address-cells = <2>;
> + #size-cells = <1>;
> +
> + spi@40430000 {
ranges is okay, but the unit-address is wrong here. It should be based
on reg below. So 'spi@0' or 'spi@0,0' since chip select is a distinct
field. It's up to you, but you need to define the format in the schema.
> + compatible = "st,stm32mp25-ospi";
> + reg = <0 0 0x400>;
> + memory-region = <&mm_ospi1>;
> + interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
> + dmas = <&hpdma 2 0x62 0x00003121 0x0>,
> + <&hpdma 2 0x42 0x00003112 0x0>;
> + dma-names = "tx", "rx";
> + clocks = <&scmi_clk CK_SCMI_OSPI1>;
> + resets = <&scmi_reset RST_SCMI_OSPI1>, <&scmi_reset RST_SCMI_OSPI1DLL>;
> + access-controllers = <&rifsc 74>;
> + power-domains = <&CLUSTER_PD>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> + st,syscfg-dlyb = <&syscfg 0x1000>;
> + };
> +
> + spi@40440000 {
spi@1,0
> + compatible = "st,stm32mp25-ospi";
> + reg = <1 0 0x400>;
> + memory-region = <&mm_ospi1>;
> + interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
> + dmas = <&hpdma 3 0x62 0x00003121 0x0>,
> + <&hpdma 3 0x42 0x00003112 0x0>;
> + dma-names = "tx", "rx";
> + clocks = <&scmi_clk CK_KER_OSPI2>;
> + resets = <&scmi_reset RST_SCMI_OSPI2>, <&scmi_reset RST_SCMI_OSPI1DLL>;
> + access-controllers = <&rifsc 75>;
> + power-domains = <&CLUSTER_PD>;
> + #address-cells = <1>;
> + #size-cells = <0>;
> + st,syscfg-dlyb = <&syscfg 0x1000>;
> + };
> + };
>
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
2025-03-21 14:02 ` Rob Herring
@ 2025-03-24 13:29 ` Patrice CHOTARD
0 siblings, 0 replies; 10+ messages in thread
From: Patrice CHOTARD @ 2025-03-24 13:29 UTC (permalink / raw)
To: Rob Herring
Cc: Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon, christophe.kerello, linux-kernel,
devicetree, linux-stm32, linux-arm-kernel
On 3/21/25 15:02, Rob Herring wrote:
> On Fri, Mar 21, 2025 at 10:32:22AM +0100, Patrice Chotard wrote:
>> Add bindings for STM32 Octo Memory Manager (OMM) controller.
>>
>> OMM manages:
>> - the muxing between 2 OSPI busses and 2 output ports.
>> There are 4 possible muxing configurations:
>> - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
>> output is on port 2
>> - OSPI1 and OSPI2 are multiplexed over the same output port 1
>> - swapped mode (no multiplexing), OSPI1 output is on port 2,
>> OSPI2 output is on port 1
>> - OSPI1 and OSPI2 are multiplexed over the same output port 2
>> - the split of the memory area shared between the 2 OSPI instances.
>> - chip select selection override.
>> - the time between 2 transactions in multiplexed mode.
>>
>> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
>> ---
>> .../memory-controllers/st,stm32mp25-omm.yaml | 227 +++++++++++++++++++++
>> 1 file changed, 227 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..2f8fa7569009369ebd077e4c6f4ab409a91838a5
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
>> @@ -0,0 +1,227 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/memory-controllers/st,stm32mp25-omm.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: STM32 Octo Memory Manager (OMM)
>> +
>> +maintainers:
>> + - Patrice Chotard <patrice.chotard@foss.st.com>
>> +
>> +description: |
>> + The STM32 Octo Memory Manager is a low-level interface that enables an
>> + efficient OCTOSPI pin assignment with a full I/O matrix (before alternate
>> + function map) and multiplex of single/dual/quad/octal SPI interfaces over
>> + the same bus. It Supports up to:
>> + - Two single/dual/quad/octal SPI interfaces
>> + - Two ports for pin assignment
>> +
>> +properties:
>> + compatible:
>> + const: st,stm32mp25-omm
>> +
>> + "#address-cells":
>> + const: 2
>> +
>> + "#size-cells":
>> + const: 1
>> +
>> + ranges:
>> + description: |
>> + Reflects the memory layout with four integer values per OSPI instance.
>
> You say 4 here...
Hi Rob,
Yes, each range is composed by 4 integers:
ranges = <0 0 0x40430000 0x400>,
<1 0 0x40440000 0x400>;
And we got 2 ranges entry, one for each OSPI instance.
Maybe to avoid confusion, i can just update the description as following:
+ description: |
+ Reflects the memory layout per OSPI instance.
Is it ok for you ?
>
>> + Format:
>> + <chip-select> 0 <registers base address> <size>
>> + minItems: 2
>> + maxItems: 2
>
> And 2 here. I'm confused. From the example it doesn't look like you are
see my answer just above.
> using ranges correctly. If you are parsing it yourself, that's wrong.
> More below.
>
>> +
>> + reg:
>> + items:
>> + - description: OMM registers
>> + - description: OMM memory map area
>> +
>> + reg-names:
>> + items:
>> + - const: regs
>> + - const: memory_map
>> +
>> + memory-region:
>> + description: |
>> + Memory region shared between the 2 OCTOSPI instance.
>> + One or two phandle to a node describing a memory mapped region
>> + depending of child number.
>> + minItems: 1
>> + maxItems: 2
>> +
>> + memory-region-names:
>> + description: |
>
> Don't need '|'.
Ok
>
>> + OCTOSPI instance's name to which memory region is associated
>
> That doesn't really tell me anything.
We must identify to which OSPI instance the memory region belongs to.
This is needed to configure/check the memory region area split between
these 2 OSPI instance.
Must i update the description ?
>
>> + items:
>> + enum: [ospi1, ospi2]
>> + minItems: 1
>> + maxItems: 2
>> +
>> + clocks:
>> + minItems: 3
>> + maxItems: 3
>> +
>> + clock-names:
>> + items:
>> + enum: [omm, ospi1, ospi2]
>
> Define the order.
Ok, i will update as following:
clock-names:
items:
- const: omm
- const: ospi1
- const: ospi2
>
>> + minItems: 3
>> + maxItems: 3
>> +
>> + resets:
>> + minItems: 3
>> + maxItems: 3
>> +
>> + reset-names:
>> + items:
>> + enum: [omm, ospi1, ospi2]
>
> Define the order.
ok, will update as below:
reset-names:
items:
- const: omm
- const: ospi1
- const: ospi2
>
>> + minItems: 3
>> + maxItems: 3
>> +
>> + access-controllers:
>> + maxItems: 1
>> +
>> + st,syscfg-amcr:
>> + $ref: /schemas/types.yaml#/definitions/phandle-array
>> + description: |
>> + The Address Mapping Control Register (AMCR) is used to split the 256MB
>> + memory map area shared between the 2 OSPI instance. The Octo Memory
>> + Manager sets the AMCR depending of the memory-region configuration.
>> + The memory split bitmask description is:
>> + - 000: OCTOSPI1 (256 Mbytes), OCTOSPI2 unmapped
>> + - 001: OCTOSPI1 (192 Mbytes), OCTOSPI2 (64 Mbytes)
>> + - 010: OCTOSPI1 (128 Mbytes), OCTOSPI2 (128 Mbytes)
>> + - 011: OCTOSPI1 (64 Mbytes), OCTOSPI2 (192 Mbytes)
>> + - 1xx: OCTOSPI1 unmapped, OCTOSPI2 (256 Mbytes)
>> + items:
>> + - description: phandle to syscfg
>> + - description: register offset within syscfg
>> + - description: register bitmask for memory split
>> +
>> + st,omm-req2ack-ns:
>> + description: |
>
> Don't need '|'.
ok
>
>> + In multiplexed mode (MUXEN = 1), this field defines the time in
>> + nanoseconds between two transactions.
>> + default: 0
>> +
>> + st,omm-cssel-ovr:
>> + $ref: /schemas/types.yaml#/definitions/uint32
>> + description: |
>> + Configure the chip select selector override for the 2 OCTOSPIs.
>> + - 0: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS1
>> + - 1: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS1
>> + - 2: OCTOSPI1 chip select send to NCS1 OCTOSPI2 chip select send to NCS2
>> + - 3: OCTOSPI1 chip select send to NCS2 OCTOSPI2 chip select send to NCS2
>> + minimum: 0
>> + maximum: 3
>> + default: 0
>> +
>> + st,omm-mux:
>> + $ref: /schemas/types.yaml#/definitions/uint32
>> + description: |
>> + Configure the muxing between the 2 OCTOSPIs busses and the 2 output ports.
>> + - 0: direct mode
>> + - 1: mux OCTOSPI1 and OCTOSPI2 to port 1
>> + - 2: swapped mode
>> + - 3: mux OCTOSPI1 and OCTOSPI2 to port 2
>> + minimum: 0
>> + maximum: 3
>> + default: 0
>> +
>> + power-domains:
>> + maxItems: 1
>> +
>> +patternProperties:
>> + ^spi@[a-f0-9]+$:
Due to your comments below, schema will be updated as following:
^spi@[0-9]:
>> + type: object
>> + $ref: /schemas/spi/st,stm32mp25-ospi.yaml#
>> + description: Required spi child node
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - "#address-cells"
>> + - "#size-cells"
>> + - clocks
>> + - clock-names
>> + - resets
>> + - reset-names
>> + - st,syscfg-amcr
>> + - ranges
>> +
>> +additionalProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/clock/st,stm32mp25-rcc.h>
>> + #include <dt-bindings/interrupt-controller/arm-gic.h>
>> + #include <dt-bindings/reset/st,stm32mp25-rcc.h>
>> + ommanager@40500000 {
>> + compatible = "st,stm32mp25-omm";
>> + reg = <0x40500000 0x400>, <0x60000000 0x10000000>;
>> + reg-names = "regs", "memory_map";
>> + ranges = <0 0 0x40430000 0x400>,
>> + <1 0 0x40440000 0x400>;
>
>> + #address-cells = <2>;
>> + #size-cells = <1>;
>> +
>
>> + spi@40430000 {
>
> ranges is okay, but the unit-address is wrong here. It should be based
> on reg below. So 'spi@0' or 'spi@0,0' since chip select is a distinct
> field. It's up to you, but you need to define the format in the schema.
Ok i will use spi@0
>
>> + compatible = "st,stm32mp25-ospi";
>> + reg = <0 0 0x400>;
>> + memory-region = <&mm_ospi1>;
>> + interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
>> + dmas = <&hpdma 2 0x62 0x00003121 0x0>,
>> + <&hpdma 2 0x42 0x00003112 0x0>;
>> + dma-names = "tx", "rx";
>> + clocks = <&scmi_clk CK_SCMI_OSPI1>;
>> + resets = <&scmi_reset RST_SCMI_OSPI1>, <&scmi_reset RST_SCMI_OSPI1DLL>;
>> + access-controllers = <&rifsc 74>;
>> + power-domains = <&CLUSTER_PD>;
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + st,syscfg-dlyb = <&syscfg 0x1000>;
>> + };
>> +
>> + spi@40440000 {
>
> spi@1,0
ok, will use spi@1
Thanks
Patrice
>
>> + compatible = "st,stm32mp25-ospi";
>> + reg = <1 0 0x400>;
>> + memory-region = <&mm_ospi1>;
>> + interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
>> + dmas = <&hpdma 3 0x62 0x00003121 0x0>,
>> + <&hpdma 3 0x42 0x00003112 0x0>;
>> + dma-names = "tx", "rx";
>> + clocks = <&scmi_clk CK_KER_OSPI2>;
>> + resets = <&scmi_reset RST_SCMI_OSPI2>, <&scmi_reset RST_SCMI_OSPI1DLL>;
>> + access-controllers = <&rifsc 75>;
>> + power-domains = <&CLUSTER_PD>;
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + st,syscfg-dlyb = <&syscfg 0x1000>;
>> + };
>> + };
>>
>> --
>> 2.25.1
>>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v6 3/7] memory: Add STM32 Octo Memory Manager driver
2025-03-21 9:32 [PATCH v6 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller Patrice Chotard
@ 2025-03-21 9:32 ` Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 4/7] arm64: dts: st: Add OMM node on stm32mp251 Patrice Chotard
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Patrice Chotard @ 2025-03-21 9:32 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon
Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
linux-arm-kernel, Patrice Chotard
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: Christophe Kerello <christophe.kerello@foss.st.com>
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
drivers/memory/Kconfig | 17 ++
drivers/memory/Makefile | 1 +
drivers/memory/stm32_omm.c | 474 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 492 insertions(+)
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index c82d8d8a16eaf154c247c0dbb9aff428b7c81402..3a0703fbfee7d1a9467cc74821604d3861fb1de0 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -225,6 +225,23 @@ config STM32_FMC2_EBI
devices (like SRAM, ethernet adapters, FPGAs, LCD displays, ...) on
SOCs containing the FMC2 External Bus Interface.
+config STM32_OMM
+ tristate "STM32 Octo Memory Manager"
+ depends on SPI_STM32_OSPI || COMPILE_TEST
+ help
+ This driver manages the muxing between the 2 OSPI busses and
+ the 2 output ports. There are 4 possible muxing configurations:
+ - direct mode (no multiplexing): OSPI1 output is on port 1 and OSPI2
+ output is on port 2
+ - OSPI1 and OSPI2 are multiplexed over the same output port 1
+ - swapped mode (no multiplexing), OSPI1 output is on port 2,
+ OSPI2 output is on port 1
+ - OSPI1 and OSPI2 are multiplexed over the same output port 2
+ It also manages :
+ - the split of the memory area shared between the 2 OSPI instances.
+ - chip select selection override.
+ - the time between 2 transactions in multiplexed mode.
+
source "drivers/memory/samsung/Kconfig"
source "drivers/memory/tegra/Kconfig"
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index d2e6ca9abbe0231c14284e3818ce734c618f83d0..c1959661bf63775bdded6dcbe87b732883c26135 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o
obj-$(CONFIG_PL353_SMC) += pl353-smc.o
obj-$(CONFIG_RENESAS_RPCIF) += renesas-rpc-if.o
obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o
+obj-$(CONFIG_STM32_OMM) += stm32_omm.o
obj-$(CONFIG_SAMSUNG_MC) += samsung/
obj-$(CONFIG_TEGRA_MC) += tegra/
diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a7029e2cb6d770b25339d79e5714f376acefeef
--- /dev/null
+++ b/drivers/memory/stm32_omm.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2025 - All Rights Reserved
+ * Author(s): Patrice Chotard <patrice.chotard@foss.st.com> for STMicroelectronics.
+ */
+
+#include <linux/bitfield.h>
+#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
+#define OMM_CLK_NB 3
+
+struct stm32_omm {
+ struct resource *mm_res;
+ struct clk_bulk_data clk_bulk[OMM_CLK_NB];
+ 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);
+ resource_size_t mm_ospi2_size = 0;
+ static const char * const mm_name[] = { "ospi1", "ospi2" };
+ struct regmap *syscfg_regmap;
+ struct device_node *node;
+ struct resource res, res1;
+ u32 amcr_base, amcr_mask;
+ int ret, idx;
+ unsigned int i, amcr, read_amcr;
+
+ for (i = 0; i < omm->nb_child; i++) {
+ idx = of_property_match_string(dev->of_node,
+ "memory-region-names",
+ mm_name[i]);
+ if (idx < 0)
+ continue;
+
+ /* res1 only used on second loop iteration */
+ res1.start = res.start;
+ res1.end = res.end;
+
+ node = of_parse_phandle(dev->of_node, "memory-region", idx);
+ if (!node)
+ continue;
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ dev_err(dev, "unable to resolve memory region\n");
+ return ret;
+ }
+
+ /* check that memory region fits inside OMM memory map area */
+ if (!resource_contains(omm->mm_res, &res)) {
+ dev_err(dev, "%s doesn't fit inside OMM memory map area\n",
+ mm_name[i]);
+ dev_err(dev, "%pR doesn't fit inside %pR\n", &res, omm->mm_res);
+
+ 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, "%pR overlaps %pR\n", &res1, &res);
+
+ return -EFAULT;
+ }
+ }
+ }
+
+ syscfg_regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "st,syscfg-amcr");
+ if (IS_ERR(syscfg_regmap))
+ return dev_err_probe(dev, PTR_ERR(syscfg_regmap),
+ "Failed to get st,syscfg-amcr property\n");
+
+ 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_toggle_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->clk_bulk[i + 1].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->clk_bulk[i + 1].clk);
+ }
+
+ first_child_clk = omm->clk_bulk[i + 1].clk;
+ }
+
+ return 0;
+}
+
+static int stm32_omm_disable_child(struct device *dev)
+{
+ static const char * const resets_name[] = {"ospi1", "ospi2"};
+ struct stm32_omm *omm = dev_get_drvdata(dev);
+ struct reset_control *reset;
+ int ret;
+ u8 i;
+
+ ret = stm32_omm_toggle_child_clock(dev, true);
+ if (!ret)
+ return ret;
+
+ for (i = 0; i < omm->nb_child; i++) {
+ reset = reset_control_get_exclusive(dev, resets_name[i]);
+ if (IS_ERR(reset)) {
+ dev_err(dev, "Can't get %s reset\n", resets_name[i]);
+ return PTR_ERR(reset);
+ };
+
+ /* reset OSPI to ensure CR_EN bit is set to 0 */
+ reset_control_assert(reset);
+ udelay(2);
+ reset_control_deassert(reset);
+
+ reset_control_put(reset);
+ }
+
+ return stm32_omm_toggle_child_clock(dev, false);
+}
+
+static int stm32_omm_configure(struct device *dev)
+{
+ static const char * const clocks_name[] = {"omm", "ospi1", "ospi2"};
+ struct stm32_omm *omm = dev_get_drvdata(dev);
+ unsigned long clk_rate_max = 0;
+ u32 mux = 0;
+ u32 cssel_ovr = 0;
+ u32 req2ack = 0;
+ struct reset_control *rstc;
+ unsigned long clk_rate;
+ int ret;
+ u8 i;
+
+ for (i = 0; i < OMM_CLK_NB; i++)
+ omm->clk_bulk[i].id = clocks_name[i];
+
+ /* retrieve OMM, OSPI1 and OSPI2 clocks */
+ ret = devm_clk_bulk_get(dev, OMM_CLK_NB, omm->clk_bulk);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get OMM/OSPI's clocks\n");
+
+ /* 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;
+
+ /* parse children's clock */
+ for (i = 1; i <= omm->nb_child; i++) {
+ clk_rate = clk_get_rate(omm->clk_bulk[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_exclusive(dev, "omm");
+ if (IS_ERR(rstc))
+ return dev_err_probe(dev, PTR_ERR(rstc), "reset get failed\n");
+
+ 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_toggle_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_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_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ u8 child_access_granted = 0;
+ struct stm32_omm *omm;
+ int ret;
+
+ omm = devm_kzalloc(dev, sizeof(*omm), GFP_KERNEL);
+ if (!omm)
+ return -ENOMEM;
+
+ omm->io_base = devm_platform_ioremap_resource_byname(pdev, "regs");
+ if (IS_ERR(omm->io_base))
+ return PTR_ERR(omm->io_base);
+
+ omm->mm_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory_map");
+ if (IS_ERR(omm->mm_res))
+ return PTR_ERR(omm->mm_res);
+
+ /* check child's access */
+ for_each_child_of_node_scoped(dev->of_node, child) {
+ if (omm->nb_child >= OMM_CHILD_NB) {
+ dev_err(dev, "Bad DT, found too much children\n");
+ return -E2BIG;
+ }
+
+ if (!of_device_is_compatible(child, "st,stm32mp25-omi"))
+ return -EINVAL;
+
+ ret = stm32_omm_check_access(child);
+ if (ret < 0 && ret != -EACCES)
+ return ret;
+
+ if (!ret)
+ child_access_granted++;
+
+ omm->nb_child++;
+ }
+
+ if (omm->nb_child != OMM_CHILD_NB)
+ return -EINVAL;
+
+ platform_set_drvdata(pdev, omm);
+
+ pm_runtime_enable(dev);
+
+ /* check if OMM's resource access is granted */
+ ret = stm32_omm_check_access(dev->of_node);
+ if (ret < 0 && ret != -EACCES)
+ goto error;
+
+ if (!ret && child_access_granted == OMM_CHILD_NB) {
+ ret = stm32_omm_configure(dev);
+ if (ret)
+ goto error;
+ } 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 error;
+ }
+
+ ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
+ if (ret) {
+ dev_err(dev, "Failed to create Octo Memory Manager child\n");
+ of_platform_depopulate(dev);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ return ret;
+
+error:
+ pm_runtime_disable(dev);
+
+ return ret;
+
+}
+
+static void stm32_omm_remove(struct platform_device *pdev)
+{
+ struct stm32_omm *omm = platform_get_drvdata(pdev);
+
+ of_platform_depopulate(&pdev->dev);
+ if (omm->cr & CR_MUXEN)
+ stm32_omm_toggle_child_clock(&pdev->dev, false);
+
+ pm_runtime_disable(&pdev->dev);
+}
+
+static const struct of_device_id stm32_omm_of_match[] = {
+ { .compatible = "st,stm32mp25-omm", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_omm_of_match);
+
+static int __maybe_unused stm32_omm_runtime_suspend(struct device *dev)
+{
+ struct stm32_omm *omm = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(omm->clk_bulk[0].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_bulk[0].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_toggle_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_toggle_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] 10+ messages in thread
* [PATCH v6 4/7] arm64: dts: st: Add OMM node on stm32mp251
2025-03-21 9:32 [PATCH v6 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
` (2 preceding siblings ...)
2025-03-21 9:32 ` [PATCH v6 3/7] memory: Add STM32 Octo Memory Manager driver Patrice Chotard
@ 2025-03-21 9:32 ` Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 5/7] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi Patrice Chotard
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Patrice Chotard @ 2025-03-21 9:32 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon
Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
linux-arm-kernel, Patrice Chotard
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 | 54 ++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp251.dtsi b/arch/arm64/boot/dts/st/stm32mp251.dtsi
index f3c6cdfd7008c5b736ba75f5210d0eddb5b43489..d1f30c76b41d68f5d7da7998b0edbceb93ce4a12 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -768,6 +768,60 @@ rng: rng@42020000 {
status = "disabled";
};
+ ommanager: ommanager@40500000 {
+ compatible = "st,stm32mp25-omm";
+ reg = <0x40500000 0x400>, <0x60000000 0x10000000>;
+ reg-names = "regs", "memory_map";
+ ranges = <0 0 0x40430000 0x400>,
+ <1 0 0x40440000 0x400>;
+ clocks = <&rcc CK_BUS_OSPIIOM>,
+ <&scmi_clk CK_SCMI_OSPI1>,
+ <&scmi_clk CK_SCMI_OSPI2>;
+ clock-names = "omm", "ospi1", "ospi2";
+ resets = <&rcc OSPIIOM_R>,
+ <&scmi_reset RST_SCMI_OSPI1>,
+ <&scmi_reset RST_SCMI_OSPI2>;
+ reset-names = "omm", "ospi1", "ospi2";
+ access-controllers = <&rifsc 111>;
+ power-domains = <&CLUSTER_PD>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ st,syscfg-amcr = <&syscfg 0x2c00 0x7>;
+ status = "disabled";
+
+ ospi1: spi@40430000 {
+ compatible = "st,stm32mp25-ospi";
+ reg = <0 0 0x400>;
+ interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&hpdma 2 0x62 0x00003121>,
+ <&hpdma 2 0x42 0x00003112>;
+ dma-names = "tx", "rx";
+ clocks = <&scmi_clk CK_SCMI_OSPI1>;
+ resets = <&scmi_reset RST_SCMI_OSPI1>,
+ <&scmi_reset RST_SCMI_OSPI1DLL>;
+ access-controllers = <&rifsc 74>;
+ power-domains = <&CLUSTER_PD>;
+ st,syscfg-dlyb = <&syscfg 0x1000>;
+ status = "disabled";
+ };
+
+ ospi2: spi@40440000 {
+ compatible = "st,stm32mp25-ospi";
+ reg = <1 0 0x400>;
+ interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&hpdma 3 0x62 0x00003121>,
+ <&hpdma 3 0x42 0x00003112>;
+ dma-names = "tx", "rx";
+ clocks = <&scmi_clk CK_SCMI_OSPI2>;
+ resets = <&scmi_reset RST_SCMI_OSPI2>,
+ <&scmi_reset RST_SCMI_OSPI2DLL>;
+ access-controllers = <&rifsc 75>;
+ power-domains = <&CLUSTER_PD>;
+ st,syscfg-dlyb = <&syscfg 0x1400>;
+ status = "disabled";
+ };
+ };
+
spi8: spi@46020000 {
#address-cells = <1>;
#size-cells = <0>;
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v6 5/7] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
2025-03-21 9:32 [PATCH v6 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
` (3 preceding siblings ...)
2025-03-21 9:32 ` [PATCH v6 4/7] arm64: dts: st: Add OMM node on stm32mp251 Patrice Chotard
@ 2025-03-21 9:32 ` Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 6/7] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 7/7] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver Patrice Chotard
6 siblings, 0 replies; 10+ messages in thread
From: Patrice Chotard @ 2025-03-21 9:32 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon
Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
linux-arm-kernel, Patrice Chotard
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 8fdd5f020425d53eefa724de9c23ec0ca211ab7f..cf5be316de2613e7d7050374c9a57fd95020d715 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] 10+ messages in thread
* [PATCH v6 6/7] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
2025-03-21 9:32 [PATCH v6 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
` (4 preceding siblings ...)
2025-03-21 9:32 ` [PATCH v6 5/7] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi Patrice Chotard
@ 2025-03-21 9:32 ` Patrice Chotard
2025-03-21 9:32 ` [PATCH v6 7/7] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver Patrice Chotard
6 siblings, 0 replies; 10+ messages in thread
From: Patrice Chotard @ 2025-03-21 9:32 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon
Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
linux-arm-kernel, Patrice Chotard
Add SPI NOR flash nor support on stm32mp257f-ev1 board.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 32 ++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index 1b88485a62a1f837770654eee6c970208fef6edc..76970c15e04387383097874a814f42e867fc94b6 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -80,6 +80,11 @@ fw@80000000 {
reg = <0x0 0x80000000 0x0 0x4000000>;
no-map;
};
+
+ mm_ospi1: mm-ospi@60000000 {
+ reg = <0x0 0x60000000 0x0 0x10000000>;
+ no-map;
+ };
};
};
@@ -190,6 +195,33 @@ &i2c8 {
status = "disabled";
};
+&ommanager {
+ memory-region = <&mm_ospi1>;
+ pinctrl-0 = <&ospi_port1_clk_pins_a
+ &ospi_port1_io03_pins_a
+ &ospi_port1_cs0_pins_a>;
+ pinctrl-1 = <&ospi_port1_clk_sleep_pins_a
+ &ospi_port1_io03_sleep_pins_a
+ &ospi_port1_cs0_sleep_pins_a>;
+ pinctrl-names = "default", "sleep";
+ status = "okay";
+
+ spi@40430000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ memory-region = <&mm_ospi1>;
+ status = "okay";
+
+ flash0: flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-rx-bus-width = <4>;
+ spi-tx-bus-width = <4>;
+ spi-max-frequency = <50000000>;
+ };
+ };
+};
+
&rtc {
status = "okay";
};
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v6 7/7] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
2025-03-21 9:32 [PATCH v6 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
` (5 preceding siblings ...)
2025-03-21 9:32 ` [PATCH v6 6/7] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board Patrice Chotard
@ 2025-03-21 9:32 ` Patrice Chotard
6 siblings, 0 replies; 10+ messages in thread
From: Patrice Chotard @ 2025-03-21 9:32 UTC (permalink / raw)
To: Krzysztof Kozlowski, Rob Herring, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Philipp Zabel, Krzysztof Kozlowski,
Catalin Marinas, Will Deacon
Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
linux-arm-kernel, Patrice Chotard
Enable STM32 OctoSPI driver.
Enable STM32 Octo Memory Manager (OMM) driver which is needed
for OSPI usage on STM32MP257F-EV1 board.
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
arch/arm64/configs/defconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index bde1287ad9a7a1341162b817873eb651bb310d52..3674d9138bae6deba19c0d13586aa6e1de6750c5 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -580,6 +580,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
@@ -1518,6 +1519,7 @@ CONFIG_EXTCON_USB_GPIO=y
CONFIG_EXTCON_USBC_CROS_EC=y
CONFIG_FSL_IFC=y
CONFIG_RENESAS_RPCIF=m
+CONFIG_STM32_OMM=m
CONFIG_IIO=y
CONFIG_EXYNOS_ADC=y
CONFIG_IMX8QXP_ADC=m
--
2.25.1
^ permalink raw reply related [flat|nested] 10+ messages in thread