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