From 8b4b440f7138809d7c68f66529387e58eb0ba816 Mon Sep 17 00:00:00 2001 From: Lavakrishna Dussa - I68641 Date: Wed, 22 May 2024 13:42:17 +0530 Subject: [PATCH] CoreQSPI: Add coreqspi driver source code These files are from coreqspi driver source repo. Commit:5f3a89ea9fd1df94cadd30f2567a69f25f2e8953 Tag :2.1.103 Jira-id: ESSBM-186 Signed-off-by: Lavakrishna Dussa - I68641 --- drivers/fpga_ip/CoreQSPI/core_qspi.c | 488 ++++++++++++++ drivers/fpga_ip/CoreQSPI/core_qspi.h | 767 ++++++++++++++++++++++ drivers/fpga_ip/CoreQSPI/core_qspi_regs.h | 272 ++++++++ 3 files changed, 1527 insertions(+) create mode 100644 drivers/fpga_ip/CoreQSPI/core_qspi.c create mode 100644 drivers/fpga_ip/CoreQSPI/core_qspi.h create mode 100644 drivers/fpga_ip/CoreQSPI/core_qspi_regs.h diff --git a/drivers/fpga_ip/CoreQSPI/core_qspi.c b/drivers/fpga_ip/CoreQSPI/core_qspi.c new file mode 100644 index 0000000..2f34c2b --- /dev/null +++ b/drivers/fpga_ip/CoreQSPI/core_qspi.c @@ -0,0 +1,488 @@ +/******************************************************************************* + * Copyright 2024 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_qspi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreQSPI driver implementation. Please refer to core_qspi.h file for + * description of functions implemented in this file. + * + */ + +#include "core_qspi_regs.h" +#include "core_qspi.h" +#include "hal/hal.h" +#include "hal/hal_assert.h" + +#define NULL_QSPI_INSTANCE ((qspi_instance_t *)0) +#define NULL_BUFFER ((uint8_t*)0) + +static void default_status_hanlder(uint32_t value); +static volatile uint32_t g_irq_rd_byte_size = 0u; +static void * g_rd_buffer; +static volatile qspi_status_handler_t g_handler; + +/***************************************************************************//** + * QSPI_init() + * See "core_qspi.h" for details of how to use this function. + */ +void +QSPI_init +( + qspi_instance_t *this_qspi, + addr_t addr +) +{ + uint32_t reg_read = 0u; + g_handler = default_status_hanlder; + + HAL_ASSERT(this_qspi != NULL_QSPI_INSTANCE); + + this_qspi->base_address = addr; + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((reg_read) | CTRL_ENABLE_MASK)); + + /* Enable the core, core samples SDI in master mode, sets SPI clock rate, + * allows spi memory operations in mode 0 or mode 3. + */ + HAL_set_32bit_reg_field(addr, CTRL_ENABLE, 1u); + HAL_set_32bit_reg_field(addr, CTRL_SAMPLE, 0u); + HAL_set_32bit_reg_field(addr, CTRL_CLKRATE, 1u); + HAL_set_32bit_reg_field(addr, CTRL_CLKIDLE, 1u); + + /* Interrupt enable register -> Enables the external interrupt for the + * corresponding interrupt*/ + HAL_set_32bit_reg(addr, INT_ENABLE, 0u); +} + +/***************************************************************************//** + * QSPI_configure() + * See core_qspi.h for details of how to use this function. + */ +void +QSPI_configure +( + qspi_instance_t *this_qspi, + const qspi_config_t* config +) +{ + /* Configure QSPI. Called from micron_mt25q.c flash_init() */ + uint32_t temp_reg_read = 0u; + + temp_reg_read = (uint32_t)((config->sample) << CTRL_SAMPLE_SHIFT) | + (uint32_t)((config->io_format) << CTRL_QMODE0_SHIFT) | + (uint32_t)((config->clk_div) << CTRL_CLKRATE_SHIFT) | + (uint32_t)((config->xip) << CTRL_XIP_SHIFT) | + (uint32_t)((config->xip_addr) << CTRL_XIPADDR_SHIFT) | + (uint32_t)((config->spi_mode) << CTRL_CLKIDLE_SHIFT) | + CTRL_ENABLE_MASK; + + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, temp_reg_read); +} + +/***************************************************************************//** + * QSPI_get_config() + * See core_qspi.h for details of how to use this function. + */ +void QSPI_get_config +( + qspi_instance_t *this_qspi, + qspi_config_t* config +) +{ + volatile uint32_t reg =0; + + reg = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + + config->spi_mode = ((reg & CTRL_CLKIDLE_MASK) >> CTRL_CLKIDLE_SHIFT); + + reg = reg & (uint32_t )((uint32_t )CTRL_QMODE12_MASK + | (uint32_t )CTRL_QMODE0_MASK); + + reg = reg >> CTRL_QMODE0_SHIFT; + + config->io_format = (qspi_io_format)reg; + config->clk_div = (qspi_clk_div)((reg & CTRL_CLKRATE_MASK) + >> CTRL_CLKRATE_SHIFT); + + config->xip = (uint8_t)((reg & CTRL_XIP_MASK) >> CTRL_XIP_SHIFT); + config->xip_addr = (uint8_t)((reg & CTRL_XIPADDR_MASK) >> CTRL_XIPADDR_SHIFT); + config->sample = (uint8_t)((reg & CTRL_SAMPLE_MASK) >> CTRL_SAMPLE_SHIFT); +} + +/***************************************************************************//** + * QSPI_polled_transfer_block() + * See mss_qspi.h for details of how to use this function. + */ +void +QSPI_polled_transfer_block +( + qspi_instance_t *this_qspi, + uint8_t num_addr_bytes, + const void * const tx_buffer, + uint32_t tx_byte_size, + const void * const rd_buffer, + uint32_t rd_byte_size, + uint8_t num_idle_cycles +) +{ + uint32_t idx; + uint32_t reg_read = 0; + uint8_t* buf8 = (uint8_t*)tx_buffer; + uint32_t* buf32 = (uint32_t*)tx_buffer; + volatile uint32_t skips; + uint32_t cbytes; + uint32_t total_byte_cnt; + uint32_t words = 0u; + uint32_t total_bytes_tx = 0u; + + HAL_ASSERT(tx_byte_size <= 0xFFFFu); + HAL_ASSERT(num_addr_bytes <= 4u); + HAL_ASSERT(num_idle_cycles <= 15u); + + cbytes = 1u + num_addr_bytes; + total_bytes_tx = 1u + tx_byte_size + num_addr_bytes; + total_byte_cnt = 1u + tx_byte_size + num_addr_bytes + rd_byte_size; + + HAL_set_32bit_reg(this_qspi->base_address, INT_ENABLE, 0u); + + do{ + reg_read = HAL_get_32bit_reg(this_qspi->base_address, STATUS); + } while(((reg_read) & STATUS_READY_MASK) == 0u); + + /* bit16 to 31 define the number of Upper bytes when count is >65535 + Write to lower 16 bit is ignored */ + HAL_set_32bit_reg(this_qspi->base_address, FRAMESUP, + total_byte_cnt & FRAMESUP_BYTESUPPER_MASK); + + if ((tx_byte_size <= 0xFFFFu) && + (num_addr_bytes <= 4u) && + (num_idle_cycles <= 15u)) + { + /* Calculating skip bits */ + skips = (total_byte_cnt & FRAMES_TOTALBYTES_MASK); + skips |= (cbytes << FRAMES_COMMANDBYTES_SHIFT); + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + skips |= (((reg_read & CTRL_QMODE12_MASK) ? 1u : 0u) << FRAMES_QSPI_SHIFT); + skips |= ((uint32_t)num_idle_cycles) << FRAMES_IDLE_SHIFT; + skips |= FRAMES_FLAGWORD_MASK; + + /* Write the calculated skip bits into frames register */ + HAL_set_32bit_reg(this_qspi->base_address, FRAMES, (uint32_t)skips); + } + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((reg_read) | CTRL_FLAGSX4_MASK)); + + words = total_bytes_tx / (uint32_t)4u; + + /* Load the transmit data into transmitdatax4 data register */ + for (idx = 0u; idx < words; ++idx) + { + do{ + reg_read = HAL_get_32bit_reg(this_qspi->base_address, STATUS); + } while((reg_read) & STATUS_TXFIFOFULL_MASK); + + HAL_set_32bit_reg(this_qspi->base_address, X4TRANSMIT_DATA, (uint32_t)buf32[idx]); + } + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((reg_read) & ~(CTRL_FLAGSX4_MASK))); + + uint32_t l_idx = (total_bytes_tx - (total_bytes_tx % 4u)); + + /* Load the transmit data into transmit data register */ + for (idx = l_idx; idx < total_bytes_tx; ++idx) + { + do{ + reg_read = HAL_get_32bit_reg(this_qspi->base_address, STATUS); + } while((reg_read) & STATUS_TXFIFOFULL_MASK); + + HAL_set_32bit_reg(this_qspi->base_address, TRANSMIT_DATA, (uint8_t)buf8[idx]); + } + + buf32 = (uint32_t*)rd_buffer; + buf8 = (uint8_t*)rd_buffer; + + /* Receive data */ + if (rd_byte_size) + { + words = rd_byte_size / 4u; + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((reg_read) | CTRL_FLAGSX4_MASK)); + + /* Load the TransmitX4 receive data into buf32 */ + for (idx = 0u; idx < words; ++idx) + { + do{ + reg_read = HAL_get_32bit_reg(this_qspi->base_address, STATUS); + } while((reg_read) & STATUS_RXFIFOEMPTY_MASK); + + buf32[idx] = HAL_get_32bit_reg(this_qspi->base_address, X4RECEIVE_DATA); + } + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((reg_read) & ~(CTRL_FLAGSX4_MASK))); + + l_idx = (rd_byte_size - (rd_byte_size % 4u)); + + /* Load the transmit data register contents into buf8 */ + for (idx = l_idx; idx < rd_byte_size; ++idx) + { + do{ + reg_read = HAL_get_32bit_reg(this_qspi->base_address, STATUS); + } while((reg_read) & STATUS_RXFIFOEMPTY_MASK); + + buf8[idx] = HAL_get_32bit_reg(this_qspi->base_address, RECEIVE_DATA); + } + + /* Wait for RXDONE to complete and ignore the skip bits */ + do{ + skips = (uint64_t)(((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, STATUS)) + & (uint32_t)(STATUS_FLAGSX4_MASK)) + ? (uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, X4RECEIVE_DATA)) + : (uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, RECEIVE_DATA))); + } while (0u == (uint32_t)((HAL_get_32bit_reg(this_qspi->base_address, STATUS)) + & STATUS_RXDONE_MASK)); + } +} + +/***************************************************************************//** + * QSPI_irq_transfer_block() + * See mss_qspi.h for details of how to use this function. + */ +uint8_t +QSPI_irq_transfer_block +( + qspi_instance_t *this_qspi, + uint8_t num_addr_bytes, + const void * const tx_buffer, + uint32_t tx_byte_size, + const void * const rd_buffer, + uint32_t rd_byte_size, + uint8_t num_idle_cycles +) +{ + uint32_t idx; + uint32_t reg_read = 0u; + uint32_t cbytes; + uint32_t total_byte_cnt; + const uint8_t* buf8 = tx_buffer; + const uint32_t* buf32 = tx_buffer; + volatile uint32_t skips = 0; + uint8_t returnval = 0u; + uint32_t l_idx = 0u; + uint32_t words = 0u; + uint32_t enable = 0u; + + HAL_ASSERT(tx_byte_size <= 0xFFFFu); + HAL_ASSERT(num_addr_bytes <= 4u); + HAL_ASSERT(num_idle_cycles <= 15u); + + g_rd_buffer = (uint32_t*)rd_buffer; + + cbytes = 1u + tx_byte_size + num_addr_bytes; + total_byte_cnt = 1u + tx_byte_size + num_addr_bytes + rd_byte_size; + + do{ + reg_read = HAL_get_32bit_reg(this_qspi->base_address, STATUS); + } while(((reg_read) & STATUS_READY_MASK) == 0u); + + enable = INT_ENABLE_TXDONE_MASK; + + /* bit16 to 31 define the number of Upper bytes when count is >65535 + Write to lower 16 bit is ignored */ + HAL_set_32bit_reg(this_qspi->base_address, FRAMESUP, + (total_byte_cnt & FRAMESUP_BYTESUPPER_MASK)); + + if((tx_byte_size <= 0xFFFFu) && + (num_addr_bytes <= 4u) && + (num_idle_cycles <= 15u)) + { + /* Calculating skip bits */ + skips = (total_byte_cnt & FRAMES_TOTALBYTES_MASK); + skips |= (cbytes << FRAMES_COMMANDBYTES_SHIFT); + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + skips |= (((reg_read & CTRL_QMODE12_MASK) ? 1u : 0u) << FRAMES_QSPI_SHIFT); + + skips |= ((uint32_t)num_idle_cycles) << FRAMES_IDLE_SHIFT; + } + + skips |= FRAMES_FLAGWORD_MASK; + HAL_set_32bit_reg(this_qspi->base_address, FRAMES, skips); + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + (reg_read | CTRL_FLAGSX4_MASK)); + words = cbytes / (uint32_t)4u; + + for (idx = 0u; idx < words; ++idx) + { + while ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, STATUS)) & + (uint32_t)STATUS_TXFIFOFULL_MASK){}; + + HAL_set_32bit_reg(this_qspi->base_address, X4TRANSMIT_DATA, + (uint32_t)buf32[idx]); + } + + reg_read = HAL_get_32bit_reg(this_qspi->base_address, CONTROL); + + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + (reg_read & (~CTRL_FLAGSX4_MASK))); + + sleep_ms(10); + for (idx = (cbytes - (cbytes % 4u)); idx < cbytes; ++idx) + { + while ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, STATUS)) & + (uint32_t)STATUS_TXFIFOFULL_MASK){}; + HAL_set_32bit_reg(this_qspi->base_address, TRANSMIT_DATA, + (uint8_t)buf8[idx]); + } + + g_irq_rd_byte_size = rd_byte_size; + enable |= (uint32_t )(INT_ENABLE_RXDONE_MASK | INT_ENABLE_RXAVAILABLE_MASK); + + + HAL_set_32bit_reg(this_qspi->base_address, INT_ENABLE, enable); + + /* + * This delay is needed to get proper data into the RXFIFOs + * With out this delay, once the RX_AVAILABLE bit is set + * the data available in RXFIFO is incorrect. + */ + if (rd_byte_size != 0) + sleep_ms(10); + + return (returnval); +} + +/***************************************************************************//** + * QSPI_set_status_handler() + * See mss_qspi.h for details of how to use this function. + */ +void +QSPI_set_status_handler +( + qspi_status_handler_t handler +) +{ + if ((qspi_status_handler_t)0 != handler) + { + g_handler = handler; + } +} + +void +qspi_isr +( + qspi_instance_t *this_qspi +) +{ + uint32_t idx; + static uint32_t empty = 0u; + static uint32_t tx_fifo_full = 0u; + uint32_t status; + uint32_t l_idx = 0; + + status = HAL_get_32bit_reg(this_qspi->base_address, STATUS); + + if (STATUS_TXDONE_MASK == (uint32_t)(status & STATUS_TXDONE_MASK)) + { + g_handler(STATUS_TXDONE_MASK); + + HAL_set_32bit_reg(this_qspi->base_address, STATUS, + ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, STATUS)) + | (uint32_t)STATUS_TXDONE_MASK)); + + } + + if (STATUS_RXAVAILABLE_MASK == (uint32_t)(status & STATUS_RXAVAILABLE_MASK)) + { + + HAL_set_32bit_reg(this_qspi->base_address, STATUS, + ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, STATUS)) + | (uint32_t)STATUS_RXAVAILABLE_MASK)); + + uint8_t* buf8 = g_rd_buffer; + uint32_t* buf32 = g_rd_buffer; + uint32_t words = 0u; + + words = g_irq_rd_byte_size / 4u; + + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, CONTROL)) + | (uint32_t)CTRL_FLAGSX4_MASK)); + + for (idx = 0u; idx < words; ++idx) + { + while ((HAL_get_32bit_reg(this_qspi->base_address, STATUS)) & STATUS_RXFIFOEMPTY_MASK){}; + buf32[idx] = HAL_get_32bit_reg(this_qspi->base_address, X4RECEIVE_DATA); + } + + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, CONTROL)) + & ~(uint32_t)(CTRL_FLAGSX4_MASK))); + + l_idx = (g_irq_rd_byte_size - (g_irq_rd_byte_size % 4u)); + for (idx = l_idx; idx < g_irq_rd_byte_size; ++idx) + { + while ((HAL_get_32bit_reg(this_qspi->base_address, STATUS)) & STATUS_RXFIFOEMPTY_MASK){}; + buf8[idx] = HAL_get_32bit_reg(this_qspi->base_address, RECEIVE_DATA); + } + + uint32_t skips = 0; + + while (0u == ((HAL_get_32bit_reg(this_qspi->base_address, + STATUS)) & STATUS_RXFIFOEMPTY_MASK)) + { + /* Make sure that the Receive FIFO is empty and any + remaining data is read from it after desired bytes + have been received. */ + skips = (uint64_t)(((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, STATUS)) + & (uint32_t)STATUS_FLAGSX4_MASK) + ? (uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, X4RECEIVE_DATA)) + : (uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, RECEIVE_DATA))); + } + } + + if (STATUS_RXDONE_MASK == (uint32_t)(status & STATUS_RXDONE_MASK)) + { + + /* This means receive transfer is now complete. invoke the callback + * function */ + g_handler(STATUS_RXDONE_MASK); + + /* disable RXDONE, RXEMPTY, RXAVLBL interrupt */ + HAL_set_32bit_reg(this_qspi->base_address, INT_ENABLE, + ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, INT_ENABLE)) + & ~(uint32_t)(INT_ENABLE_RXDONE_MASK | INT_ENABLE_RXAVAILABLE_MASK))); + + HAL_set_32bit_reg(this_qspi->base_address, STATUS, + ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, STATUS)) + | (uint32_t)STATUS_RXDONE_MASK)); + + } +} + +static void +default_status_hanlder +( + uint32_t value +) +{ + /* Take some default interrupt handling action here */ +} + +#ifdef __cplusplus +} +#endif diff --git a/drivers/fpga_ip/CoreQSPI/core_qspi.h b/drivers/fpga_ip/CoreQSPI/core_qspi.h new file mode 100644 index 0000000..cc1e9c5 --- /dev/null +++ b/drivers/fpga_ip/CoreQSPI/core_qspi.h @@ -0,0 +1,767 @@ +/******************************************************************************* + * Copyright 2024 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_qspi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreQSPI prototypes + * + */ + +/** + @mainpage CoreQSPI Bare Metal Driver + + @section intro Introduction + This CoreQSPI provides AHB system Interface and SPI interface to connect with + the SPI memory devices. The control register is used to configure the IP in + different modes and the FIFO is used to buffer the data across clock domains. + + This driver provides a set of functions for configuring and controlling + CoreQSPI as part of a bare metal system, where no operating system is + available. This driver can be adapted as part of an operating system, but the + implementation of the adaptation layer between the driver and the operating + system's driver model is outside the scope of this user guide. + + This driver is not compatible with the CoreQSPI versions below v2.1. + + @subsection features Features + - Master operation + - Motorola SPI supported + - Slave select operation in idle cycles configurable + - Supports Extended SPI operation (1, 2, and 4-bit) + - Supports QSPI operation (4-bit operation) + - Supports BSPI operation (2-bit operation) + - Support XIP (execute in place) + - Supports three or four-byte SPI address + + @section theory_op Theory of Operation + The CoreQSPI driver functions are grouped into the following categories. + - Initialization and configuration functions + - Polled transmit and receive functions + - Interrupt-driven transmit and receive functions + +@section driver_initialization_configuration Driver Initialization and Configuration + + The CoreQSPI supports the following operations: + - Normal SPI operations (1-bit) + - Dual SPI operations (2-bit) + - Quad SPI operations (4-bit) + + The CoreQSPI driver provides the QSPI_init() function to initialize the + CoreQSPI hardware block. This initialization function must be called before + calling any other CoreQSPI driver functions. + + The CoreQSPI driver provides the QSPI_config() function to configure + QSPI with the desired configuration values. It also provides the + QSPI_get_config() function to read back the current configuration of QSPI + use QSPI_get_config() function to retrieve the current configurations and + then overwrite them with application-specific values, such as SPI mode, + SPI clock rate, SDI sampling, QSPI operation, XIP mode, and XIP address bits. + All these configuration options are explained in detail in the API function + description of the respective function. + +@section block_transfers SPI Master Block Transfer Control + + Once the driver is initialized and configured, data transmission and reception + are achieved by configuring it to the desired value. CoreQSPI is designed to + specifically work with SPI flash memories. It supports a single, active-low + slave-select output. Block transfers are accomplished in the following ways: + - Polled block transfer + - Interrupt-driven block transfer + +@subsection polled_block_transfers Polled Block Transfer + The QSPI_polled_transfer_block() function accomplishes data + transfers where no interrupt is used. The QSPI_polled_transfer_block() + function polls the status register to know the current status of the on-going + transfer. This is a blocking function. A CoreQSPI block transfer always has + some amount of data to be transmitted (at least one command byte), but + receiving useful data from the target memory device is optional. So, if the + scheduled block transfer is only transferring data and not receiving any data, + then QSPI_polled_transfer_block() function exits after transmitting the + required bytes. If data needs to be received from the target memory device + during a particular transfer, the QSPI_polled_transfer_block() function + terminates once the expected data is received from the target memory device. + +@subsection interrupt_block_transfers Interrupt Driven Block Transfer + + This block transfer is accomplished using interrupts instead of polling the + status register. The following functions are provided to support + interrupt-driven block transfers: + - QSPI_irq_transfer_block() + - QSPI_set_status_handler() + + The QSPI_set_status_handler() function must be used to set a status + handler call-back function with the driver. The QSPI_set_status_handler() + function is called back by the driver at two different stages of the transfer. + At the first stage, it is called when the required number of bytes are + transmitted. At the second stage, if there is data to be received from the + target memory device, it is invoked again once the desired data is received. + An appropriate status value is passed by the driver as a parameter of this + call-back function so that the application infers that an event has occurred. + +@section qspi_status QSPI Status + The QSPI_read_status() function reads the current status of CoreQSPI. The + QSPI_read_status() function is typically used to know the status of an + ongoing transfer. The QSPI_read_status() function returns the status + register value and is called at any time after CoreQSPI is initialized and + configured. + +@section direct_access Direct Access + CoreQSPI allows direct access to the QSPI interface pins to support access to + non-standard SPI devices through direct CPU control. + + This driver provides the following functions to read and write the direct + access register of CoreQSPI: + - QSPI_read_direct_access_reg() + - QSPI_write_direct_access_reg() + + Using these functions, you generate any sequence of binary transitions on the + QSPI pins that might be needed to communicate with the non-standard target + devices. + +*/ + +#ifndef CORE_QSPI_H_ +#define CORE_QSPI_H_ + +#include "hal/cpu_types.h" +#include "hal/hal.h" +#include "core_qspi_regs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + # SDI Pin Sampling + + The following constants can be used as input parameter value to configure the + event on which the SDI pin is sampled. + + @code + qspi_config.sample = QSPI_SAMPLE_POSAGE_SPICLK; + QSPI_configure(&qspi_config); + @endcode + +| Constant | Description | +|------------------|-----------------------| +|QSPI_SAMPLE_POSAGE_SPICLK |The SDI pin is sampled at the rising edge off SPI CLOCK| +|QSPI_SAMPLE_ACTIVE_SPICLK |The SDI pin is sampled on the last falling HCLK edge in the SPI clock period| +|QSPI_SAMPLE_NEGAGE_SPICLK |The SDI pin is sampled at the rising HCLK edge as SPICLK falls| + +*/ +#define QSPI_SAMPLE_POSAGE_SPICLK 0x00u +#define QSPI_SAMPLE_ACTIVE_SPICLK 0x01u +#define QSPI_SAMPLE_NEGAGE_SPICLK 0x02u + + +/** + # Generic constant definitions + The following constants can be used to configure the CoreQSPI where a zero or + non-zero value such as enable or disable is to be provided as input parameter. + + @code + qspi_config.xip = QSPI_DISABLE; + QSPI_configure(&qspi_config); + @endcode + +| Constant | Description | +|------------------|-----------------------| +|QSPI_ENABLE |Enable | +|QSPI_DISABLE |Disable | + + */ +#define QSPI_ENABLE 0x01u +#define QSPI_DISABLE 0x00u + +/** +The following table shows that these values are used to program the io_format +parameter of the configuration structure of this driver. + +@code + qspi_config.io_format = QSPI_QUAD_FULL; + QSPI_configure(&qspi_config); +@endcode + +| Value | Description | +|--------------------|---------------------------------------------------------| +|QSPI_NORMAL | 1-bit Normal SPI operations | +| | (single DQ0 TX and single DQ1 RX lines) | +| | | +|QSPI_DUAL_EX_RO | 2-bit SPI operations | +| | (command and address bytes on DQ0 only. data on DQ[1:0])| +| | | +|QSPI_QUAD_EX_RO | 4-bit SPI operations | +| | (command and address bytes on DQ0 only. data on DQ[3:0])| +| | | +|QSPI_DUAL_EX_RW | 2-bit SPI operations | +| | (command byte on DQ0 only. Address and data on DQ[1:0]) | +| | | +|QSPI_QUAD_EX_RW | 4-bit SPI operations | +| | (command byte on DQ0 only. Address and data on DQ[3:0]) | +| | | +|QSPI_DUAL_FULL | 2-bit SPI operations | +| | (command, address, and data on DQ[1:0]) | +| | | +|QSPI_QUAD_FULL | 4-bit SPI operations | +| | (command, address, and data on DQ[3:0]) | +| | | + +*/ +typedef enum qspi_io_format_t +{ + QSPI_NORMAL = 0u, + QSPI_DUAL_EX_RO = 2u, + QSPI_QUAD_EX_RO = 3u, + QSPI_DUAL_EX_RW = 4u, + QSPI_QUAD_EX_RW = 5u, + QSPI_DUAL_FULL = 6u, + QSPI_QUAD_FULL = 7u +} qspi_io_format; + +/** +These values are used to program the spi_mode parameter of the configuration +structure of this driver. For example: + @code + qspi_config.spi_mode = QSPI_MODE0; + QSPI_configure(&qspi_config); + @endcode + + +| Value | Description | +|-------------------|----------------------------------------------------------| +| QSPI_MODE0 | Set clock IDLE to low (0) | +| QSPI_MODE3 | Set clock IDLE to high (1) | + +*/ +typedef enum qspi_protocol_mode_t +{ + QSPI_MODE0 = 0x0u, + QSPI_MODE3 = 0x1u + +} qspi_protocol_mode; + +/***************************************************************************//** +These values are used to program the spi_mode parameter of the configuration +structure of this driver. For example: + @code + qspi_config.clk_div = QSPI_CLK_DIV_2; + QSPI_configure(&qspi_config); + @endcode + +| Value | Description | +|-----------------------|---------------------------| +| QSPI_CLK_DIV_2 | Set SPI clock to HCLK/2 | +| QSPI_CLK_DIV_4 | Set SPI clock to HCLK/4 | +| QSPI_CLK_DIV_6 | Set SPI clock to HCLK/6 | +| QSPI_CLK_DIV_8 | Set SPI clock to HCLK/8 | +| QSPI_CLK_DIV_10 | Set SPI clock to HCLK/10 | +| QSPI_CLK_DIV_12 | Set SPI clock to HCLK/12 | +| QSPI_CLK_DIV_14 | Set SPI clock to HCLK/14 | +| QSPI_CLK_DIV_16 | Set SPI clock to HCLK/16 | +| QSPI_CLK_DIV_18 | Set SPI clock to HCLK/18 | +| QSPI_CLK_DIV_20 | Set SPI clock to HCLK/20 | +| QSPI_CLK_DIV_22 | Set SPI clock to HCLK/22 | +| QSPI_CLK_DIV_24 | Set SPI clock to HCLK/24 | +| QSPI_CLK_DIV_26 | Set SPI clock to HCLK/26 | +| QSPI_CLK_DIV_28 | Set SPI clock to HCLK/28 | +| QSPI_CLK_DIV_30 | Set SPI clock to HCLK/30 | + +*/ +typedef enum qspi_clk_div_t +{ + QSPI_CLK_DIV_2 = 0x1u, + QSPI_CLK_DIV_4 = 0x2u, + QSPI_CLK_DIV_6 = 0x3u, + QSPI_CLK_DIV_8 = 0x4u, + QSPI_CLK_DIV_10 = 0x5u, + QSPI_CLK_DIV_12 = 0x6u, + QSPI_CLK_DIV_14 = 0x7u, + QSPI_CLK_DIV_16 = 0x8u, + QSPI_CLK_DIV_18 = 0x9u, + QSPI_CLK_DIV_20 = 0xAu, + QSPI_CLK_DIV_22 = 0xBu, + QSPI_CLK_DIV_24 = 0xCu, + QSPI_CLK_DIV_26 = 0xDu, + QSPI_CLK_DIV_28 = 0xEu, + QSPI_CLK_DIV_30 = 0xFu +} qspi_clk_div; + + +/** + This prototype defines the function prototype that must be followed by CoreQSPI + status handler functions. This function is registered with the CoreQSPI driver + by calling the QSPI_set_status_handler() function. + + Declaring and Implementing Status Handler Function: + Slave frame receive handler functions should follow the following prototype: + void transfer_status_handler(uint32_t status); + + The actual name of the status handler not important. You can use any name + of your choice. The status parameter contains a value indicating which + of the TX-DONE, or RX-DONE event has caused the interrupt. +*/ +typedef void (*qspi_status_handler_t)(uint32_t status); + +/***************************************************************************//** + This is the structure definition for the CoreQSPI configuration instance. It + defines the configuration data that the application exchanges with the driver. + + The following parameters are the configuration options for CoreQSPI. + +| Parameter | Description | +|-------------|----------------------------------------------------------------| +| xip | Enable or disable XIP mode | +| xip_addr | Number of address bytes used in XIP mode | +| spi_mode | Select either Motorola mode0 or mode3 | +| clk_div | HCLK Clock divider for generating SPI clock | +| io_format | QSPI transfer format, extended, dual, quad and so on. | +| sample | Select the event on which the QSPI samples the incoming data | + +*/ +typedef struct qspi_config{ + uint8_t xip; + uint8_t xip_addr; + qspi_protocol_mode spi_mode; /*clkidl mode0 or mode3*/ + qspi_clk_div clk_div; + qspi_io_format io_format; + uint8_t sample; +}qspi_config_t; + +/** + * There should be one instance of this structure for each instance of CoreQSPI + * in your system. The QSPI_init() function initializes this structure. It is + * used to identify the various CoreQSPI hardware instances in your system. + * An initialized timer instance structure should be passed as first parameter to + * CoreQSPI driver functions to identify which CoreQSPI instance should perform + * the requested operation. + * Software using this driver should only need to create one single instance of + * this data structure for each hardware QSPI instance in the system. + */ +typedef struct __qspi_instance_t +{ + addr_t base_address; +} qspi_instance_t; + + +/** + The QSPI_init() function initializes and enables the CoreQSPI. + It enables the QSPI hardware block, and configures it with the default + values. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @return + This function does not return a value. + + @example + This example shows how to initialize the CoreQSPI driver. + + @code + QSPI_init(QSPI_INSTANCE, base_addr); + @endcode + + */ +void QSPI_init +( + qspi_instance_t *this_qspi, + addr_t addr +); + +/***************************************************************************//** + The QSPI_disable() function disables the CoreQSPI hardware block. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @return + This function does not return a value. + + @example + @code + QSPI_disable(QSPI_INSTANCE); + @endcode + */ +static inline void QSPI_disable +( + qspi_instance_t *this_qspi +) +{ + HAL_set_32bit_reg(this_qspi->base_address, CONTROL, + ((uint32_t)(HAL_get_32bit_reg(this_qspi->base_address, CONTROL)) + & ~(uint32_t)(CTRL_ENABLE_MASK))); + +} + +/***************************************************************************//** + The QSPI_configure() function configures the CoreQSPI to the desired + configuration values. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @param config + The config parameter is a pointer to the qspi_config_t structure, which + provides new configuration values. See the qspi_config_t section for + details. + + @return + This function does not return a value. + + @example + @code + + qspi_config.clk_div = QSPI_CLK_DIV_8; + qspi_config.sample = QSPI_SAMPLE_POSAGE_SPICLK; + qspi_config.spi_mode = QSPI_MODE3; + qspi_config.xip = QSPI_DISABLE; + qspi_config.io_format = t_io_format; + + QSPI_configure(QSPI_INSTANCE, &qspi_config); + + @endcode + */ +void QSPI_configure +( + qspi_instance_t *this_qspi, + const qspi_config_t* config +); + +/***************************************************************************//** + The QSPI_get_config() function reads-back the current configurations of + the CoreQSPI. This function can be used when you want to read the current + configurations, modify the configuration values of your choice and reconfigure + the CoreQSPI hardware, using QSPI_configure() function. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @param config + The config parameter is a pointer to an qspi_config_t structure, where + the current configuration values of the CoreQSPI are returned. + + Please see description of qspi_config_t for more details. + + @return + This function does not return a value. + + @example + @code + qspi_config_t beforexip_qspi_config = { 0 }; + QSPI_get_config(QSPI_INSTANCE, &beforexip_qspi_config); + @endcode + */ +void QSPI_get_config +( + qspi_instance_t *this_qspi, + qspi_config_t* config +); + +/***************************************************************************//** + The QSPI_polled_transfer_block() function carries out a QSPI transfer with the + target memory device using polling method of data transfer. The QSPI transfer + characteristics are configured every time a new transfer is initiated. + This is a blocking function. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @param num_addr_bytes + The num_addr_bytes parameter indicates the number of address bytes to be + used while transacting with the target memory device. Depending on the + target memory device, the address within the target memory device can be + either 3 or 4 bytes long. You must make sure that you provide the exact same + number with which the target memory device is configured. + + Note: Few command opcodes do not require specified addresses. For example + READ_ID. For such commands the num_addr_bytes parameter must be set to 0x0. + + @param target_mem_addr + The target_mem_addr parameter is the memory address in the target memory + device on which the read/write operation is to be carried out. + + @param tx_buffer + The tx_buffer parameter is the pointer to the buffer from which the data + needs to transmitted to the target memory device. + + @param tx_byte_size + The tx_byte_size parameter is the exact number of bytes that needs to be + transmitted to the target memory device. + + Note: This parameter must not consider the command opcode and address bytes + as part of the data that needs to be transmitted. + + @param rd_buffer + The rd_buffer parameter is the pointer to the buffer where the data returned + by the target memory device is stored. + + @param rd_byte_size + The rd_byte_size parameter is the exact number of bytes that needs to be + received from the target memory device. + + @param num_idle_cycles + The num_idle_cycles parameter indicates the number of Idle cycles/dummy clock + edges that must be generated after the address bytes are transmitted and + before target memory device starts sending data. This must be correctly set + based on the target memory device and the SPI command being used. This may + also vary based on SPI clock and the way the target memory device is + configured. + + @return + This function does not return a value. + + @example + @code + QSPI_polled_transfer_block(QSPI_INSTANCE, 0, command_buf, 0, rd_buf, 1,0); + @endcode + */ +void QSPI_polled_transfer_block +( + qspi_instance_t *this_qspi, + uint8_t num_addr_bytes, + const void * const tx_buffer, + uint32_t tx_byte_size, + const void * const rd_buffer, + uint32_t rd_byte_size, + uint8_t num_idle_cycles +); + +/***************************************************************************//** + The QSPI_irq_transfer_block() function is used to carry out a QSPI transfer + with the target memory device using interrupt method of data transfers. + The QSPI transfer characteristics are configured every time a new transfer is + initiated. This is non-blocking function. You must configure the interrupt + handler function, before calling this function. It will enable the interrupts + and start transmitting as many bytes as requested. You will get an indication + when the actual SPI transmit operation is complete. When The transmit-done + interrupt event occurs and this driver calls-back the interrupt handler + function that you previously provided. If the transfer includes receiving + data from the target memory device, then the receive-available and receive-done + interrupts are also enabled by this function. The data will be received in the + interrupt routine. The interrupt handler provided by you will be called-back + again when the receive-done interrupt event occurs. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @param num_addr_bytes + The num_addr_bytes parameter indicates the number of address bytes to be + used while transacting with the target memory device. Depending on the the + target memory device, the address within the target memory device can be + either 3 or 4 bytes long. You must make sure that you provide the exact + same number with which the target memory device is configured. + + Note: There will be some command opcodes for which no address needs to be + specified. e.g. READ_ID. For such commands the num_addr_bytes parameter + must be set to 0x0. + + @param target_mem_addr + The target_mem_addr parameter is the memory address in the target memory + device on which the read/write operation is to be carried out. + + @param tx_buffer + The tx_buffer parameter is the pointer to the buffer from which the data + needs to transmitted to the target QSPI memory. + + @param tx_byte_size + The tx_byte_size parameter is the exact number of bytes that needs to be + transmitted to target memory device. + + Note: This parameter must not consider the command opcode and address bytes + as part of the data that needs to be transmitted. + + @param rd_buffer + The rd_buffer parameter is a pointer to the buffer where the data returned + by the target memory device is to be stored. + + @param rd_byte_size + The rd_byte_size parameter is the exact number of bytes that needs to be + received from the target memory device. + + @param num_idle_cycles + The num_idle_cycles parameter indicates the number of IDLE/dummy clock + edges that must be generated after the address bytes are transmitted and + before target memory device starts sending data. This must be correctly set + based on the target memory device and the SPI command being used. This may + also vary based on SPI clock and the way the target memory device is + configured. + + @return + This function returns a non-zero value if the CoreQSPI is busy completing the + previous transfer and can not accept a new transfer. A zero return value + indicates successful execution of this function. + + @example + @code + QSPI_irq_transfer_block(QSPI_INSTANCE, 0, command_buf, 0, rd_buf, 1,0); + @endcode + */ +uint8_t QSPI_irq_transfer_block +( + qspi_instance_t *this_qspi, + uint8_t num_addr_bytes, + const void * const tx_buffer, + uint32_t tx_byte_size, + const void * const rd_buffer, + uint32_t rd_byte_size, + uint8_t num_idle_cycles +); + +/***************************************************************************//** + The QSPI_set_status_handler() function registers an interrupt handler + function with this driver which is used to indicate the interrupt status back + to the application. This status handler function is called by this driver in + two events. First, when the transmission of required bytes is completed + (Transmit-Done). Second, if data is to be received from the target memory + device, then this function is called again when required data is received + (Receive-Done). + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @param handler + The handler parameter is the interrupt handler function of the type + qspi_status_handler_t, which needs to be registered. + + @return + This function does not return a value. + + @example + @code + QSPI_set_status_handler(QSPI_INSTANCE, transfer_status_handler); + @endcode + + */ +void QSPI_set_status_handler +( + qspi_status_handler_t handler +); + +/***************************************************************************//** + The QSPI_read_direct_access_reg() reads the current value of the direct + access register(DAR) of the CoreQSPI. DAR allows direct access to the QSPI + interface pins to support access to non-standard SPI devices through direct + CPU control. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @param + This function takes no parameters. + + @return + This function returns the current value of the DAR of the CoreQSPI. + + */ +static inline uint32_t QSPI_read_direct_access_reg +( + qspi_instance_t *this_qspi +) +{ + return (HAL_get_32bit_reg(this_qspi->base_address, DIRECT_ACCESS)); +} + +/***************************************************************************//** + The QSPI_write_direct_access_reg() writes value of the DAR of the CoreQSPI. + DAR allows direct access to the QSPI interface pins, to support access + to the non-standard SPI devices through direct CPU control. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @param value + The value parameter is the value that needs to be set into the direct access + register of the CoreQSPI. + + @return + This function does not return a value. + + */ +static inline void QSPI_write_direct_access_reg +( + qspi_instance_t *this_qspi, + uint32_t value +) +{ + HAL_set_32bit_reg(this_qspi->base_address, DIRECT_ACCESS, value); +} + +/***************************************************************************//** + The QSPI_read_status() function is used to read the status of the CoreQSPI. + This function returns the status register value and can be called any time + after the CoreQSPI is initialized and configured. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @return + This function returns the the current value of the status register of the + CoreQSPI. + + */ +static inline uint32_t QSPI_read_status +( + qspi_instance_t *this_qspi +) +{ + return (HAL_get_32bit_reg(this_qspi->base_address, STATUS)); + +} + +/**************************************************************************//** + * Interrupt service routine to handle the QSPI interrupt events. + * The CoreQSPI interrupt will appear as an external interrupt on the processor. + * This function must be called by the application from the external interrupt + * handler which corresponds to the CoreQSPI interrupt. + + @param this_qspi + It is a pointer to the qspi_instance_t data structure that holds all the data + related to the CoreQSPI instance being initialized. A pointer to this data + structure is used in all subsequent calls to the CoreQSPI driver functions + that operate on this CoreQSPI instance. + + @return + This function does not return a value. + */ +void qspi_isr +( + qspi_instance_t *this_qspi +); +#ifdef __cplusplus +} +#endif + +#endif /* CORE_QSPI_H_*/ + diff --git a/drivers/fpga_ip/CoreQSPI/core_qspi_regs.h b/drivers/fpga_ip/CoreQSPI/core_qspi_regs.h new file mode 100644 index 0000000..624fc56 --- /dev/null +++ b/drivers/fpga_ip/CoreQSPI/core_qspi_regs.h @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright 2024 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file core_qspi_regs.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreQSPI register bit offsets and masks definitions + * + */ + +#ifndef CORE_QSPI_REGS_H_ +#define CORE_QSPI_REGS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * Control register bit offsets + */ + +#define CONTROL_REG_OFFSET 0x00u + +#define CTRL_ENABLE_OFFSET 0x0u +#define CTRL_ENABLE_MASK 0x1u +#define CTRL_ENABLE_SHIFT 0 + +#define CTRL_XIP_OFFSET 0x00u +#define CTRL_XIP_MASK 0x04u +#define CTRL_XIP_SHIFT 2 + +#define CTRL_XIPADDR_OFFSET 0x0u +#define CTRL_XIPADDR_MASK 0x08u +#define CTRL_XIPADDR_SHIFT 3 + +#define CTRL_CLKIDLE_OFFSET 0x0u +#define CTRL_CLKIDLE_MASK 0x400u +#define CTRL_CLKIDLE_SHIFT 10 + +#define CTRL_SAMPLE_OFFSET 0x0u +#define CTRL_SAMPLE_MASK 0x1800u +#define CTRL_SAMPLE_SHIFT 11 + +#define CTRL_QMODE0_OFFSET 0x0u +#define CTRL_QMODE0_MASK 0x2000u +#define CTRL_QMODE0_SHIFT 13 + +#define CTRL_QMODE12_OFFSET 0x0u +#define CTRL_QMODE12_MASK 0xC000u +#define CTRL_QMODE12_SHIFT 14 + +#define CTRL_FLAGSX4_OFFSET 0x0u +#define CTRL_FLAGSX4_MASK 0x10000u +#define CTRL_FLAGSX4_SHIFT 16 + +#define CTRL_CLKRATE_OFFSET 0x00u +#define CTRL_CLKRATE_MASK 0xF000000u +#define CTRL_CLKRATE_SHIFT 24 + +#define CTRL_SAMPLE_SCK_OFFSET (0x0u << CTRL_SAMPLE_SHIFT) +#define CTRL_SAMPLE_HCLKF_OFFSET (0x1u << CTRL_SAMPLE_SHIFT) +#define CTRL_SAMPLE_HCLKR_OFFSET (0x2u << CTRL_SAMPLE_SHIFT) + +/******************************************************************************* + * Frames register bit offsets + */ +#define FRAMES_REG_OFFSET 0x04u + +#define FRAMES_TOTALBYTES_OFFSET 0x04u +#define FRAMES_TOTALBYTES_MASK 0xFFFFu +#define FRAMES_TOTALBYTES_SHIFT 0 + +#define FRAMES_COMMANDBYTES_OFFSET 0x04u +#define FRAMES_COMMANDBYTES_MASK 0x1FF0000u +#define FRAMES_COMMANDBYTES_SHIFT 16 + +#define FRAMES_QSPI_OFFSET 0x04u +#define FRAMES_QSPI_MASK 0x2000000u +#define FRAMES_QSPI_SHIFT 25 + +#define FRAMES_IDLE_OFFSET 0x04u +#define FRAMES_IDLE_MASK 0x3C000000u +#define FRAMES_IDLE_SHIFT 26 + +#define FRAMES_FLAGBYTE_OFFSET 0x04u +#define FRAMES_FLAGBYTE_MASK 0x40000000u +#define FRAMES_FLAGBYTE_SHIFT 30 + +#define FRAMES_FLAGWORD_OFFSET 0x04u +#define FRAMES_FLAGWORD_MASK 0x80000000u +#define FRAMES_FLAGWORD_SHIFT 31 + +/******************************************************************************* + * Interrupt enable register bit offsets + */ +#define INT_ENABLE_REG_OFFSET 0x0Cu + +#define INT_ENABLE_TXDONE_OFFSET 0x0Cu +#define INT_ENABLE_TXDONE_MASK 0x01u +#define INT_ENABLE_TXDONE_SHIFT 0 + +#define INT_ENABLE_RXDONE_OFFSET 0x0Cu +#define INT_ENABLE_RXDONE_MASK 0x02u +#define INT_ENABLE_RXDONE_SHIFT 1 + +#define INT_ENABLE_RXAVAILABLE_OFFSET 0x0Cu +#define INT_ENABLE_RXAVAILABLE_MASK 0x04u +#define INT_ENABLE_RXAVAILABLE_SHIFT 2 + +#define INT_ENABLE_TXAVAILABLE_OFFSET 0x0Cu +#define INT_ENABLE_TXAVAILABLE_MASK 0x08u +#define INT_ENABLE_TXAVAILABLE_SHIFT 3 + +#define INT_ENABLE_RXFIFOEMPTY_OFFSET 0x0Cu +#define INT_ENABLE_RXFIFOEMPTY_MASK 0x10u +#define INT_ENABLE_RXFIFOEMPTY_SHIFT 4 + +#define INT_ENABLE_TXFIFOFULL_OFFSET 0x0Cu +#define INT_ENABLE_TXFIFOFULL_MASK 0x20u +#define INT_ENABLE_TXFIFOFULL_SHIFT 5 + +/****************************************************************************** + * Status register bit offsets + */ +#define STATUS_REG_OFFSET 0x10u + +#define STATUS_TXDONE_OFFSET 0x10u +#define STATUS_TXDONE_MASK 0x01u +#define STATUS_TXDONE_SHIFT 0 + +#define STATUS_RXDONE_OFFSET 0x10u +#define STATUS_RXDONE_MASK 0x02u +#define STATUS_RXDONE_SHIFT 1 + +#define STATUS_RXAVAILABLE_OFFSET 0x10u +#define STATUS_RXAVAILABLE_MASK 0x04u +#define STATUS_RXAVAILABLE_SHIFT 2 + +#define STATUS_TXAVAILABLE_OFFSET 0x10u +#define STATUS_TXAVAILABLE_MASK 0x08u +#define STATUS_TXAVAILABLE_SHIFT 3 + +#define STATUS_RXFIFOEMPTY_OFFSET 0x10u +#define STATUS_RXFIFOEMPTY_MASK 0x10u +#define STATUS_RXFIFOEMPTY_SHIFT 4 + +#define STATUS_TXFIFOFULL_OFFSET 0x10u +#define STATUS_TXFIFOFULL_MASK 0x20u +#define STATUS_TXFIFOFULL_SHIFT 5 + +#define STATUS_READY_OFFSET 0x10u +#define STATUS_READY_MASK 0x80u +#define STATUS_READY_SHIFT 7 + +#define STATUS_FLAGSX4_OFFSET 0x10u +#define STATUS_FLAGSX4_MASK 0x100u +#define STATUS_FLAGSX4_SHIFT 8 + +/****************************************************************************** + * Direct access register bit offsets + */ +#define DIRECT_ACCESS_REG_OFFSET 0x14u + +#define DIRECT_ACCESS_EN_SSEL_OFFSET 0x14u +#define DIRECT_ACCESS_EN_SSEL_MASK 0x01u +#define DIRECT_ACCESS_EN_SSEL_SHIFT 0 + +#define DIRECT_ACCESS_OP_SSEL_OFFSET 0x14u +#define DIRECT_ACCESS_OP_SSEL_MASK 0x02u +#define DIRECT_ACCESS_OP_SSEL_SHIFT 1 + +#define DIRECT_ACCESS_EN_SCLK_OFFSET 0x14u +#define DIRECT_ACCESS_EN_SCLK_MASK 0x04u +#define DIRECT_ACCESS_EN_SCLK_SHIFT 2 + +#define DIRECT_ACCESS_OP_SCLK_OFFSET 0x14u +#define DIRECT_ACCESS_OP_SCLK_MASK 0x08u +#define DIRECT_ACCESS_OP_SCLK_SHIFT 3 + +#define DIRECT_ACCESS_EN_SDO_OFFSET 0x14u +#define DIRECT_ACCESS_EN_SDO_MASK 0xF0u +#define DIRECT_ACCESS_EN_SDO_SHIFT 4 + +#define DIRECT_ACCESS_OP_SDO_OFFSET 0x14u +#define DIRECT_ACCESS_OP_SDO_MASK 0xF00u +#define DIRECT_ACCESS_OP_SDO_SHIFT 8 + +#define DIRECT_ACCESS_OP_SDOE_OFFSET 0x14u +#define DIRECT_ACCESS_OP_SDOE_MASK 0xF000u +#define DIRECT_ACCESS_OP_SDOE_SHIFT 12 + +#define DIRECT_ACCESS_IP_SDI_OFFSET 0x14u +#define DIRECT_ACCESS_IP_SDI_MASK 0xF0000u +#define DIRECT_ACCESS_IP_SDI_SHIFT 16 + +#define DIRECT_ACCESS_IP_SCLK_OFFSET 0x14u +#define DIRECT_ACCESS_IP_SCLK_MASK 0x200000u +#define DIRECT_ACCESS_IP_SCLK_SHIFT 21 + +#define DIRECT_ACCESS_IP_SSEL_OFFSET 0x14u +#define DIRECT_ACCESS_IP_SSEL_MASK 0x400000u +#define DIRECT_ACCESS_IP_SSEL_SHIFT 22 + +#define DIRECT_ACCESS_IDLE_OFFSET 0x14u +#define DIRECT_ACCESS_IDLE_MASK 0x800000u +#define DIRECT_ACCESS_IDLE_SHIFT 23 + +/****************************************************************************** + * Upper address register bit offsets + */ +#define UPPER_ADDRESS_REG_OFFSET 0x18u + +#define UPPER_ADDRESS_ADDRUP_OFFSET 0x18u +#define UPPER_ADDRESS_ADDRUP_MASK 0xFFu +#define UPPER_ADDRESS_ADDRUP_SHIFT 0 + +/****************************************************************************** + * Receive data register bit offsets + */ +#define RECEIVE_DATA_REG_OFFSET 0x40u + +#define RECEIVE_DATA_RXDATA_OFFSET 0x40u +#define RECEIVE_DATA_RXDATA_MASK 0xFFu +#define RECEIVE_DATA_RXDATA_SHIFT 0 + +/****************************************************************************** + * Transmit data register bit offsets + */ +#define TRANSMIT_DATA_REG_OFFSET 0x44u + +#define TRANSMIT_DATA_TXDATA_OFFSET 0x44u +#define TRANSMIT_DATA_TXDATA_MASK 0xFFu +#define TRANSMIT_DATA_TXDATA_SHIFT 0 + +/****************************************************************************** + * X4ReceiveData register bit offsets + */ +#define X4RECEIVE_DATA_REG_OFFSET 0x48u + +#define X4RECEIVE_DATA_RXDATA4_OFFSET 0x48u +#define X4RECEIVE_DATA_RXDATA4_MASK 0xFFFFFFFFu +#define X4RECEIVE_DATA_RXDATA4_SHIFT 0 + +/****************************************************************************** + * X4 Transmit data register bit offsets + */ +#define X4TRANSMIT_DATA_REG_OFFSET 0x4Cu + +#define X4TRANSMIT_DATA_TXDATA4_OFFSET 0x4Cu +#define X4TRANSMIT_DATA_TXDATA4_MASK 0xFFFFFFFFu +#define X4TRANSMIT_DATA_TXDATA4_SHIFT 0 + +/****************************************************************************** + * FRAMESUP register bit offsets + */ +#define FRAMESUP_REG_OFFSET 0x50 + +#define FRAMESUP_BYTESLOWER_OFFSET 0x50 +#define FRAMESUP_BYTESLOWER_MASK 0xFFFFu +#define FRAMESUP_BYTESLOWER_SHIFT 0 + +#define FRAMESUP_BYTESUPPER_OFFSET 0x50 +#define FRAMESUP_BYTESUPPER_MASK 0xFFFF0000u +#define FRAMESUP_BYTESUPPER_SHIFT 16 + + +#ifdef __cplusplus +} +#endif + +#endif /* CORE_QSPI_REGS_H_ */