embox

Форк
0
125 строк · 2.7 Кб
1
/**
2
 * @file
3
 * @brief
4
 *
5
 * @date 28.12.2012
6
 * @author Anton Bulychev
7
 */
8

9
#include <embox/unit.h>
10

11
#include <stdint.h>
12
#include <errno.h>
13

14
#include <asm/io.h>
15

16
#include <hal/ipl.h>
17
#include <hal/cpu.h>
18

19
#include <hal/clock.h>
20
#include <kernel/irq.h>
21
#include <kernel/panic.h>
22
#include <kernel/time/clock_source.h>
23
#include <kernel/time/ktime.h>
24

25
#include <module/embox/driver/interrupt/lapic.h>
26

27
#define IRQ0               0x0
28
#define LAPIC_HZ           1000     /* You can change it */
29

30
static int lapic_clock_setup(struct clock_source *cs);
31

32
static irq_return_t clock_handler(unsigned int irq_nr, void *dev_id) {
33
	clock_tick_handler(dev_id);
34
	return IRQ_HANDLED;
35
}
36

37
static struct time_event_device lapic_event_device = {
38
	.set_periodic = lapic_clock_setup,
39
	.name = "lapic clock",
40
	.irq_nr = IRQ0,
41
};
42

43
static int lapic_timer_init(struct clock_source *cs) {
44
	ipl_t ipl = ipl_save();
45

46
	if (ENOERR != irq_attach(IRQ0, clock_handler, 0, cs, "lapic")) {
47
		panic("lapic timer irq_attach failed");
48
	}
49

50
	lapic_clock_setup(NULL);
51

52
	ipl_restore(ipl);
53

54
	return ENOERR;
55
}
56

57
int lapic_clock_setup(struct clock_source *cs) {
58
	static int initialized = 0;
59
	uint32_t ticks, cpubusfreq, counter;
60
	uint8_t tmp;
61

62
	if (initialized & 0x1 << cpu_get_id()) {
63
		return ENOERR;
64
	}else
65
		initialized |= 0x1 << cpu_get_id();
66

67
	/*
68
	 * Map APIC timer to an interrupt, and by that enable it in
69
	 * one-shot mode.
70
	 */
71
	lapic_write(LAPIC_LVT_TR, 32);
72

73
	/* Set up divide value to 16 */
74
	lapic_write(LAPIC_TIMER_DCR, 0x03);
75

76
	/*
77
	 * Initialize PIT Ch 2 in one-shot mode.
78
	 * Waiting 1/100 sec.
79
	 */
80
	outb((inb(0x61) & 0xFD) | 1, 0x61);
81
	outb(0xB2, 0x43);
82

83
	/* 1193180/100 Hz = 11931 = 2e9bh */
84
	outb(0x9B, 0x42);	/* LSB */
85
	inb(0x60);	/* short delay */
86
	outb(0x2E, 0x42);	/* MSB */
87

88
	/* Reset PIT one-shot counter (start counting) */
89
	tmp = inb(0x61) & 0xFE;
90
	outb((uint8_t) tmp, 0x61);     /* Gate low */
91
	outb((uint8_t) tmp | 1, 0x61); /* Gate high */
92

93
	/* Reset APIC timer (set counter to -1) */
94
	lapic_write(LAPIC_TIMER_ICR, 0xFFFFFFFF);
95

96
	/* Now wait until PIT counter reaches zero */
97
	while(!(inb(0x61) & 0x20));
98

99
	/* Stop APIC timer */
100
	lapic_write(LAPIC_LVT_TR, 0x10000);
101

102
	/* Now do the math... */
103
	ticks = (0xFFFFFFFF - lapic_read(LAPIC_TIMER_CCR)) + 1;
104
	cpubusfreq = ticks * 16 * 100;
105
	counter = cpubusfreq / LAPIC_HZ / 16;
106

107
	/* Set APIC timer counter initializer */
108
	lapic_write(LAPIC_TIMER_ICR, counter < 16 ? 16 : counter);
109

110
	/* Finally re-enable timer in periodic mode. */
111
	lapic_write(LAPIC_LVT_TR, 32 | 0x20000);
112

113
#if 0
114
	/*
115
	 * Setting divide value register again not needed by the manuals
116
	 * although I have found buggy hardware that required it
117
	 */
118
	lapic_write(LAPIC_TIMER_DCR, 0x03);
119
#endif
120

121
	return ENOERR;
122
}
123

124
CLOCK_SOURCE_DEF(lapic_timer, lapic_timer_init, NULL,
125
	&lapic_event_device, NULL);
126

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.