aboutsummaryrefslogtreecommitdiffstats
path: root/gic-v3.c
blob: 476f703231e04b6395afc7c7376655d1d30d29ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/*
 * gic-v3.c
 *
 * Copyright (C) 2015 ARM Limited. All rights reserved.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE.txt file.
 */

#include <stdint.h>

#include <cpu.h>
#include <asm/gic-v3.h>
#include <asm/io.h>

#define GICD_CTLR			0x0
#define GICD_TYPER			0x4
#define GICD_IGROUP0			0x80
#define GICD_IGRPMOD0			0xd00

#define GICD_CTLR_EnableGrp0		(1 << 0)
#define GICD_CTLR_EnableGrp1ns		(1 << 1)
#define GICD_CTLR_EnableGrp1s		(1 << 2)
#define GICD_CTLR_ARE_S			(1 << 4)
#define GICD_CTLR_ARE_NS		(1 << 5)
#define GICD_TYPER_ITLineNumber		0x1f

#define GICR_WAKER			0x14

#define GICR_TYPER			0x8
#define GICR_IGROUP0			0x80
#define GICR_IGRPMOD0			0xD00

#define GICR_WAKER_ProcessorSleep	(1 << 1)
#define GICR_WAKER_ChildrenAsleep	(1 << 2)

#define GICR_TYPER_VLPIS		(1 << 1)
#define GICR_TYPER_Last			(1 << 4)

#define ICC_SRE_SRE			(1 << 0)
#define ICC_SRE_Enable			(1 << 3)

void gic_secure_init_primary(void)
{
	unsigned int i;
	void *gicr_ptr = (void *)GIC_RDIST_BASE;
	void *gicd_base = (void *)GIC_DIST_BASE;
	uint32_t typer;

	raw_writel(GICD_CTLR_EnableGrp0 | GICD_CTLR_EnableGrp1ns
		| GICD_CTLR_EnableGrp1s | GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS,
		gicd_base + GICD_CTLR);

	do {
		/*
		 * Wake up redistributor: kick ProcessorSleep and wait for
		 * ChildrenAsleep to be 0.
		 */
		uint32_t waker = raw_readl(gicr_ptr + GICR_WAKER);
		waker &= ~GICR_WAKER_ProcessorSleep;
		raw_writel(waker, gicr_ptr + GICR_WAKER);
		dsb(st);
		isb();
		do {
			waker = raw_readl(gicr_ptr + GICR_WAKER);
		} while (waker & GICR_WAKER_ChildrenAsleep);

		/*
		 * GICR_TYPER is 64-bit, but we do not need the upper half that
		 * contains CPU affinity.
		 */
		typer = raw_readl(gicr_ptr + GICR_TYPER);

		gicr_ptr += 0x10000; /* Go to SGI_Base */
		raw_writel(~0x0, gicr_ptr + GICR_IGROUP0);
		raw_writel(0x0, gicr_ptr + GICR_IGRPMOD0);

		/* Next redist */
		gicr_ptr += 0x10000;
		if (typer & GICR_TYPER_VLPIS)
			gicr_ptr += 0x20000;

	} while (!(typer & GICR_TYPER_Last));

	typer = raw_readl(gicd_base + GICD_TYPER);
	for (i = 1; i < (typer & GICD_TYPER_ITLineNumber); i++) {
		raw_writel(~0x0, gicd_base + GICD_IGROUP0 + i * 4);
		raw_writel(0x0, gicd_base + GICD_IGRPMOD0 + i * 4);
	}
}

void gic_secure_init(void)
{
	uint32_t cpu = read_mpidr();

	uint32_t sre;

	/*
	 * If GICv3 is not available, skip initialisation. The OS will probably
	 * fail with a warning, but this should be easier to debug than a
	 * failure within the boot wrapper.
	 */
	if (!has_gicv3_sysreg())
		return;

	if (cpu == 0)
		gic_secure_init_primary();

	sre = gic_read_icc_sre();
	sre |= ICC_SRE_Enable | ICC_SRE_SRE;
	gic_write_icc_sre(sre);
	isb();

	gic_write_icc_ctlr(0);
	isb();
}