static void omap_uart_putc_sleepable(struct omap_uart_port *port, u8 ch) { /* Wait until there is space in the FIFO */ if (!omap_uart_lowlevel_can_putc(port->base, port->reg_align)) { /* Enable the TX interrupt */ port->ier |= UART_IER_THRI; omap_serial_out(port, UART_IER, port->ier); /* Wait for completion */ vmm_completion_wait(&port->write_possible); } /* Write data to FIFO */ omap_serial_out(port, UART_THR, ch); }
static vmm_irq_return_t omap_uart_irq_handler(int irq_no, void *dev) { u16 iir, lsr; struct omap_uart_port *port = (struct omap_uart_port *)dev; iir = omap_serial_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) return VMM_IRQ_NONE; lsr = omap_serial_in(port, UART_LSR); /* Handle RX FIFO not empty */ if (iir & (UART_IIR_RLSI | UART_IIR_RTO | UART_IIR_RDI)) { if (lsr & UART_LSR_DR) { do { u8 ch = omap_serial_in(port, UART_RBR); serial_rx(port->p, &ch, 1); } while (omap_serial_in(port, UART_LSR) & (UART_LSR_DR | UART_LSR_OE)); } else if (lsr & (UART_LSR_OE | \ UART_LSR_PE | \ UART_LSR_BI | UART_LSR_FE) ) { while (1); } } omap_serial_out(port, UART_IER, port->ier); return VMM_IRQ_HANDLED; }
static vmm_irq_return_t omap_uart_irq_handler(int irq_no, void *dev) { u16 iir, lsr; struct omap_uart_port *port = (struct omap_uart_port *)dev; iir = omap_serial_in(port, UART_IIR); if (iir & UART_IIR_NO_INT) return VMM_IRQ_NONE; lsr = omap_serial_in(port, UART_LSR); /* Handle RX FIFO not empty */ if (iir & (UART_IIR_RLSI | UART_IIR_RTO | UART_IIR_RDI)) { if (lsr & UART_LSR_DR) { /* Mask RX interrupts till RX FIFO is empty */ port->ier &= ~(UART_IER_RDI | UART_IER_RLSI); /* Signal work completion to sleeping thread */ vmm_completion_complete(&port->read_possible); } else if (lsr & (UART_LSR_OE | UART_LSR_PE | UART_LSR_BI | UART_LSR_FE) ) { while(1); } } /* Handle TX FIFO not full */ if ((lsr & UART_LSR_THRE) && (iir & UART_IIR_THRI)) { /* Mask TX interrupts till TX FIFO is full */ port->ier &= ~UART_IER_THRI; /* Signal work completion to sleeping thread */ vmm_completion_complete(&port->write_possible); } omap_serial_out(port, UART_IER, port->ier); return VMM_IRQ_HANDLED; }
static u8 omap_uart_getc_sleepable(struct omap_uart_port *port) { /* Wait until there is data in the FIFO */ if (!(omap_serial_in(port, UART_LSR) & UART_LSR_DR)) { /* Enable the RX interrupt */ port->ier |= (UART_IER_RDI | UART_IER_RLSI); omap_serial_out(port, UART_IER, port->ier); /* Wait for completion */ vmm_completion_wait(&port->read_possible); } /* Read data to destination */ return (omap_serial_in(port, UART_RBR)); }
static int omap_uart_driver_remove(struct vmm_device *dev) { struct omap_uart_port *port = dev->priv; if (!port) { return VMM_OK; } /* Mask Rx interrupt */ port->ier &= ~(UART_IER_RDI | UART_IER_RLSI); omap_serial_out(port, UART_IER, port->ier); /* Free-up resources */ serial_destroy(port->p); vmm_host_irq_unregister(port->irq, port); vmm_devtree_regunmap_release(dev->of_node, port->base, 0); vmm_free(port); dev->priv = NULL; return VMM_OK; }
void omap_uart_lowlevel_putc(virtual_addr_t base, u32 reg_align, u8 ch) { while (!omap_uart_lowlevel_can_putc(base, reg_align)); omap_serial_out(UART_THR, ch); }
static int omap_uart_startup_configure(struct omap_uart_port *port) { u16 bdiv, cval; bdiv = udiv32(port->input_clock, (16 * port->baudrate)); /* * Clear the FIFO buffers and disable them. */ omap_serial_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); omap_serial_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); omap_serial_out(port, UART_FCR, 0); /* * Clear the interrupt registers. */ (void) omap_serial_in(port, UART_LSR); if (omap_serial_in(port, UART_LSR) & UART_LSR_DR) (void) omap_serial_in(port, UART_RBR); (void) omap_serial_in(port, UART_IIR); (void) omap_serial_in(port, UART_MSR); cval = UART_LCR_WLEN8; /* * Now, initialize the UART */ omap_serial_out(port, UART_LCR, cval); /* * Finally, enable interrupts */ port->ier = UART_IER_RLSI | UART_IER_RDI; omap_serial_out(port, UART_IER, port->ier); /* Enable module level wake port */ omap_serial_out(port, UART_OMAP_WER, OMAP_UART_WER_MOD_WKUP); port->fcr = UART_FCR_R_TRIG_01 | UART_FCR_T_TRIG_01 | UART_FCR_ENABLE_FIFO; port->ier &= ~UART_IER_MSI; omap_serial_out(port, UART_IER, port->ier); omap_serial_out(port, UART_LCR, cval); /* reset DLAB */ /* FCR can be changed only when the * baud clock is not running * DLL_REG and DLH_REG set to 0. */ omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_A); omap_serial_out(port, UART_DLL, 0); omap_serial_out(port, UART_DLM, 0); omap_serial_out(port, UART_LCR, 0); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_B); port->efr = omap_serial_in(port, UART_EFR); omap_serial_out(port, UART_EFR, port->efr | UART_EFR_ECB); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_A); port->mcr = omap_serial_in(port, UART_MCR); omap_serial_out(port, UART_MCR, port->mcr | UART_MCR_TCRTLR); /* FIFO ENABLE, DMA MODE */ omap_serial_out(port, UART_FCR, port->fcr); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_B); omap_serial_out(port, UART_EFR, port->efr); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_A); omap_serial_out(port, UART_MCR, port->mcr); /* Protocol, Baud Rate, and Interrupt Settings */ omap_serial_out(port, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_B); port->efr = omap_serial_in(port, UART_EFR); omap_serial_out(port, UART_EFR, port->efr | UART_EFR_ECB); omap_serial_out(port, UART_LCR, 0); omap_serial_out(port, UART_IER, 0); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_B); omap_serial_out(port, UART_DLL, bdiv & 0xff); /* LS of divisor */ omap_serial_out(port, UART_DLM, bdiv >> 8); /* MS of divisor */ omap_serial_out(port, UART_LCR, 0); omap_serial_out(port, UART_IER, port->ier); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_B); omap_serial_out(port, UART_EFR, port->efr); omap_serial_out(port, UART_LCR, cval); omap_serial_out(port, UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE); omap_serial_out(port, UART_MCR, port->mcr); uart_configure_xonxoff(port); return VMM_OK; }
void uart_configure_xonxoff(struct omap_uart_port *port) { u16 efr; port->lcr = omap_serial_in(port, UART_LCR); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_B); port->efr = omap_serial_in(port, UART_EFR); omap_serial_out(port, UART_EFR, port->efr & ~UART_EFR_ECB); omap_serial_out(port, UART_XON1, 0x11); omap_serial_out(port, UART_XOFF1, 0x13); /* clear SW control mode bits */ efr = port->efr; efr &= OMAP_UART_SW_CLR; #if 0 /* Enable if required */ /* * IXON Flag: * Enable XON/XOFF flow control on output. * Transmit XON1, XOFF1 */ efr |= OMAP_UART_SW_TX; /* * IXOFF Flag: * Enable XON/XOFF flow control on input. * Receiver compares XON1, XOFF1. */ efr |= OMAP_UART_SW_RX; #endif omap_serial_out(port, UART_EFR, port->efr | UART_EFR_ECB); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_A); port->mcr = omap_serial_in(port, UART_MCR); omap_serial_out(port, UART_MCR, port->mcr | UART_MCR_TCRTLR); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_B); omap_serial_out(port, UART_TI752_TCR, OMAP_UART_TCR_TRIG); /* Enable special char function UARTi.EFR_REG[5] and * load the new software flow control mode IXON or IXOFF * and restore the UARTi.EFR_REG[4] ENHANCED_EN value. */ omap_serial_out(port, UART_EFR, efr | UART_EFR_SCD); omap_serial_out(port, UART_LCR, UART_LCR_CONF_MODE_A); omap_serial_out(port, UART_MCR, port->mcr & ~UART_MCR_TCRTLR); omap_serial_out(port, UART_LCR, port->lcr); }
void omap_uart_lowlevel_init(virtual_addr_t base, u32 reg_align, u32 baudrate, u32 input_clock) { u16 bdiv; bdiv = udiv32(input_clock, (16 * baudrate)); /* clear interrupt enable reg */ omap_serial_out(UART_IER, 0); /* set mode select to disabled before dll/dlh */ omap_serial_out(UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); omap_serial_out(UART_LCR, UART_LCR_CONF_MODE_A); omap_serial_out(UART_DLL, 0); omap_serial_out(UART_DLM, 0); omap_serial_out(UART_LCR, 0); /* no modem control DTR RTS */ omap_serial_out(UART_MCR, 0); /* enable FIFO */ omap_serial_out(UART_FCR, UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00 | \ UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO); /* set baudrate divisor */ omap_serial_out(UART_LCR, UART_LCR_CONF_MODE_B); omap_serial_out(UART_DLL, bdiv & 0xFF); omap_serial_out(UART_DLM, (bdiv >> 8) & 0xFF); omap_serial_out(UART_LCR, UART_LCR_WLEN8); /* set mode select to 16x mode */ omap_serial_out(UART_OMAP_MDR1, UART_OMAP_MDR1_16X_MODE); }
static int omap_uart_driver_probe(struct vmm_device *dev, const struct vmm_devtree_nodeid *devid) { int rc; struct omap_uart_port *port; port = vmm_zalloc(sizeof(struct omap_uart_port)); if (!port) { rc = VMM_ENOMEM; goto free_nothing; } rc = vmm_devtree_request_regmap(dev->of_node, &port->base, 0, "omap-uart"); if (rc) { goto free_port; } if (vmm_devtree_read_u32(dev->of_node, "reg-shift", &port->reg_shift)) { port->reg_shift = 0; } if (vmm_devtree_read_u32(dev->of_node, "baudrate", &port->baudrate)) { port->baudrate = 115200; } rc = vmm_devtree_clock_frequency(dev->of_node, &port->input_clock); if (rc) { goto free_reg; } omap_uart_startup_configure(port); port->irq = vmm_devtree_irq_parse_map(dev->of_node, 0); if (!port->irq) { rc = VMM_ENODEV; goto free_reg; } if ((rc = vmm_host_irq_register(port->irq, dev->name, omap_uart_irq_handler, port))) { goto free_reg; } /* Create Serial Port */ port->p = serial_create(dev, 256, omap_uart_tx, port); if (VMM_IS_ERR_OR_NULL(port->p)) { rc = VMM_PTR_ERR(port->p); goto free_irq; } /* Save port pointer */ dev->priv = port; /* Unmask Rx interrupt */ port->ier |= (UART_IER_RDI | UART_IER_RLSI); omap_serial_out(port, UART_IER, port->ier); return VMM_OK; free_irq: vmm_host_irq_unregister(port->irq, port); free_reg: vmm_devtree_regunmap_release(dev->of_node, port->base, 0); free_port: vmm_free(port); free_nothing: return rc; }