qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

omap_uart.c (5212B)


      1 /*
      2  * TI OMAP processors UART emulation.
      3  *
      4  * Copyright (C) 2006-2008 Andrzej Zaborowski  <balrog@zabor.org>
      5  * Copyright (C) 2007-2009 Nokia Corporation
      6  *
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License as
      9  * published by the Free Software Foundation; either version 2 or
     10  * (at your option) version 3 of the License.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  * GNU General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, see <http://www.gnu.org/licenses/>.
     19  */
     20 #include "qemu/osdep.h"
     21 #include "chardev/char.h"
     22 #include "hw/arm/omap.h"
     23 #include "hw/char/serial.h"
     24 #include "exec/address-spaces.h"
     25 
     26 /* UARTs */
     27 struct omap_uart_s {
     28     MemoryRegion iomem;
     29     hwaddr base;
     30     SerialMM *serial; /* TODO */
     31     struct omap_target_agent_s *ta;
     32     omap_clk fclk;
     33     qemu_irq irq;
     34 
     35     uint8_t eblr;
     36     uint8_t syscontrol;
     37     uint8_t wkup;
     38     uint8_t cfps;
     39     uint8_t mdr[2];
     40     uint8_t scr;
     41     uint8_t clksel;
     42 };
     43 
     44 void omap_uart_reset(struct omap_uart_s *s)
     45 {
     46     s->eblr = 0x00;
     47     s->syscontrol = 0;
     48     s->wkup = 0x3f;
     49     s->cfps = 0x69;
     50     s->clksel = 0;
     51 }
     52 
     53 struct omap_uart_s *omap_uart_init(hwaddr base,
     54                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
     55                 qemu_irq txdma, qemu_irq rxdma,
     56                 const char *label, Chardev *chr)
     57 {
     58     struct omap_uart_s *s = g_new0(struct omap_uart_s, 1);
     59 
     60     s->base = base;
     61     s->fclk = fclk;
     62     s->irq = irq;
     63     s->serial = serial_mm_init(get_system_memory(), base, 2, irq,
     64                                omap_clk_getrate(fclk)/16,
     65                                chr ?: qemu_chr_new(label, "null", NULL),
     66                                DEVICE_NATIVE_ENDIAN);
     67     return s;
     68 }
     69 
     70 static uint64_t omap_uart_read(void *opaque, hwaddr addr,
     71                                unsigned size)
     72 {
     73     struct omap_uart_s *s = (struct omap_uart_s *) opaque;
     74 
     75     if (size == 4) {
     76         return omap_badwidth_read8(opaque, addr);
     77     }
     78 
     79     switch (addr) {
     80     case 0x20:	/* MDR1 */
     81         return s->mdr[0];
     82     case 0x24:	/* MDR2 */
     83         return s->mdr[1];
     84     case 0x40:	/* SCR */
     85         return s->scr;
     86     case 0x44:	/* SSR */
     87         return 0x0;
     88     case 0x48:	/* EBLR (OMAP2) */
     89         return s->eblr;
     90     case 0x4C:	/* OSC_12M_SEL (OMAP1) */
     91         return s->clksel;
     92     case 0x50:	/* MVR */
     93         return 0x30;
     94     case 0x54:	/* SYSC (OMAP2) */
     95         return s->syscontrol;
     96     case 0x58:	/* SYSS (OMAP2) */
     97         return 1;
     98     case 0x5c:	/* WER (OMAP2) */
     99         return s->wkup;
    100     case 0x60:	/* CFPS (OMAP2) */
    101         return s->cfps;
    102     }
    103 
    104     OMAP_BAD_REG(addr);
    105     return 0;
    106 }
    107 
    108 static void omap_uart_write(void *opaque, hwaddr addr,
    109                             uint64_t value, unsigned size)
    110 {
    111     struct omap_uart_s *s = (struct omap_uart_s *) opaque;
    112 
    113     if (size == 4) {
    114         omap_badwidth_write8(opaque, addr, value);
    115         return;
    116     }
    117 
    118     switch (addr) {
    119     case 0x20:	/* MDR1 */
    120         s->mdr[0] = value & 0x7f;
    121         break;
    122     case 0x24:	/* MDR2 */
    123         s->mdr[1] = value & 0xff;
    124         break;
    125     case 0x40:	/* SCR */
    126         s->scr = value & 0xff;
    127         break;
    128     case 0x48:	/* EBLR (OMAP2) */
    129         s->eblr = value & 0xff;
    130         break;
    131     case 0x4C:	/* OSC_12M_SEL (OMAP1) */
    132         s->clksel = value & 1;
    133         break;
    134     case 0x44:	/* SSR */
    135     case 0x50:	/* MVR */
    136     case 0x58:	/* SYSS (OMAP2) */
    137         OMAP_RO_REG(addr);
    138         break;
    139     case 0x54:	/* SYSC (OMAP2) */
    140         s->syscontrol = value & 0x1d;
    141         if (value & 2)
    142             omap_uart_reset(s);
    143         break;
    144     case 0x5c:	/* WER (OMAP2) */
    145         s->wkup = value & 0x7f;
    146         break;
    147     case 0x60:	/* CFPS (OMAP2) */
    148         s->cfps = value & 0xff;
    149         break;
    150     default:
    151         OMAP_BAD_REG(addr);
    152     }
    153 }
    154 
    155 static const MemoryRegionOps omap_uart_ops = {
    156     .read = omap_uart_read,
    157     .write = omap_uart_write,
    158     .endianness = DEVICE_NATIVE_ENDIAN,
    159 };
    160 
    161 struct omap_uart_s *omap2_uart_init(MemoryRegion *sysmem,
    162                 struct omap_target_agent_s *ta,
    163                 qemu_irq irq, omap_clk fclk, omap_clk iclk,
    164                 qemu_irq txdma, qemu_irq rxdma,
    165                 const char *label, Chardev *chr)
    166 {
    167     hwaddr base = omap_l4_attach(ta, 0, NULL);
    168     struct omap_uart_s *s = omap_uart_init(base, irq,
    169                     fclk, iclk, txdma, rxdma, label, chr);
    170 
    171     memory_region_init_io(&s->iomem, NULL, &omap_uart_ops, s, "omap.uart", 0x100);
    172 
    173     s->ta = ta;
    174 
    175     memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
    176 
    177     return s;
    178 }
    179 
    180 void omap_uart_attach(struct omap_uart_s *s, Chardev *chr)
    181 {
    182     /* TODO: Should reuse or destroy current s->serial */
    183     s->serial = serial_mm_init(get_system_memory(), s->base, 2, s->irq,
    184                                omap_clk_getrate(s->fclk) / 16,
    185                                chr ?: qemu_chr_new("null", "null", NULL),
    186                                DEVICE_NATIVE_ENDIAN);
    187 }