pxa2xx.c 5.8 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 14
#include "hw/hw.h"
#include "hw/pcmcia.h"
P
Paolo Bonzini 已提交
15
#include "hw/arm/pxa.h"
16

17

P
Paul Brook 已提交
18 19 20
struct PXA2xxPCMCIAState {
    PCMCIASocket slot;
    PCMCIACardState *card;
21
    MemoryRegion common_iomem;
22
    MemoryRegion attr_iomem;
23
    MemoryRegion iomem;
24 25 26 27 28

    qemu_irq irq;
    qemu_irq cd_irq;
};

29
static uint64_t pxa2xx_pcmcia_common_read(void *opaque,
A
Avi Kivity 已提交
30
                hwaddr offset, unsigned size)
31
{
P
Paul Brook 已提交
32
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
33
    PCMCIACardClass *pcc;
34 35

    if (s->slot.attached) {
36 37
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        return pcc->common_read(s->card, offset);
38 39 40 41 42
    }

    return 0;
}

A
Avi Kivity 已提交
43
static void pxa2xx_pcmcia_common_write(void *opaque, hwaddr offset,
44
                                       uint64_t value, unsigned size)
45
{
P
Paul Brook 已提交
46
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
47
    PCMCIACardClass *pcc;
48 49

    if (s->slot.attached) {
50 51
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        pcc->common_write(s->card, offset, value);
52 53 54
    }
}

55
static uint64_t pxa2xx_pcmcia_attr_read(void *opaque,
A
Avi Kivity 已提交
56
                hwaddr offset, unsigned size)
57
{
P
Paul Brook 已提交
58
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
59
    PCMCIACardClass *pcc;
60 61

    if (s->slot.attached) {
62 63
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        return pcc->attr_read(s->card, offset);
64 65 66 67 68
    }

    return 0;
}

A
Avi Kivity 已提交
69
static void pxa2xx_pcmcia_attr_write(void *opaque, hwaddr offset,
70
                                     uint64_t value, unsigned size)
71
{
P
Paul Brook 已提交
72
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
73
    PCMCIACardClass *pcc;
74 75

    if (s->slot.attached) {
76 77
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        pcc->attr_write(s->card, offset, value);
78 79 80
    }
}

81
static uint64_t pxa2xx_pcmcia_io_read(void *opaque,
A
Avi Kivity 已提交
82
                hwaddr offset, unsigned size)
83
{
P
Paul Brook 已提交
84
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
85
    PCMCIACardClass *pcc;
86 87

    if (s->slot.attached) {
88 89
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        return pcc->io_read(s->card, offset);
90 91 92 93 94
    }

    return 0;
}

A
Avi Kivity 已提交
95
static void pxa2xx_pcmcia_io_write(void *opaque, hwaddr offset,
96
                                   uint64_t value, unsigned size)
97
{
P
Paul Brook 已提交
98
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
99
    PCMCIACardClass *pcc;
100 101

    if (s->slot.attached) {
102 103
        pcc = PCMCIA_CARD_GET_CLASS(s->card);
        pcc->io_write(s->card, offset, value);
104 105 106
    }
}

107 108 109 110
static const MemoryRegionOps pxa2xx_pcmcia_common_ops = {
    .read = pxa2xx_pcmcia_common_read,
    .write = pxa2xx_pcmcia_common_write,
    .endianness = DEVICE_NATIVE_ENDIAN
111 112
};

113 114 115 116
static const MemoryRegionOps pxa2xx_pcmcia_attr_ops = {
    .read = pxa2xx_pcmcia_attr_read,
    .write = pxa2xx_pcmcia_attr_write,
    .endianness = DEVICE_NATIVE_ENDIAN
117 118
};

119 120 121 122
static const MemoryRegionOps pxa2xx_pcmcia_io_ops = {
    .read = pxa2xx_pcmcia_io_read,
    .write = pxa2xx_pcmcia_io_write,
    .endianness = DEVICE_NATIVE_ENDIAN
123 124 125 126
};

static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
{
P
Paul Brook 已提交
127
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
128 129 130 131 132 133
    if (!s->irq)
        return;

    qemu_set_irq(s->irq, level);
}

134
PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem,
A
Avi Kivity 已提交
135
                                      hwaddr base)
136
{
P
Paul Brook 已提交
137
    PXA2xxPCMCIAState *s;
138

P
Paul Brook 已提交
139
    s = (PXA2xxPCMCIAState *)
140
            g_malloc0(sizeof(PXA2xxPCMCIAState));
141 142

    /* Socket I/O Memory Space */
143
    memory_region_init_io(&s->iomem, NULL, &pxa2xx_pcmcia_io_ops, s,
144 145 146
                          "pxa2xx-pcmcia-io", 0x04000000);
    memory_region_add_subregion(sysmem, base | 0x00000000,
                                &s->iomem);
147 148 149 150

    /* Then next 64 MB is reserved */

    /* Socket Attribute Memory Space */
151
    memory_region_init_io(&s->attr_iomem, NULL, &pxa2xx_pcmcia_attr_ops, s,
152 153 154
                          "pxa2xx-pcmcia-attribute", 0x04000000);
    memory_region_add_subregion(sysmem, base | 0x08000000,
                                &s->attr_iomem);
155 156

    /* Socket Common Memory Space */
157
    memory_region_init_io(&s->common_iomem, NULL, &pxa2xx_pcmcia_common_ops, s,
158 159 160
                          "pxa2xx-pcmcia-common", 0x04000000);
    memory_region_add_subregion(sysmem, base | 0x0c000000,
                                &s->common_iomem);
161 162 163 164 165 166 167

    if (base == 0x30000000)
        s->slot.slot_string = "PXA PC Card Socket 1";
    else
        s->slot.slot_string = "PXA PC Card Socket 0";
    s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
    pcmcia_socket_register(&s->slot);
168

169 170 171 172
    return s;
}

/* Insert a new card into a slot */
P
Paul Brook 已提交
173
int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card)
174
{
P
Paul Brook 已提交
175
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
176 177 178
    PCMCIACardClass *pcc;

    if (s->slot.attached) {
179
        return -EEXIST;
180
    }
181 182 183 184 185 186

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

    s->card = card;
187
    pcc = PCMCIA_CARD_GET_CLASS(s->card);
188

189
    s->slot.attached = true;
190
    s->card->slot = &s->slot;
191
    pcc->attach(s->card);
192 193 194 195 196

    return 0;
}

/* Eject card from the slot */
A
Andreas Färber 已提交
197
int pxa2xx_pcmcia_detach(void *opaque)
198
{
P
Paul Brook 已提交
199
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
200 201 202
    PCMCIACardClass *pcc;

    if (!s->slot.attached) {
203
        return -ENOENT;
204
    }
205

206 207
    pcc = PCMCIA_CARD_GET_CLASS(s->card);
    pcc->detach(s->card);
208 209
    s->card->slot = NULL;
    s->card = NULL;
210

211
    s->slot.attached = false;
212

213
    if (s->irq) {
214
        qemu_irq_lower(s->irq);
215 216
    }
    if (s->cd_irq) {
217
        qemu_irq_lower(s->cd_irq);
218
    }
219 220 221 222 223 224 225

    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 已提交
226
    PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque;
227 228 229
    s->irq = irq;
    s->cd_irq = cd_irq;
}