mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 10:40:47 +03:00
Merge branch 'refactor/spi_sct_part_soc_header_refactor' into 'master'
refactor(driver_spi): refactor header styles of spi sct part on soc and lowlevel Closes IDF-10583, IDF-10584, IDF-10585, IDF-10586, and IDF-13725 See merge request espressif/esp-idf!51676
This commit is contained in:
@@ -928,10 +928,7 @@ static void SPI_MASTER_ISR_ATTR spi_new_sct_trans(spi_device_t *dev, spi_sct_tra
|
||||
//Reconfigure according to device settings, the function only has effect when the dev_id is changed.
|
||||
spi_setup_device(dev, NULL);
|
||||
|
||||
#if !CONFIG_IDF_TARGET_ESP32S2
|
||||
// s2 update this seg_gap_clock_len by dma from conf_buffer
|
||||
spi_hal_sct_set_conf_bits_len(&dev->host->hal, cur_sct_trans->sct_trans_desc_head->sct_gap_len);
|
||||
#endif
|
||||
s_sct_load_dma_link(dev, cur_sct_trans->rx_seg_head, cur_sct_trans->tx_seg_head);
|
||||
if (dev->cfg.pre_cb) {
|
||||
dev->cfg.pre_cb((spi_transaction_t *)cur_sct_trans->sct_trans_desc_head);
|
||||
@@ -1799,7 +1796,6 @@ static void SPI_MASTER_ATTR s_sct_format_conf_buffer(spi_device_handle_t handle,
|
||||
if (seg_end) {
|
||||
seg_config.seg_end = true;
|
||||
}
|
||||
seg_config.seg_gap_len = seg_trans_desc->sct_gap_len;
|
||||
|
||||
// set line mode to hal_config
|
||||
spi_sct_set_hal_trans_config(seg_trans_desc, &hal->trans_config);
|
||||
|
||||
@@ -7,9 +7,8 @@ set(srcs
|
||||
"test_spi_bus_lock.c"
|
||||
)
|
||||
|
||||
# TODO: IDF-10593 ~ IDF-10585: SCT is temporarily supported on follow chips
|
||||
set(sct_targets esp32s2 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2 esp32h21)
|
||||
if("${target}" IN_LIST sct_targets)
|
||||
# esp32p4 don't support because sct internal api part don't using dma link list driver
|
||||
if(NOT CONFIG_IDF_TARGET_ESP32P4)
|
||||
# sct test using slave hd APIs, need slave hd support
|
||||
# tmp skip sct test under iram_safe, both sct and slave hd are not cleaned
|
||||
if(CONFIG_SOC_SPI_SUPPORT_SLAVE_HD_VER2 AND NOT CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||
|
||||
@@ -291,6 +291,8 @@ TEST_CASE("spi_master: test_sct_dma_desc_oob_on_tail", "[spi]")
|
||||
TEST_ESP_OK(spi_bus_free(SPI2_HOST));
|
||||
}
|
||||
|
||||
// C5 multi runer use eco2 chip which don't support sleep
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C5)
|
||||
#if SOC_LIGHT_SLEEP_SUPPORTED
|
||||
/*-----------------------------------------------------------
|
||||
* Sleep Retention Test
|
||||
@@ -417,3 +419,4 @@ static void sleep_slave(void)
|
||||
}
|
||||
TEST_CASE_MULTIPLE_DEVICES("test_spi_master_sct_sleep_retention", "[spi_ms]", sleep_master, sleep_slave);
|
||||
#endif //SOC_LIGHT_SLEEP_SUPPORTED
|
||||
#endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32C5)
|
||||
|
||||
@@ -36,17 +36,18 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c2 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c2 only support gpspi2
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
typedef uint32_t spi_ll_clock_val_t;
|
||||
typedef spi_dev_t spi_dma_dev_t;
|
||||
@@ -1293,302 +1294,32 @@ static inline int spi_ll_get_slave_hd_dummy_bits(spi_line_mode_t line_mode)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SPI_LL_CONF_BUF_SET_BIT(_w, _m) ({ \
|
||||
(_w) |= (_m); \
|
||||
})
|
||||
#define SPI_LL_CONF_BUF_CLR_BIT(_w, _m) ({ \
|
||||
(_w) &= ~(_m); \
|
||||
})
|
||||
|
||||
#define SPI_LL_CONF_BUF_SET_FIELD(_w, _f, val) ({ \
|
||||
((_w) = (((_w) & ~((_f##_V) << (_f##_S))) | (((val) & (_f##_V))<<(_f##_S)))); \
|
||||
})
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t bitmap: 28;
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
#define SPI_LL_CONF_BUF_GET_FIELD(_w, _f) ({ \
|
||||
(((_w) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
|
||||
//This offset is 1, for bitmap
|
||||
#define SPI_LL_CONF_BUFFER_OFFSET (1)
|
||||
//bitmap must be the first
|
||||
#define SPI_LL_CONF_BITMAP_POS (0)
|
||||
|
||||
#define SPI_LL_ADDR_REG_POS (0)
|
||||
#define SPI_LL_CTRL_REG_POS (1)
|
||||
#define SPI_LL_CLOCK_REG_POS (2)
|
||||
#define SPI_LL_USER_REG_POS (3)
|
||||
#define SPI_LL_USER1_REG_POS (4)
|
||||
#define SPI_LL_USER2_REG_POS (5)
|
||||
#define SPI_LL_MS_DLEN_REG_POS (6)
|
||||
#define SPI_LL_MISC_REG_POS (7)
|
||||
#define SPI_LL_DIN_MODE_REG_POS (8)
|
||||
#define SPI_LL_DIN_NUM_REG_POS (9)
|
||||
#define SPI_LL_DOUT_MODE_REG_POS (10)
|
||||
#define SPI_LL_DMA_CONF_REG_POS (11)
|
||||
#define SPI_LL_DMA_INT_ENA_REG_POS (12)
|
||||
#define SPI_LL_DMA_INT_CLR_REG_POS (13)
|
||||
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bits_len(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_phase_conf_buffer(spi_dev_t *hw, bool is_end, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_conf_nxt
|
||||
if (is_end) {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_line_mode_conf_buff(spi_dev_t *hw, spi_line_mode_t line_mode, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
|
||||
switch (line_mode.cmd_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_QUAD_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.addr_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_QUAD_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.data_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_DUAL_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_DUAL_M);
|
||||
break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_QUAD_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_QUAD_M);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for prep phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS setup time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_prep_phase_conf_buffer(spi_dev_t *hw, uint8_t setup, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_setup
|
||||
if (setup) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_setup_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_TIME, setup - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_cmd_phase_conf_buffer(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_command
|
||||
if (cmdlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
}
|
||||
|
||||
//user2 reg: usr_command_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_BITLEN, cmdlen - 1);
|
||||
|
||||
//user2 reg: usr_command_value
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, cmd);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_addr_phase_conf_buffer(spi_dev_t *hw, uint64_t addr, int addrlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_addr
|
||||
if (addrlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_addr_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_BITLEN, addrlen - 1);
|
||||
|
||||
//addr reg: addr
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, HAL_SWAP32(addr));
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, (addr << (32 - addrlen)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dummy_phase_conf_buffer(spi_dev_t *hw, int dummy_n, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_dummy
|
||||
if (dummy_n) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_dummy_cyclelen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_CYCLELEN, dummy_n - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dout_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_din_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for done phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS hold time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_done_phase_conf_buffer(spi_dev_t *hw, int hold, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_hold
|
||||
if (hold) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_hold_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_TIME, hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CONF_BITMAP_POS] = 0x7FFF | (SPI_LL_SCT_MAGIC_NUMBER << 28);
|
||||
conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->addr.val;
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl.val;
|
||||
conf_buffer[SPI_LL_CLOCK_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->clock.val;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user.val;
|
||||
conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user1.val;
|
||||
conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user2.val;
|
||||
conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ms_dlen.val;
|
||||
conf_buffer[SPI_LL_MISC_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->misc.val;
|
||||
conf_buffer[SPI_LL_DIN_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_mode.val;
|
||||
conf_buffer[SPI_LL_DIN_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_num.val;
|
||||
conf_buffer[SPI_LL_DOUT_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_mode.val;
|
||||
conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_conf.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_ENA_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_ena.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_CLR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_clr.val;
|
||||
}
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
@@ -1596,11 +1327,24 @@ static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_conf_state_enable(spi_dev_t *hw, bool enable)
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
@@ -1612,6 +1356,191 @@ static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -36,17 +36,18 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c3 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c3 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1212,302 +1213,32 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SPI_LL_CONF_BUF_SET_BIT(_w, _m) ({ \
|
||||
(_w) |= (_m); \
|
||||
})
|
||||
#define SPI_LL_CONF_BUF_CLR_BIT(_w, _m) ({ \
|
||||
(_w) &= ~(_m); \
|
||||
})
|
||||
|
||||
#define SPI_LL_CONF_BUF_SET_FIELD(_w, _f, val) ({ \
|
||||
((_w) = (((_w) & ~((_f##_V) << (_f##_S))) | (((val) & (_f##_V))<<(_f##_S)))); \
|
||||
})
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t bitmap: 28;
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
#define SPI_LL_CONF_BUF_GET_FIELD(_w, _f) ({ \
|
||||
(((_w) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
|
||||
//This offset is 1, for bitmap
|
||||
#define SPI_LL_CONF_BUFFER_OFFSET (1)
|
||||
//bitmap must be the first
|
||||
#define SPI_LL_CONF_BITMAP_POS (0)
|
||||
|
||||
#define SPI_LL_ADDR_REG_POS (0)
|
||||
#define SPI_LL_CTRL_REG_POS (1)
|
||||
#define SPI_LL_CLOCK_REG_POS (2)
|
||||
#define SPI_LL_USER_REG_POS (3)
|
||||
#define SPI_LL_USER1_REG_POS (4)
|
||||
#define SPI_LL_USER2_REG_POS (5)
|
||||
#define SPI_LL_MS_DLEN_REG_POS (6)
|
||||
#define SPI_LL_MISC_REG_POS (7)
|
||||
#define SPI_LL_DIN_MODE_REG_POS (8)
|
||||
#define SPI_LL_DIN_NUM_REG_POS (9)
|
||||
#define SPI_LL_DOUT_MODE_REG_POS (10)
|
||||
#define SPI_LL_DMA_CONF_REG_POS (11)
|
||||
#define SPI_LL_DMA_INT_ENA_REG_POS (12)
|
||||
#define SPI_LL_DMA_INT_CLR_REG_POS (13)
|
||||
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bits_len(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_phase_conf_buffer(spi_dev_t *hw, bool is_end, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_conf_nxt
|
||||
if (is_end) {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_line_mode_conf_buff(spi_dev_t *hw, spi_line_mode_t line_mode, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
|
||||
switch (line_mode.cmd_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_QUAD_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.addr_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_QUAD_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.data_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_DUAL_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_DUAL_M);
|
||||
break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_QUAD_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_QUAD_M);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for prep phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS setup time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_prep_phase_conf_buffer(spi_dev_t *hw, uint8_t setup, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_setup
|
||||
if (setup) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_setup_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_TIME, setup - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_cmd_phase_conf_buffer(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_command
|
||||
if (cmdlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
}
|
||||
|
||||
//user2 reg: usr_command_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_BITLEN, cmdlen - 1);
|
||||
|
||||
//user2 reg: usr_command_value
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, cmd);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_addr_phase_conf_buffer(spi_dev_t *hw, uint64_t addr, int addrlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_addr
|
||||
if (addrlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_addr_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_BITLEN, addrlen - 1);
|
||||
|
||||
//addr reg: addr
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, HAL_SWAP32(addr));
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, (addr << (32 - addrlen)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dummy_phase_conf_buffer(spi_dev_t *hw, int dummy_n, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_dummy
|
||||
if (dummy_n) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_dummy_cyclelen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_CYCLELEN, dummy_n - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dout_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_din_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for done phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS hold time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_done_phase_conf_buffer(spi_dev_t *hw, int hold, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_hold
|
||||
if (hold) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_hold_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_TIME, hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CONF_BITMAP_POS] = 0x7FFF | (SPI_LL_SCT_MAGIC_NUMBER << 28);
|
||||
conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->addr.val;
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl.val;
|
||||
conf_buffer[SPI_LL_CLOCK_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->clock.val;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user.val;
|
||||
conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user1.val;
|
||||
conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user2.val;
|
||||
conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ms_dlen.val;
|
||||
conf_buffer[SPI_LL_MISC_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->misc.val;
|
||||
conf_buffer[SPI_LL_DIN_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_mode.val;
|
||||
conf_buffer[SPI_LL_DIN_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_num.val;
|
||||
conf_buffer[SPI_LL_DOUT_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_mode.val;
|
||||
conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_conf.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_ENA_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_ena.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_CLR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_clr.val;
|
||||
}
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
@@ -1515,11 +1246,24 @@ static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_conf_state_enable(spi_dev_t *hw, bool enable)
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
@@ -1531,6 +1275,191 @@ static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,16 +37,20 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c5 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c5 only support gpspi2
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN SPI_CONF_BITLEN
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1222,6 +1226,263 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param magic_value magic value
|
||||
*/
|
||||
static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
{
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base spi command
|
||||
*
|
||||
|
||||
@@ -36,17 +36,18 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c6 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c6 only support gpspi2
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1197,302 +1198,39 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SPI_LL_CONF_BUF_SET_BIT(_w, _m) ({ \
|
||||
(_w) |= (_m); \
|
||||
})
|
||||
#define SPI_LL_CONF_BUF_CLR_BIT(_w, _m) ({ \
|
||||
(_w) &= ~(_m); \
|
||||
})
|
||||
|
||||
#define SPI_LL_CONF_BUF_SET_FIELD(_w, _f, val) ({ \
|
||||
((_w) = (((_w) & ~((_f##_V) << (_f##_S))) | (((val) & (_f##_V))<<(_f##_S)))); \
|
||||
})
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
#define SPI_LL_CONF_BUF_GET_FIELD(_w, _f) ({ \
|
||||
(((_w) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
|
||||
//This offset is 1, for bitmap
|
||||
#define SPI_LL_CONF_BUFFER_OFFSET (1)
|
||||
//bitmap must be the first
|
||||
#define SPI_LL_CONF_BITMAP_POS (0)
|
||||
|
||||
#define SPI_LL_ADDR_REG_POS (0)
|
||||
#define SPI_LL_CTRL_REG_POS (1)
|
||||
#define SPI_LL_CLOCK_REG_POS (2)
|
||||
#define SPI_LL_USER_REG_POS (3)
|
||||
#define SPI_LL_USER1_REG_POS (4)
|
||||
#define SPI_LL_USER2_REG_POS (5)
|
||||
#define SPI_LL_MS_DLEN_REG_POS (6)
|
||||
#define SPI_LL_MISC_REG_POS (7)
|
||||
#define SPI_LL_DIN_MODE_REG_POS (8)
|
||||
#define SPI_LL_DIN_NUM_REG_POS (9)
|
||||
#define SPI_LL_DOUT_MODE_REG_POS (10)
|
||||
#define SPI_LL_DMA_CONF_REG_POS (11)
|
||||
#define SPI_LL_DMA_INT_ENA_REG_POS (12)
|
||||
#define SPI_LL_DMA_INT_CLR_REG_POS (13)
|
||||
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bits_len(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_phase_conf_buffer(spi_dev_t *hw, bool is_end, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_conf_nxt
|
||||
if (is_end) {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_line_mode_conf_buff(spi_dev_t *hw, spi_line_mode_t line_mode, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
|
||||
switch (line_mode.cmd_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_QUAD_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.addr_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_QUAD_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.data_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_DUAL_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_DUAL_M);
|
||||
break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_QUAD_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_QUAD_M);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for prep phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS setup time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_prep_phase_conf_buffer(spi_dev_t *hw, uint8_t setup, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_setup
|
||||
if (setup) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_setup_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_TIME, setup - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_cmd_phase_conf_buffer(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_command
|
||||
if (cmdlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
}
|
||||
|
||||
//user2 reg: usr_command_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_BITLEN, cmdlen - 1);
|
||||
|
||||
//user2 reg: usr_command_value
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, cmd);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_addr_phase_conf_buffer(spi_dev_t *hw, uint64_t addr, int addrlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_addr
|
||||
if (addrlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_addr_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_BITLEN, addrlen - 1);
|
||||
|
||||
//addr reg: addr
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, HAL_SWAP32(addr));
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, (addr << (32 - addrlen)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dummy_phase_conf_buffer(spi_dev_t *hw, int dummy_n, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_dummy
|
||||
if (dummy_n) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_dummy_cyclelen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_CYCLELEN, dummy_n - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dout_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_din_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for done phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS hold time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_done_phase_conf_buffer(spi_dev_t *hw, int hold, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_hold
|
||||
if (hold) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_hold_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_TIME, hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CONF_BITMAP_POS] = 0x7FFF | (SPI_LL_SCT_MAGIC_NUMBER << 28);
|
||||
conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->addr.usr_addr_value;
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl.val;
|
||||
conf_buffer[SPI_LL_CLOCK_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->clock.val;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user.val;
|
||||
conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user1.val;
|
||||
conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user2.val;
|
||||
conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ms_dlen.val;
|
||||
conf_buffer[SPI_LL_MISC_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->misc.val;
|
||||
conf_buffer[SPI_LL_DIN_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_mode.val;
|
||||
conf_buffer[SPI_LL_DIN_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_num.val;
|
||||
conf_buffer[SPI_LL_DOUT_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_mode.val;
|
||||
conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_conf.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_ENA_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_ena.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_CLR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_clr.val;
|
||||
}
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
@@ -1500,11 +1238,24 @@ static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_conf_state_enable(spi_dev_t *hw, bool enable)
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
@@ -1516,6 +1267,191 @@ static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,16 +37,20 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c61 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //c61 only support gpspi2
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) // Supported line mode: SPI2: 1, 2, 4
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN SPI_CONF_BITLEN
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1221,6 +1225,262 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
}
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param magic_value magic value
|
||||
*/
|
||||
static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
{
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base spi command
|
||||
|
||||
@@ -38,17 +38,18 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //h2 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 102) ? 1 : 2) //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //h2 only support gpspi2
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) // Supported line mode: SPI2: 1, 2, 4
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS (ESP_CHIP_REV_ABOVE(efuse_hal_chip_revision(), 102) ? 1 : 2) //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1199,307 +1200,39 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SPI_LL_CONF_BUF_SET_BIT(_w, _m) ({ \
|
||||
(_w) |= (_m); \
|
||||
})
|
||||
#define SPI_LL_CONF_BUF_CLR_BIT(_w, _m) ({ \
|
||||
(_w) &= ~(_m); \
|
||||
})
|
||||
|
||||
#define SPI_LL_CONF_BUF_SET_FIELD(_w, _f, val) ({ \
|
||||
((_w) = (((_w) & ~((_f##_V) << (_f##_S))) | (((val) & (_f##_V))<<(_f##_S)))); \
|
||||
})
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
#define SPI_LL_CONF_BUF_GET_FIELD(_w, _f) ({ \
|
||||
(((_w) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
|
||||
//This offset is 1, for bitmap
|
||||
#define SPI_LL_CONF_BUFFER_OFFSET (1)
|
||||
//bitmap must be the first
|
||||
#define SPI_LL_CONF_BITMAP_POS (0)
|
||||
|
||||
#define SPI_LL_ADDR_REG_POS (0)
|
||||
#define SPI_LL_CTRL_REG_POS (1)
|
||||
#define SPI_LL_CLOCK_REG_POS (2)
|
||||
#define SPI_LL_USER_REG_POS (3)
|
||||
#define SPI_LL_USER1_REG_POS (4)
|
||||
#define SPI_LL_USER2_REG_POS (5)
|
||||
#define SPI_LL_MS_DLEN_REG_POS (6)
|
||||
#define SPI_LL_MISC_REG_POS (7)
|
||||
#define SPI_LL_DIN_MODE_REG_POS (8)
|
||||
#define SPI_LL_DIN_NUM_REG_POS (9)
|
||||
#define SPI_LL_DOUT_MODE_REG_POS (10)
|
||||
#define SPI_LL_DMA_CONF_REG_POS (11)
|
||||
#define SPI_LL_DMA_INT_ENA_REG_POS (12)
|
||||
#define SPI_LL_DMA_INT_CLR_REG_POS (13)
|
||||
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bits_len(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_phase_conf_buffer(spi_dev_t *hw, bool is_end, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_conf_nxt
|
||||
if (is_end) {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_line_mode_conf_buff(spi_dev_t *hw, spi_line_mode_t line_mode, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
|
||||
switch (line_mode.cmd_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.addr_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.data_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_DUAL_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_DUAL_M);
|
||||
break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_QUAD_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_QUAD_M);
|
||||
break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_OCT_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_OCT_M);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for prep phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS setup time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_prep_phase_conf_buffer(spi_dev_t *hw, uint8_t setup, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_setup
|
||||
if (setup) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_setup_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_TIME, setup - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_cmd_phase_conf_buffer(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_command
|
||||
if (cmdlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
}
|
||||
|
||||
//user2 reg: usr_command_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_BITLEN, cmdlen - 1);
|
||||
|
||||
//user2 reg: usr_command_value
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, cmd);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_addr_phase_conf_buffer(spi_dev_t *hw, uint64_t addr, int addrlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_addr
|
||||
if (addrlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_addr_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_BITLEN, addrlen - 1);
|
||||
|
||||
//addr reg: addr
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, HAL_SWAP32(addr));
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, (addr << (32 - addrlen)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dummy_phase_conf_buffer(spi_dev_t *hw, int dummy_n, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_dummy
|
||||
if (dummy_n) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_dummy_cyclelen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_CYCLELEN, dummy_n - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dout_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_din_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for done phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS hold time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_done_phase_conf_buffer(spi_dev_t *hw, int hold, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_hold
|
||||
if (hold) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_hold_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_TIME, hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CONF_BITMAP_POS] = 0x7FFF | (SPI_LL_SCT_MAGIC_NUMBER << 28);
|
||||
conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->addr.usr_addr_value;
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl.val;
|
||||
conf_buffer[SPI_LL_CLOCK_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->clock.val;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user.val;
|
||||
conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user1.val;
|
||||
conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user2.val;
|
||||
conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ms_dlen.val;
|
||||
conf_buffer[SPI_LL_MISC_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->misc.val;
|
||||
conf_buffer[SPI_LL_DIN_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_mode.val;
|
||||
conf_buffer[SPI_LL_DIN_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_num.val;
|
||||
conf_buffer[SPI_LL_DOUT_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_mode.val;
|
||||
conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_conf.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_ENA_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_ena.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_CLR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_clr.val;
|
||||
}
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
@@ -1507,11 +1240,24 @@ static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_conf_state_enable(spi_dev_t *hw, bool enable)
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
@@ -1523,6 +1269,191 @@ static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,17 +38,18 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //h21 only support gpspi2
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) 6 //h21 only support gpspi2
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) //Supported line mode: DIO, DOUT, QIO, or QOUT
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
* calculation needs long time, it should be calculated during initialization and
|
||||
@@ -1187,307 +1188,39 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SPI_LL_CONF_BUF_SET_BIT(_w, _m) ({ \
|
||||
(_w) |= (_m); \
|
||||
})
|
||||
#define SPI_LL_CONF_BUF_CLR_BIT(_w, _m) ({ \
|
||||
(_w) &= ~(_m); \
|
||||
})
|
||||
|
||||
#define SPI_LL_CONF_BUF_SET_FIELD(_w, _f, val) ({ \
|
||||
((_w) = (((_w) & ~((_f##_V) << (_f##_S))) | (((val) & (_f##_V))<<(_f##_S)))); \
|
||||
})
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
#define SPI_LL_CONF_BUF_GET_FIELD(_w, _f) ({ \
|
||||
(((_w) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
|
||||
//This offset is 1, for bitmap
|
||||
#define SPI_LL_CONF_BUFFER_OFFSET (1)
|
||||
//bitmap must be the first
|
||||
#define SPI_LL_CONF_BITMAP_POS (0)
|
||||
|
||||
#define SPI_LL_ADDR_REG_POS (0)
|
||||
#define SPI_LL_CTRL_REG_POS (1)
|
||||
#define SPI_LL_CLOCK_REG_POS (2)
|
||||
#define SPI_LL_USER_REG_POS (3)
|
||||
#define SPI_LL_USER1_REG_POS (4)
|
||||
#define SPI_LL_USER2_REG_POS (5)
|
||||
#define SPI_LL_MS_DLEN_REG_POS (6)
|
||||
#define SPI_LL_MISC_REG_POS (7)
|
||||
#define SPI_LL_DIN_MODE_REG_POS (8)
|
||||
#define SPI_LL_DIN_NUM_REG_POS (9)
|
||||
#define SPI_LL_DOUT_MODE_REG_POS (10)
|
||||
#define SPI_LL_DMA_CONF_REG_POS (11)
|
||||
#define SPI_LL_DMA_INT_ENA_REG_POS (12)
|
||||
#define SPI_LL_DMA_INT_CLR_REG_POS (13)
|
||||
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bits_len(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_phase_conf_buffer(spi_dev_t *hw, bool is_end, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_conf_nxt
|
||||
if (is_end) {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_line_mode_conf_buff(spi_dev_t *hw, spi_line_mode_t line_mode, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
|
||||
switch (line_mode.cmd_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.addr_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.data_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_DUAL_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_DUAL_M);
|
||||
break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_QUAD_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_QUAD_M);
|
||||
break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_OCT_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_OCT_M);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for prep phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS setup time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_prep_phase_conf_buffer(spi_dev_t *hw, uint8_t setup, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_setup
|
||||
if (setup) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_setup_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_TIME, setup - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_cmd_phase_conf_buffer(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_command
|
||||
if (cmdlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
}
|
||||
|
||||
//user2 reg: usr_command_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_BITLEN, cmdlen - 1);
|
||||
|
||||
//user2 reg: usr_command_value
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, cmd);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_addr_phase_conf_buffer(spi_dev_t *hw, uint64_t addr, int addrlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_addr
|
||||
if (addrlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_addr_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_BITLEN, addrlen - 1);
|
||||
|
||||
//addr reg: addr
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, HAL_SWAP32(addr));
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, (addr << (32 - addrlen)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dummy_phase_conf_buffer(spi_dev_t *hw, int dummy_n, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_dummy
|
||||
if (dummy_n) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_dummy_cyclelen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_CYCLELEN, dummy_n - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dout_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_din_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for done phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS hold time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_done_phase_conf_buffer(spi_dev_t *hw, int hold, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_hold
|
||||
if (hold) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_hold_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_TIME, hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CONF_BITMAP_POS] = 0x7FFF | (SPI_LL_SCT_MAGIC_NUMBER << 28);
|
||||
conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->addr.usr_addr_value;
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl.val;
|
||||
conf_buffer[SPI_LL_CLOCK_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->clock.val;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user.val;
|
||||
conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user1.val;
|
||||
conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user2.val;
|
||||
conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ms_dlen.val;
|
||||
conf_buffer[SPI_LL_MISC_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->misc.val;
|
||||
conf_buffer[SPI_LL_DIN_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_mode.val;
|
||||
conf_buffer[SPI_LL_DIN_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_num.val;
|
||||
conf_buffer[SPI_LL_DOUT_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_mode.val;
|
||||
conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_conf.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_ENA_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_ena.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_CLR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_clr.val;
|
||||
}
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
@@ -1495,11 +1228,24 @@ static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_conf_state_enable(spi_dev_t *hw, bool enable)
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
@@ -1511,6 +1257,191 @@ static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base spi command
|
||||
*
|
||||
|
||||
@@ -37,16 +37,21 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) (4) // Supported line mode: SPI2: 1, 2, 4
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (PCR_SPI2_CLKM_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN SPI_CONF_BITLEN
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
* calculation needs long time, it should be calculated during initialization and
|
||||
@@ -1243,6 +1248,263 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param magic_value magic value
|
||||
*/
|
||||
static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
{
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base spi command
|
||||
*
|
||||
|
||||
@@ -32,21 +32,26 @@ extern "C" {
|
||||
/// Interrupt not used. Don't use in app.
|
||||
#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA)
|
||||
/// These 2 masks together will set SPI transaction to one line mode
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_OCT | SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_OCT | \
|
||||
SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_OCT | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_OCT | SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) ((host == 2) ? 4 : 8) // Supported line mode: SPI3: 1, 2, 4, SPI1/2: 1, 2, 4, 8
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (HP_SYS_CLKRST_REG_GPSPI2_MST_CLK_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (HP_SYS_CLKRST_REG_GPSPI2_MST_CLK_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN SPI_CONF_BITLEN
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1304,6 +1309,267 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param magic_value magic value
|
||||
*/
|
||||
static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
{
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.fcmd_oct = (line_mode.cmd_lines == 8);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.faddr_oct = (line_mode.addr_lines == 8);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->ctrl.fread_oct = (line_mode.data_lines == 8);
|
||||
sct_cfg->user.fwrite_oct = (line_mode.data_lines == 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base spi command
|
||||
*
|
||||
|
||||
@@ -42,21 +42,20 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_DMA_CHANNEL_NUM (3)
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 23) //reg len: 23 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (18 * 32) //Fifo len: 18 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 8 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (8192)
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) ((host == 2) ? 1 : 8) // Supported line mode: SPI3: 1, SPI1/2: 1, 2, 4, 8
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN 0x7FFFFD //23 bit wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 27) //1-word-bitmap + 27-word-regs according to TRM
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_DMA_SHARED 1 //spi_dma shared with adc and dac on S2
|
||||
|
||||
#define SPI_LL_SUPPORT_SEG_GAP 1 // support update seg_gap_len by conf buffer
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_CHANNEL_NUM (3)
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 23) //reg len: 23 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (18 * 32) //Fifo len: 18 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 8 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (8192)
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN 0x7FFFFD //23 bit wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 17) //1-word-bitmap + 17-word-regs according to TRM (except some unused registers)
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_DMA_SHARED 1 //spi_dma shared with adc and dac on S2
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1540,55 +1539,59 @@ static inline bool spi_ll_tx_get_empty_err(spi_dev_t *hw)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SPI_LL_CONF_BUF_SET_BIT(_w, _m) ({ \
|
||||
(_w) |= (_m); \
|
||||
})
|
||||
#define SPI_LL_CONF_BUF_CLR_BIT(_w, _m) ({ \
|
||||
(_w) &= ~(_m); \
|
||||
})
|
||||
|
||||
#define SPI_LL_CONF_BUF_SET_FIELD(_w, _f, val) ({ \
|
||||
((_w) = (((_w) & ~((_f##_V) << (_f##_S))) | (((val) & (_f##_V))<<(_f##_S)))); \
|
||||
})
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t bitmap: 28;
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
#define SPI_LL_CONF_BUF_GET_FIELD(_w, _f) ({ \
|
||||
(((_w) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
// volatile spi_cmd_reg_t cmd; // don't use cmd reg to align to other targets
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_ctrl1_reg_t ctrl1;
|
||||
volatile spi_ctrl2_reg_t ctrl2;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_mosi_dlen_reg_t mosi_dlen;
|
||||
volatile spi_miso_dlen_reg_t miso_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_slave_reg_t slave;
|
||||
volatile spi_fsm_reg_t fsm;
|
||||
volatile spi_hold_reg_t hold;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_raw_reg_t dma_int_raw;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
/** Below registers are hardware supported but not used in spi sct mode
|
||||
* keep here for reference
|
||||
*/
|
||||
// volatile spi_din_mode_reg_t din_mode;
|
||||
// volatile spi_din_num_reg_t din_num;
|
||||
// volatile spi_dout_mode_reg_t dout_mode;
|
||||
// volatile spi_dout_num_reg_t dout_num;
|
||||
// volatile spi_lcd_ctrl_reg_t lcd_ctrl;
|
||||
// volatile spi_lcd_ctrl1_reg_t lcd_ctrl1;
|
||||
// volatile spi_lcd_ctrl2_reg_t lcd_ctrl2;
|
||||
// volatile spi_lcd_d_mode_reg_t lcd_d_mode;
|
||||
// volatile spi_lcd_d_num_reg_t lcd_d_num;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
//This offset is 1, for bitmap
|
||||
#define SPI_LL_CONF_BUFFER_OFFSET (1)
|
||||
//bitmap must be the first
|
||||
#define SPI_LL_CONF_BITMAP_POS (0)
|
||||
|
||||
#define SPI_LL_CMD_REG_POS (0)
|
||||
#define SPI_LL_ADDR_REG_POS (1)
|
||||
#define SPI_LL_CTRL_REG_POS (2)
|
||||
#define SPI_LL_CTRL1_REG_POS (3)
|
||||
#define SPI_LL_CTRL2_REG_POS (4)
|
||||
#define SPI_LL_CLOCK_REG_POS (5)
|
||||
#define SPI_LL_USER_REG_POS (6)
|
||||
#define SPI_LL_USER1_REG_POS (7)
|
||||
#define SPI_LL_USER2_REG_POS (8)
|
||||
#define SPI_LL_MOSI_DLEN_REG_POS (9)
|
||||
#define SPI_LL_MISO_DLEN_REG_POS (10)
|
||||
#define SPI_LL_MISC_REG_POS (11)
|
||||
#define SPI_LL_SLAVE_REG_POS (12)
|
||||
#define SPI_LL_FSM_REG_POS (13)
|
||||
#define SPI_LL_HOLD_REG_POS (14)
|
||||
#define SPI_LL_DMA_INT_ENA_REG_POS (15)
|
||||
#define SPI_LL_DMA_INT_RAW_REG_POS (16)
|
||||
#define SPI_LL_DMA_INT_CLR_REG_POS (17)
|
||||
#define SPI_LL_DIN_MODE_REG_POS (18)
|
||||
#define SPI_LL_DIN_NUM_REG_POS (19)
|
||||
#define SPI_LL_DOUT_MODE_REG_POS (20)
|
||||
#define SPI_LL_DOUT_NUM_REG_POS (21)
|
||||
#define SPI_LL_LCD_CTRL_REG_POS (22)
|
||||
#define SPI_LL_LCD_CTRL1_REG_POS (23)
|
||||
#define SPI_LL_LCD_CTRL2_REG_POS (24)
|
||||
#define SPI_LL_LCD_D_MODE_REG_POS (25)
|
||||
#define SPI_LL_LCD_D_NUM_REG_POS (26)
|
||||
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slv_rd_byte.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase base bits len to HW for segment config trans mode.
|
||||
@@ -1611,295 +1614,13 @@ static inline void spi_ll_set_conf_base_bitslen(spi_dev_t *hw, uint8_t conf_base
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bits_len(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to config buffer for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_bitslen_buffer(spi_dev_t *hw, uint32_t conf_bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
//cmd reg: conf_bitlen
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_CMD_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CONF_BITLEN, conf_bitlen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_phase_conf_buffer(spi_dev_t *hw, bool is_end, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_conf_nxt
|
||||
if (is_end) {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_line_mode_conf_buff(spi_dev_t *hw, spi_line_mode_t line_mode, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
|
||||
switch (line_mode.cmd_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.addr_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.data_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_DUAL_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_DUAL_M);
|
||||
break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_QUAD_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_QUAD_M);
|
||||
break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_OCT_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_OCT_M);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for prep phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS setup time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_prep_phase_conf_buffer(spi_dev_t *hw, uint8_t setup, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_setup
|
||||
if (setup) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
}
|
||||
|
||||
//ctrl2 reg: cs_setup_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_CTRL2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_TIME, setup - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_cmd_phase_conf_buffer(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_command
|
||||
if (cmdlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
}
|
||||
|
||||
//user2 reg: usr_command_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_BITLEN, cmdlen - 1);
|
||||
|
||||
//user2 reg: usr_command_value
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, cmd);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_addr_phase_conf_buffer(spi_dev_t *hw, uint64_t addr, int addrlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_addr
|
||||
if (addrlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_addr_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_BITLEN, addrlen - 1);
|
||||
|
||||
//addr reg: addr
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, HAL_SWAP32(addr));
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, (addr << (32 - addrlen)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dummy_phase_conf_buffer(spi_dev_t *hw, int dummy_n, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_dummy
|
||||
if (dummy_n) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_dummy_cyclelen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_CYCLELEN, dummy_n - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dout_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_mosi
|
||||
if (bitlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
}
|
||||
|
||||
//mosi_dlen reg: usr_mosi_bit_len
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MOSI_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_DBITLEN, bitlen - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_din_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_miso
|
||||
if (bitlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
}
|
||||
|
||||
//miso_dlen reg: usr_miso_bit_len
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MISO_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_DBITLEN, bitlen - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for done phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS hold time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_done_phase_conf_buffer(spi_dev_t *hw, int hold, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_hold
|
||||
if (hold) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
}
|
||||
|
||||
//ctrl2 reg: cs_hold_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_CTRL2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_TIME, hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CONF_BITMAP_POS] = 0x7FFFFFF | (SPI_LL_SCT_MAGIC_NUMBER << 28);
|
||||
conf_buffer[SPI_LL_CMD_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->cmd.val;
|
||||
conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->addr.val;
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl.val;
|
||||
conf_buffer[SPI_LL_CTRL1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl1.val;
|
||||
conf_buffer[SPI_LL_CTRL2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl2.val;
|
||||
conf_buffer[SPI_LL_CLOCK_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->clock.val;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user.val;
|
||||
conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user1.val;
|
||||
conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user2.val;
|
||||
conf_buffer[SPI_LL_MOSI_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->mosi_dlen.val;
|
||||
conf_buffer[SPI_LL_MISO_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->miso_dlen.val;
|
||||
conf_buffer[SPI_LL_MISC_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->misc.val;
|
||||
conf_buffer[SPI_LL_SLAVE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->slave.val;
|
||||
conf_buffer[SPI_LL_FSM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->fsm.val;
|
||||
conf_buffer[SPI_LL_HOLD_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->hold.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_ENA_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_ena.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_RAW_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_raw.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_CLR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_clr.val;
|
||||
conf_buffer[SPI_LL_DIN_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_mode.val;
|
||||
conf_buffer[SPI_LL_DIN_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_num.val;
|
||||
conf_buffer[SPI_LL_DOUT_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_mode.val;
|
||||
conf_buffer[SPI_LL_DOUT_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_num.val;
|
||||
conf_buffer[SPI_LL_LCD_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->lcd_ctrl.val;
|
||||
conf_buffer[SPI_LL_LCD_CTRL1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->lcd_ctrl1.val;
|
||||
conf_buffer[SPI_LL_LCD_CTRL2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->lcd_ctrl2.val;
|
||||
conf_buffer[SPI_LL_LCD_D_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->lcd_d_mode.val;
|
||||
conf_buffer[SPI_LL_LCD_D_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->lcd_d_num.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_conf_state_enable(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slv_rd_byte.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
@@ -1911,6 +1632,192 @@ static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
hw->slv_rd_byte.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x3FFFE;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->ctrl1.val = hw->ctrl1.val;
|
||||
sct_cfg->ctrl2.val = hw->ctrl2.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->mosi_dlen.val = hw->mosi_dlen.val;
|
||||
sct_cfg->miso_dlen.val = hw->miso_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->slave.val = hw->slave.val;
|
||||
sct_cfg->fsm.val = hw->fsm.val;
|
||||
sct_cfg->hold.val = hw->hold.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_raw.val = hw->dma_int_raw.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->ctrl2.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->ctrl2.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.fcmd_oct = (line_mode.cmd_lines == 8);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.faddr_oct = (line_mode.addr_lines == 8);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->ctrl.fread_oct = (line_mode.data_lines == 8);
|
||||
sct_cfg->user.fwrite_oct = (line_mode.data_lines == 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->mosi_dlen.usr_mosi_dbitlen = bitlen - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->miso_dlen.usr_miso_dbitlen = bitlen - 1;
|
||||
}
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,17 +38,18 @@ extern "C" {
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) ((host == 2) ? 4 : 8) // Supported line mode: SPI3: 1, 2, 4, SPI1/2: 1, 2, 4, 8
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN (1 << 18) //reg len: 18 bits
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 2 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (16)
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN (0x3FFFA) //18 bits wide reg
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1249,307 +1250,32 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
#define SPI_LL_CONF_BUF_SET_BIT(_w, _m) ({ \
|
||||
(_w) |= (_m); \
|
||||
})
|
||||
#define SPI_LL_CONF_BUF_CLR_BIT(_w, _m) ({ \
|
||||
(_w) &= ~(_m); \
|
||||
})
|
||||
|
||||
#define SPI_LL_CONF_BUF_SET_FIELD(_w, _f, val) ({ \
|
||||
((_w) = (((_w) & ~((_f##_V) << (_f##_S))) | (((val) & (_f##_V))<<(_f##_S)))); \
|
||||
})
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t bitmap: 28;
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
#define SPI_LL_CONF_BUF_GET_FIELD(_w, _f) ({ \
|
||||
(((_w) >> (_f##_S)) & (_f##_V)); \
|
||||
})
|
||||
|
||||
//This offset is 1, for bitmap
|
||||
#define SPI_LL_CONF_BUFFER_OFFSET (1)
|
||||
//bitmap must be the first
|
||||
#define SPI_LL_CONF_BITMAP_POS (0)
|
||||
|
||||
#define SPI_LL_ADDR_REG_POS (0)
|
||||
#define SPI_LL_CTRL_REG_POS (1)
|
||||
#define SPI_LL_CLOCK_REG_POS (2)
|
||||
#define SPI_LL_USER_REG_POS (3)
|
||||
#define SPI_LL_USER1_REG_POS (4)
|
||||
#define SPI_LL_USER2_REG_POS (5)
|
||||
#define SPI_LL_MS_DLEN_REG_POS (6)
|
||||
#define SPI_LL_MISC_REG_POS (7)
|
||||
#define SPI_LL_DIN_MODE_REG_POS (8)
|
||||
#define SPI_LL_DIN_NUM_REG_POS (9)
|
||||
#define SPI_LL_DOUT_MODE_REG_POS (10)
|
||||
#define SPI_LL_DMA_CONF_REG_POS (11)
|
||||
#define SPI_LL_DMA_INT_ENA_REG_POS (12)
|
||||
#define SPI_LL_DMA_INT_CLR_REG_POS (13)
|
||||
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bits_len(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_conf_phase_conf_buffer(spi_dev_t *hw, bool is_end, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_conf_nxt
|
||||
if (is_end) {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_CONF_NXT_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_line_mode_conf_buff(spi_dev_t *hw, spi_line_mode_t line_mode, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
|
||||
switch (line_mode.cmd_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FCMD_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.addr_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_DUAL_M); break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_QUAD_M); break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FADDR_OCT_M); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (line_mode.data_lines) {
|
||||
case 2: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_DUAL_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_DUAL_M);
|
||||
break;
|
||||
case 4: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_QUAD_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_QUAD_M);
|
||||
break;
|
||||
case 8: SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FREAD_OCT_M);
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_FWRITE_OCT_M);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for prep phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS setup time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_prep_phase_conf_buffer(spi_dev_t *hw, uint8_t setup, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_setup
|
||||
if (setup) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_setup_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_SETUP_TIME, setup - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_cmd_phase_conf_buffer(spi_dev_t *hw, uint16_t cmd, int cmdlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_command
|
||||
if (cmdlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_M);
|
||||
}
|
||||
|
||||
//user2 reg: usr_command_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_BITLEN, cmdlen - 1);
|
||||
|
||||
//user2 reg: usr_command_value
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, cmd);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_COMMAND_VALUE, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_addr_phase_conf_buffer(spi_dev_t *hw, uint64_t addr, int addrlen, bool lsbfirst, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_addr
|
||||
if (addrlen) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_addr_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_BITLEN, addrlen - 1);
|
||||
|
||||
//addr reg: addr
|
||||
if (lsbfirst) {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, HAL_SWAP32(addr));
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_ADDR_VALUE, (addr << (32 - addrlen)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dummy_phase_conf_buffer(spi_dev_t *hw, int dummy_n, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: usr_dummy
|
||||
if (dummy_n) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_M);
|
||||
}
|
||||
|
||||
//user1 reg: usr_dummy_cyclelen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_DUMMY_CYCLELEN, dummy_n - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen output length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_dout_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_mosi
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MOSI_M);
|
||||
//dma_conf reg: dma_tx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_TX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param bitlen input length, in bits.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_din_phase_conf_buffer(spi_dev_t *hw, int bitlen, uint32_t *conf_buffer)
|
||||
{
|
||||
if (bitlen) {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
//ms_dlen reg: ms_data_bitlen
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_MS_DATA_BITLEN, bitlen - 1);
|
||||
} else {
|
||||
//user reg: usr_miso
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_USR_MISO_M);
|
||||
//dma_conf reg: dma_rx_ena
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_DMA_RX_ENA_M);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for done phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param setup CS hold time
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
static inline void spi_ll_format_done_phase_conf_buffer(spi_dev_t *hw, int hold, uint32_t *conf_buffer)
|
||||
{
|
||||
//user reg: cs_hold
|
||||
if (hold) {
|
||||
SPI_LL_CONF_BUF_SET_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
} else {
|
||||
SPI_LL_CONF_BUF_CLR_BIT(conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_M);
|
||||
}
|
||||
|
||||
//user1 reg: cs_hold_time
|
||||
SPI_LL_CONF_BUF_SET_FIELD(conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET], SPI_CS_HOLD_TIME, hold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_buffer Conf buffer to be updated.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
{
|
||||
conf_buffer[SPI_LL_CONF_BITMAP_POS] = 0x7FFF | (SPI_LL_SCT_MAGIC_NUMBER << 28);
|
||||
conf_buffer[SPI_LL_ADDR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->addr.val;
|
||||
conf_buffer[SPI_LL_CTRL_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ctrl.val;
|
||||
conf_buffer[SPI_LL_CLOCK_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->clock.val;
|
||||
conf_buffer[SPI_LL_USER_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user.val;
|
||||
conf_buffer[SPI_LL_USER1_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user1.val;
|
||||
conf_buffer[SPI_LL_USER2_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->user2.val;
|
||||
conf_buffer[SPI_LL_MS_DLEN_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->ms_dlen.val;
|
||||
conf_buffer[SPI_LL_MISC_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->misc.val;
|
||||
conf_buffer[SPI_LL_DIN_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_mode.val;
|
||||
conf_buffer[SPI_LL_DIN_NUM_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->din_num.val;
|
||||
conf_buffer[SPI_LL_DOUT_MODE_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dout_mode.val;
|
||||
conf_buffer[SPI_LL_DMA_CONF_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_conf.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_ENA_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_ena.val;
|
||||
conf_buffer[SPI_LL_DMA_INT_CLR_REG_POS + SPI_LL_CONF_BUFFER_OFFSET] = hw->dma_int_clr.val;
|
||||
}
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
@@ -1557,11 +1283,24 @@ static inline void spi_ll_init_conf_buffer(spi_dev_t *hw, uint32_t *conf_buffer)
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_conf_state_enable(spi_dev_t *hw, bool enable)
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
@@ -1573,6 +1312,195 @@ static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.fcmd_oct = (line_mode.cmd_lines == 8);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.faddr_oct = (line_mode.addr_lines == 8);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->ctrl.fread_oct = (line_mode.data_lines == 8);
|
||||
sct_cfg->user.fwrite_oct = (line_mode.data_lines == 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,21 +32,26 @@ extern "C" {
|
||||
/// Interrupt not used. Don't use in app.
|
||||
#define SPI_LL_UNUSED_INT_MASK (SPI_TRANS_DONE_INT_ENA | SPI_SLV_WR_DMA_DONE_INT_ENA | SPI_SLV_RD_DMA_DONE_INT_ENA | SPI_SLV_WR_BUF_DONE_INT_ENA | SPI_SLV_RD_BUF_DONE_INT_ENA)
|
||||
/// These 2 masks together will set SPI transaction to one line mode
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
#define SPI_LL_ONE_LINE_CTRL_MASK (SPI_FREAD_OCT | SPI_FREAD_QUAD | SPI_FREAD_DUAL | SPI_FCMD_OCT | \
|
||||
SPI_FCMD_QUAD | SPI_FCMD_DUAL | SPI_FADDR_OCT | SPI_FADDR_QUAD | SPI_FADDR_DUAL)
|
||||
#define SPI_LL_ONE_LINE_USER_MASK (SPI_FWRITE_OCT | SPI_FWRITE_QUAD | SPI_FWRITE_DUAL)
|
||||
/// Swap the bit order to its correct place to send
|
||||
#define HAL_SPI_SWAP_DATA_TX(data, len) HAL_SWAP32((uint32_t)(data) << (32 - len))
|
||||
|
||||
#define SPI_LL_PERIPH_CS_NUM(i) (((i)==0)? 2: (((i)==1)? 6: 3))
|
||||
#define SPI_LL_PERIPH_HAS_SCT(host) ((host) == SPI2_HOST) //If peripheral support SCT (DMA Segmented Configured Transaction) mode
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) ((host == 2) ? 4 : 8) // Supported line mode: SPI3: 1, 2, 4, SPI1/2: 1, 2, 4, 8
|
||||
#define SPI_LL_DMA_MAX_BIT_LEN SPI_MS_DATA_BITLEN
|
||||
#define SPI_LL_CPU_MAX_BIT_LEN (16 * 32) //Fifo len: 16 words
|
||||
#define SPI_LL_TX_MINI_EXTRA_BITS 1 //Minimum length of TX non byte aligned data in bits
|
||||
#define SPI_LL_RX_MINI_EXTRA_BITS 1 //Minimum length of RX non byte aligned data in bits
|
||||
#define SPI_LL_MAX_PRE_DIV_NUM (SPI_CLKDIV_PRE + 1)
|
||||
#define SPI_LL_SRC_PRE_DIV_MAX (HP_SYS_CLKRST_REG_GPSPI2_MST_CLK_DIV_NUM + 1) //source pre divider max before peripheral
|
||||
#define SPI_LL_PERIPH_CLK_DIV_MAX ((SPI_CLKCNT_N + 1) * (SPI_CLKDIV_PRE + 1)) //peripheral internal maxmum clock divider
|
||||
#define SPI_LL_MOSI_FREE_LEVEL 1 //Default level after bus initialized
|
||||
#define SPI_LL_PERIPH_BITWIDTH(host) ((host == 2) ? 4 : 8) // Supported line mode: SPI3: 1, 2, 4, SPI1/2: 1, 2, 4, 8
|
||||
#define SPI_LL_SCT_MAGIC_NUMBER (0x2)
|
||||
#define SPI_LL_SCT_CONF_BUF_NUM (1 + 14) //1-word-bitmap + 14-word-regs according to TRM
|
||||
#define SPI_LL_MAX_SCT_CONF_LEN SPI_CONF_BITLEN
|
||||
|
||||
/**
|
||||
* The data structure holding calculated clock configuration. Since the
|
||||
@@ -1300,6 +1305,267 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
|
||||
|
||||
#undef SPI_LL_UNUSED_INT_MASK
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Segmented-Configure-Transfer
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
/** bitmap : R/W; bitpos: [27:0]; default: 0;
|
||||
* SPI SCT bitmap.
|
||||
*/
|
||||
uint32_t bitmap: 28;
|
||||
/** magic_value : R/W; bitpos: [31:28]; default: 0;
|
||||
* SPI SCT magic value which compare with 'dma_seg_magic_value'
|
||||
* to check if the bitmap is valid.
|
||||
*/
|
||||
uint32_t magic_value: 4;
|
||||
};
|
||||
uint32_t val;
|
||||
} spi_ll_sct_bitmap_reg_t;
|
||||
|
||||
typedef struct spi_ll_sct_full_reg_t {
|
||||
volatile spi_ll_sct_bitmap_reg_t bitmap;
|
||||
volatile spi_addr_reg_t addr;
|
||||
volatile spi_ctrl_reg_t ctrl;
|
||||
volatile spi_clock_reg_t clock;
|
||||
volatile spi_user_reg_t user;
|
||||
volatile spi_user1_reg_t user1;
|
||||
volatile spi_user2_reg_t user2;
|
||||
volatile spi_ms_dlen_reg_t ms_dlen;
|
||||
volatile spi_misc_reg_t misc;
|
||||
volatile spi_din_mode_reg_t din_mode;
|
||||
volatile spi_din_num_reg_t din_num;
|
||||
volatile spi_dout_mode_reg_t dout_mode;
|
||||
volatile spi_dma_conf_reg_t dma_conf;
|
||||
volatile spi_dma_int_ena_reg_t dma_int_ena;
|
||||
volatile spi_dma_int_clr_reg_t dma_int_clr;
|
||||
} spi_ll_sct_full_reg_t;
|
||||
|
||||
/**
|
||||
* Enable/Disable the conf phase
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param enable True: enable; False: disable
|
||||
*/
|
||||
static inline void spi_ll_enable_conf_phase(spi_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->slave.usr_conf = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set conf phase bits len to HW for segment config trans mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param conf_bitlen Value of field conf_bitslen in cmd reg.
|
||||
*/
|
||||
static inline void spi_ll_set_conf_phase_bitlen(spi_dev_t *hw, uint32_t conf_bitlen)
|
||||
{
|
||||
if (conf_bitlen <= SPI_LL_MAX_SCT_CONF_LEN) {
|
||||
hw->cmd.conf_bitlen = conf_bitlen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Segmented-Configure-Transfer required magic value
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param magic_value magic value
|
||||
*/
|
||||
static inline void spi_ll_set_magic_number(spi_dev_t *hw, uint8_t magic_value)
|
||||
{
|
||||
hw->slave.dma_seg_magic_value = magic_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the conf buffer:
|
||||
*
|
||||
* - init bitmap
|
||||
* - save all register values into the rest of the conf buffer words
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void spi_sct_ll_init_conf_buffer(spi_dev_t *hw, spi_ll_sct_full_reg_t *sct_cfg)
|
||||
{
|
||||
sct_cfg->bitmap.bitmap = 0x7FFF;
|
||||
sct_cfg->bitmap.magic_value = SPI_LL_SCT_MAGIC_NUMBER;
|
||||
sct_cfg->addr.val = hw->addr.val;
|
||||
sct_cfg->ctrl.val = hw->ctrl.val;
|
||||
sct_cfg->clock.val = hw->clock.val;
|
||||
sct_cfg->user.val = hw->user.val;
|
||||
sct_cfg->user1.val = hw->user1.val;
|
||||
sct_cfg->user2.val = hw->user2.val;
|
||||
sct_cfg->ms_dlen.val = hw->ms_dlen.val;
|
||||
sct_cfg->misc.val = hw->misc.val;
|
||||
sct_cfg->din_mode.val = hw->din_mode.val;
|
||||
sct_cfg->din_num.val = hw->din_num.val;
|
||||
sct_cfg->dout_mode.val = hw->dout_mode.val;
|
||||
sct_cfg->dma_conf.val = hw->dma_conf.val;
|
||||
sct_cfg->dma_int_ena.val = hw->dma_int_ena.val;
|
||||
sct_cfg->dma_int_clr.val = hw->dma_int_clr.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param is_end Is this transaction the end of this segment.
|
||||
*/
|
||||
static inline void spi_sct_ll_mark_sct_end(spi_ll_sct_full_reg_t *sct_cfg, bool is_end)
|
||||
{
|
||||
sct_cfg->user.usr_conf_nxt = !is_end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set SPI to work in full duplex or half duplex mode.
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param half_duplex True to work in half duplex mode, otherwise in full duplex mode.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_duplex(spi_ll_sct_full_reg_t *sct_cfg, bool half_duplex)
|
||||
{
|
||||
sct_cfg->user.doutdin = !half_duplex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS setup time for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param setup CS setup time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_setup(spi_ll_sct_full_reg_t *sct_cfg, uint8_t setup)
|
||||
{
|
||||
sct_cfg->user.cs_setup = !!setup;
|
||||
sct_cfg->user1.cs_setup_time = setup - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS keep active for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cs_active True to keep CS active, otherwise to release CS.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_keep(spi_ll_sct_full_reg_t *sct_cfg, bool cs_active)
|
||||
{
|
||||
sct_cfg->misc.cs_keep_active = cs_active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set CS hold time post trans for a transaction in SCT
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param hold CS hold time
|
||||
*/
|
||||
static inline void spi_sct_ll_set_cs_hold(spi_ll_sct_full_reg_t *sct_cfg, int hold)
|
||||
{
|
||||
sct_cfg->user.cs_hold = !!hold;
|
||||
sct_cfg->user1.cs_hold_time = hold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the line mode of conf buffer for conf phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param line_mode line mode struct of each phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_line_mode(spi_ll_sct_full_reg_t *sct_cfg, spi_line_mode_t line_mode)
|
||||
{
|
||||
sct_cfg->ctrl.val &= ~SPI_LL_ONE_LINE_CTRL_MASK;
|
||||
sct_cfg->user.val &= ~SPI_LL_ONE_LINE_USER_MASK;
|
||||
sct_cfg->ctrl.fcmd_dual = (line_mode.cmd_lines == 2);
|
||||
sct_cfg->ctrl.fcmd_quad = (line_mode.cmd_lines == 4);
|
||||
sct_cfg->ctrl.fcmd_oct = (line_mode.cmd_lines == 8);
|
||||
sct_cfg->ctrl.faddr_dual = (line_mode.addr_lines == 2);
|
||||
sct_cfg->ctrl.faddr_quad = (line_mode.addr_lines == 4);
|
||||
sct_cfg->ctrl.faddr_oct = (line_mode.addr_lines == 8);
|
||||
sct_cfg->ctrl.fread_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->user.fwrite_dual = (line_mode.data_lines == 2);
|
||||
sct_cfg->ctrl.fread_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->user.fwrite_quad = (line_mode.data_lines == 4);
|
||||
sct_cfg->ctrl.fread_oct = (line_mode.data_lines == 8);
|
||||
sct_cfg->user.fwrite_oct = (line_mode.data_lines == 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for cmd phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param cmd Command value
|
||||
* @param cmdlen Length of the cmd phase
|
||||
* @param lsbfirst Whether LSB first
|
||||
*/
|
||||
static inline void spi_sct_ll_set_command(spi_ll_sct_full_reg_t *sct_cfg, uint16_t cmd, int cmdlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_command = !!cmdlen;
|
||||
if (cmdlen > 0) {
|
||||
sct_cfg->user2.usr_command_bitlen = cmdlen - 1;
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user2, usr_command_value, lsbfirst ? cmd : HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for addr phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param addr Address to set
|
||||
* @param addrlen Length of the address phase
|
||||
* @param lsbfirst whether the LSB first feature is enabled.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_addr(spi_ll_sct_full_reg_t *sct_cfg, uint64_t addr, int addrlen, bool lsbfirst)
|
||||
{
|
||||
sct_cfg->user.usr_addr = !!addrlen;
|
||||
if (addrlen > 0) {
|
||||
sct_cfg->user1.usr_addr_bitlen = addrlen - 1;
|
||||
sct_cfg->addr.val = lsbfirst ? HAL_SWAP32(addr) : (addr << (32 - addrlen));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dummy phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param dummy_n Dummy cycles used. 0 to disable the dummy phase.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_dummy(spi_ll_sct_full_reg_t *sct_cfg, int dummy_n)
|
||||
{
|
||||
sct_cfg->user.usr_dummy = !!dummy_n;
|
||||
if (dummy_n > 0) {
|
||||
HAL_FORCE_MODIFY_U32_REG_FIELD(sct_cfg->user1, usr_dummy_cyclelen, dummy_n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for dout phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen output length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_mosi_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_mosi = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_tx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the conf buffer for din phase
|
||||
*
|
||||
* @param sct_cfg Beginning address of the SCT conf buffer.
|
||||
* @param bitlen input length, in bits.
|
||||
*/
|
||||
static inline void spi_sct_ll_set_miso_bitlen(spi_ll_sct_full_reg_t *sct_cfg, int bitlen)
|
||||
{
|
||||
sct_cfg->user.usr_miso = !!bitlen;
|
||||
sct_cfg->dma_conf.dma_rx_ena = !!bitlen;
|
||||
if (bitlen) {
|
||||
sct_cfg->ms_dlen.ms_data_bitlen = bitlen - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base spi command
|
||||
*
|
||||
|
||||
@@ -135,7 +135,6 @@ typedef struct {
|
||||
typedef struct {
|
||||
/* CONF State */
|
||||
bool seg_end; ///< True: this segment is the end; False: this segment isn't the end;
|
||||
uint32_t seg_gap_len; ///< spi clock length of CS inactive on config phase for sct
|
||||
/* PREP State */
|
||||
int cs_setup; ///< Setup time of CS active edge before the first SPI clock
|
||||
/* CMD State */
|
||||
|
||||
@@ -49,7 +49,7 @@ void spi_hal_deinit(spi_hal_context_t *hal)
|
||||
#ifdef SPI_LL_PERIPH_HAS_SCT
|
||||
void spi_hal_sct_init(spi_hal_context_t *hal)
|
||||
{
|
||||
spi_ll_conf_state_enable(hal->hw, true);
|
||||
spi_ll_enable_conf_phase(hal->hw, true);
|
||||
spi_ll_set_magic_number(hal->hw, SPI_LL_SCT_MAGIC_NUMBER);
|
||||
spi_ll_disable_int(hal->hw); //trans_done intr enabled in `add device` phase, sct mode should use sct_trans_done only
|
||||
spi_ll_enable_intr(hal->hw, SPI_LL_INTR_SEG_DONE);
|
||||
@@ -58,7 +58,7 @@ void spi_hal_sct_init(spi_hal_context_t *hal)
|
||||
|
||||
void spi_hal_sct_deinit(spi_hal_context_t *hal)
|
||||
{
|
||||
spi_ll_conf_state_enable(hal->hw, false);
|
||||
spi_ll_enable_conf_phase(hal->hw, false);
|
||||
spi_ll_disable_intr(hal->hw, SPI_LL_INTR_SEG_DONE);
|
||||
spi_ll_clear_intr(hal->hw, SPI_LL_INTR_SEG_DONE);
|
||||
spi_ll_clear_int_stat(hal->hw);
|
||||
|
||||
@@ -279,28 +279,27 @@ void spi_hal_fetch_result(const spi_hal_context_t *hal)
|
||||
*----------------------------------------------------------------------------*/
|
||||
void spi_hal_sct_set_conf_bits_len(spi_hal_context_t *hal, uint32_t conf_len)
|
||||
{
|
||||
spi_ll_set_conf_phase_bits_len(hal->hw, conf_len);
|
||||
spi_ll_set_conf_phase_bitlen(hal->hw, conf_len);
|
||||
}
|
||||
|
||||
void spi_hal_sct_init_conf_buffer(spi_hal_context_t *hal, uint32_t *conf_buffer)
|
||||
{
|
||||
spi_ll_init_conf_buffer(hal->hw, conf_buffer);
|
||||
spi_sct_ll_init_conf_buffer(hal->hw, (spi_ll_sct_full_reg_t *)conf_buffer);
|
||||
}
|
||||
|
||||
void spi_hal_sct_format_conf_buffer(spi_hal_context_t *hal, const spi_hal_seg_config_t *config, const spi_hal_dev_config_t *dev, uint32_t *conf_buffer)
|
||||
{
|
||||
spi_ll_format_line_mode_conf_buff(hal->hw, hal->trans_config.line_mode, conf_buffer);
|
||||
spi_ll_format_prep_phase_conf_buffer(hal->hw, config->cs_setup, conf_buffer);
|
||||
spi_ll_format_cmd_phase_conf_buffer(hal->hw, config->cmd, config->cmd_bits, dev->tx_lsbfirst, conf_buffer);
|
||||
spi_ll_format_addr_phase_conf_buffer(hal->hw, config->addr, config->addr_bits, dev->rx_lsbfirst, conf_buffer);
|
||||
spi_ll_format_dummy_phase_conf_buffer(hal->hw, config->dummy_bits, conf_buffer);
|
||||
spi_ll_format_dout_phase_conf_buffer(hal->hw, config->tx_bitlen, conf_buffer);
|
||||
spi_ll_format_din_phase_conf_buffer(hal->hw, config->rx_bitlen, conf_buffer);
|
||||
spi_ll_format_done_phase_conf_buffer(hal->hw, config->cs_hold, conf_buffer);
|
||||
spi_ll_format_conf_phase_conf_buffer(hal->hw, config->seg_end, conf_buffer);
|
||||
#if SPI_LL_SUPPORT_SEG_GAP
|
||||
spi_ll_format_conf_bitslen_buffer(hal->hw, config->seg_gap_len, conf_buffer);
|
||||
#endif
|
||||
spi_ll_sct_full_reg_t *sct_cfg = (spi_ll_sct_full_reg_t *)conf_buffer;
|
||||
|
||||
spi_sct_ll_set_line_mode(sct_cfg, hal->trans_config.line_mode);
|
||||
spi_sct_ll_set_cs_setup(sct_cfg, config->cs_setup);
|
||||
spi_sct_ll_set_cs_hold(sct_cfg, config->cs_hold);
|
||||
spi_sct_ll_set_command(sct_cfg, config->cmd, config->cmd_bits, dev->tx_lsbfirst);
|
||||
spi_sct_ll_set_addr(sct_cfg, config->addr, config->addr_bits, dev->tx_lsbfirst);
|
||||
spi_sct_ll_set_dummy(sct_cfg, config->dummy_bits);
|
||||
spi_sct_ll_set_mosi_bitlen(sct_cfg, config->tx_bitlen);
|
||||
spi_sct_ll_set_miso_bitlen(sct_cfg, config->rx_bitlen);
|
||||
spi_sct_ll_mark_sct_end(sct_cfg, config->seg_end);
|
||||
}
|
||||
|
||||
#endif //#ifdef SPI_LL_PERIPH_HAS_SCT
|
||||
|
||||
Reference in New Issue
Block a user