root/drivers/tty/serial/8250/8250_aspeed_vuart.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lpc_address_show
  2. lpc_address_store
  3. sirq_show
  4. sirq_store
  5. aspeed_vuart_set_enabled
  6. aspeed_vuart_set_host_tx_discard
  7. aspeed_vuart_startup
  8. aspeed_vuart_shutdown
  9. __aspeed_vuart_set_throttle
  10. aspeed_vuart_set_throttle
  11. aspeed_vuart_throttle
  12. aspeed_vuart_unthrottle
  13. aspeed_vuart_unthrottle_exp
  14. aspeed_vuart_handle_irq
  15. aspeed_vuart_probe
  16. aspeed_vuart_remove

   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 
  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 
  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 
  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 
 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 
 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 
 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 
 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 
 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 
 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 }
 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 
 217 static void aspeed_vuart_throttle(struct uart_port *port)
 218 {
 219         aspeed_vuart_set_throttle(port, true);
 220 }
 221 
 222 static void aspeed_vuart_unthrottle(struct uart_port *port)
 223 {
 224         aspeed_vuart_set_throttle(port, false);
 225 }
 226 
 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  */
 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 
 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.handle_irq = aspeed_vuart_handle_irq;
 383         port.port.iotype = UPIO_MEM;
 384         port.port.type = PORT_16550A;
 385         port.port.uartclk = clk;
 386         port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
 387                 | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
 388 
 389         if (of_property_read_bool(np, "no-loopback-test"))
 390                 port.port.flags |= UPF_SKIP_TEST;
 391 
 392         if (port.port.fifosize)
 393                 port.capabilities = UART_CAP_FIFO;
 394 
 395         if (of_property_read_bool(np, "auto-flow-control"))
 396                 port.capabilities |= UART_CAP_AFE;
 397 
 398         rc = serial8250_register_8250_port(&port);
 399         if (rc < 0)
 400                 goto err_clk_disable;
 401 
 402         vuart->line = rc;
 403 
 404         aspeed_vuart_set_enabled(vuart, true);
 405         aspeed_vuart_set_host_tx_discard(vuart, true);
 406         platform_set_drvdata(pdev, vuart);
 407 
 408         return 0;
 409 
 410 err_clk_disable:
 411         clk_disable_unprepare(vuart->clk);
 412         irq_dispose_mapping(port.port.irq);
 413 err_sysfs_remove:
 414         sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
 415         return rc;
 416 }
 417 
 418 static int aspeed_vuart_remove(struct platform_device *pdev)
 419 {
 420         struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
 421 
 422         del_timer_sync(&vuart->unthrottle_timer);
 423         aspeed_vuart_set_enabled(vuart, false);
 424         serial8250_unregister_port(vuart->line);
 425         sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
 426         clk_disable_unprepare(vuart->clk);
 427 
 428         return 0;
 429 }
 430 
 431 static const struct of_device_id aspeed_vuart_table[] = {
 432         { .compatible = "aspeed,ast2400-vuart" },
 433         { .compatible = "aspeed,ast2500-vuart" },
 434         { },
 435 };
 436 
 437 static struct platform_driver aspeed_vuart_driver = {
 438         .driver = {
 439                 .name = "aspeed-vuart",
 440                 .of_match_table = aspeed_vuart_table,
 441         },
 442         .probe = aspeed_vuart_probe,
 443         .remove = aspeed_vuart_remove,
 444 };
 445 
 446 module_platform_driver(aspeed_vuart_driver);
 447 
 448 MODULE_AUTHOR("Jeremy Kerr <jk@ozlabs.org>");
 449 MODULE_LICENSE("GPL");
 450 MODULE_DESCRIPTION("Driver for Aspeed VUART device");

/* [<][>][^][v][top][bottom][index][help] */