1 /* 2 * QEMU PowerPC MPC8544 global util pseudo-device 3 * 4 * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved. 5 * 6 * Author: Alexander Graf, <alex@csgraf.de> 7 * 8 * This is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * ***************************************************************** 14 * 15 * The documentation for this device is noted in the MPC8544 documentation, 16 * file name "MPC8544ERM.pdf". You can easily find it on the web. 17 * 18 */ 19 20 #include "qemu/osdep.h" 21 #include "qemu/log.h" 22 #include "sysemu/runstate.h" 23 #include "cpu.h" 24 #include "hw/sysbus.h" 25 #include "qom/object.h" 26 27 #define MPC8544_GUTS_MMIO_SIZE 0x1000 28 #define MPC8544_GUTS_RSTCR_RESET 0x02 29 30 #define MPC8544_GUTS_ADDR_PORPLLSR 0x00 31 REG32(GUTS_PORPLLSR, 0x00) 32 FIELD(GUTS_PORPLLSR, E500_1_RATIO, 24, 6) 33 FIELD(GUTS_PORPLLSR, E500_0_RATIO, 16, 6) 34 FIELD(GUTS_PORPLLSR, DDR_RATIO, 9, 5) 35 FIELD(GUTS_PORPLLSR, PLAT_RATIO, 1, 5) 36 37 #define MPC8544_GUTS_ADDR_PORBMSR 0x04 38 #define MPC8544_GUTS_ADDR_PORIMPSCR 0x08 39 #define MPC8544_GUTS_ADDR_PORDEVSR 0x0C 40 #define MPC8544_GUTS_ADDR_PORDBGMSR 0x10 41 #define MPC8544_GUTS_ADDR_PORDEVSR2 0x14 42 #define MPC8544_GUTS_ADDR_GPPORCR 0x20 43 #define MPC8544_GUTS_ADDR_GPIOCR 0x30 44 #define MPC8544_GUTS_ADDR_GPOUTDR 0x40 45 #define MPC8544_GUTS_ADDR_GPINDR 0x50 46 #define MPC8544_GUTS_ADDR_PMUXCR 0x60 47 #define MPC8544_GUTS_ADDR_DEVDISR 0x70 48 #define MPC8544_GUTS_ADDR_POWMGTCSR 0x80 49 #define MPC8544_GUTS_ADDR_MCPSUMR 0x90 50 #define MPC8544_GUTS_ADDR_RSTRSCR 0x94 51 #define MPC8544_GUTS_ADDR_PVR 0xA0 52 #define MPC8544_GUTS_ADDR_SVR 0xA4 53 #define MPC8544_GUTS_ADDR_RSTCR 0xB0 54 #define MPC8544_GUTS_ADDR_IOVSELSR 0xC0 55 #define MPC8544_GUTS_ADDR_DDRCSR 0xB20 56 #define MPC8544_GUTS_ADDR_DDRCDR 0xB24 57 #define MPC8544_GUTS_ADDR_DDRCLKDR 0xB28 58 #define MPC8544_GUTS_ADDR_CLKOCR 0xE00 59 #define MPC8544_GUTS_ADDR_SRDS1CR1 0xF04 60 #define MPC8544_GUTS_ADDR_SRDS2CR1 0xF10 61 #define MPC8544_GUTS_ADDR_SRDS2CR3 0xF18 62 63 #define TYPE_MPC8544_GUTS "mpc8544-guts" 64 OBJECT_DECLARE_SIMPLE_TYPE(GutsState, MPC8544_GUTS) 65 66 struct GutsState { 67 /*< private >*/ 68 SysBusDevice parent_obj; 69 /*< public >*/ 70 71 MemoryRegion iomem; 72 }; 73 74 75 static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr, 76 unsigned size) 77 { 78 uint32_t value = 0; 79 CPUPPCState *env = cpu_env(current_cpu); 80 81 addr &= MPC8544_GUTS_MMIO_SIZE - 1; 82 switch (addr) { 83 case MPC8544_GUTS_ADDR_PORPLLSR: 84 value = FIELD_DP32(value, GUTS_PORPLLSR, E500_1_RATIO, 6); /* 3:1 */ 85 value = FIELD_DP32(value, GUTS_PORPLLSR, E500_0_RATIO, 6); /* 3:1 */ 86 value = FIELD_DP32(value, GUTS_PORPLLSR, DDR_RATIO, 12); /* 12:1 */ 87 value = FIELD_DP32(value, GUTS_PORPLLSR, PLAT_RATIO, 6); /* 6:1 */ 88 break; 89 case MPC8544_GUTS_ADDR_PVR: 90 value = env->spr[SPR_PVR]; 91 break; 92 case MPC8544_GUTS_ADDR_SVR: 93 value = env->spr[SPR_E500_SVR]; 94 break; 95 default: 96 qemu_log_mask(LOG_GUEST_ERROR, 97 "%s: Unknown register 0x%" HWADDR_PRIx "\n", 98 __func__, addr); 99 break; 100 } 101 102 return value; 103 } 104 105 static void mpc8544_guts_write(void *opaque, hwaddr addr, 106 uint64_t value, unsigned size) 107 { 108 addr &= MPC8544_GUTS_MMIO_SIZE - 1; 109 110 switch (addr) { 111 case MPC8544_GUTS_ADDR_RSTCR: 112 if (value & MPC8544_GUTS_RSTCR_RESET) { 113 qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 114 } 115 break; 116 default: 117 qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown register 0x%" HWADDR_PRIx 118 " = 0x%" PRIx64 "\n", __func__, addr, value); 119 break; 120 } 121 } 122 123 static const MemoryRegionOps mpc8544_guts_ops = { 124 .read = mpc8544_guts_read, 125 .write = mpc8544_guts_write, 126 .endianness = DEVICE_BIG_ENDIAN, 127 .valid = { 128 .min_access_size = 4, 129 .max_access_size = 4, 130 }, 131 }; 132 133 static void mpc8544_guts_initfn(Object *obj) 134 { 135 SysBusDevice *d = SYS_BUS_DEVICE(obj); 136 GutsState *s = MPC8544_GUTS(obj); 137 138 memory_region_init_io(&s->iomem, OBJECT(s), &mpc8544_guts_ops, s, 139 "mpc8544.guts", MPC8544_GUTS_MMIO_SIZE); 140 sysbus_init_mmio(d, &s->iomem); 141 } 142 143 static const TypeInfo mpc8544_guts_types[] = { 144 { 145 .name = TYPE_MPC8544_GUTS, 146 .parent = TYPE_SYS_BUS_DEVICE, 147 .instance_size = sizeof(GutsState), 148 .instance_init = mpc8544_guts_initfn, 149 }, 150 }; 151 152 DEFINE_TYPES(mpc8544_guts_types) 153