2 * Cadence SDHCI emulation
4 * Copyright (c) 2020 Wind River Systems, Inc.
7 * Bin Meng <bin.meng@windriver.com>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 or
12 * (at your option) version 3 of the License.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <http://www.gnu.org/licenses/>.
23 #include "qemu/osdep.h"
24 #include "qemu/bitops.h"
25 #include "qemu/error-report.h"
26 #include "qapi/error.h"
27 #include "migration/vmstate.h"
28 #include "hw/sd/cadence_sdhci.h"
29 #include "sdhci-internal.h"
31 /* HRS - Host Register Set (specific to Cadence) */
33 #define CADENCE_SDHCI_HRS00 0x00 /* general information */
34 #define CADENCE_SDHCI_HRS00_SWR BIT(0)
35 #define CADENCE_SDHCI_HRS00_POR_VAL 0x00010000
37 #define CADENCE_SDHCI_HRS04 0x10 /* PHY access port */
38 #define CADENCE_SDHCI_HRS04_WR BIT(24)
39 #define CADENCE_SDHCI_HRS04_RD BIT(25)
40 #define CADENCE_SDHCI_HRS04_ACK BIT(26)
42 #define CADENCE_SDHCI_HRS06 0x18 /* eMMC control */
43 #define CADENCE_SDHCI_HRS06_TUNE_UP BIT(15)
45 /* SRS - Slot Register Set (SDHCI-compatible) */
47 #define CADENCE_SDHCI_SRS_BASE 0x200
49 #define TO_REG(addr) ((addr) / sizeof(uint32_t))
51 static void cadence_sdhci_instance_init(Object
*obj
)
53 CadenceSDHCIState
*s
= CADENCE_SDHCI(obj
);
55 object_initialize_child(OBJECT(s
), "generic-sdhci",
56 &s
->sdhci
, TYPE_SYSBUS_SDHCI
);
59 static void cadence_sdhci_reset(DeviceState
*dev
)
61 CadenceSDHCIState
*s
= CADENCE_SDHCI(dev
);
63 memset(s
->regs
, 0, CADENCE_SDHCI_REG_SIZE
);
64 s
->regs
[TO_REG(CADENCE_SDHCI_HRS00
)] = CADENCE_SDHCI_HRS00_POR_VAL
;
66 device_cold_reset(DEVICE(&s
->sdhci
));
69 static uint64_t cadence_sdhci_read(void *opaque
, hwaddr addr
, unsigned int size
)
71 CadenceSDHCIState
*s
= opaque
;
74 val
= s
->regs
[TO_REG(addr
)];
79 static void cadence_sdhci_write(void *opaque
, hwaddr addr
, uint64_t val
,
82 CadenceSDHCIState
*s
= opaque
;
83 uint32_t val32
= (uint32_t)val
;
86 case CADENCE_SDHCI_HRS00
:
88 * The only writable bit is SWR (software reset) and it automatically
89 * clears to zero, so essentially this register remains unchanged.
91 if (val32
& CADENCE_SDHCI_HRS00_SWR
) {
92 cadence_sdhci_reset(DEVICE(s
));
96 case CADENCE_SDHCI_HRS04
:
98 * Only emulate the ACK bit behavior when read or write transaction
101 if (val32
& (CADENCE_SDHCI_HRS04_WR
| CADENCE_SDHCI_HRS04_RD
)) {
102 val32
|= CADENCE_SDHCI_HRS04_ACK
;
104 val32
&= ~CADENCE_SDHCI_HRS04_ACK
;
107 s
->regs
[TO_REG(addr
)] = val32
;
109 case CADENCE_SDHCI_HRS06
:
110 if (val32
& CADENCE_SDHCI_HRS06_TUNE_UP
) {
111 val32
&= ~CADENCE_SDHCI_HRS06_TUNE_UP
;
114 s
->regs
[TO_REG(addr
)] = val32
;
117 s
->regs
[TO_REG(addr
)] = val32
;
122 static const MemoryRegionOps cadence_sdhci_ops
= {
123 .read
= cadence_sdhci_read
,
124 .write
= cadence_sdhci_write
,
125 .endianness
= DEVICE_NATIVE_ENDIAN
,
127 .min_access_size
= 4,
128 .max_access_size
= 4,
131 .min_access_size
= 4,
132 .max_access_size
= 4,
136 static void cadence_sdhci_realize(DeviceState
*dev
, Error
**errp
)
138 CadenceSDHCIState
*s
= CADENCE_SDHCI(dev
);
139 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
140 SysBusDevice
*sbd_sdhci
= SYS_BUS_DEVICE(&s
->sdhci
);
142 memory_region_init(&s
->container
, OBJECT(s
),
143 "cadence.sdhci-container", 0x1000);
144 sysbus_init_mmio(sbd
, &s
->container
);
146 memory_region_init_io(&s
->iomem
, OBJECT(s
), &cadence_sdhci_ops
,
147 s
, TYPE_CADENCE_SDHCI
, CADENCE_SDHCI_REG_SIZE
);
148 memory_region_add_subregion(&s
->container
, 0, &s
->iomem
);
150 sysbus_realize(sbd_sdhci
, errp
);
151 memory_region_add_subregion(&s
->container
, CADENCE_SDHCI_SRS_BASE
,
152 sysbus_mmio_get_region(sbd_sdhci
, 0));
154 /* propagate irq and "sd-bus" from generic-sdhci */
155 sysbus_pass_irq(sbd
, sbd_sdhci
);
156 s
->bus
= qdev_get_child_bus(DEVICE(sbd_sdhci
), "sd-bus");
159 static const VMStateDescription vmstate_cadence_sdhci
= {
160 .name
= TYPE_CADENCE_SDHCI
,
162 .fields
= (const VMStateField
[]) {
163 VMSTATE_UINT32_ARRAY(regs
, CadenceSDHCIState
, CADENCE_SDHCI_NUM_REGS
),
164 VMSTATE_END_OF_LIST(),
168 static void cadence_sdhci_class_init(ObjectClass
*classp
, void *data
)
170 DeviceClass
*dc
= DEVICE_CLASS(classp
);
172 dc
->desc
= "Cadence SD/SDIO/eMMC Host Controller (SD4HC)";
173 dc
->realize
= cadence_sdhci_realize
;
174 dc
->reset
= cadence_sdhci_reset
;
175 dc
->vmsd
= &vmstate_cadence_sdhci
;
178 static const TypeInfo cadence_sdhci_types
[] = {
180 .name
= TYPE_CADENCE_SDHCI
,
181 .parent
= TYPE_SYS_BUS_DEVICE
,
182 .instance_size
= sizeof(CadenceSDHCIState
),
183 .instance_init
= cadence_sdhci_instance_init
,
184 .class_init
= cadence_sdhci_class_init
,
188 DEFINE_TYPES(cadence_sdhci_types
)