embox

Форк
0
/
sun4i_timer.c 
176 строк · 5.6 Кб
1
/**
2
 * @file
3
 *
4
 * @date Mar 17, 2023
5
 * @author Anton Bondarev
6
 */
7

8
#include <util/log.h>
9

10
#include <stdint.h>
11
#include <sys/mman.h>
12

13
#include <drivers/common/memory.h>
14

15
#include <hal/clock.h>
16
#include <hal/reg.h>
17
#include <hal/system.h>
18

19
#include <kernel/irq.h>
20
#include <kernel/time/clock_source.h>
21

22
#include <embox/unit.h>
23

24
#include <framework/mod/options.h>
25
#include <embox/unit.h>
26

27
#define BASE_ADDR     OPTION_GET(NUMBER, base_addr)
28
#define IRQ_NUM       OPTION_GET(NUMBER, irq_num)
29

30
#define BIT(nr)                     (1UL << (nr))
31

32
#define TIMER_IRQ_EN_REG          0x00
33
#define TIMER_IRQ_EN(val)         BIT(val)
34
#define TIMER_IRQ_ST_REG          0x04
35
#define TIMER_CTL_REG(val)        (0x10 * val + 0x10)
36
#define TIMER_CTL_ENABLE          BIT(0)
37
#define TIMER_CTL_RELOAD          BIT(1)
38
#define TIMER_CTL_CLK_SRC(val)    (((val) & 0x3) << 2)
39
#define TIMER_CTL_CLK_SRC_OSC24M  (1)
40
#define TIMER_CTL_CLK_PRES(val)   (((val) & 0x7) << 4)
41
#define TIMER_CTL_ONESHOT         BIT(7)
42
#define TIMER_INTVAL_REG(val)     (0x10 * (val) + 0x14)
43
#define TIMER_CNTVAL_REG(val)     (0x10 * (val) + 0x18)
44

45
#define TIMER_SYNC_TICKS          3
46

