drivers: mspi: add APMemory APS Z8 pSRAM driver
The APS Z8 driver would just support APS51216BA for now. Signed-off-by: Swift Tian <swift.tian@ambiq.com>
This commit is contained in:
parent
f5b201e0d6
commit
8ef0792eec
11 changed files with 837 additions and 6 deletions
|
@ -19,4 +19,11 @@ config MSPI_INIT_PRIORITY
|
||||||
|
|
||||||
endif # MSPI
|
endif # MSPI
|
||||||
|
|
||||||
|
if MEMC
|
||||||
|
|
||||||
|
config MEMC_INIT_PRIORITY
|
||||||
|
default 50
|
||||||
|
|
||||||
|
endif # MEMC
|
||||||
|
|
||||||
endif # BOARD_APOLLO510_EVB
|
endif # BOARD_APOLLO510_EVB
|
||||||
|
|
|
@ -120,6 +120,47 @@
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
&mspi0 {
|
||||||
|
pinctrl-0 = <&mspi0_default>;
|
||||||
|
pinctrl-1 = <&mspi0_sleep>;
|
||||||
|
pinctrl-2 = <&mspi0_psram>;
|
||||||
|
pinctrl-names = "default","sleep","psram";
|
||||||
|
status = "disabled";
|
||||||
|
zephyr,pm-device-runtime-auto;
|
||||||
|
|
||||||
|
ce-gpios = <&gpio192_223 7 GPIO_ACTIVE_LOW>;
|
||||||
|
|
||||||
|
cmdq-buffer-location = "SRAM_NO_CACHE";
|
||||||
|
cmdq-buffer-size = <256>;
|
||||||
|
|
||||||
|
ambiq,apmemory;
|
||||||
|
|
||||||
|
dqs-support;
|
||||||
|
|
||||||
|
aps51216ba: aps_z8@0 {
|
||||||
|
compatible = "ambiq,mspi-device", "mspi-aps-z8";
|
||||||
|
size = <DT_SIZE_M(512)>;
|
||||||
|
reg = <0>;
|
||||||
|
status = "disabled";
|
||||||
|
mspi-max-frequency = <125000000>;
|
||||||
|
mspi-io-mode = "MSPI_IO_MODE_HEX_8_8_16";
|
||||||
|
mspi-data-rate = "MSPI_DATA_RATE_S_D_D";
|
||||||
|
mspi-hardware-ce-num = <0>;
|
||||||
|
mspi-dqs-enable;
|
||||||
|
read-command = <0x20>;
|
||||||
|
write-command = <0xA0>;
|
||||||
|
command-length = "INSTR_1_BYTE";
|
||||||
|
address-length = "ADDR_4_BYTE";
|
||||||
|
rx-dummy = <7>;
|
||||||
|
tx-dummy = <8>;
|
||||||
|
xip-config = <1 0 DT_SIZE_M(64) 0>;
|
||||||
|
ce-break-config = <1024 4>;
|
||||||
|
ambiq,timing-config-mask = <0x62>;
|
||||||
|
ambiq,timing-config = <8 7 1 0 0 3 10 0>;
|
||||||
|
zephyr,pm-device-runtime-auto;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
&gpio0_31 {
|
&gpio0_31 {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,8 @@ if((DEFINED CONFIG_FLASH_MCUX_FLEXSPI_XIP) AND (DEFINED CONFIG_FLASH))
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_MEMC_MSPI_APS6404L memc_mspi_aps6404l.c)
|
zephyr_library_sources_ifdef(CONFIG_MEMC_MSPI_APS6404L memc_mspi_aps6404l.c)
|
||||||
zephyr_library_include_directories_ifdef(CONFIG_MEMC_MSPI_APS6404L ${ZEPHYR_BASE}/drivers/mspi)
|
zephyr_library_sources_ifdef(CONFIG_MEMC_MSPI_APS_Z8 memc_mspi_aps_z8.c)
|
||||||
|
zephyr_library_include_directories_ifdef(CONFIG_MEMC_MSPI ${ZEPHYR_BASE}/drivers/mspi)
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2024, Ambiq Micro Inc. <www.ambiq.com>
|
# Copyright (c) 2025, Ambiq Micro Inc. <www.ambiq.com>
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
menu "MSPI MEMC device driver"
|
menu "MSPI MEMC device driver"
|
||||||
|
@ -16,4 +16,11 @@ config MEMC_MSPI_APS6404L
|
||||||
select MEMC_MSPI
|
select MEMC_MSPI
|
||||||
select MSPI_AMBIQ_CONTROLLER if SOC_FAMILY_AMBIQ
|
select MSPI_AMBIQ_CONTROLLER if SOC_FAMILY_AMBIQ
|
||||||
|
|
||||||
|
config MEMC_MSPI_APS_Z8
|
||||||
|
bool "MSPI AP Memory gen Z8 pSRAM driver"
|
||||||
|
default y
|
||||||
|
depends on DT_HAS_MSPI_APS_Z8_ENABLED
|
||||||
|
select MEMC_MSPI
|
||||||
|
select MSPI_AMBIQ_CONTROLLER if SOC_FAMILY_AMBIQ
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
619
drivers/memc/memc_mspi_aps_z8.c
Normal file
619
drivers/memc/memc_mspi_aps_z8.c
Normal file
|
@ -0,0 +1,619 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Ambiq Micro Inc. <www.ambiq.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT mspi_aps_z8
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/pm/device.h>
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
#include <zephyr/sys/util.h>
|
||||||
|
#include <zephyr/cache.h>
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/drivers/mspi.h>
|
||||||
|
#include <zephyr/pm/device_runtime.h>
|
||||||
|
#include "memc_mspi_aps_z8.h"
|
||||||
|
#if CONFIG_SOC_FAMILY_AMBIQ
|
||||||
|
#include "mspi_ambiq.h"
|
||||||
|
typedef struct mspi_ambiq_timing_cfg mspi_timing_cfg;
|
||||||
|
typedef enum mspi_ambiq_timing_param mspi_timing_param;
|
||||||
|
#else
|
||||||
|
typedef struct mspi_timing_cfg mspi_timing_cfg;
|
||||||
|
typedef enum mspi_timing_param mspi_timing_param;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOG_MODULE_REGISTER(memc_mspi_aps_z8, CONFIG_MEMC_LOG_LEVEL);
|
||||||
|
|
||||||
|
#define APM_VENDOR_ID 0xD
|
||||||
|
|
||||||
|
#define APS_Z8_SYNC_WRITE 0x80
|
||||||
|
#define APS_Z8_SYNC_READ 0x00
|
||||||
|
#define APS_Z8_LINEAR_BURST_WRITE 0xA0
|
||||||
|
#define APS_Z8_LINEAR_BURST_READ 0x20
|
||||||
|
#define APS_Z8_GLOBAL_RESET 0xFF
|
||||||
|
#define APS_Z8_WRITE_REGISTER 0xC0
|
||||||
|
#define APS_Z8_READ_REGISTER 0x40
|
||||||
|
|
||||||
|
struct memc_mspi_aps_z8_config {
|
||||||
|
uint32_t port;
|
||||||
|
uint32_t mem_size;
|
||||||
|
|
||||||
|
const struct device *bus;
|
||||||
|
struct mspi_dev_id dev_id;
|
||||||
|
struct mspi_dev_cfg octal_cfg;
|
||||||
|
struct mspi_dev_cfg tar_dev_cfg;
|
||||||
|
|
||||||
|
MSPI_XIP_CFG_STRUCT_DECLARE(tar_xip_cfg)
|
||||||
|
MSPI_SCRAMBLE_CFG_STRUCT_DECLARE(tar_scramble_cfg)
|
||||||
|
MSPI_TIMING_CFG_STRUCT_DECLARE(tar_timing_cfg)
|
||||||
|
MSPI_TIMING_PARAM_DECLARE(timing_cfg_mask)
|
||||||
|
|
||||||
|
bool sw_multi_periph;
|
||||||
|
bool pm_dev_rt_auto;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct memc_mspi_aps_z8_data {
|
||||||
|
struct memc_mspi_aps_z8_reg regs;
|
||||||
|
struct mspi_dev_cfg dev_cfg;
|
||||||
|
struct mspi_xip_cfg xip_cfg;
|
||||||
|
struct mspi_scramble_cfg scramble_cfg;
|
||||||
|
mspi_timing_cfg timing_cfg;
|
||||||
|
struct mspi_xfer trans;
|
||||||
|
struct mspi_xfer_packet packet;
|
||||||
|
|
||||||
|
struct k_sem lock;
|
||||||
|
uint16_t dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_command_write(const struct device *psram, uint8_t cmd,
|
||||||
|
uint32_t addr, uint8_t *wdata, uint32_t length)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
data->packet.dir = MSPI_TX;
|
||||||
|
data->packet.cmd = cmd;
|
||||||
|
data->packet.address = addr;
|
||||||
|
data->packet.data_buf = wdata;
|
||||||
|
data->packet.num_bytes = length;
|
||||||
|
|
||||||
|
data->trans.async = false;
|
||||||
|
data->trans.xfer_mode = MSPI_PIO;
|
||||||
|
data->trans.tx_dummy = 0;
|
||||||
|
data->trans.rx_dummy = data->dev_cfg.rx_dummy;
|
||||||
|
data->trans.cmd_length = data->dev_cfg.cmd_length;
|
||||||
|
data->trans.addr_length = data->dev_cfg.addr_length;
|
||||||
|
data->trans.hold_ce = false;
|
||||||
|
data->trans.packets = &data->packet;
|
||||||
|
data->trans.num_packet = 1;
|
||||||
|
data->trans.timeout = 10;
|
||||||
|
|
||||||
|
ret = mspi_transceive(cfg->bus, &cfg->dev_id, (const struct mspi_xfer *)&data->trans);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("MSPI write transaction failed with code: %d/%u", ret, __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_command_read(const struct device *psram, uint8_t cmd,
|
||||||
|
uint32_t addr, uint8_t *rdata, uint32_t length)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
data->packet.dir = MSPI_RX;
|
||||||
|
data->packet.cmd = cmd;
|
||||||
|
data->packet.address = addr;
|
||||||
|
data->packet.data_buf = rdata;
|
||||||
|
data->packet.num_bytes = length;
|
||||||
|
|
||||||
|
data->trans.async = false;
|
||||||
|
data->trans.xfer_mode = MSPI_PIO;
|
||||||
|
data->trans.tx_dummy = data->dev_cfg.tx_dummy;
|
||||||
|
data->trans.rx_dummy = data->dev_cfg.rx_dummy;
|
||||||
|
data->trans.cmd_length = data->dev_cfg.cmd_length;
|
||||||
|
data->trans.addr_length = data->dev_cfg.addr_length;
|
||||||
|
data->trans.hold_ce = false;
|
||||||
|
data->trans.packets = &data->packet;
|
||||||
|
data->trans.num_packet = 1;
|
||||||
|
data->trans.timeout = 10;
|
||||||
|
|
||||||
|
ret = mspi_transceive(cfg->bus, &cfg->dev_id, (const struct mspi_xfer *)&data->trans);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("MSPI read transaction failed with code: %d/%u", ret, __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_enter_command_mode(const struct device *psram)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (cfg->octal_cfg.io_mode == data->dev_cfg.io_mode) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mspi_dev_config(cfg->bus, &cfg->dev_id,
|
||||||
|
MSPI_DEVICE_CONFIG_ALL, &cfg->octal_cfg);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("Failed to reconfigure MSPI while entering command mode/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->dev_cfg = cfg->octal_cfg;
|
||||||
|
|
||||||
|
data->regs.MR8_b.IOM = 0x0;
|
||||||
|
ret = memc_mspi_aps_z8_command_write(psram, APS_Z8_WRITE_REGISTER, 8, &data->regs.MR8, 1);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("Failed to exit hex mode/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_exit_command_mode(const struct device *psram)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (cfg->tar_dev_cfg.io_mode == data->dev_cfg.io_mode) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->regs.MR8_b.IOM = 0x1;
|
||||||
|
ret = memc_mspi_aps_z8_command_write(psram, APS_Z8_WRITE_REGISTER, 8, &data->regs.MR8, 1);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("Failed to enter hex mode/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mspi_dev_config(cfg->bus, &cfg->dev_id,
|
||||||
|
MSPI_DEVICE_CONFIG_ALL, &cfg->tar_dev_cfg);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("Failed to reconfigure MSPI while exiting command mode/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->dev_cfg = cfg->tar_dev_cfg;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_PM_DEVICE
|
||||||
|
static void acquire(const struct device *psram)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
|
||||||
|
k_sem_take(&data->lock, K_FOREVER);
|
||||||
|
|
||||||
|
if (cfg->sw_multi_periph) {
|
||||||
|
while (mspi_dev_config(cfg->bus, &cfg->dev_id,
|
||||||
|
MSPI_DEVICE_CONFIG_ALL, &data->dev_cfg)) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (mspi_dev_config(cfg->bus, &cfg->dev_id,
|
||||||
|
MSPI_DEVICE_CONFIG_NONE, NULL)) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_PM_DEVICE */
|
||||||
|
|
||||||
|
static void release(const struct device *psram)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
|
||||||
|
while (mspi_get_channel_status(cfg->bus, cfg->port)) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
k_sem_give(&data->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_reset(const struct device *psram)
|
||||||
|
{
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
LOG_DBG("Resetting APS Z8/%u", __LINE__);
|
||||||
|
|
||||||
|
ret = memc_mspi_aps_z8_command_write(psram, APS_Z8_GLOBAL_RESET, 0,
|
||||||
|
(uint8_t *)&data->dummy, 2);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** We need to delay 2us minimum to allow APS pSRAM to reinitialize */
|
||||||
|
k_busy_wait(2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_get_vendor_id(const struct device *psram)
|
||||||
|
{
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = memc_mspi_aps_z8_command_read(psram, APS_Z8_READ_REGISTER, 1, &data->regs.MR1, 1);
|
||||||
|
LOG_DBG("MR1 reg: %x/%u", data->regs.MR1, __LINE__);
|
||||||
|
|
||||||
|
if (data->regs.MR1_b.VID != APM_VENDOR_ID) {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_get_rlc(uint8_t rx_dummy, enum memc_mspi_aps_z8_rlc *rlc)
|
||||||
|
{
|
||||||
|
switch (rx_dummy) {
|
||||||
|
case 4:
|
||||||
|
*rlc = MEMC_MSPI_APS_Z8_RLC_4;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
*rlc = MEMC_MSPI_APS_Z8_RLC_5;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*rlc = MEMC_MSPI_APS_Z8_RLC_6;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
*rlc = MEMC_MSPI_APS_Z8_RLC_7;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*rlc = MEMC_MSPI_APS_Z8_RLC_8;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
*rlc = MEMC_MSPI_APS_Z8_RLC_9;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_get_wlc(uint8_t tx_dummy, enum memc_mspi_aps_z8_wlc *wlc)
|
||||||
|
{
|
||||||
|
switch (tx_dummy) {
|
||||||
|
case 5:
|
||||||
|
*wlc = MEMC_MSPI_APS_Z8_WLC_5;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
*wlc = MEMC_MSPI_APS_Z8_WLC_6;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
*wlc = MEMC_MSPI_APS_Z8_WLC_7;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
*wlc = MEMC_MSPI_APS_Z8_WLC_8;
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
*wlc = MEMC_MSPI_APS_Z8_WLC_9;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
*wlc = MEMC_MSPI_APS_Z8_WLC_10;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_PM_DEVICE
|
||||||
|
static int memc_mspi_aps_z8_half_sleep_enter(const struct device *psram)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
struct mspi_xip_cfg xip_cfg = data->xip_cfg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (xip_cfg.enable) {
|
||||||
|
sys_cache_data_flush_and_invd_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_MSPI_XIP
|
||||||
|
xip_cfg.enable = false;
|
||||||
|
if (mspi_xip_config(cfg->bus, &cfg->dev_id, &xip_cfg)) {
|
||||||
|
LOG_ERR("Failed to disable XIP/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MSPI_XIP */
|
||||||
|
|
||||||
|
LOG_DBG("Putting APS Z8 to half sleep/%u", __LINE__);
|
||||||
|
ret = memc_mspi_aps_z8_enter_command_mode(psram);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->regs.MR6 = 0xF0;
|
||||||
|
ret = memc_mspi_aps_z8_command_write(psram, APS_Z8_WRITE_REGISTER, 6, &data->regs.MR6, 1);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("Failed to enter half sleep/%u", __LINE__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* Minimum half sleep duration time(tHS) */
|
||||||
|
k_busy_wait(150);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_half_sleep_exit(const struct device *psram)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
LOG_DBG("Waking up aps_z8 from half sleep/%u", __LINE__);
|
||||||
|
ret = memc_mspi_aps_z8_command_write(psram, 0, 0, (uint8_t *)&data->dummy, 2);
|
||||||
|
if (ret) {
|
||||||
|
LOG_ERR("Failed to exit from half sleep/%u", __LINE__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
/* Minimum half sleep exit CE to CLK setup time(tXHS) */
|
||||||
|
k_busy_wait(150);
|
||||||
|
|
||||||
|
ret = memc_mspi_aps_z8_exit_command_mode(psram);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_MSPI_XIP
|
||||||
|
if (mspi_xip_config(cfg->bus, &cfg->dev_id, &data->xip_cfg)) {
|
||||||
|
LOG_ERR("Failed to enable XIP/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MSPI_XIP */
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_pm_action(const struct device *psram, enum pm_device_action action)
|
||||||
|
{
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case PM_DEVICE_ACTION_RESUME:
|
||||||
|
if (data->regs.MR1_b.ULP) {
|
||||||
|
acquire(psram);
|
||||||
|
memc_mspi_aps_z8_half_sleep_exit(psram);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PM_DEVICE_ACTION_SUSPEND:
|
||||||
|
if (data->regs.MR1_b.ULP) {
|
||||||
|
memc_mspi_aps_z8_half_sleep_enter(psram);
|
||||||
|
release(psram);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* IS_ENABLED(CONFIG_PM_DEVICE) */
|
||||||
|
|
||||||
|
static int memc_mspi_aps_z8_init(const struct device *psram)
|
||||||
|
{
|
||||||
|
const struct memc_mspi_aps_z8_config *cfg = psram->config;
|
||||||
|
struct memc_mspi_aps_z8_data *data = psram->data;
|
||||||
|
|
||||||
|
if (!device_is_ready(cfg->bus)) {
|
||||||
|
LOG_ERR("Controller device not ready/%u", __LINE__);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cfg->tar_dev_cfg.io_mode) {
|
||||||
|
case MSPI_IO_MODE_OCTAL:
|
||||||
|
case MSPI_IO_MODE_HEX_8_8_16:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERR("Bus mode %d not supported/%u", cfg->tar_dev_cfg.io_mode, __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->tar_dev_cfg.data_rate != MSPI_DATA_RATE_S_D_D) {
|
||||||
|
LOG_ERR("Data rate %d not supported/%u", cfg->tar_dev_cfg.data_rate, __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL, &cfg->octal_cfg)) {
|
||||||
|
LOG_ERR("Failed to config mspi controller/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->dev_cfg = cfg->octal_cfg;
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_reset(psram)) {
|
||||||
|
LOG_ERR("Could not reset pSRAM/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_get_vendor_id(psram)) {
|
||||||
|
LOG_ERR("Could not read vendor id/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_read(psram, APS_Z8_READ_REGISTER, 0, &data->regs.MR0, 1)) {
|
||||||
|
LOG_ERR("Could not read MR0 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_read(psram, APS_Z8_READ_REGISTER, 2, &data->regs.MR2, 1)) {
|
||||||
|
LOG_ERR("Could not read MR2 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_read(psram, APS_Z8_READ_REGISTER, 3, &data->regs.MR3, 1)) {
|
||||||
|
LOG_ERR("Could not read MR3 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_read(psram, APS_Z8_READ_REGISTER, 4, &data->regs.MR4, 1)) {
|
||||||
|
LOG_ERR("Could not read MR4 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_read(psram, APS_Z8_READ_REGISTER, 6, &data->regs.MR6, 1)) {
|
||||||
|
LOG_ERR("Could not read MR2 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_read(psram, APS_Z8_READ_REGISTER, 8, &data->regs.MR8, 1)) {
|
||||||
|
LOG_ERR("Could not read MR8 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum memc_mspi_aps_z8_rlc rlc;
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_get_rlc(cfg->tar_dev_cfg.rx_dummy, &rlc)) {
|
||||||
|
LOG_ERR("rx_dummy:%d not supported/%u", cfg->tar_dev_cfg.rx_dummy, __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->regs.MR0_b.RLC = rlc;
|
||||||
|
|
||||||
|
enum memc_mspi_aps_z8_wlc wlc;
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_get_wlc(cfg->tar_dev_cfg.tx_dummy, &wlc)) {
|
||||||
|
LOG_ERR("tx_dummy:%d not supported/%u", cfg->tar_dev_cfg.tx_dummy, __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->regs.MR4_b.WLC = wlc;
|
||||||
|
|
||||||
|
data->regs.MR0_b.LT = !cfg->tar_dev_cfg.dqs_enable;
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_write(psram, APS_Z8_WRITE_REGISTER, 0, &data->regs.MR0, 1)) {
|
||||||
|
LOG_ERR("Could not write MR0 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memc_mspi_aps_z8_command_write(psram, APS_Z8_WRITE_REGISTER, 4, &data->regs.MR4, 1)) {
|
||||||
|
LOG_ERR("Could not write MR4 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->tar_dev_cfg.io_mode == MSPI_IO_MODE_HEX_8_8_16) {
|
||||||
|
data->regs.MR8_b.IOM = 1;
|
||||||
|
if (memc_mspi_aps_z8_command_write(psram, APS_Z8_WRITE_REGISTER, 8,
|
||||||
|
&data->regs.MR8, 1)) {
|
||||||
|
LOG_ERR("Could not write MR8 register/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mspi_dev_config(cfg->bus, &cfg->dev_id, MSPI_DEVICE_CONFIG_ALL, &cfg->tar_dev_cfg)) {
|
||||||
|
LOG_ERR("Failed to config mspi controller/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->dev_cfg = cfg->tar_dev_cfg;
|
||||||
|
|
||||||
|
#if CONFIG_MSPI_TIMING
|
||||||
|
if (mspi_timing_config(cfg->bus, &cfg->dev_id, cfg->timing_cfg_mask,
|
||||||
|
(void *)&cfg->tar_timing_cfg)) {
|
||||||
|
LOG_ERR("Failed to config mspi timing/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->timing_cfg = cfg->tar_timing_cfg;
|
||||||
|
#endif /* CONFIG_MSPI_TIMING */
|
||||||
|
|
||||||
|
#if CONFIG_MSPI_XIP
|
||||||
|
if (cfg->tar_xip_cfg.enable) {
|
||||||
|
if (mspi_xip_config(cfg->bus, &cfg->dev_id, &cfg->tar_xip_cfg)) {
|
||||||
|
LOG_ERR("Failed to enable XIP/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->xip_cfg = cfg->tar_xip_cfg;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MSPI_XIP */
|
||||||
|
|
||||||
|
#if CONFIG_MSPI_SCRAMBLE
|
||||||
|
if (cfg->tar_scramble_cfg.enable) {
|
||||||
|
if (mspi_scramble_config(cfg->bus, &cfg->dev_id, &cfg->tar_scramble_cfg)) {
|
||||||
|
LOG_ERR("Failed to enable scrambling/%u", __LINE__);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
data->scramble_cfg = cfg->tar_scramble_cfg;
|
||||||
|
}
|
||||||
|
#endif /* MSPI_SCRAMBLE */
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) ||
|
||||||
|
!cfg->pm_dev_rt_auto) {
|
||||||
|
release(psram);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MSPI_DEVICE_CONFIG_OCTAL(n) \
|
||||||
|
{ \
|
||||||
|
.ce_num = DT_INST_PROP(n, mspi_hardware_ce_num), \
|
||||||
|
.freq = 24000000, \
|
||||||
|
.io_mode = MSPI_IO_MODE_OCTAL, \
|
||||||
|
.data_rate = MSPI_DATA_RATE_S_D_D, \
|
||||||
|
.cpp = MSPI_CPP_MODE_0, \
|
||||||
|
.endian = MSPI_XFER_LITTLE_ENDIAN, \
|
||||||
|
.ce_polarity = MSPI_CE_ACTIVE_LOW, \
|
||||||
|
.dqs_enable = DT_INST_PROP(n, mspi_dqs_enable), \
|
||||||
|
.rx_dummy = MEMC_MSPI_APS_Z8_RX_DUMMY_DEFAULT, \
|
||||||
|
.tx_dummy = MEMC_MSPI_APS_Z8_TX_DUMMY_DEFAULT, \
|
||||||
|
.read_cmd = APS_Z8_LINEAR_BURST_READ, \
|
||||||
|
.write_cmd = APS_Z8_LINEAR_BURST_WRITE, \
|
||||||
|
.cmd_length = MEMC_MSPI_APS_Z8_CMD_LENGTH_DEFAULT, \
|
||||||
|
.addr_length = MEMC_MSPI_APS_Z8_ADDR_LENGTH_DEFAULT, \
|
||||||
|
.mem_boundary = 1024, \
|
||||||
|
.time_to_break = 4, \
|
||||||
|
}
|
||||||
|
#define MSPI_TIMING_CONFIG(n) \
|
||||||
|
COND_CODE_1(CONFIG_SOC_FAMILY_AMBIQ, \
|
||||||
|
(MSPI_AMBIQ_TIMING_CONFIG(n)), ({})) \
|
||||||
|
|
||||||
|
#define MSPI_TIMING_CONFIG_MASK(n) \
|
||||||
|
COND_CODE_1(CONFIG_SOC_FAMILY_AMBIQ, \
|
||||||
|
(MSPI_AMBIQ_TIMING_CONFIG_MASK(n)), (MSPI_TIMING_PARAM_DUMMY)) \
|
||||||
|
|
||||||
|
#define MSPI_PORT(n) \
|
||||||
|
COND_CODE_1(CONFIG_SOC_FAMILY_AMBIQ, \
|
||||||
|
(MSPI_AMBIQ_PORT(n)), (0)) \
|
||||||
|
|
||||||
|
#define MEMC_MSPI_APS_Z8(n) \
|
||||||
|
static const struct memc_mspi_aps_z8_config \
|
||||||
|
memc_mspi_aps_z8_config_##n = { \
|
||||||
|
.port = MSPI_PORT(n), \
|
||||||
|
.mem_size = DT_INST_PROP(n, size) / 8, \
|
||||||
|
.bus = DEVICE_DT_GET(DT_INST_BUS(n)), \
|
||||||
|
.dev_id = MSPI_DEVICE_ID_DT_INST(n), \
|
||||||
|
.octal_cfg = MSPI_DEVICE_CONFIG_OCTAL(n), \
|
||||||
|
.tar_dev_cfg = MSPI_DEVICE_CONFIG_DT_INST(n), \
|
||||||
|
MSPI_OPTIONAL_CFG_STRUCT_INIT(CONFIG_MSPI_XIP, \
|
||||||
|
tar_xip_cfg, MSPI_XIP_CONFIG_DT_INST(n)) \
|
||||||
|
MSPI_OPTIONAL_CFG_STRUCT_INIT(CONFIG_MSPI_SCRAMBLE, \
|
||||||
|
tar_scramble_cfg, MSPI_SCRAMBLE_CONFIG_DT_INST(n)) \
|
||||||
|
MSPI_OPTIONAL_CFG_STRUCT_INIT(CONFIG_MSPI_TIMING, \
|
||||||
|
tar_timing_cfg, MSPI_TIMING_CONFIG(n)) \
|
||||||
|
MSPI_OPTIONAL_CFG_STRUCT_INIT(CONFIG_MSPI_TIMING, \
|
||||||
|
timing_cfg_mask, MSPI_TIMING_CONFIG_MASK(n)) \
|
||||||
|
.sw_multi_periph = DT_PROP(DT_INST_BUS(n), software_multiperipheral), \
|
||||||
|
.pm_dev_rt_auto = DT_INST_PROP(n, zephyr_pm_device_runtime_auto) \
|
||||||
|
}; \
|
||||||
|
static struct memc_mspi_aps_z8_data \
|
||||||
|
memc_mspi_aps_z8_data_##n = { \
|
||||||
|
.lock = Z_SEM_INITIALIZER(memc_mspi_aps_z8_data_##n.lock, 0, 1), \
|
||||||
|
.dummy = 0, \
|
||||||
|
}; \
|
||||||
|
PM_DEVICE_DT_INST_DEFINE(n, memc_mspi_aps_z8_pm_action); \
|
||||||
|
DEVICE_DT_INST_DEFINE(n, \
|
||||||
|
memc_mspi_aps_z8_init, \
|
||||||
|
PM_DEVICE_DT_INST_GET(n), \
|
||||||
|
&memc_mspi_aps_z8_data_##n, \
|
||||||
|
&memc_mspi_aps_z8_config_##n, \
|
||||||
|
POST_KERNEL, \
|
||||||
|
CONFIG_MEMC_INIT_PRIORITY, \
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(MEMC_MSPI_APS_Z8)
|
115
drivers/memc/memc_mspi_aps_z8.h
Normal file
115
drivers/memc/memc_mspi_aps_z8.h
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Ambiq Micro Inc. <www.ambiq.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum memc_mspi_aps_z8_rlc {
|
||||||
|
MEMC_MSPI_APS_Z8_RLC_4,
|
||||||
|
MEMC_MSPI_APS_Z8_RLC_5,
|
||||||
|
MEMC_MSPI_APS_Z8_RLC_6,
|
||||||
|
MEMC_MSPI_APS_Z8_RLC_7,
|
||||||
|
MEMC_MSPI_APS_Z8_RLC_8,
|
||||||
|
MEMC_MSPI_APS_Z8_RLC_9,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum memc_mspi_aps_z8_wlc {
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_3, /* reserved for APS51216BA */
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_7,
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_5,
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_9, /* reserved for APS25616N */
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_4, /* reserved for APS51216BA */
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_8, /* reserved for APS25616N */
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_6,
|
||||||
|
MEMC_MSPI_APS_Z8_WLC_10, /* reserved for APS25616N */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* default for APS51216BA */
|
||||||
|
#define MEMC_MSPI_APS_Z8_RX_DUMMY_DEFAULT 6
|
||||||
|
#define MEMC_MSPI_APS_Z8_TX_DUMMY_DEFAULT 6
|
||||||
|
|
||||||
|
#define MEMC_MSPI_APS_Z8_CMD_LENGTH_DEFAULT 1
|
||||||
|
#define MEMC_MSPI_APS_Z8_ADDR_LENGTH_DEFAULT 4
|
||||||
|
|
||||||
|
enum memc_mspi_aps_z8_ds {
|
||||||
|
MEMC_MSPI_APS_Z8_DRIVE_STRENGTH_FULL,
|
||||||
|
MEMC_MSPI_APS_Z8_DRIVE_STRENGTH_HALF,
|
||||||
|
MEMC_MSPI_APS_Z8_DRIVE_STRENGTH_QUARTER,
|
||||||
|
MEMC_MSPI_APS_Z8_DRIVE_STRENGTH_OCTUPLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct memc_mspi_aps_z8_reg {
|
||||||
|
union {
|
||||||
|
uint8_t MR0; /* Mode register 0 */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t DS: 2; /* [0..1] drive strength */
|
||||||
|
uint8_t RLC: 3; /* [2..4] Read latency code. */
|
||||||
|
uint8_t LT: 1; /* [5..5] Latency type */
|
||||||
|
uint8_t: 1;
|
||||||
|
uint8_t TSO: 1; /* [7..7] Temperature Sensor Override */
|
||||||
|
} MR0_b;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t MR1; /* Mode register 1 */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t VID: 5; /* [0..4] Vendor ID */
|
||||||
|
uint8_t: 2;
|
||||||
|
uint8_t ULP: 1; /* [7..7] Half sleep. */
|
||||||
|
} MR1_b;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t MR2; /* Mode register 2 */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t DENSITY: 3; /* [0..2] Density */
|
||||||
|
uint8_t GENERATION: 2; /* [3..4] Generation */
|
||||||
|
uint8_t GB: 3; /* [5..7] Good or bad */
|
||||||
|
} MR2_b;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t MR3; /* Mode register 3 */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t: 4;
|
||||||
|
uint8_t SRF: 2; /* [4..5] Self refresh flag */
|
||||||
|
uint8_t: 1;
|
||||||
|
uint8_t RBXen: 1; /* [7..7] Row Boundary Crossing Enable */
|
||||||
|
} MR3_b;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t MR4; /* Mode register 4 */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t PASR: 3; /* [0..2] control refresh address space */
|
||||||
|
uint8_t RFS: 2; /* [3..4] Refresh Frequency setting */
|
||||||
|
uint8_t WLC: 3; /* [5..7] Write latency code. */
|
||||||
|
} MR4_b;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t MR6; /* Mode register 6 */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t ULPM: 8; /* [0..7] ULP modes */
|
||||||
|
} MR6_b;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t MR8; /* Mode register 8 */
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint8_t BL: 2; /* [0..1] Burst Length */
|
||||||
|
uint8_t BT: 1; /* [2..2] Burst type */
|
||||||
|
uint8_t RBX: 1; /* [3..3] Row Boundary Crossing Read EN */
|
||||||
|
uint8_t: 2;
|
||||||
|
uint8_t IOM: 1; /* [6..6] IO mode */
|
||||||
|
uint8_t: 1;
|
||||||
|
} MR8_b;
|
||||||
|
};
|
||||||
|
};
|
8
dts/bindings/mtd/mspi-aps-z8.yaml
Normal file
8
dts/bindings/mtd/mspi-aps-z8.yaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Copyright (c) 2025, Ambiq Micro Inc. <www.ambiq.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: AP Memory pSRAM Version Z8 on MSPI bus
|
||||||
|
|
||||||
|
compatible: "mspi-aps-z8"
|
||||||
|
|
||||||
|
include: [mspi-device.yaml, "jedec,jesd216.yaml"]
|
|
@ -10,7 +10,7 @@ if(CONFIG_MEMC_MCUX_FLEXSPI)
|
||||||
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/drivers/memc)
|
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/drivers/memc)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CONFIG_MEMC_MSPI_APS6404L)
|
if(CONFIG_MEMC_MSPI)
|
||||||
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/include/zephyr/drivers)
|
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/include/zephyr/drivers)
|
||||||
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/drivers/mspi)
|
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/drivers/mspi)
|
||||||
endif()
|
endif()
|
||||||
|
|
6
samples/drivers/memc/boards/apollo510_evb.conf
Normal file
6
samples/drivers/memc/boards/apollo510_evb.conf
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Copyright (c) 2025 Ambiq Micro Inc. <www.ambiq.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
CONFIG_MEMC=y
|
||||||
|
CONFIG_LOG=y
|
||||||
|
CONFIG_LOG_DEFAULT_LEVEL=0
|
19
samples/drivers/memc/boards/apollo510_evb.overlay
Normal file
19
samples/drivers/memc/boards/apollo510_evb.overlay
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2025, Ambiq Micro Inc. <www.ambiq.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
aliases {
|
||||||
|
psram0 = &aps51216ba;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&mspi0 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&aps51216ba {
|
||||||
|
status = "okay";
|
||||||
|
};
|
|
@ -7,23 +7,27 @@
|
||||||
#include <zephyr/kernel.h>
|
#include <zephyr/kernel.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <zephyr/drivers/mspi.h>
|
#include <zephyr/drivers/mspi.h>
|
||||||
|
#include <zephyr/pm/device_runtime.h>
|
||||||
|
|
||||||
#if DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_flexspi)
|
#if DT_HAS_COMPAT_STATUS_OKAY(nxp_imx_flexspi)
|
||||||
/* Use memc API to get AHB base address for the device */
|
/* Use memc API to get AHB base address for the device */
|
||||||
#include "memc_mcux_flexspi.h"
|
#include "memc_mcux_flexspi.h"
|
||||||
#define FLEXSPI_DEV DEVICE_DT_GET(DT_PARENT(DT_ALIAS(sram_ext)))
|
#define FLEXSPI_DEV DEVICE_DT_GET(DT_PARENT(DT_ALIAS(sram_ext)))
|
||||||
|
#define MEMC_DEV DT_ALIAS(sram_ext)
|
||||||
#define MEMC_PORT DT_REG_ADDR(DT_ALIAS(sram_ext))
|
#define MEMC_PORT DT_REG_ADDR(DT_ALIAS(sram_ext))
|
||||||
#define MEMC_BASE ((void *)memc_flexspi_get_ahb_address(FLEXSPI_DEV, MEMC_PORT, 0))
|
#define MEMC_BASE ((void *)memc_flexspi_get_ahb_address(FLEXSPI_DEV, MEMC_PORT, 0))
|
||||||
#define MEMC_SIZE (DT_PROP(DT_ALIAS(sram_ext), size) / 8)
|
#define MEMC_SIZE (DT_PROP(DT_ALIAS(sram_ext), size) / 8)
|
||||||
#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_smartbond_nor_psram)
|
#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_smartbond_nor_psram)
|
||||||
#include <da1469x_config.h>
|
#include <da1469x_config.h>
|
||||||
|
#define MEMC_DEV DT_ALIAS(sram_ext)
|
||||||
#define MEMC_BASE ((void *)MCU_QSPIR_M_BASE)
|
#define MEMC_BASE ((void *)MCU_QSPIR_M_BASE)
|
||||||
#define MEMC_SIZE (DT_PROP(DT_ALIAS(sram_ext), dev_size) / 8)
|
#define MEMC_SIZE (DT_PROP(DT_ALIAS(sram_ext), dev_size) / 8)
|
||||||
#elif DT_HAS_COMPAT_STATUS_OKAY(ambiq_mspi_controller)
|
#elif DT_HAS_COMPAT_STATUS_OKAY(ambiq_mspi_controller)
|
||||||
#define MSPI_ DT_BUS(DT_ALIAS(psram0))
|
#define MEMC_DEV DT_ALIAS(psram0)
|
||||||
|
#define MSPI_BUS DT_BUS(MEMC_DEV)
|
||||||
#define mspi_get_xip_address(controller) DT_REG_ADDR_BY_IDX(controller, 1)
|
#define mspi_get_xip_address(controller) DT_REG_ADDR_BY_IDX(controller, 1)
|
||||||
#define MEMC_BASE (void *)(mspi_get_xip_address(MSPI_))
|
#define MEMC_BASE (void *)(mspi_get_xip_address(MSPI_BUS))
|
||||||
#define MEMC_SIZE (DT_PROP(DT_ALIAS(psram0), size) / 8)
|
#define MEMC_SIZE (DT_PROP(MEMC_DEV, size) / 8)
|
||||||
#else
|
#else
|
||||||
#error At least one driver should be selected!
|
#error At least one driver should be selected!
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,6 +69,9 @@ int main(void)
|
||||||
for (i = 0; i < BUF_SIZE; i++) {
|
for (i = 0; i < BUF_SIZE; i++) {
|
||||||
memc_write_buffer[i] = (uint8_t)i;
|
memc_write_buffer[i] = (uint8_t)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pm_device_runtime_get(DEVICE_DT_GET(MEMC_DEV));
|
||||||
|
|
||||||
printk("Writing to memory region with base %p, size 0x%0x\n\n",
|
printk("Writing to memory region with base %p, size 0x%0x\n\n",
|
||||||
memc, MEMC_SIZE);
|
memc, MEMC_SIZE);
|
||||||
/* Copy write buffer into memc region */
|
/* Copy write buffer into memc region */
|
||||||
|
@ -99,6 +106,7 @@ int main(void)
|
||||||
printk("First 1KB of Data in memory:\n");
|
printk("First 1KB of Data in memory:\n");
|
||||||
printk("===========================\n");
|
printk("===========================\n");
|
||||||
dump_memory(memc, MIN(MEMC_SIZE, KB(1)));
|
dump_memory(memc, MIN(MEMC_SIZE, KB(1)));
|
||||||
|
pm_device_runtime_put(DEVICE_DT_GET(MEMC_DEV));
|
||||||
printk("Read data matches written data\n");
|
printk("Read data matches written data\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue