root / hw / pxa2xx_mmci.c @ f4e94dfe
History | View | Annotate | Download (14 kB)
1 | a171fe39 | balrog | /*
|
---|---|---|---|
2 | a171fe39 | balrog | * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
|
3 | a171fe39 | balrog | *
|
4 | a171fe39 | balrog | * Copyright (c) 2006 Openedhand Ltd.
|
5 | a171fe39 | balrog | * Written by Andrzej Zaborowski <balrog@zabor.org>
|
6 | a171fe39 | balrog | *
|
7 | a171fe39 | balrog | * This code is licensed under the GPLv2.
|
8 | a171fe39 | balrog | */
|
9 | a171fe39 | balrog | |
10 | 87ecb68b | pbrook | #include "hw.h" |
11 | 87ecb68b | pbrook | #include "pxa.h" |
12 | a171fe39 | balrog | #include "sd.h" |
13 | a171fe39 | balrog | |
14 | bc24a225 | Paul Brook | struct PXA2xxMMCIState {
|
15 | a171fe39 | balrog | qemu_irq irq; |
16 | a171fe39 | balrog | void *dma;
|
17 | a171fe39 | balrog | |
18 | a171fe39 | balrog | SDState *card; |
19 | a171fe39 | balrog | |
20 | a171fe39 | balrog | uint32_t status; |
21 | a171fe39 | balrog | uint32_t clkrt; |
22 | a171fe39 | balrog | uint32_t spi; |
23 | a171fe39 | balrog | uint32_t cmdat; |
24 | a171fe39 | balrog | uint32_t resp_tout; |
25 | a171fe39 | balrog | uint32_t read_tout; |
26 | a171fe39 | balrog | int blklen;
|
27 | a171fe39 | balrog | int numblk;
|
28 | a171fe39 | balrog | uint32_t intmask; |
29 | a171fe39 | balrog | uint32_t intreq; |
30 | a171fe39 | balrog | int cmd;
|
31 | a171fe39 | balrog | uint32_t arg; |
32 | a171fe39 | balrog | |
33 | a171fe39 | balrog | int active;
|
34 | a171fe39 | balrog | int bytesleft;
|
35 | a171fe39 | balrog | uint8_t tx_fifo[64];
|
36 | a171fe39 | balrog | int tx_start;
|
37 | a171fe39 | balrog | int tx_len;
|
38 | a171fe39 | balrog | uint8_t rx_fifo[32];
|
39 | a171fe39 | balrog | int rx_start;
|
40 | a171fe39 | balrog | int rx_len;
|
41 | a171fe39 | balrog | uint16_t resp_fifo[9];
|
42 | a171fe39 | balrog | int resp_len;
|
43 | a171fe39 | balrog | |
44 | a171fe39 | balrog | int cmdreq;
|
45 | a171fe39 | balrog | int ac_width;
|
46 | a171fe39 | balrog | }; |
47 | a171fe39 | balrog | |
48 | a171fe39 | balrog | #define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ |
49 | a171fe39 | balrog | #define MMC_STAT 0x04 /* MMC Status register */ |
50 | a171fe39 | balrog | #define MMC_CLKRT 0x08 /* MMC Clock Rate register */ |
51 | a171fe39 | balrog | #define MMC_SPI 0x0c /* MMC SPI Mode register */ |
52 | a171fe39 | balrog | #define MMC_CMDAT 0x10 /* MMC Command/Data register */ |
53 | a171fe39 | balrog | #define MMC_RESTO 0x14 /* MMC Response Time-Out register */ |
54 | a171fe39 | balrog | #define MMC_RDTO 0x18 /* MMC Read Time-Out register */ |
55 | a171fe39 | balrog | #define MMC_BLKLEN 0x1c /* MMC Block Length register */ |
56 | a171fe39 | balrog | #define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */ |
57 | a171fe39 | balrog | #define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */ |
58 | a171fe39 | balrog | #define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */ |
59 | a171fe39 | balrog | #define MMC_I_REG 0x2c /* MMC Interrupt Request register */ |
60 | a171fe39 | balrog | #define MMC_CMD 0x30 /* MMC Command register */ |
61 | a171fe39 | balrog | #define MMC_ARGH 0x34 /* MMC Argument High register */ |
62 | a171fe39 | balrog | #define MMC_ARGL 0x38 /* MMC Argument Low register */ |
63 | a171fe39 | balrog | #define MMC_RES 0x3c /* MMC Response FIFO */ |
64 | a171fe39 | balrog | #define MMC_RXFIFO 0x40 /* MMC Receive FIFO */ |
65 | a171fe39 | balrog | #define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */ |
66 | a171fe39 | balrog | #define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */ |
67 | a171fe39 | balrog | #define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */ |
68 | a171fe39 | balrog | |
69 | a171fe39 | balrog | /* Bitfield masks */
|
70 | a171fe39 | balrog | #define STRPCL_STOP_CLK (1 << 0) |
71 | a171fe39 | balrog | #define STRPCL_STRT_CLK (1 << 1) |
72 | a171fe39 | balrog | #define STAT_TOUT_RES (1 << 1) |
73 | a171fe39 | balrog | #define STAT_CLK_EN (1 << 8) |
74 | a171fe39 | balrog | #define STAT_DATA_DONE (1 << 11) |
75 | a171fe39 | balrog | #define STAT_PRG_DONE (1 << 12) |
76 | a171fe39 | balrog | #define STAT_END_CMDRES (1 << 13) |
77 | a171fe39 | balrog | #define SPI_SPI_MODE (1 << 0) |
78 | a171fe39 | balrog | #define CMDAT_RES_TYPE (3 << 0) |
79 | a171fe39 | balrog | #define CMDAT_DATA_EN (1 << 2) |
80 | a171fe39 | balrog | #define CMDAT_WR_RD (1 << 3) |
81 | a171fe39 | balrog | #define CMDAT_DMA_EN (1 << 7) |
82 | a171fe39 | balrog | #define CMDAT_STOP_TRAN (1 << 10) |
83 | a171fe39 | balrog | #define INT_DATA_DONE (1 << 0) |
84 | a171fe39 | balrog | #define INT_PRG_DONE (1 << 1) |
85 | a171fe39 | balrog | #define INT_END_CMD (1 << 2) |
86 | a171fe39 | balrog | #define INT_STOP_CMD (1 << 3) |
87 | a171fe39 | balrog | #define INT_CLK_OFF (1 << 4) |
88 | a171fe39 | balrog | #define INT_RXFIFO_REQ (1 << 5) |
89 | a171fe39 | balrog | #define INT_TXFIFO_REQ (1 << 6) |
90 | a171fe39 | balrog | #define INT_TINT (1 << 7) |
91 | a171fe39 | balrog | #define INT_DAT_ERR (1 << 8) |
92 | a171fe39 | balrog | #define INT_RES_ERR (1 << 9) |
93 | a171fe39 | balrog | #define INT_RD_STALLED (1 << 10) |
94 | a171fe39 | balrog | #define INT_SDIO_INT (1 << 11) |
95 | a171fe39 | balrog | #define INT_SDIO_SACK (1 << 12) |
96 | a171fe39 | balrog | #define PRTBUF_PRT_BUF (1 << 0) |
97 | a171fe39 | balrog | |
98 | a171fe39 | balrog | /* Route internal interrupt lines to the global IC and DMA */
|
99 | bc24a225 | Paul Brook | static void pxa2xx_mmci_int_update(PXA2xxMMCIState *s) |
100 | a171fe39 | balrog | { |
101 | a171fe39 | balrog | uint32_t mask = s->intmask; |
102 | a171fe39 | balrog | if (s->cmdat & CMDAT_DMA_EN) {
|
103 | a171fe39 | balrog | mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ; |
104 | a171fe39 | balrog | |
105 | bc24a225 | Paul Brook | pxa2xx_dma_request(s->dma, |
106 | a171fe39 | balrog | PXA2XX_RX_RQ_MMCI, !!(s->intreq & INT_RXFIFO_REQ)); |
107 | bc24a225 | Paul Brook | pxa2xx_dma_request(s->dma, |
108 | a171fe39 | balrog | PXA2XX_TX_RQ_MMCI, !!(s->intreq & INT_TXFIFO_REQ)); |
109 | a171fe39 | balrog | } |
110 | a171fe39 | balrog | |
111 | a171fe39 | balrog | qemu_set_irq(s->irq, !!(s->intreq & ~mask)); |
112 | a171fe39 | balrog | } |
113 | a171fe39 | balrog | |
114 | bc24a225 | Paul Brook | static void pxa2xx_mmci_fifo_update(PXA2xxMMCIState *s) |
115 | a171fe39 | balrog | { |
116 | a171fe39 | balrog | if (!s->active)
|
117 | a171fe39 | balrog | return;
|
118 | a171fe39 | balrog | |
119 | a171fe39 | balrog | if (s->cmdat & CMDAT_WR_RD) {
|
120 | a171fe39 | balrog | while (s->bytesleft && s->tx_len) {
|
121 | a171fe39 | balrog | sd_write_data(s->card, s->tx_fifo[s->tx_start ++]); |
122 | a171fe39 | balrog | s->tx_start &= 0x1f;
|
123 | a171fe39 | balrog | s->tx_len --; |
124 | a171fe39 | balrog | s->bytesleft --; |
125 | a171fe39 | balrog | } |
126 | a171fe39 | balrog | if (s->bytesleft)
|
127 | a171fe39 | balrog | s->intreq |= INT_TXFIFO_REQ; |
128 | a171fe39 | balrog | } else
|
129 | a171fe39 | balrog | while (s->bytesleft && s->rx_len < 32) { |
130 | a171fe39 | balrog | s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
|
131 | a171fe39 | balrog | sd_read_data(s->card); |
132 | a171fe39 | balrog | s->bytesleft --; |
133 | a171fe39 | balrog | s->intreq |= INT_RXFIFO_REQ; |
134 | a171fe39 | balrog | } |
135 | a171fe39 | balrog | |
136 | a171fe39 | balrog | if (!s->bytesleft) {
|
137 | a171fe39 | balrog | s->active = 0;
|
138 | a171fe39 | balrog | s->intreq |= INT_DATA_DONE; |
139 | a171fe39 | balrog | s->status |= STAT_DATA_DONE; |
140 | a171fe39 | balrog | |
141 | a171fe39 | balrog | if (s->cmdat & CMDAT_WR_RD) {
|
142 | a171fe39 | balrog | s->intreq |= INT_PRG_DONE; |
143 | a171fe39 | balrog | s->status |= STAT_PRG_DONE; |
144 | a171fe39 | balrog | } |
145 | a171fe39 | balrog | } |
146 | a171fe39 | balrog | |
147 | a171fe39 | balrog | pxa2xx_mmci_int_update(s); |
148 | a171fe39 | balrog | } |
149 | a171fe39 | balrog | |
150 | bc24a225 | Paul Brook | static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) |
151 | a171fe39 | balrog | { |
152 | a171fe39 | balrog | int rsplen, i;
|
153 | bc24a225 | Paul Brook | SDRequest request; |
154 | a171fe39 | balrog | uint8_t response[16];
|
155 | a171fe39 | balrog | |
156 | a171fe39 | balrog | s->active = 1;
|
157 | a171fe39 | balrog | s->rx_len = 0;
|
158 | a171fe39 | balrog | s->tx_len = 0;
|
159 | a171fe39 | balrog | s->cmdreq = 0;
|
160 | a171fe39 | balrog | |
161 | a171fe39 | balrog | request.cmd = s->cmd; |
162 | a171fe39 | balrog | request.arg = s->arg; |
163 | a171fe39 | balrog | request.crc = 0; /* FIXME */ |
164 | a171fe39 | balrog | |
165 | a171fe39 | balrog | rsplen = sd_do_command(s->card, &request, response); |
166 | a171fe39 | balrog | s->intreq |= INT_END_CMD; |
167 | a171fe39 | balrog | |
168 | a171fe39 | balrog | memset(s->resp_fifo, 0, sizeof(s->resp_fifo)); |
169 | a171fe39 | balrog | switch (s->cmdat & CMDAT_RES_TYPE) {
|
170 | a171fe39 | balrog | #define PXAMMCI_RESP(wd, value0, value1) \
|
171 | a171fe39 | balrog | s->resp_fifo[(wd) + 0] |= (value0); \
|
172 | a171fe39 | balrog | s->resp_fifo[(wd) + 1] |= (value1) << 8; |
173 | a171fe39 | balrog | case 0: /* No response */ |
174 | a171fe39 | balrog | goto complete;
|
175 | a171fe39 | balrog | |
176 | a171fe39 | balrog | case 1: /* R1, R4, R5 or R6 */ |
177 | a171fe39 | balrog | if (rsplen < 4) |
178 | a171fe39 | balrog | goto timeout;
|
179 | a171fe39 | balrog | goto complete;
|
180 | a171fe39 | balrog | |
181 | a171fe39 | balrog | case 2: /* R2 */ |
182 | a171fe39 | balrog | if (rsplen < 16) |
183 | a171fe39 | balrog | goto timeout;
|
184 | a171fe39 | balrog | goto complete;
|
185 | a171fe39 | balrog | |
186 | a171fe39 | balrog | case 3: /* R3 */ |
187 | a171fe39 | balrog | if (rsplen < 4) |
188 | a171fe39 | balrog | goto timeout;
|
189 | a171fe39 | balrog | goto complete;
|
190 | a171fe39 | balrog | |
191 | a171fe39 | balrog | complete:
|
192 | a171fe39 | balrog | for (i = 0; rsplen > 0; i ++, rsplen -= 2) { |
193 | a171fe39 | balrog | PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]); |
194 | a171fe39 | balrog | } |
195 | a171fe39 | balrog | s->status |= STAT_END_CMDRES; |
196 | a171fe39 | balrog | |
197 | a171fe39 | balrog | if (!(s->cmdat & CMDAT_DATA_EN))
|
198 | a171fe39 | balrog | s->active = 0;
|
199 | a171fe39 | balrog | else
|
200 | a171fe39 | balrog | s->bytesleft = s->numblk * s->blklen; |
201 | a171fe39 | balrog | |
202 | a171fe39 | balrog | s->resp_len = 0;
|
203 | a171fe39 | balrog | break;
|
204 | a171fe39 | balrog | |
205 | a171fe39 | balrog | timeout:
|
206 | a171fe39 | balrog | s->active = 0;
|
207 | a171fe39 | balrog | s->status |= STAT_TOUT_RES; |
208 | a171fe39 | balrog | break;
|
209 | a171fe39 | balrog | } |
210 | a171fe39 | balrog | |
211 | a171fe39 | balrog | pxa2xx_mmci_fifo_update(s); |
212 | a171fe39 | balrog | } |
213 | a171fe39 | balrog | |
214 | c227f099 | Anthony Liguori | static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset) |
215 | a171fe39 | balrog | { |
216 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
217 | a171fe39 | balrog | uint32_t ret; |
218 | a171fe39 | balrog | |
219 | a171fe39 | balrog | switch (offset) {
|
220 | a171fe39 | balrog | case MMC_STRPCL:
|
221 | a171fe39 | balrog | return 0; |
222 | a171fe39 | balrog | case MMC_STAT:
|
223 | a171fe39 | balrog | return s->status;
|
224 | a171fe39 | balrog | case MMC_CLKRT:
|
225 | a171fe39 | balrog | return s->clkrt;
|
226 | a171fe39 | balrog | case MMC_SPI:
|
227 | a171fe39 | balrog | return s->spi;
|
228 | a171fe39 | balrog | case MMC_CMDAT:
|
229 | a171fe39 | balrog | return s->cmdat;
|
230 | a171fe39 | balrog | case MMC_RESTO:
|
231 | a171fe39 | balrog | return s->resp_tout;
|
232 | a171fe39 | balrog | case MMC_RDTO:
|
233 | a171fe39 | balrog | return s->read_tout;
|
234 | a171fe39 | balrog | case MMC_BLKLEN:
|
235 | a171fe39 | balrog | return s->blklen;
|
236 | a171fe39 | balrog | case MMC_NUMBLK:
|
237 | a171fe39 | balrog | return s->numblk;
|
238 | a171fe39 | balrog | case MMC_PRTBUF:
|
239 | a171fe39 | balrog | return 0; |
240 | a171fe39 | balrog | case MMC_I_MASK:
|
241 | a171fe39 | balrog | return s->intmask;
|
242 | a171fe39 | balrog | case MMC_I_REG:
|
243 | a171fe39 | balrog | return s->intreq;
|
244 | a171fe39 | balrog | case MMC_CMD:
|
245 | a171fe39 | balrog | return s->cmd | 0x40; |
246 | a171fe39 | balrog | case MMC_ARGH:
|
247 | a171fe39 | balrog | return s->arg >> 16; |
248 | a171fe39 | balrog | case MMC_ARGL:
|
249 | a171fe39 | balrog | return s->arg & 0xffff; |
250 | a171fe39 | balrog | case MMC_RES:
|
251 | a171fe39 | balrog | if (s->resp_len < 9) |
252 | a171fe39 | balrog | return s->resp_fifo[s->resp_len ++];
|
253 | a171fe39 | balrog | return 0; |
254 | a171fe39 | balrog | case MMC_RXFIFO:
|
255 | a171fe39 | balrog | ret = 0;
|
256 | a171fe39 | balrog | while (s->ac_width -- && s->rx_len) {
|
257 | a171fe39 | balrog | ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
|
258 | a171fe39 | balrog | s->rx_start &= 0x1f;
|
259 | a171fe39 | balrog | s->rx_len --; |
260 | a171fe39 | balrog | } |
261 | a171fe39 | balrog | s->intreq &= ~INT_RXFIFO_REQ; |
262 | a171fe39 | balrog | pxa2xx_mmci_fifo_update(s); |
263 | a171fe39 | balrog | return ret;
|
264 | a171fe39 | balrog | case MMC_RDWAIT:
|
265 | a171fe39 | balrog | return 0; |
266 | a171fe39 | balrog | case MMC_BLKS_REM:
|
267 | a171fe39 | balrog | return s->numblk;
|
268 | a171fe39 | balrog | default:
|
269 | 2ac71179 | Paul Brook | hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); |
270 | a171fe39 | balrog | } |
271 | a171fe39 | balrog | |
272 | a171fe39 | balrog | return 0; |
273 | a171fe39 | balrog | } |
274 | a171fe39 | balrog | |
275 | a171fe39 | balrog | static void pxa2xx_mmci_write(void *opaque, |
276 | c227f099 | Anthony Liguori | target_phys_addr_t offset, uint32_t value) |
277 | a171fe39 | balrog | { |
278 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
279 | a171fe39 | balrog | |
280 | a171fe39 | balrog | switch (offset) {
|
281 | a171fe39 | balrog | case MMC_STRPCL:
|
282 | a171fe39 | balrog | if (value & STRPCL_STRT_CLK) {
|
283 | a171fe39 | balrog | s->status |= STAT_CLK_EN; |
284 | a171fe39 | balrog | s->intreq &= ~INT_CLK_OFF; |
285 | a171fe39 | balrog | |
286 | a171fe39 | balrog | if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
|
287 | a171fe39 | balrog | s->status &= STAT_CLK_EN; |
288 | a171fe39 | balrog | pxa2xx_mmci_wakequeues(s); |
289 | a171fe39 | balrog | } |
290 | a171fe39 | balrog | } |
291 | a171fe39 | balrog | |
292 | a171fe39 | balrog | if (value & STRPCL_STOP_CLK) {
|
293 | a171fe39 | balrog | s->status &= ~STAT_CLK_EN; |
294 | a171fe39 | balrog | s->intreq |= INT_CLK_OFF; |
295 | a171fe39 | balrog | s->active = 0;
|
296 | a171fe39 | balrog | } |
297 | a171fe39 | balrog | |
298 | a171fe39 | balrog | pxa2xx_mmci_int_update(s); |
299 | a171fe39 | balrog | break;
|
300 | a171fe39 | balrog | |
301 | a171fe39 | balrog | case MMC_CLKRT:
|
302 | a171fe39 | balrog | s->clkrt = value & 7;
|
303 | a171fe39 | balrog | break;
|
304 | a171fe39 | balrog | |
305 | a171fe39 | balrog | case MMC_SPI:
|
306 | a171fe39 | balrog | s->spi = value & 0xf;
|
307 | a171fe39 | balrog | if (value & SPI_SPI_MODE)
|
308 | a171fe39 | balrog | printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
|
309 | a171fe39 | balrog | break;
|
310 | a171fe39 | balrog | |
311 | a171fe39 | balrog | case MMC_CMDAT:
|
312 | a171fe39 | balrog | s->cmdat = value & 0x3dff;
|
313 | a171fe39 | balrog | s->active = 0;
|
314 | a171fe39 | balrog | s->cmdreq = 1;
|
315 | a171fe39 | balrog | if (!(value & CMDAT_STOP_TRAN)) {
|
316 | a171fe39 | balrog | s->status &= STAT_CLK_EN; |
317 | a171fe39 | balrog | |
318 | a171fe39 | balrog | if (s->status & STAT_CLK_EN)
|
319 | a171fe39 | balrog | pxa2xx_mmci_wakequeues(s); |
320 | a171fe39 | balrog | } |
321 | a171fe39 | balrog | |
322 | a171fe39 | balrog | pxa2xx_mmci_int_update(s); |
323 | a171fe39 | balrog | break;
|
324 | a171fe39 | balrog | |
325 | a171fe39 | balrog | case MMC_RESTO:
|
326 | a171fe39 | balrog | s->resp_tout = value & 0x7f;
|
327 | a171fe39 | balrog | break;
|
328 | a171fe39 | balrog | |
329 | a171fe39 | balrog | case MMC_RDTO:
|
330 | a171fe39 | balrog | s->read_tout = value & 0xffff;
|
331 | a171fe39 | balrog | break;
|
332 | a171fe39 | balrog | |
333 | a171fe39 | balrog | case MMC_BLKLEN:
|
334 | a171fe39 | balrog | s->blklen = value & 0xfff;
|
335 | a171fe39 | balrog | break;
|
336 | a171fe39 | balrog | |
337 | a171fe39 | balrog | case MMC_NUMBLK:
|
338 | a171fe39 | balrog | s->numblk = value & 0xffff;
|
339 | a171fe39 | balrog | break;
|
340 | a171fe39 | balrog | |
341 | a171fe39 | balrog | case MMC_PRTBUF:
|
342 | a171fe39 | balrog | if (value & PRTBUF_PRT_BUF) {
|
343 | a171fe39 | balrog | s->tx_start ^= 32;
|
344 | a171fe39 | balrog | s->tx_len = 0;
|
345 | a171fe39 | balrog | } |
346 | a171fe39 | balrog | pxa2xx_mmci_fifo_update(s); |
347 | a171fe39 | balrog | break;
|
348 | a171fe39 | balrog | |
349 | a171fe39 | balrog | case MMC_I_MASK:
|
350 | a171fe39 | balrog | s->intmask = value & 0x1fff;
|
351 | a171fe39 | balrog | pxa2xx_mmci_int_update(s); |
352 | a171fe39 | balrog | break;
|
353 | a171fe39 | balrog | |
354 | a171fe39 | balrog | case MMC_CMD:
|
355 | a171fe39 | balrog | s->cmd = value & 0x3f;
|
356 | a171fe39 | balrog | break;
|
357 | a171fe39 | balrog | |
358 | a171fe39 | balrog | case MMC_ARGH:
|
359 | a171fe39 | balrog | s->arg &= 0x0000ffff;
|
360 | a171fe39 | balrog | s->arg |= value << 16;
|
361 | a171fe39 | balrog | break;
|
362 | a171fe39 | balrog | |
363 | a171fe39 | balrog | case MMC_ARGL:
|
364 | a171fe39 | balrog | s->arg &= 0xffff0000;
|
365 | a171fe39 | balrog | s->arg |= value & 0x0000ffff;
|
366 | a171fe39 | balrog | break;
|
367 | a171fe39 | balrog | |
368 | a171fe39 | balrog | case MMC_TXFIFO:
|
369 | a171fe39 | balrog | while (s->ac_width -- && s->tx_len < 0x20) |
370 | a171fe39 | balrog | s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
|
371 | a171fe39 | balrog | (value >> (s->ac_width << 3)) & 0xff; |
372 | a171fe39 | balrog | s->intreq &= ~INT_TXFIFO_REQ; |
373 | a171fe39 | balrog | pxa2xx_mmci_fifo_update(s); |
374 | a171fe39 | balrog | break;
|
375 | a171fe39 | balrog | |
376 | a171fe39 | balrog | case MMC_RDWAIT:
|
377 | a171fe39 | balrog | case MMC_BLKS_REM:
|
378 | a171fe39 | balrog | break;
|
379 | a171fe39 | balrog | |
380 | a171fe39 | balrog | default:
|
381 | 2ac71179 | Paul Brook | hw_error("%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset); |
382 | a171fe39 | balrog | } |
383 | a171fe39 | balrog | } |
384 | a171fe39 | balrog | |
385 | c227f099 | Anthony Liguori | static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset) |
386 | a171fe39 | balrog | { |
387 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
388 | a171fe39 | balrog | s->ac_width = 1;
|
389 | a171fe39 | balrog | return pxa2xx_mmci_read(opaque, offset);
|
390 | a171fe39 | balrog | } |
391 | a171fe39 | balrog | |
392 | c227f099 | Anthony Liguori | static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset) |
393 | a171fe39 | balrog | { |
394 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
395 | a171fe39 | balrog | s->ac_width = 2;
|
396 | a171fe39 | balrog | return pxa2xx_mmci_read(opaque, offset);
|
397 | a171fe39 | balrog | } |
398 | a171fe39 | balrog | |
399 | c227f099 | Anthony Liguori | static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset) |
400 | a171fe39 | balrog | { |
401 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
402 | a171fe39 | balrog | s->ac_width = 4;
|
403 | a171fe39 | balrog | return pxa2xx_mmci_read(opaque, offset);
|
404 | a171fe39 | balrog | } |
405 | a171fe39 | balrog | |
406 | d60efc6b | Blue Swirl | static CPUReadMemoryFunc * const pxa2xx_mmci_readfn[] = { |
407 | a171fe39 | balrog | pxa2xx_mmci_readb, |
408 | a171fe39 | balrog | pxa2xx_mmci_readh, |
409 | a171fe39 | balrog | pxa2xx_mmci_readw |
410 | a171fe39 | balrog | }; |
411 | a171fe39 | balrog | |
412 | a171fe39 | balrog | static void pxa2xx_mmci_writeb(void *opaque, |
413 | c227f099 | Anthony Liguori | target_phys_addr_t offset, uint32_t value) |
414 | a171fe39 | balrog | { |
415 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
416 | a171fe39 | balrog | s->ac_width = 1;
|
417 | a171fe39 | balrog | pxa2xx_mmci_write(opaque, offset, value); |
418 | a171fe39 | balrog | } |
419 | a171fe39 | balrog | |
420 | a171fe39 | balrog | static void pxa2xx_mmci_writeh(void *opaque, |
421 | c227f099 | Anthony Liguori | target_phys_addr_t offset, uint32_t value) |
422 | a171fe39 | balrog | { |
423 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
424 | a171fe39 | balrog | s->ac_width = 2;
|
425 | a171fe39 | balrog | pxa2xx_mmci_write(opaque, offset, value); |
426 | a171fe39 | balrog | } |
427 | a171fe39 | balrog | |
428 | a171fe39 | balrog | static void pxa2xx_mmci_writew(void *opaque, |
429 | c227f099 | Anthony Liguori | target_phys_addr_t offset, uint32_t value) |
430 | a171fe39 | balrog | { |
431 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
432 | a171fe39 | balrog | s->ac_width = 4;
|
433 | a171fe39 | balrog | pxa2xx_mmci_write(opaque, offset, value); |
434 | a171fe39 | balrog | } |
435 | a171fe39 | balrog | |
436 | d60efc6b | Blue Swirl | static CPUWriteMemoryFunc * const pxa2xx_mmci_writefn[] = { |
437 | a171fe39 | balrog | pxa2xx_mmci_writeb, |
438 | a171fe39 | balrog | pxa2xx_mmci_writeh, |
439 | a171fe39 | balrog | pxa2xx_mmci_writew |
440 | a171fe39 | balrog | }; |
441 | a171fe39 | balrog | |
442 | aa941b94 | balrog | static void pxa2xx_mmci_save(QEMUFile *f, void *opaque) |
443 | aa941b94 | balrog | { |
444 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
445 | aa941b94 | balrog | int i;
|
446 | aa941b94 | balrog | |
447 | aa941b94 | balrog | qemu_put_be32s(f, &s->status); |
448 | aa941b94 | balrog | qemu_put_be32s(f, &s->clkrt); |
449 | aa941b94 | balrog | qemu_put_be32s(f, &s->spi); |
450 | aa941b94 | balrog | qemu_put_be32s(f, &s->cmdat); |
451 | aa941b94 | balrog | qemu_put_be32s(f, &s->resp_tout); |
452 | aa941b94 | balrog | qemu_put_be32s(f, &s->read_tout); |
453 | aa941b94 | balrog | qemu_put_be32(f, s->blklen); |
454 | aa941b94 | balrog | qemu_put_be32(f, s->numblk); |
455 | aa941b94 | balrog | qemu_put_be32s(f, &s->intmask); |
456 | aa941b94 | balrog | qemu_put_be32s(f, &s->intreq); |
457 | aa941b94 | balrog | qemu_put_be32(f, s->cmd); |
458 | aa941b94 | balrog | qemu_put_be32s(f, &s->arg); |
459 | aa941b94 | balrog | qemu_put_be32(f, s->cmdreq); |
460 | aa941b94 | balrog | qemu_put_be32(f, s->active); |
461 | aa941b94 | balrog | qemu_put_be32(f, s->bytesleft); |
462 | aa941b94 | balrog | |
463 | aa941b94 | balrog | qemu_put_byte(f, s->tx_len); |
464 | aa941b94 | balrog | for (i = 0; i < s->tx_len; i ++) |
465 | aa941b94 | balrog | qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]);
|
466 | aa941b94 | balrog | |
467 | aa941b94 | balrog | qemu_put_byte(f, s->rx_len); |
468 | aa941b94 | balrog | for (i = 0; i < s->rx_len; i ++) |
469 | aa941b94 | balrog | qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]);
|
470 | aa941b94 | balrog | |
471 | aa941b94 | balrog | qemu_put_byte(f, s->resp_len); |
472 | aa941b94 | balrog | for (i = s->resp_len; i < 9; i ++) |
473 | aa941b94 | balrog | qemu_put_be16s(f, &s->resp_fifo[i]); |
474 | aa941b94 | balrog | } |
475 | aa941b94 | balrog | |
476 | aa941b94 | balrog | static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id) |
477 | aa941b94 | balrog | { |
478 | bc24a225 | Paul Brook | PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; |
479 | aa941b94 | balrog | int i;
|
480 | aa941b94 | balrog | |
481 | aa941b94 | balrog | qemu_get_be32s(f, &s->status); |
482 | aa941b94 | balrog | qemu_get_be32s(f, &s->clkrt); |
483 | aa941b94 | balrog | qemu_get_be32s(f, &s->spi); |
484 | aa941b94 | balrog | qemu_get_be32s(f, &s->cmdat); |
485 | aa941b94 | balrog | qemu_get_be32s(f, &s->resp_tout); |
486 | aa941b94 | balrog | qemu_get_be32s(f, &s->read_tout); |
487 | aa941b94 | balrog | s->blklen = qemu_get_be32(f); |
488 | aa941b94 | balrog | s->numblk = qemu_get_be32(f); |
489 | aa941b94 | balrog | qemu_get_be32s(f, &s->intmask); |
490 | aa941b94 | balrog | qemu_get_be32s(f, &s->intreq); |
491 | aa941b94 | balrog | s->cmd = qemu_get_be32(f); |
492 | aa941b94 | balrog | qemu_get_be32s(f, &s->arg); |
493 | aa941b94 | balrog | s->cmdreq = qemu_get_be32(f); |
494 | aa941b94 | balrog | s->active = qemu_get_be32(f); |
495 | aa941b94 | balrog | s->bytesleft = qemu_get_be32(f); |
496 | aa941b94 | balrog | |
497 | aa941b94 | balrog | s->tx_len = qemu_get_byte(f); |
498 | aa941b94 | balrog | s->tx_start = 0;
|
499 | aa941b94 | balrog | if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0) |
500 | aa941b94 | balrog | return -EINVAL;
|
501 | aa941b94 | balrog | for (i = 0; i < s->tx_len; i ++) |
502 | aa941b94 | balrog | s->tx_fifo[i] = qemu_get_byte(f); |
503 | aa941b94 | balrog | |
504 | aa941b94 | balrog | s->rx_len = qemu_get_byte(f); |
505 | aa941b94 | balrog | s->rx_start = 0;
|
506 | aa941b94 | balrog | if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0) |
507 | aa941b94 | balrog | return -EINVAL;
|
508 | aa941b94 | balrog | for (i = 0; i < s->rx_len; i ++) |
509 | aa941b94 | balrog | s->rx_fifo[i] = qemu_get_byte(f); |
510 | aa941b94 | balrog | |
511 | aa941b94 | balrog | s->resp_len = qemu_get_byte(f); |
512 | aa941b94 | balrog | if (s->resp_len > 9 || s->resp_len < 0) |
513 | aa941b94 | balrog | return -EINVAL;
|
514 | aa941b94 | balrog | for (i = s->resp_len; i < 9; i ++) |
515 | aa941b94 | balrog | qemu_get_be16s(f, &s->resp_fifo[i]); |
516 | aa941b94 | balrog | |
517 | aa941b94 | balrog | return 0; |
518 | aa941b94 | balrog | } |
519 | aa941b94 | balrog | |
520 | c227f099 | Anthony Liguori | PXA2xxMMCIState *pxa2xx_mmci_init(target_phys_addr_t base, |
521 | 87ecb68b | pbrook | BlockDriverState *bd, qemu_irq irq, void *dma)
|
522 | a171fe39 | balrog | { |
523 | a171fe39 | balrog | int iomemtype;
|
524 | bc24a225 | Paul Brook | PXA2xxMMCIState *s; |
525 | a171fe39 | balrog | |
526 | bc24a225 | Paul Brook | s = (PXA2xxMMCIState *) qemu_mallocz(sizeof(PXA2xxMMCIState));
|
527 | a171fe39 | balrog | s->irq = irq; |
528 | a171fe39 | balrog | s->dma = dma; |
529 | a171fe39 | balrog | |
530 | 1eed09cb | Avi Kivity | iomemtype = cpu_register_io_memory(pxa2xx_mmci_readfn, |
531 | a171fe39 | balrog | pxa2xx_mmci_writefn, s); |
532 | 187337f8 | pbrook | cpu_register_physical_memory(base, 0x00100000, iomemtype);
|
533 | a171fe39 | balrog | |
534 | a171fe39 | balrog | /* Instantiate the actual storage */
|
535 | c81b7401 | pbrook | s->card = sd_init(bd, 0);
|
536 | a171fe39 | balrog | |
537 | aa941b94 | balrog | register_savevm("pxa2xx_mmci", 0, 0, |
538 | aa941b94 | balrog | pxa2xx_mmci_save, pxa2xx_mmci_load, s); |
539 | aa941b94 | balrog | |
540 | a171fe39 | balrog | return s;
|
541 | a171fe39 | balrog | } |
542 | a171fe39 | balrog | |
543 | bc24a225 | Paul Brook | void pxa2xx_mmci_handlers(PXA2xxMMCIState *s, qemu_irq readonly,
|
544 | 02ce600c | balrog | qemu_irq coverswitch) |
545 | a171fe39 | balrog | { |
546 | e1dad5a6 | balrog | sd_set_cb(s->card, readonly, coverswitch); |
547 | a171fe39 | balrog | } |