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