brintos

brintos / linux-shallow public Read only

0
0
Text · 15.3 KiB · 364599f Raw
663 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *  Driver for GRLIB serial ports (APBUART)4 *5 *  Based on linux/drivers/serial/amba.c6 *7 *  Copyright (C) 2000 Deep Blue Solutions Ltd.8 *  Copyright (C) 2003 Konrad Eisele <eiselekd@web.de>9 *  Copyright (C) 2006 Daniel Hellstrom <daniel@gaisler.com>, Aeroflex Gaisler AB10 *  Copyright (C) 2008 Gilead Kutnick <kutnickg@zin-tech.com>11 *  Copyright (C) 2009 Kristoffer Glembo <kristoffer@gaisler.com>, Aeroflex Gaisler AB12 */13 14#include <linux/module.h>15#include <linux/tty.h>16#include <linux/tty_flip.h>17#include <linux/ioport.h>18#include <linux/init.h>19#include <linux/serial.h>20#include <linux/console.h>21#include <linux/sysrq.h>22#include <linux/kthread.h>23#include <linux/device.h>24#include <linux/of.h>25#include <linux/platform_device.h>26#include <linux/io.h>27#include <linux/serial_core.h>28#include <asm/irq.h>29 30#include "apbuart.h"31 32#define SERIAL_APBUART_MAJOR	TTY_MAJOR33#define SERIAL_APBUART_MINOR	6434#define UART_DUMMY_RSR_RX	0x8000	/* for ignore all read */35 36static void apbuart_tx_chars(struct uart_port *port);37 38static void apbuart_stop_tx(struct uart_port *port)39{40	unsigned int cr;41 42	cr = UART_GET_CTRL(port);43	cr &= ~UART_CTRL_TI;44	UART_PUT_CTRL(port, cr);45}46 47static void apbuart_start_tx(struct uart_port *port)48{49	unsigned int cr;50 51	cr = UART_GET_CTRL(port);52	cr |= UART_CTRL_TI;53	UART_PUT_CTRL(port, cr);54 55	if (UART_GET_STATUS(port) & UART_STATUS_THE)56		apbuart_tx_chars(port);57}58 59static void apbuart_stop_rx(struct uart_port *port)60{61	unsigned int cr;62 63	cr = UART_GET_CTRL(port);64	cr &= ~(UART_CTRL_RI);65	UART_PUT_CTRL(port, cr);66}67 68static void apbuart_rx_chars(struct uart_port *port)69{70	unsigned int status, rsr;71	unsigned int max_chars = port->fifosize;72	u8 ch, flag;73 74	status = UART_GET_STATUS(port);75 76	while (UART_RX_DATA(status) && (max_chars--)) {77 78		ch = UART_GET_CHAR(port);79		flag = TTY_NORMAL;80 81		port->icount.rx++;82 83		rsr = UART_GET_STATUS(port) | UART_DUMMY_RSR_RX;84		UART_PUT_STATUS(port, 0);85		if (rsr & UART_STATUS_ERR) {86 87			if (rsr & UART_STATUS_BR) {88				rsr &= ~(UART_STATUS_FE | UART_STATUS_PE);89				port->icount.brk++;90				if (uart_handle_break(port))91					goto ignore_char;92			} else if (rsr & UART_STATUS_PE) {93				port->icount.parity++;94			} else if (rsr & UART_STATUS_FE) {95				port->icount.frame++;96			}97			if (rsr & UART_STATUS_OE)98				port->icount.overrun++;99 100			rsr &= port->read_status_mask;101 102			if (rsr & UART_STATUS_PE)103				flag = TTY_PARITY;104			else if (rsr & UART_STATUS_FE)105				flag = TTY_FRAME;106		}107 108		if (uart_handle_sysrq_char(port, ch))109			goto ignore_char;110 111		uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag);112 113 114	      ignore_char:115		status = UART_GET_STATUS(port);116	}117 118	tty_flip_buffer_push(&port->state->port);119}120 121static void apbuart_tx_chars(struct uart_port *port)122{123	u8 ch;124 125	uart_port_tx_limited(port, ch, port->fifosize,126		true,127		UART_PUT_CHAR(port, ch),128		({}));129}130 131static irqreturn_t apbuart_int(int irq, void *dev_id)132{133	struct uart_port *port = dev_id;134	unsigned int status;135 136	uart_port_lock(port);137 138	status = UART_GET_STATUS(port);139	if (status & UART_STATUS_DR)140		apbuart_rx_chars(port);141	if (status & UART_STATUS_THE)142		apbuart_tx_chars(port);143 144	uart_port_unlock(port);145 146	return IRQ_HANDLED;147}148 149static unsigned int apbuart_tx_empty(struct uart_port *port)150{151	unsigned int status = UART_GET_STATUS(port);152	return status & UART_STATUS_THE ? TIOCSER_TEMT : 0;153}154 155static unsigned int apbuart_get_mctrl(struct uart_port *port)156{157	/* The GRLIB APBUART handles flow control in hardware */158	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;159}160 161static void apbuart_set_mctrl(struct uart_port *port, unsigned int mctrl)162{163	/* The GRLIB APBUART handles flow control in hardware */164}165 166static void apbuart_break_ctl(struct uart_port *port, int break_state)167{168	/* We don't support sending break */169}170 171static int apbuart_startup(struct uart_port *port)172{173	int retval;174	unsigned int cr;175 176	/* Allocate the IRQ */177	retval = request_irq(port->irq, apbuart_int, 0, "apbuart", port);178	if (retval)179		return retval;180 181	/* Finally, enable interrupts */182	cr = UART_GET_CTRL(port);183	UART_PUT_CTRL(port,184		      cr | UART_CTRL_RE | UART_CTRL_TE |185		      UART_CTRL_RI | UART_CTRL_TI);186 187	return 0;188}189 190static void apbuart_shutdown(struct uart_port *port)191{192	unsigned int cr;193 194	/* disable all interrupts, disable the port */195	cr = UART_GET_CTRL(port);196	UART_PUT_CTRL(port,197		      cr & ~(UART_CTRL_RE | UART_CTRL_TE |198			     UART_CTRL_RI | UART_CTRL_TI));199 200	/* Free the interrupt */201	free_irq(port->irq, port);202}203 204static void apbuart_set_termios(struct uart_port *port,205				struct ktermios *termios, const struct ktermios *old)206{207	unsigned int cr;208	unsigned long flags;209	unsigned int baud, quot;210 211	/* Ask the core to calculate the divisor for us. */212	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);213	if (baud == 0)214		panic("invalid baudrate %i\n", port->uartclk / 16);215 216	/* uart_get_divisor calc a *16 uart freq, apbuart is *8 */217	quot = (uart_get_divisor(port, baud)) * 2;218	cr = UART_GET_CTRL(port);219	cr &= ~(UART_CTRL_PE | UART_CTRL_PS);220 221	if (termios->c_cflag & PARENB) {222		cr |= UART_CTRL_PE;223		if ((termios->c_cflag & PARODD))224			cr |= UART_CTRL_PS;225	}226 227	/* Enable flow control. */228	if (termios->c_cflag & CRTSCTS)229		cr |= UART_CTRL_FL;230 231	uart_port_lock_irqsave(port, &flags);232 233	/* Update the per-port timeout. */234	uart_update_timeout(port, termios->c_cflag, baud);235 236	port->read_status_mask = UART_STATUS_OE;237	if (termios->c_iflag & INPCK)238		port->read_status_mask |= UART_STATUS_FE | UART_STATUS_PE;239 240	/* Characters to ignore */241	port->ignore_status_mask = 0;242	if (termios->c_iflag & IGNPAR)243		port->ignore_status_mask |= UART_STATUS_FE | UART_STATUS_PE;244 245	/* Ignore all characters if CREAD is not set. */246	if ((termios->c_cflag & CREAD) == 0)247		port->ignore_status_mask |= UART_DUMMY_RSR_RX;248 249	/* Set baud rate */250	quot -= 1;251	UART_PUT_SCAL(port, quot);252	UART_PUT_CTRL(port, cr);253 254	uart_port_unlock_irqrestore(port, flags);255}256 257static const char *apbuart_type(struct uart_port *port)258{259	return port->type == PORT_APBUART ? "GRLIB/APBUART" : NULL;260}261 262static void apbuart_release_port(struct uart_port *port)263{264	release_mem_region(port->mapbase, 0x100);265}266 267static int apbuart_request_port(struct uart_port *port)268{269	return request_mem_region(port->mapbase, 0x100, "grlib-apbuart")270	    != NULL ? 0 : -EBUSY;271	return 0;272}273 274/* Configure/autoconfigure the port */275static void apbuart_config_port(struct uart_port *port, int flags)276{277	if (flags & UART_CONFIG_TYPE) {278		port->type = PORT_APBUART;279		apbuart_request_port(port);280	}281}282 283/* Verify the new serial_struct (for TIOCSSERIAL) */284static int apbuart_verify_port(struct uart_port *port,285			       struct serial_struct *ser)286{287	int ret = 0;288	if (ser->type != PORT_UNKNOWN && ser->type != PORT_APBUART)289		ret = -EINVAL;290	if (ser->irq < 0 || ser->irq >= NR_IRQS)291		ret = -EINVAL;292	if (ser->baud_base < 9600)293		ret = -EINVAL;294	return ret;295}296 297static const struct uart_ops grlib_apbuart_ops = {298	.tx_empty = apbuart_tx_empty,299	.set_mctrl = apbuart_set_mctrl,300	.get_mctrl = apbuart_get_mctrl,301	.stop_tx = apbuart_stop_tx,302	.start_tx = apbuart_start_tx,303	.stop_rx = apbuart_stop_rx,304	.break_ctl = apbuart_break_ctl,305	.startup = apbuart_startup,306	.shutdown = apbuart_shutdown,307	.set_termios = apbuart_set_termios,308	.type = apbuart_type,309	.release_port = apbuart_release_port,310	.request_port = apbuart_request_port,311	.config_port = apbuart_config_port,312	.verify_port = apbuart_verify_port,313};314 315static struct uart_port grlib_apbuart_ports[UART_NR];316static struct device_node *grlib_apbuart_nodes[UART_NR];317 318static int apbuart_scan_fifo_size(struct uart_port *port, int portnumber)319{320	int ctrl, loop = 0;321	int status;322	int fifosize;323	unsigned long flags;324 325	ctrl = UART_GET_CTRL(port);326 327	/*328	 * Enable the transceiver and wait for it to be ready to send data.329	 * Clear interrupts so that this process will not be externally330	 * interrupted in the middle (which can cause the transceiver to331	 * drain prematurely).332	 */333 334	local_irq_save(flags);335 336	UART_PUT_CTRL(port, ctrl | UART_CTRL_TE);337 338	while (!UART_TX_READY(UART_GET_STATUS(port)))339		loop++;340 341	/*342	 * Disable the transceiver so data isn't actually sent during the343	 * actual test.344	 */345 346	UART_PUT_CTRL(port, ctrl & ~(UART_CTRL_TE));347 348	fifosize = 1;349	UART_PUT_CHAR(port, 0);350 351	/*352	 * So long as transmitting a character increments the tranceivier FIFO353	 * length the FIFO must be at least that big. These bytes will354	 * automatically drain off of the FIFO.355	 */356 357	status = UART_GET_STATUS(port);358	while (((status >> 20) & 0x3F) == fifosize) {359		fifosize++;360		UART_PUT_CHAR(port, 0);361		status = UART_GET_STATUS(port);362	}363 364	fifosize--;365 366	UART_PUT_CTRL(port, ctrl);367	local_irq_restore(flags);368 369	if (fifosize == 0)370		fifosize = 1;371 372	return fifosize;373}374 375static void apbuart_flush_fifo(struct uart_port *port)376{377	int i;378 379	for (i = 0; i < port->fifosize; i++)380		UART_GET_CHAR(port);381}382 383 384/* ======================================================================== */385/* Console driver, if enabled                                               */386/* ======================================================================== */387 388#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE389 390static void apbuart_console_putchar(struct uart_port *port, unsigned char ch)391{392	unsigned int status;393	do {394		status = UART_GET_STATUS(port);395	} while (!UART_TX_READY(status));396	UART_PUT_CHAR(port, ch);397}398 399static void400apbuart_console_write(struct console *co, const char *s, unsigned int count)401{402	struct uart_port *port = &grlib_apbuart_ports[co->index];403	unsigned int status, old_cr, new_cr;404 405	/* First save the CR then disable the interrupts */406	old_cr = UART_GET_CTRL(port);407	new_cr = old_cr & ~(UART_CTRL_RI | UART_CTRL_TI);408	UART_PUT_CTRL(port, new_cr);409 410	uart_console_write(port, s, count, apbuart_console_putchar);411 412	/*413	 *      Finally, wait for transmitter to become empty414	 *      and restore the TCR415	 */416	do {417		status = UART_GET_STATUS(port);418	} while (!UART_TX_READY(status));419	UART_PUT_CTRL(port, old_cr);420}421 422static void __init423apbuart_console_get_options(struct uart_port *port, int *baud,424			    int *parity, int *bits)425{426	if (UART_GET_CTRL(port) & (UART_CTRL_RE | UART_CTRL_TE)) {427 428		unsigned int quot, status;429		status = UART_GET_STATUS(port);430 431		*parity = 'n';432		if (status & UART_CTRL_PE) {433			if ((status & UART_CTRL_PS) == 0)434				*parity = 'e';435			else436				*parity = 'o';437		}438 439		*bits = 8;440		quot = UART_GET_SCAL(port) / 8;441		*baud = port->uartclk / (16 * (quot + 1));442	}443}444 445static int __init apbuart_console_setup(struct console *co, char *options)446{447	struct uart_port *port;448	int baud = 38400;449	int bits = 8;450	int parity = 'n';451	int flow = 'n';452 453	pr_debug("apbuart_console_setup co=%p, co->index=%i, options=%s\n",454		 co, co->index, options);455 456	/*457	 * Check whether an invalid uart number has been specified, and458	 * if so, search for the first available port that does have459	 * console support.460	 */461	if (co->index >= grlib_apbuart_port_nr)462		co->index = 0;463 464	port = &grlib_apbuart_ports[co->index];465 466	spin_lock_init(&port->lock);467 468	if (options)469		uart_parse_options(options, &baud, &parity, &bits, &flow);470	else471		apbuart_console_get_options(port, &baud, &parity, &bits);472 473	return uart_set_options(port, co, baud, parity, bits, flow);474}475 476static struct uart_driver grlib_apbuart_driver;477 478static struct console grlib_apbuart_console = {479	.name = "ttyS",480	.write = apbuart_console_write,481	.device = uart_console_device,482	.setup = apbuart_console_setup,483	.flags = CON_PRINTBUFFER,484	.index = -1,485	.data = &grlib_apbuart_driver,486};487 488 489static int grlib_apbuart_configure(void);490 491static int __init apbuart_console_init(void)492{493	if (grlib_apbuart_configure())494		return -ENODEV;495	register_console(&grlib_apbuart_console);496	return 0;497}498 499console_initcall(apbuart_console_init);500 501#define APBUART_CONSOLE	(&grlib_apbuart_console)502#else503#define APBUART_CONSOLE	NULL504#endif505 506static struct uart_driver grlib_apbuart_driver = {507	.owner = THIS_MODULE,508	.driver_name = "serial",509	.dev_name = "ttyS",510	.major = SERIAL_APBUART_MAJOR,511	.minor = SERIAL_APBUART_MINOR,512	.nr = UART_NR,513	.cons = APBUART_CONSOLE,514};515 516 517/* ======================================================================== */518/* OF Platform Driver                                                       */519/* ======================================================================== */520 521static int apbuart_probe(struct platform_device *op)522{523	int i;524	struct uart_port *port = NULL;525 526	for (i = 0; i < grlib_apbuart_port_nr; i++) {527		if (op->dev.of_node == grlib_apbuart_nodes[i])528			break;529	}530 531	port = &grlib_apbuart_ports[i];532	port->dev = &op->dev;533	port->irq = op->archdata.irqs[0];534 535	uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port);536 537	apbuart_flush_fifo((struct uart_port *) port);538 539	printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",540	       (unsigned long long) port->mapbase, port->irq);541	return 0;542}543 544static const struct of_device_id apbuart_match[] = {545	{546	 .name = "GAISLER_APBUART",547	 },548	{549	 .name = "01_00c",550	 },551	{},552};553MODULE_DEVICE_TABLE(of, apbuart_match);554 555static struct platform_driver grlib_apbuart_of_driver = {556	.probe = apbuart_probe,557	.driver = {558		.name = "grlib-apbuart",559		.of_match_table = apbuart_match,560	},561};562 563 564static int __init grlib_apbuart_configure(void)565{566	struct device_node *np;567	int line = 0;568 569	for_each_matching_node(np, apbuart_match) {570		const int *ampopts;571		const u32 *freq_hz;572		const struct amba_prom_registers *regs;573		struct uart_port *port;574		unsigned long addr;575 576		ampopts = of_get_property(np, "ampopts", NULL);577		if (ampopts && (*ampopts == 0))578			continue; /* Ignore if used by another OS instance */579		regs = of_get_property(np, "reg", NULL);580		/* Frequency of APB Bus is frequency of UART */581		freq_hz = of_get_property(np, "freq", NULL);582 583		if (!regs || !freq_hz || (*freq_hz == 0))584			continue;585 586		grlib_apbuart_nodes[line] = np;587 588		addr = regs->phys_addr;589 590		port = &grlib_apbuart_ports[line];591 592		port->mapbase = addr;593		port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map));594		port->irq = 0;595		port->iotype = UPIO_MEM;596		port->ops = &grlib_apbuart_ops;597		port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_CONSOLE);598		port->flags = UPF_BOOT_AUTOCONF;599		port->line = line;600		port->uartclk = *freq_hz;601		port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line);602		line++;603 604		/* We support maximum UART_NR uarts ... */605		if (line == UART_NR)606			break;607	}608 609	grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line;610	return line ? 0 : -ENODEV;611}612 613static int __init grlib_apbuart_init(void)614{615	int ret;616 617	/* Find all APBUARTS in device the tree and initialize their ports */618	ret = grlib_apbuart_configure();619	if (ret)620		return ret;621 622	printk(KERN_INFO "Serial: GRLIB APBUART driver\n");623 624	ret = uart_register_driver(&grlib_apbuart_driver);625 626	if (ret) {627		printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",628		       __FILE__, ret);629		return ret;630	}631 632	ret = platform_driver_register(&grlib_apbuart_of_driver);633	if (ret) {634		printk(KERN_ERR635		       "%s: platform_driver_register failed (%i)\n",636		       __FILE__, ret);637		uart_unregister_driver(&grlib_apbuart_driver);638		return ret;639	}640 641	return ret;642}643 644static void __exit grlib_apbuart_exit(void)645{646	int i;647 648	for (i = 0; i < grlib_apbuart_port_nr; i++)649		uart_remove_one_port(&grlib_apbuart_driver,650				     &grlib_apbuart_ports[i]);651 652	uart_unregister_driver(&grlib_apbuart_driver);653	platform_driver_unregister(&grlib_apbuart_of_driver);654}655 656module_init(grlib_apbuart_init);657module_exit(grlib_apbuart_exit);658 659MODULE_AUTHOR("Aeroflex Gaisler AB");660MODULE_DESCRIPTION("GRLIB APBUART serial driver");661MODULE_VERSION("2.1");662MODULE_LICENSE("GPL");663