/** * @brief closes sci peripheral of interrupt driven driver * * calls tms570_sci_poll_last_close and disables interrupts * * @param[in] tty Termios control * @param[in] base context of the driver * @param[in] args * @retval false Error occured during initialization * @retval true Driver is open and ready */ static void tms570_sci_interrupt_last_close( rtems_termios_tty *tty, rtems_termios_device_context *base, rtems_libio_open_close_args_t *args ) { tms570_sci_context *ctx = (tms570_sci_context *) base; rtems_interrupt_lock_context lock_context; rtems_interval tw; int32_t baudrate; /* Turn off RX interrupts */ rtems_termios_device_lock_acquire(base, &lock_context); tms570_sci_disable_interrupts(ctx); rtems_termios_device_lock_release(base, &lock_context); tw = rtems_clock_get_ticks_per_second(); baudrate = rtems_termios_baud_to_number(cfgetospeed(&tty->termios)); tw = tw * 10 / baudrate + 1; while ( ( ctx->regs->FLR & TMS570_SCI_FLR_TX_EMPTY ) == 0 ) { rtems_task_wake_after(tw); } /* uninstall ISR */ rtems_interrupt_handler_remove(ctx->irq, tms570_sci_interrupt_handler, tty); tms570_sci_poll_last_close(tty, base, args); }
/* Handle UART interrupts */ static void apbuart_cons_isr(void *arg) { rtems_termios_tty *tty = arg; rtems_termios_device_context *base; struct console_dev *condev = rtems_termios_get_device_context(tty); struct apbuart_priv *uart = condev_get_priv(condev); struct apbuart_regs *regs = uart->regs; unsigned int status; char buf[33]; int cnt; if (uart->mode == TERMIOS_TASK_DRIVEN) { if ((status = regs->status) & APBUART_STATUS_DR) { rtems_interrupt_lock_context lock_context; /* Turn off RX interrupts */ base = rtems_termios_get_device_context(tty); rtems_termios_device_lock_acquire(base, &lock_context); regs->ctrl &= ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF); rtems_termios_device_lock_release(base, &lock_context); /* Activate termios RX daemon task */ rtems_termios_rxirq_occured(tty); } } else { /* * Get all new characters from APBUART RX (FIFO) and store them * on the stack. Then tell termios about the new characters. * Maximum APBUART RX FIFO size is 32 characters. */ cnt = 0; while ( ((status=regs->status) & APBUART_STATUS_DR) && (cnt < sizeof(buf)) ) { buf[cnt] = regs->data; cnt++; } if (0 < cnt) { /* Tell termios layer about new characters */ rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt); } } if (uart->sending && (status & APBUART_STATUS_TE)) { /* Tell close that we sent everything */ cnt = uart->sending; /* * Tell termios how much we have sent. dequeue() may call * write_interrupt() to refill the transmitter. * write_interrupt() will eventually be called with 0 len to * disable TX interrupts. */ rtems_termios_dequeue_characters(tty, cnt); } }
/** * @brief Set attributes of the HW peripheral * * Sets attributes of the HW peripheral (parity, baud rate, etc.) * * @param[in] base context of the driver * @param[in] t termios driver * @retval true peripheral setting is changed */ static bool tms570_sci_set_attributes( rtems_termios_device_context *base, const struct termios *t ) { tms570_sci_context *ctx = (tms570_sci_context *) base; rtems_interrupt_lock_context lock_context; int32_t bauddiv; int32_t baudrate; rtems_termios_device_lock_acquire(base, &lock_context); ctx->regs->GCR1 &= ~( TMS570_SCI_GCR1_SWnRST | TMS570_SCI_GCR1_TXENA | TMS570_SCI_GCR1_RXENA ); ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_STOP; /*one stop bit*/ ctx->regs->FORMAT = TMS570_SCI_FORMAT_CHAR(0x7); switch ( t->c_cflag & ( PARENB|PARODD ) ) { case ( PARENB|PARODD ): /* Odd parity */ ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_PARITY; ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY_ENA; break; case PARENB: /* Even parity */ ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY; ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY_ENA; break; default: case 0: case PARODD: /* No Parity */ ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_PARITY_ENA; } /* Baud rate */ baudrate = rtems_termios_baud_to_number(cfgetospeed(t)); baudrate *= 2 * 16; bauddiv = (BSP_PLL_OUT_CLOCK + baudrate / 2) / baudrate; ctx->regs->BRS = bauddiv; ctx->regs->GCR1 |= TMS570_SCI_GCR1_SWnRST | TMS570_SCI_GCR1_TXENA | TMS570_SCI_GCR1_RXENA; rtems_termios_device_lock_release(base, &lock_context); return true; }
/** * @brief Set attributes of the HW peripheral * * Sets attributes of the HW peripheral (parity, baud rate, etc.) * * @param[in] base context of the driver * @param[in] t termios driver * @retval true peripheral setting is changed */ static bool tms570_sci_set_attributes( rtems_termios_device_context *base, const struct termios *t ) { tms570_sci_context *ctx = (tms570_sci_context *) base; rtems_interrupt_lock_context lock_context; int32_t bauddiv; int32_t baudrate; rtems_termios_device_lock_acquire(base, &lock_context); ctx->regs->SCIGCR1 &= ~( (1<<7) | (1<<25) | (1<<24) ); ctx->regs->SCIGCR1 &= ~(1<<4); /*one stop bit*/ ctx->regs->SCIFORMAT = 0x7; switch ( t->c_cflag & ( PARENB|PARODD ) ) { case ( PARENB|PARODD ): /* Odd parity */ ctx->regs->SCIGCR1 &= ~(1<<3); ctx->regs->SCIGCR1 |= (1<<2); break; case PARENB: /* Even parity */ ctx->regs->SCIGCR1 |= (1<<3); ctx->regs->SCIGCR1 |= (1<<2); break; default: case 0: case PARODD: /* No Parity */ ctx->regs->SCIGCR1 &= ~(1<<2); } /* Baud rate */ baudrate = rtems_termios_baud_to_number(cfgetospeed(t)); baudrate *= 2 * 16; bauddiv = (BSP_PLL_OUT_CLOCK + baudrate / 2) / baudrate; ctx->regs->BRS = bauddiv; ctx->regs->SCIGCR1 |= (1<<7) | (1<<25) | (1<<24); rtems_termios_device_lock_release(base, &lock_context); return true; }
/* This function is called from TERMIOS rxdaemon task without device lock. */ static int read_task(rtems_termios_device_context *base) { rtems_interrupt_lock_context lock_context; struct apbuart_priv *uart = base_get_priv(base); struct apbuart_regs *regs = uart->regs; int cnt; char buf[33]; struct rtems_termios_tty *tty; uint32_t ctrl_add; ctrl_add = APBUART_CTRL_RI; if (uart->cap & CAP_DI) { ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF); } tty = uart->tty; do { cnt = 0; while ( (regs->status & APBUART_STATUS_DR) && (cnt < sizeof(buf)) ) { buf[cnt] = regs->data; cnt++; } if (0 < cnt) { /* Tell termios layer about new characters */ rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt); } /* * Turn on RX interrupts. A new character in FIFO now may not * cause interrupt so we must check data ready again * afterwards. */ rtems_termios_device_lock_acquire(base, &lock_context); regs->ctrl |= ctrl_add; rtems_termios_device_lock_release(base, &lock_context); } while (regs->status & APBUART_STATUS_DR); return EOF; }
static void apbuart_last_close_interrupt( rtems_termios_tty *tty, rtems_termios_device_context *base, rtems_libio_open_close_args_t *args ) { struct apbuart_context *uart = (struct apbuart_context *) base; rtems_interrupt_lock_context lock_context; /* Turn off RX interrupts */ rtems_termios_device_lock_acquire(base, &lock_context); uart->regs->ctrl &= ~(APBUART_CTRL_RI); rtems_termios_device_lock_release(base, &lock_context); /**** Flush device ****/ while (uart->sending) { /* Wait until all data has been sent */ } /* uninstall ISR */ rtems_interrupt_handler_remove(uart->irq, apbuart_isr, tty); }
static void last_close( rtems_termios_tty *tty, rtems_termios_device_context *base, rtems_libio_open_close_args_t *args ) { struct apbuart_priv *uart = base_get_priv(base); rtems_interrupt_lock_context lock_context; if (uart->mode != TERMIOS_POLLED) { /* Turn off RX interrupts */ rtems_termios_device_lock_acquire(base, &lock_context); uart->regs->ctrl &= ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF); rtems_termios_device_lock_release(base, &lock_context); /**** Flush device ****/ while (uart->sending) { /* Wait until all data has been sent */ } while ( (uart->regs->ctrl & APBUART_CTRL_TE) && !(uart->regs->status & APBUART_STATUS_TS) ) { /* Wait until all data has left shift register */ } /* Disable and unregister interrupt handler */ drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty); } #ifdef LEON3 /* Disable TX/RX if not used for DEBUG */ if (uart->regs != leon3_debug_uart) uart->regs->ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE); #endif }
/** * @brief closes sci peripheral of interrupt driven driver * * calls tms570_sci_poll_last_close and disables interrupts * * @param[in] tty Termios control * @param[in] base context of the driver * @param[in] args * @retval false Error occured during initialization * @retval true Driver is open and ready */ static void tms570_sci_interrupt_last_close( rtems_termios_tty *tty, rtems_termios_device_context *base, rtems_libio_open_close_args_t *args ) { tms570_sci_context *ctx = (tms570_sci_context *) base; rtems_interrupt_lock_context lock_context; /* Turn off RX interrupts */ rtems_termios_device_lock_acquire(base, &lock_context); tms570_sci_disable_interrupts(ctx); rtems_termios_device_lock_release(base, &lock_context); /* Flush device */ while ( ( ctx->regs->FLR & TMS570_SCI_FLR_TX_EMPTY ) > 0 ) { ;/* Wait until all data has been sent */ } /* uninstall ISR */ rtems_interrupt_handler_remove(ctx->irq, tms570_sci_interrupt_handler, tty); tms570_sci_poll_last_close(tty, base, args); }
static bool apbuart_set_attributes( rtems_termios_device_context *base, const struct termios *t ) { struct apbuart_context *uart = (struct apbuart_context *) base; rtems_interrupt_lock_context lock_context; unsigned int scaler; unsigned int ctrl; int baud; switch (t->c_cflag & CSIZE) { default: case CS5: case CS6: case CS7: /* Hardware doesn't support other than CS8 */ return false; case CS8: break; } rtems_termios_device_lock_acquire(base, &lock_context); /* Read out current value */ ctrl = uart->regs->ctrl; switch (t->c_cflag & (PARENB|PARODD)) { case (PARENB|PARODD): /* Odd parity */ ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS; break; case PARENB: /* Even parity */ ctrl &= ~APBUART_CTRL_PS; ctrl |= APBUART_CTRL_PE; break; default: case 0: case PARODD: /* No Parity */ ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE); } if (!(t->c_cflag & CLOCAL)) { ctrl |= APBUART_CTRL_FL; } else { ctrl &= ~APBUART_CTRL_FL; } /* Update new settings */ uart->regs->ctrl = ctrl; rtems_termios_device_lock_release(base, &lock_context); /* Baud rate */ baud = rtems_termios_baud_to_number(t->c_cflag); if (baud > 0) { /* Calculate Baud rate generator "scaler" number */ scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10; /* Set new baud rate by setting scaler */ uart->regs->scaler = scaler; } return true; }
static bool set_attributes( rtems_termios_device_context *base, const struct termios *t ) { unsigned int core_clk_hz; unsigned int scaler; unsigned int ctrl; int baud; struct apbuart_priv *uart = base_get_priv(base); rtems_interrupt_lock_context lock_context; switch(t->c_cflag & CSIZE) { default: case CS5: case CS6: case CS7: /* Hardware doesn't support other than CS8 */ return false; case CS8: break; } rtems_termios_device_lock_acquire(base, &lock_context); /* Read out current value */ ctrl = uart->regs->ctrl; switch(t->c_cflag & (PARENB|PARODD)){ case (PARENB|PARODD): /* Odd parity */ ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS; break; case PARENB: /* Even parity */ ctrl &= ~LEON_REG_UART_CTRL_PS; ctrl |= LEON_REG_UART_CTRL_PE; break; default: case 0: case PARODD: /* No Parity */ ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE); } if (!(t->c_cflag & CLOCAL)) ctrl |= LEON_REG_UART_CTRL_FL; else ctrl &= ~LEON_REG_UART_CTRL_FL; /* Update new settings */ uart->regs->ctrl = ctrl; rtems_termios_device_lock_release(base, &lock_context); /* Baud rate */ baud = apbuart_baud_num2baud(t->c_ospeed); if (baud > 0){ /* Get APBUART core frequency */ drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz); /* Calculate Baud rate generator "scaler" number */ scaler = (((core_clk_hz*10)/(baud*8))-5)/10; /* Set new baud rate by setting scaler */ uart->regs->scaler = scaler; } return true; }
/** * @brief Set attributes of the HW peripheral * * Sets attributes of the HW peripheral (parity, baud rate, etc.) * * @param[in] base context of the driver * @param[in] t termios driver * @retval true peripheral setting is changed */ bool tms570_sci_set_attributes( rtems_termios_device_context *base, const struct termios *t ) { tms570_sci_context *ctx = (tms570_sci_context *) base; rtems_interrupt_lock_context lock_context; int32_t bauddiv; int32_t baudrate; uint32_t flr_tx_ready = TMS570_SCI_FLR_TX_EMPTY; /* * Test for TMS570_SCI_FLR_TXRDY is not necessary * because both SCITD and SCITXSHF has to be empty * to TX_EMPTY be asserted. But there is no interrupt * option for TX_EMPTY. Polling is used isntead. */ /* Baud rate */ baudrate = rtems_termios_baud_to_number(cfgetospeed(t)); rtems_termios_device_lock_acquire(base, &lock_context); while ( (ctx->regs->GCR1 & TMS570_SCI_GCR1_TXENA) && (ctx->regs->FLR & flr_tx_ready) != flr_tx_ready) { /* * There are pending characters in the hardware, * change in the middle of the character Tx leads * to disturb of the character and SCI engine */ rtems_interval tw; rtems_termios_device_lock_release(base, &lock_context); tw = rtems_clock_get_ticks_per_second(); tw = tw * 5 / baudrate + 1; rtems_task_wake_after( tw ); rtems_termios_device_lock_acquire(base, &lock_context); } ctx->regs->GCR1 &= ~( TMS570_SCI_GCR1_SWnRST | TMS570_SCI_GCR1_TXENA | TMS570_SCI_GCR1_RXENA ); ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_STOP; /*one stop bit*/ ctx->regs->FORMAT = TMS570_SCI_FORMAT_CHAR(0x7); switch ( t->c_cflag & ( PARENB|PARODD ) ) { case ( PARENB|PARODD ): /* Odd parity */ ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_PARITY; ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY_ENA; break; case PARENB: /* Even parity */ ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY; ctx->regs->GCR1 |= TMS570_SCI_GCR1_PARITY_ENA; break; default: case 0: case PARODD: /* No Parity */ ctx->regs->GCR1 &= ~TMS570_SCI_GCR1_PARITY_ENA; } /* Apply baudrate to the hardware */ baudrate *= 2 * 16; bauddiv = (BSP_PLL_OUT_CLOCK + baudrate / 2) / baudrate; ctx->regs->BRS = bauddiv? bauddiv - 1: 0; ctx->regs->GCR1 |= TMS570_SCI_GCR1_SWnRST | TMS570_SCI_GCR1_TXENA | TMS570_SCI_GCR1_RXENA; rtems_termios_device_lock_release(base, &lock_context); return true; }