Skip to content

Commit 4363c85

Browse files
author
Marc Zyngier
committed
Merge branch irq/cirq-v2 into irq/irqchip-next
* irq/cirq-v2: : . : Support for the MTK CIRQv2, courtesy of AngeloGioacchino Del Regno: : : "On newer SoCs (like MT8192/95 and also other non-chromebook chips), the : MediaTek CIRQ controller has a new register layout: this series adds : some more flexibility to the irq-mtk-cirq driver, allowing to select : the register layout based on a SoC-specific compatible." : : . irqchip/irq-mtk-cirq: Add support for System CIRQ on MT8192 irqchip/irq-mtk-cirq: Move register offsets to const array dt-bindings: interrupt-controller: mediatek,cirq: Document MT8192 dt-bindings: interrupt-controller: mediatek,cirq: Migrate to dt schema Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents dc7f1c2 + 5c4e0aa commit 4363c85

3 files changed

Lines changed: 146 additions & 50 deletions

File tree

Documentation/devicetree/bindings/interrupt-controller/mediatek,cirq.txt

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/interrupt-controller/mediatek,mtk-cirq.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: MediaTek System Interrupt Controller
8+
9+
maintainers:
10+
- Youlin Pei <youlin.pei@mediatek.com>
11+
12+
description:
13+
In MediaTek SoCs, the CIRQ is a low power interrupt controller designed to
14+
work outside of MCUSYS which comprises with Cortex-Ax cores, CCI and GIC.
15+
The external interrupts (outside MCUSYS) will feed through CIRQ and connect
16+
to GIC in MCUSYS. When CIRQ is enabled, it will record the edge-sensitive
17+
interrupts and generate a pulse signal to parent interrupt controller when
18+
flush command is executed. With CIRQ, MCUSYS can be completely turned off
19+
to improve the system power consumption without losing interrupts.
20+
21+
22+
properties:
23+
compatible:
24+
items:
25+
- enum:
26+
- mediatek,mt2701-cirq
27+
- mediatek,mt8135-cirq
28+
- mediatek,mt8173-cirq
29+
- mediatek,mt8192-cirq
30+
- const: mediatek,mtk-cirq
31+
32+
reg:
33+
maxItems: 1
34+
35+
'#interrupt-cells':
36+
const: 3
37+
38+
interrupt-controller: true
39+
40+
mediatek,ext-irq-range:
41+
$ref: /schemas/types.yaml#/definitions/uint32-array
42+
items:
43+
- description: First CIRQ interrupt
44+
- description: Last CIRQ interrupt
45+
description:
46+
Identifies the range of external interrupts in different SoCs
47+
48+
required:
49+
- compatible
50+
- reg
51+
- '#interrupt-cells'
52+
- interrupt-controller
53+
- mediatek,ext-irq-range
54+
55+
additionalProperties: false
56+
57+
examples:
58+
- |
59+
#include <dt-bindings/interrupt-controller/irq.h>
60+
61+
cirq: interrupt-controller@10204000 {
62+
compatible = "mediatek,mt2701-cirq", "mediatek,mtk-cirq";
63+
reg = <0x10204000 0x400>;
64+
#interrupt-cells = <3>;
65+
interrupt-controller;
66+
interrupt-parent = <&sysirq>;
67+
mediatek,ext-irq-range = <32 200>;
68+
};

drivers/irqchip/irq-mtk-cirq.c

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,41 @@
1515
#include <linux/slab.h>
1616
#include <linux/syscore_ops.h>
1717

18-
#define CIRQ_ACK 0x40
19-
#define CIRQ_MASK_SET 0xc0
20-
#define CIRQ_MASK_CLR 0x100
21-
#define CIRQ_SENS_SET 0x180
22-
#define CIRQ_SENS_CLR 0x1c0
23-
#define CIRQ_POL_SET 0x240
24-
#define CIRQ_POL_CLR 0x280
25-
#define CIRQ_CONTROL 0x300
18+
enum mtk_cirq_regoffs_index {
19+
CIRQ_STA,
20+
CIRQ_ACK,
21+
CIRQ_MASK_SET,
22+
CIRQ_MASK_CLR,
23+
CIRQ_SENS_SET,
24+
CIRQ_SENS_CLR,
25+
CIRQ_POL_SET,
26+
CIRQ_POL_CLR,
27+
CIRQ_CONTROL
28+
};
29+
30+
static const u32 mtk_cirq_regoffs_v1[] = {
31+
[CIRQ_STA] = 0x0,
32+
[CIRQ_ACK] = 0x40,
33+
[CIRQ_MASK_SET] = 0xc0,
34+
[CIRQ_MASK_CLR] = 0x100,
35+
[CIRQ_SENS_SET] = 0x180,
36+
[CIRQ_SENS_CLR] = 0x1c0,
37+
[CIRQ_POL_SET] = 0x240,
38+
[CIRQ_POL_CLR] = 0x280,
39+
[CIRQ_CONTROL] = 0x300,
40+
};
41+
42+
static const u32 mtk_cirq_regoffs_v2[] = {
43+
[CIRQ_STA] = 0x0,
44+
[CIRQ_ACK] = 0x80,
45+
[CIRQ_MASK_SET] = 0x180,
46+
[CIRQ_MASK_CLR] = 0x200,
47+
[CIRQ_SENS_SET] = 0x300,
48+
[CIRQ_SENS_CLR] = 0x380,
49+
[CIRQ_POL_SET] = 0x480,
50+
[CIRQ_POL_CLR] = 0x500,
51+
[CIRQ_CONTROL] = 0x600,
52+
};
2653

