29de9befc9
Signed-off-by: Chloe M. <chloe@mensia.org>
100 lines
2.1 KiB
C
100 lines
2.1 KiB
C
/*
|
|
* Copyright (c) 2026, Chloe M.
|
|
* Provided under the BSD-3 clause.
|
|
*
|
|
* Description: HPET driver
|
|
* Author: Chloe M.
|
|
*/
|
|
|
|
#include <machine/hpet.h>
|
|
#include <machine/hpetreg.h>
|
|
#include <drivers/acpi/tables.h>
|
|
#include <drivers/acpi/acpi.h>
|
|
#include <hal/mmio.h>
|
|
#include <mm/vmm.h>
|
|
#include <ke/knot.h>
|
|
#include <ex/trace.h>
|
|
|
|
#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(MMIOBase, 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);
|
|
}
|
|
|
|
VOID
|
|
MdHpetInit(VOID)
|
|
{
|
|
ACPI_HPET *Hpet;
|
|
UQUAD GeneralCap;
|
|
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");
|
|
}
|