1 /* 2 * QEMU 8253/8254 interval timer emulation 3 * 4 * Copyright (c) 2003-2004 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 #include "hw/hw.h" 25 #include "hw/i386/pc.h" 26 #include "hw/isa/isa.h" 27 #include "qemu/timer.h" 28 #include "hw/timer/i8254.h" 29 #include "hw/timer/i8254_internal.h" 30 31 //#define DEBUG_PIT 32 33 #define RW_STATE_LSB 1 34 #define RW_STATE_MSB 2 35 #define RW_STATE_WORD0 3 36 #define RW_STATE_WORD1 4 37 38 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); 39 40 static int pit_get_count(PITChannelState *s) 41 { 42 uint64_t d; 43 int counter; 44 45 d = muldiv64(qemu_get_clock_ns(vm_clock) - s->count_load_time, PIT_FREQ, 46 get_ticks_per_sec()); 47 switch(s->mode) { 48 case 0: 49 case 1: 50 case 4: 51 case 5: 52 counter = (s->count - d) & 0xffff; 53 break; 54 case 3: 55 /* XXX: may be incorrect for odd counts */ 56 counter = s->count - ((2 * d) % s->count); 57 break; 58 default: 59 counter = s->count - (d % s->count); 60 break; 61 } 62 return counter; 63 } 64 65 /* val must be 0 or 1 */ 66 static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc, 67 int val) 68 { 69 switch (sc->mode) { 70 default: 71 case 0: 72 case 4: 73 /* XXX: just disable/enable counting */ 74 break; 75 case 1: 76 case 5: 77 if (sc->gate < val) { 78 /* restart counting on rising edge */ 79 sc->count_load_time = qemu_get_clock_ns(vm_clock); 80 pit_irq_timer_update(sc, sc->count_load_time); 81 } 82 break; 83 case 2: 84 case 3: 85 if (sc->gate < val) { 86 /* restart counting on rising edge */ 87 sc->count_load_time = qemu_get_clock_ns(vm_clock); 88 pit_irq_timer_update(sc, sc->count_load_time); 89 } 90 /* XXX: disable/enable counting */ 91 break; 92 } 93 sc->gate = val; 94 } 95 96 static inline void pit_load_count(PITChannelState *s, int val) 97 { 98 if (val == 0) 99 val = 0x10000; 100 s->count_load_time = qemu_get_clock_ns(vm_clock); 101 s->count = val; 102 pit_irq_timer_update(s, s->count_load_time); 103 } 104 105 /* if already latched, do not latch again */ 106 static void pit_latch_count(PITChannelState *s) 107 { 108 if (!s->count_latched) { 109 s->latched_count = pit_get_count(s); 110 s->count_latched = s->rw_mode; 111 } 112 } 113 114 static void pit_ioport_write(void *opaque, hwaddr addr, 115 uint64_t val, unsigned size) 116 { 117 PITCommonState *pit = opaque; 118 int channel, access; 119 PITChannelState *s; 120 121 addr &= 3; 122 if (addr == 3) { 123 channel = val >> 6; 124 if (channel == 3) { 125 /* read back command */ 126 for(channel = 0; channel < 3; channel++) { 127 s = &pit->channels[channel]; 128 if (val & (2 << channel)) { 129 if (!(val & 0x20)) { 130 pit_latch_count(s); 131 } 132 if (!(val & 0x10) && !s->status_latched) { 133 /* status latch */ 134 /* XXX: add BCD and null count */ 135 s->status = 136 (pit_get_out(s, 137 qemu_get_clock_ns(vm_clock)) << 7) | 138 (s->rw_mode << 4) | 139 (s->mode << 1) | 140 s->bcd; 141 s->status_latched = 1; 142 } 143 } 144 } 145 } else { 146 s = &pit->channels[channel]; 147 access = (val >> 4) & 3; 148 if (access == 0) { 149 pit_latch_count(s); 150 } else { 151 s->rw_mode = access; 152 s->read_state = access; 153 s->write_state = access; 154 155 s->mode = (val >> 1) & 7; 156 s->bcd = val & 1; 157 /* XXX: update irq timer ? */ 158 } 159 } 160 } else { 161 s = &pit->channels[addr]; 162 switch(s->write_state) { 163 default: 164 case RW_STATE_LSB: 165 pit_load_count(s, val); 166 break; 167 case RW_STATE_MSB: 168 pit_load_count(s, val << 8); 169 break; 170 case RW_STATE_WORD0: 171 s->write_latch = val; 172 s->write_state = RW_STATE_WORD1; 173 break; 174 case RW_STATE_WORD1: 175 pit_load_count(s, s->write_latch | (val << 8)); 176 s->write_state = RW_STATE_WORD0; 177 break; 178 } 179 } 180 } 181 182 static uint64_t pit_ioport_read(void *opaque, hwaddr addr, 183 unsigned size) 184 { 185 PITCommonState *pit = opaque; 186 int ret, count; 187 PITChannelState *s; 188 189 addr &= 3; 190 s = &pit->channels[addr]; 191 if (s->status_latched) { 192 s->status_latched = 0; 193 ret = s->status; 194 } else if (s->count_latched) { 195 switch(s->count_latched) { 196 default: 197 case RW_STATE_LSB: 198 ret = s->latched_count & 0xff; 199 s->count_latched = 0; 200 break; 201 case RW_STATE_MSB: 202 ret = s->latched_count >> 8; 203 s->count_latched = 0; 204 break; 205 case RW_STATE_WORD0: 206 ret = s->latched_count & 0xff; 207 s->count_latched = RW_STATE_MSB; 208 break; 209 } 210 } else { 211 switch(s->read_state) { 212 default: 213 case RW_STATE_LSB: 214 count = pit_get_count(s); 215 ret = count & 0xff; 216 break; 217 case RW_STATE_MSB: 218 count = pit_get_count(s); 219 ret = (count >> 8) & 0xff; 220 break; 221 case RW_STATE_WORD0: 222 count = pit_get_count(s); 223 ret = count & 0xff; 224 s->read_state = RW_STATE_WORD1; 225 break; 226 case RW_STATE_WORD1: 227 count = pit_get_count(s); 228 ret = (count >> 8) & 0xff; 229 s->read_state = RW_STATE_WORD0; 230 break; 231 } 232 } 233 return ret; 234 } 235 236 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) 237 { 238 int64_t expire_time; 239 int irq_level; 240 241 if (!s->irq_timer || s->irq_disabled) { 242 return; 243 } 244 expire_time = pit_get_next_transition_time(s, current_time); 245 irq_level = pit_get_out(s, current_time); 246 qemu_set_irq(s->irq, irq_level); 247 #ifdef DEBUG_PIT 248 printf("irq_level=%d next_delay=%f\n", 249 irq_level, 250 (double)(expire_time - current_time) / get_ticks_per_sec()); 251 #endif 252 s->next_transition_time = expire_time; 253 if (expire_time != -1) 254 qemu_mod_timer(s->irq_timer, expire_time); 255 else 256 qemu_del_timer(s->irq_timer); 257 } 258 259 static void pit_irq_timer(void *opaque) 260 { 261 PITChannelState *s = opaque; 262 263 pit_irq_timer_update(s, s->next_transition_time); 264 } 265 266 static void pit_reset(DeviceState *dev) 267 { 268 PITCommonState *pit = DO_UPCAST(PITCommonState, dev.qdev, dev); 269 PITChannelState *s; 270 271 pit_reset_common(pit); 272 273 s = &pit->channels[0]; 274 if (!s->irq_disabled) { 275 qemu_mod_timer(s->irq_timer, s->next_transition_time); 276 } 277 } 278 279 /* When HPET is operating in legacy mode, suppress the ignored timer IRQ, 280 * reenable it when legacy mode is left again. */ 281 static void pit_irq_control(void *opaque, int n, int enable) 282 { 283 PITCommonState *pit = opaque; 284 PITChannelState *s = &pit->channels[0]; 285 286 if (enable) { 287 s->irq_disabled = 0; 288 pit_irq_timer_update(s, qemu_get_clock_ns(vm_clock)); 289 } else { 290 s->irq_disabled = 1; 291 qemu_del_timer(s->irq_timer); 292 } 293 } 294 295 static const MemoryRegionOps pit_ioport_ops = { 296 .read = pit_ioport_read, 297 .write = pit_ioport_write, 298 .impl = { 299 .min_access_size = 1, 300 .max_access_size = 1, 301 }, 302 .endianness = DEVICE_LITTLE_ENDIAN, 303 }; 304 305 static void pit_post_load(PITCommonState *s) 306 { 307 PITChannelState *sc = &s->channels[0]; 308 309 if (sc->next_transition_time != -1) { 310 qemu_mod_timer(sc->irq_timer, sc->next_transition_time); 311 } else { 312 qemu_del_timer(sc->irq_timer); 313 } 314 } 315 316 static int pit_initfn(PITCommonState *pit) 317 { 318 PITChannelState *s; 319 320 s = &pit->channels[0]; 321 /* the timer 0 is connected to an IRQ */ 322 s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s); 323 qdev_init_gpio_out(&pit->dev.qdev, &s->irq, 1); 324 325 memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4); 326 327 qdev_init_gpio_in(&pit->dev.qdev, pit_irq_control, 1); 328 329 return 0; 330 } 331 332 static Property pit_properties[] = { 333 DEFINE_PROP_HEX32("iobase", PITCommonState, iobase, -1), 334 DEFINE_PROP_END_OF_LIST(), 335 }; 336 337 static void pit_class_initfn(ObjectClass *klass, void *data) 338 { 339 PITCommonClass *k = PIT_COMMON_CLASS(klass); 340 DeviceClass *dc = DEVICE_CLASS(klass); 341 342 k->init = pit_initfn; 343 k->set_channel_gate = pit_set_channel_gate; 344 k->get_channel_info = pit_get_channel_info_common; 345 k->post_load = pit_post_load; 346 dc->reset = pit_reset; 347 dc->props = pit_properties; 348 } 349 350 static const TypeInfo pit_info = { 351 .name = "isa-pit", 352 .parent = TYPE_PIT_COMMON, 353 .instance_size = sizeof(PITCommonState), 354 .class_init = pit_class_initfn, 355 }; 356 357 static void pit_register_types(void) 358 { 359 type_register_static(&pit_info); 360 } 361 362 type_init(pit_register_types) 363