x86/topology: Update the 'cpu cores' field in /proc/cpuinfo correctly across CPU...
[cris-mirror.git] / drivers / tty / serial / 8250 / 8250_aspeed_vuart.c
blob74a408d9db24c1fc7e2c4466867f3585ee42a067
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 #include <linux/device.h>
9 #include <linux/module.h>
10 #include <linux/of_address.h>
11 #include <linux/of_irq.h>
12 #include <linux/of_platform.h>
13 #include <linux/clk.h>
15 #include "8250.h"
17 #define ASPEED_VUART_GCRA 0x20
18 #define ASPEED_VUART_GCRA_VUART_EN BIT(0)
19 #define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
20 #define ASPEED_VUART_GCRB 0x24
21 #define ASPEED_VUART_GCRB_HOST_SIRQ_MASK GENMASK(7, 4)
22 #define ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT 4
23 #define ASPEED_VUART_ADDRL 0x28
24 #define ASPEED_VUART_ADDRH 0x2c
26 struct aspeed_vuart {
27 struct device *dev;
28 void __iomem *regs;
29 struct clk *clk;
30 int line;
34 * The VUART is basically two UART 'front ends' connected by their FIFO
35 * (no actual serial line in between). One is on the BMC side (management
36 * controller) and one is on the host CPU side.
38 * It allows the BMC to provide to the host a "UART" that pipes into
39 * the BMC itself and can then be turned by the BMC into a network console
40 * of some sort for example.
42 * This driver is for the BMC side. The sysfs files allow the BMC
43 * userspace which owns the system configuration policy, to specify
44 * at what IO port and interrupt number the host side will appear
45 * to the host on the Host <-> BMC LPC bus. It could be different on a
46 * different system (though most of them use 3f8/4).
49 static ssize_t lpc_address_show(struct device *dev,
50 struct device_attribute *attr, char *buf)
52 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
53 u16 addr;
55 addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) |
56 (readb(vuart->regs + ASPEED_VUART_ADDRL));
58 return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
61 static ssize_t lpc_address_store(struct device *dev,
62 struct device_attribute *attr,
63 const char *buf, size_t count)
65 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
66 unsigned long val;
67 int err;
69 err = kstrtoul(buf, 0, &val);
70 if (err)
71 return err;
73 writeb(val >> 8, vuart->regs + ASPEED_VUART_ADDRH);
74 writeb(val >> 0, vuart->regs + ASPEED_VUART_ADDRL);
76 return count;
79 static DEVICE_ATTR_RW(lpc_address);
81 static ssize_t sirq_show(struct device *dev,
82 struct device_attribute *attr, char *buf)
84 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
85 u8 reg;
87 reg = readb(vuart->regs + ASPEED_VUART_GCRB);
88 reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
89 reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
91 return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg);
94 static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
95 const char *buf, size_t count)
97 struct aspeed_vuart *vuart = dev_get_drvdata(dev);
98 unsigned long val;
99 int err;
100 u8 reg;
102 err = kstrtoul(buf, 0, &val);
103 if (err)
104 return err;
106 val <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
107 val &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
109 reg = readb(vuart->regs + ASPEED_VUART_GCRB);
110 reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
111 reg |= val;
112 writeb(reg, vuart->regs + ASPEED_VUART_GCRB);
114 return count;
117 static DEVICE_ATTR_RW(sirq);
119 static struct attribute *aspeed_vuart_attrs[] = {
120 &dev_attr_sirq.attr,
121 &dev_attr_lpc_address.attr,
122 NULL,
125 static const struct attribute_group aspeed_vuart_attr_group = {
126 .attrs = aspeed_vuart_attrs,
129 static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
131 u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
133 if (enabled)
134 reg |= ASPEED_VUART_GCRA_VUART_EN;
135 else
136 reg &= ~ASPEED_VUART_GCRA_VUART_EN;
138 writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
141 static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
142 bool discard)
144 u8 reg;
146 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
148 /* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */
149 if (!discard)
150 reg |= ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
151 else
152 reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
154 writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
157 static int aspeed_vuart_startup(struct uart_port *uart_port)
159 struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
160 struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
161 int rc;
163 rc = serial8250_do_startup(uart_port);
164 if (rc)
165 return rc;
167 aspeed_vuart_set_host_tx_discard(vuart, false);
169 return 0;
172 static void aspeed_vuart_shutdown(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;
177 aspeed_vuart_set_host_tx_discard(vuart, true);
179 serial8250_do_shutdown(uart_port);
182 static int aspeed_vuart_probe(struct platform_device *pdev)
184 struct uart_8250_port port;
185 struct aspeed_vuart *vuart;
186 struct device_node *np;
187 struct resource *res;
188 u32 clk, prop;
189 int rc;
191 np = pdev->dev.of_node;
193 vuart = devm_kzalloc(&pdev->dev, sizeof(*vuart), GFP_KERNEL);
194 if (!vuart)
195 return -ENOMEM;
197 vuart->dev = &pdev->dev;
199 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
200 vuart->regs = devm_ioremap_resource(&pdev->dev, res);
201 if (IS_ERR(vuart->regs))
202 return PTR_ERR(vuart->regs);
204 memset(&port, 0, sizeof(port));
205 port.port.private_data = vuart;
206 port.port.membase = vuart->regs;
207 port.port.mapbase = res->start;
208 port.port.mapsize = resource_size(res);
209 port.port.startup = aspeed_vuart_startup;
210 port.port.shutdown = aspeed_vuart_shutdown;
211 port.port.dev = &pdev->dev;
213 rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
214 if (rc < 0)
215 return rc;
217 if (of_property_read_u32(np, "clock-frequency", &clk)) {
218 vuart->clk = devm_clk_get(&pdev->dev, NULL);
219 if (IS_ERR(vuart->clk)) {
220 dev_warn(&pdev->dev,
221 "clk or clock-frequency not defined\n");
222 rc = PTR_ERR(vuart->clk);
223 goto err_sysfs_remove;
226 rc = clk_prepare_enable(vuart->clk);
227 if (rc < 0)
228 goto err_sysfs_remove;
230 clk = clk_get_rate(vuart->clk);
233 /* If current-speed was set, then try not to change it. */
234 if (of_property_read_u32(np, "current-speed", &prop) == 0)
235 port.port.custom_divisor = clk / (16 * prop);
237 /* Check for shifted address mapping */
238 if (of_property_read_u32(np, "reg-offset", &prop) == 0)
239 port.port.mapbase += prop;
241 /* Check for registers offset within the devices address range */
242 if (of_property_read_u32(np, "reg-shift", &prop) == 0)
243 port.port.regshift = prop;
245 /* Check for fifo size */
246 if (of_property_read_u32(np, "fifo-size", &prop) == 0)
247 port.port.fifosize = prop;
249 /* Check for a fixed line number */
250 rc = of_alias_get_id(np, "serial");
251 if (rc >= 0)
252 port.port.line = rc;
254 port.port.irq = irq_of_parse_and_map(np, 0);
255 port.port.irqflags = IRQF_SHARED;
256 port.port.iotype = UPIO_MEM;
257 port.port.type = PORT_16550A;
258 port.port.uartclk = clk;
259 port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
260 | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
262 if (of_property_read_bool(np, "no-loopback-test"))
263 port.port.flags |= UPF_SKIP_TEST;
265 if (port.port.fifosize)
266 port.capabilities = UART_CAP_FIFO;
268 if (of_property_read_bool(np, "auto-flow-control"))
269 port.capabilities |= UART_CAP_AFE;
271 rc = serial8250_register_8250_port(&port);
272 if (rc < 0)
273 goto err_clk_disable;
275 vuart->line = rc;
277 aspeed_vuart_set_enabled(vuart, true);
278 aspeed_vuart_set_host_tx_discard(vuart, true);
279 platform_set_drvdata(pdev, vuart);
281 return 0;
283 err_clk_disable:
284 clk_disable_unprepare(vuart->clk);
285 irq_dispose_mapping(port.port.irq);
286 err_sysfs_remove:
287 sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
288 return rc;
291 static int aspeed_vuart_remove(struct platform_device *pdev)
293 struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
295 aspeed_vuart_set_enabled(vuart, false);
296 serial8250_unregister_port(vuart->line);
297 sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
298 clk_disable_unprepare(vuart->clk);
300 return 0;
303 static const struct of_device_id aspeed_vuart_table[] = {
304 { .compatible = "aspeed,ast2400-vuart" },
305 { .compatible = "aspeed,ast2500-vuart" },
306 { },
309 static struct platform_driver aspeed_vuart_driver = {
310 .driver = {
311 .name = "aspeed-vuart",
312 .of_match_table = aspeed_vuart_table,
314 .probe = aspeed_vuart_probe,
315 .remove = aspeed_vuart_remove,
318 module_platform_driver(aspeed_vuart_driver);
320 MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
321 MODULE_LICENSE("GPL");
322 MODULE_DESCRIPTION("Driver for Aspeed VUART device");