1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
7 #include <linux/init.h>
9 #include <linux/irqchip.h>
10 #include <linux/irqdomain.h>
12 #include <linux/kernel.h>
14 #include <linux/of_address.h>
15 #include <linux/of_device.h>
16 #include <linux/spinlock.h>
17 #include <linux/platform_device.h>
18 #include <linux/slab.h>
19 #include <linux/types.h>
21 #define PDC_MAX_IRQS 126
23 #define CLEAR_INTR(reg, intr) (reg & ~(1 << intr))
24 #define ENABLE_INTR(reg, intr) (reg | (1 << intr))
26 #define IRQ_ENABLE_BANK 0x10
27 #define IRQ_i_CFG 0x110
29 struct pdc_pin_region
{
35 static DEFINE_RAW_SPINLOCK(pdc_lock
);
36 static void __iomem
*pdc_base
;
37 static struct pdc_pin_region
*pdc_region
;
38 static int pdc_region_cnt
;
40 static void pdc_reg_write(int reg
, u32 i
, u32 val
)
42 writel_relaxed(val
, pdc_base
+ reg
+ i
* sizeof(u32
));
45 static u32
pdc_reg_read(int reg
, u32 i
)
47 return readl_relaxed(pdc_base
+ reg
+ i
* sizeof(u32
));
50 static void pdc_enable_intr(struct irq_data
*d
, bool on
)
52 int pin_out
= d
->hwirq
;
59 raw_spin_lock(&pdc_lock
);
60 enable
= pdc_reg_read(IRQ_ENABLE_BANK
, index
);
61 enable
= on
? ENABLE_INTR(enable
, mask
) : CLEAR_INTR(enable
, mask
);
62 pdc_reg_write(IRQ_ENABLE_BANK
, index
, enable
);
63 raw_spin_unlock(&pdc_lock
);
66 static void qcom_pdc_gic_mask(struct irq_data
*d
)
68 pdc_enable_intr(d
, false);
69 irq_chip_mask_parent(d
);
72 static void qcom_pdc_gic_unmask(struct irq_data
*d
)
74 pdc_enable_intr(d
, true);
75 irq_chip_unmask_parent(d
);
79 * GIC does not handle falling edge or active low. To allow falling edge and
80 * active low interrupts to be handled at GIC, PDC has an inverter that inverts
81 * falling edge into a rising edge and active low into an active high.
82 * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to
83 * set as per the table below.
84 * Level sensitive active low LOW
85 * Rising edge sensitive NOT USED
86 * Falling edge sensitive LOW
87 * Dual Edge sensitive NOT USED
88 * Level sensitive active High HIGH
89 * Falling Edge sensitive NOT USED
90 * Rising edge sensitive HIGH
91 * Dual Edge sensitive HIGH
93 enum pdc_irq_config_bits
{
94 PDC_LEVEL_LOW
= 0b000,
95 PDC_EDGE_FALLING
= 0b010,
96 PDC_LEVEL_HIGH
= 0b100,
97 PDC_EDGE_RISING
= 0b110,
98 PDC_EDGE_DUAL
= 0b111,
102 * qcom_pdc_gic_set_type: Configure PDC for the interrupt
104 * @d: the interrupt data
105 * @type: the interrupt type
107 * If @type is edge triggered, forward that as Rising edge as PDC
108 * takes care of converting falling edge to rising edge signal
109 * If @type is level, then forward that as level high as PDC
110 * takes care of converting falling edge to rising edge signal
112 static int qcom_pdc_gic_set_type(struct irq_data
*d
, unsigned int type
)
114 int pin_out
= d
->hwirq
;
115 enum pdc_irq_config_bits pdc_type
;
118 case IRQ_TYPE_EDGE_RISING
:
119 pdc_type
= PDC_EDGE_RISING
;
121 case IRQ_TYPE_EDGE_FALLING
:
122 pdc_type
= PDC_EDGE_FALLING
;
123 type
= IRQ_TYPE_EDGE_RISING
;
125 case IRQ_TYPE_EDGE_BOTH
:
126 pdc_type
= PDC_EDGE_DUAL
;
128 case IRQ_TYPE_LEVEL_HIGH
:
129 pdc_type
= PDC_LEVEL_HIGH
;
131 case IRQ_TYPE_LEVEL_LOW
:
132 pdc_type
= PDC_LEVEL_LOW
;
133 type
= IRQ_TYPE_LEVEL_HIGH
;
140 pdc_reg_write(IRQ_i_CFG
, pin_out
, pdc_type
);
142 return irq_chip_set_type_parent(d
, type
);
145 static struct irq_chip qcom_pdc_gic_chip
= {
147 .irq_eoi
= irq_chip_eoi_parent
,
148 .irq_mask
= qcom_pdc_gic_mask
,
149 .irq_unmask
= qcom_pdc_gic_unmask
,
150 .irq_retrigger
= irq_chip_retrigger_hierarchy
,
151 .irq_set_type
= qcom_pdc_gic_set_type
,
152 .flags
= IRQCHIP_MASK_ON_SUSPEND
|
153 IRQCHIP_SET_TYPE_MASKED
|
154 IRQCHIP_SKIP_SET_WAKE
,
155 .irq_set_vcpu_affinity
= irq_chip_set_vcpu_affinity_parent
,
156 .irq_set_affinity
= irq_chip_set_affinity_parent
,
159 static irq_hw_number_t
get_parent_hwirq(int pin
)
162 struct pdc_pin_region
*region
;
164 for (i
= 0; i
< pdc_region_cnt
; i
++) {
165 region
= &pdc_region
[i
];
166 if (pin
>= region
->pin_base
&&
167 pin
< region
->pin_base
+ region
->cnt
)
168 return (region
->parent_base
+ pin
- region
->pin_base
);
175 static int qcom_pdc_translate(struct irq_domain
*d
, struct irq_fwspec
*fwspec
,
176 unsigned long *hwirq
, unsigned int *type
)
178 if (is_of_node(fwspec
->fwnode
)) {
179 if (fwspec
->param_count
!= 2)
182 *hwirq
= fwspec
->param
[0];
183 *type
= fwspec
->param
[1] & IRQ_TYPE_SENSE_MASK
;
190 static int qcom_pdc_alloc(struct irq_domain
*domain
, unsigned int virq
,
191 unsigned int nr_irqs
, void *data
)
193 struct irq_fwspec
*fwspec
= data
;
194 struct irq_fwspec parent_fwspec
;
195 irq_hw_number_t hwirq
, parent_hwirq
;
199 ret
= qcom_pdc_translate(domain
, fwspec
, &hwirq
, &type
);
203 parent_hwirq
= get_parent_hwirq(hwirq
);
204 if (parent_hwirq
== ~0UL)
207 ret
= irq_domain_set_hwirq_and_chip(domain
, virq
, hwirq
,
208 &qcom_pdc_gic_chip
, NULL
);
212 if (type
& IRQ_TYPE_EDGE_BOTH
)
213 type
= IRQ_TYPE_EDGE_RISING
;
215 if (type
& IRQ_TYPE_LEVEL_MASK
)
216 type
= IRQ_TYPE_LEVEL_HIGH
;
218 parent_fwspec
.fwnode
= domain
->parent
->fwnode
;
219 parent_fwspec
.param_count
= 3;
220 parent_fwspec
.param
[0] = 0;
221 parent_fwspec
.param
[1] = parent_hwirq
;
222 parent_fwspec
.param
[2] = type
;
224 return irq_domain_alloc_irqs_parent(domain
, virq
, nr_irqs
,
228 static const struct irq_domain_ops qcom_pdc_ops
= {
229 .translate
= qcom_pdc_translate
,
230 .alloc
= qcom_pdc_alloc
,
231 .free
= irq_domain_free_irqs_common
,
234 static int pdc_setup_pin_mapping(struct device_node
*np
)
238 n
= of_property_count_elems_of_size(np
, "qcom,pdc-ranges", sizeof(u32
));
242 pdc_region_cnt
= n
/ 3;
243 pdc_region
= kcalloc(pdc_region_cnt
, sizeof(*pdc_region
), GFP_KERNEL
);
249 for (n
= 0; n
< pdc_region_cnt
; n
++) {
250 ret
= of_property_read_u32_index(np
, "qcom,pdc-ranges",
252 &pdc_region
[n
].pin_base
);
255 ret
= of_property_read_u32_index(np
, "qcom,pdc-ranges",
257 &pdc_region
[n
].parent_base
);
260 ret
= of_property_read_u32_index(np
, "qcom,pdc-ranges",
270 static int qcom_pdc_init(struct device_node
*node
, struct device_node
*parent
)
272 struct irq_domain
*parent_domain
, *pdc_domain
;
275 pdc_base
= of_iomap(node
, 0);
277 pr_err("%pOF: unable to map PDC registers\n", node
);
281 parent_domain
= irq_find_host(parent
);
282 if (!parent_domain
) {
283 pr_err("%pOF: unable to find PDC's parent domain\n", node
);
288 ret
= pdc_setup_pin_mapping(node
);
290 pr_err("%pOF: failed to init PDC pin-hwirq mapping\n", node
);
294 pdc_domain
= irq_domain_create_hierarchy(parent_domain
, 0, PDC_MAX_IRQS
,
295 of_fwnode_handle(node
),
296 &qcom_pdc_ops
, NULL
);
298 pr_err("%pOF: GIC domain add failed\n", node
);
311 IRQCHIP_DECLARE(pdc_sdm845
, "qcom,sdm845-pdc", qcom_pdc_init
);