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