| #include <string.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include <endian.h> |
| #include <pmap.h> |
| #include <acpi.h> |
| |
| #include "hpet.h" |
| |
| /* The HPET likes 64bit mmreg reads and writes. If the arch doesn't support |
| * them, then things are a little trickier. Probably just replace these with |
| * mm64 ops, and quit supporting 32 bit. */ |
| static inline void hpet_w64(uintptr_t reg, uint64_t val) |
| { |
| *((volatile uint64_t*)reg) = val; |
| } |
| |
| static inline uint64_t hpet_r64(uintptr_t reg) |
| { |
| return *((volatile uint64_t*)reg); |
| } |
| |
| struct Atable *parsehpet(struct Atable *parent, |
| char *name, uint8_t *raw, size_t rawsize) |
| { |
| /* Do we want to keep this table around? if so, we can use newtable, |
| * which allocs an Atable and puts it on a global stailq. then we |
| * return that pointer, not as an addr, but as a signal to parse code |
| * about whether or not it is safe to unmap (which we don't do anymore). |
| */ |
| struct Atable *hpet = mkatable(parent, HPET, "HPET", raw, rawsize, 0); |
| unsigned long hp_addr; |
| uint32_t evt_blk_id; |
| int nr_timers; |
| |
| assert(hpet); |
| printk("HPET table detected at %p, for %d bytes\n", raw, rawsize); |
| |
| evt_blk_id = l32get(raw + 36); |
| printd("EV BID 0x%08x\n", evt_blk_id); |
| |
| hp_addr = (unsigned long)KADDR_NOCHECK(l64get(raw + 44)); |
| |
| printd("cap/ip %p\n", hpet_r64(hp_addr + 0x00)); |
| printd("config %p\n", hpet_r64(hp_addr + 0x10)); |
| printd("irqsts %p\n", hpet_r64(hp_addr + 0x20)); |
| |
| nr_timers = ((hpet_r64(hp_addr) >> 8) & 0xf) + 1; |
| for (int i = 0; i < nr_timers; i++) |
| printd("Timer %d, config reg %p\n", i, |
| hpet_r64(hp_addr + 0x100 + 0x20 * i)); |
| /* 0x10, general config register. bottom two bits are legacy mode and |
| * global enable. turning them both off. need to do read-modify-writes |
| * to HPET registers with reserved fields.*/ |
| hpet_w64(hp_addr + 0x10, hpet_r64(hp_addr + 0x10) & ~0x3); |
| printk("Disabled the HPET timer\n"); |
| |
| return finatable_nochildren(hpet); |
| } |
| |
| void cmos_dumping_ground() |
| { |
| uint8_t cmos_b; |
| |
| /* this stuff tries to turn off various cmos / RTC timer bits. keeping |
| * around if we need to disable the RTC alarm. note that the HPET |
| * replaces the RTC periodic function (where available), and in those |
| * cases the RTC alarm function is implemented with SMM. */ |
| outb(0x70, 0xb); |
| cmos_b = inb(0x71); |
| printk("cmos b 0x%02x\n", cmos_b); |
| |
| cmos_b &= ~((1 << 5) | (1 << 6)); |
| outb(0x70, 0xb); |
| outb(0x71, cmos_b); |
| |
| outb(0x70, 0xb); |
| cmos_b = inb(0x71); |
| printk("cmos b 0x%02x\n", cmos_b); |
| } |