Skip to content

Commit 1d4a0d7

Browse files
jerome-pouillerkartben
authored andcommitted
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>
1 parent 91e3f78 commit 1d4a0d7

File tree

9 files changed

+197
-2
lines changed

9 files changed

+197
-2
lines changed

drivers/clock_control/clock_control_silabs_siwx91x.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ static int siwx91x_clock_on(const struct device *dev, clock_control_subsys_t sys
8282
RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
8383
RSI_CLK_GspiClkConfig(M4CLK, GSPI_INTF_PLL_CLK);
8484
break;
85+
case SIWX91X_CLK_QSPI:
86+
RSI_CLK_Qspi2ClkConfig(M4CLK, QSPI_ULPREFCLK, 0, 0, 0);
87+
break;
8588
default:
8689
return -EINVAL;
8790
}

drivers/memc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ zephyr_library_include_directories_ifdef(CONFIG_MEMC_MSPI_APS6404L ${ZEPHYR_BASE
2020
zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_S32_QSPI memc_nxp_s32_qspi.c)
2121
zephyr_library_sources_ifdef(CONFIG_MEMC_RENESAS_RA_SDRAM memc_renesas_ra_sdram.c)
2222
zephyr_library_sources_ifdef(CONFIG_MEMC_SAM_SMC memc_sam_smc.c)
23+
zephyr_library_sources_ifdef(CONFIG_MEMC_SILABS_SIWX91X_QSPI memc_silabs_siwx91x_qspi.c)
2324
zephyr_library_sources_ifdef(CONFIG_MEMC_SMARTBOND memc_smartbond_nor_psram.c)
2425
zephyr_library_sources_ifdef(CONFIG_MEMC_STM32 memc_stm32.c)
2526
zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_NOR_PSRAM memc_stm32_nor_psram.c)

drivers/memc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ source "drivers/memc/Kconfig.nxp_s32"
2626
source "drivers/memc/Kconfig.renesas_ra"
2727
source "drivers/memc/Kconfig.sam"
2828
source "drivers/memc/Kconfig.sifive"
29+
source "drivers/memc/Kconfig.siwx91x_qspi"
2930
source "drivers/memc/Kconfig.smartbond"
3031
source "drivers/memc/Kconfig.stm32"
3132
# zephyr-keep-sorted-stop

