__initfunc(static enum uart check_uart(unsigned int iobase)) { unsigned char b1,b2,b3; enum uart u; enum uart uart_tab[] = { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; if (iobase <= 0 || iobase > 0x1000-SER_EXTENT) return c_uart_unknown; if (check_region(iobase, SER_EXTENT)) return c_uart_unknown; b1 = inb(UART_MCR(iobase)); outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */ b2 = inb(UART_MSR(iobase)); outb(0x1a, UART_MCR(iobase)); b3 = inb(UART_MSR(iobase)) & 0xf0; outb(b1, UART_MCR(iobase)); /* restore old values */ outb(b2, UART_MSR(iobase)); if (b3 != 0x90) return c_uart_unknown; inb(UART_RBR(iobase)); inb(UART_RBR(iobase)); outb(0x01, UART_FCR(iobase)); /* enable FIFOs */ u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3]; if (u == c_uart_16450) { outb(0x5a, UART_SCR(iobase)); b1 = inb(UART_SCR(iobase)); outb(0xa5, UART_SCR(iobase)); b2 = inb(UART_SCR(iobase)); if ((b1 != 0x5a) || (b2 != 0xa5)) u = c_uart_8250; } return u; }
/* * This Function Wait until Data RX Ready, and return Data Read from UART. */ uint8_t uart_read_timeout(uart_num_t uart_num, uint32_t rx_timeout_nb_cycles, uart_error_t* error) { uint32_t uart_port; uint8_t uart_val; uint32_t counter; uart_port = uart_num; /* Wait Until Data Received (Rx Data Not Ready) */ counter = 0; while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0) { if (rx_timeout_nb_cycles>0) { counter++; if (counter>=rx_timeout_nb_cycles) { *error = UART_TIMEOUT_ERROR; return 0; } } } uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT); /* Clear error */ *error = UART_NO_ERROR; return uart_val; }
/* * This Function Wait until Data RX Ready, and return Data Read from UART. */ uint8_t uart_read(uart_num_t uart_num) { uint32_t uart_port; uint8_t uart_val; uart_port = uart_num; /* Wait Until Data Received (Rx Data Not Ready) */ while ((UART_LSR(uart_port) & UART_LSR_RDR) == 0); uart_val = (UART_RBR(uart_port) & UART_RBR_MASKBIT); return uart_val; }
/* * This is the serial driver's generic interrupt routine * Note: Generally it should be attached to general interrupt 10, responsile * for UART0&1 RCV and XMT interrupt, to make sure the invoked interrupt * source, look into bit 10-13 of SIC_ISR(peripheral interrupt status reg. * Finally, to see what can be done about request_irq(......) */ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct bf535_serial *info; // = &bf535_soft[CONFIG_SERIAL_CONSOLE_PORT]; unsigned short iir; /* Interrupt Identification Register */ unsigned short rx, idx; unsigned int sic_status = SIC_ISR; for (idx = 0; idx < NR_PORTS; idx++){ if (sic_status & (UART_INVOKED << 2*(idx + 5))){ /* test bit 10-11 and 12-13 */ iir = UART_IIR(idx); info = &bf535_soft[idx]; if (!(iir & UART_IIR_NOINT)){ switch (iir & UART_IIR_STATUS){ case UART_IIR_LSR: printk("Line status changed for serial port %d.\n", idx); break; case UART_IIR_RBR: /* Change access to IER & data port */ ACCESS_PORT_IER(idx) if (UART_LSR(idx) & UART_LSR_DR){ rx = UART_RBR(idx); receive_chars(info, regs, rx); } break; case UART_IIR_THR: /* Change access to IER & data port */ ACCESS_PORT_IER(idx) if (UART_LSR(idx) & UART_LSR_THRE){ transmit_chars(info); // do{ // transmit_chars(info); // }while(info->xmit_cnt > 0); } break; case UART_IIR_MSR: printk("Modem status changed for serial port.\n"); } } } }
int GetUARTBytes(u8 *buf, u32 size, u32 tmo_ms) { u32 LSR; int tmo_en = (tmo_ms) ? 1 : 0; ulong start_time = get_timer(0); while (size) { if (tmo_en && (get_timer(start_time) > tmo_ms)) break; /* kick watchdog to avoid cpu reset */ if (!tmo_en) platform_wdt_kick(); LSR = UART_READ32(UART_LSR(g_uart)); if (LSR & UART_LSR_DR) { *buf++ = (u8)UART_READ32(UART_RBR(g_uart)); size--; } } return (0 == size) ? 0 : -1; }
int serial_nonblock_getc(void) { return (int)UART_READ32(UART_RBR(g_uart)); }
/* * UART Init function */ void uart_init(uart_num_t uart_num, uart_databit_t data_nb_bits, uart_stopbit_t data_nb_stop, uart_parity_t data_parity, uint16_t uart_divisor, uint8_t uart_divaddval, uint8_t uart_mulval) { uint32_t lcr_config; uint32_t uart_port; uart_port = uart_num; switch(uart_num) { case UART0_NUM: /* use PLL1 as clock source for UART0 */ CGU_BASE_UART0_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART1_NUM: /* use PLL1 as clock source for UART1 */ CGU_BASE_UART1_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART2_NUM: /* use PLL1 as clock source for UART2 */ CGU_BASE_UART2_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; case UART3_NUM: /* use PLL1 as clock source for UART3 */ CGU_BASE_UART3_CLK = (CGU_SRC_PLL1<<UART_CGU_BASE_CLK_SEL_SHIFT) | (1<<UART_CGU_AUTOBLOCK_CLOCK_BIT); break; default: return; /* error */ } /* FIFOs RX/TX Enabled and Reset RX/TX FIFO (DMA Mode is also cleared) */ UART_FCR(uart_port) = ( UART_FCR_FIFO_EN | UART_FCR_RX_RS | UART_FCR_TX_RS); /* Disable FIFO */ UART_FCR(uart_port) = 0; // Dummy read (to clear existing data) while (UART_LSR(uart_port) & UART_LSR_RDR ) { dummy_read = UART_RBR(uart_port); } /* Wait end of TX & disable TX */ UART_TER(uart_port) = UART_TER_TXEN; /* Wait for current transmit complete */ while (!(UART_LSR(uart_port) & UART_LSR_THRE)); /* Disable Tx */ UART_TER(uart_port) = 0; /* Disable interrupt */ UART_IER(uart_port) = 0; /* Set LCR to default state */ UART_LCR(uart_port) = 0; /* Set ACR to default state */ UART_ACR(uart_port) = 0; /* Dummy Read to Clear Status */ dummy_read = UART_LSR(uart_port); /* Table 835. USART Fractional Divider Register: UARTbaudrate = PCLK / ( 16* (((256*DLM)+ DLL)*(1+(DivAddVal/MulVal))) ) The value of MULVAL and DIVADDVAL should comply to the following conditions: 1. 1 <= MULVAL <= 15 2. 0 <= DIVADDVAL <= 14 3. DIVADDVAL < MULVAL */ /* Set DLAB Bit */ UART_LCR(uart_port) |= UART_LCR_DLAB_EN; UART_DLM(uart_port) = UART_LOAD_DLM(uart_divisor); UART_DLL(uart_port) = UART_LOAD_DLL(uart_divisor); /* Clear DLAB Bit */ UART_LCR(uart_port) &= (~UART_LCR_DLAB_EN) & UART_LCR_BITMASK; UART_FDR(uart_port) = (UART_FDR_MULVAL(uart_mulval) | UART_FDR_DIVADDVAL(uart_divaddval)) & UART_FDR_BITMASK; /* Read LCR config & Force Enable of Divisor Latches Access */ lcr_config = (UART_LCR(uart_port) & UART_LCR_DLAB_EN) & UART_LCR_BITMASK; lcr_config |= data_nb_bits; /* Set Nb Data Bits */ lcr_config |= data_nb_stop; /* Set Nb Stop Bits */ lcr_config |= data_parity; /* Set Data Parity */ /* Write LCR (only 8bits) */ UART_LCR(uart_port) = (lcr_config & UART_LCR_BITMASK); /* Enable TX */ UART_TER(uart_port) = UART_TER_TXEN; }
static _INLINE_ void receive_chars(struct bf535_serial *info, struct pt_regs *regs, unsigned short rx) { struct tty_struct *tty = info->tty; unsigned char ch; int idx = info->hub2; /* * This do { } while() loop will get ALL chars out of Rx FIFO */ do { ch = (unsigned char) rx; if(info->is_cons) { if (UART_LSR(idx) & UART_LSR_BI){ /* break received */ status_handle(info, UART_LSR(idx)); return; } else if (ch == 0x10) { /* ^P */ show_state(); show_free_areas(); show_buffers(); /* show_net_buffers(); */ return; } else if (ch == 0x12) { /* ^R */ machine_restart(NULL); return; } } if(!tty){ printk("no tty\n"); goto clear_and_exit; } /* * Make sure that we do not overflow the buffer */ if (tty->flip.count >= TTY_FLIPBUF_SIZE) { queue_task(&tty->flip.tqueue, &tq_timer); return; } if(UART_LSR(idx) & UART_LSR_PE) { *tty->flip.flag_buf_ptr++ = TTY_PARITY; status_handle(info, UART_LSR(idx)); } else if(UART_LSR(idx) & UART_LSR_OE) { *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; status_handle(info, UART_LSR(idx)); } else if(UART_LSR(idx) & UART_LSR_FE) { *tty->flip.flag_buf_ptr++ = TTY_FRAME; status_handle(info, UART_LSR(idx)); } else { *tty->flip.flag_buf_ptr++ = 0; /* XXX */ } tty->flip.count++; *tty->flip.char_buf_ptr++ = ch; ACCESS_PORT_IER(idx) /* change access to port data */ rx = UART_RBR(idx); } while(UART_LSR(idx) & UART_LSR_DR); queue_task(&tty->flip.tqueue, &tq_timer); clear_and_exit: return; }