embox

Форк
0
221 строка · 4.7 Кб
1
/**
2
 * @file
3
 * @brief
4
 *
5
 * @author Aleksey Zhmulin
6
 * @date 20.10.23
7
 */
8
#include <assert.h>
9
#include <stddef.h>
10
#include <stdint.h>
11

12
#include <drivers/common/memory.h>
13
#include <drivers/irqctrl.h>
14
#include <framework/mod/options.h>
15
#include <hal/reg.h>
16
#include <kernel/critical.h>
17
#include <kernel/irq.h>
18
#include <util/field.h>
19

20
#include "gicv3.h"
21

22
#define PPI_PRIOR          0xa0U
23
#define SPI_PRIOR          0xa0U
24
#define CPU_PRIOR_MASK_LVL 0xffU
25

26
enum gic_irq_t {
27
	GIC_SGI,
28
	GIC_PPI,
29
	GIC_SPI,
30
	GIC_INVALID_TYPE,
31
};
32

33
static void gic_wait_for_rwp(uintptr_t reg32, uint32_t rwp_mask) {
34
	volatile unsigned long delay;
35
	volatile unsigned long i;
36

37
	delay = 1000000;
38

39
	while (REG32_LOAD(reg32) & rwp_mask) {
40
		i = 0;
41
		while (i < delay) {
42
			i++;
43
		}
44
	}
45
}
46

47
static enum gic_irq_t gic_irq_type(unsigned int irq_nr) {
48
	switch (irq_nr) {
49
	case 0 ... 15:
50
		return GIC_SGI;
51
	case 16 ... 31:
52
		return GIC_PPI;
53
	case 32 ... 1019:
54
		return GIC_SPI;
55
	default:
56
		return GIC_INVALID_TYPE;
57
	}
58
}
59

60
static void gic_dist_init(void) {
61
	uint64_t mpidr;
62
	size_t itlines;
63
	uint32_t affinity;
64
	int i, j;
65

66
	itlines = FIELD_GET(REG32_LOAD(GICD_TYPER), GICD_TYPER_ITLINES);
67

68
	/* Disable the distributor */
69
	REG32_STORE(GICD_CTLR, 0);
70
	gic_wait_for_rwp(GICD_CTLR, GICD_CTLR_RWP);
71

72
	for (i = 1; i <= itlines; i++) {
73
		/* Configure SPIs as non-secure Group-1 */
74
		REG32_STORE(GICD_IGROUPR(i), ~(uint32_t)0);
75

76
		/* Set SPIs to be level triggered */
77
		for (j = 0; j < 2; j++) {
78
			REG32_STORE(GICD_ICFGR(2 * i + j), 0);
79
		}
80

81
		/* Set priority for SPIs */
82
		for (j = 0; j < 8; j++) {
83
			REG32_STORE(GICD_IPRIORITYR(8 * i + j),
84
			    (SPI_PRIOR << 24) | (SPI_PRIOR << 16) | (SPI_PRIOR << 8)
85
			        | SPI_PRIOR);
86
		}
87
	}
88

89
	for (i = 0; i <= itlines; i++) {
90
		/* Deactivate and disable SGIs/PPIs/SPIs */
91
		REG32_STORE(GICD_ICACTIVER(i), ~(uint32_t)0);
92
		REG32_STORE(GICD_ICENABLER(i), ~(uint32_t)0);
93
	}
94

95
	/* Enable distributor */
96
	REG32_STORE(GICD_CTLR,
97
	    GICD_CTLR_GRP0 | GICD_CTLR_GRP1_NS | GICD_CTLR_ARE_NS);
98
	gic_wait_for_rwp(GICD_CTLR, GICD_CTLR_RWP);
99

100
	/* Set SPIs to current CPU only */
101
	mpidr = ARCH_REG_LOAD(MPIDR_EL1);
102
	affinity = (mpidr & 0x00ffffff) | ((mpidr >> 8) & 0xff000000);
103
	for (i = 0; i <= itlines; i++) {
104
		for (j = 0; j < 32; j++) {
105
			REG64_STORE(GICD_IROUTER(32 * i + j), affinity);
106
		}
107
	}
108
}
109

