Skip to content

Commit 692bea2

Browse files
authored
Configure Hamoa PDC to pass through mode and add PDC compatibility for Purwa (#423)
Configure Hamoa PDC to pass through mode and add PDC compatibility for Purwa
2 parents 8915fc6 + c344131 commit 692bea2

6 files changed

Lines changed: 136 additions & 17 deletions

File tree

Documentation/devicetree/bindings/interrupt-controller/qcom,pdc.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ properties:
5353
- qcom,sm8650-pdc
5454
- qcom,sm8750-pdc
5555
- qcom,x1e80100-pdc
56+
- qcom,x1p42100-pdc
5657
- const: qcom,pdc
5758

5859
reg:
5960
minItems: 1
6061
items:
6162
- description: PDC base register region
6263
- description: Edge or Level config register for SPI interrupts
64+
- description: PDC config for pass through or secondary IRQ mode for GPIOs
6365

6466
'#interrupt-cells':
6567
const: 2
@@ -80,6 +82,10 @@ properties:
8082
The tuples indicates the valid mapping of valid PDC ports
8183
and their hwirq mapping.
8284
85+
qcom,qmp:
86+
$ref: /schemas/types.yaml#/definitions/phandle
87+
description: Reference to the AOSS side-channel message RAM.
88+
8389
required:
8490
- compatible
8591
- reg

arch/arm64/boot/dts/qcom/hamoa.dtsi

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,14 @@
316316
exit-latency-us = <4000>;
317317
min-residency-us = <7000>;
318318
};
319+
320+
domain_ss3: domain-sleep-0 {
321+
compatible = "domain-idle-state";
322+
arm,psci-suspend-param = <0x0200c354>;
323+
entry-latency-us = <2800>;
324+
exit-latency-us = <4400>;
325+
min-residency-us = <9000>;
326+
};
319327
};
320328
};
321329

@@ -334,8 +342,7 @@
334342
firmware {
335343
scm: scm {
336344
compatible = "qcom,scm-x1e80100", "qcom,scm";
337-
interconnects = <&aggre2_noc MASTER_CRYPTO QCOM_ICC_TAG_ALWAYS
338-
&mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
345+
/* TODO: add interconnects */
339346
qcom,dload-mode = <&tcsr 0x19000>;
340347
};
341348

@@ -462,7 +469,7 @@
462469

463470
system_pd: power-domain-system {
464471
#power-domain-cells = <0>;
465-
/* TODO: system-wide idle states */
472+
domain-idle-states = <&domain_ss3>;
466473
};
467474

468475
reboot-mode {
@@ -6493,8 +6500,10 @@
64936500

64946501
pdc: interrupt-controller@b220000 {
64956502
compatible = "qcom,x1e80100-pdc", "qcom,pdc";
6496-
reg = <0 0x0b220000 0 0x30000>, <0 0x174000f0 0 0x64>;
6497-
6503+
reg = <0 0x0b220000 0 0x30000>,
6504+
<0 0x174000f0 0 0x64>,
6505+
<0 0x0b2045e8 0 0x4>;
6506+
qcom,qmp = <&aoss_qmp>;
64986507
qcom,pdc-ranges = <0 480 42>, <42 251 5>,
64996508
<47 522 52>, <99 609 32>,
65006509
<131 717 12>, <143 816 19>;

arch/arm64/boot/dts/qcom/purwa.dtsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@
164164
compatible = "qcom,x1p42100-qmp-gen4x4-pcie-phy";
165165
};
166166

167+
&pdc {
168+
compatible = "qcom,x1p42100-pdc", "qcom,pdc";
169+
};
170+
167171
&qfprom {
168172
gpu_speed_bin: gpu-speed-bin@119 {
169173
reg = <0x119 0x2>;

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);

drivers/pinctrl/qcom/pinctrl-x1e80100.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,9 +1839,7 @@ static const struct msm_pinctrl_soc_data x1e80100_pinctrl = {
18391839
.ngroups = ARRAY_SIZE(x1e80100_groups),
18401840
.ngpios = 239,
18411841
.wakeirq_map = x1e80100_pdc_map,
1842-
/* TODO: Enabling PDC currently breaks GPIO interrupts */
1843-
.nwakeirq_map = 0,
1844-
/* .nwakeirq_map = ARRAY_SIZE(x1e80100_pdc_map), */
1842+
.nwakeirq_map = ARRAY_SIZE(x1e80100_pdc_map),
18451843
.egpio_func = 9,
18461844
};
18471845

0 commit comments

Comments
 (0)