linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v8 0/7] Add STM32MP25 SPI NOR support
@ 2025-04-07 13:27 Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver Patrice Chotard
                   ` (7 more replies)
  0 siblings, 8 replies; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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

This series adds SPI NOR support for STM32MP25 SoCs from STMicroelectronics.

On STM32MP25 SoCs family, an Octo Memory Manager block manages the muxing,
the memory area split, the chip select override and the time constraint
between its 2 Octo SPI children.

Due to these depedencies, this series 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 its 2 associated Octo
SPI chidren in stm32mp251.dtsi and adds SPI NOR support in stm32mp257f-ev1
board.
    
Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>

Changes in v8:
  - update OMM's dt-bindings:
    - Remove minItems for clocks and resets properties.
    - Fix st,syscfg-amcr items declaration.
    - move power-domains property before vendor specific properties.
  - Update compatible check wrongly introduced during internal tests in
    stm32_omm.c.
  - Move ommanager's node outside bus@42080000's node in stm32mp251.dtsi.
  - Link to v7: https://lore.kernel.org/r/20250401-upstream_ospi_v6-v7-0-0ef28513ed81@foss.st.com

Changes in v7:
  - update OMM's dt-bindings by updating :
    - clock-names and reset-names properties.
    - spi unit-address node.
    - example.
  - update stm32mp251.dtsi to match with OMM's bindings update.
  - update stm32mp257f-ev1.dts to match with OMM's bindings update.
  - Link to v6: https://lore.kernel.org/r/20250321-upstream_ospi_v6-v6-0-37bbcab43439@foss.st.com

Changes in v6:
  - Update MAINTAINERS file.
  - Remove previous patch 1/8 and 2/8, merged by Mark Brown in spi git tree.
  - Fix Signed-off-by order for patch 3.
  - OMM driver:
    - Add dev_err_probe() in error path.
    - Rename stm32_omm_enable_child_clock() to stm32_omm_toggle_child_clock().
    - Reorder initialised/non-initialized variable in stm32_omm_configure()
          and stm32_omm_probe().
    - Move pm_runtime_disable() calls from stm32_omm_configure() to
      stm32_omm_probe().
    - Update children's clocks and reset management.
    - Use of_platform_populate() to probe children.
    - Add missing pm_runtime_disable().
    - Remove useless stm32_omm_check_access's first parameter.
  - Update OMM's dt-bindings by adding OSPI's clocks and resets.
  - Update stm32mp251.dtsi by adding OSPI's clock and reset in OMM's node.

Changes in v5:
  - Add Reviewed-by Krzysztof Kozlowski for patch 1 and 3.

Changes in v4:
  - Add default value requested by Krzysztof for st,omm-req2ack-ns,
    st,omm-cssel-ovr and st,omm-mux properties in st,stm32mp25-omm.yaml
  - Remove constraint in free form test for st,omm-mux property.
  - Fix drivers/memory/Kconfig by replacing TEST_COMPILE_ by COMPILE_TEST.
  - Fix SPDX-License-Identifier for stm32-omm.c.
  - Fix Kernel test robot by fixing dev_err() format in stm32-omm.c.
  - Add missing pm_runtime_disable() in the error handling path in
    stm32-omm.c.
  - Replace an int by an unsigned int in stm32-omm.c
  - Remove uneeded "," after terminator in stm32-omm.c.
  - Update cover letter description to explain dependecies between
Octo Memory Manager and its 2 Octo SPI children.

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

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

Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
---
Patrice Chotard (7):
      MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
      dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
      memory: Add STM32 Octo Memory Manager driver
      arm64: dts: st: Add OMM node on stm32mp251
      arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
      arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
      arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver

 .../memory-controllers/st,stm32mp25-omm.yaml       | 226 ++++++++++
 MAINTAINERS                                        |   6 +
 arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi      |  51 +++
 arch/arm64/boot/dts/st/stm32mp251.dtsi             |  54 +++
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts         |  32 ++
 arch/arm64/configs/defconfig                       |   2 +
 drivers/memory/Kconfig                             |  17 +
 drivers/memory/Makefile                            |   1 +
 drivers/memory/stm32_omm.c                         | 474 +++++++++++++++++++++
 9 files changed, 863 insertions(+)
---
base-commit: 88424abd55ab36c3565898a656589a0a25ecd92f
change-id: 20250320-upstream_ospi_v6-d432a8172105

Best regards,
-- 
Patrice Chotard <patrice.chotard@foss.st.com>



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

* [PATCH v8 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
@ 2025-04-07 13:27 ` Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller Patrice Chotard
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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] 19+ messages in thread

