allwinner-h3-sysctrl.c (4176B)
1/* 2 * Allwinner H3 System Control 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 "hw/sysbus.h" 23#include "migration/vmstate.h" 24#include "qemu/log.h" 25#include "qemu/module.h" 26#include "hw/misc/allwinner-h3-sysctrl.h" 27 28/* System Control register offsets */ 29enum { 30 REG_VER = 0x24, /* Version */ 31 REG_EMAC_PHY_CLK = 0x30, /* EMAC PHY Clock */ 32}; 33 34#define REG_INDEX(offset) (offset / sizeof(uint32_t)) 35 36/* System Control register reset values */ 37enum { 38 REG_VER_RST = 0x0, 39 REG_EMAC_PHY_CLK_RST = 0x58000, 40}; 41 42static uint64_t allwinner_h3_sysctrl_read(void *opaque, hwaddr offset, 43 unsigned size) 44{ 45 const AwH3SysCtrlState *s = AW_H3_SYSCTRL(opaque); 46 const uint32_t idx = REG_INDEX(offset); 47 48 if (idx >= AW_H3_SYSCTRL_REGS_NUM) { 49 qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 50 __func__, (uint32_t)offset); 51 return 0; 52 } 53 54 return s->regs[idx]; 55} 56 57static void allwinner_h3_sysctrl_write(void *opaque, hwaddr offset, 58 uint64_t val, unsigned size) 59{ 60 AwH3SysCtrlState *s = AW_H3_SYSCTRL(opaque); 61 const uint32_t idx = REG_INDEX(offset); 62 63 if (idx >= AW_H3_SYSCTRL_REGS_NUM) { 64 qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", 65 __func__, (uint32_t)offset); 66 return; 67 } 68 69 switch (offset) { 70 case REG_VER: /* Version */ 71 break; 72 default: 73 s->regs[idx] = (uint32_t) val; 74 break; 75 } 76} 77 78static const MemoryRegionOps allwinner_h3_sysctrl_ops = { 79 .read = allwinner_h3_sysctrl_read, 80 .write = allwinner_h3_sysctrl_write, 81 .endianness = DEVICE_NATIVE_ENDIAN, 82 .valid = { 83 .min_access_size = 4, 84 .max_access_size = 4, 85 }, 86 .impl.min_access_size = 4, 87}; 88 89static void allwinner_h3_sysctrl_reset(DeviceState *dev) 90{ 91 AwH3SysCtrlState *s = AW_H3_SYSCTRL(dev); 92 93 /* Set default values for registers */ 94 s->regs[REG_INDEX(REG_VER)] = REG_VER_RST; 95 s->regs[REG_INDEX(REG_EMAC_PHY_CLK)] = REG_EMAC_PHY_CLK_RST; 96} 97 98static void allwinner_h3_sysctrl_init(Object *obj) 99{ 100 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 101 AwH3SysCtrlState *s = AW_H3_SYSCTRL(obj); 102 103 /* Memory mapping */ 104 memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_h3_sysctrl_ops, s, 105 TYPE_AW_H3_SYSCTRL, 4 * KiB); 106 sysbus_init_mmio(sbd, &s->iomem); 107} 108 109static const VMStateDescription allwinner_h3_sysctrl_vmstate = { 110 .name = "allwinner-h3-sysctrl", 111 .version_id = 1, 112 .minimum_version_id = 1, 113 .fields = (VMStateField[]) { 114 VMSTATE_UINT32_ARRAY(regs, AwH3SysCtrlState, AW_H3_SYSCTRL_REGS_NUM), 115 VMSTATE_END_OF_LIST() 116 } 117}; 118 119static void allwinner_h3_sysctrl_class_init(ObjectClass *klass, void *data) 120{ 121 DeviceClass *dc = DEVICE_CLASS(klass); 122 123 dc->reset = allwinner_h3_sysctrl_reset; 124 dc->vmsd = &allwinner_h3_sysctrl_vmstate; 125} 126 127static const TypeInfo allwinner_h3_sysctrl_info = { 128 .name = TYPE_AW_H3_SYSCTRL, 129 .parent = TYPE_SYS_BUS_DEVICE, 130 .instance_init = allwinner_h3_sysctrl_init, 131 .instance_size = sizeof(AwH3SysCtrlState), 132 .class_init = allwinner_h3_sysctrl_class_init, 133}; 134 135static void allwinner_h3_sysctrl_register(void) 136{ 137 type_register_static(&allwinner_h3_sysctrl_info); 138} 139 140type_init(allwinner_h3_sysctrl_register)