diff --git a/drivers/memc/CMakeLists.txt b/drivers/memc/CMakeLists.txt index a991e4e4716..ca967b1a045 100644 --- a/drivers/memc/CMakeLists.txt +++ b/drivers/memc/CMakeLists.txt @@ -8,6 +8,7 @@ zephyr_linker_sources_ifdef(CONFIG_MEMC_STM32_SDRAM SECTIONS memc_stm32_sdram.ld zephyr_library_sources_ifdef(CONFIG_MEMC_STM32_NOR_PSRAM memc_stm32_nor_psram.c) 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) diff --git a/drivers/memc/Kconfig.mcux b/drivers/memc/Kconfig.mcux index 2a13eaaf28a..ed7e73929db 100644 --- a/drivers/memc/Kconfig.mcux +++ b/drivers/memc/Kconfig.mcux @@ -1,9 +1,17 @@ # Copyright (c) 2020-2022 NXP # Copyright (c) 2021 Basalte bv +# Copyright (c) 2023, ithinx GmbH +# Copyright (c) 2023, Tonies GmbH # SPDX-License-Identifier: Apache-2.0 if DT_HAS_NXP_IMX_FLEXSPI_ENABLED +config MEMC_MCUX_FLEXSPI_W956A8MBYA + bool "MCUX FlexSPI Winbond W956A8MBYA HyperRAM driver" + default y + depends on DT_HAS_NXP_IMX_FLEXSPI_W956A8MBYA_ENABLED + select MEMC_MCUX_FLEXSPI + config MEMC_MCUX_FLEXSPI_S27KS0641 bool "MCUX FlexSPI Cypress S27KS0641 HyperRAM driver" default y diff --git a/drivers/memc/memc_mcux_flexspi_w956a8mbya.c b/drivers/memc/memc_mcux_flexspi_w956a8mbya.c new file mode 100644 index 00000000000..ad24ecccdc7 --- /dev/null +++ b/drivers/memc/memc_mcux_flexspi_w956a8mbya.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2023, ithinx GmbH + * Copyright (c) 2023, Tonies GmbH + * + * 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_w956a8mbya + +#include +#include + +#include "memc_mcux_flexspi.h" + + +LOG_MODULE_REGISTER(memc_flexspi_w956a8mbya, CONFIG_MEMC_LOG_LEVEL); + +enum { + READ_DATA, + WRITE_DATA, + READ_REG, + WRITE_REG, +}; + +struct memc_flexspi_w956a8mbya_config { + flexspi_port_t port; + flexspi_device_config_t config; +}; + +/* Device variables used in critical sections should be in this structure */ +struct memc_flexspi_w956a8mbya_data { + const struct device *controller; +}; + +static const uint32_t memc_flexspi_w956a8mbya_lut[][4] = { + /* Read Data */ + [READ_DATA] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xA0, + kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, + kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + }, + + /* Write Data */ + [WRITE_DATA] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x20, + kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, + kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + }, + + /* Read Register */ + [READ_REG] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0xE0, + kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, + kFLEXSPI_Command_DUMMY_RWDS_DDR, kFLEXSPI_8PAD, 0x07), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_READ_DDR, kFLEXSPI_8PAD, 0x04, + kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0x00), + }, + + /* Write Register */ + [WRITE_REG] = { + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_DDR, kFLEXSPI_8PAD, 0x60, + kFLEXSPI_Command_RADDR_DDR, kFLEXSPI_8PAD, 0x18), + FLEXSPI_LUT_SEQ(kFLEXSPI_Command_CADDR_DDR, kFLEXSPI_8PAD, 0x10, + kFLEXSPI_Command_WRITE_DDR, kFLEXSPI_8PAD, 0x04), + }, +}; + +static int memc_flexspi_w956a8mbya_get_vendor_id(const struct device *dev, + uint16_t *vendor_id) +{ + const struct memc_flexspi_w956a8mbya_config *config = dev->config; + struct memc_flexspi_w956a8mbya_data *data = dev->data; + uint32_t buffer = 0; + int ret; + + flexspi_transfer_t transfer = { + .deviceAddress = 0, + .port = config->port, + .cmdType = kFLEXSPI_Read, + .SeqNumber = 1, + .seqIndex = READ_REG, + .data = &buffer, + .dataSize = 4, + }; + + LOG_DBG("Reading id"); + + ret = memc_flexspi_transfer(data->controller, &transfer); + *vendor_id = buffer & 0xffff; + + return ret; +} + +static int memc_flexspi_w956a8mbya_init(const struct device *dev) +{ + const struct memc_flexspi_w956a8mbya_config *config = dev->config; + struct memc_flexspi_w956a8mbya_data *data = dev->data; + uint16_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, + config->port)) { + LOG_ERR("Could not set device configuration"); + return -EINVAL; + } + + if (memc_flexspi_update_lut(data->controller, 0, + (const uint32_t *) memc_flexspi_w956a8mbya_lut, + sizeof(memc_flexspi_w956a8mbya_lut) / 4)) { + LOG_ERR("Could not update lut"); + return -EINVAL; + } + + memc_flexspi_reset(data->controller); + + if (memc_flexspi_w956a8mbya_get_vendor_id(dev, &vendor_id)) { + LOG_ERR("Could not read vendor id"); + return -EIO; + } + LOG_DBG("Vendor id: 0x%0x", 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), \ + .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 = true, \ + } \ + +#define MEMC_FLEXSPI_W956A8MBYA(n) \ + static const struct memc_flexspi_w956a8mbya_config \ + memc_flexspi_w956a8mbya_config_##n = { \ + .port = DT_INST_REG_ADDR(n), \ + .config = MEMC_FLEXSPI_DEVICE_CONFIG(n), \ + }; \ + \ + static struct memc_flexspi_w956a8mbya_data \ + memc_flexspi_w956a8mbya_data_##n = { \ + .controller = DEVICE_DT_GET(DT_INST_BUS(n)), \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, \ + memc_flexspi_w956a8mbya_init, \ + NULL, \ + &memc_flexspi_w956a8mbya_data_##n, \ + &memc_flexspi_w956a8mbya_config_##n, \ + POST_KERNEL, \ + CONFIG_MEMC_INIT_PRIORITY, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(MEMC_FLEXSPI_W956A8MBYA) diff --git a/dts/bindings/mtd/nxp,imx-flexspi-w956a8mbya.yaml b/dts/bindings/mtd/nxp,imx-flexspi-w956a8mbya.yaml new file mode 100644 index 00000000000..ebfcaf3c36b --- /dev/null +++ b/dts/bindings/mtd/nxp,imx-flexspi-w956a8mbya.yaml @@ -0,0 +1,9 @@ +# Copyright (c) 2023, ithinx GmbH +# Copyright (c) 2023, Tonies GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: Winbond W956A8MBYA HyperRAM on NXP FlexSPI bus + +compatible: "nxp,imx-flexspi-w956a8mbya" + +include: nxp,imx-flexspi-device.yaml