110
static void gic_redist_init(void) {
111
	int i;
112

113
	/* Wake up this CPU redistributor */
114
	REG32_CLEAR(GICR_WAKER, GICR_WAKER_PS);
115
	while (REG32_LOAD(GICR_WAKER) & GICR_WAKER_CA) {}
116

117
	/* Configure SGIs/PPIs as non-secure Group-1 */
118
	REG32_STORE(GICR_IGROUPR0, ~(uint32_t)0);
119

120
	/* Set SGIs/PPIs to be level triggered */
121
	for (i = 0; i < 2; i++) {
122
		REG32_STORE(GICR_ICFGR0, 0);
123
	}
124

125
	/* Set priority for SGIs/PPIs */
126
	for (i = 0; i < 8; i++) {
127
		REG32_STORE(GICR_IPRIORITYR(i), (PPI_PRIOR << 24) | (PPI_PRIOR << 16)
128
		                                    | (PPI_PRIOR << 8) | PPI_PRIOR);
129
	}
130

131
	/* Deactivate and disable SPIs */
132
	REG32_STORE(GICR_ICACTIVER0, ~(uint32_t)0);
133
	REG32_STORE(GICR_ICENABLER0, ~(uint32_t)0);
134

135
	gic_wait_for_rwp(GICR_CTLR, GICR_CTLR_RWP);
136
}
137

138
static void gic_cpu_init(void) {
139
	uint64_t reg;
140

141
	/* CPU interface configuration */
142
	reg = ARCH_REG_LOAD(ICC_SRE_EL1);
143
	if (!(reg & ICC_SRE_SRE)) {
144
		ARCH_REG_STORE(ICC_SRE_EL1, reg | ICC_SRE_SRE);
145
	}
146

147
	ARCH_REG_STORE(ICC_PMR_EL1, CPU_PRIOR_MASK_LVL);
148
	/* EOI deactivates interrupt (mode 0) */
149
	ARCH_REG_CLEAR(ICC_CTLR_EL1, ICC_CTLR_EL1_EOImode);
150
	ARCH_REG_STORE(ICC_IGRPEN1_EL1, ICC_IGRPEN1_EL1_EN);
151
}
152

153
static int gic_irqctrl_init(void) {
154
	gic_dist_init();
155
	gic_redist_init();
156
	gic_cpu_init();
157

158
	return 0;
159
}
160

161
void irqctrl_enable(unsigned int irq) {
162
	unsigned int reg_nr;
163
	uint32_t value;
164

165
	assert(irq_nr_valid(irq));
166

167
	reg_nr = irq >> 5;
168
	value = 1U << (irq & 0x1f);
169

170
	if (gic_irq_type(irq) == GIC_SPI) {
171
		REG32_STORE(GICD_ISENABLER(reg_nr), value);
172
	}
173
	else {
174
		REG32_STORE(GICR_ISENABLER0, value);
175
	}
176
}
177

178
void irqctrl_disable(unsigned int irq) {
179
	unsigned int reg_nr;
180
	uint32_t value;
181

182
	assert(irq_nr_valid(irq));
183

184
	reg_nr = irq >> 5;
185
	value = 1U << (irq & 0x1f);
186

187
	if (gic_irq_type(irq) == GIC_SPI) {
188
		REG32_STORE(GICD_ICENABLER(reg_nr), value);
189
	}
190
	else {
191
		REG32_STORE(GICR_ICENABLER0, value);
192
	}
193
}
194

195
void irqctrl_force(unsigned int irq) {
196
}
197

198
int irqctrl_pending(unsigned int irq) {
199
	return 0;
200
}
201

202
/* Sends an EOI (end of interrupt) signal to the PICs. */
203
void irqctrl_eoi(unsigned int irq) {
204
	assert(irq_nr_valid(irq));
205

206
	ARCH_REG_STORE(ICC_EOIR1_EL1, irq);
207
}
208

209
unsigned int irqctrl_get_intid(void) {
210
	return ARCH_REG_LOAD(ICC_IAR1_EL1) & ICC_IAR1_EL1_INTID_MASK;
211
}
212

213
void gicv3_init_el3(void) {
214
	REG32_STORE(GICD_CTLR, GICD_CTLR_DS);
215
	ARCH_REG_STORE(ICC_IGRPEN1_EL3, ICC_IGRPEN1_EL3_EN1NS);
216
}
217

218
IRQCTRL_DEF(gicv3, gic_irqctrl_init);
219

220
PERIPH_MEMORY_DEFINE(gicd, GICD_BASE, 0x10000);
221
PERIPH_MEMORY_DEFINE(gicr, GICR_BASE, 0x20000);
222

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

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

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

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