Statistics
| Branch: | Revision:

root / hw / arm_sysctl.c @ 8bd4824a

History | View | Annotate | Download (17.6 kB)

1 5fafdf24 ths
/*
2 e69954b9 pbrook
 * Status and system control registers for ARM RealView/Versatile boards.
3 e69954b9 pbrook
 *
4 9ee6e8bb pbrook
 * Copyright (c) 2006-2007 CodeSourcery.
5 e69954b9 pbrook
 * Written by Paul Brook
6 e69954b9 pbrook
 *
7 8e31bf38 Matthew Fernandez
 * This code is licensed under the GPL.
8 e69954b9 pbrook
 */
9 e69954b9 pbrook
10 83c9f4ca Paolo Bonzini
#include "hw/hw.h"
11 1de7afc9 Paolo Bonzini
#include "qemu/timer.h"
12 71538323 Peter Maydell
#include "qemu/bitops.h"
13 83c9f4ca Paolo Bonzini
#include "hw/sysbus.h"
14 83c9f4ca Paolo Bonzini
#include "hw/primecell.h"
15 9c17d615 Paolo Bonzini
#include "sysemu/sysemu.h"
16 e69954b9 pbrook
17 e69954b9 pbrook
#define LOCK_VALUE 0xa05f
18 e69954b9 pbrook
19 e69954b9 pbrook
typedef struct {
20 82634c2d Paul Brook
    SysBusDevice busdev;
21 460d7c53 Avi Kivity
    MemoryRegion iomem;
22 242ea2c6 Peter Maydell
    qemu_irq pl110_mux_ctrl;
23 242ea2c6 Peter Maydell
24 e69954b9 pbrook
    uint32_t sys_id;
25 e69954b9 pbrook
    uint32_t leds;
26 e69954b9 pbrook
    uint16_t lockval;
27 e69954b9 pbrook
    uint32_t cfgdata1;
28 e69954b9 pbrook
    uint32_t cfgdata2;
29 e69954b9 pbrook
    uint32_t flags;
30 e69954b9 pbrook
    uint32_t nvflags;
31 e69954b9 pbrook
    uint32_t resetlevel;
32 26e92f65 Paul Brook
    uint32_t proc_id;
33 b50ff6f5 Peter Maydell
    uint32_t sys_mci;
34 34933c8c Peter Maydell
    uint32_t sys_cfgdata;
35 34933c8c Peter Maydell
    uint32_t sys_cfgctrl;
36 34933c8c Peter Maydell
    uint32_t sys_cfgstat;
37 242ea2c6 Peter Maydell
    uint32_t sys_clcd;
38 8bd4824a Peter Maydell
    uint32_t db_num_vsensors;
39 8bd4824a Peter Maydell
    uint32_t *db_voltage;
40 e69954b9 pbrook
} arm_sysctl_state;
41 e69954b9 pbrook
42 b5ad0ae7 Peter Maydell
static const VMStateDescription vmstate_arm_sysctl = {
43 b5ad0ae7 Peter Maydell
    .name = "realview_sysctl",
44 242ea2c6 Peter Maydell
    .version_id = 3,
45 b5ad0ae7 Peter Maydell
    .minimum_version_id = 1,
46 b5ad0ae7 Peter Maydell
    .fields = (VMStateField[]) {
47 b5ad0ae7 Peter Maydell
        VMSTATE_UINT32(leds, arm_sysctl_state),
48 b5ad0ae7 Peter Maydell
        VMSTATE_UINT16(lockval, arm_sysctl_state),
49 b5ad0ae7 Peter Maydell
        VMSTATE_UINT32(cfgdata1, arm_sysctl_state),
50 b5ad0ae7 Peter Maydell
        VMSTATE_UINT32(cfgdata2, arm_sysctl_state),
51 b5ad0ae7 Peter Maydell
        VMSTATE_UINT32(flags, arm_sysctl_state),
52 b5ad0ae7 Peter Maydell
        VMSTATE_UINT32(nvflags, arm_sysctl_state),
53 b5ad0ae7 Peter Maydell
        VMSTATE_UINT32(resetlevel, arm_sysctl_state),
54 34933c8c Peter Maydell
        VMSTATE_UINT32_V(sys_mci, arm_sysctl_state, 2),
55 34933c8c Peter Maydell
        VMSTATE_UINT32_V(sys_cfgdata, arm_sysctl_state, 2),
56 34933c8c Peter Maydell
        VMSTATE_UINT32_V(sys_cfgctrl, arm_sysctl_state, 2),
57 34933c8c Peter Maydell
        VMSTATE_UINT32_V(sys_cfgstat, arm_sysctl_state, 2),
58 242ea2c6 Peter Maydell
        VMSTATE_UINT32_V(sys_clcd, arm_sysctl_state, 3),
59 b5ad0ae7 Peter Maydell
        VMSTATE_END_OF_LIST()
60 b5ad0ae7 Peter Maydell
    }
61 b5ad0ae7 Peter Maydell
};
62 b5ad0ae7 Peter Maydell
63 b50ff6f5 Peter Maydell
/* The PB926 actually uses a different format for
64 b50ff6f5 Peter Maydell
 * its SYS_ID register. Fortunately the bits which are
65 b50ff6f5 Peter Maydell
 * board type on later boards are distinct.
66 b50ff6f5 Peter Maydell
 */
