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"
27 #include "qapi/error.h"
28 #include "migration/vmstate.h"
30 #include "hw/sd/cadence_sdhci.h"
31 #include "sdhci-internal.h"
33 /* HRS - Host Register Set (specific to Cadence) */
35 #define CADENCE_SDHCI_HRS00 0x00 /* general information */
36 #define CADENCE_SDHCI_HRS00_SWR BIT(0)
37 #define CADENCE_SDHCI_HRS00_POR_VAL 0x00010000
39 #define CADENCE_SDHCI_HRS04 0x10 /* PHY access port */
40 #define CADENCE_SDHCI_HRS04_WR BIT(24)
41 #define CADENCE_SDHCI_HRS04_RD BIT(25)
42 #define CADENCE_SDHCI_HRS04_ACK BIT(26)
44 #define CADENCE_SDHCI_HRS06 0x18 /* eMMC control */
45 #define CADENCE_SDHCI_HRS06_TUNE_UP BIT(15)
47 /* SRS - Slot Register Set (SDHCI-compatible) */
49 #define CADENCE_SDHCI_SRS_BASE 0x200
51 #define TO_REG(addr) ((addr) / sizeof(uint32_t))
53 static void cadence_sdhci_instance_init(Object
*obj
)
55 CadenceSDHCIState
*s
= CADENCE_SDHCI(obj
);
57 object_initialize_child(OBJECT(s
), "generic-sdhci",
58 &s
->sdhci
, TYPE_SYSBUS_SDHCI
);
61 static void cadence_sdhci_reset(DeviceState
*dev
)
63 CadenceSDHCIState
*s
= CADENCE_SDHCI(dev
);
65 memset(s
->regs
, 0, CADENCE_SDHCI_REG_SIZE
);
66 s
->regs
[TO_REG(CADENCE_SDHCI_HRS00
)] = CADENCE_SDHCI_HRS00_POR_VAL
;
68 device_cold_reset(DEVICE(&s
->sdhci
));
71 static uint64_t cadence_sdhci_read(void *opaque
, hwaddr addr
, unsigned int size
)
73 CadenceSDHCIState
*s
= opaque
;
76 val
= s
->regs
[TO_REG(addr
)];
81 static void cadence_sdhci_write(void *opaque
, hwaddr addr
, uint64_t val
,
84 CadenceSDHCIState
*s
= opaque
;
85 uint32_t val32
= (uint32_t)val
;
88 case CADENCE_SDHCI_HRS00
:
90 * The only writable bit is SWR (software reset) and it automatically
91 * clears to zero, so essentially this register remains unchanged.
93 if (val32
& CADENCE_SDHCI_HRS00_SWR
) {
94 cadence_sdhci_reset(DEVICE(s
));
98 case CADENCE_SDHCI_HRS04
:
100 * Only emulate the ACK bit behavior when read or write transaction
103 if (val32
& (CADENCE_SDHCI_HRS04_WR
| CADENCE_SDHCI_HRS04_RD
)) {
104 val32
|= CADENCE_SDHCI_HRS04_ACK
;
106 val32
&= ~CADENCE_SDHCI_HRS04_ACK
;
109 s
->regs
[TO_REG(addr
)] = val32
;
111 case CADENCE_SDHCI_HRS06
:
112 if (val32
& CADENCE_SDHCI_HRS06_TUNE_UP
) {
113 val32
&= ~CADENCE_SDHCI_HRS06_TUNE_UP
;
116 s
->regs
[TO_REG(addr
)] = val32
;
119 s
->regs
[TO_REG(addr
)] = val32
;
124 static const MemoryRegionOps cadence_sdhci_ops
= {
125 .read
= cadence_sdhci_read
,
126 .write
= cadence_sdhci_write
,
127 .endianness
= DEVICE_NATIVE_ENDIAN
,
129 .min_access_size
= 4,
130 .max_access_size
= 4,
133 .min_access_size
= 4,
134 .max_access_size
= 4,
138 static void cadence_sdhci_realize(DeviceState
*dev
, Error
**errp
)
140 CadenceSDHCIState
*s
= CADENCE_SDHCI(dev
);
141 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
142 SysBusDevice
*sbd_sdhci
= SYS_BUS_DEVICE(&s
->sdhci
);
144 memory_region_init(&s
->container
, OBJECT(s
),
145 "cadence.sdhci-container", 0x1000);
146 sysbus_init_mmio(sbd
, &s
->container
);
148 memory_region_init_io(&s
->iomem
, OBJECT(s
), &cadence_sdhci_ops
,
149 s
, TYPE_CADENCE_SDHCI
, CADENCE_SDHCI_REG_SIZE
);
150 memory_region_add_subregion(&s
->container
, 0, &s
->iomem
);
152 sysbus_realize(sbd_sdhci
, errp
);
153 memory_region_add_subregion(&s
->container
, CADENCE_SDHCI_SRS_BASE
,
154 sysbus_mmio_get_region(sbd_sdhci
, 0));
156 /* propagate irq and "sd-bus" from generic-sdhci */
157 sysbus_pass_irq(sbd
, sbd_sdhci
);
158 s
->bus
= qdev_get_child_bus(DEVICE(sbd_sdhci
), "sd-bus");
161 static const VMStateDescription vmstate_cadence_sdhci
= {
162 .name
= TYPE_CADENCE_SDHCI
,
164 .fields
= (VMStateField
[]) {
165 VMSTATE_UINT32_ARRAY(regs
, CadenceSDHCIState
, CADENCE_SDHCI_NUM_REGS
),
166 VMSTATE_END_OF_LIST(),
170 static void cadence_sdhci_class_init(ObjectClass
*classp
, void *data
)
172 DeviceClass
*dc
= DEVICE_CLASS(classp
);
174 dc
->desc
= "Cadence SD/SDIO/eMMC Host Controller (SD4HC)";
175 dc
->realize
= cadence_sdhci_realize
;
176 dc
->reset
= cadence_sdhci_reset
;
177 dc
->vmsd
= &vmstate_cadence_sdhci
;
180 static TypeInfo cadence_sdhci_info
= {
181 .name
= TYPE_CADENCE_SDHCI
,
182 .parent
= TYPE_SYS_BUS_DEVICE
,
183 .instance_size
= sizeof(CadenceSDHCIState
),
184 .instance_init
= cadence_sdhci_instance_init
,
185 .class_init
= cadence_sdhci_class_init
,
188 static void cadence_sdhci_register_types(void)
190 type_register_static(&cadence_sdhci_info
);
193 type_init(cadence_sdhci_register_types
)