1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  Serial Port driver for Aspeed VUART device
4  *
5  *    Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp.
6  *    Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp.
7  */
8 #if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
9 #define SUPPORT_SYSRQ
10 #endif
11 
12 #include <linux/device.h>
13 #include <linux/module.h>
14 #include <linux/of_address.h>
15 #include <linux/of_irq.h>
16 #include <linux/of_platform.h>
17 #include <linux/tty.h>
18 #include <linux/tty_flip.h>
19 #include <linux/clk.h>
20 
21 #include "8250.h"
22 
23 #define ASPEED_VUART_GCRA		0x20
24 #define ASPEED_VUART_GCRA_VUART_EN		BIT(0)
25 #define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
26 #define ASPEED_VUART_GCRB		0x24
27 #define ASPEED_VUART_GCRB_HOST_SIRQ_MASK	GENMASK(7, 4)
28 #define ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT	4
29 #define ASPEED_VUART_ADDRL		0x28
30 #define ASPEED_VUART_ADDRH		0x2c
31 
32 struct aspeed_vuart {
33 	struct device		*dev;
34 	void __iomem		*regs;
35 	struct clk		*clk;
36 	int			line;
37 	struct timer_list	unthrottle_timer;
38 	struct uart_8250_port	*port;
39 };
40 
41 /*
42  * If we fill the tty flip buffers, we throttle the data ready interrupt
43  * to prevent dropped characters. This timeout defines how long we wait
44  * to (conditionally, depending on buffer state) unthrottle.
45  */
46 static const int unthrottle_timeout = HZ/10;
47 
48 /*
49  * The VUART is basically two UART 'front ends' connected by their FIFO
50  * (no actual serial line in between). One is on the BMC side (management
51  * controller) and one is on the host CPU side.
52  *
53  * It allows the BMC to provide to the host a "UART" that pipes into
54  * the BMC itself and can then be turned by the BMC into a network console
55  * of some sort for example.
56  *
57  * This driver is for the BMC side. The sysfs files allow the BMC
58  * userspace which owns the system configuration policy, to specify
59  * at what IO port and interrupt number the host side will appear
60  * to the host on the Host <-> BMC LPC bus. It could be different on a
61  * different system (though most of them use 3f8/4).
62  */
63 
lpc_address_show(struct device * dev,struct device_attribute * attr,char * buf)64 static ssize_t lpc_address_show(struct device *dev,
65 				struct device_attribute *attr, char *buf)
66 {
67 	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
68 	u16 addr;
69 
70 	addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) |
71 		(readb(vuart->regs + ASPEED_VUART_ADDRL));
72 
73 	return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
74 }
75 
lpc_address_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)76 static ssize_t lpc_address_store(struct device *dev,
77 				 struct device_attribute *attr,
78 				 const char *buf, size_t count)
79 {
80 	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
81 	unsigned long val;
82 	int err;
83 
84 	err = kstrtoul(buf, 0, &val);
85 	if (err)
86 		return err;
87 
88 	writeb(val >> 8, vuart->regs + ASPEED_VUART_ADDRH);
89 	writeb(val >> 0, vuart->regs + ASPEED_VUART_ADDRL);
90 
91 	return count;
92 }
93 
94 static DEVICE_ATTR_RW(lpc_address);
95 
sirq_show(struct device * dev,struct device_attribute * attr,char * buf)96 static ssize_t sirq_show(struct device *dev,
97 			 struct device_attribute *attr, char *buf)
98 {
99 	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
100 	u8 reg;
101 
102 	reg = readb(vuart->regs + ASPEED_VUART_GCRB);
103 	reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
104 	reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
105 
106 	return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg);
107 }
108 
sirq_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)109 static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
110 			  const char *buf, size_t count)
111 {
112 	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
113 	unsigned long val;
114 	int err;
115 	u8 reg;
116 
117 	err = kstrtoul(buf, 0, &val);
118 	if (err)
119 		return err;
120 
121 	val <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
122 	val &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
123 
124 	reg = readb(vuart->regs + ASPEED_VUART_GCRB);
125 	reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
126 	reg |= val;
127 	writeb(reg, vuart->regs + ASPEED_VUART_GCRB);
128 
129 	return count;
130 }
131 
132 static DEVICE_ATTR_RW(sirq);
133 
134 static struct attribute *aspeed_vuart_attrs[] = {
135 	&dev_attr_sirq.attr,
136 	&dev_attr_lpc_address.attr,
137 	NULL,
138 };
139 
140 static const struct attribute_group aspeed_vuart_attr_group = {
141 	.attrs = aspeed_vuart_attrs,
142 };
143 
aspeed_vuart_set_enabled(struct aspeed_vuart * vuart,bool enabled)144 static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
145 {
146 	u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
147 
148 	if (enabled)
149 		reg |= ASPEED_VUART_GCRA_VUART_EN;
150 	else
151 		reg &= ~ASPEED_VUART_GCRA_VUART_EN;
152 
153 	writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
154 }
155 
aspeed_vuart_set_host_tx_discard(struct aspeed_vuart * vuart,bool discard)156 static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
157 					     bool discard)
158 {
159 	u8 reg;
160 
161 	reg = readb(vuart->regs + ASPEED_VUART_GCRA);
162 
163 	/* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */
164 	if (!discard)
165 		reg |= ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
166 	else
167 		reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
168 
169 	writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
170 }
171 
aspeed_vuart_startup(struct uart_port * uart_port)172 static int aspeed_vuart_startup(struct uart_port *uart_port)
173 {
174 	struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
175 	struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
176 	int rc;
177 
178 	rc = serial8250_do_startup(uart_port);
179 	if (rc)
180 		return rc;
181 
182 	aspeed_vuart_set_host_tx_discard(vuart, false);
183 
184 	return 0;
185 }
186 
aspeed_vuart_shutdown(struct uart_port * uart_port)187 static void aspeed_vuart_shutdown(struct uart_port *uart_port)
188 {
189 	struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
190 	struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
191 
192 	aspeed_vuart_set_host_tx_discard(vuart, true);
193 
194 	serial8250_do_shutdown(uart_port);
195 }
196 
__aspeed_vuart_set_throttle(struct uart_8250_port * up,bool throttle)197 static void __aspeed_vuart_set_throttle(struct uart_8250_port *up,
198 		bool throttle)
199 {
200 	unsigned char irqs = UART_IER_RLSI | UART_IER_RDI;
201 
202 	up->ier &= ~irqs;
203 	if (!throttle)
204 		up->ier |= irqs;
205 	serial_out(up, UART_IER, up->ier);
206 }
aspeed_vuart_set_throttle(struct uart_port * port,bool throttle)207 static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
208 {
209 	struct uart_8250_port *up = up_to_u8250p(port);
210 	unsigned long flags;
211 
212 	spin_lock_irqsave(&port->lock, flags);
213 	__aspeed_vuart_set_throttle(up, throttle);
214 	spin_unlock_irqrestore(&port->lock, flags);
215 }
216 
aspeed_vuart_throttle(struct uart_port * port)217 static void aspeed_vuart_throttle(struct uart_port *port)
218 {
219 	aspeed_vuart_set_throttle(port, true);
220 }
221 
aspeed_vuart_unthrottle(struct uart_port * port)222 static void aspeed_vuart_unthrottle(struct uart_port *port)
223 {
224 	aspeed_vuart_set_throttle(port, false);
225 }
226 
aspeed_vuart_unthrottle_exp(struct timer_list * timer)227 static void aspeed_vuart_unthrottle_exp(struct timer_list *timer)
228 {
229 	struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer);
230 	struct uart_8250_port *up = vuart->port;
231 
232 	if (!tty_buffer_space_avail(&up->port.state->port)) {
233 		mod_timer(&vuart->unthrottle_timer,
234 			  jiffies + unthrottle_timeout);
235 		return;
236 	}
237 
238 	aspeed_vuart_unthrottle(&up->port);
239 }
240 
241 /*
242  * Custom interrupt handler to manage finer-grained flow control. Although we
243  * have throttle/unthrottle callbacks, we've seen that the VUART device can
244  * deliver characters faster than the ldisc has a chance to check buffer space
245  * against the throttle threshold. This results in dropped characters before
246  * the throttle.
247  *
248  * We do this by checking for flip buffer space before RX. If we have no space,
249  * throttle now and schedule an unthrottle for later, once the ldisc has had
250  * a chance to drain the buffers.
251  */
aspeed_vuart_handle_irq(struct uart_port * port)252 static int aspeed_vuart_handle_irq(struct uart_port *port)
253 {
254 	struct uart_8250_port *up = up_to_u8250p(port);
255 	unsigned int iir, lsr;
256 	unsigned long flags;
257 	int space, count;
258 
259 	iir = serial_port_in(port, UART_IIR);
260 
261 	if (iir & UART_IIR_NO_INT)
262 		return 0;
263 
264 	spin_lock_irqsave(&port->lock, flags);
265 
266 	lsr = serial_port_in(port, UART_LSR);
267 
268 	if (lsr & (UART_LSR_DR | UART_LSR_BI)) {
269 		space = tty_buffer_space_avail(&port->state->port);
270 
271 		if (!space) {
272 			/* throttle and schedule an unthrottle later */
273 			struct aspeed_vuart *vuart = port->private_data;
274 			__aspeed_vuart_set_throttle(up, true);
275 
276 			if (!timer_pending(&vuart->unthrottle_timer)) {
277 				vuart->port = up;
278 				mod_timer(&vuart->unthrottle_timer,
279 					  jiffies + unthrottle_timeout);
280 			}
281 
282 		} else {
283 			count = min(space, 256);
284 
285 			do {
286 				serial8250_read_char(up, lsr);
287 				lsr = serial_in(up, UART_LSR);
288 				if (--count == 0)
289 					break;
290 			} while (lsr & (UART_LSR_DR | UART_LSR_BI));
291 
292 			tty_flip_buffer_push(&port->state->port);
293 		}
294 	}
295 
296 	serial8250_modem_status(up);
297 	if (lsr & UART_LSR_THRE)
298 		serial8250_tx_chars(up);
299 
300 	uart_unlock_and_check_sysrq(port, flags);
301 
302 	return 1;
303 }
304 
aspeed_vuart_probe(struct platform_device * pdev)305 static int aspeed_vuart_probe(struct platform_device *pdev)
306 {
307 	struct uart_8250_port port;
308 	struct aspeed_vuart *vuart;
309 	struct device_node *np;
310 	struct resource *res;
311 	u32 clk, prop;
312 	int rc;
313 
314 	np = pdev->dev.of_node;
315 
316 	vuart = devm_kzalloc(&pdev->dev, sizeof(*vuart), GFP_KERNEL);
317 	if (!vuart)
318 		return -ENOMEM;
319 
320 	vuart->dev = &pdev->dev;
321 	timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0);
322 
323 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
324 	vuart->regs = devm_ioremap_resource(&pdev->dev, res);
325 	if (IS_ERR(vuart->regs))
326 		return PTR_ERR(vuart->regs);
327 
328 	memset(&port, 0, sizeof(port));
329 	port.port.private_data = vuart;
330 	port.port.membase = vuart->regs;
331 	port.port.mapbase = res->start;
332 	port.port.mapsize = resource_size(res);
333 	port.port.startup = aspeed_vuart_startup;
334 	port.port.shutdown = aspeed_vuart_shutdown;
335 	port.port.throttle = aspeed_vuart_throttle;
336 	port.port.unthrottle = aspeed_vuart_unthrottle;
337 	port.port.status = UPSTAT_SYNC_FIFO;
338 	port.port.dev = &pdev->dev;
339 
340 	rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
341 	if (rc < 0)
342 		return rc;
343 
344 	if (of_property_read_u32(np, "clock-frequency", &clk)) {
345 		vuart->clk = devm_clk_get(&pdev->dev, NULL);
346 		if (IS_ERR(vuart->clk)) {
347 			dev_warn(&pdev->dev,
348 				"clk or clock-frequency not defined\n");
349 			rc = PTR_ERR(vuart->clk);
350 			goto err_sysfs_remove;
351 		}
352 
353 		rc = clk_prepare_enable(vuart->clk);
354 		if (rc < 0)
355 			goto err_sysfs_remove;
356 
357 		clk = clk_get_rate(vuart->clk);
358 	}
359 
360 	/* If current-speed was set, then try not to change it. */
361 	if (of_property_read_u32(np, "current-speed", &prop) == 0)
362 		port.port.custom_divisor = clk / (16 * prop);
363 
364 	/* Check for shifted address mapping */
365 	if (of_property_read_u32(np, "reg-offset", &prop) == 0)
366 		port.port.mapbase += prop;
367 
368 	/* Check for registers offset within the devices address range */
369 	if (of_property_read_u32(np, "reg-shift", &prop) == 0)
370 		port.port.regshift = prop;
371 
372 	/* Check for fifo size */
373 	if (of_property_read_u32(np, "fifo-size", &prop) == 0)
374 		port.port.fifosize = prop;
375 
376 	/* Check for a fixed line number */
377 	rc = of_alias_get_id(np, "serial");
378 	if (rc >= 0)
379 		port.port.line = rc;
380 
381 	port.port.irq = irq_of_parse_and_map(np, 0);
382 	port.port.irqflags = IRQF_SHARED;
383 	port.port.handle_irq = aspeed_vuart_handle_irq;
384 	port.port.iotype = UPIO_MEM;
385 	port.port.type = PORT_16550A;
386 	port.port.uartclk = clk;
387 	port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
388 		| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
389 
390 	if (of_property_read_bool(np, "no-loopback-test"))
391 		port.port.flags |= UPF_SKIP_TEST;
392 
393 	if (port.port.fifosize)
394 		port.capabilities = UART_CAP_FIFO;
395 
396 	if (of_property_read_bool(np, "auto-flow-control"))
397 		port.capabilities |= UART_CAP_AFE;
398 
399 	rc = serial8250_register_8250_port(&port);
400 	if (rc < 0)
401 		goto err_clk_disable;
402 
403 	vuart->line = rc;
404 
405 	aspeed_vuart_set_enabled(vuart, true);
406 	aspeed_vuart_set_host_tx_discard(vuart, true);
407 	platform_set_drvdata(pdev, vuart);
408 
409 	return 0;
410 
411 err_clk_disable:
412 	clk_disable_unprepare(vuart->clk);
413 	irq_dispose_mapping(port.port.irq);
414 err_sysfs_remove:
415 	sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
416 	return rc;
417 }
418 
aspeed_vuart_remove(struct platform_device * pdev)419 static int aspeed_vuart_remove(struct platform_device *pdev)
420 {
421 	struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
422 
423 	del_timer_sync(&vuart->unthrottle_timer);
424 	aspeed_vuart_set_enabled(vuart, false);
425 	serial8250_unregister_port(vuart->line);
426 	sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
427 	clk_disable_unprepare(vuart->clk);
428 
429 	return 0;
430 }
431 
432 static const struct of_device_id aspeed_vuart_table[] = {
433 	{ .compatible = "aspeed,ast2400-vuart" },
434 	{ .compatible = "aspeed,ast2500-vuart" },
435 	{ },
436 };
437 
438 static struct platform_driver aspeed_vuart_driver = {
439 	.driver = {
440 		.name = "aspeed-vuart",
441 		.of_match_table = aspeed_vuart_table,
442 	},
443 	.probe = aspeed_vuart_probe,
444 	.remove = aspeed_vuart_remove,
445 };
446 
447 module_platform_driver(aspeed_vuart_driver);
448 
449 MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
450 MODULE_LICENSE("GPL");
451 MODULE_DESCRIPTION("Driver for Aspeed VUART device");
452