* [PATCH v8 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver Patrice Chotard
@ 2025-04-07 13:27 ` Patrice Chotard
  2025-04-08  6:45   ` Krzysztof Kozlowski
  2025-04-07 13:27 ` [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver Patrice Chotard
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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       | 226 +++++++++++++++++++++
 1 file changed, 226 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..223b7e4c4b146c116bfa936a04f4f5c4ac4d50af
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/st,stm32mp25-omm.yaml
@@ -0,0 +1,226 @@
+# 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 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:
+      Identify to which OSPI instance the memory region belongs to.
+    items:
+      enum: [ospi1, ospi2]
+    minItems: 1
+    maxItems: 2
+
+  clocks:
+    maxItems: 3
+
+  clock-names:
+    items:
+      - const: omm
+      - const: ospi1
+      - const: ospi2
+
+  resets:
+    maxItems: 3
+
+  reset-names:
+    items:
+      - const: omm
+      - const: ospi1
+      - const: ospi2
+
+  access-controllers:
+    maxItems: 1
+
+  power-domains:
+    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:
+      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
+
+patternProperties:
+  ^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>;
+      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@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@1 {
+        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] 19+ messages in thread

* [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller Patrice Chotard
@ 2025-04-07 13:27 ` Patrice Chotard
  2025-04-08  7:00   ` Krzysztof Kozlowski
  2025-04-08  8:59   ` Philipp Zabel
  2025-04-07 13:27 ` [PATCH v8 4/7] arm64: dts: st: Add OMM node on stm32mp251 Patrice Chotard
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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..db50aeffb0aa32a9d51a205d8ba30ab2299e1c34
--- /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-ospi"))
+			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] 19+ messages in thread

* [PATCH v8 4/7] arm64: dts: st: Add OMM node on stm32mp251
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
                   ` (2 preceding siblings ...)
  2025-04-07 13:27 ` [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver Patrice Chotard
@ 2025-04-07 13:27 ` Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 5/7] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi Patrice Chotard
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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..bb95d61ff7b54bcbb70d981c88dfffcc1951e103 100644
--- a/arch/arm64/boot/dts/st/stm32mp251.dtsi
+++ b/arch/arm64/boot/dts/st/stm32mp251.dtsi
@@ -230,6 +230,60 @@ hpdma3: dma-controller@40420000 {
 			#dma-cells = <3>;
 		};
 
