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