67 b50ff6f5 Peter Maydell
#define BOARD_ID_PB926 0x100
68 b50ff6f5 Peter Maydell
#define BOARD_ID_EB 0x140
69 b50ff6f5 Peter Maydell
#define BOARD_ID_PBA8 0x178
70 b50ff6f5 Peter Maydell
#define BOARD_ID_PBX 0x182
71 34933c8c Peter Maydell
#define BOARD_ID_VEXPRESS 0x190
72 b50ff6f5 Peter Maydell
73 b50ff6f5 Peter Maydell
static int board_id(arm_sysctl_state *s)
74 b50ff6f5 Peter Maydell
{
75 b50ff6f5 Peter Maydell
    /* Extract the board ID field from the SYS_ID register value */
76 b50ff6f5 Peter Maydell
    return (s->sys_id >> 16) & 0xfff;
77 b50ff6f5 Peter Maydell
}
78 b50ff6f5 Peter Maydell
79 be0f204a Paul Brook
static void arm_sysctl_reset(DeviceState *d)
80 be0f204a Paul Brook
{
81 1356b98d Andreas Färber
    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, SYS_BUS_DEVICE(d));
82 be0f204a Paul Brook
83 be0f204a Paul Brook
    s->leds = 0;
84 be0f204a Paul Brook
    s->lockval = 0;
85 be0f204a Paul Brook
    s->cfgdata1 = 0;
86 be0f204a Paul Brook
    s->cfgdata2 = 0;
87 be0f204a Paul Brook
    s->flags = 0;
88 be0f204a Paul Brook
    s->resetlevel = 0;
89 242ea2c6 Peter Maydell
    if (board_id(s) == BOARD_ID_VEXPRESS) {
90 242ea2c6 Peter Maydell
        /* On VExpress this register will RAZ/WI */
91 242ea2c6 Peter Maydell
        s->sys_clcd = 0;
92 242ea2c6 Peter Maydell
    } else {
93 242ea2c6 Peter Maydell
        /* All others: CLCDID 0x1f, indicating VGA */
94 242ea2c6 Peter Maydell
        s->sys_clcd = 0x1f00;
95 242ea2c6 Peter Maydell
    }
96 be0f204a Paul Brook
}
97 be0f204a Paul Brook
98 a8170e5e Avi Kivity
static uint64_t arm_sysctl_read(void *opaque, hwaddr offset,
99 460d7c53 Avi Kivity
                                unsigned size)
