root/drivers/tty/goldfish.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_rw_io
  2. goldfish_tty_rw
  3. goldfish_tty_do_write
  4. goldfish_tty_interrupt
  5. goldfish_tty_activate
  6. goldfish_tty_shutdown
  7. goldfish_tty_open
  8. goldfish_tty_close
  9. goldfish_tty_hangup
  10. goldfish_tty_write
  11. goldfish_tty_write_room
  12. goldfish_tty_chars_in_buffer
  13. goldfish_tty_console_write
  14. goldfish_tty_console_device
  15. goldfish_tty_console_setup
  16. goldfish_tty_create_driver
  17. goldfish_tty_delete_driver
  18. goldfish_tty_probe
  19. goldfish_tty_remove
  20. gf_early_console_putchar
  21. gf_early_write
  22. gf_earlycon_setup

   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 
  36 struct 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 
  47 static DEFINE_MUTEX(goldfish_tty_lock);
  48 static struct tty_driver *goldfish_tty_driver;
  49 static u32 goldfish_tty_line_count = 8;
  50 static u32 goldfish_tty_current_line_count;
  51 static struct goldfish_tty *goldfish_ttys;
  52 
  53 static 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         writel(count, base + GOLDFISH_TTY_REG_DATA_LEN);
  65 
  66         if (is_write)
  67                 writel(GOLDFISH_TTY_CMD_WRITE_BUFFER,
  68                        base + GOLDFISH_TTY_REG_CMD);
  69         else
  70                 writel(GOLDFISH_TTY_CMD_READ_BUFFER,
  71                        base + GOLDFISH_TTY_REG_CMD);
  72 
  73         spin_unlock_irqrestore(&qtty->lock, irq_flags);
  74 }
  75 
  76 static 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 
 128 static 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 
 137 static 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 = 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 
 158 static 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         writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
 163         return 0;
 164 }
 165 
 166 static void goldfish_tty_shutdown(struct tty_port *port)
 167 {
 168         struct goldfish_tty *qtty = container_of(port, struct goldfish_tty,
 169                                                                         port);
 170         writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD);
 171 }
 172 
 173 static 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 
 179 static void goldfish_tty_close(struct tty_struct *tty, struct file *filp)
 180 {
 181         tty_port_close(tty->port, tty, filp);
 182 }
 183 
 184 static void goldfish_tty_hangup(struct tty_struct *tty)
 185 {
 186         tty_port_hangup(tty->port);
 187 }
 188 
 189 static 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 
 196 static int goldfish_tty_write_room(struct tty_struct *tty)
 197 {
 198         return 0x10000;
 199 }
 200 
 201 static 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 readl(base + GOLDFISH_TTY_REG_BYTES_READY);
 206 }
 207 
 208 static 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 
 214 static 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 
 221 static 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 
 230 static const struct tty_port_operations goldfish_port_ops = {
 231         .activate = goldfish_tty_activate,
 232         .shutdown = goldfish_tty_shutdown
 233 };
 234 
 235 static 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 
 244 static 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 = alloc_tty_driver(goldfish_tty_line_count);
 257         if (tty == NULL) {
 258                 ret = -ENOMEM;
 259                 goto err_alloc_tty_driver_failed;
 260         }
 261         tty->driver_name = "goldfish";
 262         tty->name = "ttyGF";
 263         tty->type = TTY_DRIVER_TYPE_SERIAL;
 264         tty->subtype = SERIAL_TYPE_NORMAL;
 265         tty->init_termios = tty_std_termios;
 266         tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
 267                                                 TTY_DRIVER_DYNAMIC_DEV;
 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 
 276 err_tty_register_driver_failed:
 277         put_tty_driver(tty);
 278 err_alloc_tty_driver_failed:
 279         kfree(goldfish_ttys);
 280         goldfish_ttys = NULL;
 281 err_alloc_goldfish_ttys_failed:
 282         return ret;
 283 }
 284 
 285 static void goldfish_tty_delete_driver(void)
 286 {
 287         tty_unregister_driver(goldfish_tty_driver);
 288         put_tty_driver(goldfish_tty_driver);
 289         goldfish_tty_driver = NULL;
 290         kfree(goldfish_ttys);
 291         goldfish_ttys = NULL;
 292 }
 293 
 294 static 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 = 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         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 
 407 err_tty_register_device_failed:
 408         free_irq(irq, qtty);
 409 err_dec_line_count:
 410         goldfish_tty_current_line_count--;
 411         if (goldfish_tty_current_line_count == 0)
 412                 goldfish_tty_delete_driver();
 413 err_unlock:
 414         mutex_unlock(&goldfish_tty_lock);
 415 err_unmap:
 416         iounmap(base);
 417         return ret;
 418 }
 419 
 420 static 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
 439 static void gf_early_console_putchar(struct uart_port *port, int ch)
 440 {
 441         __raw_writel(ch, port->membase);
 442 }
 443 
 444 static 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 
 451 static 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 
 461 OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup);
 462 #endif
 463 
 464 static const struct of_device_id goldfish_tty_of_match[] = {
 465         { .compatible = "google,goldfish-tty", },
 466         {},
 467 };
 468 
 469 MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
 470 
 471 static 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 
 480 module_platform_driver(goldfish_tty_platform_driver);
 481 
 482 MODULE_LICENSE("GPL v2");

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