Implement the PXA2xx I2C master controller.
[qemu] / hw / pxa2xx_pcmcia.c
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 "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);
152     cpu_register_physical_memory(s->io_base, 0x03ffffff, iomemtype);
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);
160     cpu_register_physical_memory(s->attr_base, 0x03ffffff, iomemtype);
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);
166     cpu_register_physical_memory(s->common_base, 0x03ffffff, iomemtype);
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);
174
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 }