qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

hw/arm/allwinner-h3: add SDRAM controller device

In the Allwinner H3 SoC the SDRAM controller is responsible
for interfacing with the external Synchronous Dynamic Random
Access Memory (SDRAM). Types of memory that the SDRAM controller
supports are DDR2/DDR3 and capacities of up to 2GiB. This commit
adds emulation support of the Allwinner H3 SDRAM controller.

Signed-off-by: Niek Linnenbank <nieklinnenbank@gmail.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20200311221854.30370-12-nieklinnenbank@gmail.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

authored by

Niek Linnenbank and committed by
Peter Maydell
b71d0385 a80beb16

+502 -3
+16 -3
hw/arm/allwinner-h3.c
··· 56 56 [AW_H3_UART2] = 0x01c28800, 57 57 [AW_H3_UART3] = 0x01c28c00, 58 58 [AW_H3_EMAC] = 0x01c30000, 59 + [AW_H3_DRAMCOM] = 0x01c62000, 60 + [AW_H3_DRAMCTL] = 0x01c63000, 61 + [AW_H3_DRAMPHY] = 0x01c65000, 59 62 [AW_H3_GIC_DIST] = 0x01c81000, 60 63 [AW_H3_GIC_CPU] = 0x01c82000, 61 64 [AW_H3_GIC_HYP] = 0x01c84000, ··· 110 113 { "scr", 0x01c2c400, 1 * KiB }, 111 114 { "gpu", 0x01c40000, 64 * KiB }, 112 115 { "hstmr", 0x01c60000, 4 * KiB }, 113 - { "dramcom", 0x01c62000, 4 * KiB }, 114 - { "dramctl0", 0x01c63000, 4 * KiB }, 115 - { "dramphy0", 0x01c65000, 4 * KiB }, 116 116 { "spi0", 0x01c68000, 4 * KiB }, 117 117 { "spi1", 0x01c69000, 4 * KiB }, 118 118 { "csi", 0x01cb0000, 320 * KiB }, ··· 228 228 229 229 sysbus_init_child_obj(obj, "emac", &s->emac, sizeof(s->emac), 230 230 TYPE_AW_SUN8I_EMAC); 231 + 232 + sysbus_init_child_obj(obj, "dramc", &s->dramc, sizeof(s->dramc), 233 + TYPE_AW_H3_DRAMC); 234 + object_property_add_alias(obj, "ram-addr", OBJECT(&s->dramc), 235 + "ram-addr", &error_abort); 236 + object_property_add_alias(obj, "ram-size", OBJECT(&s->dramc), 237 + "ram-size", &error_abort); 231 238 } 232 239 233 240 static void allwinner_h3_realize(DeviceState *dev, Error **errp) ··· 411 418 serial_mm_init(get_system_memory(), s->memmap[AW_H3_UART3], 2, 412 419 qdev_get_gpio_in(DEVICE(&s->gic), AW_H3_GIC_SPI_UART3), 413 420 115200, serial_hd(3), DEVICE_NATIVE_ENDIAN); 421 + 422 + /* DRAMC */ 423 + qdev_init_nofail(DEVICE(&s->dramc)); 424 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 0, s->memmap[AW_H3_DRAMCOM]); 425 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 1, s->memmap[AW_H3_DRAMCTL]); 426 + sysbus_mmio_map(SYS_BUS_DEVICE(&s->dramc), 2, s->memmap[AW_H3_DRAMPHY]); 414 427 415 428 /* Unimplemented devices */ 416 429 for (i = 0; i < ARRAY_SIZE(unimplemented); i++) {
+6
hw/arm/orangepi.c
··· 80 80 /* Setup EMAC properties */ 81 81 object_property_set_int(OBJECT(&h3->emac), 1, "phy-addr", &error_abort); 82 82 83 + /* DRAMC */ 84 + object_property_set_uint(OBJECT(h3), h3->memmap[AW_H3_SDRAM], 85 + "ram-addr", &error_abort); 86 + object_property_set_int(OBJECT(h3), machine->ram_size / MiB, "ram-size", 87 + &error_abort); 88 + 83 89 /* Mark H3 object realized */ 84 90 object_property_set_bool(OBJECT(h3), true, "realized", &error_abort); 85 91
+1
hw/misc/Makefile.objs
··· 30 30 31 31 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-ccu.o 32 32 obj-$(CONFIG_ALLWINNER_H3) += allwinner-cpucfg.o 33 + common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-dramc.o 33 34 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-h3-sysctrl.o 34 35 common-obj-$(CONFIG_ALLWINNER_H3) += allwinner-sid.o 35 36 common-obj-$(CONFIG_REALVIEW) += arm_sysctl.o
+358
hw/misc/allwinner-h3-dramc.c
··· 1 + /* 2 + * Allwinner H3 SDRAM Controller emulation 3 + * 4 + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com> 5 + * 6 + * This program is free software: you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation, either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #include "qemu/osdep.h" 21 + #include "qemu/units.h" 22 + #include "qemu/error-report.h" 23 + #include "hw/sysbus.h" 24 + #include "migration/vmstate.h" 25 + #include "qemu/log.h" 26 + #include "qemu/module.h" 27 + #include "exec/address-spaces.h" 28 + #include "hw/qdev-properties.h" 29 + #include "qapi/error.h" 30 + #include "hw/misc/allwinner-h3-dramc.h" 31 + #include "trace.h" 32 + 33 + #define REG_INDEX(offset) (offset / sizeof(uint32_t)) 34 + 35 + /* DRAMCOM register offsets */ 36 + enum { 37 + REG_DRAMCOM_CR = 0x0000, /* Control Register */ 38 + }; 39 + 40 + /* DRAMCTL register offsets */ 41 + enum { 42 + REG_DRAMCTL_PIR = 0x0000, /* PHY Initialization Register */ 43 + REG_DRAMCTL_PGSR = 0x0010, /* PHY General Status Register */ 44 + REG_DRAMCTL_STATR = 0x0018, /* Status Register */ 45 + }; 46 + 47 + /* DRAMCTL register flags */ 48 + enum { 49 + REG_DRAMCTL_PGSR_INITDONE = (1 << 0), 50 + }; 51 + 52 + enum { 53 + REG_DRAMCTL_STATR_ACTIVE = (1 << 0), 54 + }; 55 + 56 + static void allwinner_h3_dramc_map_rows(AwH3DramCtlState *s, uint8_t row_bits, 57 + uint8_t bank_bits, uint16_t page_size) 58 + { 59 + /* 60 + * This function simulates row addressing behavior when bootloader 61 + * software attempts to detect the amount of available SDRAM. In U-Boot 62 + * the controller is configured with the widest row addressing available. 63 + * Then a pattern is written to RAM at an offset on the row boundary size. 64 + * If the value read back equals the value read back from the 65 + * start of RAM, the bootloader knows the amount of row bits. 66 + * 67 + * This function inserts a mirrored memory region when the configured row 68 + * bits are not matching the actual emulated memory, to simulate the 69 + * same behavior on hardware as expected by the bootloader. 70 + */ 71 + uint8_t row_bits_actual = 0; 72 + 73 + /* Calculate the actual row bits using the ram_size property */ 74 + for (uint8_t i = 8; i < 12; i++) { 75 + if (1 << i == s->ram_size) { 76 + row_bits_actual = i + 3; 77 + break; 78 + } 79 + } 80 + 81 + if (s->ram_size == (1 << (row_bits - 3))) { 82 + /* When row bits is the expected value, remove the mirror */ 83 + memory_region_set_enabled(&s->row_mirror_alias, false); 84 + trace_allwinner_h3_dramc_rowmirror_disable(); 85 + 86 + } else if (row_bits_actual) { 87 + /* Row bits not matching ram_size, install the rows mirror */ 88 + hwaddr row_mirror = s->ram_addr + ((1 << (row_bits_actual + 89 + bank_bits)) * page_size); 90 + 91 + memory_region_set_enabled(&s->row_mirror_alias, true); 92 + memory_region_set_address(&s->row_mirror_alias, row_mirror); 93 + 94 + trace_allwinner_h3_dramc_rowmirror_enable(row_mirror); 95 + } 96 + } 97 + 98 + static uint64_t allwinner_h3_dramcom_read(void *opaque, hwaddr offset, 99 + unsigned size) 100 + { 101 + const AwH3DramCtlState *s = AW_H3_DRAMC(opaque); 102 + const uint32_t idx = REG_INDEX(offset); 103 + 104 + if (idx >= AW_H3_DRAMCOM_REGS_NUM) { 105 + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 106 + __func__, (uint32_t)offset); 107 + return 0; 108 + } 109 + 110 + trace_allwinner_h3_dramcom_read(offset, s->dramcom[idx], size); 111 + 112 + return s->dramcom[idx]; 113 + } 114 + 115 + static void allwinner_h3_dramcom_write(void *opaque, hwaddr offset, 116 + uint64_t val, unsigned size) 117 + { 118 + AwH3DramCtlState *s = AW_H3_DRAMC(opaque); 119 + const uint32_t idx = REG_INDEX(offset); 120 + 121 + trace_allwinner_h3_dramcom_write(offset, val, size); 122 + 123 + if (idx >= AW_H3_DRAMCOM_REGS_NUM) { 124 + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 125 + __func__, (uint32_t)offset); 126 + return; 127 + } 128 + 129 + switch (offset) { 130 + case REG_DRAMCOM_CR: /* Control Register */ 131 + allwinner_h3_dramc_map_rows(s, ((val >> 4) & 0xf) + 1, 132 + ((val >> 2) & 0x1) + 2, 133 + 1 << (((val >> 8) & 0xf) + 3)); 134 + break; 135 + default: 136 + break; 137 + }; 138 + 139 + s->dramcom[idx] = (uint32_t) val; 140 + } 141 + 142 + static uint64_t allwinner_h3_dramctl_read(void *opaque, hwaddr offset, 143 + unsigned size) 144 + { 145 + const AwH3DramCtlState *s = AW_H3_DRAMC(opaque); 146 + const uint32_t idx = REG_INDEX(offset); 147 + 148 + if (idx >= AW_H3_DRAMCTL_REGS_NUM) { 149 + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 150 + __func__, (uint32_t)offset); 151 + return 0; 152 + } 153 + 154 + trace_allwinner_h3_dramctl_read(offset, s->dramctl[idx], size); 155 + 156 + return s->dramctl[idx]; 157 + } 158 + 159 + static void allwinner_h3_dramctl_write(void *opaque, hwaddr offset, 160 + uint64_t val, unsigned size) 161 + { 162 + AwH3DramCtlState *s = AW_H3_DRAMC(opaque); 163 + const uint32_t idx = REG_INDEX(offset); 164 + 165 + trace_allwinner_h3_dramctl_write(offset, val, size); 166 + 167 + if (idx >= AW_H3_DRAMCTL_REGS_NUM) { 168 + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 169 + __func__, (uint32_t)offset); 170 + return; 171 + } 172 + 173 + switch (offset) { 174 + case REG_DRAMCTL_PIR: /* PHY Initialization Register */ 175 + s->dramctl[REG_INDEX(REG_DRAMCTL_PGSR)] |= REG_DRAMCTL_PGSR_INITDONE; 176 + s->dramctl[REG_INDEX(REG_DRAMCTL_STATR)] |= REG_DRAMCTL_STATR_ACTIVE; 177 + break; 178 + default: 179 + break; 180 + } 181 + 182 + s->dramctl[idx] = (uint32_t) val; 183 + } 184 + 185 + static uint64_t allwinner_h3_dramphy_read(void *opaque, hwaddr offset, 186 + unsigned size) 187 + { 188 + const AwH3DramCtlState *s = AW_H3_DRAMC(opaque); 189 + const uint32_t idx = REG_INDEX(offset); 190 + 191 + if (idx >= AW_H3_DRAMPHY_REGS_NUM) { 192 + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 193 + __func__, (uint32_t)offset); 194 + return 0; 195 + } 196 + 197 + trace_allwinner_h3_dramphy_read(offset, s->dramphy[idx], size); 198 + 199 + return s->dramphy[idx]; 200 + } 201 + 202 + static void allwinner_h3_dramphy_write(void *opaque, hwaddr offset, 203 + uint64_t val, unsigned size) 204 + { 205 + AwH3DramCtlState *s = AW_H3_DRAMC(opaque); 206 + const uint32_t idx = REG_INDEX(offset); 207 + 208 + trace_allwinner_h3_dramphy_write(offset, val, size); 209 + 210 + if (idx >= AW_H3_DRAMPHY_REGS_NUM) { 211 + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 212 + __func__, (uint32_t)offset); 213 + return; 214 + } 215 + 216 + s->dramphy[idx] = (uint32_t) val; 217 + } 218 + 219 + static const MemoryRegionOps allwinner_h3_dramcom_ops = { 220 + .read = allwinner_h3_dramcom_read, 221 + .write = allwinner_h3_dramcom_write, 222 + .endianness = DEVICE_NATIVE_ENDIAN, 223 + .valid = { 224 + .min_access_size = 4, 225 + .max_access_size = 4, 226 + }, 227 + .impl.min_access_size = 4, 228 + }; 229 + 230 + static const MemoryRegionOps allwinner_h3_dramctl_ops = { 231 + .read = allwinner_h3_dramctl_read, 232 + .write = allwinner_h3_dramctl_write, 233 + .endianness = DEVICE_NATIVE_ENDIAN, 234 + .valid = { 235 + .min_access_size = 4, 236 + .max_access_size = 4, 237 + }, 238 + .impl.min_access_size = 4, 239 + }; 240 + 241 + static const MemoryRegionOps allwinner_h3_dramphy_ops = { 242 + .read = allwinner_h3_dramphy_read, 243 + .write = allwinner_h3_dramphy_write, 244 + .endianness = DEVICE_NATIVE_ENDIAN, 245 + .valid = { 246 + .min_access_size = 4, 247 + .max_access_size = 4, 248 + }, 249 + .impl.min_access_size = 4, 250 + }; 251 + 252 + static void allwinner_h3_dramc_reset(DeviceState *dev) 253 + { 254 + AwH3DramCtlState *s = AW_H3_DRAMC(dev); 255 + 256 + /* Set default values for registers */ 257 + memset(&s->dramcom, 0, sizeof(s->dramcom)); 258 + memset(&s->dramctl, 0, sizeof(s->dramctl)); 259 + memset(&s->dramphy, 0, sizeof(s->dramphy)); 260 + } 261 + 262 + static void allwinner_h3_dramc_realize(DeviceState *dev, Error **errp) 263 + { 264 + AwH3DramCtlState *s = AW_H3_DRAMC(dev); 265 + 266 + /* Only power of 2 RAM sizes from 256MiB up to 2048MiB are supported */ 267 + for (uint8_t i = 8; i < 13; i++) { 268 + if (1 << i == s->ram_size) { 269 + break; 270 + } else if (i == 12) { 271 + error_report("%s: ram-size %u MiB is not supported", 272 + __func__, s->ram_size); 273 + exit(1); 274 + } 275 + } 276 + 277 + /* Setup row mirror mappings */ 278 + memory_region_init_ram(&s->row_mirror, OBJECT(s), 279 + "allwinner-h3-dramc.row-mirror", 280 + 4 * KiB, &error_abort); 281 + memory_region_add_subregion_overlap(get_system_memory(), s->ram_addr, 282 + &s->row_mirror, 10); 283 + 284 + memory_region_init_alias(&s->row_mirror_alias, OBJECT(s), 285 + "allwinner-h3-dramc.row-mirror-alias", 286 + &s->row_mirror, 0, 4 * KiB); 287 + memory_region_add_subregion_overlap(get_system_memory(), 288 + s->ram_addr + 1 * MiB, 289 + &s->row_mirror_alias, 10); 290 + memory_region_set_enabled(&s->row_mirror_alias, false); 291 + } 292 + 293 + static void allwinner_h3_dramc_init(Object *obj) 294 + { 295 + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 296 + AwH3DramCtlState *s = AW_H3_DRAMC(obj); 297 + 298 + /* DRAMCOM registers */ 299 + memory_region_init_io(&s->dramcom_iomem, OBJECT(s), 300 + &allwinner_h3_dramcom_ops, s, 301 + TYPE_AW_H3_DRAMC, 4 * KiB); 302 + sysbus_init_mmio(sbd, &s->dramcom_iomem); 303 + 304 + /* DRAMCTL registers */ 305 + memory_region_init_io(&s->dramctl_iomem, OBJECT(s), 306 + &allwinner_h3_dramctl_ops, s, 307 + TYPE_AW_H3_DRAMC, 4 * KiB); 308 + sysbus_init_mmio(sbd, &s->dramctl_iomem); 309 + 310 + /* DRAMPHY registers */ 311 + memory_region_init_io(&s->dramphy_iomem, OBJECT(s), 312 + &allwinner_h3_dramphy_ops, s, 313 + TYPE_AW_H3_DRAMC, 4 * KiB); 314 + sysbus_init_mmio(sbd, &s->dramphy_iomem); 315 + } 316 + 317 + static Property allwinner_h3_dramc_properties[] = { 318 + DEFINE_PROP_UINT64("ram-addr", AwH3DramCtlState, ram_addr, 0x0), 319 + DEFINE_PROP_UINT32("ram-size", AwH3DramCtlState, ram_size, 256 * MiB), 320 + DEFINE_PROP_END_OF_LIST() 321 + }; 322 + 323 + static const VMStateDescription allwinner_h3_dramc_vmstate = { 324 + .name = "allwinner-h3-dramc", 325 + .version_id = 1, 326 + .minimum_version_id = 1, 327 + .fields = (VMStateField[]) { 328 + VMSTATE_UINT32_ARRAY(dramcom, AwH3DramCtlState, AW_H3_DRAMCOM_REGS_NUM), 329 + VMSTATE_UINT32_ARRAY(dramctl, AwH3DramCtlState, AW_H3_DRAMCTL_REGS_NUM), 330 + VMSTATE_UINT32_ARRAY(dramphy, AwH3DramCtlState, AW_H3_DRAMPHY_REGS_NUM), 331 + VMSTATE_END_OF_LIST() 332 + } 333 + }; 334 + 335 + static void allwinner_h3_dramc_class_init(ObjectClass *klass, void *data) 336 + { 337 + DeviceClass *dc = DEVICE_CLASS(klass); 338 + 339 + dc->reset = allwinner_h3_dramc_reset; 340 + dc->vmsd = &allwinner_h3_dramc_vmstate; 341 + dc->realize = allwinner_h3_dramc_realize; 342 + device_class_set_props(dc, allwinner_h3_dramc_properties); 343 + } 344 + 345 + static const TypeInfo allwinner_h3_dramc_info = { 346 + .name = TYPE_AW_H3_DRAMC, 347 + .parent = TYPE_SYS_BUS_DEVICE, 348 + .instance_init = allwinner_h3_dramc_init, 349 + .instance_size = sizeof(AwH3DramCtlState), 350 + .class_init = allwinner_h3_dramc_class_init, 351 + }; 352 + 353 + static void allwinner_h3_dramc_register(void) 354 + { 355 + type_register_static(&allwinner_h3_dramc_info); 356 + } 357 + 358 + type_init(allwinner_h3_dramc_register)
+10
hw/misc/trace-events
··· 5 5 allwinner_cpucfg_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 6 6 allwinner_cpucfg_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 7 7 8 + # allwinner-h3-dramc.c 9 + allwinner_h3_dramc_rowmirror_disable(void) "Disable row mirror" 10 + allwinner_h3_dramc_rowmirror_enable(uint64_t addr) "Enable row mirror: addr 0x%" PRIx64 11 + allwinner_h3_dramcom_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 12 + allwinner_h3_dramcom_write(uint64_t offset, uint64_t data, unsigned size) "Write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 13 + allwinner_h3_dramctl_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 14 + allwinner_h3_dramctl_write(uint64_t offset, uint64_t data, unsigned size) "Write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 15 + allwinner_h3_dramphy_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 16 + allwinner_h3_dramphy_write(uint64_t offset, uint64_t data, unsigned size) "write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 17 + 8 18 # allwinner-sid.c 9 19 allwinner_sid_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 10 20 allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32
+5
include/hw/arm/allwinner-h3.h
··· 41 41 #include "hw/intc/arm_gic.h" 42 42 #include "hw/misc/allwinner-h3-ccu.h" 43 43 #include "hw/misc/allwinner-cpucfg.h" 44 + #include "hw/misc/allwinner-h3-dramc.h" 44 45 #include "hw/misc/allwinner-h3-sysctrl.h" 45 46 #include "hw/misc/allwinner-sid.h" 46 47 #include "hw/sd/allwinner-sdhost.h" ··· 80 81 AW_H3_UART2, 81 82 AW_H3_UART3, 82 83 AW_H3_EMAC, 84 + AW_H3_DRAMCOM, 85 + AW_H3_DRAMCTL, 86 + AW_H3_DRAMPHY, 83 87 AW_H3_GIC_DIST, 84 88 AW_H3_GIC_CPU, 85 89 AW_H3_GIC_HYP, ··· 120 124 AwA10PITState timer; 121 125 AwH3ClockCtlState ccu; 122 126 AwCpuCfgState cpucfg; 127 + AwH3DramCtlState dramc; 123 128 AwH3SysCtrlState sysctrl; 124 129 AwSidState sid; 125 130 AwSdHostState mmc0;
+106
include/hw/misc/allwinner-h3-dramc.h
··· 1 + /* 2 + * Allwinner H3 SDRAM Controller emulation 3 + * 4 + * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com> 5 + * 6 + * This program is free software: you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation, either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 + */ 19 + 20 + #ifndef HW_MISC_ALLWINNER_H3_DRAMC_H 21 + #define HW_MISC_ALLWINNER_H3_DRAMC_H 22 + 23 + #include "qom/object.h" 24 + #include "hw/sysbus.h" 25 + #include "exec/hwaddr.h" 26 + 27 + /** 28 + * Constants 29 + * @{ 30 + */ 31 + 32 + /** Highest register address used by DRAMCOM module */ 33 + #define AW_H3_DRAMCOM_REGS_MAXADDR (0x804) 34 + 35 + /** Total number of known DRAMCOM registers */ 36 + #define AW_H3_DRAMCOM_REGS_NUM (AW_H3_DRAMCOM_REGS_MAXADDR / \ 37 + sizeof(uint32_t)) 38 + 39 + /** Highest register address used by DRAMCTL module */ 40 + #define AW_H3_DRAMCTL_REGS_MAXADDR (0x88c) 41 + 42 + /** Total number of known DRAMCTL registers */ 43 + #define AW_H3_DRAMCTL_REGS_NUM (AW_H3_DRAMCTL_REGS_MAXADDR / \ 44 + sizeof(uint32_t)) 45 + 46 + /** Highest register address used by DRAMPHY module */ 47 + #define AW_H3_DRAMPHY_REGS_MAXADDR (0x4) 48 + 49 + /** Total number of known DRAMPHY registers */ 50 + #define AW_H3_DRAMPHY_REGS_NUM (AW_H3_DRAMPHY_REGS_MAXADDR / \ 51 + sizeof(uint32_t)) 52 + 53 + /** @} */ 54 + 55 + /** 56 + * Object model 57 + * @{ 58 + */ 59 + 60 + #define TYPE_AW_H3_DRAMC "allwinner-h3-dramc" 61 + #define AW_H3_DRAMC(obj) \ 62 + OBJECT_CHECK(AwH3DramCtlState, (obj), TYPE_AW_H3_DRAMC) 63 + 64 + /** @} */ 65 + 66 + /** 67 + * Allwinner H3 SDRAM Controller object instance state. 68 + */ 69 + typedef struct AwH3DramCtlState { 70 + /*< private >*/ 71 + SysBusDevice parent_obj; 72 + /*< public >*/ 73 + 74 + /** Physical base address for start of RAM */ 75 + hwaddr ram_addr; 76 + 77 + /** Total RAM size in megabytes */ 78 + uint32_t ram_size; 79 + 80 + /** 81 + * @name Memory Regions 82 + * @{ 83 + */ 84 + 85 + MemoryRegion row_mirror; /**< Simulates rows for RAM size detection */ 86 + MemoryRegion row_mirror_alias; /**< Alias of the row which is mirrored */ 87 + MemoryRegion dramcom_iomem; /**< DRAMCOM module I/O registers */ 88 + MemoryRegion dramctl_iomem; /**< DRAMCTL module I/O registers */ 89 + MemoryRegion dramphy_iomem; /**< DRAMPHY module I/O registers */ 90 + 91 + /** @} */ 92 + 93 + /** 94 + * @name Hardware Registers 95 + * @{ 96 + */ 97 + 98 + uint32_t dramcom[AW_H3_DRAMCOM_REGS_NUM]; /**< Array of DRAMCOM registers */ 99 + uint32_t dramctl[AW_H3_DRAMCTL_REGS_NUM]; /**< Array of DRAMCTL registers */ 100 + uint32_t dramphy[AW_H3_DRAMPHY_REGS_NUM] ;/**< Array of DRAMPHY registers */ 101 + 102 + /** @} */ 103 + 104 + } AwH3DramCtlState; 105 + 106 + #endif /* HW_MISC_ALLWINNER_H3_DRAMC_H */