#include <config.h>
#include <machine/io.h>
#include <arch/machine.h>
#include <arch/kernel/apic.h>
#include <arch/linker.h>
#include <plat/machine/devices.h>
#include <plat/machine/pit.h>
static BOOT_CODE uint32_t
apic_measure_freq(void)
{
pit_init();
pit_wait_wraparound();
apic_write_reg(APIC_TIMER_DIVIDE, 0xb);
apic_write_reg(APIC_TIMER_COUNT, 0xffffffff);
pit_wait_wraparound();
return (0xffffffff - apic_read_reg(APIC_TIMER_CURRENT)) / PIT_WRAPAROUND_MS;
}
BOOT_CODE paddr_t
apic_get_base_paddr(void)
{
apic_base_msr_t apic_base_msr;
apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
return apic_base_msr_get_base_addr(apic_base_msr);
}
BOOT_CODE bool_t
apic_init(bool_t mask_legacy_irqs)
{
apic_version_t apic_version;
uint32_t num_lvt_entries;
uint32_t apic_khz;
if (!apic_enable()) {
return false;
}
apic_khz = apic_measure_freq();
apic_version.words[0] = apic_read_reg(APIC_VERSION);
if (apic_version_get_version(apic_version) >> 4 != 1) {
printf("APIC: apic_version must be 0x1X\n");
return false;
}
num_lvt_entries = apic_version_get_max_lvt_entry(apic_version) + 1;
if (num_lvt_entries < 3) {
printf("APIC: number of LVT entries: %d\n", num_lvt_entries);
printf("APIC: number of LVT entries must be >= 3\n");
return false;
}
apic_write_reg(APIC_TIMER_DIVIDE, 0xb);
apic_write_reg(APIC_TIMER_COUNT, apic_khz * CONFIG_TIMER_TICK_MS);
apic_write_reg(
APIC_SVR,
apic_svr_new(
0,
1,
int_spurious
).words[0]
);
apic_write_reg(
APIC_LVT_LINT0,
apic_lvt_new(
0,
mask_legacy_irqs,
0,
0,
0,
0,
7,
0
).words[0]
);
apic_write_reg(
APIC_LVT_LINT1,
apic_lvt_new(
0,
1,
0,
0,
0,
0,
0,
0
).words[0]
);
apic_write_reg(
APIC_LVT_TIMER,
apic_lvt_new(
1,
0,
0,
0,
0,
0,
0,
int_timer
).words[0]
);
return true;
}
void apic_ack_active_interrupt(void)
{
apic_write_reg(APIC_EOI, 0);
}