drivers/memc/Kconfig.siwx91x_qspi

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright (c) 2025 Silicon Laboratories Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config MEMC_SILABS_SIWX91X_QSPI
5+
bool "Silabs SiWx91x QSPI memory controller"
6+
default y
7+
depends on DT_HAS_SILABS_SIWX91X_QSPI_MEMORY_ENABLED
8+
select PINCTRL
9+
help
10+
Enable Silabs SiWx91x QSPI (Quad Serial Peripheral Interface) memory
11+
controller.
12+
13+
If you want to rely on the linker to place symbols in this memory
14+
(using`zephyr_code_relocate() or Z_GENERIC_SECTION()), you have to
15+
ensure this driver in initialized before KERNEL_INIT_PRIORITY_OBJECTS
16+
(=30). In addition, this driver may depends on a clock. Then, you have
17+
to ensure the clock will be started before this driver (see
18+
CLOCK_CONTROL_INIT_PRIORITY)
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/* Copyright (c) 2025 Silicon Laboratories Inc.
2+
* SPDX-License-Identifier: Apache-2.0
3+
*/
4+
#define DT_DRV_COMPAT silabs_siwx91x_qspi_memory
5+
#include <zephyr/logging/log.h>
6+
#include <zephyr/drivers/clock_control.h>
7+
#include <zephyr/drivers/pinctrl.h>
8+
9+
#include <zephyr/sys/util.h>
10+
#include <zephyr/device.h>
11+
#include <zephyr/kernel.h>
12+
13+
#include "rsi_qspi_proto.h"
14+
#include "sl_si91x_psram_handle.h"
15+
16+
LOG_MODULE_REGISTER(siwx91x_memc, CONFIG_MEMC_LOG_LEVEL);
17+
18+
struct siwx91x_memc_config {
19+
qspi_reg_t *reg;
20+
const struct device *clock_dev;
21+
clock_control_subsys_t clock_subsys;
22+
const struct pinctrl_dev_config *pincfg;
23+
};
24+
25+
static int siwx91x_memc_init(const struct device *dev)
26+
{
27+
const struct siwx91x_memc_config *config = dev->config;
28+
int ret;
29+
30+
/* Memory controller is automatically setup by the siwx91x bootloader,
31+
* so we have to uninitialize it before to change the configuration
32+
*/
33+
ret = sl_si91x_psram_uninit();
34+
if (ret) {
35+
return -EIO;
36+
}
37+
38+
ret = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
39+
if (ret) {
40+
return -EIO;
41+
}
42+
if (config->clock_dev) {
43+
ret = device_is_ready(config->clock_dev);
44+
if (!ret) {
45+
return -EINVAL;
46+
}
47+
ret = clock_control_on(config->clock_dev, config->clock_subsys);
48+
if (ret && ret != -EALREADY && ret != -ENOSYS) {
49+
return ret;
50+
}
51+
}
52+
53+
ret = sl_si91x_psram_init();
54+
if (ret) {
55+
LOG_ERR("sl_si91x_psram_init() returned %d", ret);
56+
return -EIO;
57+
}
58+
59+
return 0;
60+
}
61+
62+
PINCTRL_DT_INST_DEFINE(0);
63+
static const struct siwx91x_memc_config siwx91x_memc_config = {
64+
.reg = (void *)DT_INST_REG_ADDR(0),
65+
.clock_dev = DEVICE_DT_GET_OR_NULL(DT_INST_CLOCKS_CTLR(0)),
66+
.clock_subsys = (void *)DT_INST_PHA_OR(0, clocks, clkid, NULL),
67+
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
68+
};
69+
/* Required to properly initialize ,deviceID */
70+
static const uint8_t devid[] = DT_INST_PROP(0, device_id);
71+
72+
/* PSRAM_Device is directly referenced by sl_si91x_psram_init() */
73+
struct sl_psram_info_type_t PSRAM_Device = {
74+
.deviceID.MFID = devid[0],
75+
.deviceID.KGD = devid[1],
76+
.deviceID.EID = { devid[2], devid[3], devid[4], devid[5], devid[6], devid[7] },
77+
/* FIXME: Currently, the Chip Select (.cs_no property) and the RAM start
78+
* address are hard coded. The hardware also support Chip Select == 1,
79+
* then RAM start address will be 0xb000000.
80+
*/
81+
.devDensity = DT_REG_SIZE(DT_INST_CHILD(0, psram_a000000)),
82+
.normalReadMAXFrequency = DT_INST_PROP(0, normal_freq),
83+
.fastReadMAXFrequency = DT_INST_PROP(0, fast_freq),
84+
.rwType = QUAD_RW,
85+
.defaultBurstWrapSize = 1024,
86+
.toggleBurstWrapSize = 0,
87+
.spi_config.spi_config_2.auto_mode = 1,
88+
/* FIXME: user may want to customize these values */
89+
.spi_config.spi_config_1.read_cmd = 0xEB,
90+
.spi_config.spi_config_3.wr_cmd = 0x38,
91+
.spi_config.spi_config_1.extra_byte_mode = QUAD_MODE,
92+
.spi_config.spi_config_1.dummy_mode = QUAD_MODE,
93+
.spi_config.spi_config_1.addr_mode = QUAD_MODE,
94+
.spi_config.spi_config_1.data_mode = QUAD_MODE,
95+
.spi_config.spi_config_1.inst_mode = QUAD_MODE,
96+
.spi_config.spi_config_3.wr_addr_mode = QUAD_MODE,
97+
.spi_config.spi_config_3.wr_data_mode = QUAD_MODE,
98+
.spi_config.spi_config_3.wr_inst_mode = QUAD_MODE,
99+
.spi_config.spi_config_2.wrap_len_in_bytes = NO_WRAP,
100+
.spi_config.spi_config_2.swap_en = 1,
101+
.spi_config.spi_config_2.addr_width = 3, /* 24 bits */
102+
.spi_config.spi_config_2.cs_no = 0,
103+
.spi_config.spi_config_4.secondary_csn = 1,
104+
.spi_config.spi_config_2.neg_edge_sampling = 1,
105+
.spi_config.spi_config_1.no_of_dummy_bytes = 3,
106+
.spi_config.spi_config_1.dummy_W_or_R = DUMMY_READS,
107+
.spi_config.spi_config_2.full_duplex = IGNORE_FULL_DUPLEX,
108+
.spi_config.spi_config_2.qspi_clk_en = QSPI_FULL_TIME_CLK,
109+
.spi_config.spi_config_1.flash_type = 0xf,
110+
.spi_config.spi_config_3.dummys_4_jump = 1,
111+
.spi_config.spi_config_4.valid_prot_bits = 4,
112+
.spi_config.spi_config_1.d3d2_data = 0x03,
113+
.spi_config.spi_config_5.d7_d4_data = 0x0f,
114+
};
115+
/* PSRAMSecureSegments is directly referenced by sl_si91x_psram_init() */
116+
struct PSRAMSecureSegmentType PSRAMSecureSegments[MAX_SEC_SEGMENTS] = {
117+
[0].segmentEnable = 1,
118+
[0].lowerBoundary = 0x00000,
119+
[0].higherBoundary = 0x0ffff,
120+
};
121+
DEVICE_DT_INST_DEFINE(0, siwx91x_memc_init, NULL, NULL, &siwx91x_memc_config,
122+
PRE_KERNEL_1, CONFIG_MEMC_INIT_PRIORITY, NULL);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
description: |
2+
Silicon Labs QSPI (Quad Serial Protocol Interface) memory controller.
3+
4+
This driver expects a children node compatible with "zephyr,memory-region".
5+
The size of the PSRAM is taken from this node. It also used by Zephyr to
6+
declare the area in the linker script.
7+
8+
Note after the chip reset, the bootloader may automatically configure the
9+
Memory Controller. So, the user may be able to properly use the PSRAM without
10+
this driver (in this case, only the "zephyr,memory-region" node is required).
11+
12+
This driver allows for non default configurations. In this case, if the users
13+
want to take advantage of the automatic data relocation of Zephyr, they have
14+
to tune the MEMC_INIT_PRIORITY value to initialize this driver before the
15+
initialization of the kernel resources. Then, they will probably want to also
16+
initialize the clock driver before this driver.
17+
18+
Otherwise, it is also possible to start this driver later in the boot
19+
sequence, but the user will have to manage the memory region manually.
20+
21+
include: [base.yaml, pinctrl-device.yaml]
22+
23+
compatible: "silabs,siwx91x-qspi-memory"
24+
25+
properties:
26+
reg:
27+
required: true
28+
29+
device-id:
30+
type: uint8-array
31+
required: true
32+
description: |
33+
Value returned by the chip on READ_ID command. An array of 8 bytes is
34+
expected. However only the two first bytes (should be "Manufacturer ID"
35+
and "Known Good Die") are used. The driver won't continue if the value
36+
returned by the chip does not match this field.
37+
38+
normal-freq:
39+
type: int
40+
required: true
41+
42+
fast-freq:
43+
type: int
44+
required: true

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SIWX91X_CLK_DMA0 7
1515
#define SIWX91X_CLK_WATCHDOG 8
1616
#define SIWX91X_CLK_PWM 9
17-
#define SIWX91X_CLK_GSPI 10
17+
#define SIWX91X_CLK_GSPI 10
18+
#define SIWX91X_CLK_QSPI 11
1819

1920
#endif

modules/hal_silabs/wiseconnect/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ zephyr_library_sources_ifdef(CONFIG_DMA_SILABS_SIWX91X
6969
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/rom_driver/src/rsi_rom_table_si91x.c
7070
)
7171

72+
zephyr_library_sources_ifdef(CONFIG_MEMC_SILABS_SIWX91X_QSPI
73+
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_psram.c
74+
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_qspi.c
75+
)
76+
7277
if(CONFIG_WIFI_SILABS_SIWX91X)
7378
zephyr_library_sources(
7479
${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/sl_net/src/sl_si91x_net_internal_stack.c

west.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ manifest:
235235
groups:
236236
- hal
237237
- name: hal_silabs
238-
revision: 15994d76eac4be404825fbef35a1ef1a42e4fc50
238+
revision: 389726f350880238b9a1034f575ffd46c4309827
239239
path: modules/hal/silabs
240240
groups:
241241
- hal

0 commit comments

Comments
 (0)