diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c index e83da6df394f..e013d9cd5132 100644 --- a/drivers/irqchip/qcom-pdc.c +++ b/drivers/irqchip/qcom-pdc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -29,6 +30,14 @@ #define IRQ_ENABLE_BANK 0x10 #define IRQ_i_CFG 0x110 +#define IRQ_i_CFG_IRQ_ENABLE BIT(3) +#define IRQ_i_CFG_TYPE_MASK 0x7 + +#define VERSION 0x1000 +#define MAJOR_VER_MASK 0xFF +#define MAJOR_VER_SHIFT 16 +#define MINOR_VER_MASK 0xFF +#define MINOR_VER_SHIFT 8 struct pdc_pin_region { u32 pin_base; @@ -53,6 +62,7 @@ static struct pdc_pin_region *pdc_region; static int pdc_region_cnt; static struct spi_cfg_regs *spi_cfg; static void *pdc_ipc_log; +static bool enable_in_cfg; static u32 __spi_pin_read(unsigned int pin) { @@ -125,15 +135,21 @@ static void pdc_enable_intr(struct irq_data *d, bool on) unsigned long flags; u32 index, mask; - index = pin_out / 32; - mask = pin_out % 32; - raw_spin_lock_irqsave(&pdc_lock, flags); - enable = pdc_reg_read(IRQ_ENABLE_BANK, index); - __assign_bit(mask, &enable, on); - pdc_reg_write(IRQ_ENABLE_BANK, index, enable); - ipc_log_string(pdc_ipc_log, "PIN=%d enable=%d", d->hwirq, on); + if (!enable_in_cfg) { + index = pin_out / 32; + mask = pin_out % 32; + enable = pdc_reg_read(IRQ_ENABLE_BANK, index); + __assign_bit(mask, &enable, on); + pdc_reg_write(IRQ_ENABLE_BANK, index, enable); + } else { + index = d->hwirq; + enable = pdc_reg_read(IRQ_i_CFG, index); + __assign_bit(IRQ_i_CFG_IRQ_ENABLE, &enable, on); + pdc_reg_write(IRQ_i_CFG, index, enable); + } raw_spin_unlock_irqrestore(&pdc_lock, flags); + ipc_log_string(pdc_ipc_log, "PIN=%d enable=%d", d->hwirq, on); } static void qcom_pdc_gic_disable(struct irq_data *d) @@ -214,6 +230,7 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) } old_pdc_type = pdc_reg_read(IRQ_i_CFG, d->hwirq); + pdc_type |= (old_pdc_type & ~IRQ_i_CFG_TYPE_MASK); pdc_reg_write(IRQ_i_CFG, d->hwirq, pdc_type); ipc_log_string(pdc_ipc_log, "Set type: PIN=%d pdc_type=%d gic_type=%d", d->hwirq, pdc_type, type); @@ -325,8 +342,8 @@ static const struct irq_domain_ops qcom_pdc_ops = { static int pdc_setup_pin_mapping(struct device_node *np) { - int ret, n, i; - u32 irq_index, reg_index, val; + int ret, n, i, last_region; + u32 irq_index, reg_index, val, max_irq; n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32)); if (n <= 0 || n % 3) @@ -355,14 +372,25 @@ static int pdc_setup_pin_mapping(struct device_node *np) &pdc_region[n].cnt); if (ret) return ret; + } - for (i = 0; i < pdc_region[n].cnt; i++) { + last_region = pdc_region_cnt - 1; + max_irq = pdc_region[last_region].pin_base + pdc_region[last_region].cnt; + + if (!enable_in_cfg) { + for (i = 0; i < max_irq; i++) { reg_index = (i + pdc_region[n].pin_base) >> 5; irq_index = (i + pdc_region[n].pin_base) & 0x1f; val = pdc_reg_read(IRQ_ENABLE_BANK, reg_index); val &= ~BIT(irq_index); pdc_reg_write(IRQ_ENABLE_BANK, reg_index, val); } + } else { + for (i = 0; i < max_irq; i++) { + val = pdc_reg_read(IRQ_i_CFG, i); + val &= ~IRQ_i_CFG_IRQ_ENABLE; + pdc_reg_write(IRQ_i_CFG, i, val); + } } return 0; @@ -373,6 +401,7 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) struct irq_domain *parent_domain, *pdc_domain; struct resource res; int ret; + u32 version, major_ver, minor_ver; pdc_base = of_iomap(node, 0); if (!pdc_base) { @@ -380,6 +409,16 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) return -ENXIO; } + version = pdc_reg_read(VERSION, 0); + major_ver = version & (MAJOR_VER_MASK << MAJOR_VER_SHIFT); + major_ver >>= MAJOR_VER_SHIFT; + minor_ver = version & (MINOR_VER_MASK << MINOR_VER_SHIFT); + minor_ver >>= MINOR_VER_SHIFT; + if (major_ver >= 3 && minor_ver > 1) + enable_in_cfg = true; + else + enable_in_cfg = false; + parent_domain = irq_find_host(parent); if (!parent_domain) { pr_err("%pOF: unable to find PDC's parent domain\n", node);