From cc1266ad6a2f73dec72e37c737e7db707265d7f6 Mon Sep 17 00:00:00 2001 From: David Missael Maciel Date: Tue, 15 Oct 2024 16:58:46 +0000 Subject: [PATCH] drivers: memc: add memc_mcux_flexspi_aps6404l driver Add driver for aps6404l PSRAM, using FlexSPI MEMC driver interface. Signed-off-by: David Missael Maciel --- drivers/memc/CMakeLists.txt | 1 + drivers/memc/Kconfig.mcux | 6 + drivers/memc/memc_mcux_flexspi_aps6404l.c | 268 ++++++++++++++++++ .../mtd/nxp,imx-flexspi-aps6404l.yaml | 8 + 4 files changed, 283 insertions(+) create mode 100644 drivers/memc/memc_mcux_flexspi_aps6404l.c create mode 100644 dts/bindings/mtd/nxp,imx-flexspi-aps6404l.yaml diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index c45825d68ca..5cfb571c342 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI memc_mcux_flexspi.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_W956A8MBYA memc_mcux_flexspi_w956a8mbya.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_S27KS0641 memc_mcux_flexspi_s27ks0641.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6408L memc_mcux_flexspi_aps6408l.c) +zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6404L memc_mcux_flexspi_aps6404l.c) zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_IS66WVQ8M4 memc_mcux_flexspi_is66wvq8m4.c) zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_FLEXRAM memc_nxp_flexram.c) diff --git a/drivers/memc/Kconfig.mcux b/drivers/memc/Kconfig.mcux index 7d231808ea3..23aac7e3fa7 100644 --- a/drivers/memc/Kconfig.mcux +++ b/drivers/memc/Kconfig.mcux @@ -30,6 +30,12 @@ config MEMC_MCUX_FLEXSPI_IS66WVQ8M4 depends on DT_HAS_NXP_IMX_FLEXSPI_IS66WVQ8M4_ENABLED select MEMC_MCUX_FLEXSPI +config MEMC_MCUX_FLEXSPI_APS6404L + bool "MCUX FlexSPI AP Memory APS6404L pSRAM driver" + default y + depends on DT_HAS_NXP_IMX_FLEXSPI_APS6404L_ENABLED + select MEMC_MCUX_FLEXSPI + config MEMC_MCUX_FLEXSPI_INIT_PRIORITY int "MCUX FLEXSPI MEMC driver initialization priority" default MEMC_INIT_PRIORITY diff --git a/drivers/memc/memc_mcux_flexspi_aps6404l.c b/drivers/memc/memc_mcux_flexspi_aps6404l.c new file mode 100644 index 00000000000..cbf7182112d --- /dev/null +++ b/drivers/memc/memc_mcux_flexspi_aps6404l.c @@ -0,0 +1,268 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + + /* + * Based on memc_mcux_flexspi_s27ks0641, which is: Copyright 2021 Basalte bv + */ + + #define DT_DRV_COMPAT nxp_imx_flexspi_aps6404l + + #include + #include + #include + + #include "memc_mcux_flexspi.h" + + +/* + * NOTE: If CONFIG_FLASH_MCUX_FLEXSPI_XIP is selected, Any external functions + * called while interacting with the flexspi MUST be relocated to SRAM or ITCM + * at runtime, so that the chip does not access the flexspi to read program + * instructions while it is being written to + */ +#if defined(CONFIG_FLASH_MCUX_FLEXSPI_XIP) && (CONFIG_MEMC_LOG_LEVEL > 0) +#warning "Enabling memc driver logging and XIP mode simultaneously can cause \ + read-while-write hazards. This configuration is not recommended." +#endif + +LOG_MODULE_REGISTER(memc_flexspi_aps6404l, CONFIG_MEMC_LOG_LEVEL); + +#define APM_VENDOR_ID 0xD + +enum { + READ_DATA = 0, + WRITE_DATA, + RESET_EN, + RESET, + READ_ID +}; + +struct memc_flexspi_aps6404l_config { + flexspi_port_t port; + flexspi_device_config_t config; +}; + +/* Device variables used in critical sections should be in this structure */ +struct memc_flexspi_aps6404l_data { + const struct device *controller; +}; + + +static const uint32_t memc_flexspi_aps6404l_lut[][4] = { + /* Read Data (Sync read, linear burst) */ + [READ_DATA] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0xEB, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DUMMY_SDR, kFLEXSPI_4PAD, + 0x06, kFLEXSPI_Command_READ_SDR, kFLEXSPI_4PAD, 0x04), + }, + /* Write Data (Sync write, linear burst) */ + [WRITE_DATA] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x38, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_4PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_SDR, kFLEXSPI_4PAD, + 0x00, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + }, + + [RESET_EN] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x66, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + }, + /* Reset (Global reset) */ + [RESET] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x99, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + }, + + [READ_ID] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x9F, + kFLEXSPI_Command_RADDR_SDR, kFLEXSPI_1PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_SDR, kFLEXSPI_1PAD, 0x08, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0), + }, +}; + + +static int memc_flexspi_aps6404l_get_vendor_id(const struct device *dev, + uint8_t *vendor_id) +{ + const struct memc_flexspi_aps6404l_config *config = dev->config; + struct memc_flexspi_aps6404l_data *data = dev->data; + uint32_t buffer = 0; + int ret; + + flexspi_transfer_t transfer = { + .deviceAddress = 0x0, + .port = config->port, + .cmdType = kFLEXSPI_Read, + .SeqNumber = 1, + .seqIndex = READ_ID, + .data = &buffer, + .dataSize = 1, + }; + + ret = memc_flexspi_transfer(data->controller, &transfer); + *vendor_id = buffer & 0x1f; + + return ret; +} + +static int memc_flexspi_aps6404l_reset_enable(const struct device *dev) +{ + const struct memc_flexspi_aps6404l_config *config = dev->config; + struct memc_flexspi_aps6404l_data *data = dev->data; + int ret; + + flexspi_transfer_t transfer = { + .deviceAddress = 0x0, + .port = config->port, + .cmdType = kFLEXSPI_Command, + .SeqNumber = 1, + .seqIndex = RESET_EN, + .data = NULL, + .dataSize = 0, + }; + + LOG_DBG("Enabling reset ram"); + ret = memc_flexspi_transfer(data->controller, &transfer); + if (ret < 0) { + return ret; + } + /* We need to delay 5 ms to allow APS6404L pSRAM to reinitialize */ + k_msleep(5); + + return ret; +} + + +static int memc_flexspi_aps6404l_reset(const struct device *dev) +{ + const struct memc_flexspi_aps6404l_config *config = dev->config; + struct memc_flexspi_aps6404l_data *data = dev->data; + int ret; + + flexspi_transfer_t transfer = { + .deviceAddress = 0x0, + .port = config->port, + .cmdType = kFLEXSPI_Command, + .SeqNumber = 1, + .seqIndex = RESET, + .data = NULL, + .dataSize = 0, + }; + + LOG_DBG("Resetting ram"); + ret = memc_flexspi_transfer(data->controller, &transfer); + if (ret < 0) { + return ret; + } + /* We need to delay 5 ms to allow APS6404L pSRAM to reinitialize */ + k_msleep(5); + + return ret; +} + +static int memc_flexspi_aps6404l_init(const struct device *dev) +{ + const struct memc_flexspi_aps6404l_config *config = dev->config; + struct memc_flexspi_aps6404l_data *data = dev->data; + uint8_t vendor_id; + + if (!device_is_ready(data->controller)) { + LOG_ERR("Controller device not ready"); + return -ENODEV; + } + + if (memc_flexspi_set_device_config(data->controller, &config->config, + (const uint32_t *) memc_flexspi_aps6404l_lut, + sizeof(memc_flexspi_aps6404l_lut) / MEMC_FLEXSPI_CMD_SIZE, + config->port)) { + LOG_ERR("Could not set device configuration"); + return -EINVAL; + } + + memc_flexspi_reset(data->controller); + + if (memc_flexspi_aps6404l_reset_enable(dev)) { + LOG_ERR("Could not enable reset pSRAM"); + return -EIO; + } + + if (memc_flexspi_aps6404l_reset(dev)) { + LOG_ERR("Could not reset pSRAM"); + return -EIO; + } + + if (memc_flexspi_aps6404l_get_vendor_id(dev, &vendor_id)) { + LOG_ERR("Could not read vendor id"); + return -EIO; + } + LOG_DBG("Vendor id: 0x%0x", vendor_id); + if (vendor_id != APM_VENDOR_ID) { + LOG_WRN("Vendor ID does not match expected value of 0x%0x", + APM_VENDOR_ID); + } + + return 0; +} + +#define CONCAT3(x, y, z) x ## y ## z + +#define CS_INTERVAL_UNIT(unit) \ + CONCAT3(kFLEXSPI_CsIntervalUnit, unit, SckCycle) + +#define AHB_WRITE_WAIT_UNIT(unit) \ + CONCAT3(kFLEXSPI_AhbWriteWaitUnit, unit, AhbCycle) + +#define MEMC_FLEXSPI_DEVICE_CONFIG(n) \ + { \ + .flexspiRootClk = DT_INST_PROP(n, spi_max_frequency), \ + .isSck2Enabled = false, \ + .flashSize = DT_INST_PROP(n, size) / 8 / KB(1), \ + .addressShift = false, \ + .CSIntervalUnit = \ + CS_INTERVAL_UNIT( \ + DT_INST_PROP(n, cs_interval_unit)), \ + .CSInterval = DT_INST_PROP(n, cs_interval), \ + .CSHoldTime = DT_INST_PROP(n, cs_hold_time), \ + .CSSetupTime = DT_INST_PROP(n, cs_setup_time), \ + .dataValidTime = DT_INST_PROP(n, data_valid_time), \ + .columnspace = DT_INST_PROP(n, column_space), \ + .enableWordAddress = DT_INST_PROP(n, word_addressable), \ + .AWRSeqIndex = WRITE_DATA, \ + .AWRSeqNumber = 1, \ + .ARDSeqIndex = READ_DATA, \ + .ARDSeqNumber = 1, \ + .AHBWriteWaitUnit = \ + AHB_WRITE_WAIT_UNIT( \ + DT_INST_PROP(n, ahb_write_wait_unit)), \ + .AHBWriteWaitInterval = \ + DT_INST_PROP(n, ahb_write_wait_interval), \ + .enableWriteMask = false, \ + } \ + +#define MEMC_FLEXSPI_APS6404L(n) \ + static const struct memc_flexspi_aps6404l_config \ + memc_flexspi_aps6404l_config_##n = { \ + .port = DT_INST_REG_ADDR(n), \ + .config = MEMC_FLEXSPI_DEVICE_CONFIG(n), \ + }; \ + \ + static struct memc_flexspi_aps6404l_data \ + memc_flexspi_aps6404l_data_##n = { \ + .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + memc_flexspi_aps6404l_init, \ + NULL, \ + &memc_flexspi_aps6404l_data_##n, \ + &memc_flexspi_aps6404l_config_##n, \ + POST_KERNEL, \ + CONFIG_MEMC_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI_APS6404L) diff --git a/dts/bindings/mtd/nxp,imx-flexspi-aps6404l.yaml b/dts/bindings/mtd/nxp,imx-flexspi-aps6404l.yaml new file mode 100644 index 00000000000..1f38a7288be --- /dev/null +++ b/dts/bindings/mtd/nxp,imx-flexspi-aps6404l.yaml @@ -0,0 +1,8 @@ +# Copyright 2022 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: AP Memory APS6404L pSRAM on NXP FlexSPI bus + +compatible: "nxp,imx-flexspi-aps6404l" + +include: nxp,imx-flexspi-device.yaml