]>
Commit | Line | Data |
---|---|---|
82e48382 NL |
1 | /* |
2 | * Allwinner (sun4i and above) SD Host Controller emulation | |
3 | * | |
4 | * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com> | |
5 | * | |
6 | * This program is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include "qemu/osdep.h" | |
21 | #include "qemu/log.h" | |
22 | #include "qemu/module.h" | |
23 | #include "qemu/units.h" | |
b3aec952 | 24 | #include "qapi/error.h" |
82e48382 | 25 | #include "sysemu/blockdev.h" |
b3aec952 PMD |
26 | #include "sysemu/dma.h" |
27 | #include "hw/qdev-properties.h" | |
82e48382 NL |
28 | #include "hw/irq.h" |
29 | #include "hw/sd/allwinner-sdhost.h" | |
30 | #include "migration/vmstate.h" | |
31 | #include "trace.h" | |
db1015e9 | 32 | #include "qom/object.h" |
82e48382 NL |
33 | |
34 | #define TYPE_AW_SDHOST_BUS "allwinner-sdhost-bus" | |
35 | #define AW_SDHOST_BUS(obj) \ | |
36 | OBJECT_CHECK(SDBus, (obj), TYPE_AW_SDHOST_BUS) | |
37 | ||
38 | /* SD Host register offsets */ | |
39 | enum { | |
40 | REG_SD_GCTL = 0x00, /* Global Control */ | |
41 | REG_SD_CKCR = 0x04, /* Clock Control */ | |
42 | REG_SD_TMOR = 0x08, /* Timeout */ | |
43 | REG_SD_BWDR = 0x0C, /* Bus Width */ | |
44 | REG_SD_BKSR = 0x10, /* Block Size */ | |
45 | REG_SD_BYCR = 0x14, /* Byte Count */ | |
46 | REG_SD_CMDR = 0x18, /* Command */ | |
47 | REG_SD_CAGR = 0x1C, /* Command Argument */ | |
48 | REG_SD_RESP0 = 0x20, /* Response Zero */ | |
49 | REG_SD_RESP1 = 0x24, /* Response One */ | |
50 | REG_SD_RESP2 = 0x28, /* Response Two */ | |
51 | REG_SD_RESP3 = 0x2C, /* Response Three */ | |
52 | REG_SD_IMKR = 0x30, /* Interrupt Mask */ | |
53 | REG_SD_MISR = 0x34, /* Masked Interrupt Status */ | |
54 | REG_SD_RISR = 0x38, /* Raw Interrupt Status */ | |
55 | REG_SD_STAR = 0x3C, /* Status */ | |
56 | REG_SD_FWLR = 0x40, /* FIFO Water Level */ | |
57 | REG_SD_FUNS = 0x44, /* FIFO Function Select */ | |
58 | REG_SD_DBGC = 0x50, /* Debug Enable */ | |
59 | REG_SD_A12A = 0x58, /* Auto command 12 argument */ | |
60 | REG_SD_NTSR = 0x5C, /* SD NewTiming Set */ | |
61 | REG_SD_SDBG = 0x60, /* SD newTiming Set Debug */ | |
62 | REG_SD_HWRST = 0x78, /* Hardware Reset Register */ | |
63 | REG_SD_DMAC = 0x80, /* Internal DMA Controller Control */ | |
64 | REG_SD_DLBA = 0x84, /* Descriptor List Base Address */ | |
65 | REG_SD_IDST = 0x88, /* Internal DMA Controller Status */ | |
66 | REG_SD_IDIE = 0x8C, /* Internal DMA Controller IRQ Enable */ | |
67 | REG_SD_THLDC = 0x100, /* Card Threshold Control */ | |
68 | REG_SD_DSBD = 0x10C, /* eMMC DDR Start Bit Detection Control */ | |
69 | REG_SD_RES_CRC = 0x110, /* Response CRC from card/eMMC */ | |
70 | REG_SD_DATA7_CRC = 0x114, /* CRC Data 7 from card/eMMC */ | |
71 | REG_SD_DATA6_CRC = 0x118, /* CRC Data 6 from card/eMMC */ | |
72 | REG_SD_DATA5_CRC = 0x11C, /* CRC Data 5 from card/eMMC */ | |
73 | REG_SD_DATA4_CRC = 0x120, /* CRC Data 4 from card/eMMC */ | |
74 | REG_SD_DATA3_CRC = 0x124, /* CRC Data 3 from card/eMMC */ | |
75 | REG_SD_DATA2_CRC = 0x128, /* CRC Data 2 from card/eMMC */ | |
76 | REG_SD_DATA1_CRC = 0x12C, /* CRC Data 1 from card/eMMC */ | |
77 | REG_SD_DATA0_CRC = 0x130, /* CRC Data 0 from card/eMMC */ | |
78 | REG_SD_CRC_STA = 0x134, /* CRC status from card/eMMC during write */ | |
79 | REG_SD_FIFO = 0x200, /* Read/Write FIFO */ | |
80 | }; | |
81 | ||
82 | /* SD Host register flags */ | |
83 | enum { | |
84 | SD_GCTL_FIFO_AC_MOD = (1 << 31), | |
85 | SD_GCTL_DDR_MOD_SEL = (1 << 10), | |
86 | SD_GCTL_CD_DBC_ENB = (1 << 8), | |
87 | SD_GCTL_DMA_ENB = (1 << 5), | |
88 | SD_GCTL_INT_ENB = (1 << 4), | |
89 | SD_GCTL_DMA_RST = (1 << 2), | |
90 | SD_GCTL_FIFO_RST = (1 << 1), | |
91 | SD_GCTL_SOFT_RST = (1 << 0), | |
92 | }; | |
93 | ||
94 | enum { | |
95 | SD_CMDR_LOAD = (1 << 31), | |
96 | SD_CMDR_CLKCHANGE = (1 << 21), | |
97 | SD_CMDR_WRITE = (1 << 10), | |
98 | SD_CMDR_AUTOSTOP = (1 << 12), | |
99 | SD_CMDR_DATA = (1 << 9), | |
100 | SD_CMDR_RESPONSE_LONG = (1 << 7), | |
101 | SD_CMDR_RESPONSE = (1 << 6), | |
102 | SD_CMDR_CMDID_MASK = (0x3f), | |
103 | }; | |
104 | ||
105 | enum { | |
106 | SD_RISR_CARD_REMOVE = (1 << 31), | |
107 | SD_RISR_CARD_INSERT = (1 << 30), | |
108 | SD_RISR_SDIO_INTR = (1 << 16), | |
109 | SD_RISR_AUTOCMD_DONE = (1 << 14), | |
110 | SD_RISR_DATA_COMPLETE = (1 << 3), | |
111 | SD_RISR_CMD_COMPLETE = (1 << 2), | |
112 | SD_RISR_NO_RESPONSE = (1 << 1), | |
113 | }; | |
114 | ||
115 | enum { | |
116 | SD_STAR_CARD_PRESENT = (1 << 8), | |
117 | }; | |
118 | ||
119 | enum { | |
120 | SD_IDST_INT_SUMMARY = (1 << 8), | |
121 | SD_IDST_RECEIVE_IRQ = (1 << 1), | |
122 | SD_IDST_TRANSMIT_IRQ = (1 << 0), | |
123 | SD_IDST_IRQ_MASK = (1 << 1) | (1 << 0) | (1 << 8), | |
124 | SD_IDST_WR_MASK = (0x3ff), | |
125 | }; | |
126 | ||
127 | /* SD Host register reset values */ | |
128 | enum { | |
129 | REG_SD_GCTL_RST = 0x00000300, | |
130 | REG_SD_CKCR_RST = 0x0, | |
131 | REG_SD_TMOR_RST = 0xFFFFFF40, | |
132 | REG_SD_BWDR_RST = 0x0, | |
133 | REG_SD_BKSR_RST = 0x00000200, | |
134 | REG_SD_BYCR_RST = 0x00000200, | |
135 | REG_SD_CMDR_RST = 0x0, | |
136 | REG_SD_CAGR_RST = 0x0, | |
137 | REG_SD_RESP_RST = 0x0, | |
138 | REG_SD_IMKR_RST = 0x0, | |
139 | REG_SD_MISR_RST = 0x0, | |
140 | REG_SD_RISR_RST = 0x0, | |
141 | REG_SD_STAR_RST = 0x00000100, | |
142 | REG_SD_FWLR_RST = 0x000F0000, | |
143 | REG_SD_FUNS_RST = 0x0, | |
144 | REG_SD_DBGC_RST = 0x0, | |
145 | REG_SD_A12A_RST = 0x0000FFFF, | |
146 | REG_SD_NTSR_RST = 0x00000001, | |
147 | REG_SD_SDBG_RST = 0x0, | |
148 | REG_SD_HWRST_RST = 0x00000001, | |
149 | REG_SD_DMAC_RST = 0x0, | |
150 | REG_SD_DLBA_RST = 0x0, | |
151 | REG_SD_IDST_RST = 0x0, | |
152 | REG_SD_IDIE_RST = 0x0, | |
153 | REG_SD_THLDC_RST = 0x0, | |
154 | REG_SD_DSBD_RST = 0x0, | |
155 | REG_SD_RES_CRC_RST = 0x0, | |
156 | REG_SD_DATA_CRC_RST = 0x0, | |
157 | REG_SD_CRC_STA_RST = 0x0, | |
158 | REG_SD_FIFO_RST = 0x0, | |
159 | }; | |
160 | ||
161 | /* Data transfer descriptor for DMA */ | |
162 | typedef struct TransferDescriptor { | |
163 | uint32_t status; /* Status flags */ | |
164 | uint32_t size; /* Data buffer size */ | |
165 | uint32_t addr; /* Data buffer address */ | |
166 | uint32_t next; /* Physical address of next descriptor */ | |
167 | } TransferDescriptor; | |
168 | ||
169 | /* Data transfer descriptor flags */ | |
170 | enum { | |
171 | DESC_STATUS_HOLD = (1 << 31), /* Set when descriptor is in use by DMA */ | |
172 | DESC_STATUS_ERROR = (1 << 30), /* Set when DMA transfer error occurred */ | |
173 | DESC_STATUS_CHAIN = (1 << 4), /* Indicates chained descriptor. */ | |
174 | DESC_STATUS_FIRST = (1 << 3), /* Set on the first descriptor */ | |
175 | DESC_STATUS_LAST = (1 << 2), /* Set on the last descriptor */ | |
176 | DESC_STATUS_NOIRQ = (1 << 1), /* Skip raising interrupt after transfer */ | |
177 | DESC_SIZE_MASK = (0xfffffffc) | |
178 | }; | |
179 | ||
180 | static void allwinner_sdhost_update_irq(AwSdHostState *s) | |
181 | { | |
182 | uint32_t irq; | |
183 | ||
184 | if (s->global_ctl & SD_GCTL_INT_ENB) { | |
185 | irq = s->irq_status & s->irq_mask; | |
186 | } else { | |
187 | irq = 0; | |
188 | } | |
189 | ||
190 | trace_allwinner_sdhost_update_irq(irq); | |
191 | qemu_set_irq(s->irq, irq); | |
192 | } | |
193 | ||
194 | static void allwinner_sdhost_update_transfer_cnt(AwSdHostState *s, | |
195 | uint32_t bytes) | |
196 | { | |
197 | if (s->transfer_cnt > bytes) { | |
198 | s->transfer_cnt -= bytes; | |
199 | } else { | |
200 | s->transfer_cnt = 0; | |
201 | } | |
202 | ||
203 | if (!s->transfer_cnt) { | |
204 | s->irq_status |= SD_RISR_DATA_COMPLETE; | |
205 | } | |
206 | } | |
207 | ||
208 | static void allwinner_sdhost_set_inserted(DeviceState *dev, bool inserted) | |
209 | { | |
210 | AwSdHostState *s = AW_SDHOST(dev); | |
211 | ||
212 | trace_allwinner_sdhost_set_inserted(inserted); | |
213 | ||
214 | if (inserted) { | |
215 | s->irq_status |= SD_RISR_CARD_INSERT; | |
216 | s->irq_status &= ~SD_RISR_CARD_REMOVE; | |
217 | s->status |= SD_STAR_CARD_PRESENT; | |
218 | } else { | |
219 | s->irq_status &= ~SD_RISR_CARD_INSERT; | |
220 | s->irq_status |= SD_RISR_CARD_REMOVE; | |
221 | s->status &= ~SD_STAR_CARD_PRESENT; | |
222 | } | |
223 | ||
224 | allwinner_sdhost_update_irq(s); | |
225 | } | |
226 | ||
227 | static void allwinner_sdhost_send_command(AwSdHostState *s) | |
228 | { | |
229 | SDRequest request; | |
230 | uint8_t resp[16]; | |
231 | int rlen; | |
232 | ||
233 | /* Auto clear load flag */ | |
234 | s->command &= ~SD_CMDR_LOAD; | |
235 | ||
236 | /* Clock change does not actually interact with the SD bus */ | |
237 | if (!(s->command & SD_CMDR_CLKCHANGE)) { | |
238 | ||
239 | /* Prepare request */ | |
240 | request.cmd = s->command & SD_CMDR_CMDID_MASK; | |
241 | request.arg = s->command_arg; | |
242 | ||
243 | /* Send request to SD bus */ | |
244 | rlen = sdbus_do_command(&s->sdbus, &request, resp); | |
245 | if (rlen < 0) { | |
246 | goto error; | |
247 | } | |
248 | ||
249 | /* If the command has a response, store it in the response registers */ | |
250 | if ((s->command & SD_CMDR_RESPONSE)) { | |
251 | if (rlen == 4 && !(s->command & SD_CMDR_RESPONSE_LONG)) { | |
252 | s->response[0] = ldl_be_p(&resp[0]); | |
253 | s->response[1] = s->response[2] = s->response[3] = 0; | |
254 | ||
255 | } else if (rlen == 16 && (s->command & SD_CMDR_RESPONSE_LONG)) { | |
256 | s->response[0] = ldl_be_p(&resp[12]); | |
257 | s->response[1] = ldl_be_p(&resp[8]); | |
258 | s->response[2] = ldl_be_p(&resp[4]); | |
259 | s->response[3] = ldl_be_p(&resp[0]); | |
260 | } else { | |
261 | goto error; | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | /* Set interrupt status bits */ | |
267 | s->irq_status |= SD_RISR_CMD_COMPLETE; | |
268 | return; | |
269 | ||
270 | error: | |
271 | s->irq_status |= SD_RISR_NO_RESPONSE; | |
272 | } | |
273 | ||
274 | static void allwinner_sdhost_auto_stop(AwSdHostState *s) | |
275 | { | |
276 | /* | |
277 | * The stop command (CMD12) ensures the SD bus | |
278 | * returns to the transfer state. | |
279 | */ | |
280 | if ((s->command & SD_CMDR_AUTOSTOP) && (s->transfer_cnt == 0)) { | |
281 | /* First save current command registers */ | |
282 | uint32_t saved_cmd = s->command; | |
283 | uint32_t saved_arg = s->command_arg; | |
284 | ||
285 | /* Prepare stop command (CMD12) */ | |
286 | s->command &= ~SD_CMDR_CMDID_MASK; | |
287 | s->command |= 12; /* CMD12 */ | |
288 | s->command_arg = 0; | |
289 | ||
290 | /* Put the command on SD bus */ | |
291 | allwinner_sdhost_send_command(s); | |
292 | ||
293 | /* Restore command values */ | |
294 | s->command = saved_cmd; | |
295 | s->command_arg = saved_arg; | |
296 | ||
297 | /* Set IRQ status bit for automatic stop done */ | |
298 | s->irq_status |= SD_RISR_AUTOCMD_DONE; | |
299 | } | |
300 | } | |
301 | ||
302 | static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s, | |
303 | hwaddr desc_addr, | |
304 | TransferDescriptor *desc, | |
305 | bool is_write, uint32_t max_bytes) | |
306 | { | |
307 | AwSdHostClass *klass = AW_SDHOST_GET_CLASS(s); | |
308 | uint32_t num_done = 0; | |
309 | uint32_t num_bytes = max_bytes; | |
310 | uint8_t buf[1024]; | |
311 | ||
312 | /* Read descriptor */ | |
b3aec952 | 313 | dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc)); |
82e48382 NL |
314 | if (desc->size == 0) { |
315 | desc->size = klass->max_desc_size; | |
316 | } else if (desc->size > klass->max_desc_size) { | |
317 | qemu_log_mask(LOG_GUEST_ERROR, "%s: DMA descriptor buffer size " | |
318 | " is out-of-bounds: %" PRIu32 " > %zu", | |
319 | __func__, desc->size, klass->max_desc_size); | |
320 | desc->size = klass->max_desc_size; | |
321 | } | |
322 | if (desc->size < num_bytes) { | |
323 | num_bytes = desc->size; | |
324 | } | |
325 | ||
326 | trace_allwinner_sdhost_process_desc(desc_addr, desc->size, | |
327 | is_write, max_bytes); | |
328 | ||
329 | while (num_done < num_bytes) { | |
330 | /* Try to completely fill the local buffer */ | |
331 | uint32_t buf_bytes = num_bytes - num_done; | |
332 | if (buf_bytes > sizeof(buf)) { | |
333 | buf_bytes = sizeof(buf); | |
334 | } | |
335 | ||
336 | /* Write to SD bus */ | |
337 | if (is_write) { | |
b3aec952 PMD |
338 | dma_memory_read(&s->dma_as, |
339 | (desc->addr & DESC_SIZE_MASK) + num_done, | |
340 | buf, buf_bytes); | |
62a21be6 | 341 | sdbus_write_data(&s->sdbus, buf, buf_bytes); |
82e48382 NL |
342 | |
343 | /* Read from SD bus */ | |
344 | } else { | |
618e0be1 | 345 | sdbus_read_data(&s->sdbus, buf, buf_bytes); |
b3aec952 PMD |
346 | dma_memory_write(&s->dma_as, |
347 | (desc->addr & DESC_SIZE_MASK) + num_done, | |
348 | buf, buf_bytes); | |
82e48382 NL |
349 | } |
350 | num_done += buf_bytes; | |
351 | } | |
352 | ||
353 | /* Clear hold flag and flush descriptor */ | |
354 | desc->status &= ~DESC_STATUS_HOLD; | |
b3aec952 | 355 | dma_memory_write(&s->dma_as, desc_addr, desc, sizeof(*desc)); |
82e48382 NL |
356 | |
357 | return num_done; | |
358 | } | |
359 | ||
360 | static void allwinner_sdhost_dma(AwSdHostState *s) | |
361 | { | |
362 | TransferDescriptor desc; | |
363 | hwaddr desc_addr = s->desc_base; | |
364 | bool is_write = (s->command & SD_CMDR_WRITE); | |
365 | uint32_t bytes_done = 0; | |
366 | ||
367 | /* Check if DMA can be performed */ | |
368 | if (s->byte_count == 0 || s->block_size == 0 || | |
369 | !(s->global_ctl & SD_GCTL_DMA_ENB)) { | |
370 | return; | |
371 | } | |
372 | ||
373 | /* | |
374 | * For read operations, data must be available on the SD bus | |
375 | * If not, it is an error and we should not act at all | |
376 | */ | |
377 | if (!is_write && !sdbus_data_ready(&s->sdbus)) { | |
378 | return; | |
379 | } | |
380 | ||
381 | /* Process the DMA descriptors until all data is copied */ | |
382 | while (s->byte_count > 0) { | |
383 | bytes_done = allwinner_sdhost_process_desc(s, desc_addr, &desc, | |
384 | is_write, s->byte_count); | |
385 | allwinner_sdhost_update_transfer_cnt(s, bytes_done); | |
386 | ||
387 | if (bytes_done <= s->byte_count) { | |
388 | s->byte_count -= bytes_done; | |
389 | } else { | |
390 | s->byte_count = 0; | |
391 | } | |
392 | ||
393 | if (desc.status & DESC_STATUS_LAST) { | |
394 | break; | |
395 | } else { | |
396 | desc_addr = desc.next; | |
397 | } | |
398 | } | |
399 | ||
400 | /* Raise IRQ to signal DMA is completed */ | |
401 | s->irq_status |= SD_RISR_DATA_COMPLETE | SD_RISR_SDIO_INTR; | |
402 | ||
403 | /* Update DMAC bits */ | |
404 | s->dmac_status |= SD_IDST_INT_SUMMARY; | |
405 | ||
406 | if (is_write) { | |
407 | s->dmac_status |= SD_IDST_TRANSMIT_IRQ; | |
408 | } else { | |
409 | s->dmac_status |= SD_IDST_RECEIVE_IRQ; | |
410 | } | |
411 | } | |
412 | ||
413 | static uint64_t allwinner_sdhost_read(void *opaque, hwaddr offset, | |
414 | unsigned size) | |
415 | { | |
416 | AwSdHostState *s = AW_SDHOST(opaque); | |
417 | uint32_t res = 0; | |
418 | ||
419 | switch (offset) { | |
420 | case REG_SD_GCTL: /* Global Control */ | |
421 | res = s->global_ctl; | |
422 | break; | |
423 | case REG_SD_CKCR: /* Clock Control */ | |
424 | res = s->clock_ctl; | |
425 | break; | |
426 | case REG_SD_TMOR: /* Timeout */ | |
427 | res = s->timeout; | |
428 | break; | |
429 | case REG_SD_BWDR: /* Bus Width */ | |
430 | res = s->bus_width; | |
431 | break; | |
432 | case REG_SD_BKSR: /* Block Size */ | |
433 | res = s->block_size; | |
434 | break; | |
435 | case REG_SD_BYCR: /* Byte Count */ | |
436 | res = s->byte_count; | |
437 | break; | |
438 | case REG_SD_CMDR: /* Command */ | |
439 | res = s->command; | |
440 | break; | |
441 | case REG_SD_CAGR: /* Command Argument */ | |
442 | res = s->command_arg; | |
443 | break; | |
444 | case REG_SD_RESP0: /* Response Zero */ | |
445 | res = s->response[0]; | |
446 | break; | |
447 | case REG_SD_RESP1: /* Response One */ | |
448 | res = s->response[1]; | |
449 | break; | |
450 | case REG_SD_RESP2: /* Response Two */ | |
451 | res = s->response[2]; | |
452 | break; | |
453 | case REG_SD_RESP3: /* Response Three */ | |
454 | res = s->response[3]; | |
455 | break; | |
456 | case REG_SD_IMKR: /* Interrupt Mask */ | |
457 | res = s->irq_mask; | |
458 | break; | |
459 | case REG_SD_MISR: /* Masked Interrupt Status */ | |
460 | res = s->irq_status & s->irq_mask; | |
461 | break; | |
462 | case REG_SD_RISR: /* Raw Interrupt Status */ | |
463 | res = s->irq_status; | |
464 | break; | |
465 | case REG_SD_STAR: /* Status */ | |
466 | res = s->status; | |
467 | break; | |
468 | case REG_SD_FWLR: /* FIFO Water Level */ | |
469 | res = s->fifo_wlevel; | |
470 | break; | |
471 | case REG_SD_FUNS: /* FIFO Function Select */ | |
472 | res = s->fifo_func_sel; | |
473 | break; | |
474 | case REG_SD_DBGC: /* Debug Enable */ | |
475 | res = s->debug_enable; | |
476 | break; | |
477 | case REG_SD_A12A: /* Auto command 12 argument */ | |
478 | res = s->auto12_arg; | |
479 | break; | |
480 | case REG_SD_NTSR: /* SD NewTiming Set */ | |
481 | res = s->newtiming_set; | |
482 | break; | |
483 | case REG_SD_SDBG: /* SD newTiming Set Debug */ | |
484 | res = s->newtiming_debug; | |
485 | break; | |
486 | case REG_SD_HWRST: /* Hardware Reset Register */ | |
487 | res = s->hardware_rst; | |
488 | break; | |
489 | case REG_SD_DMAC: /* Internal DMA Controller Control */ | |
490 | res = s->dmac; | |
491 | break; | |
492 | case REG_SD_DLBA: /* Descriptor List Base Address */ | |
493 | res = s->desc_base; | |
494 | break; | |
495 | case REG_SD_IDST: /* Internal DMA Controller Status */ | |
496 | res = s->dmac_status; | |
497 | break; | |
498 | case REG_SD_IDIE: /* Internal DMA Controller Interrupt Enable */ | |
499 | res = s->dmac_irq; | |
500 | break; | |
501 | case REG_SD_THLDC: /* Card Threshold Control */ | |
502 | res = s->card_threshold; | |
503 | break; | |
504 | case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ | |
505 | res = s->startbit_detect; | |
506 | break; | |
507 | case REG_SD_RES_CRC: /* Response CRC from card/eMMC */ | |
508 | res = s->response_crc; | |
509 | break; | |
510 | case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */ | |
511 | case REG_SD_DATA6_CRC: /* CRC Data 6 from card/eMMC */ | |
512 | case REG_SD_DATA5_CRC: /* CRC Data 5 from card/eMMC */ | |
513 | case REG_SD_DATA4_CRC: /* CRC Data 4 from card/eMMC */ | |
514 | case REG_SD_DATA3_CRC: /* CRC Data 3 from card/eMMC */ | |
515 | case REG_SD_DATA2_CRC: /* CRC Data 2 from card/eMMC */ | |
516 | case REG_SD_DATA1_CRC: /* CRC Data 1 from card/eMMC */ | |
517 | case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */ | |
518 | res = s->data_crc[((offset - REG_SD_DATA7_CRC) / sizeof(uint32_t))]; | |
519 | break; | |
520 | case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */ | |
521 | res = s->status_crc; | |
522 | break; | |
523 | case REG_SD_FIFO: /* Read/Write FIFO */ | |
524 | if (sdbus_data_ready(&s->sdbus)) { | |
618e0be1 PMD |
525 | sdbus_read_data(&s->sdbus, &res, sizeof(uint32_t)); |
526 | le32_to_cpus(&res); | |
82e48382 NL |
527 | allwinner_sdhost_update_transfer_cnt(s, sizeof(uint32_t)); |
528 | allwinner_sdhost_auto_stop(s); | |
529 | allwinner_sdhost_update_irq(s); | |
530 | } else { | |
531 | qemu_log_mask(LOG_GUEST_ERROR, "%s: no data ready on SD bus\n", | |
532 | __func__); | |
533 | } | |
534 | break; | |
535 | default: | |
536 | qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %" | |
537 | HWADDR_PRIx"\n", __func__, offset); | |
538 | res = 0; | |
539 | break; | |
540 | } | |
541 | ||
542 | trace_allwinner_sdhost_read(offset, res, size); | |
543 | return res; | |
544 | } | |
545 | ||
546 | static void allwinner_sdhost_write(void *opaque, hwaddr offset, | |
547 | uint64_t value, unsigned size) | |
548 | { | |
549 | AwSdHostState *s = AW_SDHOST(opaque); | |
62a21be6 | 550 | uint32_t u32; |
82e48382 NL |
551 | |
552 | trace_allwinner_sdhost_write(offset, value, size); | |
553 | ||
554 | switch (offset) { | |
555 | case REG_SD_GCTL: /* Global Control */ | |
556 | s->global_ctl = value; | |
557 | s->global_ctl &= ~(SD_GCTL_DMA_RST | SD_GCTL_FIFO_RST | | |
558 | SD_GCTL_SOFT_RST); | |
559 | allwinner_sdhost_update_irq(s); | |
560 | break; | |
561 | case REG_SD_CKCR: /* Clock Control */ | |
562 | s->clock_ctl = value; | |
563 | break; | |
564 | case REG_SD_TMOR: /* Timeout */ | |
565 | s->timeout = value; | |
566 | break; | |
567 | case REG_SD_BWDR: /* Bus Width */ | |
568 | s->bus_width = value; | |
569 | break; | |
570 | case REG_SD_BKSR: /* Block Size */ | |
571 | s->block_size = value; | |
572 | break; | |
573 | case REG_SD_BYCR: /* Byte Count */ | |
574 | s->byte_count = value; | |
575 | s->transfer_cnt = value; | |
576 | break; | |
577 | case REG_SD_CMDR: /* Command */ | |
578 | s->command = value; | |
579 | if (value & SD_CMDR_LOAD) { | |
580 | allwinner_sdhost_send_command(s); | |
581 | allwinner_sdhost_dma(s); | |
582 | allwinner_sdhost_auto_stop(s); | |
583 | } | |
584 | allwinner_sdhost_update_irq(s); | |
585 | break; | |
586 | case REG_SD_CAGR: /* Command Argument */ | |
587 | s->command_arg = value; | |
588 | break; | |
589 | case REG_SD_RESP0: /* Response Zero */ | |
590 | s->response[0] = value; | |
591 | break; | |
592 | case REG_SD_RESP1: /* Response One */ | |
593 | s->response[1] = value; | |
594 | break; | |
595 | case REG_SD_RESP2: /* Response Two */ | |
596 | s->response[2] = value; | |
597 | break; | |
598 | case REG_SD_RESP3: /* Response Three */ | |
599 | s->response[3] = value; | |
600 | break; | |
601 | case REG_SD_IMKR: /* Interrupt Mask */ | |
602 | s->irq_mask = value; | |
603 | allwinner_sdhost_update_irq(s); | |
604 | break; | |
605 | case REG_SD_MISR: /* Masked Interrupt Status */ | |
606 | case REG_SD_RISR: /* Raw Interrupt Status */ | |
607 | s->irq_status &= ~value; | |
608 | allwinner_sdhost_update_irq(s); | |
609 | break; | |
610 | case REG_SD_STAR: /* Status */ | |
611 | s->status &= ~value; | |
612 | allwinner_sdhost_update_irq(s); | |
613 | break; | |
614 | case REG_SD_FWLR: /* FIFO Water Level */ | |
615 | s->fifo_wlevel = value; | |
616 | break; | |
617 | case REG_SD_FUNS: /* FIFO Function Select */ | |
618 | s->fifo_func_sel = value; | |
619 | break; | |
620 | case REG_SD_DBGC: /* Debug Enable */ | |
621 | s->debug_enable = value; | |
622 | break; | |
623 | case REG_SD_A12A: /* Auto command 12 argument */ | |
624 | s->auto12_arg = value; | |
625 | break; | |
626 | case REG_SD_NTSR: /* SD NewTiming Set */ | |
627 | s->newtiming_set = value; | |
628 | break; | |
629 | case REG_SD_SDBG: /* SD newTiming Set Debug */ | |
630 | s->newtiming_debug = value; | |
631 | break; | |
632 | case REG_SD_HWRST: /* Hardware Reset Register */ | |
633 | s->hardware_rst = value; | |
634 | break; | |
635 | case REG_SD_DMAC: /* Internal DMA Controller Control */ | |
636 | s->dmac = value; | |
637 | allwinner_sdhost_update_irq(s); | |
638 | break; | |
639 | case REG_SD_DLBA: /* Descriptor List Base Address */ | |
640 | s->desc_base = value; | |
641 | break; | |
642 | case REG_SD_IDST: /* Internal DMA Controller Status */ | |
643 | s->dmac_status &= (~SD_IDST_WR_MASK) | (~value & SD_IDST_WR_MASK); | |
644 | allwinner_sdhost_update_irq(s); | |
645 | break; | |
646 | case REG_SD_IDIE: /* Internal DMA Controller Interrupt Enable */ | |
647 | s->dmac_irq = value; | |
648 | allwinner_sdhost_update_irq(s); | |
649 | break; | |
650 | case REG_SD_THLDC: /* Card Threshold Control */ | |
651 | s->card_threshold = value; | |
652 | break; | |
653 | case REG_SD_DSBD: /* eMMC DDR Start Bit Detection Control */ | |
654 | s->startbit_detect = value; | |
655 | break; | |
656 | case REG_SD_FIFO: /* Read/Write FIFO */ | |
62a21be6 PMD |
657 | u32 = cpu_to_le32(value); |
658 | sdbus_write_data(&s->sdbus, &u32, sizeof(u32)); | |
659 | allwinner_sdhost_update_transfer_cnt(s, sizeof(u32)); | |
82e48382 NL |
660 | allwinner_sdhost_auto_stop(s); |
661 | allwinner_sdhost_update_irq(s); | |
662 | break; | |
663 | case REG_SD_RES_CRC: /* Response CRC from card/eMMC */ | |
664 | case REG_SD_DATA7_CRC: /* CRC Data 7 from card/eMMC */ | |
665 | case REG_SD_DATA6_CRC: /* CRC Data 6 from card/eMMC */ | |
666 | case REG_SD_DATA5_CRC: /* CRC Data 5 from card/eMMC */ | |
667 | case REG_SD_DATA4_CRC: /* CRC Data 4 from card/eMMC */ | |
668 | case REG_SD_DATA3_CRC: /* CRC Data 3 from card/eMMC */ | |
669 | case REG_SD_DATA2_CRC: /* CRC Data 2 from card/eMMC */ | |
670 | case REG_SD_DATA1_CRC: /* CRC Data 1 from card/eMMC */ | |
671 | case REG_SD_DATA0_CRC: /* CRC Data 0 from card/eMMC */ | |
672 | case REG_SD_CRC_STA: /* CRC status from card/eMMC in write operation */ | |
673 | break; | |
674 | default: | |
675 | qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset %" | |
676 | HWADDR_PRIx"\n", __func__, offset); | |
677 | break; | |
678 | } | |
679 | } | |
680 | ||
681 | static const MemoryRegionOps allwinner_sdhost_ops = { | |
682 | .read = allwinner_sdhost_read, | |
683 | .write = allwinner_sdhost_write, | |
684 | .endianness = DEVICE_NATIVE_ENDIAN, | |
685 | .valid = { | |
686 | .min_access_size = 4, | |
687 | .max_access_size = 4, | |
688 | }, | |
689 | .impl.min_access_size = 4, | |
690 | }; | |
691 | ||
692 | static const VMStateDescription vmstate_allwinner_sdhost = { | |
693 | .name = "allwinner-sdhost", | |
694 | .version_id = 1, | |
695 | .minimum_version_id = 1, | |
696 | .fields = (VMStateField[]) { | |
697 | VMSTATE_UINT32(global_ctl, AwSdHostState), | |
698 | VMSTATE_UINT32(clock_ctl, AwSdHostState), | |
699 | VMSTATE_UINT32(timeout, AwSdHostState), | |
700 | VMSTATE_UINT32(bus_width, AwSdHostState), | |
701 | VMSTATE_UINT32(block_size, AwSdHostState), | |
702 | VMSTATE_UINT32(byte_count, AwSdHostState), | |
703 | VMSTATE_UINT32(transfer_cnt, AwSdHostState), | |
704 | VMSTATE_UINT32(command, AwSdHostState), | |
705 | VMSTATE_UINT32(command_arg, AwSdHostState), | |
706 | VMSTATE_UINT32_ARRAY(response, AwSdHostState, 4), | |
707 | VMSTATE_UINT32(irq_mask, AwSdHostState), | |
708 | VMSTATE_UINT32(irq_status, AwSdHostState), | |
709 | VMSTATE_UINT32(status, AwSdHostState), | |
710 | VMSTATE_UINT32(fifo_wlevel, AwSdHostState), | |
711 | VMSTATE_UINT32(fifo_func_sel, AwSdHostState), | |
712 | VMSTATE_UINT32(debug_enable, AwSdHostState), | |
713 | VMSTATE_UINT32(auto12_arg, AwSdHostState), | |
714 | VMSTATE_UINT32(newtiming_set, AwSdHostState), | |
715 | VMSTATE_UINT32(newtiming_debug, AwSdHostState), | |
716 | VMSTATE_UINT32(hardware_rst, AwSdHostState), | |
717 | VMSTATE_UINT32(dmac, AwSdHostState), | |
718 | VMSTATE_UINT32(desc_base, AwSdHostState), | |
719 | VMSTATE_UINT32(dmac_status, AwSdHostState), | |
720 | VMSTATE_UINT32(dmac_irq, AwSdHostState), | |
721 | VMSTATE_UINT32(card_threshold, AwSdHostState), | |
722 | VMSTATE_UINT32(startbit_detect, AwSdHostState), | |
723 | VMSTATE_UINT32(response_crc, AwSdHostState), | |
724 | VMSTATE_UINT32_ARRAY(data_crc, AwSdHostState, 8), | |
725 | VMSTATE_UINT32(status_crc, AwSdHostState), | |
726 | VMSTATE_END_OF_LIST() | |
727 | } | |
728 | }; | |
729 | ||
b3aec952 PMD |
730 | static Property allwinner_sdhost_properties[] = { |
731 | DEFINE_PROP_LINK("dma-memory", AwSdHostState, dma_mr, | |
732 | TYPE_MEMORY_REGION, MemoryRegion *), | |
733 | DEFINE_PROP_END_OF_LIST(), | |
734 | }; | |
735 | ||
82e48382 NL |
736 | static void allwinner_sdhost_init(Object *obj) |
737 | { | |
738 | AwSdHostState *s = AW_SDHOST(obj); | |
739 | ||
740 | qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), | |
741 | TYPE_AW_SDHOST_BUS, DEVICE(s), "sd-bus"); | |
742 | ||
743 | memory_region_init_io(&s->iomem, obj, &allwinner_sdhost_ops, s, | |
744 | TYPE_AW_SDHOST, 4 * KiB); | |
745 | sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); | |
746 | sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); | |
747 | } | |
748 | ||
b3aec952 PMD |
749 | static void allwinner_sdhost_realize(DeviceState *dev, Error **errp) |
750 | { | |
751 | AwSdHostState *s = AW_SDHOST(dev); | |
752 | ||
753 | if (!s->dma_mr) { | |
754 | error_setg(errp, TYPE_AW_SDHOST " 'dma-memory' link not set"); | |
755 | return; | |
756 | } | |
757 | ||
758 | address_space_init(&s->dma_as, s->dma_mr, "sdhost-dma"); | |
759 | } | |
760 | ||
82e48382 NL |
761 | static void allwinner_sdhost_reset(DeviceState *dev) |
762 | { | |
763 | AwSdHostState *s = AW_SDHOST(dev); | |
764 | ||
765 | s->global_ctl = REG_SD_GCTL_RST; | |
766 | s->clock_ctl = REG_SD_CKCR_RST; | |
767 | s->timeout = REG_SD_TMOR_RST; | |
768 | s->bus_width = REG_SD_BWDR_RST; | |
769 | s->block_size = REG_SD_BKSR_RST; | |
770 | s->byte_count = REG_SD_BYCR_RST; | |
771 | s->transfer_cnt = 0; | |
772 | ||
773 | s->command = REG_SD_CMDR_RST; | |
774 | s->command_arg = REG_SD_CAGR_RST; | |
775 | ||
776 | for (int i = 0; i < ARRAY_SIZE(s->response); i++) { | |
777 | s->response[i] = REG_SD_RESP_RST; | |
778 | } | |
779 | ||
780 | s->irq_mask = REG_SD_IMKR_RST; | |
781 | s->irq_status = REG_SD_RISR_RST; | |
782 | s->status = REG_SD_STAR_RST; | |
783 | ||
784 | s->fifo_wlevel = REG_SD_FWLR_RST; | |
785 | s->fifo_func_sel = REG_SD_FUNS_RST; | |
786 | s->debug_enable = REG_SD_DBGC_RST; | |
787 | s->auto12_arg = REG_SD_A12A_RST; | |
788 | s->newtiming_set = REG_SD_NTSR_RST; | |
789 | s->newtiming_debug = REG_SD_SDBG_RST; | |
790 | s->hardware_rst = REG_SD_HWRST_RST; | |
791 | s->dmac = REG_SD_DMAC_RST; | |
792 | s->desc_base = REG_SD_DLBA_RST; | |
793 | s->dmac_status = REG_SD_IDST_RST; | |
794 | s->dmac_irq = REG_SD_IDIE_RST; | |
795 | s->card_threshold = REG_SD_THLDC_RST; | |
796 | s->startbit_detect = REG_SD_DSBD_RST; | |
797 | s->response_crc = REG_SD_RES_CRC_RST; | |
798 | ||
799 | for (int i = 0; i < ARRAY_SIZE(s->data_crc); i++) { | |
800 | s->data_crc[i] = REG_SD_DATA_CRC_RST; | |
801 | } | |
802 | ||
803 | s->status_crc = REG_SD_CRC_STA_RST; | |
804 | } | |
805 | ||
806 | static void allwinner_sdhost_bus_class_init(ObjectClass *klass, void *data) | |
807 | { | |
808 | SDBusClass *sbc = SD_BUS_CLASS(klass); | |
809 | ||
810 | sbc->set_inserted = allwinner_sdhost_set_inserted; | |
811 | } | |
812 | ||
813 | static void allwinner_sdhost_class_init(ObjectClass *klass, void *data) | |
814 | { | |
815 | DeviceClass *dc = DEVICE_CLASS(klass); | |
816 | ||
817 | dc->reset = allwinner_sdhost_reset; | |
818 | dc->vmsd = &vmstate_allwinner_sdhost; | |
b3aec952 PMD |
819 | dc->realize = allwinner_sdhost_realize; |
820 | device_class_set_props(dc, allwinner_sdhost_properties); | |
82e48382 NL |
821 | } |
822 | ||
823 | static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data) | |
824 | { | |
825 | AwSdHostClass *sc = AW_SDHOST_CLASS(klass); | |
826 | sc->max_desc_size = 8 * KiB; | |
827 | } | |
828 | ||
829 | static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data) | |
830 | { | |
831 | AwSdHostClass *sc = AW_SDHOST_CLASS(klass); | |
832 | sc->max_desc_size = 64 * KiB; | |
833 | } | |
834 | ||
835 | static TypeInfo allwinner_sdhost_info = { | |
836 | .name = TYPE_AW_SDHOST, | |
837 | .parent = TYPE_SYS_BUS_DEVICE, | |
838 | .instance_init = allwinner_sdhost_init, | |
839 | .instance_size = sizeof(AwSdHostState), | |
840 | .class_init = allwinner_sdhost_class_init, | |
841 | .class_size = sizeof(AwSdHostClass), | |
842 | .abstract = true, | |
843 | }; | |
844 | ||
845 | static const TypeInfo allwinner_sdhost_sun4i_info = { | |
846 | .name = TYPE_AW_SDHOST_SUN4I, | |
847 | .parent = TYPE_AW_SDHOST, | |
848 | .class_init = allwinner_sdhost_sun4i_class_init, | |
849 | }; | |
850 | ||
851 | static const TypeInfo allwinner_sdhost_sun5i_info = { | |
852 | .name = TYPE_AW_SDHOST_SUN5I, | |
853 | .parent = TYPE_AW_SDHOST, | |
854 | .class_init = allwinner_sdhost_sun5i_class_init, | |
855 | }; | |
856 | ||
857 | static const TypeInfo allwinner_sdhost_bus_info = { | |
858 | .name = TYPE_AW_SDHOST_BUS, | |
859 | .parent = TYPE_SD_BUS, | |
860 | .instance_size = sizeof(SDBus), | |
861 | .class_init = allwinner_sdhost_bus_class_init, | |
862 | }; | |
863 | ||
864 | static void allwinner_sdhost_register_types(void) | |
865 | { | |
866 | type_register_static(&allwinner_sdhost_info); | |
867 | type_register_static(&allwinner_sdhost_sun4i_info); | |
868 | type_register_static(&allwinner_sdhost_sun5i_info); | |
869 | type_register_static(&allwinner_sdhost_bus_info); | |
870 | } | |
871 | ||
872 | type_init(allwinner_sdhost_register_types) |