100 e69954b9 pbrook
{
101 e69954b9 pbrook
    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
102 e69954b9 pbrook
103 e69954b9 pbrook
    switch (offset) {
104 e69954b9 pbrook
    case 0x00: /* ID */
105 e69954b9 pbrook
        return s->sys_id;
106 e69954b9 pbrook
    case 0x04: /* SW */
107 e69954b9 pbrook
        /* General purpose hardware switches.
108 e69954b9 pbrook
           We don't have a useful way of exposing these to the user.  */
109 e69954b9 pbrook
        return 0;
110 e69954b9 pbrook
    case 0x08: /* LED */
111 e69954b9 pbrook
        return s->leds;
112 e69954b9 pbrook
    case 0x20: /* LOCK */
113 e69954b9 pbrook
        return s->lockval;
114 e69954b9 pbrook
    case 0x0c: /* OSC0 */
115 e69954b9 pbrook
    case 0x10: /* OSC1 */
116 e69954b9 pbrook
    case 0x14: /* OSC2 */
117 e69954b9 pbrook
    case 0x18: /* OSC3 */
118 e69954b9 pbrook
    case 0x1c: /* OSC4 */
119 e69954b9 pbrook
    case 0x24: /* 100HZ */
120 e69954b9 pbrook
        /* ??? Implement these.  */
121 e69954b9 pbrook
        return 0;
122 e69954b9 pbrook
    case 0x28: /* CFGDATA1 */
123 e69954b9 pbrook
        return s->cfgdata1;
124 e69954b9 pbrook
    case 0x2c: /* CFGDATA2 */
125 e69954b9 pbrook
        return s->cfgdata2;
126 e69954b9 pbrook
    case 0x30: /* FLAGS */
127 e69954b9 pbrook
        return s->flags;
128 e69954b9 pbrook
    case 0x38: /* NVFLAGS */
129 e69954b9 pbrook
        return s->nvflags;
130 e69954b9 pbrook
    case 0x40: /* RESETCTL */
131 34933c8c Peter Maydell
        if (board_id(s) == BOARD_ID_VEXPRESS) {
132 34933c8c Peter Maydell
            /* reserved: RAZ/WI */
133 34933c8c Peter Maydell
            return 0;
134 34933c8c Peter Maydell
        }
135 e69954b9 pbrook
        return s->resetlevel;
136 e69954b9 pbrook
    case 0x44: /* PCICTL */
137 e69954b9 pbrook
        return 1;
138 e69954b9 pbrook
    case 0x48: /* MCI */
139 b50ff6f5 Peter Maydell
        return s->sys_mci;
140 e69954b9 pbrook
    case 0x4c: /* FLASH */
141 e69954b9 pbrook
        return 0;
142 e69954b9 pbrook
    case 0x50: /* CLCD */
143 242ea2c6 Peter Maydell
        return s->sys_clcd;
144 e69954b9 pbrook
    case 0x54: /* CLCDSER */
145 e69954b9 pbrook
        return 0;
146 e69954b9 pbrook
    case 0x58: /* BOOTCS */
147 e69954b9 pbrook
        return 0;
148 e69954b9 pbrook
    case 0x5c: /* 24MHz */
149 74475455 Paolo Bonzini
        return muldiv64(qemu_get_clock_ns(vm_clock), 24000000, get_ticks_per_sec());
150 e69954b9 pbrook
    case 0x60: /* MISC */
151 e69954b9 pbrook
        return 0;
152 e69954b9 pbrook
    case 0x84: /* PROCID0 */
153 26e92f65 Paul Brook
        return s->proc_id;
154 e69954b9 pbrook
    case 0x88: /* PROCID1 */
155 e69954b9 pbrook
        return 0xff000000;
156 e69954b9 pbrook
    case 0x64: /* DMAPSR0 */
157 e69954b9 pbrook
    case 0x68: /* DMAPSR1 */
158 e69954b9 pbrook
    case 0x6c: /* DMAPSR2 */
159 e69954b9 pbrook
    case 0x70: /* IOSEL */
160 e69954b9 pbrook
    case 0x74: /* PLDCTL */
161 e69954b9 pbrook
    case 0x80: /* BUSID */
162 e69954b9 pbrook
    case 0x8c: /* OSCRESET0 */
163 e69954b9 pbrook
    case 0x90: /* OSCRESET1 */
164 e69954b9 pbrook
    case 0x94: /* OSCRESET2 */
165 e69954b9 pbrook
    case 0x98: /* OSCRESET3 */
166 e69954b9 pbrook
    case 0x9c: /* OSCRESET4 */
167 e69954b9 pbrook
    case 0xc0: /* SYS_TEST_OSC0 */
168 e69954b9 pbrook
    case 0xc4: /* SYS_TEST_OSC1 */
169 e69954b9 pbrook
    case 0xc8: /* SYS_TEST_OSC2 */
170 e69954b9 pbrook
    case 0xcc: /* SYS_TEST_OSC3 */
171 e69954b9 pbrook
    case 0xd0: /* SYS_TEST_OSC4 */
172 e69954b9 pbrook
        return 0;
173 34933c8c Peter Maydell
    case 0xa0: /* SYS_CFGDATA */
174 34933c8c Peter Maydell
        if (board_id(s) != BOARD_ID_VEXPRESS) {
175 34933c8c Peter Maydell
            goto bad_reg;
176 34933c8c Peter Maydell
        }
177 34933c8c Peter Maydell
        return s->sys_cfgdata;
178 34933c8c Peter Maydell
    case 0xa4: /* SYS_CFGCTRL */
179 34933c8c Peter Maydell
        if (board_id(s) != BOARD_ID_VEXPRESS) {
180 34933c8c Peter Maydell
            goto bad_reg;
181 34933c8c Peter Maydell
        }
182 34933c8c Peter Maydell
        return s->sys_cfgctrl;
183 34933c8c Peter Maydell
    case 0xa8: /* SYS_CFGSTAT */
184 34933c8c Peter Maydell
        if (board_id(s) != BOARD_ID_VEXPRESS) {
185 34933c8c Peter Maydell
            goto bad_reg;
186 34933c8c Peter Maydell
        }
187 34933c8c Peter Maydell
        return s->sys_cfgstat;
188 e69954b9 pbrook
    default:
189 34933c8c Peter Maydell
    bad_reg:
190 0c896f06 Peter Maydell
        qemu_log_mask(LOG_GUEST_ERROR,
191 0c896f06 Peter Maydell
                      "arm_sysctl_read: Bad register offset 0x%x\n",
192 0c896f06 Peter Maydell
                      (int)offset);
193 e69954b9 pbrook
        return 0;
194 e69954b9 pbrook
    }
195 e69954b9 pbrook
}
196 e69954b9 pbrook
197 71538323 Peter Maydell
/* SYS_CFGCTRL functions */
198 71538323 Peter Maydell
#define SYS_CFG_OSC 1
199 71538323 Peter Maydell
#define SYS_CFG_VOLT 2
200 71538323 Peter Maydell
#define SYS_CFG_AMP 3
201 71538323 Peter Maydell
#define SYS_CFG_TEMP 4
202 71538323 Peter Maydell
#define SYS_CFG_RESET 5
203 71538323 Peter Maydell
#define SYS_CFG_SCC 6
204 71538323 Peter Maydell
#define SYS_CFG_MUXFPGA 7
205 71538323 Peter Maydell
#define SYS_CFG_SHUTDOWN 8
206 71538323 Peter Maydell
#define SYS_CFG_REBOOT 9
207 71538323 Peter Maydell
#define SYS_CFG_DVIMODE 11
208 71538323 Peter Maydell
#define SYS_CFG_POWER 12
209 71538323 Peter Maydell
#define SYS_CFG_ENERGY 13
210 71538323 Peter Maydell
211 71538323 Peter Maydell
/* SYS_CFGCTRL site field values */
212 71538323 Peter Maydell
#define SYS_CFG_SITE_MB 0
213 71538323 Peter Maydell
#define SYS_CFG_SITE_DB1 1
214 71538323 Peter Maydell
#define SYS_CFG_SITE_DB2 2
215 71538323 Peter Maydell
216 71538323 Peter Maydell
/**
217 71538323 Peter Maydell
 * vexpress_cfgctrl_read:
218 71538323 Peter Maydell
 * @s: arm_sysctl_state pointer
219 71538323 Peter Maydell
 * @dcc, @function, @site, @position, @device: split out values from
220 71538323 Peter Maydell
 * SYS_CFGCTRL register
221 71538323 Peter Maydell
 * @val: pointer to where to put the read data on success
222 71538323 Peter Maydell
 *
223 71538323 Peter Maydell
 * Handle a VExpress SYS_CFGCTRL register read. On success, return true and
224 71538323 Peter Maydell
 * write the read value to *val. On failure, return false (and val may
225 71538323 Peter Maydell
 * or may not be written to).
226 71538323 Peter Maydell
 */
