/** * version of printf that works better in exception context. * * @param format * * XXX If this function weren't in cvmx-interrupt.c, we'd use the SDK version. */ void cvmx_safe_printf(const char *format, ...) { char buffer[256]; char *ptr = buffer; int count; va_list args; va_start(args, format); #ifndef __U_BOOT__ count = vsnprintf(buffer, sizeof(buffer), format, args); #else count = vsprintf(buffer, format, args); #endif va_end(args); while (count-- > 0) { cvmx_uart_lsr_t lsrval; /* Spin until there is room */ do { lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); #if !defined(CONFIG_OCTEON_SIM_SPEED) if (lsrval.s.temt == 0) cvmx_wait(10000); /* Just to reduce the load on the system */ #endif } while (lsrval.s.temt == 0); if (*ptr == '\n') cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); } }
/** * version of printf that works better in exception context. * * @param format */ static void safe_printf(const char *format, ...) { static char buffer[256]; va_list args; va_start(args, format); int count = vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); char *ptr = buffer; while (count-- > 0) { cvmx_uart_lsr_t lsrval; /* Spin until there is room */ do { lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); if (lsrval.s.temt == 0) cvmx_wait(10000); /* Just to reduce the load on the system */ } while (lsrval.s.temt == 0); if (*ptr == '\n') cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); } }
/** * Get a single byte from serial port. * * @param uart_index Uart to read from (0 or 1) * @return The byte read */ inline uint8_t uart_read_byte_wait( int uart_index ) { /* Read and return the data. Will not be returned if there is no data */ if( !pci_console ) { cvmx_uart_lsr_t lsrval; while ( 1 ) { lsrval.u64 = cvmx_read_csr( CVMX_MIO_UARTX_LSR( uart_index ) ); if ( lsrval.s.dr ) { return cvmx_read_csr( CVMX_MIO_UARTX_RBR( uart_index ) ); } return getchar(); } } else { char c; while ( 1 ) { if ( !pci_cons_desc_addr ) { return 0; } octeon_pci_console_read(pci_cons_desc_addr, 0, &c, 1, 1); return c; } } }
int uart_read_byte_nowait( int uart_index ) { /* Read and return the data. Zero will be returned if there is no data */ if( !pci_console ) { cvmx_uart_lsr_t lsrval; lsrval.u64 = cvmx_read_csr( CVMX_MIO_UARTX_LSR( uart_index ) ); if ( lsrval.s.dr ) { return cvmx_read_csr( CVMX_MIO_UARTX_RBR( uart_index ) ); } else { return -1; } } else { char c; if ( !pci_cons_desc_addr ) { return 0; } octeon_pci_console_read(pci_cons_desc_addr, 0, &c, 1, 1); return c; } }
static int octeon_serial_tstc(void) { cvmx_uart_lsr_t lsrval; uint8_t uart_index = GET_UART_INDEX(gd->arch.console_uart); uint8_t node = GET_UART_NODE(gd->arch.console_uart); octeon_board_poll(); WATCHDOG_RESET(); lsrval.u64 = cvmx_read_csr_node(node, CVMX_MIO_UARTX_LSR(uart_index)); return lsrval.s.dr; }
/** * Wait for the TX buffer to be empty * * @param uart_index Uart to check */ void uart_wait_idle( int uart_index ) { cvmx_uart_lsr_t lsrval; // Spin until there is room do { lsrval.u64 = cvmx_read_csr( CVMX_MIO_UARTX_LSR( uart_index ) ); if ( lsrval.s.temt == 0 ) { cvmx_wait( 10000 ); // Just to reduce the load on the system } } while ( lsrval.s.temt == 0 ); }
/** * Put a single byte to uart port. * * @param uart_index Uart to write to (0 or 1) * @param ch Byte to write */ static inline void uart_write_byte(int uart, uint8_t ch) { cvmx_uart_lsr_t lsrval; uint8_t uart_index = GET_UART_INDEX(uart); uint8_t node = GET_UART_NODE(uart); /* Spin until there is room */ do { lsrval.u64 = cvmx_read_csr_node(node, CVMX_MIO_UARTX_LSR(uart_index)); } while (lsrval.s.thre == 0); WATCHDOG_RESET(); /* Write the byte */ cvmx_write_csr_node(node, CVMX_MIO_UARTX_THR(uart_index), ch); }
/** * Get a single byte from serial port. * * @param uart_index Uart to read from (0 or 1) * @return The byte read */ static inline uint8_t uart_read_byte(int uart) { cvmx_uart_lsr_t lsrval; uint8_t uart_index = GET_UART_INDEX(uart); uint8_t node = GET_UART_NODE(uart); /* Spin until data is available */ do { lsrval.u64 = cvmx_read_csr_node(node, CVMX_MIO_UARTX_LSR(uart_index)); WATCHDOG_RESET(); octeon_board_poll(); } while (!lsrval.s.dr); /* Read and return the data */ return cvmx_read_csr_node(node, CVMX_MIO_UARTX_RBR(uart_index)); }
/** * Put a single byte to uart port. * * @param uart_index Uart to write to (0 or 1) * @param ch Byte to write */ inline void uart_write_byte( int uart_index, uint8_t ch ) { if ( !pci_console ) { cvmx_uart_lsr_t lsrval; // Spin until there is room do { lsrval.u64 = cvmx_read_csr( CVMX_MIO_UARTX_LSR( uart_index ) ); if ( lsrval.s.thre == 0 ) { cvmx_wait( 10000 ); /* Just to reduce the load on the system */ } } while ( lsrval.s.thre == 0 ); // Write the byte cvmx_write_csr( CVMX_MIO_UARTX_THR( uart_index ), ch ); return; } else { char r = '\r'; if ( pci_cons_desc_addr ) { if (ch == '\n') octeon_pci_console_write(pci_cons_desc_addr, 0, &r, 1, OCT_PCI_CON_FLAG_NONBLOCK); octeon_pci_console_write(pci_cons_desc_addr, 0, (char *)&ch, 1, OCT_PCI_CON_FLAG_NONBLOCK); } else { printf( "pci_console read error\n" ); } } }
/** * Function that does the real work of setting up the Octeon uart. * Takes all parameters as arguments, so it does not require gd * structure to be set up. * * @param uart_index Index of uart to configure * @param cpu_clock_hertz * CPU clock frequency in Hz * @param baudrate Baudrate to configure * * @return 0 on success * !0 on error */ int octeon_uart_setup2(int uart, int cpu_clock_hertz, int baudrate) { uint16_t divisor; cvmx_uart_fcr_t fcrval; cvmx_uart_mcr_t mcrval; cvmx_uart_lcr_t lcrval; uint8_t uart_index = GET_UART_INDEX(uart); uint8_t node = GET_UART_NODE(uart); #if !CONFIG_OCTEON_SIM_SPEED uint64_t read_cycle; #endif fcrval.u64 = 0; fcrval.s.en = 1; /* enable the FIFO's */ fcrval.s.rxfr = 1; /* reset the RX fifo */ fcrval.s.txfr = 1; /* reset the TX fifo */ divisor = compute_divisor(cpu_clock_hertz, baudrate); cvmx_write_csr_node(node, CVMX_MIO_UARTX_FCR(uart_index), fcrval.u64); mcrval.u64 = 0; #if CONFIG_OCTEON_SIM_SETUP if (uart_index == 1) mcrval.s.afce = 1; /* enable auto flow control for * simulator. Needed for gdb * regression callfuncs.exp. */ else mcrval.s.afce = 0; /* disable auto flow control so board * can power on without serial port * connected */ #else mcrval.s.afce = 0; /* disable auto flow control so board can power * on without serial port connected */ #endif mcrval.s.rts = 1; /* looks like this must be set for auto flow * control to work */ cvmx_read_csr_node(node, CVMX_MIO_UARTX_LSR(uart_index)); lcrval.u64 = 0; lcrval.s.cls = CVMX_UART_BITS8; lcrval.s.stop = 0; /* stop bit included? */ lcrval.s.pen = 0; /* no parity? */ lcrval.s.eps = 1; /* even parity? */ lcrval.s.dlab = 1; /* temporary to program the divisor */ cvmx_write_csr_node(node, CVMX_MIO_UARTX_LCR(uart_index), lcrval.u64); cvmx_write_csr_node(node, CVMX_MIO_UARTX_DLL(uart_index), divisor & 0xff); cvmx_write_csr_node(node, CVMX_MIO_UARTX_DLH(uart_index), (divisor >> 8) & 0xff); /* divisor is programmed now, set this back to normal */ lcrval.s.dlab = 0; cvmx_write_csr_node(node, CVMX_MIO_UARTX_LCR(uart_index), lcrval.u64); #if !CONFIG_OCTEON_SIM_SPEED /* spec says need to wait after you program the divisor */ read_cycle = octeon_get_cycles() + (2 * divisor * 16) + 10000; while (octeon_get_cycles() < read_cycle) { /* Spin */ } #endif /* Don't enable flow control until after baud rate is configured. - we * don't want to allow characters in until after the baud rate is * fully configured */ cvmx_write_csr_node(node, CVMX_MIO_UARTX_MCR(uart_index), mcrval.u64); return 0; }