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 "vl.h" 11 #include "arm_pic.h" 12 13 #define LOCK_VALUE 0xa05f 14 15 typedef struct { 16 uint32_t base; 17 uint32_t sys_id; 18 uint32_t leds; 19 uint16_t lockval; 20 uint32_t cfgdata1; 21 uint32_t cfgdata2; 22 uint32_t flags; 23 uint32_t nvflags; 24 uint32_t resetlevel; 25 } arm_sysctl_state; 26 27 static uint32_t arm_sysctl_read(void *opaque, target_phys_addr_t offset) 28 { 29 arm_sysctl_state *s = (arm_sysctl_state *)opaque; 30 31 offset -= s->base; 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 offset -= s->base; 111 112 switch (offset) { 113 case 0x08: /* LED */ 114 s->leds = val; 115 case 0x0c: /* OSC0 */ 116 case 0x10: /* OSC1 */ 117 case 0x14: /* OSC2 */ 118 case 0x18: /* OSC3 */ 119 case 0x1c: /* OSC4 */ 120 /* ??? */ 121 break; 122 case 0x20: /* LOCK */ 123 if (val == LOCK_VALUE) 124 s->lockval = val; 125 else 126 s->lockval = val & 0x7fff; 127 break; 128 case 0x28: /* CFGDATA1 */ 129 /* ??? Need to implement this. */ 130 s->cfgdata1 = val; 131 break; 132 case 0x2c: /* CFGDATA2 */ 133 /* ??? Need to implement this. */ 134 s->cfgdata2 = val; 135 break; 136 case 0x30: /* FLAGSSET */ 137 s->flags |= val; 138 break; 139 case 0x34: /* FLAGSCLR */ 140 s->flags &= ~val; 141 break; 142 case 0x38: /* NVFLAGSSET */ 143 s->nvflags |= val; 144 break; 145 case 0x3c: /* NVFLAGSCLR */ 146 s->nvflags &= ~val; 147 break; 148 case 0x40: /* RESETCTL */ 149 if (s->lockval == LOCK_VALUE) { 150 s->resetlevel = val; 151 if (val & 0x100) 152 qemu_system_reset_request (); 153 } 154 break; 155 case 0x44: /* PCICTL */ 156 /* nothing to do. */ 157 break; 158 case 0x4c: /* FLASH */ 159 case 0x50: /* CLCD */ 160 case 0x54: /* CLCDSER */ 161 case 0x64: /* DMAPSR0 */ 162 case 0x68: /* DMAPSR1 */ 163 case 0x6c: /* DMAPSR2 */ 164 case 0x70: /* IOSEL */ 165 case 0x74: /* PLDCTL */ 166 case 0x80: /* BUSID */ 167 case 0x84: /* PROCID0 */ 168 case 0x88: /* PROCID1 */ 169 case 0x8c: /* OSCRESET0 */ 170 case 0x90: /* OSCRESET1 */ 171 case 0x94: /* OSCRESET2 */ 172 case 0x98: /* OSCRESET3 */ 173 case 0x9c: /* OSCRESET4 */ 174 break; 175 default: 176 printf ("arm_sysctl_write: Bad register offset 0x%x\n", (int)offset); 177 return; 178 } 179 } 180 181 static CPUReadMemoryFunc *arm_sysctl_readfn[] = { 182 arm_sysctl_read, 183 arm_sysctl_read, 184 arm_sysctl_read 185 }; 186 187 static CPUWriteMemoryFunc *arm_sysctl_writefn[] = { 188 arm_sysctl_write, 189 arm_sysctl_write, 190 arm_sysctl_write 191 }; 192 193 void arm_sysctl_init(uint32_t base, uint32_t sys_id) 194 { 195 arm_sysctl_state *s; 196 int iomemtype; 197 198 s = (arm_sysctl_state *)qemu_mallocz(sizeof(arm_sysctl_state)); 199 if (!s) 200 return; 201 s->base = base; 202 s->sys_id = sys_id; 203 /* The MPcore bootloader uses these flags to start secondary CPUs. 204 We don't use a bootloader, so do this here. */ 205 s->flags = 3; 206 iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn, 207 arm_sysctl_writefn, s); 208 cpu_register_physical_memory(base, 0x00001000, iomemtype); 209 /* ??? Save/restore. */ 210 } 211 212