📄 bfin_5xx.c
字号:
uart->tx_count = UART_XMIT_SIZE - xmit->tail; blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail), (unsigned long)(xmit->buf+xmit->tail+uart->tx_count)); set_dma_config(uart->tx_dma_channel, set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP, INTR_ON_BUF, DIMENSION_LINEAR, DATA_SIZE_8)); set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail)); set_dma_x_count(uart->tx_dma_channel, uart->tx_count); set_dma_x_modify(uart->tx_dma_channel, 1); enable_dma(uart->tx_dma_channel);#ifdef CONFIG_BF54x UART_SET_IER(uart, ETBEI);#else ier = UART_GET_IER(uart); ier |= ETBEI; UART_PUT_IER(uart, ier);#endif spin_unlock_irqrestore(&uart->port.lock, flags);}static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart){ struct tty_struct *tty = uart->port.info->tty; int i, flg, status; status = UART_GET_LSR(uart); uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);; if (status & BI) { uart->port.icount.brk++; if (uart_handle_break(&uart->port)) goto dma_ignore_char; status &= ~(PE | FE); } if (status & PE) uart->port.icount.parity++; if (status & OE) uart->port.icount.overrun++; if (status & FE) uart->port.icount.frame++; status &= uart->port.read_status_mask; if (status & BI) flg = TTY_BREAK; else if (status & PE) flg = TTY_PARITY; else if (status & FE) flg = TTY_FRAME; else flg = TTY_NORMAL; for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) { if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i])) goto dma_ignore_char; uart_insert_char(&uart->port, status, OE, uart->rx_dma_buf.buf[i], flg); } dma_ignore_char: tty_flip_buffer_push(tty);}void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart){ int x_pos, pos; int flags = 0; bfin_serial_dma_tx_chars(uart); spin_lock_irqsave(&uart->port.lock, flags); x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel); if (x_pos == DMA_RX_XCOUNT) x_pos = 0; pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos; if (pos>uart->rx_dma_buf.tail) { uart->rx_dma_buf.tail = pos; bfin_serial_dma_rx_chars(uart); uart->rx_dma_buf.head = uart->rx_dma_buf.tail; } spin_unlock_irqrestore(&uart->port.lock, flags); uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; add_timer(&(uart->rx_dma_timer));}static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id){ struct bfin_serial_port *uart = dev_id; struct circ_buf *xmit = &uart->port.info->xmit; unsigned short ier; spin_lock(&uart->port.lock); if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) { clear_dma_irqstat(uart->tx_dma_channel); disable_dma(uart->tx_dma_channel);#ifdef CONFIG_BF54x UART_CLEAR_IER(uart, ETBEI);#else ier = UART_GET_IER(uart); ier &= ~ETBEI; UART_PUT_IER(uart, ier);#endif xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1); uart->port.icount.tx+=uart->tx_count; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uart->port); if (uart_circ_empty(xmit)) bfin_serial_stop_tx(&uart->port); uart->tx_done = 1; } spin_unlock(&uart->port.lock); return IRQ_HANDLED;}static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id){ struct bfin_serial_port *uart = dev_id; unsigned short irqstat; uart->rx_dma_nrows++; if (uart->rx_dma_nrows == DMA_RX_YCOUNT) { uart->rx_dma_nrows = 0; uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT; bfin_serial_dma_rx_chars(uart); uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0; } spin_lock(&uart->port.lock); irqstat = get_dma_curr_irqstat(uart->rx_dma_channel); clear_dma_irqstat(uart->rx_dma_channel); spin_unlock(&uart->port.lock); return IRQ_HANDLED;}#endif/* * Return TIOCSER_TEMT when transmitter is not busy. */static unsigned int bfin_serial_tx_empty(struct uart_port *port){ struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned short lsr; lsr = UART_GET_LSR(uart); if (lsr & TEMT) return TIOCSER_TEMT; else return 0;}static unsigned int bfin_serial_get_mctrl(struct uart_port *port){#ifdef CONFIG_SERIAL_BFIN_CTSRTS struct bfin_serial_port *uart = (struct bfin_serial_port *)port; if (uart->cts_pin < 0) return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; if (gpio_get_value(uart->cts_pin)) return TIOCM_DSR | TIOCM_CAR; else#endif return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;}static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl){#ifdef CONFIG_SERIAL_BFIN_CTSRTS struct bfin_serial_port *uart = (struct bfin_serial_port *)port; if (uart->rts_pin < 0) return; if (mctrl & TIOCM_RTS) gpio_set_value(uart->rts_pin, 0); else gpio_set_value(uart->rts_pin, 1);#endif}/* * Handle any change of modem status signal since we were last called. */static void bfin_serial_mctrl_check(struct bfin_serial_port *uart){#ifdef CONFIG_SERIAL_BFIN_CTSRTS unsigned int status;# ifdef CONFIG_SERIAL_BFIN_DMA struct uart_info *info = uart->port.info; struct tty_struct *tty = info->tty; status = bfin_serial_get_mctrl(&uart->port); if (!(status & TIOCM_CTS)) { tty->hw_stopped = 1; } else { tty->hw_stopped = 0; }# else status = bfin_serial_get_mctrl(&uart->port); uart_handle_cts_change(&uart->port, status & TIOCM_CTS); if (!(status & TIOCM_CTS)) schedule_work(&uart->cts_workqueue);# endif#endif}/* * Interrupts are always disabled. */static void bfin_serial_break_ctl(struct uart_port *port, int break_state){ struct bfin_serial_port *uart = (struct bfin_serial_port *)port; u16 lcr = UART_GET_LCR(uart); if (break_state) lcr |= SB; else lcr &= ~SB; UART_PUT_LCR(uart, lcr); SSYNC();}static int bfin_serial_startup(struct uart_port *port){ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;#ifdef CONFIG_SERIAL_BFIN_DMA dma_addr_t dma_handle; if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) { printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n"); return -EBUSY; } if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) { printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n"); free_dma(uart->rx_dma_channel); return -EBUSY; } set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart); set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart); uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA); uart->rx_dma_buf.head = 0; uart->rx_dma_buf.tail = 0; uart->rx_dma_nrows = 0; set_dma_config(uart->rx_dma_channel, set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO, INTR_ON_ROW, DIMENSION_2D, DATA_SIZE_8)); set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT); set_dma_x_modify(uart->rx_dma_channel, 1); set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT); set_dma_y_modify(uart->rx_dma_channel, 1); set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf); enable_dma(uart->rx_dma_channel); uart->rx_dma_timer.data = (unsigned long)(uart); uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout; uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES; add_timer(&(uart->rx_dma_timer));#else if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED, "BFIN_UART_RX", uart)) {# ifdef CONFIG_KGDB_UART if (uart->port.line != CONFIG_KGDB_UART_PORT) {# endif printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n"); return -EBUSY;# ifdef CONFIG_KGDB_UART }# endif } if (request_irq (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED, "BFIN_UART_TX", uart)) { printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n"); free_irq(uart->port.irq, uart); return -EBUSY; }#endif#ifdef CONFIG_BF54x UART_SET_IER(uart, ERBFI);#else UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);#endif return 0;}static void bfin_serial_shutdown(struct uart_port *port){ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;#ifdef CONFIG_SERIAL_BFIN_DMA disable_dma(uart->tx_dma_channel); free_dma(uart->tx_dma_channel); disable_dma(uart->rx_dma_channel); free_dma(uart->rx_dma_channel); del_timer(&(uart->rx_dma_timer));#else#ifdef CONFIG_KGDB_UART if (uart->port.line != CONFIG_KGDB_UART_PORT)#endif free_irq(uart->port.irq, uart); free_irq(uart->port.irq+1, uart);#endif}static voidbfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old){ struct bfin_serial_port *uart = (struct bfin_serial_port *)port; unsigned long flags; unsigned int baud, quot; unsigned short val, ier, lsr, lcr = 0; switch (termios->c_cflag & CSIZE) { case CS8: lcr = WLS(8); break; case CS7: lcr = WLS(7); break; case CS6: lcr = WLS(6); break; case CS5: lcr = WLS(5); break; default: printk(KERN_ERR "%s: word lengh not supported\n", __FUNCTION__); } if (termios->c_cflag & CSTOPB) lcr |= STB; if (termios->c_cflag & PARENB) lcr |= PEN; if (!(termios->c_cflag & PARODD)) lcr |= EPS; if (termios->c_cflag & CMSPAR) lcr |= STP; port->read_status_mask = OE; if (termios->c_iflag & INPCK) port->read_status_mask |= (FE | PE); if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= BI; /* * Characters to ignore */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= FE | PE; if (termios->c_iflag & IGNBRK) { port->ignore_status_mask |= BI; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= OE; } baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); quot = uart_get_divisor(port, baud); spin_lock_irqsave(&uart->port.lock, flags); do { lsr = UART_GET_LSR(uart); } while (!(lsr & TEMT)); /* Disable UART */ ier = UART_GET_IER(uart);#ifdef CONFIG_BF54x UART_CLEAR_IER(uart, 0xF);#else UART_PUT_IER(uart, 0);#endif#ifndef CONFIG_BF54x /* Set DLAB in LCR to Access DLL and DLH */ val = UART_GET_LCR(uart); val |= DLAB; UART_PUT_LCR(uart, val); SSYNC();#endif UART_PUT_DLL(uart, quot & 0xFF); SSYNC(); UART_PUT_DLH(uart, (quot >> 8) & 0xFF); SSYNC();#ifndef CONFIG_BF54x /* Clear DLAB in LCR to Access THR RBR IER */ val = UART_GET_LCR(uart); val &= ~DLAB; UART_PUT_LCR(uart, val); SSYNC();#endif UART_PUT_LCR(uart, lcr); /* Enable UART */#ifdef CONFIG_BF54x UART_SET_IER(uart, ier);#else UART_PUT_IER(uart, ier);#endif val = UART_GET_GCTL(uart); val |= UCEN; UART_PUT_GCTL(uart, val); spin_unlock_irqrestore(&uart->port.lock, flags);}static const char *bfin_serial_type(struct uart_port *port){ struct bfin_serial_port *uart = (struct bfin_serial_port *)port; return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;}/* * Release the memory region(s) being used by 'port'. */static void bfin_serial_release_port(struct uart_port *port)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -