18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#include <linux/sh_intc.h>
38c2ecf20Sopenharmony_ci#include <linux/irq.h>
48c2ecf20Sopenharmony_ci#include <linux/irqdomain.h>
58c2ecf20Sopenharmony_ci#include <linux/list.h>
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/types.h>
88c2ecf20Sopenharmony_ci#include <linux/radix-tree.h>
98c2ecf20Sopenharmony_ci#include <linux/device.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
128c2ecf20Sopenharmony_ci	((shift) | ((width) << 5) | ((fn) << 9) | ((mode) << 13) | \
138c2ecf20Sopenharmony_ci	 ((addr_e) << 16) | ((addr_d << 24)))
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define _INTC_SHIFT(h)		(h & 0x1f)
168c2ecf20Sopenharmony_ci#define _INTC_WIDTH(h)		((h >> 5) & 0xf)
178c2ecf20Sopenharmony_ci#define _INTC_FN(h)		((h >> 9) & 0xf)
188c2ecf20Sopenharmony_ci#define _INTC_MODE(h)		((h >> 13) & 0x7)
198c2ecf20Sopenharmony_ci#define _INTC_ADDR_E(h)		((h >> 16) & 0xff)
208c2ecf20Sopenharmony_ci#define _INTC_ADDR_D(h)		((h >> 24) & 0xff)
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
238c2ecf20Sopenharmony_ci#define IS_SMP(x)		(x.smp)
248c2ecf20Sopenharmony_ci#define INTC_REG(d, x, c)	(d->reg[(x)] + ((d->smp[(x)] & 0xff) * c))
258c2ecf20Sopenharmony_ci#define SMP_NR(d, x)		((d->smp[(x)] >> 8) ? (d->smp[(x)] >> 8) : 1)
268c2ecf20Sopenharmony_ci#else
278c2ecf20Sopenharmony_ci#define IS_SMP(x)		0
288c2ecf20Sopenharmony_ci#define INTC_REG(d, x, c)	(d->reg[(x)])
298c2ecf20Sopenharmony_ci#define SMP_NR(d, x)		1
308c2ecf20Sopenharmony_ci#endif
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct intc_handle_int {
338c2ecf20Sopenharmony_ci	unsigned int irq;
348c2ecf20Sopenharmony_ci	unsigned long handle;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistruct intc_window {
388c2ecf20Sopenharmony_ci	phys_addr_t phys;
398c2ecf20Sopenharmony_ci	void __iomem *virt;
408c2ecf20Sopenharmony_ci	unsigned long size;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistruct intc_map_entry {
448c2ecf20Sopenharmony_ci	intc_enum enum_id;
458c2ecf20Sopenharmony_ci	struct intc_desc_int *desc;
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistruct intc_subgroup_entry {
498c2ecf20Sopenharmony_ci	unsigned int pirq;
508c2ecf20Sopenharmony_ci	intc_enum enum_id;
518c2ecf20Sopenharmony_ci	unsigned long handle;
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistruct intc_desc_int {
558c2ecf20Sopenharmony_ci	struct list_head list;
568c2ecf20Sopenharmony_ci	struct device dev;
578c2ecf20Sopenharmony_ci	struct radix_tree_root tree;
588c2ecf20Sopenharmony_ci	raw_spinlock_t lock;
598c2ecf20Sopenharmony_ci	unsigned int index;
608c2ecf20Sopenharmony_ci	unsigned long *reg;
618c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP
628c2ecf20Sopenharmony_ci	unsigned long *smp;
638c2ecf20Sopenharmony_ci#endif
648c2ecf20Sopenharmony_ci	unsigned int nr_reg;
658c2ecf20Sopenharmony_ci	struct intc_handle_int *prio;
668c2ecf20Sopenharmony_ci	unsigned int nr_prio;
678c2ecf20Sopenharmony_ci	struct intc_handle_int *sense;
688c2ecf20Sopenharmony_ci	unsigned int nr_sense;
698c2ecf20Sopenharmony_ci	struct intc_window *window;
708c2ecf20Sopenharmony_ci	unsigned int nr_windows;
718c2ecf20Sopenharmony_ci	struct irq_domain *domain;
728c2ecf20Sopenharmony_ci	struct irq_chip chip;
738c2ecf20Sopenharmony_ci	bool skip_suspend;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cienum {
788c2ecf20Sopenharmony_ci	REG_FN_ERR = 0,
798c2ecf20Sopenharmony_ci	REG_FN_TEST_BASE = 1,
808c2ecf20Sopenharmony_ci	REG_FN_WRITE_BASE = 5,
818c2ecf20Sopenharmony_ci	REG_FN_MODIFY_BASE = 9
828c2ecf20Sopenharmony_ci};
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cienum {	MODE_ENABLE_REG = 0, /* Bit(s) set -> interrupt enabled */
858c2ecf20Sopenharmony_ci	MODE_MASK_REG,       /* Bit(s) set -> interrupt disabled */
868c2ecf20Sopenharmony_ci	MODE_DUAL_REG,       /* Two registers, set bit to enable / disable */
878c2ecf20Sopenharmony_ci	MODE_PRIO_REG,       /* Priority value written to enable interrupt */
888c2ecf20Sopenharmony_ci	MODE_PCLR_REG,       /* Above plus all bits set to disable interrupt */
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic inline struct intc_desc_int *get_intc_desc(unsigned int irq)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct irq_chip *chip = irq_get_chip(irq);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return container_of(chip, struct intc_desc_int, chip);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/*
998c2ecf20Sopenharmony_ci * Grumble.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic inline void activate_irq(int irq)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	irq_modify_status(irq, IRQ_NOREQUEST, IRQ_NOPROBE);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic inline int intc_handle_int_cmp(const void *a, const void *b)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	const struct intc_handle_int *_a = a;
1098c2ecf20Sopenharmony_ci	const struct intc_handle_int *_b = b;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return _a->irq - _b->irq;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* access.c */
1158c2ecf20Sopenharmony_ciextern unsigned long
1168c2ecf20Sopenharmony_ci(*intc_reg_fns[])(unsigned long addr, unsigned long h, unsigned long data);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciextern unsigned long
1198c2ecf20Sopenharmony_ci(*intc_enable_fns[])(unsigned long addr, unsigned long handle,
1208c2ecf20Sopenharmony_ci		     unsigned long (*fn)(unsigned long,
1218c2ecf20Sopenharmony_ci				unsigned long, unsigned long),
1228c2ecf20Sopenharmony_ci		     unsigned int irq);
1238c2ecf20Sopenharmony_ciextern unsigned long
1248c2ecf20Sopenharmony_ci(*intc_disable_fns[])(unsigned long addr, unsigned long handle,
1258c2ecf20Sopenharmony_ci		      unsigned long (*fn)(unsigned long,
1268c2ecf20Sopenharmony_ci				unsigned long, unsigned long),
1278c2ecf20Sopenharmony_ci		      unsigned int irq);
1288c2ecf20Sopenharmony_ciextern unsigned long
1298c2ecf20Sopenharmony_ci(*intc_enable_noprio_fns[])(unsigned long addr, unsigned long handle,
1308c2ecf20Sopenharmony_ci		            unsigned long (*fn)(unsigned long,
1318c2ecf20Sopenharmony_ci				unsigned long, unsigned long),
1328c2ecf20Sopenharmony_ci			    unsigned int irq);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciunsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address);
1358c2ecf20Sopenharmony_ciunsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address);
1368c2ecf20Sopenharmony_ciunsigned int intc_set_field_from_handle(unsigned int value,
1378c2ecf20Sopenharmony_ci			    unsigned int field_value,
1388c2ecf20Sopenharmony_ci			    unsigned int handle);
1398c2ecf20Sopenharmony_ciunsigned long intc_get_field_from_handle(unsigned int value,
1408c2ecf20Sopenharmony_ci					 unsigned int handle);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci/* balancing.c */
1438c2ecf20Sopenharmony_ci#ifdef CONFIG_INTC_BALANCING
1448c2ecf20Sopenharmony_civoid intc_balancing_enable(unsigned int irq);
1458c2ecf20Sopenharmony_civoid intc_balancing_disable(unsigned int irq);
1468c2ecf20Sopenharmony_civoid intc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
1478c2ecf20Sopenharmony_ci			  struct intc_desc_int *d, intc_enum id);
1488c2ecf20Sopenharmony_ci#else
1498c2ecf20Sopenharmony_cistatic inline void intc_balancing_enable(unsigned int irq) { }
1508c2ecf20Sopenharmony_cistatic inline void intc_balancing_disable(unsigned int irq) { }
1518c2ecf20Sopenharmony_cistatic inline void
1528c2ecf20Sopenharmony_ciintc_set_dist_handle(unsigned int irq, struct intc_desc *desc,
1538c2ecf20Sopenharmony_ci		     struct intc_desc_int *d, intc_enum id) { }
1548c2ecf20Sopenharmony_ci#endif
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/* chip.c */
1578c2ecf20Sopenharmony_ciextern struct irq_chip intc_irq_chip;
1588c2ecf20Sopenharmony_civoid _intc_enable(struct irq_data *data, unsigned long handle);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/* core.c */
1618c2ecf20Sopenharmony_ciextern struct list_head intc_list;
1628c2ecf20Sopenharmony_ciextern raw_spinlock_t intc_big_lock;
1638c2ecf20Sopenharmony_ciextern struct bus_type intc_subsys;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ciunsigned int intc_get_dfl_prio_level(void);
1668c2ecf20Sopenharmony_ciunsigned int intc_get_prio_level(unsigned int irq);
1678c2ecf20Sopenharmony_civoid intc_set_prio_level(unsigned int irq, unsigned int level);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci/* handle.c */
1708c2ecf20Sopenharmony_ciunsigned int intc_get_mask_handle(struct intc_desc *desc,
1718c2ecf20Sopenharmony_ci				  struct intc_desc_int *d,
1728c2ecf20Sopenharmony_ci				  intc_enum enum_id, int do_grps);
1738c2ecf20Sopenharmony_ciunsigned int intc_get_prio_handle(struct intc_desc *desc,
1748c2ecf20Sopenharmony_ci				  struct intc_desc_int *d,
1758c2ecf20Sopenharmony_ci				  intc_enum enum_id, int do_grps);
1768c2ecf20Sopenharmony_ciunsigned int intc_get_sense_handle(struct intc_desc *desc,
1778c2ecf20Sopenharmony_ci				   struct intc_desc_int *d,
1788c2ecf20Sopenharmony_ci				   intc_enum enum_id);
1798c2ecf20Sopenharmony_civoid intc_set_ack_handle(unsigned int irq, struct intc_desc *desc,
1808c2ecf20Sopenharmony_ci			 struct intc_desc_int *d, intc_enum id);
1818c2ecf20Sopenharmony_ciunsigned long intc_get_ack_handle(unsigned int irq);
1828c2ecf20Sopenharmony_civoid intc_enable_disable_enum(struct intc_desc *desc, struct intc_desc_int *d,
1838c2ecf20Sopenharmony_ci			      intc_enum enum_id, int enable);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/* irqdomain.c */
1868c2ecf20Sopenharmony_civoid intc_irq_domain_init(struct intc_desc_int *d, struct intc_hw_desc *hw);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/* virq.c */
1898c2ecf20Sopenharmony_civoid intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d);
1908c2ecf20Sopenharmony_civoid intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d);
1918c2ecf20Sopenharmony_cistruct intc_map_entry *intc_irq_xlate_get(unsigned int irq);
192