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/npcm7xx_sdhci.h"
20 #include "migration/vmstate.h"
21 #include "sdhci-internal.h"
24 static uint64_t npcm7xx_sdhci_read(void *opaque
, hwaddr addr
, unsigned int size
)
26 NPCM7xxSDHCIState
*s
= opaque
;
30 case NPCM7XX_PRSTVALS_0
:
31 case NPCM7XX_PRSTVALS_1
:
32 case NPCM7XX_PRSTVALS_2
:
33 case NPCM7XX_PRSTVALS_3
:
34 case NPCM7XX_PRSTVALS_4
:
35 case NPCM7XX_PRSTVALS_5
:
36 val
= s
->regs
.prstvals
[(addr
- NPCM7XX_PRSTVALS_0
) / 2];
38 case NPCM7XX_BOOTTOCTRL
:
39 val
= s
->regs
.boottoctrl
;
42 qemu_log_mask(LOG_GUEST_ERROR
, "SDHCI read of nonexistent reg: 0x%02"
50 static void npcm7xx_sdhci_write(void *opaque
, hwaddr addr
, uint64_t val
,
53 NPCM7xxSDHCIState
*s
= opaque
;
56 case NPCM7XX_BOOTTOCTRL
:
57 s
->regs
.boottoctrl
= val
;
60 qemu_log_mask(LOG_GUEST_ERROR
, "SDHCI write of nonexistent reg: 0x%02"
66 static bool npcm7xx_sdhci_check_mem_op(void *opaque
, hwaddr addr
,
67 unsigned size
, bool is_write
,
71 case NPCM7XX_PRSTVALS_0
:
72 case NPCM7XX_PRSTVALS_1
:
73 case NPCM7XX_PRSTVALS_2
:
74 case NPCM7XX_PRSTVALS_3
:
75 case NPCM7XX_PRSTVALS_4
:
76 case NPCM7XX_PRSTVALS_5
:
78 return !is_write
&& size
== 2;
79 case NPCM7XX_BOOTTOCTRL
:
87 static const MemoryRegionOps npcm7xx_sdhci_ops
= {
88 .read
= npcm7xx_sdhci_read
,
89 .write
= npcm7xx_sdhci_write
,
90 .endianness
= DEVICE_NATIVE_ENDIAN
,
95 .accepts
= npcm7xx_sdhci_check_mem_op
,
99 static void npcm7xx_sdhci_realize(DeviceState
*dev
, Error
**errp
)
101 NPCM7xxSDHCIState
*s
= NPCM7XX_SDHCI(dev
);
102 SysBusDevice
*sbd
= SYS_BUS_DEVICE(dev
);
103 SysBusDevice
*sbd_sdhci
= SYS_BUS_DEVICE(&s
->sdhci
);
105 memory_region_init(&s
->container
, OBJECT(s
),
106 "npcm7xx.sdhci-container", 0x1000);
107 sysbus_init_mmio(sbd
, &s
->container
);
109 memory_region_init_io(&s
->iomem
, OBJECT(s
), &npcm7xx_sdhci_ops
, s
,
110 TYPE_NPCM7XX_SDHCI
, NPCM7XX_SDHCI_REGSIZE
);
111 memory_region_add_subregion_overlap(&s
->container
, NPCM7XX_PRSTVALS
,
114 sysbus_realize(sbd_sdhci
, errp
);
115 memory_region_add_subregion(&s
->container
, 0,
116 sysbus_mmio_get_region(sbd_sdhci
, 0));
118 /* propagate irq and "sd-bus" from generic-sdhci */
119 sysbus_pass_irq(sbd
, sbd_sdhci
);
120 s
->bus
= qdev_get_child_bus(DEVICE(sbd_sdhci
), "sd-bus");
122 /* Set the read only preset values. */
123 memset(s
->regs
.prstvals
, 0, sizeof(s
->regs
.prstvals
));
124 s
->regs
.prstvals
[0] = NPCM7XX_PRSTVALS_0_RESET
;
125 s
->regs
.prstvals
[1] = NPCM7XX_PRSTVALS_1_RESET
;
126 s
->regs
.prstvals
[3] = NPCM7XX_PRSTVALS_3_RESET
;
129 static void npcm7xx_sdhci_reset(DeviceState
*dev
)
131 NPCM7xxSDHCIState
*s
= NPCM7XX_SDHCI(dev
);
132 device_cold_reset(DEVICE(&s
->sdhci
));
133 s
->regs
.boottoctrl
= 0;
135 s
->sdhci
.prnsts
= NPCM7XX_PRSNTS_RESET
;
136 s
->sdhci
.blkgap
= NPCM7XX_BLKGAP_RESET
;
137 s
->sdhci
.capareg
= NPCM7XX_CAPAB_RESET
;
138 s
->sdhci
.maxcurr
= NPCM7XX_MAXCURR_RESET
;
139 s
->sdhci
.version
= NPCM7XX_HCVER_RESET
;
142 static const VMStateDescription vmstate_npcm7xx_sdhci
= {
143 .name
= TYPE_NPCM7XX_SDHCI
,
145 .fields
= (VMStateField
[]) {
146 VMSTATE_UINT32(regs
.boottoctrl
, NPCM7xxSDHCIState
),
147 VMSTATE_END_OF_LIST(),
151 static void npcm7xx_sdhci_class_init(ObjectClass
*classp
, void *data
)
153 DeviceClass
*dc
= DEVICE_CLASS(classp
);
155 dc
->desc
= "NPCM7xx SD/eMMC Host Controller";
156 dc
->realize
= npcm7xx_sdhci_realize
;
157 dc
->reset
= npcm7xx_sdhci_reset
;
158 dc
->vmsd
= &vmstate_npcm7xx_sdhci
;
161 static void npcm7xx_sdhci_instance_init(Object
*obj
)
163 NPCM7xxSDHCIState
*s
= NPCM7XX_SDHCI(obj
);
165 object_initialize_child(OBJECT(s
), "generic-sdhci", &s
->sdhci
,
169 static const TypeInfo npcm7xx_sdhci_info
= {
170 .name
= TYPE_NPCM7XX_SDHCI
,
171 .parent
= TYPE_SYS_BUS_DEVICE
,
172 .instance_size
= sizeof(NPCM7xxSDHCIState
),
173 .instance_init
= npcm7xx_sdhci_instance_init
,
174 .class_init
= npcm7xx_sdhci_class_init
,
177 static void npcm7xx_sdhci_register_types(void)
179 type_register_static(&npcm7xx_sdhci_info
);
182 type_init(npcm7xx_sdhci_register_types
)