227 71538323 Peter Maydell
static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
228 71538323 Peter Maydell
                                  unsigned int function, unsigned int site,
229 71538323 Peter Maydell
                                  unsigned int position, unsigned int device,
230 71538323 Peter Maydell
                                  uint32_t *val)
231 71538323 Peter Maydell
{
232 71538323 Peter Maydell
    /* We don't support anything other than DCC 0, board stack position 0
233 71538323 Peter Maydell
     * or sites other than motherboard/daughterboard:
234 71538323 Peter Maydell
     */
235 71538323 Peter Maydell
    if (dcc != 0 || position != 0 ||
236 71538323 Peter Maydell
        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
237 71538323 Peter Maydell
        goto cfgctrl_unimp;
238 71538323 Peter Maydell
    }
239 71538323 Peter Maydell
240 71538323 Peter Maydell
    switch (function) {
241 8bd4824a Peter Maydell
    case SYS_CFG_VOLT:
242 8bd4824a Peter Maydell
        if (site == SYS_CFG_SITE_DB1 && device < s->db_num_vsensors) {
243 8bd4824a Peter Maydell
            *val = s->db_voltage[device];
244 8bd4824a Peter Maydell
            return true;
245 8bd4824a Peter Maydell
        }
246 8bd4824a Peter Maydell
        if (site == SYS_CFG_SITE_MB && device == 0) {
247 8bd4824a Peter Maydell
            /* There is only one motherboard voltage sensor:
248 8bd4824a Peter Maydell
             * VIO : 3.3V : bus voltage between mother and daughterboard
249 8bd4824a Peter Maydell
             */
250 8bd4824a Peter Maydell
            *val = 3300000;
251 8bd4824a Peter Maydell
            return true;
252 8bd4824a Peter Maydell
        }
253 8bd4824a Peter Maydell
        break;
254 71538323 Peter Maydell
    default:
255 71538323 Peter Maydell
        break;
256 71538323 Peter Maydell
    }
257 71538323 Peter Maydell
258 71538323 Peter Maydell
cfgctrl_unimp:
259 71538323 Peter Maydell
    qemu_log_mask(LOG_UNIMP,
260 71538323 Peter Maydell
                  "arm_sysctl: Unimplemented SYS_CFGCTRL read of function "
261 71538323 Peter Maydell
                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
262 71538323 Peter Maydell
                  function, dcc, site, position, device);
263 71538323 Peter Maydell
    return false;
264 71538323 Peter Maydell
}
265 71538323 Peter Maydell
266 71538323 Peter Maydell
/**
267 71538323 Peter Maydell
 * vexpress_cfgctrl_write:
268 71538323 Peter Maydell
 * @s: arm_sysctl_state pointer
269 71538323 Peter Maydell
 * @dcc, @function, @site, @position, @device: split out values from
270 71538323 Peter Maydell
 * SYS_CFGCTRL register
271 71538323 Peter Maydell
 * @val: data to write
272 71538323 Peter Maydell
 *
273 71538323 Peter Maydell
 * Handle a VExpress SYS_CFGCTRL register write. On success, return true.
274 71538323 Peter Maydell
 * On failure, return false.
275 71538323 Peter Maydell
 */
276 71538323 Peter Maydell
static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
277 71538323 Peter Maydell
                                   unsigned int function, unsigned int site,
278 71538323 Peter Maydell
                                   unsigned int position, unsigned int device,
279 71538323 Peter Maydell
                                   uint32_t val)