+		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@0 {
+				compatible = "st,stm32mp25-ospi";
+				reg = <0 0 0x400>;
+				interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&hpdma 2 0x62 0x3121>,
+				       <&hpdma 2 0x42 0x3112>;
+				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@1 {
+				compatible = "st,stm32mp25-ospi";
+				reg = <1 0 0x400>;
+				interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+				dmas = <&hpdma 3 0x62 0x3121>,
+				       <&hpdma 3 0x42 0x3112>;
+				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";
+			};
+		};
+
 		rifsc: bus@42080000 {
 			compatible = "st,stm32mp25-rifsc", "simple-bus";
 			reg = <0x42080000 0x1000>;

-- 
2.25.1



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

* [PATCH v8 5/7] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
                   ` (3 preceding siblings ...)
  2025-04-07 13:27 ` [PATCH v8 4/7] arm64: dts: st: Add OMM node on stm32mp251 Patrice Chotard
@ 2025-04-07 13:27 ` Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 6/7] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board Patrice Chotard
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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] 19+ messages in thread

* [PATCH v8 6/7] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
                   ` (4 preceding siblings ...)
  2025-04-07 13:27 ` [PATCH v8 5/7] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi Patrice Chotard
@ 2025-04-07 13:27 ` Patrice Chotard
  2025-04-07 13:27 ` [PATCH v8 7/7] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver Patrice Chotard
  2025-04-08  6:38 ` [PATCH v8 0/7] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
  7 siblings, 0 replies; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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..9d1a1155e36ccc283cb73e51b91f3200ee54a4aa 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@0 {
+		#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] 19+ messages in thread

* [PATCH v8 7/7] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
                   ` (5 preceding siblings ...)
  2025-04-07 13:27 ` [PATCH v8 6/7] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board Patrice Chotard
@ 2025-04-07 13:27 ` Patrice Chotard
  2025-04-08  6:38 ` [PATCH v8 0/7] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
  7 siblings, 0 replies; 19+ messages in thread
From: Patrice Chotard @ 2025-04-07 13:27 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] 19+ messages in thread

* Re: [PATCH v8 0/7] Add STM32MP25 SPI NOR support
  2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
                   ` (6 preceding siblings ...)
  2025-04-07 13:27 ` [PATCH v8 7/7] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver Patrice Chotard
@ 2025-04-08  6:38 ` Krzysztof Kozlowski
  2025-04-08  7:02   ` Krzysztof Kozlowski
  2025-04-09 15:54   ` Patrice CHOTARD
  7 siblings, 2 replies; 19+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-08  6:38 UTC (permalink / raw)
  To: Patrice Chotard
  Cc: Rob Herring, 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 Mon, Apr 07, 2025 at 03:27:31PM GMT, Patrice Chotard wrote:
> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
> ---
> Patrice Chotard (7):
>       MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
>       dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
>       memory: Add STM32 Octo Memory Manager driver
>       arm64: dts: st: Add OMM node on stm32mp251
>       arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
>       arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
>       arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
> 
>  .../memory-controllers/st,stm32mp25-omm.yaml       | 226 ++++++++++
>  MAINTAINERS                                        |   6 +
>  arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi      |  51 +++
>  arch/arm64/boot/dts/st/stm32mp251.dtsi             |  54 +++
>  arch/arm64/boot/dts/st/stm32mp257f-ev1.dts         |  32 ++
>  arch/arm64/configs/defconfig                       |   2 +
>  drivers/memory/Kconfig                             |  17 +
>  drivers/memory/Makefile                            |   1 +
>  drivers/memory/stm32_omm.c                         | 474 +++++++++++++++++++++
>  9 files changed, 863 insertions(+)
> ---
> base-commit: 88424abd55ab36c3565898a656589a0a25ecd92f

That's unknown commit.

b4 diff '20250407-upstream_ospi_v6-v8-0-7b7716c1c1f6@foss.st.com'
Using cached copy of the lookup
---
Analyzing 81 messages in the thread
Preparing fake-am for v7: MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
ERROR: Could not write fake-am tree
---
Could not create fake-am range for lower series v7

I tried on latest next, on some March next, on latest mainline. It seems
you use some weird base here, so anyway I won't be able to apply it.

Please split the patchset per subsystem and send something based on
maintainer tree (so for me my for-next branch), mainline (which is the
same as for-next currently) or linux-next.... which would be the same as
my for-next branch currently.

Best regards,
Krzysztof



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

* Re: [PATCH v8 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
  2025-04-07 13:27 ` [PATCH v8 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller Patrice Chotard
@ 2025-04-08  6:45   ` Krzysztof Kozlowski
  2025-04-08 13:16     ` Patrice CHOTARD
  0 siblings, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-08  6:45 UTC (permalink / raw)
  To: Patrice Chotard
  Cc: Rob Herring, 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 Mon, Apr 07, 2025 at 03:27:33PM GMT, Patrice Chotard wrote:
> +  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:
> +      items:

That's not what Rob asked. Are we goign to repeat the story of Benjamin
and VD55G1? You got the exact code to use, which only need corrections
in indentation probably. Why not using it?

You miss here '-'.

Best regards,
Krzysztof



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

* Re: [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver
  2025-04-07 13:27 ` [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver Patrice Chotard
@ 2025-04-08  7:00   ` Krzysztof Kozlowski
  2025-04-09 15:27     ` Patrice CHOTARD
  2025-04-08  8:59   ` Philipp Zabel
  1 sibling, 1 reply; 19+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-08  7:00 UTC (permalink / raw)
  To: Patrice Chotard
  Cc: Rob Herring, 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 Mon, Apr 07, 2025 at 03:27:34PM GMT, Patrice Chotard wrote:
> +	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");

Where do you drop reference to node?

> +			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;

iterations are always unsigned ints (or ints), not other types.

> +	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");

That's unnecessary complicated. Instead create error handling label,
goto it and unwind iterating from last position of 'i'.

> +				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]);

You should acquire resources in the probe, not on every suspend/resume.
Then you can use `return dev_err_probe`.

> +			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;

That's a confusing label - it jumps to PM put, not clk disable. It
isn't matching the source of error either (get rate, not clock 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-ospi"))
> +			return -EINVAL;

continue;

or better just drop the code - you are not supposed to validate the DTB.
DT schema's job is for that.

> +
> +		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);

