2 * Samsung Exynos4210 SD/MMC host controller model
4 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * Mitsyanko Igor <i.mitsyanko@samsung.com>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
24 #define EXYNOS4_SDHC_CAPABILITIES 0x05E80080
25 #define EXYNOS4_SDHC_MAX_BUFSZ 512
27 #define EXYNOS4_SDHC_DEBUG 0
29 #if EXYNOS4_SDHC_DEBUG == 0
30 #define DPRINT_L1(fmt, args...) do { } while (0)
31 #define DPRINT_L2(fmt, args...) do { } while (0)
32 #define ERRPRINT(fmt, args...) do { } while (0)
33 #elif EXYNOS4_SDHC_DEBUG == 1
34 #define DPRINT_L1(fmt, args...) \
35 do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
36 #define DPRINT_L2(fmt, args...) do { } while (0)
37 #define ERRPRINT(fmt, args...) \
38 do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0)
40 #define DPRINT_L1(fmt, args...) \
41 do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
42 #define DPRINT_L2(fmt, args...) \
43 do {fprintf(stderr, "QEMU SDHC: "fmt, ## args); } while (0)
44 #define ERRPRINT(fmt, args...) \
45 do {fprintf(stderr, "QEMU SDHC ERROR: "fmt, ## args); } while (0)
49 #define TYPE_EXYNOS4_SDHC "exynos4210.sdhci"
50 #define EXYNOS4_SDHCI(obj) \
51 OBJECT_CHECK(Exynos4SDHCIState, (obj), TYPE_EXYNOS4_SDHC)
53 /* ADMA Error Status Register */
54 #define EXYNOS4_SDHC_FINAL_BLOCK (1 << 10)
55 #define EXYNOS4_SDHC_CONTINUE_REQ (1 << 9)
56 #define EXYNOS4_SDHC_IRQ_STAT (1 << 8)
57 /* Control register 2 */
58 #define EXYNOS4_SDHC_CONTROL2 0x80
59 #define EXYNOS4_SDHC_HWINITFIN (1 << 0)
60 #define EXYNOS4_SDHC_DISBUFRD (1 << 6)
61 #define EXYNOS4_SDHC_SDOPSIGPC (1 << 12)
62 #define EXYNOS4_SDHC_SDINPSIGPC (1 << 3)
63 /* Control register 3 */
64 #define EXYNOS4_SDHC_CONTROL3 0x84
65 /* Control register 4 */
66 #define EXYNOS4_SDHC_CONTROL4 0x8C
67 /* Clock control register */
68 #define EXYNOS4_SDHC_SDCLK_STBL (1 << 3)
70 #define EXYNOS4_SDHC_CMD_USES_DAT(cmd) \
71 (((cmd) & SDHC_CMD_DATA_PRESENT) || \
72 ((cmd) & SDHC_CMD_RESPONSE) == SDHC_CMD_RSP_WITH_BUSY)
74 typedef struct Exynos4SDHCIState
{
83 static uint8_t sdhci_slotint(SDHCIState
*s
)
85 return (s
->norintsts
& s
->norintsigen
) || (s
->errintsts
& s
->errintsigen
) ||
86 ((s
->norintsts
& SDHC_NIS_INSERT
) && (s
->wakcon
& SDHC_WKUP_ON_INS
)) ||
87 ((s
->norintsts
& SDHC_NIS_REMOVE
) && (s
->wakcon
& SDHC_WKUP_ON_RMV
));
90 static inline void exynos4210_sdhci_update_irq(SDHCIState
*s
)
92 qemu_set_irq(s
->irq
, sdhci_slotint(s
));
95 static void exynos4210_sdhci_reset(DeviceState
*d
)
97 Exynos4SDHCIState
*s
= EXYNOS4_SDHCI(d
);
99 SDHCI_GET_CLASS(d
)->reset(SDHCI(d
));
100 s
->stopped_adma
= false;
103 s
->control3
= 0x7F5F3F1F;
106 static void exynos4210_sdhci_start_adma(SDHCIState
*sdhci
)
108 Exynos4SDHCIState
*s
= EXYNOS4_SDHCI(sdhci
);
109 unsigned int length
, n
, begin
;
113 const uint16_t block_size
= sdhci
->blksize
& 0x0fff;
115 ~(EXYNOS4_SDHC_FINAL_BLOCK
| SDHC_ADMAERR_LENGTH_MISMATCH
);
118 addr
= length
= attributes
= 0;
119 entry_addr
= (hwaddr
)(sdhci
->admasysaddr
& 0xFFFFFFFFull
);
121 /* fetch next entry from descriptor table */
122 cpu_physical_memory_read(entry_addr
+ 4, (uint8_t *)(&addr
), 4);
123 cpu_physical_memory_read(entry_addr
+ 2, (uint8_t *)(&length
), 2);
124 cpu_physical_memory_read(entry_addr
, (uint8_t *)(&attributes
), 1);
125 DPRINT_L1("ADMA loop: addr=0x%08x, len=%d, attr=%x\n",
126 addr
, length
, attributes
);
128 if ((attributes
& SDHC_ADMA_ATTR_VALID
) == 0) {
129 /* Indicate that error occurred in ST_FDS state */
130 s
->admaerr
&= ~SDHC_ADMAERR_STATE_MASK
;
131 s
->admaerr
|= SDHC_ADMAERR_STATE_ST_FDS
;
132 DPRINT_L1("ADMA not valid at addr=0x%lx\n", sdhci
->admasysaddr
);
134 if (sdhci
->errintstsen
& SDHC_EISEN_ADMAERR
) {
135 sdhci
->errintsts
|= SDHC_EIS_ADMAERR
;
136 sdhci
->norintsts
|= SDHC_NIS_ERR
;
139 exynos4210_sdhci_update_irq(sdhci
);
147 addr
&= 0xfffffffc; /* minimum unit of addr is 4 byte */
149 switch (attributes
& SDHC_ADMA_ATTR_ACT_MASK
) {
150 case SDHC_ADMA_ATTR_ACT_TRAN
: /* data transfer */
151 if (sdhci
->trnmod
& SDHC_TRNS_READ
) {
153 if (sdhci
->data_count
== 0) {
154 for (n
= 0; n
< block_size
; n
++) {
155 sdhci
->fifo_buffer
[n
] = sd_read_data(sdhci
->card
);
158 begin
= sdhci
->data_count
;
159 if ((length
+ begin
) < block_size
) {
160 sdhci
->data_count
= length
+ begin
;
163 sdhci
->data_count
= block_size
;
164 length
-= block_size
- begin
;
166 cpu_physical_memory_write(addr
, &sdhci
->fifo_buffer
[begin
],
167 sdhci
->data_count
- begin
);
168 addr
+= sdhci
->data_count
- begin
;
169 if (sdhci
->data_count
== block_size
) {
170 sdhci
->data_count
= 0;
171 if (sdhci
->trnmod
& SDHC_TRNS_BLK_CNT_EN
) {
173 if (sdhci
->blkcnt
== 0) {
181 begin
= sdhci
->data_count
;
182 if ((length
+ begin
) < block_size
) {
183 sdhci
->data_count
= length
+ begin
;
186 sdhci
->data_count
= block_size
;
187 length
-= block_size
- begin
;
189 cpu_physical_memory_read(addr
,
190 &sdhci
->fifo_buffer
[begin
], sdhci
->data_count
);
191 addr
+= sdhci
->data_count
- begin
;
192 if (sdhci
->data_count
== block_size
) {
193 for (n
= 0; n
< block_size
; n
++) {
194 sd_write_data(sdhci
->card
, sdhci
->fifo_buffer
[n
]);
196 sdhci
->data_count
= 0;
197 if (sdhci
->trnmod
& SDHC_TRNS_BLK_CNT_EN
) {
199 if (sdhci
->blkcnt
== 0) {
206 sdhci
->admasysaddr
+= 8;
208 case SDHC_ADMA_ATTR_ACT_LINK
: /* link to next descriptor table */
209 sdhci
->admasysaddr
= addr
;
210 DPRINT_L1("ADMA link: admasysaddr=0x%lx\n", sdhci
->admasysaddr
);
213 sdhci
->admasysaddr
+= 8;
217 /* ADMA transfer terminates if blkcnt == 0 or by END attribute */
218 if (((sdhci
->trnmod
& SDHC_TRNS_BLK_CNT_EN
) && (sdhci
->blkcnt
== 0)) ||
219 (attributes
& SDHC_ADMA_ATTR_END
)) {
220 DPRINT_L2("ADMA transfer completed\n");
221 if (length
|| ((attributes
& SDHC_ADMA_ATTR_END
) &&
222 (sdhci
->trnmod
& SDHC_TRNS_BLK_CNT_EN
) && sdhci
->blkcnt
!= 0) ||
223 ((sdhci
->trnmod
& SDHC_TRNS_BLK_CNT_EN
) && sdhci
->blkcnt
== 0 &&
224 (attributes
& SDHC_ADMA_ATTR_END
) == 0)) {
225 ERRPRINT("ADMA length mismatch\n");
226 s
->admaerr
|= SDHC_ADMAERR_LENGTH_MISMATCH
|
227 SDHC_ADMAERR_STATE_ST_TFR
;
228 if (sdhci
->errintstsen
& SDHC_EISEN_ADMAERR
) {
229 sdhci
->errintsts
|= SDHC_EIS_ADMAERR
;
230 sdhci
->norintsts
|= SDHC_NIS_ERR
;
233 exynos4210_sdhci_update_irq(sdhci
);
236 s
->admaerr
|= EXYNOS4_SDHC_FINAL_BLOCK
;
237 SDHCI_GET_CLASS(sdhci
)->end_data_transfer(sdhci
);
241 if (attributes
& SDHC_ADMA_ATTR_INT
) {
242 DPRINT_L1("ADMA interrupt: addr=0x%lx\n", sdhci
->admasysaddr
);
243 s
->admaerr
|= EXYNOS4_SDHC_IRQ_STAT
;
244 s
->stopped_adma
= true;
245 if (sdhci
->norintstsen
& SDHC_NISEN_DMA
) {
246 sdhci
->norintsts
|= SDHC_NIS_DMA
;
248 exynos4210_sdhci_update_irq(sdhci
);
254 static bool exynos4210_sdhci_can_issue_command(SDHCIState
*sdhci
)
256 Exynos4SDHCIState
*s
= EXYNOS4_SDHCI(sdhci
);
258 /* Check that power is supplied and clock is enabled.
259 * If SDOPSIGPC and SDINPSIGPC bits in CONTROL2 register are not set, power
260 * is supplied regardless of the PWRCON register state */
261 if (!SDHC_CLOCK_IS_ON(sdhci
->clkcon
) || (!(sdhci
->pwrcon
& SDHC_POWER_ON
) &&
262 (s
->control2
& (EXYNOS4_SDHC_SDOPSIGPC
| EXYNOS4_SDHC_SDINPSIGPC
)))) {
266 /* Controller cannot issue a command which uses data line (unless its an
267 * ABORT command) if data line is currently busy */
268 if (((sdhci
->prnsts
& SDHC_DATA_INHIBIT
) || sdhci
->stopped_state
) &&
269 (EXYNOS4_SDHC_CMD_USES_DAT(sdhci
->cmdreg
) &&
270 SDHC_COMMAND_TYPE(sdhci
->cmdreg
) != SDHC_CMD_ABORT
)) {
278 exynos4210_sdhci_readfn(void *opaque
, hwaddr offset
, unsigned size
)
280 Exynos4SDHCIState
*s
= (Exynos4SDHCIState
*)opaque
;
283 switch (offset
& ~0x3) {
285 /* Buffer data port read can be disabled by CONTROL2 register */
286 if (s
->control2
& EXYNOS4_SDHC_DISBUFRD
) {
289 ret
= SDHCI_GET_CLASS(s
)->mem_read(SDHCI(s
), offset
, size
);
293 ret
= (s
->admaerr
>> 8 * (offset
- SDHC_ADMAERR
)) &
294 ((1 << 8 * size
) - 1);
296 case EXYNOS4_SDHC_CONTROL2
:
297 ret
= (s
->control2
>> 8 * (offset
- EXYNOS4_SDHC_CONTROL2
)) &
298 ((1 << 8 * size
) - 1);
300 case EXYNOS4_SDHC_CONTROL3
:
301 ret
= (s
->control3
>> 8 * (offset
- EXYNOS4_SDHC_CONTROL3
)) &
302 ((1 << 8 * size
) - 1);
304 case EXYNOS4_SDHC_CONTROL4
:
308 ret
= SDHCI_GET_CLASS(s
)->mem_read(SDHCI(s
), offset
, size
);
312 DPRINT_L2("read %ub: addr[0x%04x] -> %u(0x%x)\n", size
, offset
, ret
, ret
);
316 static void exynos4210_sdhci_writefn(void *opaque
, hwaddr offset
,
317 uint64_t val
, unsigned size
)
319 Exynos4SDHCIState
*s
= (Exynos4SDHCIState
*)opaque
;
320 SDHCIState
*sdhci
= SDHCI(s
);
323 DPRINT_L2("write %ub: addr[0x%04x] <- %u(0x%x)\n", size
, (uint32_t)offset
,
324 (uint32_t)val
, (uint32_t)val
);
328 if ((val
& SDHC_CLOCK_SDCLK_EN
) &&
329 (sdhci
->prnsts
& SDHC_CARD_PRESENT
)) {
330 val
|= EXYNOS4_SDHC_SDCLK_STBL
;
332 val
&= ~EXYNOS4_SDHC_SDCLK_STBL
;
334 /* Break out to superclass write to handle the rest of this register */
336 case EXYNOS4_SDHC_CONTROL2
... EXYNOS4_SDHC_CONTROL2
+ 3:
337 shift
= (offset
- EXYNOS4_SDHC_CONTROL2
) * 8;
338 s
->control2
= (s
->control2
& ~(((1 << 8 * size
) - 1) << shift
)) |
341 case EXYNOS4_SDHC_CONTROL3
... EXYNOS4_SDHC_CONTROL3
+ 3:
342 shift
= (offset
- EXYNOS4_SDHC_CONTROL2
) * 8;
343 s
->control3
= (s
->control3
& ~(((1 << 8 * size
) - 1) << shift
)) |
346 case SDHC_ADMAERR
... SDHC_ADMAERR
+ 3:
347 if (size
== 4 || (size
== 2 && offset
== SDHC_ADMAERR
) ||
348 (size
== 1 && offset
== (SDHC_ADMAERR
+ 1))) {
353 } else if (size
== 1) {
358 s
->admaerr
= (s
->admaerr
& (mask
| EXYNOS4_SDHC_FINAL_BLOCK
|
359 EXYNOS4_SDHC_IRQ_STAT
)) | (val
& ~(EXYNOS4_SDHC_FINAL_BLOCK
|
360 EXYNOS4_SDHC_IRQ_STAT
| EXYNOS4_SDHC_CONTINUE_REQ
));
361 s
->admaerr
&= ~(val
& EXYNOS4_SDHC_IRQ_STAT
);
362 if ((s
->stopped_adma
) && (val
& EXYNOS4_SDHC_CONTINUE_REQ
) &&
363 (SDHC_DMA_TYPE(sdhci
->hostctl
) == SDHC_CTRL_ADMA2_32
)) {
364 s
->stopped_adma
= false;
365 SDHCI_GET_CLASS(sdhci
)->do_adma(sdhci
);
368 uint32_t mask
= (1 << (size
* 8)) - 1;
369 shift
= 8 * (offset
& 0x3);
371 mask
= ~(mask
<< shift
);
372 s
->admaerr
= (s
->admaerr
& mask
) | val
;
377 SDHCI_GET_CLASS(s
)->mem_write(sdhci
, offset
, val
, size
);
380 static const MemoryRegionOps exynos4210_sdhci_mmio_ops
= {
381 .read
= exynos4210_sdhci_readfn
,
382 .write
= exynos4210_sdhci_writefn
,
384 .min_access_size
= 1,
385 .max_access_size
= 4,
388 .endianness
= DEVICE_LITTLE_ENDIAN
,
391 static const VMStateDescription exynos4210_sdhci_vmstate
= {
392 .name
= "exynos4210.sdhci",
394 .minimum_version_id
= 1,
395 .fields
= (VMStateField
[]) {
396 VMSTATE_STRUCT(sdhci
, Exynos4SDHCIState
, 1, sdhci_vmstate
, SDHCIState
),
397 VMSTATE_UINT32(admaerr
, Exynos4SDHCIState
),
398 VMSTATE_UINT32(control2
, Exynos4SDHCIState
),
399 VMSTATE_UINT32(control3
, Exynos4SDHCIState
),
400 VMSTATE_BOOL(stopped_adma
, Exynos4SDHCIState
),
401 VMSTATE_END_OF_LIST()
405 static int exynos4210_sdhci_realize(SysBusDevice
*busdev
)
407 SDHCIState
*sdhci
= SDHCI(busdev
);
409 qdev_prop_set_uint32(DEVICE(busdev
), "capareg", EXYNOS4_SDHC_CAPABILITIES
);
410 sdhci
->buf_maxsz
= EXYNOS4_SDHC_MAX_BUFSZ
;
411 sdhci
->fifo_buffer
= g_malloc0(sdhci
->buf_maxsz
);
412 sysbus_init_irq(busdev
, &sdhci
->irq
);
413 memory_region_init_io(&sdhci
->iomem
, &exynos4210_sdhci_mmio_ops
,
414 EXYNOS4_SDHCI(sdhci
), "exynos4210.sdhci", SDHC_REGISTERS_MAP_SIZE
);
415 sysbus_init_mmio(busdev
, &sdhci
->iomem
);
419 static void exynos4210_sdhci_class_init(ObjectClass
*klass
, void *data
)
421 DeviceClass
*dc
= DEVICE_CLASS(klass
);
422 SysBusDeviceClass
*sbdc
= SYS_BUS_DEVICE_CLASS(klass
);
423 SDHCIClass
*k
= SDHCI_CLASS(klass
);
425 dc
->vmsd
= &exynos4210_sdhci_vmstate
;
426 dc
->reset
= exynos4210_sdhci_reset
;
427 sbdc
->init
= exynos4210_sdhci_realize
;
429 k
->can_issue_command
= exynos4210_sdhci_can_issue_command
;
430 k
->do_adma
= exynos4210_sdhci_start_adma
;
433 static const TypeInfo exynos4210_sdhci_type_info
= {
434 .name
= TYPE_EXYNOS4_SDHC
,
435 .parent
= TYPE_SDHCI
,
436 .instance_size
= sizeof(Exynos4SDHCIState
),
437 .class_init
= exynos4210_sdhci_class_init
,
440 static void exynos4210_sdhci_register_types(void)
442 type_register_static(&exynos4210_sdhci_type_info
);
445 type_init(exynos4210_sdhci_register_types
)