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>
This commit is contained in:
parent
91e3f78837
commit
1d4a0d78e3
9 changed files with 197 additions and 2 deletions
|
@ -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_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
|
||||||
RSI_CLK_GspiClkConfig(M4CLK, GSPI_INTF_PLL_CLK);
|
RSI_CLK_GspiClkConfig(M4CLK, GSPI_INTF_PLL_CLK);
|
||||||
break;
|
break;
|
||||||
|
case SIWX91X_CLK_QSPI:
|
||||||
|
RSI_CLK_Qspi2ClkConfig(M4CLK, QSPI_ULPREFCLK, 0, 0, 0);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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_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_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_SMARTBOND memc_smartbond_nor_psram.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_MEMC_STM32 memc_stm32.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)
|
zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_NOR_PSRAM memc_stm32_nor_psram.c)
|
||||||
|
|
|
@ -26,6 +26,7 @@ source "drivers/memc/Kconfig.nxp_s32"
|
||||||
source "drivers/memc/Kconfig.renesas_ra"
|
source "drivers/memc/Kconfig.renesas_ra"
|
||||||
source "drivers/memc/Kconfig.sam"
|
source "drivers/memc/Kconfig.sam"
|
||||||
source "drivers/memc/Kconfig.sifive"
|
source "drivers/memc/Kconfig.sifive"
|
||||||
|
source "drivers/memc/Kconfig.siwx91x_qspi"
|
||||||
source "drivers/memc/Kconfig.smartbond"
|
source "drivers/memc/Kconfig.smartbond"
|
||||||
source "drivers/memc/Kconfig.stm32"
|
source "drivers/memc/Kconfig.stm32"
|
||||||
# zephyr-keep-sorted-stop
|
# zephyr-keep-sorted-stop
|
||||||
|
|
18
drivers/memc/Kconfig.siwx91x_qspi
Normal file
18
drivers/memc/Kconfig.siwx91x_qspi
Normal file
|
@ -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
Normal file
122
drivers/memc/memc_silabs_siwx91x_qspi.c
Normal file
|
@ -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);
|
|
@ -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
|
|
@ -14,6 +14,7 @@
|
||||||
#define SIWX91X_CLK_DMA0 7
|
#define SIWX91X_CLK_DMA0 7
|
||||||
#define SIWX91X_CLK_WATCHDOG 8
|
#define SIWX91X_CLK_WATCHDOG 8
|
||||||
#define SIWX91X_CLK_PWM 9
|
#define SIWX91X_CLK_PWM 9
|
||||||
#define SIWX91X_CLK_GSPI 10
|
#define SIWX91X_CLK_GSPI 10
|
||||||
|
#define SIWX91X_CLK_QSPI 11
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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
|
${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)
|
if(CONFIG_WIFI_SILABS_SIWX91X)
|
||||||
zephyr_library_sources(
|
zephyr_library_sources(
|
||||||
${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/sl_net/src/sl_si91x_net_internal_stack.c
|
${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/sl_net/src/sl_si91x_net_internal_stack.c
|
||||||
|
|
2
west.yml
2
west.yml
|
@ -235,7 +235,7 @@ manifest:
|
||||||
groups:
|
groups:
|
||||||
- hal
|
- hal
|
||||||
- name: hal_silabs
|
- name: hal_silabs
|
||||||
revision: 15994d76eac4be404825fbef35a1ef1a42e4fc50
|
revision: 389726f350880238b9a1034f575ffd46c4309827
|
||||||
path: modules/hal/silabs
|
path: modules/hal/silabs
|
||||||
groups:
|
groups:
|
||||||
- hal
|
- hal
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue