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
mpc8544_guts_read(void * opaque,hwaddr addr,unsigned size)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
mpc8544_guts_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)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
mpc8544_guts_initfn(Object * obj)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