1/* @title: HPET */
2#pragma once
3#include <compiler.h>
4#include <drivers/mmio.h>
5#include <stdatomic.h>
6#include <stdbool.h>
7#include <stdint.h>
8#include <types/types.h>
9
10void hpet_init(void);
11uint64_t hpet_timestamp_ns(void);
12void hpet_program_oneshot(uint64_t future_ms);
13uint64_t hpet_timestamp_ms(void);
14uint64_t hpet_timestamp_us(void);
15
16void hpet_disable(void);
17void hpet_enable(void);
18void hpet_clear_interrupt_status(void);
19void hpet_setup_timer(uint8_t timer_index, irq_t irq_line, bool periodic,
20 bool edge_triggered);
21
22#define HPET_GEN_CAP_ID_OFFSET 0x0
23#define HPET_GEN_CONF_OFFSET 0x10
24#define HPET_GEN_INT_STAT_OFFSET 0x20
25#define HPET_IRQ_BASE 2
26#define HPET_MAIN_COUNTER_OFFSET 0xF0
27extern uint64_t *hpet_base;
28extern uint64_t hpet_timer_count;
29extern uint64_t hpet_fs_per_tick;
30
31#define HPET_TIMER_CONF_OFFSET(num) (0x100 + (num * 0x20))
32#define HPET_TIMER_COMPARATOR_OFFSET(num) (HPET_TIMER_CONF_OFFSET(num) + 0x8)
33
34/* TODO: We need to start using the HPET and figure out a caller contract */
35#define HPET_CURRENT (smp_id_raw() % hpet_timer_count)
36
37#define HPET_IRQ_LINE 2
38
39union hpet_timer_general_capabilities {
40 uint64_t raw;
41 struct {
42 uint64_t rev_id : 7; /* Revision ID */
43 uint64_t num_timers : 5; /* Number of timers */
44 uint64_t counter_size : 1; /* 0 = 32 bits wide, 1 = 64 bits wide */
45 uint64_t reserved : 1;
46 uint64_t leg_rt_cap : 1; /* Legacy replacement route capable */
47 uint64_t vendor_id : 16;
48 uint64_t counter_clock_period : 32;
49 };
50} __packed;
51
52union hpet_timer_config {
53 uint64_t raw;
54 struct {
55 uint64_t reserved0 : 1;
56 uint64_t interrupt_type : 1; /* 0 = edge, 1 = level */
57 uint64_t interrupt_enable : 1; /* 1 = interrupt enabled */
58 uint64_t type : 1; /* 0 = one-shot, 1 = periodic */
59 uint64_t periodic_capable : 1; /* read-only */
60 uint64_t size_capable : 1; /* read-only, 1 = 64-bit capable */
61 uint64_t value_set : 1;
62 uint64_t reserved1 : 1;
63 uint64_t timer_32bit : 1;
64 uint64_t ioapic_route : 5;
65 uint64_t fsb_int_enable : 1;
66 uint64_t fsb_int_delivery : 1;
67 uint64_t reserved2 : 16;
68 uint64_t route_cap : 32;
69 };
70} __packed;
71
72static inline void hpet_write64(uint64_t offset, uint64_t value) {
73 mmio_write_64(address: (void *) ((uintptr_t) hpet_base + offset), value);
74}
75
76static inline uint64_t hpet_read64(uint64_t offset) {
77 return mmio_read_64(address: (void *) ((uintptr_t) hpet_base + offset));
78}
79