13 typedef void (*uart_client_callback_t)(
void *data,
int error,
28 typedef volatile struct {
35 static uint32_t write_pos[QM_UART_NUM];
36 static uint32_t read_pos[QM_UART_NUM];
41 static dma_context_t dma_context_tx[QM_UART_NUM];
43 static dma_context_t dma_context_rx[QM_UART_NUM];
45 static qm_dma_t dma_core[QM_UART_NUM];
47 static dma_callback_par_t dma_delayed_callback_par[QM_UART_NUM];
49 static bool is_read_xfer_complete(
const qm_uart_t uart)
53 return read_pos[uart] >= transfer->
data_len;
56 static bool is_write_xfer_complete(
const qm_uart_t uart)
60 return write_pos[uart] >= transfer->
data_len;
63 static void uart_client_callback(
qm_uart_t uart,
void *data,
int error,
66 static void qm_uart_isr_handler(
const qm_uart_t uart)
69 uint8_t interrupt_id = regs->
iir_fcr & QM_UART_IIR_IID_MASK;
71 uart_read_transfer[uart];
73 uart_write_transfer[uart];
81 switch (interrupt_id) {
82 case QM_UART_IIR_THR_EMPTY:
84 if (dma_delayed_callback_par[uart].context) {
89 regs->
ier_dlh &= ~QM_UART_IER_ETBEI;
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;
99 if (is_write_xfer_complete(uart)) {
100 regs->
ier_dlh &= ~QM_UART_IER_ETBEI;
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)) {
126 write_transfer->
data[write_pos[uart]++];
133 if (is_write_xfer_complete(uart)) {
134 regs->
iir_fcr = QM_UART_FCR_TX_0_RX_1_2_THRESHOLD |
140 case QM_UART_IIR_CHAR_TIMEOUT:
141 case QM_UART_IIR_RECV_DATA_AVAIL:
146 while (!is_read_xfer_complete(uart)) {
147 uint32_t lsr = regs->
lsr;
157 if (lsr & QM_UART_LSR_ERROR_BITS) {
161 lsr & QM_UART_LSR_ERROR_BITS, 0);
164 if (lsr & QM_UART_LSR_DR) {
165 read_transfer->
data[read_pos[uart]++] =
173 if (is_read_xfer_complete(uart)) {
179 ~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
189 case QM_UART_IIR_RECV_LINE_STATUS:
197 regs->
lsr & QM_UART_LSR_ERROR_BITS, 0);
205 qm_uart_isr_handler(QM_UART_0);
206 QM_ISR_EOI(QM_IRQ_UART_0_INT_VECTOR);
211 qm_uart_isr_handler(QM_UART_1);
212 QM_ISR_EOI(QM_IRQ_UART_1_INT_VECTOR);
217 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
218 QM_CHECK(cfg != NULL, -EINVAL);
221 volatile uint32_t unused_lsr __attribute__((unused));
227 regs->
lcr = QM_UART_LCR_DLAB;
237 if (
true == cfg->
hw_fc) {
238 regs->
mcr |= QM_UART_MCR_AFCE | QM_UART_MCR_RTS;
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;
248 unused_lsr = regs->
lsr;
255 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
256 QM_CHECK(status != NULL, -EINVAL);
258 uint32_t lsr = regs->
lsr;
260 *status = (lsr & (QM_UART_LSR_OE | QM_UART_LSR_PE | QM_UART_LSR_FE |
267 if (regs->
scr & BIT(0)) {
268 regs->
scr &= ~BIT(0);
269 }
else if (!(lsr & (QM_UART_LSR_TEMT))) {
273 if (lsr & QM_UART_LSR_DR) {
282 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
286 while (regs->
lsr & QM_UART_LSR_THRE) {
290 while (!(regs->
lsr & QM_UART_LSR_TEMT)) {
299 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
300 QM_CHECK(data != NULL, -EINVAL);
304 uint32_t lsr = regs->
lsr;
305 while (!(lsr & QM_UART_LSR_DR)) {
309 if (lsr & QM_UART_LSR_ERROR_BITS) {
311 *status = (lsr & QM_UART_LSR_ERROR_BITS);
322 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
333 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
334 QM_CHECK(data != NULL, -EINVAL);
345 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
346 QM_CHECK(data != NULL, -EINVAL);
350 uint8_t *d = (uint8_t *)data;
357 while (regs->
lsr & QM_UART_LSR_THRE) {
363 while (!(regs->
lsr & QM_UART_LSR_TEMT)) {
371 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
372 QM_CHECK(xfer != NULL, -EINVAL);
377 uart_write_transfer[uart] = xfer;
381 (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
384 regs->
ier_dlh |= QM_UART_IER_ETBEI;
391 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
392 QM_CHECK(xfer != NULL, -EINVAL);
397 uart_read_transfer[uart] = xfer;
401 (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
407 regs->
ier_dlh |= QM_UART_IER_ERBFI | QM_UART_IER_ELSI;
414 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
420 regs->
ier_dlh &= ~QM_UART_IER_ETBEI;
431 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
440 regs->
ier_dlh &= ~(QM_UART_IER_ERBFI | QM_UART_IER_ELSI);
454 static void uart_dma_callback(
void *callback_context, uint32_t len,
458 QM_ASSERT(callback_context);
465 if (callback_context >= (
void *)&dma_context_tx[0] &&
466 callback_context <= (
void *)&dma_context_tx[QM_UART_NUM - 1]) {
472 uart = (dma_context_t *)callback_context - dma_context_tx;
473 QM_ASSERT(callback_context == (
void *)&dma_context_tx[uart]);
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;
485 (QM_UART_FCR_FIFOE | QM_UART_FCR_TX_0_RX_1_2_THRESHOLD);
486 regs->
ier_dlh |= QM_UART_IER_ETBEI;
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);
496 static void uart_client_callback(
qm_uart_t uart,
void *data,
int error,
501 const uart_client_callback_t client_callback = xfer->
callback;
503 const uint32_t client_expected_len = xfer->
data_len;
507 if (!client_callback) {
511 status = regs->
lsr & QM_UART_LSR_ERROR_BITS;
519 client_callback(client_data, error, status, 0);
520 }
else if (len == client_expected_len) {
522 client_callback(client_data, 0, status, len);
524 QM_ASSERT(len < client_expected_len);
526 client_callback(client_data, -ECANCELED, status, len);
535 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
552 switch (dma_channel_direction) {
562 dma_context_tx[uart].dma_channel_id = dma_channel_id;
575 dma_context_rx[uart].dma_channel_id = dma_channel_id;
584 dma_core[uart] = dma_ctrl_id;
594 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
595 QM_CHECK(xfer, -EINVAL);
596 QM_CHECK(xfer->
data, -EINVAL);
607 dma_core[uart], dma_context_tx[uart].dma_channel_id, &dma_trans);
613 dma_context_tx[uart].xfer = xfer;
617 (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
620 dma_context_tx[uart].dma_channel_id);
627 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
628 QM_CHECK(xfer, -EINVAL);
629 QM_CHECK(xfer->
data, -EINVAL);
640 dma_core[uart], dma_context_rx[uart].dma_channel_id, &dma_trans);
646 dma_context_rx[uart].xfer = xfer;
650 (QM_UART_FCR_FIFOE | QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
653 dma_context_rx[uart].dma_channel_id);
660 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
663 dma_core[uart], dma_context_tx[uart].dma_channel_id);
670 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
673 dma_core[uart], dma_context_rx[uart].dma_channel_id);
678 #if (ENABLE_RESTORE_CONTEXT)
681 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
682 QM_CHECK(ctx != NULL, -EINVAL);
693 regs->
lcr |= QM_UART_LCR_DLAB;
696 regs->
lcr &= ~QM_UART_LCR_DLAB;
704 QM_CHECK(uart < QM_UART_NUM, -EINVAL);
705 QM_CHECK(ctx != NULL, -EINVAL);
710 regs->
lcr |= QM_UART_LCR_DLAB;
713 regs->
lcr &= ~QM_UART_LCR_DLAB;
728 (QM_UART_FCR_FIFOE | QM_UART_FCR_RFIFOR | QM_UART_FCR_XFIFOR |
729 QM_UART_FCR_DEFAULT_TX_RX_THRESHOLD);
uint32_t dlh
Divisor Latch High.
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.
int qm_uart_irq_read(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
Interrupt based RX on UART.
DMA channel configuration structure.
qm_dma_transfer_type_t transfer_type
DMA transfer type.
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.
uint32_t mcr
Modem Control.
Burst length 8 data items.
uint32_t * destination_address
DMA destination transfer address.
UART context to be saved between sleep/resume.
QM_RW uint32_t dlf
Divisor Latch Fraction.
QM_RW uint32_t lcr
Line Control.
int qm_uart_save_context(const qm_uart_t uart, qm_uart_context_t *const ctx)
Save UART context.
DMA single block transfer configuration structure.
QM_RW uint32_t mcr
MODEM Control.
qm_dma_burst_length_t source_burst_length
DMA source burst length.
UART asynchronous transfer structure.
int qm_uart_get_status(const qm_uart_t uart, qm_uart_status_t *const status)
Get UART bus status.
qm_uart_lc_t line_control
Line control (enum).
int qm_uart_dma_write_terminate(const qm_uart_t uart)
Terminate the current DMA TX transfer on the UART bus.
uint32_t block_size
DMA block size, Min = 1, Max = 4095.
void * callback_context
DMA client context passed to the callbacks.
uint8_t * data
Pre-allocated write or read buffer.
qm_uart_t
Number of UART controllers.
void(* callback)(void *data, int error, qm_uart_status_t status, uint32_t len)
Transfer callback.
Transfer width of 8 bits.
uint32_t htx
Halt Transmission.
QM_RW uint32_t rbr_thr_dll
Rx Buffer/ Tx Holding/ Div Latch Low.
QM_ISR_DECLARE(qm_uart_0_isr)
ISR for UART 0 interrupt.
int qm_uart_dma_read_terminate(const qm_uart_t uart)
Terminate the current DMA RX transfer on the UART bus.
int qm_uart_irq_write(const qm_uart_t uart, const qm_uart_transfer_t *const xfer)
Interrupt based TX on UART.
int qm_uart_write_non_block(const qm_uart_t uart, const uint8_t data)
UART character data write.
int qm_uart_read_non_block(const qm_uart_t uart, uint8_t *const data)
UART character data read.
qm_dma_handshake_interface_t handshake_interface
DMA channel handshake interface ID.
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.
bool hw_fc
Hardware Automatic Flow Control.
qm_dma_handshake_polarity_t handshake_polarity
DMA channel handshake polarity.
QM_RW uint32_t htx
Halt Transmission.
QM_RW uint32_t lsr
Line Status.
qm_uart_status_t
UART Status type.
Peripheral to memory transfer.
qm_dma_burst_length_t destination_burst_length
DMA destination burst length.
int qm_uart_set_config(const qm_uart_t uart, const qm_uart_config_t *cfg)
Set UART configuration.
qm_dma_transfer_width_t destination_transfer_width
DMA destination transfer width.
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.
int qm_uart_restore_context(const qm_uart_t uart, const qm_uart_context_t *const ctx)
Restore UART context.
QM_RW uint32_t ier_dlh
Interrupt Enable / Divisor Latch High.
Number of DMA controllers.
qm_dma_transfer_width_t source_transfer_width
DMA source transfer width.
int qm_uart_irq_write_terminate(const qm_uart_t uart)
Terminate UART IRQ TX transfer.
void * callback_data
Callback identifier.
int qm_dma_transfer_terminate(const qm_dma_t dma, const qm_dma_channel_id_t channel_id)
Terminate a DMA transfer.
uint32_t dll
Divisor Latch Low.
qm_dma_channel_direction_t
DMA channel direction.
uint32_t baud_divisor
Baud Divisor.
int qm_dma_transfer_start(const qm_dma_t dma, const qm_dma_channel_id_t channel_id)
Start a DMA transfer.
QM_RW uint32_t iir_fcr
Interrupt Identification / FIFO Control.
Memory to peripheral transfer.
QM_RW uint32_t scr
Scratchpad.
uint32_t * source_address
DMA source transfer address.
qm_dma_channel_id_t
DMA channel IDs.
int qm_uart_write(const qm_uart_t uart, const uint8_t data)
UART character data write.
int qm_uart_irq_read_terminate(const qm_uart_t uart)
Terminate UART IRQ RX transfer.
UART configuration structure type.
uint32_t lcr
Line Control.
uint32_t data_len
Number of bytes to transfer.
qm_dma_channel_direction_t channel_direction
DMA channel direction.
int qm_uart_read(const qm_uart_t uart, uint8_t *const data, qm_uart_status_t *status)
UART character data read.
uint32_t dlf
Divisor Latch Fraction.
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.
uint32_t ier
Interrupt Enable Register.
int qm_uart_write_buffer(const qm_uart_t uart, const uint8_t *const data, uint32_t len)
UART multi-byte data write.
void(* client_callback)(void *callback_context, uint32_t len, int error_code)
Client callback for DMA transfer ISR.