/* * Copyright (c) 2026, Chloe M. * Provided under the BSD-3 clause. * * Description: HPET driver * Author: Chloe M. */ #include #include #include #include #include #include #include #include #include #define DTRACE(Fmt, ...) \ TRACE("[ HPET ]: " Fmt, ##__VA_ARGS__) static VOID *MMIOBase = NULL; /* * Write a 64-bit value to an HPET register * * @Register: Register to write to * @Value: Value to write */ static VOID HpetWriteq(UCHAR Register, UQUAD Value) { VOID *RegBase; if (MMIOBase == NULL) { return; } RegBase = PTR_OFFSET(MMIOBase, Register); MMIOWrite64(RegBase, Value); } /* * Read a 64-bit value from an HPET register * * @Register: Register to read from */ static UQUAD HpetReadq(UCHAR Register) { VOID *RegBase; if (MMIOBase == NULL) { return 0; } RegBase = PTR_OFFSET(MMIOBase, Register); return MMIORead64(RegBase); } USIZE MdHpetTimeUsec(VOID) { UQUAD Period, Freq, Caps; UQUAD Counter; Caps = HpetReadq(HPET_GENERAL_CAP); Period = (Caps >> HPET_PERIOD_SHIFT) & HPET_PERIOD_MASK; Freq = FSEC_PER_SECOND / Period; Counter = HpetReadq(HPET_MAIN_COUNTER); return (Counter * USEC_PER_SECOND) / Freq; } VOID MdHpetInit(VOID) { ACPI_HPET *Hpet; UQUAD GeneralCap, GeneralConf; ULONG ClkPeriod; UCHAR RevId; const ACPI_GAS *Gas; Hpet = AcpiQuery("HPET"); if (Hpet == NULL) { KeKnot( KNOT_UNBOUND_RSRC, "could not detect HPET on this platform\n" ); } /* Some informational logging */ DTRACE("detected hpet with pci vendor id : %x\n", Hpet->PciVendorId); DTRACE("counter size : %d\n", Hpet->CounterSize); DTRACE("minimum tick : %d\n", Hpet->MinimumTick); /* Obtain the MMIO base address */ Gas = &Hpet->Gas; MMIOBase = PMA_TO_VMA(Gas->Address); GeneralCap = HpetReadq(HPET_GENERAL_CAP); ClkPeriod = (GeneralCap >> HPET_PERIOD_SHIFT) & HPET_PERIOD_MASK; RevId = GeneralCap & 0xFF; DTRACE("counter clk period : %d\n", ClkPeriod); /* * Verify that the clock period and the revision ID are not * garbage values. */ if (ClkPeriod > HPET_MAX_CLK_PERIOD) KeKnot(KNOT_MISC, "hpet: bad counter clk period\n"); if (RevId == 0) KeKnot(KNOT_MISC, "hpet: bad revision id, must not be zero\n"); HpetWriteq(HPET_MAIN_COUNTER, 0); /* Enable the counter */ GeneralConf = HpetReadq(HPET_GENERAL_CONF); GeneralConf |= HPET_GCONF_EN; HpetWriteq(HPET_GENERAL_CONF, GeneralConf); }