pxa2xx.c 7.2 KB
Newer Older
1 2 3 4 5 6 7
/*
 * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
 *
 * Copyright (c) 2006 Openedhand Ltd.
 * Written by Andrzej Zaborowski <balrog@zabor.org>
 *
 * This code is licensed under the GPLv2.
8 9 10
 *
 * Contributions after 2012-01-13 are licensed under the terms of the
 * 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"
P
Paolo Bonzini 已提交
16
#include "hw/arm/pxa.h"
17

18 19 20
#define TYPE_PXA2XX_PCMCIA "pxa2xx-pcmcia"
#define PXA2XX_PCMCIA(obj) \
    OBJECT_CHECK(PXA2xxPCMCIAState, obj, TYPE_PXA2XX_PCMCIA)
21

P
Paul Brook 已提交
22
struct PXA2xxPCMCIAState {
23 24
    SysBusDevice parent_obj;

P
Paul Brook 已提交
25
    PCMCIASocket slot;
26
    MemoryRegion container_mem;
27
    MemoryRegion common_iomem;
28
    MemoryRegion attr_iomem;
29
    MemoryRegion iomem;
30 31 32

    qemu_irq irq;
    qemu_irq cd_irq;
33 34

    PCMCIACardState *card;
35 36
};

37
static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
A
Avi Kivity 已提交
38
                hwaddr offset, unsigned size)
39
{
P
Paul Brook 已提交
40
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
41
    PCMCIACardClass *pcc;
42 43

    if (s->slot.attached) {
44 45
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        return pcc->common_read(s->card, offset);
46 47 48 49 50
    }

    return 0;
}

A
Avi Kivity 已提交
51
static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
52
                                       uint64_t value, unsigned size)
53
{
P
Paul Brook 已提交
54
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
55
    PCMCIACardClass *pcc;
56 57

    if (s->slot.attached) {
58 59
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        pcc->common_write(s->card, offset, value);
60 61 62
    }
}

63
static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
A
Avi Kivity 已提交
64
                hwaddr offset, unsigned size)
65
{
P
Paul Brook 已提交
66
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
67
    PCMCIACardClass *pcc;
68 69

    if (s->slot.attached) {
70 71
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        return pcc->attr_read(s->card, offset);
72 73 74 75 76
    }

    return 0;
}

A
Avi Kivity 已提交
77
static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
78
                                     uint64_t value, unsigned size)
79
{
P
Paul Brook 已提交
80
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
81
    PCMCIACardClass *pcc;
82 83

    if (s->slot.attached) {
84 85
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        pcc->attr_write(s->card, offset, value);
86 87 88
    }
}

89
static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
A
Avi Kivity 已提交
90
                hwaddr offset, unsigned size)
91
{
P
Paul Brook 已提交
92
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
93
    PCMCIACardClass *pcc;
94 95

    if (s->slot.attached) {
96 97
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        return pcc->io_read(s->card, offset);
98 99 100 101 102
    }

    return 0;
}

A
Avi Kivity 已提交
103
static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
104
                                   uint64_t value, unsigned size)
105
{
P
Paul Brook 已提交
106
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
107
    PCMCIACardClass *pcc;
108 109

    if (s->slot.attached) {
110 111
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        pcc->io_write(s->card, offset, value);
112 113 114
    }
}

115 116 117 118
static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
    .read = pxa2xx_pcmcia_common_read,
    .write = pxa2xx_pcmcia_common_write,
    .endianness = DEVICE_NATIVE_ENDIAN
119 120
};

121 122 123 124
static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
    .read = pxa2xx_pcmcia_attr_read,
    .write = pxa2xx_pcmcia_attr_write,
    .endianness = DEVICE_NATIVE_ENDIAN
125 126
};

127 128 129 130
static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
    .read = pxa2xx_pcmcia_io_read,
    .write = pxa2xx_pcmcia_io_write,
    .endianness = DEVICE_NATIVE_ENDIAN
131 132 133 134
};

static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
{
P
Paul Brook 已提交
135
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
136 137 138 139 140 141
    if (!s->irq)
        return;

    qemu_set_irq(s->irq, level);
}

142
PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
A
Avi Kivity 已提交
143
                                      hwaddr base)
144
{
145
    DeviceState *dev;
P
Paul Brook 已提交
146
    PXA2xxPCMCIAState *s;
147

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    dev = qdev_create(NULL, TYPE_PXA2XX_PCMCIA);
    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
    s = PXA2XX_PCMCIA(dev);

    if (base == 0x30000000) {
        s->slot.slot_string = "PXA PC Card Socket 1";
    } else {
        s->slot.slot_string = "PXA PC Card Socket 0";
    }

    qdev_init_nofail(dev);

    return s;
}

static void pxa2xx_pcmcia_realize(DeviceState *dev, Error **errp)
{
    PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(dev);

    pcmcia_socket_register(&s->slot);
}

static void pxa2xx_pcmcia_initfn(Object *obj)
{
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    PXA2xxPCMCIAState *s = PXA2XX_PCMCIA(obj);

    memory_region_init(&s->container_mem, obj, "container", 0x10000000);
    sysbus_init_mmio(sbd, &s->container_mem);
177 178

    /* Socket I/O Memory Space */
