File Index
Files and directories
Sign in
FILE

qcom-pdc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/irqchip/qcom-pdc.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  4 */
  5
  6#include <linux/err.h>
  7#include <linux/init.h>
  8#include <linux/interrupt.h>
  9#include <linux/irq.h>
 10#include <linux/irqchip.h>
 11#include <linux/irqdomain.h>
 12#include <linux/io.h>
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/of.h>
 16#include <linux/of_address.h>
 17#include <linux/of_irq.h>
 18#include <linux/soc/qcom/irq.h>
 19#include <linux/spinlock.h>
 20#include <linux/slab.h>
 21#include <linux/types.h>
 22
 23#define PDC_MAX_GPIO_IRQS	256
 24#define PDC_DRV_OFFSET		0x10000
 25
 26/* Valid only on HW version < 3.2 */
 27#define IRQ_ENABLE_BANK		0x10
 28#define IRQ_ENABLE_BANK_MAX	(IRQ_ENABLE_BANK + BITS_TO_BYTES(PDC_MAX_GPIO_IRQS))
 29#define IRQ_i_CFG		0x110
 30
 31/* Valid only on HW version >= 3.2 */
 32#define IRQ_i_CFG_IRQ_ENABLE	3
 33
 34#define IRQ_i_CFG_TYPE_MASK	GENMASK(2, 0)
 35
 36#define PDC_VERSION_REG		0x1000
 37
 38/* Notable PDC versions */
 39#define PDC_VERSION_3_2		0x30200
 40
 41struct pdc_pin_region {
 42	u32 pin_base;
 43	u32 parent_base;
 44	u32 cnt;
 45};
 46
 47#define pin_to_hwirq(r, p)	((r)->parent_base + (p) - (r)->pin_base)
 48
 49static DEFINE_RAW_SPINLOCK(pdc_lock);
 50static void __iomem *pdc_base;
 51static void __iomem *pdc_prev_base;
 52static struct pdc_pin_region *pdc_region;
 53static int pdc_region_cnt;
 54static unsigned int pdc_version;
 55static bool pdc_x1e_quirk;
 56
 57static void pdc_base_reg_write(void __iomem *base, int reg, u32 i, u32 val)
 58{
 59	writel_relaxed(val, base + reg + i * sizeof(u32));
 60}
 61
 62static void pdc_reg_write(int reg, u32 i, u32 val)
 63{
 64	pdc_base_reg_write(pdc_base, reg, i, val);
 65}
 66
 67static u32 pdc_reg_read(int reg, u32 i)
 68{
 69	return readl_relaxed(pdc_base + reg + i * sizeof(u32));
 70}
 71
 72static void pdc_x1e_irq_enable_write(u32 bank, u32 enable)
 73{
 74	void __iomem *base;
 75
 76	/* Remap the write access to work around a hardware bug on X1E */
 77	switch (bank) {
 78	case 0 ... 1:
 79		/* Use previous DRV (client) region and shift to bank 3-4 */
 80		base = pdc_prev_base;
 81		bank += 3;
 82		break;
 83	case 2 ... 4:
 84		/* Use our own region and shift to bank 0-2 */
 85		base = pdc_base;
 86		bank -= 2;
 87		break;
 88	case 5:
 89		/* No fixup required for bank 5 */
 90		base = pdc_base;
 91		break;
 92	default:
 93		WARN_ON(1);
 94		return;
 95	}
 96
 97	pdc_base_reg_write(base, IRQ_ENABLE_BANK, bank, enable);
 98}
 99
