Skip to content

Commit 64a2b24

Browse files
maulik-k-shahsmankad-oss
authored andcommitted
FROMLIST: irqchip/qcom-pdc: Configure PDC to pass through mode
There are two modes PDC irqchip supports pass through mode and secondary controller mode. All PDC irqchip supports pass through mode in which both Direct SPIs and GPIO IRQs (as SPIs) are sent to GIC without latching at PDC. Newer PDCs (v3.0 onwards) also support additional secondary controller mode where PDC latches GPIO IRQs and sends to GIC as level type IRQ. Direct SPIs still works same as pass through mode without latching at PDC even in secondary controller mode. All the SoCs so far default uses pass through mode with the exception of x1e. x1e PDC may be set to secondary controller mode for builds on CRD boards whereas it may be set to pass through mode for IoT-EVK. There is no way to read which current mode it is set to and make PDC work in respective mode as the read access is not opened up for non secure world. There is though write access opened up via SCM write API to set the mode. Configure PDC mode to pass through mode for all x1e based boards via SCM write. Link: https://lore.kernel.org/r/20260312-hamoa_pdc-v1-3-760c8593ce50@oss.qualcomm.com Co-developed-by: Sneh Mankad <sneh.mankad@oss.qualcomm.com> Signed-off-by: Sneh Mankad <sneh.mankad@oss.qualcomm.com> Signed-off-by: Maulik Shah <maulik.shah@oss.qualcomm.com>
1 parent 388e0c1 commit 64a2b24

2 files changed

Lines changed: 111 additions & 9 deletions

File tree

drivers/irqchip/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,7 @@ config GOLDFISH_PIC
504504
config QCOM_PDC
505505
tristate "QCOM PDC"
506506
depends on ARCH_QCOM
507+
depends on QCOM_AOSS_QMP
507508
select IRQ_DOMAIN_HIERARCHY
508509
help
509510
Power Domain Controller driver to manage and configure wakeup

drivers/irqchip/qcom-pdc.c

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,32 @@
1919
#include <linux/spinlock.h>
2020
#include <linux/slab.h>
2121
#include <linux/types.h>
22+
#include <linux/firmware/qcom/qcom_scm.h>
23+
#include <linux/soc/qcom/qcom_aoss.h>
2224

2325
#define PDC_MAX_GPIO_IRQS 256
2426
#define PDC_DRV_OFFSET 0x10000
2527

2628
/* Valid only on HW version < 3.2 */
2729
#define IRQ_ENABLE_BANK 0x10
2830
#define IRQ_ENABLE_BANK_MAX (IRQ_ENABLE_BANK + BITS_TO_BYTES(PDC_MAX_GPIO_IRQS))
31+
#define IRQ_i_CFG_IRQ_MASK_3_0 3
2932
#define IRQ_i_CFG 0x110
3033

3134
/* Valid only on HW version >= 3.2 */
35+
#define IRQ_i_CFG_IRQ_MASK_3_2 4
3236
#define IRQ_i_CFG_IRQ_ENABLE 3
3337

3438
#define IRQ_i_CFG_TYPE_MASK GENMASK(2, 0)
3539

3640
#define PDC_VERSION_REG 0x1000
3741

3842
/* Notable PDC versions */
43+
#define PDC_VERSION_3_0 0x30000
3944
#define PDC_VERSION_3_2 0x30200
4045

46+
#define PDC_PASS_THROUGH_MODE 0
47+
4148
struct pdc_pin_region {
4249
u32 pin_base;
4350
u32 parent_base;
@@ -97,6 +104,33 @@ static void pdc_x1e_irq_enable_write(u32 bank, u32 enable)
97104
pdc_base_reg_write(base, IRQ_ENABLE_BANK, bank, enable);
98105
}
99106

107+
/*
108+
* The new mask bit controls whether the interrupt is to be forwarded to the
109+
* parent GIC in secondary controller mode. Writing the mask is do not care
110+
* when the PDC is set to pass through mode.
111+
*
112+
* As linux only makes so far make use of pass through mode set all IRQs
113+
* masked during probe.
114+
*/
115+
static void __pdc_mask_intr(int pin_out, bool mask)
116+
{
117+
unsigned long irq_cfg;
118+
int mask_bit;
119+
120+
/* Mask bit available from v3.0 */
121+
if (pdc_version < PDC_VERSION_3_0)
122+
return;
123+
124+
if (pdc_version < PDC_VERSION_3_2)
125+
mask_bit = IRQ_i_CFG_IRQ_MASK_3_0;
126+
else
127+
mask_bit = IRQ_i_CFG_IRQ_MASK_3_2;
128+
129+
irq_cfg = pdc_reg_read(IRQ_i_CFG, pin_out);
130+
__assign_bit(mask_bit, &irq_cfg, mask);
131+
pdc_reg_write(IRQ_i_CFG, pin_out, irq_cfg);
132+
}
133+
100134
static void __pdc_enable_intr(int pin_out, bool on)
101135
{
102136
unsigned long enable;
@@ -312,7 +346,6 @@ static const struct irq_domain_ops qcom_pdc_ops = {
312346
static int pdc_setup_pin_mapping(struct device_node *np)
313347
{
314348
int ret, n, i;
315-
316349
n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32));
317350
if (n <= 0 || n % 3)
318351
return -EINVAL;
@@ -341,8 +374,10 @@ static int pdc_setup_pin_mapping(struct device_node *np)
341374
if (ret)
342375
return ret;
343376

344-
for (i = 0; i < pdc_region[n].cnt; i++)
377+
for (i = 0; i < pdc_region[n].cnt; i++) {
345378
__pdc_enable_intr(i + pdc_region[n].pin_base, 0);
379+
__pdc_mask_intr(i + pdc_region[n].pin_base, true);
380+
}
346381
}
347382

