2 * NPCM7xx SD-3.0 / eMMC-4.51 Host Controller
4 * Copyright (c) 2021 Google LLC
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "qemu/osdep.h"
19 #include "hw/sd/sdhci.h"
20 #include "hw/sd/npcm7xx_sdhci.h"
21 #include "migration/vmstate.h"
22 #include "sdhci-internal.h"
25 static uint64_t npcm7xx_sdhci_read(void *opaque
, hwaddr addr
, unsigned int size
)
27 NPCM7xxSDHCIState
*s
= opaque
;
31 case NPCM7XX_PRSTVALS_0
:
32 case NPCM7XX_PRSTVALS_1
:
33 case NPCM7XX_PRSTVALS_2
:
34 case NPCM7XX_PRSTVALS_3
:
35 case NPCM7XX_PRSTVALS_4
:
36 case NPCM7XX_PRSTVALS_5
:
37 val
= s
->regs
.prstvals
[(addr
- NPCM7XX_PRSTVALS_0
) / 2];
39 case NPCM7XX_BOOTTOCTRL
:
40 val
= s
->regs
.boottoctrl
;
43 qemu_log_mask(LOG_GUEST_ERROR
, "SDHCI read of nonexistent reg: 0x%02"
51 static void npcm7xx_sdhci_write(void *opaque
, hwaddr addr
, uint64_t val
,
54 NPCM7xxSDHCIState
*s
= opaque
;
57 case NPCM7XX_BOOTTOCTRL
:
58 s
->regs
.boottoctrl
= val
;
61 qemu_log_mask(LOG_GUEST_ERROR
, "SDHCI write of nonexistent reg: 0x%02"
67 static bool npcm7xx_sdhci_check_mem_op(void *opaque
, hwaddr addr
,
68 unsigned size
, bool is_write
,
72 case NPCM7XX_PRSTVALS_0
:
73 case NPCM7XX_PRSTVALS_1
:
74 case NPCM7XX_PRSTVALS_2
:
75 case NPCM7XX_PRSTVALS_3
:
76 case NPCM7XX_PRSTVALS_4
:
77 case NPCM7XX_PRSTVALS_5
:
79 return !is_write
&& size
== 2;
80 case NPCM7XX_BOOTTOCTRL
:
88 static const MemoryRegionOps npcm7xx_sdhci_ops
= {
89 .read
= npcm7xx_sdhci_read
,
90 .write
= npcm7xx_sdhci_write
,
91 .endianness
= DEVICE_NATIVE_ENDIAN
,
96 .accepts
= npcm7xx_sdhci_check_mem_op
,
100 static void npcm7xx_sdhci_realize(DeviceState
*dev
, Error
**errp
)
102 NPCM7xxSDHCIState
*s
= NPCM7XX_SDHCI(dev
);
103 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
104 SysBusDevice
*sbd_sdhci
= SYS_BUS_DEVICE(&s
->sdhci
);
106 memory_region_init(&s
->container
, OBJECT(s
),
107 "npcm7xx.sdhci-container", 0x1000);
108 sysbus_init_mmio(sbd
, &s
->container
);
110 memory_region_init_io(&s
->iomem
, OBJECT(s
), &npcm7xx_sdhci_ops
, s
,
111 TYPE_NPCM7XX_SDHCI
, NPCM7XX_SDHCI_REGSIZE
);
112 memory_region_add_subregion_overlap(&s
->container
, NPCM7XX_PRSTVALS
,
115 sysbus_realize(sbd_sdhci
, errp
);
116 memory_region_add_subregion(&s
->container
, 0,
117 sysbus_mmio_get_region(sbd_sdhci
, 0));
119 /* propagate irq and "sd-bus" from generic-sdhci */
120 sysbus_pass_irq(sbd
, sbd_sdhci
);
121 s
->bus
= qdev_get_child_bus(DEVICE(sbd_sdhci
), "sd-bus");
123 /* Set the read only preset values. */
124 memset(s
->regs
.prstvals
, 0, sizeof(s
->regs
.prstvals
));
125 s
->regs
.prstvals
[0] = NPCM7XX_PRSTVALS_0_RESET
;
126 s
->regs
.prstvals
[1] = NPCM7XX_PRSTVALS_1_RESET
;
127 s
->regs
.prstvals
[3] = NPCM7XX_PRSTVALS_3_RESET
;
130 static void npcm7xx_sdhci_reset(DeviceState
*dev
)
132 NPCM7xxSDHCIState
*s
= NPCM7XX_SDHCI(dev
);
133 device_cold_reset(DEVICE(&s
->sdhci
));
134 s
->regs
.boottoctrl
= 0;
136 s
->sdhci
.prnsts
= NPCM7XX_PRSNTS_RESET
;
137 s
->sdhci
.blkgap
= NPCM7XX_BLKGAP_RESET
;
138 s
->sdhci
.capareg
= NPCM7XX_CAPAB_RESET
;
139 s
->sdhci
.maxcurr
= NPCM7XX_MAXCURR_RESET
;
140 s
->sdhci
.version
= NPCM7XX_HCVER_RESET
;
143 static const VMStateDescription vmstate_npcm7xx_sdhci
= {
144 .name
= TYPE_NPCM7XX_SDHCI
,
146 .fields
= (const VMStateField
[]) {
147 VMSTATE_UINT32(regs
.boottoctrl
, NPCM7xxSDHCIState
),
148 VMSTATE_END_OF_LIST(),
152 static void npcm7xx_sdhci_class_init(ObjectClass
*classp
, void *data
)
154 DeviceClass
*dc
= DEVICE_CLASS(classp
);
156 dc
->desc
= "NPCM7xx SD/eMMC Host Controller";
157 dc
->realize
= npcm7xx_sdhci_realize
;
158 device_class_set_legacy_reset(dc
, npcm7xx_sdhci_reset
);
159 dc
->vmsd
= &vmstate_npcm7xx_sdhci
;
162 static void npcm7xx_sdhci_instance_init(Object
*obj
)
164 NPCM7xxSDHCIState
*s
= NPCM7XX_SDHCI(obj
);
166 object_initialize_child(OBJECT(s
), TYPE_SYSBUS_SDHCI
, &s
->sdhci
,
170 static const TypeInfo npcm7xx_sdhci_types
[] = {
172 .name
= TYPE_NPCM7XX_SDHCI
,
173 .parent
= TYPE_SYS_BUS_DEVICE
,
174 .instance_size
= sizeof(NPCM7xxSDHCIState
),
175 .instance_init
= npcm7xx_sdhci_instance_init
,
176 .class_init
= npcm7xx_sdhci_class_init
,
180 DEFINE_TYPES(npcm7xx_sdhci_types
)