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