Changeset 38b0ae2 in mainline


Ignore:
Timestamp:
2018-02-12T20:16:44Z (6 years ago)
Author:
GitHub <noreply@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
448e093
Parents:
8192d8a
git-author:
Jiří Zárevúcky <zarevucky.jiri@…> (2018-02-12 20:16:44)
git-committer:
GitHub <noreply@…> (2018-02-12 20:16:44)
Message:

Generalize ns16550 driver to work with more chips. (#20)

Some UART controllers are compatible with 16550A, but have more spacing
between registers. In particular, ARMADA 385, which is the basis of
Turris Omnia router, has a compatible UART with 32b registers instead of 8b
(with the top three bytes unused).

Note: The device tree file hints that some UARTs may need register reads/writes
that are wider than 8 bits, and this commit does not address that possibility.

Location:
kernel
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/amd64/src/amd64.c

    r8192d8a r38b0ae2  
    216216#endif
    217217        ns16550_instance_t *ns16550_instance
    218             = ns16550_init((ns16550_t *) NS16550_BASE, IRQ_NS16550, NULL, NULL,
     218            = ns16550_init(NS16550_BASE, 0, IRQ_NS16550, NULL, NULL,
    219219            ns16550_out_ptr);
    220220        if (ns16550_instance) {
  • kernel/arch/ia32/src/ia32.c

    r8192d8a r38b0ae2  
    201201#endif
    202202        ns16550_instance_t *ns16550_instance
    203             = ns16550_init((ns16550_t *) NS16550_BASE, IRQ_NS16550, NULL, NULL,
     203            = ns16550_init(NS16550_BASE, 0, IRQ_NS16550, NULL, NULL,
    204204            ns16550_out_ptr);
    205205        if (ns16550_instance) {
  • kernel/arch/ia64/src/ia64.c

    r8192d8a r38b0ae2  
    181181#ifdef CONFIG_NS16550
    182182        ns16550_instance_t *ns16550_instance
    183             = ns16550_init((ns16550_t *) NS16550_BASE, NS16550_IRQ, NULL, NULL,
     183            = ns16550_init(NS16550_BASE, 0, NS16550_IRQ, NULL, NULL,
    184184            NULL);
    185185        if (ns16550_instance) {
  • kernel/arch/sparc64/src/drivers/kbd.c

    r8192d8a r38b0ae2  
    118118        size_t offset = pa - aligned_addr;
    119119       
    120         ns16550_t *ns16550 = (ns16550_t *) (km_map(aligned_addr, offset + size,
     120        ioport8_t *ns16550 = (ioport8_t *) (km_map(aligned_addr, offset + size,
    121121            PAGE_WRITE | PAGE_NOT_CACHEABLE) + offset);
    122122       
    123         ns16550_instance_t *ns16550_instance = ns16550_init(ns16550, inr, cir,
     123        ns16550_instance_t *ns16550_instance = ns16550_init(ns16550, 0, inr, cir,
    124124            cir_arg, NULL);
    125125        if (ns16550_instance) {
  • kernel/genarch/include/genarch/drivers/ns16550/ns16550.h

    r8192d8a r38b0ae2  
    5050
    5151/** NS16550 registers. */
    52 typedef struct {
    53         union {
    54                 ioport8_t rbr;      /**< Receiver Buffer Register (read). */
    55                 ioport8_t thr;      /**< Transmitter Holder Register (write). */
    56         } __attribute__ ((packed));
    57         ioport8_t ier;      /**< Interrupt Enable Register. */
    58         union {
    59                 ioport8_t iir;  /**< Interrupt Ident Register (read). */
    60                 ioport8_t fcr;  /**< FIFO control register (write). */
    61         } __attribute__ ((packed));
    62         ioport8_t lcr;      /**< Line Control register. */
    63         ioport8_t mcr;      /**< Modem Control Register. */
    64         ioport8_t lsr;      /**< Line Status Register. */
    65 } __attribute__ ((packed)) ns16550_t;
     52enum {
     53        NS16550_REG_RBR = 0,  /**< Receiver Buffer Register (read). */
     54        NS16550_REG_THR = 0,  /**< Transmitter Holder Register (write). */
     55        NS16550_REG_IER = 1,  /**< Interrupt Enable Register. */
     56        NS16550_REG_IIR = 2,  /**< Interrupt Ident Register (read). */
     57        NS16550_REG_FCR = 2,  /**< FIFO control register (write). */
     58        NS16550_REG_LCR = 3,  /**< Line Control register. */
     59        NS16550_REG_MCR = 4,  /**< Modem Control Register. */
     60        NS16550_REG_LSR = 5,  /**< Line Status Register. */
     61};
    6662
    6763/** Structure representing the ns16550 device. */
    6864typedef struct {
    6965        irq_t irq;
    70         ns16550_t *ns16550;
     66        volatile ioport8_t *ns16550;
    7167        indev_t *input;
    7268        outdev_t *output;
    7369        parea_t parea;
     70        int reg_shift;
    7471} ns16550_instance_t;
    7572
    76 extern ns16550_instance_t *ns16550_init(ns16550_t *, inr_t, cir_t, void *,
     73extern ns16550_instance_t *ns16550_init(ioport8_t *, int, inr_t, cir_t, void *,
    7774    outdev_t **);
    7875extern void ns16550_wire(ns16550_instance_t *, indev_t *);
  • kernel/genarch/src/drivers/ns16550/ns16550.c

    r8192d8a r38b0ae2  
    11/*
    22 * Copyright (c) 2009 Jakub Jermar
     3 * Copyright (c) 2018 CZ.NIC, z.s.p.o.
    34 * All rights reserved.
    45 *
     
    4647#define LSR_TH_READY    0x20
    4748
     49static inline uint8_t _read(ns16550_instance_t *inst, int reg) {
     50        return pio_read_8(&inst->ns16550[reg << inst->reg_shift]);
     51}
     52
     53static inline void _write(ns16550_instance_t *inst, int reg, uint8_t val) {
     54        pio_write_8(&inst->ns16550[reg << inst->reg_shift], val);
     55}
     56
    4857static irq_ownership_t ns16550_claim(irq_t *irq)
    4958{
    5059        ns16550_instance_t *instance = irq->instance;
    51         ns16550_t *dev = instance->ns16550;
    52        
    53         if (pio_read_8(&dev->lsr) & LSR_DATA_READY)
     60
     61        if (_read(instance, NS16550_REG_LSR) & LSR_DATA_READY)
    5462                return IRQ_ACCEPT;
    5563        else
     
    6068{
    6169        ns16550_instance_t *instance = irq->instance;
    62         ns16550_t *dev = instance->ns16550;
    6370       
    64         if (pio_read_8(&dev->lsr) & LSR_DATA_READY) {
    65                 uint8_t data = pio_read_8(&dev->rbr);
     71        while (_read(instance, NS16550_REG_LSR) & LSR_DATA_READY) {
     72                uint8_t data = _read(instance, NS16550_REG_RBR);
    6673                indev_push_character(instance->input, data);
    6774        }
     
    6976
    7077/**< Clear input buffer. */
    71 static void ns16550_clear_buffer(ns16550_t *dev)
     78static void ns16550_clear_buffer(ns16550_instance_t *instance)
    7279{
    73         while ((pio_read_8(&dev->lsr) & LSR_DATA_READY))
    74                 (void) pio_read_8(&dev->rbr);
     80        while (_read(instance, NS16550_REG_LSR) & LSR_DATA_READY)
     81                (void) _read(instance, NS16550_REG_RBR);
    7582}
    7683
    77 static void ns16550_sendb(ns16550_t *dev, uint8_t byte)
     84static void ns16550_sendb(ns16550_instance_t *instance, uint8_t byte)
    7885{
    79         while (!(pio_read_8(&dev->lsr) & LSR_TH_READY))
     86        while (!(_read(instance, NS16550_REG_LSR) & LSR_TH_READY))
    8087                ;
    81         pio_write_8(&dev->thr, byte);
     88        _write(instance, NS16550_REG_THR, byte);
    8289}
    8390
     
    8895        if ((!instance->parea.mapped) || (console_override)) {
    8996                if (ascii_check(ch))
    90                         ns16550_sendb(instance->ns16550, (uint8_t) ch);
     97                        ns16550_sendb(instance, (uint8_t) ch);
    9198                else
    92                         ns16550_sendb(instance->ns16550, U_SPECIAL);
     99                        ns16550_sendb(instance, U_SPECIAL);
    93100        }
    94101}
     
    101108/** Initialize ns16550.
    102109 *
    103  * @param dev      Addrress of the beginning of the device in I/O space.
    104  * @param inr      Interrupt number.
    105  * @param cir      Clear interrupt function.
    106  * @param cir_arg  First argument to cir.
    107  * @param output   Where to store pointer to the output device
    108  *                 or NULL if the caller is not interested in
    109  *                 writing to the serial port.
     110 * @param dev        Address of the beginning of the device in I/O space.
     111 * @param reg_shift  Spacing between individual register addresses, in log2.
     112 *                   The individual register location is calculated as
     113 *                   `base + (register offset << reg_shift)`.
     114 * @param inr        Interrupt number.
     115 * @param cir        Clear interrupt function.
     116 * @param cir_arg    First argument to cir.
     117 * @param output     Where to store pointer to the output device
     118 *                   or NULL if the caller is not interested in
     119 *                   writing to the serial port.
    110120 *
    111121 * @return Keyboard instance or NULL on failure.
    112122 *
    113123 */
    114 ns16550_instance_t *ns16550_init(ns16550_t *dev, inr_t inr, cir_t cir,
    115     void *cir_arg, outdev_t **output)
     124ns16550_instance_t *ns16550_init(ioport8_t *dev, int reg_shift, inr_t inr,
     125    cir_t cir, void *cir_arg, outdev_t **output)
    116126{
    117127        ns16550_instance_t *instance
     
    119129        if (instance) {
    120130                instance->ns16550 = dev;
     131                instance->reg_shift = reg_shift;
    121132                instance->input = NULL;
    122133                instance->output = NULL;
     
    162173        irq_register(&instance->irq);
    163174       
    164         ns16550_clear_buffer(instance->ns16550);
     175        ns16550_clear_buffer(instance);
    165176       
    166177        /* Enable interrupts */
    167         pio_write_8(&instance->ns16550->ier, IER_ERBFI);
    168         pio_write_8(&instance->ns16550->mcr, MCR_OUT2);
     178        _write(instance, NS16550_REG_IER, IER_ERBFI);
     179        _write(instance, NS16550_REG_MCR, MCR_OUT2);
    169180}
    170181
Note: See TracChangeset for help on using the changeset viewer.