microblaze: linux-user support.
[qemu] / hw / arm_sysctl.c
1 /*
2  * Status and system control registers for ARM RealView/Versatile boards.
3  *
4  * Copyright (c) 2006-2007 CodeSourcery.
5  * Written by Paul Brook
6  *
7  * This code is licenced under the GPL.
8  */
9
10 #include "sysbus.h"
11 #include "primecell.h"
12 #include "sysemu.h"
13
14 #define LOCK_VALUE 0xa05f
15
16 typedef struct {
17     SysBusDevice busdev;
18     uint32_t sys_id;
19     uint32_t leds;
20     uint16_t lockval;
21     uint32_t cfgdata1;
22     uint32_t cfgdata2;
23     uint32_t flags;
24     uint32_t nvflags;
25     uint32_t resetlevel;
26 } arm_sysctl_state;
27
28 static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset)
29 {
30     arm_sysctl_state *s = (arm_sysctl_state *)opaque;
31
32     switch (offset) {
33     case 0x00: /* ID */
34         return s->sys_id;
35     case 0x04: /* SW */
36         /* General purpose hardware switches.
37            We don't have a useful way of exposing these to the user.  */
38         return 0;
39     case 0x08: /* LED */
40         return s->leds;
41     case 0x20: /* LOCK */
42         return s->lockval;
43     case 0x0c: /* OSC0 */
44     case 0x10: /* OSC1 */
45     case 0x14: /* OSC2 */
46     case 0x18: /* OSC3 */
47     case 0x1c: /* OSC4 */
48     case 0x24: /* 100HZ */
49         /* ??? Implement these.  */
50         return 0;
51     case 0x28: /* CFGDATA1 */
52         return s->cfgdata1;
53     case 0x2c: /* CFGDATA2 */
54         return s->cfgdata2;
55     case 0x30: /* FLAGS */
56         return s->flags;
57     case 0x38: /* NVFLAGS */
58         return s->nvflags;
59     case 0x40: /* RESETCTL */
60         return s->resetlevel;
61     case 0x44: /* PCICTL */
62         return 1;
63     case 0x48: /* MCI */
64         return 0;
65     case 0x4c: /* FLASH */
66         return 0;
67     case 0x50: /* CLCD */
68         return 0x1000;
69     case 0x54: /* CLCDSER */
70         return 0;
71     case 0x58: /* BOOTCS */
72         return 0;
73     case 0x5c: /* 24MHz */
74         /* ??? not implemented.  */
75         return 0;
76     case 0x60: /* MISC */
77         return 0;
78     case 0x84: /* PROCID0 */
79         /* ??? Don't know what the proper value for the core tile ID is.  */
80         return 0x02000000;
81     case 0x88: /* PROCID1 */
82         return 0xff000000;
83     case 0x64: /* DMAPSR0 */
84     case 0x68: /* DMAPSR1 */
85     case 0x6c: /* DMAPSR2 */
86     case 0x70: /* IOSEL */
87     case 0x74: /* PLDCTL */
88     case 0x80: /* BUSID */
89     case 0x8c: /* OSCRESET0 */
90     case 0x90: /* OSCRESET1 */
91     case 0x94: /* OSCRESET2 */
92     case 0x98: /* OSCRESET3 */
93     case 0x9c: /* OSCRESET4 */
94     case 0xc0: /* SYS_TEST_OSC0 */
95     case 0xc4: /* SYS_TEST_OSC1 */
96     case 0xc8: /* SYS_TEST_OSC2 */
97     case 0xcc: /* SYS_TEST_OSC3 */
98     case 0xd0: /* SYS_TEST_OSC4 */
99         return 0;
100     default:
101         printf ("arm_sysctl_read: Bad register offset 0x%x\n", (int)offset);
102         return 0;
103     }
104 }
105
106 static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
107                           uint32_t val)
108 {
109     arm_sysctl_state *s = (arm_sysctl_state *)opaque;
110
111     switch (offset) {
112     case 0x08: /* LED */
113         s->leds = val;
114     case 0x0c: /* OSC0 */
115     case 0x10: /* OSC1 */
116     case 0x14: /* OSC2 */
117     case 0x18: /* OSC3 */
118     case 0x1c: /* OSC4 */
119         /* ??? */
120         break;
121     case 0x20: /* LOCK */
122         if (val == LOCK_VALUE)
123             s->lockval = val;
124         else
125             s->lockval = val & 0x7fff;
126         break;
127     case 0x28: /* CFGDATA1 */
128         /* ??? Need to implement this.  */
129         s->cfgdata1 = val;
130         break;
131     case 0x2c: /* CFGDATA2 */
132         /* ??? Need to implement this.  */
133         s->cfgdata2 = val;
134         break;
135     case 0x30: /* FLAGSSET */
136         s->flags |= val;
137         break;
138     case 0x34: /* FLAGSCLR */
139         s->flags &= ~val;
140         break;
141     case 0x38: /* NVFLAGSSET */
142         s->nvflags |= val;
143         break;
144     case 0x3c: /* NVFLAGSCLR */
145         s->nvflags &= ~val;
146         break;
147     case 0x40: /* RESETCTL */
148         if (s->lockval == LOCK_VALUE) {
149             s->resetlevel = val;
150             if (val & 0x100)
151                 qemu_system_reset_request ();
152         }
153         break;
154     case 0x44: /* PCICTL */
155         /* nothing to do.  */
156         break;
157     case 0x4c: /* FLASH */
158     case 0x50: /* CLCD */
159     case 0x54: /* CLCDSER */
160     case 0x64: /* DMAPSR0 */
161     case 0x68: /* DMAPSR1 */
162     case 0x6c: /* DMAPSR2 */
163     case 0x70: /* IOSEL */
164     case 0x74: /* PLDCTL */
165     case 0x80: /* BUSID */
166     case 0x84: /* PROCID0 */
167     case 0x88: /* PROCID1 */
168     case 0x8c: /* OSCRESET0 */
169     case 0x90: /* OSCRESET1 */
170     case 0x94: /* OSCRESET2 */
171     case 0x98: /* OSCRESET3 */
172     case 0x9c: /* OSCRESET4 */
173         break;
174     default:
175         printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset);
176         return;
177     }
178 }
179
180 static CPUReadMemoryFunc *arm_sysctl_readfn[] = {
181    arm_sysctl_read,
182    arm_sysctl_read,
183    arm_sysctl_read
184 };
185
186 static CPUWriteMemoryFunc *arm_sysctl_writefn[] = {
187    arm_sysctl_write,
188    arm_sysctl_write,
189    arm_sysctl_write
190 };
191
192 static void arm_sysctl_init1(SysBusDevice *dev)
193 {
194     arm_sysctl_state *s = FROM_SYSBUS(arm_sysctl_state, dev);
195     int iomemtype;
196
197     s->sys_id = qdev_get_prop_int(&dev->qdev, "sys_id", 0);
198     /* The MPcore bootloader uses these flags to start secondary CPUs.
199        We don't use a bootloader, so do this here.  */
200     s->flags = 3;
201     iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn,
202                                        arm_sysctl_writefn, s);
203     sysbus_init_mmio(dev, 0x1000, iomemtype);
204     /* ??? Save/restore.  */
205 }
206
207 /* Legacy helper function.  */
208 void arm_sysctl_init(uint32_t base, uint32_t sys_id)
209 {
210     DeviceState *dev;
211
212     dev = qdev_create(NULL, "realview_sysctl");
213     qdev_set_prop_int(dev, "sys_id", sys_id);
214     qdev_init(dev);
215     sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
216 }
217
218 static void arm_sysctl_register_devices(void)
219 {
220     sysbus_register_dev("realview_sysctl", sizeof(arm_sysctl_state),
221                         arm_sysctl_init1);
222 }
223
224 device_init(arm_sysctl_register_devices)