diff --git a/components/driver/sdio_slave.c b/components/driver/sdio_slave.c index 98e4f4ae40..317e492bc5 100644 --- a/components/driver/sdio_slave.c +++ b/components/driver/sdio_slave.c @@ -162,7 +162,7 @@ typedef enum { ringbuf_free_ptr = offset_of(sdio_ringbuf_t, free_ptr), } sdio_ringbuf_pointer_t; -#define SDIO_RINGBUF_INITIALIZER() (sdio_ringbuf_t){.write_spinlock = portMUX_INITIALIZER_UNLOCKED,} +#define SDIO_RINGBUF_INITIALIZER {.write_spinlock = portMUX_INITIALIZER_UNLOCKED,} typedef struct { sdio_slave_config_t config; @@ -191,24 +191,26 @@ typedef struct { portMUX_TYPE recv_spinlock; } sdio_context_t; -static sdio_context_t context = { - .intr_handle = NULL, - /*------- events ---------------*/ - .events = {}, - .reg_spinlock = portMUX_INITIALIZER_UNLOCKED, - /*------- sending ---------------*/ - .send_state = STATE_IDLE, - .sendbuf = SDIO_RINGBUF_INITIALIZER(), - .ret_queue = NULL, - .in_flight = NULL, - .in_flight_end = NULL, - .in_flight_next = NULL, - /*------- receiving ---------------*/ - .recv_link_list = STAILQ_HEAD_INITIALIZER(context.recv_link_list), - .recv_reg_list = TAILQ_HEAD_INITIALIZER(context.recv_reg_list), - .recv_cur_ret = NULL, - .recv_spinlock = portMUX_INITIALIZER_UNLOCKED, -}; +#define CONTEXT_INIT_VAL { \ + .intr_handle = NULL, \ + /*------- events ---------------*/ \ + .events = {}, \ + .reg_spinlock = portMUX_INITIALIZER_UNLOCKED, \ + /*------- sending ---------------*/ \ + .send_state = STATE_IDLE, \ + .sendbuf = SDIO_RINGBUF_INITIALIZER, \ + .ret_queue = NULL, \ + .in_flight = NULL, \ + .in_flight_end = NULL, \ + .in_flight_next = NULL, \ + /*------- receiving ---------------*/ \ + .recv_link_list = STAILQ_HEAD_INITIALIZER(context.recv_link_list), \ + .recv_reg_list = TAILQ_HEAD_INITIALIZER(context.recv_reg_list), \ + .recv_cur_ret = NULL, \ + .recv_spinlock = portMUX_INITIALIZER_UNLOCKED, \ +} + +static sdio_context_t context = CONTEXT_INIT_VAL; static void sdio_intr(void*); static void sdio_intr_host(void*); @@ -238,7 +240,7 @@ static void sdio_ringbuf_deinit(sdio_ringbuf_t* buf) { if (buf->remain_cnt != NULL) vSemaphoreDelete(buf->remain_cnt); if (buf->data != NULL) free(buf->data); - *buf = SDIO_RINGBUF_INITIALIZER(); + *buf = (sdio_ringbuf_t) SDIO_RINGBUF_INITIALIZER; } static esp_err_t sdio_ringbuf_init(sdio_ringbuf_t* buf, int item_size, int item_cnt) @@ -251,7 +253,7 @@ static esp_err_t sdio_ringbuf_init(sdio_ringbuf_t* buf, int item_size, int item_ //one item is not used. buf->size = item_size * (item_cnt+1); //apply for resources - buf->data = (uint8_t*)malloc(buf->size); + buf->data = (uint8_t*)heap_caps_malloc(buf->size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); if (buf->data == NULL) goto no_mem; buf->remain_cnt = xSemaphoreCreateCounting(item_cnt, item_cnt); if (buf->remain_cnt == NULL) goto no_mem; @@ -451,6 +453,7 @@ static esp_err_t init_context(sdio_slave_config_t *config) { SDIO_SLAVE_CHECK(*(uint32_t*)&context.config == 0, "sdio slave already initialized", ESP_ERR_INVALID_STATE); + context = (sdio_context_t)CONTEXT_INIT_VAL; context.config = *config; // in theory we can queue infinite buffers in the linked list, but for multi-core reason we have to use a queue to @@ -472,8 +475,6 @@ static esp_err_t init_context(sdio_slave_config_t *config) context.ret_queue = xQueueCreate(config->send_queue_size, sizeof(void*)); if (context.ret_queue == NULL) goto no_mem; - context.recv_link_list = (buf_stailq_t)STAILQ_HEAD_INITIALIZER(context.recv_link_list); - context.recv_reg_list = (buf_tailq_t)TAILQ_HEAD_INITIALIZER(context.recv_reg_list); return ESP_OK; no_mem: @@ -485,9 +486,9 @@ static void configure_pin(int pin, uint32_t func, bool pullup) { const int sdmmc_func = func; const int drive_strength = 3; - assert(pin!=-1); + assert(pin != -1); uint32_t reg = GPIO_PIN_MUX_REG[pin]; - assert(reg!=UINT32_MAX); + assert(reg != UINT32_MAX); PIN_INPUT_ENABLE(reg); PIN_FUNC_SELECT(reg, sdmmc_func); @@ -574,6 +575,29 @@ static inline esp_err_t sdio_slave_hw_init(sdio_slave_config_t *config) return ESP_OK; } +static void recover_pin(int pin, int sdio_func) +{ + uint32_t reg = GPIO_PIN_MUX_REG[pin]; + assert(reg != UINT32_MAX); + + int func = REG_GET_FIELD(reg, MCU_SEL); + if (func == sdio_func) { + gpio_set_direction(pin, GPIO_MODE_INPUT); + PIN_FUNC_SELECT(reg, PIN_FUNC_GPIO); + } +} + +static void sdio_slave_hw_deinit(void) +{ + const sdio_slave_slot_info_t *slot = &sdio_slave_slot_info[1]; + recover_pin(slot->clk_gpio, slot->func); + recover_pin(slot->cmd_gpio, slot->func); + recover_pin(slot->d0_gpio, slot->func); + recover_pin(slot->d1_gpio, slot->func); + recover_pin(slot->d2_gpio, slot->func); + recover_pin(slot->d3_gpio, slot->func); +} + esp_err_t sdio_slave_initialize(sdio_slave_config_t *config) { esp_err_t r; @@ -594,6 +618,20 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config) void sdio_slave_deinit(void) { + sdio_slave_hw_deinit(); + + //unregister all buffers in the queue, and not in the queue + buf_desc_t *temp_desc; + buf_desc_t *desc; + TAILQ_FOREACH_SAFE(desc, &context.recv_reg_list, te, temp_desc) { + TAILQ_REMOVE(&context.recv_reg_list, desc, te); + free(desc); + } + STAILQ_FOREACH_SAFE(desc, &context.recv_link_list, qe, temp_desc) { + STAILQ_REMOVE(&context.recv_link_list, desc, buf_desc_s, qe); + free(desc); + } + esp_err_t ret = esp_intr_free(context.intr_handle); assert(ret==ESP_OK); context.intr_handle = NULL; @@ -1165,9 +1203,9 @@ static void sdio_intr_recv(void* arg) // This may cause the ``cur_ret`` pointer to be NULL, indicating the list is empty, // in this case the ``tx_done`` should happen no longer until new desc is appended. // The app is responsible to place the pointer to the right place again when appending new desc. - critical_enter_recv(); + portENTER_CRITICAL_ISR(&context.recv_spinlock); context.recv_cur_ret = STAILQ_NEXT(context.recv_cur_ret, qe); - critical_exit_recv(); + portEXIT_CRITICAL_ISR(&context.recv_spinlock); ESP_EARLY_LOGV(TAG, "intr_recv: Give"); xSemaphoreGiveFromISR(context.recv_event, &yield); SLC.slc0_int_clr.tx_done = 1; @@ -1201,6 +1239,7 @@ esp_err_t sdio_slave_recv_load_buf(sdio_slave_buf_handle_t handle) SLC.slc0_tx_link.addr = (uint32_t)desc; SLC.slc0_tx_link.start = 1; ESP_LOGV(TAG, "recv_load_buf: start new"); + SLC.slc0_int_ena.tx_done = 1; } else { //restart former ll operation SLC.slc0_tx_link.restart = 1; @@ -1216,7 +1255,7 @@ sdio_slave_buf_handle_t sdio_slave_recv_register_buf(uint8_t *start) { SDIO_SLAVE_CHECK(esp_ptr_dma_capable(start) && (uint32_t)start%4==0, "buffer to register should be DMA capable and 32-bit aligned", NULL); - buf_desc_t *desc = (buf_desc_t*)malloc(sizeof(buf_desc_t)); + buf_desc_t *desc = (buf_desc_t*)heap_caps_malloc(sizeof(buf_desc_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); if (desc == NULL) { SDIO_SLAVE_LOGE("cannot allocate lldesc for new buffer"); return NULL;