linux/drivers/tty/serial/21285.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
   4 *
   5 * Based on drivers/char/serial.c
   6 */
   7#include <linux/module.h>
   8#include <linux/tty.h>
   9#include <linux/ioport.h>
  10#include <linux/init.h>
  11#include <linux/console.h>
  12#include <linux/device.h>
  13#include <linux/tty_flip.h>
  14#include <linux/serial_core.h>
  15#include <linux/serial.h>
  16#include <linux/io.h>
  17
  18#include <asm/irq.h>
  19#include <asm/mach-types.h>
  20#include <asm/system_info.h>
  21#include <asm/hardware/dec21285.h>
  22#include <mach/hardware.h>
  23
  24#define BAUD_BASE               (mem_fclk_21285/64)
  25
  26#define SERIAL_21285_NAME       "ttyFB"
  27#define SERIAL_21285_MAJOR      204
  28#define SERIAL_21285_MINOR      4
  29
  30#define RXSTAT_DUMMY_READ       0x80000000
  31#define RXSTAT_FRAME            (1 << 0)
  32#define RXSTAT_PARITY           (1 << 1)
  33#define RXSTAT_OVERRUN          (1 << 2)
  34#define RXSTAT_ANYERR           (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN)
  35
  36#define H_UBRLCR_BREAK          (1 << 0)
  37#define H_UBRLCR_PARENB         (1 << 1)
  38#define H_UBRLCR_PAREVN         (1 << 2)
  39#define H_UBRLCR_STOPB          (1 << 3)
  40#define H_UBRLCR_FIFO           (1 << 4)
  41
  42static const char serial21285_name[] = "Footbridge UART";
  43
  44/*
  45 * We only need 2 bits of data, so instead of creating a whole structure for
  46 * this, use bits of the private_data pointer of the uart port structure.
  47 */
  48#define tx_enabled_bit  0
  49#define rx_enabled_bit  1
  50
  51static bool is_enabled(struct uart_port *port, int bit)
  52{
  53        unsigned long *private_data = (unsigned long *)&port->private_data;
  54
  55        if (test_bit(bit, private_data))
  56                return true;
  57        return false;
  58}
  59
  60static void enable(struct uart_port *port, int bit)
  61{
  62        unsigned long *private_data = (unsigned long *)&port->private_data;
  63
  64        set_bit(bit, private_data);
  65}
  66
  67static void disable(struct uart_port *port, int bit)
  68{
  69        unsigned long *private_data = (unsigned long *)&port->private_data;
  70
  71        clear_bit(bit, private_data);
  72}
  73
  74#define is_tx_enabled(port)     is_enabled(port, tx_enabled_bit)
  75#define tx_enable(port)         enable(port, tx_enabled_bit)
  76#define tx_disable(port)        disable(port, tx_enabled_bit)
  77
  78#define is_rx_enabled(port)     is_enabled(port, rx_enabled_bit)
  79#define rx_enable(port)         enable(port, rx_enabled_bit)
  80#define rx_disable(port)        disable(port, rx_enabled_bit)
  81
  82/*
  83 * The documented expression for selecting the divisor is:
  84 *  BAUD_BASE / baud - 1
  85 * However, typically BAUD_BASE is not divisible by baud, so
  86 * we want to select the divisor that gives us the minimum
  87 * error.  Therefore, we want:
  88 *  int(BAUD_BASE / baud - 0.5) ->
  89 *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
  90 *  int((BAUD_BASE - (baud >> 1)) / baud)
  91 */
  92
  93static void serial21285_stop_tx(struct uart_port *port)
  94{
  95        if (is_tx_enabled(port)) {
  96                disable_irq_nosync(IRQ_CONTX);
  97                tx_disable(port);
  98        }
  99}
 100
 101static void serial21285_start_tx(struct uart_port *port)
 102{
 103        if (!is_tx_enabled(port)) {
 104                enable_irq(IRQ_CONTX);
 105                tx_enable(port);
 106        }
 107}
 108
 109static void serial21285_stop_rx(struct uart_port *port)
 110{
 111        if (is_rx_enabled(port)) {
 112                disable_irq_nosync(IRQ_CONRX);
 113                rx_disable(port);
 114        }
 115}
 116
 117static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
 118{
 119        struct uart_port *port = dev_id;
 120        unsigned int status, ch, flag, rxs, max_count = 256;
 121
 122        status = *CSR_UARTFLG;
 123        while (!(status & 0x10) && max_count--) {
 124                ch = *CSR_UARTDR;
 125                flag = TTY_NORMAL;
 126                port->icount.rx++;
 127
 128                rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ;
 129                if (unlikely(rxs & RXSTAT_ANYERR)) {
 130                        if (rxs & RXSTAT_PARITY)
 131                                port->icount.parity++;
 132                        else if (rxs & RXSTAT_FRAME)
 133                                port->icount.frame++;
 134                        if (rxs & RXSTAT_OVERRUN)
 135                                port->icount.overrun++;
 136
 137                        rxs &= port->read_status_mask;
 138
 139                        if (rxs & RXSTAT_PARITY)
 140                                flag = TTY_PARITY;
 141                        else if (rxs & RXSTAT_FRAME)
 142                                flag = TTY_FRAME;
 143                }
 144
 145                uart_insert_char(port, rxs, RXSTAT_OVERRUN, ch, flag);
 146
 147                status = *CSR_UARTFLG;
 148        }
 149        tty_flip_buffer_push(&port->state->port);
 150
 151        return IRQ_HANDLED;
 152}
 153
 154static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
 155{
 156        struct uart_port *port = dev_id;
 157        struct circ_buf *xmit = &port->state->xmit;
 158        int count = 256;
 159
 160        if (port->x_char) {
 161                *CSR_UARTDR = port->x_char;
 162                port->icount.tx++;
 163                port->x_char = 0;
 164                goto out;
 165        }
 166        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
 167                serial21285_stop_tx(port);
 168                goto out;
 169        }
 170
 171        do {
 172                *CSR_UARTDR = xmit->buf[xmit->tail];
 173                xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 174                port->icount.tx++;
 175                if (uart_circ_empty(xmit))
 176                        break;
 177        } while (--count > 0 && !(*CSR_UARTFLG & 0x20));
 178
 179        if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 180                uart_write_wakeup(port);
 181
 182        if (uart_circ_empty(xmit))
 183                serial21285_stop_tx(port);
 184
 185 out:
 186        return IRQ_HANDLED;
 187}
 188
 189static unsigned int serial21285_tx_empty(struct uart_port *port)
 190{
 191        return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT;
 192}
 193
 194/* no modem control lines */
 195static unsigned int serial21285_get_mctrl(struct uart_port *port)
 196{
 197        return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
 198}
 199
 200static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl)
 201{
 202}
 203
 204static void serial21285_break_ctl(struct uart_port *port, int break_state)
 205{
 206        unsigned long flags;
 207        unsigned int h_lcr;
 208
 209        spin_lock_irqsave(&port->lock, flags);
 210        h_lcr = *CSR_H_UBRLCR;
 211        if (break_state)
 212                h_lcr |= H_UBRLCR_BREAK;
 213        else
 214                h_lcr &= ~H_UBRLCR_BREAK;
 215        *CSR_H_UBRLCR = h_lcr;
 216        spin_unlock_irqrestore(&port->lock, flags);
 217}
 218
 219static int serial21285_startup(struct uart_port *port)
 220{
 221        int ret;
 222
 223        tx_enable(port);
 224        rx_enable(port);
 225
 226        ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0,
 227                          serial21285_name, port);
 228        if (ret == 0) {
 229                ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0,
 230                                  serial21285_name, port);
 231                if (ret)
 232                        free_irq(IRQ_CONRX, port);
 233        }
 234
 235        return ret;
 236}
 237
 238static void serial21285_shutdown(struct uart_port *port)
 239{
 240        free_irq(IRQ_CONTX, port);
 241        free_irq(IRQ_CONRX, port);
 242}
 243
 244static void
 245serial21285_set_termios(struct uart_port *port, struct ktermios *termios,
 246                        struct ktermios *old)
 247{
 248        unsigned long flags;
 249        unsigned int baud, quot, h_lcr, b;
 250
 251        /*
 252         * We don't support modem control lines.
 253         */
 254        termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
 255        termios->c_cflag |= CLOCAL;
 256
 257        /*
 258         * We don't support BREAK character recognition.
 259         */
 260        termios->c_iflag &= ~(IGNBRK | BRKINT);
 261
 262        /*
 263         * Ask the core to calculate the divisor for us.
 264         */
 265        baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
 266        quot = uart_get_divisor(port, baud);
 267        b = port->uartclk / (16 * quot);
 268        tty_termios_encode_baud_rate(termios, b, b);
 269
 270        switch (termios->c_cflag & CSIZE) {
 271        case CS5:
 272                h_lcr = 0x00;
 273                break;
 274        case CS6:
 275                h_lcr = 0x20;
 276                break;
 277        case CS7:
 278                h_lcr = 0x40;
 279                break;
 280        default: /* CS8 */
 281                h_lcr = 0x60;
 282                break;
 283        }
 284
 285        if (termios->c_cflag & CSTOPB)
 286                h_lcr |= H_UBRLCR_STOPB;
 287        if (termios->c_cflag & PARENB) {
 288                h_lcr |= H_UBRLCR_PARENB;
 289                if (!(termios->c_cflag & PARODD))
 290                        h_lcr |= H_UBRLCR_PAREVN;
 291        }
 292
 293        if (port->fifosize)
 294                h_lcr |= H_UBRLCR_FIFO;
 295
 296        spin_lock_irqsave(&port->lock, flags);
 297
 298        /*
 299         * Update the per-port timeout.
 300         */
 301        uart_update_timeout(port, termios->c_cflag, baud);
 302
 303        /*
 304         * Which character status flags are we interested in?
 305         */
 306        port->read_status_mask = RXSTAT_OVERRUN;
 307        if (termios->c_iflag & INPCK)
 308                port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
 309
 310        /*
 311         * Which character status flags should we ignore?
 312         */
 313        port->ignore_status_mask = 0;
 314        if (termios->c_iflag & IGNPAR)
 315                port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY;
 316        if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
 317                port->ignore_status_mask |= RXSTAT_OVERRUN;
 318
 319        /*
 320         * Ignore all characters if CREAD is not set.
 321         */
 322        if ((termios->c_cflag & CREAD) == 0)
 323                port->ignore_status_mask |= RXSTAT_DUMMY_READ;
 324
 325        quot -= 1;
 326
 327        *CSR_UARTCON = 0;
 328        *CSR_L_UBRLCR = quot & 0xff;
 329        *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
 330        *CSR_H_UBRLCR = h_lcr;
 331        *CSR_UARTCON = 1;
 332
 333        spin_unlock_irqrestore(&port->lock, flags);
 334}
 335
 336static const char *serial21285_type(struct uart_port *port)
 337{
 338        return port->type == PORT_21285 ? "DC21285" : NULL;
 339}
 340
 341static void serial21285_release_port(struct uart_port *port)
 342{
 343        release_mem_region(port->mapbase, 32);
 344}
 345
 346static int serial21285_request_port(struct uart_port *port)
 347{
 348        return request_mem_region(port->mapbase, 32, serial21285_name)
 349                         != NULL ? 0 : -EBUSY;
 350}
 351
 352static void serial21285_config_port(struct uart_port *port, int flags)
 353{
 354        if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0)
 355                port->type = PORT_21285;
 356}
 357
 358/*
 359 * verify the new serial_struct (for TIOCSSERIAL).
 360 */
 361static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser)
 362{
 363        int ret = 0;
 364        if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285)
 365                ret = -EINVAL;
 366        if (ser->irq <= 0)
 367                ret = -EINVAL;
 368        if (ser->baud_base != port->uartclk / 16)
 369                ret = -EINVAL;
 370        return ret;
 371}
 372
 373static const struct uart_ops serial21285_ops = {
 374        .tx_empty       = serial21285_tx_empty,
 375        .get_mctrl      = serial21285_get_mctrl,
 376        .set_mctrl      = serial21285_set_mctrl,
 377        .stop_tx        = serial21285_stop_tx,
 378        .start_tx       = serial21285_start_tx,
 379        .stop_rx        = serial21285_stop_rx,
 380        .break_ctl      = serial21285_break_ctl,
 381        .startup        = serial21285_startup,
 382        .shutdown       = serial21285_shutdown,
 383        .set_termios    = serial21285_set_termios,
 384        .type           = serial21285_type,
 385        .release_port   = serial21285_release_port,
 386        .request_port   = serial21285_request_port,
 387        .config_port    = serial21285_config_port,
 388        .verify_port    = serial21285_verify_port,
 389};
 390
 391static struct uart_port serial21285_port = {
 392        .mapbase        = 0x42000160,
 393        .iotype         = UPIO_MEM,
 394        .irq            = 0,
 395        .fifosize       = 16,
 396        .ops            = &serial21285_ops,
 397        .flags          = UPF_BOOT_AUTOCONF,
 398};
 399
 400static void serial21285_setup_ports(void)
 401{
 402        serial21285_port.uartclk = mem_fclk_21285 / 4;
 403}
 404
 405#ifdef CONFIG_SERIAL_21285_CONSOLE
 406static void serial21285_console_putchar(struct uart_port *port, int ch)
 407{
 408        while (*CSR_UARTFLG & 0x20)
 409                barrier();
 410        *CSR_UARTDR = ch;
 411}
 412
 413static void
 414serial21285_console_write(struct console *co, const char *s,
 415                          unsigned int count)
 416{
 417        uart_console_write(&serial21285_port, s, count, serial21285_console_putchar);
 418}
 419
 420static void __init
 421serial21285_get_options(struct uart_port *port, int *baud,
 422                        int *parity, int *bits)
 423{
 424        if (*CSR_UARTCON == 1) {
 425                unsigned int tmp;
 426
 427                tmp = *CSR_H_UBRLCR;
 428                switch (tmp & 0x60) {
 429                case 0x00:
 430                        *bits = 5;
 431                        break;
 432                case 0x20:
 433                        *bits = 6;
 434                        break;
 435                case 0x40:
 436                        *bits = 7;
 437                        break;
 438                default:
 439                case 0x60:
 440                        *bits = 8;
 441                        break;
 442                }
 443
 444                if (tmp & H_UBRLCR_PARENB) {
 445                        *parity = 'o';
 446                        if (tmp & H_UBRLCR_PAREVN)
 447                                *parity = 'e';
 448                }
 449
 450                tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8);
 451
 452                *baud = port->uartclk / (16 * (tmp + 1));
 453        }
 454}
 455
 456static int __init serial21285_console_setup(struct console *co, char *options)
 457{
 458        struct uart_port *port = &serial21285_port;
 459        int baud = 9600;
 460        int bits = 8;
 461        int parity = 'n';
 462        int flow = 'n';
 463
 464        if (machine_is_personal_server())
 465                baud = 57600;
 466
 467        /*
 468         * Check whether an invalid uart number has been specified, and
 469         * if so, search for the first available port that does have
 470         * console support.
 471         */
 472        if (options)
 473                uart_parse_options(options, &baud, &parity, &bits, &flow);
 474        else
 475                serial21285_get_options(port, &baud, &parity, &bits);
 476
 477        return uart_set_options(port, co, baud, parity, bits, flow);
 478}
 479
 480static struct uart_driver serial21285_reg;
 481
 482static struct console serial21285_console =
 483{
 484        .name           = SERIAL_21285_NAME,
 485        .write          = serial21285_console_write,
 486        .device         = uart_console_device,
 487        .setup          = serial21285_console_setup,
 488        .flags          = CON_PRINTBUFFER,
 489        .index          = -1,
 490        .data           = &serial21285_reg,
 491};
 492
 493static int __init rs285_console_init(void)
 494{
 495        serial21285_setup_ports();
 496        register_console(&serial21285_console);
 497        return 0;
 498}
 499console_initcall(rs285_console_init);
 500
 501#define SERIAL_21285_CONSOLE    &serial21285_console
 502#else
 503#define SERIAL_21285_CONSOLE    NULL
 504#endif
 505
 506static struct uart_driver serial21285_reg = {
 507        .owner                  = THIS_MODULE,
 508        .driver_name            = "ttyFB",
 509        .dev_name               = "ttyFB",
 510        .major                  = SERIAL_21285_MAJOR,
 511        .minor                  = SERIAL_21285_MINOR,
 512        .nr                     = 1,
 513        .cons                   = SERIAL_21285_CONSOLE,
 514};
 515
 516static int __init serial21285_init(void)
 517{
 518        int ret;
 519
 520        printk(KERN_INFO "Serial: 21285 driver\n");
 521
 522        serial21285_setup_ports();
 523
 524        ret = uart_register_driver(&serial21285_reg);
 525        if (ret == 0)
 526                uart_add_one_port(&serial21285_reg, &serial21285_port);
 527
 528        return ret;
 529}
 530
 531static void __exit serial21285_exit(void)
 532{
 533        uart_remove_one_port(&serial21285_reg, &serial21285_port);
 534        uart_unregister_driver(&serial21285_reg);
 535}
 536
 537module_init(serial21285_init);
 538module_exit(serial21285_exit);
 539
 540MODULE_LICENSE("GPL");
 541MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
 542MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
 543