1 /* 2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 /******************************************************************************* 8 * NOTICE 9 * The hal is not public api, don't use in application code. 10 * See readme.md in hal/include/hal/readme.md 11 ******************************************************************************/ 12 13 // The HAL layer for SDIO slave (common part) 14 15 // SDIO slave HAL usages: 16 17 /* 18 Architecture: 19 20 The whole SDIO slave peripheral consists of three parts: the registers (including the interrupt 21 control and shared registers), a send FIFO, and a receive FIFO. The document 22 ``esp_slave_protocol.rst`` describes the functionality of the peripheral in detail. An SDIO host 23 will only ever access one of the three parts at any one time, thus the hardware functionality of 24 the SDIO slave peripheral are completely independent. Likewise, this HAL is organized in such a 25 fashion as to correspond to the three independent parts. 26 27 The shared registers are quite simple: the slave can directly access them from the internal data 28 bus, while the host can access them by CMD52/53 with the correct address. As for the interrupts: 29 when an SDIO host interrupts the SDIO slave peripheral (by writing a command), the corresponding 30 bit in the interrupt register will be set; when the SDIO slave peripheral needs to interrupt the 31 host, it write some register to cause the host interrupt bit being set, and the slave hardware 32 will output the interrupt signal on the DAT1 line. 33 34 For the FIFOs, the peripheral provides counters as registers so that the host can always know whether the slave 35 is ready to send/receive data. The HAL resets the counters during initialization, and the host should somehow 36 inform the slave to reset the counters again if it should reboot (or lose the counter value for some reasons). 37 Then the host can read/write the FIFOs by CMD53 commands according to the counters. 38 39 In order to avoid copying data to/from the FIFOs or memory buffers each time, the HAL layer 40 contains a descriptor queue (implemented as linked-list) that allows descriptors of memory 41 buffers to be queued for transmission/reception. Once a buffer is queued, the HAL takes ownership 42 of the buffer until some "finish" functions successfully return, indicating the 43 transmission/reception of that buffer is complete. The ISR is invoked multiple times to iterate 44 through the queued descriptors, and also to signal to the upper layer if a buffer has been 45 freed. 46 47 The HAL is used as below: 48 49 - Receiving part: 50 51 1. Call `sdio_slave_hal_recv_start` to start the receiving DMA. 52 53 If there are already buffers loaded, the receiving will start from those buffers first. 54 55 2. Call `sdio_slave_hal_recv_init_desc` with a `sdio_slave_hal_recv_desc_t` and the buffer address to 56 associate the descriptor with the buffer. 57 58 The HAL initialize this descriptors with the determined length and maybe some extra data. 59 60 3. Call `sdio_slave_hal_load_buf` with the initialized descriptor of the buffer to load a 61 receiving buffer to the HAL. 62 63 When the DMA is started, the descriptors is loaded onto the DMA linked-list, and the 64 counter of receiving buffers is increased so that the host will know this by the 65 receiving interrupt. The hardware will automatically go through the linked list and write 66 data into the buffers loaded on the list. 67 68 4. (Optional, mandatory only when interrupt enabled) Call `sdio_slave_hal_recv_done` to check 69 and clear the receiving interrupt bits. 70 71 5. Call `sdio_slave_hal_recv_has_next_item` to check whether there are finished buffers. 72 73 6. Call `sdio_slave_hal_recv_unload_desc` for the same times as 74 `sdio_slave_hal_recv_has_next_item` successfully returns. 75 76 7. (Optional) Call `sdio_slave_hal_recv_reset_counter` to reset the counter to current loaded 77 but not used buffers if you want to reset the counter only. This is available only when 78 the DMA is stopped. 79 80 8. (Optional) Call `sdio_slave_hal_recv_flush_one_buffer` (recursively) if you want to 81 discard data of one (or more) buffers and load them again. This is available only when 82 the DMA is stopped. 83 84 9. (Optional when deinitialization) Call `sdio_slave_hal_recv_unload_desc` recursively to get 85 all the buffers loaded to the HAL, no matter they are used or not. Don't do this when the 86 DMA is not stopped. 87 88 - Sending part: 89 90 The sending driver is slightly different, since we are not using the re-start feature. 91 (TODO: re-write this part if the stitch mode is released) 92 93 1. Call `sdio_slave_hal_send_start` to start the sending DMA. 94 95 If there is already any data queued, it will ne ready to be sent to host now. 96 97 2. Call `sdio_slave_hal_send_queue` to queue the data to send. 98 99 If the interrupt is enabled, the ISR will be invoked. 100 101 3. (Required if interrupt enabled) Call `` to clear the interrupt bits used by the SW 102 invoking logic. 103 104 4. Call `sdio_slave_hal_send_new_packet_if_exist` to check and send new packet (if there is 105 data queued). 106 107 5. Call `sdio_slave_hal_send_eof_happened` to check whether the previous packet is done. 108 109 It will also clear the interrupt status bit for this event. 110 111 6. Call `sdio_slave_hal_send_get_next_finished_arg` recursively to get the arguments for the 112 finished buffers. 113 114 7. (Optional when deinitialization) Call `sdio_slave_hal_send_flush_next_buffer` recursively 115 to get all buffers queued, regardless sent or not. Don't do this when the DMA is not stopped. 116 117 8. (Optional) Call `sdio_slave_hal_send_reset_counter` to reset the counter to current loaded 118 but not sent buffers if you want to reset the counter only. Don't do this when the DMA is not 119 stopped. 120 121 Note a counter should be used when performing step 2 and 6, to make sure that the queue size 122 is enough. 123 124 - Host part: 125 126 1. Call `sdio_slave_hal_hostint_set_ena` and `sdio_slave_hal_hostint_get_ena` to 127 enable/disable the interrupt sent to master. Note that the host can also modify the same 128 registers at the same time. Try to avoid using them outside the initialization process. 129 130 2. Call `sdio_slave_hal_hostint_send` and `sdio_slave_hal_hostint_clear` to trigger general 131 purpose interrupts or cancel all kinds of interrupts send to the host. These interrupts are 132 set/cleared in a concurrent-safe way, so the slave can call these functions safely. 133 134 3. Call `sdio_slave_hal_slvint_fetch_clear` to fetch the general purpose interrupts sent by 135 the host to the slave. These interrupts will also be cleared after the calls. 136 137 4. Call `sdio_slave_hal_host_get_reg` and `sdio_slave_hal_host_set_reg` to read/write the 138 general purpose shared between the host and slave. Note that these registers are also not 139 concurrent-safe. Try not to write to the same register from two directions at the same time. 140 */ 141 142 #pragma once 143 #include <esp_err.h> 144 #include "hal/sdio_slave_types.h" 145 #include "hal/sdio_slave_ll.h" 146 147 /// Space used for each sending descriptor. Should initialize the sendbuf accoring to this size. 148 #define SDIO_SLAVE_SEND_DESC_SIZE sizeof(sdio_slave_hal_send_desc_t) 149 150 151 /// Status of the sending part 152 typedef enum { 153 STATE_IDLE = 1, 154 STATE_WAIT_FOR_START = 2, 155 STATE_SENDING = 3, 156 STATE_GETTING_RESULT = 4, 157 STATE_GETTING_UNSENT_DESC = 5, 158 } send_state_t; 159 160 typedef struct { 161 uint8_t* data; ///< Address of the buffer 162 size_t size; ///< Size of the buffer, but can only queue (size/SDIO_SLAVE_SEND_DESC_SIZE)-1 descriptors 163 uint8_t* write_ptr; 164 uint8_t* read_ptr; 165 uint8_t* free_ptr; 166 } sdio_ringbuf_t; 167 168 // Append two extra words to be used by the HAL. 169 // Should Initialize the member `data` of `send_desc_queue` of the HAL context 170 // with size of this desc * N. 171 172 /// DMA descriptor with extra fields 173 typedef struct sdio_slave_hal_send_desc_s { 174 sdio_slave_ll_desc_t dma_desc; ///< Used by Hardware, has pointer linking to next desc 175 uint32_t pkt_len; ///< Accumulated length till this descriptor 176 void* arg; ///< Holding arguments indicating this buffer */ 177 } sdio_slave_hal_send_desc_t; 178 179 /// Descriptor used by the receiving part, call `sdio_slave_hal_recv_init_desc` 180 /// to initialize it before use. 181 typedef sdio_slave_ll_desc_t sdio_slave_hal_recv_desc_t; 182 #define sdio_slave_hal_recv_desc_s sdio_slave_ll_desc_s 183 typedef STAILQ_HEAD(recv_stailq_head_s, sdio_slave_hal_recv_desc_s) sdio_slave_hal_recv_stailq_t; 184 185 186 /** HAL context structure. Call `sdio_slave_hal_init` to initialize it and 187 * configure required members before actually use the HAL. 188 */ 189 typedef struct { 190 /// Hardware registers for this SDIO slave peripheral, configured by 191 /// `sdio_slave_hal_init` 192 struct { 193 slc_dev_t* slc; 194 host_dev_t* host; 195 hinf_dev_t* hinf; 196 }; 197 sdio_slave_sending_mode_t sending_mode; /**< Sending mode, should be manually configured before using the HAL. 198 * see `sdio_slave_sending_mode_t`. 199 */ 200 sdio_slave_timing_t timing; /**< Timing mode (launch edge and latch edge settings). Should be manually 201 * configured before using the HAL. `SDIO_SLAVE_TIMING_PSEND_PSAMPLE` is 202 * recommended by default. 203 */ 204 //some boolean flags 205 struct { 206 uint32_t no_highspeed: 1; /**< Disable the highspeed support */ 207 }; 208 int send_queue_size; /**< Max buffers that can be queued before sending. Should be manually 209 * configured before using the HAL. 210 */ 211 size_t recv_buffer_size; /**< The size of each buffer. The host and slave should share a 212 * pre-negotiated value. Should be manually configured before using 213 * the HAL. 214 */ 215 sdio_ringbuf_t send_desc_queue; /**< The ring buffer used to hold queued descriptors. Should be manually 216 * initialized before using the HAL. 217 */ 218 219 //Internal status, no need to touch. 220 send_state_t send_state; // Current state of sending part. 221 uint32_t tail_pkt_len; // The accumulated send length of the tail packet. 222 sdio_slave_hal_send_desc_t* in_flight_head; // The head of linked list in-flight. 223 sdio_slave_hal_send_desc_t* in_flight_end; // The end of linked list in-flight. 224 sdio_slave_hal_send_desc_t* in_flight_next; // The header of linked list to be sent next time. 225 sdio_slave_hal_send_desc_t* returned_desc; // The last returned descriptor 226 227 sdio_slave_hal_recv_stailq_t recv_link_list; // Linked list of buffers ready to hold data and the buffers already hold data. 228 volatile sdio_slave_hal_recv_desc_t* recv_cur_ret; // Next desc to return, NULL if all loaded descriptors are returned. 229 } sdio_slave_context_t ; 230 231 /** 232 * Initialize the HAL, should provide buffers to the context and configure the 233 * members before this funciton is called. 234 * 235 * @param hal Context of the HAL layer. 236 */ 237 void sdio_slave_hal_init(sdio_slave_context_t *hal); 238 239 /** 240 * Initialize the SDIO slave peripheral hardware. 241 * 242 * @param hal Context of the HAL layer. 243 */ 244 void sdio_slave_hal_hw_init(sdio_slave_context_t *hal); 245 246 /** 247 * Set the IO ready for host to read. 248 * 249 * @param hal Context of the HAL layer. 250 * @param ready true to tell the host the slave is ready, otherwise false. 251 */ 252 void sdio_slave_hal_set_ioready(sdio_slave_context_t *hal, bool ready); 253 254 /*--------------------------------------------------------------------------- 255 * Send 256 *--------------------------------------------------------------------------*/ 257 258 /** 259 * The hardware sending DMA starts. If there is existing data, send them. 260 * 261 * @param hal Context of the HAL layer. 262 */ 263 esp_err_t sdio_slave_hal_send_start(sdio_slave_context_t *hal); 264 265 /** 266 * Stops hardware sending DMA. 267 * 268 * @note The data in the queue, as well as the counter are not touched. 269 * @param hal Context of the HAL layer. 270 */ 271 void sdio_slave_hal_send_stop(sdio_slave_context_t *hal); 272 273 /** 274 * Put some data into the sending queue. 275 * 276 * @note The caller should keeps the buffer, until the `arg` is returned by 277 * `sdio_slave_hal_send_get_next_finished_arg`. 278 * @note The caller should count to ensure there is enough space in the queue. 279 * The initial queue size is sizeof(sendbuf.data)/sizeof(sdio_slave_hal_send_desc_t)-1, 280 * Will decrease by one when this function successfully returns. 281 * Released only by `sdio_slave_hal_send_get_next_finished_arg` or 282 * `sdio_slave_hal_send_flush_next_buffer`. 283 * 284 * @note The HAL is not thread-safe. The caller should use a spinlock to ensure 285 * the `sdio_slave_hal_send_queue` and ... are not called at the same time. 286 * 287 * @param hal Context of the HAL layer. 288 * @param addr Address of data in the memory to send. 289 * @param len Length of data to send. 290 * @param arg Argument indicating this sending. 291 * @return Always ESP_OK. 292 */ 293 esp_err_t sdio_slave_hal_send_queue(sdio_slave_context_t *hal, uint8_t *addr, size_t len, void *arg); 294 295 /** 296 * The ISR should call this, to handle the SW invoking event. 297 * @param hal Context of the HAL layer. 298 */ 299 void sdio_slave_hal_send_handle_isr_invoke(sdio_slave_context_t *hal); 300 301 /** 302 * Check whether there is no in-flight transactions, and send new packet if there 303 * is new packets queued. 304 * 305 * @param hal Context of the HAL layer. 306 * @return 307 * - ESP_OK: The DMA starts to send a new packet. 308 * - ESP_ERR_NOT_FOUND: No packet waiting to be sent. 309 * - ESP_ERR_INVALID_STATE: There is packet in-flight. 310 */ 311 esp_err_t sdio_slave_hal_send_new_packet_if_exist(sdio_slave_context_t *hal); 312 313 /** 314 * Check whether the sending EOF has happened and clear the interrupt. 315 * 316 * Call `sdio_slave_hal_send_get_next_finished_arg` recursively to retrieve arguments of finished 317 * buffers. 318 * 319 * @param hal Context of the HAL layer. 320 * @return true if happened, otherwise false. 321 */ 322 bool sdio_slave_hal_send_eof_happened(sdio_slave_context_t *hal); 323 324 /** 325 * Get the arguments of finished packets. Call recursively until all finished 326 * arguments are all retrieved. 327 * 328 * @param hal Context of the HAL layer. 329 * @param out_arg Output argument of the finished buffer. 330 * @param out_returned_cnt Released queue size to be queued again. 331 * @return 332 * - ESP_OK: if one argument retrieved. 333 * - ESP_ERR_NOT_FOUND: All the arguments of the finished buffers are retrieved. 334 */ 335 esp_err_t sdio_slave_hal_send_get_next_finished_arg(sdio_slave_context_t *hal, void **out_arg, uint32_t* out_returned_cnt); 336 337 /** 338 * Flush one buffer in the queue, no matter sent, canceled or not sent yet. 339 * 340 * Call recursively to clear the whole queue before deinitialization. 341 * 342 * @note Only call when the DMA is stopped! 343 * @param hal Context of the HAL layer. 344 * @param out_arg Argument indiciating the buffer to send 345 * @param out_return_cnt Space in the queue released after this descriptor is flushed. 346 * @return 347 * - ESP_ERR_INVALID_STATE: This function call be called only when the DMA is stopped. 348 * - ESP_ERR_NOT_FOUND: if no buffer in the queue 349 * - ESP_OK: if a buffer is successfully flushed and returned. 350 */ 351 esp_err_t sdio_slave_hal_send_flush_next_buffer(sdio_slave_context_t *hal, void **out_arg, uint32_t *out_return_cnt); 352 353 /** 354 * Walk through all the unsent buffers and reset the counter to the accumulated length of them. The data will be kept. 355 * 356 * @note Only call when the DMA is stopped! 357 * @param hal Context of the HAL layer. 358 * @return 359 * - ESP_ERR_INVALID_STATE: this function call be called only when the DMA is stopped 360 * - ESP_OK: if success 361 */ 362 esp_err_t sdio_slave_hal_send_reset_counter(sdio_slave_context_t *hal); 363 364 365 /*--------------------------------------------------------------------------- 366 * Receive 367 *--------------------------------------------------------------------------*/ 368 /** 369 * Start the receiving DMA. 370 * 371 * @note If there are already some buffers loaded, will receive from them first. 372 * @param hal Context of the HAL layer. 373 */ 374 void sdio_slave_hal_recv_start(sdio_slave_context_t *hal); 375 376 /** 377 * Stop the receiving DMA. 378 * 379 * @note Data and the counter will not be touched. You can still call 380 * `sdio_slave_hal_recv_has_next_item` to get the received buffer. 381 * And unused buffers loaded to the HAL will still be in the `loaded` 382 * state in the HAL, until returned by `sdio_slave_hal_recv_unload_desc`. 383 * @param hal Context of the HAL layer. 384 */ 385 void sdio_slave_hal_recv_stop(sdio_slave_context_t* hal); 386 387 /** 388 * Associate the buffer to the descriptor given. The descriptor may also be initialized with some 389 * other data. 390 * 391 * @param hal Context of the HAL layer. 392 * @param desc Descriptor to associate with the buffer 393 * @param start Start address of the buffer 394 */ 395 void sdio_slave_hal_recv_init_desc(sdio_slave_context_t *hal, sdio_slave_hal_recv_desc_t *desc, uint8_t *start); 396 397 /** 398 * Load the buffer to the HAL to be used to receive data. 399 * 400 * @note Loaded buffers will be returned to the upper layer only when: 401 * 1. Returned by `sdio_slave_hal_recv_has_next_item` when receiving to that buffer successfully 402 * done. 403 * 2. Returned by `sdio_slave_hal_recv_unload_desc` unconditionally. 404 * @param hal Context of the HAL layer. 405 * @param desc Descriptor to load to the HAL to receive. 406 */ 407 void sdio_slave_hal_load_buf(sdio_slave_context_t *hal, sdio_slave_hal_recv_desc_t *desc); 408 409 /** 410 * Check and clear the interrupt indicating a buffer has finished receiving. 411 * 412 * @param hal Context of the HAL layer. 413 * @return true if interrupt triggered, otherwise false. 414 */ 415 bool sdio_slave_hal_recv_done(sdio_slave_context_t* hal); 416 417 /** 418 * Call this function recursively to check whether there is any buffer that has 419 * finished receiving. 420 * 421 * Will walk through the linked list to find a newer finished buffer. For each successful return, 422 * it means there is one finished buffer. You can one by `sdio_slave_hal_recv_unload_desc`. You can 423 * also call `sdio_slave_hal_recv_has_next_item` several times continuously before you call the 424 * `sdio_slave_hal_recv_unload_desc` for the same times. 425 * 426 * @param hal Context of the HAL layer. 427 * @return true if there is 428 */ 429 bool sdio_slave_hal_recv_has_next_item(sdio_slave_context_t* hal); 430 431 /** 432 * Unconditionally remove and return the first descriptor loaded to the HAL. 433 * 434 * Unless during de-initialization, `sdio_slave_hal_recv_has_next_item` should have succeed for the 435 * same times as this function is called, to ensure the returned descriptor has finished its 436 * receiving job. 437 * 438 * @param hal Context of the HAL layer. 439 * @return The removed descriptor, NULL means the linked-list is empty. 440 */ 441 sdio_slave_hal_recv_desc_t *sdio_slave_hal_recv_unload_desc(sdio_slave_context_t *hal); 442 443 /** 444 * Walk through all the unused buffers and reset the counter to the number of 445 * them. 446 * 447 * @note Only call when the DMA is stopped! 448 * @param hal Context of the HAL layer. 449 */ 450 void sdio_slave_hal_recv_reset_counter(sdio_slave_context_t *hal); 451 452 /** 453 * Walk through all the used buffers, clear the finished flag and appended them 454 * back to the end of the unused list, waiting to receive then. 455 * 456 * @note You will lose all the received data in the buffer. 457 * @note Only call when the DMA is stopped! 458 * @param hal Context of the HAL layer. 459 */ 460 void sdio_slave_hal_recv_flush_one_buffer(sdio_slave_context_t *hal); 461 462 463 /*--------------------------------------------------------------------------- 464 * Host 465 *--------------------------------------------------------------------------*/ 466 467 /** 468 * Enable some of the interrupts for the host. 469 * 470 * @note May have concurrency issue wit the host or other tasks, suggest only use it during 471 * initialization. 472 * @param hal Context of the HAL layer. 473 * @param mask Bitwise mask for the interrupts to enable. 474 */ 475 void sdio_slave_hal_hostint_set_ena(sdio_slave_context_t *hal, const sdio_slave_hostint_t *mask); 476 477 /** 478 * Get the enabled interrupts. 479 * 480 * @param hal Context of the HAL layer. 481 * @param out_int_mask Output of the enabled interrupts 482 */ 483 void sdio_slave_hal_hostint_get_ena(sdio_slave_context_t *hal, sdio_slave_hostint_t *out_int_mask); 484 485 /** 486 * Send general purpose interrupt (slave send to host). 487 * @param hal Context of the HAL layer. 488 * @param mask Interrupts to send, only `SDIO_SLAVE_HOSTINT_BIT*` are allowed. 489 */ 490 void sdio_slave_hal_hostint_send(sdio_slave_context_t *hal, const sdio_slave_hostint_t *mask); 491 492 /** 493 * Cleared the specified interrupts for the host. 494 * 495 * @param hal Context of the HAL layer. 496 * @param mask Interrupts to clear. 497 */ 498 void sdio_slave_hal_hostint_clear(sdio_slave_context_t *hal, const sdio_slave_hostint_t *mask); 499 500 501 /** 502 * Fetch the interrupt (host send to slave) status bits and clear all of them. 503 * @param hal Context of the HAL layer. 504 * @param out_int_mask Output interrupt status 505 */ 506 void sdio_slave_hal_slvint_fetch_clear(sdio_slave_context_t *hal, sdio_slave_ll_slvint_t *out_int_mask); 507 508 /** 509 * Get the value of a shared general purpose register. 510 * 511 * @param hal Context of the HAL layer. 512 * @param pos Position of the register, 4 bytes share a word. 0-63 except 24-27. 513 * @return The register value. 514 */ 515 uint8_t sdio_slave_hal_host_get_reg(sdio_slave_context_t *hal, int pos); 516 517 /** 518 * Set the value of shared general purpose register. 519 * 520 * @param hal Context of the HAL layer. 521 * @param pos Position of the register, 4 bytes share a word. 0-63 except 24-27. 522 * @param reg Value to set. 523 */ 524 void sdio_slave_hal_host_set_reg(sdio_slave_context_t *hal, int pos, uint8_t reg); 525