2 * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
4 * Copyright (c) 2006 Openedhand Ltd.
5 * Written by Andrzej Zaborowski <balrog@zabor.org>
7 * This code is licensed under the GPLv2.
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.
13 #include "qemu/osdep.h"
15 #include "hw/sysbus.h"
16 #include "qapi/error.h"
17 #include "qemu/module.h"
18 #include "hw/pcmcia.h"
19 #include "hw/arm/pxa.h"
21 struct PXA2xxPCMCIAState
{
22 SysBusDevice parent_obj
;
25 MemoryRegion container_mem
;
26 MemoryRegion common_iomem
;
27 MemoryRegion attr_iomem
;
33 PCMCIACardState
*card
;
36 static uint64_t pxa2xx_pcmcia_common_read(void *opaque
,
37 hwaddr offset
, unsigned size
)
39 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
42 if (s
->slot
.attached
) {
43 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
44 return pcc
->common_read(s
->card
, offset
);
50 static void pxa2xx_pcmcia_common_write(void *opaque
, hwaddr offset
,
51 uint64_t value
, unsigned size
)
53 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
56 if (s
->slot
.attached
) {
57 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
58 pcc
->common_write(s
->card
, offset
, value
);
62 static uint64_t pxa2xx_pcmcia_attr_read(void *opaque
,
63 hwaddr offset
, unsigned size
)
65 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
68 if (s
->slot
.attached
) {
69 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
70 return pcc
->attr_read(s
->card
, offset
);
76 static void pxa2xx_pcmcia_attr_write(void *opaque
, hwaddr offset
,
77 uint64_t value
, unsigned size
)
79 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
82 if (s
->slot
.attached
) {
83 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
84 pcc
->attr_write(s
->card
, offset
, value
);
88 static uint64_t pxa2xx_pcmcia_io_read(void *opaque
,
89 hwaddr offset
, unsigned size
)
91 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
94 if (s
->slot
.attached
) {
95 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
96 return pcc
->io_read(s
->card
, offset
);
102 static void pxa2xx_pcmcia_io_write(void *opaque
, hwaddr offset
,
103 uint64_t value
, unsigned size
)
105 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
106 PCMCIACardClass
*pcc
;
108 if (s
->slot
.attached
) {
109 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
110 pcc
->io_write(s
->card
, offset
, value
);
114 static const MemoryRegionOps pxa2xx_pcmcia_common_ops
= {
115 .read
= pxa2xx_pcmcia_common_read
,
116 .write
= pxa2xx_pcmcia_common_write
,
117 .endianness
= DEVICE_NATIVE_ENDIAN
120 static const MemoryRegionOps pxa2xx_pcmcia_attr_ops
= {
121 .read
= pxa2xx_pcmcia_attr_read
,
122 .write
= pxa2xx_pcmcia_attr_write
,
123 .endianness
= DEVICE_NATIVE_ENDIAN
126 static const MemoryRegionOps pxa2xx_pcmcia_io_ops
= {
127 .read
= pxa2xx_pcmcia_io_read
,
128 .write
= pxa2xx_pcmcia_io_write
,
129 .endianness
= DEVICE_NATIVE_ENDIAN
132 static void pxa2xx_pcmcia_set_irq(void *opaque
, int line
, int level
)
134 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
138 qemu_set_irq(s
->irq
, level
);
141 static void pxa2xx_pcmcia_initfn(Object
*obj
)
143 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
144 PXA2xxPCMCIAState
*s
= PXA2XX_PCMCIA(obj
);
146 memory_region_init(&s
->container_mem
, obj
, "container", 0x10000000);
147 sysbus_init_mmio(sbd
, &s
->container_mem
);
149 /* Socket I/O Memory Space */
150 memory_region_init_io(&s
->iomem
, obj
, &pxa2xx_pcmcia_io_ops
, s
,
151 "pxa2xx-pcmcia-io", 0x04000000);
152 memory_region_add_subregion(&s
->container_mem
, 0x00000000,
155 /* Then next 64 MB is reserved */
157 /* Socket Attribute Memory Space */
158 memory_region_init_io(&s
->attr_iomem
, obj
, &pxa2xx_pcmcia_attr_ops
, s
,
159 "pxa2xx-pcmcia-attribute", 0x04000000);
160 memory_region_add_subregion(&s
->container_mem
, 0x08000000,
163 /* Socket Common Memory Space */
164 memory_region_init_io(&s
->common_iomem
, obj
, &pxa2xx_pcmcia_common_ops
, s
,
165 "pxa2xx-pcmcia-common", 0x04000000);
166 memory_region_add_subregion(&s
->container_mem
, 0x0c000000,
169 s
->slot
.irq
= qemu_allocate_irq(pxa2xx_pcmcia_set_irq
, s
, 0);
171 object_property_add_link(obj
, "card", TYPE_PCMCIA_CARD
,
173 NULL
, /* read-only property */
177 /* Insert a new card into a slot */
178 int pxa2xx_pcmcia_attach(void *opaque
, PCMCIACardState
*card
)
180 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
181 PCMCIACardClass
*pcc
;
183 if (s
->slot
.attached
) {
188 qemu_irq_raise(s
->cd_irq
);
192 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
194 s
->slot
.attached
= true;
195 s
->card
->slot
= &s
->slot
;
196 pcc
->attach(s
->card
);
201 /* Eject card from the slot */
202 int pxa2xx_pcmcia_detach(void *opaque
)
204 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
205 PCMCIACardClass
*pcc
;
207 if (!s
->slot
.attached
) {
211 pcc
= PCMCIA_CARD_GET_CLASS(s
->card
);
212 pcc
->detach(s
->card
);
213 s
->card
->slot
= NULL
;
216 s
->slot
.attached
= false;
219 qemu_irq_lower(s
->irq
);
222 qemu_irq_lower(s
->cd_irq
);
228 /* Who to notify on card events */
229 void pxa2xx_pcmcia_set_irq_cb(void *opaque
, qemu_irq irq
, qemu_irq cd_irq
)
231 PXA2xxPCMCIAState
*s
= (PXA2xxPCMCIAState
*) opaque
;
236 static const TypeInfo pxa2xx_pcmcia_type_info
= {
237 .name
= TYPE_PXA2XX_PCMCIA
,
238 .parent
= TYPE_SYS_BUS_DEVICE
,
239 .instance_size
= sizeof(PXA2xxPCMCIAState
),
240 .instance_init
= pxa2xx_pcmcia_initfn
,
243 static void pxa2xx_pcmcia_register_types(void)
245 type_register_static(&pxa2xx_pcmcia_type_info
);
248 type_init(pxa2xx_pcmcia_register_types
)