47
static inline void allwinner_sun4i_clkevt_sync(void  *base) {
48
	uint32_t old = REG32_LOAD(base + TIMER_CNTVAL_REG(1));
49

50
	while ((old - REG32_LOAD(base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS) {
51
	//	cpu_relax();
52
	}
53
}
54

55
static inline void allwinner_sun4i_clkevt_time_stop(void *base, uint8_t timer) {
56
	uint32_t val = REG32_LOAD(base + TIMER_CTL_REG(timer));
57
	REG32_STORE(base + TIMER_CTL_REG(timer), val & ~TIMER_CTL_ENABLE);
58
	allwinner_sun4i_clkevt_sync(base);
59
}
60

61
static inline void allwinner_sun4i_clkevt_time_setup(void *base, uint8_t timer, uint32_t delay) {
62
	REG32_STORE(base + TIMER_INTVAL_REG(timer), delay);
63
}
64

65
static inline void allwinner_sun4i_clkevt_time_start(void *base, uint8_t timer, int periodic) {
66
	uint32_t val = REG32_LOAD(base + TIMER_CTL_REG(timer));
67

68
	if (periodic) {
69
		val &= ~TIMER_CTL_ONESHOT;
70
	} else{
71
		val |= TIMER_CTL_ONESHOT;
72
	}
73

74
	REG32_STORE((base + TIMER_CTL_REG(timer)), val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD);
75
}
76

77

78
static inline void allwinner_sun4i_timer_clear_interrupt(void *base) {
79
	REG32_STORE(base + TIMER_IRQ_ST_REG, TIMER_IRQ_EN(0));
80
}
81

82
static inline void allwinner_sun4i_show_regs(void) {
83
	log_debug("\n**********************");
84
	log_debug("0x00 TIMER_IRQ_EN_REG: 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_IRQ_EN_REG));
85
	log_debug("0x04 TIMER_IRQ_ST_REG: 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_IRQ_ST_REG));
86

87
	log_debug("0x10 TIMER_CTL_REG(0): 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_CTL_REG(0)));
88
	log_debug("0x14 TIMER_INTVAL_REG(0): 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_INTVAL_REG(0)));
89
	log_debug("0x18 TIMER_CNTVAL_REG(0): 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_CNTVAL_REG(0)));
90

91
	log_debug("0x20 TIMER_CTL_REG(1): 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_CTL_REG(1)));
92
	log_debug("0x24 TIMER_INTVAL_REG(1): 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_INTVAL_REG(1)));
93
	log_debug("0x28 TIMER_CNTVAL_REG(1): 0x%8x", REG32_LOAD(BASE_ADDR + TIMER_CNTVAL_REG(1)));
94
}
95

96
static irq_return_t allwinner_sun4i_timer_handler(unsigned int irq_nr, void *dev_id) {
97
	allwinner_sun4i_timer_clear_interrupt((void *)(uintptr_t)BASE_ADDR);
98

99
	clock_tick_handler(dev_id);
100
	return IRQ_HANDLED;
101
}
102

103
static int allwinner_sun4i_timer_set_oneshot(struct clock_source *cs) {
104

105
	allwinner_sun4i_clkevt_time_stop((void *)(uintptr_t)BASE_ADDR, 0);
106
	allwinner_sun4i_clkevt_time_start((void *)(uintptr_t)BASE_ADDR, 0, false);
107

108
	allwinner_sun4i_show_regs();
109

110
	return ENOERR;
111
}
112

113

114
static int allwinner_sun4i_timer_set_periodic(struct clock_source *cs) {
115

116
	allwinner_sun4i_clkevt_time_stop((void *)(uintptr_t)BASE_ADDR, 0);
117
	allwinner_sun4i_clkevt_time_setup((void *)(uintptr_t)BASE_ADDR, 0, 25000); //cs->event_device->event_hz);
118
	allwinner_sun4i_clkevt_time_start((void *)(uintptr_t)BASE_ADDR, 0, true);
119

120
	allwinner_sun4i_show_regs();
121

122
	return ENOERR;
123
}
124

125
static int allwinner_sun4i_timer_set_next_event(struct clock_source *cs,
126
		uint32_t next_event) {
127

128
	allwinner_sun4i_clkevt_time_stop((void *)(uintptr_t)BASE_ADDR, 0);
129
	allwinner_sun4i_clkevt_time_setup((void *)(uintptr_t)BASE_ADDR, 0, 25000 - TIMER_SYNC_TICKS); //cs->event_device->event_hz);
130
	allwinner_sun4i_clkevt_time_start((void *)(uintptr_t)BASE_ADDR, 0, true);
131

132
	allwinner_sun4i_show_regs();
133

134
	return ENOERR;
135
}
136

137
static struct time_event_device allwinner_sun4i_timer_event_device  = {
138
	.set_oneshot = allwinner_sun4i_timer_set_oneshot,
139
	.set_periodic = allwinner_sun4i_timer_set_periodic,
140
	.set_next_event = allwinner_sun4i_timer_set_next_event,
141
	.name = "allwinner_sun4i_timer",
142
	.irq_nr = IRQ_NUM
143
};
144

145
static int allwinner_sun4i_timer_init(struct clock_source *cs) {
146
	uint32_t val;
147

148
	REG32_STORE(BASE_ADDR + TIMER_INTVAL_REG(1), ~0);
149
	REG32_STORE(BASE_ADDR + TIMER_CTL_REG(1),
150
			TIMER_CTL_ENABLE | TIMER_CTL_RELOAD |
151
			TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M));
152

153
	REG32_STORE(BASE_ADDR + TIMER_CTL_REG(0),
154
			TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M));
155

156
	/* Make sure timer is stopped before playing with interrupts */
157
	allwinner_sun4i_clkevt_time_stop((void *)(uintptr_t)BASE_ADDR, 0);
158

159
	/* clear timer0 interrupt */
160
	allwinner_sun4i_timer_clear_interrupt((void *)(uintptr_t)BASE_ADDR);
161

162
	/* Enable timer0 interrupt */
163
	val = REG32_LOAD(BASE_ADDR + TIMER_IRQ_EN_REG);
164
	REG32_STORE(BASE_ADDR + TIMER_IRQ_EN_REG, val | TIMER_IRQ_EN(0));
165

166
	allwinner_sun4i_show_regs();
167

168
	return irq_attach(IRQ_NUM, allwinner_sun4i_timer_handler, 0, cs, "allwinner sun4i timer");
169
}
170

171
STATIC_IRQ_ATTACH(IRQ_NUM, allwinner_sun4i_timer_handler, &this_clock_source);
172

173
PERIPH_MEMORY_DEFINE(allwinner_sun4i_timer, BASE_ADDR, 0x100);
174

175
CLOCK_SOURCE_DEF(allwinner_sun4i_timer, allwinner_sun4i_timer_init, NULL,
176
	&allwinner_sun4i_timer_event_device, NULL);
177

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

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

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

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