diff --git a/drivers/clock_control/clock_control_silabs_siwx91x.c b/drivers/clock_control/clock_control_silabs_siwx91x.c index 795b8aa5fc1..2c8bdcd7c0b 100644 --- a/drivers/clock_control/clock_control_silabs_siwx91x.c +++ b/drivers/clock_control/clock_control_silabs_siwx91x.c @@ -82,6 +82,9 @@ static int siwx91x_clock_on(const struct device *dev, clock_control_subsys_t sys RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI); RSI_CLK_GspiClkConfig(M4CLK, GSPI_INTF_PLL_CLK); break; + case SIWX91X_CLK_QSPI: + RSI_CLK_Qspi2ClkConfig(M4CLK, QSPI_ULPREFCLK, 0, 0, 0); + break; default: return -EINVAL; } diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index 31b36f1adc2..c1ec964e427 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -20,6 +20,7 @@ zephyr_library_include_directories_ifdef(CONFIG_MEMC_MSPI_APS6404L ${ZEPHYR_BASE zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_S32_QSPI memc_nxp_s32_qspi.c) zephyr_library_sources_ifdef(CONFIG_MEMC_RENESAS_RA_SDRAM memc_renesas_ra_sdram.c) zephyr_library_sources_ifdef(CONFIG_MEMC_SAM_SMC memc_sam_smc.c) +zephyr_library_sources_ifdef(CONFIG_MEMC_SILABS_SIWX91X_QSPI memc_silabs_siwx91x_qspi.c) zephyr_library_sources_ifdef(CONFIG_MEMC_SMARTBOND memc_smartbond_nor_psram.c) zephyr_library_sources_ifdef(CONFIG_MEMC_STM32 memc_stm32.c) zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_NOR_PSRAM memc_stm32_nor_psram.c) diff --git a/drivers/memc/Kconfig b/drivers/memc/Kconfig index 2dbd2f9b3f9..07eb8103420 100644 --- a/drivers/memc/Kconfig +++ b/drivers/memc/Kconfig @@ -26,6 +26,7 @@ source "drivers/memc/Kconfig.nxp_s32" source "drivers/memc/Kconfig.renesas_ra" source "drivers/memc/Kconfig.sam" source "drivers/memc/Kconfig.sifive" +source "drivers/memc/Kconfig.siwx91x_qspi" source "drivers/memc/Kconfig.smartbond" source "drivers/memc/Kconfig.stm32" # zephyr-keep-sorted-stop diff --git a/drivers/memc/Kconfig.siwx91x_qspi b/drivers/memc/Kconfig.siwx91x_qspi new file mode 100644 index 00000000000..ffecef247a3 --- /dev/null +++ b/drivers/memc/Kconfig.siwx91x_qspi @@ -0,0 +1,18 @@ +# Copyright (c) 2025 Silicon Laboratories Inc. +# SPDX-License-Identifier: Apache-2.0 + +config MEMC_SILABS_SIWX91X_QSPI + bool "Silabs SiWx91x QSPI memory controller" + default y + depends on DT_HAS_SILABS_SIWX91X_QSPI_MEMORY_ENABLED + select PINCTRL + help + Enable Silabs SiWx91x QSPI (Quad Serial Peripheral Interface) memory + controller. + + If you want to rely on the linker to place symbols in this memory + (using`zephyr_code_relocate() or Z_GENERIC_SECTION()), you have to + ensure this driver in initialized before KERNEL_INIT_PRIORITY_OBJECTS + (=30). In addition, this driver may depends on a clock. Then, you have + to ensure the clock will be started before this driver (see + CLOCK_CONTROL_INIT_PRIORITY) diff --git a/drivers/memc/memc_silabs_siwx91x_qspi.c b/drivers/memc/memc_silabs_siwx91x_qspi.c new file mode 100644 index 00000000000..b3aa6e99ffb --- /dev/null +++ b/drivers/memc/memc_silabs_siwx91x_qspi.c @@ -0,0 +1,122 @@ +/* Copyright (c) 2025 Silicon Laboratories Inc. + * SPDX-License-Identifier: Apache-2.0 + */ +#define DT_DRV_COMPAT silabs_siwx91x_qspi_memory +#include +#include +#include + +#include +#include +#include + +#include "rsi_qspi_proto.h" +#include "sl_si91x_psram_handle.h" + +LOG_MODULE_REGISTER(siwx91x_memc, CONFIG_MEMC_LOG_LEVEL); + +struct siwx91x_memc_config { + qspi_reg_t *reg; + const struct device *clock_dev; + clock_control_subsys_t clock_subsys; + const struct pinctrl_dev_config *pincfg; +}; + +static int siwx91x_memc_init(const struct device *dev) +{ + const struct siwx91x_memc_config *config = dev->config; + int ret; + + /* Memory controller is automatically setup by the siwx91x bootloader, + * so we have to uninitialize it before to change the configuration + */ + ret = sl_si91x_psram_uninit(); + if (ret) { + return -EIO; + } + + ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + if (ret) { + return -EIO; + } + if (config->clock_dev) { + ret = device_is_ready(config->clock_dev); + if (!ret) { + return -EINVAL; + } + ret = clock_control_on(config->clock_dev, config->clock_subsys); + if (ret && ret != -EALREADY && ret != -ENOSYS) { + return ret; + } + } + + ret = sl_si91x_psram_init(); + if (ret) { + LOG_ERR("sl_si91x_psram_init() returned %d", ret); + return -EIO; + } + + return 0; +} + +PINCTRL_DT_INST_DEFINE(0); +static const struct siwx91x_memc_config siwx91x_memc_config = { + .reg = (void *)DT_INST_REG_ADDR(0), + .clock_dev = DEVICE_DT_GET_OR_NULL(DT_INST_CLOCKS_CTLR(0)), + .clock_subsys = (void *)DT_INST_PHA_OR(0, clocks, clkid, NULL), + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0), +}; +/* Required to properly initialize ,deviceID */ +static const uint8_t devid[] = DT_INST_PROP(0, device_id); + +/* PSRAM_Device is directly referenced by sl_si91x_psram_init() */ +struct sl_psram_info_type_t PSRAM_Device = { + .deviceID.MFID = devid[0], + .deviceID.KGD = devid[1], + .deviceID.EID = { devid[2], devid[3], devid[4], devid[5], devid[6], devid[7] }, + /* FIXME: Currently, the Chip Select (.cs_no property) and the RAM start + * address are hard coded. The hardware also support Chip Select == 1, + * then RAM start address will be 0xb000000. + */ + .devDensity = DT_REG_SIZE(DT_INST_CHILD(0, psram_a000000)), + .normalReadMAXFrequency = DT_INST_PROP(0, normal_freq), + .fastReadMAXFrequency = DT_INST_PROP(0, fast_freq), + .rwType = QUAD_RW, + .defaultBurstWrapSize = 1024, + .toggleBurstWrapSize = 0, + .spi_config.spi_config_2.auto_mode = 1, + /* FIXME: user may want to customize these values */ + .spi_config.spi_config_1.read_cmd = 0xEB, + .spi_config.spi_config_3.wr_cmd = 0x38, + .spi_config.spi_config_1.extra_byte_mode = QUAD_MODE, + .spi_config.spi_config_1.dummy_mode = QUAD_MODE, + .spi_config.spi_config_1.addr_mode = QUAD_MODE, + .spi_config.spi_config_1.data_mode = QUAD_MODE, + .spi_config.spi_config_1.inst_mode = QUAD_MODE, + .spi_config.spi_config_3.wr_addr_mode = QUAD_MODE, + .spi_config.spi_config_3.wr_data_mode = QUAD_MODE, + .spi_config.spi_config_3.wr_inst_mode = QUAD_MODE, + .spi_config.spi_config_2.wrap_len_in_bytes = NO_WRAP, + .spi_config.spi_config_2.swap_en = 1, + .spi_config.spi_config_2.addr_width = 3, /* 24 bits */ + .spi_config.spi_config_2.cs_no = 0, + .spi_config.spi_config_4.secondary_csn = 1, + .spi_config.spi_config_2.neg_edge_sampling = 1, + .spi_config.spi_config_1.no_of_dummy_bytes = 3, + .spi_config.spi_config_1.dummy_W_or_R = DUMMY_READS, + .spi_config.spi_config_2.full_duplex = IGNORE_FULL_DUPLEX, + .spi_config.spi_config_2.qspi_clk_en = QSPI_FULL_TIME_CLK, + .spi_config.spi_config_1.flash_type = 0xf, + .spi_config.spi_config_3.dummys_4_jump = 1, + .spi_config.spi_config_4.valid_prot_bits = 4, + .spi_config.spi_config_1.d3d2_data = 0x03, + .spi_config.spi_config_5.d7_d4_data = 0x0f, +}; +/* PSRAMSecureSegments is directly referenced by sl_si91x_psram_init() */ +struct PSRAMSecureSegmentType PSRAMSecureSegments[MAX_SEC_SEGMENTS] = { + [0].segmentEnable = 1, + [0].lowerBoundary = 0x00000, + [0].higherBoundary = 0x0ffff, +}; +DEVICE_DT_INST_DEFINE(0, siwx91x_memc_init, NULL, NULL, &siwx91x_memc_config, + PRE_KERNEL_1, CONFIG_MEMC_INIT_PRIORITY, NULL); diff --git a/dts/bindings/memory-controllers/silabs,siwx91x-qspi-memory.yaml b/dts/bindings/memory-controllers/silabs,siwx91x-qspi-memory.yaml new file mode 100644 index 00000000000..d0cecbe3ca0 --- /dev/null +++ b/dts/bindings/memory-controllers/silabs,siwx91x-qspi-memory.yaml @@ -0,0 +1,44 @@ +description: | + Silicon Labs QSPI (Quad Serial Protocol Interface) memory controller. + + This driver expects a children node compatible with "zephyr,memory-region". + The size of the PSRAM is taken from this node. It also used by Zephyr to + declare the area in the linker script. + + Note after the chip reset, the bootloader may automatically configure the + Memory Controller. So, the user may be able to properly use the PSRAM without + this driver (in this case, only the "zephyr,memory-region" node is required). + + This driver allows for non default configurations. In this case, if the users + want to take advantage of the automatic data relocation of Zephyr, they have + to tune the MEMC_INIT_PRIORITY value to initialize this driver before the + initialization of the kernel resources. Then, they will probably want to also + initialize the clock driver before this driver. + + Otherwise, it is also possible to start this driver later in the boot + sequence, but the user will have to manage the memory region manually. + +include: [base.yaml, pinctrl-device.yaml] + +compatible: "silabs,siwx91x-qspi-memory" + +properties: + reg: + required: true + + device-id: + type: uint8-array + required: true + description: | + Value returned by the chip on READ_ID command. An array of 8 bytes is + expected. However only the two first bytes (should be "Manufacturer ID" + and "Known Good Die") are used. The driver won't continue if the value + returned by the chip does not match this field. + + normal-freq: + type: int + required: true + + fast-freq: + type: int + required: true diff --git a/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h b/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h index 199053a6c72..9c47ccab519 100644 --- a/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h +++ b/include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h @@ -14,6 +14,7 @@ #define SIWX91X_CLK_DMA0 7 #define SIWX91X_CLK_WATCHDOG 8 #define SIWX91X_CLK_PWM 9 -#define SIWX91X_CLK_GSPI 10 +#define SIWX91X_CLK_GSPI 10 +#define SIWX91X_CLK_QSPI 11 #endif diff --git a/modules/hal_silabs/wiseconnect/CMakeLists.txt b/modules/hal_silabs/wiseconnect/CMakeLists.txt index b9aaffd16e6..db7fe9c3d6a 100644 --- a/modules/hal_silabs/wiseconnect/CMakeLists.txt +++ b/modules/hal_silabs/wiseconnect/CMakeLists.txt @@ -69,6 +69,11 @@ zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/rom_driver/src/rsi_rom_table_si91x.c ) +zephyr_library_sources_ifdef(CONFIG_MEMC_SILABS_SIWX91X_QSPI + ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_psram.c + ${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_qspi.c +) + if(CONFIG_WIFI_SILABS_SIWX91X) zephyr_library_sources( ${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/sl_net/src/sl_si91x_net_internal_stack.c diff --git a/west.yml b/west.yml index 406df5b8cd5..2e4c62339c8 100644 --- a/west.yml +++ b/west.yml @@ -235,7 +235,7 @@ manifest: groups: - hal - name: hal_silabs - revision: 15994d76eac4be404825fbef35a1ef1a42e4fc50 + revision: 389726f350880238b9a1034f575ffd46c4309827 path: modules/hal/silabs groups: - hal