qemu

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

pxa2xx.c (6885B)


      1 /*
      2  * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
      3  *
      4  * Copyright (c) 2006 Openedhand Ltd.
      5  * Written by Andrzej Zaborowski <balrog@zabor.org>
      6  *
      7  * This code is licensed under the GPLv2.
      8  *
      9  * Contributions after 2012-01-13 are licensed under the terms of the
     10  * GNU GPL, version 2 or (at your option) any later version.
     11  */
     12 
     13 #include "qemu/osdep.h"
     14 #include "hw/irq.h"
     15 #include "hw/sysbus.h"
     16 #include "qapi/error.h"
     17 #include "qemu/module.h"
     18 #include "hw/pcmcia.h"
     19 #include "hw/arm/pxa.h"
     20 
     21 struct PXA2xxPCMCIAState {
     22     SysBusDevice parent_obj;
     23 
     24     PCMCIASocket slot;
     25     MemoryRegion container_mem;
     26     MemoryRegion common_iomem;
     27     MemoryRegion attr_iomem;
     28     MemoryRegion iomem;
     29 
     30     qemu_irq irq;
     31     qemu_irq cd_irq;
     32 
     33     PCMCIACardState *card;
     34 };
     35 
     36 static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
     37                 hwaddr offset, unsigned size)
     38 {
     39     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
     40     PCMCIACardClass *pcc;
     41 
     42     if (s->slot.attached) {
     43         pcc = PCMCIA_CARD_GET_CLASS(s->card);
     44         return pcc->common_read(s->card, offset);
     45     }
     46 
     47     return 0;
     48 }
     49 
     50 static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
     51                                        uint64_t value, unsigned size)
     52 {
     53     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
     54     PCMCIACardClass *pcc;
     55 
     56     if (s->slot.attached) {
     57         pcc = PCMCIA_CARD_GET_CLASS(s->card);
     58         pcc->common_write(s->card, offset, value);
     59     }
     60 }
     61 
     62 static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
     63                 hwaddr offset, unsigned size)
     64 {
     65     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
     66     PCMCIACardClass *pcc;
     67 
     68     if (s->slot.attached) {
     69         pcc = PCMCIA_CARD_GET_CLASS(s->card);
     70         return pcc->attr_read(s->card, offset);
     71     }
     72 
     73     return 0;
     74 }
     75 
     76 static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
     77                                      uint64_t value, unsigned size)
     78 {
     79     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
     80     PCMCIACardClass *pcc;
     81 
     82     if (s->slot.attached) {
     83         pcc = PCMCIA_CARD_GET_CLASS(s->card);
     84         pcc->attr_write(s->card, offset, value);
     85     }
     86 }
     87 
     88 static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
     89                 hwaddr offset, unsigned size)
     90 {
     91     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
     92     PCMCIACardClass *pcc;
     93 
     94     if (s->slot.attached) {
     95         pcc = PCMCIA_CARD_GET_CLASS(s->card);
     96         return pcc->io_read(s->card, offset);
     97     }
     98 
     99     return 0;
    100 }
    101 
    102 static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
    103                                    uint64_t value, unsigned size)
    104 {
    105     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
    106     PCMCIACardClass *pcc;
    107 
    108     if (s->slot.attached) {
    109         pcc = PCMCIA_CARD_GET_CLASS(s->card);
    110         pcc->io_write(s->card, offset, value);
    111     }
    112 }
    113 
    114 static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
    115     .read = pxa2xx_pcmcia_common_read,
    116     .write = pxa2xx_pcmcia_common_write,
    117     .endianness = DEVICE_NATIVE_ENDIAN
    118 };
    119 
    120 static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
    121     .read = pxa2xx_pcmcia_attr_read,
    122     .write = pxa2xx_pcmcia_attr_write,
    123     .endianness = DEVICE_NATIVE_ENDIAN
    124 };
    125 
    126 static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
    127     .read = pxa2xx_pcmcia_io_read,
    128     .write = pxa2xx_pcmcia_io_write,
    129     .endianness = DEVICE_NATIVE_ENDIAN
    130 };
    131 
    132 static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
    133 {
    134     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
    135     if (!s->irq)
    136         return;
    137 
    138     qemu_set_irq(s->irq, level);
    139 }
    140 
    141 PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
    142                                       hwaddr base)
    143 {
    144     DeviceState *dev;
    145     PXA2xxPCMCIAState *s;
    146 
    147     dev = qdev_new(TYPE_PXA2XX_PCMCIA);
    148     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
    149     s = PXA2XX_PCMCIA(dev);
    150 
    151     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
    152 
    153     return s;
    154 }
    155 
    156 static void pxa2xx_pcmcia_initfn(Object *obj)
    157 {
    158     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    159     PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(obj);
    160 
    161     memory_region_init(&s->container_mem, obj, "container", 0x10000000);
    162     sysbus_init_mmio(sbd, &s->container_mem);
    163 
    164     /* Socket I/O Memory Space */
    165     memory_region_init_io(&s->iomem, obj, &pxa2xx_pcmcia_io_ops, s,
    166                           "pxa2xx-pcmcia-io", 0x04000000);
    167     memory_region_add_subregion(&s->container_mem, 0x00000000,
    168                                 &s->iomem);
    169 
    170     /* Then next 64 MB is reserved */
    171 
    172     /* Socket Attribute Memory Space */
    173     memory_region_init_io(&s->attr_iomem, obj, &pxa2xx_pcmcia_attr_ops, s,
    174                           "pxa2xx-pcmcia-attribute", 0x04000000);
    175     memory_region_add_subregion(&s->container_mem, 0x08000000,
    176                                 &s->attr_iomem);
    177 
    178     /* Socket Common Memory Space */
    179     memory_region_init_io(&s->common_iomem, obj, &pxa2xx_pcmcia_common_ops, s,
    180                           "pxa2xx-pcmcia-common", 0x04000000);
    181     memory_region_add_subregion(&s->container_mem, 0x0c000000,
    182                                 &s->common_iomem);
    183 
    184     s->slot.irq = qemu_allocate_irq(pxa2xx_pcmcia_set_irq, s, 0);
    185 
    186     object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
    187                              (Object **)&s->card,
    188                              NULL, /* read-only property */
    189                              0);
    190 }
    191 
    192 /* Insert a new card into a slot */
    193 int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
    194 {
    195     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
    196     PCMCIACardClass *pcc;
    197 
    198     if (s->slot.attached) {
    199         return -EEXIST;
    200     }
    201 
    202     if (s->cd_irq) {
    203         qemu_irq_raise(s->cd_irq);
    204     }
    205 
    206     s->card = card;
    207     pcc = PCMCIA_CARD_GET_CLASS(s->card);
    208 
    209     s->slot.attached = true;
    210     s->card->slot = &s->slot;
    211     pcc->attach(s->card);
    212 
    213     return 0;
    214 }
    215 
    216 /* Eject card from the slot */
    217 int pxa2xx_pcmcia_detach(void *opaque)
    218 {
    219     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
    220     PCMCIACardClass *pcc;
    221 
    222     if (!s->slot.attached) {
    223         return -ENOENT;
    224     }
    225 
    226     pcc = PCMCIA_CARD_GET_CLASS(s->card);
    227     pcc->detach(s->card);
    228     s->card->slot = NULL;
    229     s->card = NULL;
    230 
    231     s->slot.attached = false;
    232 
    233     if (s->irq) {
    234         qemu_irq_lower(s->irq);
    235     }
    236     if (s->cd_irq) {
    237         qemu_irq_lower(s->cd_irq);
    238     }
    239 
    240     return 0;
    241 }
    242 
    243 /* Who to notify on card events */
    244 void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
    245 {
    246     PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
    247     s->irq = irq;
    248     s->cd_irq = cd_irq;
    249 }
    250 
    251 static const TypeInfo pxa2xx_pcmcia_type_info = {
    252     .name = TYPE_PXA2XX_PCMCIA,
    253     .parent = TYPE_SYS_BUS_DEVICE,
    254     .instance_size = sizeof(PXA2xxPCMCIAState),
    255     .instance_init = pxa2xx_pcmcia_initfn,
    256 };
    257 
    258 static void pxa2xx_pcmcia_register_types(void)
    259 {
    260     type_register_static(&pxa2xx_pcmcia_type_info);
    261 }
    262 
    263 type_init(pxa2xx_pcmcia_register_types)