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