280 71538323 Peter Maydell
{
281 71538323 Peter Maydell
    /* We don't support anything other than DCC 0, board stack position 0
282 71538323 Peter Maydell
     * or sites other than motherboard/daughterboard:
283 71538323 Peter Maydell
     */
284 71538323 Peter Maydell
    if (dcc != 0 || position != 0 ||
285 71538323 Peter Maydell
        (site != SYS_CFG_SITE_MB && site != SYS_CFG_SITE_DB1)) {
286 71538323 Peter Maydell
        goto cfgctrl_unimp;
287 71538323 Peter Maydell
    }
288 71538323 Peter Maydell
289 71538323 Peter Maydell
    switch (function) {
290 8ff05c98 Peter Maydell
    case SYS_CFG_MUXFPGA:
291 8ff05c98 Peter Maydell
        if (site == SYS_CFG_SITE_MB && device == 0) {
292 8ff05c98 Peter Maydell
            /* Select whether video output comes from motherboard
293 8ff05c98 Peter Maydell
             * or daughterboard: log and ignore as QEMU doesn't
294 8ff05c98 Peter Maydell
             * support this.
295 8ff05c98 Peter Maydell
             */
296 8ff05c98 Peter Maydell
            qemu_log_mask(LOG_UNIMP, "arm_sysctl: selection of video output "
297 8ff05c98 Peter Maydell
                          "not supported, ignoring\n");
298 8ff05c98 Peter Maydell
            return true;
299 8ff05c98 Peter Maydell
        }
300 8ff05c98 Peter Maydell
        break;
301 71538323 Peter Maydell
    case SYS_CFG_SHUTDOWN:
302 71538323 Peter Maydell
        if (site == SYS_CFG_SITE_MB && device == 0) {
303 71538323 Peter Maydell
            qemu_system_shutdown_request();
304 71538323 Peter Maydell
            return true;
305 71538323 Peter Maydell
        }
306 71538323 Peter Maydell
        break;
307 71538323 Peter Maydell
    case SYS_CFG_REBOOT:
308 71538323 Peter Maydell
        if (site == SYS_CFG_SITE_MB && device == 0) {
309 71538323 Peter Maydell
            qemu_system_reset_request();
310 71538323 Peter Maydell
            return true;
311 71538323 Peter Maydell
        }
312 71538323 Peter Maydell
        break;
313 291155cb Peter Maydell
    case SYS_CFG_DVIMODE:
314 291155cb Peter Maydell
        if (site == SYS_CFG_SITE_MB && device == 0) {
315 291155cb Peter Maydell
            /* Selecting DVI mode is meaningless for QEMU: we will
316 291155cb Peter Maydell
             * always display the output correctly according to the
317 291155cb Peter Maydell
             * pixel height/width programmed into the CLCD controller.
318 291155cb Peter Maydell
             */
319 291155cb Peter Maydell
            return true;
320 291155cb Peter Maydell
        }
321 71538323 Peter Maydell
    default:
322 71538323 Peter Maydell
        break;
323 71538323 Peter Maydell
    }
324 71538323 Peter Maydell
325 71538323 Peter Maydell
cfgctrl_unimp:
326 71538323 Peter Maydell
    qemu_log_mask(LOG_UNIMP,
327 71538323 Peter Maydell
                  "arm_sysctl: Unimplemented SYS_CFGCTRL write of function "
328 71538323 Peter Maydell
                  "0x%x DCC 0x%x site 0x%x position 0x%x device 0x%x\n",
329 71538323 Peter Maydell
                  function, dcc, site, position, device);
330 71538323 Peter Maydell
    return false;
331 71538323 Peter Maydell
}
332 71538323 Peter Maydell
333 a8170e5e Avi Kivity
static void arm_sysctl_write(void *opaque, hwaddr offset,
334 460d7c53 Avi Kivity
                             uint64_t val, unsigned size)
