Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
qm_uart.c
1 /*
2  * {% copyright %}
3  */
4 
5 #include <errno.h>
6 #include "qm_uart.h"
7 
8 #ifndef UNIT_TEST
9 qm_uart_reg_t *qm_uart[QM_UART_NUM] = {(qm_uart_reg_t *)QM_UART_0_BASE,
10  (qm_uart_reg_t *)QM_UART_1_BASE};
11 #endif
12 
13 typedef void (*uart_client_callback_t)(void *data, int error,
14  qm_uart_status_t status, uint32_t len);
15 
16 /**
17  * DMA transfer information, relevant on callback invocations from the DMA
18  * driver.
19  */
20 typedef struct {
21  qm_dma_channel_id_t dma_channel_id; /**< DMA channel. */
22  const qm_uart_transfer_t *xfer; /**< User transfer structure. */
23 } dma_context_t;
24 
25 /**
26  * Parameters returned by DMA driver on DMA transfer complete callback.
27  */
28 typedef volatile struct {
29  void *context; /**< Pointer to dma_context_t struct. */
30  uint32_t len; /**< Amount of data successfully transferred. */
31  int error_code; /**< Error code of failed transfer. */
32 } dma_callback_par_t;
33 
34 /* Buffer pointers to store transmit / receive data for UART */
35 static uint32_t write_pos[QM_UART_NUM];
36 static uint32_t read_pos[QM_UART_NUM];
37 static const qm_uart_transfer_t *uart_read_transfer[QM_UART_NUM];
38 static const qm_uart_transfer_t *uart_write_transfer[QM_UART_NUM];
39 
40 /* DMA (memory to UART) callback information. */
41 static dma_context_t dma_context_tx[QM_UART_NUM];
42 /* DMA (UART to memory) callback information. */
43 static dma_context_t dma_context_rx[QM_UART_NUM];
44 /* DMA core being used by each UART. */
45 static qm_dma_t dma_core[QM_UART_NUM];
46 /* DMA callback parameters returned by DMA driver (TX transfers). */
47 static dma_callback_par_t dma_delayed_callback_par[QM_UART_NUM];
48 
49 static bool is_read_xfer_complete(const qm_uart_t uart)
50 {
51  const qm_uart_transfer_t *const transfer = uart_read_transfer[uart];
52 
53  return read_pos[uart] >= transfer->data_len;
54 }
55 
56 static bool is_write_xfer_complete(const qm_uart_t uart)
57 {
58  const qm_uart_transfer_t *const transfer = uart_write_transfer[uart];
59 
60  return write_pos[uart] >= transfer->data_len;
61 }
62 
63 static void uart_client_callback(qm_uart_t uart, void *data, int error,
64  uint32_t len);
65 
66 static void qm_uart_isr_handler(const qm_uart_t uart)
67 {
68  qm_uart_reg_t *const regs = QM_UART[uart];
69  uint8_t interrupt_id = regs->iir_fcr & QM_UART_IIR_IID_MASK;
70  const qm_uart_transfer_t *const read_transfer =
71  uart_read_transfer[uart];
72  const qm_uart_transfer_t *const write_transfer =
73  uart_write_transfer[uart];
74 
75  /*
76  * Interrupt ID priority levels (from highest to lowest):
77  * 1: QM_UART_IIR_RECV_LINE_STATUS
78  * 2: QM_UART_IIR_RECV_DATA_AVAIL and QM_UART_IIR_CHAR_TIMEOUT
79  * 3: QM_UART_IIR_THR_EMPTY
80  */
81  switch (interrupt_id) {
82  case QM_UART_IIR_THR_EMPTY:
83 
84  if (dma_delayed_callback_par[uart].context) {
85  /*
86  * A DMA TX transfer just completed, disable interrupt
87  * and invoke client callback.
88  */
89  regs->ier_dlh &= ~QM_UART_IER_ETBEI;
90 
91  uart_client_callback(
92  uart, dma_delayed_callback_par[uart].context,
93  dma_delayed_callback_par[uart].error_code,
94  dma_delayed_callback_par[uart].len);
95  dma_delayed_callback_par[uart].context = NULL;
96  return;
97  }
98 
99  if (is_write_xfer_complete(uart)) {
100  regs->ier_dlh &= ~QM_UART_IER_ETBEI;
101  /*
102  * At this point the FIFOs are empty, but the shift
103  * register still is transmitting the last 8 bits. So if
104  * we were to read LSR, it would say the device is still
105  * busy. Use the SCR Bit 0 to indicate an irq tx is
106  * complete.
107  */
108  regs->scr |= BIT(0);
109  if (write_transfer->callback) {
110  write_transfer->callback(
111  write_transfer->callback_data, 0,
112  QM_UART_IDLE, write_pos[uart]);
113  }
114  return;
115  }
116 
117  /*
118  * If we are starting the transfer then the TX FIFO is empty.
119  * In that case we set 'count' variable to QM_UART_FIFO_DEPTH
120  * in order to take advantage of the whole FIFO capacity.
121  */
122  int count = (write_pos[uart] == 0) ? QM_UART_FIFO_DEPTH
123  : QM_UART_FIFO_HALF_DEPTH;
124  while (count-- && !is_write_xfer_complete(uart)) {
125  regs->rbr_thr_dll =
126  write_transfer->data[write_pos[uart]++];
127  }
128 
129  /*
130  * Change the threshold level to trigger an interrupt when the
131  * TX buffer is empty.
132  */
133  if (is_write_xfer_complete(uart)) {
134  regs->iir_fcr = QM_UART_FCR_TX_0_RX_1_2_THRESHOLD |
135  QM_UART_FCR_FIFOE;
136  }
137 
138  break;
139 
140  case QM_UART_IIR_CHAR_TIMEOUT:
141  case QM_UART_IIR_RECV_DATA_AVAIL:
142  /*
143  * Copy data from RX FIFO to xfer buffer as long as the xfer
144  * has not completed and we have data in the RX FIFO.
145  */
146  while (!is_read_xfer_complete(uart)) {
147  uint32_t lsr = regs->lsr;
148  /*
149  * A break condition may cause a line status interrupt
150  * to follow very closely after a char timeout
151  * interrupt, but reading the lsr effectively clears the
152  * pending interrupts so we issue here the callback
153  * instead, otherwise we would miss it.
154  * NOTE: Returned len is 0 for now, this might change
155  * in the future.
156  */
157  if (lsr & QM_UART_LSR_ERROR_BITS) {
158  if (read_transfer->callback) {
159  read_transfer->callback(
160  read_transfer->callback_data, -EIO,
161  lsr & QM_UART_LSR_ERROR_BITS, 0);
162  }
163  }
164  if (lsr & QM_UART_LSR_DR) {
165  read_transfer->data[read_pos[uart]++] =
166  regs->rbr_thr_dll;
167  } else {
168  /* No more data in the RX FIFO */
169  break;
170  }
171  }
172 
173  if (is_read_xfer_complete(uart)) {
174  /*
175  * Disable both 'Receiver Data Available' and
176  * 'Receiver Line Status' interrupts.
177  */
178  regs->ier_dlh &=
179  ~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
180  if (read_transfer->callback) {
181  read_transfer->callback(
182  read_transfer->callback_data, 0,
183  QM_UART_IDLE, read_pos[uart]);
184  }
185  }
186 
187  break;
188 
189  case QM_UART_IIR_RECV_LINE_STATUS:
190  if (read_transfer->callback) {
191  /*
192  * NOTE: Returned len is 0 for now, this might change
193  * in the future.
194  */
195  read_transfer->callback(
196  read_transfer->callback_data, -EIO,
197  regs->lsr & QM_UART_LSR_ERROR_BITS, 0);
198  }
199  break;
200  }
201 }
202 
203 QM_ISR_DECLARE(qm_uart_0_isr)
204 {
205  qm_uart_isr_handler(QM_UART_0);
206  QM_ISR_EOI(QM_IRQ_UART_0_INT_VECTOR);
207 }
208 
209 QM_ISR_DECLARE(qm_uart_1_isr)
210 {
211  qm_uart_isr_handler(QM_UART_1);
212  QM_ISR_EOI(QM_IRQ_UART_1_INT_VECTOR);
213 }
214 
215 int qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *cfg)
216 {
217  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
218  QM_CHECK(cfg != NULL, -EINVAL);
219 
220  qm_uart_reg_t *const regs = QM_UART[uart];
221  volatile uint32_t unused_lsr __attribute__((unused));
222 
223  /* Clear DLAB by unsetting line parameters */
224  regs->lcr = 0;
225 
226  /* Set divisor latch registers (integer + fractional part) */
227  regs->lcr = QM_UART_LCR_DLAB;
228  regs->ier_dlh = QM_UART_CFG_BAUD_DLH_UNPACK(cfg->baud_divisor);
229  regs->rbr_thr_dll = QM_UART_CFG_BAUD_DLL_UNPACK(cfg->baud_divisor);
230  regs->dlf = QM_UART_CFG_BAUD_DLF_UNPACK(cfg->baud_divisor);
231 
232  /* Set line parameters. This also unsets the DLAB */
233  regs->lcr = cfg->line_control;
234 
235  /* Hardware automatic flow control */
236  regs->mcr = 0;
237  if (true == cfg->hw_fc) {
238  regs->mcr |= QM_UART_MCR_AFCE | QM_UART_MCR_RTS;
239  }
240 
241  /* FIFO's enable and reset, set interrupt threshold */
242  regs->iir_fcr =
243  (QM_UART_FCR_FIFOE | QM_UART_FCR_RFIFOR | QM_UART_FCR_XFIFOR |
244  QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
245  regs->ier_dlh |= QM_UART_IER_PTIME;
246 
247  /* Clear LSR */
248  unused_lsr = regs->lsr;
249 
250  return 0;
251 }
252 
253 int qm_uart_get_status(const qm_uart_t uart, qm_uart_status_t *const status)
254 {
255  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
256  QM_CHECK(status != NULL, -EINVAL);
257  qm_uart_reg_t *const regs = QM_UART[uart];
258  uint32_t lsr = regs->lsr;
259 
260  *status = (lsr & (QM_UART_LSR_OE | QM_UART_LSR_PE | QM_UART_LSR_FE |
261  QM_UART_LSR_BI));
262 
263  /*
264  * Check as an IRQ TX completed, if so, the Shift register may still be
265  * busy.
266  */
267  if (regs->scr & BIT(0)) {
268  regs->scr &= ~BIT(0);
269  } else if (!(lsr & (QM_UART_LSR_TEMT))) {
270  *status |= QM_UART_TX_BUSY;
271  }
272 
273  if (lsr & QM_UART_LSR_DR) {
274  *status |= QM_UART_RX_BUSY;
275  }
276 
277  return 0;
278 }
279 
280 int qm_uart_write(const qm_uart_t uart, const uint8_t data)
281 {
282  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
283 
284  qm_uart_reg_t *const regs = QM_UART[uart];
285 
286  while (regs->lsr & QM_UART_LSR_THRE) {
287  }
288  regs->rbr_thr_dll = data;
289  /* Wait for transaction to complete. */
290  while (!(regs->lsr & QM_UART_LSR_TEMT)) {
291  }
292 
293  return 0;
294 }
295 
296 int qm_uart_read(const qm_uart_t uart, uint8_t *const data,
297  qm_uart_status_t *status)
298 {
299  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
300  QM_CHECK(data != NULL, -EINVAL);
301 
302  qm_uart_reg_t *const regs = QM_UART[uart];
303 
304  uint32_t lsr = regs->lsr;
305  while (!(lsr & QM_UART_LSR_DR)) {
306  lsr = regs->lsr;
307  }
308  /* Check if there are any errors on the line. */
309  if (lsr & QM_UART_LSR_ERROR_BITS) {
310  if (status) {
311  *status = (lsr & QM_UART_LSR_ERROR_BITS);
312  }
313  return -EIO;
314  }
315  *data = regs->rbr_thr_dll;
316 
317  return 0;
318 }
319 
320 int qm_uart_write_non_block(const qm_uart_t uart, const uint8_t data)
321 {
322  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
323 
324  qm_uart_reg_t *const regs = QM_UART[uart];
325 
326  regs->rbr_thr_dll = data;
327 
328  return 0;
329 }
330 
331 int qm_uart_read_non_block(const qm_uart_t uart, uint8_t *const data)
332 {
333  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
334  QM_CHECK(data != NULL, -EINVAL);
335  qm_uart_reg_t *const regs = QM_UART[uart];
336 
337  *data = regs->rbr_thr_dll;
338 
339  return 0;
340 }
341 
342 int qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data,
343  uint32_t len)
344 {
345  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
346  QM_CHECK(data != NULL, -EINVAL);
347 
348  qm_uart_reg_t *const regs = QM_UART[uart];
349 
350  uint8_t *d = (uint8_t *)data;
351 
352  while (len--) {
353  /*
354  * Because FCR_FIFOE and IER_PTIME are enabled, LSR_THRE
355  * behaves as a TX FIFO full indicator.
356  */
357  while (regs->lsr & QM_UART_LSR_THRE) {
358  }
359  regs->rbr_thr_dll = *d;
360  d++;
361  }
362  /* Wait for transaction to complete. */
363  while (!(regs->lsr & QM_UART_LSR_TEMT)) {
364  }
365  return 0;
366 }
367 
369  const qm_uart_transfer_t *const xfer)
370 {
371  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
372  QM_CHECK(xfer != NULL, -EINVAL);
373 
374  qm_uart_reg_t *const regs = QM_UART[uart];
375 
376  write_pos[uart] = 0;
377  uart_write_transfer[uart] = xfer;
378 
379  /* Set threshold */
380  regs->iir_fcr =
381  (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
382 
383  /* Enable TX holding reg empty interrupt. */
384  regs->ier_dlh |= QM_UART_IER_ETBEI;
385 
386  return 0;
387 }
388 
389 int qm_uart_irq_read(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
390 {
391  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
392  QM_CHECK(xfer != NULL, -EINVAL);
393 
394  qm_uart_reg_t *const regs = QM_UART[uart];
395 
396  read_pos[uart] = 0;
397  uart_read_transfer[uart] = xfer;
398 
399  /* Set threshold */
400  regs->iir_fcr =
401  (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
402 
403  /*
404  * Enable both 'Receiver Data Available' and 'Receiver
405  * Line Status' interrupts.
406  */
407  regs->ier_dlh |= QM_UART_IER_ERBFI | QM_UART_IER_ELSI;
408 
409  return 0;
410 }
411 
413 {
414  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
415 
416  qm_uart_reg_t *const regs = QM_UART[uart];
417  const qm_uart_transfer_t *const transfer = uart_write_transfer[uart];
418 
419  /* Disable TX holding reg empty interrupt. */
420  regs->ier_dlh &= ~QM_UART_IER_ETBEI;
421  if (transfer->callback) {
422  transfer->callback(transfer->callback_data, -ECANCELED,
423  QM_UART_IDLE, write_pos[uart]);
424  }
425 
426  return 0;
427 }
428 
430 {
431  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
432 
433  qm_uart_reg_t *const regs = QM_UART[uart];
434  const qm_uart_transfer_t *const transfer = uart_read_transfer[uart];
435 
436  /*
437  * Disable both 'Receiver Data Available' and 'Receiver Line Status'
438  * interrupts.
439  */
440  regs->ier_dlh &= ~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
441  if (transfer->callback) {
442  transfer->callback(transfer->callback_data, -ECANCELED,
443  QM_UART_IDLE, read_pos[uart]);
444  }
445 
446  return 0;
447 }
448 
449 /*
450  * Called by the DMA driver when the whole TX buffer has been written to the TX
451  * FIFO (write transfers) or the expected amount of data has been read from the
452  * RX FIFO (read transfers).
453  */
454 static void uart_dma_callback(void *callback_context, uint32_t len,
455  int error_code)
456 {
457  qm_uart_t uart;
458  QM_ASSERT(callback_context);
459  /*
460  * On TX transfers, the DMA driver invokes this function as soon as all
461  * data has been written to the TX FIFO, but we still need to wait until
462  * everything has been written to the shift register (TX FIFO empty
463  * interrupt) before the client callback is invoked.
464  */
465  if (callback_context >= (void *)&dma_context_tx[0] &&
466  callback_context <= (void *)&dma_context_tx[QM_UART_NUM - 1]) {
467  /*
468  * callback_context is within dma_context_tx array so this is a
469  * TX transfer, we extract the uart index from the position in
470  * the array.
471  */
472  uart = (dma_context_t *)callback_context - dma_context_tx;
473  QM_ASSERT(callback_context == (void *)&dma_context_tx[uart]);
474  qm_uart_reg_t *const regs = QM_UART[uart];
475 
476  dma_delayed_callback_par[uart].context = callback_context;
477  dma_delayed_callback_par[uart].len = len;
478  dma_delayed_callback_par[uart].error_code = error_code;
479 
480  /*
481  * Change the threshold level to trigger an interrupt when the
482  * TX FIFO is empty and enable the TX FIFO empty interrupt.
483  */
484  regs->iir_fcr =
485  (QM_UART_FCR_FIFOE | QM_UART_FCR_TX_0_RX_1_2_THRESHOLD);
486  regs->ier_dlh |= QM_UART_IER_ETBEI;
487  } else {
488  /* RX transfer. */
489  uart = (dma_context_t *)callback_context - dma_context_rx;
490  QM_ASSERT(callback_context == (void *)&dma_context_rx[uart]);
491  uart_client_callback(uart, callback_context, error_code, len);
492  }
493 }
494 
495 /* Invoke the UART client callback. */
496 static void uart_client_callback(qm_uart_t uart, void *data, int error,
497  uint32_t len)
498 {
499  const qm_uart_transfer_t *const xfer = ((dma_context_t *)data)->xfer;
500  QM_ASSERT(xfer);
501  const uart_client_callback_t client_callback = xfer->callback;
502  void *const client_data = xfer->callback_data;
503  const uint32_t client_expected_len = xfer->data_len;
504  qm_uart_reg_t *const regs = QM_UART[uart];
505  qm_uart_status_t status;
506 
507  if (!client_callback) {
508  return;
509  }
510 
511  status = regs->lsr & QM_UART_LSR_ERROR_BITS;
512  status |= (regs->lsr & QM_UART_LSR_DR) ? QM_UART_RX_BUSY : 0;
513 
514  if (error) {
515  /*
516  * Transfer failed, pass to client the error code returned by
517  * the DMA driver.
518  */
519  client_callback(client_data, error, status, 0);
520  } else if (len == client_expected_len) {
521  /* Transfer completed successfully. */
522  client_callback(client_data, 0, status, len);
523  } else {
524  QM_ASSERT(len < client_expected_len);
525  /* Transfer cancelled. */
526  client_callback(client_data, -ECANCELED, status, len);
527  }
528 }
529 
531  const qm_uart_t uart, const qm_dma_t dma_ctrl_id,
532  const qm_dma_channel_id_t dma_channel_id,
533  const qm_dma_channel_direction_t dma_channel_direction)
534 {
535  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
536  QM_CHECK(dma_ctrl_id < QM_DMA_NUM, -EINVAL);
537  QM_CHECK(dma_channel_id < QM_DMA_CHANNEL_NUM, -EINVAL);
538 
539  int ret = -EINVAL;
540  qm_dma_channel_config_t dma_chan_cfg = {0};
541  /* UART has inverted handshake polarity. */
543  dma_chan_cfg.channel_direction = dma_channel_direction;
546  /* Default FIFO threshold is 1/2 full (8 bytes). */
549  dma_chan_cfg.client_callback = uart_dma_callback;
550  dma_chan_cfg.transfer_type = QM_DMA_TYPE_SINGLE;
551 
552  switch (dma_channel_direction) {
554  dma_chan_cfg.handshake_interface = (QM_UART_0 == uart)
557 
558  /*
559  * The DMA driver needs a pointer to the DMA context structure
560  * used on DMA callback invocation.
561  */
562  dma_context_tx[uart].dma_channel_id = dma_channel_id;
563  dma_chan_cfg.callback_context = &dma_context_tx[uart];
564  break;
565 
567  dma_chan_cfg.handshake_interface = (QM_UART_0 == uart)
570 
571  /*
572  * The DMA driver needs a pointer to the DMA context structure
573  * used on DMA callback invocation.
574  */
575  dma_context_rx[uart].dma_channel_id = dma_channel_id;
576  dma_chan_cfg.callback_context = &dma_context_rx[uart];
577  break;
578 
579  default:
580  /* Direction not allowed on UART transfers. */
581  return -EINVAL;
582  }
583 
584  dma_core[uart] = dma_ctrl_id;
585 
586  ret = qm_dma_channel_set_config(dma_ctrl_id, dma_channel_id,
587  &dma_chan_cfg);
588  return ret;
589 }
590 
592  const qm_uart_transfer_t *const xfer)
593 {
594  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
595  QM_CHECK(xfer, -EINVAL);
596  QM_CHECK(xfer->data, -EINVAL);
597  QM_CHECK(xfer->data_len, -EINVAL);
598 
599  int ret = -EINVAL;
600  qm_uart_reg_t *regs = QM_UART[uart];
601  qm_dma_transfer_t dma_trans = {0};
602  dma_trans.block_size = xfer->data_len;
603  dma_trans.source_address = (uint32_t *)xfer->data;
604  dma_trans.destination_address = (uint32_t *)&regs->rbr_thr_dll;
605 
607  dma_core[uart], dma_context_tx[uart].dma_channel_id, &dma_trans);
608  if (ret) {
609  return ret;
610  }
611 
612  /* Store the user transfer pointer that we will need on DMA callback. */
613  dma_context_tx[uart].xfer = xfer;
614 
615  /* Set the FCR register FIFO thresholds. */
616  regs->iir_fcr =
617  (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
618 
619  ret = qm_dma_transfer_start(dma_core[uart],
620  dma_context_tx[uart].dma_channel_id);
621 
622  return ret;
623 }
624 
625 int qm_uart_dma_read(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
626 {
627  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
628  QM_CHECK(xfer, -EINVAL);
629  QM_CHECK(xfer->data, -EINVAL);
630  QM_CHECK(xfer->data_len, -EINVAL);
631 
632  int ret = -EINVAL;
633  qm_uart_reg_t *regs = QM_UART[uart];
634  qm_dma_transfer_t dma_trans = {0};
635  dma_trans.block_size = xfer->data_len;
636  dma_trans.source_address = (uint32_t *)&regs->rbr_thr_dll;
637  dma_trans.destination_address = (uint32_t *)xfer->data;
638 
640  dma_core[uart], dma_context_rx[uart].dma_channel_id, &dma_trans);
641  if (ret) {
642  return ret;
643  }
644 
645  /* Store the user transfer pointer that we will need on DMA callback. */
646  dma_context_rx[uart].xfer = xfer;
647 
648  /* Set the FCR register FIFO thresholds. */
649  regs->iir_fcr =
650  (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
651 
652  ret = qm_dma_transfer_start(dma_core[uart],
653  dma_context_rx[uart].dma_channel_id);
654 
655  return ret;
656 }
657 
659 {
660  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
661 
662  int ret = qm_dma_transfer_terminate(
663  dma_core[uart], dma_context_tx[uart].dma_channel_id);
664 
665  return ret;
666 }
667 
669 {
670  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
671 
672  int ret = qm_dma_transfer_terminate(
673  dma_core[uart], dma_context_rx[uart].dma_channel_id);
674 
675  return ret;
676 }
677 
678 #if (ENABLE_RESTORE_CONTEXT)
680 {
681  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
682  QM_CHECK(ctx != NULL, -EINVAL);
683 
684  qm_uart_reg_t *const regs = QM_UART[uart];
685 
686  ctx->ier = regs->ier_dlh;
687  ctx->lcr = regs->lcr;
688  ctx->mcr = regs->mcr;
689  ctx->scr = regs->scr;
690  ctx->htx = regs->htx;
691  ctx->dlf = regs->dlf;
692 
693  regs->lcr |= QM_UART_LCR_DLAB;
694  ctx->dlh = regs->ier_dlh;
695  ctx->dll = regs->rbr_thr_dll;
696  regs->lcr &= ~QM_UART_LCR_DLAB;
697 
698  return 0;
699 }
700 
702  const qm_uart_context_t *const ctx)
703 {
704  QM_CHECK(uart < QM_UART_NUM, -EINVAL);
705  QM_CHECK(ctx != NULL, -EINVAL);
706 
707  qm_uart_reg_t *const regs = QM_UART[uart];
708 
709  /* When DLAB is set, DLL and DLH registers can be accessed. */
710  regs->lcr |= QM_UART_LCR_DLAB;
711  regs->ier_dlh = ctx->dlh;
712  regs->rbr_thr_dll = ctx->dll;
713  regs->lcr &= ~QM_UART_LCR_DLAB;
714 
715  regs->ier_dlh = ctx->ier;
716  regs->lcr = ctx->lcr;
717  regs->mcr = ctx->mcr;
718  regs->scr = ctx->scr;
719  regs->htx = ctx->htx;
720  regs->dlf = ctx->dlf;
721 
722  /*
723  * FIFO control register cannot be read back,
724  * default config is applied for this register.
725  * Application will need to restore its own parameters.
726  */
727  regs->iir_fcr =
728  (QM_UART_FCR_FIFOE | QM_UART_FCR_RFIFOR | QM_UART_FCR_XFIFOR |
729  QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
730 
731  return 0;
732 }
733 #else
735 {
736  (void)uart;
737  (void)ctx;
738 
739  return 0;
740 }
741 
743  const qm_uart_context_t *const ctx)
744 {
745  (void)uart;
746  (void)ctx;
747 
748  return 0;
749 }
750 #endif /* ENABLE_RESTORE_CONTEXT */
uint32_t dlh
Divisor Latch High.
Definition: qm_soc_regs.h:995
int qm_uart_dma_channel_config(const qm_uart_t uart, const qm_dma_t dma_ctrl_id, const qm_dma_channel_id_t dma_channel_id, const qm_dma_channel_direction_t dma_channel_direction)
Configure a DMA channel with a specific transfer direction.
Definition: qm_uart.c:530
int qm_uart_irq_read(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
Interrupt based RX on UART.
Definition: qm_uart.c:389
DMA channel configuration structure.
Definition: qm_dma.h:77
qm_dma_transfer_type_t transfer_type
DMA transfer type.
Definition: qm_dma.h:100
int qm_uart_dma_read(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
Perform a DMA-based RX transfer on the UART bus.
Definition: qm_uart.c:625
uint32_t mcr
Modem Control.
Definition: qm_soc_regs.h:998
Burst length 8 data items.
Definition: qm_dma.h:32
uint32_t * destination_address
DMA destination transfer address.
Definition: qm_dma.h:136
qm_dma_t
DMA instances.
Definition: qm_soc_regs.h:1480
UART context to be saved between sleep/resume.
Definition: qm_soc_regs.h:993
QM_RW uint32_t dlf
Divisor Latch Fraction.
Definition: qm_soc_regs.h:678
QM_RW uint32_t lcr
Line Control.
Definition: qm_soc_regs.h:663
int qm_uart_save_context(const qm_uart_t uart, qm_uart_context_t *const ctx)
Save UART context.
Definition: qm_uart.c:679
Number of DMA channels.
Definition: qm_soc_regs.h:1489
DMA single block transfer configuration structure.
Definition: qm_dma.h:133
QM_RW uint32_t mcr
MODEM Control.
Definition: qm_soc_regs.h:664
qm_dma_burst_length_t source_burst_length
DMA source burst length.
Definition: qm_dma.h:94
IDLE.
Definition: qm_uart.h:53
UART asynchronous transfer structure.
Definition: qm_uart.h:76
int qm_uart_get_status(const qm_uart_t uart, qm_uart_status_t *const status)
Get UART bus status.
Definition: qm_uart.c:253
qm_uart_lc_t line_control
Line control (enum).
Definition: qm_uart.h:68
int qm_uart_dma_write_terminate(const qm_uart_t uart)
Terminate the current DMA TX transfer on the UART bus.
Definition: qm_uart.c:658
uint32_t block_size
DMA block size, Min = 1, Max = 4095.
Definition: qm_dma.h:134
void * callback_context
DMA client context passed to the callbacks.
Definition: qm_dma.h:113
UART register map.
Definition: qm_soc_regs.h:658
uint8_t * data
Pre-allocated write or read buffer.
Definition: qm_uart.h:77
qm_uart_t
Number of UART controllers.
Definition: qm_soc_regs.h:655
void(* callback)(void *data, int error, qm_uart_status_t status, uint32_t len)
Transfer callback.
Definition: qm_uart.h:89
Transfer width of 8 bits.
Definition: qm_dma.h:45
uint32_t htx
Halt Transmission.
Definition: qm_soc_regs.h:1000
QM_RW uint32_t rbr_thr_dll
Rx Buffer/ Tx Holding/ Div Latch Low.
Definition: qm_soc_regs.h:660
QM_ISR_DECLARE(qm_uart_0_isr)
ISR for UART 0 interrupt.
Definition: qm_uart.c:203
int qm_uart_dma_read_terminate(const qm_uart_t uart)
Terminate the current DMA RX transfer on the UART bus.
Definition: qm_uart.c:668
int qm_uart_irq_write(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
Interrupt based TX on UART.
Definition: qm_uart.c:368
int qm_uart_write_non_block(const qm_uart_t uart, const uint8_t data)
UART character data write.
Definition: qm_uart.c:320
int qm_uart_read_non_block(const qm_uart_t uart, uint8_t *const data)
UART character data read.
Definition: qm_uart.c:331
qm_dma_handshake_interface_t handshake_interface
DMA channel handshake interface ID.
Definition: qm_dma.h:79
int qm_dma_transfer_set_config(const qm_dma_t dma, const qm_dma_channel_id_t channel_id, qm_dma_transfer_t *const transfer_config)
Setup a DMA single block transfer.
Definition: qm_dma.c:345
bool hw_fc
Hardware Automatic Flow Control.
Definition: qm_uart.h:70
qm_dma_handshake_polarity_t handshake_polarity
DMA channel handshake polarity.
Definition: qm_dma.h:82
Set HS polarity low.
Definition: qm_dma.h:23
Single block mode.
Definition: qm_dma.h:67
QM_RW uint32_t htx
Halt Transmission.
Definition: qm_soc_regs.h:671
QM_RW uint32_t lsr
Line Status.
Definition: qm_soc_regs.h:665
qm_uart_status_t
UART Status type.
Definition: qm_uart.h:52
Peripheral to memory transfer.
Definition: qm_dma.h:60
uint32_t scr
Scratchpad.
Definition: qm_soc_regs.h:999
qm_dma_burst_length_t destination_burst_length
DMA destination burst length.
Definition: qm_dma.h:97
int qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *cfg)
Set UART configuration.
Definition: qm_uart.c:215
qm_dma_transfer_width_t destination_transfer_width
DMA destination transfer width.
Definition: qm_dma.h:91
int qm_dma_channel_set_config(const qm_dma_t dma, const qm_dma_channel_id_t channel_id, qm_dma_channel_config_t *const channel_config)
Setup a DMA channel configuration.
Definition: qm_dma.c:254
int qm_uart_restore_context(const qm_uart_t uart, const qm_uart_context_t *const ctx)
Restore UART context.
Definition: qm_uart.c:701
QM_RW uint32_t ier_dlh
Interrupt Enable / Divisor Latch High.
Definition: qm_soc_regs.h:661
Number of DMA controllers.
Definition: qm_soc_regs.h:1482
qm_dma_transfer_width_t source_transfer_width
DMA source transfer width.
Definition: qm_dma.h:88
int qm_uart_irq_write_terminate(const qm_uart_t uart)
Terminate UART IRQ TX transfer.
Definition: qm_uart.c:412
RX Busy flag.
Definition: qm_uart.h:59
void * callback_data
Callback identifier.
Definition: qm_uart.h:91
int qm_dma_transfer_terminate(const qm_dma_t dma, const qm_dma_channel_id_t channel_id)
Terminate a DMA transfer.
Definition: qm_dma.c:618
uint32_t dll
Divisor Latch Low.
Definition: qm_soc_regs.h:996
qm_dma_channel_direction_t
DMA channel direction.
Definition: qm_dma.h:56
uint32_t baud_divisor
Baud Divisor.
Definition: qm_uart.h:69
int qm_dma_transfer_start(const qm_dma_t dma, const qm_dma_channel_id_t channel_id)
Start a DMA transfer.
Definition: qm_dma.c:582
QM_RW uint32_t iir_fcr
Interrupt Identification / FIFO Control.
Definition: qm_soc_regs.h:662
Memory to peripheral transfer.
Definition: qm_dma.h:58
QM_RW uint32_t scr
Scratchpad.
Definition: qm_soc_regs.h:667
uint32_t * source_address
DMA source transfer address.
Definition: qm_dma.h:135
qm_dma_channel_id_t
DMA channel IDs.
Definition: qm_soc_regs.h:1486
int qm_uart_write(const qm_uart_t uart, const uint8_t data)
UART character data write.
Definition: qm_uart.c:280
int qm_uart_irq_read_terminate(const qm_uart_t uart)
Terminate UART IRQ RX transfer.
Definition: qm_uart.c:429
UART configuration structure type.
Definition: qm_uart.h:67
uint32_t lcr
Line Control.
Definition: qm_soc_regs.h:997
uint32_t data_len
Number of bytes to transfer.
Definition: qm_uart.h:78
qm_dma_channel_direction_t channel_direction
DMA channel direction.
Definition: qm_dma.h:85
int qm_uart_read(const qm_uart_t uart, uint8_t *const data, qm_uart_status_t *status)
UART character data read.
Definition: qm_uart.c:296
uint32_t dlf
Divisor Latch Fraction.
Definition: qm_soc_regs.h:1001
TX Busy flag.
Definition: qm_uart.h:58
int qm_uart_dma_write(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
Perform a DMA-based TX transfer on the UART bus.
Definition: qm_uart.c:591
uint32_t ier
Interrupt Enable Register.
Definition: qm_soc_regs.h:994
int qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data, uint32_t len)
UART multi-byte data write.
Definition: qm_uart.c:342
void(* client_callback)(void *callback_context, uint32_t len, int error_code)
Client callback for DMA transfer ISR.
Definition: qm_dma.h:109