diff --git a/drivers/flash/CMakeLists.txt b/drivers/flash/CMakeLists.txt index 089259a2572a..821f78c25d94 100644 --- a/drivers/flash/CMakeLists.txt +++ b/drivers/flash/CMakeLists.txt @@ -1,3 +1,5 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# # SPDX-License-Identifier: Apache-2.0 zephyr_library_sources(flash_util.c) @@ -34,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_MX25UM51345G flash_mcux_f zephyr_library_sources_ifdef(CONFIG_FLASH_MCUX_FLEXSPI_NOR flash_mcux_flexspi_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_ATXP032 flash_mspi_atxp032.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_EMUL_DEVICE flash_mspi_emul_device.c) +zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_INFINEON_S25H flash_mspi_infineon_s25h.c) zephyr_library_sources_ifdef(CONFIG_FLASH_MSPI_NOR flash_mspi_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_NOR flash_npcx_fiu_nor.c) zephyr_library_sources_ifdef(CONFIG_FLASH_NPCX_FIU_QSPI flash_npcx_fiu_qspi.c) diff --git a/drivers/flash/Kconfig.mspi b/drivers/flash/Kconfig.mspi index d699aa493093..f0bce8effd00 100644 --- a/drivers/flash/Kconfig.mspi +++ b/drivers/flash/Kconfig.mspi @@ -1,4 +1,5 @@ # Copyright (c) 2024 Ambiq Micro Inc. +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 menu "MSPI flash device driver" @@ -51,4 +52,12 @@ config FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE endif # FLASH_MSPI_NOR +config FLASH_MSPI_INFINEON_S25H + bool "MSPI Infineon S25H driver" + default y + depends on DT_HAS_INFINEON_S25H_FLASH_ENABLED + select FLASH_MSPI + select FLASH_HAS_PAGE_LAYOUT + select FLASH_HAS_EXPLICIT_ERASE + endmenu diff --git a/drivers/flash/flash_mspi_infineon_s25h.c b/drivers/flash/flash_mspi_infineon_s25h.c new file mode 100644 index 000000000000..7e0514ac321f --- /dev/null +++ b/drivers/flash/flash_mspi_infineon_s25h.c @@ -0,0 +1,837 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT infineon_s25h_flash + +#include "flash_mspi_infineon_s25h.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(flash_mspi_infineon_s25h, CONFIG_FLASH_LOG_LEVEL); + +struct flash_mspi_infineon_s25h_cfg { + DEVICE_MMIO_ROM; + const struct device *bus; + const struct pinctrl_dev_config *pinctrl; + k_timeout_t reset_startup_duration; + + const struct mspi_dev_cfg mspi_dev_cfg; + + const struct flash_pages_layout page_layout; + const struct flash_parameters parameters; + + const struct mspi_dev_id dev_id; +}; + +struct flash_mspi_infineon_s25h_data { + struct mspi_dev_cfg mspi_dev_cfg; + uint8_t read_jedec_cmd; + uint8_t read_flash_cmd; + uint8_t read_flash_dummy_cycles; +}; + +static int flash_mspi_infineon_s25h_prepare_mspi_bus(const struct device *dev) +{ + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *data = dev->data; + + return mspi_dev_config(config->bus, &config->dev_id, + MSPI_DEVICE_CONFIG_CE_NUM | MSPI_DEVICE_CONFIG_IO_MODE | + MSPI_DEVICE_CONFIG_CPP | MSPI_DEVICE_CONFIG_CE_POL | + MSPI_DEVICE_CONFIG_DQS | MSPI_DEVICE_CONFIG_DATA_RATE | + MSPI_DEVICE_CONFIG_ENDIAN, + &data->mspi_dev_cfg); +} + +static int flash_mspi_infineon_s25h_reset(const struct device *dev) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + const struct mspi_xfer_packet reset_packets[] = { + { + .dir = MSPI_TX, + .cmd = INF_MSPI_S25H_OPCODE_RESET_ENABLE, + .num_bytes = 0, + }, + { + .dir = MSPI_TX, + .cmd = INF_MSPI_S25H_OPCODE_RESET, + .num_bytes = 0, + }}; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .rx_dummy = 0, + .addr_length = 0, + .num_packet = 2, + .packets = reset_packets, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer); + if (ret < 0) { + return ret; + } + + k_sleep(config->reset_startup_duration); + + return 0; +} + +static int flash_mspi_infineon_s25h_set_writing_forbidden(const struct device *dev, + bool writing_forbidden) +{ + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + uint8_t cmd = writing_forbidden ? INF_MSPI_S25H_OPCODE_WRITE_DISABLE + : INF_MSPI_S25H_OPCODE_WRITE_ENABLE; + const struct mspi_xfer_packet packet = { + .dir = MSPI_TX, + .cmd = cmd, + .num_bytes = 0, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA_SINGLE_CMD, + .packets = &packet, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + return mspi_transceive(config->bus, &config->dev_id, &xfer); +} + +static int flash_mspi_infineon_s25h_rw_any_register(const struct device *dev, uint32_t address, + uint8_t *value, uint32_t delay, + enum mspi_xfer_direction dir) +{ + int ret; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; + uint32_t cmd; + uint32_t rx_dummy; + + if (dir == MSPI_TX) { + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error disabling write protection before changing configuration"); + return ret; + } + } + + if (dir == MSPI_RX) { + cmd = INF_MSPI_S25H_OPCODE_READ_ANY_REGISTER; + rx_dummy = delay; + } else { + cmd = INF_MSPI_S25H_OPCODE_WRITE_ANY_REGISTER; + rx_dummy = 0; + } + + const struct mspi_xfer_packet packet = { + .dir = dir, + .cmd = cmd, + .num_bytes = 1, + .data_buf = value, + .address = address, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = dev_data->mspi_dev_cfg.addr_length, + .rx_dummy = rx_dummy, + .packets = &packet, + .num_packet = 1, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + return mspi_transceive(config->bus, &config->dev_id, &xfer); +} + +static int flash_mspi_infineon_s25h_is_write_protection_enabled(const struct device *dev, + uint8_t *is_enabled) +{ + int ret = 0; + uint8_t val = 0; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, + &val, 0, MSPI_RX); + if (ret < 0) { + return ret; + } + *is_enabled = (val & INF_MSPI_S25H_STATUS_1_WRPGEN_BIT); + return 0; +} + +static int flash_mspi_infineon_s25h_wait_for_idle(const struct device *dev, uint32_t timeout_ms) +{ + int ret = 0; + uint8_t status_1 = 0; + uint32_t retries = timeout_ms / INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL_MS; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, + &status_1, 0, MSPI_RX); + if (ret < 0) { + return ret; + } + + while ((status_1 & INF_MSPI_S25H_STATUS_1_RDYBSY_BIT) != 0 && retries > 0) { + k_sleep(INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL); + ret = flash_mspi_infineon_s25h_rw_any_register( + dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, &status_1, 0, MSPI_RX); + if (ret < 0) { + return ret; + } + --retries; + } + + if (retries == 0) { + LOG_ERR("Waiting for flash to enter idle. Status 1 register: 0x%X", status_1); + return -EIO; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_read_jedec_id(const struct device *dev, uint8_t *buf) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *data = dev->data; + + const struct mspi_xfer_packet packet = { + .dir = MSPI_RX, + .cmd = data->read_jedec_cmd, + .num_bytes = 3, + .data_buf = buf, + .address = 0, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = 0, + .rx_dummy = 0, + .packets = &packet, + .num_packet = 1, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer); + if (ret < 0) { + LOG_ERR("Error reading JEDEC id"); + return ret; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_read(const struct device *dev, off_t addr, void *data, + size_t size) +{ + int ret = 0; + bool requires_cleanup = false; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; + + /* The S25H allows for continuous read operations which happen by sending + * 0xAX after an address. The driver doesn't implement this which is why we + * don't want this and instead wait for 2 cycles. However since the flash + * pins could be in high impedance state from the MSPI controller after the + * address was sent an address ending with 0xA could put the flash into a + * continuous read mode. To prevent this the driver will read the jedec id, + * if the address wasn't aligned to prevent accidentally fulfilling the + * requirement. + */ + if (dev_data->mspi_dev_cfg.io_mode == MSPI_IO_MODE_QUAD && (addr % 16 != 0)) { + requires_cleanup = true; + } + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error setting up the MSPI bus for the flash device"); + return ret; + } + + const struct mspi_xfer_packet packet = { + .address = addr, + .cmd = dev_data->read_flash_cmd, + .data_buf = data, + .dir = MSPI_RX, + .num_bytes = size, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = dev_data->mspi_dev_cfg.addr_length, + .rx_dummy = dev_data->read_flash_dummy_cycles, + .packets = &packet, + .num_packet = 1, + /* 20 milliseconds + 1 ms per 4KiB; for 256 KiB this results in 84 ms */ + .timeout = (size / 4096) + 20, + }; + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer); + if (ret < 0) { + return ret; + } + + if (requires_cleanup) { + uint8_t unused[3]; + (void)unused; + return flash_mspi_infineon_s25h_read_jedec_id(dev, unused); + } + + return ret; +} + +static int flash_mspi_infineon_s25h_single_block_write(const struct device *dev, + const struct mspi_xfer *xfer_write) +{ + int ret; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + uint8_t status_1; + + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error disabling write protection before trying to write data into " + "flash"); + return ret; + } + + ret = mspi_transceive(config->bus, &config->dev_id, xfer_write); + if (ret < 0) { + LOG_ERR("Error writing flash memory"); + return ret; + } + + ret = flash_mspi_infineon_s25h_wait_for_idle(dev, + INF_MSPI_S25H_TIMEOUT_IDLE_WRITE_BLOCK_MS); + if (ret < 0) { + LOG_ERR("Error waiting for flash to enter idle after writing"); + return ret; + } + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1, + &status_1, 0, MSPI_RX); + + if (ret < 0) { + LOG_ERR("Error reading back status 1 register to confirm valid write"); + return ret; + } + + if (status_1 & INF_MSPI_S25H_STATUS_1_PRGERR_BIT) { + LOG_ERR("Last programming transaction wasn't successful"); + return -EIO; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_write(const struct device *dev, off_t addr, + const void *transmission_data, size_t size) +{ + int ret = 0; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; + uint8_t old_write_protection; + uint8_t *data_buf = (uint8_t *)transmission_data; + + /* Check whether we are not aligned and would write over a block boundary */ + if ((addr % INF_MSPI_S25H_WRITE_BLOCK_SIZE) != 0 && + (addr % INF_MSPI_S25H_WRITE_BLOCK_SIZE) + size >= INF_MSPI_S25H_WRITE_BLOCK_SIZE) { + LOG_ERR("Non-aligned write that goes above another block isn't supported"); + return -ENOSYS; + } + + struct mspi_xfer_packet packet_write = { + .cmd = INF_MSPI_S25H_OPCODE_WRITE_FLASH, + .dir = MSPI_TX, + }; + + struct mspi_xfer xfer_write = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = dev_data->mspi_dev_cfg.addr_length, + .rx_dummy = 0, + .packets = &packet_write, + .num_packet = 1, + /* 20 milliseconds + 1 ms per 16KiB; for 256 KiB this results in 36 ms */ + .timeout = (size / 16384) + 20, + }; + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error setting up the MSPI bus for the flash device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_is_write_protection_enabled(dev, &old_write_protection); + if (ret < 0) { + LOG_ERR("Error querying whether write protection is enabled"); + return ret; + } + + uint32_t remaining_bytes = size; + uint32_t write_index = 0; + uint32_t write_block_count = size / INF_MSPI_S25H_WRITE_BLOCK_SIZE; + uint32_t current_transaction_transfer_size; + + if (size % INF_MSPI_S25H_WRITE_BLOCK_SIZE != 0) { + ++write_block_count; + } + + do { + current_transaction_transfer_size = + MIN(remaining_bytes, INF_MSPI_S25H_WRITE_BLOCK_SIZE); + packet_write.num_bytes = current_transaction_transfer_size; + packet_write.address = addr + (write_index * INF_MSPI_S25H_WRITE_BLOCK_SIZE); + packet_write.data_buf = &data_buf[write_index * INF_MSPI_S25H_WRITE_BLOCK_SIZE]; + + ret = flash_mspi_infineon_s25h_single_block_write(dev, &xfer_write); + if (ret < 0) { + return ret; + } + + remaining_bytes -= current_transaction_transfer_size; + ++write_index; + + } while (remaining_bytes > 0); + + if (old_write_protection) { + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error re-enabling write protection after writing data into flash"); + return ret; + } + } + + return 0; +} + +static int flash_mspi_infineon_s25h_erase(const struct device *dev, off_t addr, size_t size) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *dev_data = dev->data; + uint8_t old_write_protection; + + struct mspi_xfer_packet packet_erase = { + .cmd = INF_MSPI_S25H_OPCODE_ERASE_256K, + .data_buf = NULL, + .num_bytes = 0, + .dir = MSPI_TX, + }; + + const struct mspi_xfer xfer_erase = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .addr_length = dev_data->mspi_dev_cfg.addr_length, + .rx_dummy = 0, + .packets = &packet_erase, + .num_packet = 1, + /* 20 milliseconds + 1 ms per 16KiB; for 256 KiB this results in 36 ms */ + .timeout = (size / 16384) + 20, + }; + + if (addr % INF_MSPI_S25H_ERASE_SECTOR_SIZE != 0) { + LOG_WRN("Erase sector is not aligned! This might erase data you don't want to " + "erase"); + } + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error setting up the MSPI bus for the flash device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_is_write_protection_enabled(dev, &old_write_protection); + if (ret < 0) { + LOG_ERR("Error querying whether write protection is enabled"); + return ret; + } + + uint32_t count = size / INF_MSPI_S25H_ERASE_SECTOR_SIZE; + + if (size % INF_MSPI_S25H_ERASE_SECTOR_SIZE != 0) { + ++count; + } + + for (uint32_t i = 0; i < count; ++i) { + packet_erase.address = addr + (i * INF_MSPI_S25H_ERASE_SECTOR_SIZE); + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error disabling write protection before flash erase"); + return ret; + } + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer_erase); + if (ret) { + LOG_ERR("Error sending erase command"); + return ret; + } + + ret = flash_mspi_infineon_s25h_wait_for_idle( + dev, INF_MSPI_S25H_TIMEOUT_IDLE_ERASE_SECTOR_MS); + if (ret < 0) { + LOG_ERR("Error waiting for flash to enter idle after erasing"); + return ret; + } + } + + if (old_write_protection) { + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, false); + if (ret < 0) { + LOG_ERR("Error re-enabling write protection after flash erase"); + return ret; + } + } + + return 0; +} + +static const struct flash_parameters * +flash_mspi_infineon_s25h_get_parameters(const struct device *dev) +{ + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + return &config->parameters; +} + +#if defined(CONFIG_FLASH_PAGE_LAYOUT) +static void flash_mspi_infineon_s25h_pages_layout(const struct device *dev, + const struct flash_pages_layout **layout, + size_t *layout_size) +{ + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + *layout = &config->page_layout; + *layout_size = 1; +} +#endif + +static int flash_mspi_infineon_s25h_verify_jedec_id(const struct device *dev) +{ + uint8_t id[3]; + int ret; + + ret = flash_mspi_infineon_s25h_read_jedec_id(dev, id); + if (ret < 0) { + LOG_ERR("Error reading JEDEC ids from flash"); + return ret; + } + + uint8_t manufacturer_id = id[0]; + uint16_t device_id = (id[1] << 8) | id[2]; + + if (manufacturer_id != INF_MSPI_S25H_MANUFACTURER_ID || + device_id != INF_MSPI_S25H_DEVICE_ID) { + LOG_ERR("Rear JEDEC ids don't match expected ids. The communication is possibly " + "broken or the non-volatile flash configuration is something unexpected"); + LOG_ERR("Read manufacturer id: 0x%02X. Expected: 0x%02X", manufacturer_id, + INF_MSPI_S25H_MANUFACTURER_ID); + LOG_ERR("Read device id: 0x%04X. Expected: 0x%04X", device_id, + INF_MSPI_S25H_DEVICE_ID); + return -EIO; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_switch_to_quad_transfer(const struct device *dev) +{ + int ret; + struct flash_mspi_infineon_s25h_data *data = dev->data; + + uint8_t cfg_value; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1, + &cfg_value, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading flash register"); + return ret; + } + + cfg_value |= INF_MSPI_S25H_CFG_1_QUADIT_BIT; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1, + &cfg_value, 0, MSPI_TX); + if (ret < 0) { + LOG_ERR("Error writing flash register"); + return ret; + } + + /* set address + data to 4 lanes */ + data->mspi_dev_cfg.io_mode = MSPI_IO_MODE_QUAD_1_4_4; + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + + if (ret < 0) { + LOG_ERR("Error switching MSPI mode to 4 lane data width"); + return ret; + } + + data->read_flash_cmd = INF_MSPI_S25H_OPCODE_READ_FLASH_QUAD; + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1, + &cfg_value, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading flash register"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + LOG_ERR("JEDEC ID mismatch after switching to 4 lane MSPI. Communication is " + "broken"); + return ret; + } + + /* set command to 4 lanes */ + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_2, + &cfg_value, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading flash register"); + return ret; + } + + cfg_value |= INF_MSPI_S25H_CFG_2_QPI_IT_BIT; + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_2, + &cfg_value, 0, MSPI_TX); + if (ret < 0) { + LOG_ERR("Error writing flash register"); + return ret; + } + + data->mspi_dev_cfg.io_mode = MSPI_IO_MODE_QUAD; + data->read_jedec_cmd = INF_MSPI_S25H_OPCODE_READ_JEDEC_ID_QUAD; + data->read_flash_dummy_cycles = INF_MSPI_S25H_DELAY_READ_QUADSPI; + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error switching bus mode to full quad MSPI mode"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + LOG_ERR("JEDEC ID mismatch after switching to full quad MSPI mode. Communication " + "is broken"); + return ret; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_disable_hybrid_sector_mode(const struct device *dev) +{ + /* This driver needs the hybrid sector mode to be disabled. So if it's found to be turned on + * it gets changed. This requires changing the non-volatile configuration and also a reset + */ + int ret = 0; + uint8_t conf3 = 0; + + ret = flash_mspi_infineon_s25h_rw_any_register(dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_3, + &conf3, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading volatile configuration register 3"); + return ret; + } + + if ((conf3 & INF_MSPI_S25H_CFG_3_UNHYSA_BIT) == 0) { + LOG_INF("Flash is in hybrid sector mode. Changing non-volatile config to correct " + "this"); + + conf3 |= INF_MSPI_S25H_CFG_3_UNHYSA_BIT; + + ret = flash_mspi_infineon_s25h_rw_any_register( + dev, INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_3, &conf3, 0, MSPI_TX); + if (ret < 0) { + LOG_ERR("Error changing non-volatile configuration of flash"); + return ret; + } + + ret = flash_mspi_infineon_s25h_wait_for_idle(dev, + INF_MSPI_S25H_TIMEOUT_IDLE_STARTUP); + if (ret < 0) { + LOG_ERR("Error waiting for flash to enter idle after disabling hybrid " + "sector mode"); + return ret; + } + + ret = flash_mspi_infineon_s25h_reset(dev); + if (ret < 0) { + LOG_ERR("Error resetting flash via reset command"); + return ret; + } + + conf3 = 0; + ret = flash_mspi_infineon_s25h_rw_any_register( + dev, INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_3, &conf3, 0, MSPI_RX); + if (ret < 0) { + LOG_ERR("Error reading volatile config 3 register of flash"); + return ret; + } + + if ((conf3 & INF_MSPI_S25H_CFG_3_UNHYSA_BIT) == 0) { + LOG_ERR("Changing the flash configuration to Uniform mode didn't work"); + return -EIO; + } + + ret = flash_mspi_infineon_s25h_set_writing_forbidden(dev, true); + if (ret < 0) { + LOG_ERR("Error re-enabling the write protection"); + return ret; + } + } + + return 0; +} + +static int flash_mspi_infineon_s25h_enter_4_byte_address_mode(const struct device *dev) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + struct flash_mspi_infineon_s25h_data *data = dev->data; + + const struct mspi_xfer_packet enter_4_byte_cmd = { + .dir = MSPI_TX, + .cmd = INF_MSPI_S25H_OPCODE_ENABLE_4_BYTE_ADDR_MODE, + .num_bytes = 0, + }; + + struct mspi_xfer xfer = { + INF_MSPI_S25H_DEFAULT_XFER_DATA, + .rx_dummy = 0, + .addr_length = 0, + .num_packet = 1, + .packets = &enter_4_byte_cmd, + .timeout = INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT, + }; + + ret = mspi_transceive(config->bus, &config->dev_id, &xfer); + if (ret < 0) { + LOG_ERR("Error sending command to enter 4 byte address mode"); + return ret; + } + + data->mspi_dev_cfg.addr_length = 4; + + if (ret < 0) { + LOG_ERR("Error setting up MSPI bus after changing address length"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + LOG_ERR("Error verifying JEDEC id after entering 4 byte address mode"); + return ret; + } + + return 0; +} + +static int flash_mspi_infineon_s25h_init(const struct device *dev) +{ + int ret = 0; + const struct flash_mspi_infineon_s25h_cfg *config = dev->config; + + ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to apply pinctrl"); + return ret; + } + + ret = flash_mspi_infineon_s25h_prepare_mspi_bus(dev); + if (ret < 0) { + LOG_ERR("Error switching MSPI configuration to the requirements of the flash " + "device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_reset(dev); + if (ret < 0) { + LOG_ERR("Error resetting flash device"); + return ret; + } + + ret = flash_mspi_infineon_s25h_verify_jedec_id(dev); + if (ret < 0) { + return ret; + } + + ret = flash_mspi_infineon_s25h_disable_hybrid_sector_mode(dev); + if (ret < 0) { + return ret; + } + + ret = flash_mspi_infineon_s25h_enter_4_byte_address_mode(dev); + if (ret < 0) { + return ret; + } + + ret = flash_mspi_infineon_s25h_switch_to_quad_transfer(dev); + if (ret < 0) { + return ret; + } + + return 0; +} + +static DEVICE_API(flash, flash_mspi_infineon_s25h_driver_api) = { + .read = flash_mspi_infineon_s25h_read, + .write = flash_mspi_infineon_s25h_write, + .erase = flash_mspi_infineon_s25h_erase, + .get_parameters = flash_mspi_infineon_s25h_get_parameters, +#if defined(CONFIG_FLASH_JESD216_API) + .read_jedec_id = flash_mspi_infineon_s25h_read_jedec_id, +#endif +#if defined(CONFIG_FLASH_PAGE_LAYOUT) + .page_layout = flash_mspi_infineon_s25h_pages_layout, +#endif +}; + +#define INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, prop) \ + BUILD_ASSERT(DT_NODE_HAS_PROP(DT_DRV_INST(n), prop) == 0, \ + "The Infineon S25H driver ignores the property " #prop ". Don't use it") + +/* Check for ignored/wrong values in the devicetree */ +#define INFINEON_MSPI_FLASH_S25H_CHECK_DEVICETREE_CONFIG(n) \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, rx_dummy); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, tx_dummy); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, read_command); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, write_command); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, xip_config); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, scramble_config); \ + INFINEON_MSPI_FLASH_S25H_CHECK_PROP_IS_UNDEFINED(n, ce_break_config); \ + BUILD_ASSERT(DT_ENUM_HAS_VALUE(DT_DRV_INST(n), command_length, INSTR_1_BYTE) == 1, \ + "The Infineon S25H chip uses only 1 byte opcodes") + +#define INFINFEON_MSPI_FLASH_S25H_DEFINE(n) \ + INFINEON_MSPI_FLASH_S25H_CHECK_DEVICETREE_CONFIG(n); \ + PINCTRL_DT_DEFINE(DT_DRV_INST(n)); \ + static const struct flash_mspi_infineon_s25h_cfg flash_mspi_infineon_s25h_cfg_##n = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ + .bus = DEVICE_DT_GET(DT_BUS(DT_DRV_INST(n))), \ + .pinctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .reset_startup_duration = K_USEC(DT_INST_PROP(n, reset_startup_time_us)), \ + .dev_id = MSPI_DEVICE_ID_DT_INST(n), \ + .page_layout = {.pages_count = DT_INST_PROP(n, flash_size) / \ + DT_INST_PROP(n, erase_block_size), \ + .pages_size = DT_INST_PROP(n, erase_block_size)}, \ + .parameters = {.erase_value = 0xFF, \ + .write_block_size = DT_INST_PROP(n, write_block_size)}}; \ + static struct flash_mspi_infineon_s25h_data flash_mspi_infineon_s25h_data_##n = { \ + .mspi_dev_cfg = MSPI_DEVICE_CONFIG_DT_INST(n), \ + .read_jedec_cmd = INF_MSPI_S25H_OPCODE_READ_JEDEC_ID, \ + .read_flash_cmd = INF_MSPI_S25H_OPCODE_READ_FLASH, \ + .read_flash_dummy_cycles = 0, \ + }; \ + DEVICE_DT_INST_DEFINE(n, flash_mspi_infineon_s25h_init, NULL, \ + &flash_mspi_infineon_s25h_data_##n, \ + &flash_mspi_infineon_s25h_cfg_##n, POST_KERNEL, \ + CONFIG_FLASH_INIT_PRIORITY, &flash_mspi_infineon_s25h_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(INFINFEON_MSPI_FLASH_S25H_DEFINE) diff --git a/drivers/flash/flash_mspi_infineon_s25h.h b/drivers/flash/flash_mspi_infineon_s25h.h new file mode 100644 index 000000000000..67fee8a77707 --- /dev/null +++ b/drivers/flash/flash_mspi_infineon_s25h.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_FLASH_MSPI_INFINEON_S25H_ +#define ZEPHYR_DRIVERS_FLASH_MSPI_INFINEON_S25H_ + +#include "zephyr/kernel.h" +#include "zephyr/sys/util_macro.h" + +/* defaults */ +#define INF_MSPI_S25H_DEFAULT_MSPI_TIMEOUT 30 + +/* opcodes 1-1-1 mode */ +#define INF_MSPI_S25H_OPCODE_WRITE_ENABLE 0x06 +#define INF_MSPI_S25H_OPCODE_WRITE_DISABLE 0x04 +#define INF_MSPI_S25H_OPCODE_ENABLE_4_BYTE_ADDR_MODE 0xB7 + +#define INF_MSPI_S25H_OPCODE_READ_ANY_REGISTER 0x65 +#define INF_MSPI_S25H_OPCODE_WRITE_ANY_REGISTER 0x71 + +#define INF_MSPI_S25H_OPCODE_ERASE_256K 0xD8 +#define INF_MSPI_S25H_OPCODE_READ_FLASH 0x03 +#define INF_MSPI_S25H_OPCODE_WRITE_FLASH 0x02 + +#define INF_MSPI_S25H_OPCODE_RESET_ENABLE 0x66 +#define INF_MSPI_S25H_OPCODE_RESET 0x99 + +#define INF_MSPI_S25H_OPCODE_READ_JEDEC_ID 0x9F + +/* opcodes 4-4-4 mode */ +#define INF_MSPI_S25H_OPCODE_READ_FLASH_QUAD 0xEB +#define INF_MSPI_S25H_OPCODE_READ_JEDEC_ID_QUAD 0xAF + +/* RX delay */ +/* 2 cycles for the mode bit to be ignored in Quad SPI mode; 8 from the default configuration */ +#define INF_MSPI_S25H_DELAY_READ_QUADSPI (2 + 8) + +/* addresses */ +#define INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_1 0x00800000 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_STATUS_2 0x00800001 + +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_1 0x00800002 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_2 0x00800003 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_3 0x00800004 +#define INF_MSPI_S25H_ADDRESS_VOLATILE_CFG_4 0x00800005 + +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_STATUS_1 0x0 + +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_1 0x2 +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_2 0x3 +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_3 0x4 +#define INF_MSPI_S25H_ADDRESS_NON_VOLATILE_CFG_4 0x5 + +/* device specific data */ +#define INF_MSPI_S25H_MANUFACTURER_ID 0x34 +#define INF_MSPI_S25H_DEVICE_ID 0x2A1A + +#define INF_MSPI_S25H_ERASE_SECTOR_SIZE 262144 +#define INF_MSPI_S25H_WRITE_BLOCK_SIZE 256 + +/* default data */ +#define INF_MSPI_S25H_DEFAULT_XFER_DATA \ + .async = false, .cmd_length = 1, .hold_ce = false, .priority = 0, .tx_dummy = 0, \ + .xfer_mode = MSPI_PIO + +#define INF_MSPI_S25H_DEFAULT_XFER_DATA_SINGLE_CMD \ + INF_MSPI_S25H_DEFAULT_XFER_DATA, .rx_dummy = 0, .addr_length = 0, .num_packet = 1 + +#define INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL_MS 10 +#define INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL \ + K_MSEC(INF_MSPI_S25H_TIMEOUT_IDLE_RETRY_INTERVAL_MS) +#define INF_MSPI_S25H_TIMEOUT_IDLE_ERASE_SECTOR_MS 1000 +#define INF_MSPI_S25H_TIMEOUT_IDLE_WRITE_BLOCK_MS 1000 +#define INF_MSPI_S25H_TIMEOUT_IDLE_STARTUP 100 + +/* register bits */ +#define INF_MSPI_S25H_STATUS_1_RDYBSY_BIT BIT(0) +#define INF_MSPI_S25H_STATUS_1_WRPGEN_BIT BIT(1) +#define INF_MSPI_S25H_STATUS_1_LBPROT_SHIFT 2 +#define INF_MSPI_S25H_STATUS_1_LBPROT_MASK BIT_MASK(3) +#define INF_MSPI_S25H_STATUS_1_ERSERR_BIT BIT(5) +#define INF_MSPI_S25H_STATUS_1_PRGERR_BIT BIT(6) +#define INF_MSPI_S25H_STATUS_1_STCFWR_BIT BIT(7) + +#define INF_MSPI_S25H_STATUS_2_PROGMS_BIT BIT(0) +#define INF_MSPI_S25H_STATUS_2_ERASES_BIT BIT(1) +#define INF_MSPI_S25H_STATUS_2_SESTAT_BIT BIT(2) +#define INF_MSPI_S25H_STATUS_2_DICRCA_BIT BIT(3) +#define INF_MSPI_S25H_STATUS_2_DICRCS_BIT BIT(4) + +#define INF_MSPI_S25H_CFG_1_TLPROT_BIT BIT(0) +#define INF_MSPI_S25H_CFG_1_QUADIT_BIT BIT(1) +#define INF_MSPI_S25H_CFG_1_TB4KBS_BIT BIT(2) +#define INF_MSPI_S25H_CFG_1_PLPROT_BIT BIT(4) +#define INF_MSPI_S25H_CFG_1_TBPROT_BIT BIT(5) +#define INF_MSPI_S25H_CFG_1_SP4KBS_BIT BIT(6) + +#define INF_MSPI_S25H_CFG_2_MEMLAT_SHIFT 0 +#define INF_MSPI_S25H_CFG_2_MEMLAT_MASK BIT_MASK(4) +#define INF_MSPI_S25H_CFG_2_DQ3RST_BIT BIT(5) +#define INF_MSPI_S25H_CFG_2_QPI_IT_BIT BIT(6) +#define INF_MSPI_S25H_CFG_2_ADRBYT_BIT BIT(7) + +#define INF_MSPI_S25H_CFG_3_LSFRST_BIT BIT(0) +#define INF_MSPI_S25H_CFG_3_CLSRSM_BIT BIT(2) +#define INF_MSPI_S25H_CFG_3_UNHYSA_BIT BIT(3) +#define INF_MSPI_S25H_CFG_3_PGMBUF_BIT BIT(4) +#define INF_MSPI_S25H_CFG_3_BLKCHK_BIT BIT(5) +#define INF_MSPI_S25H_CFG_3_VRGLAT_SHIFT 6 +#define INF_MSPI_S25H_CFG_3_VRGLAT_MASK BIT_MASK(2) + +#define INF_MSPI_S25H_CFG_4_RBSTWL_SHIFT 0 +#define INF_MSPI_S25H_CFG_4_RBSTWL_MASK BIT_MASK(2) +#define INF_MSPI_S25H_CFG_4_DPDPOR_BIT BIT(2) +#define INF_MSPI_S25H_CFG_4_ECC12S_BIT BIT(3) +#define INF_MSPI_S25H_CFG_4_RBSTWP_BIT BIT(4) +#define INF_MSPI_S25H_CFG_4_IOIMPD_SHIFT 5 +#define INF_MSPI_S25H_CFG_4_IOIMPD_MASK BIT_MASK(3) + +#endif /* ZEPHYR_DRIVERS_FLASH_MSPI_INFINEON_S25H_ */ diff --git a/drivers/mspi/CMakeLists.txt b/drivers/mspi/CMakeLists.txt index 78f704393f42..29402023088b 100644 --- a/drivers/mspi/CMakeLists.txt +++ b/drivers/mspi/CMakeLists.txt @@ -1,3 +1,4 @@ +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/mspi.h) @@ -6,3 +7,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_MSPI_AMBIQ_AP3 mspi_ambiq_ap3.c) zephyr_library_sources_ifdef(CONFIG_MSPI_DW mspi_dw.c) zephyr_library_sources_ifdef(CONFIG_MSPI_EMUL mspi_emul.c) +zephyr_library_sources_ifdef(CONFIG_MSPI_TI_K3 mspi_ti_k3.c) diff --git a/drivers/mspi/Kconfig b/drivers/mspi/Kconfig index 269d8d16f04a..7795613394ba 100644 --- a/drivers/mspi/Kconfig +++ b/drivers/mspi/Kconfig @@ -1,6 +1,7 @@ # MSPI driver configuration options # Copyright (c) 2024 Ambiq Micro Inc. +# Copyright (c) 2025 Siemens Mobility GmbH # SPDX-License-Identifier: Apache-2.0 # @@ -62,5 +63,6 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/mspi/Kconfig.ambiq" source "drivers/mspi/Kconfig.dw" source "drivers/mspi/Kconfig.mspi_emul" +source "drivers/mspi/Kconfig.ti_k3" endif # MSPI diff --git a/drivers/mspi/Kconfig.ti_k3 b/drivers/mspi/Kconfig.ti_k3 new file mode 100644 index 000000000000..779efc31f8d5 --- /dev/null +++ b/drivers/mspi/Kconfig.ti_k3 @@ -0,0 +1,13 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +config MSPI_TI_K3 + bool "TI K3 MSPI driver" + default y + depends on DT_HAS_TI_K3_MSPI_CONTROLLER_ENABLED + # GPIO is required for ce_gpios despite the field being ignored + select GPIO + select PINCTRL + select MSPI_TIMING + help + Enable driver for Ti Keystone 3 devices diff --git a/drivers/mspi/mspi_ti_k3.c b/drivers/mspi/mspi_ti_k3.c new file mode 100644 index 000000000000..d9e99fc46069 --- /dev/null +++ b/drivers/mspi/mspi_ti_k3.c @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_k3_mspi_controller + +#include "mspi_ti_k3.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(mspi_ti_k3, CONFIG_MSPI_LOG_LEVEL); + +struct mspi_ti_k3_config { + DEVICE_MMIO_ROM; + struct mspi_cfg mspi_config; + const struct pinctrl_dev_config *pinctrl; + const uint32_t fifo_addr; + const uint32_t sram_allocated_for_read; + + const struct mspi_ti_k3_timing_cfg initial_timing_cfg; +}; + +struct mspi_ti_k3_data { + DEVICE_MMIO_RAM; + struct k_mutex lock; +}; + +/* helper function to easily modify parts of registers */ +static void mspi_ti_k3_set_bits_shifted(const uint32_t value, const uint32_t num_bits, + const uint32_t shift, const mem_addr_t address) +{ + __ASSERT(num_bits <= 32, "Invalid number of bits provided"); + __ASSERT(shift <= 31, "Invalid shift value provided"); + __ASSERT((value & ~BIT_MASK(num_bits)) == 0, + "Tried writing a value that overflows the number of bits that should be changed"); + + uint32_t tmp = sys_read32(address); + + tmp &= ~(BIT_MASK(num_bits) << shift); + tmp |= (value << shift); + + sys_write32(tmp, address); +} + +/** + * Set value in part of a register. The reg is the name of the register where + * content should be set and field is the field that should be changed. It is + * implemented via macro concatenation to prevent overly long code. An + * explanation of how the registers / fields are named are in the corresponding + * header file. + */ +#define MSPI_TI_K3_REG_WRITE(value, reg, field, base_addr) \ + mspi_ti_k3_set_bits_shifted(value, TI_K3_OSPI_##reg##_##field##_FLD_SIZE, \ + TI_K3_OSPI_##reg##_##field##_FLD_OFFSET, \ + base_addr + TI_K3_OSPI_##reg##_REG) + +/** + * Read an entire register by name. Short version for sys_read32 with base_addr and offset + */ +#define MSPI_TI_K3_REG_READ(reg, base_addr) sys_read32(base_addr + TI_K3_OSPI_##reg##_REG) + +/** + * Read part of a register. This is done via macro concatenation to allow + * shorter code. The reg is the name of the register from which should be read + * and the field is which field of the register should be extracted. + */ +#define MSPI_TI_K3_REG_READ_MASKED(reg, field, base_addr) \ + ((sys_read32(base_addr + TI_K3_OSPI_##reg##_REG) >> \ + TI_K3_OSPI_##reg##_##field##_FLD_OFFSET) & \ + BIT_MASK(TI_K3_OSPI_##reg##_##field##_FLD_SIZE)) + +/** + * Wait for the OSPI controller to enter idle with the default timeout + */ +int mspi_ti_k3_wait_for_idle(const struct device *controller) +{ + const mem_addr_t base_addr = DEVICE_MMIO_GET(controller); + uint32_t idle = MSPI_TI_K3_REG_READ_MASKED(CONFIG, IDLE, base_addr); + uint32_t retries = TI_K3_OSPI_GET_NUM_RETRIES(CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE); + + while (idle == 0 && retries > 0) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + idle = MSPI_TI_K3_REG_READ_MASKED(CONFIG, IDLE, base_addr); + --retries; + } + if (retries == 0) { + LOG_ERR("Timeout while waiting for MSPI to enter idle"); + return -EIO; + } + return 0; +} + +/** + * Check whether a single request package is requesting something that the driver + * doesn't implement / the hardware doesn't support + */ +static int mspi_ti_k3_check_transfer_package(const struct mspi_xfer *request, uint32_t index) +{ + const struct mspi_xfer_packet *packet = &request->packets[index]; + /* check that we won't truncate the address */ + if (packet->address >> (8 * request->addr_length)) { + LOG_ERR("Address too long for amount of address bytes"); + return -EINVAL; + } + if (packet->cb_mask != MSPI_BUS_NO_CB) { + LOG_ERR("Callbacks aren't implemented"); + return -ENOSYS; + } + if (packet->cmd >> 16) { + LOG_ERR("Commands over 2 byte long aren't supported"); + return -ENOTSUP; + } + if (packet->cmd >> 8) { + LOG_ERR("Support for dual byte opcodes hasn't been implemented"); + return -ENOSYS; + } + if (packet->num_bytes) { + __ASSERT(packet->data_buf != NULL, + "Request gave a NULL buffer when bytes should be transfererd"); + } + return 0; +} + +/** + * Check whether a full request has invalid / not supported parts + */ +static int mspi_ti_k3_check_transfer_request(const struct mspi_xfer *request) +{ + if (request->async) { + LOG_ERR("Asynchronous requests are not implemented"); + return -ENOSYS; + } + + if (request->cmd_length == 2) { + LOG_ERR("Dual byte opcode is not implemented"); + return -ENOSYS; + } else if (request->cmd_length > 2) { + LOG_ERR("Cmds over 2 bytes long aren't supported"); + return -ENOTSUP; + } else if (request->cmd_length != 1) { + LOG_ERR("Can't handle transfer without cmd"); + return -ENOSYS; + } + + if (request->addr_length > 4) { + LOG_ERR("Address too long. Only up to 32 bit are supported"); + return -ENOTSUP; + } + + if (request->priority != 0) { + LOG_WRN("Ignoring request to give transfer higher priority"); + } + + if (request->num_packet == 0) { + LOG_ERR("Got transfer requests without packages"); + return -EINVAL; + } + __ASSERT(request->packets != NULL, "Packets in transfer request are NULL"); + + if (request->xfer_mode != MSPI_PIO) { + LOG_ERR("Other modes than PIO are not supported"); + return -ENOTSUP; + } + + if (request->rx_dummy & + ~BIT_MASK(TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DUMMY_RD_CLK_CYCLES_FLD_SIZE) || + request->tx_dummy & + ~BIT_MASK(TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DUMMY_WR_CLK_CYCLES_FLD_SIZE)) { + LOG_ERR("Request contains too many dummy cycles"); + return -ENOTSUP; + } + + int ret = 0; + + for (uint32_t i = 0; i < request->num_packet; ++i) { + ret = mspi_ti_k3_check_transfer_package(request, i); + if (ret < 0) { + return ret; + } + } + + return 0; +} + +static int mspi_ti_k3_init(const struct device *dev) +{ + DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE); + const struct mspi_ti_k3_config *config = dev->config; + const struct mspi_ti_k3_timing_cfg *timing_config = &config->initial_timing_cfg; + struct mspi_ti_k3_data *data = dev->data; + const mem_addr_t base_addr = DEVICE_MMIO_GET(dev); + int ret; + + k_mutex_init(&data->lock); + + ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT); + if (ret < 0) { + LOG_ERR("Failed to apply pinctrl"); + return ret; + } + + /* disable OSPI */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_SPI, base_addr); + + ret = mspi_ti_k3_wait_for_idle(dev); + if (ret < 0) { + return ret; + } + + /* disable direct access the driver always uses indirect accesses */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENB_DIR_ACC_CTRL, base_addr); + + /* disable DTR protocol */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_DTR_PROTOCOL, base_addr); + + /* leave XIP mode */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENTER_XIP_MODE, base_addr); + + /* set how many FSS0 SRAM locations are allocated for read; the other ones + * are allocated for writes + */ + MSPI_TI_K3_REG_WRITE(config->sram_allocated_for_read, SRAM_PARTITION_CFG, ADDR, base_addr); + + /* only allow one CS to be active */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, PERIPH_SEL_DEC, base_addr); + + /* CS selection is based on "manual" pin selection */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_AHB_DECODER, base_addr); + + /* DQ3 should not be used as reset pin */ + MSPI_TI_K3_REG_WRITE(1, CONFIG, RESET_CFG, base_addr); + + /* Set baud rate division to 32; formula: (n + 1) * 2 */ + MSPI_TI_K3_REG_WRITE(15, CONFIG, MSTR_BAUD_DIV, base_addr); + + /* disable dual byte opcodes */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, DUAL_BYTE_OPCODE_EN, base_addr); + + /* disable PHY pipeline mode */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, PIPELINE_PHY, base_addr); + + /* disable PHY module generally */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, PHY_MODE_ENABLE, base_addr); + + /* disable CRC */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, CRC_ENABLE, base_addr); + + /* disable DMA generally since it's not supported */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENB_DMA_IF, base_addr); + + /* disable automatic write protection disablement of MSPI peripherals */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, WR_PROT_FLASH, base_addr); + + /* disable possible reset pin */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, RESET_PIN, base_addr); + + /* general clock cycle delays */ + MSPI_TI_K3_REG_WRITE(timing_config->nss, DEV_DELAY, D_NSS, base_addr); + MSPI_TI_K3_REG_WRITE(timing_config->btwn, DEV_DELAY, D_BTWN, base_addr); + MSPI_TI_K3_REG_WRITE(timing_config->after, DEV_DELAY, D_AFTER, base_addr); + MSPI_TI_K3_REG_WRITE(timing_config->init, DEV_DELAY, D_INIT, base_addr); + + /* set trigger reg address and range to 0 */ + MSPI_TI_K3_REG_WRITE(0, IND_AHB_ADDR_TRIGGER, ADDR, base_addr); + MSPI_TI_K3_REG_WRITE(0, INDIRECT_TRIGGER_ADDR_RANGE, IND_RANGE_WIDTH, base_addr); + + /* disable loop-back via DQS */ + MSPI_TI_K3_REG_WRITE(1, RD_DATA_CAPTURE, BYPASS, base_addr); + + /* disable auto polling for write completion */ + MSPI_TI_K3_REG_WRITE(1, WRITE_COMPLETION_CTRL, DISABLE_POLLING, base_addr); + + /* disable automatic write enable command before indirect write transactions */ + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_WR_CONFIG, WEL_DIS, base_addr); + + /* reset mode bit (hardware CRC checking on read, if supported) */ + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, MODE_BIT_ENABLE, base_addr); + + /* disable DDR mode */ + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, DDR_EN, base_addr); + + uint32_t val; + + /* disable all interrupts via masking */ + val = sys_read32(base_addr + TI_K3_OSPI_IRQ_MASK_REG); + val &= ~TI_K3_OSPI_IRQ_MASK_ALL; + sys_write32(val, base_addr + TI_K3_OSPI_IRQ_MASK_REG); + + /* clear currently pending interrupts */ + val = sys_read32(base_addr + TI_K3_OSPI_IRQ_STATUS_REG); + val |= TI_K3_OSPI_IRQ_STATUS_ALL; + sys_write32(val, base_addr + TI_K3_OSPI_IRQ_STATUS_REG); + + /* re-enable OSPI controller */ + MSPI_TI_K3_REG_WRITE(1, CONFIG, ENABLE_SPI, base_addr); + + return 0; +} + +static int mspi_ti_k3_small_transfer(const struct device *controller, const struct mspi_xfer *req, + uint32_t index, const uint64_t start_time) +{ + const mem_addr_t base_address = DEVICE_MMIO_GET(controller); + const struct mspi_xfer_packet *packet = &req->packets[index]; + uint32_t dummy_cycles = 0; + + /* reset previous command configuration completely */ + sys_write32(0, base_address + TI_K3_OSPI_FLASH_CMD_CTRL_REG); + + if (packet->dir == MSPI_RX) { + if (packet->num_bytes != 0) { + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, ENB_READ_DATA, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes - 1, FLASH_CMD_CTRL, + NUM_RD_DATA_BYTES, base_address); + } + dummy_cycles = req->rx_dummy; + } else { + if (packet->num_bytes != 0) { + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, ENB_WRITE_DATA, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes - 1, FLASH_CMD_CTRL, + NUM_WR_DATA_BYTES, base_address); + if (packet->num_bytes > 4) { + uint32_t upper = 0; + + memcpy(&upper, &packet->data_buf[4], packet->num_bytes - 4); + sys_write32(upper, + base_address + TI_K3_OSPI_FLASH_WR_DATA_UPPER_REG); + } + uint32_t lower = 0; + + memcpy(&lower, &packet->data_buf[0], MIN(packet->num_bytes, 4)); + sys_write32(lower, base_address + TI_K3_OSPI_FLASH_WR_DATA_LOWER_REG); + } + dummy_cycles = req->tx_dummy; + } + + MSPI_TI_K3_REG_WRITE(packet->cmd, FLASH_CMD_CTRL, CMD_OPCODE, base_address); + MSPI_TI_K3_REG_WRITE(dummy_cycles, FLASH_CMD_CTRL, NUM_DUMMY_CYCLES, base_address); + + if (req->addr_length) { + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, ENB_COMD_ADDR, base_address); + MSPI_TI_K3_REG_WRITE(req->addr_length - 1, FLASH_CMD_CTRL, NUM_ADDR_BYTES, + base_address); + MSPI_TI_K3_REG_WRITE(packet->address, FLASH_CMD_ADDR, ADDR, base_address); + } + + /* start transaction */ + MSPI_TI_K3_REG_WRITE(1, FLASH_CMD_CTRL, CMD_EXEC, base_address); + + uint32_t exec_status = + MSPI_TI_K3_REG_READ_MASKED(FLASH_CMD_CTRL, CMD_EXEC_STATUS, base_address); + while (exec_status != 0 && k_uptime_get() - start_time < req->timeout) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + exec_status = + MSPI_TI_K3_REG_READ_MASKED(FLASH_CMD_CTRL, CMD_EXEC_STATUS, base_address); + } + if (exec_status != 0) { + LOG_ERR("Timeout while waiting for dedicated command to finish"); + return -EIO; + } + + if (packet->dir == MSPI_RX) { + if (packet->num_bytes > 4) { + uint32_t higher = MSPI_TI_K3_REG_READ(FLASH_RD_DATA_UPPER, base_address); + + memcpy(&packet->data_buf[4], &higher, packet->num_bytes - 4); + } + uint32_t lower = MSPI_TI_K3_REG_READ(FLASH_RD_DATA_LOWER, base_address); + + lower = sys_read32(base_address + TI_K3_OSPI_FLASH_RD_DATA_LOWER_REG); + memcpy(&packet->data_buf[0], &lower, MIN(packet->num_bytes, 4)); + } + + return 0; +} + +static int mspi_ti_k3_indirect_read(const struct device *controller, const struct mspi_xfer *req, + uint32_t index, const uint64_t start_time) +{ + const mem_addr_t base_address = DEVICE_MMIO_GET(controller); + const struct mspi_ti_k3_config *config = controller->config; + const struct mspi_xfer_packet *packet = &req->packets[index]; + + MSPI_TI_K3_REG_WRITE(packet->cmd, DEV_INSTR_RD_CONFIG, RD_OPCODE_NON_XIP, base_address); + MSPI_TI_K3_REG_WRITE(packet->address, INDIRECT_READ_XFER_START, ADDR, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes, INDIRECT_READ_XFER_NUM_BYTES, VALUE, base_address); + MSPI_TI_K3_REG_WRITE(req->addr_length - 1, DEV_SIZE_CONFIG, NUM_ADDR_BYTES, base_address); + MSPI_TI_K3_REG_WRITE(req->rx_dummy, DEV_INSTR_RD_CONFIG, DUMMY_RD_CLK_CYCLES, base_address); + + /* Start transfer */ + MSPI_TI_K3_REG_WRITE(1, INDIRECT_READ_XFER_CTRL, START, base_address); + + uint32_t remaining_bytes = packet->num_bytes; + uint8_t *write_ptr = packet->data_buf; + uint32_t num_new_words = 0; + uint32_t current_new_word; + int bytes_to_copy_from_current_word; + + while (remaining_bytes > 0) { + if (k_uptime_get() - start_time > req->timeout) { + LOG_ERR("Timeout while receiving data from MSPI device"); + goto timeout; + } + num_new_words = MSPI_TI_K3_REG_READ_MASKED(SRAM_FILL, INDAC_READ, base_address); + while (remaining_bytes > 0 && num_new_words > 0) { + current_new_word = sys_read32(config->fifo_addr); + bytes_to_copy_from_current_word = MIN(remaining_bytes, 4); + memcpy(write_ptr, ¤t_new_word, bytes_to_copy_from_current_word); + write_ptr += bytes_to_copy_from_current_word; + remaining_bytes -= bytes_to_copy_from_current_word; + --num_new_words; + } + } + + /* wait until official indirect read completion */ + uint32_t done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_READ_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + while (done_status == 0 && k_uptime_get() - start_time < req->timeout) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_READ_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + } + if (done_status == 0) { + LOG_ERR("Timeout waiting for official indirect read done confirmation"); + goto timeout; + } + MSPI_TI_K3_REG_WRITE(1, INDIRECT_READ_XFER_CTRL, IND_OPS_DONE_STATUS, base_address); + + return 0; + +timeout: + MSPI_TI_K3_REG_WRITE(1, INDIRECT_READ_XFER_CTRL, CANCEL, base_address); + return -EIO; +} + +static int mspi_ti_k3_indirect_write(const struct device *controller, const struct mspi_xfer *req, + uint32_t index, const uint64_t start_time) +{ + const mem_addr_t base_address = DEVICE_MMIO_GET(controller); + const struct mspi_ti_k3_config *config = controller->config; + const struct mspi_xfer_packet *packet = &req->packets[index]; + + MSPI_TI_K3_REG_WRITE(packet->cmd, DEV_INSTR_WR_CONFIG, WR_OPCODE_NON_XIP, base_address); + MSPI_TI_K3_REG_WRITE(req->tx_dummy, DEV_INSTR_WR_CONFIG, DUMMY_WR_CLK_CYCLES, base_address); + MSPI_TI_K3_REG_WRITE(req->addr_length - 1, DEV_SIZE_CONFIG, NUM_ADDR_BYTES, base_address); + MSPI_TI_K3_REG_WRITE(packet->address, INDIRECT_WRITE_XFER_START, ADDR, base_address); + MSPI_TI_K3_REG_WRITE(packet->num_bytes, INDIRECT_WRITE_XFER_NUM_BYTES, VALUE, base_address); + + MSPI_TI_K3_REG_WRITE(1, INDIRECT_WRITE_XFER_CTRL, START, base_address); + + uint32_t read_offset = 0; + uint32_t remaining_bytes = packet->num_bytes; + uint32_t free_words = 0; + uint32_t current_word_to_write; + + while (remaining_bytes > 0) { + if (k_uptime_get() - start_time > req->timeout) { + LOG_ERR("Timeout while sending data to MSPI device"); + goto timeout; + } + free_words = config->sram_allocated_for_read - + MSPI_TI_K3_REG_READ_MASKED(SRAM_FILL, INDAC_WRITE, base_address); + while (free_words > 0 && remaining_bytes > 0) { + current_word_to_write = 0; + memcpy(¤t_word_to_write, &packet->data_buf[read_offset], + MIN(remaining_bytes, 4)); + sys_write32(current_word_to_write, config->fifo_addr); + remaining_bytes = (remaining_bytes > 4 ? remaining_bytes - 4 : 0); + read_offset += 4; + --free_words; + } + } + + /* Wait for official finish */ + uint32_t done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_WRITE_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + while (done_status == 0 && k_uptime_get() - start_time < req->timeout) { + k_sleep(TI_K3_OSPI_TIME_BETWEEN_RETRIES); + done_status = MSPI_TI_K3_REG_READ_MASKED(INDIRECT_WRITE_XFER_CTRL, + IND_OPS_DONE_STATUS, base_address); + } + if (done_status == 0) { + LOG_ERR("Timeout while waiting for official write done confirmation"); + goto timeout; + } + MSPI_TI_K3_REG_WRITE(1, INDIRECT_WRITE_XFER_CTRL, IND_OPS_DONE_STATUS, base_address); + + return 0; +timeout: + MSPI_TI_K3_REG_WRITE(1, INDIRECT_WRITE_XFER_CTRL, CANCEL, base_address); + return -EIO; +} + +static int mspi_ti_k3_transceive(const struct device *controller, const struct mspi_dev_id *dev_id, + const struct mspi_xfer *req) +{ + uint64_t start_time = k_uptime_get(); + struct mspi_ti_k3_data *data = controller->data; + int ret = 0; + + ret = mspi_ti_k3_check_transfer_request(req); + if (ret) { + return ret; + } + + if (req->timeout > CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE) { + LOG_ERR("Request timeout exceeds configured maximum in Kconfig"); + return -EINVAL; + } + + ret = k_mutex_lock(&data->lock, K_MSEC(req->timeout)); + if (ret < 0) { + return ret; + } + + for (uint32_t i = 0; i < req->num_packet; ++i) { + const struct mspi_xfer_packet *packet = &req->packets[i]; + /* the FLASH_CMD_REGISTER is good for small transfers with only very little/no data + */ + if (packet->num_bytes <= 8) { + ret = mspi_ti_k3_small_transfer(controller, req, i, start_time); + if (ret < 0) { + goto exit; + } + } else { + /* big transfer via indirect transfer mode */ + if (packet->dir == MSPI_RX) { + ret = mspi_ti_k3_indirect_read(controller, req, i, start_time); + } else { + ret = mspi_ti_k3_indirect_write(controller, req, i, start_time); + } + if (ret < 0) { + goto exit; + } + } + } + +exit: + k_mutex_unlock(&data->lock); + return ret; +} + +static int mspi_ti_k3_set_opcode_lines(const mem_addr_t base_addr, enum mspi_io_mode io_mode) +{ + switch (io_mode) { + case MSPI_IO_MODE_SINGLE: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_DUAL_1_2_2: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_QUAD_1_4_4: + case MSPI_IO_MODE_OCTAL_1_1_8: + case MSPI_IO_MODE_OCTAL_1_8_8: + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + case MSPI_IO_MODE_DUAL: + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + case MSPI_IO_MODE_QUAD: + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + case MSPI_IO_MODE_OCTAL: + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_RD_CONFIG, INSTR_TYPE, base_addr); + return 0; + default: + return -ENOTSUP; + } +} + +static int mspi_ti_k3_set_addr_lines(const mem_addr_t base_addr, enum mspi_io_mode io_mode) +{ + switch (io_mode) { + case MSPI_IO_MODE_SINGLE: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_OCTAL_1_1_8: + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + case MSPI_IO_MODE_DUAL: + case MSPI_IO_MODE_DUAL_1_2_2: + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + case MSPI_IO_MODE_QUAD: + case MSPI_IO_MODE_QUAD_1_4_4: + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + case MSPI_IO_MODE_OCTAL: + case MSPI_IO_MODE_OCTAL_1_8_8: + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_RD_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_WR_CONFIG, ADDR_XFER_TYPE_STD_MODE, base_addr); + return 0; + default: + return -ENOTSUP; + } +} + +static int mspi_ti_k3_set_data_lines(const mem_addr_t base_addr, enum mspi_io_mode io_mode) +{ + switch (io_mode) { + case MSPI_IO_MODE_SINGLE: + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(0, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + case MSPI_IO_MODE_DUAL: + case MSPI_IO_MODE_DUAL_1_1_2: + case MSPI_IO_MODE_DUAL_1_2_2: + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(1, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + case MSPI_IO_MODE_QUAD: + case MSPI_IO_MODE_QUAD_1_1_4: + case MSPI_IO_MODE_QUAD_1_4_4: + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(2, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + case MSPI_IO_MODE_OCTAL: + case MSPI_IO_MODE_OCTAL_1_1_8: + case MSPI_IO_MODE_OCTAL_1_8_8: + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_RD_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + MSPI_TI_K3_REG_WRITE(3, DEV_INSTR_WR_CONFIG, DATA_XFER_TYPE_EXT_MODE, base_addr); + return 0; + default: + return -ENOTSUP; + } +} + +int mspi_ti_k3_dev_config(const struct device *controller, const struct mspi_dev_id *dev_id, + const enum mspi_dev_cfg_mask param_mask, const struct mspi_dev_cfg *cfg) +{ + const mem_addr_t base_addr = DEVICE_MMIO_GET(controller); + struct mspi_ti_k3_data *data = controller->data; + int ret = 0; + + ret = k_mutex_lock(&data->lock, K_MSEC(CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE)); + + if (ret < 0) { + LOG_ERR("Error waiting for MSPI controller lock for changing device config"); + return ret; + } + + if (param_mask & TI_K3_OSPI_NOT_IMPLEMENT_DEV_CONFIG_PARAMS) { + LOG_ERR("Device config includes non implemented features"); + return -ENOSYS; + } + if (param_mask & TI_K3_OSPI_IGNORED_DEV_CONFIG_PARAMS) { + LOG_WRN("Device configuration includes ignored parameters. These are taken from " + "the transceive request instead"); + } + + if (param_mask & MSPI_DEVICE_CONFIG_ENDIAN) { + if (cfg->endian != MSPI_XFER_LITTLE_ENDIAN) { + LOG_ERR("Only little Endian is supported for now"); + /* There is no hardware native support for big endian but it can be + * done in software + */ + return -ENOSYS; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_CE_POL) { + if (cfg->ce_polarity != MSPI_CE_ACTIVE_LOW) { + LOG_ERR("Non active low chip enable polarities haven't been implemented " + "yet"); + return -ENOSYS; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_DQS) { + if (cfg->dqs_enable) { + LOG_ERR("DQS is not implemented yet"); + return -ENOSYS; + } + } + + if (param_mask & MSPI_DEVICE_CONFIG_DATA_RATE) { + if (cfg->data_rate != MSPI_DATA_RATE_SINGLE) { + LOG_ERR("Only single data rate is supported for now"); + return -ENOSYS; + } + } + + /* Disable OSPI during configuration */ + MSPI_TI_K3_REG_WRITE(0, CONFIG, ENABLE_SPI, base_addr); + + ret = mspi_ti_k3_wait_for_idle(controller); + if (ret < 0) { + goto exit; + } + + if (param_mask & MSPI_DEVICE_CONFIG_CE_NUM) { + uint32_t num; + + if (cfg->ce_num > 3) { + LOG_ERR("Non implemented chip select. Only hardware CS 0 to 3 are " + "implemented"); + ret = -ENOSYS; + goto exit; + } + num = ~BIT(cfg->ce_num) & BIT_MASK(4); + + MSPI_TI_K3_REG_WRITE(num, CONFIG, PERIPH_CS_LINES, base_addr); + } + if (param_mask & MSPI_DEVICE_CONFIG_IO_MODE) { + ret = mspi_ti_k3_set_opcode_lines(base_addr, cfg->io_mode); + if (ret) { + goto exit; + } + ret = mspi_ti_k3_set_data_lines(base_addr, cfg->io_mode); + if (ret) { + goto exit; + } + ret = mspi_ti_k3_set_addr_lines(base_addr, cfg->io_mode); + if (ret) { + goto exit; + } + } + if (param_mask & MSPI_DEVICE_CONFIG_CPP) { + switch (cfg->cpp) { + case MSPI_CPP_MODE_0: + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_PHASE, base_addr); + break; + case MSPI_CPP_MODE_1: + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_PHASE, base_addr); + break; + case MSPI_CPP_MODE_2: + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(0, CONFIG, SEL_CLK_PHASE, base_addr); + break; + case MSPI_CPP_MODE_3: + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_POL, base_addr); + MSPI_TI_K3_REG_WRITE(1, CONFIG, SEL_CLK_PHASE, base_addr); + break; + default: + LOG_ERR("Invalid clock polarity/phase configuration"); + ret = -ENOTSUP; + goto exit; + } + } +exit: + /* Re-enable OSPI */ + MSPI_TI_K3_REG_WRITE(1, CONFIG, ENABLE_SPI, base_addr); + + k_mutex_unlock(&data->lock); + + return ret; +} + +#ifdef CONFIG_MSPI_TIMING +int mspi_ti_k3_timing(const struct device *controller, const struct mspi_dev_id *dev_id, + const uint32_t param_mask, void *timing_cfg) +{ + ARG_UNUSED(dev_id); + + const mem_addr_t base_addr = DEVICE_MMIO_GET(controller); + struct mspi_ti_k3_data *data = controller->data; + struct mspi_ti_k3_timing_cfg *timing = timing_cfg; + int ret; + + ret = k_mutex_lock(&data->lock, K_MSEC(CONFIG_MSPI_COMPLETION_TIMEOUT_TOLERANCE)); + + if (ret < 0) { + LOG_ERR("Error waiting for MSPI controller lock for changing timing"); + return ret; + } + + if (param_mask & MSPI_TI_K3_TIMING_PARAM_NSS) { + MSPI_TI_K3_REG_WRITE(timing->nss, DEV_DELAY, D_NSS, base_addr); + } + + if (param_mask & MSPI_TI_K3_TIMING_PARAM_BTWN) { + MSPI_TI_K3_REG_WRITE(timing->btwn, DEV_DELAY, D_BTWN, base_addr); + } + + if (param_mask & MSPI_TI_K3_TIMING_PARAM_AFTER) { + MSPI_TI_K3_REG_WRITE(timing->after, DEV_DELAY, D_AFTER, base_addr); + } + + if (param_mask & MSPI_TI_K3_TIMING_PARAM_INIT) { + MSPI_TI_K3_REG_WRITE(timing->init, DEV_DELAY, D_INIT, base_addr); + } + + k_mutex_unlock(&data->lock); + + return 0; +} +#endif /* CONFIG_MSPI_TIMING */ + +static DEVICE_API(mspi, mspi_ti_k3_driver_api) = { + .config = NULL, + .dev_config = mspi_ti_k3_dev_config, + .xip_config = NULL, + .scramble_config = NULL, +#ifdef CONFIG_MSPI_TIMING + .timing_config = mspi_ti_k3_timing, +#else + .timing_config = NULL, +#endif + .get_channel_status = NULL, + .register_callback = NULL, + .transceive = mspi_ti_k3_transceive, +}; + +#define MSPI_CONFIG(n) \ + {.op_mode = DT_INST_ENUM_IDX_OR(n, op_mode, MSPI_OP_MODE_CONTROLLER), \ + .sw_multi_periph = DT_INST_PROP(n, software_multiperipheral)} + +#define TI_K3_MSPI_DEFINE(n) \ + PINCTRL_DT_DEFINE(DT_DRV_INST(n)); \ + static const struct mspi_ti_k3_config mspi_ti_k3_config##n = { \ + DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)), \ + .pinctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + .mspi_config = MSPI_CONFIG(n), \ + .fifo_addr = DT_REG_ADDR_BY_IDX(DT_DRV_INST(n), 1), \ + .sram_allocated_for_read = DT_PROP(DT_DRV_INST(n), sram_allocated_for_read), \ + .initial_timing_cfg = { \ + .nss = DT_PROP_OR(DT_DRV_INST(n), init_nss_delay, \ + TI_K3_OSPI_DEFAULT_DELAY), \ + .btwn = DT_PROP_OR(DT_DRV_INST(n), init_btwn_delay, \ + TI_K3_OSPI_DEFAULT_DELAY), \ + .after = DT_PROP_OR(DT_DRV_INST(n), init_after_delay, \ + TI_K3_OSPI_DEFAULT_DELAY), \ + .init = DT_PROP_OR(DT_DRV_INST(n), init_init_delay, \ + TI_K3_OSPI_DEFAULT_DELAY), \ + }}; \ + static struct mspi_ti_k3_data mspi_ti_k3_data##n = {}; \ + DEVICE_DT_INST_DEFINE(n, mspi_ti_k3_init, NULL, &mspi_ti_k3_data##n, \ + &mspi_ti_k3_config##n, PRE_KERNEL_2, CONFIG_MSPI_INIT_PRIORITY, \ + &mspi_ti_k3_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(TI_K3_MSPI_DEFINE) diff --git a/drivers/mspi/mspi_ti_k3.h b/drivers/mspi/mspi_ti_k3.h new file mode 100644 index 000000000000..aa489fefe64d --- /dev/null +++ b/drivers/mspi/mspi_ti_k3.h @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2025 Siemens Mobility GmbH + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_DRIVERS_MSPI_TI_K3_H_ +#define ZEPHYR_DRIVERS_MSPI_TI_K3_H_ + +#include "zephyr/kernel.h" +#include "zephyr/sys/util_macro.h" + +/** + * Timing configuration for the TI K3 MSPI peripheral. + * + * These values are put into the DEV_DELAY register and the names match the + * register parts. + */ +struct mspi_ti_k3_timing_cfg { + /* amount of clock cycles the CS pin is deasserted between transactions */ + uint8_t nss; + /* amount of clock cycles no peripheral is selected during switching */ + uint8_t btwn; + /* amount of clock cycles chip select is held after the last bit was + * transmitted + */ + uint8_t after; + /* amount of clock cycles after CS is asserted and the first bit is + * transmitted + */ + uint8_t init; +}; + +/** + * Enum which timing parameters should be modified + */ +enum mspi_ti_k3_timing_param { + MSPI_TI_K3_TIMING_PARAM_NSS = BIT(0), + MSPI_TI_K3_TIMING_PARAM_BTWN = BIT(1), + MSPI_TI_K3_TIMING_PARAM_AFTER = BIT(2), + MSPI_TI_K3_TIMING_PARAM_INIT = BIT(3) +}; + +/* Not implemented mspi_dev_cfg bits */ +#define TI_K3_OSPI_NOT_IMPLEMENT_DEV_CONFIG_PARAMS \ + (MSPI_DEVICE_CONFIG_FREQUENCY | MSPI_DEVICE_CONFIG_MEM_BOUND | \ + MSPI_DEVICE_CONFIG_BREAK_TIME) + +/* Ignored dev_cfg_bits */ +#define TI_K3_OSPI_IGNORED_DEV_CONFIG_PARAMS \ + (MSPI_DEVICE_CONFIG_RX_DUMMY | MSPI_DEVICE_CONFIG_TX_DUMMY | MSPI_DEVICE_CONFIG_READ_CMD | \ + MSPI_DEVICE_CONFIG_WRITE_CMD | MSPI_DEVICE_CONFIG_CMD_LEN | MSPI_DEVICE_CONFIG_ADDR_LEN) + +/* Default delay for time between clock enablement and chip select and other */ +#define TI_K3_OSPI_DEFAULT_DELAY 10 + +/* Timeout calculations and default timeout values */ +#define TI_K3_OSPI_TIME_BETWEEN_RETRIES_MS 10 +#define TI_K3_OSPI_TIME_BETWEEN_RETRIES K_MSEC(TI_K3_OSPI_TIME_BETWEEN_RETRIES_MS) +#define TI_K3_OSPI_GET_NUM_RETRIES(timeout_ms) (timeout_ms / TI_K3_OSPI_TIME_BETWEEN_RETRIES_MS) + +/* + * General register naming: + * Since the driver uses macro concatention the register names need to be in a specific format. + * The offsets from the base addresses are named TI_K3_OSPI_[REGISTER_NAME]_REG. + * + * For the individual fields the offset and length of the field must be + * specified. They follow the format: + * Field offset: TI_K3_OSPI_[REGISTER_NAME]_[FIELD_NAME]_FLD_OFFSET + * Field size in bits: TI_K3_OSPI_[REGISTER_NAME]_[FIELD_NAME]_FLD_SIZE + */ + +/* General register offsets */ +#define TI_K3_OSPI_CONFIG_REG 0x0u +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_REG 0x4u +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_REG 0x8u +#define TI_K3_OSPI_DEV_DELAY_REG 0xcu +#define TI_K3_OSPI_RD_DATA_CAPTURE_REG 0x10u +#define TI_K3_OSPI_DEV_SIZE_CONFIG_REG 0x14u +#define TI_K3_OSPI_SRAM_PARTITION_CFG_REG 0x18u +#define TI_K3_OSPI_IND_AHB_ADDR_TRIGGER_REG 0x1cu +#define TI_K3_OSPI_DMA_PERIPH_CONFIG_REG 0x20u +#define TI_K3_OSPI_REMAP_ADDR_REG 0x24u +#define TI_K3_OSPI_MODE_BIT_CONFIG_REG 0x28u +#define TI_K3_OSPI_SRAM_FILL_REG 0x2cu +#define TI_K3_OSPI_TX_THRESH_REG 0x30u +#define TI_K3_OSPI_RX_THRESH_REG 0x34u +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_REG 0x38u +#define TI_K3_OSPI_NO_OF_POLLS_BEF_EXP_REG 0x3cu +#define TI_K3_OSPI_IRQ_STATUS_REG 0x40u +#define TI_K3_OSPI_IRQ_MASK_REG 0x44u +#define TI_K3_OSPI_LOWER_WR_PROT_REG 0x50u +#define TI_K3_OSPI_UPPER_WR_PROT_REG 0x54u +#define TI_K3_OSPI_WR_PROT_CTRL_REG 0x58u +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_REG 0x60u +#define TI_K3_OSPI_INDIRECT_READ_XFER_WATERMARK_REG 0x64u +#define TI_K3_OSPI_INDIRECT_READ_XFER_START_REG 0x68u +#define TI_K3_OSPI_INDIRECT_READ_XFER_NUM_BYTES_REG 0x6cu +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_REG 0x70u +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_WATERMARK_REG 0x74u +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_START_REG 0x78u +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_NUM_BYTES_REG 0x7cu +#define TI_K3_OSPI_INDIRECT_TRIGGER_ADDR_RANGE_REG 0x80u +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_REG 0x8cu +#define TI_K3_OSPI_FLASH_CMD_CTRL_REG 0x90u +#define TI_K3_OSPI_FLASH_CMD_ADDR_REG 0x94u +#define TI_K3_OSPI_FLASH_RD_DATA_LOWER_REG 0xa0u +#define TI_K3_OSPI_FLASH_RD_DATA_UPPER_REG 0xa4u +#define TI_K3_OSPI_FLASH_WR_DATA_LOWER_REG 0xa8u +#define TI_K3_OSPI_FLASH_WR_DATA_UPPER_REG 0xacu +#define TI_K3_OSPI_POLLING_FLASH_STATUS_REG 0xb0u +#define TI_K3_OSPI_PHY_CONFIGURATION_REG 0xb4u +#define TI_K3_OSPI_PHY_MASTER_CONTROL_REG 0xb8u +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_REG 0xbcu +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_REG 0xc0u +#define TI_K3_OSPI_OPCODE_EXT_LOWER_REG 0xe0u +#define TI_K3_OSPI_OPCODE_EXT_UPPER_REG 0xe4u +#define TI_K3_OSPI_MODULE_ID_REG 0xfcu + +/* CONFIG */ +#define TI_K3_OSPI_CONFIG_IDLE_FLD_OFFSET 31 +#define TI_K3_OSPI_CONFIG_DUAL_BYTE_OPCODE_EN_FLD_OFFSET 30 +#define TI_K3_OSPI_CONFIG_CRC_ENABLE_FLD_OFFSET 29 +#define TI_K3_OSPI_CONFIG_PIPELINE_PHY_FLD_OFFSET 25 +#define TI_K3_OSPI_CONFIG_ENABLE_DTR_PROTOCOL_FLD_OFFSET 24 +#define TI_K3_OSPI_CONFIG_ENABLE_AHB_DECODER_FLD_OFFSET 23 +#define TI_K3_OSPI_CONFIG_MSTR_BAUD_DIV_FLD_OFFSET 19 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_IMM_FLD_OFFSET 18 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_FLD_OFFSET 17 +#define TI_K3_OSPI_CONFIG_ENB_AHB_ADDR_REMAP_FLD_OFFSET 16 +#define TI_K3_OSPI_CONFIG_ENB_DMA_IF_FLD_OFFSET 15 +#define TI_K3_OSPI_CONFIG_WR_PROT_FLASH_FLD_OFFSET 14 +#define TI_K3_OSPI_CONFIG_PERIPH_CS_LINES_FLD_OFFSET 10 +#define TI_K3_OSPI_CONFIG_PERIPH_SEL_DEC_FLD_OFFSET 9 +#define TI_K3_OSPI_CONFIG_ENB_LEGACY_IP_MODE_FLD_OFFSET 8 +#define TI_K3_OSPI_CONFIG_ENB_DIR_ACC_CTRL_FLD_OFFSET 7 +#define TI_K3_OSPI_CONFIG_RESET_CFG_FLD_OFFSET 6 +#define TI_K3_OSPI_CONFIG_RESET_PIN_FLD_OFFSET 5 +#define TI_K3_OSPI_CONFIG_HOLD_PIN_FLD_OFFSET 4 +#define TI_K3_OSPI_CONFIG_PHY_MODE_ENABLE_FLD_OFFSET 3 +#define TI_K3_OSPI_CONFIG_SEL_CLK_PHASE_FLD_OFFSET 2 +#define TI_K3_OSPI_CONFIG_SEL_CLK_POL_FLD_OFFSET 1 +#define TI_K3_OSPI_CONFIG_ENABLE_SPI_FLD_OFFSET 0 + +#define TI_K3_OSPI_CONFIG_IDLE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_DUAL_BYTE_OPCODE_EN_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_CRC_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_PIPELINE_PHY_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENABLE_DTR_PROTOCOL_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENABLE_AHB_DECODER_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_MSTR_BAUD_DIV_FLD_SIZE 4 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_IMM_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENTER_XIP_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_AHB_ADDR_REMAP_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_DMA_IF_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_WR_PROT_FLASH_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_PERIPH_CS_LINES_FLD_SIZE 4 +#define TI_K3_OSPI_CONFIG_PERIPH_SEL_DEC_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_LEGACY_IP_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENB_DIR_ACC_CTRL_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_RESET_CFG_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_RESET_PIN_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_HOLD_PIN_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_PHY_MODE_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_SEL_CLK_PHASE_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_SEL_CLK_POL_FLD_SIZE 1 +#define TI_K3_OSPI_CONFIG_ENABLE_SPI_FLD_SIZE 1 + +/* DEV_INSTR_RD_CONFIG */ +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DUMMY_RD_CLK_CYCLES_FLD_OFFSET 24 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_MODE_BIT_ENABLE_FLD_OFFSET 20 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_OFFSET 12 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DDR_EN_FLD_OFFSET 10 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_INSTR_TYPE_FLD_OFFSET 8 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_RD_OPCODE_NON_XIP_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DUMMY_RD_CLK_CYCLES_FLD_SIZE 5 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_MODE_BIT_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_DDR_EN_FLD_SIZE 1 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_INSTR_TYPE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_RD_CONFIG_RD_OPCODE_NON_XIP_FLD_SIZE 8 + +/* DEV_INSTR_WR_CONFIG */ +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DUMMY_WR_CLK_CYCLES_FLD_OFFSET 24 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_OFFSET 12 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WEL_DIS_FLD_OFFSET 8 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WR_OPCODE_NON_XIP_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DUMMY_WR_CLK_CYCLES_FLD_SIZE 5 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_DATA_XFER_TYPE_EXT_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_ADDR_XFER_TYPE_STD_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WEL_DIS_FLD_SIZE 1 +#define TI_K3_OSPI_DEV_INSTR_WR_CONFIG_WR_OPCODE_NON_XIP_FLD_SIZE 8 + +/* DEV_DELAY */ +#define TI_K3_OSPI_DEV_DELAY_D_NSS_FLD_OFFSET 24 +#define TI_K3_OSPI_DEV_DELAY_D_BTWN_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_DELAY_D_AFTER_FLD_OFFSET 8 +#define TI_K3_OSPI_DEV_DELAY_D_INIT_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_DELAY_D_NSS_FLD_SIZE 8 +#define TI_K3_OSPI_DEV_DELAY_D_BTWN_FLD_SIZE 8 +#define TI_K3_OSPI_DEV_DELAY_D_AFTER_FLD_SIZE 8 +#define TI_K3_OSPI_DEV_DELAY_D_INIT_FLD_SIZE 8 + +/* RD_DATA_CAPTURE */ +#define TI_K3_OSPI_RD_DATA_CAPTURE_DDR_READ_DELAY_FLD_OFFSET 16 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DQS_ENABLE_FLD_OFFSET 8 +#define TI_K3_OSPI_RD_DATA_CAPTURE_SAMPLE_EDGE_SEL_FLD_OFFSET 5 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DELAY_FLD_OFFSET 1 +#define TI_K3_OSPI_RD_DATA_CAPTURE_BYPASS_FLD_OFFSET 0 + +#define TI_K3_OSPI_RD_DATA_CAPTURE_DDR_READ_DELAY_FLD_SIZE 4 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DQS_ENABLE_FLD_SIZE 1 +#define TI_K3_OSPI_RD_DATA_CAPTURE_SAMPLE_EDGE_SEL_FLD_SIZE 1 +#define TI_K3_OSPI_RD_DATA_CAPTURE_DELAY_FLD_SIZE 4 +#define TI_K3_OSPI_RD_DATA_CAPTURE_BYPASS_FLD_SIZE 1 + +/* DEV_SIZE_CONFIG */ +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS3_FLD_OFFSET 27 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS2_FLD_OFFSET 25 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS1_FLD_OFFSET 23 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS0_FLD_OFFSET 21 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_SUBSECTOR_FLD_OFFSET 16 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_DEVICE_PAGE_FLD_OFFSET 4 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_NUM_ADDR_BYTES_FLD_OFFSET 0 + +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS3_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS2_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS1_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_MEM_SIZE_ON_CS0_FLD_SIZE 2 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_SUBSECTOR_FLD_SIZE 5 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_BYTES_PER_DEVICE_PAGE_FLD_SIZE 12 +#define TI_K3_OSPI_DEV_SIZE_CONFIG_NUM_ADDR_BYTES_FLD_SIZE 4 + +/* SRAM_PARTITION_CFG */ +#define TI_K3_OSPI_SRAM_PARTITION_CFG_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_SRAM_PARTITION_CFG_ADDR_FLD_SIZE 8 + +/* INDIRECT_TRIGGER_ADDR_RANGE */ +#define TI_K3_OSPI_INDIRECT_TRIGGER_ADDR_RANGE_IND_RANGE_WIDTH_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_TRIGGER_ADDR_RANGE_IND_RANGE_WIDTH_FLD_SIZE 4 + +/* REMAP_ADDR */ +#define TI_K3_OSPI_REMAP_ADDR_VALUE_FLD_OFFSET 0 + +#define TI_K3_OSPI_REMAP_ADDR_VALUE_FLD_SIZE 32 + +/* SRAM_FILL */ +#define TI_K3_OSPI_SRAM_FILL_INDAC_WRITE_FLD_OFFSET 16 +#define TI_K3_OSPI_SRAM_FILL_INDAC_READ_FLD_OFFSET 0 + +#define TI_K3_OSPI_SRAM_FILL_INDAC_WRITE_FLD_SIZE 16 +#define TI_K3_OSPI_SRAM_FILL_INDAC_READ_FLD_SIZE 16 + +/* TX_THRESH */ +#define TI_K3_OSPI_TX_THRESH_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_TX_THRESH_LEVEL_FLD_SIZE 5 + +/* RX_THRESH */ +#define TI_K3_OSPI_RX_THRESH_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_RX_THRESH_LEVEL_FLD_SIZE 5 + +/* WRITE_COMPLETION_CTRL */ +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_REP_DELAY_FLD_OFFSET 24 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_COUNT_FLD_OFFSET 16 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_ENABLE_POLLING_EXP_FLD_OFFSET 15 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_DISABLE_POLLING_FLD_OFFSET 14 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_POLARITY_FLD_OFFSET 13 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_BIT_INDEX_FLD_OFFSET 8 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_OPCODE_FLD_OFFSET 0 + +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_REP_DELAY_FLD_SIZE 8 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLL_COUNT_FLD_SIZE 8 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_ENABLE_POLLING_EXP_FLD_SIZE 1 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_DISABLE_POLLING_FLD_SIZE 1 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_POLARITY_FLD_SIZE 1 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_POLLING_BIT_INDEX_FLD_SIZE 3 +#define TI_K3_OSPI_WRITE_COMPLETION_CTRL_OPCODE_FLD_SIZE 8 + +/* NO_OF_POLLS_BEF_EXP */ +#define TI_K3_OSPI_NO_OF_POLLS_BEF_EXP_NO_OF_POLLS_BEF_EXP_FLD_OFFSET 0 + +#define TI_K3_OSPI_NO_OF_POLLS_BEF_EXP_NO_OF_POLLS_BEF_EXP_FLD_SIZE 32 + +/* IRQ_STATUS */ +#define TI_K3_OSPI_IRQ_STATUS_ECC_FAIL_FLD_OFFSET 19 +#define TI_K3_OSPI_IRQ_STATUS_TX_CRC_CHUNK_BRK_FLD_OFFSET 18 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_VAL_FLD_OFFSET 17 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_ERR_FLD_OFFSET 16 +#define TI_K3_OSPI_IRQ_STATUS_STIG_REQ_INT_FLD_OFFSET 14 +#define TI_K3_OSPI_IRQ_STATUS_POLL_EXP_INT_FLD_OFFSET 13 +#define TI_K3_OSPI_IRQ_STATUS_INDRD_SRAM_FULL_FLD_OFFSET 12 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_FULL_FLD_OFFSET 11 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_NOT_EMPTY_FLD_OFFSET 10 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_FULL_FLD_OFFSET 9 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_NOT_FULL_FLD_OFFSET 8 +#define TI_K3_OSPI_IRQ_STATUS_RECV_OVERFLOW_FLD_OFFSET 7 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_XFER_LEVEL_BREACH_FLD_OFFSET 6 +#define TI_K3_OSPI_IRQ_STATUS_ILLEGAL_ACCESS_DET_FLD_OFFSET 5 +#define TI_K3_OSPI_IRQ_STATUS_PROT_WR_ATTEMPT_FLD_OFFSET 4 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_READ_REJECT_FLD_OFFSET 3 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_OP_DONE_FLD_OFFSET 2 +#define TI_K3_OSPI_IRQ_STATUS_UNDERFLOW_DET_FLD_OFFSET 1 +#define TI_K3_OSPI_IRQ_STATUS_MODE_M_FAIL_FLD_OFFSET 0 + +#define TI_K3_OSPI_IRQ_STATUS_ECC_FAIL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_TX_CRC_CHUNK_BRK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_VAL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_CRC_DATA_ERR_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_STIG_REQ_INT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_POLL_EXP_INT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDRD_SRAM_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RX_FIFO_NOT_EMPTY_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_TX_FIFO_NOT_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_RECV_OVERFLOW_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_XFER_LEVEL_BREACH_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_ILLEGAL_ACCESS_DET_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_PROT_WR_ATTEMPT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_READ_REJECT_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_INDIRECT_OP_DONE_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_UNDERFLOW_DET_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_STATUS_MODE_M_FAIL_FLD_SIZE 1 + +#define TI_K3_OSPI_IRQ_STATUS_ALL (BIT_MASK(19) & ~BIT(15)) + +/* IRQ_MASK */ +#define TI_K3_OSPI_IRQ_MASK_ECC_FAIL_MASK_FLD_OFFSET 19 +#define TI_K3_OSPI_IRQ_MASK_TX_CRC_CHUNK_BRK_MASK_FLD_OFFSET 18 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_VAL_MASK_FLD_OFFSET 17 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_ERR_MASK_FLD_OFFSET 16 +#define TI_K3_OSPI_IRQ_MASK_STIG_REQ_INT_MASK_FLD_OFFSET 14 +#define TI_K3_OSPI_IRQ_MASK_POLL_EXP_INT_MASK_FLD_OFFSET 13 +#define TI_K3_OSPI_IRQ_MASK_INDRD_SRAM_FULL_MASK_FLD_OFFSET 12 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_FULL_MASK_FLD_OFFSET 11 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_NOT_EMPTY_MASK_FLD_OFFSET 10 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_FULL_MASK_FLD_OFFSET 9 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_NOT_FULL_MASK_FLD_OFFSET 8 +#define TI_K3_OSPI_IRQ_MASK_RECV_OVERFLOW_MASK_FLD_OFFSET 7 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_XFER_LEVEL_BREACH_MASK_FLD_OFFSET 6 +#define TI_K3_OSPI_IRQ_MASK_ILLEGAL_ACCESS_DET_MASK_FLD_OFFSET 5 +#define TI_K3_OSPI_IRQ_MASK_PROT_WR_ATTEMPT_MASK_FLD_OFFSET 4 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_READ_REJECT_MASK_FLD_OFFSET 3 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_OP_DONE_MASK_FLD_OFFSET 2 +#define TI_K3_OSPI_IRQ_MASK_UNDERFLOW_DET_MASK_FLD_OFFSET 1 +#define TI_K3_OSPI_IRQ_MASK_MODE_M_FAIL_MASK_FLD_OFFSET 0 + +#define TI_K3_OSPI_IRQ_MASK_ECC_FAIL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_TX_CRC_CHUNK_BRK_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_VAL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_CRC_DATA_ERR_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_STIG_REQ_INT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_POLL_EXP_INT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDRD_SRAM_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RX_FIFO_NOT_EMPTY_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_TX_FIFO_NOT_FULL_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_RECV_OVERFLOW_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_XFER_LEVEL_BREACH_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_ILLEGAL_ACCESS_DET_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_PROT_WR_ATTEMPT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_READ_REJECT_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_INDIRECT_OP_DONE_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_UNDERFLOW_DET_MASK_FLD_SIZE 1 +#define TI_K3_OSPI_IRQ_MASK_MODE_M_FAIL_MASK_FLD_SIZE 1 + +#define TI_K3_OSPI_IRQ_MASK_ALL (BIT_MASK(19) & ~BIT(15)) + +/* LOWER_WR_PROT */ +#define TI_K3_OSPI_LOWER_WR_PROT_SUBSECTOR_FLD_OFFSET 0 + +#define TI_K3_OSPI_LOWER_WR_PROT_SUBSECTOR_FLD_SIZE 32 + +/* UPPER_WR_PROT */ +#define TI_K3_OSPI_UPPER_WR_PROT_SUBSECTOR_FLD_OFFSET 0 + +#define TI_K3_OSPI_UPPER_WR_PROT_SUBSECTOR_FLD_SIZE 32 + +/* WR_PROT_CTRL */ +#define TI_K3_OSPI_WR_PROT_CTRL_ENB_FLD_OFFSET 1 +#define TI_K3_OSPI_WR_PROT_CTRL_INV_FLD_OFFSET 0 + +#define TI_K3_OSPI_WR_PROT_CTRL_ENB_FLD_SIZE 1 +#define TI_K3_OSPI_WR_PROT_CTRL_INV_FLD_SIZE 1 + +/* INDIRECT_READ_XFER_CTRL */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_NUM_IND_OPS_DONE_FLD_OFFSET 6 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_OFFSET 5 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_QUEUED_FLD_OFFSET 4 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_SRAM_FULL_FLD_OFFSET 3 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_STATUS_FLD_OFFSET 2 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_CANCEL_FLD_OFFSET 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_START_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_NUM_IND_OPS_DONE_FLD_SIZE 2 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_QUEUED_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_SRAM_FULL_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_RD_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_CANCEL_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_READ_XFER_CTRL_START_FLD_SIZE 1 + +/* INDIRECT_READ_XFER_WATERMARK */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_WATERMARK_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_WATERMARK_LEVEL_FLD_SIZE 32 + +/* INDIRECT_READ_XFER_START */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_START_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_START_ADDR_FLD_SIZE 32 + +/* INDIRECT_READ_XFER_NUM_BYTES */ +#define TI_K3_OSPI_INDIRECT_READ_XFER_NUM_BYTES_VALUE_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_READ_XFER_NUM_BYTES_VALUE_FLD_SIZE 32 + +/* INDIRECT_WRITE_XFER_CTRL_REG */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_NUM_IND_OPS_DONE_FLD_OFFSET 6 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_OFFSET 5 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_QUEUED_FLD_OFFSET 4 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_STATUS_FLD_OFFSET 2 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_CANCEL_FLD_OFFSET 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_START_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_NUM_IND_OPS_DONE_FLD_SIZE 2 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_IND_OPS_DONE_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_QUEUED_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_WR_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_CANCEL_FLD_SIZE 1 +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_CTRL_START_FLD_SIZE 1 + +/* INDIRECT_WRITE_XFER_WATERMARK */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_WATERMARK_LEVEL_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_WATERMARK_LEVEL_FLD_SIZE 32 + +/* INDIRECT_WRITE_XFER_START */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_START_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_START_ADDR_FLD_SIZE 32 + +/* INDIRECT_WRITE_XFER_NUM_BYTES */ +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_NUM_BYTES_VALUE_FLD_OFFSET 0 + +#define TI_K3_OSPI_INDIRECT_WRITE_XFER_NUM_BYTES_VALUE_FLD_SIZE 32 + +/* IND_AHB_ADDR_TRIGGER */ +#define TI_K3_OSPI_IND_AHB_ADDR_TRIGGER_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_IND_AHB_ADDR_TRIGGER_ADDR_FLD_SIZE 32 + +/* FLASH_COMMAND_CTRL_MEM */ +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_ADDR_FLD_OFFSET 20 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_NB_OF_STIG_READ_BYTES_FLD_OFFSET 16 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_READ_DATA_FLD_OFFSET 8 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_REQ_IN_PROGRESS_FLD_OFFSET 1 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_TRIGGER_MEM_BANK_REQ_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_ADDR_FLD_SIZE 9 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_NB_OF_STIG_READ_BYTES_FLD_SIZE 3 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_READ_DATA_FLD_SIZE 8 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_MEM_BANK_REQ_IN_PROGRESS_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_COMMAND_CTRL_MEM_TRIGGER_MEM_BANK_REQ_FLD_SIZE 1 + +/* FLASH_CMD_CTRL */ +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_OPCODE_FLD_OFFSET 24 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_READ_DATA_FLD_OFFSET 23 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_RD_DATA_BYTES_FLD_OFFSET 20 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_COMD_ADDR_FLD_OFFSET 19 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_MODE_BIT_FLD_OFFSET 18 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_ADDR_BYTES_FLD_OFFSET 16 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_WRITE_DATA_FLD_OFFSET 15 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_WR_DATA_BYTES_FLD_OFFSET 12 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_DUMMY_CYCLES_FLD_OFFSET 7 +#define TI_K3_OSPI_FLASH_CMD_CTRL_STIG_MEM_BANK_EN_FLD_OFFSET 2 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_STATUS_FLD_OFFSET 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_READ_DATA_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_RD_DATA_BYTES_FLD_SIZE 3 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_COMD_ADDR_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_MODE_BIT_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_ADDR_BYTES_FLD_SIZE 2 +#define TI_K3_OSPI_FLASH_CMD_CTRL_ENB_WRITE_DATA_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_WR_DATA_BYTES_FLD_SIZE 3 +#define TI_K3_OSPI_FLASH_CMD_CTRL_NUM_DUMMY_CYCLES_FLD_SIZE 5 +#define TI_K3_OSPI_FLASH_CMD_CTRL_STIG_MEM_BANK_EN_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_STATUS_FLD_SIZE 1 +#define TI_K3_OSPI_FLASH_CMD_CTRL_CMD_EXEC_FLD_SIZE 1 + +/* FLASH_CMD_ADDR */ +#define TI_K3_OSPI_FLASH_CMD_ADDR_ADDR_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_CMD_ADDR_ADDR_FLD_SIZE 32 + +/* FLASH_RD_DATA_LOWER */ +#define TI_K3_OSPI_FLASH_RD_DATA_LOWER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_RD_DATA_LOWER_DATA_FLD_SIZE 32 + +/* FLASH_RD_DATA_UPPER */ +#define TI_K3_OSPI_FLASH_RD_DATA_UPPER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_RD_DATA_UPPER_DATA_FLD_SIZE 32 + +/* FLASH_WR_DATA_LOWER */ +#define TI_K3_OSPI_FLASH_WR_DATA_LOWER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_WR_DATA_LOWER_DATA_FLD_SIZE 32 + +/* FLASH_WR_DATA_UPPER */ +#define TI_K3_OSPI_FLASH_WR_DATA_UPPER_DATA_FLD_OFFSET 0 + +#define TI_K3_OSPI_FLASH_WR_DATA_UPPER_DATA_FLD_SIZE 32 + +/* POLLING_FLASH_STATUS */ +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_NB_DUMMY_FLD_OFFSET 16 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_VALID_FLD_OFFSET 8 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_FLD_OFFSET 0 + +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_NB_DUMMY_FLD_SIZE 4 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_VALID_FLD_SIZE 1 +#define TI_K3_OSPI_POLLING_FLASH_STATUS_DEVICE_STATUS_FLD_SIZE 8 + +/* PHY_CONFIGURATION */ +#define TI_K3_OSPI_PHY_CONFIGURATION_RESYNC_FLD_OFFSET 31 +#define TI_K3_OSPI_PHY_CONFIGURATION_RESET_FLD_OFFSET 30 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_BYPASS_FLD_OFFSET 29 +#define TI_K3_OSPI_PHY_CONFIGURATION_TX_DLL_DELAY_FLD_OFFSET 16 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_DELAY_FLD_OFFSET 0 + +#define TI_K3_OSPI_PHY_CONFIGURATION_RESYNC_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_CONFIGURATION_RESET_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_BYPASS_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_CONFIGURATION_TX_DLL_DELAY_FLD_SIZE 7 +#define TI_K3_OSPI_PHY_CONFIGURATION_RX_DLL_DELAY_FLD_SIZE 7 + +/* PHY_MASTER_CONTROL */ +#define TI_K3_OSPI_PHY_MASTER_CONTROL_LOCK_MODE_FLD_OFFSET 24 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_BYPASS_MODE_FLD_OFFSET 23 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_PHASE_DETECT_SELECTOR_FLD_OFFSET 20 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_NB_INDICATIONS_FLD_OFFSET 16 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_INITIAL_DELAY_FLD_OFFSET 0 + +#define TI_K3_OSPI_PHY_MASTER_CONTROL_LOCK_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_BYPASS_MODE_FLD_SIZE 1 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_PHASE_DETECT_SELECTOR_FLD_SIZE 3 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_NB_INDICATIONS_FLD_SIZE 3 +#define TI_K3_OSPI_PHY_MASTER_CONTROL_INITIAL_DELAY_FLD_SIZE 7 + +/* DLL_OBSERVABLE_LOWER */ +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD_OFFSET 24 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD_OFFSET 16 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD_OFFSET 15 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD_OFFSET 8 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD_OFFSET 3 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD_OFFSET 1 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD_OFFSET 0 + +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_INC_FLD_SIZE 8 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_DEC_FLD_SIZE 8 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOOPBACK_LOCK_FLD_SIZE 1 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_VALUE_FLD_SIZE 7 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_UNLOCK_COUNTER_FLD_SIZE 5 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_LOCK_MODE_FLD_SIZE 2 +#define TI_K3_OSPI_DLL_OBSERVABLE_LOWER_DLL_LOCK_FLD_SIZE 1 + +/* DLL_OBSERVABLE_UPPER */ +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD_OFFSET 16 +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_RX_DECODER_OUTPUT_FLD_OFFSET 0 + +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_TX_DECODER_OUTPUT_FLD_SIZE 7 +#define TI_K3_OSPI_DLL_OBSERVABLE_UPPER_RX_DECODER_OUTPUT_FLD_SIZE 7 + +/* OPCODE_EXT_LOWER */ +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_READ_OPCODE_FLD_OFFSET 24 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_WRITE_OPCODE_FLD_OFFSET 16 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_POLL_OPCODE_FLD_OFFSET 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_STIG_OPCODE_FLD_OFFSET 0 + +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_READ_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_WRITE_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_POLL_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_LOWER_EXT_STIG_OPCODE_FLD_SIZE 8 + +/* OPCODE_EXT_UPPER */ +#define TI_K3_OSPI_OPCODE_EXT_UPPER_WEL_OPCODE_FLD_OFFSET 24 +#define TI_K3_OSPI_OPCODE_EXT_UPPER_EXT_WEL_OPCODE_FLD_OFFSET 16 + +#define TI_K3_OSPI_OPCODE_EXT_UPPER_WEL_OPCODE_FLD_SIZE 8 +#define TI_K3_OSPI_OPCODE_EXT_UPPER_EXT_WEL_OPCODE_FLD_SIZE 8 + +#endif /* ZEPHYR_DRIVERS_MSPI_TI_K3_H_*/ diff --git a/dts/bindings/mspi/ti,mspi-k3-controller.yaml b/dts/bindings/mspi/ti,mspi-k3-controller.yaml new file mode 100644 index 000000000000..c3f4221209d3 --- /dev/null +++ b/dts/bindings/mspi/ti,mspi-k3-controller.yaml @@ -0,0 +1,48 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: TI K3 MSPI Controller + +compatible: "ti,k3-mspi-controller" + +include: [mspi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + description: | + Address and length of the MSPI configuration register and the indirect + write FIFO location. + + sram-allocated-for-read: + required: true + type: int + description: | + Amount of SRAM that is allocated for read data from the MSPI bus. The rest + is allocated for data written to the MSPI bus. + The value needs to be between 0 and 255 + + init-nss-delay: + type: int + description: | + Amount of clock cycles between the CS pin is deasserted between + transactions after startup. Can be changed during runtime via the timing + config + + init-btwn-delay: + type: int + description: | + Amount of clock cycles no peripheral is selected during switching device + after startup. Can be changed during runtime via the timing config + + init-after-delay: + type: int + description: | + Amount of clock cycles the CS pin is continue being held after the last + bit was transferred. Can be changed during runtime via the timing config + + init-init-delay: + type: int + description: | + Amount of clock cycles is asserted before sending the first bit of the + transmission. Can be changed during runtime via the timing config diff --git a/dts/bindings/mtd/infineon,s25h-flash.yaml b/dts/bindings/mtd/infineon,s25h-flash.yaml new file mode 100644 index 000000000000..47d09b3a82cb --- /dev/null +++ b/dts/bindings/mtd/infineon,s25h-flash.yaml @@ -0,0 +1,24 @@ +# Copyright (c) 2025 Siemens Mobility GmbH +# SPDX-License-Identifier: Apache-2.0 + +description: MSPI Infineon S25H Flash + +compatible: "infineon,s25h-flash" + +on-bus: mspi + +include: ["soc-nv-flash.yaml", "pinctrl-device.yaml", "mspi-device.yaml"] + +properties: + reg: + required: true + + reset-startup-time-us: + required: true + type: int + description: Time the device requires to recover after a reset in microseconds + + flash-size: + required: true + type: int + description: Size of the flash in byte