335 e69954b9 pbrook
{
336 e69954b9 pbrook
    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
337 e69954b9 pbrook
338 e69954b9 pbrook
    switch (offset) {
339 e69954b9 pbrook
    case 0x08: /* LED */
340 e69954b9 pbrook
        s->leds = val;
341 bf4229d3 Peter Maydell
        break;
342 e69954b9 pbrook
    case 0x0c: /* OSC0 */
343 e69954b9 pbrook
    case 0x10: /* OSC1 */
344 e69954b9 pbrook
    case 0x14: /* OSC2 */
345 e69954b9 pbrook
    case 0x18: /* OSC3 */
346 e69954b9 pbrook
    case 0x1c: /* OSC4 */
347 e69954b9 pbrook
        /* ??? */
348 e69954b9 pbrook
        break;
349 e69954b9 pbrook
    case 0x20: /* LOCK */
350 e69954b9 pbrook
        if (val == LOCK_VALUE)
351 e69954b9 pbrook
            s->lockval = val;
352 e69954b9 pbrook
        else
353 e69954b9 pbrook
            s->lockval = val & 0x7fff;
354 e69954b9 pbrook
        break;
355 e69954b9 pbrook
    case 0x28: /* CFGDATA1 */
356 e69954b9 pbrook
        /* ??? Need to implement this.  */
357 e69954b9 pbrook
        s->cfgdata1 = val;
358 e69954b9 pbrook
        break;
359 e69954b9 pbrook
    case 0x2c: /* CFGDATA2 */
360 e69954b9 pbrook
        /* ??? Need to implement this.  */
361 e69954b9 pbrook
        s->cfgdata2 = val;
362 e69954b9 pbrook
        break;
363 e69954b9 pbrook
    case 0x30: /* FLAGSSET */
364 e69954b9 pbrook
        s->flags |= val;
365 e69954b9 pbrook
        break;
366 e69954b9 pbrook
    case 0x34: /* FLAGSCLR */
367 e69954b9 pbrook
        s->flags &= ~val;
368 e69954b9 pbrook
        break;
369 e69954b9 pbrook
    case 0x38: /* NVFLAGSSET */
370 e69954b9 pbrook
        s->nvflags |= val;
371 e69954b9 pbrook
        break;
372 e69954b9 pbrook
    case 0x3c: /* NVFLAGSCLR */
373 e69954b9 pbrook
        s->nvflags &= ~val;
374 e69954b9 pbrook
        break;
375 e69954b9 pbrook
    case 0x40: /* RESETCTL */
376 b2887c43 Jean-Christophe DUBOIS
        switch (board_id(s)) {
377 b2887c43 Jean-Christophe DUBOIS
        case BOARD_ID_PB926:
378 b2887c43 Jean-Christophe DUBOIS
            if (s->lockval == LOCK_VALUE) {
379 b2887c43 Jean-Christophe DUBOIS
                s->resetlevel = val;
380 b2887c43 Jean-Christophe DUBOIS
                if (val & 0x100) {
381 b2887c43 Jean-Christophe DUBOIS
                    qemu_system_reset_request();
382 b2887c43 Jean-Christophe DUBOIS
                }
383 b2887c43 Jean-Christophe DUBOIS
            }
384 b2887c43 Jean-Christophe DUBOIS
            break;
385 b2887c43 Jean-Christophe DUBOIS
        case BOARD_ID_PBX:
386 b2887c43 Jean-Christophe DUBOIS
        case BOARD_ID_PBA8:
387 b2887c43 Jean-Christophe DUBOIS
            if (s->lockval == LOCK_VALUE) {
388 b2887c43 Jean-Christophe DUBOIS
                s->resetlevel = val;
389 b2887c43 Jean-Christophe DUBOIS
                if (val & 0x04) {
390 b2887c43 Jean-Christophe DUBOIS
                    qemu_system_reset_request();
391 b2887c43 Jean-Christophe DUBOIS
                }
392 b2887c43 Jean-Christophe DUBOIS
            }
393 b2887c43 Jean-Christophe DUBOIS
            break;
394 b2887c43 Jean-Christophe DUBOIS
        case BOARD_ID_VEXPRESS:
395 b2887c43 Jean-Christophe DUBOIS
        case BOARD_ID_EB:
396 b2887c43 Jean-Christophe DUBOIS
        default:
397 34933c8c Peter Maydell
            /* reserved: RAZ/WI */
398 34933c8c Peter Maydell
            break;
399 34933c8c Peter Maydell
        }
400 e69954b9 pbrook
        break;
401 e69954b9 pbrook
    case 0x44: /* PCICTL */
402 e69954b9 pbrook
        /* nothing to do.  */
403 e69954b9 pbrook
        break;
404 e69954b9 pbrook
    case 0x4c: /* FLASH */
405 242ea2c6 Peter Maydell
        break;
406 e69954b9 pbrook
    case 0x50: /* CLCD */
407 242ea2c6 Peter Maydell
        switch (board_id(s)) {
408 242ea2c6 Peter Maydell
        case BOARD_ID_PB926:
409 242ea2c6 Peter Maydell
            /* On 926 bits 13:8 are R/O, bits 1:0 control
410 242ea2c6 Peter Maydell
             * the mux that defines how to interpret the PL110
411 242ea2c6 Peter Maydell
             * graphics format, and other bits are r/w but we
412 242ea2c6 Peter Maydell
             * don't implement them to do anything.
413 242ea2c6 Peter Maydell
             */
414 242ea2c6 Peter Maydell
            s->sys_clcd &= 0x3f00;
415 242ea2c6 Peter Maydell
            s->sys_clcd |= val & ~0x3f00;
416 242ea2c6 Peter Maydell
            qemu_set_irq(s->pl110_mux_ctrl, val & 3);
417 242ea2c6 Peter Maydell
            break;
418 242ea2c6 Peter Maydell
        case BOARD_ID_EB:
419 242ea2c6 Peter Maydell
            /* The EB is the same except that there is no mux since
420 242ea2c6 Peter Maydell
             * the EB has a PL111.
421 242ea2c6 Peter Maydell
             */
422 242ea2c6 Peter Maydell
            s->sys_clcd &= 0x3f00;
423 242ea2c6 Peter Maydell
            s->sys_clcd |= val & ~0x3f00;
424 242ea2c6 Peter Maydell
            break;
425 242ea2c6 Peter Maydell
        case BOARD_ID_PBA8:
426 242ea2c6 Peter Maydell
        case BOARD_ID_PBX:
427 242ea2c6 Peter Maydell
            /* On PBA8 and PBX bit 7 is r/w and all other bits
428 242ea2c6 Peter Maydell
             * are either r/o or RAZ/WI.
429 242ea2c6 Peter Maydell
             */
430 242ea2c6 Peter Maydell
            s->sys_clcd &= (1 << 7);
431 242ea2c6 Peter Maydell
            s->sys_clcd |= val & ~(1 << 7);
432 242ea2c6 Peter Maydell
            break;
433 242ea2c6 Peter Maydell
        case BOARD_ID_VEXPRESS:
434 242ea2c6 Peter Maydell
        default:
435 242ea2c6 Peter Maydell
            /* On VExpress this register is unimplemented and will RAZ/WI */
436 242ea2c6 Peter Maydell
            break;
437 242ea2c6 Peter Maydell
        }
438 bf4229d3 Peter Maydell
        break;
439 e69954b9 pbrook
    case 0x54: /* CLCDSER */
440 e69954b9 pbrook
    case 0x64: /* DMAPSR0 */
441 e69954b9 pbrook
    case 0x68: /* DMAPSR1 */
442 e69954b9 pbrook
    case 0x6c: /* DMAPSR2 */
443 e69954b9 pbrook
    case 0x70: /* IOSEL */
444 e69954b9 pbrook
    case 0x74: /* PLDCTL */
445 e69954b9 pbrook
    case 0x80: /* BUSID */
446 e69954b9 pbrook
    case 0x84: /* PROCID0 */
447 e69954b9 pbrook
    case 0x88: /* PROCID1 */
448 e69954b9 pbrook
    case 0x8c: /* OSCRESET0 */
449 e69954b9 pbrook
    case 0x90: /* OSCRESET1 */
450 e69954b9 pbrook
    case 0x94: /* OSCRESET2 */
451 e69954b9 pbrook
    case 0x98: /* OSCRESET3 */
452 e69954b9 pbrook
    case 0x9c: /* OSCRESET4 */
453 e69954b9 pbrook
        break;
454 34933c8c Peter Maydell
    case 0xa0: /* SYS_CFGDATA */
455 34933c8c Peter Maydell
        if (board_id(s) != BOARD_ID_VEXPRESS) {
456 34933c8c Peter Maydell
            goto bad_reg;
457 34933c8c Peter Maydell
        }
458 34933c8c Peter Maydell
        s->sys_cfgdata = val;
459 34933c8c Peter Maydell
        return;
460 34933c8c Peter Maydell
    case 0xa4: /* SYS_CFGCTRL */
461 34933c8c Peter Maydell
        if (board_id(s) != BOARD_ID_VEXPRESS) {
462 34933c8c Peter Maydell
            goto bad_reg;
463 34933c8c Peter Maydell
        }
464 71538323 Peter Maydell
        /* Undefined bits [19:18] are RAZ/WI, and writing to
465 71538323 Peter Maydell
         * the start bit just triggers the action; it always reads
466 71538323 Peter Maydell
         * as zero.
467 71538323 Peter Maydell
         */
468 71538323 Peter Maydell
        s->sys_cfgctrl = val & ~((3 << 18) | (1 << 31));
469 71538323 Peter Maydell
        if (val & (1 << 31)) {
470 71538323 Peter Maydell
            /* Start bit set -- actually do something */
471 71538323 Peter Maydell
            unsigned int dcc = extract32(s->sys_cfgctrl, 26, 4);
472 71538323 Peter Maydell
            unsigned int function = extract32(s->sys_cfgctrl, 20, 6);
473 71538323 Peter Maydell
            unsigned int site = extract32(s->sys_cfgctrl, 16, 2);
474 71538323 Peter Maydell
            unsigned int position = extract32(s->sys_cfgctrl, 12, 4);
475 71538323 Peter Maydell
            unsigned int device = extract32(s->sys_cfgctrl, 0, 12);
476 71538323 Peter Maydell
            s->sys_cfgstat = 1;            /* complete */
477 71538323 Peter Maydell
            if (s->sys_cfgctrl & (1 << 30)) {
478 71538323 Peter Maydell
                if (!vexpress_cfgctrl_write(s, dcc, function, site, position,
479 71538323 Peter Maydell
                                            device, s->sys_cfgdata)) {
480 71538323 Peter Maydell
                    s->sys_cfgstat |= 2;        /* error */
481 71538323 Peter Maydell
                }
482 71538323 Peter Maydell
            } else {
483 71538323 Peter Maydell
                uint32_t val;
484 71538323 Peter Maydell
                if (!vexpress_cfgctrl_read(s, dcc, function, site, position,
485 71538323 Peter Maydell
                                           device, &val)) {
486 71538323 Peter Maydell
                    s->sys_cfgstat |= 2;        /* error */
487 71538323 Peter Maydell
                } else {
488 71538323 Peter Maydell
                    s->sys_cfgdata = val;
489 71538323 Peter Maydell
                }
490 71538323 Peter Maydell
            }
491 34933c8c Peter Maydell
        }
492 706872a5 Christoffer Dall
        s->sys_cfgctrl &= ~(1 << 31);
493 34933c8c Peter Maydell
        return;
494 34933c8c Peter Maydell
    case 0xa8: /* SYS_CFGSTAT */
495 34933c8c Peter Maydell
        if (board_id(s) != BOARD_ID_VEXPRESS) {
496 34933c8c Peter Maydell
            goto bad_reg;
497 34933c8c Peter Maydell
        }
498 34933c8c Peter Maydell
        s->sys_cfgstat = val & 3;
499 34933c8c Peter Maydell
        return;
500 e69954b9 pbrook
    default:
501 34933c8c Peter Maydell
    bad_reg:
502 0c896f06 Peter Maydell
        qemu_log_mask(LOG_GUEST_ERROR,
503 0c896f06 Peter Maydell
                      "arm_sysctl_write: Bad register offset 0x%x\n",
504 0c896f06 Peter Maydell
                      (int)offset);
505 e69954b9 pbrook
        return;
506 e69954b9 pbrook
    }
507 e69954b9 pbrook
}
508 e69954b9 pbrook
509 460d7c53 Avi Kivity
static const MemoryRegionOps arm_sysctl_ops = {
510 460d7c53 Avi Kivity
    .read = arm_sysctl_read,
511 460d7c53 Avi Kivity
    .write = arm_sysctl_write,
512 460d7c53 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
513 e69954b9 pbrook
};
514 e69954b9 pbrook
515 b50ff6f5 Peter Maydell
static void arm_sysctl_gpio_set(void *opaque, int line, int level)
516 b50ff6f5 Peter Maydell
{
517 b50ff6f5 Peter Maydell
    arm_sysctl_state *s = (arm_sysctl_state *)opaque;
518 b50ff6f5 Peter Maydell
    switch (line) {
519 b50ff6f5 Peter Maydell
    case ARM_SYSCTL_GPIO_MMC_WPROT:
520 b50ff6f5 Peter Maydell
    {
521 b50ff6f5 Peter Maydell
        /* For PB926 and EB write-protect is bit 2 of SYS_MCI;
522 b50ff6f5 Peter Maydell
         * for all later boards it is bit 1.
523 b50ff6f5 Peter Maydell
         */
524 b50ff6f5 Peter Maydell
        int bit = 2;
525 b50ff6f5 Peter Maydell
        if ((board_id(s) == BOARD_ID_PB926) || (board_id(s) == BOARD_ID_EB)) {
526 b50ff6f5 Peter Maydell
            bit = 4;
527 b50ff6f5 Peter Maydell
        }
528 b50ff6f5 Peter Maydell
        s->sys_mci &= ~bit;
529 b50ff6f5 Peter Maydell
        if (level) {
530 b50ff6f5 Peter Maydell
            s->sys_mci |= bit;
531 b50ff6f5 Peter Maydell
        }
532 b50ff6f5 Peter Maydell
        break;
533 b50ff6f5 Peter Maydell
    }
534 b50ff6f5 Peter Maydell
    case ARM_SYSCTL_GPIO_MMC_CARDIN:
535 b50ff6f5 Peter Maydell
        s->sys_mci &= ~1;
536 b50ff6f5 Peter Maydell
        if (level) {
537 b50ff6f5 Peter Maydell
            s->sys_mci |= 1;
538 b50ff6f5 Peter Maydell
        }
539 b50ff6f5 Peter Maydell
        break;
540 b50ff6f5 Peter Maydell
    }
541 b50ff6f5 Peter Maydell
}
542 b50ff6f5 Peter Maydell
543 1f56f50a Peter Maydell
static void arm_sysctl_init(Object *obj)
544 e69954b9 pbrook
{
545 1f56f50a Peter Maydell
    DeviceState *dev = DEVICE(obj);
546 1f56f50a Peter Maydell
    SysBusDevice *sd = SYS_BUS_DEVICE(obj);
547 1f56f50a Peter Maydell
    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, sd);
