1 /* 2 * SuperH Timer modules. 3 * 4 * Copyright (c) 2007 Magnus Damm 5 * Based on arm_timer.c by Paul Brook 6 * Copyright (c) 2005-2006 CodeSourcery. 7 * 8 * This code is licenced under the GPL. 9 */ 10 11 #include "hw.h" 12 #include "sh.h" 13 #include "qemu-timer.h" 14 15 //#define DEBUG_TIMER 16 17 #define TIMER_TCR_TPSC (7 << 0) 18 #define TIMER_TCR_CKEG (3 << 3) 19 #define TIMER_TCR_UNIE (1 << 5) 20 #define TIMER_TCR_ICPE (3 << 6) 21 #define TIMER_TCR_UNF (1 << 8) 22 #define TIMER_TCR_ICPF (1 << 9) 23 #define TIMER_TCR_RESERVED (0x3f << 10) 24 25 #define TIMER_FEAT_CAPT (1 << 0) 26 #define TIMER_FEAT_EXTCLK (1 << 1) 27 28 typedef struct { 29 ptimer_state *timer; 30 uint32_t tcnt; 31 uint32_t tcor; 32 uint32_t tcr; 33 uint32_t tcpr; 34 int freq; 35 int int_level; 36 int old_level; 37 int feat; 38 int enabled; 39 qemu_irq irq; 40 } sh_timer_state; 41 42 /* Check all active timers, and schedule the next timer interrupt. */ 43 44 static void sh_timer_update(sh_timer_state *s) 45 { 46 int new_level = s->int_level && (s->tcr & TIMER_TCR_UNIE); 47 48 if (new_level != s->old_level) 49 qemu_set_irq (s->irq, new_level); 50 51 s->old_level = s->int_level; 52 s->int_level = new_level; 53 } 54 55 static uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) 56 { 57 sh_timer_state *s = (sh_timer_state *)opaque; 58 59 switch (offset >> 2) { 60 case 0: 61 return s->tcor; 62 case 1: 63 return ptimer_get_count(s->timer); 64 case 2: 65 return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0); 66 case 3: 67 if (s->feat & TIMER_FEAT_CAPT) 68 return s->tcpr; 69 default: 70 cpu_abort (cpu_single_env, "sh_timer_read: Bad offset %x\n", 71 (int)offset); 72 return 0; 73 } 74 } 75 76 static void sh_timer_write(void *opaque, target_phys_addr_t offset, 77 uint32_t value) 78 { 79 sh_timer_state *s = (sh_timer_state *)opaque; 80 int freq; 81 82 switch (offset >> 2) { 83 case 0: 84 s->tcor = value; 85 ptimer_set_limit(s->timer, s->tcor, 0); 86 break; 87 case 1: 88 s->tcnt = value; 89 ptimer_set_count(s->timer, s->tcnt); 90 break; 91 case 2: 92 if (s->enabled) { 93 /* Pause the timer if it is running. This may cause some 94 inaccuracy dure to rounding, but avoids a whole lot of other 95 messyness. */ 96 ptimer_stop(s->timer); 97 } 98 freq = s->freq; 99 /* ??? Need to recalculate expiry time after changing divisor. */ 100 switch (value & TIMER_TCR_TPSC) { 101 case 0: freq >>= 2; break; 102 case 1: freq >>= 4; break; 103 case 2: freq >>= 6; break; 104 case 3: freq >>= 8; break; 105 case 4: freq >>= 10; break; 106 case 6: 107 case 7: if (s->feat & TIMER_FEAT_EXTCLK) break; 108 default: cpu_abort (cpu_single_env, 109 "sh_timer_write: Reserved TPSC value\n"); break; 110 } 111 switch ((value & TIMER_TCR_CKEG) >> 3) { 112 case 0: break; 113 case 1: 114 case 2: 115 case 3: if (s->feat & TIMER_FEAT_EXTCLK) break; 116 default: cpu_abort (cpu_single_env, 117 "sh_timer_write: Reserved CKEG value\n"); break; 118 } 119 switch ((value & TIMER_TCR_ICPE) >> 6) { 120 case 0: break; 121 case 2: 122 case 3: if (s->feat & TIMER_FEAT_CAPT) break; 123 default: cpu_abort (cpu_single_env, 124 "sh_timer_write: Reserved ICPE value\n"); break; 125 } 126 if ((value & TIMER_TCR_UNF) == 0) 127 s->int_level = 0; 128 129 value &= ~TIMER_TCR_UNF; 130 131 if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) 132 cpu_abort (cpu_single_env, 133 "sh_timer_write: Reserved ICPF value\n"); 134 135 value &= ~TIMER_TCR_ICPF; /* capture not supported */ 136 137 if (value & TIMER_TCR_RESERVED) 138 cpu_abort (cpu_single_env, 139 "sh_timer_write: Reserved TCR bits set\n"); 140 s->tcr = value; 141 ptimer_set_limit(s->timer, s->tcor, 0); 142 ptimer_set_freq(s->timer, freq); 143 if (s->enabled) { 144 /* Restart the timer if still enabled. */ 145 ptimer_run(s->timer, 0); 146 } 147 break; 148 case 3: 149 if (s->feat & TIMER_FEAT_CAPT) { 150 s->tcpr = value; 151 break; 152 } 153 default: 154 cpu_abort (cpu_single_env, "sh_timer_write: Bad offset %x\n", 155 (int)offset); 156 } 157 sh_timer_update(s); 158 } 159 160 static void sh_timer_start_stop(void *opaque, int enable) 161 { 162 sh_timer_state *s = (sh_timer_state *)opaque; 163 164 #ifdef DEBUG_TIMER 165 printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); 166 #endif 167 168 if (s->enabled && !enable) { 169 ptimer_stop(s->timer); 170 } 171 if (!s->enabled && enable) { 172 ptimer_run(s->timer, 0); 173 } 174 s->enabled = !!enable; 175 176 #ifdef DEBUG_TIMER 177 printf("sh_timer_start_stop done %d\n", s->enabled); 178 #endif 179 } 180 181 static void sh_timer_tick(void *opaque) 182 { 183 sh_timer_state *s = (sh_timer_state *)opaque; 184 s->int_level = s->enabled; 185 sh_timer_update(s); 186 } 187 188 static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) 189 { 190 sh_timer_state *s; 191 QEMUBH *bh; 192 193 s = (sh_timer_state *)qemu_mallocz(sizeof(sh_timer_state)); 194 s->freq = freq; 195 s->feat = feat; 196 s->tcor = 0xffffffff; 197 s->tcnt = 0xffffffff; 198 s->tcpr = 0xdeadbeef; 199 s->tcor = 0; 200 s->enabled = 0; 201 s->irq = irq; 202 203 bh = qemu_bh_new(sh_timer_tick, s); 204 s->timer = ptimer_init(bh); 205 /* ??? Save/restore. */ 206 return s; 207 } 208 209 typedef struct { 210 void *timer[3]; 211 int level[3]; 212 uint32_t tocr; 213 uint32_t tstr; 214 target_phys_addr_t base; 215 int feat; 216 } tmu012_state; 217 218 static uint32_t tmu012_read(void *opaque, target_phys_addr_t offset) 219 { 220 tmu012_state *s = (tmu012_state *)opaque; 221 222 #ifdef DEBUG_TIMER 223 printf("tmu012_read 0x%lx\n", (unsigned long) offset); 224 #endif 225 offset -= s->base; 226 227 if (offset >= 0x20) { 228 if (!(s->feat & TMU012_FEAT_3CHAN)) 229 cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", 230 (int)offset); 231 return sh_timer_read(s->timer[2], offset - 0x20); 232 } 233 234 if (offset >= 0x14) 235 return sh_timer_read(s->timer[1], offset - 0x14); 236 237 if (offset >= 0x08) 238 return sh_timer_read(s->timer[0], offset - 0x08); 239 240 if (offset == 4) 241 return s->tstr; 242 243 if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) 244 return s->tocr; 245 246 cpu_abort (cpu_single_env, "tmu012_write: Bad offset %x\n", 247 (int)offset); 248 return 0; 249 } 250 251 static void tmu012_write(void *opaque, target_phys_addr_t offset, 252 uint32_t value) 253 { 254 tmu012_state *s = (tmu012_state *)opaque; 255 256 #ifdef DEBUG_TIMER 257 printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value); 258 #endif 259 offset -= s->base; 260 261 if (offset >= 0x20) { 262 if (!(s->feat & TMU012_FEAT_3CHAN)) 263 cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", 264 (int)offset); 265 sh_timer_write(s->timer[2], offset - 0x20, value); 266 return; 267 } 268 269 if (offset >= 0x14) { 270 sh_timer_write(s->timer[1], offset - 0x14, value); 271 return; 272 } 273 274 if (offset >= 0x08) { 275 sh_timer_write(s->timer[0], offset - 0x08, value); 276 return; 277 } 278 279 if (offset == 4) { 280 sh_timer_start_stop(s->timer[0], value & (1 << 0)); 281 sh_timer_start_stop(s->timer[1], value & (1 << 1)); 282 if (s->feat & TMU012_FEAT_3CHAN) 283 sh_timer_start_stop(s->timer[2], value & (1 << 2)); 284 else 285 if (value & (1 << 2)) 286 cpu_abort (cpu_single_env, "tmu012_write: Bad channel\n"); 287 288 s->tstr = value; 289 return; 290 } 291 292 if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) { 293 s->tocr = value & (1 << 0); 294 } 295 } 296 297 static CPUReadMemoryFunc *tmu012_readfn[] = { 298 tmu012_read, 299 tmu012_read, 300 tmu012_read 301 }; 302 303 static CPUWriteMemoryFunc *tmu012_writefn[] = { 304 tmu012_write, 305 tmu012_write, 306 tmu012_write 307 }; 308 309 void tmu012_init(target_phys_addr_t base, int feat, uint32_t freq, 310 qemu_irq ch0_irq, qemu_irq ch1_irq, 311 qemu_irq ch2_irq0, qemu_irq ch2_irq1) 312 { 313 int iomemtype; 314 tmu012_state *s; 315 int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0; 316 317 s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state)); 318 s->base = base; 319 s->feat = feat; 320 s->timer[0] = sh_timer_init(freq, timer_feat, ch0_irq); 321 s->timer[1] = sh_timer_init(freq, timer_feat, ch1_irq); 322 if (feat & TMU012_FEAT_3CHAN) 323 s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT, 324 ch2_irq0); /* ch2_irq1 not supported */ 325 iomemtype = cpu_register_io_memory(0, tmu012_readfn, 326 tmu012_writefn, s); 327 cpu_register_physical_memory(base, 0x00001000, iomemtype); 328 /* ??? Save/restore. */ 329 } 330