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