Lines Matching +full:port +full:-
1 // SPDX-License-Identifier: GPL-2.0+
10 * This is a generic driver for ARM AMBA-type serial ports. They
11 * have a lot of 16550-like features, but are not register compatible.
49 * We wrap our port structure around the generic uart_port.
52 struct uart_port port; member
59 static void pl010_stop_tx(struct uart_port *port) in pl010_stop_tx() argument
62 container_of(port, struct uart_amba_port, port); in pl010_stop_tx()
65 cr = readb(uap->port.membase + UART010_CR); in pl010_stop_tx()
67 writel(cr, uap->port.membase + UART010_CR); in pl010_stop_tx()
70 static void pl010_start_tx(struct uart_port *port) in pl010_start_tx() argument
73 container_of(port, struct uart_amba_port, port); in pl010_start_tx()
76 cr = readb(uap->port.membase + UART010_CR); in pl010_start_tx()
78 writel(cr, uap->port.membase + UART010_CR); in pl010_start_tx()
81 static void pl010_stop_rx(struct uart_port *port) in pl010_stop_rx() argument
84 container_of(port, struct uart_amba_port, port); in pl010_stop_rx()
87 cr = readb(uap->port.membase + UART010_CR); in pl010_stop_rx()
89 writel(cr, uap->port.membase + UART010_CR); in pl010_stop_rx()
92 static void pl010_disable_ms(struct uart_port *port) in pl010_disable_ms() argument
94 struct uart_amba_port *uap = (struct uart_amba_port *)port; in pl010_disable_ms()
97 cr = readb(uap->port.membase + UART010_CR); in pl010_disable_ms()
99 writel(cr, uap->port.membase + UART010_CR); in pl010_disable_ms()
102 static void pl010_enable_ms(struct uart_port *port) in pl010_enable_ms() argument
105 container_of(port, struct uart_amba_port, port); in pl010_enable_ms()
108 cr = readb(uap->port.membase + UART010_CR); in pl010_enable_ms()
110 writel(cr, uap->port.membase + UART010_CR); in pl010_enable_ms()
113 static void pl010_rx_chars(struct uart_port *port) in pl010_rx_chars() argument
118 status = readb(port->membase + UART01x_FR); in pl010_rx_chars()
119 while (UART_RX_DATA(status) && max_count--) { in pl010_rx_chars()
120 ch = readb(port->membase + UART01x_DR); in pl010_rx_chars()
123 port->icount.rx++; in pl010_rx_chars()
129 rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX; in pl010_rx_chars()
131 writel(0, port->membase + UART01x_ECR); in pl010_rx_chars()
135 port->icount.brk++; in pl010_rx_chars()
136 if (uart_handle_break(port)) in pl010_rx_chars()
139 port->icount.parity++; in pl010_rx_chars()
141 port->icount.frame++; in pl010_rx_chars()
143 port->icount.overrun++; in pl010_rx_chars()
145 rsr &= port->read_status_mask; in pl010_rx_chars()
155 if (uart_handle_sysrq_char(port, ch)) in pl010_rx_chars()
158 uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); in pl010_rx_chars()
161 status = readb(port->membase + UART01x_FR); in pl010_rx_chars()
163 tty_flip_buffer_push(&port->state->port); in pl010_rx_chars()
166 static void pl010_tx_chars(struct uart_port *port) in pl010_tx_chars() argument
170 uart_port_tx_limited(port, ch, port->fifosize >> 1, in pl010_tx_chars()
172 writel(ch, port->membase + UART01x_DR), in pl010_tx_chars()
178 struct uart_port *port = &uap->port; in pl010_modem_status() local
181 writel(0, port->membase + UART010_ICR); in pl010_modem_status()
183 status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY; in pl010_modem_status()
185 delta = status ^ uap->old_status; in pl010_modem_status()
186 uap->old_status = status; in pl010_modem_status()
192 uart_handle_dcd_change(port, status & UART01x_FR_DCD); in pl010_modem_status()
195 port->icount.dsr++; in pl010_modem_status()
198 uart_handle_cts_change(port, status & UART01x_FR_CTS); in pl010_modem_status()
200 wake_up_interruptible(&port->state->port.delta_msr_wait); in pl010_modem_status()
206 struct uart_port *port = &uap->port; in pl010_int() local
210 uart_port_lock(port); in pl010_int()
212 status = readb(port->membase + UART010_IIR); in pl010_int()
216 pl010_rx_chars(port); in pl010_int()
220 pl010_tx_chars(port); in pl010_int()
222 if (pass_counter-- == 0) in pl010_int()
225 status = readb(port->membase + UART010_IIR); in pl010_int()
231 uart_port_unlock(port); in pl010_int()
236 static unsigned int pl010_tx_empty(struct uart_port *port) in pl010_tx_empty() argument
238 unsigned int status = readb(port->membase + UART01x_FR); in pl010_tx_empty()
243 static unsigned int pl010_get_mctrl(struct uart_port *port) in pl010_get_mctrl() argument
248 status = readb(port->membase + UART01x_FR); in pl010_get_mctrl()
259 static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) in pl010_set_mctrl() argument
262 container_of(port, struct uart_amba_port, port); in pl010_set_mctrl()
264 if (uap->data) in pl010_set_mctrl()
265 uap->data->set_mctrl(uap->dev, port->membase, mctrl); in pl010_set_mctrl()
268 static void pl010_break_ctl(struct uart_port *port, int break_state) in pl010_break_ctl() argument
273 uart_port_lock_irqsave(port, &flags); in pl010_break_ctl()
274 lcr_h = readb(port->membase + UART010_LCRH); in pl010_break_ctl()
275 if (break_state == -1) in pl010_break_ctl()
279 writel(lcr_h, port->membase + UART010_LCRH); in pl010_break_ctl()
280 uart_port_unlock_irqrestore(port, flags); in pl010_break_ctl()
283 static int pl010_startup(struct uart_port *port) in pl010_startup() argument
286 container_of(port, struct uart_amba_port, port); in pl010_startup()
292 retval = clk_prepare_enable(uap->clk); in pl010_startup()
296 port->uartclk = clk_get_rate(uap->clk); in pl010_startup()
301 retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", uap); in pl010_startup()
308 uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY; in pl010_startup()
314 port->membase + UART010_CR); in pl010_startup()
319 clk_disable_unprepare(uap->clk); in pl010_startup()
324 static void pl010_shutdown(struct uart_port *port) in pl010_shutdown() argument
327 container_of(port, struct uart_amba_port, port); in pl010_shutdown()
332 free_irq(port->irq, uap); in pl010_shutdown()
335 * disable all interrupts, disable the port in pl010_shutdown()
337 writel(0, port->membase + UART010_CR); in pl010_shutdown()
340 writel(readb(port->membase + UART010_LCRH) & in pl010_shutdown()
342 port->membase + UART010_LCRH); in pl010_shutdown()
347 clk_disable_unprepare(uap->clk); in pl010_shutdown()
351 pl010_set_termios(struct uart_port *port, struct ktermios *termios, in pl010_set_termios() argument
361 baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); in pl010_set_termios()
362 quot = uart_get_divisor(port, baud); in pl010_set_termios()
364 switch (termios->c_cflag & CSIZE) { in pl010_set_termios()
378 if (termios->c_cflag & CSTOPB) in pl010_set_termios()
380 if (termios->c_cflag & PARENB) { in pl010_set_termios()
382 if (!(termios->c_cflag & PARODD)) in pl010_set_termios()
385 if (port->fifosize > 1) in pl010_set_termios()
388 uart_port_lock_irqsave(port, &flags); in pl010_set_termios()
391 * Update the per-port timeout. in pl010_set_termios()
393 uart_update_timeout(port, termios->c_cflag, baud); in pl010_set_termios()
395 port->read_status_mask = UART01x_RSR_OE; in pl010_set_termios()
396 if (termios->c_iflag & INPCK) in pl010_set_termios()
397 port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; in pl010_set_termios()
398 if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) in pl010_set_termios()
399 port->read_status_mask |= UART01x_RSR_BE; in pl010_set_termios()
404 port->ignore_status_mask = 0; in pl010_set_termios()
405 if (termios->c_iflag & IGNPAR) in pl010_set_termios()
406 port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; in pl010_set_termios()
407 if (termios->c_iflag & IGNBRK) { in pl010_set_termios()
408 port->ignore_status_mask |= UART01x_RSR_BE; in pl010_set_termios()
413 if (termios->c_iflag & IGNPAR) in pl010_set_termios()
414 port->ignore_status_mask |= UART01x_RSR_OE; in pl010_set_termios()
420 if ((termios->c_cflag & CREAD) == 0) in pl010_set_termios()
421 port->ignore_status_mask |= UART_DUMMY_RSR_RX; in pl010_set_termios()
423 old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE; in pl010_set_termios()
425 if (UART_ENABLE_MS(port, termios->c_cflag)) in pl010_set_termios()
429 quot -= 1; in pl010_set_termios()
430 writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM); in pl010_set_termios()
431 writel(quot & 0xff, port->membase + UART010_LCRL); in pl010_set_termios()
434 * ----------v----------v----------v----------v----- in pl010_set_termios()
436 * ----------^----------^----------^----------^----- in pl010_set_termios()
438 writel(lcr_h, port->membase + UART010_LCRH); in pl010_set_termios()
439 writel(old_cr, port->membase + UART010_CR); in pl010_set_termios()
441 uart_port_unlock_irqrestore(port, flags); in pl010_set_termios()
444 static void pl010_set_ldisc(struct uart_port *port, struct ktermios *termios) in pl010_set_ldisc() argument
446 if (termios->c_line == N_PPS) { in pl010_set_ldisc()
447 port->flags |= UPF_HARDPPS_CD; in pl010_set_ldisc()
448 uart_port_lock_irq(port); in pl010_set_ldisc()
449 pl010_enable_ms(port); in pl010_set_ldisc()
450 uart_port_unlock_irq(port); in pl010_set_ldisc()
452 port->flags &= ~UPF_HARDPPS_CD; in pl010_set_ldisc()
453 if (!UART_ENABLE_MS(port, termios->c_cflag)) { in pl010_set_ldisc()
454 uart_port_lock_irq(port); in pl010_set_ldisc()
455 pl010_disable_ms(port); in pl010_set_ldisc()
456 uart_port_unlock_irq(port); in pl010_set_ldisc()
461 static const char *pl010_type(struct uart_port *port) in pl010_type() argument
463 return port->type == PORT_AMBA ? "AMBA" : NULL; in pl010_type()
467 * Release the memory region(s) being used by 'port'
469 static void pl010_release_port(struct uart_port *port) in pl010_release_port() argument
471 release_mem_region(port->mapbase, UART_PORT_SIZE); in pl010_release_port()
475 * Request the memory region(s) being used by 'port'
477 static int pl010_request_port(struct uart_port *port) in pl010_request_port() argument
479 return request_mem_region(port->mapbase, UART_PORT_SIZE, "uart-pl010") in pl010_request_port()
480 != NULL ? 0 : -EBUSY; in pl010_request_port()
484 * Configure/autoconfigure the port.
486 static void pl010_config_port(struct uart_port *port, int flags) in pl010_config_port() argument
489 port->type = PORT_AMBA; in pl010_config_port()
490 pl010_request_port(port); in pl010_config_port()
497 static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser) in pl010_verify_port() argument
500 if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) in pl010_verify_port()
501 ret = -EINVAL; in pl010_verify_port()
502 if (ser->irq < 0 || ser->irq >= nr_irqs) in pl010_verify_port()
503 ret = -EINVAL; in pl010_verify_port()
504 if (ser->baud_base < 9600) in pl010_verify_port()
505 ret = -EINVAL; in pl010_verify_port()
533 static void pl010_console_putchar(struct uart_port *port, unsigned char ch) in pl010_console_putchar() argument
538 status = readb(port->membase + UART01x_FR); in pl010_console_putchar()
541 writel(ch, port->membase + UART01x_DR); in pl010_console_putchar()
547 struct uart_amba_port *uap = amba_ports[co->index]; in pl010_console_write()
548 struct uart_port *port = &uap->port; in pl010_console_write() local
551 clk_enable(uap->clk); in pl010_console_write()
556 old_cr = readb(port->membase + UART010_CR); in pl010_console_write()
557 writel(UART01x_CR_UARTEN, port->membase + UART010_CR); in pl010_console_write()
559 uart_console_write(port, s, count, pl010_console_putchar); in pl010_console_write()
566 status = readb(port->membase + UART01x_FR); in pl010_console_write()
569 writel(old_cr, port->membase + UART010_CR); in pl010_console_write()
571 clk_disable(uap->clk); in pl010_console_write()
578 if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) { in pl010_console_get_options()
580 lcr_h = readb(uap->port.membase + UART010_LCRH); in pl010_console_get_options()
595 quot = readb(uap->port.membase + UART010_LCRL) | in pl010_console_get_options()
596 readb(uap->port.membase + UART010_LCRM) << 8; in pl010_console_get_options()
597 *baud = uap->port.uartclk / (16 * (quot + 1)); in pl010_console_get_options()
612 * if so, search for the first available port that does have in pl010_console_setup()
615 if (co->index >= UART_NR) in pl010_console_setup()
616 co->index = 0; in pl010_console_setup()
617 uap = amba_ports[co->index]; in pl010_console_setup()
619 return -ENODEV; in pl010_console_setup()
621 ret = clk_prepare(uap->clk); in pl010_console_setup()
625 uap->port.uartclk = clk_get_rate(uap->clk); in pl010_console_setup()
632 return uart_set_options(&uap->port, co, baud, parity, bits, flow); in pl010_console_setup()
642 .index = -1,
673 return -EBUSY; in pl010_probe()
675 uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), in pl010_probe()
678 return -ENOMEM; in pl010_probe()
680 base = devm_ioremap(&dev->dev, dev->res.start, in pl010_probe()
681 resource_size(&dev->res)); in pl010_probe()
683 return -ENOMEM; in pl010_probe()
685 uap->clk = devm_clk_get(&dev->dev, NULL); in pl010_probe()
686 if (IS_ERR(uap->clk)) in pl010_probe()
687 return PTR_ERR(uap->clk); in pl010_probe()
689 uap->port.dev = &dev->dev; in pl010_probe()
690 uap->port.mapbase = dev->res.start; in pl010_probe()
691 uap->port.membase = base; in pl010_probe()
692 uap->port.iotype = UPIO_MEM; in pl010_probe()
693 uap->port.irq = dev->irq[0]; in pl010_probe()
694 uap->port.fifosize = 16; in pl010_probe()
695 uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL010_CONSOLE); in pl010_probe()
696 uap->port.ops = &amba_pl010_pops; in pl010_probe()
697 uap->port.flags = UPF_BOOT_AUTOCONF; in pl010_probe()
698 uap->port.line = i; in pl010_probe()
699 uap->dev = dev; in pl010_probe()
700 uap->data = dev_get_platdata(&dev->dev); in pl010_probe()
711 dev_err(uap->port.dev, in pl010_probe()
712 "Failed to register AMBA-PL010 driver\n"); in pl010_probe()
718 ret = uart_add_one_port(&amba_reg, &uap->port); in pl010_probe()
731 uart_remove_one_port(&amba_reg, &uap->port); in pl010_remove()
749 uart_suspend_port(&amba_reg, &uap->port); in pl010_suspend()
759 uart_resume_port(&amba_reg, &uap->port); in pl010_resume()
779 .name = "uart-pl010",
803 MODULE_DESCRIPTION("ARM AMBA serial port driver");