That's odd. Why do you depopulate if populate did not happen? Anyway,
don't mix devm with standard error paths, so this all should be handled
by devm.

> +		ret = -EINVAL;
> +		goto error;
> +	}
> +
> +	return ret;
> +
> +error:
> +	pm_runtime_disable(dev);

This as well

> +
> +	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);

This as well, via devm calback.

> +
> +	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);

Best regards,
Krzysztof



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

* Re: [PATCH v8 0/7] Add STM32MP25 SPI NOR support
  2025-04-08  6:38 ` [PATCH v8 0/7] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
@ 2025-04-08  7:02   ` Krzysztof Kozlowski
  2025-04-09 15:54   ` Patrice CHOTARD
  1 sibling, 0 replies; 19+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-08  7:02 UTC (permalink / raw)
  To: Patrice Chotard
  Cc: Rob Herring, 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 Tue, Apr 08, 2025 at 08:38:08AM GMT, Krzysztof Kozlowski wrote:
> On Mon, Apr 07, 2025 at 03:27:31PM GMT, Patrice Chotard wrote:
> > Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
> > ---
> > Patrice Chotard (7):
> >       MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
> >       dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
> >       memory: Add STM32 Octo Memory Manager driver
> >       arm64: dts: st: Add OMM node on stm32mp251
> >       arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
> >       arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
> >       arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
> > 
> >  .../memory-controllers/st,stm32mp25-omm.yaml       | 226 ++++++++++
> >  MAINTAINERS                                        |   6 +
> >  arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi      |  51 +++
> >  arch/arm64/boot/dts/st/stm32mp251.dtsi             |  54 +++
> >  arch/arm64/boot/dts/st/stm32mp257f-ev1.dts         |  32 ++
> >  arch/arm64/configs/defconfig                       |   2 +
> >  drivers/memory/Kconfig                             |  17 +
> >  drivers/memory/Makefile                            |   1 +
> >  drivers/memory/stm32_omm.c                         | 474 +++++++++++++++++++++
> >  9 files changed, 863 insertions(+)
> > ---
> > base-commit: 88424abd55ab36c3565898a656589a0a25ecd92f
> 
> That's unknown commit.
> 
> b4 diff '20250407-upstream_ospi_v6-v8-0-7b7716c1c1f6@foss.st.com'
> Using cached copy of the lookup
> ---
> Analyzing 81 messages in the thread
> Preparing fake-am for v7: MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
> ERROR: Could not write fake-am tree
> ---
> Could not create fake-am range for lower series v7

Hm, both v7 and v8 apply cleanly on next, so not sure why fake-am
failed.

Best regards,
Krzysztof



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

* Re: [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver
  2025-04-07 13:27 ` [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver Patrice Chotard
  2025-04-08  7:00   ` Krzysztof Kozlowski
@ 2025-04-08  8:59   ` Philipp Zabel
  2025-04-08 15:04     ` Patrice CHOTARD
  1 sibling, 1 reply; 19+ messages in thread
From: Philipp Zabel @ 2025-04-08  8:59 UTC (permalink / raw)
  To: Patrice Chotard, Krzysztof Kozlowski, Rob Herring, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Krzysztof Kozlowski,
	Catalin Marinas, Will Deacon
  Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
	linux-arm-kernel

On Mo, 2025-04-07 at 15:27 +0200, Patrice Chotard wrote:
> 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/stm32_omm.c b/drivers/memory/stm32_omm.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..db50aeffb0aa32a9d51a205d8ba30ab2299e1c34
> --- /dev/null
> +++ b/drivers/memory/stm32_omm.c
> @@ -0,0 +1,474 @@
[...]
> +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);

With this reset_control_put(), you are effectively stating that you
don't care about the state of the reset line after this point. To
guarantee the reset line stays deasserted, the driver should keep the
reset control around.

Are you requesting and dropping the reset controls here so the child
drivers can request them at some point? If so, there is an
acquire/relase mechanism for this:

https://docs.kernel.org/driver-api/reset.html#c.reset_control_acquire

Either way, reset_control_get/put() belong in probe/remove.

regards
Philipp


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

* Re: [PATCH v8 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
  2025-04-08  6:45   ` Krzysztof Kozlowski
@ 2025-04-08 13:16     ` Patrice CHOTARD
  0 siblings, 0 replies; 19+ messages in thread
From: Patrice CHOTARD @ 2025-04-08 13:16 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, 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 4/8/25 08:45, Krzysztof Kozlowski wrote:
> On Mon, Apr 07, 2025 at 03:27:33PM GMT, Patrice Chotard wrote:
>> +  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:
>> +      items:
> 
> That's not what Rob asked. Are we goign to repeat the story of Benjamin
> and VD55G1? You got the exact code to use, which only need corrections
> in indentation probably. Why not using it?
> 
> You miss here '-'.

Hi Krzysztof

Sorry but Errare humanum est and dtbs_check didn't detect this.
I will fix it. 

Thanks
Patrice

> 
> Best regards,
> Krzysztof
> 


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

* Re: [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver
  2025-04-08  8:59   ` Philipp Zabel
@ 2025-04-08 15:04     ` Patrice CHOTARD
  0 siblings, 0 replies; 19+ messages in thread
From: Patrice CHOTARD @ 2025-04-08 15:04 UTC (permalink / raw)
  To: Philipp Zabel, Krzysztof Kozlowski, Rob Herring, Conor Dooley,
	Maxime Coquelin, Alexandre Torgue, Krzysztof Kozlowski,
	Catalin Marinas, Will Deacon
  Cc: christophe.kerello, linux-kernel, devicetree, linux-stm32,
	linux-arm-kernel



On 4/8/25 10:59, Philipp Zabel wrote:
> On Mo, 2025-04-07 at 15:27 +0200, Patrice Chotard wrote:
>> 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/stm32_omm.c b/drivers/memory/stm32_omm.c
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..db50aeffb0aa32a9d51a205d8ba30ab2299e1c34
>> --- /dev/null
>> +++ b/drivers/memory/stm32_omm.c
>> @@ -0,0 +1,474 @@
> [...]
>> +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);
> 
> With this reset_control_put(), you are effectively stating that you
> don't care about the state of the reset line after this point. To
> guarantee the reset line stays deasserted, the driver should keep the
> reset control around.
> 
> Are you requesting and dropping the reset controls here so the child
> drivers can request them at some point? If so, there is an
> acquire/relase mechanism for this:
> 
> https://docs.kernel.org/driver-api/reset.html#c.reset_control_acquire

Hi Philipp,

Yes, that's my point, children will request these resets during their
initialization.
I will have a look at reset acquire/release.

Thanks
Patrice

> 
> Either way, reset_control_get/put() belong in probe/remove.
> 
> regards
> Philipp


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

* Re: [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver
  2025-04-08  7:00   ` Krzysztof Kozlowski
@ 2025-04-09 15:27     ` Patrice CHOTARD
  0 siblings, 0 replies; 19+ messages in thread
From: Patrice CHOTARD @ 2025-04-09 15:27 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, 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 4/8/25 09:00, Krzysztof Kozlowski wrote:
> On Mon, Apr 07, 2025 at 03:27:34PM GMT, Patrice Chotard wrote:
>> +	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");
> 
> Where do you drop reference to node?

right, will add of_node_put() here

> 
>> +			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;
> 
> iterations are always unsigned ints (or ints), not other types.

ok

> 
>> +	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");
> 
> That's unnecessary complicated. Instead create error handling label,
> goto it and unwind iterating from last position of 'i'.

ok

> 
>> +				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]);
> 
> You should acquire resources in the probe, not on every suspend/resume.
> Then you can use `return dev_err_probe`.

ok

> 
>> +			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;
> 
> That's a confusing label - it jumps to PM put, not clk disable. It
> isn't matching the source of error either (get rate, not clock disable).

ok

> 
>> +		}
>> +
>> +		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-ospi"))
>> +			return -EINVAL;
> 
> continue;
> 
> or better just drop the code - you are not supposed to validate the DTB.
> DT schema's job is for that.

ok

> 
>> +
>> +		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);
> 
> That's odd. Why do you depopulate if populate did not happen? Anyway,
> don't mix devm with standard error paths, so this all should be handled
> by devm.

ok

> 
>> +		ret = -EINVAL;
>> +		goto error;
>> +	}
>> +
>> +	return ret;
>> +
>> +error:
>> +	pm_runtime_disable(dev);
> 
> This as well


ok
> 
>> +
>> +	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);
> 
> This as well, via devm calback.

ok

> 
>> +
>> +	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);
> 
> Best regards,
> Krzysztof
> 


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

* Re: [PATCH v8 0/7] Add STM32MP25 SPI NOR support
  2025-04-08  6:38 ` [PATCH v8 0/7] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
  2025-04-08  7:02   ` Krzysztof Kozlowski
@ 2025-04-09 15:54   ` Patrice CHOTARD
  2025-04-09 16:13     ` [Linux-stm32] " Patrice CHOTARD
  1 sibling, 1 reply; 19+ messages in thread
From: Patrice CHOTARD @ 2025-04-09 15:54 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, 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 4/8/25 08:38, Krzysztof Kozlowski wrote:
> On Mon, Apr 07, 2025 at 03:27:31PM GMT, Patrice Chotard wrote:
>> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
>> ---
>> Patrice Chotard (7):
>>       MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
>>       dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
>>       memory: Add STM32 Octo Memory Manager driver
>>       arm64: dts: st: Add OMM node on stm32mp251
>>       arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
>>       arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
>>       arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
>>
>>  .../memory-controllers/st,stm32mp25-omm.yaml       | 226 ++++++++++
>>  MAINTAINERS                                        |   6 +
>>  arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi      |  51 +++
>>  arch/arm64/boot/dts/st/stm32mp251.dtsi             |  54 +++
>>  arch/arm64/boot/dts/st/stm32mp257f-ev1.dts         |  32 ++
>>  arch/arm64/configs/defconfig                       |   2 +
>>  drivers/memory/Kconfig                             |  17 +
>>  drivers/memory/Makefile                            |   1 +
>>  drivers/memory/stm32_omm.c                         | 474 +++++++++++++++++++++
>>  9 files changed, 863 insertions(+)
>> ---
>> base-commit: 88424abd55ab36c3565898a656589a0a25ecd92f
> 
> That's unknown commit.
> 
> b4 diff '20250407-upstream_ospi_v6-v8-0-7b7716c1c1f6@foss.st.com'
> Using cached copy of the lookup
> ---
> Analyzing 81 messages in the thread
> Preparing fake-am for v7: MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
> ERROR: Could not write fake-am tree
> ---
> Could not create fake-am range for lower series v7
> 
> I tried on latest next, on some March next, on latest mainline. It seems
> you use some weird base here, so anyway I won't be able to apply it.

It was based on next-20250317 plus the 2 ospi patches already merged 
by Mark Brown, that's why.

> 
> Please split the patchset per subsystem and send something based on
> maintainer tree (so for me my for-next branch), mainline (which is the
> same as for-next currently) or linux-next.... which would be the same as
> my for-next branch currently.

ok

Thanks
Patrice

> 
> Best regards,
> Krzysztof
> 


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

* Re: [Linux-stm32] [PATCH v8 0/7] Add STM32MP25 SPI NOR support
  2025-04-09 15:54   ` Patrice CHOTARD
@ 2025-04-09 16:13     ` Patrice CHOTARD
  2025-04-10  5:33       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 19+ messages in thread
From: Patrice CHOTARD @ 2025-04-09 16:13 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, Conor Dooley, Maxime Coquelin, devicetree,
	Catalin Marinas, linux-kernel, Philipp Zabel, Krzysztof Kozlowski,
	Will Deacon, linux-stm32, linux-arm-kernel



On 4/9/25 17:54, Patrice CHOTARD wrote:
> 
> 
> On 4/8/25 08:38, Krzysztof Kozlowski wrote:
>> On Mon, Apr 07, 2025 at 03:27:31PM GMT, Patrice Chotard wrote:
>>> Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com>
>>> ---
>>> Patrice Chotard (7):
>>>       MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
>>>       dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller
>>>       memory: Add STM32 Octo Memory Manager driver
>>>       arm64: dts: st: Add OMM node on stm32mp251
>>>       arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi
>>>       arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board
>>>       arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver
>>>
>>>  .../memory-controllers/st,stm32mp25-omm.yaml       | 226 ++++++++++
>>>  MAINTAINERS                                        |   6 +
>>>  arch/arm64/boot/dts/st/stm32mp25-pinctrl.dtsi      |  51 +++
>>>  arch/arm64/boot/dts/st/stm32mp251.dtsi             |  54 +++
>>>  arch/arm64/boot/dts/st/stm32mp257f-ev1.dts         |  32 ++
>>>  arch/arm64/configs/defconfig                       |   2 +
>>>  drivers/memory/Kconfig                             |  17 +
>>>  drivers/memory/Makefile                            |   1 +
>>>  drivers/memory/stm32_omm.c                         | 474 +++++++++++++++++++++
>>>  9 files changed, 863 insertions(+)
>>> ---
>>> base-commit: 88424abd55ab36c3565898a656589a0a25ecd92f
>>
>> That's unknown commit.
>>
>> b4 diff '20250407-upstream_ospi_v6-v8-0-7b7716c1c1f6@foss.st.com'
>> Using cached copy of the lookup
>> ---
>> Analyzing 81 messages in the thread
>> Preparing fake-am for v7: MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver
>> ERROR: Could not write fake-am tree
>> ---
>> Could not create fake-am range for lower series v7
>>
>> I tried on latest next, on some March next, on latest mainline. It seems
>> you use some weird base here, so anyway I won't be able to apply it.
> 
> It was based on next-20250317 plus the 2 ospi patches already merged 
> by Mark Brown, that's why.
> 
>>
>> Please split the patchset per subsystem and send something based on
>> maintainer tree (so for me my for-next branch), mainline (which is the
>> same as for-next currently) or linux-next.... which would be the same as
>> my for-next branch currently.
> 
> ok

For memory-controller subsystem i will include:
 _ memory controller dt-bindings
 _ memory controller driver
 _ defconfig update
 _ Maintainers file update

Are you ok with this proposal ?

Patrice

> 
> Thanks
> Patrice
> 
>>
>> Best regards,
>> Krzysztof
>>
> _______________________________________________
> Linux-stm32 mailing list
> Linux-stm32@st-md-mailman.stormreply.com
> https://st-md-mailman.stormreply.com/mailman/listinfo/linux-stm32


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

* Re: [Linux-stm32] [PATCH v8 0/7] Add STM32MP25 SPI NOR support
  2025-04-09 16:13     ` [Linux-stm32] " Patrice CHOTARD
@ 2025-04-10  5:33       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 19+ messages in thread
From: Krzysztof Kozlowski @ 2025-04-10  5:33 UTC (permalink / raw)
  To: Patrice CHOTARD
  Cc: Rob Herring, Conor Dooley, Maxime Coquelin, devicetree,
	Catalin Marinas, linux-kernel, Philipp Zabel, Krzysztof Kozlowski,
	Will Deacon, linux-stm32, linux-arm-kernel

On 09/04/2025 18:13, Patrice CHOTARD wrote:
>>
>>>
>>> Please split the patchset per subsystem and send something based on
>>> maintainer tree (so for me my for-next branch), mainline (which is the
>>> same as for-next currently) or linux-next.... which would be the same as
>>> my for-next branch currently.
>>
>> ok
> 
> For memory-controller subsystem i will include:
>  _ memory controller dt-bindings
>  _ memory controller driver
>  _ defconfig update
>  _ Maintainers file update
defconfig should rather go to arm-soc. Rest is fine.

Best regards,
Krzysztof


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

end of thread, other threads:[~2025-04-10  5:36 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-07 13:27 [PATCH v8 0/7] Add STM32MP25 SPI NOR support Patrice Chotard
2025-04-07 13:27 ` [PATCH v8 1/7] MAINTAINERS: add entry for STM32 OCTO MEMORY MANAGER driver Patrice Chotard
2025-04-07 13:27 ` [PATCH v8 2/7] dt-bindings: memory-controllers: Add STM32 Octo Memory Manager controller Patrice Chotard
2025-04-08  6:45   ` Krzysztof Kozlowski
2025-04-08 13:16     ` Patrice CHOTARD
2025-04-07 13:27 ` [PATCH v8 3/7] memory: Add STM32 Octo Memory Manager driver Patrice Chotard
2025-04-08  7:00   ` Krzysztof Kozlowski
2025-04-09 15:27     ` Patrice CHOTARD
2025-04-08  8:59   ` Philipp Zabel
2025-04-08 15:04     ` Patrice CHOTARD
2025-04-07 13:27 ` [PATCH v8 4/7] arm64: dts: st: Add OMM node on stm32mp251 Patrice Chotard
2025-04-07 13:27 ` [PATCH v8 5/7] arm64: dts: st: Add ospi port1 pinctrl entries in stm32mp25-pinctrl.dtsi Patrice Chotard
2025-04-07 13:27 ` [PATCH v8 6/7] arm64: dts: st: Add SPI NOR flash support on stm32mp257f-ev1 board Patrice Chotard
2025-04-07 13:27 ` [PATCH v8 7/7] arm64: defconfig: Enable STM32 Octo Memory Manager and OcstoSPI driver Patrice Chotard
2025-04-08  6:38 ` [PATCH v8 0/7] Add STM32MP25 SPI NOR support Krzysztof Kozlowski
2025-04-08  7:02   ` Krzysztof Kozlowski
2025-04-09 15:54   ` Patrice CHOTARD
2025-04-09 16:13     ` [Linux-stm32] " Patrice CHOTARD
2025-04-10  5:33       ` Krzysztof Kozlowski

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).