static int uart_octeon_probe(device_t dev) { struct uart_softc *sc; int unit; unit = device_get_unit(dev); sc = device_get_softc(dev); sc->sc_class = &uart_oct16550_class; /* * We inherit the settings from the systme console. Note, the bst * bad bus_space_map are bogus here, but obio doesn't yet support * them, it seems. */ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_bas.bst = uart_bus_space_mem; /* * XXX * RBR isn't really a great base address. */ if (bus_space_map(sc->sc_bas.bst, CVMX_MIO_UARTX_RBR(0), uart_getrange(sc->sc_class), 0, &sc->sc_bas.bsh) != 0) return (ENXIO); return (uart_bus_probe(dev, sc->sc_bas.regshft, 0, 0, unit)); }
/** * 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 struct resource * obio_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct resource *rv; struct rman *rm; bus_space_tag_t bt = 0; bus_space_handle_t bh = 0; struct obio_softc *sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: switch (device_get_unit(child)) { case 0: start = end = OCTEON_IRQ_UART0; break; case 1: start = end = OCTEON_IRQ_UART1; break; default: return (NULL); } rm = &sc->oba_irq_rman; break; case SYS_RES_MEMORY: return (NULL); case SYS_RES_IOPORT: rm = &sc->oba_rman; bt = &octeon_uart_tag; bh = CVMX_MIO_UARTX_RBR(device_get_unit(child)); start = bh; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { return (NULL); } if (type == SYS_RES_IRQ) { return (rv); } rman_set_rid(rv, *rid); rman_set_bustag(rv, bt); rman_set_bushandle(rv, bh); if (0) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); }
/** * 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)); }
static int obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); sc->oba_st = mips_bus_space_generic; /* * XXX * Here and elsewhere using RBR as a base address because it kind of * is, but that feels pretty sloppy. Should consider adding a define * that's more semantic, at least. */ sc->oba_addr = CVMX_MIO_UARTX_RBR(0); sc->oba_size = 0x10000; sc->oba_rman.rm_type = RMAN_ARRAY; sc->oba_rman.rm_descr = "OBIO I/O"; if (rman_init(&sc->oba_rman) != 0 || rman_manage_region(&sc->oba_rman, sc->oba_addr, sc->oba_addr + sc->oba_size) != 0) panic("obio_attach: failed to set up I/O rman"); sc->oba_irq_rman.rm_type = RMAN_ARRAY; sc->oba_irq_rman.rm_descr = "OBIO IRQ"; /* * This module is intended for UART purposes only and * manages IRQs for UART0 and UART1. */ if (rman_init(&sc->oba_irq_rman) != 0 || rman_manage_region(&sc->oba_irq_rman, OCTEON_IRQ_UART0, OCTEON_IRQ_UART1) != 0) panic("obio_attach: failed to set up IRQ rman"); device_add_child(dev, "uart", 1); /* Setup Uart-1 first. */ device_add_child(dev, "uart", 0); /* Uart-0 next. So it is first in console list */ bus_generic_probe(dev); bus_generic_attach(dev); return (0); }
static int __init octeon_serial_init(void) { int enable_uart0; int enable_uart1; int enable_uart2; struct plat_serial8250_port *p; #ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL /* * If we are configured to run as the second of two kernels, * disable uart0 and enable uart1. Uart0 is owned by the first * kernel */ enable_uart0 = 0; enable_uart1 = 1; #else /* * We are configured for the first kernel. We'll enable uart0 * if the bootloader told us to use 0, otherwise will enable * uart 1. */ enable_uart0 = (octeon_get_boot_uart() == 0); enable_uart1 = (octeon_get_boot_uart() == 1); #ifdef CONFIG_KGDB enable_uart1 = 1; #endif #endif /* Right now CN52XX is the only chip with a third uart */ enable_uart2 = OCTEON_IS_MODEL(OCTEON_CN52XX); p = octeon_uart8250_data; if (enable_uart0) { /* Add a ttyS device for hardware uart 0 */ octeon_uart_set_common(p); p->membase = (void *) CVMX_MIO_UARTX_RBR(0); p->mapbase = CVMX_MIO_UARTX_RBR(0) & ((1ull << 49) - 1); p->irq = OCTEON_IRQ_UART0; p++; } if (enable_uart1) { /* Add a ttyS device for hardware uart 1 */ octeon_uart_set_common(p); p->membase = (void *) CVMX_MIO_UARTX_RBR(1); p->mapbase = CVMX_MIO_UARTX_RBR(1) & ((1ull << 49) - 1); p->irq = OCTEON_IRQ_UART1; p++; } if (enable_uart2) { /* Add a ttyS device for hardware uart 2 */ octeon_uart_set_common(p); p->membase = (void *) CVMX_MIO_UART2_RBR; p->mapbase = CVMX_MIO_UART2_RBR & ((1ull << 49) - 1); p->irq = OCTEON_IRQ_UART2; p++; } BUG_ON(p > &octeon_uart8250_data[OCTEON_MAX_UARTS]); return platform_device_register(&octeon_uart8250_device); }