embox

Форк
0
150 строк · 4.2 Кб
1
/**
2
 * @file
3
 * @brief Programmable Interval Timer (PIT) chip driver
4
 *
5
 * @date 27.12.10
6
 * @author Nikolay Korotky
7
 */
8

9
#include <framework/mod/options.h>
10

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

15
#include <lib/libds/array.h>
16

17
#include <hal/clock.h>
18

19
#include <asm/io.h>
20

21
#include <kernel/irq.h>
22
#include <kernel/panic.h>
23
#include <kernel/time/clock_source.h>
24
#include <kernel/time/ktime.h>
25

26
#define INPUT_CLOCK        1193182L /* clock tick rate, Hz */
27
#define IRQ_NR             OPTION_GET(NUMBER,irq_num)
28

29
#define PIT_HZ 1000
30

31
#define PIT_LOAD ((INPUT_CLOCK + PIT_HZ / 2) / PIT_HZ)
32
static_assert(PIT_LOAD < 0x10000, "");
33

34
/**
35
 * The PIT chip uses the following I/O ports:
36
 * I/O port     Usage
37
 * 0x40         Channel 0 data port (read/write)
38
 * 0x41         Channel 1 data port (read/write)
39
 * 0x42         Channel 2 data port (read/write)
40
 * 0x43         Mode/Command register (write only, a read is ignored):
41
 * +---------------+------------+--------------+---------------+
42
 * |7             6|5          4|3            1|              0|
43
 * |Select channel |Access mode |Operating mode|BCD/Binary mode|
44
 *
45
 * Select channel:
46
 *           00 = Channel 0
47
 *           01 = Channel 1
48
 *           10 = Channel 2
49
 *           11 = Read-back command (8254 only)
50
 * Access mode:
51
 *           00 = Latch count value command
52
 *           01 = Access mode: lobyte only
53
 *           10 = Access mode: hibyte only
54
 *           11 = Access mode: lobyte/hibyte
55
 * Operating mode:
56
 *           000 = Mode 0 (interrupt on terminal count)
57
 *           001 = Mode 1 (hardware re-triggerable one-shot)
58
 *           010 = Mode 2 (rate generator)
59
 *           011 = Mode 3 (square wave generator)
60
 *           100 = Mode 4 (software triggered strobe)
61
 *           101 = Mode 5 (hardware triggered strobe)
62
 *           110 = Mode 2 (rate generator, same as 010b)
63
 *           111 = Mode 3 (square wave generator, same as 011b)
64
 * BCD/Binary mode: 0 = 16-bit binary, 1 = four-digit BCD
65
 */
66
#define CHANNEL0 0x40
67
#define CHANNEL1 0x41
68
#define CHANNEL2 0x42
69
#define MODE_REG 0x43
70

71
/* Mode register bits */
72
#define PIT_SEL0        0x00    /* select counter 0 */
73
#define PIT_SEL1        0x40    /* select counter 1 */
74
#define PIT_SEL2        0x80    /* select counter 2 */
75
#define PIT_INTTC       0x00    /* mode 0, intr on terminal cnt */
76
#define PIT_ONESHOT     0x02    /* mode 1, one shot */
77
#define PIT_RATEGEN     0x04    /* mode 2, rate generator */
78
#define PIT_SQWAVE      0x06    /* mode 3, square wave */
79
#define PIT_SWSTROBE    0x08    /* mode 4, s/w triggered strobe */
80
#define PIT_HWSTROBE    0x0a    /* mode 5, h/w triggered strobe */
81
#define PIT_LATCH       0x00    /* latch counter for reading */
82
#define PIT_LSB         0x10    /* r/w counter LSB */
83
#define PIT_MSB         0x20    /* r/w counter MSB */
84
#define PIT_16BIT       0x30    /* r/w counter 16 bits, LSB first */
85
#define PIT_BCD         0x01    /* count in BCD */
86

87
static inline void pit_out8(uint8_t val, int port) {
88
	out8(val, port);
89
}
90

91
static inline uint8_t pit_in8(int port) {
92
	return in8(port);
93
}
94

95
static cycle_t i8253_read(struct clock_source *cs) {
96
	unsigned char lsb, msb;
97

98
	irq_lock();
99
	{
100
		pit_out8(PIT_SEL0 | PIT_LATCH, MODE_REG);
101
		lsb = pit_in8(CHANNEL0);
102
		msb = pit_in8(CHANNEL0);
103
	}
104
	irq_unlock();
105

106
	return PIT_LOAD - ((msb << 8) | lsb);
107
}
108

109
static irq_return_t clock_handler(unsigned int irq_nr, void *dev_id) {
110
	clock_tick_handler(dev_id);
111
	return IRQ_HANDLED;
112
}
113

114
static int pit_clock_setup(struct clock_source *cs) {
115
	uint16_t divisor = PIT_LOAD;
116

117
	/* Propose switch by all modes in future */
118
	/* Set control byte */
119
	pit_out8(PIT_SEL0 | PIT_16BIT | PIT_RATEGEN, MODE_REG);
120

121
	/* Send divisor */
122
	pit_out8(divisor & 0xFF, CHANNEL0);
123
	pit_out8(divisor >> 8, CHANNEL0);
124

125
	return ENOERR;
126
}
127

128
static struct time_event_device pit_event_device = {
129
	.set_periodic = pit_clock_setup,
130
	.irq_nr = IRQ_NR,
131
};
132

133
static struct time_counter_device pit_counter_device = {
134
	.read = i8253_read,
135
	.cycle_hz = INPUT_CLOCK,
136
	.mask = 0xffff,
137
};
138

139
static int pit_clock_init(struct clock_source *cs) {
140
	pit_clock_setup(NULL);
141

142
	if (ENOERR != irq_attach(IRQ_NR, clock_handler, 0, cs, "PIT")) {
143
		panic("pit timer irq_attach failed");
144
	}
145

146
	return ENOERR;
147
}
148

149
CLOCK_SOURCE_DEF(pit, pit_clock_init, NULL,
150
	&pit_event_device, &pit_counter_device);
151

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

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

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

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