diff --git a/drivers/rz/CMakeLists.txt b/drivers/rz/CMakeLists.txt index 4a8e0df5..b206b627 100644 --- a/drivers/rz/CMakeLists.txt +++ b/drivers/rz/CMakeLists.txt @@ -96,3 +96,11 @@ zephyr_library_sources_ifdef(CONFIG_USE_RZ_FSP_MTU zephyr_library_sources_ifdef(CONFIG_USE_RZ_FSP_CMTW fsp/src/${SOC_SERIES_PREFIX}/r_cmtw/r_cmtw.c) + +if(CONFIG_DT_HAS_RENESAS_RZ_QSPI_SPIBSC_ENABLED) + zephyr_library_sources_ifdef(CONFIG_USE_RZ_FSP_QSPI + fsp/src/${SOC_SERIES_PREFIX}/r_spibsc/r_spibsc.c) +else() + zephyr_library_sources_ifdef(CONFIG_USE_RZ_FSP_QSPI + fsp/src/${SOC_SERIES_PREFIX}/r_xspi_qspi/r_xspi_qspi.c) +endif() diff --git a/drivers/rz/fsp/inc/api/r_spi_flash_api.h b/drivers/rz/fsp/inc/api/r_spi_flash_api.h new file mode 100644 index 00000000..d18979f9 --- /dev/null +++ b/drivers/rz/fsp/inc/api/r_spi_flash_api.h @@ -0,0 +1,334 @@ +/* +* Copyright (c) 2020 - 2025 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/*******************************************************************************************************************//** + * @ingroup RENESAS_STORAGE_INTERFACES + * @defgroup SPI_FLASH_API SPI Flash Interface + * @brief Interface for accessing external SPI flash devices. + * + * @section SPI_FLASH_API_SUMMARY Summary + * The SPI flash API provides an interface that configures, writes, and erases sectors in SPI flash devices. + * @{ + **********************************************************************************************************************/ + +#ifndef R_SPI_FLASH_API_H +#define R_SPI_FLASH_API_H + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ + +/* Register definitions, common services and error codes. */ +#include "bsp_api.h" + +/* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */ +FSP_HEADER + +/********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ + +#define SPI_FLASH_ERASE_SIZE_CHIP_ERASE (UINT32_MAX) + +/********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/** Read mode. */ +typedef enum e_spi_flash_read_mode +{ + SPI_FLASH_READ_MODE_STANDARD = 0, ///< Standard Read Mode (no dummy cycles) + SPI_FLASH_READ_MODE_FAST_READ = 1, ///< Fast Read Mode (dummy cycles between address and data) + SPI_FLASH_READ_MODE_FAST_READ_DUAL_OUTPUT = 2, ///< Fast Read Dual Output Mode (data on 2 lines) + SPI_FLASH_READ_MODE_FAST_READ_DUAL_IO = 3, ///< Fast Read Dual I/O Mode (address and data on 2 lines) + SPI_FLASH_READ_MODE_FAST_READ_QUAD_OUTPUT = 4, ///< Fast Read Quad Output Mode (data on 4 lines) + SPI_FLASH_READ_MODE_FAST_READ_QUAD_IO = 5, ///< Fast Read Quad I/O Mode (address and data on 4 lines) +} spi_flash_read_mode_t; + +/** SPI protocol. */ +typedef enum e_spi_flash_protocol +{ + /** Extended SPI mode (commands on 1 line) */ + SPI_FLASH_PROTOCOL_EXTENDED_SPI = 0x000, + + /** QPI mode (commands on 4 lines). Note that the application must ensure the device is in QPI mode. */ + SPI_FLASH_PROTOCOL_QPI = 0x002, + + /** SOPI mode (command and data on 8 lines). Note that the application must ensure the device is in SOPI mode. */ + SPI_FLASH_PROTOCOL_SOPI = 0x003, + + /** DOPI mode (command and data on 8 lines, dual data rate). Note that the application must ensure the device is in DOPI mode. */ + SPI_FLASH_PROTOCOL_DOPI = 0x004, + + /** 1S-1S-1S protocol mode */ + SPI_FLASH_PROTOCOL_1S_1S_1S = 0x000, + + /** 4S-4D-4D protocol mode */ + SPI_FLASH_PROTOCOL_4S_4D_4D = 0x3B2, + + /** 8D-8D-8D protocol mode */ + SPI_FLASH_PROTOCOL_8D_8D_8D = 0x3FF, + + /** 1S-2S-2S protocol mode */ + SPI_FLASH_PROTOCOL_1S_2S_2S = 0x048, + + /** 2S-2S-2S protocol mode */ + SPI_FLASH_PROTOCOL_2S_2S_2S = 0x049, + + /** 1S-4S-4S protocol mode */ + SPI_FLASH_PROTOCOL_1S_4S_4S = 0x090, + + /** 4S-4S-4S protocol mode */ + SPI_FLASH_PROTOCOL_4S_4S_4S = 0x092 +} spi_flash_protocol_t; + +/** Number of bytes in the address. */ +typedef enum e_spi_flash_address_bytes +{ + SPI_FLASH_ADDRESS_BYTES_3 = 2, ///< 3 address bytes + + /** 4 address bytes with standard commands. If this option is selected, the application must issue the EN4B + * command using @ref spi_flash_api_t::directWrite() if required by the device. */ + SPI_FLASH_ADDRESS_BYTES_4 = 3, + + /** 4 address bytes using standard 4-byte command set. */ + SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE = 0x13, +} spi_flash_address_bytes_t; + +/** Number of data lines used. */ +typedef enum e_spi_flash_data_lines +{ + SPI_FLASH_DATA_LINES_1 = 0, ///< 1 data line + SPI_FLASH_DATA_LINES_2 = 1, ///< 2 data lines + SPI_FLASH_DATA_LINES_4 = 2, ///< 4 data lines +} spi_flash_data_lines_t; + +/** Number of dummy cycles for fast read operations. */ +typedef enum e_spi_flash_dummy_clocks +{ + SPI_FLASH_DUMMY_CLOCKS_0 = 0, ///< 0 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_1, ///< 1 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_2, ///< 2 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_3, ///< 3 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_4, ///< 4 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_5, ///< 5 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_6, ///< 6 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_7, ///< 7 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_8, ///< 8 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_9, ///< 9 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_10, ///< 10 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_11, ///< 11 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_12, ///< 12 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_13, ///< 13 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_14, ///< 14 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_15, ///< 15 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_16, ///< 16 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_17, ///< 17 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_18, ///< 18 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_19, ///< 19 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_20, ///< 20 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_21, ///< 21 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_22, ///< 22 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_23, ///< 23 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_24, ///< 24 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_25, ///< 25 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_26, ///< 26 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_27, ///< 27 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_28, ///< 28 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_29, ///< 29 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_30, ///< 30 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_31, ///< 31 dummy clocks + SPI_FLASH_DUMMY_CLOCKS_DEFAULT = 0xFF, +} spi_flash_dummy_clocks_t; + +/** Direct Read and Write direction */ +typedef enum e_spi_flash_direct_transfer_dir_option +{ + SPI_FLASH_DIRECT_TRANSFER_DIR_READ = 0x0, + SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE = 0x1 +} spi_flash_direct_transfer_dir_t; + +/** Structure to define an erase command and associated erase size. */ +typedef struct st_spi_flash_erase_command +{ + uint16_t command; ///< Erase command + uint32_t size; ///< Size of erase for associated command, set to SPI_FLASH_ERASE_SIZE_CHIP_ERASE for chip erase +} spi_flash_erase_command_t; + +/** Structure to define a direct transfer. */ +typedef struct st_spi_flash_direct_transfer +{ + union + { + uint64_t data_u64; ///< Data (64-bit) + uint32_t data; ///< Data + }; + uint32_t address; ///< Starting address + uint16_t command; ///< Transfer command + uint8_t dummy_cycles; ///< Number of dummy cycles + uint8_t command_length; ///< Command length + uint8_t address_length; ///< Address length + uint8_t data_length; ///< Data length +} spi_flash_direct_transfer_t; + +/** User configuration structure used by the open function */ +typedef struct st_spi_flash_cfg +{ + spi_flash_protocol_t spi_protocol; ///< Initial SPI protocol. SPI protocol can be changed in @ref spi_flash_api_t::spiProtocolSet. + spi_flash_read_mode_t read_mode; ///< Read mode + spi_flash_address_bytes_t address_bytes; ///< Number of bytes used to represent the address + spi_flash_dummy_clocks_t dummy_clocks; ///< Number of dummy clocks to use for fast read operations + + /** Number of lines used to send address for page program command. This should either be 1 or match the number of lines used in + * the selected read mode. */ + spi_flash_data_lines_t page_program_address_lines; + uint8_t write_status_bit; ///< Which bit determines write status + uint8_t write_enable_bit; ///< Which bit determines write status + uint32_t page_size_bytes; ///< Page size in bytes (maximum number of bytes for page program). Used to specify single continuous write size (bytes) in case of OSPI RAM. + uint8_t page_program_command; ///< Page program command + uint8_t write_enable_command; ///< Command to enable write or erase, typically 0x06 + uint8_t status_command; ///< Command to read the write status + uint8_t read_command; ///< Read command - OSPI SPI mode only + uint8_t xip_enter_command; ///< Command to enter XIP mode + uint8_t xip_exit_command; ///< Command to exit XIP mode + uint8_t erase_command_list_length; ///< Length of erase command list + spi_flash_erase_command_t const * p_erase_command_list; ///< List of all erase commands and associated sizes + void const * p_extend; ///< Pointer to implementation specific extended configurations +} spi_flash_cfg_t; + +/** SPI flash control block. Allocate an instance specific control block to pass into the SPI flash API calls. + */ +typedef void spi_flash_ctrl_t; + +/** Status. */ +typedef struct st_spi_flash_status +{ + /** Whether or not a write is in progress. This is determined by reading the @ref spi_flash_cfg_t::write_status_bit + * from the @ref spi_flash_cfg_t::status_command. */ + bool write_in_progress; +} spi_flash_status_t; + +/** SPI flash implementations follow this API. */ +typedef struct st_spi_flash_api +{ + /** Open the SPI flash driver module. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[in] p_cfg Pointer to a configuration structure + **/ + fsp_err_t (* open)(spi_flash_ctrl_t * const p_ctrl, spi_flash_cfg_t const * const p_cfg); + + /** Write raw data to the SPI flash. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[in] p_src Pointer to raw data to write, must include any required command/address + * @param[in] bytes Number of bytes to write + * @param[in] read_after_write If true, the slave select remains asserted and the peripheral does not return + * to direct communications mode. If false, the slave select is deasserted and + * memory mapped access is possible after this function returns if the device + * is not busy. + **/ + fsp_err_t (* directWrite)(spi_flash_ctrl_t * const p_ctrl, uint8_t const * const p_src, uint32_t const bytes, + bool const read_after_write); + + /** Read raw data from the SPI flash. Must follow a call to @ref spi_flash_api_t::directWrite. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[out] p_dest Pointer to read raw data into + * @param[in] bytes Number of bytes to read + **/ + fsp_err_t (* directRead)(spi_flash_ctrl_t * const p_ctrl, uint8_t * const p_dest, uint32_t const bytes); + + /** Direct Read/Write raw data to the SPI flash. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[in] p_data Pointer to command, address and data values and lengths + * @param[in] direction Direct Read/Write + **/ + fsp_err_t (* directTransfer)(spi_flash_ctrl_t * const p_ctrl, spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction); + + /** Change the SPI protocol in the driver. The application must change the SPI protocol on the device. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[in] spi_protocol Desired SPI protocol + **/ + fsp_err_t (* spiProtocolSet)(spi_flash_ctrl_t * const p_ctrl, spi_flash_protocol_t spi_protocol); + + /** Program a page of data to the flash. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[in] p_src The memory address of the data to write to the flash device + * @param[in] p_dest The location in the flash device address space to write the data to + * @param[in] byte_count The number of bytes to write + **/ + fsp_err_t (* write)(spi_flash_ctrl_t * const p_ctrl, uint8_t const * const p_src, uint8_t * const p_dest, + uint32_t byte_count); + + /** Erase a certain number of bytes of the flash. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[in] p_device_address The location in the flash device address space to start the erase from + * @param[in] byte_count The number of bytes to erase. Set to SPI_FLASH_ERASE_SIZE_CHIP_ERASE to erase entire + * chip. + **/ + fsp_err_t (* erase)(spi_flash_ctrl_t * const p_ctrl, uint8_t * const p_device_address, uint32_t byte_count); + + /** Get the write or erase status of the flash. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[out] p_status Current status of the SPI flash device stored here. + **/ + fsp_err_t (* statusGet)(spi_flash_ctrl_t * const p_ctrl, spi_flash_status_t * const p_status); + + /** Enter XIP mode. + * + * @param[in] p_ctrl Pointer to a driver handle + **/ + fsp_err_t (* xipEnter)(spi_flash_ctrl_t * const p_ctrl); + + /** Exit XIP mode. + * + * @param[in] p_ctrl Pointer to a driver handle + **/ + fsp_err_t (* xipExit)(spi_flash_ctrl_t * const p_ctrl); + + /** Select the bank to access. See implementation for details. + * + * @param[in] p_ctrl Pointer to a driver handle + * @param[in] bank The bank number + **/ + fsp_err_t (* bankSet)(spi_flash_ctrl_t * const p_ctrl, uint32_t bank); + + /** AutoCalibrate the SPI flash driver module. Expected to be used when auto-calibrating OSPI RAM device. + * + * @param[in] p_ctrl Pointer to a driver handle + **/ + fsp_err_t (* autoCalibrate)(spi_flash_ctrl_t * const p_ctrl); + + /** Close the SPI flash driver module. + * + * @param[in] p_ctrl Pointer to a driver handle + **/ + fsp_err_t (* close)(spi_flash_ctrl_t * const p_ctrl); +} spi_flash_api_t; + +/** This structure encompasses everything that is needed to use an instance of this interface. */ +typedef struct st_spi_flash_instance +{ + spi_flash_ctrl_t * p_ctrl; ///< Pointer to the control structure for this instance + spi_flash_cfg_t const * p_cfg; ///< Pointer to the configuration structure for this instance + spi_flash_api_t const * p_api; ///< Pointer to the API structure for this instance +} spi_flash_instance_t; + +/* Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */ +FSP_FOOTER + +#endif + +/*******************************************************************************************************************//** + * @} (end defgroup SPI_FLASH_API) + **********************************************************************************************************************/ diff --git a/drivers/rz/fsp/inc/instances/rza/r_spibsc.h b/drivers/rz/fsp/inc/instances/rza/r_spibsc.h new file mode 100644 index 00000000..389a6782 --- /dev/null +++ b/drivers/rz/fsp/inc/instances/rza/r_spibsc.h @@ -0,0 +1,101 @@ +/* +* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/*******************************************************************************************************************//** + * @addtogroup SPIBSC + * @{ + **********************************************************************************************************************/ + +#ifndef R_SPIBSC_H +#define R_SPIBSC_H + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ +#include "bsp_api.h" +#include "r_spibsc_cfg.h" +#include "r_spi_flash_api.h" + +/* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */ +FSP_HEADER + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/* Delay settings. */ +typedef struct st_spibsc_delay +{ + uint8_t slch : 3; ///< SLCH (Select to Clock Delay) cycles + uint8_t clsh : 3; ///< CLSH (Clock Low to Deselect Delay) cycles + uint8_t shsl : 3; ///< SHSL (Deselect to Select Delay) cycles +} spibsc_delay_t; + +/* Extended configuration. */ +typedef struct st_spibsc_extended_cfg +{ + spibsc_delay_t delay; ///< Delay setting + uint8_t io_fix_mask; ///< Enable to fixture IOn signal level during idle state (bit mapped) + uint8_t io_fix_value; ///< Value to fixture IOn signal level during idle state (bit mapped) +} spibsc_extended_cfg_t; + +/** Instance control block. DO NOT INITIALIZE. Initialization occurs when @ref spi_flash_api_t::open is called */ +typedef struct st_spibsc_instance_ctrl +{ + spi_flash_cfg_t cfg; // Copy of configuration + spibsc_extended_cfg_t ext; // Copy of extended configuration + spi_flash_erase_command_t * p_erase_command_list; // Copy of erase command list (dynamically allocated) + uint32_t open; // Whether or not driver is open + bool is_xip_enabled; // The driver enables XIP (omitting cmd) mode + R_SPIBSC_Type * p_reg; // Controller register base address +} spibsc_instance_ctrl_t; + +/********************************************************************************************************************** + * Exported global variables + **********************************************************************************************************************/ + +/** @cond INC_HEADER_DEFS_SEC */ +/** Filled in Interface API structure for this Instance. */ +extern const spi_flash_api_t g_spi_flash_on_spibsc; + +/** @endcond */ + +fsp_err_t R_SPIBSC_Open(spi_flash_ctrl_t * p_api_ctrl, spi_flash_cfg_t const * const p_cfg) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_Close(spi_flash_ctrl_t * p_api_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_DirectWrite(spi_flash_ctrl_t * p_api_ctrl, + uint8_t const * const p_src, + uint32_t const bytes, + bool const read_after_write) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_DirectRead(spi_flash_ctrl_t * p_api_ctrl, uint8_t * const p_dest, + uint32_t const bytes) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_SpiProtocolSet(spi_flash_ctrl_t * p_api_ctrl, + spi_flash_protocol_t spi_protocol) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_XipEnter(spi_flash_ctrl_t * p_api_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_XipExit(spi_flash_ctrl_t * p_api_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_Write(spi_flash_ctrl_t * p_api_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_Erase(spi_flash_ctrl_t * p_api_ctrl, uint8_t * const p_device_address, + uint32_t byte_count) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_StatusGet(spi_flash_ctrl_t * p_api_ctrl, spi_flash_status_t * const p_status) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_BankSet(spi_flash_ctrl_t * p_api_ctrl, uint32_t bank) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_DirectTransfer(spi_flash_ctrl_t * p_api_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +fsp_err_t R_SPIBSC_AutoCalibrate(spi_flash_ctrl_t * p_api_ctrl); + +/* Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */ +FSP_FOOTER + +#endif + +/*******************************************************************************************************************//** + * @} (end defgroup SPIBSC) + **********************************************************************************************************************/ diff --git a/drivers/rz/fsp/inc/instances/rzn/r_xspi_qspi.h b/drivers/rz/fsp/inc/instances/rzn/r_xspi_qspi.h new file mode 100644 index 00000000..3afc58ef --- /dev/null +++ b/drivers/rz/fsp/inc/instances/rzn/r_xspi_qspi.h @@ -0,0 +1,183 @@ +/* +* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/*******************************************************************************************************************//** + * @addtogroup XSPI_QSPI + * @{ + **********************************************************************************************************************/ + +#ifndef R_XSPI_QSPI_H +#define R_XSPI_QSPI_H + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ +#include "bsp_api.h" +#include +#include "r_xspi_qspi_cfg.h" +#include "r_spi_flash_api.h" + +/* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */ +FSP_HEADER + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/* QSPI Flash chip select */ +typedef enum e_xspi_qspi_chip_select +{ + XSPI_QSPI_CHIP_SELECT_0, ///< Device connected to Chip-Select 0 + XSPI_QSPI_CHIP_SELECT_1, ///< Device connected to Chip-Select 1 +} xspi_qspi_chip_select_t; + +/* QSPI Flash memory size */ +typedef enum e_xspi_qspi_memory_size +{ + XSPI_QSPI_MEMORY_SIZE_1MB = 0x00, ///< Memory size 1MB + XSPI_QSPI_MEMORY_SIZE_2MB = 0x01, ///< Memory size 2MB + XSPI_QSPI_MEMORY_SIZE_4MB = 0x03, ///< Memory size 4MB + XSPI_QSPI_MEMORY_SIZE_8MB = 0x07, ///< Memory size 8MB + XSPI_QSPI_MEMORY_SIZE_16MB = 0x0F, ///< Memory size 16MB + XSPI_QSPI_MEMORY_SIZE_32MB = 0x1F, ///< Memory size 32MB + XSPI_QSPI_MEMORY_SIZE_64MB = 0x3F, ///< Memory size 64MB +} xspi_qspi_memory_size_t; + +/* QSPI command to command interval*/ +typedef enum e_xspi_qspi_command_interval_clocks +{ + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_1, ///< 1 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_2, ///< 2 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_3, ///< 3 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_4, ///< 4 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_5, ///< 5 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_6, ///< 6 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_7, ///< 7 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_8, ///< 8 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_9, ///< 9 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_10, ///< 10 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_11, ///< 11 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_12, ///< 12 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_13, ///< 13 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_14, ///< 14 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_15, ///< 15 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_16, ///< 16 interval clocks +} xspi_qspi_command_interval_clocks_t; + +/* QSPI chip select de-assertion duration */ +typedef enum e_xspi_qspi_cs_pullup_clocks +{ + XSPI_QSPI_CS_PULLUP_CLOCKS_NO_EXTENSION = 0, ///< CS asserting No extension + XSPI_QSPI_CS_PULLUP_CLOCKS_1, ///< CS asserting Extend 1 cycle +} xspi_qspi_cs_pullup_clocks_t; + +/* QSPI chip select assertion duration */ +typedef enum e_xspi_qspi_cs_pulldown_clocks +{ + XSPI_QSPI_CS_PULLDOWN_CLOCKS_NO_EXTENSION = 0, ///< CS negating No extension + XSPI_QSPI_CS_PULLDOWN_CLOCKS_1, ///< CS negating Extend 1 cycle +} xspi_qspi_cs_pulldown_clocks_t; + +/* Memory mapped timing */ +typedef struct st_qspi_timing_setting +{ + xspi_qspi_command_interval_clocks_t command_to_command_interval; ///< Interval between 2 consecutive commands + xspi_qspi_cs_pullup_clocks_t cs_pullup_lag; ///< Duration to de-assert CS line after the last command + xspi_qspi_cs_pulldown_clocks_t cs_pulldown_lead; ///< Duration to assert CS line before the first command +} xspi_qspi_timing_setting_t; + +/* Prefetch function settings */ +typedef enum e_xspi_qspi_prefetch_function +{ + XSPI_QSPI_PREFETCH_FUNCTION_DISABLE = 0x00, ///< Prefetch function disable + XSPI_QSPI_PREFETCH_FUNCTION_ENABLE = 0x01, ///< Prefetch function enable +} xspi_qspi_prefetch_function_t; + +/* IO voltage settings */ +typedef enum e_xspi_qspi_io_voltage +{ + XSPI_QSPI_IO_VOLTAGE_1_8V = 0x00, ///< IO voltage 1.8V + XSPI_QSPI_IO_VOLTAGE_3_3V = 0x01, ///< IO voltage 3.3V +} xspi_qspi_io_voltage_t; + +/* Address space settings */ +typedef struct st_qspi_address_space +{ + uint32_t unit0_cs0_end_address; ///< xSPI unit0 cs0 end address + uint32_t unit0_cs1_start_address; ///< xSPI unit0 cs1 start address + uint32_t unit0_cs1_end_address; ///< xSPI unit0 cs1 end address + uint32_t unit1_cs0_end_address; ///< xSPI unit1 cs0 end address + uint32_t unit1_cs1_start_address; ///< xSPI unit1 cs1 start address + uint32_t unit1_cs1_end_address; ///< xSPI unit1 cs1 end address +} xspi_qspi_address_space_t; + +/* Extended configuration. */ +typedef struct st_xspi_qspi_extended_cfg +{ + uint8_t unit; ///< Unit number of xSPI + xspi_qspi_chip_select_t chip_select; ///< Device number to be used for memory device + xspi_qspi_memory_size_t memory_size; ///< Size of memory device + xspi_qspi_timing_setting_t const * p_timing_settings; ///< Memory mapped timing settings + xspi_qspi_prefetch_function_t prefetch_en; ///< Prefetch function settings + xspi_qspi_io_voltage_t io_voltage; ///< Voltage setting of xSPI IO domain + xspi_qspi_address_space_t const * p_address_space; ///< Address space settings when custom address space enabled +} xspi_qspi_extended_cfg_t; + +/** Instance control block. DO NOT INITIALIZE. Initialization occurs when @ref spi_flash_api_t::open is called */ +typedef struct st_xspi_qspi_instance_ctrl +{ + spi_flash_cfg_t const * p_cfg; // Pointer to initial configuration + spi_flash_data_lines_t data_lines; // Data lines + uint32_t total_size_bytes; // Total size of the flash in bytes + uint32_t open; // Whether or not driver is open + R_XSPI0_Type * p_reg; // Base register for this channel + spi_flash_protocol_t spi_protocol; // Current SPI protocol selected +} xspi_qspi_instance_ctrl_t; + +/********************************************************************************************************************** + * Exported global variables + **********************************************************************************************************************/ + +/** @cond INC_HEADER_DEFS_SEC */ +/** Filled in Interface API structure for this Instance. */ +extern const spi_flash_api_t g_spi_flash_on_xspi_qspi; + +/** @endcond */ + +fsp_err_t R_XSPI_QSPI_Open(spi_flash_ctrl_t * p_ctrl, spi_flash_cfg_t const * const p_cfg); +fsp_err_t R_XSPI_QSPI_Close(spi_flash_ctrl_t * p_ctrl); +fsp_err_t R_XSPI_QSPI_DirectWrite(spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint32_t const bytes, + bool const read_after_write); +fsp_err_t R_XSPI_QSPI_DirectRead(spi_flash_ctrl_t * p_ctrl, uint8_t * const p_dest, uint32_t const bytes); +fsp_err_t R_XSPI_QSPI_SpiProtocolSet(spi_flash_ctrl_t * p_ctrl, spi_flash_protocol_t spi_protocol); +fsp_err_t R_XSPI_QSPI_XipEnter(spi_flash_ctrl_t * p_ctrl); +fsp_err_t R_XSPI_QSPI_XipExit(spi_flash_ctrl_t * p_ctrl); +fsp_err_t R_XSPI_QSPI_Write(spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count); +fsp_err_t R_XSPI_QSPI_Erase(spi_flash_ctrl_t * p_ctrl, uint8_t * const p_device_address, uint32_t byte_count); +fsp_err_t R_XSPI_QSPI_StatusGet(spi_flash_ctrl_t * p_ctrl, spi_flash_status_t * const p_status); +fsp_err_t R_XSPI_QSPI_BankSet(spi_flash_ctrl_t * p_ctrl, uint32_t bank); +fsp_err_t R_XSPI_QSPI_DirectTransfer(spi_flash_ctrl_t * p_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction); +fsp_err_t R_XSPI_QSPI_AutoCalibrate(spi_flash_ctrl_t * p_ctrl); + +/* Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */ +FSP_FOOTER + +#endif + +/*******************************************************************************************************************//** + * @} (end defgroup XSPI_QSPI) + **********************************************************************************************************************/ diff --git a/drivers/rz/fsp/inc/instances/rzt/r_xspi_qspi.h b/drivers/rz/fsp/inc/instances/rzt/r_xspi_qspi.h new file mode 100644 index 00000000..d71a5607 --- /dev/null +++ b/drivers/rz/fsp/inc/instances/rzt/r_xspi_qspi.h @@ -0,0 +1,222 @@ +/* +* Copyright (c) 2020 - 2025 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/*******************************************************************************************************************//** + * @addtogroup XSPI_QSPI + * @{ + **********************************************************************************************************************/ + +#ifndef R_XSPI_QSPI_H +#define R_XSPI_QSPI_H + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ +#include "bsp_api.h" +#include +#include "r_xspi_qspi_cfg.h" +#include "r_spi_flash_api.h" + +#if XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE + #include "r_transfer_api.h" +#endif + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE + #include "r_rsip_api.h" + #include "r_rsip_reg.h" +#endif + +/* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */ +FSP_HEADER + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/* QSPI Flash chip select */ +typedef enum e_xspi_qspi_chip_select +{ + XSPI_QSPI_CHIP_SELECT_0, ///< Device connected to Chip-Select 0 + XSPI_QSPI_CHIP_SELECT_1, ///< Device connected to Chip-Select 1 +} xspi_qspi_chip_select_t; + +/* QSPI Flash memory size */ +typedef enum e_xspi_qspi_memory_size +{ + XSPI_QSPI_MEMORY_SIZE_1MB = 0x00, ///< Memory size 1MB + XSPI_QSPI_MEMORY_SIZE_2MB = 0x01, ///< Memory size 2MB + XSPI_QSPI_MEMORY_SIZE_4MB = 0x03, ///< Memory size 4MB + XSPI_QSPI_MEMORY_SIZE_8MB = 0x07, ///< Memory size 8MB + XSPI_QSPI_MEMORY_SIZE_16MB = 0x0F, ///< Memory size 16MB + XSPI_QSPI_MEMORY_SIZE_32MB = 0x1F, ///< Memory size 32MB + XSPI_QSPI_MEMORY_SIZE_64MB = 0x3F, ///< Memory size 64MB +} xspi_qspi_memory_size_t; + +/* QSPI command to command interval*/ +typedef enum e_xspi_qspi_command_interval_clocks +{ + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_1, ///< 1 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_2, ///< 2 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_3, ///< 3 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_4, ///< 4 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_5, ///< 5 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_6, ///< 6 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_7, ///< 7 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_8, ///< 8 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_9, ///< 9 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_10, ///< 10 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_11, ///< 11 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_12, ///< 12 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_13, ///< 13 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_14, ///< 14 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_15, ///< 15 interval clocks + XSPI_QSPI_COMMAND_INTERVAL_CLOCKS_16, ///< 16 interval clocks +} xspi_qspi_command_interval_clocks_t; + +/* QSPI chip select de-assertion duration */ +typedef enum e_xspi_qspi_cs_pullup_clocks +{ + XSPI_QSPI_CS_PULLUP_CLOCKS_NO_EXTENSION = 0, ///< CS asserting No extension + XSPI_QSPI_CS_PULLUP_CLOCKS_1, ///< CS asserting Extend 1 cycle +} xspi_qspi_cs_pullup_clocks_t; + +/* QSPI chip select assertion duration */ +typedef enum e_xspi_qspi_cs_pulldown_clocks +{ + XSPI_QSPI_CS_PULLDOWN_CLOCKS_NO_EXTENSION = 0, ///< CS negating No extension + XSPI_QSPI_CS_PULLDOWN_CLOCKS_1, ///< CS negating Extend 1 cycle +} xspi_qspi_cs_pulldown_clocks_t; + +/* Memory mapped timing */ +typedef struct st_qspi_timing_setting +{ + xspi_qspi_command_interval_clocks_t command_to_command_interval; ///< Interval between 2 consecutive commands + xspi_qspi_cs_pullup_clocks_t cs_pullup_lag; ///< Duration to de-assert CS line after the last command + xspi_qspi_cs_pulldown_clocks_t cs_pulldown_lead; ///< Duration to assert CS line before the first command +} xspi_qspi_timing_setting_t; + +/* Prefetch function settings */ +typedef enum e_xspi_qspi_prefetch_function +{ + XSPI_QSPI_PREFETCH_FUNCTION_DISABLE = 0x00, ///< Prefetch function disable + XSPI_QSPI_PREFETCH_FUNCTION_ENABLE = 0x01, ///< Prefetch function enable +} xspi_qspi_prefetch_function_t; + +/* IO voltage settings */ +typedef enum e_xspi_qspi_io_voltage +{ + XSPI_QSPI_IO_VOLTAGE_1_8V = 0x00, ///< IO voltage 1.8V + XSPI_QSPI_IO_VOLTAGE_3_3V = 0x01, ///< IO voltage 3.3V +} xspi_qspi_io_voltage_t; + +/* Address space settings */ +typedef struct st_qspi_address_space +{ + uint32_t unit0_cs0_end_address; ///< xSPI unit0 cs0 end address + uint32_t unit0_cs1_start_address; ///< xSPI unit0 cs1 start address + uint32_t unit0_cs1_end_address; ///< xSPI unit0 cs1 end address + uint32_t unit1_cs0_end_address; ///< xSPI unit1 cs0 end address + uint32_t unit1_cs1_start_address; ///< xSPI unit1 cs1 start address + uint32_t unit1_cs1_end_address; ///< xSPI unit1 cs1 end address +} xspi_qspi_address_space_t; + +/* OTFD AES Type. */ +typedef enum e_xspi_qspi_otfd_aes_key_type +{ + XSPI_QSPI_OTFD_AES_KEY_TYPE_128 = 0U, + XSPI_QSPI_OTFD_AES_KEY_TYPE_256 = 2U, +} xspi_qspi_otfd_aes_key_type_t; + +/* This structure is used to hold all the OTFD related configuration. */ +typedef struct st_xspi_qspi_otfd_cfg +{ + xspi_qspi_otfd_aes_key_type_t key_type; + uint32_t * p_start_addr; + uint32_t * p_end_addr; + uint32_t * p_key; + uint32_t * p_iv; +} xspi_qspi_otfd_cfg_t; + +/* Extended configuration. */ +typedef struct st_xspi_qspi_extended_cfg +{ + uint8_t unit; ///< Unit number of xSPI + xspi_qspi_chip_select_t chip_select; ///< Device number to be used for memory device + xspi_qspi_memory_size_t memory_size; ///< Size of memory device + xspi_qspi_timing_setting_t const * p_timing_settings; ///< Memory mapped timing settings + xspi_qspi_prefetch_function_t prefetch_en; ///< Prefetch function settings + xspi_qspi_io_voltage_t io_voltage; ///< Voltage setting of xSPI IO domain + xspi_qspi_address_space_t const * p_address_space; ///< Address space settings when custom address space enabled + +#if XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE + transfer_instance_t const * p_lower_lvl_transfer; ///< DMAC Transfer instance used for data transmission +#endif + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE + xspi_qspi_otfd_cfg_t const * p_otfd_cfg; ///< OTFD Configuration. Set to NULL if unused. +#endif +} xspi_qspi_extended_cfg_t; + +/** Instance control block. DO NOT INITIALIZE. Initialization occurs when @ref spi_flash_api_t::open is called */ +typedef struct st_xspi_qspi_instance_ctrl +{ + spi_flash_cfg_t const * p_cfg; // Pointer to initial configuration + spi_flash_data_lines_t data_lines; // Data lines + uint32_t total_size_bytes; // Total size of the flash in bytes + uint32_t open; // Whether or not driver is open + R_XSPI0_Type * p_reg; // Base register for this channel + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE + R_OTFD0_Type * p_otfd_reg; // Base OTFD register for this channel +#endif + + spi_flash_protocol_t spi_protocol; // Current SPI protocol selected +} xspi_qspi_instance_ctrl_t; + +/********************************************************************************************************************** + * Exported global variables + **********************************************************************************************************************/ + +/** @cond INC_HEADER_DEFS_SEC */ +/** Filled in Interface API structure for this Instance. */ +extern const spi_flash_api_t g_spi_flash_on_xspi_qspi; + +/** @endcond */ + +fsp_err_t R_XSPI_QSPI_Open(spi_flash_ctrl_t * p_ctrl, spi_flash_cfg_t const * const p_cfg); +fsp_err_t R_XSPI_QSPI_Close(spi_flash_ctrl_t * p_ctrl); +fsp_err_t R_XSPI_QSPI_DirectWrite(spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint32_t const bytes, + bool const read_after_write); +fsp_err_t R_XSPI_QSPI_DirectRead(spi_flash_ctrl_t * p_ctrl, uint8_t * const p_dest, uint32_t const bytes); +fsp_err_t R_XSPI_QSPI_SpiProtocolSet(spi_flash_ctrl_t * p_ctrl, spi_flash_protocol_t spi_protocol); +fsp_err_t R_XSPI_QSPI_XipEnter(spi_flash_ctrl_t * p_ctrl); +fsp_err_t R_XSPI_QSPI_XipExit(spi_flash_ctrl_t * p_ctrl); +fsp_err_t R_XSPI_QSPI_Write(spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count); +fsp_err_t R_XSPI_QSPI_Erase(spi_flash_ctrl_t * p_ctrl, uint8_t * const p_device_address, uint32_t byte_count); +fsp_err_t R_XSPI_QSPI_StatusGet(spi_flash_ctrl_t * p_ctrl, spi_flash_status_t * const p_status); +fsp_err_t R_XSPI_QSPI_BankSet(spi_flash_ctrl_t * p_ctrl, uint32_t bank); +fsp_err_t R_XSPI_QSPI_DirectTransfer(spi_flash_ctrl_t * p_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction); +fsp_err_t R_XSPI_QSPI_AutoCalibrate(spi_flash_ctrl_t * p_ctrl); + +/* Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */ +FSP_FOOTER + +#endif + +/*******************************************************************************************************************//** + * @} (end defgroup XSPI_QSPI) + **********************************************************************************************************************/ diff --git a/drivers/rz/fsp/src/rza/r_spibsc/r_spibsc.c b/drivers/rz/fsp/src/rza/r_spibsc/r_spibsc.c new file mode 100644 index 00000000..47473d3f --- /dev/null +++ b/drivers/rz/fsp/src/rza/r_spibsc/r_spibsc.c @@ -0,0 +1,2339 @@ +/* +* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ +#include +#include "bsp_api.h" +#include "r_spibsc.h" +#include "r_spibsc_private.h" + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ +#define SPIBSC_PRV_OPEN (0x53504942) +#ifndef SPIBSC_CFG_PARAM_CHECKING_ENABLE + #define SPIBSC_CFG_PARAM_CHECKING_ENABLE true +#endif +#ifndef SPIBSC_CFG_ALREADY_INITIALIZED + #define SPIBSC_CFG_ALREADY_INITIALIZED 1 +#endif +#ifndef SPIBSC_CFG_CODE_SECTION + #define SPIBSC_CFG_CODE_SECTION ".text.spibsc" +#endif +#ifndef SPIBSC_CFG_MMAP_BASE + #define SPIBSC_CFG_MMAP_BASE 0x20000000UL +#endif +#ifndef SPIBSC_CFG_WRITE_BUFFER_OFFSET + #define SPIBSC_CFG_WRITE_BUFFER_OFFSET 0x10000UL +#endif +#ifndef SPIBSC_CFG_STOP_ON_CLOSE + #define SPIBSC_CFG_STOP_ON_CLOSE 0 +#endif + +/* Driver settings */ +#define SPIBSC_PRV_RESET_DURATION_US (10) +#define SPIBSC_PRV_DEFAULT_VOLTAGE_IS_1800MV (1) + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ +typedef enum e_xspi_transfer_form +{ + SPI_FORM_1_1_1, /* Command executes at 1-1-1 form */ + SPI_FORM_1_1_2, /* Command executes at 1-1-2 form */ + SPI_FORM_1_2_2, /* Command executes at 1-2-2 form */ + SPI_FORM_2_2_2, /* Command executes at 2-2-2 form */ + SPI_FORM_1_1_4, /* Command executes at 1-1-4 form */ + SPI_FORM_1_4_4, /* Command executes at 1-4-4 form */ + SPI_FORM_4_4_4, /* Command executes at 4-4-4 form */ + SPI_FORM_1_1_8, /* Command executes at 1-1-8 form */ + SPI_FORM_1_8_8, /* Command executes at 1-8-8 form */ + SPI_FORM_8_8_8, /* Command executes at 8-8-8 form */ +} xspi_transfer_form_t; + +typedef struct st_xspi_op +{ + xspi_transfer_form_t form; ///< Transfer form + uint16_t op; ///< Operation code (for 2 byte op, highside used as 1st byte) + uint8_t op_size; ///< Operation code size (0 to 2) + uint32_t address; ///< Address (ignored for configuring in-place access) + uint8_t address_size; ///< Address size (0 to 4) + uint8_t additional_size; ///< Additional data size + uint32_t additional_value; ///< Additional data value + uint8_t dummy_cycles; ///< Dummy cycle count (as clocks) + size_t transfer_size; ///< Transfer size by bytes (ignored for configuring in-place access) + void * transfer_buffer; ///< Transfer buffer pointer (ignored for configuring in-place access) + uint8_t force_idle_level_mask; ///< Whether or not to force each IO level during the idle state + uint8_t force_idle_level_value; ///< IO level during the idle state + uint8_t slch_value; ///< Clock delay after select (SLCH) + uint8_t clsh_value; ///< De-select delay after clock stopped (CLSH) + uint8_t shsl_value; ///< Cycle delay between transaction (SHSL) +} xspi_op_t; + +typedef struct st_spibsc_mmap_cfg +{ + /* Search indexes */ + spi_flash_protocol_t spi_protocol; ///< The protocol + spi_flash_read_mode_t read_mode; ///< The read mode + spi_flash_address_bytes_t address_bytes; ///< The address bytes + + /* The parameters */ + xspi_transfer_form_t form; ///< Transfer form + uint8_t op; ///< Operation code + uint8_t address_size; ///< Address size (0 to 4) + uint8_t additional_size; ///< Additional data size + uint8_t dummy_cycles; ///< Dummy cycle count (as clocks) +} spibsc_mmap_cfg_t; + +/*********************************************************************************************************************** + * Private function prototypes + **********************************************************************************************************************/ +static fsp_err_t spibsc_configure_mmap_sub(spibsc_instance_ctrl_t * p_ctrl, + xspi_op_t const * const rop) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static void spibsc_start_mmap_internal(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static void spibsc_test_tend(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static fsp_err_t spibsc_exec_op(spibsc_instance_ctrl_t * p_ctrl, xspi_op_t const * const op, + bool is_write) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static int spibsc_stop_mmap_internal(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static fsp_err_t spibsc_configure_mmap(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static void spibsc_select_spim(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static fsp_err_t spibsc_write_enable(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static void spibsc_init_phy(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static void spibsc_ip_init(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static uint32_t spibsc_cmncr_set(uint8_t mask, uint8_t value, int pos) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static void spibsc_set_idlelevel(spibsc_instance_ctrl_t * p_ctrl, const xspi_op_t * const op) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static void test_sslf(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static void send_256(spibsc_instance_ctrl_t * p_ctrl, xspi_transfer_form_t form, uintptr_t buffer, + uint32_t smenr) BSP_PLACE_IN_SECTION(SPIBSC_CFG_CODE_SECTION); +static void send_4(spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static void send_2(spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static void send_1(spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static void receive(spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static void no_data(spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); +static bool spibsc_stop_mmap_temporarily(spibsc_instance_ctrl_t * p_ctrl) BSP_PLACE_IN_SECTION( + SPIBSC_CFG_CODE_SECTION); + +/*********************************************************************************************************************** + * Private global variables + **********************************************************************************************************************/ +static const spibsc_mmap_cfg_t g_mmap_cfg[] = +{ + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_STANDARD, // 1-1-1 (Max 50MHz or above, depends on flash device) + SPI_FLASH_ADDRESS_BYTES_3, // 3-byte address + + SPI_FORM_1_1_1, + 0x03, + 3, + 0, + 0 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_STANDARD, // 1-1-1 (Max 50MHz or above, depends on flash device) + SPI_FLASH_ADDRESS_BYTES_4, // 4-byte address (needs EN4B command or similar operation) + + SPI_FORM_1_1_1, + 0x03, + 4, + 0, + 0 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_STANDARD, // 1-1-1 (Max 50MHz or above, depends on flash device) + SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE, // 4-byte address + + SPI_FORM_1_1_1, + 0x13, + 4, + 0, + 0 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ, // 1-1-1 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_3, // 3-byte address + + SPI_FORM_1_1_1, + 0x0B, + 3, + 0, + 8 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ, // 1-1-1 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_4, // 4-byte address (needs EN4B command or similar operation) + + SPI_FORM_1_1_1, + 0x0B, + 4, + 0, + 8 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ, // 1-1-1 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE, // 4-byte address + + SPI_FORM_1_1_1, + 0x0C, + 4, + 0, + 8 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ_QUAD_OUTPUT, // x-1-4 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_3, // 3-byte address + + SPI_FORM_1_1_4, + 0x6B, + 3, + 0, + 8 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ_QUAD_OUTPUT, // x-1-4 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_4, // 4-byte address (needs EN4B command or similar operation) + + SPI_FORM_1_1_4, + 0x6B, + 4, + 0, + 8 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ_QUAD_OUTPUT, // x-1-4 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE, // 4-byte address + + SPI_FORM_1_1_4, + 0x6C, + 4, + 0, + 8 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ_QUAD_IO, // x-4-4 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_3, // 3-byte address + + SPI_FORM_1_4_4, + 0xEB, + 3, + 1, + 4 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ_QUAD_IO, // x-4-4 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_4, // 4-byte address (needs EN4B command or similar operation) + + SPI_FORM_1_4_4, + 0xEB, + 4, + 1, + 4 + }, + { + SPI_FLASH_PROTOCOL_EXTENDED_SPI, // 1-x-x + SPI_FLASH_READ_MODE_FAST_READ_QUAD_IO, // x-4-4 (Allows beyond 50MHz) + SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE, // 4-byte address + + SPI_FORM_1_4_4, + 0xEC, + 4, + 1, + 4 + }, +}; + +static const uint32_t cmncr_init_mask = + R_SPIBSC_CMNCR_BSZ_Msk | + R_SPIBSC_CMNCR_IO0FV_Msk | + R_SPIBSC_CMNCR_IO2FV_Msk | + R_SPIBSC_CMNCR_IO3FV_Msk | + R_SPIBSC_CMNCR_MOIIO0_Msk | + R_SPIBSC_CMNCR_MOIIO1_Msk | + R_SPIBSC_CMNCR_MOIIO2_Msk | + R_SPIBSC_CMNCR_MOIIO3_Msk; + +/* IOn maintained as Hi-Z at idle + * IO0 Value sets Hi-Z while dummy and 1-bit read transfer phase + * IO2/IO3 Value sets high while 1-bit command/address/additional-data phase + */ +static const uint32_t cmncr_init_value = + 1U << R_SPIBSC_CMNCR_MD_Pos | + SPIBSC_CMNCR_BSZ_SINGLE << R_SPIBSC_CMNCR_BSZ_Pos | + SPIBSC_CMNCR_IO_HIZ << R_SPIBSC_CMNCR_IO0FV_Pos | + SPIBSC_CMNCR_IO_HIGH << R_SPIBSC_CMNCR_IO2FV_Pos | + SPIBSC_CMNCR_IO_HIGH << R_SPIBSC_CMNCR_IO3FV_Pos | + SPIBSC_CMNCR_IO_HIZ << R_SPIBSC_CMNCR_MOIIO0_Pos | + SPIBSC_CMNCR_IO_HIZ << R_SPIBSC_CMNCR_MOIIO1_Pos | + SPIBSC_CMNCR_IO_HIZ << R_SPIBSC_CMNCR_MOIIO2_Pos | + SPIBSC_CMNCR_IO_HIZ << R_SPIBSC_CMNCR_MOIIO3_Pos; + +static const uint32_t ssldr_init_mask = + R_SPIBSC_SSLDR_SCKDL_Msk | + R_SPIBSC_SSLDR_SLNDL_Msk | + R_SPIBSC_SSLDR_SPNDL_Msk; + +static const uint32_t ssldr_init_value = + 0U << R_SPIBSC_SSLDR_SCKDL_Pos | + 0U << R_SPIBSC_SSLDR_SLNDL_Pos | + 0U << R_SPIBSC_SSLDR_SPNDL_Pos; + +static const uint32_t drcr_init_mask = + R_SPIBSC_DRCR_RBURST_Msk | + R_SPIBSC_DRCR_RCF_Msk | + R_SPIBSC_DRCR_RBE_Msk | + R_SPIBSC_DRCR_SSLE_Msk; + +static const uint32_t drcr_init_value = + 7U << R_SPIBSC_DRCR_RBURST_Pos | + 1U << R_SPIBSC_DRCR_RCF_Pos | + 1U << R_SPIBSC_DRCR_RBE_Pos | + 1U << R_SPIBSC_DRCR_SSLE_Pos; + +static const uint32_t drear_init_mask = + R_SPIBSC_DREAR_EAC_Msk | + R_SPIBSC_DREAR_EAV_Msk; + +static const uint32_t drear_init_value = + 3U << R_SPIBSC_DREAR_EAC_Pos | + 0U << R_SPIBSC_DREAR_EAV_Pos; + +static const uint32_t drdrenr_init_mask = + R_SPIBSC_DRDRENR_ADDRE_Msk | + R_SPIBSC_DRDRENR_OPDRE_Msk | + R_SPIBSC_DRDRENR_DRDRE_Msk; + +static const uint32_t drdrenr_init_value = + 0U << R_SPIBSC_DRDRENR_ADDRE_Pos | + 0U << R_SPIBSC_DRDRENR_OPDRE_Pos | + 0U << R_SPIBSC_DRDRENR_DRDRE_Pos; + +static const uint32_t phycnt_init_mask = + R_SPIBSC_PHYCNT_CAL_Msk | + R_SPIBSC_PHYCNT_CKSEL_Msk | + R_SPIBSC_PHYCNT_HS_Msk | + R_SPIBSC_PHYCNT_PHYMEM_Msk | + R_SPIBSC_PHYCNT_WBUF2_Msk | + R_SPIBSC_PHYCNT_WBUF_Msk; + +static const uint32_t phycnt_init_value = + 0U << R_SPIBSC_PHYCNT_CAL_Pos | + 0U << R_SPIBSC_PHYCNT_CKSEL_Pos | + 0U << R_SPIBSC_PHYCNT_HS_Pos | + 0U << R_SPIBSC_PHYCNT_PHYMEM_Pos | + 0U << R_SPIBSC_PHYCNT_WBUF2_Pos | + 0U << R_SPIBSC_PHYCNT_WBUF_Pos; + +static const uint32_t phyoffset1_init_mask = R_SPIBSC_PHYOFFSET1_DDRTMG_Msk; + +static const uint32_t phyoffset1_init_value = SPIBSC_PHYOFFSET1_SDR << R_SPIBSC_PHYOFFSET1_DDRTMG_Pos; + +static const uint32_t phyoffset2_init_mask = R_SPIBSC_PHYOFFSET2_OCTTMG_Msk; + +static const uint32_t phyoffset2_init_value = SPIBSC_PHYOFFSET2_SPI << R_SPIBSC_PHYOFFSET2_OCTTMG_Pos; + +static const uint32_t smcmr_clearmask = + R_SPIBSC_SMCMR_CMD_Msk | + R_SPIBSC_SMCMR_OCMD_Msk; + +static const uint32_t smenr_clearmask = + R_SPIBSC_SMENR_ADB_Msk | + R_SPIBSC_SMENR_ADE_Msk | + R_SPIBSC_SMENR_CDB_Msk | + R_SPIBSC_SMENR_CDE_Msk | + R_SPIBSC_SMENR_DME_Msk | + R_SPIBSC_SMENR_SPIDB_Msk | + R_SPIBSC_SMENR_OCDB_Msk | + R_SPIBSC_SMENR_OCDE_Msk | + R_SPIBSC_SMENR_OPDB_Msk | + R_SPIBSC_SMENR_OPDE_Msk | + R_SPIBSC_SMENR_SPIDE_Msk; + +static const uint32_t smdrenr_clearmask = + R_SPIBSC_SMDRENR_ADDRE_Msk | + R_SPIBSC_SMDRENR_SPIDRE_Msk | + R_SPIBSC_SMDRENR_OPDRE_Msk; + +static const uint32_t smdmcr_clearmask = + R_SPIBSC_SMDMCR_DMCYC_Msk; + +static const uint32_t ssldr_clearmask = + R_SPIBSC_SSLDR_SCKDL_Msk | + R_SPIBSC_SSLDR_SLNDL_Msk | + R_SPIBSC_SSLDR_SPNDL_Msk; + +/* SMENR value for 1-1-1 command */ +static const uint32_t smenr_form_111 = + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_CDB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_OCDB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_ADB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_OPDB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_SPIDB_Pos; + +/* SMENR value for 1-1-4 command */ +static const uint32_t smenr_form_114 = + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_CDB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_OCDB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_ADB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_OPDB_Pos | + SPIBSC_SMENR_DB_4BIT << R_SPIBSC_SMENR_SPIDB_Pos; + +/* SMENR value for 1-4-4 command */ +static const uint32_t smenr_form_144 = + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_CDB_Pos | + SPIBSC_SMENR_DB_1BIT << R_SPIBSC_SMENR_OCDB_Pos | + SPIBSC_SMENR_DB_4BIT << R_SPIBSC_SMENR_ADB_Pos | + SPIBSC_SMENR_DB_4BIT << R_SPIBSC_SMENR_OPDB_Pos | + SPIBSC_SMENR_DB_4BIT << R_SPIBSC_SMENR_SPIDB_Pos; + +/* SMENR value for no opcode */ +static const uint32_t smenr_op_none = + 0U << R_SPIBSC_SMENR_CDE_Pos | + 0U << R_SPIBSC_SMENR_OCDE_Pos; + +/* SMENR value for 1-byte opcode */ +static const uint32_t smenr_op_1byte = + 1U << R_SPIBSC_SMENR_CDE_Pos | + 0U << R_SPIBSC_SMENR_OCDE_Pos; + +/* SMENR value for 2-byte opcode */ +static const uint32_t smenr_op_2byte = + 1U << R_SPIBSC_SMENR_CDE_Pos | + 1U << R_SPIBSC_SMENR_OCDE_Pos; + +/* SMENR value for no address */ +static const uint32_t smenr_addr_none = + SPIBSC_SMENR_ADE_NONE << R_SPIBSC_SMENR_ADE_Pos; + +/* SMENR value for 3-byte address */ +static const uint32_t smenr_addr_3byte = + SPIBSC_SMENR_ADE_3BYTE << R_SPIBSC_SMENR_ADE_Pos; + +/* SMENR value for 4-byte address */ +static const uint32_t smenr_addr_4byte = + SPIBSC_SMENR_ADE_4BYTE << R_SPIBSC_SMENR_ADE_Pos; + +/* SMENR value for no additional data */ +static const uint32_t smenr_additional_none = + SPIBSC_SMENR_OPDE_NONE << R_SPIBSC_SMENR_OPDE_Pos; + +/* SMENR value for 1-byte additional data */ +static const uint32_t smenr_additional_1byte = + SPIBSC_SMENR_OPDE_1BYTE << R_SPIBSC_SMENR_OPDE_Pos; + +/* SMENR value for 2-byte additional data */ +static const uint32_t smenr_additional_2byte = + SPIBSC_SMENR_OPDE_2BYTE << R_SPIBSC_SMENR_OPDE_Pos; + +/* SMENR value for 3-byte additional data */ +static const uint32_t smenr_additional_3byte = + SPIBSC_SMENR_OPDE_3BYTE << R_SPIBSC_SMENR_OPDE_Pos; + +/* SMENR value for 4-byte additional data */ +static const uint32_t smenr_additional_4byte = + SPIBSC_SMENR_OPDE_4BYTE << R_SPIBSC_SMENR_OPDE_Pos; + +static const uint32_t drcmr_clearmask = + R_SPIBSC_DRCMR_CMD_Msk | + R_SPIBSC_DRCMR_OCMD_Msk; + +static const uint32_t drenr_clearmask = + R_SPIBSC_DRENR_ADB_Msk | + R_SPIBSC_DRENR_ADE_Msk | + R_SPIBSC_DRENR_CDB_Msk | + R_SPIBSC_DRENR_CDE_Msk | + R_SPIBSC_DRENR_DME_Msk | + R_SPIBSC_DRENR_DRDB_Msk | + R_SPIBSC_DRENR_OCDB_Msk | + R_SPIBSC_DRENR_OCDE_Msk | + R_SPIBSC_DRENR_OPDB_Msk | + R_SPIBSC_DRENR_OPDE_Msk; + +static const uint32_t drdrenr_clearmask = + R_SPIBSC_DRDRENR_ADDRE_Msk | + R_SPIBSC_DRDRENR_DRDRE_Msk | + R_SPIBSC_DRDRENR_OPDRE_Msk; + +static const uint32_t drdmcr_clearmask = + R_SPIBSC_DRDMCR_DMCYC_Msk; + +/* DRENR value for 1-1-1 command */ +static const uint32_t drenr_form_111 = + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_CDB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OCDB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_ADB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OPDB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_DRDB_Pos; + +/* DRENR value for 1-1-4 command */ +static const uint32_t drenr_form_114 = + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_CDB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OCDB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_ADB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OPDB_Pos | + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_DRDB_Pos; + +/* DRENR value for 1-4-4 command */ +static const uint32_t drenr_form_144 = + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_CDB_Pos | + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OCDB_Pos | + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_ADB_Pos | + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_OPDB_Pos | + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_DRDB_Pos; + +/* DRENR value for no opcode */ +static const uint32_t drenr_op_none = + 0U << R_SPIBSC_DRENR_CDE_Pos | + 0U << R_SPIBSC_DRENR_OCDE_Pos; + +/* DRENR value for 1-byte opcode */ +static const uint32_t drenr_op_1byte = + 1U << R_SPIBSC_DRENR_CDE_Pos | + 0U << R_SPIBSC_DRENR_OCDE_Pos; + +/* DRENR value for 2-byte opcode */ +static const uint32_t drenr_op_2byte = + 1U << R_SPIBSC_DRENR_CDE_Pos | + 1U << R_SPIBSC_DRENR_OCDE_Pos; + +/* DRENR value for no address */ +static const uint32_t drenr_addr_none = + SPIBSC_DRENR_ADE_NONE << R_SPIBSC_DRENR_ADE_Pos; + +/* DRENR value for 3-byte address */ +static const uint32_t drenr_addr_3byte = + SPIBSC_DRENR_ADE_3BYTE << R_SPIBSC_DRENR_ADE_Pos; + +/* DRENR value for 4-byte address */ +static const uint32_t drenr_addr_4byte = + SPIBSC_DRENR_ADE_4BYTE << R_SPIBSC_DRENR_ADE_Pos; + +/* DRENR value for no additional data */ +static const uint32_t drenr_additional_none = + SPIBSC_DRENR_OPDE_NONE << R_SPIBSC_DRENR_OPDE_Pos; + +/* DRENR value for 1-byte additional data */ +static const uint32_t drenr_additional_1byte = + SPIBSC_DRENR_OPDE_1BYTE << R_SPIBSC_DRENR_OPDE_Pos; + +/* DRENR value for 2-byte additional data */ +static const uint32_t drenr_additional_2byte = + SPIBSC_DRENR_OPDE_2BYTE << R_SPIBSC_DRENR_OPDE_Pos; + +/* DRENR value for 3-byte additional data */ +static const uint32_t drenr_additional_3byte = + SPIBSC_DRENR_OPDE_3BYTE << R_SPIBSC_DRENR_OPDE_Pos; + +/* DRENR value for 4-byte additional data */ +static const uint32_t drenr_additional_4byte = + SPIBSC_DRENR_OPDE_4BYTE << R_SPIBSC_DRENR_OPDE_Pos; + +/*******************************************************************************************************************//** + * @addtogroup SPIBSC + * @{ + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Global Variables + **********************************************************************************************************************/ + +const spi_flash_api_t g_spi_flash_on_spibsc = +{ + .open = R_SPIBSC_Open, + .directWrite = R_SPIBSC_DirectWrite, + .directRead = R_SPIBSC_DirectRead, + .directTransfer = R_SPIBSC_DirectTransfer, + .spiProtocolSet = R_SPIBSC_SpiProtocolSet, + .write = R_SPIBSC_Write, + .erase = R_SPIBSC_Erase, + .statusGet = R_SPIBSC_StatusGet, + .xipEnter = R_SPIBSC_XipEnter, + .xipExit = R_SPIBSC_XipExit, + .bankSet = R_SPIBSC_BankSet, + .autoCalibrate = R_SPIBSC_AutoCalibrate, + .close = R_SPIBSC_Close, +}; + +/*********************************************************************************************************************** + * Functions + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Open the SPIBSC driver module. + * + * Implements @ref spi_flash_api_t::open. + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_ASSERTION The parameter p_api_ctrl or p_cfg is NULL. + * @retval FSP_ERR_UNSUPPORTED One or more parameters in p_cfg are not supported by this implementation. + * @retval FSP_ERR_OUT_OF_MEMORY Memory allocation error. + * @retval FSP_ERR_INVALID_SIZE Page size is not specified. + * @retval FSP_ERR_INVALID_POINTER Pointer points to invalid memory location. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_ALREADY_OPEN Driver has already been opened with the same p_api_ctrl. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_Open (spi_flash_ctrl_t * p_api_ctrl, spi_flash_cfg_t const * const p_cfg) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + spibsc_instance_ctrl_t ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_api_ctrl); + FSP_ASSERT(NULL != p_cfg); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN != p_ctrl->open, FSP_ERR_ALREADY_OPEN); + + /* Check configuration parameters */ + FSP_ERROR_RETURN( + SPI_FLASH_DATA_LINES_1 == p_cfg->page_program_address_lines || SPI_FLASH_DATA_LINES_4 == p_cfg->page_program_address_lines, + FSP_ERR_UNSUPPORTED); + FSP_ERROR_RETURN((!p_cfg->page_program_command) || p_cfg->page_size_bytes, FSP_ERR_INVALID_SIZE) + FSP_ERROR_RETURN((!p_cfg->erase_command_list_length) || p_cfg->p_erase_command_list, FSP_ERR_INVALID_POINTER) +#endif + + /* Duplicate erase command table */ + void * p_erase_list = NULL; + size_t erase_list_bytes = sizeof(spi_flash_erase_command_t) * p_cfg->erase_command_list_length; + if (erase_list_bytes) + { + p_erase_list = malloc(erase_list_bytes); + FSP_ERROR_RETURN(p_erase_list, FSP_ERR_OUT_OF_MEMORY); + memcpy(p_erase_list, p_cfg->p_erase_command_list, erase_list_bytes); + } + + fsp_err_t result = FSP_SUCCESS; + + /* Initialize instance control datas */ + ctrl = *p_ctrl; + ctrl.cfg = *p_cfg; + ctrl.ext = *(spibsc_extended_cfg_t *) p_cfg->p_extend; + ctrl.p_erase_command_list = (spi_flash_erase_command_t *) p_erase_list; + ctrl.open = SPIBSC_PRV_OPEN; + ctrl.is_xip_enabled = false; + ctrl.p_reg = R_SPIBSC; + + if (!SPIBSC_CFG_ALREADY_INITIALIZED) + { + /* Initializes the SPIBSC for enabling memory-mapped (external address reading) access mode */ + result = spibsc_configure_mmap(&ctrl); + } + else + { + /* Obtaining the XIP (Suppressing the operation code phase) status from SPIBSC register */ + uint32_t drenr = MMIO_READ_32(p_ctrl->p_reg->DRENR); + drenr &= + (R_SPIBSC_DRENR_ADB_Msk | R_SPIBSC_DRENR_OPDB_Msk | R_SPIBSC_DRENR_DRDB_Msk | R_SPIBSC_DRENR_DME_Msk | + R_SPIBSC_DRENR_CDE_Msk | R_SPIBSC_DRENR_OPDE_Msk); + static const uint32_t drenr_expected = SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_ADB_Pos | SPIBSC_DRENR_DB_4BIT << + R_SPIBSC_DRENR_OPDB_Pos | SPIBSC_DRENR_DB_4BIT << + R_SPIBSC_DRENR_DRDB_Pos | R_SPIBSC_DRENR_DME_Msk | + SPIBSC_DRENR_OPDE_1BYTE << R_SPIBSC_DRENR_OPDE_Pos; + if (drenr == drenr_expected) + { + ctrl.is_xip_enabled = true; + } + } + + if (result != FSP_SUCCESS) + { + /* Cleanup allocated memory */ + if (ctrl.p_erase_command_list) + { + free(ctrl.p_erase_command_list); + } + } + + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + /* Overwrite new instance ctrl object */ + *p_ctrl = ctrl; + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * DEPRECATED: Writes raw data directly to the flash device. + * + * Implements @ref spi_flash_api_t::directWrite. + * + * @note After sending operations that change its contents, it may be inconsistent with cached contents. + * @warning Its behavior is not guaranteed if the caller and/or the callee are stored in the same device + * you are trying to change its contents. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_UNSUPPORTED Read-after-write is not supported by this implementation. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_DirectWrite (spi_flash_ctrl_t * p_api_ctrl, + uint8_t const * const p_src, + uint32_t const bytes, + bool const read_after_write) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(p_ctrl); + FSP_ASSERT(NULL != p_src); + FSP_ASSERT(bytes > 0); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + FSP_ERROR_RETURN(read_after_write == false, FSP_ERR_UNSUPPORTED); + FSP_ERROR_RETURN(p_ctrl->is_xip_enabled == false, FSP_ERR_INVALID_MODE); + + xspi_op_t op; + op.clsh_value = p_ctrl->ext.delay.clsh; + op.shsl_value = p_ctrl->ext.delay.shsl; + op.slch_value = p_ctrl->ext.delay.slch; + op.force_idle_level_mask = p_ctrl->ext.io_fix_mask; + op.force_idle_level_value = p_ctrl->ext.io_fix_value; + op.transfer_buffer = (void *) p_src; + op.transfer_size = bytes; + op.additional_size = 0; + op.additional_value = 0; + op.address = 0; + op.address_size = 0; + op.dummy_cycles = 0; + switch (p_ctrl->cfg.spi_protocol) + { + case SPI_FLASH_PROTOCOL_EXTENDED_SPI: + { + op.form = SPI_FORM_1_1_1; + break; + } + + default: + { + FSP_ERROR_RETURN(p_ctrl->cfg.spi_protocol == SPI_FLASH_PROTOCOL_EXTENDED_SPI, FSP_ERR_UNSUPPORTED); + break; + } + } + + fsp_err_t result = spibsc_exec_op(p_ctrl, &op, true); + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Reads raw data directly from the flash device. Unsupported by SPIBSC. + * + * Implements @ref spi_flash_api_t::directRead. + * + * @retval FSP_ERR_UNSUPPORTED API not supported by SPIBSC. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_DirectRead (spi_flash_ctrl_t * p_api_ctrl, uint8_t * const p_dest, uint32_t const bytes) +{ + FSP_PARAMETER_NOT_USED(p_api_ctrl); + FSP_PARAMETER_NOT_USED(p_dest); + FSP_PARAMETER_NOT_USED(bytes); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Read/Write raw data directly with the flash device. + * + * Implements @ref spi_flash_api_t::directTransfer. + * + * @note After sending operations that change its contents, it may be inconsistent with cached contents. + * @warning Its behavior is not guaranteed if the caller and/or the callee are stored in the same device + * you are trying to change its contents. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_DirectTransfer (spi_flash_ctrl_t * p_api_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(p_ctrl); + FSP_ASSERT(p_transfer); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + FSP_ERROR_RETURN(p_ctrl->is_xip_enabled == false, FSP_ERR_INVALID_MODE); + + xspi_op_t op; + memset(&op, 0, sizeof(op)); + op.clsh_value = p_ctrl->ext.delay.clsh; + op.shsl_value = p_ctrl->ext.delay.shsl; + op.slch_value = p_ctrl->ext.delay.slch; + op.force_idle_level_mask = p_ctrl->ext.io_fix_mask; + op.force_idle_level_value = p_ctrl->ext.io_fix_value; + op.op = p_transfer->command; + op.op_size = p_transfer->command_length; + op.address = p_transfer->address; + op.address_size = p_transfer->address_length; + op.dummy_cycles = p_transfer->dummy_cycles; + op.transfer_buffer = &p_transfer->data; + op.transfer_size = p_transfer->data_length; + op.form = SPI_FORM_1_1_1; + bool is_write = (SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE == direction); + fsp_err_t result = spibsc_exec_op(p_ctrl, &op, is_write); + + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Enters XIP (execute in place) mode. + * + * Implements @ref spi_flash_api_t::xipEnter. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_INVALID_MODE This function can't be called when already enabled or not 4-bit transfer. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_XipEnter (spi_flash_ctrl_t * p_api_ctrl) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(p_ctrl); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + FSP_ERROR_RETURN(!p_ctrl->is_xip_enabled, FSP_ERR_INVALID_MODE); + + uint32_t drenr = MMIO_READ_32(p_ctrl->p_reg->DRENR) & (uint32_t) ~R_SPIBSC_SMENR_SPIDE_Msk; + + /*** Check if ready or not ***/ + /* Address phase must 4-bit */ + FSP_ERROR_RETURN(((drenr & R_SPIBSC_DRENR_ADB_Msk) >> R_SPIBSC_DRENR_ADB_Pos) == SPIBSC_DRENR_DB_4BIT, + FSP_ERR_INVALID_MODE); + + /* Stop memory-mapped read mode */ + spibsc_stop_mmap_internal(p_ctrl); + + /* Optional data */ + uint32_t opr = (uint32_t) p_ctrl->cfg.xip_enter_command << R_SPIBSC_SMOPR_OPD3_Pos; + MMIO_WRITE_32(p_ctrl->p_reg->DROPR, opr); + MMIO_WRITE_32(p_ctrl->p_reg->SMOPR, opr); + + /* Clone settings */ + MMIO_WRITE_32(p_ctrl->p_reg->SMCMR, MMIO_READ_32(p_ctrl->p_reg->DRCMR)); + MMIO_WRITE_32(p_ctrl->p_reg->SMENR, drenr | SPIBSC_SMENR_SPIDE_LONG << R_SPIBSC_SMENR_SPIDE_Pos); + MMIO_WRITE_32(p_ctrl->p_reg->SMDMCR, MMIO_READ_32(p_ctrl->p_reg->DRDMCR)); + MMIO_WRITE_32(p_ctrl->p_reg->SMDRENR, MMIO_READ_32(p_ctrl->p_reg->DRDRENR)); + + /* Execute command for start flash's XIP mode (suppressing op-code) */ + MMIO_WRITE_32(p_ctrl->p_reg->SMCR, R_SPIBSC_SMCR_SPIRE_Msk | R_SPIBSC_SMCR_SPIE_Msk); + + /* Wait complete (Read data will ignored) */ + spibsc_test_tend(p_ctrl); + + /* Set suppressing the op-code for memory-mapped read */ + drenr &= (uint32_t) ~R_SPIBSC_DRENR_CDE_Msk; + MMIO_WRITE_32(p_ctrl->p_reg->DRENR, drenr); + + /* Change xip state */ + p_ctrl->is_xip_enabled = true; + + /* Enabling memory-mapped read mode */ + spibsc_start_mmap_internal(p_ctrl); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Exits XIP (execute in place) mode. + * + * Implements @ref spi_flash_api_t::xipExit. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_XipExit (spi_flash_ctrl_t * p_api_ctrl) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(p_ctrl); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + FSP_ERROR_RETURN(p_ctrl->is_xip_enabled, FSP_ERR_INVALID_MODE); + + /* Stop memory-mapped read mode */ + spibsc_stop_mmap_internal(p_ctrl); + + /* Optional data */ + uint32_t opr = (uint32_t) p_ctrl->cfg.xip_exit_command << R_SPIBSC_SMOPR_OPD3_Pos; + MMIO_WRITE_32(p_ctrl->p_reg->DROPR, opr); + MMIO_WRITE_32(p_ctrl->p_reg->SMOPR, opr); + + /* Clone settings */ + uint32_t drenr = MMIO_READ_32(p_ctrl->p_reg->DRENR); + MMIO_WRITE_32(p_ctrl->p_reg->SMCMR, MMIO_READ_32(p_ctrl->p_reg->DRCMR)); + MMIO_WRITE_32(p_ctrl->p_reg->SMENR, drenr); + MMIO_WRITE_32(p_ctrl->p_reg->SMDMCR, MMIO_READ_32(p_ctrl->p_reg->DRDMCR)); + MMIO_WRITE_32(p_ctrl->p_reg->SMDRENR, MMIO_READ_32(p_ctrl->p_reg->DRDRENR)); + + /* Execute command for stop flash's XIP mode (enabling op-code) */ + MMIO_WRITE_32(p_ctrl->p_reg->SMCR, R_SPIBSC_SMCR_SPIRE_Msk | R_SPIBSC_SMCR_SPIE_Msk); + + /* Wait complete (Read data will ignored) */ + spibsc_test_tend(p_ctrl); + + /* Set enabling op-code for memory-mapped read */ + drenr |= R_SPIBSC_DRENR_CDE_Msk; + MMIO_WRITE_32(p_ctrl->p_reg->DRENR, drenr); + + /* Enabling memory-mapped read mode */ + spibsc_start_mmap_internal(p_ctrl); + + /* Change xip state */ + p_ctrl->is_xip_enabled = false; + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Program a page of data to the flash. + * + * Implements @ref spi_flash_api_t::write. + * + * @note After writing, it may be inconsistent with cached contents. + * @warning Its behavior is not guaranteed if the caller and/or the callee are stored in the same device + * you are writing. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION p_api_ctrl, p_dest or p_src is NULL, or byte_count crosses a page boundary. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_Write (spi_flash_ctrl_t * p_api_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(p_ctrl); + FSP_ASSERT(p_src); + FSP_ASSERT(p_dest); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + FSP_ERROR_RETURN(p_ctrl->is_xip_enabled == false, FSP_ERR_INVALID_MODE); + + /* Enable write */ + fsp_err_t result = spibsc_write_enable(p_ctrl); + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + uint32_t chip_address = (uint32_t) ((ptrdiff_t) p_dest - (ptrdiff_t) SPIBSC_CFG_MMAP_BASE); + + /* Make operation structure */ + xspi_op_t op; + memset(&op, 0, sizeof(op)); + op.clsh_value = p_ctrl->ext.delay.clsh; + op.shsl_value = p_ctrl->ext.delay.shsl; + op.slch_value = p_ctrl->ext.delay.slch; + op.force_idle_level_mask = p_ctrl->ext.io_fix_mask; + op.force_idle_level_value = p_ctrl->ext.io_fix_value; + op.op = p_ctrl->cfg.page_program_command; + op.op_size = 1; + op.address = chip_address; + switch (p_ctrl->cfg.address_bytes) + { + case SPI_FLASH_ADDRESS_BYTES_4: // As 4-byte, fall through + case SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE: // Also as 4-byte + { + op.address_size = 4; + break; + } + + case SPI_FLASH_ADDRESS_BYTES_3: // As 4-byte, fall through + { + op.address_size = 3; + break; + } + + default: // Invalid + FSP_ERROR_RETURN(false, FSP_ERR_INVALID_MODE); + } + + op.transfer_buffer = (void *) p_src; + op.transfer_size = byte_count; + switch (p_ctrl->cfg.page_program_address_lines) + { + case SPI_FLASH_DATA_LINES_1: // As 1-bit. The transfer phase is same as "Read Mode" setting. + { + switch (p_ctrl->cfg.read_mode) + { + case SPI_FLASH_READ_MODE_FAST_READ_QUAD_OUTPUT: // 4-bit transfer, fall through + case SPI_FLASH_READ_MODE_FAST_READ_QUAD_IO: // 4-bit transfer, fall through + { + op.form = SPI_FORM_1_1_4; + break; + } + + default: // 1-bit for others. (2-bit is blocked on open API) + { + op.form = SPI_FORM_1_1_1; + break; + } + } + + break; + } + + case SPI_FLASH_DATA_LINES_4: // As 4-bit. The transfer phase also becomes 4-bit + { + op.form = SPI_FORM_1_4_4; + break; + } + + default: // Invalid + FSP_ERROR_RETURN(false, FSP_ERR_INVALID_MODE); + } + + /* Execute operation */ + bool is_write = true; + result = spibsc_exec_op(p_ctrl, &op, is_write); + + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Erase a block or sector of flash. The byte_count must exactly match one of the erase sizes defined in spi_flash_cfg_t. + * For chip erase, byte_count must be SPI_FLASH_ERASE_SIZE_CHIP_ERASE. + * + * Implements @ref spi_flash_api_t::erase. + * + * @note After erasing, it may be inconsistent with cached contents. + * @warning Its behavior is not guaranteed if the caller and/or the callee are stored in the same device + * you are erasing. + * + * @retval FSP_SUCCESS The command to erase the flash was executed successfully. + * @retval FSP_ERR_ASSERTION p_api_ctrl or p_device_address is NULL, or byte_count doesn't match an erase + * size defined in spi_flash_cfg_t, or device is in XIP mode. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_Erase (spi_flash_ctrl_t * p_api_ctrl, uint8_t * const p_device_address, uint32_t byte_count) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(p_ctrl); + FSP_ASSERT(NULL != p_device_address); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + FSP_ERROR_RETURN(p_ctrl->is_xip_enabled == false, FSP_ERR_INVALID_MODE); + + /* Enable write */ + fsp_err_t result = spibsc_write_enable(p_ctrl); + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + uint16_t erase_command = 0; + uint32_t chip_address = (uint32_t) ((ptrdiff_t) p_device_address - (ptrdiff_t) SPIBSC_CFG_MMAP_BASE); + bool send_address = true; + + for (uint32_t index = 0; index < p_ctrl->cfg.erase_command_list_length; index++) + { + /* If requested byte_count is supported by underlying flash, store the command. */ + if (byte_count == p_ctrl->cfg.p_erase_command_list[index].size) + { + if (SPI_FLASH_ERASE_SIZE_CHIP_ERASE == byte_count) + { + /* Don't send address for chip erase. */ + send_address = false; + } + + erase_command = p_ctrl->cfg.p_erase_command_list[index].command; + break; + } + } + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(0U != erase_command); +#endif + + /* Make operation structure */ + xspi_op_t op; + memset(&op, 0, sizeof(op)); + op.clsh_value = p_ctrl->ext.delay.clsh; + op.shsl_value = p_ctrl->ext.delay.shsl; + op.slch_value = p_ctrl->ext.delay.slch; + op.force_idle_level_mask = p_ctrl->ext.io_fix_mask; + op.force_idle_level_value = p_ctrl->ext.io_fix_value; + op.op = erase_command; + op.op_size = 1; + op.address = chip_address; + if (send_address) + { + switch (p_ctrl->cfg.address_bytes) + { + case SPI_FLASH_ADDRESS_BYTES_4: // As 4-byte, fall through + case SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE: // Also as 4-byte + { + op.address_size = 4; + break; + } + + case SPI_FLASH_ADDRESS_BYTES_3: // As 4-byte, fall through + { + op.address_size = 3; + break; + } + + default: // Invalid + FSP_ERROR_RETURN(false, FSP_ERR_INVALID_MODE); + } + } + + op.form = SPI_FORM_1_1_1; + + /* Execute operation */ + bool is_write = false; + result = spibsc_exec_op(p_ctrl, &op, is_write); + + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Gets the write or erase status of the flash. + * + * Implements @ref spi_flash_api_t::statusGet. + * + * @retval FSP_SUCCESS The write status is in p_status. + * @retval FSP_ERR_ASSERTION p_api_ctrl or p_status is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_StatusGet (spi_flash_ctrl_t * p_api_ctrl, spi_flash_status_t * const p_status) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + uint8_t status; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_ctrl); + FSP_ASSERT(NULL != p_status); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + FSP_ERROR_RETURN(p_ctrl->is_xip_enabled == false, FSP_ERR_INVALID_MODE); + + /* Make operation structure */ + xspi_op_t op; + memset(&op, 0, sizeof(op)); + op.clsh_value = p_ctrl->ext.delay.clsh; + op.shsl_value = p_ctrl->ext.delay.shsl; + op.slch_value = p_ctrl->ext.delay.slch; + op.force_idle_level_mask = p_ctrl->ext.io_fix_mask; + op.force_idle_level_value = p_ctrl->ext.io_fix_value; + op.op = p_ctrl->cfg.status_command; + op.op_size = 1; + op.form = SPI_FORM_1_1_1; + op.transfer_buffer = &status; + op.transfer_size = 1; + + bool is_write = false; + fsp_err_t result = spibsc_exec_op(p_ctrl, &op, is_write); + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + /* Check the status and store it */ + uint8_t target = 1U << p_ctrl->cfg.write_status_bit; + if (status & target) + { + p_status->write_in_progress = true; + } + else + { + p_status->write_in_progress = false; + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Selects the bank to access. A bank is a 256Mega-byte access window into the SPI Multi area. To access + * device address 0x10000000, select bank 1, then read from address 0x20000000(physical). To access device address + * 0x20001000, select bank 2, then read from address 0x20001000(physical). + * + * This function is not required for memory devices less than or equal to 256Mega-byte. + * + * Implements @ref spi_flash_api_t::bankSet. + * + * @note After different bank selections, it becomes inconsistent with cache. + * @warning Its behavior is not guaranteed if the caller and/or the callee are stored in the same device + * you are trying to select banks. After changing the bank, the contents (code, data, or more) of the + * previously selected bank will become inaccessible. + * + * @retval FSP_SUCCESS Bank successfully selected. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_INVALID_ARGUMENT "bank" is invalid. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_BankSet (spi_flash_ctrl_t * p_api_ctrl, uint32_t bank) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_ctrl); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + /* Limit the parameter */ + FSP_ERROR_RETURN(16 > bank, FSP_ERR_INVALID_ARGUMENT); + + /* Set DREAR.EAV field */ + uint32_t drear = (bank << 3) << R_SPIBSC_DREAR_EAV_Pos; + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DREAR, R_SPIBSC_DREAR_EAV_Msk, drear); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Sets the SPI protocol. + * + * Implements @ref spi_flash_api_t::spiProtocolSet. + * + * @retval FSP_ERR_UNSUPPORTED API not supported by SPIBSC + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_SpiProtocolSet (spi_flash_ctrl_t * p_api_ctrl, spi_flash_protocol_t spi_protocol) +{ + FSP_PARAMETER_NOT_USED(p_api_ctrl); + FSP_PARAMETER_NOT_USED(spi_protocol); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Auto-calibrate the OctaRAM device using the preamble pattern. Unsupported by SPIBSC. + * + * Implements @ref spi_flash_api_t::autoCalibrate. + * + * @retval FSP_ERR_UNSUPPORTED API not supported by SPIBSC + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_AutoCalibrate (spi_flash_ctrl_t * p_api_ctrl) +{ + FSP_PARAMETER_NOT_USED(p_api_ctrl); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Close the SPIBSC driver module. + * + * Implements @ref spi_flash_api_t::close. + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_ASSERTION p_api_ctrl is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_SPIBSC_Close (spi_flash_ctrl_t * p_api_ctrl) +{ + spibsc_instance_ctrl_t * p_ctrl = (spibsc_instance_ctrl_t *) p_api_ctrl; + +#if SPIBSC_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_ctrl); + FSP_ERROR_RETURN(SPIBSC_PRV_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + if (SPIBSC_CFG_STOP_ON_CLOSE) + { + /* Stop SPIM clock */ + R_BSP_MODULE_STOP(FSP_IP_SPI_MULTI, 0); + } + + p_ctrl->open = 0U; + + /* Cleanup allocated memory */ + if (p_ctrl->p_erase_command_list) + { + free(p_ctrl->p_erase_command_list); + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * @} (end addtogroup SPIBSC) + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Enabling write functionality of flash device (internally used). + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_INVALID_MODE One or more values in configuration are not met the condition of the controller mode. + **********************************************************************************************************************/ +static fsp_err_t spibsc_write_enable (spibsc_instance_ctrl_t * p_ctrl) +{ + /* Make operation structure */ + xspi_op_t op; + memset(&op, 0, sizeof(op)); + op.clsh_value = p_ctrl->ext.delay.clsh; + op.shsl_value = p_ctrl->ext.delay.shsl; + op.slch_value = p_ctrl->ext.delay.slch; + op.force_idle_level_mask = p_ctrl->ext.io_fix_mask; + op.force_idle_level_value = p_ctrl->ext.io_fix_value; + op.op = p_ctrl->cfg.write_enable_command; + op.op_size = 1; + op.form = SPI_FORM_1_1_1; + + /* Execute operation */ + bool is_write = false; + fsp_err_t result = spibsc_exec_op(p_ctrl, &op, is_write); + + FSP_ERROR_RETURN(result == FSP_SUCCESS, result); + + return FSP_SUCCESS; +} + +static void spibsc_select_spim (spibsc_instance_ctrl_t * p_ctrl) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); +#if (BSP_FEATURE_BSP_SUPPORT_OCTAL_MEMORY) + + /* Check if OCTA selected */ + uint32_t ipcont_spi_octa = R_SYSC->SYS_IPCONT_SEL_SPI_OCTA; + if ((ipcont_spi_octa & R_SYSC_SYS_IPCONT_SEL_SPI_OCTA_SEL_SPI_OCTA_Msk) == + R_SYSC_SYS_IPCONT_SEL_SPI_OCTA_SEL_SPI_OCTA_Msk) + { + /* Reset the OCTA controller and the devices connected, + * required to change the device mode from OPI to SPI. + * Otherwise, the octa devices can not communicate with the SPIM controller. + *//* Assert reset line */ + R_OCTA->RSTCNT_b.RSTVAL = 0; + + /* Stop OCTA */ + R_BSP_MODULE_STOP(FSP_IP_OCTA, 0); + } + + /* Wait for reset SPI device */ + R_BSP_SoftwareDelay(SPIBSC_PRV_RESET_DURATION_US, BSP_DELAY_UNITS_MICROSECONDS); +#endif + + /* force voltage setting + * Note: This is required if the boot mode is neither 3 nor 4. + */ + uint8_t voltage = SPIBSC_PRV_DEFAULT_VOLTAGE_IS_1800MV ? 1 : 0; + R_GPIO->QSPI = voltage; + R_GPIO->QSPI; + + /* Supply SPIM clock */ + R_BSP_MODULE_START(FSP_IP_SPI_MULTI, 0); +#if (BSP_FEATURE_BSP_SUPPORT_OCTAL_MEMORY) + + /* Select SPIM for SPI controller */ + ipcont_spi_octa &= (uint32_t) ~R_SYSC_SYS_IPCONT_SEL_SPI_OCTA_SEL_SPI_OCTA_Msk; + R_SYSC->SYS_IPCONT_SEL_SPI_OCTA = ipcont_spi_octa; + R_SYSC->SYS_IPCONT_SEL_SPI_OCTA; +#endif +} + +static void spibsc_test_tend (spibsc_instance_ctrl_t * p_ctrl) +{ + while (true) + { + if (p_ctrl->p_reg->CMNSR & R_SPIBSC_CMNSR_TEND_Msk) + { + break; + } + } +} + +static void spibsc_init_phy (spibsc_instance_ctrl_t * p_ctrl) +{ + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ2, 0xa5390000UL); + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ1, 0x80000000UL); + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ2, 0x00008080UL); + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ1, 0x80000022UL); + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ2, 0x00008080UL); + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ1, 0x80000024UL); + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ2, 0x00000030UL); + MMIO_WRITE_32(p_ctrl->p_reg->PHYADJ1, 0x80000032UL); +} + +static void spibsc_ip_init (spibsc_instance_ctrl_t * p_ctrl) +{ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->CMNCR, cmncr_init_mask, cmncr_init_value); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SSLDR, ssldr_init_mask, ssldr_init_value); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DRCR, drcr_init_mask, drcr_init_value); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DREAR, drear_init_mask, drear_init_value); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DRDRENR, drdrenr_init_mask, drdrenr_init_value); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYCNT, phycnt_init_mask, phycnt_init_value | R_SPIBSC_PHYCNT_CAL_Msk); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYOFFSET1, phyoffset1_init_mask, phyoffset1_init_value); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYOFFSET2, phyoffset2_init_mask, phyoffset2_init_value); + spibsc_init_phy(p_ctrl); +} + +/*******************************************************************************************************************//** + * Configuring memory-mapped access (internally used). + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_UNSUPPORTED One or more values in configuration are not supported. + * @retval FSP_ERR_INVALID_MODE One or more values in configuration are not met the condition of the controller mode. + **********************************************************************************************************************/ +static fsp_err_t spibsc_configure_mmap (spibsc_instance_ctrl_t * p_ctrl) +{ + /* Check parameters */ + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_EXTENDED_SPI == p_ctrl->cfg.spi_protocol, FSP_ERR_UNSUPPORTED); + FSP_ERROR_RETURN( + SPI_FLASH_READ_MODE_STANDARD == p_ctrl->cfg.read_mode || SPI_FLASH_READ_MODE_FAST_READ == p_ctrl->cfg.read_mode || SPI_FLASH_READ_MODE_FAST_READ_QUAD_OUTPUT == p_ctrl->cfg.read_mode || SPI_FLASH_READ_MODE_FAST_READ_QUAD_IO == p_ctrl->cfg.read_mode, + FSP_ERR_UNSUPPORTED); + FSP_ERROR_RETURN( + SPI_FLASH_ADDRESS_BYTES_3 == p_ctrl->cfg.address_bytes || SPI_FLASH_ADDRESS_BYTES_4 == p_ctrl->cfg.address_bytes || SPI_FLASH_ADDRESS_BYTES_4_4BYTE_READ_CODE == p_ctrl->cfg.address_bytes, + FSP_ERR_UNSUPPORTED); + + spibsc_select_spim(p_ctrl); + spibsc_ip_init(p_ctrl); + + /* Search mmap config table */ + int i; + int max_cfg_index = sizeof(g_mmap_cfg) / sizeof(g_mmap_cfg[0]); + const spibsc_mmap_cfg_t * p_mmap_cfg = NULL; + for (i = 0; i < max_cfg_index && p_mmap_cfg == NULL; i++) + { + if (p_ctrl->cfg.spi_protocol == g_mmap_cfg[i].spi_protocol) + { + if (p_ctrl->cfg.read_mode == g_mmap_cfg[i].read_mode) + { + if (p_ctrl->cfg.address_bytes == g_mmap_cfg[i].address_bytes) + { + p_mmap_cfg = &g_mmap_cfg[i]; + } + } + } + } + + FSP_ERROR_RETURN(p_mmap_cfg, FSP_ERR_UNSUPPORTED); + + /* Create configuration structure */ + xspi_op_t rop; + memset(&rop, 0, sizeof(rop)); + if (p_ctrl->cfg.read_command) + { + rop.op = p_ctrl->cfg.read_command; + } + else + { + rop.op = p_mmap_cfg->op; + } + + switch (p_ctrl->cfg.dummy_clocks) + { + case SPI_FLASH_DUMMY_CLOCKS_DEFAULT: + { + rop.dummy_cycles = p_mmap_cfg->dummy_cycles; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_3: + { + rop.dummy_cycles = 3 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_4: + { + rop.dummy_cycles = 4 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_5: + { + rop.dummy_cycles = 5 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_6: + { + rop.dummy_cycles = 6 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_7: + { + rop.dummy_cycles = 7 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_8: + { + rop.dummy_cycles = 8 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_9: + { + rop.dummy_cycles = 9 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_10: + { + rop.dummy_cycles = 10 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_11: + { + rop.dummy_cycles = 11 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_12: + { + rop.dummy_cycles = 12 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_13: + { + rop.dummy_cycles = 13 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_14: + { + rop.dummy_cycles = 14 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_15: + { + rop.dummy_cycles = 15 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_16: + { + rop.dummy_cycles = 16 - p_mmap_cfg->additional_size; + break; + } + + case SPI_FLASH_DUMMY_CLOCKS_17: + { + rop.dummy_cycles = 17 - p_mmap_cfg->additional_size; + break; + } + + default: + FSP_ERROR_RETURN(false && p_ctrl->cfg.dummy_clocks, FSP_ERR_UNSUPPORTED); + } + + rop.op_size = 1; + rop.additional_size = p_mmap_cfg->additional_size; + rop.address_size = p_mmap_cfg->address_size; + rop.force_idle_level_mask = p_ctrl->ext.io_fix_mask; + rop.force_idle_level_value = p_ctrl->ext.io_fix_value; + rop.form = p_mmap_cfg->form; + + return spibsc_configure_mmap_sub(p_ctrl, &rop); +} + +static uint32_t spibsc_cmncr_set (uint8_t mask, uint8_t value, int pos) +{ + int moiionpos = -1; + int ionfvpos = -1; + uint32_t cmncr_set = 0; + uint32_t moiio = 0; + uint32_t ionfv = 0; + + switch (pos) + { + case 1: + { + moiionpos = R_SPIBSC_CMNCR_MOIIO1_Pos; + break; + } + + case 2: + { + moiionpos = R_SPIBSC_CMNCR_MOIIO2_Pos; + ionfvpos = R_SPIBSC_CMNCR_IO2FV_Pos; + break; + } + + case 3: + { + moiionpos = R_SPIBSC_CMNCR_MOIIO3_Pos; + ionfvpos = R_SPIBSC_CMNCR_IO3FV_Pos; + break; + } + } + + if (mask & 1 << pos) + { + moiio = value & 1 << pos ? SPIBSC_CMNCR_IO_HIGH : SPIBSC_CMNCR_IO_LOW; + ionfv = SPIBSC_CMNCR_IO_KEEP; + } + else + { + moiio = SPIBSC_CMNCR_IO_HIZ; + ionfv = SPIBSC_CMNCR_IO_HIZ; + } + + if (moiionpos >= 0) + { + cmncr_set |= moiio << moiionpos; + } + + if (ionfvpos >= 0) + { + cmncr_set |= ionfv << ionfvpos; + } + + return cmncr_set; +} + +static void spibsc_set_idlelevel (spibsc_instance_ctrl_t * p_ctrl, const xspi_op_t * const op) +{ + static const uint32_t cmncr_mask = + R_SPIBSC_CMNCR_IO2FV_Msk | + R_SPIBSC_CMNCR_IO3FV_Msk | + R_SPIBSC_CMNCR_MOIIO1_Msk | + R_SPIBSC_CMNCR_MOIIO2_Msk | + R_SPIBSC_CMNCR_MOIIO3_Msk; + + uint32_t cmncr_set = 0; + + cmncr_set |= spibsc_cmncr_set(op->force_idle_level_mask, op->force_idle_level_value, 1); + cmncr_set |= spibsc_cmncr_set(op->force_idle_level_mask, op->force_idle_level_value, 2); + cmncr_set |= spibsc_cmncr_set(op->force_idle_level_mask, op->force_idle_level_value, 3); + + MMIO_CLRSETBITS_32(p_ctrl->p_reg->CMNCR, cmncr_mask, cmncr_set); +} + +static void spibsc_start_mmap_internal (spibsc_instance_ctrl_t * p_ctrl) +{ + MMIO_CLRBITS_32(p_ctrl->p_reg->CMNCR, R_SPIBSC_CMNCR_MD_Msk); + MMIO_READ_32(p_ctrl->p_reg->CMNCR); +} + +static void test_sslf (spibsc_instance_ctrl_t * p_ctrl) +{ + while (true) + { + if ((MMIO_READ_32(p_ctrl->p_reg->CMNSR) & R_SPIBSC_CMNSR_SSLF_Msk) == 0) + { + break; + } + } +} + +static int spibsc_stop_mmap_internal (spibsc_instance_ctrl_t * p_ctrl) +{ + int result = 0; + uint32_t drcr = MMIO_READ_32(p_ctrl->p_reg->DRCR); + if ((drcr & (R_SPIBSC_DRCR_RBE_Msk | R_SPIBSC_DRCR_SSLE_Msk)) == (R_SPIBSC_DRCR_RBE_Msk | R_SPIBSC_DRCR_SSLE_Msk)) + { + /* Set SSLN and wait for sslf */ + MMIO_WRITE_32(p_ctrl->p_reg->DRCR, drcr | R_SPIBSC_DRCR_SSLN_Msk); + test_sslf(p_ctrl); + } + + spibsc_test_tend(p_ctrl); + + /* Set MD bit */ + MMIO_SETBITS_32(p_ctrl->p_reg->CMNCR, R_SPIBSC_CMNCR_MD_Msk); + + return result; +} + +static bool spibsc_stop_mmap_temporarily (spibsc_instance_ctrl_t * p_ctrl) +{ + /* Stop XIP and return previous state*/ + bool state = !(MMIO_READ_32(p_ctrl->p_reg->CMNCR) & R_SPIBSC_CMNCR_MD_Msk); + spibsc_stop_mmap_internal(p_ctrl); + + return state; +} + +static void send_256 (spibsc_instance_ctrl_t * p_ctrl, xspi_transfer_form_t form, uintptr_t buffer, uint32_t smenr) +{ + /* Use wbuffer for transfer */ + MMIO_SETBITS_32(p_ctrl->p_reg->DRCR, R_SPIBSC_DRCR_RCF_Msk); + MMIO_SETBITS_32(p_ctrl->p_reg->PHYCNT, + R_SPIBSC_PHYCNT_WBUF2_Msk | R_SPIBSC_PHYCNT_WBUF_Msk | R_SPIBSC_PHYCNT_CAL_Msk); + if ((form == SPI_FORM_1_1_4) || (form == SPI_FORM_1_4_4)) + { + uint32_t phyoffset2_msk = R_SPIBSC_PHYOFFSET2_OCTTMG_Msk; + uint32_t phyoffset2_set = SPIBSC_PHYOFFSET2_SPI_WBUF << R_SPIBSC_PHYOFFSET2_OCTTMG_Pos; + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYOFFSET2, phyoffset2_msk, phyoffset2_set); + } + + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMENR, smenr_clearmask, + smenr | (SPIBSC_SMENR_SPIDE_LONG << R_SPIBSC_SMENR_SPIDE_Pos)); + + /* Write data to buffer */ + uintptr_t write_buffer = (uintptr_t) p_ctrl->p_reg + SPIBSC_CFG_WRITE_BUFFER_OFFSET; + for (uintptr_t bytes = 0; bytes < SPIBSC_BUFFER_SIZE; bytes += 8) + { + *(volatile uint64_t *) (write_buffer + bytes) = *(uint64_t *) (buffer + bytes); + } +} + +static void send_4 (spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) +{ + /* Set SPIDE */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMENR, smenr_clearmask, + smenr | (SPIBSC_SMENR_SPIDE_LONG << R_SPIBSC_SMENR_SPIDE_Pos)); + + /* Write data to SMWDR */ + MMIO_WRITE_32(p_ctrl->p_reg->SMWDR0, *(uint32_t *) buffer); +} + +static void send_2 (spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) +{ + /* Set SPIDE */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMENR, smenr_clearmask, + smenr | (SPIBSC_SMENR_SPIDE_WORD << R_SPIBSC_SMENR_SPIDE_Pos)); + + /* Write data to SMWDR */ + MMIO_WRITE_16(p_ctrl->p_reg->SMWDR0_hword.L, *(uint16_t *) buffer); +} + +static void send_1 (spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) +{ + /* Set SPIDE */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMENR, smenr_clearmask, + smenr | (SPIBSC_SMENR_SPIDE_BYTE << R_SPIBSC_SMENR_SPIDE_Pos)); + + /* Write data to SMWDR */ + MMIO_WRITE_8(p_ctrl->p_reg->SMWDR0_byte.LL, *(uint8_t *) buffer); +} + +static void receive (spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) +{ + FSP_PARAMETER_NOT_USED(buffer); + + /* Set SPIDE */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMENR, smenr_clearmask, + smenr | (SPIBSC_SMENR_SPIDE_LONG << R_SPIBSC_SMENR_SPIDE_Pos)); +} + +static void no_data (spibsc_instance_ctrl_t * p_ctrl, uintptr_t buffer, uint32_t smenr) +{ + FSP_PARAMETER_NOT_USED(buffer); + + /* No transfer data */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMENR, smenr_clearmask, + smenr | (SPIBSC_SMENR_SPIDE_NONE << R_SPIBSC_SMENR_SPIDE_Pos)); +} + +/*******************************************************************************************************************//** + * Executing operation on flash device (internally used). + * + * @retval FSP_SUCCESS Operation was successful. + * @retval FSP_ERR_INVALID_MODE One or more values in op are invalid. + **********************************************************************************************************************/ +static fsp_err_t spibsc_exec_op (spibsc_instance_ctrl_t * p_ctrl, xspi_op_t const * const op, bool is_write) +{ + bool is_xip; + uint32_t smcmr_set = 0; + uint32_t smenr_set = 0; + uint32_t smdrenr_set = 0; + uint32_t smdmcr_set = 0; + uint32_t ssldr_set = 0; + uint32_t smopr = 0; + + switch (op->form) + { + case SPI_FORM_1_1_1: + case SPI_FORM_1_1_4: + case SPI_FORM_1_4_4: + { + break; + } + + default: + FSP_ERROR_RETURN(false && op->form, FSP_ERR_INVALID_MODE); + } + + /* Command form */ + switch (op->form) + { + case SPI_FORM_1_1_1: + { + smenr_set |= smenr_form_111; + break; + } + + case SPI_FORM_1_1_4: + { + smenr_set |= smenr_form_114; + break; + } + + case SPI_FORM_1_4_4: + { + smenr_set |= smenr_form_144; + break; + } + + default: + FSP_ERROR_RETURN(false && op->form, FSP_ERR_INVALID_MODE); + } + + /* Opcode */ + switch (op->op_size) + { + case 0: + { + smenr_set |= smenr_op_none; + break; + } + + case 1: + { + smenr_set |= smenr_op_1byte; + smcmr_set |= PICK_LL(op->op) << R_SPIBSC_SMCMR_CMD_Pos; + break; + } + + case 2: + { + smenr_set |= smenr_op_2byte; + smcmr_set |= PICK_LL(op->op) << R_SPIBSC_SMCMR_OCMD_Pos; + smcmr_set |= PICK_LH(op->op) << R_SPIBSC_SMCMR_CMD_Pos; + break; + } + + default: + FSP_ERROR_RETURN(false && op->op_size, FSP_ERR_INVALID_MODE); + } + + /* Address */ + switch (op->address_size) + { + case 0: + { + smenr_set |= smenr_addr_none; + break; + } + + case 3: + { + smenr_set |= smenr_addr_3byte; + break; + } + + case 4: + { + smenr_set |= smenr_addr_4byte; + break; + } + + default: + FSP_ERROR_RETURN(false && op->address_size, FSP_ERR_INVALID_MODE); + } + + /* Additional data */ + switch (op->additional_size) + { + case 0: + { + smenr_set |= smenr_additional_none; + break; + } + + case 1: + { + smenr_set |= smenr_additional_1byte; + smopr = PICK_LL(op->additional_value) << R_SPIBSC_SMOPR_OPD3_Pos; + break; + } + + case 2: + { + smenr_set |= smenr_additional_2byte; + smopr = PICK_LL(op->additional_value) << R_SPIBSC_SMOPR_OPD2_Pos; + smopr |= PICK_LH(op->additional_value) << R_SPIBSC_SMOPR_OPD3_Pos; + break; + } + + case 3: + { + smenr_set |= smenr_additional_3byte; + smopr = PICK_LL(op->additional_value) << R_SPIBSC_SMOPR_OPD1_Pos; + smopr |= PICK_LH(op->additional_value) << R_SPIBSC_SMOPR_OPD2_Pos; + smopr |= PICK_HL(op->additional_value) << R_SPIBSC_SMOPR_OPD3_Pos; + break; + } + + case 4: + { + smenr_set |= smenr_additional_4byte; + smopr = PICK_LL(op->additional_value) << R_SPIBSC_SMOPR_OPD0_Pos; + smopr |= PICK_LH(op->additional_value) << R_SPIBSC_SMOPR_OPD1_Pos; + smopr |= PICK_HL(op->additional_value) << R_SPIBSC_SMOPR_OPD2_Pos; + smopr |= PICK_HH(op->additional_value) << R_SPIBSC_SMOPR_OPD3_Pos; + break; + } + + default: + FSP_ERROR_RETURN(false && op->additional_size, FSP_ERR_INVALID_MODE); + } + + /* Dummy cycle */ + if (op->dummy_cycles == 0) + { + smenr_set |= 0U << R_SPIBSC_SMENR_DME_Pos; + smdmcr_set |= 0U << R_SPIBSC_SMDMCR_DMCYC_Pos; + } + else if ((op->dummy_cycles == 1) || (op->dummy_cycles > 20)) + { + FSP_ERROR_RETURN(false && op->dummy_cycles, FSP_ERR_INVALID_MODE); + } + else + { + smenr_set |= 1U << R_SPIBSC_SMENR_DME_Pos; + smdmcr_set |= (op->dummy_cycles - 1U) << R_SPIBSC_SMDMCR_DMCYC_Pos; + } + + /* SLCH (SSL assert to CLK high) */ + if (op->slch_value < 8) + { + ssldr_set |= op->slch_value << R_SPIBSC_SSLDR_SCKDL_Pos; + } + else + { + FSP_ERROR_RETURN(false && op->slch_value, FSP_ERR_INVALID_MODE); + } + + /* CLSH (CLK low tp SSL negative) */ + if (op->clsh_value < 8) + { + ssldr_set |= op->clsh_value << R_SPIBSC_SSLDR_SLNDL_Pos; + } + else + { + FSP_ERROR_RETURN(false && op->clsh_value, FSP_ERR_INVALID_MODE); + } + + /* SHSL (SSL negative to SSL assert) */ + if (op->shsl_value < 8) + { + ssldr_set |= op->shsl_value << R_SPIBSC_SSLDR_SPNDL_Pos; + } + else + { + FSP_ERROR_RETURN(false && op->shsl_value, FSP_ERR_INVALID_MODE); + } + + /* Save XIP state and stop XIP */ + is_xip = spibsc_stop_mmap_temporarily(p_ctrl); + + /* Wait for transaction end */ + spibsc_test_tend(p_ctrl); + + /* Change I/O level while idle state */ + spibsc_set_idlelevel(p_ctrl, op); + + /* Create values to write the registers */ + uint32_t smadr = op->address; + uint32_t save_ssldr = MMIO_READ_32(p_ctrl->p_reg->SSLDR); + uint32_t save_phyoffset1 = MMIO_READ_32(p_ctrl->p_reg->PHYOFFSET1); + uint32_t save_phyoffset2 = MMIO_READ_32(p_ctrl->p_reg->PHYOFFSET2); + uint32_t save_phycnt = MMIO_READ_32(p_ctrl->p_reg->PHYCNT); + + /* PHYOFFSET1 setting */ + uint32_t phyoffset1_msk = R_SPIBSC_PHYOFFSET1_DDRTMG_Msk; + uint32_t phyoffset1_set; + phyoffset1_set = SPIBSC_PHYOFFSET1_SDR << R_SPIBSC_PHYOFFSET1_DDRTMG_Pos; + + /* PHYCNT setting */ + uint32_t phycnt_msk = R_SPIBSC_PHYCNT_PHYMEM_Msk; + uint32_t phycnt_set; + phycnt_set = SPIBSC_PHYCNT_SDR << R_SPIBSC_PHYCNT_PHYMEM_Pos; + + /* Write the register */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMCMR, smcmr_clearmask, smcmr_set); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMDRENR, smdrenr_clearmask, smdrenr_set); + MMIO_WRITE_32(p_ctrl->p_reg->SMADR, smadr); + MMIO_WRITE_32(p_ctrl->p_reg->SMOPR, smopr); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SMDMCR, smdmcr_clearmask, smdmcr_set); + MMIO_WRITE_32(p_ctrl->p_reg->SSLDR, (save_ssldr & ~ssldr_clearmask) | ssldr_set); + MMIO_WRITE_32(p_ctrl->p_reg->PHYOFFSET1, (save_phyoffset1 & ~phyoffset1_msk) | phyoffset1_set); + MMIO_WRITE_32(p_ctrl->p_reg->PHYCNT, (save_phycnt & ~phycnt_msk) | phycnt_set | R_SPIBSC_PHYCNT_CAL_Msk); + + int64_t remain = (int64_t) op->transfer_size; + uintptr_t buffer = (uintptr_t) op->transfer_buffer; + uint32_t smcr; + + /* Enable transmit */ + if (is_write && remain) + { + smcr = R_SPIBSC_SMCR_SPIWE_Msk | R_SPIBSC_SMCR_SPIE_Msk; + } + else if (remain) + { + smcr = R_SPIBSC_SMCR_SPIRE_Msk | R_SPIBSC_SMCR_SPIE_Msk; + } + else + { + smcr = R_SPIBSC_SMCR_SPIE_Msk; + } + + do + { + uint32_t xfer_count; + + /* Block size per single transfer */ + if (is_write && (remain >= SPIBSC_BUFFER_SIZE)) + { + send_256(p_ctrl, op->form, buffer, smenr_set); + xfer_count = SPIBSC_BUFFER_SIZE; + } + else if (is_write && (remain >= 4)) + { + send_4(p_ctrl, buffer, smenr_set); + xfer_count = 4; + } + else if (is_write && (remain >= 2)) + { + send_2(p_ctrl, buffer, smenr_set); + xfer_count = 2; + } + else if (is_write && remain) + { + send_1(p_ctrl, buffer, smenr_set); + xfer_count = 1; + } + else if (remain) + { + receive(p_ctrl, buffer, smenr_set); + xfer_count = 4; + } + else + { + no_data(p_ctrl, buffer, smenr_set); + xfer_count = 0; + } + + /* Set SSLKP if transaction is remained and write transfer */ + if (is_write && (remain > xfer_count)) + { + smcr |= R_SPIBSC_SMCR_SSLKP_Msk; + } + else + { + smcr &= (uint32_t) ~R_SPIBSC_SMCR_SSLKP_Msk; + } + + /* Exec transaction */ + MMIO_WRITE_32(p_ctrl->p_reg->SMCR, smcr); + spibsc_test_tend(p_ctrl); + + /* Store received data */ + if (!is_write && remain) + { + uint32_t smrdr = MMIO_READ_32(p_ctrl->p_reg->SMRDR0); + if (remain > 3) + { + *(uint32_t *) buffer = smrdr; + } + else + { + *(uint8_t *) buffer = (uint8_t) PICK_LL(smrdr); + if (remain > 1) + { + *(uint8_t *) (buffer + 1) = (uint8_t) PICK_LH(smrdr); + } + + if (remain > 2) + { + *(uint8_t *) (buffer + 2) = (uint8_t) PICK_HL(smrdr); + } + } + } + + remain -= xfer_count; + buffer += xfer_count; + + /* Clear write buffer flag and restore OCTTMG */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYCNT, + R_SPIBSC_PHYCNT_WBUF2_Msk | R_SPIBSC_PHYCNT_WBUF_Msk, + R_SPIBSC_PHYCNT_CAL_Msk); + MMIO_WRITE_32(p_ctrl->p_reg->PHYOFFSET2, save_phyoffset2); + + if (remain > 0) + { + if (!is_write) + { + /* Increment address */ + smadr += xfer_count; + MMIO_WRITE_32(p_ctrl->p_reg->SMADR, smadr); + } + else + { + /* Clear enabler bits for continuous write access */ + smenr_set &= + (uint32_t) ~(R_SPIBSC_SMENR_DME_Msk | R_SPIBSC_SMENR_CDE_Msk | R_SPIBSC_SMENR_OCDE_Msk | + R_SPIBSC_SMENR_ADE_Msk | + R_SPIBSC_SMENR_OPDE_Msk); + } + } + } while (remain > 0); + + /* Resume regs */ + MMIO_WRITE_32(p_ctrl->p_reg->SSLDR, save_ssldr); + MMIO_WRITE_32(p_ctrl->p_reg->PHYCNT, save_phycnt | R_SPIBSC_PHYCNT_CAL_Msk); + MMIO_WRITE_32(p_ctrl->p_reg->PHYOFFSET1, save_phyoffset1); + + if (is_xip) + { + /* Resume XIP state */ + spibsc_start_mmap_internal(p_ctrl); + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Configuring memory-mapped read (internally used). + * + * @retval FSP_SUCCESS Operation was successful. + * @retval FSP_ERR_INVALID_MODE One or more values in op are invalid. + **********************************************************************************************************************/ +static fsp_err_t spibsc_configure_mmap_sub (spibsc_instance_ctrl_t * p_ctrl, xspi_op_t const * const rop) +{ + uint32_t drenr_set = 0; + uint32_t drcmr_set = 0; + uint32_t drdrenr_set = 0; + uint32_t drdmcr_set = 0; + uint32_t dropr = 0; + uint32_t ssldr_clear = 0; + uint32_t ssldr_set = 0; + uint32_t phyoffset1_msk = R_SPIBSC_PHYOFFSET1_DDRTMG_Msk; + uint32_t phyoffset1_set = 0; + uint32_t phyoffset2_msk = R_SPIBSC_PHYOFFSET2_OCTTMG_Msk; + uint32_t phyoffset2_set = SPIBSC_PHYOFFSET2_SPI << R_SPIBSC_PHYOFFSET2_OCTTMG_Pos; + uint32_t phycnt_msk = R_SPIBSC_PHYCNT_PHYMEM_Msk; + uint32_t phycnt_set = 0; + + /* Command form */ + switch (rop->form) + { + case SPI_FORM_1_1_1: + { + drenr_set |= drenr_form_111; + break; + } + + case SPI_FORM_1_1_4: + { + drenr_set |= drenr_form_114; + break; + } + + case SPI_FORM_1_4_4: + { + drenr_set |= drenr_form_144; + break; + } + + default: + FSP_ERROR_RETURN(false && rop->form, FSP_ERR_INVALID_MODE); + } + + /* Opcode */ + switch (rop->op_size) + { + case 0: + { + drenr_set |= drenr_op_none; + break; + } + + case 1: + { + drenr_set |= drenr_op_1byte; + drcmr_set |= PICK_LL(rop->op) << R_SPIBSC_DRCMR_CMD_Pos; + break; + } + + case 2: + { + drenr_set |= drenr_op_2byte; + drcmr_set |= PICK_LL(rop->op) << R_SPIBSC_DRCMR_OCMD_Pos; + drcmr_set |= PICK_LH(rop->op) << R_SPIBSC_DRCMR_CMD_Pos; + break; + } + + default: + FSP_ERROR_RETURN(false && rop->op_size, FSP_ERR_INVALID_MODE); + } + + /* Address */ + switch (rop->address_size) + { + case 0: + { + drenr_set |= drenr_addr_none; + break; + } + + case 3: + { + drenr_set |= drenr_addr_3byte; + break; + } + + case 4: + { + drenr_set |= drenr_addr_4byte; + break; + } + + default: + FSP_ERROR_RETURN(false && rop->address_size, FSP_ERR_INVALID_MODE); + } + + /* Additional data */ + switch (rop->additional_size) + { + case 0: + { + drenr_set |= drenr_additional_none; + break; + } + + case 1: + { + drenr_set |= drenr_additional_1byte; + dropr |= PICK_LL(rop->additional_value) << R_SPIBSC_DROPR_OPD3_Pos; + break; + } + + case 2: + { + drenr_set |= drenr_additional_2byte; + dropr |= PICK_LL(rop->additional_value) << R_SPIBSC_DROPR_OPD2_Pos; + dropr |= PICK_LH(rop->additional_value) << R_SPIBSC_DROPR_OPD3_Pos; + break; + } + + case 3: + { + drenr_set |= drenr_additional_3byte; + dropr |= PICK_LL(rop->additional_value) << R_SPIBSC_DROPR_OPD1_Pos; + dropr |= PICK_LH(rop->additional_value) << R_SPIBSC_DROPR_OPD2_Pos; + dropr |= PICK_HL(rop->additional_value) << R_SPIBSC_DROPR_OPD3_Pos; + break; + } + + case 4: + { + drenr_set |= drenr_additional_4byte; + dropr |= PICK_LL(rop->additional_value) << R_SPIBSC_DROPR_OPD0_Pos; + dropr |= PICK_LH(rop->additional_value) << R_SPIBSC_DROPR_OPD1_Pos; + dropr |= PICK_HL(rop->additional_value) << R_SPIBSC_DROPR_OPD2_Pos; + dropr |= PICK_HH(rop->additional_value) << R_SPIBSC_DROPR_OPD3_Pos; + break; + } + + default: + FSP_ERROR_RETURN(false && rop->additional_size, FSP_ERR_INVALID_MODE); + } + + /* Dummy cycle */ + if (rop->dummy_cycles == 0) + { + drenr_set |= 0U << R_SPIBSC_DRENR_DME_Pos; + drdmcr_set |= 0U << R_SPIBSC_DRDMCR_DMCYC_Pos; + } + else if ((rop->dummy_cycles == 1) || (rop->dummy_cycles > 20)) + { + FSP_ERROR_RETURN(false && rop->dummy_cycles, FSP_ERR_INVALID_MODE); + } + else + { + drenr_set |= 1U << R_SPIBSC_DRENR_DME_Pos; + drdmcr_set |= (rop->dummy_cycles - 1U) << R_SPIBSC_DRDMCR_DMCYC_Pos; + } + + /* Set operation timing for PHYOFFSET1 */ + phyoffset1_set = SPIBSC_PHYOFFSET1_SDR << R_SPIBSC_PHYOFFSET1_DDRTMG_Pos; + + /* Set data transfer mode for PHYCNT */ + phycnt_set = SPIBSC_PHYCNT_SDR << R_SPIBSC_PHYCNT_PHYMEM_Pos; + + /* SLCH (SSL assert to CLK high) */ + if (rop->slch_value < 8) + { + ssldr_clear |= R_SPIBSC_SSLDR_SCKDL_Msk; + ssldr_set |= rop->slch_value << R_SPIBSC_SSLDR_SCKDL_Pos; + } + else + { + FSP_ERROR_RETURN(false && rop->slch_value, FSP_ERR_INVALID_MODE); + } + + /* CLSH (CLK low tp SSL negative) */ + if (rop->clsh_value < 8) + { + ssldr_clear |= R_SPIBSC_SSLDR_SLNDL_Msk; + ssldr_set |= rop->clsh_value << R_SPIBSC_SSLDR_SLNDL_Pos; + } + else + { + FSP_ERROR_RETURN(false && rop->clsh_value, FSP_ERR_INVALID_MODE); + } + + /* SHSL (SSL negative to SSL assert) */ + if (rop->shsl_value < 8) + { + ssldr_clear |= R_SPIBSC_SSLDR_SPNDL_Msk; + ssldr_set |= rop->shsl_value << R_SPIBSC_SSLDR_SPNDL_Pos; + } + else + { + FSP_ERROR_RETURN(false && rop->shsl_value, FSP_ERR_INVALID_MODE); + } + + /* Change I/O level while idle state */ + spibsc_set_idlelevel(p_ctrl, rop); + + /* Write the register */ + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DRCMR, drcmr_clearmask, drcmr_set); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DRENR, drenr_clearmask, drenr_set); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DRDRENR, drdrenr_clearmask, drdrenr_set); + MMIO_WRITE_32(p_ctrl->p_reg->DROPR, dropr); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->DRDMCR, drdmcr_clearmask, drdmcr_set); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->SSLDR, ssldr_clear, ssldr_set); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYOFFSET1, phyoffset1_msk, phyoffset1_set); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYOFFSET2, phyoffset2_msk, phyoffset2_set); + MMIO_CLRSETBITS_32(p_ctrl->p_reg->PHYCNT, phycnt_msk, phycnt_set | R_SPIBSC_PHYCNT_CAL_Msk); + + return FSP_SUCCESS; +} diff --git a/drivers/rz/fsp/src/rza/r_spibsc/r_spibsc_private.h b/drivers/rz/fsp/src/rza/r_spibsc/r_spibsc_private.h new file mode 100644 index 00000000..f3fa6ff6 --- /dev/null +++ b/drivers/rz/fsp/src/rza/r_spibsc/r_spibsc_private.h @@ -0,0 +1,150 @@ +/* +* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef R_SPIBSC_PRIVATE_H +#define R_SPIBSC_PRIVATE_H + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ +#include "bsp_api.h" + +/* Common macro for FSP header files. There is also a corresponding FSP_FOOTER macro at the end of this file. */ +FSP_HEADER + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ + +/* Data picker utility macros */ +#define PICK_LL(a) ((a) % 256U) +#define PICK_LH(a) (((a) >> 8) % 256U) +#define PICK_HL(a) (((a) >> 16) % 256U) +#define PICK_HH(a) (((a) >> 24) % 256U) + +/* Clear and Set utility macros */ +#define MMIO_WRITE_32(_reg, _value) _reg = _value +#define MMIO_WRITE_16(_reg, _value) _reg = _value +#define MMIO_WRITE_8(_reg, _value) _reg = _value +#define MMIO_READ_32(_reg) _reg +#define MMIO_CLRSETBITS_32(_reg, _clear, _set) _reg = ((_reg) & (uint32_t) ~(_clear)) | (uint32_t) (_set) +#define MMIO_CLRBITS_32(_reg, _clear) _reg = (_reg) & (uint32_t) ~(_clear) +#define MMIO_SETBITS_32(_reg, _set) _reg = (_reg) | (uint32_t) (_set) + +/* CMNCR field */ +#define SPIBSC_CMNCR_IO_LOW (0U) +#define SPIBSC_CMNCR_IO_HIGH (1U) +#define SPIBSC_CMNCR_IO_KEEP (2U) +#define SPIBSC_CMNCR_IO_HIZ (3U) +#define SPIBSC_CMNCR_BSZ_SINGLE (0U) +#define SPIBSC_CMNCR_BSZ_DUAL (1U) +#define SPIBSC_CMNCR_BSZ_OCTA (1U) +#define SPIBSC_CMNCR_BSZ_HYPER (1U) + +/* DRENR field */ +#define SPIBSC_DRENR_DB_4BIT (2U) +#define SPIBSC_DRENR_DB_1BIT (0U) +#define SPIBSC_DRENR_ADE_3BYTE (7U) +#define SPIBSC_DRENR_ADE_4BYTE (15U) +#define SPIBSC_DRENR_ADE_OPI (12U) +#define SPIBSC_DRENR_ADE_HYPER (4U) +#define SPIBSC_DRENR_ADE_NONE (0U) +#define SPIBSC_DRENR_OPDE_NONE (0U) +#define SPIBSC_DRENR_OPDE_1BYTE (8U) +#define SPIBSC_DRENR_OPDE_2BYTE (12U) +#define SPIBSC_DRENR_OPDE_3BYTE (14U) +#define SPIBSC_DRENR_OPDE_4BYTE (15U) +#define DRENR_FORM111 ( \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_CDB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OCDB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_ADB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OPDB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_DRDB_Pos) +#define DRENR_FORM114 ( \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_CDB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OCDB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_ADB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OPDB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_DRDB_Pos) +#define DRENR_FORM144 ( \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_CDB_Pos | \ + SPIBSC_DRENR_DB_1BIT << R_SPIBSC_DRENR_OCDB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_ADB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_OPDB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_DRDB_Pos) +#define DRENR_FORM444 ( \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_CDB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_OCDB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_ADB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_OPDB_Pos | \ + SPIBSC_DRENR_DB_4BIT << R_SPIBSC_DRENR_DRDB_Pos) +#define DRENR_COMMAND_DISABLE (0U << R_SPIBSC_DRENR_CDE_Pos) ///< Command = disable +#define DRENR_COMMAND_ENABLE (1U << R_SPIBSC_DRENR_CDE_Pos) ///< Command = enable +#define DRENR_OCOMMAND_DISABLE (0U << R_SPIBSC_DRENR_OCDE_Pos) ///< Optional Command = disable +#define DRENR_OCOMMAND_ENABLE (1U << R_SPIBSC_DRENR_OCDE_Pos) ///< Optional Command = enable +#define DRENR_ADR3BYTE (SPIBSC_DRENR_ADE_3BYTE << R_SPIBSC_DRENR_ADE_Pos) ///< Address = 3-byte +#define DRENR_ADR4BYTE (SPIBSC_DRENR_ADE_4BYTE << R_SPIBSC_DRENR_ADE_Pos) ///< Address = 4-byte +#define DRENR_ODATA_DISABLE (SPIBSC_DRENR_OPDE_NONE << R_SPIBSC_DRENR_OPDE_Pos) ///< Optional Data = disable +#define DRENR_ODATA_ENABLE (SPIBSC_DRENR_OPDE_1BYTE << R_SPIBSC_DRENR_OPDE_Pos) ///< Optional Data = enable +#define DRENR_DUMMY_DISABLE (0U << R_SPIBSC_DRENR_DME_Pos) ///< Dummy = disable +#define DRENR_DUMMY_ENABLE (1U << R_SPIBSC_DRENR_DME_Pos) ///< Dummy = enable + +/* SMENR field */ +#define SPIBSC_SMENR_DB_4BIT (2U) +#define SPIBSC_SMENR_DB_1BIT (0U) +#define SPIBSC_SMENR_ADE_3BYTE (7U) +#define SPIBSC_SMENR_ADE_4BYTE (15U) +#define SPIBSC_SMENR_ADE_OPI (12U) +#define SPIBSC_SMENR_ADE_HYPER (4U) +#define SPIBSC_SMENR_ADE_NONE (0U) +#define SPIBSC_SMENR_OPDE_NONE (0U) +#define SPIBSC_SMENR_OPDE_1BYTE (8U) +#define SPIBSC_SMENR_OPDE_2BYTE (12U) +#define SPIBSC_SMENR_OPDE_3BYTE (14U) +#define SPIBSC_SMENR_OPDE_4BYTE (15U) +#define SPIBSC_SMENR_SPIDE_NONE (0U) +#define SPIBSC_SMENR_SPIDE_BYTE (8U) +#define SPIBSC_SMENR_SPIDE_WORD (12U) +#define SPIBSC_SMENR_SPIDE_LONG (15U) + +/* DRDRENR field */ +#define SPIBSC_DRDRENR_SPI (0U) +#define SPIBSC_DRDRENR_DDR (5U) +#define SPIBSC_DRDRENR_OCTADDR (4U) + +/* SMDRENR field */ +#define SPIBSCSSCC_SMDRENR_SPI (0U) +#define SPIBSCSSCC_SMDRENR_DDR (5U) +#define SPIBSCSSCC_SMDRENR_OCTADDR (4U) + +/* PHYCNT field */ +#define SPIBSC_PHYCNT_OCTA_DDR_ALT (1U) +#define SPIBSC_PHYCNT_OCTA_DDR_SEQ (2U) +#define SPIBSC_PHYCNT_SDR (0U) +#define SPIBSC_PHYCNT_DDR (1U) +#define SPIBSC_PHYCNT_HYPER (3U) + +/* PHYOFFSET1 field */ +#define SPIBSC_PHYOFFSET1_DDR (2U) +#define SPIBSC_PHYOFFSET1_SDR (3U) + +/* PHYOFFSET2 field */ +#define SPIBSC_PHYOFFSET2_SPI (4U) +#define SPIBSC_PHYOFFSET2_HYPER (4U) +#define SPIBSC_PHYOFFSET2_SPI_WBUF (0U) +#define SPIBSC_PHYOFFSET2_OPI (3U) + +/* Misc constants */ +#define SPIBSC_BUFFER_SIZE (256) + +/* Common macro for FSP header files. There is also a corresponding FSP_HEADER macro at the top of this file. */ +FSP_FOOTER + +#endif + +/*******************************************************************************************************************//** + * @} (end defgroup SPIBSC) + **********************************************************************************************************************/ diff --git a/drivers/rz/fsp/src/rzn/CMakeLists.txt b/drivers/rz/fsp/src/rzn/CMakeLists.txt index b935a237..04b3a60c 100644 --- a/drivers/rz/fsp/src/rzn/CMakeLists.txt +++ b/drivers/rz/fsp/src/rzn/CMakeLists.txt @@ -11,6 +11,7 @@ set(srcs bsp/mcu/all/bsp_io.c bsp/mcu/all/bsp_irq.c bsp/mcu/all/bsp_register_protection.c + bsp/mcu/all/bsp_reset.c bsp/mcu/all/cr/bsp_delay_core.c ) diff --git a/drivers/rz/fsp/src/rzn/bsp/mcu/all/bsp_reset.c b/drivers/rz/fsp/src/rzn/bsp/mcu/all/bsp_reset.c new file mode 100644 index 00000000..a82bfd30 --- /dev/null +++ b/drivers/rz/fsp/src/rzn/bsp/mcu/all/bsp_reset.c @@ -0,0 +1,372 @@ +/* +* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/*********************************************************************************************************************** + * Includes , "Project Includes" + **********************************************************************************************************************/ +#include "bsp_api.h" + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ +#define BSP_RESET_MRCTL_BIT_SHIFT_MASK (0x0000001FU) +#define BSP_RESET_MRCTL_SELECT_MASK (0x001F0000U) +#define BSP_RESET_MRCTL_REGION_SELECT_MASK (0x00400000U) + +#define BSP_RESET_RMR_RESET_REQUEST_AARCH64 (0x3) + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Exported global variables (to be accessed by other files) + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Private global variables and functions + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * @addtogroup BSP_MCU + * + * @{ + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Occur the system software reset. + **********************************************************************************************************************/ +void R_BSP_SystemReset (void) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + /* System software reset. */ + R_SYSC_S->SWRSYS = BSP_PRV_RESET_KEY; +} + +/*******************************************************************************************************************//** + * Occur the CPU software reset. + * + * @param[in] cpu to be reset state. + * + * @note With Cortex-A55, you cannot use resets that are not automatically released when a software reset is executed. + **********************************************************************************************************************/ +void R_BSP_CPUReset (bsp_reset_t cpu) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CR52_0 == cpu) + { + /* CR52_0 software reset. */ + R_SYSC_S->SWRCPU0 = BSP_PRV_RESET_KEY; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + +#if defined(BSP_CFG_CORE_CR52) && (0 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); +#endif + } + +#if (1U < BSP_FEATURE_BSP_CR52_CORE_NUM) + else if (BSP_RESET_CR52_1 == cpu) + { + /* CR52_1 software reset. */ + R_SYSC_S->SWRCPU1 = BSP_PRV_RESET_KEY; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if defined(BSP_CFG_CORE_CR52) && (1 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); + #endif + } +#endif +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + else if (BSP_RESET_CA55_CLUSTER == cpu) + { + /* CA55_cluster software reset. */ + R_SYSC_S->SWR55C = BSP_PRV_RESET_KEY; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } +#endif + else + { + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } +} + +/*******************************************************************************************************************//** + * Occur the CPU software reset. When using this function, the CPU reset state is automatically released + * after an elapsed time corresponding to the setting value in SCKCR2.DIVSELSUB bit. + * + * @param[in] cpu to be reset state. + **********************************************************************************************************************/ +void R_BSP_CPUResetAutoRelease (bsp_reset_t cpu) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CR52_0 == cpu) + { + /* CR52_0 software reset. */ + R_SYSC_S->SWRCPU0 = BSP_PRV_RESET_KEY_AUTO_RELEASE; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + +#if defined(BSP_CFG_CORE_CR52) && (0 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); +#endif + } + +#if (1U < BSP_FEATURE_BSP_CR52_CORE_NUM) + else if (BSP_RESET_CR52_1 == cpu) + { + /* CR52_1 software reset. */ + R_SYSC_S->SWRCPU1 = BSP_PRV_RESET_KEY_AUTO_RELEASE; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if defined(BSP_CFG_CORE_CR52) && (1 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); + #endif + } +#endif +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + else if (BSP_RESET_CA55_CLUSTER == cpu) + { + /* CA55_cluster software reset. */ + R_SYSC_S->SWR55C = BSP_PRV_RESET_KEY_AUTO_RELEASE; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } + #if defined(BSP_CFG_CORE_CA55) + else if (BSP_RESET_CA55_0 == cpu) + { + /* CA55_0 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (0 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + else if (BSP_RESET_CA55_1 == cpu) + { + /* CA55_1 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (1 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + else if (BSP_RESET_CA55_2 == cpu) + { + /* CA55_2 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (2 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + else if (BSP_RESET_CA55_3 == cpu) + { + /* CA55_3 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (3 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + #endif +#endif + else + { + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } +} + +/*******************************************************************************************************************//** + * Release the CPU reset state. + * + * @param[in] cpu to be release reset state. + **********************************************************************************************************************/ +void R_BSP_CPUResetRelease (bsp_reset_t cpu) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CR52_0 == cpu) + { + /* Release CR52_0 reset state. */ + R_SYSC_S->SWRCPU0 = BSP_PRV_RESET_RELEASE_KEY; + } + +#if (1U < BSP_FEATURE_BSP_CR52_CORE_NUM) + else if (BSP_RESET_CR52_1 == cpu) + { + /* Release CR52_1 reset state. */ + R_SYSC_S->SWRCPU1 = BSP_PRV_RESET_RELEASE_KEY; + } +#endif +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + else if (BSP_RESET_CA55_CLUSTER == cpu) + { + /* Release CA55_cluster software reset. */ + R_SYSC_S->SWR55C = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_0 == cpu) + { + /* Release CA55_0 reset state. */ + R_SYSC_S->SWR550 = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_1 == cpu) + { + /* Release CA55_1 reset state. */ + R_SYSC_S->SWR551 = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_2 == cpu) + { + /* Release CA55_2 reset state. */ + R_SYSC_S->SWR552 = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_3 == cpu) + { + /* Release CA55_3 reset state. */ + R_SYSC_S->SWR553 = BSP_PRV_RESET_RELEASE_KEY; + } +#endif + else + { + /* Do Nothing. */ + } + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); +} + +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + +/*******************************************************************************************************************//** + * Controls whether the core is automatically released from reset when a CA55 cluster reset is performed. + * + * @param[in] cpu to be release reset state. + * @param[in] release Enable/disable automatic reset release. + **********************************************************************************************************************/ +void R_BSP_CPUClusterResetAutoReleaseControl (bsp_reset_t cpu, bsp_cluster_reset_auto_release_t release) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CA55_0 == cpu) + { + /* Controls the automatic reset release of CA55_0. */ + R_SYSC_S->SWR55ARC_b.ARC550 = release; + } + else if (BSP_RESET_CA55_1 == cpu) + { + /* Controls the automatic reset release of CA55_1. */ + R_SYSC_S->SWR55ARC_b.ARC551 = release; + } + else if (BSP_RESET_CA55_2 == cpu) + { + /* Controls the automatic reset release of CA55_2. */ + R_SYSC_S->SWR55ARC_b.ARC552 = release; + } + else if (BSP_RESET_CA55_3 == cpu) + { + /* Controls the automatic reset release of CA55_3. */ + R_SYSC_S->SWR55ARC_b.ARC553 = release; + } + else + { + /* Do Nothing. */ + } + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); +} + +#endif + +/*******************************************************************************************************************//** + * Enable module reset state. + * + * @param[in] module_to_enable Modules to enable module reset state. + **********************************************************************************************************************/ +void R_BSP_ModuleResetEnable (bsp_module_reset_t module_to_enable) +{ + volatile uint32_t mrctl; + uint32_t * p_reg; + + /** When MRCTLn register exists in the safety region, + * it is necessary to add an offset of safety region. */ + p_reg = (uint32_t *) &R_SYSC_NS->MRCTLA + + (((module_to_enable & BSP_RESET_MRCTL_SELECT_MASK) >> 16U) + + (module_to_enable & BSP_RESET_MRCTL_REGION_SELECT_MASK)); + mrctl = 1U << (module_to_enable & BSP_RESET_MRCTL_BIT_SHIFT_MASK); + + /** Enable module reset state using MRCTLE register. */ + *p_reg |= mrctl; + + /** To ensure processing after module reset. */ + mrctl = *(volatile uint32_t *) (p_reg); +} + +/*******************************************************************************************************************//** + * Disable module reset state. + * + * @param[in] module_to_disable Modules to disable module reset state. + * + * @note After reset release is performed by the module control register, a dummy read is performed to allow access + * to other than the RTC and LCDC. This is done several times according to the RZ microprocessor manual. + * However, the dummy read count for the RTC and LCDC may not be met depending on the device used. + * In that case, please perform additional dummy read processing after API execution. + * For example, in the case of RZN2H, 300 dummy reads are required for RTC and + * 100 dummy reads are required for LCDC. + * + **********************************************************************************************************************/ +void R_BSP_ModuleResetDisable (bsp_module_reset_t module_to_disable) +{ + volatile uint32_t mrctl; + uint32_t * p_reg; + + /** When MRCTLn register exists in the safety region, + * it is necessary to add an offset of safety region. */ + p_reg = (uint32_t *) &R_SYSC_NS->MRCTLA + + (((module_to_disable & BSP_RESET_MRCTL_SELECT_MASK) >> 16U) + + (module_to_disable & BSP_RESET_MRCTL_REGION_SELECT_MASK)); + mrctl = 1U << (module_to_disable & BSP_RESET_MRCTL_BIT_SHIFT_MASK); + + /** Disable module stop state using MRCTLn register. */ + *p_reg &= ~mrctl; + + /** In order to secure processing after release from module reset, + * dummy read the same register. + * Refer to "Notes on Module Reset Control Register Operation" of the RZ microprocessor manual. */ + uint32_t dummy_read_cnt = BSP_FEATURE_BSP_MODULE_RESET_DUMMY_READ_COUNT; + + while (dummy_read_cnt) + { + mrctl = *(volatile uint32_t *) (p_reg); + dummy_read_cnt--; + } +} + +/** @} (end addtogroup BSP_MCU) */ diff --git a/drivers/rz/fsp/src/rzn/r_xspi_qspi/r_xspi_qspi.c b/drivers/rz/fsp/src/rzn/r_xspi_qspi/r_xspi_qspi.c new file mode 100644 index 00000000..e4b8f127 --- /dev/null +++ b/drivers/rz/fsp/src/rzn/r_xspi_qspi/r_xspi_qspi.c @@ -0,0 +1,1169 @@ +/* +* Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "bsp_api.h" + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ +#include "r_xspi_qspi.h" + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ +#define XSPI_QSPI_PRV_OPEN (0x51535049) + +#define XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET (0U) +#define XSPI_QSPI_PRV_LIOCFGCS_PRTMD_VALUE_MASK (0x3FFU) +#define XSPI_QSPI_PRV_LIOCFGCS_PRTMD_MASK (0x3FFU << XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET) +#define XSPI_QSPI_PRV_LIOCFGCS_CSMIN_OFFSET (16U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSMIN_VALUE_MASK (0x0FU) +#define XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_OFFSET (20U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_VALUE_MASK (0x01U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_OFFSET (21U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_VALUE_MASK (0x01U) + +#define XSPI_QSPI_PRV_CMCFG0_FFMT_OFFSET (0U) +#define XSPI_QSPI_PRV_CMCFG0_ADDSIZE_OFFSET (2U) +#define XSPI_QSPI_PRV_CMCFG0_ADDSIZE_VALUE_MASK (0x03U) +#define XSPI_QSPI_PRV_CMCFG1_RDCMD_UPPER_OFFSET (8U) +#define XSPI_QSPI_PRV_CMCFG1_RDCMD_VALUE_MASK (0xFFU) +#define XSPI_QSPI_PRV_CMCFG1_RDLATE_OFFSET (16U) +#define XSPI_QSPI_PRV_CMCFG1_RDLATE_VALUE_MASK (0x1FU) + +#define XSPI_QSPI_PRV_CMCFG2_WRCMD_UPPER_OFFSET (8U) +#define XSPI_QSPI_PRV_CMCFG1_WRCMD_VALUE_MASK (0xFFU) +#define XSPI_QSPI_PRV_CMCFG2_WRLATE_OFFSET (16U) + +#define XSPI_QSPI_PRV_BMCFG_WRMD_OFFSET (0U) +#define XSPI_QSPI_PRV_BMCFG_MWRCOMB_OFFSET (7U) +#define XSPI_QSPI_PRV_BMCFG_MWRSIZE_OFFSET (8U) +#define XSPI_QSPI_PRV_BMCFG_PREEN_OFFSET (16U) +#define XSPI_QSPI_PRV_BMCFG_PREEN_VALUE_MASK (0x01U) + +#define XSPI_QSPI_PRV_BMCTL_DEFAULT_VALUE (0x000000FFUL) + +#define XSPI_QSPI_PRV_BMCTL_CSNACC_R_ENABLE (0x01U) +#define XSPI_QSPI_PRV_BMCTL_CSNACC_R_W_ENABLE (0x03U) + +#define XSPI_QSPI_PRV_CDTBUF_CMDSIZE_OFFSET (0U) +#define XSPI_QSPI_PRV_CDTBUF_CMDSIZE_VALUE_MASK (0x03U) +#define XSPI_QSPI_PRV_CDTBUF_ADDSIZE_OFFSET (2U) +#define XSPI_QSPI_PRV_CDTBUF_ADDSIZE_VALUE_MASK (0x07U) +#define XSPI_QSPI_PRV_CDTBUF_DATASIZE_OFFSET (5U) +#define XSPI_QSPI_PRV_CDTBUF_DATASIZE_VALUE_MASK (0x0FU) +#define XSPI_QSPI_PRV_CDTBUF_LATE_OFFSET (9U) +#define XSPI_QSPI_PRV_CDTBUF_LATE_VALUE_MASK (0x1FU) +#define XSPI_QSPI_PRV_CDTBUF_TRTYPE_OFFSET (15U) +#define XSPI_QSPI_PRV_CDTBUF_TRTYPE_VALUE_MASK (0x01U) +#define XSPI_QSPI_PRV_CDTBUF_CMD_UPPER_OFFSET (24U) +#define XSPI_QSPI_PRV_CDTBUF_CMD_VALUE_MASK (0xFFU) + +#define XSPI_QSPI_PRV_COMSTT_MEMACC_OFFSET (0U) +#define XSPI_QSPI_PRV_COMSTT_MEMACC_VALUE_MASK (0x01U) +#define XSPI_QSPI_PRV_COMSTT_WRBUFNE_OFFSET (6U) +#define XSPI_QSPI_PRV_COMSTT_WRBUFNE_VALUE_MASK (0x01U) + +#define XSPI_QSPI_PRV_INTC_CMDCMPC_OFFSET (0U) + +#define XSPI_QSPI_PRV_DEVICE_WRITE_STATUS_BIT_MASK (1U) + +#define XSPI_QSPI_PRV_MAX_COMBINE_SIZE (64U) +#define XSPI_QSPI_PRV_UINT32_BITS (32U) + +#define XSPI_QSPI_PRV_WORD_ACCESS_SIZE (4U) +#define XSPI_QSPI_PRV_HALF_WORD_ACCESS_SIZE (2U) + +#define XSPI_QSPI_PRV_1MB_MEMORY_SPACE (0xFFFFFU) +#define XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT (20U) +#define XSPI_QSPI_PRV_DIRECT_TRANSFER_MAX_BYTES (8U) + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/* Number of address bytes in 4 byte address mode. */ +#define QSPI_4_BYTE_ADDRESS (4U) + +/*********************************************************************************************************************** + * Private function prototypes + **********************************************************************************************************************/ +static void r_xspi_qspi_write_enable(xspi_qspi_instance_ctrl_t * p_instance_ctrl); +static bool r_xspi_qspi_status_sub(xspi_qspi_instance_ctrl_t * p_instance_ctrl); +static fsp_err_t r_xspi_qspi_xip(xspi_qspi_instance_ctrl_t * p_instance_ctrl, uint8_t code, bool enter_mode); +static void r_xspi_qspi_direct_transfer(xspi_qspi_instance_ctrl_t * p_instance_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction); + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE +static fsp_err_t r_xspi_qspi_param_checking_dcom(xspi_qspi_instance_ctrl_t * p_instance_ctrl); +static fsp_err_t r_xspi_qspi_program_param_check(xspi_qspi_instance_ctrl_t * p_instance_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count); + +#endif + +/*********************************************************************************************************************** + * Private global variables + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * @addtogroup XSPI_QSPI + * @{ + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Global Variables + **********************************************************************************************************************/ + +const spi_flash_api_t g_spi_flash_on_xspi_qspi = +{ + .open = R_XSPI_QSPI_Open, + .directWrite = R_XSPI_QSPI_DirectWrite, + .directRead = R_XSPI_QSPI_DirectRead, + .directTransfer = R_XSPI_QSPI_DirectTransfer, + .spiProtocolSet = R_XSPI_QSPI_SpiProtocolSet, + .write = R_XSPI_QSPI_Write, + .erase = R_XSPI_QSPI_Erase, + .statusGet = R_XSPI_QSPI_StatusGet, + .xipEnter = R_XSPI_QSPI_XipEnter, + .xipExit = R_XSPI_QSPI_XipExit, + .bankSet = R_XSPI_QSPI_BankSet, + .autoCalibrate = R_XSPI_QSPI_AutoCalibrate, + .close = R_XSPI_QSPI_Close, +}; + +/*********************************************************************************************************************** + * Functions + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Open the QSPI driver module. After the driver is open, the QSPI can be accessed like internal flash memory starting + * at address 0x60000000 or 0x40000000. + * + * Implements @ref spi_flash_api_t::open. + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_ASSERTION The parameter p_instance_ctrl or p_cfg is NULL. + * @retval FSP_ERR_ALREADY_OPEN Driver has already been opened with the same p_instance_ctrl. + * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT The requested channel does not exist on this MCU. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Open (spi_flash_ctrl_t * p_ctrl, spi_flash_cfg_t const * const p_cfg) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ASSERT(NULL != p_cfg); + FSP_ASSERT(NULL != p_cfg->p_extend); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN != p_instance_ctrl->open, FSP_ERR_ALREADY_OPEN); + + /* Make sure this unit exists. */ + FSP_ERROR_RETURN(BSP_FEATURE_XSPI_CHANNELS & (1U << ((xspi_qspi_extended_cfg_t *) p_cfg->p_extend)->unit), + FSP_ERR_IP_CHANNEL_NOT_PRESENT); +#endif + + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + + /* Enable clock to the QSPI block */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + R_BSP_MODULE_START(FSP_IP_XSPI, p_cfg_extend->unit); + if (0U == p_cfg_extend->unit) + { + R_BSP_ModuleResetDisable(BSP_MODULE_RESET_XSPI0); + } + else + { + R_BSP_ModuleResetDisable(BSP_MODULE_RESET_XSPI1); + } + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SYSTEM); + +#if BSP_FEATURE_BSP_SLAVE_STOP_SUPPORTED + + /* Release from slave stop. */ + if (0U == p_cfg_extend->unit) + { + R_BSP_SlaveStopRelease(BSP_BUS_SLAVE_XSPI0); + } + else + { + R_BSP_SlaveStopRelease(BSP_BUS_SLAVE_XSPI1); + } +#endif + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SYSTEM); + uintptr_t base_address = (uintptr_t) R_XSPI0 + (p_cfg_extend->unit * ((uintptr_t) R_XSPI1 - (uintptr_t) R_XSPI0)); + p_instance_ctrl->p_reg = (R_XSPI0_Type *) base_address; + + /* Initialize control block. */ + p_instance_ctrl->p_cfg = p_cfg; + + /* xSPI configuration (see RZ microprocessor User's Manual section "Flow of Configuration"). */ + p_instance_ctrl->p_reg->LIOCFGCS[p_cfg_extend->chip_select] = (p_cfg->spi_protocol) << + XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET; + p_instance_ctrl->spi_protocol = p_cfg->spi_protocol; + + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SYSTEM); + + /* Set xSPI IO voltage */ +#if BSP_FEATURE_XSPI_VOLTAGE_SETTING_SUPPORTED + if (0 == p_cfg_extend->unit) + { + R_XSPI0_MISC->IOVOLCTL = p_cfg_extend->io_voltage; + } + else + { + R_XSPI1_MISC->IOVOLCTL = p_cfg_extend->io_voltage; + } +#endif + + /* Set xSPI CSn address space. */ +#if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + uint32_t mirror_address_delta; + #if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0; + #else + mirror_address_delta = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; + #endif + R_XSPI0_MISC->CS0ENDAD = p_cfg_extend->p_address_space->unit0_cs0_end_address - mirror_address_delta; + R_XSPI0_MISC->CS1STRAD = p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta; + R_XSPI0_MISC->CS1ENDAD = p_cfg_extend->p_address_space->unit0_cs1_end_address - mirror_address_delta; + R_XSPI1_MISC->CS0ENDAD = p_cfg_extend->p_address_space->unit1_cs0_end_address - mirror_address_delta; + R_XSPI1_MISC->CS1STRAD = p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta; + R_XSPI1_MISC->CS1ENDAD = p_cfg_extend->p_address_space->unit1_cs1_end_address - mirror_address_delta; +#else + #if 1 == BSP_FEATURE_XSPI_CS_ADDRESS_SPACE_SETTING_TYPE + + /* Set xSPI CSn slave memory size. */ + if (XSPI_QSPI_CHIP_SELECT_0 == p_cfg_extend->chip_select) + { + p_instance_ctrl->p_reg->CSSCTL_b.CS0SIZE = p_cfg_extend->memory_size; + } + else + { + p_instance_ctrl->p_reg->CSSCTL_b.CS1SIZE = p_cfg_extend->memory_size; + } + + #elif 2 == BSP_FEATURE_XSPI_CS_ADDRESS_SPACE_SETTING_TYPE + uint32_t mirror_address_delta; + #if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0U; + #else + mirror_address_delta = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; + #endif + + if (XSPI_QSPI_CHIP_SELECT_0 == p_cfg_extend->chip_select) + { + if (0 == p_cfg_extend->unit) + { + R_XSPI0_MISC->CS0ENDAD = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + else + { + R_XSPI1_MISC->CS0ENDAD = BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + } + else + { + if (0 == p_cfg_extend->unit) + { + R_XSPI0_MISC->CS1STRAD = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta; + + R_XSPI0_MISC->CS1ENDAD = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + else + { + R_XSPI1_MISC->CS1STRAD = BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta; + + R_XSPI1_MISC->CS1ENDAD = BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + } + #endif +#endif + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SYSTEM); + + p_instance_ctrl->p_reg->LIOCFGCS[p_cfg_extend->chip_select] = + ((p_cfg->spi_protocol & XSPI_QSPI_PRV_LIOCFGCS_PRTMD_VALUE_MASK) << XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET) | + ((p_cfg_extend->p_timing_settings->command_to_command_interval & + XSPI_QSPI_PRV_LIOCFGCS_CSMIN_VALUE_MASK) << XSPI_QSPI_PRV_LIOCFGCS_CSMIN_OFFSET) | + ((p_cfg_extend->p_timing_settings->cs_pulldown_lead & XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_VALUE_MASK) << + XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_OFFSET) | + ((p_cfg_extend->p_timing_settings->cs_pullup_lag & XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_VALUE_MASK) << + XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_OFFSET); + + /* Specifies the read/write commands and Read dummy clocks for Device + * (see RZ microprocessor User's Manual section "Flow of Memory-mapping"). */ + p_instance_ctrl->p_reg->CSa[p_cfg_extend->chip_select].CMCFG0 = + (0U << XSPI_QSPI_PRV_CMCFG0_FFMT_OFFSET) | + ((p_cfg->address_bytes & XSPI_QSPI_PRV_CMCFG0_ADDSIZE_VALUE_MASK) << XSPI_QSPI_PRV_CMCFG0_ADDSIZE_OFFSET); + + p_instance_ctrl->p_reg->CSa[p_cfg_extend->chip_select].CMCFG1 = + ((p_cfg->read_command & XSPI_QSPI_PRV_CMCFG1_RDCMD_VALUE_MASK) << XSPI_QSPI_PRV_CMCFG1_RDCMD_UPPER_OFFSET) | + ((p_cfg->dummy_clocks & XSPI_QSPI_PRV_CMCFG1_RDLATE_VALUE_MASK) << XSPI_QSPI_PRV_CMCFG1_RDLATE_OFFSET); + + p_instance_ctrl->p_reg->CSa[p_cfg_extend->chip_select].CMCFG2 = + ((p_cfg->page_program_command & XSPI_QSPI_PRV_CMCFG1_WRCMD_VALUE_MASK) << + XSPI_QSPI_PRV_CMCFG2_WRCMD_UPPER_OFFSET) | + (0U << XSPI_QSPI_PRV_CMCFG2_WRLATE_OFFSET); + + p_instance_ctrl->p_reg->BMCTL0 = XSPI_QSPI_PRV_BMCTL_DEFAULT_VALUE; + + /* Return response after issuing write transaction to xSPI bus, Enable prefetch function. */ + p_instance_ctrl->p_reg->BMCFG = (0 << XSPI_QSPI_PRV_BMCFG_WRMD_OFFSET) | + (1 << XSPI_QSPI_PRV_BMCFG_MWRCOMB_OFFSET) | + (0x0F << XSPI_QSPI_PRV_BMCFG_MWRSIZE_OFFSET) | + ((p_cfg_extend->prefetch_en & XSPI_QSPI_PRV_BMCFG_PREEN_VALUE_MASK) << + XSPI_QSPI_PRV_BMCFG_PREEN_OFFSET); + + /* Set use Channel. */ + p_instance_ctrl->p_reg->CDCTL0_b.CSSEL = p_cfg_extend->chip_select; + + /* The memory size is read from the device if needed. */ + p_instance_ctrl->total_size_bytes = 0U; + + p_instance_ctrl->open = XSPI_QSPI_PRV_OPEN; + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Writes raw data directly to the QSPI. + * + * Implements @ref spi_flash_api_t::directWrite. + * + * @retval FSP_ERR_UNSUPPORTED API not supported. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_DirectWrite (spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint32_t const bytes, + bool const read_after_write) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + FSP_PARAMETER_NOT_USED(p_src); + FSP_PARAMETER_NOT_USED(bytes); + FSP_PARAMETER_NOT_USED(read_after_write); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Reads raw data directly from the QSPI. + * + * Implements @ref spi_flash_api_t::directRead. + * + * @retval FSP_ERR_UNSUPPORTED API not supported. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_DirectRead (spi_flash_ctrl_t * p_ctrl, uint8_t * const p_dest, uint32_t const bytes) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + FSP_PARAMETER_NOT_USED(p_dest); + FSP_PARAMETER_NOT_USED(bytes); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Read/Write raw data directly with the SerialFlash. + * + * Implements @ref spi_flash_api_t::directTransfer. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function must be called after R_XSPI_QSPI_DirectWrite with read_after_write set + * to true. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_DirectTransfer (spi_flash_ctrl_t * p_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + fsp_err_t err = r_xspi_qspi_param_checking_dcom(p_instance_ctrl); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ASSERT(NULL != p_transfer); + FSP_ASSERT(0 != p_transfer->command_length); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + r_xspi_qspi_direct_transfer(p_instance_ctrl, p_transfer, direction); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Enters XIP (execute in place) mode. + * @note If the xSPI address space is cache-enabled, cache should be invalidated before executing XipEnter. Otherwise, it is not guaranteed that the slave device will be in XiP mode immediately after XipEnter is executed. + * + * Implements @ref spi_flash_api_t::xipEnter. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_XipEnter (spi_flash_ctrl_t * p_ctrl) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + fsp_err_t err; + + err = r_xspi_qspi_xip(p_instance_ctrl, p_instance_ctrl->p_cfg->xip_enter_command, true); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Exits XIP (execute in place) mode. + * @note If the xSPI address space is cache-enabled, cache should be invalidated before executing XipExit. Otherwise, it is not guaranteed that the slave device will exit XiP mode immediately after XipEnter is executed. + * + * Implements @ref spi_flash_api_t::xipExit. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_XipExit (spi_flash_ctrl_t * p_ctrl) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + fsp_err_t err; + + err = r_xspi_qspi_xip(p_instance_ctrl, p_instance_ctrl->p_cfg->xip_exit_command, false); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Program a page of data to the flash. + * + * Implements @ref spi_flash_api_t::write. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION p_instance_ctrl, p_dest or p_src is NULL, or byte_count crosses a page boundary. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + * + * @note In this API, the number of bytes that can be written at one time depends on the MCU : + * any byte within 64bytes for RZ/N2L, 8bytes for RZ/N2H. + * @note This API performs page program operations to the device. Writing across pages is not supported. + * Please set the write address and write size according to the page size of your device. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Write (spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + fsp_err_t err = r_xspi_qspi_program_param_check(p_instance_ctrl, p_src, p_dest, byte_count); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); +#endif + FSP_ERROR_RETURN(false == r_xspi_qspi_status_sub(p_instance_ctrl), FSP_ERR_DEVICE_BUSY); + + r_xspi_qspi_write_enable(p_instance_ctrl); +#if BSP_FEATURE_XSPI_HAS_AXI_BRIDGE + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + uint32_t chip_address; + uint32_t chip_select = p_cfg_extend->chip_select; + uint32_t unit = p_cfg_extend->unit; + uint32_t mirror_address_delta; + + #ifdef BSP_CFG_CORE_CA55 + uintptr_t p_dest_va = (uintptr_t) p_dest; + uintptr_t p_dest_pa = 0U; + + R_BSP_MmuVatoPa(p_dest_va, &p_dest_pa); + #else + uintptr_t p_dest_pa = (uintptr_t) p_dest; + #endif + + /* Get device start address. */ + #if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0U; + #else + mirror_address_delta = ((uintptr_t) p_dest < BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS) ? + 0U : + BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; + #endif + + chip_address = (0 == chip_select) ? + (0 == unit) ? + (uint32_t) p_dest_pa - (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta) : // unit0 cs0 + (uint32_t) p_dest_pa - (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta) : // unit1 cs0 + (0 == unit) + #if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + ? (uint32_t) p_dest_pa - + (p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta) : // unit0 cs1 + (uint32_t) p_dest_pa - + (p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta); // unit1 cs1 + #else + ? (uint32_t) p_dest_pa - + (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta) : // unit0 cs1 + (uint32_t) p_dest_pa - + (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta); // unit1 cs1 + #endif + + spi_flash_direct_transfer_t write_transfer; + write_transfer.data_u64 = *(uint64_t *) p_src; + write_transfer.data_length = (uint8_t) byte_count; + write_transfer.address = chip_address; + write_transfer.address_length = (p_instance_ctrl->p_cfg->address_bytes == SPI_FLASH_ADDRESS_BYTES_4) ? 4U : 3U; + write_transfer.dummy_cycles = 0; + + write_transfer.command = p_instance_ctrl->p_cfg->page_program_command; + write_transfer.command_length = 1U; + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &write_transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); +#else + uint32_t i = 0; + + FSP_CRITICAL_SECTION_DEFINE; + FSP_CRITICAL_SECTION_ENTER; + + /* Word access */ + if (0 == byte_count % XSPI_QSPI_PRV_WORD_ACCESS_SIZE) + { + uint32_t * p_word_aligned_dest = (uint32_t *) p_dest; + uint32_t * p_word_aligned_src = (uint32_t *) p_src; + for (i = 0; i < byte_count / XSPI_QSPI_PRV_WORD_ACCESS_SIZE; i++) + { + *p_word_aligned_dest = *p_word_aligned_src; + p_word_aligned_dest++; + p_word_aligned_src++; + } + } + /* Half Word access */ + else if (0 == byte_count % XSPI_QSPI_PRV_HALF_WORD_ACCESS_SIZE) + { + uint16_t * p_half_word_aligned_dest = (uint16_t *) p_dest; + uint16_t * p_half_word_aligned_src = (uint16_t *) p_src; + for (i = 0; i < byte_count / XSPI_QSPI_PRV_HALF_WORD_ACCESS_SIZE; i++) + { + *p_half_word_aligned_dest = *p_half_word_aligned_src; + p_half_word_aligned_dest++; + p_half_word_aligned_src++; + } + } + /* Byte access */ + else + { + for (i = 0; i < byte_count; i++) + { + p_dest[i] = p_src[i]; + } + } + + /* Ensure that all write data is in the xSPI write buffer. */ + __DSB(); + + /* Request to push the pending data */ + if (XSPI_QSPI_PRV_MAX_COMBINE_SIZE > byte_count) + { + /* Push the pending data. */ + p_instance_ctrl->p_reg->BMCTL1_b.MWRPUSH = 1; + } + + /* Wait until memory access starts in write API. */ + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->COMSTT_b.MEMACC, 1); + + FSP_CRITICAL_SECTION_EXIT; +#endif + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Erase a block or sector of flash. The byte_count must exactly match one of the erase sizes defined in spi_flash_cfg_t. + * For chip erase, byte_count must be SPI_FLASH_ERASE_SIZE_CHIP_ERASE. + * + * Implements @ref spi_flash_api_t::erase. + * + * @retval FSP_SUCCESS The command to erase the flash was executed successfully. + * @retval FSP_ERR_ASSERTION p_instance_ctrl or p_device_address is NULL, or byte_count doesn't match an erase + * size defined in spi_flash_cfg_t, or device is in XIP mode. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Erase (spi_flash_ctrl_t * p_ctrl, uint8_t * const p_device_address, uint32_t byte_count) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + fsp_err_t err = r_xspi_qspi_param_checking_dcom(p_instance_ctrl); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + FSP_ASSERT(NULL != p_device_address); +#endif + xspi_qspi_extended_cfg_t * p_cfg_extend = + (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + + uint8_t unit = p_cfg_extend->unit; + uint8_t chip_select = p_cfg_extend->chip_select; + + uint16_t erase_command = 0; + uintptr_t chip_address; + bool send_address = true; + uint32_t mirror_address_delta; + +#ifdef BSP_CFG_CORE_CA55 + uintptr_t p_device_address_va = (uintptr_t) p_device_address; + uintptr_t p_device_address_pa = 0U; + + R_BSP_MmuVatoPa(p_device_address_va, &p_device_address_pa); +#else + uintptr_t p_device_address_pa = (uintptr_t) p_device_address; +#endif + + /* Get device start address. */ +#if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0U; +#else + mirror_address_delta = (p_device_address_pa < BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS) ? + 0U : + BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; +#endif + + chip_address = (0 == chip_select) ? + (0 == unit) ? + p_device_address_pa - (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta) : // unit0 cs0 + p_device_address_pa - (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta) : // unit1 cs0 + (0 == unit) +#if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + ? p_device_address_pa - + (p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta) : // unit0 cs1 + p_device_address_pa - + (p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta); // unit1 cs1 +#else + ? p_device_address_pa - + (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta) : // unit0 cs1 + p_device_address_pa - + (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta); // unit1 cs1 +#endif + + for (uint32_t index = 0; index < p_instance_ctrl->p_cfg->erase_command_list_length; index++) + { + /* If requested byte_count is supported by underlying flash, store the command. */ + if (byte_count == p_instance_ctrl->p_cfg->p_erase_command_list[index].size) + { + if (SPI_FLASH_ERASE_SIZE_CHIP_ERASE == byte_count) + { + /* Don't send address for chip erase. */ + send_address = false; + } + + erase_command = p_instance_ctrl->p_cfg->p_erase_command_list[index].command; + break; + } + } + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(0U != erase_command); +#endif + + r_xspi_qspi_write_enable(p_instance_ctrl); + + spi_flash_direct_transfer_t direct_command = {0}; + direct_command.command = erase_command; + direct_command.address = (uint32_t) chip_address; + direct_command.address_length = (true == send_address) ? + (((p_instance_ctrl->p_cfg->address_bytes) + 1U)) & + XSPI_QSPI_PRV_CDTBUF_ADDSIZE_VALUE_MASK : 0U; + direct_command.command_length = 1U; + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &direct_command, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Gets the write or erase status of the flash. + * + * Implements @ref spi_flash_api_t::statusGet. + * + * @retval FSP_SUCCESS The write status is in p_status. + * @retval FSP_ERR_ASSERTION p_instance_ctrl or p_status is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_StatusGet (spi_flash_ctrl_t * p_ctrl, spi_flash_status_t * const p_status) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ASSERT(NULL != p_status); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); + FSP_ERROR_RETURN(0U == p_instance_ctrl->p_reg->CMCTL_b.XIPEN, FSP_ERR_INVALID_MODE); +#endif + + uint32_t comstt = p_instance_ctrl->p_reg->COMSTT; + bool memacc = (bool) ((comstt >> XSPI_QSPI_PRV_COMSTT_MEMACC_OFFSET) & XSPI_QSPI_PRV_COMSTT_MEMACC_VALUE_MASK); + bool wrbufne = + (bool) ((comstt >> XSPI_QSPI_PRV_COMSTT_WRBUFNE_OFFSET) & XSPI_QSPI_PRV_COMSTT_WRBUFNE_VALUE_MASK); + + if ((true == memacc) || (true == wrbufne)) + { + /* If the xSPI is accessing memory or data is in the write buffer, + * it is judged a "write in progress" without access to QSPI. */ + p_status->write_in_progress = (bool) (wrbufne | memacc); + } + else + { + /* Read device status. */ + p_status->write_in_progress = r_xspi_qspi_status_sub(p_instance_ctrl); + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Selects the bank to access. + * + * Implements @ref spi_flash_api_t::bankSet. + * + * @retval FSP_ERR_UNSUPPORTED API not supported. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_BankSet (spi_flash_ctrl_t * p_ctrl, uint32_t bank) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + FSP_PARAMETER_NOT_USED(bank); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Sets the SPI protocol. + * + * Implements @ref spi_flash_api_t::spiProtocolSet. + * + * @retval FSP_SUCCESS SPI protocol updated on MCU peripheral. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_ARGUMENT Invalid SPI protocol requested. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_SpiProtocolSet (spi_flash_ctrl_t * p_ctrl, spi_flash_protocol_t spi_protocol) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); + + /* Not allow the following arguremnts with this IP. */ + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_QPI != spi_protocol, FSP_ERR_INVALID_ARGUMENT); + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_SOPI != spi_protocol, FSP_ERR_INVALID_ARGUMENT); + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_DOPI != spi_protocol, FSP_ERR_INVALID_ARGUMENT); + + /* Not allow the following arguremnts with QSPI HAL Driver. */ + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_8D_8D_8D != spi_protocol, FSP_ERR_INVALID_ARGUMENT); +#else + FSP_PARAMETER_NOT_USED(p_instance_ctrl); +#endif + + spi_flash_cfg_t * p_cfg = (spi_flash_cfg_t *) p_instance_ctrl->p_cfg; + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + + p_instance_ctrl->spi_protocol = spi_protocol; + + /* Update the SPI protocol. */ + p_instance_ctrl->p_reg->LIOCFGCS_b[p_cfg_extend->chip_select].PRTMD = spi_protocol & + XSPI_QSPI_PRV_LIOCFGCS_PRTMD_MASK; + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Auto-calibrate the OctaRAM device using the preamble pattern. Unsupported by XSPI_QSPI. + * Implements @ref spi_flash_api_t::autoCalibrate. + * + * @retval FSP_ERR_UNSUPPORTED API not supported by XSPI_QSPI + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_AutoCalibrate (spi_flash_ctrl_t * p_ctrl) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Close the QSPI driver module. + * + * Implements @ref spi_flash_api_t::close. + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_ASSERTION p_instance_ctrl is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Close (spi_flash_ctrl_t * p_ctrl) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + spi_flash_cfg_t * p_cfg = (spi_flash_cfg_t *) p_instance_ctrl->p_cfg; + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + + p_instance_ctrl->open = 0U; + + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SYSTEM); +#if BSP_FEATURE_BSP_SLAVE_STOP_SUPPORTED + + /* Slave stop request */ + if (0U == p_cfg_extend->unit) + { + R_BSP_SlaveStop(BSP_BUS_SLAVE_XSPI0); + } + else + { + R_BSP_SlaveStop(BSP_BUS_SLAVE_XSPI1); + } +#endif + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SYSTEM); + + /* Disable clock to the QSPI block */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + /* Enable reset */ + if (0U == p_cfg_extend->unit) + { + R_BSP_ModuleResetEnable(BSP_MODULE_RESET_XSPI0); + } + else + { + R_BSP_ModuleResetEnable(BSP_MODULE_RESET_XSPI1); + } + + R_BSP_MODULE_STOP(FSP_IP_XSPI, p_cfg_extend->unit); + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * @} (end addtogroup XSPI_QSPI) + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Send Write enable command to the SerialFlash + * + * @param[in] p_instance_ctrl Pointer to QSPI specific control structure + **********************************************************************************************************************/ +static void r_xspi_qspi_write_enable (xspi_qspi_instance_ctrl_t * p_instance_ctrl) +{ + spi_flash_direct_transfer_t direct_command = {0}; + spi_flash_cfg_t const * p_cfg = p_instance_ctrl->p_cfg; + + direct_command.command = p_cfg->write_enable_command; + direct_command.command_length = 1U; + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &direct_command, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); +} + +/*******************************************************************************************************************//** + * Enters or exits XIP (execute in place) mode. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * @param[in] code Code to place in M7-M0 + * @param[in] enter_mode True to enter, false to exit + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_xip (xspi_qspi_instance_ctrl_t * p_instance_ctrl, uint8_t code, bool enter_mode) +{ +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + + /* FSP_ASSERT(NULL != p_instance_ctrl) is optimized out when it shouldn't be. It appears to be affected by GCC bug + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90949. */ + xspi_qspi_instance_ctrl_t * volatile p_volatile_ctrl = p_instance_ctrl; + FSP_ASSERT(NULL != p_volatile_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + xspi_qspi_extended_cfg_t * p_cfg_extend = + (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + + uint8_t unit = p_cfg_extend->unit; + uint8_t chip_select = p_cfg_extend->chip_select; + + volatile uint8_t dummy = 0; + FSP_PARAMETER_NOT_USED(dummy); + + /* XiP configuration (see RZ microprocessor User's Manual section "Flow of XiP"). */ + if (true == enter_mode) + { + if (XSPI_QSPI_CHIP_SELECT_0 == chip_select) + { + p_instance_ctrl->p_reg->BMCTL0_b.CS0ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_ENABLE; + } + else + { + p_instance_ctrl->p_reg->BMCTL0_b.CS1ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_ENABLE; + } + } + + p_instance_ctrl->p_reg->CMCTL_b.XIPENCODE = code; + p_instance_ctrl->p_reg->CMCTL_b.XIPEXCODE = code; + p_instance_ctrl->p_reg->CMCTL_b.XIPEN = enter_mode; + + /* Read from QSPI to send the XIP entry request. + * Read via a cache-invalid mirror area to ensure access to QSPI. */ + + uint32_t mirror_address_delta; +#if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0; +#else + mirror_address_delta = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; +#endif + + uintptr_t dummy_address = (0 == chip_select) ? + (0 == unit) ? + BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta : // unit0 cs0 + BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta : // unit1 cs0 + (0 == unit) +#if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + ? p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta : // unit0 cs1 + p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta; // unit1 cs1 +#else + ? BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / + 2 - mirror_address_delta : // unit0 cs1 + BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta; // unit1 cs1 +#endif + +#ifdef BSP_CFG_CORE_CA55 + uintptr_t dummy_address_va = 0U; + R_BSP_MmuPatoVa(dummy_address, &dummy_address_va, BSP_MMU_CONVERSION_NON_CACHE); + if (0U == dummy_address_va) + { + R_BSP_MmuPatoVa(dummy_address, &dummy_address_va, BSP_MMU_CONVERSION_CACHE); + } + dummy_address = dummy_address_va; +#endif + + dummy = *(uint8_t *) dummy_address; + + if (false == enter_mode) + { + if (XSPI_QSPI_CHIP_SELECT_0 == chip_select) + { + p_instance_ctrl->p_reg->BMCTL0_b.CS0ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_W_ENABLE; + } + else + { + p_instance_ctrl->p_reg->BMCTL0_b.CS1ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_W_ENABLE; + } + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Gets device status. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * + * @return True if busy, false if not. + **********************************************************************************************************************/ +static bool r_xspi_qspi_status_sub (xspi_qspi_instance_ctrl_t * p_instance_ctrl) +{ + spi_flash_cfg_t const * p_cfg = p_instance_ctrl->p_cfg; + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + + spi_flash_direct_transfer_t direct_command = {0}; + + bool restore_spi_protocol = false; + spi_flash_protocol_t setting_protocol = (spi_flash_protocol_t) 0x00; + + direct_command.command = p_cfg->status_command; + direct_command.command_length = 1U; + direct_command.data_length = 1U; + + /* For most devices, the Read Status Register instruction is executed with the 1S-1S-1S instruction, + * even if it assumes 1S-2S-2S or 1S-4S-4S Write instruction. + * Therefore, the communication protocol is temporarily switched. */ + if ((SPI_FLASH_PROTOCOL_1S_4S_4S == p_instance_ctrl->spi_protocol) || + (SPI_FLASH_PROTOCOL_1S_2S_2S == p_instance_ctrl->spi_protocol)) + { + setting_protocol = p_instance_ctrl->spi_protocol; + p_instance_ctrl->p_reg->LIOCFGCS_b[p_cfg_extend->chip_select].PRTMD = SPI_FLASH_PROTOCOL_1S_1S_1S; + p_instance_ctrl->spi_protocol = SPI_FLASH_PROTOCOL_1S_1S_1S; + restore_spi_protocol = true; + } + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &direct_command, SPI_FLASH_DIRECT_TRANSFER_DIR_READ); + + /* Restore communication protocol. */ + if (true == restore_spi_protocol) + { + p_instance_ctrl->p_reg->LIOCFGCS_b[p_cfg_extend->chip_select].PRTMD = setting_protocol; + p_instance_ctrl->spi_protocol = setting_protocol; + } + + return (bool) ((direct_command.data >> p_instance_ctrl->p_cfg->write_status_bit) & + XSPI_QSPI_PRV_DEVICE_WRITE_STATUS_BIT_MASK); +} + +/*******************************************************************************************************************//** + * Performs direct data transfer with the SerialFlash + * + * @param[in] p_instance_ctrl Pointer to QSPI specific control structure + * @param[in] p_transfer Pointer to transfer parameters + * @param[in] direction Read/Write + **********************************************************************************************************************/ +static void r_xspi_qspi_direct_transfer (xspi_qspi_instance_ctrl_t * p_instance_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction) +{ + p_instance_ctrl->p_reg->CDCTL0_b.TRNUM = 0; + + /* Direct Read/Write settings + * (see RZ microprocessor User's Manual section "Flow of Manual-command Procedure"). */ + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->CDCTL0_b.TRREQ, 0); + + p_instance_ctrl->p_reg->BUF[0].CDT = + ((p_transfer->command_length & XSPI_QSPI_PRV_CDTBUF_CMDSIZE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_CMDSIZE_OFFSET) | + ((p_transfer->address_length & XSPI_QSPI_PRV_CDTBUF_ADDSIZE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_ADDSIZE_OFFSET) | + ((p_transfer->data_length & XSPI_QSPI_PRV_CDTBUF_DATASIZE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_DATASIZE_OFFSET) | + ((p_transfer->dummy_cycles & XSPI_QSPI_PRV_CDTBUF_LATE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_LATE_OFFSET) | + ((direction & XSPI_QSPI_PRV_CDTBUF_TRTYPE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_TRTYPE_OFFSET) | + ((p_transfer->command & XSPI_QSPI_PRV_CDTBUF_CMD_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_CMD_UPPER_OFFSET); + + p_instance_ctrl->p_reg->BUF[0].CDA = p_transfer->address; + + if (SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE == direction) + { + p_instance_ctrl->p_reg->BUF[0].CDD0 = (uint32_t) p_transfer->data_u64 & UINT32_MAX; + if (p_transfer->data_length > sizeof(uint32_t)) + { + p_instance_ctrl->p_reg->BUF[0].CDD1 = (uint32_t) (p_transfer->data_u64 >> XSPI_QSPI_PRV_UINT32_BITS) & + UINT32_MAX; + } + } + + p_instance_ctrl->p_reg->CDCTL0_b.TRREQ = 1; + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->INTS_b.CMDCMP, 1); + + if (SPI_FLASH_DIRECT_TRANSFER_DIR_READ == direction) + { + p_transfer->data_u64 = p_instance_ctrl->p_reg->BUF[0].CDD0; + if (p_transfer->data_length > sizeof(uint32_t)) + { + p_transfer->data_u64 |= (uint64_t) (p_instance_ctrl->p_reg->BUF[0].CDD1) << XSPI_QSPI_PRV_UINT32_BITS; + } + } + + p_instance_ctrl->p_reg->INTC = 1 << XSPI_QSPI_PRV_INTC_CMDCMPC_OFFSET; +} + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + +/*******************************************************************************************************************//** + * Parameter checking. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * + * @retval FSP_SUCCESS Device size stored in p_device_size_bytes + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_param_checking_dcom (xspi_qspi_instance_ctrl_t * p_instance_ctrl) +{ + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); + + FSP_ERROR_RETURN(0U == p_instance_ctrl->p_reg->CMCTL_b.XIPEN, FSP_ERR_INVALID_MODE); + + /* Verify device is not busy. */ + FSP_ERROR_RETURN(!r_xspi_qspi_status_sub(p_instance_ctrl), FSP_ERR_DEVICE_BUSY); + + return FSP_SUCCESS; +} + +#endif + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + +/*******************************************************************************************************************//** + * Parameter checking for R_XSPI_QSPI_Write. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * @param[in] p_src The source of the data to write to QSPI + * @param[in] p_dest The address in QSPI to write to + * @param[in] byte_count The number of bytes to write + * + * @retval FSP_SUCCESS Parameters are valid. + * @retval FSP_ERR_ASSERTION p_instance_ctrl,p_device_address or p_memory_address is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_program_param_check (xspi_qspi_instance_ctrl_t * p_instance_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count) +{ + fsp_err_t err = r_xspi_qspi_param_checking_dcom(p_instance_ctrl); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + FSP_ASSERT(NULL != p_src); + FSP_ASSERT(NULL != p_dest); + + /* Check if byte_count is valid */ + uintptr_t page_size_bytes = p_instance_ctrl->p_cfg->page_size_bytes; + uintptr_t bytes_left_in_page = page_size_bytes - ((uintptr_t) p_dest % page_size_bytes); + FSP_ASSERT(byte_count <= bytes_left_in_page); + + #if BSP_FEATURE_XSPI_HAS_AXI_BRIDGE + FSP_ASSERT(XSPI_QSPI_PRV_DIRECT_TRANSFER_MAX_BYTES >= byte_count); + #else + FSP_ASSERT(XSPI_QSPI_PRV_MAX_COMBINE_SIZE >= byte_count); + #endif + + return FSP_SUCCESS; +} + +#endif diff --git a/drivers/rz/fsp/src/rzt/CMakeLists.txt b/drivers/rz/fsp/src/rzt/CMakeLists.txt index 6b4f387c..baa593d0 100644 --- a/drivers/rz/fsp/src/rzt/CMakeLists.txt +++ b/drivers/rz/fsp/src/rzt/CMakeLists.txt @@ -10,6 +10,7 @@ set(srcs bsp/mcu/all/bsp_io.c bsp/mcu/all/bsp_irq.c bsp/mcu/all/bsp_register_protection.c + bsp/mcu/all/bsp_reset.c bsp/mcu/all/cr/bsp_delay_core.c ) diff --git a/drivers/rz/fsp/src/rzt/bsp/mcu/all/bsp_reset.c b/drivers/rz/fsp/src/rzt/bsp/mcu/all/bsp_reset.c new file mode 100644 index 00000000..69e2e95b --- /dev/null +++ b/drivers/rz/fsp/src/rzt/bsp/mcu/all/bsp_reset.c @@ -0,0 +1,371 @@ +/* +* Copyright (c) 2020 - 2025 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +/*********************************************************************************************************************** + * Includes , "Project Includes" + **********************************************************************************************************************/ +#include "bsp_api.h" + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ +#define BSP_RESET_MRCTL_BIT_SHIFT_MASK (0x0000001FU) +#define BSP_RESET_MRCTL_SELECT_MASK (0x001F0000U) +#define BSP_RESET_MRCTL_REGION_SELECT_MASK (0x00400000U) + +#define BSP_RESET_RMR_RESET_REQUEST_AARCH64 (0x3) + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Exported global variables (to be accessed by other files) + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Private global variables and functions + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * @addtogroup BSP_MCU + * + * @{ + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Occur the system software reset. + **********************************************************************************************************************/ +void R_BSP_SystemReset (void) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + /* System software reset. */ + R_SYSC_S->SWRSYS = BSP_PRV_RESET_KEY; +} + +/*******************************************************************************************************************//** + * Occur the CPU software reset. + * + * @param[in] cpu to be reset state. + * + * @note With Cortex-A55, you cannot use resets that are not automatically released when a software reset is executed. + **********************************************************************************************************************/ +void R_BSP_CPUReset (bsp_reset_t cpu) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CR52_0 == cpu) + { + /* CR52_0 software reset. */ + R_SYSC_S->SWRCPU0 = BSP_PRV_RESET_KEY; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + +#if defined(BSP_CFG_CORE_CR52) && (0 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); +#endif + } + +#if (1U < BSP_FEATURE_BSP_CR52_CORE_NUM) + else if (BSP_RESET_CR52_1 == cpu) + { + /* CR52_1 software reset. */ + R_SYSC_S->SWRCPU1 = BSP_PRV_RESET_KEY; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if defined(BSP_CFG_CORE_CR52) && (1 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); + #endif + } +#endif +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + else if (BSP_RESET_CA55_CLUSTER == cpu) + { + /* CA55_cluster software reset. */ + R_SYSC_S->SWR55C = BSP_PRV_RESET_KEY; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } +#endif + else + { + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } +} + +/*******************************************************************************************************************//** + * Occur the CPU software reset. When using this function, the CPU reset state is automatically released + * after an elapsed time corresponding to the setting value in SCKCR2.DIVSELSUB bit. + * + * @param[in] cpu to be reset state. + **********************************************************************************************************************/ +void R_BSP_CPUResetAutoRelease (bsp_reset_t cpu) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CR52_0 == cpu) + { + /* CR52_0 software reset. */ + R_SYSC_S->SWRCPU0 = BSP_PRV_RESET_KEY_AUTO_RELEASE; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + +#if defined(BSP_CFG_CORE_CR52) && (0 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); +#endif + } + +#if (1U < BSP_FEATURE_BSP_CR52_CORE_NUM) + else if (BSP_RESET_CR52_1 == cpu) + { + /* CR52_1 software reset. */ + R_SYSC_S->SWRCPU1 = BSP_PRV_RESET_KEY_AUTO_RELEASE; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if defined(BSP_CFG_CORE_CR52) && (1 == BSP_CFG_CORE_CR52) + __asm volatile ("WFI"); + #endif + } +#endif +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + else if (BSP_RESET_CA55_CLUSTER == cpu) + { + /* CA55_cluster software reset. */ + R_SYSC_S->SWR55C = BSP_PRV_RESET_KEY_AUTO_RELEASE; + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } + #if defined(BSP_CFG_CORE_CA55) + else if (BSP_RESET_CA55_0 == cpu) + { + /* CA55_0 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (0 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + else if (BSP_RESET_CA55_1 == cpu) + { + /* CA55_1 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (1 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + else if (BSP_RESET_CA55_2 == cpu) + { + /* CA55_2 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (2 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + else if (BSP_RESET_CA55_3 == cpu) + { + /* CA55_3 software reset. */ + __asm volatile ( + "MOV x0, %0 \n" + "MSR RMR_EL3, x0 \n" + ::"r" (BSP_RESET_RMR_RESET_REQUEST_AARCH64) : "memory"); + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + #if (3 == BSP_CFG_CORE_CA55) + __asm volatile ("WFI"); + #endif + } + #endif +#endif + else + { + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } +} + +/*******************************************************************************************************************//** + * Release the CPU reset state. + * + * @param[in] cpu to be release reset state. + **********************************************************************************************************************/ +void R_BSP_CPUResetRelease (bsp_reset_t cpu) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CR52_0 == cpu) + { + /* Release CR52_0 reset state. */ + R_SYSC_S->SWRCPU0 = BSP_PRV_RESET_RELEASE_KEY; + } + +#if (1U < BSP_FEATURE_BSP_CR52_CORE_NUM) + else if (BSP_RESET_CR52_1 == cpu) + { + /* Release CR52_1 reset state. */ + R_SYSC_S->SWRCPU1 = BSP_PRV_RESET_RELEASE_KEY; + } +#endif +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + else if (BSP_RESET_CA55_CLUSTER == cpu) + { + /* Release CA55_cluster software reset. */ + R_SYSC_S->SWR55C = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_0 == cpu) + { + /* Release CA55_0 reset state. */ + R_SYSC_S->SWR550 = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_1 == cpu) + { + /* Release CA55_1 reset state. */ + R_SYSC_S->SWR551 = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_2 == cpu) + { + /* Release CA55_2 reset state. */ + R_SYSC_S->SWR552 = BSP_PRV_RESET_RELEASE_KEY; + } + else if (BSP_RESET_CA55_3 == cpu) + { + /* Release CA55_3 reset state. */ + R_SYSC_S->SWR553 = BSP_PRV_RESET_RELEASE_KEY; + } +#endif + else + { + /* Do Nothing. */ + } + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); +} + +#if (1U < BSP_FEATURE_BSP_CA55_CORE_NUM) + +/*******************************************************************************************************************//** + * Controls whether the core is automatically released from reset when a CA55 cluster reset is performed. + * + * @param[in] cpu to be release reset state. + * @param[in] release Enable/disable automatic reset release. + **********************************************************************************************************************/ +void R_BSP_CPUClusterResetAutoReleaseControl (bsp_reset_t cpu, bsp_cluster_reset_auto_release_t release) +{ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + if (BSP_RESET_CA55_0 == cpu) + { + /* Controls the automatic reset release of CA55_0. */ + R_SYSC_S->SWR55ARC_b.ARC550 = release; + } + else if (BSP_RESET_CA55_1 == cpu) + { + /* Controls the automatic reset release of CA55_1. */ + R_SYSC_S->SWR55ARC_b.ARC551 = release; + } + else if (BSP_RESET_CA55_2 == cpu) + { + /* Controls the automatic reset release of CA55_2. */ + R_SYSC_S->SWR55ARC_b.ARC552 = release; + } + else if (BSP_RESET_CA55_3 == cpu) + { + /* Controls the automatic reset release of CA55_3. */ + R_SYSC_S->SWR55ARC_b.ARC553 = release; + } + else + { + /* Do Nothing. */ + } + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); +} + +#endif + +/*******************************************************************************************************************//** + * Enable module reset state. + * + * @param[in] module_to_enable Modules to enable module reset state. + **********************************************************************************************************************/ +void R_BSP_ModuleResetEnable (bsp_module_reset_t module_to_enable) +{ + volatile uint32_t mrctl; + uint32_t * p_reg; + + /** When MRCTLn register exists in the safety region, + * it is necessary to add an offset of safety region. */ + p_reg = (uint32_t *) &R_SYSC_NS->MRCTLA + + (((module_to_enable & BSP_RESET_MRCTL_SELECT_MASK) >> 16U) + + (module_to_enable & BSP_RESET_MRCTL_REGION_SELECT_MASK)); + mrctl = 1U << (module_to_enable & BSP_RESET_MRCTL_BIT_SHIFT_MASK); + + /** Enable module reset state using MRCTLE register. */ + *p_reg |= mrctl; + + /** To ensure processing after module reset. */ + mrctl = *(volatile uint32_t *) (p_reg); +} + +/*******************************************************************************************************************//** + * Disable module reset state. + * + * @param[in] module_to_disable Modules to disable module reset state. + * + * @note After reset release is performed by the module control register, a dummy read is performed to allow access + * to other than the RTC and LCDC. This is done several times according to the RZ microprocessor manual. + * However, the dummy read count for the RTC and LCDC may not be met depending on the device used. + * In that case, please perform additional dummy read processing after API execution. + * For example, in the case of RZT2H, 300 dummy reads are required for RTC and + * 100 dummy reads are required for LCDC. + **********************************************************************************************************************/ +void R_BSP_ModuleResetDisable (bsp_module_reset_t module_to_disable) +{ + volatile uint32_t mrctl; + uint32_t * p_reg; + + /** When MRCTLn register exists in the safety region, + * it is necessary to add an offset of safety region. */ + p_reg = (uint32_t *) &R_SYSC_NS->MRCTLA + + (((module_to_disable & BSP_RESET_MRCTL_SELECT_MASK) >> 16U) + + (module_to_disable & BSP_RESET_MRCTL_REGION_SELECT_MASK)); + mrctl = 1U << (module_to_disable & BSP_RESET_MRCTL_BIT_SHIFT_MASK); + + /** Disable module stop state using MRCTLn register. */ + *p_reg &= ~mrctl; + + /** In order to secure processing after release from module reset, + * dummy read the same register. + * Refer to "Notes on Module Reset Control Register Operation" of the RZ microprocessor manual. */ + uint32_t dummy_read_cnt = BSP_FEATURE_BSP_MODULE_RESET_DUMMY_READ_COUNT; + + while (dummy_read_cnt) + { + mrctl = *(volatile uint32_t *) (p_reg); + dummy_read_cnt--; + } +} + +/** @} (end addtogroup BSP_MCU) */ diff --git a/drivers/rz/fsp/src/rzt/r_xspi_qspi/r_xspi_qspi.c b/drivers/rz/fsp/src/rzt/r_xspi_qspi/r_xspi_qspi.c new file mode 100644 index 00000000..fdec6d7d --- /dev/null +++ b/drivers/rz/fsp/src/rzt/r_xspi_qspi/r_xspi_qspi.c @@ -0,0 +1,1535 @@ +/* +* Copyright (c) 2020 - 2025 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#include "bsp_api.h" + +/*********************************************************************************************************************** + * Includes + **********************************************************************************************************************/ +#include "r_xspi_qspi.h" + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE + #include "r_rsip.h" +#endif + +#if XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE + #include "r_dmac.h" +#endif + +/*********************************************************************************************************************** + * Macro definitions + **********************************************************************************************************************/ +#define XSPI_QSPI_PRV_OPEN (0x51535049) + +#define XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET (0U) +#define XSPI_QSPI_PRV_LIOCFGCS_PRTMD_VALUE_MASK (0x3FFU) +#define XSPI_QSPI_PRV_LIOCFGCS_PRTMD_MASK (0x3FFU << XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET) +#define XSPI_QSPI_PRV_LIOCFGCS_CSMIN_OFFSET (16U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSMIN_VALUE_MASK (0x0FU) +#define XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_OFFSET (20U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_VALUE_MASK (0x01U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_OFFSET (21U) +#define XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_VALUE_MASK (0x01U) + +#define XSPI_QSPI_PRV_CMCFG0_FFMT_OFFSET (0U) +#define XSPI_QSPI_PRV_CMCFG0_ADDSIZE_OFFSET (2U) +#define XSPI_QSPI_PRV_CMCFG0_ADDSIZE_VALUE_MASK (0x03U) +#define XSPI_QSPI_PRV_CMCFG1_RDCMD_UPPER_OFFSET (8U) +#define XSPI_QSPI_PRV_CMCFG1_RDCMD_VALUE_MASK (0xFFU) +#define XSPI_QSPI_PRV_CMCFG1_RDLATE_OFFSET (16U) +#define XSPI_QSPI_PRV_CMCFG1_RDLATE_VALUE_MASK (0x1FU) + +#define XSPI_QSPI_PRV_CMCFG2_WRCMD_UPPER_OFFSET (8U) +#define XSPI_QSPI_PRV_CMCFG1_WRCMD_VALUE_MASK (0xFFU) +#define XSPI_QSPI_PRV_CMCFG2_WRLATE_OFFSET (16U) + +#define XSPI_QSPI_PRV_BMCFG_WRMD_OFFSET (0U) +#define XSPI_QSPI_PRV_BMCFG_MWRCOMB_OFFSET (7U) +#define XSPI_QSPI_PRV_BMCFG_MWRSIZE_OFFSET (8U) +#define XSPI_QSPI_PRV_BMCFG_PREEN_OFFSET (16U) +#define XSPI_QSPI_PRV_BMCFG_PREEN_VALUE_MASK (0x01U) + +#define XSPI_QSPI_PRV_BMCTL_DEFAULT_VALUE (0x000000FFUL) + +#define XSPI_QSPI_PRV_BMCTL_CSNACC_R_ENABLE (0x01U) +#define XSPI_QSPI_PRV_BMCTL_CSNACC_R_W_ENABLE (0x03U) + +#define XSPI_QSPI_PRV_CDTBUF_CMDSIZE_OFFSET (0U) +#define XSPI_QSPI_PRV_CDTBUF_CMDSIZE_VALUE_MASK (0x03U) +#define XSPI_QSPI_PRV_CDTBUF_ADDSIZE_OFFSET (2U) +#define XSPI_QSPI_PRV_CDTBUF_ADDSIZE_VALUE_MASK (0x07U) +#define XSPI_QSPI_PRV_CDTBUF_DATASIZE_OFFSET (5U) +#define XSPI_QSPI_PRV_CDTBUF_DATASIZE_VALUE_MASK (0x0FU) +#define XSPI_QSPI_PRV_CDTBUF_LATE_OFFSET (9U) +#define XSPI_QSPI_PRV_CDTBUF_LATE_VALUE_MASK (0x1FU) +#define XSPI_QSPI_PRV_CDTBUF_TRTYPE_OFFSET (15U) +#define XSPI_QSPI_PRV_CDTBUF_TRTYPE_VALUE_MASK (0x01U) +#define XSPI_QSPI_PRV_CDTBUF_CMD_UPPER_OFFSET (24U) +#define XSPI_QSPI_PRV_CDTBUF_CMD_VALUE_MASK (0xFFU) + +#define XSPI_QSPI_PRV_COMSTT_MEMACC_OFFSET (0U) +#define XSPI_QSPI_PRV_COMSTT_MEMACC_VALUE_MASK (0x01U) +#define XSPI_QSPI_PRV_COMSTT_WRBUFNE_OFFSET (6U) +#define XSPI_QSPI_PRV_COMSTT_WRBUFNE_VALUE_MASK (0x01U) + +#define XSPI_QSPI_PRV_INTC_CMDCMPC_OFFSET (0U) + +#define XSPI_QSPI_PRV_DEVICE_WRITE_STATUS_BIT_MASK (1U) + +#define XSPI_QSPI_PRV_MAX_COMBINE_SIZE (64U) + +#define XSPI_QSPI_PRV_WORD_ACCESS_SIZE (4U) +#define XSPI_QSPI_PRV_HALF_WORD_ACCESS_SIZE (2U) + +#define XSPI_QSPI_PRV_1MB_MEMORY_SPACE (0xFFFFFU) +#define XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT (20U) +#define XSPI_QSPI_PRV_DIRECT_TRANSFER_MAX_BYTES (8U) + +#define XSPI_QSPI_PRV_UINT32_BITS (32U) +#define XSPI_QSPI_UNIT_FLAG_MASK (3U) + +#define XSPI_QSPI_BUFFER_WRITE_WAIT_CYCLE (5U) + +#if BSP_FEATURE_XSPI_OTFD_SUPPORTED + #define XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET (16U) + #define XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_MASK (0x01U) + #define XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_ACK_MASK (0x02U) + #define XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_MASK (0x10U) + #define XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_ACK_MASK (0x20U) +#endif + +#define XSPI_QSPI_PRV_OTFD_REG00_RESET_VALUE (0x22000000) +#define XSPI_QSPI_PRV_OTFD_SEED_1_SEED_MASK (0x3) +#define XSPI_QSPI_PRV_OTFD_SEED_1_ENABLE_MASK (0xC) + +/*********************************************************************************************************************** + * Typedef definitions + **********************************************************************************************************************/ + +/* Number of address bytes in 4 byte address mode. */ +#define QSPI_4_BYTE_ADDRESS (4U) + +/*********************************************************************************************************************** + * Private function prototypes + **********************************************************************************************************************/ +static void r_xspi_qspi_write_enable(xspi_qspi_instance_ctrl_t * p_instance_ctrl); +static bool r_xspi_qspi_status_sub(xspi_qspi_instance_ctrl_t * p_instance_ctrl); +static fsp_err_t r_xspi_qspi_xip(xspi_qspi_instance_ctrl_t * p_instance_ctrl, uint8_t code, bool enter_mode); +static void r_xspi_qspi_direct_transfer(xspi_qspi_instance_ctrl_t * p_instance_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction); + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE +static fsp_err_t r_xspi_qspi_param_checking_dcom(xspi_qspi_instance_ctrl_t * p_instance_ctrl); +static fsp_err_t r_xspi_qspi_program_param_check(xspi_qspi_instance_ctrl_t * p_instance_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count); + +#endif + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE +static fsp_err_t r_xspi_qspi_otfd_side_channal_seed_init(uint32_t p_seed[]); +static fsp_err_t r_xspi_qspi_otfd_setup(xspi_qspi_instance_ctrl_t * p_instance_ctrl); + +#endif + +/*********************************************************************************************************************** + * Private global variables + **********************************************************************************************************************/ + +/* Bit-flags specifying which channels are open so the module can be stopped when all are closed. */ +static uint32_t g_xspi_qspi_channels_open_flags = 0; + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE +static rsip_instance_ctrl_t g_xspi_qspi_rsip_ctrl; +static const rsip_cfg_t g_xspi_qspi_rsip_cfg; + +#endif + +/*******************************************************************************************************************//** + * @addtogroup XSPI_QSPI + * @{ + **********************************************************************************************************************/ + +/*********************************************************************************************************************** + * Global Variables + **********************************************************************************************************************/ + +const spi_flash_api_t g_spi_flash_on_xspi_qspi = +{ + .open = R_XSPI_QSPI_Open, + .directWrite = R_XSPI_QSPI_DirectWrite, + .directRead = R_XSPI_QSPI_DirectRead, + .directTransfer = R_XSPI_QSPI_DirectTransfer, + .spiProtocolSet = R_XSPI_QSPI_SpiProtocolSet, + .write = R_XSPI_QSPI_Write, + .erase = R_XSPI_QSPI_Erase, + .statusGet = R_XSPI_QSPI_StatusGet, + .xipEnter = R_XSPI_QSPI_XipEnter, + .xipExit = R_XSPI_QSPI_XipExit, + .bankSet = R_XSPI_QSPI_BankSet, + .autoCalibrate = R_XSPI_QSPI_AutoCalibrate, + .close = R_XSPI_QSPI_Close, +}; + +/*********************************************************************************************************************** + * Functions + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Open the QSPI driver module. After the driver is open, the QSPI can be accessed like internal flash memory starting + * at address 0x60000000 or 0x40000000. + * + * Implements @ref spi_flash_api_t::open. + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_ASSERTION The parameter p_instance_ctrl or p_cfg is NULL. + * @retval FSP_ERR_ALREADY_OPEN Driver has already been opened with the same p_instance_ctrl. + * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT The requested channel does not exist on this MCU. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Open (spi_flash_ctrl_t * p_ctrl, spi_flash_cfg_t const * const p_cfg) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ASSERT(NULL != p_cfg); + FSP_ASSERT(NULL != p_cfg->p_extend); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN != p_instance_ctrl->open, FSP_ERR_ALREADY_OPEN); + + /* Make sure this unit exists. */ + FSP_ERROR_RETURN(BSP_FEATURE_XSPI_CHANNELS & (1U << ((xspi_qspi_extended_cfg_t *) p_cfg->p_extend)->unit), + FSP_ERR_IP_CHANNEL_NOT_PRESENT); +#endif + + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ERROR_RETURN( + (g_xspi_qspi_channels_open_flags & (1U << ((p_cfg_extend->unit << 1U) + p_cfg_extend->chip_select))) == 0, + FSP_ERR_ALREADY_OPEN); +#endif + + /* Enable clock to the QSPI block */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + R_BSP_MODULE_START(FSP_IP_XSPI, p_cfg_extend->unit); + if (0U == p_cfg_extend->unit) + { + R_BSP_ModuleResetDisable(BSP_MODULE_RESET_XSPI0); + } + else + { + R_BSP_ModuleResetDisable(BSP_MODULE_RESET_XSPI1); + } + + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SYSTEM); + +#if BSP_FEATURE_BSP_SLAVE_STOP_SUPPORTED + + /* Release from slave stop. */ + if (0U == p_cfg_extend->unit) + { + R_BSP_SlaveStopRelease(BSP_BUS_SLAVE_XSPI0); + } + else + { + R_BSP_SlaveStopRelease(BSP_BUS_SLAVE_XSPI1); + } +#endif + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE + if (NULL != p_cfg_extend->p_otfd_cfg) + { + /* OTFD enable. */ + R_XSPI_MISC2->OTFD_ENABLE |= + (uint32_t) (R_XSPI_MISC2_OTFD_ENABLE_OTFD0E_Msk << + (R_XSPI_MISC2_OTFD_ENABLE_OTFD1E_Pos * p_cfg_extend->unit)); + } + else + { + /* OTFD disable. */ + R_XSPI_MISC2->OTFD_ENABLE &= + (uint32_t) ~(R_XSPI_MISC2_OTFD_ENABLE_OTFD0E_Msk << + (R_XSPI_MISC2_OTFD_ENABLE_OTFD1E_Pos * p_cfg_extend->unit)); + } +#endif + +#if BSP_FEATURE_XSPI_OTFD_SUPPORTED + + /* Bus release request */ + R_XSPI_MISC2->MSTP_CTRL_XSPI &= + ~(XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_MASK << (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)); + FSP_HARDWARE_REGISTER_WAIT(((R_XSPI_MISC2->MSTP_CTRL_XSPI >> + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)) & + XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_ACK_MASK), + 0U); + + /* Module release request */ + R_XSPI_MISC2->MSTP_CTRL_XSPI &= + ~(XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_MASK << (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)); + FSP_HARDWARE_REGISTER_WAIT(((R_XSPI_MISC2->MSTP_CTRL_XSPI >> + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)) & + XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_ACK_MASK), + 0U); +#endif + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SYSTEM); + + uintptr_t base_address = (uintptr_t) R_XSPI0 + (p_cfg_extend->unit * ((uintptr_t) R_XSPI1 - (uintptr_t) R_XSPI0)); + p_instance_ctrl->p_reg = (R_XSPI0_Type *) base_address; + + /* Initialize control block. */ + p_instance_ctrl->p_cfg = p_cfg; + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE + if (NULL != p_cfg_extend->p_otfd_cfg) + { + uintptr_t base_otfd_address = (uintptr_t) R_OTFD0 + + (p_cfg_extend->unit * ((uintptr_t) R_OTFD1 - (uintptr_t) R_OTFD0)); + p_instance_ctrl->p_otfd_reg = (R_OTFD0_Type *) base_otfd_address; + + fsp_err_t otfd_ret = r_xspi_qspi_otfd_setup(p_instance_ctrl); + if (FSP_SUCCESS != otfd_ret) + { + R_RSIP_Close(&g_xspi_qspi_rsip_ctrl); + + #if BSP_FEATURE_XSPI_OTFD_SUPPORTED + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SYSTEM); + + /* Module stop request */ + R_XSPI_MISC2->MSTP_CTRL_XSPI |= XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_MASK << + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit); + FSP_HARDWARE_REGISTER_WAIT(((R_XSPI_MISC2->MSTP_CTRL_XSPI >> + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)) & + XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_ACK_MASK), + XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_ACK_MASK); + + /* Bus stop request */ + R_XSPI_MISC2->MSTP_CTRL_XSPI |= XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_MASK << + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit); + FSP_HARDWARE_REGISTER_WAIT(((R_XSPI_MISC2->MSTP_CTRL_XSPI >> + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)) & + XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_ACK_MASK), + XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_ACK_MASK); + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SYSTEM); + #endif + + /* If the OTFD initialization fails, stop the module. */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + R_BSP_MODULE_STOP(FSP_IP_XSPI, p_cfg_extend->unit); + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + + return otfd_ret; + } + } +#endif + +#if XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE + transfer_instance_t const * p_transfer = p_cfg_extend->p_lower_lvl_transfer; + #if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_transfer); + #endif + + /* Initialize transfer instance */ + p_transfer->p_api->open(p_transfer->p_ctrl, p_transfer->p_cfg); +#endif + + /* xSPI configuration (see RZ microprocessor User's Manual section "Flow of Configuration"). */ + p_instance_ctrl->p_reg->LIOCFGCS[p_cfg_extend->chip_select] = (p_cfg->spi_protocol) << + XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET; + p_instance_ctrl->spi_protocol = p_cfg->spi_protocol; + + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SYSTEM); + + /* Set xSPI IO voltage */ +#if BSP_FEATURE_XSPI_VOLTAGE_SETTING_SUPPORTED + if (0 == p_cfg_extend->unit) + { + R_XSPI0_MISC->IOVOLCTL = p_cfg_extend->io_voltage; + } + else + { + R_XSPI1_MISC->IOVOLCTL = p_cfg_extend->io_voltage; + } +#endif + + /* Set xSPI CSn address space. */ +#if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + uint32_t mirror_address_delta; + #if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0; + #else + mirror_address_delta = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; + #endif + R_XSPI0_MISC->CS0ENDAD = p_cfg_extend->p_address_space->unit0_cs0_end_address - mirror_address_delta; + R_XSPI0_MISC->CS1STRAD = p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta; + R_XSPI0_MISC->CS1ENDAD = p_cfg_extend->p_address_space->unit0_cs1_end_address - mirror_address_delta; + R_XSPI1_MISC->CS0ENDAD = p_cfg_extend->p_address_space->unit1_cs0_end_address - mirror_address_delta; + R_XSPI1_MISC->CS1STRAD = p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta; + R_XSPI1_MISC->CS1ENDAD = p_cfg_extend->p_address_space->unit1_cs1_end_address - mirror_address_delta; +#else + #if 1 == BSP_FEATURE_XSPI_CS_ADDRESS_SPACE_SETTING_TYPE + + /* Set xSPI CSn slave memory size. */ + if (XSPI_QSPI_CHIP_SELECT_0 == p_cfg_extend->chip_select) + { + p_instance_ctrl->p_reg->CSSCTL_b.CS0SIZE = p_cfg_extend->memory_size; + } + else + { + p_instance_ctrl->p_reg->CSSCTL_b.CS1SIZE = p_cfg_extend->memory_size; + } + + #elif 2 == BSP_FEATURE_XSPI_CS_ADDRESS_SPACE_SETTING_TYPE + uint32_t mirror_address_delta; + #if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0U; + #else + mirror_address_delta = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; + #endif + + if (XSPI_QSPI_CHIP_SELECT_0 == p_cfg_extend->chip_select) + { + if (0 == p_cfg_extend->unit) + { + R_XSPI0_MISC->CS0ENDAD = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + else + { + R_XSPI1_MISC->CS0ENDAD = BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + } + else + { + if (0 == p_cfg_extend->unit) + { + R_XSPI0_MISC->CS1STRAD = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta; + + R_XSPI0_MISC->CS1ENDAD = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + else + { + R_XSPI1_MISC->CS1STRAD = BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta; + + R_XSPI1_MISC->CS1ENDAD = BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2U - mirror_address_delta + + (uint32_t) (p_cfg_extend->memory_size << XSPI_QSPI_PRV_MEMORY_SIZE_SHIFT) + + XSPI_QSPI_PRV_1MB_MEMORY_SPACE; + } + } + #endif +#endif + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SYSTEM); + + p_instance_ctrl->p_reg->LIOCFGCS[p_cfg_extend->chip_select] = + ((p_cfg->spi_protocol & XSPI_QSPI_PRV_LIOCFGCS_PRTMD_VALUE_MASK) << XSPI_QSPI_PRV_LIOCFGCS_PRTMD_OFFSET) | + ((p_cfg_extend->p_timing_settings->command_to_command_interval & + XSPI_QSPI_PRV_LIOCFGCS_CSMIN_VALUE_MASK) << XSPI_QSPI_PRV_LIOCFGCS_CSMIN_OFFSET) | + ((p_cfg_extend->p_timing_settings->cs_pulldown_lead & XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_VALUE_MASK) << + XSPI_QSPI_PRV_LIOCFGCS_CSASTEX_OFFSET) | + ((p_cfg_extend->p_timing_settings->cs_pullup_lag & XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_VALUE_MASK) << + XSPI_QSPI_PRV_LIOCFGCS_CSENGEX_OFFSET); + + /* Specifies the read/write commands and Read dummy clocks for Device + * (see RZ microprocessor User's Manual section "Flow of Memory-mapping"). */ + p_instance_ctrl->p_reg->CSa[p_cfg_extend->chip_select].CMCFG0 = + (0U << XSPI_QSPI_PRV_CMCFG0_FFMT_OFFSET) | + ((p_cfg->address_bytes & XSPI_QSPI_PRV_CMCFG0_ADDSIZE_VALUE_MASK) << XSPI_QSPI_PRV_CMCFG0_ADDSIZE_OFFSET); + + p_instance_ctrl->p_reg->CSa[p_cfg_extend->chip_select].CMCFG1 = + ((p_cfg->read_command & XSPI_QSPI_PRV_CMCFG1_RDCMD_VALUE_MASK) << XSPI_QSPI_PRV_CMCFG1_RDCMD_UPPER_OFFSET) | + ((p_cfg->dummy_clocks & XSPI_QSPI_PRV_CMCFG1_RDLATE_VALUE_MASK) << XSPI_QSPI_PRV_CMCFG1_RDLATE_OFFSET); + + p_instance_ctrl->p_reg->CSa[p_cfg_extend->chip_select].CMCFG2 = + ((p_cfg->page_program_command & XSPI_QSPI_PRV_CMCFG1_WRCMD_VALUE_MASK) << + XSPI_QSPI_PRV_CMCFG2_WRCMD_UPPER_OFFSET) | + (0U << XSPI_QSPI_PRV_CMCFG2_WRLATE_OFFSET); + + p_instance_ctrl->p_reg->BMCTL0 = XSPI_QSPI_PRV_BMCTL_DEFAULT_VALUE; + + /* Return response after issuing write transaction to xSPI bus, Enable prefetch function. */ + p_instance_ctrl->p_reg->BMCFG = (0 << XSPI_QSPI_PRV_BMCFG_WRMD_OFFSET) | + (1 << XSPI_QSPI_PRV_BMCFG_MWRCOMB_OFFSET) | + (0x0F << XSPI_QSPI_PRV_BMCFG_MWRSIZE_OFFSET) | + ((p_cfg_extend->prefetch_en & XSPI_QSPI_PRV_BMCFG_PREEN_VALUE_MASK) << + XSPI_QSPI_PRV_BMCFG_PREEN_OFFSET); + + /* Set use Channel. */ + p_instance_ctrl->p_reg->CDCTL0_b.CSSEL = p_cfg_extend->chip_select; + + /* The memory size is read from the device if needed. */ + p_instance_ctrl->total_size_bytes = 0U; + + p_instance_ctrl->open = XSPI_QSPI_PRV_OPEN; + g_xspi_qspi_channels_open_flags |= (1U << ((p_cfg_extend->unit << 1U) + p_cfg_extend->chip_select)); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Writes raw data directly to the QSPI. + * + * Implements @ref spi_flash_api_t::directWrite. + * + * @retval FSP_ERR_UNSUPPORTED API not supported. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_DirectWrite (spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint32_t const bytes, + bool const read_after_write) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + FSP_PARAMETER_NOT_USED(p_src); + FSP_PARAMETER_NOT_USED(bytes); + FSP_PARAMETER_NOT_USED(read_after_write); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Reads raw data directly from the QSPI. + * + * Implements @ref spi_flash_api_t::directRead. + * + * @retval FSP_ERR_UNSUPPORTED API not supported. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_DirectRead (spi_flash_ctrl_t * p_ctrl, uint8_t * const p_dest, uint32_t const bytes) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + FSP_PARAMETER_NOT_USED(p_dest); + FSP_PARAMETER_NOT_USED(bytes); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Read/Write raw data directly with the SerialFlash. + * + * Implements @ref spi_flash_api_t::directTransfer. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function must be called after R_XSPI_QSPI_DirectWrite with read_after_write set + * to true. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_DirectTransfer (spi_flash_ctrl_t * p_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + fsp_err_t err = r_xspi_qspi_param_checking_dcom(p_instance_ctrl); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ASSERT(NULL != p_transfer); + FSP_ASSERT(0 != p_transfer->command_length); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + r_xspi_qspi_direct_transfer(p_instance_ctrl, p_transfer, direction); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Enters XIP (execute in place) mode. + * @note If the xSPI address space is cache-enabled, cache should be invalidated before executing XipEnter. Otherwise, it is not guaranteed that the slave device will be in XiP mode immediately after XipEnter is executed. + * + * Implements @ref spi_flash_api_t::xipEnter. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_XipEnter (spi_flash_ctrl_t * p_ctrl) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + fsp_err_t err; + + err = r_xspi_qspi_xip(p_instance_ctrl, p_instance_ctrl->p_cfg->xip_enter_command, true); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Exits XIP (execute in place) mode. + * @note If the xSPI address space is cache-enabled, cache should be invalidated before executing XipExit. Otherwise, it is not guaranteed that the slave device will exit XiP mode immediately after XipEnter is executed. + * + * Implements @ref spi_flash_api_t::xipExit. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_XipExit (spi_flash_ctrl_t * p_ctrl) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + fsp_err_t err; + + err = r_xspi_qspi_xip(p_instance_ctrl, p_instance_ctrl->p_cfg->xip_exit_command, false); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Program a page of data to the flash. + * + * Implements @ref spi_flash_api_t::write. + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION p_instance_ctrl, p_dest or p_src is NULL, or byte_count crosses a page boundary. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + * + * @note In this API, data can be written up to 64 bytes at a time if DMAC support is enabled. + * Otherwise, the number of bytes that can be written at one time depends on the MCU : + * 64bytes for RZ/T2M and RZ/T2L, 8bytes for RZ/T2ME and RZ/T2H. + * @note This API performs page program operations to the device. Writing across pages is not supported. + * Please set the write address and write size according to the page size of your device. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Write (spi_flash_ctrl_t * p_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + fsp_err_t err = r_xspi_qspi_program_param_check(p_instance_ctrl, p_src, p_dest, byte_count); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); +#endif + FSP_ERROR_RETURN(false == r_xspi_qspi_status_sub(p_instance_ctrl), FSP_ERR_DEVICE_BUSY); + + r_xspi_qspi_write_enable(p_instance_ctrl); + +#if XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + + /* Setup and start DMAC transfer. */ + transfer_instance_t const * p_transfer = p_cfg_extend->p_lower_lvl_transfer; + + p_transfer->p_cfg->p_info->src_size = TRANSFER_SIZE_1_BYTE; + p_transfer->p_cfg->p_info->dest_size = TRANSFER_SIZE_1_BYTE; + p_transfer->p_cfg->p_info->src_addr_mode = TRANSFER_ADDR_MODE_INCREMENTED; + p_transfer->p_cfg->p_info->dest_addr_mode = TRANSFER_ADDR_MODE_INCREMENTED; + p_transfer->p_cfg->p_info->p_src = p_src; + p_transfer->p_cfg->p_info->p_dest = p_dest; + p_transfer->p_cfg->p_info->length = byte_count; + fsp_err_t dmac_err = p_transfer->p_api->reconfigure(p_transfer->p_ctrl, p_transfer->p_cfg->p_info); + FSP_ERROR_RETURN(FSP_SUCCESS == dmac_err, dmac_err); + + /* Start DMA */ + dmac_err = p_transfer->p_api->softwareStart(p_transfer->p_ctrl, TRANSFER_START_MODE_SINGLE); + FSP_ERROR_RETURN(FSP_SUCCESS == dmac_err, dmac_err); + + /* Wait for DMAC to complete to maintain deterministic processing and backward compatability */ + volatile transfer_properties_t transfer_properties = {0U}; + dmac_err = p_transfer->p_api->infoGet(p_transfer->p_ctrl, (transfer_properties_t *) &transfer_properties); + FSP_ERROR_RETURN(FSP_SUCCESS == dmac_err, dmac_err); + while (FSP_SUCCESS == dmac_err && transfer_properties.transfer_length_remaining > 0) + { + dmac_err = p_transfer->p_api->infoGet(p_transfer->p_ctrl, (transfer_properties_t *) &transfer_properties); + FSP_ERROR_RETURN(FSP_SUCCESS == dmac_err, dmac_err); + } + + /* Request to push the pending data */ + if (XSPI_QSPI_PRV_MAX_COMBINE_SIZE > byte_count) + { + /* Push the pending data. */ + p_instance_ctrl->p_reg->BMCTL1_b.MWRPUSH = 1; + } + +#elif BSP_FEATURE_XSPI_HAS_AXI_BRIDGE + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + uint32_t chip_address; + uint32_t chip_select = p_cfg_extend->chip_select; + uint32_t unit = p_cfg_extend->unit; + uint32_t mirror_address_delta; + + #ifdef BSP_CFG_CORE_CA55 + uintptr_t dest_va = (uintptr_t) p_dest; + uintptr_t dest_pa = 0U; + + fsp_err_t mmu_err; + mmu_err = R_BSP_MmuVatoPa(dest_va, &dest_pa); + FSP_ERROR_RETURN(FSP_SUCCESS == mmu_err, mmu_err); + #else + uintptr_t dest_pa = (uintptr_t) p_dest; + #endif + + /* Get device start address. */ + #if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0U; + #else + mirror_address_delta = ((uintptr_t) p_dest < BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS) ? + 0U : + BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; + #endif + + chip_address = (0 == chip_select) ? + (0 == unit) ? + (uint32_t) dest_pa - (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta) : // unit0 cs0 + (uint32_t) dest_pa - (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta) : // unit1 cs0 + (0 == unit) + #if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + ? (uint32_t) dest_pa - + (p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta) : // unit0 cs1 + (uint32_t) dest_pa - + (p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta); // unit1 cs1 + #else + ? (uint32_t) dest_pa - + (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta) : // unit0 cs1 + (uint32_t) dest_pa - + (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta); // unit1 cs1 + #endif + + spi_flash_direct_transfer_t write_transfer; + write_transfer.data_u64 = *(uint64_t *) p_src; + write_transfer.data_length = (uint8_t) byte_count; + write_transfer.address = chip_address; + write_transfer.address_length = (p_instance_ctrl->p_cfg->address_bytes == SPI_FLASH_ADDRESS_BYTES_4) ? 4U : 3U; + write_transfer.dummy_cycles = 0; + + write_transfer.command = p_instance_ctrl->p_cfg->page_program_command; + write_transfer.command_length = 1U; + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &write_transfer, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); + + /* If prefetch is enabled, make sure the banks aren't being used and flush the prefetch caches after an erase. */ + if (p_cfg_extend->prefetch_en == XSPI_QSPI_PREFETCH_FUNCTION_ENABLE) + { + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->COMSTT_b.MEMACC, 0); + p_instance_ctrl->p_reg->BMCTL1_b.PBUFCLR = 1; + } + +#else + uint32_t i = 0; + + FSP_CRITICAL_SECTION_DEFINE; + FSP_CRITICAL_SECTION_ENTER; + + /* Word access */ + if (0 == byte_count % XSPI_QSPI_PRV_WORD_ACCESS_SIZE) + { + uint32_t * p_word_aligned_dest = (uint32_t *) p_dest; + uint32_t * p_word_aligned_src = (uint32_t *) p_src; + for (i = 0; i < byte_count / XSPI_QSPI_PRV_WORD_ACCESS_SIZE; i++) + { + *p_word_aligned_dest = *p_word_aligned_src; + p_word_aligned_dest++; + p_word_aligned_src++; + } + } + /* Half Word access */ + else if (0 == byte_count % XSPI_QSPI_PRV_HALF_WORD_ACCESS_SIZE) + { + uint16_t * p_half_word_aligned_dest = (uint16_t *) p_dest; + uint16_t * p_half_word_aligned_src = (uint16_t *) p_src; + for (i = 0; i < byte_count / XSPI_QSPI_PRV_HALF_WORD_ACCESS_SIZE; i++) + { + *p_half_word_aligned_dest = *p_half_word_aligned_src; + p_half_word_aligned_dest++; + p_half_word_aligned_src++; + } + } + /* Byte access */ + else + { + for (i = 0; i < byte_count; i++) + { + p_dest[i] = p_src[i]; + } + } + + /* Protect the order between access to the xSPI external memory space and the xSPI peripheral space. */ + __DSB(); + + /* Request to push the pending data */ + if (XSPI_QSPI_PRV_MAX_COMBINE_SIZE > byte_count) + { + /* Do dummy read for wait. + * To ensure that all write data is stored in the xSPI internal write buffer before issuing a push request, + * it is necessary to wait a few cycles. */ + volatile uint32_t dummy; + for (uint32_t wait_cycle = 0; wait_cycle < XSPI_QSPI_BUFFER_WRITE_WAIT_CYCLE; wait_cycle++) + { + dummy = p_instance_ctrl->p_reg->COMCFG; + FSP_PARAMETER_NOT_USED(dummy); + } + + /* Push the pending data. */ + p_instance_ctrl->p_reg->BMCTL1_b.MWRPUSH = 1; + } + + /* Wait until memory access starts in write API. */ + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->COMSTT_b.MEMACC, 1); + + FSP_CRITICAL_SECTION_EXIT; +#endif + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Erase a block or sector of flash. The byte_count must exactly match one of the erase sizes defined in spi_flash_cfg_t. + * For chip erase, byte_count must be SPI_FLASH_ERASE_SIZE_CHIP_ERASE. + * + * Implements @ref spi_flash_api_t::erase. + * + * @retval FSP_SUCCESS The command to erase the flash was executed successfully. + * @retval FSP_ERR_ASSERTION p_instance_ctrl or p_device_address is NULL, or byte_count doesn't match an erase + * size defined in spi_flash_cfg_t, or device is in XIP mode. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Erase (spi_flash_ctrl_t * p_ctrl, uint8_t * const p_device_address, uint32_t byte_count) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + fsp_err_t err = r_xspi_qspi_param_checking_dcom(p_instance_ctrl); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + FSP_ASSERT(NULL != p_device_address); +#endif + + xspi_qspi_extended_cfg_t * p_cfg_extend = + (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + + uint8_t unit = p_cfg_extend->unit; + uint8_t chip_select = p_cfg_extend->chip_select; + + uint16_t erase_command = 0; + uintptr_t chip_address = 0; + bool send_address = true; + + if (SPI_FLASH_ERASE_SIZE_CHIP_ERASE != byte_count) + { + uint32_t mirror_address_delta; + +#ifdef BSP_CFG_CORE_CA55 + uintptr_t device_address_va = (uintptr_t) p_device_address; + uintptr_t device_address_pa = 0U; + + fsp_err_t mmu_err; + mmu_err = R_BSP_MmuVatoPa(device_address_va, &device_address_pa); + FSP_ERROR_RETURN(FSP_SUCCESS == mmu_err, mmu_err); +#else + uintptr_t device_address_pa = (uintptr_t) p_device_address; +#endif + + /* Get device start address. */ +#if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0U; +#else + mirror_address_delta = (device_address_pa < BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS) ? + 0U : + BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; +#endif + + chip_address = (0 == chip_select) ? + (0 == unit) ? + device_address_pa - (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta) : // unit0 cs0 + device_address_pa - (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta) : // unit1 cs0 + (0 == unit) +#if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + ? device_address_pa - + (p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta) : // unit0 cs1 + device_address_pa - + (p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta); // unit1 cs1 +#else + ? device_address_pa - + (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta) : // unit0 cs1 + device_address_pa - + (BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta); // unit1 cs1 +#endif + } + + for (uint32_t index = 0; index < p_instance_ctrl->p_cfg->erase_command_list_length; index++) + { + /* If requested byte_count is supported by underlying flash, store the command. */ + if (byte_count == p_instance_ctrl->p_cfg->p_erase_command_list[index].size) + { + if (SPI_FLASH_ERASE_SIZE_CHIP_ERASE == byte_count) + { + /* Don't send address for chip erase. */ + send_address = false; + } + + erase_command = p_instance_ctrl->p_cfg->p_erase_command_list[index].command; + break; + } + } + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(0U != erase_command); +#endif + + r_xspi_qspi_write_enable(p_instance_ctrl); + + spi_flash_direct_transfer_t direct_command = {0}; + direct_command.command = erase_command; + direct_command.address = (uint32_t) chip_address; + direct_command.address_length = (true == send_address) ? + (((p_instance_ctrl->p_cfg->address_bytes) + 1U)) & + XSPI_QSPI_PRV_CDTBUF_ADDSIZE_VALUE_MASK : 0U; + direct_command.command_length = 1U; + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &direct_command, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); + + /* If prefetch is enabled, make sure the banks aren't being used and flush the prefetch caches after an erase. */ + if (p_cfg_extend->prefetch_en == XSPI_QSPI_PREFETCH_FUNCTION_ENABLE) + { + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->COMSTT_b.MEMACC, 0); + p_instance_ctrl->p_reg->BMCTL1_b.PBUFCLR = 1; + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Gets the write or erase status of the flash. + * + * Implements @ref spi_flash_api_t::statusGet. + * + * @retval FSP_SUCCESS The write status is in p_status. + * @retval FSP_ERR_ASSERTION p_instance_ctrl or p_status is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_StatusGet (spi_flash_ctrl_t * p_ctrl, spi_flash_status_t * const p_status) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ASSERT(NULL != p_status); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); + FSP_ERROR_RETURN(0U == p_instance_ctrl->p_reg->CMCTL_b.XIPEN, FSP_ERR_INVALID_MODE); +#endif + + uint32_t comstt = p_instance_ctrl->p_reg->COMSTT; + bool memacc = (bool) ((comstt >> XSPI_QSPI_PRV_COMSTT_MEMACC_OFFSET) & XSPI_QSPI_PRV_COMSTT_MEMACC_VALUE_MASK); + bool wrbufne = + (bool) ((comstt >> XSPI_QSPI_PRV_COMSTT_WRBUFNE_OFFSET) & XSPI_QSPI_PRV_COMSTT_WRBUFNE_VALUE_MASK); + + if ((true == memacc) || (true == wrbufne)) + { + /* If the xSPI is accessing memory or data is in the write buffer, + * it is judged a "write in progress" without access to QSPI. */ + p_status->write_in_progress = (bool) (wrbufne | memacc); + } + else + { + /* Read device status. */ + p_status->write_in_progress = r_xspi_qspi_status_sub(p_instance_ctrl); + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Selects the bank to access. + * + * Implements @ref spi_flash_api_t::bankSet. + * + * @retval FSP_ERR_UNSUPPORTED API not supported. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_BankSet (spi_flash_ctrl_t * p_ctrl, uint32_t bank) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + FSP_PARAMETER_NOT_USED(bank); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Sets the SPI protocol. + * + * Implements @ref spi_flash_api_t::spiProtocolSet. + * + * @retval FSP_SUCCESS SPI protocol updated on MCU peripheral. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_ARGUMENT Invalid SPI protocol requested. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_SpiProtocolSet (spi_flash_ctrl_t * p_ctrl, spi_flash_protocol_t spi_protocol) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); + + /* Not allow the following arguremnts with this IP. */ + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_QPI != spi_protocol, FSP_ERR_INVALID_ARGUMENT); + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_SOPI != spi_protocol, FSP_ERR_INVALID_ARGUMENT); + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_DOPI != spi_protocol, FSP_ERR_INVALID_ARGUMENT); + + /* Not allow the following arguremnts with QSPI HAL Driver. */ + FSP_ERROR_RETURN(SPI_FLASH_PROTOCOL_8D_8D_8D != spi_protocol, FSP_ERR_INVALID_ARGUMENT); +#else + FSP_PARAMETER_NOT_USED(p_instance_ctrl); +#endif + + spi_flash_cfg_t * p_cfg = (spi_flash_cfg_t *) p_instance_ctrl->p_cfg; + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + + p_instance_ctrl->spi_protocol = spi_protocol; + + /* Update the SPI protocol. */ + p_instance_ctrl->p_reg->LIOCFGCS_b[p_cfg_extend->chip_select].PRTMD = spi_protocol & + XSPI_QSPI_PRV_LIOCFGCS_PRTMD_MASK; + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Auto-calibrate the OctaRAM device using the preamble pattern. Unsupported by XSPI_QSPI. + * Implements @ref spi_flash_api_t::autoCalibrate. + * + * @retval FSP_ERR_UNSUPPORTED API not supported by XSPI_QSPI + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_AutoCalibrate (spi_flash_ctrl_t * p_ctrl) +{ + FSP_PARAMETER_NOT_USED(p_ctrl); + + return FSP_ERR_UNSUPPORTED; +} + +/*******************************************************************************************************************//** + * Close the QSPI driver module. + * + * Implements @ref spi_flash_api_t::close. + * + * @retval FSP_SUCCESS Configuration was successful. + * @retval FSP_ERR_ASSERTION p_instance_ctrl is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * + * @note If another chip select of the same unit is used by other drivers, + * the other chip select operation will also stop when this function is executed. + **********************************************************************************************************************/ +fsp_err_t R_XSPI_QSPI_Close (spi_flash_ctrl_t * p_ctrl) +{ + xspi_qspi_instance_ctrl_t * p_instance_ctrl = (xspi_qspi_instance_ctrl_t *) p_ctrl; +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + spi_flash_cfg_t * p_cfg = (spi_flash_cfg_t *) p_instance_ctrl->p_cfg; + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + + p_instance_ctrl->open = 0U; + g_xspi_qspi_channels_open_flags &= ~(1U << ((p_cfg_extend->unit << 1U) + p_cfg_extend->chip_select)); + + if ((g_xspi_qspi_channels_open_flags & (XSPI_QSPI_UNIT_FLAG_MASK << (p_cfg_extend->unit << 1U))) == 0) + { + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_SYSTEM); + +#if BSP_FEATURE_XSPI_OTFD_SUPPORTED + + /* Module stop request */ + R_XSPI_MISC2->MSTP_CTRL_XSPI |= XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_MASK << + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit); + FSP_HARDWARE_REGISTER_WAIT(((R_XSPI_MISC2->MSTP_CTRL_XSPI >> + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)) & + XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_ACK_MASK), + XSPI_QSPI_PRV_MSTP_CTRL_MODULE_STOP_ACK_MASK); + + /* Bus stop request */ + R_XSPI_MISC2->MSTP_CTRL_XSPI |= XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_MASK << + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit); + FSP_HARDWARE_REGISTER_WAIT(((R_XSPI_MISC2->MSTP_CTRL_XSPI >> + (XSPI_QSPI_PRV_MSTP_CTRL_UNIT_OFFSET * p_cfg_extend->unit)) & + XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_ACK_MASK), + XSPI_QSPI_PRV_MSTP_CTRL_BUS_STOP_ACK_MASK); +#endif + +#if BSP_FEATURE_BSP_SLAVE_STOP_SUPPORTED + + /* Slave stop request */ + if (0U == p_cfg_extend->unit) + { + R_BSP_SlaveStop(BSP_BUS_SLAVE_XSPI0); + } + else + { + R_BSP_SlaveStop(BSP_BUS_SLAVE_XSPI1); + } +#endif + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_SYSTEM); + + /* Disable clock to the QSPI block */ + R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_LPC_RESET); + + /* Enable reset */ + if (0U == p_cfg_extend->unit) + { + R_BSP_ModuleResetEnable(BSP_MODULE_RESET_XSPI0); + } + else + { + R_BSP_ModuleResetEnable(BSP_MODULE_RESET_XSPI1); + } + + R_BSP_MODULE_STOP(FSP_IP_XSPI, p_cfg_extend->unit); + R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_LPC_RESET); + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * @} (end addtogroup XSPI_QSPI) + **********************************************************************************************************************/ + +/*******************************************************************************************************************//** + * Send Write enable command to the SerialFlash + * + * @param[in] p_instance_ctrl Pointer to QSPI specific control structure + **********************************************************************************************************************/ +static void r_xspi_qspi_write_enable (xspi_qspi_instance_ctrl_t * p_instance_ctrl) +{ + spi_flash_direct_transfer_t direct_command = {0}; + spi_flash_cfg_t const * p_cfg = p_instance_ctrl->p_cfg; + + direct_command.command = p_cfg->write_enable_command; + direct_command.command_length = 1U; + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &direct_command, SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE); +} + +/*******************************************************************************************************************//** + * Enters or exits XIP (execute in place) mode. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * @param[in] code Code to place in M7-M0 + * @param[in] enter_mode True to enter, false to exit + * + * @retval FSP_SUCCESS The flash was programmed successfully. + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_xip (xspi_qspi_instance_ctrl_t * p_instance_ctrl, uint8_t code, bool enter_mode) +{ +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + + /* FSP_ASSERT(NULL != p_instance_ctrl) is optimized out when it shouldn't be. It appears to be affected by GCC bug + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90949. */ + xspi_qspi_instance_ctrl_t * volatile p_volatile_ctrl = p_instance_ctrl; + FSP_ASSERT(NULL != p_volatile_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); +#endif + + xspi_qspi_extended_cfg_t * p_cfg_extend = + (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + + uint8_t unit = p_cfg_extend->unit; + uint8_t chip_select = p_cfg_extend->chip_select; + + volatile uint8_t dummy = 0; + FSP_PARAMETER_NOT_USED(dummy); + + /* XiP configuration (see RZ microprocessor User's Manual section "Flow of XiP"). */ + if (true == enter_mode) + { + if (XSPI_QSPI_CHIP_SELECT_0 == chip_select) + { + p_instance_ctrl->p_reg->BMCTL0_b.CS0ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_ENABLE; + } + else + { + p_instance_ctrl->p_reg->BMCTL0_b.CS1ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_ENABLE; + } + } + + p_instance_ctrl->p_reg->CMCTL_b.XIPENCODE = code; + p_instance_ctrl->p_reg->CMCTL_b.XIPEXCODE = code; + p_instance_ctrl->p_reg->CMCTL_b.XIPEN = enter_mode; + + /* Read from QSPI to send the XIP entry request. + * Read via a cache-invalid mirror area to ensure access to QSPI. */ + + uint32_t mirror_address_delta; +#if 0 == BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS + mirror_address_delta = 0; +#else + mirror_address_delta = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; +#endif + + uintptr_t dummy_address = (0 == chip_select) ? + (0 == unit) ? + BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - mirror_address_delta : // unit0 cs0 + BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS - mirror_address_delta : // unit1 cs0 + (0 == unit) +#if XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE + ? p_cfg_extend->p_address_space->unit0_cs1_start_address - mirror_address_delta : // unit0 cs1 + p_cfg_extend->p_address_space->unit1_cs1_start_address - mirror_address_delta; // unit1 cs1 +#else + ? BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / + 2 - mirror_address_delta : // unit0 cs1 + BSP_FEATURE_XSPI_DEVICE_1_START_ADDRESS + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE / 2 - + mirror_address_delta; // unit1 cs1 +#endif + +#ifdef BSP_CFG_CORE_CA55 + uintptr_t dummy_address_va = 0U; + R_BSP_MmuPatoVa(dummy_address, &dummy_address_va, BSP_MMU_CONVERSION_NON_CACHE); + if (0U == dummy_address_va) + { + R_BSP_MmuPatoVa(dummy_address, &dummy_address_va, BSP_MMU_CONVERSION_CACHE); + } + dummy_address = dummy_address_va; +#endif + + dummy = *(uint8_t *) dummy_address; + + if (false == enter_mode) + { + if (XSPI_QSPI_CHIP_SELECT_0 == chip_select) + { + p_instance_ctrl->p_reg->BMCTL0_b.CS0ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_W_ENABLE; + } + else + { + p_instance_ctrl->p_reg->BMCTL0_b.CS1ACC = XSPI_QSPI_PRV_BMCTL_CSNACC_R_W_ENABLE; + } + } + + return FSP_SUCCESS; +} + +/*******************************************************************************************************************//** + * Gets device status. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * + * @return True if busy, false if not. + **********************************************************************************************************************/ +static bool r_xspi_qspi_status_sub (xspi_qspi_instance_ctrl_t * p_instance_ctrl) +{ + spi_flash_cfg_t const * p_cfg = p_instance_ctrl->p_cfg; + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_cfg->p_extend; + + spi_flash_direct_transfer_t direct_command = {0}; + + bool restore_spi_protocol = false; + spi_flash_protocol_t setting_protocol = (spi_flash_protocol_t) 0x00; + + direct_command.command = p_cfg->status_command; + direct_command.command_length = 1U; + direct_command.data_length = 1U; + + /* For most devices, the Read Status Register instruction is executed with the 1S-1S-1S instruction, + * even if it assumes 1S-2S-2S or 1S-4S-4S Write instruction. + * Therefore, the communication protocol is temporarily switched. */ + if ((SPI_FLASH_PROTOCOL_1S_4S_4S == p_instance_ctrl->spi_protocol) || + (SPI_FLASH_PROTOCOL_1S_2S_2S == p_instance_ctrl->spi_protocol)) + { + setting_protocol = p_instance_ctrl->spi_protocol; + p_instance_ctrl->p_reg->LIOCFGCS_b[p_cfg_extend->chip_select].PRTMD = SPI_FLASH_PROTOCOL_1S_1S_1S; + p_instance_ctrl->spi_protocol = SPI_FLASH_PROTOCOL_1S_1S_1S; + restore_spi_protocol = true; + } + + r_xspi_qspi_direct_transfer(p_instance_ctrl, &direct_command, SPI_FLASH_DIRECT_TRANSFER_DIR_READ); + + /* Restore communication protocol. */ + if (true == restore_spi_protocol) + { + p_instance_ctrl->p_reg->LIOCFGCS_b[p_cfg_extend->chip_select].PRTMD = setting_protocol; + p_instance_ctrl->spi_protocol = setting_protocol; + } + + return (bool) ((direct_command.data >> p_instance_ctrl->p_cfg->write_status_bit) & + XSPI_QSPI_PRV_DEVICE_WRITE_STATUS_BIT_MASK); +} + +/*******************************************************************************************************************//** + * Performs direct data transfer with the SerialFlash + * + * @param[in] p_instance_ctrl Pointer to QSPI specific control structure + * @param[in] p_transfer Pointer to transfer parameters + * @param[in] direction Read/Write + **********************************************************************************************************************/ +static void r_xspi_qspi_direct_transfer (xspi_qspi_instance_ctrl_t * p_instance_ctrl, + spi_flash_direct_transfer_t * const p_transfer, + spi_flash_direct_transfer_dir_t direction) +{ + p_instance_ctrl->p_reg->CDCTL0_b.TRNUM = 0; + + /* Direct Read/Write settings + * (see RZ microprocessor User's Manual section "Flow of Manual-command Procedure"). */ + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->CDCTL0_b.TRREQ, 0); + + p_instance_ctrl->p_reg->BUF[0].CDT = + ((p_transfer->command_length & XSPI_QSPI_PRV_CDTBUF_CMDSIZE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_CMDSIZE_OFFSET) | + ((p_transfer->address_length & XSPI_QSPI_PRV_CDTBUF_ADDSIZE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_ADDSIZE_OFFSET) | + ((p_transfer->data_length & XSPI_QSPI_PRV_CDTBUF_DATASIZE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_DATASIZE_OFFSET) | + ((p_transfer->dummy_cycles & XSPI_QSPI_PRV_CDTBUF_LATE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_LATE_OFFSET) | + ((direction & XSPI_QSPI_PRV_CDTBUF_TRTYPE_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_TRTYPE_OFFSET) | + ((p_transfer->command & XSPI_QSPI_PRV_CDTBUF_CMD_VALUE_MASK) << + XSPI_QSPI_PRV_CDTBUF_CMD_UPPER_OFFSET); + + p_instance_ctrl->p_reg->BUF[0].CDA = p_transfer->address; + + if (SPI_FLASH_DIRECT_TRANSFER_DIR_WRITE == direction) + { + p_instance_ctrl->p_reg->BUF[0].CDD0 = (uint32_t) p_transfer->data_u64 & UINT32_MAX; + if (p_transfer->data_length > sizeof(uint32_t)) + { + p_instance_ctrl->p_reg->BUF[0].CDD1 = (uint32_t) (p_transfer->data_u64 >> XSPI_QSPI_PRV_UINT32_BITS) & + UINT32_MAX; + } + } + + p_instance_ctrl->p_reg->CDCTL0_b.TRREQ = 1; + FSP_HARDWARE_REGISTER_WAIT(p_instance_ctrl->p_reg->INTS_b.CMDCMP, 1); + + if (SPI_FLASH_DIRECT_TRANSFER_DIR_READ == direction) + { + p_transfer->data_u64 = p_instance_ctrl->p_reg->BUF[0].CDD0; + if (p_transfer->data_length > sizeof(uint32_t)) + { + p_transfer->data_u64 |= (uint64_t) (p_instance_ctrl->p_reg->BUF[0].CDD1) << XSPI_QSPI_PRV_UINT32_BITS; + } + } + + p_instance_ctrl->p_reg->INTC = 1 << XSPI_QSPI_PRV_INTC_CMDCMPC_OFFSET; +} + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + +/*******************************************************************************************************************//** + * Parameter checking. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * + * @retval FSP_SUCCESS Device size stored in p_device_size_bytes + * @retval FSP_ERR_ASSERTION A required pointer is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_param_checking_dcom (xspi_qspi_instance_ctrl_t * p_instance_ctrl) +{ + FSP_ASSERT(NULL != p_instance_ctrl); + FSP_ERROR_RETURN(XSPI_QSPI_PRV_OPEN == p_instance_ctrl->open, FSP_ERR_NOT_OPEN); + + FSP_ERROR_RETURN(0U == p_instance_ctrl->p_reg->CMCTL_b.XIPEN, FSP_ERR_INVALID_MODE); + + /* Verify device is not busy. */ + FSP_ERROR_RETURN(!r_xspi_qspi_status_sub(p_instance_ctrl), FSP_ERR_DEVICE_BUSY); + + return FSP_SUCCESS; +} + +#endif + +#if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + +/*******************************************************************************************************************//** + * Parameter checking for R_XSPI_QSPI_Write. + * + * @param[in] p_instance_ctrl Pointer to a driver handle + * @param[in] p_src The source of the data to write to QSPI + * @param[in] p_dest The address in QSPI to write to + * @param[in] byte_count The number of bytes to write + * + * @retval FSP_SUCCESS Parameters are valid. + * @retval FSP_ERR_ASSERTION p_instance_ctrl,p_device_address or p_memory_address is NULL. + * @retval FSP_ERR_NOT_OPEN Driver is not opened. + * @retval FSP_ERR_INVALID_MODE This function can't be called when XIP mode is enabled. + * @retval FSP_ERR_DEVICE_BUSY The device is busy. + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_program_param_check (xspi_qspi_instance_ctrl_t * p_instance_ctrl, + uint8_t const * const p_src, + uint8_t * const p_dest, + uint32_t byte_count) +{ + fsp_err_t err = r_xspi_qspi_param_checking_dcom(p_instance_ctrl); + FSP_ERROR_RETURN(FSP_SUCCESS == err, err); + FSP_ASSERT(NULL != p_src); + FSP_ASSERT(NULL != p_dest); + + /* Check if byte_count is valid */ + uintptr_t page_size_bytes = p_instance_ctrl->p_cfg->page_size_bytes; + uintptr_t bytes_left_in_page = page_size_bytes - ((uintptr_t) p_dest % page_size_bytes); + FSP_ASSERT(byte_count <= bytes_left_in_page); + + #if !XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE && BSP_FEATURE_XSPI_HAS_AXI_BRIDGE + FSP_ASSERT(XSPI_QSPI_PRV_DIRECT_TRANSFER_MAX_BYTES >= byte_count); + #else + FSP_ASSERT(XSPI_QSPI_PRV_MAX_COMBINE_SIZE >= byte_count); + #endif + + return FSP_SUCCESS; +} + +#endif + +#if XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE + +/*******************************************************************************************************************//** + * Configures OTFD side channel seed information. + * + * @param[out] p_seed Pointer to seed array. + * @retval FSP_SUCCESS OTFD seed initialization completed successfully. + * @return See @ref RENESAS_ERROR_CODES or functions called by this function for other possible return codes. + * This function calls: + * * @ref R_RSIP_RandomNumberGenerate + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_otfd_side_channal_seed_init (uint32_t p_seed[]) +{ + uint32_t random_number[4U] = {0}; + fsp_err_t err = R_RSIP_RandomNumberGenerate(&g_xspi_qspi_rsip_ctrl, (uint8_t *) &random_number[0]); + + if (FSP_SUCCESS == err) + { + p_seed[0] = random_number[0]; + p_seed[1] = (random_number[1] & XSPI_QSPI_PRV_OTFD_SEED_1_SEED_MASK) | XSPI_QSPI_PRV_OTFD_SEED_1_ENABLE_MASK; + } + + return err; +} + +/*******************************************************************************************************************//** + * Configures the device for OTFD operation. + * + * @param[in] p_instance_ctrl Pointer to the instance ctrl struct. + * @retval FSP_SUCCESS OTFD configuration completed successfully. + * @retval FSP_ERR_INVALID_ARGUMENT Invalid key type argument or invalid OTFD conversion area. + * @return See @ref RENESAS_ERROR_CODES or functions called by this function for other possible return codes. + * This function calls: + * * @ref R_RSIP_Open + * * @ref R_RSIP_InjectedKeyImport + * * @ref R_RSIP_OTF_Init + * * @ref R_RSIP_Close + **********************************************************************************************************************/ +static fsp_err_t r_xspi_qspi_otfd_setup (xspi_qspi_instance_ctrl_t * p_instance_ctrl) +{ + fsp_err_t rsip_ret = FSP_SUCCESS; + uint32_t mirror_address_delta = BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS - + BSP_FEATURE_XSPI_DEVICE_0_MIRROR_START_ADDRESS; + uint32_t seed[2] = {0}; + uint8_t wrapped_key[RSIP_BYTE_SIZE_WRAPPED_KEY_AES_256] = {0}; + + xspi_qspi_extended_cfg_t * p_cfg_extend = (xspi_qspi_extended_cfg_t *) p_instance_ctrl->p_cfg->p_extend; + xspi_qspi_otfd_cfg_t * p_otfd_cfg = (xspi_qspi_otfd_cfg_t *) p_cfg_extend->p_otfd_cfg; + + rsip_key_type_t key_type = RSIP_KEY_TYPE_AES_128; + + if (XSPI_QSPI_OTFD_AES_KEY_TYPE_128 == p_otfd_cfg->key_type) + { + key_type = RSIP_KEY_TYPE_AES_128; + } + else if (XSPI_QSPI_OTFD_AES_KEY_TYPE_256 == p_otfd_cfg->key_type) + { + key_type = RSIP_KEY_TYPE_AES_256; + } + else + { + return FSP_ERR_INVALID_ARGUMENT; + } + + #if XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE + + /* Verify OTFD conversion area. */ + FSP_ERROR_RETURN((uint32_t) p_otfd_cfg->p_end_addr >= (uint32_t) p_otfd_cfg->p_start_addr, + FSP_ERR_INVALID_ARGUMENT); + FSP_ERROR_RETURN((uint32_t) p_otfd_cfg->p_start_addr >= + (uint32_t) (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + (p_cfg_extend->unit) * + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE), + FSP_ERR_INVALID_ARGUMENT); + FSP_ERROR_RETURN((uint32_t) p_otfd_cfg->p_end_addr < + (uint32_t) (BSP_FEATURE_XSPI_DEVICE_0_START_ADDRESS + (p_cfg_extend->unit + 1U) * + BSP_FEATURE_XSPI_DEVICE_ADDRESS_SPACE_SIZE), + FSP_ERR_INVALID_ARGUMENT); + #endif + + /* Set the start and end area for OTFD conversion. */ + p_instance_ctrl->p_otfd_reg->CONVAREAST = ((uint32_t) p_otfd_cfg->p_start_addr - mirror_address_delta) & + R_OTFD0_CONVAREAST_CONVAREAST_Msk; + p_instance_ctrl->p_otfd_reg->CONVAREAED = ((uint32_t) p_otfd_cfg->p_end_addr - mirror_address_delta) & + R_OTFD0_CONVAREAED_CONVAREAED_Msk; + + /* Open RSIP. */ + rsip_ret = R_RSIP_Open(&g_xspi_qspi_rsip_ctrl, &g_xspi_qspi_rsip_cfg); + FSP_ERROR_RETURN(FSP_SUCCESS == rsip_ret, rsip_ret); + + rsip_wrapped_key_t * p_wrapped_key = (rsip_wrapped_key_t *) wrapped_key; + + /* Generates structure data "rsip_wrapped_key_t". */ + rsip_ret = R_RSIP_InjectedKeyImport(key_type, + (uint8_t *) p_otfd_cfg->p_key, + p_wrapped_key, + RSIP_BYTE_SIZE_WRAPPED_KEY_AES_256); + FSP_ERROR_RETURN(FSP_SUCCESS == rsip_ret, rsip_ret); + + rsip_ret = r_xspi_qspi_otfd_side_channal_seed_init(seed); + FSP_ERROR_RETURN(FSP_SUCCESS == rsip_ret, rsip_ret); + + /* Init OTFD. */ + rsip_ret = + R_RSIP_OTF_Init(&g_xspi_qspi_rsip_ctrl, + (rsip_otf_channel_t) p_cfg_extend->unit, + p_wrapped_key, + (uint8_t *) &seed[0]); + FSP_ERROR_RETURN(FSP_SUCCESS == rsip_ret, rsip_ret); + + if (FSP_SUCCESS == rsip_ret) + { + /* Disable byte order conversion. */ + p_instance_ctrl->p_otfd_reg->REG00 = (XSPI_QSPI_PRV_OTFD_REG00_RESET_VALUE | R_OTFD0_REG00_B09_Msk); + + /* Load the IV. */ + p_instance_ctrl->p_otfd_reg->REG03 = p_otfd_cfg->p_iv[0]; + p_instance_ctrl->p_otfd_reg->REG03 = p_otfd_cfg->p_iv[1]; + p_instance_ctrl->p_otfd_reg->REG03 = p_otfd_cfg->p_iv[2]; + p_instance_ctrl->p_otfd_reg->REG03 = p_otfd_cfg->p_iv[3]; + } + + /* Close RSIP. */ + rsip_ret = R_RSIP_Close(&g_xspi_qspi_rsip_ctrl); + FSP_ERROR_RETURN(FSP_SUCCESS == rsip_ret, rsip_ret); + + return rsip_ret; +} + +#endif diff --git a/zephyr/rz/rz_cfg/fsp_cfg/rza/r_spibsc_cfg.h b/zephyr/rz/rz_cfg/fsp_cfg/rza/r_spibsc_cfg.h new file mode 100644 index 00000000..f1086786 --- /dev/null +++ b/zephyr/rz/rz_cfg/fsp_cfg/rza/r_spibsc_cfg.h @@ -0,0 +1,13 @@ +/* +* Copyright (c) 2020 - 2025 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef R_SPIBSC_CFG_H_ +#define R_SPIBSC_CFG_H_ +#define SPIBSC_CFG_PARAM_CHECKING_ENABLE (1) +#define SPIBSC_CFG_INITIALIZATION (0) +#define SPIBSC_CFG_CODE_SECTION ".text" +#define SPIBSC_CFG_MMAP_BASE 0x20000000 +#endif /* R_SPIBSC_CFG_H_ */ diff --git a/zephyr/rz/rz_cfg/fsp_cfg/rzn/r_xspi_qspi_cfg.h b/zephyr/rz/rz_cfg/fsp_cfg/rzn/r_xspi_qspi_cfg.h new file mode 100644 index 00000000..8068ea81 --- /dev/null +++ b/zephyr/rz/rz_cfg/fsp_cfg/rzn/r_xspi_qspi_cfg.h @@ -0,0 +1,23 @@ +/* +* Copyright (c) 2020 - 2025 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef R_XSPI_QSPI_CFG_H_ +#define R_XSPI_QSPI_CFG_H_ +#define XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE (BSP_CFG_PARAM_CHECKING_ENABLE) +#define XSPI_QSPI_CFG_UNIT_0_PREFETCH_FUNCTION (0) +#define XSPI_QSPI_CFG_UNIT_1_PREFETCH_FUNCTION (0) +#define XSPI_QSPI_CFG_UNIT_0_IOVOLTAGE (0) +#define XSPI_QSPI_CFG_UNIT_1_IOVOLTAGE (0) +#define XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE (0) +#define XSPI_QSPI_CFG_UNIT_0_CS_0_END_ADDRESS (0x600FFFFF) +#define XSPI_QSPI_CFG_UNIT_0_CS_1_START_ADDRESS (0x64000000) +#define XSPI_QSPI_CFG_UNIT_0_CS_1_END_ADDRESS (0x640FFFFF) +#define XSPI_QSPI_CFG_UNIT_1_CS_0_END_ADDRESS (0x680FFFFF) +#define XSPI_QSPI_CFG_UNIT_1_CS_1_START_ADDRESS (0x6C000000) +#define XSPI_QSPI_CFG_UNIT_1_CS_1_END_ADDRESS (0x6C0FFFFF) +#define XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE (0) +#define XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE (0) +#endif /* R_XSPI_QSPI_CFG_H_ */ diff --git a/zephyr/rz/rz_cfg/fsp_cfg/rzt/r_xspi_qspi_cfg.h b/zephyr/rz/rz_cfg/fsp_cfg/rzt/r_xspi_qspi_cfg.h new file mode 100644 index 00000000..8068ea81 --- /dev/null +++ b/zephyr/rz/rz_cfg/fsp_cfg/rzt/r_xspi_qspi_cfg.h @@ -0,0 +1,23 @@ +/* +* Copyright (c) 2020 - 2025 Renesas Electronics Corporation and/or its affiliates +* +* SPDX-License-Identifier: BSD-3-Clause +*/ + +#ifndef R_XSPI_QSPI_CFG_H_ +#define R_XSPI_QSPI_CFG_H_ +#define XSPI_QSPI_CFG_PARAM_CHECKING_ENABLE (BSP_CFG_PARAM_CHECKING_ENABLE) +#define XSPI_QSPI_CFG_UNIT_0_PREFETCH_FUNCTION (0) +#define XSPI_QSPI_CFG_UNIT_1_PREFETCH_FUNCTION (0) +#define XSPI_QSPI_CFG_UNIT_0_IOVOLTAGE (0) +#define XSPI_QSPI_CFG_UNIT_1_IOVOLTAGE (0) +#define XSPI_QSPI_CFG_DMAC_SUPPORT_ENABLE (0) +#define XSPI_QSPI_CFG_UNIT_0_CS_0_END_ADDRESS (0x600FFFFF) +#define XSPI_QSPI_CFG_UNIT_0_CS_1_START_ADDRESS (0x64000000) +#define XSPI_QSPI_CFG_UNIT_0_CS_1_END_ADDRESS (0x640FFFFF) +#define XSPI_QSPI_CFG_UNIT_1_CS_0_END_ADDRESS (0x680FFFFF) +#define XSPI_QSPI_CFG_UNIT_1_CS_1_START_ADDRESS (0x6C000000) +#define XSPI_QSPI_CFG_UNIT_1_CS_1_END_ADDRESS (0x6C0FFFFF) +#define XSPI_QSPI_CFG_CUSTOM_ADDR_SPACE_ENABLE (0) +#define XSPI_QSPI_CFG_OTFD_SUPPORT_ENABLE (0) +#endif /* R_XSPI_QSPI_CFG_H_ */