179
    memory_region_init_io(&s->iomem, NULL, &pxa2xx_pcmcia_io_ops, s,
180
                          "pxa2xx-pcmcia-io", 0x04000000);
181
    memory_region_add_subregion(&s->container_mem, 0x00000000,
182
                                &s->iomem);
183 184 185 186

    /* Then next 64 MB is reserved */

    /* Socket Attribute Memory Space */
187
    memory_region_init_io(&s->attr_iomem, NULL, &pxa2xx_pcmcia_attr_ops, s,
188
                          "pxa2xx-pcmcia-attribute", 0x04000000);
189
    memory_region_add_subregion(&s->container_mem, 0x08000000,
190
                                &s->attr_iomem);
191 192

    /* Socket Common Memory Space */
193
    memory_region_init_io(&s->common_iomem, NULL, &pxa2xx_pcmcia_common_ops, s,
194
                          "pxa2xx-pcmcia-common", 0x04000000);
195
    memory_region_add_subregion(&s->container_mem, 0x0c000000,
196
                                &s->common_iomem);
197 198

    s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
199

200
    object_property_add_link(obj, "card", TYPE_PCMCIA_CARD,
201
                             (Object **)&s->card, 0, NULL);
202 203 204
}

/* Insert a new card into a slot */
P
Paul Brook 已提交
205
int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
206
{
P
Paul Brook 已提交
207
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
208 209 210
    PCMCIACardClass *pcc;

    if (s->slot.attached) {
211
        return -EEXIST;
212
    }
213 214 215 216 217 218

    if (s->cd_irq) {
        qemu_irq_raise(s->cd_irq);
    }

    s->card = card;
219
    pcc = PCMCIA_CARD_GET_CLASS(s->card);
220

221
    s->slot.attached = true;
222
    s->card->slot = &s->slot;
223
    pcc->attach(s->card);
224 225 226 227 228

    return 0;
}

/* Eject card from the slot */
A
Andreas Färber 已提交
229
int pxa2xx_pcmcia_detach(void *opaque)
230
{
P
Paul Brook 已提交
231
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
232 233 234
    PCMCIACardClass *pcc;

    if (!s->slot.attached) {
235
        return -ENOENT;
236
    }
237

238 239
    pcc = PCMCIA_CARD_GET_CLASS(s->card);
    pcc->detach(s->card);
240 241
    s->card->slot = NULL;
    s->card = NULL;
242

243
    s->slot.attached = false;
244

245
    if (s->irq) {
246
        qemu_irq_lower(s->irq);
247 248
    }
    if (s->cd_irq) {
249
        qemu_irq_lower(s->cd_irq);
250
    }
251 252 253 254 255 256 257

    return 0;
}

/* Who to notify on card events */
void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
{
P
Paul Brook 已提交
258
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
259 260 261
    s->irq = irq;
    s->cd_irq = cd_irq;
}
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283

static void pxa2xx_pcmcia_class_init(ObjectClass *oc, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(oc);

    dc->realize = pxa2xx_pcmcia_realize;
}

static const TypeInfo pxa2xx_pcmcia_type_info = {
    .name = TYPE_PXA2XX_PCMCIA,
    .parent = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(PXA2xxPCMCIAState),
    .instance_init = pxa2xx_pcmcia_initfn,
    .class_init = pxa2xx_pcmcia_class_init,
};

static void pxa2xx_pcmcia_register_types(void)
{
    type_register_static(&pxa2xx_pcmcia_type_info);
}

type_init(pxa2xx_pcmcia_register_types)