Merge branch 'feature/spi_dma_segmented_configure_transfer' into 'master'

feat(spi_master): new feature dma controlled segmented configure transfer(sct) mode (part_1)

Closes IDF-4998

See merge request espressif/esp-idf!22684
This commit is contained in:
Wan Lei
2024-03-21 18:50:03 +08:00
27 changed files with 3259 additions and 79 deletions
+330 -2
View File
@@ -296,7 +296,7 @@ static inline void spi_ll_user_start(spi_dev_t *hw)
*/
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
{
return hw->cmd.val;
return hw->cmd.usr;
}
/**
@@ -650,8 +650,8 @@ static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t li
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
}
@@ -1260,6 +1260,334 @@ static inline int spi_ll_get_slave_hd_dummy_bits(spi_line_mode_t line_mode)
return 8;
}
/*------------------------------------------------------------------------------
* 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)))); \
})
#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 <= SOC_SPI_SCT_CONF_BITLEN_MAX) {
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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;
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;
}
/**
* 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->slave.usr_conf = enable;
}
/**
* 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;
}
#undef SPI_LL_RST_MASK
#undef SPI_LL_UNUSED_INT_MASK
+327 -2
View File
@@ -298,7 +298,7 @@ static inline void spi_ll_user_start(spi_dev_t *hw)
*/
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
{
return hw->cmd.val;
return hw->cmd.usr;
}
/**
@@ -652,8 +652,8 @@ static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t li
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
}
@@ -1175,6 +1175,331 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
return hw->slave1.last_addr;
}
/*------------------------------------------------------------------------------
* 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)))); \
})
#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 <= SOC_SPI_SCT_CONF_BITLEN_MAX) {
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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;
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;
}
/**
* 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->slave.usr_conf = enable;
}
/**
* 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;
}
#undef SPI_LL_RST_MASK
#undef SPI_LL_UNUSED_INT_MASK
+328 -2
View File
@@ -290,7 +290,7 @@ static inline void spi_ll_user_start(spi_dev_t *hw)
*/
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
{
return hw->cmd.val;
return hw->cmd.usr;
}
/**
@@ -644,8 +644,8 @@ static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t li
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
}
@@ -1167,6 +1167,332 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
return hw->slave1.slv_last_addr;
}
/*------------------------------------------------------------------------------
* 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)))); \
})
#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 <= SOC_SPI_SCT_CONF_BITLEN_MAX) {
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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;
}
/**
* 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->slave.usr_conf = enable;
}
/**
* 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;
}
#undef SPI_LL_RST_MASK
#undef SPI_LL_UNUSED_INT_MASK
+334 -2
View File
@@ -289,7 +289,7 @@ static inline void spi_ll_user_start(spi_dev_t *hw)
*/
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
{
return hw->cmd.val;
return hw->cmd.usr;
}
/**
@@ -643,8 +643,8 @@ static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t li
hw->ctrl.faddr_dual = (line_mode.addr_lines == 2);
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
}
@@ -1166,6 +1166,338 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
return hw->slave1.slv_last_addr;
}
/*------------------------------------------------------------------------------
* 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)))); \
})
#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 <= SOC_SPI_SCT_CONF_BITLEN_MAX) {
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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;
}
/**
* 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->slave.usr_conf = enable;
}
/**
* 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;
}
#undef SPI_LL_RST_MASK
#undef SPI_LL_UNUSED_INT_MASK
+384 -5
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,10 +18,13 @@
#include <string.h>
#include "esp_types.h"
#include "esp_attr.h"
#include "esp_bit_defs.h"
#include "soc/spi_periph.h"
#include "soc/spi_struct.h"
#include "soc/spi_reg.h"
#include "soc/dport_reg.h"
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "hal/assert.h"
#include "hal/misc.h"
#include "hal/spi_types.h"
@@ -308,7 +311,7 @@ static inline void spi_ll_user_start(spi_dev_t *hw)
*/
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
{
return hw->cmd.val;
return hw->cmd.usr;
}
/**
@@ -641,10 +644,10 @@ static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t li
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
hw->ctrl.faddr_oct = (line_mode.addr_lines == 8);
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
hw->ctrl.fread_oct = (line_mode.data_lines == 8);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
hw->user.fwrite_oct = (line_mode.data_lines == 8);
}
@@ -1017,7 +1020,6 @@ static inline void spi_ll_set_command(spi_dev_t *hw, uint16_t cmd, int cmdlen, b
* more straightly.
*/
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->user2, usr_command_value, HAL_SPI_SWAP_DATA_TX(cmd, cmdlen));
}
}
@@ -1463,6 +1465,383 @@ static inline bool spi_ll_tx_get_empty_err(spi_dev_t *hw)
return hw->dma_int_raw.outfifo_empty_err;
}
/*------------------------------------------------------------------------------
* 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)))); \
})
#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_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)
/**
* Set conf phase base bits len to HW for segment config trans mode.
* need let transaction gap more than approx 2 us under different freq, calculated by driver layer.
*
* @param hw Beginning address of the peripheral registers.
* @param conf_base Conf base bits len.
*/
static inline void spi_ll_set_conf_base_bitslen(spi_dev_t *hw, uint8_t conf_base)
{
// 7 bits wide
if(conf_base < 128) {
hw->slv_wrbuf_dlen.conf_base_bitlen = conf_base;
}
}
/**
* 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 <= SOC_SPI_SCT_CONF_BITLEN_MAX) {
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//cmd reg: conf_bitlen
if (conf_bitlen <= SOC_SPI_SCT_CONF_BITLEN_MAX) {
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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;
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
*
* @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->slv_rd_byte.dma_seg_magic_value = magic_value;
}
#undef SPI_LL_RST_MASK
#undef SPI_LL_UNUSED_INT_MASK
+335 -3
View File
@@ -305,7 +305,7 @@ static inline void spi_ll_user_start(spi_dev_t *hw)
*/
static inline uint32_t spi_ll_get_running_cmd(spi_dev_t *hw)
{
return hw->cmd.val;
return hw->cmd.usr;
}
/**
@@ -661,10 +661,10 @@ static inline void spi_ll_master_set_line_mode(spi_dev_t *hw, spi_line_mode_t li
hw->ctrl.faddr_quad = (line_mode.addr_lines == 4);
hw->ctrl.faddr_oct = (line_mode.addr_lines == 8);
hw->ctrl.fread_dual = (line_mode.data_lines == 2);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->ctrl.fread_quad = (line_mode.data_lines == 4);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
hw->ctrl.fread_oct = (line_mode.data_lines == 8);
hw->user.fwrite_dual = (line_mode.data_lines == 2);
hw->user.fwrite_quad = (line_mode.data_lines == 4);
hw->user.fwrite_oct = (line_mode.data_lines == 8);
}
@@ -1195,6 +1195,338 @@ static inline uint32_t spi_ll_slave_hd_get_last_addr(spi_dev_t *hw)
return hw->slave1.last_addr;
}
/*------------------------------------------------------------------------------
* 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)))); \
})
#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 <= SOC_SPI_SCT_CONF_BITLEN_MAX) {
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
//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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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;
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;
}
/**
* 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->slave.usr_conf = enable;
}
/**
* 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;
}
#undef SPI_LL_RST_MASK
#undef SPI_LL_UNUSED_INT_MASK
+80
View File
@@ -133,6 +133,33 @@ typedef struct {
};//boolean configurations
} spi_hal_dev_config_t;
#if SOC_SPI_SCT_SUPPORTED
/**
* SCT mode required configurations, per segment
*/
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 */
uint16_t cmd; ///< Command value to be sent
int cmd_bits; ///< Length (in bits) of the command phase
/* ADDR State */
uint64_t addr; ///< Address value to be sent
int addr_bits; ///< Length (in bits) of the address phase
/* DUMMY State */
int dummy_bits; ///< Base length (in bits) of the dummy phase.
/* DOUT State */
int tx_bitlen; ///< TX length, in bits
/* DIN State */
int rx_bitlen; ///< RX length, in bits
/* DONE State */
int cs_hold; ///< Hold time of CS inactive edge after the last SPI clock
} spi_hal_seg_config_t;
#endif //#if SOC_SPI_SCT_SUPPORTED
/**
* Init the peripheral and the context.
*
@@ -266,6 +293,59 @@ void spi_hal_cal_timing(int source_freq_hz, int eff_clk, bool gpio_is_used, int
*/
int spi_hal_get_freq_limit(bool gpio_is_used, int input_delay_ns);
#if SOC_SPI_SCT_SUPPORTED
/*----------------------------------------------------------
* Segmented-Configure-Transfer (SCT) Mode
* ---------------------------------------------------------*/
/**
* Initialise SCT mode required registers and hal states
*
* @param hal Context of the HAL layer.
*/
void spi_hal_sct_init(spi_hal_context_t *hal);
/**
* Initialise conf buffer, give it an initial value
*
* @param hal Context of the HAL layer.
*/
void spi_hal_sct_init_conf_buffer(spi_hal_context_t *hal, uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX]);
/**
* Format the conf buffer
* According to the `spi_hal_seg_config_t`, update the conf buffer
*
* @param hal Context of the HAL layer.
* @param config Conf buffer configuration, per segment. See `spi_hal_seg_config_t` to know what can be configured
* @param conf_buffer 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[SOC_SPI_SCT_BUFFER_NUM_MAX]);
/**
* Deinit SCT mode related registers and hal states
*/
void spi_hal_sct_deinit(spi_hal_context_t *hal);
/**
* Set conf_bitslen to HW for sct.
*/
void spi_hal_sct_set_conf_bits_len(spi_hal_context_t *hal, uint32_t conf_len);
/**
* Clear SPI interrupt bits by mask
*/
void spi_hal_clear_intr_mask(spi_hal_context_t *hal, uint32_t mask);
/**
* Get SPI interrupt bits status by mask
*/
bool spi_hal_get_intr_mask(spi_hal_context_t *hal, uint32_t mask);
/**
* Set conf_bitslen base to HW for sct, only supported on s2.
*/
#define spi_hal_sct_setup_conf_base(hal, conf_base) spi_ll_set_conf_base_bitslen((hal)->hw, conf_base)
#endif //#if SOC_SPI_SCT_SUPPORTED
#endif //#if SOC_GPSPI_SUPPORTED
#ifdef __cplusplus
+20
View File
@@ -52,6 +52,26 @@ void spi_hal_deinit(spi_hal_context_t *hal)
}
}
#if SOC_SPI_SCT_SUPPORTED
void spi_hal_sct_init(spi_hal_context_t *hal)
{
spi_ll_conf_state_enable(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 shoud use sct_trans_done only
spi_ll_enable_intr(hal->hw, SPI_LL_INTR_SEG_DONE);
spi_ll_set_intr(hal->hw, SPI_LL_INTR_SEG_DONE);
}
void spi_hal_sct_deinit(spi_hal_context_t *hal)
{
spi_ll_conf_state_enable(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);
spi_ll_enable_int(hal->hw); //recover trans_done intr
}
#endif //#if SOC_SPI_SCT_SUPPORTED
esp_err_t spi_hal_cal_clock_conf(const spi_hal_timing_param_t *timing_param, spi_hal_timing_conf_t *timing_conf)
{
spi_hal_timing_conf_t temp_conf = {};
+41 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -162,3 +162,43 @@ void spi_hal_fetch_result(const spi_hal_context_t *hal)
spi_ll_read_buffer(hal->hw, trans->rcv_buffer, trans->rx_bitlen);
}
}
#if SOC_SPI_SCT_SUPPORTED
/*------------------------------------------------------------------------------
* Segmented-Configure-Transfer
*----------------------------------------------------------------------------*/
void spi_hal_clear_intr_mask(spi_hal_context_t *hal, uint32_t mask) {
spi_ll_clear_intr(hal->hw, mask);
}
bool spi_hal_get_intr_mask(spi_hal_context_t *hal, uint32_t mask) {
return spi_ll_get_intr(hal->hw, mask);
}
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);
}
void spi_hal_sct_init_conf_buffer(spi_hal_context_t *hal, uint32_t conf_buffer[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
spi_ll_init_conf_buffer(hal->hw, 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[SOC_SPI_SCT_BUFFER_NUM_MAX])
{
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 CONFIG_IDF_TARGET_ESP32S2
// only s2 support update seg_gap_len by conf_buffer
spi_ll_format_conf_bitslen_buffer(hal->hw, config->seg_gap_len, conf_buffer);
#endif
}
#endif //#if SOC_SPI_SCT_SUPPORTED