xref: /openbmc/qemu/hw/ppc/mpc8544_guts.c (revision 63dc36944383f70f1c7a20f6104966d8560300fa)
1c68c4a56SPaolo Bonzini /*
2c68c4a56SPaolo Bonzini  * QEMU PowerPC MPC8544 global util pseudo-device
3c68c4a56SPaolo Bonzini  *
4c68c4a56SPaolo Bonzini  * Copyright (C) 2011 Freescale Semiconductor, Inc. All rights reserved.
5c68c4a56SPaolo Bonzini  *
6c68c4a56SPaolo Bonzini  * Author: Alexander Graf, <alex@csgraf.de>
7c68c4a56SPaolo Bonzini  *
8c68c4a56SPaolo Bonzini  * This is free software; you can redistribute it and/or modify
9c68c4a56SPaolo Bonzini  * it under the terms of  the GNU General  Public License as published by
10c68c4a56SPaolo Bonzini  * the Free Software Foundation;  either version 2 of the  License, or
11c68c4a56SPaolo Bonzini  * (at your option) any later version.
12c68c4a56SPaolo Bonzini  *
13c68c4a56SPaolo Bonzini  * *****************************************************************
14c68c4a56SPaolo Bonzini  *
15c68c4a56SPaolo Bonzini  * The documentation for this device is noted in the MPC8544 documentation,
16c68c4a56SPaolo Bonzini  * file name "MPC8544ERM.pdf". You can easily find it on the web.
17c68c4a56SPaolo Bonzini  *
18c68c4a56SPaolo Bonzini  */
19c68c4a56SPaolo Bonzini 
200d75590dSPeter Maydell #include "qemu/osdep.h"
21b3b5c5d3SCédric Le Goater #include "qemu/log.h"
2254d31236SMarkus Armbruster #include "sysemu/runstate.h"
234771d756SPaolo Bonzini #include "cpu.h"
24c68c4a56SPaolo Bonzini #include "hw/sysbus.h"
25db1015e9SEduardo Habkost #include "qom/object.h"
26c68c4a56SPaolo Bonzini 
27c68c4a56SPaolo Bonzini #define MPC8544_GUTS_MMIO_SIZE        0x1000
28c68c4a56SPaolo Bonzini #define MPC8544_GUTS_RSTCR_RESET      0x02
29c68c4a56SPaolo Bonzini 
30c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PORPLLSR    0x00
316b0cc658SBernhard Beschow REG32(GUTS_PORPLLSR, 0x00)
326b0cc658SBernhard Beschow     FIELD(GUTS_PORPLLSR, E500_1_RATIO, 24, 6)
336b0cc658SBernhard Beschow     FIELD(GUTS_PORPLLSR, E500_0_RATIO, 16, 6)
346b0cc658SBernhard Beschow     FIELD(GUTS_PORPLLSR, DDR_RATIO, 9, 5)
356b0cc658SBernhard Beschow     FIELD(GUTS_PORPLLSR, PLAT_RATIO, 1, 5)
366b0cc658SBernhard Beschow 
37c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PORBMSR     0x04
38c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PORIMPSCR   0x08
39c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PORDEVSR    0x0C
40c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PORDBGMSR   0x10
41c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PORDEVSR2   0x14
42c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_GPPORCR     0x20
43c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_GPIOCR      0x30
44c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_GPOUTDR     0x40
45c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_GPINDR      0x50
46c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PMUXCR      0x60
47c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_DEVDISR     0x70
48c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_POWMGTCSR   0x80
49c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_MCPSUMR     0x90
50c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_RSTRSCR     0x94
51c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_PVR         0xA0
52c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_SVR         0xA4
53c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_RSTCR       0xB0
54c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_IOVSELSR    0xC0
55c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_DDRCSR      0xB20
56c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_DDRCDR      0xB24
57c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_DDRCLKDR    0xB28
58c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_CLKOCR      0xE00
59c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_SRDS1CR1    0xF04
60c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_SRDS2CR1    0xF10
61c68c4a56SPaolo Bonzini #define MPC8544_GUTS_ADDR_SRDS2CR3    0xF18
62c68c4a56SPaolo Bonzini 
6343f691e9SAndreas Färber #define TYPE_MPC8544_GUTS "mpc8544-guts"
648063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(GutsState, MPC8544_GUTS)
6543f691e9SAndreas Färber 
66c68c4a56SPaolo Bonzini struct GutsState {
6743f691e9SAndreas Färber     /*< private >*/
6843f691e9SAndreas Färber     SysBusDevice parent_obj;
6943f691e9SAndreas Färber     /*< public >*/
7043f691e9SAndreas Färber 
71c68c4a56SPaolo Bonzini     MemoryRegion iomem;
72c68c4a56SPaolo Bonzini };
73c68c4a56SPaolo Bonzini 
74c68c4a56SPaolo Bonzini 
mpc8544_guts_read(void * opaque,hwaddr addr,unsigned size)75c68c4a56SPaolo Bonzini static uint64_t mpc8544_guts_read(void *opaque, hwaddr addr,
76c68c4a56SPaolo Bonzini                                   unsigned size)
77c68c4a56SPaolo Bonzini {
78c68c4a56SPaolo Bonzini     uint32_t value = 0;
79794511bcSPhilippe Mathieu-Daudé     CPUPPCState *env = cpu_env(current_cpu);
80c68c4a56SPaolo Bonzini 
81c68c4a56SPaolo Bonzini     addr &= MPC8544_GUTS_MMIO_SIZE - 1;
82c68c4a56SPaolo Bonzini     switch (addr) {
836b0cc658SBernhard Beschow     case MPC8544_GUTS_ADDR_PORPLLSR:
846b0cc658SBernhard Beschow         value = FIELD_DP32(value, GUTS_PORPLLSR, E500_1_RATIO, 6); /* 3:1 */
856b0cc658SBernhard Beschow         value = FIELD_DP32(value, GUTS_PORPLLSR, E500_0_RATIO, 6); /* 3:1 */
866b0cc658SBernhard Beschow         value = FIELD_DP32(value, GUTS_PORPLLSR, DDR_RATIO, 12); /* 12:1 */
876b0cc658SBernhard Beschow         value = FIELD_DP32(value, GUTS_PORPLLSR, PLAT_RATIO, 6); /* 6:1 */
886b0cc658SBernhard Beschow         break;
89c68c4a56SPaolo Bonzini     case MPC8544_GUTS_ADDR_PVR:
90c68c4a56SPaolo Bonzini         value = env->spr[SPR_PVR];
91c68c4a56SPaolo Bonzini         break;
92c68c4a56SPaolo Bonzini     case MPC8544_GUTS_ADDR_SVR:
93c68c4a56SPaolo Bonzini         value = env->spr[SPR_E500_SVR];
94c68c4a56SPaolo Bonzini         break;
95c68c4a56SPaolo Bonzini     default:
96b3b5c5d3SCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR,
97b3b5c5d3SCédric Le Goater                       "%s: Unknown register 0x%" HWADDR_PRIx "\n",
98b3b5c5d3SCédric Le Goater                       __func__, addr);
99c68c4a56SPaolo Bonzini         break;
100c68c4a56SPaolo Bonzini     }
101c68c4a56SPaolo Bonzini 
102c68c4a56SPaolo Bonzini     return value;
103c68c4a56SPaolo Bonzini }
104c68c4a56SPaolo Bonzini 
mpc8544_guts_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)105c68c4a56SPaolo Bonzini static void mpc8544_guts_write(void *opaque, hwaddr addr,
106c68c4a56SPaolo Bonzini                                uint64_t value, unsigned size)
107c68c4a56SPaolo Bonzini {
108c68c4a56SPaolo Bonzini     addr &= MPC8544_GUTS_MMIO_SIZE - 1;
109c68c4a56SPaolo Bonzini 
110c68c4a56SPaolo Bonzini     switch (addr) {
111c68c4a56SPaolo Bonzini     case MPC8544_GUTS_ADDR_RSTCR:
112c68c4a56SPaolo Bonzini         if (value & MPC8544_GUTS_RSTCR_RESET) {
113cf83f140SEric Blake             qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
114c68c4a56SPaolo Bonzini         }
115c68c4a56SPaolo Bonzini         break;
116c68c4a56SPaolo Bonzini     default:
117b3b5c5d3SCédric Le Goater         qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown register 0x%" HWADDR_PRIx
118b3b5c5d3SCédric Le Goater                        " = 0x%" PRIx64 "\n", __func__, addr, value);
119c68c4a56SPaolo Bonzini         break;
120c68c4a56SPaolo Bonzini     }
121c68c4a56SPaolo Bonzini }
122c68c4a56SPaolo Bonzini 
123c68c4a56SPaolo Bonzini static const MemoryRegionOps mpc8544_guts_ops = {
124c68c4a56SPaolo Bonzini     .read = mpc8544_guts_read,
125c68c4a56SPaolo Bonzini     .write = mpc8544_guts_write,
126c68c4a56SPaolo Bonzini     .endianness = DEVICE_BIG_ENDIAN,
127c68c4a56SPaolo Bonzini     .valid = {
128c68c4a56SPaolo Bonzini         .min_access_size = 4,
129c68c4a56SPaolo Bonzini         .max_access_size = 4,
130c68c4a56SPaolo Bonzini     },
131c68c4a56SPaolo Bonzini };
132c68c4a56SPaolo Bonzini 
mpc8544_guts_initfn(Object * obj)1337587ea5bSAndreas Färber static void mpc8544_guts_initfn(Object *obj)
134c68c4a56SPaolo Bonzini {
1357587ea5bSAndreas Färber     SysBusDevice *d = SYS_BUS_DEVICE(obj);
1367587ea5bSAndreas Färber     GutsState *s = MPC8544_GUTS(obj);
137c68c4a56SPaolo Bonzini 
13840c5dce9SPaolo Bonzini     memory_region_init_io(&s->iomem, OBJECT(s), &mpc8544_guts_ops, s,
1391f1a83f4SAndreas Färber                           "mpc8544.guts", MPC8544_GUTS_MMIO_SIZE);
1407587ea5bSAndreas Färber     sysbus_init_mmio(d, &s->iomem);
141c68c4a56SPaolo Bonzini }
142c68c4a56SPaolo Bonzini 
143*0ab117f0SBernhard Beschow static const TypeInfo mpc8544_guts_types[] = {
144*0ab117f0SBernhard Beschow     {
14543f691e9SAndreas Färber         .name          = TYPE_MPC8544_GUTS,
146c68c4a56SPaolo Bonzini         .parent        = TYPE_SYS_BUS_DEVICE,
147c68c4a56SPaolo Bonzini         .instance_size = sizeof(GutsState),
1487587ea5bSAndreas Färber         .instance_init = mpc8544_guts_initfn,
149*0ab117f0SBernhard Beschow     },
150c68c4a56SPaolo Bonzini };
151c68c4a56SPaolo Bonzini 
152*0ab117f0SBernhard Beschow DEFINE_TYPES(mpc8544_guts_types)
153