File Index
Files and directories
Sign in
FILE

8250_aspeed_vuart.c

File preview with syntax highlighting.

linux-6.19.14/drivers/tty/serial/8250/8250_aspeed_vuart.c C
  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#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/regmap.h>
 14#include <linux/mfd/syscon.h>
 15#include <linux/tty.h>
 16#include <linux/tty_flip.h>
 17#include <linux/clk.h>
 18
 19#include "8250.h"
 20
 21#define ASPEED_VUART_GCRA		0x20
 22#define ASPEED_VUART_GCRA_VUART_EN		BIT(0)
 23#define ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY	BIT(1)
 24#define ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD BIT(5)
 25#define ASPEED_VUART_GCRB		0x24
 26#define ASPEED_VUART_GCRB_HOST_SIRQ_MASK	GENMASK(7, 4)
 27#define ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT	4
 28#define ASPEED_VUART_ADDRL		0x28
 29#define ASPEED_VUART_ADDRH		0x2c
 30
 31#define ASPEED_VUART_DEFAULT_LPC_ADDR	0x3f8
 32#define ASPEED_VUART_DEFAULT_SIRQ	4
 33#define ASPEED_VUART_DEFAULT_SIRQ_POLARITY	IRQ_TYPE_LEVEL_LOW
 34
 35struct aspeed_vuart {
 36	struct device		*dev;
 37	int			line;
 38	struct timer_list	unthrottle_timer;
 39	struct uart_8250_port	*port;
 40};
 41
 42/*
 43 * If we fill the tty flip buffers, we throttle the data ready interrupt
 44 * to prevent dropped characters. This timeout defines how long we wait
 45 * to (conditionally, depending on buffer state) unthrottle.
 46 */
 47static const int unthrottle_timeout = HZ/10;
 48
 49/*
 50 * The VUART is basically two UART 'front ends' connected by their FIFO
 51 * (no actual serial line in between). One is on the BMC side (management
 52 * controller) and one is on the host CPU side.
 53 *
 54 * It allows the BMC to provide to the host a "UART" that pipes into
 55 * the BMC itself and can then be turned by the BMC into a network console
 56 * of some sort for example.
 57 *
 58 * This driver is for the BMC side. The sysfs files allow the BMC
 59 * userspace which owns the system configuration policy, to specify
 60 * at what IO port and interrupt number the host side will appear
 61 * to the host on the Host <-> BMC LPC bus. It could be different on a
 62 * different system (though most of them use 3f8/4).
 63 */
 64
 65static inline u8 aspeed_vuart_readb(struct aspeed_vuart *vuart, u8 reg)
 66{
 67	return readb(vuart->port->port.membase + reg);
 68}
 69
 70static inline void aspeed_vuart_writeb(struct aspeed_vuart *vuart, u8 val, u8 reg)
 71{
 72	writeb(val, vuart->port->port.membase + reg);
 73}
 74
 75static ssize_t lpc_address_show(struct device *dev,
 76				struct device_attribute *attr, char *buf)
 77{
 78	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
 79	u16 addr;
 80
 81	addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) |
 82		(aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL));
 83
 84	return sysfs_emit(buf, "0x%x\n", addr);
 85}
 86
 87static int aspeed_vuart_set_lpc_address(struct aspeed_vuart *vuart, u32 addr)
 88{
 89	if (addr > U16_MAX)
 90		return -EINVAL;
 91
 92	aspeed_vuart_writeb(vuart, addr >> 8, ASPEED_VUART_ADDRH);
 93	aspeed_vuart_writeb(vuart, addr >> 0, ASPEED_VUART_ADDRL);
 94
 95	return 0;
 96}
 97
 98static ssize_t lpc_address_store(struct device *dev,
 99				 struct device_attribute *attr,
100				 const char *buf, size_t count)
101{
102	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
103	u32 val;
104	int err;
105
106	err = kstrtou32(buf, 0, &val);
107	if (err)
108		return err;
109
110	err = aspeed_vuart_set_lpc_address(vuart, val);
111	return err ? : count;
112}
113
114static DEVICE_ATTR_RW(lpc_address);
115
116static ssize_t sirq_show(struct device *dev,
117			 struct device_attribute *attr, char *buf)
118{
119	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
120	u8 reg;
121
122	reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB);
123	reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
124	reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
125
126	return sysfs_emit(buf, "%u\n", reg);
127}
128
129static int aspeed_vuart_set_sirq(struct aspeed_vuart *vuart, u32 sirq)
130{
131	u8 reg;
132
133	if (sirq > (ASPEED_VUART_GCRB_HOST_SIRQ_MASK >> ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT))
134		return -EINVAL;
135
136	sirq <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
137	sirq &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
138
139	reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB);
140	reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
141	reg |= sirq;
142	aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRB);
143
144	return 0;
145}
146
147static ssize_t sirq_store(struct device *dev, struct device_attribute *attr,
148			  const char *buf, size_t count)
149{
150	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
151	unsigned long val;
152	int err;
153
154	err = kstrtoul(buf, 0, &val);
155	if (err)
156		return err;
157
158	err = aspeed_vuart_set_sirq(vuart, val);
159	return err ? : count;
160}
161
162static DEVICE_ATTR_RW(sirq);
163
164static ssize_t sirq_polarity_show(struct device *dev,
165				  struct device_attribute *attr, char *buf)
166{
167	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
168	u8 reg;
169
170	reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
171	reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
172
173	return sysfs_emit(buf, "%u\n", reg ? 1 : 0);
174}
175
176static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart,
177					   bool polarity)
178{
179	u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
180
181	if (polarity)
182		reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
183	else
184		reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
185
186	aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
187}
188
189static ssize_t sirq_polarity_store(struct device *dev,
190				   struct device_attribute *attr,
191				   const char *buf, size_t count)
192{
193	struct aspeed_vuart *vuart = dev_get_drvdata(dev);
194	unsigned long val;
195	int err;
196
197	err = kstrtoul(buf, 0, &val);
198	if (err)
199		return err;
200
201	aspeed_vuart_set_sirq_polarity(vuart, val != 0);
202
203	return count;
204}
205
206static DEVICE_ATTR_RW(sirq_polarity);
207
208static struct attribute *aspeed_vuart_attrs[] = {
209	&dev_attr_sirq.attr,
210	&dev_attr_sirq_polarity.attr,
211	&dev_attr_lpc_address.attr,
212	NULL,
213};
214
215static const struct attribute_group aspeed_vuart_attr_group = {
216	.attrs = aspeed_vuart_attrs,
217};
218
219static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
220{
221	u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
222
223	if (enabled)
224		reg |= ASPEED_VUART_GCRA_VUART_EN;
225	else
226		reg &= ~ASPEED_VUART_GCRA_VUART_EN;
227
228	aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
229}
230
231static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
232					     bool discard)
233{
234	u8 reg;
235
236	reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
237
238	/* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */
239	if (!discard)
240		reg |= ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
241	else
242		reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
243
244	aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
245}
246
247static int aspeed_vuart_startup(struct uart_port *uart_port)
248{
249	struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
250	struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
251	int rc;
252
253	rc = serial8250_do_startup(uart_port);
254	if (rc)
255		return rc;
256
257	aspeed_vuart_set_host_tx_discard(vuart, false);
258
259	return 0;
260}
261
262static void aspeed_vuart_shutdown(struct uart_port *uart_port)
263{
264	struct uart_8250_port *uart_8250_port = up_to_u8250p(uart_port);
265	struct aspeed_vuart *vuart = uart_8250_port->port.private_data;
266
267	aspeed_vuart_set_host_tx_discard(vuart, true);
268
269	serial8250_do_shutdown(uart_port);
270}
271
272static void __aspeed_vuart_set_throttle(struct uart_8250_port *up,
273		bool throttle)
274{
275	unsigned char irqs = UART_IER_RLSI | UART_IER_RDI;
276
277	/* Port locked to synchronize UART_IER access against the console. */
278	lockdep_assert_held_once(&up->port.lock);
279
280	up->ier &= ~irqs;
281	if (!throttle)
282		up->ier |= irqs;
283	serial_out(up, UART_IER, up->ier);
284}
285static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle)
286{
287	struct uart_8250_port *up = up_to_u8250p(port);
288	unsigned long flags;
289
290	uart_port_lock_irqsave(port, &flags);
291	__aspeed_vuart_set_throttle(up, throttle);
292	uart_port_unlock_irqrestore(port, flags);
293}
294
295static void aspeed_vuart_throttle(struct uart_port *port)
296{
297	aspeed_vuart_set_throttle(port, true);
298}
299
300static void aspeed_vuart_unthrottle(struct uart_port *port)
301{
302	aspeed_vuart_set_throttle(port, false);
303}
304
305static void aspeed_vuart_unthrottle_exp(struct timer_list *timer)
306{
307	struct aspeed_vuart *vuart = timer_container_of(vuart, timer,
308							unthrottle_timer);
309	struct uart_8250_port *up = vuart->port;
310
311	if (!tty_buffer_space_avail(&up->port.state->port)) {
312		mod_timer(&vuart->unthrottle_timer,
313			  jiffies + unthrottle_timeout);
314		return;
315	}
316
317	aspeed_vuart_unthrottle(&up->port);
318}
319
320/*
321 * Custom interrupt handler to manage finer-grained flow control. Although we
322 * have throttle/unthrottle callbacks, we've seen that the VUART device can
323 * deliver characters faster than the ldisc has a chance to check buffer space
324 * against the throttle threshold. This results in dropped characters before
325 * the throttle.
326 *
327 * We do this by checking for flip buffer space before RX. If we have no space,
328 * throttle now and schedule an unthrottle for later, once the ldisc has had
329 * a chance to drain the buffers.
330 */
331static int aspeed_vuart_handle_irq(struct uart_port *port)
332{
333	struct uart_8250_port *up = up_to_u8250p(port);
334	unsigned int iir, lsr;
335	unsigned long flags;
336	unsigned int space, count;
337
338	iir = serial_port_in(port, UART_IIR);
339
340	if (iir & UART_IIR_NO_INT)
341		return 0;
342
343	uart_port_lock_irqsave(port, &flags);
344
345	lsr = serial_port_in(port, UART_LSR);
346
347	if (lsr & (UART_LSR_DR | UART_LSR_BI)) {
348		space = tty_buffer_space_avail(&port->state->port);
349
350		if (!space) {
351			/* throttle and schedule an unthrottle later */
352			struct aspeed_vuart *vuart = port->private_data;
353			__aspeed_vuart_set_throttle(up, true);
354
355			if (!timer_pending(&vuart->unthrottle_timer))
356				mod_timer(&vuart->unthrottle_timer,
357					  jiffies + unthrottle_timeout);
358
359		} else {
360			count = min(space, 256U);
361
362			do {
363				serial8250_read_char(up, lsr);
364				lsr = serial_in(up, UART_LSR);
365				if (--count == 0)
366					break;
367			} while (lsr & (UART_LSR_DR | UART_LSR_BI));
368
369			tty_flip_buffer_push(&port->state->port);
370		}
371	}
372
373	serial8250_modem_status(up);
374	if (lsr & UART_LSR_THRE)
375		serial8250_tx_chars(up);
376
377	uart_unlock_and_check_sysrq_irqrestore(port, flags);
378
379	return 1;
380}
381
382static void aspeed_vuart_auto_configure_sirq_polarity(
383	struct aspeed_vuart *vuart, struct device_node *syscon_np,
384	u32 reg_offset, u32 reg_mask)
385{
386	struct regmap *regmap;
387	u32 value;
388
389	regmap = syscon_node_to_regmap(syscon_np);
390	if (IS_ERR(regmap)) {
391		dev_warn(vuart->dev,
392			 "could not get regmap for aspeed,sirq-polarity-sense\n");
393		return;
394	}
395	if (regmap_read(regmap, reg_offset, &value)) {
396		dev_warn(vuart->dev, "could not read hw strap table\n");
397		return;
398	}
399
400	aspeed_vuart_set_sirq_polarity(vuart, (value & reg_mask) == 0);
401}
402
403static int aspeed_vuart_map_irq_polarity(u32 dt)
404{
405	switch (dt) {
406	case IRQ_TYPE_LEVEL_LOW:
407		return 0;
408	case IRQ_TYPE_LEVEL_HIGH:
409		return 1;
410	default:
411		return -EINVAL;
412	}
413}
414
415static int aspeed_vuart_probe(struct platform_device *pdev)
416{
417	struct of_phandle_args sirq_polarity_sense_args;
418	struct device *dev = &pdev->dev;
419	struct uart_8250_port port;
420	struct aspeed_vuart *vuart;
421	struct device_node *np;
422	struct resource *res;
423	int rc, sirq_polarity;
424	u32 prop, sirq[2];
425	struct clk *vclk;
426
427	np = pdev->dev.of_node;
428
429	vuart = devm_kzalloc(&pdev->dev, sizeof(*vuart), GFP_KERNEL);
430	if (!vuart)
431		return -ENOMEM;
432
433	vuart->dev = &pdev->dev;
434	timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0);
435
436	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
437	if (!res)
438		return -EINVAL;
439
440	memset(&port, 0, sizeof(port));
441	port.port.private_data = vuart;
442	port.port.mapbase = res->start;
443	port.port.mapsize = resource_size(res);
444	port.port.startup = aspeed_vuart_startup;
445	port.port.shutdown = aspeed_vuart_shutdown;
446	port.port.throttle = aspeed_vuart_throttle;
447	port.port.unthrottle = aspeed_vuart_unthrottle;
448	port.port.status = UPSTAT_SYNC_FIFO;
449	port.port.dev = &pdev->dev;
450	port.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
451	port.port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE |
452			  UPF_NO_THRE_TEST;
453	port.bugs |= UART_BUG_TXRACE;
454
455	rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
456	if (rc < 0)
457		return rc;
458
459	rc = uart_read_port_properties(&port.port);
460	if (rc)
461		goto err_sysfs_remove;
462
463	/* Get clk rate through clk driver if present */
464	if (!port.port.uartclk) {
465		vclk = devm_clk_get_enabled(dev, NULL);
466		if (IS_ERR(vclk)) {
467			rc = dev_err_probe(dev, PTR_ERR(vclk), "clk or clock-frequency not defined\n");
468			goto err_sysfs_remove;
469		}
470
471		port.port.uartclk = clk_get_rate(vclk);
472	}
473
474	/* If current-speed was set, then try not to change it. */
475	if (of_property_read_u32(np, "current-speed", &prop) == 0)
476		port.port.custom_divisor = port.port.uartclk / (16 * prop);
477
478	port.port.handle_irq = aspeed_vuart_handle_irq;
479	port.port.type = PORT_ASPEED_VUART;
480
481	if (port.port.fifosize)
482		port.capabilities = UART_CAP_FIFO;
483
484	if (of_property_read_bool(np, "auto-flow-control"))
485		port.capabilities |= UART_CAP_AFE;
486
487	rc = serial8250_register_8250_port(&port);
488	if (rc < 0)
489		goto err_sysfs_remove;
490
491	vuart->line = rc;
492	vuart->port = serial8250_get_port(vuart->line);
493
494	rc = of_parse_phandle_with_fixed_args(
495		np, "aspeed,sirq-polarity-sense", 2, 0,
496		&sirq_polarity_sense_args);
497	if (rc < 0) {
498		dev_dbg(&pdev->dev,
499			"aspeed,sirq-polarity-sense property not found\n");
500	} else {
501		aspeed_vuart_auto_configure_sirq_polarity(
502			vuart, sirq_polarity_sense_args.np,
503			sirq_polarity_sense_args.args[0],
504			BIT(sirq_polarity_sense_args.args[1]));
505		of_node_put(sirq_polarity_sense_args.np);
506	}
507
508	rc = of_property_read_u32(np, "aspeed,lpc-io-reg", &prop);
509	if (rc < 0)
510		prop = ASPEED_VUART_DEFAULT_LPC_ADDR;
511
512	rc = aspeed_vuart_set_lpc_address(vuart, prop);
513	if (rc < 0) {
514		dev_err_probe(dev, rc, "invalid value in aspeed,lpc-io-reg property\n");
515		goto err_sysfs_remove;
516	}
517
518	rc = of_property_read_u32_array(np, "aspeed,lpc-interrupts", sirq, 2);
519	if (rc < 0) {
520		sirq[0] = ASPEED_VUART_DEFAULT_SIRQ;
521		sirq[1] = ASPEED_VUART_DEFAULT_SIRQ_POLARITY;
522	}
523
524	rc = aspeed_vuart_set_sirq(vuart, sirq[0]);
525	if (rc < 0) {
526		dev_err_probe(dev, rc, "invalid sirq number in aspeed,lpc-interrupts property\n");
527		goto err_sysfs_remove;
528	}
529
530	sirq_polarity = aspeed_vuart_map_irq_polarity(sirq[1]);
531	if (sirq_polarity < 0) {
532		rc = dev_err_probe(dev, sirq_polarity,
533				   "invalid sirq polarity in aspeed,lpc-interrupts property\n");
534		goto err_sysfs_remove;
535	}
536
537	aspeed_vuart_set_sirq_polarity(vuart, sirq_polarity);
538
539	aspeed_vuart_set_enabled(vuart, true);
540	aspeed_vuart_set_host_tx_discard(vuart, true);
541	platform_set_drvdata(pdev, vuart);
542
543	return 0;
544
545err_sysfs_remove:
546	sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
547	return rc;
548}
549
550static void aspeed_vuart_remove(struct platform_device *pdev)
551{
552	struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
553
554	timer_delete_sync(&vuart->unthrottle_timer);
555	aspeed_vuart_set_enabled(vuart, false);
556	serial8250_unregister_port(vuart->line);
557	sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
558}
559
560static const struct of_device_id aspeed_vuart_table[] = {
561	{ .compatible = "aspeed,ast2400-vuart" },
562	{ .compatible = "aspeed,ast2500-vuart" },
563	{ },
564};
565MODULE_DEVICE_TABLE(of, aspeed_vuart_table);
566
567static struct platform_driver aspeed_vuart_driver = {
568	.driver = {
569		.name = "aspeed-vuart",
570		.of_match_table = aspeed_vuart_table,
571	},
572	.probe = aspeed_vuart_probe,
573	.remove = aspeed_vuart_remove,
574};
575
576module_platform_driver(aspeed_vuart_driver);
577
578MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
579MODULE_LICENSE("GPL");
580MODULE_DESCRIPTION("Driver for Aspeed VUART device");
~/ Read-only file preview.