add time tracking interface
[AquilaOS.git] / kernel / arch / i386 / platform / misc / pit.c
blob58532aecb06d6bdcc199b98e5ffa9c6d8f1045a9
1 #include <core/system.h>
2 #include <core/string.h>
3 #include <core/kargs.h>
4 #include <cpu/io.h>
5 #include <platform/misc.h>
7 static struct ioaddr pit_ioaddr;
9 #define PIT_CHANNEL0 0x00
10 #define PIT_CMD 0x03
12 struct pit_cmd_register {
13 union {
14 struct {
15 uint32_t bcd : 1;
16 uint32_t mode : 3;
17 uint32_t access : 2;
18 uint32_t channel: 2;
19 } __packed;
20 uint8_t raw;
21 } __packed;
22 } __packed;
24 #define PIT_MODE_RATE_GENERATOR 0x2
25 #define PIT_MODE_SQUARE_WAVE 0x3
26 #define PIT_ACCESS_LOHIBYTE 0x3
28 int x86_pit_setup(struct ioaddr *io)
30 printk("i8254: Initializing [%p (%s)]\n", io->addr, ioaddr_type_str(io));
31 pit_ioaddr = *io;
32 return 0;
35 #define FBASE 1193182ULL /* PIT Oscillator operates at 1.193182 MHz */
37 static uint32_t atou32(const char *s)
39 uint32_t ret = 0;
41 while (*s) {
42 ret = ret * 10 + (*s - '0');
43 ++s;
46 return ret;
49 uint32_t x86_pit_period_set(uint32_t period_ns)
51 printk("i8254: requested period %d ns\n", period_ns);
53 uint32_t div;
54 const char *arg_div = NULL;
56 if (!kargs_get("i8254.div", &arg_div)) {
57 div = atou32(arg_div);
58 } else {
59 div = period_ns/838UL;
62 if (div == 0) div = 1;
64 period_ns = 1000000000UL/(FBASE/div);
66 printk("i8254: Setting period to %d ns (div = %d)\n", period_ns, div);
68 struct pit_cmd_register cmd = {
69 .bcd = 0,
70 .mode = PIT_MODE_SQUARE_WAVE,
71 .access = PIT_ACCESS_LOHIBYTE,
72 .channel = 0,
75 io_out8(&pit_ioaddr, PIT_CMD, cmd.raw);
76 io_out8(&pit_ioaddr, PIT_CHANNEL0, (div >> 0) & 0xFF);
77 io_out8(&pit_ioaddr, PIT_CHANNEL0, (div >> 8) & 0xFF);
79 return period_ns;