111 lines
4.0 KiB
C
111 lines
4.0 KiB
C
//
|
|
// Created by rick on 9/22/19.
|
|
//
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <myke/cpu/pit.h>
|
|
#include <myke/drivers/ports.h>
|
|
#include <myke/cpu/isr.h>
|
|
#include <myke/libk/libk.h>
|
|
#include <myke/libk/kprint.h>
|
|
#include <myke/tasks/task.h>
|
|
|
|
// https://wiki.osdev.org/PIT
|
|
#define PIT_MODE_BIN_BCD (1 << 0)
|
|
#define PIT_MODE_BIN (0 << 0)
|
|
#define PIT_MODE_BCD (1 << 0)
|
|
#define PIT_GENERATOR_MODE (0b111 << 1)
|
|
#define PIT_MODE_INTERRUPT_ON_TERMINAL_COUNT (0b000 << 1)
|
|
#define PIT_MODE_HARDWARE_RETRIGGERABLE_ONE_SHOT (0b001 << 1)
|
|
#define PIT_MODE_HARDWARE_RATE_GENERATOR (0b010 << 1)
|
|
#define PIT_MODE_HARDWARE_SQUARE_WAVE_GENERATOR (0b011 << 1)
|
|
#define PIT_MODE_SOFTWARE_TRIGGERED_STROBE (0b100 << 1)
|
|
#define PIT_MODE_HARDWARE_TRIGGERED_STROBE (0b101 << 1)
|
|
#define PIT_ACCESS_MODE (0b11 << 4)
|
|
#define PIT_ACCESS_MODE_LATCH_COUNT (0b00 << 4)
|
|
#define PIT_ACCESS_MODE_L (0b01 << 4)
|
|
#define PIT_ACCESS_MODE_H (0b10 << 4)
|
|
#define PIT_ACCESS_MODE_LH (0b11 << 4)
|
|
#define PIT_CHANNEL (0b11 << 6)
|
|
#define PIT_CHANNEL_0 (0b00 << 6)
|
|
#define PIT_CHANNEL_1 (0b01 << 6)
|
|
#define PIT_CHANNEL_2 (0b10 << 6)
|
|
#define PIT_CHANNEL_READ_BACK (0b11 << 6)
|
|
#define PIT_RB_LATCH_COUNT (0)
|
|
#define PIT_RB_LATCH_NO_COUNT (1 << 5)
|
|
#define PIT_RB_LATCH_STATUS (0)
|
|
#define PIT_RB_LATCH_NO_STATUS (1 << 4)
|
|
#define PIT_RB_CHANNEL_2 (1 << 3)
|
|
#define PIT_RB_CHANNEL_1 (1 << 2)
|
|
#define PIT_RB_CHANNEL_0 (1 << 1)
|
|
#define PIT_STATUS_OUTPUT_STATE (1 << 7)
|
|
#define PIT_STATUS_NULL_COUNT (1 << 6)
|
|
#define PIT_STATUS_ACCESS_MODE (0b11 >> 4)
|
|
#define PIT_STATUS_OPERATING_MODE (0b111 < 1)
|
|
#define PIT_STATUS_BCD_BIN (1)
|
|
|
|
#define PIT_FREQUENCY 1193182 /*Hz*/
|
|
uint32_t tick = 0;
|
|
|
|
uint32_t pit_ms_to_div(uint32_t ms) {
|
|
uint32_t divisor = PIT_FREQUENCY / ms;
|
|
return divisor;
|
|
}
|
|
|
|
static void pit_callback(isr_registers_t *regs) {
|
|
tick++;
|
|
task_switch_next();
|
|
}
|
|
|
|
uint32_t pit_get_tick() {
|
|
return tick;
|
|
}
|
|
|
|
void pit_sleep(uint32_t milliseconds) {
|
|
uint32_t done = tick + milliseconds;
|
|
while (tick != done) {
|
|
k_wait_for_interrupt();
|
|
}
|
|
}
|
|
|
|
void print_current_tick() {
|
|
char msg[32];
|
|
memset(msg, 0, 32);
|
|
itoa(tick, msg, 10);
|
|
kprint(msg);
|
|
kprint("\n");
|
|
}
|
|
|
|
int pit_int_frequency(uint32_t freq) {
|
|
register_interrupt_handler(IRQ0, pit_callback);
|
|
|
|
uint32_t divisor = PIT_FREQUENCY / freq;
|
|
uint8_t low = (uint8_t) (divisor & 0xFF);
|
|
uint8_t high = (uint8_t) ((divisor >> 8) & 0xFF);
|
|
port_byte_out(PORT_PIT_COMMAND,
|
|
PIT_MODE_BIN | PIT_MODE_HARDWARE_SQUARE_WAVE_GENERATOR | PIT_ACCESS_MODE_LH | PIT_CHANNEL_0);
|
|
port_byte_out(PORT_PIT_DATA_0, low);
|
|
port_byte_out(PORT_PIT_DATA_0, high);
|
|
return 0;
|
|
}
|
|
|
|
// pit_sleep without interrupts
|
|
void pit_sleep_ms(const uint32_t sleep) {
|
|
// todo locking
|
|
uint32_t divider = pit_ms_to_div(sleep);
|
|
if (divider > UINT16_MAX) {
|
|
k_panics("Sleep for to long");
|
|
}
|
|
port_byte_out(PORT_PIT_COMMAND,
|
|
PIT_MODE_BIN | PIT_MODE_INTERRUPT_ON_TERMINAL_COUNT | PIT_ACCESS_MODE_LH | PIT_CHANNEL_0);
|
|
port_byte_out(PORT_PIT_DATA_0, divider & 0xFF);
|
|
port_byte_out(PORT_PIT_DATA_0, divider >> 8);
|
|
do {
|
|
__builtin_ia32_pause();
|
|
port_byte_out(PORT_PIT_COMMAND,
|
|
PIT_CHANNEL_READ_BACK | PIT_RB_CHANNEL_0 | PIT_RB_LATCH_NO_COUNT | PIT_RB_LATCH_STATUS);
|
|
} while (port_byte_in(PORT_PIT_DATA_0) & PIT_STATUS_OUTPUT_STATE);
|
|
}
|