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