staging: erofs: integrate decompression inplace
[linux/fpc-iii.git] / drivers / tty / serial / 8250 / 8250_aspeed_vuart.c
blob0438d9a905ce979840b342f34eac5c6873f588dd
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Serial Port driver for Aspeed VUART device
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
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>
21 #include "8250.h"
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
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;
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.
46 static const int unthrottle_timeout = HZ/10;
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.
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.
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).
64 static ssize_t lpc_address_show(struct device *dev,
65 struct device_attribute *attr, char *buf)
67 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
68 u16 addr;
70 addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) |
71 (readb(vuart->regs + ASPEED_VUART_ADDRL));
73 return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
76 static ssize_t lpc_address_store(struct device *dev,
77 struct device_attribute *attr,
78 const char *buf, size_t count)
80 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
81 unsigned long val;
82 int err;
84 err = kstrtoul(buf, 0, &val);
85 if (err)
86 return err;
88 writeb(val >> 8, vuart->regs + ASPEED_VUART_ADDRH);
89 writeb(val >> 0, vuart->regs + ASPEED_VUART_ADDRL);
91 return count;
94 static DEVICE_ATTR_RW(lpc_address);
96 static ssize_t sirq_show(struct device *dev,
97 struct device_attribute *attr, char *buf)
99 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
100 u8 reg;
102 reg = readb(vuart->regs + ASPEED_VUART_GCRB);
103 reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
104 reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
106 return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg);
109 static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
110 const char *buf, size_t count)
112 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
113 unsigned long val;
114 int err;
115 u8 reg;
117 err = kstrtoul(buf, 0, &val);
118 if (err)
119 return err;
121 val <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
122 val &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
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);
129 return count;
132 static DEVICE_ATTR_RW(sirq);
134 static struct attribute *aspeed_vuart_attrs[] = {
135 &dev_attr_sirq.attr,
136 &dev_attr_lpc_address.attr,
137 NULL,
140 static const struct attribute_group aspeed_vuart_attr_group = {
141 .attrs = aspeed_vuart_attrs,
144 static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
146 u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
148 if (enabled)
149 reg |= ASPEED_VUART_GCRA_VUART_EN;
150 else
151 reg &= ~ASPEED_VUART_GCRA_VUART_EN;
153 writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
156 static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
157 bool discard)
159 u8 reg;
161 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
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;
169 writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
172 static int aspeed_vuart_startup(struct uart_port *uart_port)
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;
178 rc = serial8250_do_startup(uart_port);
179 if (rc)
180 return rc;
182 aspeed_vuart_set_host_tx_discard(vuart, false);
184 return 0;
187 static void aspeed_vuart_shutdown(struct uart_port *uart_port)
189 struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
190 struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
192 aspeed_vuart_set_host_tx_discard(vuart, true);
194 serial8250_do_shutdown(uart_port);
197 static void __aspeed_vuart_set_throttle(struct uart_8250_port *up,
198 bool throttle)
200 unsigned char irqs = UART_IER_RLSI | UART_IER_RDI;
202 up->ier &= ~irqs;
203 if (!throttle)
204 up->ier |= irqs;
205 serial_out(up, UART_IER, up->ier);
207 static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
209 struct uart_8250_port *up = up_to_u8250p(port);
210 unsigned long flags;
212 spin_lock_irqsave(&port->lock, flags);
213 __aspeed_vuart_set_throttle(up, throttle);
214 spin_unlock_irqrestore(&port->lock, flags);
217 static void aspeed_vuart_throttle(struct uart_port *port)
219 aspeed_vuart_set_throttle(port, true);
222 static void aspeed_vuart_unthrottle(struct uart_port *port)
224 aspeed_vuart_set_throttle(port, false);
227 static void aspeed_vuart_unthrottle_exp(struct timer_list *timer)
229 struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer);
230 struct uart_8250_port *up = vuart->port;
232 if (!tty_buffer_space_avail(&up->port.state->port)) {
233 mod_timer(&vuart->unthrottle_timer,
234 jiffies + unthrottle_timeout);
235 return;
238 aspeed_vuart_unthrottle(&up->port);
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.
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.
252 static int aspeed_vuart_handle_irq(struct uart_port *port)
254 struct uart_8250_port *up = up_to_u8250p(port);
255 unsigned int iir, lsr;
256 unsigned long flags;
257 int space, count;
259 iir = serial_port_in(port, UART_IIR);
261 if (iir & UART_IIR_NO_INT)
262 return 0;
264 spin_lock_irqsave(&port->lock, flags);
266 lsr = serial_port_in(port, UART_LSR);
268 if (lsr & (UART_LSR_DR | UART_LSR_BI)) {
269 space = tty_buffer_space_avail(&port->state->port);
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);
276 if (!timer_pending(&vuart->unthrottle_timer)) {
277 vuart->port = up;
278 mod_timer(&vuart->unthrottle_timer,
279 jiffies + unthrottle_timeout);
282 } else {
283 count = min(space, 256);
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));
292 tty_flip_buffer_push(&port->state->port);
296 serial8250_modem_status(up);
297 if (lsr & UART_LSR_THRE)
298 serial8250_tx_chars(up);
300 uart_unlock_and_check_sysrq(port, flags);
302 return 1;
305 static int aspeed_vuart_probe(struct platform_device *pdev)
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;
314 np = pdev->dev.of_node;
316 vuart = devm_kzalloc(&pdev->dev, sizeof(*vuart), GFP_KERNEL);
317 if (!vuart)
318 return -ENOMEM;
320 vuart->dev = &pdev->dev;
321 timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0);
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);
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;
340 rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
341 if (rc < 0)
342 return rc;
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;
353 rc = clk_prepare_enable(vuart->clk);
354 if (rc < 0)
355 goto err_sysfs_remove;
357 clk = clk_get_rate(vuart->clk);
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);
364 /* Check for shifted address mapping */
365 if (of_property_read_u32(np, "reg-offset", &prop) == 0)
366 port.port.mapbase += prop;
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;
372 /* Check for fifo size */
373 if (of_property_read_u32(np, "fifo-size", &prop) == 0)
374 port.port.fifosize = prop;
376 /* Check for a fixed line number */
377 rc = of_alias_get_id(np, "serial");
378 if (rc >= 0)
379 port.port.line = rc;
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;
390 if (of_property_read_bool(np, "no-loopback-test"))
391 port.port.flags |= UPF_SKIP_TEST;
393 if (port.port.fifosize)
394 port.capabilities = UART_CAP_FIFO;
396 if (of_property_read_bool(np, "auto-flow-control"))
397 port.capabilities |= UART_CAP_AFE;
399 rc = serial8250_register_8250_port(&port);
400 if (rc < 0)
401 goto err_clk_disable;
403 vuart->line = rc;
405 aspeed_vuart_set_enabled(vuart, true);
406 aspeed_vuart_set_host_tx_discard(vuart, true);
407 platform_set_drvdata(pdev, vuart);
409 return 0;
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;
419 static int aspeed_vuart_remove(struct platform_device *pdev)
421 struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
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);
429 return 0;
432 static const struct of_device_id aspeed_vuart_table[] = {
433 { .compatible = "aspeed,ast2400-vuart" },
434 { .compatible = "aspeed,ast2500-vuart" },
435 { },
438 static struct platform_driver aspeed_vuart_driver = {
439 .driver = {
440 .name = "aspeed-vuart",
441 .of_match_table = aspeed_vuart_table,
443 .probe = aspeed_vuart_probe,
444 .remove = aspeed_vuart_remove,
447 module_platform_driver(aspeed_vuart_driver);
449 MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
450 MODULE_LICENSE("GPL");
451 MODULE_DESCRIPTION("Driver for Aspeed VUART device");