From 5ee353c331b66a777a53595688ca9aa64d0e99f5 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Thu, 20 Feb 2025 12:52:27 +0100 Subject: [PATCH 01/20] drivers: gpio: davinci: fix config layout Zephyr GPIO drivers require the pin mask `struct gpio_driver_data` to be the first element of the driver config. Reordering fixes failures in ASSERT statements of the GPIO driver due to the base address being interpreted as supported pin mask. Signed-off-by: Mika Braunschweig --- drivers/gpio/gpio_davinci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio_davinci.c b/drivers/gpio/gpio_davinci.c index b0f30adf2d9c..a11683110029 100644 --- a/drivers/gpio/gpio_davinci.c +++ b/drivers/gpio/gpio_davinci.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2023 BeagleBoard.org Foundation * Copyright (C) 2023 S Prashanth + * Copyright (C) 2025 Siemens Mobility GmbH * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,8 +54,8 @@ struct gpio_davinci_data { }; struct gpio_davinci_config { - void (*bank_config)(const struct device *dev); struct gpio_driver_config common; + void (*bank_config)(const struct device *dev); DEVICE_MMIO_NAMED_ROM(port_base); From 1abbb72355c868a75be36f932a60e2b1eae7f115 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Fri, 14 Feb 2025 15:58:22 +0100 Subject: [PATCH 02/20] soc: ti: k3: split up soc-specific Kconfig Split up Kconfig settings for the ti Keystone 3 (K3) architecture. The old configuration assumed that every R5F is initialized via a table that's compatible with the linux remote proc framework and OpenAMP library. Additionally the number of interrupts and speed of the system timer was specified only by the cpu type for this series. For better extendability this was split up into different files that reflect the subseries of the soc. Signed-off-by: Mika Braunschweig --- soc/ti/k3/am6x/Kconfig | 11 ++++++++++- soc/ti/k3/am6x/Kconfig.defconfig | 14 ++++---------- soc/ti/k3/am6x/Kconfig.defconfig.am6x | 15 +++++++++++++++ soc/ti/k3/am6x/Kconfig.defconfig.j72x | 13 +++++++++++++ 4 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 soc/ti/k3/am6x/Kconfig.defconfig.am6x create mode 100644 soc/ti/k3/am6x/Kconfig.defconfig.j72x diff --git a/soc/ti/k3/am6x/Kconfig b/soc/ti/k3/am6x/Kconfig index 504e044184a6..434bd1a99281 100644 --- a/soc/ti/k3/am6x/Kconfig +++ b/soc/ti/k3/am6x/Kconfig @@ -1,4 +1,5 @@ # Copyright (c) 2023 Enphase Energy +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 config SOC_SERIES_AM6X_A53 @@ -28,9 +29,17 @@ config SOC_SERIES_AM6X_R5 select ARM_CUSTOM_INTERRUPT_CONTROLLER select VIM select TI_DM_TIMER - select OPENAMP_RSC_TABLE select UART_NS16550_ACCESS_WORD_ONLY if UART_NS16550 +config SOC_J721E_MAIN_R5F0_0 + select OPENAMP_RSC_TABLE + +config SOC_J722S_MAIN_R5F0_0 + select OPENAMP_RSC_TABLE + +config SOC_J722S_MCU_R5F0_0 + select OPENAMP_RSC_TABLE + config SOC_PART_NUMBER default "AM6234" if SOC_AM6234_A53 default "AM6234" if SOC_AM6234_M4 diff --git a/soc/ti/k3/am6x/Kconfig.defconfig b/soc/ti/k3/am6x/Kconfig.defconfig index 445a04cd01a7..ea2ba1671ce0 100644 --- a/soc/ti/k3/am6x/Kconfig.defconfig +++ b/soc/ti/k3/am6x/Kconfig.defconfig @@ -1,8 +1,12 @@ # Copyright (c) 2023 Enphase Energy +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 if SOC_SERIES_AM6X +rsource "Kconfig.defconfig.am*" +rsource "Kconfig.defconfig.j*" + config KERNEL_ENTRY default "_vector_table" @@ -15,16 +19,6 @@ config FLASH_SIZE config FLASH_BASE_ADDRESS default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_FLASH)) -config NUM_IRQS - default 64 if SOC_SERIES_AM6X_M4 - default 280 if SOC_SERIES_AM6X_A53 - default 512 if SOC_SERIES_AM6X_R5 - -config SYS_CLOCK_HW_CYCLES_PER_SEC - default 400000000 if SOC_SERIES_AM6X_M4 - default 200000000 if SOC_SERIES_AM6X_A53 - default 19200000 if SOC_SERIES_AM6X_R5 - if SERIAL config UART_NS16550 diff --git a/soc/ti/k3/am6x/Kconfig.defconfig.am6x b/soc/ti/k3/am6x/Kconfig.defconfig.am6x new file mode 100644 index 000000000000..d15f51db2af6 --- /dev/null +++ b/soc/ti/k3/am6x/Kconfig.defconfig.am6x @@ -0,0 +1,15 @@ +# Copyright (c) 2023 Enphase Energy +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +if SOC_AM6234_A53 || SOC_AM6234_M4 || SOC_AM6442_M4 + +config NUM_IRQS + default 64 if SOC_SERIES_AM6X_M4 + default 280 if SOC_SERIES_AM6X_A53 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 400000000 if SOC_SERIES_AM6X_M4 + default 200000000 if SOC_SERIES_AM6X_A53 + +endif # SOC_AM6234_A53 || SOC_AM6234_M4 || SOC_AM6442_M4 diff --git a/soc/ti/k3/am6x/Kconfig.defconfig.j72x b/soc/ti/k3/am6x/Kconfig.defconfig.j72x new file mode 100644 index 000000000000..391aca44b6be --- /dev/null +++ b/soc/ti/k3/am6x/Kconfig.defconfig.j72x @@ -0,0 +1,13 @@ +# Copyright (c) 2023 Enphase Energy +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +if SOC_J721E_MAIN_R5F0_0 || SOC_J722S_MAIN_R5F0_0 || SOC_J722S_MCU_R5F0_0 + +config NUM_IRQS + default 512 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 19200000 + +endif # SOC_J721E_MAIN_R5F0_0 || SOC_J722S_MAIN_R5F0_0 || SOC_J722S_MCU_R5F0_0 From ba289e863330860fd51899b2b8e6065b1a907754 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 10 Mar 2025 15:20:32 +0100 Subject: [PATCH 03/20] soc: ti: k3: initial am2434 soc support Add initial support for the Texas Instruments AM2434 SoC which allows using it in combination with a board to build applications. Signed-off-by: Mika Braunschweig --- dts/arm/ti/am2434_main_r5.dtsi | 89 +++++++++++++++++++++++++ soc/ti/k3/am6x/Kconfig | 1 + soc/ti/k3/am6x/Kconfig.defconfig.am243x | 20 ++++++ soc/ti/k3/am6x/Kconfig.soc | 6 ++ soc/ti/k3/soc.yml | 6 ++ 5 files changed, 122 insertions(+) create mode 100644 dts/arm/ti/am2434_main_r5.dtsi create mode 100644 soc/ti/k3/am6x/Kconfig.defconfig.am243x diff --git a/dts/arm/ti/am2434_main_r5.dtsi b/dts/arm/ti/am2434_main_r5.dtsi new file mode 100644 index 000000000000..775ba048fb10 --- /dev/null +++ b/dts/arm/ti/am2434_main_r5.dtsi @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/ { + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-r5"; + reg = <0>; + clock-frequency = ; + i-cache-line-size = ; + d-cache-line-size = ; + }; + }; + + // SRAM the core runs exclusively on. No other core should access this + sram_core: memory@70080000 { + reg = <0x70080000 DT_SIZE_K(256)>; + }; + + // SRAM that could be used by all cores. Atomic instructions (e.g. LDREX) + // don't work due to how the SRAM is connected! + sram_shared: memory@70180000 { + reg = <0x70180000 DT_SIZE_K(256)>; + }; + + // SRAM where the bootloader ran. Could be used, if needed + sram_bootloader: memory@70000000 { + reg = <0x70000000 (DT_SIZE_K(256) * 2)>; + }; + + // When not changing the reset vector it's located at 0x0 which is inside the ATCM. To be + // able to use it for the reset vector and code/data it's split up into two chunks + atcm_boot: memory@0 { + device_type = "memory"; + compatible = "mmio-sram"; + reg = <0x0 DT_SIZE_K(1)>; + }; + + atcm: memory@400 { + device_type = "memory"; + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x400 DT_SIZE_K(31)>; + zephyr,memory-region = "ATCM"; + zephyr,memory-region-flags = "rwx"; + }; + + btcm: memory@41010000 { + device_type = "memory"; + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x41010000 DT_SIZE_K(32)>; + zephyr,memory-region = "BTCM"; + zephyr,memory-region-flags = "rwx"; + }; + + vim: interrupt-controller@2fff0000 { + #address-cells = <1>; + compatible = "ti,vim"; + reg = <0x2fff0000 0x2400>; + interrupt-controller; + #interrupt-cells = <4>; + status = "okay"; + }; + + // We use timer 11 as Zephyr time source since there is no dedicated one that fulfills the + // requirements + systick_timer: timer@24b0000 { + compatible = "ti,am654-timer"; + reg = <0x024b0000 0x70>; + interrupts = <0 163 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + status = "okay"; + }; + + chosen { + zephyr,sram = &sram_core; + }; +}; diff --git a/soc/ti/k3/am6x/Kconfig b/soc/ti/k3/am6x/Kconfig index 434bd1a99281..c8fd16264bcc 100644 --- a/soc/ti/k3/am6x/Kconfig +++ b/soc/ti/k3/am6x/Kconfig @@ -44,4 +44,5 @@ config SOC_PART_NUMBER default "AM6234" if SOC_AM6234_A53 default "AM6234" if SOC_AM6234_M4 default "AM6442" if SOC_AM6442_M4 + default "AM2434" if SOC_AM2434_MAIN_R5F0_0 default "J721e" if SOC_J721E_MAIN_R5F0_0 diff --git a/soc/ti/k3/am6x/Kconfig.defconfig.am243x b/soc/ti/k3/am6x/Kconfig.defconfig.am243x new file mode 100644 index 000000000000..99f007b06b8a --- /dev/null +++ b/soc/ti/k3/am6x/Kconfig.defconfig.am243x @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +if SOC_AM2434_MAIN_R5F0_0 + +config NUM_IRQS + default 256 + +config SYS_CLOCK_HW_CYCLES_PER_SEC + default 25000000 + +config ROMSTART_RELOCATION_ROM + default y + +config ROMSTART_REGION_ADDRESS + default $(dt_nodelabel_reg_addr_hex,atcm_boot) +config ROMSTART_REGION_SIZE + default $(dt_nodelabel_reg_size_hex,atcm_boot,0,K) + +endif # SOC_SERIES_AM6X_R5 diff --git a/soc/ti/k3/am6x/Kconfig.soc b/soc/ti/k3/am6x/Kconfig.soc index 82c56f200b87..99935e391897 100644 --- a/soc/ti/k3/am6x/Kconfig.soc +++ b/soc/ti/k3/am6x/Kconfig.soc @@ -1,4 +1,5 @@ # Copyright (c) 2023 Enphase Energy +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 config SOC_SERIES_AM6X @@ -35,6 +36,10 @@ config SOC_AM6442_M4 bool select SOC_SERIES_AM6X_M4 +config SOC_AM2434_MAIN_R5F0_0 + bool + select SOC_SERIES_AM6X_R5 + config SOC_J721E_MAIN_R5F0_0 bool select SOC_SERIES_AM6X_R5 @@ -53,5 +58,6 @@ config SOC_SERIES config SOC default "am6234" if SOC_AM6234_M4 || SOC_AM6234_A53 default "am6442" if SOC_AM6442_M4 + default "am2434" if SOC_AM2434_MAIN_R5F0_0 default "j721e" if SOC_J721E_MAIN_R5F0_0 default "j722s" if SOC_J722S_MAIN_R5F0_0 || SOC_J722S_MCU_R5F0_0 diff --git a/soc/ti/k3/soc.yml b/soc/ti/k3/soc.yml index 44e530703a81..e22649d862ae 100644 --- a/soc/ti/k3/soc.yml +++ b/soc/ti/k3/soc.yml @@ -1,3 +1,6 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + family: - name: ti_k3 series: @@ -10,6 +13,9 @@ family: - name: am6442 cpuclusters: - name: m4 + - name: am2434 + cpuclusters: + - name: main_r5f0_0 - name: j721e cpuclusters: - name: main_r5f0_0 From 2425611a11b7fd084a7af3acda567fa7d3f66d45 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Thu, 6 Mar 2025 14:15:19 +0100 Subject: [PATCH 04/20] soc: ti: k3: add mpu configuration for am2434 Adds a default MPU configuration based on the TI MCU+ SDK. The SRAM region the core runs on needs to be marked as non-shareable since atomic instructions are used on it and for this SoC it's connected in a way that dosen't allow atomic instructions (e.g. ldrex) to have exclusive access. Due to that the Cortex-R causes a data abort in such cases. To allow these instructions anyway the region is marked a non-shared which is fine as long as only one core is accessing the memory area without external synchronization. Signed-off-by: Mika Braunschweig --- soc/ti/k3/am6x/CMakeLists.txt | 2 ++ soc/ti/k3/am6x/Kconfig.defconfig.am243x | 10 +++++++ soc/ti/k3/am6x/r5/mpu_am2434.c | 39 +++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 soc/ti/k3/am6x/r5/mpu_am2434.c diff --git a/soc/ti/k3/am6x/CMakeLists.txt b/soc/ti/k3/am6x/CMakeLists.txt index d5e88b78e25a..cf3caa216008 100644 --- a/soc/ti/k3/am6x/CMakeLists.txt +++ b/soc/ti/k3/am6x/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2023 Enphase Energy +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 zephyr_include_directories(.) @@ -20,6 +21,7 @@ elseif(CONFIG_SOC_SERIES_AM6X_M4) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/m4/linker.ld CACHE INTERNAL "") elseif(CONFIG_SOC_SERIES_AM6X_R5) zephyr_sources(r5/soc.c) + zephyr_sources_ifdef(CONFIG_SOC_AM2434_MAIN_R5F0_0 r5/mpu_am2434.c) zephyr_include_directories(r5) diff --git a/soc/ti/k3/am6x/Kconfig.defconfig.am243x b/soc/ti/k3/am6x/Kconfig.defconfig.am243x index 99f007b06b8a..025496d04de7 100644 --- a/soc/ti/k3/am6x/Kconfig.defconfig.am243x +++ b/soc/ti/k3/am6x/Kconfig.defconfig.am243x @@ -17,4 +17,14 @@ config ROMSTART_REGION_ADDRESS config ROMSTART_REGION_SIZE default $(dt_nodelabel_reg_size_hex,atcm_boot,0,K) +# The MPU needs to be enabled to mark the SRAM as non-shared. Otherwise atomic +# instructions (used for e.g. semaphores and logging) cause data aborts. +# Another option is to locate those in the L1-TCM but there is no easy way to do +# this currently +config MPU + default y + +config ARM_MPU + default y + endif # SOC_SERIES_AM6X_R5 diff --git a/soc/ti/k3/am6x/r5/mpu_am2434.c b/soc/ti/k3/am6x/r5/mpu_am2434.c new file mode 100644 index 000000000000..825c63734ed9 --- /dev/null +++ b/soc/ti/k3/am6x/r5/mpu_am2434.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +/* based off the TI MCU+ SDK default layout */ +static const struct arm_mpu_region mpu_regions[] = { + MPU_REGION_ENTRY("Base permissions", 0x0, ARM_MPU_REGION_SIZE_2GB << MPU_RASR_SIZE_Pos, + {MPU_RASR_S_Msk | MPU_RASR_XN_Msk | P_RW_U_RO_Msk}), + MPU_REGION_ENTRY( + "ATCM", DT_REG_ADDR(DT_NODELABEL(atcm_boot)), + ARM_MPU_REGION_SIZE_32KB << MPU_RASR_SIZE_Pos, + {MPU_RASR_C_Msk | MPU_RASR_B_Msk | (1 << MPU_RASR_TEX_Pos) | P_RW_U_RO_Msk}), + MPU_REGION_ENTRY( + "BTCM", DT_REG_ADDR(DT_NODELABEL(btcm)), + ARM_MPU_REGION_SIZE_32KB << MPU_RASR_SIZE_Pos, + {MPU_RASR_C_Msk | MPU_RASR_B_Msk | (1 << MPU_RASR_TEX_Pos) | P_RW_U_RO_Msk}), + /* protect SRAM generally so the memory of other cores can't be accessed by accident */ + MPU_REGION_ENTRY( + "SRAM other", 0x70000000, ARM_MPU_REGION_SIZE_2MB << MPU_RASR_SIZE_Pos, + {MPU_RASR_C_Msk | MPU_RASR_B_Msk | (1 << MPU_RASR_TEX_Pos) | NO_ACCESS_Msk}), + /* SRAM partition the core exclusively runs on; no other core should access it */ + MPU_REGION_ENTRY( + "SRAM core partition", DT_REG_ADDR(DT_NODELABEL(sram_core)), + ARM_MPU_REGION_SIZE_256KB << MPU_RASR_SIZE_Pos, + {MPU_RASR_C_Msk | MPU_RASR_B_Msk | (1 << MPU_RASR_TEX_Pos) | P_RW_U_RO_Msk}), + /* Shared SRAM. Caching is disabled for now */ + MPU_REGION_ENTRY("SRAM shared", DT_REG_ADDR(DT_NODELABEL(sram_shared)), + ARM_MPU_REGION_SIZE_256KB << MPU_RASR_SIZE_Pos, + {(0b100 << MPU_RASR_TEX_Pos) | MPU_RASR_S_Msk | P_RW_U_RO_Msk}), +}; + +const struct arm_mpu_config mpu_config = {.num_regions = ARRAY_SIZE(mpu_regions), + .mpu_regions = mpu_regions}; From 9a59b44b5bde46ed7bf5edac739945a454403548 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Thu, 6 Mar 2025 14:22:26 +0100 Subject: [PATCH 05/20] dts: arm: ti: k3: add pinctrl to am2434 Add pinctrl node to the am2434 soc Signed-off-by: Mika Braunschweig --- dts/arm/ti/am2434_main_r5.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dts/arm/ti/am2434_main_r5.dtsi b/dts/arm/ti/am2434_main_r5.dtsi index 775ba048fb10..71674cc1c148 100644 --- a/dts/arm/ti/am2434_main_r5.dtsi +++ b/dts/arm/ti/am2434_main_r5.dtsi @@ -24,6 +24,12 @@ }; }; + pinctrl: pinctrl@f4000 { + compatible = "ti,k3-pinctrl"; + reg = <0x000f4000 0x2ac>; + status = "okay"; + }; + // SRAM the core runs exclusively on. No other core should access this sram_core: memory@70080000 { reg = <0x70080000 DT_SIZE_K(256)>; From c816c01c05f4efe92e8305a09aa9c186a2898129 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 17 Feb 2025 11:24:43 +0100 Subject: [PATCH 06/20] dts: arm: ti: k3: add uart nodes to the am2434 soc Add UART devicetree nodes to the am2434 soc Signed-off-by: Mika Braunschweig --- dts/arm/ti/am2434_main_r5.dtsi | 70 ++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/dts/arm/ti/am2434_main_r5.dtsi b/dts/arm/ti/am2434_main_r5.dtsi index 71674cc1c148..8c8a036c5a87 100644 --- a/dts/arm/ti/am2434_main_r5.dtsi +++ b/dts/arm/ti/am2434_main_r5.dtsi @@ -70,6 +70,76 @@ zephyr,memory-region-flags = "rwx"; }; + uart0: uart@2800000 { + compatible = "ns16550"; + reg = <0x02800000 0x200>; + clock-frequency = ; + interrupts = <0 210 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + reg-shift = <2>; + status = "disabled"; + }; + + uart1: uart@2810000 { + compatible = "ns16550"; + reg = <0x02810000 0x200>; + clock-frequency = ; + interrupts = <0 211 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + reg-shift = <2>; + status = "disabled"; + }; + + uart2: uart@2820000 { + compatible = "ns16550"; + reg = <0x02820000 0x200>; + clock-frequency = ; + interrupts = <0 212 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + reg-shift = <2>; + status = "disabled"; + }; + + uart3: uart@2830000 { + compatible = "ns16550"; + reg = <0x02830000 0x200>; + clock-frequency = ; + interrupts = <0 213 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + reg-shift = <2>; + status = "disabled"; + }; + + uart4: uart@2840000 { + compatible = "ns16550"; + reg = <0x02840000 0x200>; + clock-frequency = ; + interrupts = <0 214 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + reg-shift = <2>; + status = "disabled"; + }; + + uart5: uart@2850000 { + compatible = "ns16550"; + reg = <0x02850000 0x200>; + clock-frequency = ; + interrupts = <0 215 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + reg-shift = <2>; + status = "disabled"; + }; + + uart6: uart@2860000 { + compatible = "ns16550"; + reg = <0x02860000 0x200>; + clock-frequency = ; + interrupts = <0 216 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>; + interrupt-parent = <&vim>; + reg-shift = <2>; + status = "disabled"; + }; + vim: interrupt-controller@2fff0000 { #address-cells = <1>; compatible = "ti,vim"; From e502e106693cfb1b2d5620333d68f33b599be082 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 10 Mar 2025 15:21:42 +0100 Subject: [PATCH 07/20] boards: arm: ti: k3: add am243x-launchpad Add initial support for the AM243x Launchpad. It's possible to run a blinky program by manually modifying pinctrl and gpio registers of the board. Signed-off-by: Mika Braunschweig --- .../am243x_launchpad/Kconfig.am243x_launchpad | 8 + .../am243x_launchpad_main_r5f0_0.dts | 14 ++ .../am243x_launchpad_main_r5f0_0_defconfig | 10 + boards/ti/am243x_launchpad/board.yml | 8 + boards/ti/am243x_launchpad/doc/index.rst | 209 ++++++++++++++++++ 5 files changed, 249 insertions(+) create mode 100644 boards/ti/am243x_launchpad/Kconfig.am243x_launchpad create mode 100644 boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts create mode 100644 boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig create mode 100644 boards/ti/am243x_launchpad/board.yml create mode 100644 boards/ti/am243x_launchpad/doc/index.rst diff --git a/boards/ti/am243x_launchpad/Kconfig.am243x_launchpad b/boards/ti/am243x_launchpad/Kconfig.am243x_launchpad new file mode 100644 index 000000000000..764ea69a6a6a --- /dev/null +++ b/boards/ti/am243x_launchpad/Kconfig.am243x_launchpad @@ -0,0 +1,8 @@ +# Texas Instruments AM243x Launchpad +# +# Copyright (c) 2025 Siemens Mobility GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_AM243X_LAUNCHPAD + select SOC_AM2434_MAIN_R5F0_0 diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts new file mode 100644 index 000000000000..6f376210ced9 --- /dev/null +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "AM243x LaunchPad"; + compatible = "ti,am243x_launchpad"; +}; diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig new file mode 100644 index 000000000000..af502467f9e5 --- /dev/null +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig @@ -0,0 +1,10 @@ +# Texas Instruments AM243x Launchpad +# +# Copyright (c) 2025 Siemens Mobility GmbH +# +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 + +# XIP is deactivated for now since we have no flash support yet +CONFIG_XIP=n diff --git a/boards/ti/am243x_launchpad/board.yml b/boards/ti/am243x_launchpad/board.yml new file mode 100644 index 000000000000..1a22bd68e857 --- /dev/null +++ b/boards/ti/am243x_launchpad/board.yml @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 +board: + name: am243x_launchpad + full_name: TI AM243x LaunchPad + vendor: ti + socs: + - name: am2434 diff --git a/boards/ti/am243x_launchpad/doc/index.rst b/boards/ti/am243x_launchpad/doc/index.rst new file mode 100644 index 000000000000..43496a53428c --- /dev/null +++ b/boards/ti/am243x_launchpad/doc/index.rst @@ -0,0 +1,209 @@ +.. zephyr:board:: am243x_launchpad + +Overview +******** + +The AM243x Launchpad is a development board that is based of a AM2434 SoC. The +Cortex R5F cores in the SoC run at 800 MHz. The board also includes a flash +chip, DIP-Switches for the boot mode selection and 2 RJ45 Ethernet ports. + + +Hardware +******** + +The AM2434 SoC has 2 domains. A MAIN domain and a MCU domain. The MAIN domain +consists of 4 R5F cores and the MCU domain of one M4F core. Zephyr can currently +only run alone on the starting R5F core in the MAIN domain and has only very +limited driver support. + +The board physically contains: + +* 512 Mb of Infineon NOR Flash +* DIP switches to change the boot mode +* Buttons to reset parts of the SoC in different ways +* A push button connected to a GPIO pin +* Multiple LEDs (some for power indication and some connected to GPIO pins) +* A XDS110 debug probe (JTAG emulation) + + +Supported Features +================== + +.. zephyr:board-supported-hw:: + + +Connections and IOs +=================== + +For now the Launchpad doesn't support any configuration. + + +Programming and Debugging +************************* + +Flashing +======== +The boot process of the AM2434 SoC requires the booting image to be in a +specific format and to wait for the internal DMSC-L of the AM2434 to start up +and configure memory firewalls. Since there exists no Zephyr support it's +required to use one of the SBL bootloader examples from the TI MCU+ SDK. + + +Prerequisites +------------- + +The following steps are from the time this documentation was written and might +change in the future. They also target Linux with assumption some basic things +(like python3 and openssl) are installed. + +To build these you need to install the TI MCU+ SDK. To do this you need to +follow the steps described in the ``mcupsdk-core`` repository, which includes +cloning the repositories with west. It's recommended to use another Python venv +for this since the MCU+ SDK has own Python dependencies that could conflict with +Zephyr dependencies. You can replace ``all/dev.yml`` in the ``west init`` +command with ``am243x/dev.yml``, if you want to clone a few less repositories. + +You also need to follow the "Downloading And Installing Dependencies" section +but you need to replace all ``am263x`` occurences in commands with ``am243x``. +Please also take note of the ``tools`` and ``mcu_plus_sdk`` install path. The +``tools`` install path will later be referred to as ``$TI_TOOLS`` and the MCU+ +SDK path as ``$MCUPSDK``. You can pass ``--skip_doxygen=true`` and +``--skip_ccs=true`` to the install script since they aren't needed. You might +encounter a error that a script can't be executed. To fix it you need to mark it +as executable with ``chmod +x `` and run the ``download_components.sh`` +again. + +Summarized you will most likely want to run the following commands or similar +versions for setting up the MCU+ SDK: + +.. code-block:: console + + python3 -m venv .venv + source .venv/bin/activate + pip3 install west + west init -m https://github.com/TexasInstruments/mcupsdk-manifests.git --mr mcupsdk_west --mf am243x/dev.yml + west update + ./mcupsdk_setup/am243x/download_components.sh --skip_doxygen=true --skip_ccs=true + # the following two commands are not needed, if the download_components.sh script ran successfully + chmod +x mcupsdk_setup/releases/10_01_00/am243x/download_components.sh + ./mcupsdk_setup/am243x/download_components.sh --skip_doxygen=true --skip_ccs=true + + +After the script finished successfully you want to switch into the +``mcu_plus_sdk`` directory and edit the +``source/drivers/bootloader/bootloader.c`` file to set the ``entryPoint`` to +``0`` inside ``Bootloader_runCpu`` unconditionally. This is needed due to how +Zephyr builds the image currently. + +Now you can build the internal libraries with the following commands: + +.. code-block:: console + + make gen-buildfiles DEVICE=am243x PROFILE=release + make libs DEVICE=am243x PROFILE=release + +If you encounter compile errors you have to fix them. For that you might have to +change parameter types, remove missing source files from makefiles or download +missing headers from the TI online reference. + +Depending on whether you later want to boot from flash or by loading the image +via UART either the ``sbl_ospi`` or the ``sbl_uart`` example is relevant for the +next section. + + +Building the bootloader itself +------------------------------ + +The example is found in the +``examples/drivers/boot//am243x-lp/r5fss0-0_nortos`` directory. You +want to edit the ``main.c`` file to include ``kernel/dpl/HwiP.h`` and run +``HwiP_disableInt(160)`` right before the ``runCpu`` function is called since +Zephyr will otherwise fault due to the bootloader timer still running and +generating an spurious interrupt. + +You can then build the example by invoking ``make -C +examples/drivers/boot//am243x-lp/r5fss0-0_nortos/ti-arm-clang/ +DEVICE=am243x PROFILE=release`` outside the ``mcu_plus_sdk`` root directory. If +you want to boot from flash you should also build the UART uniflash example by +running the same command again but with ``example`` being ``sbl_uart_uniflash``. + + +Converting the Zephyr application +--------------------------------- + +Additionally for booting you need to convert your built Zephyr binary into a +format that the TI example bootloader can boot. You can do this with the +following commands, where ``$TI_TOOLS`` refers to the root of where your +ti-tools (clang, sysconfig etc.) are installed (``$HOME/ti`` by default) and +``$MCUPSDK`` to the root of the MCU+ SDK (directory called ``mcu_plus_sdk``). +You might have to change version numbers in the commands. It's expected that the +``zephyr.elf`` from the build output is in the current directory. + +.. code-block:: bash + + $TI_TOOLS/sysconfig_1.21.2/nodejs/node $MCUPSDK/tools/boot/out2rprc/elf2rprc.js ./zephyr.elf + $MCUPSDK/tools/boot/xipGen/xipGen.out -i ./zephyr.rprc -o ./zephyr.rprc_out -x ./zephyr.rprc_out_xip --flash-start-addr 0x60000000 + $MCUPSDK/tools/boot/xipGen/xipGen.out -i ./zephyr.rprc -o ./zephyr.rprc_out -x ./zephyr.rprc_out_xip --flash-start-addr 0x60000000 + $TI_TOOLS/sysconfig_1.21.2/nodejs/node $MCUPSDK/tools/boot/multicoreImageGen/multicoreImageGen.js --devID 55 --out ./zephyr.appimage ./zephyr.rprc_out@4 + $TI_TOOLS/sysconfig_1.21.2/nodejs/node $MCUPSDK/tools/boot/multicoreImageGen/multicoreImageGen.js --devID 55 --out ./zephyr.appimage_xip ./zephyr.rprc_out_xip@4 + python3 $MCUPSDK/source/security/security_common/tools/boot/signing/appimage_x509_cert_gen.py --bin ./zephyr.appimage --authtype 1 --key $MCUPSDK/source/security/security_common/tools/boot/signing/app_degenerateKey.pem --output ./zephyr.appimage.hs_fs + + +Running the Zephyr image +------------------------ + +After that you want to switch the bootmode to UART by switching the DIP-Switches +into a ``11100000`` position. + +If you want to just run the image via UART you need to run ``python3 +uart_bootloader.py -p /dev/ttyACM0 --bootloader=sbl_uart.release.hs_fs.tiimage +--file=zephyr.appimage.hs_fs``. The ``uart_bootloader.py`` script is found in +``$MCUPSDK/tools/boot`` and the ``sbl_uart.release.hs_fs.tiimage`` in +``$MCUPSDK/tools/boot/sbl_prebuilt/am243x-lp``. After sending the image your +Zephyr application will run after a 2 second long delay. + +If you want to flash the image instead you have to take one example config file +from the ``$MCUPSDK/tools/boot/sbl_prebuilt/am243x-lp`` directory and change the +filepath according to your names. It should look approximately like this: + +.. code-block:: + + --flash-writer=sbl_uart_uniflash.release.hs_fs.tiimage + --file=zephyr.appimage.hs_fs --operation=flash --flash-offset=0x80000 + --file=zephyr.appimage_xip --operation=flash-xip + +You then need to run ``python3 uart_uniflash.py -p /dev/ttyACM0 +--cfg=``. The scripts and images are in the same path +as described in the UART section above. + +After flashing your image you can power off your board, switch the DIP-Switches +into ``01000100`` position and power your board back on. After that your Zephyr +image will boot immeadiatly. + + +Debugging +========= + +For debugging you can use OpenOCD. As of now you need to compile it yourself to +get a version that supports the board. The board config file is called +``ti_am243_launchpad.cfg``. + +Additionally you can use the UART interface that is natively supported. + + +References +********** + +AM2434 documents: + https://www.ti.com/product/de-de/AM2434#tech-docs + +MCU+ SDK Github repository: + https://github.com/TexasInstruments/mcupsdk-core + + +License +******* + +This document Copyright (c) Siemens Mobility GmbH + +SPDX-License-Identifier: Apache-2.0 From 53345cb37e498d7a8d0eb0d264ee8fb037c9b064 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 17 Feb 2025 11:25:32 +0100 Subject: [PATCH 08/20] boards: arm: ti: k3: add uart support for the am243x-launchpad Enable the uart0 instance in the devicetree, configure the pinctrl, add it as uart-shell/console and enable necessary Kconfig options for the board so it can be used for the echo_bot sample. Signed-off-by: Mika Braunschweig --- .../am243x_launchpad_main_r5f0_0-pinctrl.dtsi | 17 +++++++++++++++++ .../am243x_launchpad_main_r5f0_0.dts | 13 +++++++++++++ .../am243x_launchpad_main_r5f0_0_defconfig | 7 +++++++ boards/ti/am243x_launchpad/doc/index.rst | 12 +++++++++++- 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi new file mode 100644 index 000000000000..3d304cd82f33 --- /dev/null +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +&pinctrl { + uart0_rx_default: uart0_rx_default { + pinmux = ; + }; + + uart0_tx_default: uart0_tx_default { + pinmux = ; + }; +}; diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts index 6f376210ced9..fc5abcca2888 100644 --- a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts @@ -7,8 +7,21 @@ /dts-v1/; #include +#include "am243x_launchpad_main_r5f0_0-pinctrl.dtsi" / { model = "AM243x LaunchPad"; compatible = "ti,am243x_launchpad"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; +}; + +&uart0 { + status = "okay"; + pinctrl-0 = <&uart0_tx_default &uart0_rx_default>; + pinctrl-names = "default"; + current-speed = <115200>; }; diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig index af502467f9e5..5e064bcc761d 100644 --- a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0_defconfig @@ -8,3 +8,10 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=25000000 # XIP is deactivated for now since we have no flash support yet CONFIG_XIP=n + +# Serial Driver +CONFIG_SERIAL=y + +# Enable Console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/boards/ti/am243x_launchpad/doc/index.rst b/boards/ti/am243x_launchpad/doc/index.rst index 43496a53428c..7523c3bc12dc 100644 --- a/boards/ti/am243x_launchpad/doc/index.rst +++ b/boards/ti/am243x_launchpad/doc/index.rst @@ -35,7 +35,17 @@ Supported Features Connections and IOs =================== -For now the Launchpad doesn't support any configuration. +This table shows the connected pins. It only includes the ones that are +configured for this board. UART0 is connected to the onboard XDS110 chip and can +be accessed through it without requiring additional hardware. + ++-----------+---------------------+----------+ +| Type | Name | Pin | ++===========+=====================+==========+ +| UART | UART0 TX | GPIO1 30 | ++-----------+---------------------+----------+ +| UART | UART0 RX | GPIO1 29 | ++-----------+---------------------+----------+ Programming and Debugging From 80fe1b7838a87e395d03f9710363a99883bf4808 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 17 Feb 2025 16:16:41 +0100 Subject: [PATCH 09/20] dts: arm: ti: k3: add gpio nodes Add gpio nodes for the ti am2434 soc Signed-off-by: Mika Braunschweig --- dts/arm/ti/am2434_main_r5.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dts/arm/ti/am2434_main_r5.dtsi b/dts/arm/ti/am2434_main_r5.dtsi index 8c8a036c5a87..6ee8ac1ac812 100644 --- a/dts/arm/ti/am2434_main_r5.dtsi +++ b/dts/arm/ti/am2434_main_r5.dtsi @@ -70,6 +70,22 @@ zephyr,memory-region-flags = "rwx"; }; + gpio0: gpio@600010 { + compatible = "ti,davinci-gpio"; + reg = <0x00600010 0x100>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + + gpio1: gpio@601010 { + compatible = "ti,davinci-gpio"; + reg = <0x00601010 0x100>; + gpio-controller; + #gpio-cells = <2>; + status = "disabled"; + }; + uart0: uart@2800000 { compatible = "ns16550"; reg = <0x02800000 0x200>; From ae2f2fd3f22b97775074f740b66588d46f12eaa5 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Thu, 13 Mar 2025 14:27:19 +0100 Subject: [PATCH 10/20] boards: ti: k3: add led to am243x-launchpad Add one of the onboard LEDs to the am243x launchpad board. The blinky example is working but since GPIO drivers only support the first 32 bit the other LEDs weren't added yet. Link: https://github.com/zephyrproject-rtos/zephyr/issues/81100 Signed-off-by: Mika Braunschweig --- .../am243x_launchpad_main_r5f0_0-pinctrl.dtsi | 7 ++++++ .../am243x_launchpad_main_r5f0_0.dts | 23 +++++++++++++++++++ boards/ti/am243x_launchpad/doc/index.rst | 2 ++ 3 files changed, 32 insertions(+) diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi index 3d304cd82f33..35650ceb400c 100644 --- a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi @@ -14,4 +14,11 @@ uart0_tx_default: uart0_tx_default { pinmux = ; }; + + led0_output: led0_output { // GPIO0 22 + pinmux = ; + }; + + // the other leds can't be controlled due to + // https://github.com/zephyrproject-rtos/zephyr/issues/81100 }; diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts index fc5abcca2888..44caea8d5996 100644 --- a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts @@ -8,6 +8,7 @@ #include #include "am243x_launchpad_main_r5f0_0-pinctrl.dtsi" +#include / { model = "AM243x LaunchPad"; @@ -17,6 +18,22 @@ zephyr,console = &uart0; zephyr,shell-uart = &uart0; }; + + leds { + compatible = "gpio-leds"; + led0: led_0 { + gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>; + label = "Test LED 1 Green"; + }; + + // the other leds can't be controlled due to + // https://github.com/zephyrproject-rtos/zephyr/issues/81100 + }; + + aliases { + led0 = &led0; + }; + }; &uart0 { @@ -25,3 +42,9 @@ pinctrl-names = "default"; current-speed = <115200>; }; + +&gpio0 { + status = "okay"; + pinctrl-0 = <&led0_output>; + pinctrl-names = "default"; +}; diff --git a/boards/ti/am243x_launchpad/doc/index.rst b/boards/ti/am243x_launchpad/doc/index.rst index 7523c3bc12dc..9782b775d4e3 100644 --- a/boards/ti/am243x_launchpad/doc/index.rst +++ b/boards/ti/am243x_launchpad/doc/index.rst @@ -42,6 +42,8 @@ be accessed through it without requiring additional hardware. +-----------+---------------------+----------+ | Type | Name | Pin | +===========+=====================+==========+ +| LED | Test LED 1 Green | GPIO0 22 | ++-----------+---------------------+----------+ | UART | UART0 TX | GPIO1 30 | +-----------+---------------------+----------+ | UART | UART0 RX | GPIO1 29 | From 48b12364aa4b3d2107990882c27d65d6965112e6 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Thu, 6 Mar 2025 15:34:11 +0100 Subject: [PATCH 11/20] drivers: mspi: ti: k3: add initial MSPI driver Add a pretty basic MSPI driver. The driver was tested in 1S-1S-1S mode on a am243x-lp board with the onboard Infineon flash. Theoretically the driver also has support for other MSPI modes though they weren't tested. The command and dummy cycles are always taken from the xfer request and never from the devicetree. The driver is pretty basic for now and lacks e.g. callback implementation. This is something that can be added in the future. If a non-supported / invalid request is detected a error code is returned. Signed-off-by: Mika Braunschweig --- drivers/mspi/CMakeLists.txt | 1 + drivers/mspi/Kconfig | 2 + drivers/mspi/Kconfig.ti_k3 | 10 + drivers/mspi/mspi_ti_k3.c | 755 +++++++++++++++++++ drivers/mspi/mspi_ti_k3.h | 565 ++++++++++++++ dts/bindings/mspi/ti,mspi-k3-controller.yaml | 28 + soc/ti/k3/am6x/r5/mpu_am2434.c | 4 + 7 files changed, 1365 insertions(+) create mode 100644 drivers/mspi/Kconfig.ti_k3 create mode 100644 drivers/mspi/mspi_ti_k3.c create mode 100644 drivers/mspi/mspi_ti_k3.h create mode 100644 dts/bindings/mspi/ti,mspi-k3-controller.yaml diff --git a/drivers/mspi/CMakeLists.txt b/drivers/mspi/CMakeLists.txt index 78f704393f42..420586d18e9a 100644 --- a/drivers/mspi/CMakeLists.txt +++ b/drivers/mspi/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ_AP3 mspi_ambiq_ap3.c) zephyr_library_sources_ifdef(CONFIG_MSPI_DW mspi_dw.c) zephyr_library_sources_ifdef(CONFIG_MSPI_EMUL mspi_emul.c) +zephyr_library_sources_ifdef(CONFIG_MSPI_TI_K3 mspi_ti_k3.c) diff --git a/drivers/mspi/Kconfig b/drivers/mspi/Kconfig index 269d8d16f04a..7795613394ba 100644 --- a/drivers/mspi/Kconfig +++ b/drivers/mspi/Kconfig @@ -1,6 +1,7 @@ # MSPI driver configuration options # Copyright (c) 2024 Ambiq Micro Inc. +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 # @@ -62,5 +63,6 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/mspi/Kconfig.ambiq" source "drivers/mspi/Kconfig.dw" source "drivers/mspi/Kconfig.mspi_emul" +source "drivers/mspi/Kconfig.ti_k3" endif # MSPI diff --git a/drivers/mspi/Kconfig.ti_k3 b/drivers/mspi/Kconfig.ti_k3 new file mode 100644 index 000000000000..e0939bc3c7ae --- /dev/null +++ b/drivers/mspi/Kconfig.ti_k3 @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +config MSPI_TI_K3 + bool "TI K3 MSPI driver" + default y + depends on DT_HAS_TI_K3_MSPI_CONTROLLER_ENABLED + select PINCTRL + help + Enable driver for Ti Keystone 3 devices diff --git a/drivers/mspi/mspi_ti_k3.c b/drivers/mspi/mspi_ti_k3.c new file mode 100644 index 000000000000..fa0e611873d7 --- /dev/null +++ b/drivers/mspi/mspi_ti_k3.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_k3_mspi_controller + +#include "mspi_ti_k3.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(flash_ti_k3_mspi, CONFIG_MSPI_LOG_LEVEL); + +struct mspi_ti_k3_config { + DEVICE_MMIO_ROM; + struct mspi_cfg mspi_config; + const struct pinctrl_dev_config *pinctrl; + const uint32_t fifo_addr; + const uint32_t sram_allocated_for_read; +}; + +struct mspi_ti_k3_data { +}; + +/* helper function to easily modify parts of registers */ +static void mspi_ti_k3_set_bits_shifted(const uint32_t value, const uint32_t num_bits, + const uint32_t shift, const mem_addr_t address) +{ + __ASSERT(num_bits <= 32, "Invalid number of bits provided"); + __ASSERT(shift <= 31, "Invalid shift value provided"); + __ASSERT((value & ~BIT_MASK(num_bits)) == 0, + "Tried writing a value that overflows the number of bits that should be changed"); + + uint32_t tmp = sys_read32(address); + + tmp &= ~(BIT_MASK(num_bits) << shift); + tmp |= (value << shift); + + sys_write32(tmp, address); +} + +#define MSPI_TI_K3_REG_WRITE(value, reg, field, base_addr) \ + mspi_ti_k3_set_bits_shifted(value, TI_K3_OSPI_##reg##_##field##_FLD_SIZE, \ + TI_K3_OSPI_##reg##_##field##_FLD_OFFSET, \ + base_addr + TI_K3_OSPI_##reg##_REG) + +#define MSPI_TI_K3_REG_READ(reg, base_addr) sys_read32(base_addr + TI_K3_OSPI_##reg##_REG) + +#define MSPI_TI_K3_REG_READ_MASKED(reg, field, base_addr) \ + ((sys_read32(base_addr + TI_K3_OSPI_##reg##_REG) >> \ + TI_K3_OSPI_##reg##_##field##_FLD_OFFSET) & \ + BIT_MASK(TI_K3_OSPI_##reg##_##field##_FLD_SIZE)) + +/** + * Wait for the OSPI controller to enter idle with the default timeout + */ +int mspi_ti_k3_wait_for_idle(const struct device *controller) +{ + const mem_addr_t base_addr = DEVICE_MMIO_GET(controller); + uint32_t idle = MSPI_TI_K3_REG_READ_MASKED(CONFIG, IDLE, base_addr); + uint32_t retries = TI_K3_OSPI_GET_NUM_RETRIES(TI_K3_OSPI_DEFAULT_TIMEOUT_US); + + while (idle == 0 && retries > 0) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + idle = MSPI_TI_K3_REG_READ_MASKED(CONFIG, IDLE, base_addr); + --retries; + } + if (retries == 0) { + LOG_ERR("Timeout while waiting for MSPI to enter idle"); + return -EIO; + } + return 0; +} + +/** + * Check whether a single request package is requesting something that the driver + * doesn't implement / the hardware doesn't support + */ +static int mspi_ti_k3_check_transfer_package(const struct mspi_xfer *request, uint32_t index) +{ + const struct mspi_xfer_packet *packet = &request->packets[index]; + /* check that we won't truncate the address */ + if (packet->address >> (8 * request->addr_length)) { + LOG_ERR("Address too long for amount of address bytes"); + return -EINVAL; + } + if (packet->cb_mask != MSPI_BUS_NO_CB) { + LOG_ERR("Callbacks aren't implemented"); + return -ENOSYS; + } + if (packet->cmd >> 16) { + LOG_ERR("Commands over 2 byte long aren't supported"); + return -ENOTSUP; + } + if (packet->cmd >> 8) { + LOG_ERR("Support for dual byte opcodes hasn't been implemented"); + return -ENOSYS; + } + if (packet->num_bytes) { + __ASSERT(packet->data_buf != NULL, + "Request gave a NULL buffer when bytes should be transfererd"); + } + return 0; +} + +/** + * Check whether a full request has invalid / not supported parts + */ +static int mspi_ti_k3_check_transfer_request(const struct mspi_xfer *request) +{ + if (request->async) { + LOG_ERR("Asynchronous requests are not implemented"); + return -ENOSYS; + } + + if (request->cmd_length == 2) { + LOG_ERR("Dual byte opcode is not implemented"); + return -ENOSYS; + } else if (request->cmd_length > 2) { + LOG_ERR("Cmds over 2 bytes long aren't supported"); + return -ENOTSUP; + } else if (request->cmd_length != 1) { + LOG_ERR("Can't handle transfer without cmd"); + return -ENOSYS; + } + + if (request->addr_length > 4) { + LOG_ERR("Address too long. Only up to 32 bit are supported"); + return -ENOTSUP; + } + + if (request->priority != 0) { + LOG_WRN("Ignoring request to give transfer higher priority"); + } + + if (request->num_packet == 0) { + LOG_ERR("Got transfer requests without packages"); + return -EINVAL; + } + __ASSERT(request->packets != NULL, "Packets in transfer request are NULL"); + + if (request->xfer_mode != MSPI_PIO) { + LOG_ERR("Other modes than PIO are not supported"); + return -ENOTSUP; + } + + if (request->rx_dummy & + ~BIT_MASK(TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DUMMY_RD_CLK_CYCLES_FLD_SIZE) || + request->tx_dummy & + ~BIT_MASK(TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DUMMY_WR_CLK_CYCLES_FLD_SIZE)) { + LOG_ERR("Request contains too many dummy cycles"); + return -ENOTSUP; + } + + int ret = 0; + + for (uint32_t i = 0; i < request->num_packet; ++i) { + ret = mspi_ti_k3_check_transfer_package(request, i); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static int mspi_ti_k3_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + const struct mspi_ti_k3_config *config = dev->config; + const mem_addr_t base_addr = DEVICE_MMIO_GET(dev); + int ret; + + ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to apply pinctrl"); + return ret; + } + + /* disable OSPI */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_SPI, base_addr); + + ret = mspi_ti_k3_wait_for_idle(dev); + if (ret < 0) { + return ret; + } + + /* disable direct access the driver always uses indirect accesses */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENB_DIR_ACC_CTRL, base_addr); + + /* disable DTR protocol */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_DTR_PROTOCOL, base_addr); + + /* leave XIP mode */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENTER_XIP_MODE, base_addr); + + /* set how many FSS0 SRAM locations are allocated for read; the other ones + * are allocated for writes + */ + MSPI_TI_K3_REG_WRITE(config->sram_allocated_for_read, SRAM_PARTITION_CFG, ADDR, base_addr); + + /* only allow one CS to be active */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, PERIPH_SEL_DEC, base_addr); + + /* CS selection is based on manual pin selection instead of address mapping to flash devices + */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_AHB_DECODER, base_addr); + + /* DQ3 should not be used as reset pin */ + MSPI_TI_K3_REG_WRITE(1, CONFIG, RESET_CFG, base_addr); + + /* Set baud rate division to 32; formula: (n + 1) * 2 */ + MSPI_TI_K3_REG_WRITE(15, CONFIG, MSTR_BAUD_DIV, base_addr); + + /* disable dual byte opcodes */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, DUAL_BYTE_OPCODE_EN, base_addr); + + /* disable PHY pipeline mode */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, PIPELINE_PHY, base_addr); + + /* disable PHY module generally */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, PHY_MODE_ENABLE, base_addr); + + /* disable CRC */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, CRC_ENABLE, base_addr); + + /* disable DMA generally since it's not supported */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENB_DMA_IF, base_addr); + + /* disable write protection of the MSPI peripheral */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, WR_PROT_FLASH, base_addr); + + /* disable possible reset pin */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, RESET_PIN, base_addr); + + /* general clock cycle delays */ + MSPI_TI_K3_REG_WRITE(TI_K3_OSPI_DEFAULT_DELAY, DEV_DELAY, D_NSS, base_addr); + MSPI_TI_K3_REG_WRITE(TI_K3_OSPI_DEFAULT_DELAY, DEV_DELAY, D_BTWN, base_addr); + MSPI_TI_K3_REG_WRITE(TI_K3_OSPI_DEFAULT_DELAY, DEV_DELAY, D_AFTER, base_addr); + MSPI_TI_K3_REG_WRITE(TI_K3_OSPI_DEFAULT_DELAY, DEV_DELAY, D_INIT, base_addr); + + /* set trigger reg address and range to 0 */ + MSPI_TI_K3_REG_WRITE(0, IND_AHB_ADDR_TRIGGER, ADDR, base_addr); + MSPI_TI_K3_REG_WRITE(0, INDIRECT_TRIGGER_ADDR_RANGE, IND_RANGE_WIDTH, base_addr); + + /* disable loop-back via DQS */ + MSPI_TI_K3_REG_WRITE(1, RD_DATA_CAPTURE, BYPASS, base_addr); + + /* disable auto polling for write completion */ + MSPI_TI_K3_REG_WRITE(1, WRITE_COMPLETION_CTRL, DISABLE_POLLING, base_addr); + + /* disable automatic write enable command before indirect write transactions */ + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_WR_CONFIG, WEL_DIS, base_addr); + + /* reset mode bit (hardware CRC checking on read, if supported) */ + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, MODE_BIT_ENABLE, base_addr); + + /* disable DDR mode */ + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, DDR_EN, base_addr); + + uint32_t val; + + /* disable all interrupts via masking */ + val = sys_read32(base_addr + TI_K3_OSPI_IRQ_MASK_REG); + val &= ~TI_K3_OSPI_IRQ_MASK_ALL; + sys_write32(val, base_addr + TI_K3_OSPI_IRQ_MASK_REG); + + /* clear currently pending interrupts */ + val = sys_read32(base_addr + TI_K3_OSPI_IRQ_STATUS_REG); + val |= TI_K3_OSPI_IRQ_STATUS_ALL; + sys_write32(val, base_addr + TI_K3_OSPI_IRQ_STATUS_REG); + + /* re-enable OSPI controller */ + MSPI_TI_K3_REG_WRITE(1, CONFIG, ENABLE_SPI, base_addr); + + return 0; +} + +static int mspi_ti_k3_small_transfer(const struct device *controller, const struct mspi_xfer *req, + uint32_t index, const uint64_t start_cycles) +{ + const mem_addr_t base_address = DEVICE_MMIO_GET(controller); + const struct mspi_xfer_packet *packet = &req->packets[index]; + uint32_t dummy_cycles = 0; + + /* reset previous command configuration completely */ + sys_write32(0, base_address + TI_K3_OSPI_FLASH_CMD_CTRL_REG); + + if (packet->dir == MSPI_RX) { + if (packet->num_bytes != 0) { + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, ENB_READ_DATA, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes - 1, FLASH_CMD_CTRL, + NUM_RD_DATA_BYTES, base_address); + } + dummy_cycles = req->rx_dummy; + } else { + if (packet->num_bytes != 0) { + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, ENB_WRITE_DATA, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes - 1, FLASH_CMD_CTRL, + NUM_WR_DATA_BYTES, base_address); + if (packet->num_bytes > 4) { + uint32_t upper = 0; + + memcpy(&upper, &packet->data_buf[4], packet->num_bytes - 4); + sys_write32(upper, + base_address + TI_K3_OSPI_FLASH_WR_DATA_UPPER_REG); + } + uint32_t lower = 0; + + memcpy(&lower, &packet->data_buf[0], MIN(packet->num_bytes, 4)); + sys_write32(lower, base_address + TI_K3_OSPI_FLASH_WR_DATA_LOWER_REG); + } + dummy_cycles = req->tx_dummy; + } + + MSPI_TI_K3_REG_WRITE(packet->cmd, FLASH_CMD_CTRL, CMD_OPCODE, base_address); + MSPI_TI_K3_REG_WRITE(dummy_cycles, FLASH_CMD_CTRL, NUM_DUMMY_CYCLES, base_address); + + if (req->addr_length) { + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, ENB_COMD_ADDR, base_address); + MSPI_TI_K3_REG_WRITE(req->addr_length - 1, FLASH_CMD_CTRL, NUM_ADDR_BYTES, + base_address); + MSPI_TI_K3_REG_WRITE(packet->address, FLASH_CMD_ADDR, ADDR, base_address); + } + + /* start transaction */ + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, CMD_EXEC, base_address); + + uint32_t exec_status = + MSPI_TI_K3_REG_READ_MASKED(FLASH_CMD_CTRL, CMD_EXEC_STATUS, base_address); + while (exec_status != 0 && + k_cyc_to_us_floor32(k_uptime_get() - start_cycles) < req->timeout) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + exec_status = + MSPI_TI_K3_REG_READ_MASKED(FLASH_CMD_CTRL, CMD_EXEC_STATUS, base_address); + } + if (exec_status != 0) { + LOG_ERR("Timeout while waiting for dedicated flash operation to finish"); + return -EIO; + } + + if (packet->dir == MSPI_RX) { + if (packet->num_bytes > 4) { + uint32_t higher = MSPI_TI_K3_REG_READ(FLASH_RD_DATA_UPPER, base_address); + + memcpy(&packet->data_buf[4], &higher, packet->num_bytes - 4); + } + uint32_t lower = MSPI_TI_K3_REG_READ(FLASH_RD_DATA_LOWER, base_address); + + lower = sys_read32(base_address + TI_K3_OSPI_FLASH_RD_DATA_LOWER_REG); + memcpy(&packet->data_buf[0], &lower, MIN(packet->num_bytes, 4)); + } + + return 0; +} + +static int mspi_ti_k3_indirect_read(const struct device *controller, const struct mspi_xfer *req, + uint32_t index, const uint64_t start_cycles) +{ + const mem_addr_t base_address = DEVICE_MMIO_GET(controller); + const struct mspi_ti_k3_config *config = controller->config; + const struct mspi_xfer_packet *packet = &req->packets[index]; + + MSPI_TI_K3_REG_WRITE(packet->cmd, DEV_INSTR_RD_CONFIG, RD_OPCODE_NON_XIP, base_address); + MSPI_TI_K3_REG_WRITE(packet->address, INDIRECT_READ_XFER_START, ADDR, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes, INDIRECT_READ_XFER_NUM_BYTES, VALUE, base_address); + MSPI_TI_K3_REG_WRITE(req->addr_length - 1, DEV_SIZE_CONFIG, NUM_ADDR_BYTES, base_address); + MSPI_TI_K3_REG_WRITE(req->rx_dummy, DEV_INSTR_RD_CONFIG, DUMMY_RD_CLK_CYCLES, base_address); + + /* Start transfer */ + MSPI_TI_K3_REG_WRITE(1, INDIRECT_READ_XFER_CTRL, START, base_address); + + uint32_t remaining_bytes = packet->num_bytes; + uint8_t *write_ptr = packet->data_buf; + uint32_t num_new_words = 0; + uint32_t current_new_word; + int bytes_to_copy_from_current_word; + + while (remaining_bytes > 0) { + if (k_ticks_to_us_floor32(k_uptime_get() - start_cycles) > req->timeout) { + LOG_ERR("Timeout while receiving data from flash"); + goto timeout; + } + num_new_words = MSPI_TI_K3_REG_READ_MASKED(SRAM_FILL, INDAC_READ, base_address); + while (remaining_bytes > 0 && num_new_words > 0) { + current_new_word = sys_read32(config->fifo_addr); + bytes_to_copy_from_current_word = MIN(remaining_bytes, 4); + memcpy(write_ptr, ¤t_new_word, bytes_to_copy_from_current_word); + write_ptr += bytes_to_copy_from_current_word; + remaining_bytes -= bytes_to_copy_from_current_word; + --num_new_words; + } + } + + /* wait until official indirect read completion */ + uint32_t done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_READ_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + while (done_status == 0 && + k_ticks_to_us_floor32(k_uptime_get() - start_cycles) < req->timeout) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_READ_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + } + if (done_status == 0) { + LOG_ERR("Timeout waiting for official indirect read done confirmation"); + goto timeout; + } + MSPI_TI_K3_REG_WRITE(1, INDIRECT_READ_XFER_CTRL, IND_OPS_DONE_STATUS, base_address); + + return 0; + +timeout: + MSPI_TI_K3_REG_WRITE(1, INDIRECT_READ_XFER_CTRL, CANCEL, base_address); + return -EIO; +} + +static int mspi_ti_k3_indirect_write(const struct device *controller, const struct mspi_xfer *req, + uint32_t index, const uint64_t start_cycles) +{ + const mem_addr_t base_address = DEVICE_MMIO_GET(controller); + const struct mspi_ti_k3_config *config = controller->config; + const struct mspi_xfer_packet *packet = &req->packets[index]; + + MSPI_TI_K3_REG_WRITE(packet->cmd, DEV_INSTR_WR_CONFIG, WR_OPCODE_NON_XIP, base_address); + MSPI_TI_K3_REG_WRITE(req->tx_dummy, DEV_INSTR_WR_CONFIG, DUMMY_WR_CLK_CYCLES, base_address); + MSPI_TI_K3_REG_WRITE(req->addr_length - 1, DEV_SIZE_CONFIG, NUM_ADDR_BYTES, base_address); + MSPI_TI_K3_REG_WRITE(packet->address, INDIRECT_WRITE_XFER_START, ADDR, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes, INDIRECT_WRITE_XFER_NUM_BYTES, VALUE, base_address); + + MSPI_TI_K3_REG_WRITE(1, INDIRECT_WRITE_XFER_CTRL, START, base_address); + + uint32_t read_offset = 0; + uint32_t remaining_bytes = packet->num_bytes; + uint32_t free_words = 0; + uint32_t current_word_to_write; + + while (remaining_bytes > 0) { + if (k_ticks_to_us_floor32(k_uptime_get() - start_cycles) > req->timeout) { + LOG_ERR("Timeout while sending data to flash"); + goto timeout; + } + free_words = config->sram_allocated_for_read - + MSPI_TI_K3_REG_READ_MASKED(SRAM_FILL, INDAC_WRITE, base_address); + while (free_words > 0 && remaining_bytes > 0) { + current_word_to_write = 0; + memcpy(¤t_word_to_write, &packet->data_buf[read_offset], + MIN(remaining_bytes, 4)); + sys_write32(current_word_to_write, config->fifo_addr); + remaining_bytes = (remaining_bytes > 4 ? remaining_bytes - 4 : 0); + read_offset += 4; + --free_words; + } + } + + /* Wait for official finish */ + uint32_t done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_WRITE_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + while (done_status == 0 && + k_ticks_to_us_floor32(k_uptime_get() - start_cycles) < req->timeout) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_WRITE_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + } + if (done_status == 0) { + LOG_ERR("Timeout while waiting for official write done confirmation"); + goto timeout; + } + MSPI_TI_K3_REG_WRITE(1, INDIRECT_WRITE_XFER_CTRL, IND_OPS_DONE_STATUS, base_address); + + return 0; +timeout: + MSPI_TI_K3_REG_WRITE(1, INDIRECT_WRITE_XFER_CTRL, CANCEL, base_address); + return -EIO; +} + +static int mspi_ti_k3_transceive(const struct device *controller, const struct mspi_dev_id *dev_id, + const struct mspi_xfer *req) +{ + /* timeouts are in us and ticks are too inprecise */ + uint64_t start_cycle = k_uptime_get(); + int ret; + + ret = mspi_ti_k3_check_transfer_request(req); + if (ret) { + return ret; + } + for (uint32_t i = 0; i < req->num_packet; ++i) { + const struct mspi_xfer_packet *packet = &req->packets[i]; + /* the FLASH_CMD_REGISTER is good for small transfers with only very little/no data + */ + if (packet->num_bytes <= 8) { + ret = mspi_ti_k3_small_transfer(controller, req, i, start_cycle); + if (ret < 0) { + return ret; + } + } else { + /* big transfer via indirect transfer mode */ + if (packet->dir == MSPI_RX) { + ret = mspi_ti_k3_indirect_read(controller, req, i, start_cycle); + } else { + ret = mspi_ti_k3_indirect_write(controller, req, i, start_cycle); + } + if (ret < 0) { + return ret; + } + } + } + + return 0; +} + +static int mspi_ti_k3_set_opcode_lines(const mem_addr_t base_addr, enum mspi_io_mode io_mode) +{ + switch (io_mode) { + case MSPI_IO_MODE_SINGLE: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_DUAL_1_2_2: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_QUAD_1_4_4: + case MSPI_IO_MODE_OCTAL_1_1_8: + case MSPI_IO_MODE_OCTAL_1_8_8: + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + case MSPI_IO_MODE_DUAL: + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + case MSPI_IO_MODE_QUAD: + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + case MSPI_IO_MODE_OCTAL: + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + default: + return -ENOTSUP; + } +} + +static int mspi_ti_k3_set_addr_lines(const mem_addr_t base_addr, enum mspi_io_mode io_mode) +{ + switch (io_mode) { + case MSPI_IO_MODE_SINGLE: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_OCTAL_1_1_8: + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + case MSPI_IO_MODE_DUAL: + case MSPI_IO_MODE_DUAL_1_2_2: + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + case MSPI_IO_MODE_QUAD: + case MSPI_IO_MODE_QUAD_1_4_4: + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + case MSPI_IO_MODE_OCTAL: + case MSPI_IO_MODE_OCTAL_1_8_8: + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + default: + return -ENOTSUP; + } +} + +static int mspi_ti_k3_set_data_lines(const mem_addr_t base_addr, enum mspi_io_mode io_mode) +{ + switch (io_mode) { + case MSPI_IO_MODE_SINGLE: + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + case MSPI_IO_MODE_DUAL: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_DUAL_1_2_2: + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + case MSPI_IO_MODE_QUAD: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_QUAD_1_4_4: + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + case MSPI_IO_MODE_OCTAL: + case MSPI_IO_MODE_OCTAL_1_1_8: + case MSPI_IO_MODE_OCTAL_1_8_8: + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + default: + return -ENOTSUP; + } +} + +int mspi_ti_k3_dev_config(const struct device *controller, const struct mspi_dev_id *dev_id, + const enum mspi_dev_cfg_mask param_mask, const struct mspi_dev_cfg *cfg) +{ + const mem_addr_t base_addr = DEVICE_MMIO_GET(controller); + int ret = 0; + + if (param_mask & TI_K3_OSPI_NOT_IMPLEMENT_DEV_CONFIG_PARAMS) { + LOG_ERR("Device config includes non implemented features"); + return -ENOSYS; + } + if (param_mask & TI_K3_OSPI_IGNORED_DEV_CONFIG_PARAMS) { + LOG_WRN("Device configuration includes ignored parameters. These are taken from " + "the transceive request instead"); + } + + if (param_mask & MSPI_DEVICE_CONFIG_ENDIAN) { + if (cfg->endian != MSPI_XFER_LITTLE_ENDIAN) { + LOG_ERR("Only little Endian is supported for now"); + /* There is no hardware native support for big endian but it can be + * done in software + */ + return -ENOSYS; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_CE_POL) { + if (cfg->ce_polarity != MSPI_CE_ACTIVE_LOW) { + LOG_ERR("Non active low chip enable polarities haven't been implemented " + "yet"); + return -ENOSYS; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_DQS) { + if (cfg->dqs_enable) { + LOG_ERR("DQS is not implemented yet"); + return -ENOSYS; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_DATA_RATE) { + if (cfg->data_rate != MSPI_DATA_RATE_SINGLE) { + LOG_ERR("Only single data rate is supported for now"); + return -ENOSYS; + } + } + + /* Disable OSPI during configuration */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_SPI, base_addr); + + ret = mspi_ti_k3_wait_for_idle(controller); + if (ret < 0) { + goto exit; + } + + if (param_mask & MSPI_DEVICE_CONFIG_CE_NUM) { + uint32_t num; + + if (cfg->ce_num > 3) { + LOG_ERR("Non implemented chip select. Only hardware CS 0 to 3 are " + "implemented"); + ret = -ENOSYS; + goto exit; + } + num = ~BIT(cfg->ce_num) & BIT_MASK(4); + + MSPI_TI_K3_REG_WRITE(num, CONFIG, PERIPH_CS_LINES, base_addr); + } + if (param_mask & MSPI_DEVICE_CONFIG_IO_MODE) { + ret = mspi_ti_k3_set_opcode_lines(base_addr, cfg->io_mode); + if (ret) { + goto exit; + } + ret = mspi_ti_k3_set_data_lines(base_addr, cfg->io_mode); + if (ret) { + goto exit; + } + ret = mspi_ti_k3_set_addr_lines(base_addr, cfg->io_mode); + if (ret) { + goto exit; + } + } + if (param_mask & MSPI_DEVICE_CONFIG_CPP) { + switch (cfg->cpp) { + case MSPI_CPP_MODE_0: + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_PHASE, base_addr); + break; + case MSPI_CPP_MODE_1: + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_PHASE, base_addr); + break; + case MSPI_CPP_MODE_2: + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_PHASE, base_addr); + break; + case MSPI_CPP_MODE_3: + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_PHASE, base_addr); + break; + default: + LOG_ERR("Invalid clock polarity/phase configuration"); + ret = -ENOTSUP; + goto exit; + } + } +exit: + /* Re-enable OSPI */ + MSPI_TI_K3_REG_WRITE(1, CONFIG, ENABLE_SPI, base_addr); + + return ret; +} + +static DEVICE_API(mspi, mspi_ti_k3_driver_api) = { + .config = NULL, + .dev_config = mspi_ti_k3_dev_config, + .xip_config = NULL, + .scramble_config = NULL, + .timing_config = NULL, + .get_channel_status = NULL, + .register_callback = NULL, + .transceive = mspi_ti_k3_transceive, +}; + +#define MSPI_CONFIG(n) \ + {.op_mode = DT_INST_ENUM_IDX_OR(n, op_mode, MSPI_OP_MODE_CONTROLLER), \ + .sw_multi_periph = DT_INST_PROP(n, software_multiperipheral)} + +#define TI_K3_MSPI_DEFINE(n) \ + PINCTRL_DT_DEFINE(DT_DRV_INST(n)); \ + static const struct mspi_ti_k3_config mspi_ti_k3_config##n = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ + .pinctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .mspi_config = MSPI_CONFIG(n), \ + .fifo_addr = DT_REG_ADDR_BY_IDX(DT_DRV_INST(n), 1), \ + .sram_allocated_for_read = DT_PROP(DT_DRV_INST(n), sram_allocated_for_read), \ + }; \ + static struct mspi_ti_k3_data mspi_ti_k3_data##n = {}; \ + DEVICE_DT_INST_DEFINE(n, mspi_ti_k3_init, NULL, &mspi_ti_k3_data##n, \ + &mspi_ti_k3_config##n, PRE_KERNEL_2, CONFIG_MSPI_INIT_PRIORITY, \ + &mspi_ti_k3_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TI_K3_MSPI_DEFINE) diff --git a/drivers/mspi/mspi_ti_k3.h b/drivers/mspi/mspi_ti_k3.h new file mode 100644 index 000000000000..6337056ce5ef --- /dev/null +++ b/drivers/mspi/mspi_ti_k3.h @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_MSPI_TI_K3_H_ +#define ZEPHYR_DRIVERS_MSPI_TI_K3_H_ + +#include "zephyr/kernel.h" +#include "zephyr/sys/util_macro.h" + +/* Not implemented mspi_dev_cfg bits */ +#define TI_K3_OSPI_NOT_IMPLEMENT_DEV_CONFIG_PARAMS \ + (MSPI_DEVICE_CONFIG_FREQUENCY | MSPI_DEVICE_CONFIG_MEM_BOUND | \ + MSPI_DEVICE_CONFIG_BREAK_TIME) + +/* Ignored dev_cfg_bits */ +#define TI_K3_OSPI_IGNORED_DEV_CONFIG_PARAMS \ + (MSPI_DEVICE_CONFIG_RX_DUMMY | MSPI_DEVICE_CONFIG_TX_DUMMY | MSPI_DEVICE_CONFIG_READ_CMD | \ + MSPI_DEVICE_CONFIG_WRITE_CMD | MSPI_DEVICE_CONFIG_CMD_LEN | MSPI_DEVICE_CONFIG_ADDR_LEN) + +/* Default delay for time between clock enablement and chip select and other */ +#define TI_K3_OSPI_DEFAULT_DELAY 10 + +/* Timeout calculations and default timeout values */ +#define TI_K3_OSPI_TIME_BETWEEN_RETRIES_US 10 +#define TI_K3_OSPI_TIME_BETWEEN_RETRIES K_USEC(TI_K3_OSPI_TIME_BETWEEN_RETRIES_US) +#define TI_K3_OSPI_DEFAULT_TIMEOUT_US 100 +#define TI_K3_OSPI_GET_NUM_RETRIES(timeout_us) (timeout_us / TI_K3_OSPI_TIME_BETWEEN_RETRIES_US) + +/* General register offsets */ +#define TI_K3_OSPI_CONFIG_REG 0x0u +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_REG 0x4u +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_REG 0x8u +#define TI_K3_OSPI_DEV_DELAY_REG 0xcu +#define TI_K3_OSPI_RD_DATA_CAPTURE_REG 0x10u +#define TI_K3_OSPI_DEV_SIZE_CONFIG_REG 0x14u +#define TI_K3_OSPI_SRAM_PARTITION_CFG_REG 0x18u +#define TI_K3_OSPI_IND_AHB_ADDR_TRIGGER_REG 0x1cu +#define TI_K3_OSPI_DMA_PERIPH_CONFIG_REG 0x20u +#define TI_K3_OSPI_REMAP_ADDR_REG 0x24u +#define TI_K3_OSPI_MODE_BIT_CONFIG_REG 0x28u +#define TI_K3_OSPI_SRAM_FILL_REG 0x2cu +#define TI_K3_OSPI_TX_THRESH_REG 0x30u +#define TI_K3_OSPI_RX_THRESH_REG 0x34u +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_REG 0x38u +#define TI_K3_OSPI_NO_OF_POLLS_BEF_EXP_REG 0x3cu +#define TI_K3_OSPI_IRQ_STATUS_REG 0x40u +#define TI_K3_OSPI_IRQ_MASK_REG 0x44u +#define TI_K3_OSPI_LOWER_WR_PROT_REG 0x50u +#define TI_K3_OSPI_UPPER_WR_PROT_REG 0x54u +#define TI_K3_OSPI_WR_PROT_CTRL_REG 0x58u +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_REG 0x60u +#define TI_K3_OSPI_INDIRECT_READ_XFER_WATERMARK_REG 0x64u +#define TI_K3_OSPI_INDIRECT_READ_XFER_START_REG 0x68u +#define TI_K3_OSPI_INDIRECT_READ_XFER_NUM_BYTES_REG 0x6cu +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_REG 0x70u +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_WATERMARK_REG 0x74u +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_START_REG 0x78u +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_NUM_BYTES_REG 0x7cu +#define TI_K3_OSPI_INDIRECT_TRIGGER_ADDR_RANGE_REG 0x80u +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_REG 0x8cu +#define TI_K3_OSPI_FLASH_CMD_CTRL_REG 0x90u +#define TI_K3_OSPI_FLASH_CMD_ADDR_REG 0x94u +#define TI_K3_OSPI_FLASH_RD_DATA_LOWER_REG 0xa0u +#define TI_K3_OSPI_FLASH_RD_DATA_UPPER_REG 0xa4u +#define TI_K3_OSPI_FLASH_WR_DATA_LOWER_REG 0xa8u +#define TI_K3_OSPI_FLASH_WR_DATA_UPPER_REG 0xacu +#define TI_K3_OSPI_POLLING_FLASH_STATUS_REG 0xb0u +#define TI_K3_OSPI_PHY_CONFIGURATION_REG 0xb4u +#define TI_K3_OSPI_PHY_MASTER_CONTROL_REG 0xb8u +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_REG 0xbcu +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_REG 0xc0u +#define TI_K3_OSPI_OPCODE_EXT_LOWER_REG 0xe0u +#define TI_K3_OSPI_OPCODE_EXT_UPPER_REG 0xe4u +#define TI_K3_OSPI_MODULE_ID_REG 0xfcu + +/* CONFIG */ +#define TI_K3_OSPI_CONFIG_IDLE_FLD_OFFSET 31 +#define TI_K3_OSPI_CONFIG_DUAL_BYTE_OPCODE_EN_FLD_OFFSET 30 +#define TI_K3_OSPI_CONFIG_CRC_ENABLE_FLD_OFFSET 29 +#define TI_K3_OSPI_CONFIG_PIPELINE_PHY_FLD_OFFSET 25 +#define TI_K3_OSPI_CONFIG_ENABLE_DTR_PROTOCOL_FLD_OFFSET 24 +#define TI_K3_OSPI_CONFIG_ENABLE_AHB_DECODER_FLD_OFFSET 23 +#define TI_K3_OSPI_CONFIG_MSTR_BAUD_DIV_FLD_OFFSET 19 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_IMM_FLD_OFFSET 18 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_FLD_OFFSET 17 +#define TI_K3_OSPI_CONFIG_ENB_AHB_ADDR_REMAP_FLD_OFFSET 16 +#define TI_K3_OSPI_CONFIG_ENB_DMA_IF_FLD_OFFSET 15 +#define TI_K3_OSPI_CONFIG_WR_PROT_FLASH_FLD_OFFSET 14 +#define TI_K3_OSPI_CONFIG_PERIPH_CS_LINES_FLD_OFFSET 10 +#define TI_K3_OSPI_CONFIG_PERIPH_SEL_DEC_FLD_OFFSET 9 +#define TI_K3_OSPI_CONFIG_ENB_LEGACY_IP_MODE_FLD_OFFSET 8 +#define TI_K3_OSPI_CONFIG_ENB_DIR_ACC_CTRL_FLD_OFFSET 7 +#define TI_K3_OSPI_CONFIG_RESET_CFG_FLD_OFFSET 6 +#define TI_K3_OSPI_CONFIG_RESET_PIN_FLD_OFFSET 5 +#define TI_K3_OSPI_CONFIG_HOLD_PIN_FLD_OFFSET 4 +#define TI_K3_OSPI_CONFIG_PHY_MODE_ENABLE_FLD_OFFSET 3 +#define TI_K3_OSPI_CONFIG_SEL_CLK_PHASE_FLD_OFFSET 2 +#define TI_K3_OSPI_CONFIG_SEL_CLK_POL_FLD_OFFSET 1 +#define TI_K3_OSPI_CONFIG_ENABLE_SPI_FLD_OFFSET 0 + +#define TI_K3_OSPI_CONFIG_IDLE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_DUAL_BYTE_OPCODE_EN_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_CRC_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_PIPELINE_PHY_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENABLE_DTR_PROTOCOL_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENABLE_AHB_DECODER_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_MSTR_BAUD_DIV_FLD_SIZE 4 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_IMM_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_AHB_ADDR_REMAP_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_DMA_IF_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_WR_PROT_FLASH_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_PERIPH_CS_LINES_FLD_SIZE 4 +#define TI_K3_OSPI_CONFIG_PERIPH_SEL_DEC_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_LEGACY_IP_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_DIR_ACC_CTRL_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_RESET_CFG_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_RESET_PIN_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_HOLD_PIN_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_PHY_MODE_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_SEL_CLK_PHASE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_SEL_CLK_POL_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENABLE_SPI_FLD_SIZE 1 + +/* DEV_INSTR_RD_CONFIG */ +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DUMMY_RD_CLK_CYCLES_FLD_OFFSET 24 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_MODE_BIT_ENABLE_FLD_OFFSET 20 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_OFFSET 12 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DDR_EN_FLD_OFFSET 10 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_INSTR_TYPE_FLD_OFFSET 8 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_RD_OPCODE_NON_XIP_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DUMMY_RD_CLK_CYCLES_FLD_SIZE 5 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_MODE_BIT_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DDR_EN_FLD_SIZE 1 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_INSTR_TYPE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_RD_OPCODE_NON_XIP_FLD_SIZE 8 + +/* DEV_INSTR_WR_CONFIG */ +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DUMMY_WR_CLK_CYCLES_FLD_OFFSET 24 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_OFFSET 12 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WEL_DIS_FLD_OFFSET 8 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WR_OPCODE_NON_XIP_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DUMMY_WR_CLK_CYCLES_FLD_SIZE 5 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WEL_DIS_FLD_SIZE 1 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WR_OPCODE_NON_XIP_FLD_SIZE 8 + +/* DEV_DELAY */ +#define TI_K3_OSPI_DEV_DELAY_D_NSS_FLD_OFFSET 24 +#define TI_K3_OSPI_DEV_DELAY_D_BTWN_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_DELAY_D_AFTER_FLD_OFFSET 8 +#define TI_K3_OSPI_DEV_DELAY_D_INIT_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_DELAY_D_NSS_FLD_SIZE 8 +#define TI_K3_OSPI_DEV_DELAY_D_BTWN_FLD_SIZE 8 +#define TI_K3_OSPI_DEV_DELAY_D_AFTER_FLD_SIZE 8 +#define TI_K3_OSPI_DEV_DELAY_D_INIT_FLD_SIZE 8 + +/* RD_DATA_CAPTURE */ +#define TI_K3_OSPI_RD_DATA_CAPTURE_DDR_READ_DELAY_FLD_OFFSET 16 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DQS_ENABLE_FLD_OFFSET 8 +#define TI_K3_OSPI_RD_DATA_CAPTURE_SAMPLE_EDGE_SEL_FLD_OFFSET 5 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DELAY_FLD_OFFSET 1 +#define TI_K3_OSPI_RD_DATA_CAPTURE_BYPASS_FLD_OFFSET 0 + +#define TI_K3_OSPI_RD_DATA_CAPTURE_DDR_READ_DELAY_FLD_SIZE 4 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DQS_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_RD_DATA_CAPTURE_SAMPLE_EDGE_SEL_FLD_SIZE 1 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DELAY_FLD_SIZE 4 +#define TI_K3_OSPI_RD_DATA_CAPTURE_BYPASS_FLD_SIZE 1 + +/* DEV_SIZE_CONFIG */ +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS3_FLD_OFFSET 27 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS2_FLD_OFFSET 25 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS1_FLD_OFFSET 23 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS0_FLD_OFFSET 21 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_SUBSECTOR_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_DEVICE_PAGE_FLD_OFFSET 4 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_NUM_ADDR_BYTES_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS3_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS2_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS1_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS0_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_SUBSECTOR_FLD_SIZE 5 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_DEVICE_PAGE_FLD_SIZE 12 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_NUM_ADDR_BYTES_FLD_SIZE 4 + +/* SRAM_PARTITION_CFG */ +#define TI_K3_OSPI_SRAM_PARTITION_CFG_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_SRAM_PARTITION_CFG_ADDR_FLD_SIZE 8 + +/* INDIRECT_TRIGGER_ADDR_RANGE */ +#define TI_K3_OSPI_INDIRECT_TRIGGER_ADDR_RANGE_IND_RANGE_WIDTH_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_TRIGGER_ADDR_RANGE_IND_RANGE_WIDTH_FLD_SIZE 4 + +/* REMAP_ADDR */ +#define TI_K3_OSPI_REMAP_ADDR_VALUE_FLD_OFFSET 0 + +#define TI_K3_OSPI_REMAP_ADDR_VALUE_FLD_SIZE 32 + +/* SRAM_FILL */ +#define TI_K3_OSPI_SRAM_FILL_INDAC_WRITE_FLD_OFFSET 16 +#define TI_K3_OSPI_SRAM_FILL_INDAC_READ_FLD_OFFSET 0 + +#define TI_K3_OSPI_SRAM_FILL_INDAC_WRITE_FLD_SIZE 16 +#define TI_K3_OSPI_SRAM_FILL_INDAC_READ_FLD_SIZE 16 + +/* TX_THRESH */ +#define TI_K3_OSPI_TX_THRESH_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_TX_THRESH_LEVEL_FLD_SIZE 5 + +/* RX_THRESH */ +#define TI_K3_OSPI_RX_THRESH_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_RX_THRESH_LEVEL_FLD_SIZE 5 + +/* WRITE_COMPLETION_CTRL */ +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_REP_DELAY_FLD_OFFSET 24 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_COUNT_FLD_OFFSET 16 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_ENABLE_POLLING_EXP_FLD_OFFSET 15 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_DISABLE_POLLING_FLD_OFFSET 14 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_POLARITY_FLD_OFFSET 13 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_BIT_INDEX_FLD_OFFSET 8 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_OPCODE_FLD_OFFSET 0 + +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_REP_DELAY_FLD_SIZE 8 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_COUNT_FLD_SIZE 8 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_ENABLE_POLLING_EXP_FLD_SIZE 1 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_DISABLE_POLLING_FLD_SIZE 1 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_POLARITY_FLD_SIZE 1 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_BIT_INDEX_FLD_SIZE 3 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_OPCODE_FLD_SIZE 8 + +/* NO_OF_POLLS_BEF_EXP */ +#define TI_K3_OSPI_NO_OF_POLLS_BEF_EXP_NO_OF_POLLS_BEF_EXP_FLD_OFFSET 0 + +#define TI_K3_OSPI_NO_OF_POLLS_BEF_EXP_NO_OF_POLLS_BEF_EXP_FLD_SIZE 32 + +/* IRQ_STATUS */ +#define TI_K3_OSPI_IRQ_STATUS_ECC_FAIL_FLD_OFFSET 19 +#define TI_K3_OSPI_IRQ_STATUS_TX_CRC_CHUNK_BRK_FLD_OFFSET 18 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_VAL_FLD_OFFSET 17 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_ERR_FLD_OFFSET 16 +#define TI_K3_OSPI_IRQ_STATUS_STIG_REQ_INT_FLD_OFFSET 14 +#define TI_K3_OSPI_IRQ_STATUS_POLL_EXP_INT_FLD_OFFSET 13 +#define TI_K3_OSPI_IRQ_STATUS_INDRD_SRAM_FULL_FLD_OFFSET 12 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_FULL_FLD_OFFSET 11 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_NOT_EMPTY_FLD_OFFSET 10 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_FULL_FLD_OFFSET 9 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_NOT_FULL_FLD_OFFSET 8 +#define TI_K3_OSPI_IRQ_STATUS_RECV_OVERFLOW_FLD_OFFSET 7 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_XFER_LEVEL_BREACH_FLD_OFFSET 6 +#define TI_K3_OSPI_IRQ_STATUS_ILLEGAL_ACCESS_DET_FLD_OFFSET 5 +#define TI_K3_OSPI_IRQ_STATUS_PROT_WR_ATTEMPT_FLD_OFFSET 4 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_READ_REJECT_FLD_OFFSET 3 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_OP_DONE_FLD_OFFSET 2 +#define TI_K3_OSPI_IRQ_STATUS_UNDERFLOW_DET_FLD_OFFSET 1 +#define TI_K3_OSPI_IRQ_STATUS_MODE_M_FAIL_FLD_OFFSET 0 + +#define TI_K3_OSPI_IRQ_STATUS_ECC_FAIL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_TX_CRC_CHUNK_BRK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_VAL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_ERR_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_STIG_REQ_INT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_POLL_EXP_INT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDRD_SRAM_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_NOT_EMPTY_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_NOT_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RECV_OVERFLOW_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_XFER_LEVEL_BREACH_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_ILLEGAL_ACCESS_DET_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_PROT_WR_ATTEMPT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_READ_REJECT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_OP_DONE_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_UNDERFLOW_DET_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_MODE_M_FAIL_FLD_SIZE 1 + +#define TI_K3_OSPI_IRQ_STATUS_ALL (BIT_MASK(19) & ~BIT(15)) + +/* IRQ_MASK */ +#define TI_K3_OSPI_IRQ_MASK_ECC_FAIL_MASK_FLD_OFFSET 19 +#define TI_K3_OSPI_IRQ_MASK_TX_CRC_CHUNK_BRK_MASK_FLD_OFFSET 18 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_VAL_MASK_FLD_OFFSET 17 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_ERR_MASK_FLD_OFFSET 16 +#define TI_K3_OSPI_IRQ_MASK_STIG_REQ_INT_MASK_FLD_OFFSET 14 +#define TI_K3_OSPI_IRQ_MASK_POLL_EXP_INT_MASK_FLD_OFFSET 13 +#define TI_K3_OSPI_IRQ_MASK_INDRD_SRAM_FULL_MASK_FLD_OFFSET 12 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_FULL_MASK_FLD_OFFSET 11 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_NOT_EMPTY_MASK_FLD_OFFSET 10 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_FULL_MASK_FLD_OFFSET 9 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_NOT_FULL_MASK_FLD_OFFSET 8 +#define TI_K3_OSPI_IRQ_MASK_RECV_OVERFLOW_MASK_FLD_OFFSET 7 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_XFER_LEVEL_BREACH_MASK_FLD_OFFSET 6 +#define TI_K3_OSPI_IRQ_MASK_ILLEGAL_ACCESS_DET_MASK_FLD_OFFSET 5 +#define TI_K3_OSPI_IRQ_MASK_PROT_WR_ATTEMPT_MASK_FLD_OFFSET 4 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_READ_REJECT_MASK_FLD_OFFSET 3 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_OP_DONE_MASK_FLD_OFFSET 2 +#define TI_K3_OSPI_IRQ_MASK_UNDERFLOW_DET_MASK_FLD_OFFSET 1 +#define TI_K3_OSPI_IRQ_MASK_MODE_M_FAIL_MASK_FLD_OFFSET 0 + +#define TI_K3_OSPI_IRQ_MASK_ECC_FAIL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_TX_CRC_CHUNK_BRK_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_VAL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_ERR_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_STIG_REQ_INT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_POLL_EXP_INT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDRD_SRAM_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_NOT_EMPTY_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_NOT_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RECV_OVERFLOW_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_XFER_LEVEL_BREACH_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_ILLEGAL_ACCESS_DET_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_PROT_WR_ATTEMPT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_READ_REJECT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_OP_DONE_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_UNDERFLOW_DET_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_MODE_M_FAIL_MASK_FLD_SIZE 1 + +#define TI_K3_OSPI_IRQ_MASK_ALL (BIT_MASK(19) & ~BIT(15)) + +/* LOWER_WR_PROT */ +#define TI_K3_OSPI_LOWER_WR_PROT_SUBSECTOR_FLD_OFFSET 0 + +#define TI_K3_OSPI_LOWER_WR_PROT_SUBSECTOR_FLD_SIZE 32 + +/* UPPER_WR_PROT */ +#define TI_K3_OSPI_UPPER_WR_PROT_SUBSECTOR_FLD_OFFSET 0 + +#define TI_K3_OSPI_UPPER_WR_PROT_SUBSECTOR_FLD_SIZE 32 + +/* WR_PROT_CTRL */ +#define TI_K3_OSPI_WR_PROT_CTRL_ENB_FLD_OFFSET 1 +#define TI_K3_OSPI_WR_PROT_CTRL_INV_FLD_OFFSET 0 + +#define TI_K3_OSPI_WR_PROT_CTRL_ENB_FLD_SIZE 1 +#define TI_K3_OSPI_WR_PROT_CTRL_INV_FLD_SIZE 1 + +/* INDIRECT_READ_XFER_CTRL */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_NUM_IND_OPS_DONE_FLD_OFFSET 6 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_OFFSET 5 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_QUEUED_FLD_OFFSET 4 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_SRAM_FULL_FLD_OFFSET 3 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_STATUS_FLD_OFFSET 2 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_CANCEL_FLD_OFFSET 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_START_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_NUM_IND_OPS_DONE_FLD_SIZE 2 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_QUEUED_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_SRAM_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_CANCEL_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_START_FLD_SIZE 1 + +/* INDIRECT_READ_XFER_WATERMARK */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_WATERMARK_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_WATERMARK_LEVEL_FLD_SIZE 32 + +/* INDIRECT_READ_XFER_START */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_START_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_START_ADDR_FLD_SIZE 32 + +/* INDIRECT_READ_XFER_NUM_BYTES */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_NUM_BYTES_VALUE_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_NUM_BYTES_VALUE_FLD_SIZE 32 + +/* INDIRECT_WRITE_XFER_CTRL_REG */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_NUM_IND_OPS_DONE_FLD_OFFSET 6 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_OFFSET 5 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_QUEUED_FLD_OFFSET 4 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_STATUS_FLD_OFFSET 2 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_CANCEL_FLD_OFFSET 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_START_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_NUM_IND_OPS_DONE_FLD_SIZE 2 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_QUEUED_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_CANCEL_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_START_FLD_SIZE 1 + +/* INDIRECT_WRITE_XFER_WATERMARK */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_WATERMARK_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_WATERMARK_LEVEL_FLD_SIZE 32 + +/* INDIRECT_WRITE_XFER_START */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_START_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_START_ADDR_FLD_SIZE 32 + +/* INDIRECT_WRITE_XFER_NUM_BYTES */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_NUM_BYTES_VALUE_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_NUM_BYTES_VALUE_FLD_SIZE 32 + +/* IND_AHB_ADDR_TRIGGER */ +#define TI_K3_OSPI_IND_AHB_ADDR_TRIGGER_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_IND_AHB_ADDR_TRIGGER_ADDR_FLD_SIZE 32 + +/* FLASH_COMMAND_CTRL_MEM */ +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_ADDR_FLD_OFFSET 20 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_NB_OF_STIG_READ_BYTES_FLD_OFFSET 16 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_READ_DATA_FLD_OFFSET 8 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_REQ_IN_PROGRESS_FLD_OFFSET 1 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_TRIGGER_MEM_BANK_REQ_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_ADDR_FLD_SIZE 9 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_NB_OF_STIG_READ_BYTES_FLD_SIZE 3 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_READ_DATA_FLD_SIZE 8 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_REQ_IN_PROGRESS_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_TRIGGER_MEM_BANK_REQ_FLD_SIZE 1 + +/* FLASH_CMD_CTRL */ +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_OPCODE_FLD_OFFSET 24 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_READ_DATA_FLD_OFFSET 23 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_RD_DATA_BYTES_FLD_OFFSET 20 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_COMD_ADDR_FLD_OFFSET 19 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_MODE_BIT_FLD_OFFSET 18 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_ADDR_BYTES_FLD_OFFSET 16 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_WRITE_DATA_FLD_OFFSET 15 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_WR_DATA_BYTES_FLD_OFFSET 12 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_DUMMY_CYCLES_FLD_OFFSET 7 +#define TI_K3_OSPI_FLASH_CMD_CTRL_STIG_MEM_BANK_EN_FLD_OFFSET 2 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_STATUS_FLD_OFFSET 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_READ_DATA_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_RD_DATA_BYTES_FLD_SIZE 3 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_COMD_ADDR_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_MODE_BIT_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_ADDR_BYTES_FLD_SIZE 2 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_WRITE_DATA_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_WR_DATA_BYTES_FLD_SIZE 3 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_DUMMY_CYCLES_FLD_SIZE 5 +#define TI_K3_OSPI_FLASH_CMD_CTRL_STIG_MEM_BANK_EN_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_FLD_SIZE 1 + +/* FLASH_CMD_ADDR */ +#define TI_K3_OSPI_FLASH_CMD_ADDR_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_CMD_ADDR_ADDR_FLD_SIZE 32 + +/* FLASH_RD_DATA_LOWER */ +#define TI_K3_OSPI_FLASH_RD_DATA_LOWER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_RD_DATA_LOWER_DATA_FLD_SIZE 32 + +/* FLASH_RD_DATA_UPPER */ +#define TI_K3_OSPI_FLASH_RD_DATA_UPPER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_RD_DATA_UPPER_DATA_FLD_SIZE 32 + +/* FLASH_WR_DATA_LOWER */ +#define TI_K3_OSPI_FLASH_WR_DATA_LOWER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_WR_DATA_LOWER_DATA_FLD_SIZE 32 + +/* FLASH_WR_DATA_UPPER */ +#define TI_K3_OSPI_FLASH_WR_DATA_UPPER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_WR_DATA_UPPER_DATA_FLD_SIZE 32 + +/* POLLING_FLASH_STATUS */ +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_NB_DUMMY_FLD_OFFSET 16 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_VALID_FLD_OFFSET 8 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_FLD_OFFSET 0 + +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_NB_DUMMY_FLD_SIZE 4 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_VALID_FLD_SIZE 1 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_FLD_SIZE 8 + +/* PHY_CONFIGURATION */ +#define TI_K3_OSPI_PHY_CONFIGURATION_RESYNC_FLD_OFFSET 31 +#define TI_K3_OSPI_PHY_CONFIGURATION_RESET_FLD_OFFSET 30 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_BYPASS_FLD_OFFSET 29 +#define TI_K3_OSPI_PHY_CONFIGURATION_TX_DLL_DELAY_FLD_OFFSET 16 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_DELAY_FLD_OFFSET 0 + +#define TI_K3_OSPI_PHY_CONFIGURATION_RESYNC_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_CONFIGURATION_RESET_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_BYPASS_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_CONFIGURATION_TX_DLL_DELAY_FLD_SIZE 7 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_DELAY_FLD_SIZE 7 + +/* PHY_MASTER_CONTROL */ +#define TI_K3_OSPI_PHY_MASTER_CONTROL_LOCK_MODE_FLD_OFFSET 24 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_BYPASS_MODE_FLD_OFFSET 23 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_PHASE_DETECT_SELECTOR_FLD_OFFSET 20 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_NB_INDICATIONS_FLD_OFFSET 16 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_INITIAL_DELAY_FLD_OFFSET 0 + +#define TI_K3_OSPI_PHY_MASTER_CONTROL_LOCK_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_BYPASS_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_PHASE_DETECT_SELECTOR_FLD_SIZE 3 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_NB_INDICATIONS_FLD_SIZE 3 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_INITIAL_DELAY_FLD_SIZE 7 + +/* DLL_OBSERVABLE_LOWER */ +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD_OFFSET 24 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD_OFFSET 16 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD_OFFSET 15 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD_OFFSET 8 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD_OFFSET 3 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD_OFFSET 1 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD_OFFSET 0 + +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD_SIZE 8 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD_SIZE 8 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD_SIZE 1 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD_SIZE 7 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD_SIZE 5 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD_SIZE 1 + +/* DLL_OBSERVABLE_UPPER */ +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD_OFFSET 16 +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_RX_DECODER_OUTPUT_FLD_OFFSET 0 + +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD_SIZE 7 +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_RX_DECODER_OUTPUT_FLD_SIZE 7 + +/* OPCODE_EXT_LOWER */ +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_READ_OPCODE_FLD_OFFSET 24 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_WRITE_OPCODE_FLD_OFFSET 16 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_POLL_OPCODE_FLD_OFFSET 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_STIG_OPCODE_FLD_OFFSET 0 + +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_READ_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_WRITE_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_POLL_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_STIG_OPCODE_FLD_SIZE 8 + +/* OPCODE_EXT_UPPER */ +#define TI_K3_OSPI_OPCODE_EXT_UPPER_WEL_OPCODE_FLD_OFFSET 24 +#define TI_K3_OSPI_OPCODE_EXT_UPPER_EXT_WEL_OPCODE_FLD_OFFSET 16 + +#define TI_K3_OSPI_OPCODE_EXT_UPPER_WEL_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_UPPER_EXT_WEL_OPCODE_FLD_SIZE 8 + +#endif /* ZEPHYR_DRIVERS_MSPI_TI_K3_H_*/ diff --git a/dts/bindings/mspi/ti,mspi-k3-controller.yaml b/dts/bindings/mspi/ti,mspi-k3-controller.yaml new file mode 100644 index 000000000000..8232cb26a3bf --- /dev/null +++ b/dts/bindings/mspi/ti,mspi-k3-controller.yaml @@ -0,0 +1,28 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: TI K3 MSPI Controller + +compatible: "ti,k3-mspi-controller" + +include: [mspi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + description: | + Address and length of the MSPI configuration register and the indirect + write FIFO location. + + ce-gpios: + description: | + The used chip select GPIO pins. This property is not used since the driver + only supports the hardware controlled chip select pins. + + sram-allocated-for-read: + required: true + type: int + description: | + Amount of SRAM that is allocated for read data from the MSPI bus. The rest + is allocated for data written to the MSPI bus. + The value needs to be between 0 and 255 diff --git a/soc/ti/k3/am6x/r5/mpu_am2434.c b/soc/ti/k3/am6x/r5/mpu_am2434.c index 825c63734ed9..8f172645b16a 100644 --- a/soc/ti/k3/am6x/r5/mpu_am2434.c +++ b/soc/ti/k3/am6x/r5/mpu_am2434.c @@ -33,6 +33,10 @@ static const struct arm_mpu_region mpu_regions[] = { MPU_REGION_ENTRY("SRAM shared", DT_REG_ADDR(DT_NODELABEL(sram_shared)), ARM_MPU_REGION_SIZE_256KB << MPU_RASR_SIZE_Pos, {(0b100 << MPU_RASR_TEX_Pos) | MPU_RASR_S_Msk | P_RW_U_RO_Msk}), +#if DT_NODE_HAS_STATUS(DT_NODELABEL(mspi0), okay) + MPU_REGION_ENTRY("FSS0", DT_REG_ADDR_BY_IDX(DT_NODELABEL(mspi0), 1), + ARM_MPU_REGION_SIZE_32B << MPU_RASR_SIZE_Pos, {P_RW_U_NA_Msk}), +#endif }; const struct arm_mpu_config mpu_config = {.num_regions = ARRAY_SIZE(mpu_regions), From 218cdf1e5e3e3900ca5cdc7435593d32fdf233a9 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Thu, 6 Mar 2025 15:54:56 +0100 Subject: [PATCH 12/20] dts: arm: ti: k3: add mspi0 bus to am2434 soc Add the mspi0 bus in disabled state to the am2434 soc Signed-off-by: Mika Braunschweig --- dts/arm/ti/am2434_main_r5.dtsi | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dts/arm/ti/am2434_main_r5.dtsi b/dts/arm/ti/am2434_main_r5.dtsi index 6ee8ac1ac812..ffa7fc663e51 100644 --- a/dts/arm/ti/am2434_main_r5.dtsi +++ b/dts/arm/ti/am2434_main_r5.dtsi @@ -86,6 +86,13 @@ status = "disabled"; }; + mspi0: mspi@fc40000 { + compatible = "ti,k3-mspi-controller"; + reg = <0x0fc40000 0x100 0x60000000 0x4>; + sram-allocated-for-read = <0x80>; + status = "disabled"; + }; + uart0: uart@2800000 { compatible = "ns16550"; reg = <0x02800000 0x200>; From e3bfcdd714fa70122d752e16fca50dcf26394862 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 10 Mar 2025 13:48:52 +0100 Subject: [PATCH 13/20] drivers: mtd: add infineon s25h mspi nor flash Add a infineon s25h mspi nor flash driver. This driver was tested on the am243x-lp board in 1S-1S-1S mode. The driver doesn't check the configuration for dummy cycles and assumes a factory default configuration. It also changes, if needed, a non-volatile configuration bit so the erase sectors are uniform. On startup the JEDEC id is read and checked as basic communication test. Signed-off-by: Mika Braunschweig --- drivers/flash/CMakeLists.txt | 3 + drivers/flash/Kconfig.mspi | 9 + drivers/flash/flash_mspi_infineon_s25h.c | 650 ++++++++++++++++++++++ drivers/flash/flash_mspi_infineon_s25h.h | 114 ++++ drivers/mspi/CMakeLists.txt | 2 + dts/bindings/mtd/infineon,s25h-flash.yaml | 19 + 6 files changed, 797 insertions(+) create mode 100644 drivers/flash/flash_mspi_infineon_s25h.c create mode 100644 drivers/flash/flash_mspi_infineon_s25h.h create mode 100644 dts/bindings/mtd/infineon,s25h-flash.yaml diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 089259a2572a..821f78c25d94 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -1,3 +1,5 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources(flash_util.c) @@ -34,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G flash_mcux_f zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_NOR flash_mcux_flexspi_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_ATXP032 flash_mspi_atxp032.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_EMUL_DEVICE flash_mspi_emul_device.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_INFINEON_S25H flash_mspi_infineon_s25h.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_NOR flash_mspi_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c) diff --git a/drivers/flash/Kconfig.mspi b/drivers/flash/Kconfig.mspi index d699aa493093..f0bce8effd00 100644 --- a/drivers/flash/Kconfig.mspi +++ b/drivers/flash/Kconfig.mspi @@ -1,4 +1,5 @@ # Copyright (c) 2024 Ambiq Micro Inc. +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 menu "MSPI flash device driver" @@ -51,4 +52,12 @@ config FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE endif # FLASH_MSPI_NOR +config FLASH_MSPI_INFINEON_S25H + bool "MSPI Infineon S25H driver" + default y + depends on DT_HAS_INFINEON_S25H_FLASH_ENABLED + select FLASH_MSPI + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_EXPLICIT_ERASE + endmenu diff --git a/drivers/flash/flash_mspi_infineon_s25h.c b/drivers/flash/flash_mspi_infineon_s25h.c new file mode 100644 index 000000000000..a4a5ea36b0a5 --- /dev/null +++ b/drivers/flash/flash_mspi_infineon_s25h.c @@ -0,0 +1,650 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_s25h_flash + +#include "flash_mspi_infineon_s25h.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(flash_mspi_infineon_s25h, CONFIG_FLASH_LOG_LEVEL); + +struct flash_mspi_infineon_s25h_cfg { + DEVICE_MMIO_ROM; + const struct device *bus; + const struct pinctrl_dev_config *pinctrl; + k_timeout_t reset_startup_duration; + + const struct mspi_dev_cfg mspi_dev_cfg; + const struct mspi_dev_id dev_id; +}; + +struct flash_mspi_infineon_s25h_data { +}; + +static int flash_mspi_infineon_s25h_prepare_mspi_bus(const struct device *dev) +{ + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + return mspi_dev_config(config->bus, &config->dev_id, + MSPI_DEVICE_CONFIG_CE_NUM | MSPI_DEVICE_CONFIG_IO_MODE | + MSPI_DEVICE_CONFIG_CPP | MSPI_DEVICE_CONFIG_CE_POL | + MSPI_DEVICE_CONFIG_DQS | MSPI_DEVICE_CONFIG_DATA_RATE | + MSPI_DEVICE_CONFIG_ENDIAN, + &config->mspi_dev_cfg); +} + +static int flash_mspi_infineon_s25h_reset(const struct device *dev) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + const struct mspi_xfer_packet reset_packets[] = { + { + .dir = MSPI_TX, + .cmd = INF_MSPI_S25H_OPCODE_RESET_ENABLE, + .num_bytes = 0, + }, + { + .dir = MSPI_TX, + .cmd = INF_MSPI_S25H_OPCODE_RESET, + .num_bytes = 0, + }}; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .rx_dummy = 0, + .addr_length = 0, + .num_packet = 2, + .packets = reset_packets, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer); + if (ret < 0) { + return ret; + } + + k_sleep(config->reset_startup_duration); + + return 0; +} + +static int flash_mspi_infineon_s25h_set_writing_forbidden(const struct device *dev, + bool writing_forbidden) +{ + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + uint8_t cmd = writing_forbidden ? INF_MSPI_S25H_OPCODE_WRITE_DISABLE + : INF_MSPI_S25H_OPCODE_WRITE_ENABLE; + const struct mspi_xfer_packet packet = { + .dir = MSPI_TX, + .cmd = cmd, + .num_bytes = 0, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA_SINGLE_CMD, + .packets = &packet, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + return mspi_transceive(config->bus, &config->dev_id, &xfer); +} + +static int flash_mspi_infineon_s25h_rw_any_register(const struct device *dev, uint32_t address, + uint8_t *value, uint32_t delay, + enum mspi_xfer_direction dir) +{ + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + uint32_t cmd; + uint32_t rx_dummy; + + if (dir == MSPI_RX) { + cmd = INF_MSPI_S25H_OPCODE_READ_ANY_REGISTER; + rx_dummy = delay; + } else { + cmd = INF_MSPI_S25H_OPCODE_WRITE_ANY_REGISTER; + rx_dummy = 0; + } + + const struct mspi_xfer_packet packet = { + .dir = dir, + .cmd = cmd, + .num_bytes = 1, + .data_buf = value, + .address = address, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = config->mspi_dev_cfg.addr_length, + .rx_dummy = rx_dummy, + .packets = &packet, + .num_packet = 1, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + return mspi_transceive(config->bus, &config->dev_id, &xfer); +} + +static int flash_mspi_infineon_s25h_is_write_protection_enabled(const struct device *dev, + uint8_t *is_enabled) +{ + int ret = 0; + uint8_t val = 0; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, + &val, 0, MSPI_RX); + if (ret < 0) { + return ret; + } + *is_enabled = (val & INF_MSPI_S25H_STATUS_1_WRPGEN_BIT); + return 0; +} + +static int flash_mspi_infineon_s25h_wait_for_idle(const struct device *dev, uint32_t timeout_ms) +{ + int ret = 0; + uint8_t status_1 = 0; + uint32_t retries = timeout_ms / INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL_MS; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, + &status_1, 0, MSPI_RX); + if (ret < 0) { + return ret; + } + + while ((status_1 & INF_MSPI_S25H_STATUS_1_RDYBSY_BIT) != 0 && retries > 0) { + k_sleep(INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL); + ret = flash_mspi_infineon_s25h_rw_any_register( + dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, &status_1, 0, MSPI_RX); + if (ret < 0) { + return ret; + } + --retries; + } + + if (retries == 0) { + LOG_ERR("Error waiting for flash to idle"); + return -EIO; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_read_jedec_id(const struct device *dev, uint8_t *buf) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + const struct mspi_xfer_packet packet = { + .dir = MSPI_RX, + .cmd = INF_MSPI_S25H_OPCODE_READ_JEDEC_ID, + .num_bytes = 3, + .data_buf = buf, + .address = 0, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = 0, + .rx_dummy = 0, + .packets = &packet, + .num_packet = 1, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer); + if (ret < 0) { + LOG_ERR("Error reading JEDEC id"); + return ret; + } + return 0; +} + +static int flash_mspi_infineon_s25h_read(const struct device *dev, off_t addr, void *data, + size_t size) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error setting up the MSPI bus for the flash device"); + return ret; + } + + const struct mspi_xfer_packet packet = { + .address = addr, + .cmd = INF_MSPI_S25H_OPCODE_READ_FLASH, + .data_buf = data, + .dir = MSPI_RX, + .num_bytes = size, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = config->mspi_dev_cfg.addr_length, + .rx_dummy = 0, + .packets = &packet, + .num_packet = 1, + /* 1 us per byte; this gives for 256KiB around 0.26 seconds */ + .timeout = size, + }; + + return mspi_transceive(config->bus, &config->dev_id, &xfer); +} + +static int flash_mspi_infineon_s25h_single_block_write(const struct device *dev, + const struct mspi_xfer *xfer_write) +{ + int ret; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + uint8_t status_1; + + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error disabling write protection before trying to write data into " + "flash"); + return ret; + } + + ret = mspi_transceive(config->bus, &config->dev_id, xfer_write); + if (ret < 0) { + LOG_ERR("Error writing flash memory"); + return ret; + } + + ret = flash_mspi_infineon_s25h_wait_for_idle(dev, + INF_MSPI_S25H_TIMEOUT_IDLE_WRITE_BLOCK_MS); + if (ret < 0) { + LOG_ERR("Error waiting for flash to enter idle after writing"); + return ret; + } + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, + &status_1, 0, MSPI_RX); + + if (ret < 0) { + LOG_ERR("Error reading back status 1 register to confirm valid write"); + return ret; + } + + if (status_1 & INF_MSPI_S25H_STATUS_1_PRGERR_BIT) { + LOG_ERR("Last programming transaction wasn't successful"); + return -EIO; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_write(const struct device *dev, off_t addr, const void *data, + size_t size) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + uint8_t old_write_protection; + uint8_t *data_buf = (uint8_t *)data; + + /* Check whether we are not aligned and would write over a block boundary */ + if ((addr % INF_MSPI_S25H_WRITE_BLOCK_SIZE) != 0 && + (addr % INF_MSPI_S25H_WRITE_BLOCK_SIZE) + size >= INF_MSPI_S25H_WRITE_BLOCK_SIZE) { + LOG_ERR("Non-aligned write that goes above another block isn't supported"); + return -ENOSYS; + } + + struct mspi_xfer_packet packet_write = { + .cmd = INF_MSPI_S25H_OPCODE_WRITE_FLASH, + .dir = MSPI_TX, + }; + + struct mspi_xfer xfer_write = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = config->mspi_dev_cfg.addr_length, + .rx_dummy = 0, + .packets = &packet_write, + .num_packet = 1, + /* 1 us per byte; this gives for 256KiB around 0.26 seconds */ + .timeout = size, + }; + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error setting up the MSPI bus for the flash device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_is_write_protection_enabled(dev, &old_write_protection); + if (ret < 0) { + LOG_ERR("Error querying whether write protection is enabled"); + return ret; + } + + uint32_t remaining_bytes = size; + uint32_t write_index = 0; + uint32_t write_block_count = size / INF_MSPI_S25H_WRITE_BLOCK_SIZE; + uint32_t current_transaction_transfer_size; + + if (size % INF_MSPI_S25H_WRITE_BLOCK_SIZE != 0) { + ++write_block_count; + } + + do { + current_transaction_transfer_size = + MIN(remaining_bytes, INF_MSPI_S25H_WRITE_BLOCK_SIZE); + packet_write.num_bytes = current_transaction_transfer_size; + packet_write.address = addr + (write_index * INF_MSPI_S25H_WRITE_BLOCK_SIZE); + packet_write.data_buf = &data_buf[write_index * INF_MSPI_S25H_WRITE_BLOCK_SIZE]; + + ret = flash_mspi_infineon_s25h_single_block_write(dev, &xfer_write); + if (ret < 0) { + return ret; + } + + remaining_bytes -= current_transaction_transfer_size; + ++write_index; + + } while (remaining_bytes > 0); + + if (old_write_protection) { + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + LOG_ERR("Error re-enabling write protection after writing data into flash"); + return ret; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_erase(const struct device *dev, off_t addr, size_t size) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + uint8_t old_write_protection; + + struct mspi_xfer_packet packet_erase = { + .cmd = INF_MSPI_S25H_OPCODE_ERASE_256K, + .data_buf = NULL, + .num_bytes = 0, + .dir = MSPI_TX, + }; + + const struct mspi_xfer xfer_erase = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = config->mspi_dev_cfg.addr_length, + .rx_dummy = 0, + .packets = &packet_erase, + .num_packet = 1, + /* 1 us per byte; this gives for 256KiB around 0.26 seconds */ + .timeout = size, + }; + + if (addr % INF_MSPI_S25H_ERASE_SECTOR_SIZE != 0) { + LOG_WRN("Erase sector is not aligned! This might erase data you don't want to " + "erase"); + } + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error setting up the MSPI bus for the flash device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_is_write_protection_enabled(dev, &old_write_protection); + if (ret < 0) { + LOG_ERR("Error querying whether write protection is enabled"); + return ret; + } + + uint32_t count = size / INF_MSPI_S25H_ERASE_SECTOR_SIZE; + + if (size % INF_MSPI_S25H_ERASE_SECTOR_SIZE != 0) { + ++count; + } + + for (uint32_t i = 0; i < count; ++i) { + packet_erase.address = addr + (i * INF_MSPI_S25H_ERASE_SECTOR_SIZE); + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error disabling write protection before flash erase"); + return ret; + } + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer_erase); + if (ret) { + LOG_ERR("Error sending erase command"); + return ret; + } + + ret = flash_mspi_infineon_s25h_wait_for_idle( + dev, INF_MSPI_S25H_TIMEOUT_IDLE_ERASE_SECTOR_MS); + if (ret < 0) { + LOG_ERR("Error waiting for flash to enter idle after writing"); + return ret; + } + } + + if (old_write_protection) { + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error re-enabling write protection after flash erase"); + return ret; + } + } + + uint8_t status_1; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, + &status_1, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading back status 1 register to confirm valid write"); + return ret; + } + + if (status_1 & INF_MSPI_S25H_STATUS_1_ERSERR_BIT) { + LOG_ERR("Last erase transaction wasn't successful"); + return -EIO; + } + + return 0; +} + +static const struct flash_parameters * +flash_mspi_infineon_s25h_get_parameters(const struct device *dev) +{ + static const struct flash_parameters parameters = { + .erase_value = 0xFF, .write_block_size = INF_MSPI_S25H_WRITE_BLOCK_SIZE}; + return ¶meters; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void flash_mspi_infineon_s25h_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + static const struct flash_pages_layout real_layout = { + .pages_count = 256, + .pages_size = INF_MSPI_S25H_ERASE_SECTOR_SIZE, + }; + + *layout = &real_layout; + *layout_size = 1; +} +#endif + +static int flash_mspi_infineon_s25h_init(const struct device *dev) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error setting up the MSPI bus for the flash device"); + return ret; + } + + ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to apply pinctrl"); + return ret; + } + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error switching MSPI configuration to the requirements of the flash " + "device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_reset(dev); + if (ret < 0) { + LOG_ERR("Error resetting flash device"); + return ret; + } + + uint8_t id[3]; + + ret = flash_mspi_infineon_s25h_read_jedec_id(dev, id); + if (ret < 0) { + LOG_ERR("Error reading JEDEC ids from flash"); + return ret; + } + + uint8_t manufacturer_id = id[0]; + uint16_t device_id = (id[1] << 8) | id[2]; + + if (manufacturer_id != INF_MSPI_S25H_MANUFACTURER_ID || + device_id != INF_MSPI_S25H_DEVICE_ID) { + LOG_ERR("Rear JEDEC ids don't match expected ids. The communication is possibly " + "broken or the non-volatile flash configuration is something unexpected"); + LOG_ERR("Read manufacturer id: 0x%02X. Expected: 0x%02X", manufacturer_id, + INF_MSPI_S25H_MANUFACTURER_ID); + LOG_ERR("Read device id: 0x%04X. Expected: 0x%04X", device_id, + INF_MSPI_S25H_DEVICE_ID); + return -EIO; + } + + /* This driver needs the hybrid sector mode to be disabled. So if it's found to be turned on + * it gets changed. This requires changing the non-volatile configuration and also a reset + */ + uint8_t conf3 = 0; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_3, + &conf3, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading volatile configuration register 3"); + return ret; + } + + if ((conf3 & INF_MSPI_S25H_CFG_3_UNHYSA_BIT) == 0) { + LOG_INF("Flash is in hybrid sector mode. Changing non-volatile config to correct " + "this"); + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error disabling write protection for flash device"); + return ret; + } + conf3 |= INF_MSPI_S25H_CFG_3_UNHYSA_BIT; + + ret = flash_mspi_infineon_s25h_rw_any_register( + dev, INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_3, &conf3, 0, MSPI_TX); + if (ret < 0) { + LOG_ERR("Error changing non-volatile configuration of flash"); + return ret; + } + + ret = flash_mspi_infineon_s25h_wait_for_idle(dev, + INF_MSPI_S25H_TIMEOUT_IDLE_STARTUP); + if (ret < 0) { + LOG_ERR("Error waiting for flash to enter idle"); + return ret; + } + + ret = flash_mspi_infineon_s25h_reset(dev); + if (ret < 0) { + LOG_ERR("Error resetting flash via reset command"); + return ret; + } + + conf3 = 0; + ret = flash_mspi_infineon_s25h_rw_any_register( + dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_3, &conf3, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading volatile config 3 register of flash"); + return ret; + } + + if ((conf3 & INF_MSPI_S25H_CFG_3_UNHYSA_BIT) == 0) { + LOG_ERR("Changing the flash configuration to Uniform mode didn't work"); + return -EIO; + } + + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, true); + if (ret < 0) { + LOG_ERR("Error re-enabling the write protection"); + return ret; + } + } + + return 0; +} + +static DEVICE_API(flash, flash_mspi_infineon_s25h_driver_api) = { + .read = flash_mspi_infineon_s25h_read, + .write = flash_mspi_infineon_s25h_write, + .erase = flash_mspi_infineon_s25h_erase, + .get_parameters = flash_mspi_infineon_s25h_get_parameters, +#if defined(CONFIG_FLASH_JESD216_API) + .read_jedec_id = flash_mspi_infineon_s25h_read_jedec_id, +#endif +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_mspi_infineon_s25h_pages_layout, +#endif +}; + +#define INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, prop) \ + BUILD_ASSERT(DT_NODE_HAS_PROP(DT_DRV_INST(n), prop) == 0, \ + "The Infineon S25H driver ignores the property " #prop) + +/* Check for ignored/wrong values in the devicetree */ +#define INFINEON_MSPI_FLASH_S25H_CHECK_DEVICETREE_CONFIG(n) \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, rx_dummy); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, tx_dummy); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, read_command); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, write_command); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, xip_config); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, scramble_config); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, ce_break_config); \ + BUILD_ASSERT(DT_ENUM_HAS_VALUE(DT_DRV_INST(n), command_length, INSTR_1_BYTE) == 1, \ + "The Infineon S25H chip uses only 1 byte opcodes") + +#define INFINFEON_MSPI_FLASH_S25H_DEFINE(n) \ + INFINEON_MSPI_FLASH_S25H_CHECK_DEVICETREE_CONFIG(n); \ + PINCTRL_DT_DEFINE(DT_DRV_INST(n)); \ + static const struct flash_mspi_infineon_s25h_cfg flash_mspi_infineon_s25h_cfg_##n = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ + .bus = DEVICE_DT_GET(DT_BUS(DT_DRV_INST(n))), \ + .pinctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .reset_startup_duration = K_USEC(DT_INST_PROP(n, reset_startup_time_us)), \ + .dev_id = \ + { \ + .dev_idx = DT_REG_ADDR(DT_DRV_INST(n)), \ + }, \ + .mspi_dev_cfg = MSPI_DEVICE_CONFIG_DT_INST(n), \ + }; \ + static struct flash_mspi_infineon_s25h_data flash_mspi_infineon_s25h_data_##n = {}; \ + DEVICE_DT_INST_DEFINE(n, flash_mspi_infineon_s25h_init, NULL, \ + &flash_mspi_infineon_s25h_data_##n, \ + &flash_mspi_infineon_s25h_cfg_##n, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_mspi_infineon_s25h_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(INFINFEON_MSPI_FLASH_S25H_DEFINE) diff --git a/drivers/flash/flash_mspi_infineon_s25h.h b/drivers/flash/flash_mspi_infineon_s25h.h new file mode 100644 index 000000000000..b049731919b8 --- /dev/null +++ b/drivers/flash/flash_mspi_infineon_s25h.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_FLASH_MSPI_INFINEON_S25H_ +#define ZEPHYR_DRIVERS_FLASH_MSPI_INFINEON_S25H_ + +#include "zephyr/kernel.h" +#include "zephyr/sys/util_macro.h" + +/* defaults */ +#define INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT 100 + +/* opcodes */ +#define INF_MSPI_S25H_OPCODE_WRITE_ENABLE 0x06 +#define INF_MSPI_S25H_OPCODE_WRITE_DISABLE 0x04 + +#define INF_MSPI_S25H_OPCODE_READ_ANY_REGISTER 0x65 +#define INF_MSPI_S25H_OPCODE_WRITE_ANY_REGISTER 0x71 + +#define INF_MSPI_S25H_OPCODE_ERASE_256K 0xD8 +#define INF_MSPI_S25H_OPCODE_READ_FLASH 0x03 +#define INF_MSPI_S25H_OPCODE_WRITE_FLASH 0x02 + +#define INF_MSPI_S25H_OPCODE_RESET_ENABLE 0x66 +#define INF_MSPI_S25H_OPCODE_RESET 0x99 + +#define INF_MSPI_S25H_OPCODE_READ_JEDEC_ID 0x9F + +/* addresses */ +#define INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1 0x00800000 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_2 0x00800001 + +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1 0x00800002 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_2 0x00800003 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_3 0x00800004 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_4 0x00800005 + +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_STATUS_1 0x0 + +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_1 0x2 +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_2 0x3 +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_3 0x4 +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_4 0x5 + +/* device specific data */ +#define INF_MSPI_S25H_MANUFACTURER_ID 0x34 +#define INF_MSPI_S25H_DEVICE_ID 0x2A1A + +#define INF_MSPI_S25H_ERASE_SECTOR_SIZE 262144 +#define INF_MSPI_S25H_WRITE_BLOCK_SIZE 256 + +/* default data */ +#define INF_MSPI_S25H_DEFAULT_XFER_DATA \ + .async = false, .cmd_length = 1, .hold_ce = false, .priority = 0, .tx_dummy = 0, \ + .xfer_mode = MSPI_PIO + +#define INF_MSPI_S25H_DEFAULT_XFER_DATA_SINGLE_CMD \ + INF_MSPI_S25H_DEFAULT_XFER_DATA, .rx_dummy = 0, .addr_length = 0, .num_packet = 1 + +#define INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL_MS 10 +#define INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL \ + K_MSEC(INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL_MS) +#define INF_MSPI_S25H_TIMEOUT_IDLE_ERASE_SECTOR_MS 1000 +#define INF_MSPI_S25H_TIMEOUT_IDLE_WRITE_BLOCK_MS 1000 +#define INF_MSPI_S25H_TIMEOUT_IDLE_STARTUP 100 + +/* register bits */ +#define INF_MSPI_S25H_STATUS_1_RDYBSY_BIT BIT(0) +#define INF_MSPI_S25H_STATUS_1_WRPGEN_BIT BIT(1) +#define INF_MSPI_S25H_STATUS_1_LBPROT_SHIFT 2 +#define INF_MSPI_S25H_STATUS_1_LBPROT_MASK BIT_MASK(3) +#define INF_MSPI_S25H_STATUS_1_ERSERR_BIT BIT(5) +#define INF_MSPI_S25H_STATUS_1_PRGERR_BIT BIT(6) +#define INF_MSPI_S25H_STATUS_1_STCFWR_BIT BIT(7) + +#define INF_MSPI_S25H_STATUS_2_PROGMS_BIT BIT(0) +#define INF_MSPI_S25H_STATUS_2_ERASES_BIT BIT(1) +#define INF_MSPI_S25H_STATUS_2_SESTAT_BIT BIT(2) +#define INF_MSPI_S25H_STATUS_2_DICRCA_BIT BIT(3) +#define INF_MSPI_S25H_STATUS_2_DICRCS_BIT BIT(4) + +#define INF_MSPI_S25H_CFG_1_TLPROT_BIT BIT(0) +#define INF_MSPI_S25H_CFG_1_QUADIT_BIT BIT(1) +#define INF_MSPI_S25H_CFG_1_TB4KBS_BIT BIT(2) +#define INF_MSPI_S25H_CFG_1_PLPROT_BIT BIT(4) +#define INF_MSPI_S25H_CFG_1_TBPROT_BIT BIT(5) +#define INF_MSPI_S25H_CFG_1_SP4KBS_BIT BIT(6) + +#define INF_MSPI_S25H_CFG_2_MEMLAT_SHIFT 0 +#define INF_MSPI_S25H_CFG_2_MEMLAT_MASK BIT_MASK(4) +#define INF_MSPI_S25H_CFG_2_DQ3RST_BIT BIT(5) +#define INF_MSPI_S25H_CFG_2_QPI_IT_BIT BIT(6) +#define INF_MSPI_S25H_CFG_2_ADRBYT_BIT BIT(7) + +#define INF_MSPI_S25H_CFG_3_LSFRST_BIT BIT(0) +#define INF_MSPI_S25H_CFG_3_CLSRSM_BIT BIT(2) +#define INF_MSPI_S25H_CFG_3_UNHYSA_BIT BIT(3) +#define INF_MSPI_S25H_CFG_3_PGMBUF_BIT BIT(4) +#define INF_MSPI_S25H_CFG_3_BLKCHK_BIT BIT(5) +#define INF_MSPI_S25H_CFG_3_VRGLAT_SHIFT 6 +#define INF_MSPI_S25H_CFG_3_VRGLAT_MASK BIT_MASK(2) + +#define INF_MSPI_S25H_CFG_4_RBSTWL_SHIFT 0 +#define INF_MSPI_S25H_CFG_4_RBSTWL_MASK BIT_MASK(2) +#define INF_MSPI_S25H_CFG_4_DPDPOR_BIT BIT(2) +#define INF_MSPI_S25H_CFG_4_ECC12S_BIT BIT(3) +#define INF_MSPI_S25H_CFG_4_RBSTWP_BIT BIT(4) +#define INF_MSPI_S25H_CFG_4_IOIMPD_SHIFT 5 +#define INF_MSPI_S25H_CFG_4_IOIMPD_MASK BIT_MASK(3) + +#endif /* ZEPHYR_DRIVERS_FLASH_MSPI_INFINEON_S25H_ */ diff --git a/drivers/mspi/CMakeLists.txt b/drivers/mspi/CMakeLists.txt index 420586d18e9a..54962236bdb1 100644 --- a/drivers/mspi/CMakeLists.txt +++ b/drivers/mspi/CMakeLists.txt @@ -1,3 +1,5 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# # SPDX-License-Identifier: Apache-2.0 zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/mspi.h) diff --git a/dts/bindings/mtd/infineon,s25h-flash.yaml b/dts/bindings/mtd/infineon,s25h-flash.yaml new file mode 100644 index 000000000000..ef5a4d1900dc --- /dev/null +++ b/dts/bindings/mtd/infineon,s25h-flash.yaml @@ -0,0 +1,19 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: MSPI Infineon S25H Flash + +compatible: "infineon,s25h-flash" + +on-bus: mspi + +include: ["flash-controller.yaml", "pinctrl-device.yaml", "mspi-device.yaml"] + +properties: + reg: + required: true + + reset-startup-time-us: + required: true + type: int + description: Time the device requires to recover after a reset in microseconds From d8aff053007c88c552cc843193d3692b4d4a627f Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Thu, 6 Mar 2025 16:08:21 +0100 Subject: [PATCH 14/20] boards: ti: k3: add flash to am243x-launchpad Add the Infineon flash chip to the devicetree of the am243x launchpad Signed-off-by: Mika Braunschweig --- .../am243x_launchpad_main_r5f0_0-pinctrl.dtsi | 32 +++++++++++++++++++ .../am243x_launchpad_main_r5f0_0.dts | 30 +++++++++++++++++ boards/ti/am243x_launchpad/doc/index.rst | 17 ++++++++++ 3 files changed, 79 insertions(+) diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi index 35650ceb400c..f1fdc4735796 100644 --- a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0-pinctrl.dtsi @@ -19,6 +19,38 @@ pinmux = ; }; + ospi_clk: ospi_clk { + pinmux = ; + }; + + ospi_csn0: ospi_csn0 { // GPIO0 11 + pinmux = ; + }; + + ospi_d0: ospi_d0 { + pinmux = ; + }; + + ospi_d1: ospi_d1 { + pinmux = ; + }; + + ospi_d2: ospi_d2 { + pinmux = ; + }; + + ospi_d3: ospi_d3 { + pinmux = ; + }; + + ospi_dqs: ospi_dqs { + pinmux = ; + }; + + ospi_lbclko: ospi_lbclko { + pinmux = ; + }; + // the other leds can't be controlled due to // https://github.com/zephyrproject-rtos/zephyr/issues/81100 }; diff --git a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts index 44caea8d5996..3f1a446f05d1 100644 --- a/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts +++ b/boards/ti/am243x_launchpad/am243x_launchpad_main_r5f0_0.dts @@ -36,6 +36,36 @@ }; +&mspi0 { + ce-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&ospi_clk &ospi_d0 &ospi_d1 &ospi_d2 &ospi_d3 &ospi_dqs &ospi_lbclko>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + + s25hl512tfamhi010: qspi-nor-flash@0 { + compatible = "infineon,s25h-flash"; + reg = <0>; + pinctrl-0 = <&ospi_csn0>; + pinctrl-names = "default"; + + reset-startup-time-us = <600>; + + mspi-max-frequency = ; + + mspi-io-mode = "MSPI_IO_MODE_SINGLE"; + mspi-data-rate = "MSPI_DATA_RATE_SINGLE"; + mspi-hardware-ce-num = <0>; + mspi-cpp-mode = "MSPI_CPP_MODE_0"; + mspi-ce-polarity = "MSPI_CE_ACTIVE_LOW"; + address-length = "ADDR_3_BYTE"; + command-length = "INSTR_1_BYTE"; + + status = "okay"; + }; + status = "okay"; +}; + &uart0 { status = "okay"; pinctrl-0 = <&uart0_tx_default &uart0_rx_default>; diff --git a/boards/ti/am243x_launchpad/doc/index.rst b/boards/ti/am243x_launchpad/doc/index.rst index 9782b775d4e3..9da7d1a2057b 100644 --- a/boards/ti/am243x_launchpad/doc/index.rst +++ b/boards/ti/am243x_launchpad/doc/index.rst @@ -48,11 +48,28 @@ be accessed through it without requiring additional hardware. +-----------+---------------------+----------+ | UART | UART0 RX | GPIO1 29 | +-----------+---------------------+----------+ +| NOR Flash | CLK | GPIO0 0 | ++-----------+---------------------+----------+ +| NOR Flash | CSn0 | GPIO0 11 | ++-----------+---------------------+----------+ +| NOR Flash | D0 | GPIO0 3 | ++-----------+---------------------+----------+ +| NOR Flash | D1 | GPIO0 4 | ++-----------+---------------------+----------+ +| NOR Flash | D2 | GPIO0 5 | ++-----------+---------------------+----------+ +| NOR Flash | D3 | GPIO0 6 | ++-----------+---------------------+----------+ +| NOR Flash | DQS | GPIO0 2 | ++-----------+---------------------+----------+ +| NOR Flash | LBCLKO | GPIO0 1 | ++-----------+---------------------+----------+ Programming and Debugging ************************* + Flashing ======== The boot process of the AM2434 SoC requires the booting image to be in a From 611dc4b3adc545e8520297b20b751794bbd55854 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Fri, 14 Mar 2025 13:24:04 +0100 Subject: [PATCH 15/20] tests: drivers: mspi: flash: add am243x launchpad The test looks for devices that are enabled on a bus that's aliased mspi0. To allow the am243x launchpad to run this test it was needed to add an overlay which creates this alias Signed-off-by: Mika Braunschweig --- .../boards/am243x_launchpad_am2434_main_r5f0_0.overlay | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/drivers/mspi/flash/boards/am243x_launchpad_am2434_main_r5f0_0.overlay diff --git a/tests/drivers/mspi/flash/boards/am243x_launchpad_am2434_main_r5f0_0.overlay b/tests/drivers/mspi/flash/boards/am243x_launchpad_am2434_main_r5f0_0.overlay new file mode 100644 index 000000000000..2b2eae5086e1 --- /dev/null +++ b/tests/drivers/mspi/flash/boards/am243x_launchpad_am2434_main_r5f0_0.overlay @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * SPDX-License-Identifier: Apache-2.0 + */ +/ { + aliases { + mspi0 = &mspi0; + }; +}; From 4d497beb84964f31443b4a0c8bcda573c2f8e93f Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Fri, 14 Mar 2025 14:37:54 +0100 Subject: [PATCH 16/20] drivers: mtd: s25h: remove double mspi initialization The old implementation requested more often than neccessary to switch the mspi device configuration which has now been removed. Signed-off-by: Mika Braunschweig --- drivers/flash/flash_mspi_infineon_s25h.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/flash/flash_mspi_infineon_s25h.c b/drivers/flash/flash_mspi_infineon_s25h.c index a4a5ea36b0a5..f9867ba40ea5 100644 --- a/drivers/flash/flash_mspi_infineon_s25h.c +++ b/drivers/flash/flash_mspi_infineon_s25h.c @@ -486,12 +486,6 @@ static int flash_mspi_infineon_s25h_init(const struct device *dev) int ret = 0; const struct flash_mspi_infineon_s25h_cfg *config = dev->config; - ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); - if (ret < 0) { - LOG_ERR("Error setting up the MSPI bus for the flash device"); - return ret; - } - ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); if (ret < 0) { LOG_ERR("Failed to apply pinctrl"); From 2af7dfb884ff715a0b54b3d30a5fa2071d4cb9d1 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 17 Mar 2025 14:32:17 +0100 Subject: [PATCH 17/20] drivers: mtd: s25h: automatically disable write protection When using the function to write to a configuration/status register the write protection should be automatically disabled so it doesn't have to be done manually which can be easily forgotten. This has now been improved Signed-off-by: Mika Braunschweig --- drivers/flash/flash_mspi_infineon_s25h.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/flash/flash_mspi_infineon_s25h.c b/drivers/flash/flash_mspi_infineon_s25h.c index f9867ba40ea5..9a693748aa39 100644 --- a/drivers/flash/flash_mspi_infineon_s25h.c +++ b/drivers/flash/flash_mspi_infineon_s25h.c @@ -105,10 +105,19 @@ static int flash_mspi_infineon_s25h_rw_any_register(const struct device *dev, ui uint8_t *value, uint32_t delay, enum mspi_xfer_direction dir) { + int ret; const struct flash_mspi_infineon_s25h_cfg *config = dev->config; uint32_t cmd; uint32_t rx_dummy; + if (dir == MSPI_TX) { + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error disabling write protection before changing configuration"); + return ret; + } + } + if (dir == MSPI_RX) { cmd = INF_MSPI_S25H_OPCODE_READ_ANY_REGISTER; rx_dummy = delay; @@ -542,11 +551,7 @@ static int flash_mspi_infineon_s25h_init(const struct device *dev) if ((conf3 & INF_MSPI_S25H_CFG_3_UNHYSA_BIT) == 0) { LOG_INF("Flash is in hybrid sector mode. Changing non-volatile config to correct " "this"); - ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); - if (ret < 0) { - LOG_ERR("Error disabling write protection for flash device"); - return ret; - } + conf3 |= INF_MSPI_S25H_CFG_3_UNHYSA_BIT; ret = flash_mspi_infineon_s25h_rw_any_register( From 453977f7fdb03472c126d57fc0999f567954be53 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 17 Mar 2025 14:34:43 +0100 Subject: [PATCH 18/20] drivers: mtd: s25h: automatically use quad spi Until now the Infineon S25H driver ran MSPI only in single IO mode. With this change the driver now switches the IO mode to Quad SPI at the end of the initialization for higher transfer rates Signed-off-by: Mika Braunschweig --- drivers/flash/flash_mspi_infineon_s25h.c | 189 +++++++++++++++++++---- drivers/flash/flash_mspi_infineon_s25h.h | 10 +- 2 files changed, 166 insertions(+), 33 deletions(-) diff --git a/drivers/flash/flash_mspi_infineon_s25h.c b/drivers/flash/flash_mspi_infineon_s25h.c index 9a693748aa39..da2ba6732f62 100644 --- a/drivers/flash/flash_mspi_infineon_s25h.c +++ b/drivers/flash/flash_mspi_infineon_s25h.c @@ -25,23 +25,27 @@ struct flash_mspi_infineon_s25h_cfg { const struct pinctrl_dev_config *pinctrl; k_timeout_t reset_startup_duration; - const struct mspi_dev_cfg mspi_dev_cfg; const struct mspi_dev_id dev_id; }; struct flash_mspi_infineon_s25h_data { + struct mspi_dev_cfg mspi_dev_cfg; + uint8_t read_jedec_cmd; + uint8_t read_flash_cmd; + uint8_t read_flash_dummy_cycles; }; static int flash_mspi_infineon_s25h_prepare_mspi_bus(const struct device *dev) { const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *data = dev->data; return mspi_dev_config(config->bus, &config->dev_id, MSPI_DEVICE_CONFIG_CE_NUM | MSPI_DEVICE_CONFIG_IO_MODE | MSPI_DEVICE_CONFIG_CPP | MSPI_DEVICE_CONFIG_CE_POL | MSPI_DEVICE_CONFIG_DQS | MSPI_DEVICE_CONFIG_DATA_RATE | MSPI_DEVICE_CONFIG_ENDIAN, - &config->mspi_dev_cfg); + &data->mspi_dev_cfg); } static int flash_mspi_infineon_s25h_reset(const struct device *dev) @@ -107,6 +111,7 @@ static int flash_mspi_infineon_s25h_rw_any_register(const struct device *dev, ui { int ret; const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; uint32_t cmd; uint32_t rx_dummy; @@ -136,7 +141,7 @@ static int flash_mspi_infineon_s25h_rw_any_register(const struct device *dev, ui struct mspi_xfer xfer = { INF_MSPI_S25H_DEFAULT_XFER_DATA, - .addr_length = config->mspi_dev_cfg.addr_length, + .addr_length = dev_data->mspi_dev_cfg.addr_length, .rx_dummy = rx_dummy, .packets = &packet, .num_packet = 1, @@ -195,10 +200,11 @@ static int flash_mspi_infineon_s25h_read_jedec_id(const struct device *dev, uint { int ret = 0; const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *data = dev->data; const struct mspi_xfer_packet packet = { .dir = MSPI_RX, - .cmd = INF_MSPI_S25H_OPCODE_READ_JEDEC_ID, + .cmd = data->read_jedec_cmd, .num_bytes = 3, .data_buf = buf, .address = 0, @@ -218,6 +224,7 @@ static int flash_mspi_infineon_s25h_read_jedec_id(const struct device *dev, uint LOG_ERR("Error reading JEDEC id"); return ret; } + return 0; } @@ -226,6 +233,20 @@ static int flash_mspi_infineon_s25h_read(const struct device *dev, off_t addr, v { int ret = 0; const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; + + /* The S25H allows for continuous read operations which happen by sending + * 0xAX after an address. The driver doesn't implement this which is why we + * don't want this and instead wait for 2 cycles. However since the flash + * pins could be in high impedance state from the MSPI controller after the + * address was sent an address ending with 0xA could put the flash into a + * continuous read mode. To prevent this this driver requires the address to + * be aligned to 16 byte when in Quad SPI mode + */ + if (dev_data->mspi_dev_cfg.io_mode == MSPI_IO_MODE_QUAD && (addr % 16 != 0)) { + LOG_ERR("Address wasn't aligned to 16 byte while in Quad SPI mode"); + return -ENOTSUP; + } ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); if (ret < 0) { @@ -235,7 +256,7 @@ static int flash_mspi_infineon_s25h_read(const struct device *dev, off_t addr, v const struct mspi_xfer_packet packet = { .address = addr, - .cmd = INF_MSPI_S25H_OPCODE_READ_FLASH, + .cmd = dev_data->read_flash_cmd, .data_buf = data, .dir = MSPI_RX, .num_bytes = size, @@ -243,8 +264,8 @@ static int flash_mspi_infineon_s25h_read(const struct device *dev, off_t addr, v struct mspi_xfer xfer = { INF_MSPI_S25H_DEFAULT_XFER_DATA, - .addr_length = config->mspi_dev_cfg.addr_length, - .rx_dummy = 0, + .addr_length = dev_data->mspi_dev_cfg.addr_length, + .rx_dummy = dev_data->read_flash_dummy_cycles, .packets = &packet, .num_packet = 1, /* 1 us per byte; this gives for 256KiB around 0.26 seconds */ @@ -297,13 +318,13 @@ static int flash_mspi_infineon_s25h_single_block_write(const struct device *dev, return 0; } -static int flash_mspi_infineon_s25h_write(const struct device *dev, off_t addr, const void *data, - size_t size) +static int flash_mspi_infineon_s25h_write(const struct device *dev, off_t addr, + const void *transmission_data, size_t size) { int ret = 0; - const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; uint8_t old_write_protection; - uint8_t *data_buf = (uint8_t *)data; + uint8_t *data_buf = (uint8_t *)transmission_data; /* Check whether we are not aligned and would write over a block boundary */ if ((addr % INF_MSPI_S25H_WRITE_BLOCK_SIZE) != 0 && @@ -319,7 +340,7 @@ static int flash_mspi_infineon_s25h_write(const struct device *dev, off_t addr, struct mspi_xfer xfer_write = { INF_MSPI_S25H_DEFAULT_XFER_DATA, - .addr_length = config->mspi_dev_cfg.addr_length, + .addr_length = dev_data->mspi_dev_cfg.addr_length, .rx_dummy = 0, .packets = &packet_write, .num_packet = 1, @@ -378,6 +399,7 @@ static int flash_mspi_infineon_s25h_erase(const struct device *dev, off_t addr, { int ret = 0; const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; uint8_t old_write_protection; struct mspi_xfer_packet packet_erase = { @@ -389,7 +411,7 @@ static int flash_mspi_infineon_s25h_erase(const struct device *dev, off_t addr, const struct mspi_xfer xfer_erase = { INF_MSPI_S25H_DEFAULT_XFER_DATA, - .addr_length = config->mspi_dev_cfg.addr_length, + .addr_length = dev_data->mspi_dev_cfg.addr_length, .rx_dummy = 0, .packets = &packet_erase, .num_packet = 1, @@ -490,6 +512,117 @@ static void flash_mspi_infineon_s25h_pages_layout(const struct device *dev, } #endif +static int flash_mspi_infineon_s25h_verify_jedec_id(const struct device *dev) +{ + uint8_t id[3]; + int ret; + + ret = flash_mspi_infineon_s25h_read_jedec_id(dev, id); + if (ret < 0) { + LOG_ERR("Error reading JEDEC ids from flash"); + return ret; + } + + uint8_t manufacturer_id = id[0]; + uint16_t device_id = (id[1] << 8) | id[2]; + + if (manufacturer_id != INF_MSPI_S25H_MANUFACTURER_ID || + device_id != INF_MSPI_S25H_DEVICE_ID) { + LOG_ERR("Rear JEDEC ids don't match expected ids. The communication is possibly " + "broken or the non-volatile flash configuration is something unexpected"); + LOG_ERR("Read manufacturer id: 0x%02X. Expected: 0x%02X", manufacturer_id, + INF_MSPI_S25H_MANUFACTURER_ID); + LOG_ERR("Read device id: 0x%04X. Expected: 0x%04X", device_id, + INF_MSPI_S25H_DEVICE_ID); + return -EIO; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_switch_to_quad_transfer(const struct device *dev) +{ + int ret; + struct flash_mspi_infineon_s25h_data *data = dev->data; + + uint8_t cfg_value; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1, + &cfg_value, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading flash register"); + return ret; + } + + cfg_value |= INF_MSPI_S25H_CFG_1_QUADIT_BIT; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1, + &cfg_value, 0, MSPI_TX); + if (ret < 0) { + LOG_ERR("Error writing flash register"); + return ret; + } + + /* set address + data to 4 lanes */ + data->mspi_dev_cfg.io_mode = MSPI_IO_MODE_QUAD_1_4_4; + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + + if (ret < 0) { + LOG_ERR("Error switching MSPI mode to 4 lane data width"); + return ret; + } + + data->read_flash_cmd = INF_MSPI_S25H_OPCODE_READ_FLASH_QUAD; + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1, + &cfg_value, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading flash register"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + LOG_ERR("JEDEC ID mismatch after switching to 4 lane MSPI. Communication is " + "broken"); + return ret; + } + + /* set command to 4 lanes */ + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_2, + &cfg_value, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading flash register"); + return ret; + } + + cfg_value |= INF_MSPI_S25H_CFG_2_QPI_IT_BIT; + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_2, + &cfg_value, 0, MSPI_TX); + if (ret < 0) { + LOG_ERR("Error writing flash register"); + return ret; + } + + data->mspi_dev_cfg.io_mode = MSPI_IO_MODE_QUAD; + data->read_jedec_cmd = INF_MSPI_S25H_OPCODE_READ_JEDEC_ID_QUAD; + data->read_flash_dummy_cycles = INF_MSPI_S25H_DELAY_READ_QUADSPI; + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error switching bus mode to full quad MSPI mode"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + LOG_ERR("JEDEC ID mismatch after switching to full quad MSPI mode. Communication " + "is broken"); + return ret; + } + + return 0; +} + static int flash_mspi_infineon_s25h_init(const struct device *dev) { int ret = 0; @@ -514,28 +647,11 @@ static int flash_mspi_infineon_s25h_init(const struct device *dev) return ret; } - uint8_t id[3]; - - ret = flash_mspi_infineon_s25h_read_jedec_id(dev, id); + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); if (ret < 0) { - LOG_ERR("Error reading JEDEC ids from flash"); return ret; } - uint8_t manufacturer_id = id[0]; - uint16_t device_id = (id[1] << 8) | id[2]; - - if (manufacturer_id != INF_MSPI_S25H_MANUFACTURER_ID || - device_id != INF_MSPI_S25H_DEVICE_ID) { - LOG_ERR("Rear JEDEC ids don't match expected ids. The communication is possibly " - "broken or the non-volatile flash configuration is something unexpected"); - LOG_ERR("Read manufacturer id: 0x%02X. Expected: 0x%02X", manufacturer_id, - INF_MSPI_S25H_MANUFACTURER_ID); - LOG_ERR("Read device id: 0x%04X. Expected: 0x%04X", device_id, - INF_MSPI_S25H_DEVICE_ID); - return -EIO; - } - /* This driver needs the hybrid sector mode to be disabled. So if it's found to be turned on * it gets changed. This requires changing the non-volatile configuration and also a reset */ @@ -594,6 +710,11 @@ static int flash_mspi_infineon_s25h_init(const struct device *dev) } } + ret = flash_mspi_infineon_s25h_switch_to_quad_transfer(dev); + if (ret < 0) { + return ret; + } + return 0; } @@ -638,9 +759,13 @@ static DEVICE_API(flash, flash_mspi_infineon_s25h_driver_api) = { { \ .dev_idx = DT_REG_ADDR(DT_DRV_INST(n)), \ }, \ + }; \ + static struct flash_mspi_infineon_s25h_data flash_mspi_infineon_s25h_data_##n = { \ .mspi_dev_cfg = MSPI_DEVICE_CONFIG_DT_INST(n), \ + .read_jedec_cmd = INF_MSPI_S25H_OPCODE_READ_JEDEC_ID, \ + .read_flash_cmd = INF_MSPI_S25H_OPCODE_READ_FLASH, \ + .read_flash_dummy_cycles = 0, \ }; \ - static struct flash_mspi_infineon_s25h_data flash_mspi_infineon_s25h_data_##n = {}; \ DEVICE_DT_INST_DEFINE(n, flash_mspi_infineon_s25h_init, NULL, \ &flash_mspi_infineon_s25h_data_##n, \ &flash_mspi_infineon_s25h_cfg_##n, POST_KERNEL, \ diff --git a/drivers/flash/flash_mspi_infineon_s25h.h b/drivers/flash/flash_mspi_infineon_s25h.h index b049731919b8..987bbd842db1 100644 --- a/drivers/flash/flash_mspi_infineon_s25h.h +++ b/drivers/flash/flash_mspi_infineon_s25h.h @@ -13,7 +13,7 @@ /* defaults */ #define INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT 100 -/* opcodes */ +/* opcodes 1-1-1 mode */ #define INF_MSPI_S25H_OPCODE_WRITE_ENABLE 0x06 #define INF_MSPI_S25H_OPCODE_WRITE_DISABLE 0x04 @@ -29,6 +29,14 @@ #define INF_MSPI_S25H_OPCODE_READ_JEDEC_ID 0x9F +/* opcodes 4-4-4 mode */ +#define INF_MSPI_S25H_OPCODE_READ_FLASH_QUAD 0xEB +#define INF_MSPI_S25H_OPCODE_READ_JEDEC_ID_QUAD 0xAF + +/* RX delay */ +/* 2 cycles for the mode bit to be ignored in Quad SPI mode */ +#define INF_MSPI_S25H_DELAY_READ_QUADSPI 2 + /* addresses */ #define INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1 0x00800000 #define INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_2 0x00800001 From acf91f78623e47d83834493413fd04c8a2ce683c Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 17 Mar 2025 14:35:42 +0100 Subject: [PATCH 19/20] drivers: mtd: s25h: move hybrid sectore code in own function The Infineon S25H driver requires the hybrid sectory architecture to be disabled. For better readability this code has been moved into an own function that is now called from the init function Signed-off-by: Mika Braunschweig --- drivers/flash/flash_mspi_infineon_s25h.c | 67 ++++++++++++++---------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/drivers/flash/flash_mspi_infineon_s25h.c b/drivers/flash/flash_mspi_infineon_s25h.c index da2ba6732f62..0adc9090a645 100644 --- a/drivers/flash/flash_mspi_infineon_s25h.c +++ b/drivers/flash/flash_mspi_infineon_s25h.c @@ -623,38 +623,12 @@ static int flash_mspi_infineon_s25h_switch_to_quad_transfer(const struct device return 0; } -static int flash_mspi_infineon_s25h_init(const struct device *dev) +static int flash_mspi_infineon_s25h_disable_hybrid_sector_mode(const struct device *dev) { - int ret = 0; - const struct flash_mspi_infineon_s25h_cfg *config = dev->config; - - ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); - if (ret < 0) { - LOG_ERR("Failed to apply pinctrl"); - return ret; - } - - ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); - if (ret < 0) { - LOG_ERR("Error switching MSPI configuration to the requirements of the flash " - "device"); - return ret; - } - - ret = flash_mspi_infineon_s25h_reset(dev); - if (ret < 0) { - LOG_ERR("Error resetting flash device"); - return ret; - } - - ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); - if (ret < 0) { - return ret; - } - /* This driver needs the hybrid sector mode to be disabled. So if it's found to be turned on * it gets changed. This requires changing the non-volatile configuration and also a reset */ + int ret = 0; uint8_t conf3 = 0; ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_3, @@ -710,6 +684,43 @@ static int flash_mspi_infineon_s25h_init(const struct device *dev) } } + return 0; +} + +static int flash_mspi_infineon_s25h_init(const struct device *dev) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to apply pinctrl"); + return ret; + } + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error switching MSPI configuration to the requirements of the flash " + "device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_reset(dev); + if (ret < 0) { + LOG_ERR("Error resetting flash device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + return ret; + } + + ret = flash_mspi_infineon_s25h_disable_hybrid_sector_mode(dev); + if (ret < 0) { + return ret; + } + ret = flash_mspi_infineon_s25h_switch_to_quad_transfer(dev); if (ret < 0) { return ret; From 09a1c7c8c6cb6a5904cb670931d418a4570c6634 Mon Sep 17 00:00:00 2001 From: Mika Braunschweig Date: Mon, 17 Mar 2025 13:46:56 +0100 Subject: [PATCH 20/20] drivers: mtd: s25h: automatically enter 4 byte address mode To be able to address the full flash memory it's required to enter the 4 byte address mode. This is now done automatically during startup Signed-off-by: Mika Braunschweig --- drivers/flash/flash_mspi_infineon_s25h.c | 48 ++++++++++++++++++++++++ drivers/flash/flash_mspi_infineon_s25h.h | 5 ++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/flash/flash_mspi_infineon_s25h.c b/drivers/flash/flash_mspi_infineon_s25h.c index 0adc9090a645..518137307d09 100644 --- a/drivers/flash/flash_mspi_infineon_s25h.c +++ b/drivers/flash/flash_mspi_infineon_s25h.c @@ -687,6 +687,49 @@ static int flash_mspi_infineon_s25h_disable_hybrid_sector_mode(const struct devi return 0; } +static int flash_mspi_infineon_s25h_enter_4_byte_address_mode(const struct device *dev) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *data = dev->data; + + const struct mspi_xfer_packet enter_4_byte_cmd = { + .dir = MSPI_TX, + .cmd = INF_MSPI_S25H_OPCODE_ENABLE_4_BYTE_ADDR_MODE, + .num_bytes = 0, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .rx_dummy = 0, + .addr_length = 0, + .num_packet = 1, + .packets = &enter_4_byte_cmd, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer); + if (ret < 0) { + LOG_ERR("Error sending command to enter 4 byte address mode"); + return ret; + } + + data->mspi_dev_cfg.addr_length = 4; + + if (ret < 0) { + LOG_ERR("Error setting up MSPI bus after changing address length"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + LOG_ERR("Error verifying JEDEC id after entering 4 byte address mode"); + return ret; + } + + return 0; +} + static int flash_mspi_infineon_s25h_init(const struct device *dev) { int ret = 0; @@ -721,6 +764,11 @@ static int flash_mspi_infineon_s25h_init(const struct device *dev) return ret; } + ret = flash_mspi_infineon_s25h_enter_4_byte_address_mode(dev); + if (ret < 0) { + return ret; + } + ret = flash_mspi_infineon_s25h_switch_to_quad_transfer(dev); if (ret < 0) { return ret; diff --git a/drivers/flash/flash_mspi_infineon_s25h.h b/drivers/flash/flash_mspi_infineon_s25h.h index 987bbd842db1..23ad0075e9ea 100644 --- a/drivers/flash/flash_mspi_infineon_s25h.h +++ b/drivers/flash/flash_mspi_infineon_s25h.h @@ -14,8 +14,9 @@ #define INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT 100 /* opcodes 1-1-1 mode */ -#define INF_MSPI_S25H_OPCODE_WRITE_ENABLE 0x06 -#define INF_MSPI_S25H_OPCODE_WRITE_DISABLE 0x04 +#define INF_MSPI_S25H_OPCODE_WRITE_ENABLE 0x06 +#define INF_MSPI_S25H_OPCODE_WRITE_DISABLE 0x04 +#define INF_MSPI_S25H_OPCODE_ENABLE_4_BYTE_ADDR_MODE 0xB7 #define INF_MSPI_S25H_OPCODE_READ_ANY_REGISTER 0x65 #define INF_MSPI_S25H_OPCODE_WRITE_ANY_REGISTER 0x71