348383
return 0;
@@ -352,10 +387,13 @@ static int pdc_setup_pin_mapping(struct device_node *np)
352387

353388
static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *parent)
354389
{
390+
static const char buf[64] = "{class: cx_mol, res: cx, val: mol}";
391+
unsigned int domain_flag = IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP;
355392
struct irq_domain *parent_domain, *pdc_domain;
356393
struct device_node *node = pdev->dev.of_node;
357394
resource_size_t res_size;
358395
struct resource res;
396+
struct qmp *pdc_qmp;
359397
int ret;
360398

361399
/* compat with old sm8150 DT which had very small region for PDC */
@@ -366,6 +404,13 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare
366404
if (res_size > resource_size(&res))
367405
pr_warn("%pOF: invalid reg size, please fix DT\n", node);
368406

407+
pdc_base = ioremap(res.start, res_size);
408+
if (!pdc_base) {
409+
pr_err("%pOF: unable to map PDC registers\n", node);
410+
ret = -ENXIO;
411+
goto fail;
412+
}
413+
369414
/*
370415
* PDC has multiple DRV regions, each one provides the same set of
371416
* registers for a particular client in the system. Due to a hardware
@@ -382,15 +427,71 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare
382427
}
383428

384429
pdc_x1e_quirk = true;
385-
}
386430

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;
431+
/*
432+
* There are two modes PDC irqchip can work in
433+
* - pass through mode
434+
* - secondary controller mode
435+
*
436+
* All PDC irqchip supports pass through mode in which both
437+
* Direct SPIs and GPIO IRQs (as SPIs) are sent to GIC
438+
* without latching at PDC.
439+
*
440+
* Newer PDCs (v3.0 onwards) also support additional
441+
* secondary controller mode where PDC latches GPIO IRQs
442+
* and sends to GIC as level type IRQ. Direct SPIs still
443+
* works same as pass through mode without latching at PDC
444+
* even in secondary controller mode.
445+
*
446+
* All the SoCs so far default uses pass through mode with
447+
* the exception of x1e.
448+
*
449+
* x1e modes:
450+
*
451+
* x1e PDC may be set to secondary controller mode for
452+
* builds on CRD boards whereas it may be set to pass
453+
* through mode for IoT-EVK boards.
454+
*
455+
* There is no way to read which current mode it is set to
456+
* and make PDC work in respective mode as the read access
457+
* is not opened up for non secure world. There is though
458+
* write access opened up via SCM write API to set the mode.
459+
*
460+
* Configure PDC mode to pass through mode for all x1e based
461+
* boards.
462+
*
463+
* For successful write:
464+
* - Nothing more to be done
465+
*
466+
* For unsuccessful write:
467+
* - Inform TLMM to monitor GPIO IRQs (same as MPM)
468+
* - Prevent SoC low power mode (CxPC) as PDC is not
469+
* monitoring GPIO IRQs which may be needed to wake
470+
* the SoC from low power mode.
471+
*/
472+
ret = of_address_to_resource(node, 2, &res);
473+
if (ret) {
474+
domain_flag = IRQ_DOMAIN_FLAG_QCOM_MPM_WAKEUP;
475+
goto skip_scm_write;
476+
}
477+
478+
ret = qcom_scm_io_writel(res.start, PDC_PASS_THROUGH_MODE);
479+
if (ret) {
480+
pdc_qmp = qmp_get(&pdev->dev);
481+
if (IS_ERR(pdc_qmp)) {
482+
ret = PTR_ERR(pdc_qmp);
483+
goto fail;
484+
} else {
485+
ret = qmp_send(pdc_qmp, buf, sizeof(buf));
486+
qmp_put(pdc_qmp);
487+
if (ret)
488+
goto fail;
489+
}
490+
domain_flag = IRQ_DOMAIN_FLAG_QCOM_MPM_WAKEUP;
491+
}
392492
}
393493

494+
skip_scm_write:
394495
pdc_version = pdc_reg_read(PDC_VERSION_REG, 0);
395496

396497
parent_domain = irq_find_host(parent);
@@ -407,7 +508,7 @@ static int qcom_pdc_probe(struct platform_device *pdev, struct device_node *pare
407508
}
408509

409510
pdc_domain = irq_domain_create_hierarchy(parent_domain,
410-
IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP,
511+
domain_flag,
411512
PDC_MAX_GPIO_IRQS,
412513
of_fwnode_handle(node),
413514
&qcom_pdc_ops, NULL);

0 commit comments

Comments
 (0)