100static void __pdc_enable_intr(int pin_out, bool on)
101{
102	unsigned long enable;
103
104	if (pdc_version < PDC_VERSION_3_2) {
105		u32 index, mask;
106
107		index = pin_out / 32;
108		mask = pin_out % 32;
109
110		enable = pdc_reg_read(IRQ_ENABLE_BANK, index);
111		__assign_bit(mask, &enable, on);
112
113		if (pdc_x1e_quirk)
114			pdc_x1e_irq_enable_write(index, enable);
115		else
116			pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
117	} else {
118		enable = pdc_reg_read(IRQ_i_CFG, pin_out);
119		__assign_bit(IRQ_i_CFG_IRQ_ENABLE, &enable, on);
120		pdc_reg_write(IRQ_i_CFG, pin_out, enable);
121	}
122}
123
124static void pdc_enable_intr(struct irq_data *d, bool on)
125{
126	unsigned long flags;
127
128	raw_spin_lock_irqsave(&pdc_lock, flags);
129	__pdc_enable_intr(d->hwirq, on);
130	raw_spin_unlock_irqrestore(&pdc_lock, flags);
131}
132
133static void qcom_pdc_gic_disable(struct irq_data *d)
134{
135	pdc_enable_intr(d, false);
136	irq_chip_disable_parent(d);
137}
138
139static void qcom_pdc_gic_enable(struct irq_data *d)
140{
141	pdc_enable_intr(d, true);
142	irq_chip_enable_parent(d);
143}
144
145/*
146 * GIC does not handle falling edge or active low. To allow falling edge and
147 * active low interrupts to be handled at GIC, PDC has an inverter that inverts
148 * falling edge into a rising edge and active low into an active high.
149 * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to
150 * set as per the table below.
151 * Level sensitive active low    LOW
152 * Rising edge sensitive         NOT USED
153 * Falling edge sensitive        LOW
154 * Dual Edge sensitive           NOT USED
155 * Level sensitive active High   HIGH
156 * Falling Edge sensitive        NOT USED
157 * Rising edge sensitive         HIGH
158 * Dual Edge sensitive           HIGH
159 */
160enum pdc_irq_config_bits {
161	PDC_LEVEL_LOW		= 0b000,
162	PDC_EDGE_FALLING	= 0b010,
163	PDC_LEVEL_HIGH		= 0b100,
164	PDC_EDGE_RISING		= 0b110,
165	PDC_EDGE_DUAL		= 0b111,
166};
167
168/**
169 * qcom_pdc_gic_set_type: Configure PDC for the interrupt
170 *
171 * @d: the interrupt data
172 * @type: the interrupt type
173 *
174 * If @type is edge triggered, forward that as Rising edge as PDC
175 * takes care of converting falling edge to rising edge signal
176 * If @type is level, then forward that as level high as PDC
177 * takes care of converting falling edge to rising edge signal
178 */
179static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
180{
181	enum pdc_irq_config_bits pdc_type;
182	enum pdc_irq_config_bits old_pdc_type;
183	int ret;
184
185	switch (type) {
186	case IRQ_TYPE_EDGE_RISING:
187		pdc_type = PDC_EDGE_RISING;
188		break;
189	case IRQ_TYPE_EDGE_FALLING:
190		pdc_type = PDC_EDGE_FALLING;
191		type = IRQ_TYPE_EDGE_RISING;
192		break;
193	case IRQ_TYPE_EDGE_BOTH:
194		pdc_type = PDC_EDGE_DUAL;
195		type = IRQ_TYPE_EDGE_RISING;
196		break;
197	case IRQ_TYPE_LEVEL_HIGH:
198		pdc_type = PDC_LEVEL_HIGH;
199		break;
200	case IRQ_TYPE_LEVEL_LOW:
201		pdc_type = PDC_LEVEL_LOW;
202		type = IRQ_TYPE_LEVEL_HIGH;
203		break;
204	default:
205		WARN_ON(1);
206		return -EINVAL;
207	}
208
209	old_pdc_type = pdc_reg_read(IRQ_i_CFG, d->hwirq);
210	pdc_type |= (old_pdc_type & ~IRQ_i_CFG_TYPE_MASK);
211	pdc_reg_write(IRQ_i_CFG, d->hwirq, pdc_type);
212
213	ret = irq_chip_set_type_parent(d, type);
214	if (ret)
215		return ret;
216
217	/*
218	 * When we change types the PDC can give a phantom interrupt.
219	 * Clear it.  Specifically the phantom shows up when reconfiguring
220	 * polarity of interrupt without changing the state of the signal
221	 * but let's be consistent and clear it always.
222	 *
223	 * Doing this works because we have IRQCHIP_SET_TYPE_MASKED so the
224	 * interrupt will be cleared before the rest of the system sees it.
225	 */
226	if (old_pdc_type != pdc_type)
227		irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false);
228
229	return 0;
230}
231
232static struct irq_chip qcom_pdc_gic_chip = {
233	.name			= "PDC",
234	.irq_eoi		= irq_chip_eoi_parent,
235	.irq_mask		= irq_chip_mask_parent,
236	.irq_unmask		= irq_chip_unmask_parent,
237	.irq_disable		= qcom_pdc_gic_disable,
238	.irq_enable		= qcom_pdc_gic_enable,
239	.irq_get_irqchip_state	= irq_chip_get_parent_state,
240	.irq_set_irqchip_state	= irq_chip_set_parent_state,
241	.irq_retrigger		= irq_chip_retrigger_hierarchy,
242	.irq_set_type		= qcom_pdc_gic_set_type,
243	.flags			= IRQCHIP_MASK_ON_SUSPEND |
244				  IRQCHIP_SET_TYPE_MASKED |
245				  IRQCHIP_SKIP_SET_WAKE |
246				  IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,
247	.irq_set_vcpu_affinity	= irq_chip_set_vcpu_affinity_parent,
248	.irq_set_affinity	= irq_chip_set_affinity_parent,
249};
250
251static struct pdc_pin_region *get_pin_region(int pin)
252{
253	int i;
254
255	for (i = 0; i < pdc_region_cnt; i++) {
256		if (pin >= pdc_region[i].pin_base &&
257		    pin < pdc_region[i].pin_base + pdc_region[i].cnt)
258			return &pdc_region[i];
259	}
260
261	return NULL;
262}
263
264static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq,
265			  unsigned int nr_irqs, void *data)
266{
267	struct irq_fwspec *fwspec = data;
268	struct irq_fwspec parent_fwspec;
269	struct pdc_pin_region *region;
270	irq_hw_number_t hwirq;
271	unsigned int type;
272	int ret;
273
274	ret = irq_domain_translate_twocell(domain, fwspec, &hwirq, &type);
275	if (ret)
276		return ret;
277
278	if (hwirq == GPIO_NO_WAKE_IRQ)
279		return irq_domain_disconnect_hierarchy(domain, virq);
280
281	ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
282					    &qcom_pdc_gic_chip, NULL);
283	if (ret)
284		return ret;
285
286	region = get_pin_region(hwirq);
287	if (!region)
288		return irq_domain_disconnect_hierarchy(domain->parent, virq);
289
290	if (type & IRQ_TYPE_EDGE_BOTH)
291		type = IRQ_TYPE_EDGE_RISING;
292
293	if (type & IRQ_TYPE_LEVEL_MASK)
294		type = IRQ_TYPE_LEVEL_HIGH;
295
296	parent_fwspec.fwnode      = domain->parent->fwnode;
297	parent_fwspec.param_count = 3;
298	parent_fwspec.param[0]    = 0;
299	parent_fwspec.param[1]    = pin_to_hwirq(region, hwirq);
300	parent_fwspec.param[2]    = type;
301
302	return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
303					    &parent_fwspec);
304}
305
306static const struct irq_domain_ops qcom_pdc_ops = {
307	.translate	= irq_domain_translate_twocell,
308	.alloc		= qcom_pdc_alloc,
309	.free		= irq_domain_free_irqs_common,
310};
311
312static int pdc_setup_pin_mapping(struct device_node *np)
313{
314	int ret, n, i;
315
316	n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32));
317	if (n <= 0 || n % 3)
318		return -EINVAL;
319
320	pdc_region_cnt = n / 3;
321	pdc_region = kcalloc(pdc_region_cnt, sizeof(*pdc_region), GFP_KERNEL);
322	if (!pdc_region) {
323		pdc_region_cnt = 0;
324		return -ENOMEM;
325	}
326
327	for (n = 0; n < pdc_region_cnt; n++) {
328		ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
329						 n * 3 + 0,
330						 &pdc_region[n].pin_base);
331		if (ret)
332			return ret;
333		ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
334						 n * 3 + 1,
335						 &pdc_region[n].parent_base);
336		if (ret)
337			return ret;
338		ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
339						 n * 3 + 2,
340						 &pdc_region[n].cnt);
341		if (ret)
342			return ret;
343
344		for (i = 0; i < pdc_region[n].cnt; i++)
345			__pdc_enable_intr(i + pdc_region[n].pin_base, 0);
346	}
347
348	return 0;
349}
350
351#define QCOM_PDC_SIZE 0x30000
352
353static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *parent)
354{
355	struct irq_domain *parent_domain, *pdc_domain;
356	struct device_node *node = pdev->dev.of_node;
357	resource_size_t res_size;
358	struct resource res;
359	int ret;
360
361	/* compat with old sm8150 DT which had very small region for PDC */
362	if (of_address_to_resource(node, 0, &res))
363		return -EINVAL;
364
365	res_size = max_t(resource_size_t, resource_size(&res), QCOM_PDC_SIZE);
366	if (res_size > resource_size(&res))
367		pr_warn("%pOF: invalid reg size, please fix DT\n", node);
368
369	/*
370	 * PDC has multiple DRV regions, each one provides the same set of
371	 * registers for a particular client in the system. Due to a hardware
372	 * bug on X1E, some writes to the IRQ_ENABLE_BANK register must be
373	 * issued inside the previous region. This region belongs to
374	 * a different client and is not described in the device tree. Map the
375	 * region with the expected offset to preserve support for old DTs.
376	 */
377	if (of_device_is_compatible(node, "qcom,x1e80100-pdc")) {
378		pdc_prev_base = ioremap(res.start - PDC_DRV_OFFSET, IRQ_ENABLE_BANK_MAX);
379		if (!pdc_prev_base) {
380			pr_err("%pOF: unable to map previous PDC DRV region\n", node);
381			return -ENXIO;
382		}
383
384		pdc_x1e_quirk = true;
385	}
386
387	pdc_base = ioremap(res.start, res_size);
388	if (!pdc_base) {
389		pr_err("%pOF: unable to map PDC registers\n", node);
390		ret = -ENXIO;
391		goto fail;
392	}
393
394	pdc_version = pdc_reg_read(PDC_VERSION_REG, 0);
395
396	parent_domain = irq_find_host(parent);
397	if (!parent_domain) {
398		pr_err("%pOF: unable to find PDC's parent domain\n", node);
399		ret = -ENXIO;
400		goto fail;
401	}
402
403	ret = pdc_setup_pin_mapping(node);
404	if (ret) {
405		pr_err("%pOF: failed to init PDC pin-hwirq mapping\n", node);
406		goto fail;
407	}
408
409	pdc_domain = irq_domain_create_hierarchy(parent_domain,
410					IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP,
411					PDC_MAX_GPIO_IRQS,
412					of_fwnode_handle(node),
413					&qcom_pdc_ops, NULL);
414	if (!pdc_domain) {
415		pr_err("%pOF: PDC domain add failed\n", node);
416		ret = -ENOMEM;
417		goto fail;
418	}
419
420	irq_domain_update_bus_token(pdc_domain, DOMAIN_BUS_WAKEUP);
421
422	return 0;
423
424fail:
425	kfree(pdc_region);
426	iounmap(pdc_base);
427	iounmap(pdc_prev_base);
428	return ret;
429}
430
431IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc)
432IRQCHIP_MATCH("qcom,pdc", qcom_pdc_probe)
433IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc)
434MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
435MODULE_LICENSE("GPL v2");
~/ Read-only file preview.