1 #include "hal/spi_slave_hal.h"
2 #include "hal/spi_ll.h"
3 #include "soc/soc_caps.h"
4 
5 //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
6 #if SOC_GDMA_SUPPORTED
7 #include "soc/gdma_struct.h"
8 #include "hal/gdma_ll.h"
9 
10 #define spi_dma_ll_rx_reset(dev, chan)                             gdma_ll_rx_reset_channel(&GDMA, chan)
11 #define spi_dma_ll_tx_reset(dev, chan)                             gdma_ll_tx_reset_channel(&GDMA, chan);
12 #define spi_dma_ll_rx_start(dev, chan, addr) do {\
13             gdma_ll_rx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
14             gdma_ll_rx_start(&GDMA, chan);\
15         } while (0)
16 #define spi_dma_ll_tx_start(dev, chan, addr) do {\
17             gdma_ll_tx_set_desc_addr(&GDMA, chan, (uint32_t)addr);\
18             gdma_ll_tx_start(&GDMA, chan);\
19         } while (0)
20 #endif
21 
spi_slave_hal_usr_is_done(spi_slave_hal_context_t * hal)22 bool spi_slave_hal_usr_is_done(spi_slave_hal_context_t* hal)
23 {
24     return spi_ll_usr_is_done(hal->hw);
25 }
26 
spi_slave_hal_user_start(const spi_slave_hal_context_t * hal)27 void spi_slave_hal_user_start(const spi_slave_hal_context_t *hal)
28 {
29     spi_ll_clear_int_stat(hal->hw); //clear int bit
30     spi_ll_slave_user_start(hal->hw);
31 }
32 
spi_slave_hal_prepare_data(const spi_slave_hal_context_t * hal)33 void spi_slave_hal_prepare_data(const spi_slave_hal_context_t *hal)
34 {
35     if (hal->use_dma) {
36 
37         //Fill DMA descriptors
38         if (hal->rx_buffer) {
39             lldesc_setup_link(hal->dmadesc_rx, hal->rx_buffer, ((hal->bitlen + 7) / 8), true);
40 
41             //reset dma inlink, this should be reset before spi related reset
42             spi_dma_ll_rx_reset(hal->dma_in, hal->rx_dma_chan);
43             spi_ll_dma_rx_fifo_reset(hal->dma_in);
44             spi_ll_slave_reset(hal->hw);
45             spi_ll_infifo_full_clr(hal->hw);
46 
47             spi_ll_dma_rx_enable(hal->hw, 1);
48             spi_dma_ll_rx_start(hal->dma_in, hal->rx_dma_chan, &hal->dmadesc_rx[0]);
49         }
50         if (hal->tx_buffer) {
51             lldesc_setup_link(hal->dmadesc_tx, hal->tx_buffer, (hal->bitlen + 7) / 8, false);
52             //reset dma outlink, this should be reset before spi related reset
53             spi_dma_ll_tx_reset(hal->dma_out, hal->tx_dma_chan);
54             spi_ll_dma_tx_fifo_reset(hal->dma_out);
55             spi_ll_slave_reset(hal->hw);
56             spi_ll_outfifo_empty_clr(hal->hw);
57 
58             spi_ll_dma_tx_enable(hal->hw, 1);
59             spi_dma_ll_tx_start(hal->dma_out, hal->tx_dma_chan, (&hal->dmadesc_tx[0]));
60         }
61     } else {
62         //No DMA. Turn off SPI and copy data to transmit buffers.
63         if (hal->tx_buffer) {
64             spi_ll_slave_reset(hal->hw);
65             spi_ll_write_buffer(hal->hw, hal->tx_buffer, hal->bitlen);
66         }
67 
68         spi_ll_cpu_tx_fifo_reset(hal->hw);
69     }
70 
71     spi_ll_slave_set_rx_bitlen(hal->hw, hal->bitlen);
72     spi_ll_slave_set_tx_bitlen(hal->hw, hal->bitlen);
73 
74 #ifdef CONFIG_IDF_TARGET_ESP32
75     //SPI Slave mode on ESP32 requires MOSI/MISO enable
76     spi_ll_enable_mosi(hal->hw, (hal->rx_buffer == NULL) ? 0 : 1);
77     spi_ll_enable_miso(hal->hw, (hal->tx_buffer == NULL) ? 0 : 1);
78 #endif
79 }
80 
spi_slave_hal_store_result(spi_slave_hal_context_t * hal)81 void spi_slave_hal_store_result(spi_slave_hal_context_t *hal)
82 {
83     //when data of cur_trans->length are all sent, the slv_rdata_bit
84     //will be the length sent-1 (i.e. cur_trans->length-1 ), otherwise
85     //the length sent.
86     hal->rcv_bitlen = spi_ll_slave_get_rcv_bitlen(hal->hw);
87     if (hal->rcv_bitlen == hal->bitlen - 1) {
88         hal->rcv_bitlen++;
89     }
90     if (!hal->use_dma && hal->rx_buffer) {
91         //Copy result out
92         spi_ll_read_buffer(hal->hw, hal->rx_buffer, hal->bitlen);
93     }
94 }
95 
spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t * hal)96 uint32_t spi_slave_hal_get_rcv_bitlen(spi_slave_hal_context_t *hal)
97 {
98     return hal->rcv_bitlen;
99 }
100 
101 #if CONFIG_IDF_TARGET_ESP32
102 //This workaround is only for esp32
spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t * hal)103 bool spi_slave_hal_dma_need_reset(const spi_slave_hal_context_t *hal)
104 {
105     bool ret;
106     ret = false;
107     if (hal->use_dma && hal->rx_buffer) {
108         int i;
109         //In case CS goes high too soon, the transfer is aborted while the DMA channel still thinks it's going. This
110         //leads to issues later on, so in that case we need to reset the channel. The state can be detected because
111         //the DMA system doesn't give back the offending descriptor; the owner is still set to DMA.
112         for (i = 0; hal->dmadesc_rx[i].eof == 0 && hal->dmadesc_rx[i].owner == 0; i++) {}
113         if (hal->dmadesc_rx[i].owner) {
114             ret = true;
115         }
116     }
117     return ret;
118 }
119 #endif //#if CONFIG_IDF_TARGET_ESP32
120