2754
#define CIRQ_EN 0x1
2855
#define CIRQ_EDGE 0x2
@@ -32,18 +59,32 @@ struct mtk_cirq_chip_data {
3259
void __iomem *base;
3360
unsigned int ext_irq_start;
3461
unsigned int ext_irq_end;
62+
const u32 *offsets;
3563
struct irq_domain *domain;
3664
};
3765

3866
static struct mtk_cirq_chip_data *cirq_data;
3967

40-
static void mtk_cirq_write_mask(struct irq_data *data, unsigned int offset)
68+
static void __iomem *mtk_cirq_reg(struct mtk_cirq_chip_data *chip_data,
69+
enum mtk_cirq_regoffs_index idx)
70+
{
71+
return chip_data->base + chip_data->offsets[idx];
72+
}
73+
74+
static void __iomem *mtk_cirq_irq_reg(struct mtk_cirq_chip_data *chip_data,
75+
enum mtk_cirq_regoffs_index idx,
76+
unsigned int cirq_num)
77+
{
78+
return mtk_cirq_reg(chip_data, idx) + (cirq_num / 32) * 4;
79+
}
80+
81+
static void mtk_cirq_write_mask(struct irq_data *data, enum mtk_cirq_regoffs_index idx)
4182
{
4283
struct mtk_cirq_chip_data *chip_data = data->chip_data;
4384
unsigned int cirq_num = data->hwirq;
4485
u32 mask = 1 << (cirq_num % 32);
4586

46-
writel_relaxed(mask, chip_data->base + offset + (cirq_num / 32) * 4);
87+
writel_relaxed(mask, mtk_cirq_irq_reg(chip_data, idx, cirq_num));
4788
}
4889

4990
static void mtk_cirq_mask(struct irq_data *data)
@@ -160,6 +201,7 @@ static const struct irq_domain_ops cirq_domain_ops = {
160201
#ifdef CONFIG_PM_SLEEP
161202
static int mtk_cirq_suspend(void)
162203
{
204+
void __iomem *reg;
163205
u32 value, mask;
164206
unsigned int irq, hwirq_num;
165207
bool pending, masked;
@@ -200,31 +242,34 @@ static int mtk_cirq_suspend(void)
200242
continue;
201243
}
202244

245+
reg = mtk_cirq_irq_reg(cirq_data, CIRQ_ACK, i);
203246
mask = 1 << (i % 32);
204-
writel_relaxed(mask, cirq_data->base + CIRQ_ACK + (i / 32) * 4);
247+
writel_relaxed(mask, reg);
205248
}
206249

207250
/* set edge_only mode, record edge-triggerd interrupts */
208251
/* enable cirq */
209-
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
252+
reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
253+
value = readl_relaxed(reg);
210254
value |= (CIRQ_EDGE | CIRQ_EN);
211-
writel_relaxed(value, cirq_data->base + CIRQ_CONTROL);
255+
writel_relaxed(value, reg);
212256

213257
return 0;
214258
}
215259

216260
static void mtk_cirq_resume(void)
217261
{
262+
void __iomem *reg = mtk_cirq_reg(cirq_data, CIRQ_CONTROL);
218263
u32 value;
219264

220265
/* flush recorded interrupts, will send signals to parent controller */
221-
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
222-
writel_relaxed(value | CIRQ_FLUSH, cirq_data->base + CIRQ_CONTROL);
266+
value = readl_relaxed(reg);
267+
writel_relaxed(value | CIRQ_FLUSH, reg);
223268

224269
/* disable cirq */
225-
value = readl_relaxed(cirq_data->base + CIRQ_CONTROL);
270+
value = readl_relaxed(reg);
226271
value &= ~(CIRQ_EDGE | CIRQ_EN);
227-
writel_relaxed(value, cirq_data->base + CIRQ_CONTROL);
272+
writel_relaxed(value, reg);
228273
}
229274

230275
static struct syscore_ops mtk_cirq_syscore_ops = {
@@ -240,10 +285,19 @@ static void mtk_cirq_syscore_init(void)
240285
static inline void mtk_cirq_syscore_init(void) {}
241286
#endif
242287

288+
static const struct of_device_id mtk_cirq_of_match[] = {
289+
{ .compatible = "mediatek,mt2701-cirq", .data = &mtk_cirq_regoffs_v1 },
290+
{ .compatible = "mediatek,mt8135-cirq", .data = &mtk_cirq_regoffs_v1 },
291+
{ .compatible = "mediatek,mt8173-cirq", .data = &mtk_cirq_regoffs_v1 },
292+
{ .compatible = "mediatek,mt8192-cirq", .data = &mtk_cirq_regoffs_v2 },
293+
{ /* sentinel */ }
294+
};
295+
243296
static int __init mtk_cirq_of_init(struct device_node *node,
244297
struct device_node *parent)
245298
{
246299
struct irq_domain *domain, *domain_parent;
300+
const struct of_device_id *match;
247301
unsigned int irq_num;
248302
int ret;
249303

@@ -274,6 +328,13 @@ static int __init mtk_cirq_of_init(struct device_node *node,
274328
if (ret)
275329
goto out_unmap;
276330

331+
match = of_match_node(mtk_cirq_of_match, node);
332+
if (!match) {
333+
ret = -ENODEV;
334+
goto out_unmap;
335+
}
336+
cirq_data->offsets = match->data;
337+
277338
irq_num = cirq_data->ext_irq_end - cirq_data->ext_irq_start + 1;
278339
domain = irq_domain_add_hierarchy(domain_parent, 0,
279340
irq_num, node,

0 commit comments

Comments
 (0)