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