Browse Source

drivers: memc: Add support for siwx91x QSPI controller

Silabs siwx91x includes a memory controller for (Quad-)SPI PSRAM. It
allows the application to use the PSRAM as if it was any other RAM.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
pull/87786/head
Jérôme Pouiller 3 months ago committed by Benjamin Cabé
parent
commit
1d4a0d78e3
  1. 3
      drivers/clock_control/clock_control_silabs_siwx91x.c
  2. 1
      drivers/memc/CMakeLists.txt
  3. 1
      drivers/memc/Kconfig
  4. 18
      drivers/memc/Kconfig.siwx91x_qspi
  5. 122
      drivers/memc/memc_silabs_siwx91x_qspi.c
  6. 44
      dts/bindings/memory-controllers/silabs,siwx91x-qspi-memory.yaml
  7. 3
      include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h
  8. 5
      modules/hal_silabs/wiseconnect/CMakeLists.txt
  9. 2
      west.yml

3
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 @@ -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;
}

1
drivers/memc/CMakeLists.txt

@ -20,6 +20,7 @@ zephyr_library_include_directories_ifdef(CONFIG_MEMC_MSPI_APS6404L ${ZEPHYR_BASE @@ -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)

1
drivers/memc/Kconfig

@ -26,6 +26,7 @@ source "drivers/memc/Kconfig.nxp_s32" @@ -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

18
drivers/memc/Kconfig.siwx91x_qspi

@ -0,0 +1,18 @@ @@ -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)

122
drivers/memc/memc_silabs_siwx91x_qspi.c

@ -0,0 +1,122 @@ @@ -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 <zephyr/logging/log.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/sys/util.h>
#include <zephyr/device.h>
#include <zephyr/kernel.h>
#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);

44
dts/bindings/memory-controllers/silabs,siwx91x-qspi-memory.yaml

@ -0,0 +1,44 @@ @@ -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

3
include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h

@ -14,6 +14,7 @@ @@ -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

5
modules/hal_silabs/wiseconnect/CMakeLists.txt

@ -69,6 +69,11 @@ zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X @@ -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

2
west.yml

@ -235,7 +235,7 @@ manifest: @@ -235,7 +235,7 @@ manifest:
groups:
- hal
- name: hal_silabs
revision: 15994d76eac4be404825fbef35a1ef1a42e4fc50
revision: 389726f350880238b9a1034f575ffd46c4309827
path: modules/hal/silabs
groups:
- hal

Loading…
Cancel
Save