1 | /* |
2 | * Power Management device simulation in PKUnity SoC |
3 | * |
4 | * Copyright (C) 2010-2012 Guan Xuetao |
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 version 2 as |
8 | * published by the Free Software Foundation, or any later version. |
9 | * See the COPYING file in the top-level directory. |
10 | */ |
11 | |
12 | #include "qemu/osdep.h" |
13 | #include "hw/sysbus.h" |
14 | |
15 | #undef DEBUG_PUV3 |
16 | #include "hw/unicore32/puv3.h" |
17 | #include "qemu/module.h" |
18 | |
19 | #define TYPE_PUV3_PM "puv3_pm" |
20 | #define PUV3_PM(obj) OBJECT_CHECK(PUV3PMState, (obj), TYPE_PUV3_PM) |
21 | |
22 | typedef struct PUV3PMState { |
23 | SysBusDevice parent_obj; |
24 | |
25 | MemoryRegion iomem; |
26 | |
27 | uint32_t reg_PMCR; |
28 | uint32_t reg_PCGR; |
29 | uint32_t reg_PLL_SYS_CFG; |
30 | uint32_t reg_PLL_DDR_CFG; |
31 | uint32_t reg_PLL_VGA_CFG; |
32 | uint32_t reg_DIVCFG; |
33 | } PUV3PMState; |
34 | |
35 | static uint64_t puv3_pm_read(void *opaque, hwaddr offset, |
36 | unsigned size) |
37 | { |
38 | PUV3PMState *s = opaque; |
39 | uint32_t ret = 0; |
40 | |
41 | switch (offset) { |
42 | case 0x14: |
43 | ret = s->reg_PCGR; |
44 | break; |
45 | case 0x18: |
46 | ret = s->reg_PLL_SYS_CFG; |
47 | break; |
48 | case 0x1c: |
49 | ret = s->reg_PLL_DDR_CFG; |
50 | break; |
51 | case 0x20: |
52 | ret = s->reg_PLL_VGA_CFG; |
53 | break; |
54 | case 0x24: |
55 | ret = s->reg_DIVCFG; |
56 | break; |
57 | case 0x28: /* PLL SYS STATUS */ |
58 | ret = 0x00002401; |
59 | break; |
60 | case 0x2c: /* PLL DDR STATUS */ |
61 | ret = 0x00100c00; |
62 | break; |
63 | case 0x30: /* PLL VGA STATUS */ |
64 | ret = 0x00003801; |
65 | break; |
66 | case 0x34: /* DIV STATUS */ |
67 | ret = 0x22f52015; |
68 | break; |
69 | case 0x38: /* SW RESET */ |
70 | ret = 0x0; |
71 | break; |
72 | case 0x44: /* PLL DFC DONE */ |
73 | ret = 0x7; |
74 | break; |
75 | default: |
76 | DPRINTF("Bad offset 0x%x\n" , offset); |
77 | } |
78 | DPRINTF("offset 0x%x, value 0x%x\n" , offset, ret); |
79 | |
80 | return ret; |
81 | } |
82 | |
83 | static void puv3_pm_write(void *opaque, hwaddr offset, |
84 | uint64_t value, unsigned size) |
85 | { |
86 | PUV3PMState *s = opaque; |
87 | |
88 | switch (offset) { |
89 | case 0x0: |
90 | s->reg_PMCR = value; |
91 | break; |
92 | case 0x14: |
93 | s->reg_PCGR = value; |
94 | break; |
95 | case 0x18: |
96 | s->reg_PLL_SYS_CFG = value; |
97 | break; |
98 | case 0x1c: |
99 | s->reg_PLL_DDR_CFG = value; |
100 | break; |
101 | case 0x20: |
102 | s->reg_PLL_VGA_CFG = value; |
103 | break; |
104 | case 0x24: |
105 | case 0x38: |
106 | break; |
107 | default: |
108 | DPRINTF("Bad offset 0x%x\n" , offset); |
109 | } |
110 | DPRINTF("offset 0x%x, value 0x%x\n" , offset, value); |
111 | } |
112 | |
113 | static const MemoryRegionOps puv3_pm_ops = { |
114 | .read = puv3_pm_read, |
115 | .write = puv3_pm_write, |
116 | .impl = { |
117 | .min_access_size = 4, |
118 | .max_access_size = 4, |
119 | }, |
120 | .endianness = DEVICE_NATIVE_ENDIAN, |
121 | }; |
122 | |
123 | static void puv3_pm_realize(DeviceState *dev, Error **errp) |
124 | { |
125 | PUV3PMState *s = PUV3_PM(dev); |
126 | |
127 | s->reg_PCGR = 0x0; |
128 | |
129 | memory_region_init_io(&s->iomem, OBJECT(s), &puv3_pm_ops, s, "puv3_pm" , |
130 | PUV3_REGS_OFFSET); |
131 | sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); |
132 | } |
133 | |
134 | static void puv3_pm_class_init(ObjectClass *klass, void *data) |
135 | { |
136 | DeviceClass *dc = DEVICE_CLASS(klass); |
137 | |
138 | dc->realize = puv3_pm_realize; |
139 | } |
140 | |
141 | static const TypeInfo puv3_pm_info = { |
142 | .name = TYPE_PUV3_PM, |
143 | .parent = TYPE_SYS_BUS_DEVICE, |
144 | .instance_size = sizeof(PUV3PMState), |
145 | .class_init = puv3_pm_class_init, |
146 | }; |
147 | |
148 | static void puv3_pm_register_type(void) |
149 | { |
150 | type_register_static(&puv3_pm_info); |
151 | } |
152 | |
153 | type_init(puv3_pm_register_type) |
154 | |