1 // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 
16 #include <string.h>
17 #include "sdkconfig.h"
18 #include "driver/spi_master.h"
19 #include "soc/spi_periph.h"
20 #include "esp_types.h"
21 #include "esp_attr.h"
22 #include "esp_log.h"
23 #include "esp_err.h"
24 #include "soc/soc.h"
25 #include "soc/soc_caps.h"
26 #include "soc/lldesc.h"
27 #include "driver/gpio.h"
28 #include "driver/periph_ctrl.h"
29 #include "esp_heap_caps.h"
30 #include "driver/spi_common_internal.h"
31 #include "stdatomic.h"
32 #include "hal/spi_hal.h"
33 #include "hal/gpio_hal.h"
34 #include "esp_rom_gpio.h"
35 #if CONFIG_IDF_TARGET_ESP32
36 #include "soc/dport_reg.h"
37 #endif
38 #if SOC_GDMA_SUPPORTED
39 #include "esp_private/gdma.h"
40 #endif
41 
42 static const char *SPI_TAG = "spi";
43 
44 #define SPI_CHECK(a, str, ret_val) do { \
45     if (!(a)) { \
46         ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
47         return (ret_val); \
48     } \
49     } while(0)
50 
51 #define SPI_CHECK_PIN(pin_num, pin_name, check_output) if (check_output) { \
52             SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
53         } else { \
54             SPI_CHECK(GPIO_IS_VALID_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
55         }
56 
57 #define SPI_MAIN_BUS_DEFAULT() { \
58         .host_id = 0, \
59         .bus_attr = { \
60             .tx_dma_chan = 0, \
61             .rx_dma_chan = 0, \
62             .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, \
63             .dma_desc_num= 0, \
64         }, \
65     }
66 
67 #define FUNC_GPIO   PIN_FUNC_GPIO
68 
69 
70 typedef struct {
71     int host_id;
72     spi_destroy_func_t destroy_func;
73     void* destroy_arg;
74     spi_bus_attr_t bus_attr;
75 #if SOC_GDMA_SUPPORTED
76     gdma_channel_handle_t tx_channel;
77     gdma_channel_handle_t rx_channel;
78 #endif
79 } spicommon_bus_context_t;
80 
81 //Periph 1 is 'claimed' by SPI flash code.
82 static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false),
83 #if (SOC_SPI_PERIPH_NUM >= 3)
84 ATOMIC_VAR_INIT(false),
85 #endif
86 #if (SOC_SPI_PERIPH_NUM >= 4)
87 ATOMIC_VAR_INIT(false),
88 #endif
89 };
90 
91 static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
92 static spicommon_bus_context_t s_mainbus = SPI_MAIN_BUS_DEFAULT();
93 static spicommon_bus_context_t* bus_ctx[SOC_SPI_PERIPH_NUM] = {&s_mainbus};
94 
95 #if !SOC_GDMA_SUPPORTED
96 //Each bit stands for 1 dma channel, BIT(0) should be used for SPI1
97 static uint8_t spi_dma_chan_enabled = 0;
98 static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
99 #endif  //#if !SOC_GDMA_SUPPORTED
100 
101 
is_valid_host(spi_host_device_t host)102 static inline bool is_valid_host(spi_host_device_t host)
103 {
104 #if (SOC_SPI_PERIPH_NUM == 2)
105     return host >= SPI1_HOST && host <= SPI2_HOST;
106 #elif (SOC_SPI_PERIPH_NUM == 3)
107     return host >= SPI1_HOST && host <= SPI3_HOST;
108 #endif
109 }
110 
111 //----------------------------------------------------------alloc spi periph-------------------------------------------------------//
112 //Returns true if this peripheral is successfully claimed, false if otherwise.
spicommon_periph_claim(spi_host_device_t host,const char * source)113 bool spicommon_periph_claim(spi_host_device_t host, const char* source)
114 {
115     bool false_var = false;
116     bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true);
117     if (ret) {
118         spi_claiming_func[host] = source;
119         periph_module_enable(spi_periph_signal[host].module);
120     } else {
121         ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host+1, spi_claiming_func[host]);
122     }
123     return ret;
124 }
125 
spicommon_periph_in_use(spi_host_device_t host)126 bool spicommon_periph_in_use(spi_host_device_t host)
127 {
128     return atomic_load(&spi_periph_claimed[host]);
129 }
130 
131 //Returns true if this peripheral is successfully freed, false if otherwise.
spicommon_periph_free(spi_host_device_t host)132 bool spicommon_periph_free(spi_host_device_t host)
133 {
134     bool true_var = true;
135     bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &true_var, false);
136     if (ret) periph_module_disable(spi_periph_signal[host].module);
137     return ret;
138 }
139 
spicommon_irqsource_for_host(spi_host_device_t host)140 int spicommon_irqsource_for_host(spi_host_device_t host)
141 {
142     return spi_periph_signal[host].irq;
143 }
144 
spicommon_irqdma_source_for_host(spi_host_device_t host)145 int spicommon_irqdma_source_for_host(spi_host_device_t host)
146 {
147     return spi_periph_signal[host].irq_dma;
148 }
149 
150 //----------------------------------------------------------alloc dma periph-------------------------------------------------------//
151 #if !SOC_GDMA_SUPPORTED
get_dma_periph(int dma_chan)152 static inline periph_module_t get_dma_periph(int dma_chan)
153 {
154     assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM);
155 #if CONFIG_IDF_TARGET_ESP32S2
156     if (dma_chan == 1) {
157         return PERIPH_SPI2_DMA_MODULE;
158     } else if (dma_chan == 2) {
159         return PERIPH_SPI3_DMA_MODULE;
160     } else {
161         abort();
162     }
163 #elif CONFIG_IDF_TARGET_ESP32
164     return PERIPH_SPI_DMA_MODULE;
165 #endif
166 }
167 
spicommon_dma_chan_claim(int dma_chan,uint32_t * out_actual_dma_chan)168 static bool spicommon_dma_chan_claim(int dma_chan, uint32_t *out_actual_dma_chan)
169 {
170     bool ret = false;
171 
172     portENTER_CRITICAL(&spi_dma_spinlock);
173     bool is_used = (BIT(dma_chan) & spi_dma_chan_enabled);
174     if (!is_used) {
175         spi_dma_chan_enabled |= BIT(dma_chan);
176         periph_module_enable(get_dma_periph(dma_chan));
177         *out_actual_dma_chan = dma_chan;
178         ret = true;
179     }
180     portEXIT_CRITICAL(&spi_dma_spinlock);
181 
182     return ret;
183 }
184 
spicommon_connect_spi_and_dma(spi_host_device_t host,int dma_chan)185 static void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan)
186 {
187 #if CONFIG_IDF_TARGET_ESP32
188     DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
189 #elif CONFIG_IDF_TARGET_ESP32S2
190     //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them.
191 #endif
192 }
193 
spicommon_dma_chan_alloc(spi_host_device_t host_id,spi_dma_chan_t dma_chan,uint32_t * out_actual_tx_dma_chan,uint32_t * out_actual_rx_dma_chan)194 static esp_err_t spicommon_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
195 {
196     assert(is_valid_host(host_id));
197 #if CONFIG_IDF_TARGET_ESP32
198     assert(dma_chan > SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO);
199 #elif CONFIG_IDF_TARGET_ESP32S2
200     assert(dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO);
201 #endif
202 
203     esp_err_t ret = ESP_OK;
204     bool success = false;
205     uint32_t actual_dma_chan = 0;
206 
207     if (dma_chan == SPI_DMA_CH_AUTO) {
208 #if CONFIG_IDF_TARGET_ESP32
209         for (int i = 1; i < SOC_SPI_DMA_CHAN_NUM+1; i++) {
210             success = spicommon_dma_chan_claim(i, &actual_dma_chan);
211             if (success) {
212                 break;
213             }
214         }
215 #elif CONFIG_IDF_TARGET_ESP32S2
216         //On ESP32S2, each SPI controller has its own DMA channel
217         success = spicommon_dma_chan_claim(host_id, &actual_dma_chan);
218 #endif  //#if CONFIG_IDF_TARGET_XXX
219     } else {
220         success = spicommon_dma_chan_claim((int)dma_chan, &actual_dma_chan);
221     }
222 
223     //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
224     *out_actual_tx_dma_chan = actual_dma_chan;
225     *out_actual_rx_dma_chan = actual_dma_chan;
226 
227     if (!success) {
228         SPI_CHECK(false, "no available dma channel", ESP_ERR_NOT_FOUND);
229     }
230 
231     spicommon_connect_spi_and_dma(host_id, *out_actual_tx_dma_chan);
232 
233     return ret;
234 }
235 
236 #else //SOC_GDMA_SUPPORTED
spicommon_dma_chan_alloc(spi_host_device_t host_id,spi_dma_chan_t dma_chan,uint32_t * out_actual_tx_dma_chan,uint32_t * out_actual_rx_dma_chan)237 static esp_err_t spicommon_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
238 {
239     assert(is_valid_host(host_id));
240     assert(dma_chan == SPI_DMA_CH_AUTO);
241 
242     esp_err_t ret = ESP_OK;
243     spicommon_bus_context_t *ctx = bus_ctx[host_id];
244 
245     if (dma_chan == SPI_DMA_CH_AUTO) {
246         gdma_channel_alloc_config_t tx_alloc_config = {
247             .flags.reserve_sibling = 1,
248             .direction = GDMA_CHANNEL_DIRECTION_TX,
249         };
250         ret = gdma_new_channel(&tx_alloc_config, &ctx->tx_channel);
251         if (ret != ESP_OK) {
252             return ret;
253         }
254 
255         gdma_channel_alloc_config_t rx_alloc_config = {
256             .direction = GDMA_CHANNEL_DIRECTION_RX,
257             .sibling_chan = ctx->tx_channel,
258         };
259         ret = gdma_new_channel(&rx_alloc_config, &ctx->rx_channel);
260         if (ret != ESP_OK) {
261             return ret;
262         }
263 
264         if (host_id == SPI2_HOST) {
265             gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2));
266             gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2));
267         }
268 #if (SOC_SPI_PERIPH_NUM >= 3)
269         else if (host_id == SPI3_HOST) {
270             gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3));
271             gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3));
272         }
273 #endif
274         gdma_get_channel_id(ctx->tx_channel, (int *)out_actual_tx_dma_chan);
275         gdma_get_channel_id(ctx->rx_channel, (int *)out_actual_rx_dma_chan);
276     }
277 
278     return ret;
279 }
280 #endif  //#if !SOC_GDMA_SUPPORTED
281 
spicommon_slave_dma_chan_alloc(spi_host_device_t host_id,spi_dma_chan_t dma_chan,uint32_t * out_actual_tx_dma_chan,uint32_t * out_actual_rx_dma_chan)282 esp_err_t spicommon_slave_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
283 {
284     assert(is_valid_host(host_id));
285 #if CONFIG_IDF_TARGET_ESP32
286     assert(dma_chan > SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO);
287 #elif CONFIG_IDF_TARGET_ESP32S2
288     assert(dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO);
289 #endif
290 
291     esp_err_t ret = ESP_OK;
292     uint32_t actual_tx_dma_chan = 0;
293     uint32_t actual_rx_dma_chan = 0;
294     spicommon_bus_context_t *ctx = (spicommon_bus_context_t *)calloc(1, sizeof(spicommon_bus_context_t));
295     if (!ctx) {
296         ret = ESP_ERR_NO_MEM;
297         goto cleanup;
298     }
299     bus_ctx[host_id] = ctx;
300     ctx->host_id = host_id;
301 
302     ret = spicommon_dma_chan_alloc(host_id, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
303     if (ret != ESP_OK) {
304         goto cleanup;
305     }
306     ctx->bus_attr.tx_dma_chan = actual_tx_dma_chan;
307     ctx->bus_attr.rx_dma_chan = actual_rx_dma_chan;
308     *out_actual_tx_dma_chan = actual_tx_dma_chan;
309     *out_actual_rx_dma_chan = actual_rx_dma_chan;
310 
311     return ret;
312 
313 cleanup:
314     free(ctx);
315     ctx = NULL;
316     return ret;
317 }
318 
319 //----------------------------------------------------------free dma periph-------------------------------------------------------//
spicommon_dma_chan_free(spi_host_device_t host_id)320 static esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id)
321 {
322     assert(is_valid_host(host_id));
323 
324     spicommon_bus_context_t *ctx = bus_ctx[host_id];
325 #if !SOC_GDMA_SUPPORTED
326     //On ESP32S2, each SPI controller has its own DMA channel
327     int dma_chan = ctx->bus_attr.tx_dma_chan;
328     assert(spi_dma_chan_enabled & BIT(dma_chan));
329 
330     portENTER_CRITICAL(&spi_dma_spinlock);
331     spi_dma_chan_enabled &= ~BIT(dma_chan);
332     periph_module_disable(get_dma_periph(dma_chan));
333     portEXIT_CRITICAL(&spi_dma_spinlock);
334 
335 #else //SOC_GDMA_SUPPORTED
336     if (ctx->rx_channel) {
337         gdma_disconnect(ctx->rx_channel);
338         gdma_del_channel(ctx->rx_channel);
339     }
340     if (ctx->tx_channel) {
341         gdma_disconnect(ctx->tx_channel);
342         gdma_del_channel(ctx->tx_channel);
343     }
344 #endif
345 
346     return ESP_OK;
347 }
348 
spicommon_slave_free_dma(spi_host_device_t host_id)349 esp_err_t spicommon_slave_free_dma(spi_host_device_t host_id)
350 {
351     assert(is_valid_host(host_id));
352 
353     esp_err_t ret = spicommon_dma_chan_free(host_id);
354     free(bus_ctx[host_id]);
355     bus_ctx[host_id] = NULL;
356 
357     return ret;
358 }
359 
360 //----------------------------------------------------------IO general-------------------------------------------------------//
bus_uses_iomux_pins(spi_host_device_t host,const spi_bus_config_t * bus_config)361 static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
362 {
363     if (bus_config->sclk_io_num>=0 &&
364         bus_config->sclk_io_num != spi_periph_signal[host].spiclk_iomux_pin) {
365             return false;
366         }
367     if (bus_config->quadwp_io_num>=0 &&
368         bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) {
369             return false;
370         }
371     if (bus_config->quadhd_io_num>=0 &&
372         bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) {
373             return false;
374             }
375     if (bus_config->mosi_io_num >= 0 &&
376         bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) {
377             return false;
378         }
379     if (bus_config->miso_io_num>=0 &&
380         bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) {
381             return false;
382         }
383 
384     return true;
385 }
386 
387 /*
388 Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pins. Feed it a host number and a
389 bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value,
390 it should be able to be initialized.
391 */
spicommon_bus_initialize_io(spi_host_device_t host,const spi_bus_config_t * bus_config,uint32_t flags,uint32_t * flags_o)392 esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t* flags_o)
393 {
394     uint32_t temp_flag = 0;
395 
396     bool miso_need_output;
397     bool mosi_need_output;
398     bool sclk_need_output;
399     if ((flags&SPICOMMON_BUSFLAG_MASTER) != 0) {
400         //initial for master
401         miso_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
402         mosi_need_output = true;
403         sclk_need_output = true;
404     } else {
405         //initial for slave
406         miso_need_output = true;
407         mosi_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
408         sclk_need_output = false;
409     }
410 
411     const bool wp_need_output = true;
412     const bool hd_need_output = true;
413 
414     //check pin capabilities
415     if (bus_config->sclk_io_num>=0) {
416         temp_flag |= SPICOMMON_BUSFLAG_SCLK;
417         SPI_CHECK_PIN(bus_config->sclk_io_num, "sclk", sclk_need_output);
418     }
419     if (bus_config->quadwp_io_num>=0) {
420         SPI_CHECK_PIN(bus_config->quadwp_io_num, "wp", wp_need_output);
421     }
422     if (bus_config->quadhd_io_num>=0) {
423         SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", hd_need_output);
424     }
425     //set flags for QUAD mode according to the existence of wp and hd
426     if (bus_config->quadhd_io_num >= 0 && bus_config->quadwp_io_num >= 0) temp_flag |= SPICOMMON_BUSFLAG_WPHD;
427     if (bus_config->mosi_io_num >= 0) {
428         temp_flag |= SPICOMMON_BUSFLAG_MOSI;
429         SPI_CHECK_PIN(bus_config->mosi_io_num, "mosi", mosi_need_output);
430     }
431     if (bus_config->miso_io_num>=0) {
432         temp_flag |= SPICOMMON_BUSFLAG_MISO;
433         SPI_CHECK_PIN(bus_config->miso_io_num, "miso", miso_need_output);
434     }
435     //set flags for DUAL mode according to output-capability of MOSI and MISO pins.
436     if ( (bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num)) &&
437         (bus_config->miso_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->miso_io_num)) ) {
438         temp_flag |= SPICOMMON_BUSFLAG_DUAL;
439     }
440 
441     //check if the selected pins correspond to the iomux pins of the peripheral
442     bool use_iomux = !(flags & SPICOMMON_BUSFLAG_GPIO_PINS) && bus_uses_iomux_pins(host, bus_config);
443     if (use_iomux) {
444         temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
445     } else {
446         temp_flag |= SPICOMMON_BUSFLAG_GPIO_PINS;
447     }
448 
449     uint32_t missing_flag = flags & ~temp_flag;
450     missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
451 
452     if (missing_flag != 0) {
453     //check pins existence
454         if (missing_flag & SPICOMMON_BUSFLAG_SCLK) ESP_LOGE(SPI_TAG, "sclk pin required.");
455         if (missing_flag & SPICOMMON_BUSFLAG_MOSI) ESP_LOGE(SPI_TAG, "mosi pin required.");
456         if (missing_flag & SPICOMMON_BUSFLAG_MISO) ESP_LOGE(SPI_TAG, "miso pin required.");
457         if (missing_flag & SPICOMMON_BUSFLAG_DUAL) ESP_LOGE(SPI_TAG, "not both mosi and miso output capable");
458         if (missing_flag & SPICOMMON_BUSFLAG_WPHD) ESP_LOGE(SPI_TAG, "both wp and hd required.");
459         if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins");
460         SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
461     }
462 
463     if (use_iomux) {
464         //All SPI iomux pin selections resolve to 1, so we put that here instead of trying to figure
465         //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
466         ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1);
467         if (bus_config->mosi_io_num >= 0) {
468             gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
469             gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
470         }
471         if (bus_config->miso_io_num >= 0) {
472             gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
473             gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
474         }
475         if (bus_config->quadwp_io_num >= 0) {
476             gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
477             gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
478         }
479         if (bus_config->quadhd_io_num >= 0) {
480             gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
481             gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
482         }
483         if (bus_config->sclk_io_num >= 0) {
484             gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
485             gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
486         }
487         temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
488     } else {
489         //Use GPIO matrix
490         ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
491         if (bus_config->mosi_io_num >= 0) {
492             if (mosi_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
493                 gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT);
494                 esp_rom_gpio_connect_out_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_out, false, false);
495             } else {
496                 gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT);
497             }
498             esp_rom_gpio_connect_in_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_in, false);
499 #if CONFIG_IDF_TARGET_ESP32S2
500             PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->mosi_io_num]);
501 #endif
502             gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], FUNC_GPIO);
503         }
504         if (bus_config->miso_io_num >= 0) {
505             if (miso_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
506                 gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT_OUTPUT);
507                 esp_rom_gpio_connect_out_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_out, false, false);
508             } else {
509                 gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT);
510             }
511             esp_rom_gpio_connect_in_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_in, false);
512 #if CONFIG_IDF_TARGET_ESP32S2
513             PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->miso_io_num]);
514 #endif
515             gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->miso_io_num], FUNC_GPIO);
516         }
517         if (bus_config->quadwp_io_num >= 0) {
518             gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_INPUT_OUTPUT);
519             esp_rom_gpio_connect_out_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_out, false, false);
520             esp_rom_gpio_connect_in_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in, false);
521 #if CONFIG_IDF_TARGET_ESP32S2
522             PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num]);
523 #endif
524             gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], FUNC_GPIO);
525         }
526         if (bus_config->quadhd_io_num >= 0) {
527             gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_INPUT_OUTPUT);
528             esp_rom_gpio_connect_out_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_out, false, false);
529             esp_rom_gpio_connect_in_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in, false);
530 #if CONFIG_IDF_TARGET_ESP32S2
531             PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num]);
532 #endif
533             gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], FUNC_GPIO);
534         }
535         if (bus_config->sclk_io_num >= 0) {
536             if (sclk_need_output) {
537                 gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT_OUTPUT);
538                 esp_rom_gpio_connect_out_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_out, false, false);
539             } else {
540                 gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT);
541             }
542             esp_rom_gpio_connect_in_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in, false);
543 #if CONFIG_IDF_TARGET_ESP32S2
544             PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->sclk_io_num]);
545 #endif
546             gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
547         }
548     }
549 
550     if (flags_o) *flags_o = temp_flag;
551     return ESP_OK;
552 }
553 
spicommon_bus_free_io_cfg(const spi_bus_config_t * bus_cfg)554 esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg)
555 {
556     int pin_array[] = {
557         bus_cfg->mosi_io_num,
558         bus_cfg->miso_io_num,
559         bus_cfg->sclk_io_num,
560         bus_cfg->quadwp_io_num,
561         bus_cfg->quadhd_io_num,
562     };
563     for (int i = 0; i < sizeof(pin_array)/sizeof(int); i ++) {
564         const int io = pin_array[i];
565         if (io >= 0 && GPIO_IS_VALID_GPIO(io)) gpio_reset_pin(io);
566     }
567     return ESP_OK;
568 }
569 
spicommon_cs_initialize(spi_host_device_t host,int cs_io_num,int cs_num,int force_gpio_matrix)570 void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix)
571 {
572     if (!force_gpio_matrix && cs_io_num == spi_periph_signal[host].spics0_iomux_pin && cs_num == 0) {
573         //The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
574         gpio_iomux_in(cs_io_num, spi_periph_signal[host].spics_in);
575         gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false);
576     } else {
577         //Use GPIO matrix
578         if (GPIO_IS_VALID_OUTPUT_GPIO(cs_io_num)) {
579             gpio_set_direction(cs_io_num, GPIO_MODE_INPUT_OUTPUT);
580             esp_rom_gpio_connect_out_signal(cs_io_num, spi_periph_signal[host].spics_out[cs_num], false, false);
581         } else {
582             gpio_set_direction(cs_io_num, GPIO_MODE_INPUT);
583         }
584         if (cs_num == 0) esp_rom_gpio_connect_in_signal(cs_io_num, spi_periph_signal[host].spics_in, false);
585         PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
586         gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
587     }
588 }
589 
spicommon_cs_free_io(int cs_gpio_num)590 void spicommon_cs_free_io(int cs_gpio_num)
591 {
592     assert(cs_gpio_num>=0 && GPIO_IS_VALID_GPIO(cs_gpio_num));
593     gpio_reset_pin(cs_gpio_num);
594 }
595 
spicommon_bus_using_iomux(spi_host_device_t host)596 bool spicommon_bus_using_iomux(spi_host_device_t host)
597 {
598 #define CHECK_IOMUX_PIN(HOST, PIN_NAME) if (GPIO.func_in_sel_cfg[spi_periph_signal[(HOST)].PIN_NAME##_in].sig_in_sel) return false
599 
600     CHECK_IOMUX_PIN(host, spid);
601     CHECK_IOMUX_PIN(host, spiq);
602     CHECK_IOMUX_PIN(host, spiwp);
603     CHECK_IOMUX_PIN(host, spihd);
604     return true;
605 }
606 
607 
spi_bus_main_set_lock(spi_bus_lock_handle_t lock)608 void spi_bus_main_set_lock(spi_bus_lock_handle_t lock)
609 {
610     bus_ctx[0]->bus_attr.lock = lock;
611 }
612 
spi_bus_lock_get_by_id(spi_host_device_t host_id)613 spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id)
614 {
615     return bus_ctx[host_id]->bus_attr.lock;
616 }
617 
618 //----------------------------------------------------------master bus init-------------------------------------------------------//
spi_bus_initialize(spi_host_device_t host_id,const spi_bus_config_t * bus_config,spi_dma_chan_t dma_chan)619 esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan)
620 {
621     esp_err_t err = ESP_OK;
622     spicommon_bus_context_t *ctx = NULL;
623     spi_bus_attr_t *bus_attr = NULL;
624     uint32_t actual_tx_dma_chan = 0;
625     uint32_t actual_rx_dma_chan = 0;
626 
627     SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
628     SPI_CHECK(bus_ctx[host_id] == NULL, "SPI bus already initialized.", ESP_ERR_INVALID_STATE);
629 #ifdef CONFIG_IDF_TARGET_ESP32
630     SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
631 #elif CONFIG_IDF_TARGET_ESP32S2
632     SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
633 #elif SOC_GDMA_SUPPORTED
634     SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG );
635 #endif
636     SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
637 #ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
638     SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
639 #endif
640 
641     bool spi_chan_claimed = spicommon_periph_claim(host_id, "spi master");
642     SPI_CHECK(spi_chan_claimed, "host_id already in use", ESP_ERR_INVALID_STATE);
643 
644     //clean and initialize the context
645     ctx = (spicommon_bus_context_t *)calloc(1, sizeof(spicommon_bus_context_t));
646     if (!ctx) {
647         err = ESP_ERR_NO_MEM;
648         goto cleanup;
649     }
650     bus_ctx[host_id] = ctx;
651     ctx->host_id = host_id;
652     bus_attr = &ctx->bus_attr;
653     bus_attr->bus_cfg = *bus_config;
654 
655     if (dma_chan != SPI_DMA_DISABLED) {
656         bus_attr->dma_enabled = 1;
657 
658         err = spicommon_dma_chan_alloc(host_id, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
659         if (err != ESP_OK) {
660             goto cleanup;
661         }
662         bus_attr->tx_dma_chan = actual_tx_dma_chan;
663         bus_attr->rx_dma_chan = actual_rx_dma_chan;
664 
665         int dma_desc_ct = lldesc_get_required_num(bus_config->max_transfer_sz);
666         if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
667 
668         bus_attr->max_transfer_sz = dma_desc_ct * LLDESC_MAX_NUM_PER_DESC;
669         bus_attr->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
670         bus_attr->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
671         if (bus_attr->dmadesc_tx == NULL || bus_attr->dmadesc_rx == NULL) {
672             err = ESP_ERR_NO_MEM;
673             goto cleanup;
674         }
675         bus_attr->dma_desc_num = dma_desc_ct;
676     } else {
677         bus_attr->dma_enabled = 0;
678         bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
679         bus_attr->dma_desc_num = 0;
680     }
681 
682     spi_bus_lock_config_t lock_config = {
683         .host_id = host_id,
684         .cs_num = SOC_SPI_PERIPH_CS_NUM(host_id),
685     };
686     err = spi_bus_init_lock(&bus_attr->lock, &lock_config);
687     if (err != ESP_OK) {
688         goto cleanup;
689     }
690 
691 #ifdef CONFIG_PM_ENABLE
692     err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
693             &bus_attr->pm_lock);
694     if (err != ESP_OK) {
695         goto cleanup;
696     }
697 #endif //CONFIG_PM_ENABLE
698 
699     err = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags);
700     if (err != ESP_OK) {
701         goto cleanup;
702     }
703 
704     return ESP_OK;
705 
706 cleanup:
707     if (bus_attr) {
708 #ifdef CONFIG_PM_ENABLE
709         esp_pm_lock_delete(bus_attr->pm_lock);
710 #endif
711         if (bus_attr->lock) {
712             spi_bus_deinit_lock(bus_attr->lock);
713         }
714         free(bus_attr->dmadesc_tx);
715         free(bus_attr->dmadesc_rx);
716         bus_attr->dmadesc_tx = NULL;
717         bus_attr->dmadesc_rx = NULL;
718         if (bus_attr->dma_enabled) {
719             spicommon_dma_chan_free(host_id);
720         }
721     }
722     spicommon_periph_free(host_id);
723     free(bus_ctx[host_id]);
724     bus_ctx[host_id] = NULL;
725     return err;
726 }
727 
spi_bus_get_attr(spi_host_device_t host_id)728 const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id)
729 {
730     if (bus_ctx[host_id] == NULL) return NULL;
731 
732     return &bus_ctx[host_id]->bus_attr;
733 }
734 
spi_bus_free(spi_host_device_t host_id)735 esp_err_t spi_bus_free(spi_host_device_t host_id)
736 {
737     esp_err_t err = ESP_OK;
738     spicommon_bus_context_t* ctx = bus_ctx[host_id];
739     spi_bus_attr_t* bus_attr = &ctx->bus_attr;
740 
741     if (ctx->destroy_func) {
742         err = ctx->destroy_func(ctx->destroy_arg);
743     }
744 
745     spicommon_bus_free_io_cfg(&bus_attr->bus_cfg);
746 
747 #ifdef CONFIG_PM_ENABLE
748     esp_pm_lock_delete(bus_attr->pm_lock);
749 #endif
750     spi_bus_deinit_lock(bus_attr->lock);
751     free(bus_attr->dmadesc_rx);
752     free(bus_attr->dmadesc_tx);
753     bus_attr->dmadesc_tx = NULL;
754     bus_attr->dmadesc_rx = NULL;
755     if (bus_attr->dma_enabled > 0) {
756         spicommon_dma_chan_free(host_id);
757     }
758     spicommon_periph_free(host_id);
759     free(ctx);
760     bus_ctx[host_id] = NULL;
761     return err;
762 }
763 
spi_bus_register_destroy_func(spi_host_device_t host_id,spi_destroy_func_t f,void * arg)764 esp_err_t spi_bus_register_destroy_func(spi_host_device_t host_id,
765                                         spi_destroy_func_t f, void *arg)
766 {
767     bus_ctx[host_id]->destroy_func = f;
768     bus_ctx[host_id]->destroy_arg = arg;
769     return ESP_OK;
770 }
771 
772 
773 /*
774 Code for workaround for DMA issue in ESP32 v0/v1 silicon
775 */
776 #if CONFIG_IDF_TARGET_ESP32
777 static volatile int dmaworkaround_channels_busy[2] = {0, 0};
778 static dmaworkaround_cb_t dmaworkaround_cb;
779 static void *dmaworkaround_cb_arg;
780 static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
781 static int dmaworkaround_waiting_for_chan = 0;
782 #endif
783 
spicommon_dmaworkaround_req_reset(int dmachan,dmaworkaround_cb_t cb,void * arg)784 bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
785 {
786 #if CONFIG_IDF_TARGET_ESP32
787     int otherchan = (dmachan == 1) ? 2 : 1;
788     bool ret;
789     portENTER_CRITICAL_ISR(&dmaworkaround_mux);
790     if (dmaworkaround_channels_busy[otherchan-1]) {
791         //Other channel is busy. Call back when it's done.
792         dmaworkaround_cb = cb;
793         dmaworkaround_cb_arg = arg;
794         dmaworkaround_waiting_for_chan = otherchan;
795         ret = false;
796     } else {
797         //Reset DMA
798         periph_module_reset( PERIPH_SPI_DMA_MODULE );
799         ret = true;
800     }
801     portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
802     return ret;
803 #else
804     //no need to reset
805     return true;
806 #endif
807 }
808 
spicommon_dmaworkaround_reset_in_progress(void)809 bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress(void)
810 {
811 #if CONFIG_IDF_TARGET_ESP32
812     return (dmaworkaround_waiting_for_chan != 0);
813 #else
814     return false;
815 #endif
816 }
817 
spicommon_dmaworkaround_idle(int dmachan)818 void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
819 {
820 #if CONFIG_IDF_TARGET_ESP32
821     portENTER_CRITICAL_ISR(&dmaworkaround_mux);
822     dmaworkaround_channels_busy[dmachan-1] = 0;
823     if (dmaworkaround_waiting_for_chan == dmachan) {
824         //Reset DMA
825         periph_module_reset( PERIPH_SPI_DMA_MODULE );
826         dmaworkaround_waiting_for_chan = 0;
827         //Call callback
828         dmaworkaround_cb(dmaworkaround_cb_arg);
829 
830     }
831     portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
832 #endif
833 }
834 
spicommon_dmaworkaround_transfer_active(int dmachan)835 void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
836 {
837 #if CONFIG_IDF_TARGET_ESP32
838     portENTER_CRITICAL_ISR(&dmaworkaround_mux);
839     dmaworkaround_channels_busy[dmachan-1] = 1;
840     portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
841 #endif
842 }
843