1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
4 * Loongson PCH PIC support
7 #define pr_fmt(fmt) "pch-pic: " fmt
9 #include <linux/interrupt.h>
10 #include <linux/irq.h>
11 #include <linux/irqchip.h>
12 #include <linux/irqdomain.h>
13 #include <linux/kernel.h>
14 #include <linux/platform_device.h>
16 #include <linux/of_address.h>
17 #include <linux/of_irq.h>
18 #include <linux/syscore_ops.h>
20 #include "irq-loongson.h"
23 #define PCH_PIC_MASK 0x20
24 #define PCH_PIC_HTMSI_EN 0x40
25 #define PCH_PIC_EDGE 0x60
26 #define PCH_PIC_CLR 0x80
27 #define PCH_PIC_AUTO0 0xc0
28 #define PCH_PIC_AUTO1 0xe0
29 #define PCH_INT_ROUTE(irq) (0x100 + irq)
30 #define PCH_INT_HTVEC(irq) (0x200 + irq)
31 #define PCH_PIC_POL 0x3e0
33 #define PIC_COUNT_PER_REG 32
34 #define PIC_REG_COUNT 2
35 #define PIC_COUNT (PIC_COUNT_PER_REG * PIC_REG_COUNT)
36 #define PIC_REG_IDX(irq_id) ((irq_id) / PIC_COUNT_PER_REG)
37 #define PIC_REG_BIT(irq_id) ((irq_id) % PIC_COUNT_PER_REG)
38 #define PIC_UNDEF_VECTOR 255
44 struct irq_domain
*pic_domain
;
46 raw_spinlock_t pic_lock
;
49 u32 saved_vec_en
[PIC_REG_COUNT
];
50 u32 saved_vec_pol
[PIC_REG_COUNT
];
51 u32 saved_vec_edge
[PIC_REG_COUNT
];
56 static struct pch_pic
*pch_pic_priv
[MAX_IO_PICS
];
58 struct fwnode_handle
*pch_pic_handle
[MAX_IO_PICS
];
60 static inline u8
hwirq_to_bit(struct pch_pic
*priv
, int hirq
)
62 return priv
->table
[hirq
];
65 static void pch_pic_bitset(struct pch_pic
*priv
, int offset
, int bit
)
68 void __iomem
*addr
= priv
->base
+ offset
+ PIC_REG_IDX(bit
) * 4;
70 raw_spin_lock(&priv
->pic_lock
);
72 reg
|= BIT(PIC_REG_BIT(bit
));
74 raw_spin_unlock(&priv
->pic_lock
);
77 static void pch_pic_bitclr(struct pch_pic
*priv
, int offset
, int bit
)
80 void __iomem
*addr
= priv
->base
+ offset
+ PIC_REG_IDX(bit
) * 4;
82 raw_spin_lock(&priv
->pic_lock
);
84 reg
&= ~BIT(PIC_REG_BIT(bit
));
86 raw_spin_unlock(&priv
->pic_lock
);
89 static void pch_pic_mask_irq(struct irq_data
*d
)
91 struct pch_pic
*priv
= irq_data_get_irq_chip_data(d
);
93 pch_pic_bitset(priv
, PCH_PIC_MASK
, hwirq_to_bit(priv
, d
->hwirq
));
94 irq_chip_mask_parent(d
);
97 static void pch_pic_unmask_irq(struct irq_data
*d
)
99 struct pch_pic
*priv
= irq_data_get_irq_chip_data(d
);
100 int bit
= hwirq_to_bit(priv
, d
->hwirq
);
102 writel(BIT(PIC_REG_BIT(bit
)),
103 priv
->base
+ PCH_PIC_CLR
+ PIC_REG_IDX(bit
) * 4);
105 irq_chip_unmask_parent(d
);
106 pch_pic_bitclr(priv
, PCH_PIC_MASK
, bit
);
109 static int pch_pic_set_type(struct irq_data
*d
, unsigned int type
)
111 struct pch_pic
*priv
= irq_data_get_irq_chip_data(d
);
112 int bit
= hwirq_to_bit(priv
, d
->hwirq
);
116 case IRQ_TYPE_EDGE_RISING
:
117 pch_pic_bitset(priv
, PCH_PIC_EDGE
, bit
);
118 pch_pic_bitclr(priv
, PCH_PIC_POL
, bit
);
119 irq_set_handler_locked(d
, handle_edge_irq
);
121 case IRQ_TYPE_EDGE_FALLING
:
122 pch_pic_bitset(priv
, PCH_PIC_EDGE
, bit
);
123 pch_pic_bitset(priv
, PCH_PIC_POL
, bit
);
124 irq_set_handler_locked(d
, handle_edge_irq
);
126 case IRQ_TYPE_LEVEL_HIGH
:
127 pch_pic_bitclr(priv
, PCH_PIC_EDGE
, bit
);
128 pch_pic_bitclr(priv
, PCH_PIC_POL
, bit
);
129 irq_set_handler_locked(d
, handle_level_irq
);
131 case IRQ_TYPE_LEVEL_LOW
:
132 pch_pic_bitclr(priv
, PCH_PIC_EDGE
, bit
);
133 pch_pic_bitset(priv
, PCH_PIC_POL
, bit
);
134 irq_set_handler_locked(d
, handle_level_irq
);
144 static void pch_pic_ack_irq(struct irq_data
*d
)
147 struct pch_pic
*priv
= irq_data_get_irq_chip_data(d
);
148 int bit
= hwirq_to_bit(priv
, d
->hwirq
);
150 reg
= readl(priv
->base
+ PCH_PIC_EDGE
+ PIC_REG_IDX(bit
) * 4);
151 if (reg
& BIT(PIC_REG_BIT(bit
))) {
152 writel(BIT(PIC_REG_BIT(bit
)),
153 priv
->base
+ PCH_PIC_CLR
+ PIC_REG_IDX(bit
) * 4);
155 irq_chip_ack_parent(d
);
158 static struct irq_chip pch_pic_irq_chip
= {
160 .irq_mask
= pch_pic_mask_irq
,
161 .irq_unmask
= pch_pic_unmask_irq
,
162 .irq_ack
= pch_pic_ack_irq
,
163 .irq_set_affinity
= irq_chip_set_affinity_parent
,
164 .irq_set_type
= pch_pic_set_type
,
165 .flags
= IRQCHIP_SKIP_SET_WAKE
,
168 static int pch_pic_domain_translate(struct irq_domain
*d
,
169 struct irq_fwspec
*fwspec
,
170 unsigned long *hwirq
,
173 struct pch_pic
*priv
= d
->host_data
;
174 struct device_node
*of_node
= to_of_node(fwspec
->fwnode
);
179 if (fwspec
->param_count
< 2)
182 *hwirq
= fwspec
->param
[0];
183 *type
= fwspec
->param
[1] & IRQ_TYPE_SENSE_MASK
;
185 if (fwspec
->param_count
< 1)
188 *hwirq
= fwspec
->param
[0] - priv
->gsi_base
;
190 if (fwspec
->param_count
> 1)
191 *type
= fwspec
->param
[1] & IRQ_TYPE_SENSE_MASK
;
193 *type
= IRQ_TYPE_NONE
;
196 raw_spin_lock_irqsave(&priv
->pic_lock
, flags
);
197 /* Check pic-table to confirm if the hwirq has been assigned */
198 for (i
= 0; i
< priv
->inuse
; i
++) {
199 if (priv
->table
[i
] == *hwirq
) {
204 if (i
== priv
->inuse
) {
205 /* Assign a new hwirq in pic-table */
206 if (priv
->inuse
>= PIC_COUNT
) {
207 pr_err("pch-pic domain has no free vectors\n");
208 raw_spin_unlock_irqrestore(&priv
->pic_lock
, flags
);
211 priv
->table
[priv
->inuse
] = *hwirq
;
212 *hwirq
= priv
->inuse
++;
214 raw_spin_unlock_irqrestore(&priv
->pic_lock
, flags
);
219 static int pch_pic_alloc(struct irq_domain
*domain
, unsigned int virq
,
220 unsigned int nr_irqs
, void *arg
)
225 struct irq_fwspec
*fwspec
= arg
;
226 struct irq_fwspec parent_fwspec
;
227 struct pch_pic
*priv
= domain
->host_data
;
229 err
= pch_pic_domain_translate(domain
, fwspec
, &hwirq
, &type
);
233 /* Write vector ID */
234 writeb(priv
->ht_vec_base
+ hwirq
, priv
->base
+ PCH_INT_HTVEC(hwirq_to_bit(priv
, hwirq
)));
236 parent_fwspec
.fwnode
= domain
->parent
->fwnode
;
237 parent_fwspec
.param_count
= 1;
238 parent_fwspec
.param
[0] = hwirq
+ priv
->ht_vec_base
;
240 err
= irq_domain_alloc_irqs_parent(domain
, virq
, 1, &parent_fwspec
);
244 irq_domain_set_info(domain
, virq
, hwirq
,
245 &pch_pic_irq_chip
, priv
,
246 handle_level_irq
, NULL
, NULL
);
252 static const struct irq_domain_ops pch_pic_domain_ops
= {
253 .translate
= pch_pic_domain_translate
,
254 .alloc
= pch_pic_alloc
,
255 .free
= irq_domain_free_irqs_parent
,
258 static void pch_pic_reset(struct pch_pic
*priv
)
262 for (i
= 0; i
< PIC_COUNT
; i
++) {
263 /* Write vector ID */
264 writeb(priv
->ht_vec_base
+ i
, priv
->base
+ PCH_INT_HTVEC(hwirq_to_bit(priv
, i
)));
265 /* Hardcode route to HT0 Lo */
266 writeb(1, priv
->base
+ PCH_INT_ROUTE(i
));
269 for (i
= 0; i
< PIC_REG_COUNT
; i
++) {
270 /* Clear IRQ cause registers, mask all interrupts */
271 writel_relaxed(0xFFFFFFFF, priv
->base
+ PCH_PIC_MASK
+ 4 * i
);
272 writel_relaxed(0xFFFFFFFF, priv
->base
+ PCH_PIC_CLR
+ 4 * i
);
273 /* Clear auto bounce, we don't need that */
274 writel_relaxed(0, priv
->base
+ PCH_PIC_AUTO0
+ 4 * i
);
275 writel_relaxed(0, priv
->base
+ PCH_PIC_AUTO1
+ 4 * i
);
276 /* Enable HTMSI transformer */
277 writel_relaxed(0xFFFFFFFF, priv
->base
+ PCH_PIC_HTMSI_EN
+ 4 * i
);
281 static int pch_pic_suspend(void)
285 for (i
= 0; i
< nr_pics
; i
++) {
286 for (j
= 0; j
< PIC_REG_COUNT
; j
++) {
287 pch_pic_priv
[i
]->saved_vec_pol
[j
] =
288 readl(pch_pic_priv
[i
]->base
+ PCH_PIC_POL
+ 4 * j
);
289 pch_pic_priv
[i
]->saved_vec_edge
[j
] =
290 readl(pch_pic_priv
[i
]->base
+ PCH_PIC_EDGE
+ 4 * j
);
291 pch_pic_priv
[i
]->saved_vec_en
[j
] =
292 readl(pch_pic_priv
[i
]->base
+ PCH_PIC_MASK
+ 4 * j
);
299 static void pch_pic_resume(void)
303 for (i
= 0; i
< nr_pics
; i
++) {
304 pch_pic_reset(pch_pic_priv
[i
]);
305 for (j
= 0; j
< PIC_REG_COUNT
; j
++) {
306 writel(pch_pic_priv
[i
]->saved_vec_pol
[j
],
307 pch_pic_priv
[i
]->base
+ PCH_PIC_POL
+ 4 * j
);
308 writel(pch_pic_priv
[i
]->saved_vec_edge
[j
],
309 pch_pic_priv
[i
]->base
+ PCH_PIC_EDGE
+ 4 * j
);
310 writel(pch_pic_priv
[i
]->saved_vec_en
[j
],
311 pch_pic_priv
[i
]->base
+ PCH_PIC_MASK
+ 4 * j
);
316 static struct syscore_ops pch_pic_syscore_ops
= {
317 .suspend
= pch_pic_suspend
,
318 .resume
= pch_pic_resume
,
321 static int pch_pic_init(phys_addr_t addr
, unsigned long size
, int vec_base
,
322 struct irq_domain
*parent_domain
, struct fwnode_handle
*domain_handle
,
325 struct pch_pic
*priv
;
328 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
332 raw_spin_lock_init(&priv
->pic_lock
);
333 priv
->base
= ioremap(addr
, size
);
338 for (i
= 0; i
< PIC_COUNT
; i
++)
339 priv
->table
[i
] = PIC_UNDEF_VECTOR
;
341 priv
->ht_vec_base
= vec_base
;
342 priv
->vec_count
= ((readq(priv
->base
) >> 48) & 0xff) + 1;
343 priv
->gsi_base
= gsi_base
;
345 priv
->pic_domain
= irq_domain_create_hierarchy(parent_domain
, 0,
346 priv
->vec_count
, domain_handle
,
347 &pch_pic_domain_ops
, priv
);
349 if (!priv
->pic_domain
) {
350 pr_err("Failed to create IRQ domain\n");
355 pch_pic_handle
[nr_pics
] = domain_handle
;
356 pch_pic_priv
[nr_pics
++] = priv
;
359 register_syscore_ops(&pch_pic_syscore_ops
);
373 static int pch_pic_of_init(struct device_node
*node
,
374 struct device_node
*parent
)
378 struct irq_domain
*parent_domain
;
380 if (of_address_to_resource(node
, 0, &res
))
383 parent_domain
= irq_find_host(parent
);
384 if (!parent_domain
) {
385 pr_err("Failed to find the parent domain\n");
389 if (of_property_read_u32(node
, "loongson,pic-base-vec", &vec_base
)) {
390 pr_err("Failed to determine pic-base-vec\n");
394 err
= pch_pic_init(res
.start
, resource_size(&res
), vec_base
,
395 parent_domain
, of_node_to_fwnode(node
), 0);
402 IRQCHIP_DECLARE(pch_pic
, "loongson,pch-pic-1.0", pch_pic_of_init
);
407 int find_pch_pic(u32 gsi
)
411 /* Find the PCH_PIC that manages this GSI. */
412 for (i
= 0; i
< MAX_IO_PICS
; i
++) {
413 struct pch_pic
*priv
= pch_pic_priv
[i
];
418 if (gsi
>= priv
->gsi_base
&& gsi
< (priv
->gsi_base
+ priv
->vec_count
))
422 pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi
);
426 static int __init
pch_lpc_parse_madt(union acpi_subtable_headers
*header
,
427 const unsigned long end
)
429 struct acpi_madt_lpc_pic
*pchlpc_entry
= (struct acpi_madt_lpc_pic
*)header
;
431 return pch_lpc_acpi_init(pch_pic_priv
[0]->pic_domain
, pchlpc_entry
);
434 static int __init
acpi_cascade_irqdomain_init(void)
438 r
= acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC
, pch_lpc_parse_madt
, 0);
445 int __init
pch_pic_acpi_init(struct irq_domain
*parent
,
446 struct acpi_madt_bio_pic
*acpi_pchpic
)
449 struct fwnode_handle
*domain_handle
;
451 if (find_pch_pic(acpi_pchpic
->gsi_base
) >= 0)
454 domain_handle
= irq_domain_alloc_fwnode(&acpi_pchpic
->address
);
455 if (!domain_handle
) {
456 pr_err("Unable to allocate domain handle\n");
460 ret
= pch_pic_init(acpi_pchpic
->address
, acpi_pchpic
->size
,
461 0, parent
, domain_handle
, acpi_pchpic
->gsi_base
);
464 irq_domain_free_fwnode(domain_handle
);
468 if (acpi_pchpic
->id
== 0)
469 ret
= acpi_cascade_irqdomain_init();