548 e69954b9 pbrook
549 460d7c53 Avi Kivity
    memory_region_init_io(&s->iomem, &arm_sysctl_ops, s, "arm-sysctl", 0x1000);
550 1f56f50a Peter Maydell
    sysbus_init_mmio(sd, &s->iomem);
551 1f56f50a Peter Maydell
    qdev_init_gpio_in(dev, arm_sysctl_gpio_set, 2);
552 1f56f50a Peter Maydell
    qdev_init_gpio_out(dev, &s->pl110_mux_ctrl, 1);
553 e69954b9 pbrook
}
554 82634c2d Paul Brook
555 8bd4824a Peter Maydell
static void arm_sysctl_finalize(Object *obj)
556 8bd4824a Peter Maydell
{
557 8bd4824a Peter Maydell
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
558 8bd4824a Peter Maydell
    arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
559 8bd4824a Peter Maydell
    g_free(s->db_voltage);
560 8bd4824a Peter Maydell
}
561 8bd4824a Peter Maydell
562 999e12bb Anthony Liguori
static Property arm_sysctl_properties[] = {
563 999e12bb Anthony Liguori
    DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
564 999e12bb Anthony Liguori
    DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
565 8bd4824a Peter Maydell
    /* Daughterboard power supply voltages (as reported via SYS_CFG) */
566 8bd4824a Peter Maydell
    DEFINE_PROP_ARRAY("db-voltage", arm_sysctl_state, db_num_vsensors,
567 8bd4824a Peter Maydell
                      db_voltage, qdev_prop_uint32, uint32_t),
568 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
569 999e12bb Anthony Liguori
};
570 999e12bb Anthony Liguori
571 999e12bb Anthony Liguori
static void arm_sysctl_class_init(ObjectClass *klass, void *data)
572 999e12bb Anthony Liguori
{
573 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
574 999e12bb Anthony Liguori
575 39bffca2 Anthony Liguori
    dc->reset = arm_sysctl_reset;
576 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_arm_sysctl;
577 39bffca2 Anthony Liguori
    dc->props = arm_sysctl_properties;
578 999e12bb Anthony Liguori
}
579 999e12bb Anthony Liguori
580 8c43a6f0 Andreas Färber
static const TypeInfo arm_sysctl_info = {
581 39bffca2 Anthony Liguori
    .name          = "realview_sysctl",
582 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
583 39bffca2 Anthony Liguori
    .instance_size = sizeof(arm_sysctl_state),
584 1f56f50a Peter Maydell
    .instance_init = arm_sysctl_init,
585 8bd4824a Peter Maydell
    .instance_finalize = arm_sysctl_finalize,
586 39bffca2 Anthony Liguori
    .class_init    = arm_sysctl_class_init,
587 ee6847d1 Gerd Hoffmann
};
588 ee6847d1 Gerd Hoffmann
589 83f7d43a Andreas Färber
static void arm_sysctl_register_types(void)
590 82634c2d Paul Brook
{
591 39bffca2 Anthony Liguori
    type_register_static(&arm_sysctl_info);
592 82634c2d Paul Brook
}
593 82634c2d Paul Brook
594 83f7d43a Andreas Färber
type_init(arm_sysctl_register_types)