embox

Форк
0
180 строк · 4.8 Кб
1
/**
2
 * @file
3
 * @brief Gaisler Research GPTIMER General Purpose Timer Unit driver.
4
 *
5
 * @date 19.11.09
6
 * @author Anton Bondarev
7
 * @author Eldar Abusalimov
8
 */
9

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

14
#include <drivers/amba_pnp.h>
15
#include <hal/clock.h>
16
#include <hal/reg.h>
17
#include <hal/system.h>
18
#include <kernel/irq.h>
19
#include <kernel/panic.h>
20
#include <kernel/time/clock_source.h>
21
#include <kernel/time/ktime.h>
22

23
#include <embox/unit.h>
24

25
#define SCALER_RELOAD (SYS_CLOCK / 1000000 - 1)
26
#define TIMER0_RELOAD (1000000 / 1000 - 1)
27

28
#define CTRL_EN (1 << 0) /**< Enable. */
29
#define CTRL_RS (1 << 1) /**< Restart. */
30
#define CTRL_LD (1 << 2) /**< Load. */
31
#define CTRL_IE (1 << 3) /**< Interrupt Enable. */
32
#define CTRL_IP (1 << 4) /**< Interrupt Pending. */
33
#define CTRL_CH (1 << 5) /**< Chain. */
34
#define CTRL_DH (1 << 6) /**< Debug Halt. */
35

36
#define CTRL_INITIAL (CTRL_EN | CTRL_RS | CTRL_LD | CTRL_IE)
37

38
#define CFG_NTIMERS(cfg_reg) (cfg_reg & 0x7)
39
#define CFG_IRQ(cfg_reg)    ((cfg_reg >> 3) & 0x1f)
40
#define CFG_SI(cfg_reg)     ((cfg_reg >> 8) & 0x1) /**< Separate interrupts. */
41

42
/**
43
 * General Purpose Timer Unit registers.
44
 */
45
struct gptimer_regs {
46
	/**
47
	 * The prescaler is clocked by the system clock and decremented on each
48
	 * clock cycle.
49
	 */
50
	/* 0x00 */uint32_t scaler_counter;
51
	/**
52
	 * When the prescaler underflows,
53
	 * it is reloaded from the prescaler reload
54
	 * register and a timer tick is generated.
55
	 */
56
	/* 0x04 */uint32_t scaler_reload;
57
	/*-------+----+----+-----+---------+
58
	 | resrv | DF | SI | IRQ | ntimers |
59
	 | 31-10 | 9  | 8  | 7-3 | 2-0     |
60
	 +-------+----+----+-----+---------*/
61
	/* 0x08 */uint32_t cfg;
62
	/* Just a place holder. */
63
	/* 0x0C */uint32_t dummy;
64
	/**
65
	 * Register sets for each implemented timer.
66
	 */
67
	struct timer_entry {
68
		/**
69
		 * Timer Counter value.
70
		 * Decremented by 1 for each prescaler tick.
71
		 */
72
		/* 0xn0 */uint32_t counter;
73
		/**
74
		 * Timer Reload value.
75
		 * This value is loaded into the timer counter
76
		 * value register when the LD bit is written to
77
		 * load bit in the timers control register or when
78
		 * the RS bit is set in the control register and the
79
		 * timer underflows.
80
		 */
81
		/* 0xn4 */uint32_t reload;
82
		/*------+----+----+----+----+----+----+----+
83
		 | resv | DH | CH | IP | IE | LD | RS | EN |
84
		 | 31-7 | 6  | 5  | 4  | 3  | 2  | 1  | 0  |
85
		 +------+----+----+----+----+----+----+----*/
86
		/* 0xn8 */uint32_t ctrl;
87
		/* Just a place holder. */
88
		/* 0xnC */uint32_t dummy;
89
	} timer[];
90
};
91

92
static volatile struct gptimer_regs *dev_regs;
93

94
static int dev_regs_init(unsigned int *irq_nr);
95

96
static struct time_event_device gptimer_ed;
97

98
static irq_return_t clock_handler(unsigned int irq_nr, void *dev_id) {
99
	// XXX clock_hander is called from arch part
100
	clock_tick_handler(dev_id);
101
	return IRQ_HANDLED;
102
}
103

104
static int gptimer_init(struct clock_source *cs) {
105
	uint32_t cfg_reg;
106
	unsigned int irq_nr;
107
	int i;
108

109
	if (NULL != dev_regs) {
110
		return 0;
111
	}
112

113
	if (0 != dev_regs_init(&irq_nr)) {
114
		panic("Unable to initialize gptimer dev_regs");
115
	}
116
	assert(NULL != dev_regs);
117

118
	gptimer_ed.irq_nr = irq_nr;
119

120
	cfg_reg = REG_LOAD(&dev_regs->cfg);
121
	for (i = 0; i < CFG_NTIMERS(cfg_reg); ++i) {
122
		REG_STORE(&dev_regs->timer[i].ctrl, 0x0);
123
	}
124

125
	REG_STORE(&dev_regs->scaler_reload, SCALER_RELOAD);
126
	REG_STORE(&dev_regs->scaler_counter, 0);
127

128
	return irq_attach(irq_nr, clock_handler, 0, cs, "gptimer");
129
}
130

131
static int gptimer_set_periodic(struct clock_source *cs);
132

133
static cycle_t gptimer_read(struct clock_source *cs) {
134
	return TIMER0_RELOAD - REG_LOAD(&dev_regs->timer[0].counter);
135
}
136

137
static struct time_event_device gptimer_ed = {
138
	.set_periodic = gptimer_set_periodic ,
139
};
140

141
static struct time_counter_device gptimer_cd = {
142
	.read = gptimer_read,
143
	.cycle_hz = 1000000,
144
};
145

146
static int gptimer_set_periodic(struct clock_source *cs) {
147
	REG_STORE(&dev_regs->timer[0].reload, TIMER0_RELOAD);
148
	REG_STORE(&dev_regs->timer[0].counter, 0);
149
	REG_STORE(&dev_regs->timer[0].ctrl, CTRL_INITIAL);
150
	return 0;
151
}
152

153
#ifdef DRIVER_AMBAPP
154
static int dev_regs_init(unsigned int *irq_nr) {
155
	amba_dev_t amba_dev;
156

157
	assert(NULL != irq_nr);
158
	if (-1 == capture_amba_dev(&amba_dev, AMBAPP_VENDOR_GAISLER,
159
			AMBAPP_DEVICE_GAISLER_GPTIMER, false, false)) {
160
		printk("can't capture apb dev venID=0x%X, devID=0x%X\n",
161
				AMBAPP_VENDOR_GAISLER, AMBAPP_DEVICE_GAISLER_GPTIMER);
162
		return -ENODEV;
163
	}
164
	dev_regs = (struct gptimer_regs *) amba_dev.bar[0].start;
165
	*irq_nr = amba_dev.dev_info.irq;
166
	return 0;
167
}
168
#elif OPTION_DEFINED(NUMBER,gptimer_base)
169
static int dev_regs_init(unsigned int *irq_nr) {
170
	assert(NULL != irq_nr);
171
	dev_regs = (volatile struct gptimer_regs *) OPTION_GET(NUMBER,gptimer_base);
172
	*irq_nr = OPTION_GET(NUMBER,irq_num);
173
	return 0;
174
}
175
#else
176
# error "Either DRIVER_AMBAPP or gptimer_base must be defined"
177
#endif /* DRIVER_AMBAPP */
178

179
CLOCK_SOURCE_DEF(gptimer, gptimer_init, NULL,
180
	&gptimer_ed, &gptimer_cd);
181

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

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

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

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