]>
Commit | Line | Data |
---|---|---|
a171fe39 AZ |
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 | ||
87ecb68b PB |
10 | #include "hw.h" |
11 | #include "pcmcia.h" | |
9596ebb7 | 12 | #include "pxa.h" |
a171fe39 | 13 | |
bc24a225 PB |
14 | struct PXA2xxPCMCIAState { |
15 | PCMCIASocket slot; | |
16 | PCMCIACardState *card; | |
354a8c06 | 17 | MemoryRegion common_iomem; |
a171fe39 AZ |
18 | |
19 | qemu_irq irq; | |
20 | qemu_irq cd_irq; | |
21 | }; | |
22 | ||
354a8c06 BC |
23 | static uint64_t pxa2xx_pcmcia_common_read(void *opaque, |
24 | target_phys_addr_t offset, unsigned size) | |
a171fe39 | 25 | { |
bc24a225 | 26 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
27 | |
28 | if (s->slot.attached) { | |
a171fe39 AZ |
29 | return s->card->common_read(s->card->state, offset); |
30 | } | |
31 | ||
32 | return 0; | |
33 | } | |
34 | ||
354a8c06 BC |
35 | static void pxa2xx_pcmcia_common_write(void *opaque, target_phys_addr_t offset, |
36 | uint64_t value, unsigned size) | |
a171fe39 | 37 | { |
bc24a225 | 38 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
39 | |
40 | if (s->slot.attached) { | |
a171fe39 AZ |
41 | s->card->common_write(s->card->state, offset, value); |
42 | } | |
43 | } | |
44 | ||
45 | static uint32_t pxa2xx_pcmcia_attr_read(void *opaque, | |
c227f099 | 46 | target_phys_addr_t offset) |
a171fe39 | 47 | { |
bc24a225 | 48 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
49 | |
50 | if (s->slot.attached) { | |
a171fe39 AZ |
51 | return s->card->attr_read(s->card->state, offset); |
52 | } | |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
57 | static void pxa2xx_pcmcia_attr_write(void *opaque, | |
c227f099 | 58 | target_phys_addr_t offset, uint32_t value) |
a171fe39 | 59 | { |
bc24a225 | 60 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
61 | |
62 | if (s->slot.attached) { | |
a171fe39 AZ |
63 | s->card->attr_write(s->card->state, offset, value); |
64 | } | |
65 | } | |
66 | ||
67 | static uint32_t pxa2xx_pcmcia_io_read(void *opaque, | |
c227f099 | 68 | target_phys_addr_t offset) |
a171fe39 | 69 | { |
bc24a225 | 70 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
71 | |
72 | if (s->slot.attached) { | |
a171fe39 AZ |
73 | return s->card->io_read(s->card->state, offset); |
74 | } | |
75 | ||
76 | return 0; | |
77 | } | |
78 | ||
79 | static void pxa2xx_pcmcia_io_write(void *opaque, | |
c227f099 | 80 | target_phys_addr_t offset, uint32_t value) |
a171fe39 | 81 | { |
bc24a225 | 82 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
83 | |
84 | if (s->slot.attached) { | |
a171fe39 AZ |
85 | s->card->io_write(s->card->state, offset, value); |
86 | } | |
87 | } | |
88 | ||
354a8c06 BC |
89 | static const MemoryRegionOps pxa2xx_pcmcia_common_ops = { |
90 | .read = pxa2xx_pcmcia_common_read, | |
91 | .write = pxa2xx_pcmcia_common_write, | |
92 | .endianness = DEVICE_NATIVE_ENDIAN | |
a171fe39 AZ |
93 | }; |
94 | ||
d60efc6b | 95 | static CPUReadMemoryFunc * const pxa2xx_pcmcia_attr_readfn[] = { |
a171fe39 AZ |
96 | pxa2xx_pcmcia_attr_read, |
97 | pxa2xx_pcmcia_attr_read, | |
98 | pxa2xx_pcmcia_attr_read, | |
99 | }; | |
100 | ||
d60efc6b | 101 | static CPUWriteMemoryFunc * const pxa2xx_pcmcia_attr_writefn[] = { |
a171fe39 AZ |
102 | pxa2xx_pcmcia_attr_write, |
103 | pxa2xx_pcmcia_attr_write, | |
104 | pxa2xx_pcmcia_attr_write, | |
105 | }; | |
106 | ||
d60efc6b | 107 | static CPUReadMemoryFunc * const pxa2xx_pcmcia_io_readfn[] = { |
a171fe39 AZ |
108 | pxa2xx_pcmcia_io_read, |
109 | pxa2xx_pcmcia_io_read, | |
110 | pxa2xx_pcmcia_io_read, | |
111 | }; | |
112 | ||
d60efc6b | 113 | static CPUWriteMemoryFunc * const pxa2xx_pcmcia_io_writefn[] = { |
a171fe39 AZ |
114 | pxa2xx_pcmcia_io_write, |
115 | pxa2xx_pcmcia_io_write, | |
116 | pxa2xx_pcmcia_io_write, | |
117 | }; | |
118 | ||
119 | static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level) | |
120 | { | |
bc24a225 | 121 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
122 | if (!s->irq) |
123 | return; | |
124 | ||
125 | qemu_set_irq(s->irq, level); | |
126 | } | |
127 | ||
354a8c06 BC |
128 | PXA2xxPCMCIAState *pxa2xx_pcmcia_init(MemoryRegion *sysmem, |
129 | target_phys_addr_t base) | |
a171fe39 AZ |
130 | { |
131 | int iomemtype; | |
bc24a225 | 132 | PXA2xxPCMCIAState *s; |
a171fe39 | 133 | |
bc24a225 | 134 | s = (PXA2xxPCMCIAState *) |
7267c094 | 135 | g_malloc0(sizeof(PXA2xxPCMCIAState)); |
a171fe39 AZ |
136 | |
137 | /* Socket I/O Memory Space */ | |
1eed09cb | 138 | iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_io_readfn, |
2507c12a | 139 | pxa2xx_pcmcia_io_writefn, s, DEVICE_NATIVE_ENDIAN); |
8da3ff18 | 140 | cpu_register_physical_memory(base | 0x00000000, 0x04000000, iomemtype); |
a171fe39 AZ |
141 | |
142 | /* Then next 64 MB is reserved */ | |
143 | ||
144 | /* Socket Attribute Memory Space */ | |
1eed09cb | 145 | iomemtype = cpu_register_io_memory(pxa2xx_pcmcia_attr_readfn, |
2507c12a | 146 | pxa2xx_pcmcia_attr_writefn, s, DEVICE_NATIVE_ENDIAN); |
8da3ff18 | 147 | cpu_register_physical_memory(base | 0x08000000, 0x04000000, iomemtype); |
a171fe39 AZ |
148 | |
149 | /* Socket Common Memory Space */ | |
354a8c06 BC |
150 | memory_region_init_io(&s->common_iomem, &pxa2xx_pcmcia_common_ops, s, |
151 | "pxa2xx-pcmcia-common", 0x04000000); | |
152 | memory_region_add_subregion(sysmem, base | 0x0c000000, | |
153 | &s->common_iomem); | |
a171fe39 AZ |
154 | |
155 | if (base == 0x30000000) | |
156 | s->slot.slot_string = "PXA PC Card Socket 1"; | |
157 | else | |
158 | s->slot.slot_string = "PXA PC Card Socket 0"; | |
159 | s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0]; | |
160 | pcmcia_socket_register(&s->slot); | |
3f582262 | 161 | |
a171fe39 AZ |
162 | return s; |
163 | } | |
164 | ||
165 | /* Insert a new card into a slot */ | |
bc24a225 | 166 | int pxa2xx_pcmcia_attach(void *opaque, PCMCIACardState *card) |
a171fe39 | 167 | { |
bc24a225 | 168 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
169 | if (s->slot.attached) |
170 | return -EEXIST; | |
171 | ||
172 | if (s->cd_irq) { | |
173 | qemu_irq_raise(s->cd_irq); | |
174 | } | |
175 | ||
176 | s->card = card; | |
177 | ||
178 | s->slot.attached = 1; | |
179 | s->card->slot = &s->slot; | |
180 | s->card->attach(s->card->state); | |
181 | ||
182 | return 0; | |
183 | } | |
184 | ||
185 | /* Eject card from the slot */ | |
186 | int pxa2xx_pcmcia_dettach(void *opaque) | |
187 | { | |
bc24a225 | 188 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
189 | if (!s->slot.attached) |
190 | return -ENOENT; | |
191 | ||
192 | s->card->detach(s->card->state); | |
b9d38e95 BS |
193 | s->card->slot = NULL; |
194 | s->card = NULL; | |
a171fe39 AZ |
195 | |
196 | s->slot.attached = 0; | |
197 | ||
198 | if (s->irq) | |
199 | qemu_irq_lower(s->irq); | |
200 | if (s->cd_irq) | |
201 | qemu_irq_lower(s->cd_irq); | |
202 | ||
203 | return 0; | |
204 | } | |
205 | ||
206 | /* Who to notify on card events */ | |
207 | void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq) | |
208 | { | |
bc24a225 | 209 | PXA2xxPCMCIAState *s = (PXA2xxPCMCIAState *) opaque; |
a171fe39 AZ |
210 | s->irq = irq; |
211 | s->cd_irq = cd_irq; | |
212 | } |