~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: 779e646c1263913aaf5d5617b241a606b91d71d2 (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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2022 MediaTek Inc. All rights reserved.
 *
 * Author: Weijie Gao <weijie.gao@mediatek.com>
 */

#include <asm/io.h>
#include <asm/addrspace.h>
#include <asm/mipsregs.h>
#include <asm/cm.h>
#include <linux/bitfield.h>
#include "../mt7621.h"

/* GIC Shared Register Bases */
#define GIC_SH_POL_BASE		0x100
#define GIC_SH_TRIG_BASE	0x180
#define GIC_SH_RMASK_BASE	0x300
#define GIC_SH_SMASK_BASE	0x380
#define GIC_SH_MASK_BASE	0x400
#define GIC_SH_PEND_BASE	0x480
#define GIC_SH_MAP_PIN_BASE	0x500
#define GIC_SH_MAP_VPE_BASE	0x2000

/* GIC Registers */
#define GIC_SH_POL31_0		(GIC_SH_POL_BASE + 0x00)
#define GIC_SH_POL63_32		(GIC_SH_POL_BASE + 0x04)

#define GIC_SH_TRIG31_0		(GIC_SH_TRIG_BASE + 0x00)
#define GIC_SH_TRIG63_32	(GIC_SH_TRIG_BASE + 0x04)

#define GIC_SH_RMASK31_0	(GIC_SH_RMASK_BASE + 0x00)
#define GIC_SH_RMASK63_32	(GIC_SH_RMASK_BASE + 0x04)

#define GIC_SH_SMASK31_0	(GIC_SH_SMASK_BASE + 0x00)
#define GIC_SH_SMASK63_32	(GIC_SH_SMASK_BASE + 0x04)

#define GIC_SH_MAP_PIN(n)	(GIC_SH_MAP_PIN_BASE + (n) * 4)

#define GIC_SH_MAP_VPE(n, v)	(GIC_SH_MAP_VPE_BASE + (n) * 0x20 + ((v) / 32) * 4)
#define GIC_SH_MAP_VPE31_0(n)	GIC_SH_MAP_VPE(n, 0)

/* GIC_SH_MAP_PIN fields */
#define GIC_MAP_TO_PIN		BIT(31)
#define GIC_MAP_TO_NMI		BIT(30)
#define GIC_MAP			GENMASK(5, 0)
#define GIC_MAP_SHIFT		0

static void cm_init(void __iomem *cm_base)
{
	u32 gcrcfg, num_cores;

	gcrcfg = readl(cm_base + GCR_CONFIG);
	num_cores = FIELD_GET(GCR_CONFIG_PCORES, gcrcfg) + 1;

	writel((1 << num_cores) - 1, cm_base + GCR_ACCESS);

	writel(GCR_REG0_BASE_VALUE, cm_base + GCR_REG0_BASE);
	writel(GCR_REG1_BASE_VALUE, cm_base + GCR_REG1_BASE);
	writel(GCR_REG2_BASE_VALUE, cm_base + GCR_REG2_BASE);
	writel(GCR_REG3_BASE_VALUE, cm_base + GCR_REG3_BASE);

	clrsetbits_32(cm_base + GCR_REG0_MASK,
		      GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
		      FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG0_MASK_VALUE) |
		      GCR_REGn_MASK_CMTGT_IOCU0);

	clrsetbits_32(cm_base + GCR_REG1_MASK,
		      GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
		      FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG1_MASK_VALUE) |
		      GCR_REGn_MASK_CMTGT_IOCU0);

	clrsetbits_32(cm_base + GCR_REG2_MASK,
		      GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
		      FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG2_MASK_VALUE) |
		      GCR_REGn_MASK_CMTGT_IOCU0);

	clrsetbits_32(cm_base + GCR_REG3_MASK,
		      GCR_REGn_MASK_ADDRMASK | GCR_REGn_MASK_CMTGT,
		      FIELD_PREP(GCR_REGn_MASK_ADDRMASK, GCR_REG3_MASK_VALUE) |
		      GCR_REGn_MASK_CMTGT_IOCU0);

	clrbits_32(cm_base + GCR_BASE, CM_DEFAULT_TARGET_MASK);
	setbits_32(cm_base + GCR_CONTROL, GCR_CONTROL_SYNCCTL);
}

static void gic_init(void)
{
	void __iomem *gic_base = (void *)KSEG1ADDR(MIPS_GIC_BASE);
	int i;

	/* Interrupt 0..5: Level Trigger, Active High */
	writel(0, gic_base + GIC_SH_TRIG31_0);
	writel(0x3f, gic_base + GIC_SH_RMASK31_0);
	writel(0x3f, gic_base + GIC_SH_POL31_0);
	writel(0x3f, gic_base + GIC_SH_SMASK31_0);

	/* Interrupt 56..63: Edge Trigger, Rising Edge */
	/* Hardcoded to set up the last 8 external interrupts for IPI. */
	writel(0xff000000, gic_base + GIC_SH_TRIG63_32);
	writel(0xff000000, gic_base + GIC_SH_RMASK63_32);
	writel(0xff000000, gic_base + GIC_SH_POL63_32);
	writel(0xff000000, gic_base + GIC_SH_SMASK63_32);

	/* Map interrupt source to particular hardware interrupt pin */
	/* source {0,1,2,3,4,5} -> pin {0,0,4,3,0,5} */
	writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(0));
	writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(1));
	writel(GIC_MAP_TO_PIN | 4, gic_base + GIC_SH_MAP_PIN(2));
	writel(GIC_MAP_TO_PIN | 3, gic_base + GIC_SH_MAP_PIN(3));
	writel(GIC_MAP_TO_PIN | 0, gic_base + GIC_SH_MAP_PIN(4));
	writel(GIC_MAP_TO_PIN | 5, gic_base + GIC_SH_MAP_PIN(5));

	/* source 56~59 -> pin 1, 60~63 -> pin 2 */
	writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(56));
	writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(57));
	writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(58));
	writel(GIC_MAP_TO_PIN | 1, gic_base + GIC_SH_MAP_PIN(59));
	writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(60));
	writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(61));
	writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(62));
	writel(GIC_MAP_TO_PIN | 2, gic_base + GIC_SH_MAP_PIN(63));

	/* Interrupt map to VPE (bit mask) */
	for (i = 0; i < 32; i++)
		writel(BIT(0), gic_base + GIC_SH_MAP_VPE31_0(i));

	/*
	 * Direct GIC_int 56..63 to vpe 0..3
	 * MIPS Linux convention that last 16 interrupts implemented be set
	 * aside for IPI signaling.
	 * The actual interrupts are tied low and software sends interrupts
	 * via GIC_SH_WEDGE writes.
	 */
	for (i = 0; i < 4; i++) {
		writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 56));
		writel(BIT(i), gic_base + GIC_SH_MAP_VPE31_0(i + 60));
	}
}

void mt7621_cps_init(void)
{
	void __iomem *cm_base = (void *)KSEG1ADDR(CONFIG_MIPS_CM_BASE);

	/* Enable GIC */
	writel(MIPS_GIC_BASE | GCR_GIC_EN, cm_base + GCR_GIC_BASE);

	/* Enable CPC */
	writel(MIPS_CPC_BASE | GCR_CPC_EN, cm_base + GCR_CPC_BASE);

	gic_init();
	cm_init(cm_base);
}