linux/drivers/tty/goldfish.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2007 Google, Inc.
   4 * Copyright (C) 2012 Intel, Inc.
   5 * Copyright (C) 2017 Imagination Technologies Ltd.
   6 */
   7
   8#include <linux/console.h>
   9#include <linux/interrupt.h>
  10#include <linux/platform_device.h>
  11#include <linux/tty.h>
  12#include <linux/tty_flip.h>
  13#include <linux/slab.h>
  14#include <linux/io.h>
  15#include <linux/module.h>
  16#include <linux/mod_devicetable.h>
  17#include <linux/goldfish.h>
  18#include <linux/mm.h>
  19#include <linux/dma-mapping.h>
  20#include <linux/serial_core.h>
  21
  22/* Goldfish tty register's offsets */
  23#define GOLDFISH_TTY_REG_BYTES_READY    0x04
  24#define GOLDFISH_TTY_REG_CMD            0x08
  25#define GOLDFISH_TTY_REG_DATA_PTR       0x10
  26#define GOLDFISH_TTY_REG_DATA_LEN       0x14
  27#define GOLDFISH_TTY_REG_DATA_PTR_HIGH  0x18
  28#define GOLDFISH_TTY_REG_VERSION        0x20
  29
  30/* Goldfish tty commands */
  31#define GOLDFISH_TTY_CMD_INT_DISABLE    0
  32#define GOLDFISH_TTY_CMD_INT_ENABLE     1
  33#define GOLDFISH_TTY_CMD_WRITE_BUFFER   2
  34#define GOLDFISH_TTY_CMD_READ_BUFFER    3
  35
  36struct goldfish_tty {
  37        struct tty_port port;
  38        spinlock_t lock;
  39        void __iomem *base;
  40        u32 irq;
  41        int opencount;
  42        struct console console;
  43        u32 version;
  44        struct device *dev;
  45};
  46
  47static DEFINE_MUTEX(goldfish_tty_lock);
  48static struct tty_driver *goldfish_tty_driver;
  49static u32 goldfish_tty_line_count = 8;
  50static u32 goldfish_tty_current_line_count;
  51static struct goldfish_tty *goldfish_ttys;
  52
  53static void do_rw_io(struct goldfish_tty *qtty,
  54                     unsigned long address,
  55                     unsigned int count,
  56                     int is_write)
  57{
  58        unsigned long irq_flags;
  59        void __iomem *base = qtty->base;
  60
  61        spin_lock_irqsave(&qtty->lock, irq_flags);
  62        gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR,
  63                     base + GOLDFISH_TTY_REG_DATA_PTR_HIGH);
  64        __raw_writel(count, base + GOLDFISH_TTY_REG_DATA_LEN);
  65
  66        if (is_write)
  67                __raw_writel(GOLDFISH_TTY_CMD_WRITE_BUFFER,
  68                       base + GOLDFISH_TTY_REG_CMD);
  69        else
  70                __raw_writel(GOLDFISH_TTY_CMD_READ_BUFFER,
  71                       base + GOLDFISH_TTY_REG_CMD);
  72
  73        spin_unlock_irqrestore(&qtty->lock, irq_flags);
  74}
  75
  76static void goldfish_tty_rw(struct goldfish_tty *qtty,
  77                            unsigned long addr,
  78                            unsigned int count,
  79                            int is_write)
  80{
  81        dma_addr_t dma_handle;
  82        enum dma_data_direction dma_dir;
  83
  84        dma_dir = (is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
  85        if (qtty->version > 0) {
  86                /*
  87                 * Goldfish TTY for Ranchu platform uses
  88                 * physical addresses and DMA for read/write operations
  89                 */
  90                unsigned long addr_end = addr + count;
  91
  92                while (addr < addr_end) {
  93                        unsigned long pg_end = (addr & PAGE_MASK) + PAGE_SIZE;
  94                        unsigned long next =
  95                                        pg_end < addr_end ? pg_end : addr_end;
  96                        unsigned long avail = next - addr;
  97
  98                        /*
  99                         * Map the buffer's virtual address to the DMA address
 100                         * so the buffer can be accessed by the device.
 101                         */
 102                        dma_handle = dma_map_single(qtty->dev, (void *)addr,
 103                                                    avail, dma_dir);
 104
 105                        if (dma_mapping_error(qtty->dev, dma_handle)) {
 106                                dev_err(qtty->dev, "tty: DMA mapping error.\n");
 107                                return;
 108                        }
 109                        do_rw_io(qtty, dma_handle, avail, is_write);
 110
 111                        /*
 112                         * Unmap the previously mapped region after
 113                         * the completion of the read/write operation.
 114                         */
 115                        dma_unmap_single(qtty->dev, dma_handle, avail, dma_dir);
 116
 117                        addr += avail;
 118                }
 119        } else {
 120                /*
 121                 * Old style Goldfish TTY used on the Goldfish platform
 122                 * uses virtual addresses.
 123                 */
 124                do_rw_io(qtty, addr, count, is_write);
 125        }
 126}
 127
 128static void goldfish_tty_do_write(int line, const char *buf,
 129                                  unsigned int count)
 130{
 131        struct goldfish_tty *qtty = &goldfish_ttys[line];
 132        unsigned long address = (unsigned long)(void *)buf;
 133
 134        goldfish_tty_rw(qtty, address, count, 1);
 135}
 136
 137static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
 138{
 139        struct goldfish_tty *qtty = dev_id;
 140        void __iomem *base = qtty->base;
 141        unsigned long address;
 142        unsigned char *buf;
 143        u32 count;
 144
 145        count = __raw_readl(base + GOLDFISH_TTY_REG_BYTES_READY);
 146        if (count == 0)
 147                return IRQ_NONE;
 148
 149        count = tty_prepare_flip_string(&qtty->port, &buf, count);
 150
 151        address = (unsigned long)(void *)buf;
 152        goldfish_tty_rw(qtty, address, count, 0);
 153
 154        tty_schedule_flip(&qtty->port);
 155        return IRQ_HANDLED;
 156}
 157
 158static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
 159{
 160        struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
 161                                                                        port);
 162        __raw_writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
 163        return 0;
 164}
 165
 166static void goldfish_tty_shutdown(struct tty_port *port)
 167{
 168        struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
 169                                                                        port);
 170        __raw_writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
 171}
 172
 173static int goldfish_tty_open(struct tty_struct *tty, struct file *filp)
 174{
 175        struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
 176        return tty_port_open(&qtty->port, tty, filp);
 177}
 178
 179static void goldfish_tty_close(struct tty_struct *tty, struct file *filp)
 180{
 181        tty_port_close(tty->port, tty, filp);
 182}
 183
 184static void goldfish_tty_hangup(struct tty_struct *tty)
 185{
 186        tty_port_hangup(tty->port);
 187}
 188
 189static int goldfish_tty_write(struct tty_struct *tty, const unsigned char *buf,
 190                                                                int count)
 191{
 192        goldfish_tty_do_write(tty->index, buf, count);
 193        return count;
 194}
 195
 196static unsigned int goldfish_tty_write_room(struct tty_struct *tty)
 197{
 198        return 0x10000;
 199}
 200
 201static unsigned int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
 202{
 203        struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
 204        void __iomem *base = qtty->base;
 205        return __raw_readl(base + GOLDFISH_TTY_REG_BYTES_READY);
 206}
 207
 208static void goldfish_tty_console_write(struct console *co, const char *b,
 209                                                                unsigned count)
 210{
 211        goldfish_tty_do_write(co->index, b, count);
 212}
 213
 214static struct tty_driver *goldfish_tty_console_device(struct console *c,
 215                                                                int *index)
 216{
 217        *index = c->index;
 218        return goldfish_tty_driver;
 219}
 220
 221static int goldfish_tty_console_setup(struct console *co, char *options)
 222{
 223        if ((unsigned)co->index >= goldfish_tty_line_count)
 224                return -ENODEV;
 225        if (!goldfish_ttys[co->index].base)
 226                return -ENODEV;
 227        return 0;
 228}
 229
 230static const struct tty_port_operations goldfish_port_ops = {
 231        .activate = goldfish_tty_activate,
 232        .shutdown = goldfish_tty_shutdown
 233};
 234
 235static const struct tty_operations goldfish_tty_ops = {
 236        .open = goldfish_tty_open,
 237        .close = goldfish_tty_close,
 238        .hangup = goldfish_tty_hangup,
 239        .write = goldfish_tty_write,
 240        .write_room = goldfish_tty_write_room,
 241        .chars_in_buffer = goldfish_tty_chars_in_buffer,
 242};
 243
 244static int goldfish_tty_create_driver(void)
 245{
 246        int ret;
 247        struct tty_driver *tty;
 248
 249        goldfish_ttys = kcalloc(goldfish_tty_line_count,
 250                                sizeof(*goldfish_ttys),
 251                                GFP_KERNEL);
 252        if (goldfish_ttys == NULL) {
 253                ret = -ENOMEM;
 254                goto err_alloc_goldfish_ttys_failed;
 255        }
 256        tty = tty_alloc_driver(goldfish_tty_line_count,
 257                        TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
 258                        TTY_DRIVER_DYNAMIC_DEV);
 259        if (IS_ERR(tty)) {
 260                ret = PTR_ERR(tty);
 261                goto err_tty_alloc_driver_failed;
 262        }
 263        tty->driver_name = "goldfish";
 264        tty->name = "ttyGF";
 265        tty->type = TTY_DRIVER_TYPE_SERIAL;
 266        tty->subtype = SERIAL_TYPE_NORMAL;
 267        tty->init_termios = tty_std_termios;
 268        tty_set_operations(tty, &goldfish_tty_ops);
 269        ret = tty_register_driver(tty);
 270        if (ret)
 271                goto err_tty_register_driver_failed;
 272
 273        goldfish_tty_driver = tty;
 274        return 0;
 275
 276err_tty_register_driver_failed:
 277        tty_driver_kref_put(tty);
 278err_tty_alloc_driver_failed:
 279        kfree(goldfish_ttys);
 280        goldfish_ttys = NULL;
 281err_alloc_goldfish_ttys_failed:
 282        return ret;
 283}
 284
 285static void goldfish_tty_delete_driver(void)
 286{
 287        tty_unregister_driver(goldfish_tty_driver);
 288        tty_driver_kref_put(goldfish_tty_driver);
 289        goldfish_tty_driver = NULL;
 290        kfree(goldfish_ttys);
 291        goldfish_ttys = NULL;
 292}
 293
 294static int goldfish_tty_probe(struct platform_device *pdev)
 295{
 296        struct goldfish_tty *qtty;
 297        int ret = -ENODEV;
 298        struct resource *r;
 299        struct device *ttydev;
 300        void __iomem *base;
 301        u32 irq;
 302        unsigned int line;
 303
 304        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 305        if (!r) {
 306                pr_err("goldfish_tty: No MEM resource available!\n");
 307                return -ENOMEM;
 308        }
 309
 310        base = ioremap(r->start, 0x1000);
 311        if (!base) {
 312                pr_err("goldfish_tty: Unable to ioremap base!\n");
 313                return -ENOMEM;
 314        }
 315
 316        r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 317        if (!r) {
 318                pr_err("goldfish_tty: No IRQ resource available!\n");
 319                goto err_unmap;
 320        }
 321
 322        irq = r->start;
 323
 324        mutex_lock(&goldfish_tty_lock);
 325
 326        if (pdev->id == PLATFORM_DEVID_NONE)
 327                line = goldfish_tty_current_line_count;
 328        else
 329                line = pdev->id;
 330
 331        if (line >= goldfish_tty_line_count) {
 332                pr_err("goldfish_tty: Reached maximum tty number of %d.\n",
 333                       goldfish_tty_current_line_count);
 334                ret = -ENOMEM;
 335                goto err_unlock;
 336        }
 337
 338        if (goldfish_tty_current_line_count == 0) {
 339                ret = goldfish_tty_create_driver();
 340                if (ret)
 341                        goto err_unlock;
 342        }
 343        goldfish_tty_current_line_count++;
 344
 345        qtty = &goldfish_ttys[line];
 346        spin_lock_init(&qtty->lock);
 347        tty_port_init(&qtty->port);
 348        qtty->port.ops = &goldfish_port_ops;
 349        qtty->base = base;
 350        qtty->irq = irq;
 351        qtty->dev = &pdev->dev;
 352
 353        /*
 354         * Goldfish TTY device used by the Goldfish emulator
 355         * should identify itself with 0, forcing the driver
 356         * to use virtual addresses. Goldfish TTY device
 357         * on Ranchu emulator (qemu2) returns 1 here and
 358         * driver will use physical addresses.
 359         */
 360        qtty->version = __raw_readl(base + GOLDFISH_TTY_REG_VERSION);
 361
 362        /*
 363         * Goldfish TTY device on Ranchu emulator (qemu2)
 364         * will use DMA for read/write IO operations.
 365         */
 366        if (qtty->version > 0) {
 367                /*
 368                 * Initialize dma_mask to 32-bits.
 369                 */
 370                if (!pdev->dev.dma_mask)
 371                        pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
 372                ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
 373                if (ret) {
 374                        dev_err(&pdev->dev, "No suitable DMA available.\n");
 375                        goto err_dec_line_count;
 376                }
 377        }
 378
 379        __raw_writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD);
 380
 381        ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED,
 382                          "goldfish_tty", qtty);
 383        if (ret) {
 384                pr_err("goldfish_tty: No IRQ available!\n");
 385                goto err_dec_line_count;
 386        }
 387
 388        ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
 389                                          line, &pdev->dev);
 390        if (IS_ERR(ttydev)) {
 391                ret = PTR_ERR(ttydev);
 392                goto err_tty_register_device_failed;
 393        }
 394
 395        strcpy(qtty->console.name, "ttyGF");
 396        qtty->console.write = goldfish_tty_console_write;
 397        qtty->console.device = goldfish_tty_console_device;
 398        qtty->console.setup = goldfish_tty_console_setup;
 399        qtty->console.flags = CON_PRINTBUFFER;
 400        qtty->console.index = line;
 401        register_console(&qtty->console);
 402        platform_set_drvdata(pdev, qtty);
 403
 404        mutex_unlock(&goldfish_tty_lock);
 405        return 0;
 406
 407err_tty_register_device_failed:
 408        free_irq(irq, qtty);
 409err_dec_line_count:
 410        goldfish_tty_current_line_count--;
 411        if (goldfish_tty_current_line_count == 0)
 412                goldfish_tty_delete_driver();
 413err_unlock:
 414        mutex_unlock(&goldfish_tty_lock);
 415err_unmap:
 416        iounmap(base);
 417        return ret;
 418}
 419
 420static int goldfish_tty_remove(struct platform_device *pdev)
 421{
 422        struct goldfish_tty *qtty = platform_get_drvdata(pdev);
 423
 424        mutex_lock(&goldfish_tty_lock);
 425
 426        unregister_console(&qtty->console);
 427        tty_unregister_device(goldfish_tty_driver, qtty->console.index);
 428        iounmap(qtty->base);
 429        qtty->base = NULL;
 430        free_irq(qtty->irq, pdev);
 431        goldfish_tty_current_line_count--;
 432        if (goldfish_tty_current_line_count == 0)
 433                goldfish_tty_delete_driver();
 434        mutex_unlock(&goldfish_tty_lock);
 435        return 0;
 436}
 437
 438#ifdef CONFIG_GOLDFISH_TTY_EARLY_CONSOLE
 439static void gf_early_console_putchar(struct uart_port *port, int ch)
 440{
 441        __raw_writel(ch, port->membase);
 442}
 443
 444static void gf_early_write(struct console *con, const char *s, unsigned int n)
 445{
 446        struct earlycon_device *dev = con->data;
 447
 448        uart_console_write(&dev->port, s, n, gf_early_console_putchar);
 449}
 450
 451static int __init gf_earlycon_setup(struct earlycon_device *device,
 452                                    const char *opt)
 453{
 454        if (!device->port.membase)
 455                return -ENODEV;
 456
 457        device->con->write = gf_early_write;
 458        return 0;
 459}
 460
 461OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup);
 462#endif
 463
 464static const struct of_device_id goldfish_tty_of_match[] = {
 465        { .compatible = "google,goldfish-tty", },
 466        {},
 467};
 468
 469MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
 470
 471static struct platform_driver goldfish_tty_platform_driver = {
 472        .probe = goldfish_tty_probe,
 473        .remove = goldfish_tty_remove,
 474        .driver = {
 475                .name = "goldfish_tty",
 476                .of_match_table = goldfish_tty_of_match,
 477        }
 478};
 479
 480module_platform_driver(goldfish_tty_platform_driver);
 481
 482MODULE_LICENSE("GPL v2");
 483