Loading drivers/irqchip/qcom-pdc.c +96 −4 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/err.h> #include <linux/init.h> #include <linux/ipc_logging.h> #include <linux/irq.h> #include <linux/irqchip.h> #include <linux/irqdomain.h> Loading @@ -18,6 +19,8 @@ #include <linux/slab.h> #include <linux/types.h> #define PDC_IPC_LOG_SZ 2 #define PDC_MAX_IRQS 138 #define PDC_MAX_GPIO_IRQS 256 Loading @@ -36,9 +39,11 @@ struct pdc_pin_region { }; static DEFINE_RAW_SPINLOCK(pdc_lock); static void __iomem *pdc_base; static void __iomem *pdc_base, *pdc_cfg_base; static struct pdc_pin_region *pdc_region; static int pdc_region_cnt; static resource_size_t pdc_cfg_size; static void *pdc_ipc_log; static void pdc_reg_write(int reg, u32 i, u32 val) { Loading @@ -63,15 +68,34 @@ static void pdc_enable_intr(struct irq_data *d, bool on) enable = pdc_reg_read(IRQ_ENABLE_BANK, index); enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask); pdc_reg_write(IRQ_ENABLE_BANK, index, enable); ipc_log_string(pdc_ipc_log, "PIN=%d enable=%d", d->hwirq, on); raw_spin_unlock(&pdc_lock); } static void qcom_pdc_gic_mask(struct irq_data *d) static void qcom_pdc_gic_disable(struct irq_data *d) { if (d->hwirq == GPIO_NO_WAKE_IRQ) return; pdc_enable_intr(d, false); irq_chip_disable_parent(d); } static void qcom_pdc_gic_enable(struct irq_data *d) { if (d->hwirq == GPIO_NO_WAKE_IRQ) return; pdc_enable_intr(d, true); irq_chip_enable_parent(d); } static void qcom_pdc_gic_mask(struct irq_data *d) { if (d->hwirq == GPIO_NO_WAKE_IRQ) return; ipc_log_string(pdc_ipc_log, "PIN=%d mask", d->hwirq); irq_chip_mask_parent(d); } Loading @@ -80,10 +104,37 @@ static void qcom_pdc_gic_unmask(struct irq_data *d) if (d->hwirq == GPIO_NO_WAKE_IRQ) return; pdc_enable_intr(d, true); ipc_log_string(pdc_ipc_log, "PIN=%d unmask", d->hwirq); irq_chip_unmask_parent(d); } static int spi_configure_type(irq_hw_number_t hwirq, unsigned int type) { int spi = hwirq - 32; unsigned int pin = spi / 32; unsigned int mask = BIT(spi % 32); void __iomem *cfg_reg = pdc_cfg_base + pin * 4; unsigned int val; unsigned long flags; if (pin * 4 > pdc_cfg_size) return -EFAULT; raw_spin_lock_irqsave(&pdc_lock, flags); val = readl_relaxed(cfg_reg); rmb(); /* Ensure the read is complete before modifying */ val &= ~mask; if (type & IRQ_TYPE_LEVEL_MASK) val |= mask; writel_relaxed(val, cfg_reg); ipc_log_string(pdc_ipc_log, "SPI config: GIC-SPI=%d (reg=%d,bit=%d) val=%d", spi, pin, spi % 32, type & IRQ_TYPE_LEVEL_MASK); raw_spin_unlock_irqrestore(&pdc_lock, flags); return 0; } /* * GIC does not handle falling edge or active low. To allow falling edge and * active low interrupts to be handled at GIC, PDC has an inverter that inverts Loading Loading @@ -121,7 +172,9 @@ enum pdc_irq_config_bits { static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) { int pin_out = d->hwirq; int parent_hwirq = d->parent_data->hwirq; enum pdc_irq_config_bits pdc_type; int ret; if (pin_out == GPIO_NO_WAKE_IRQ) return 0; Loading Loading @@ -151,6 +204,15 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) } pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type); ipc_log_string(pdc_ipc_log, "Set type: PIN=%d pdc_type=%d gic_type=%d", pin_out, pdc_type, type); /* Additionally, configure (only) the GPIO in the f/w */ if (d->domain->host_data) { ret = spi_configure_type(parent_hwirq, type); if (ret) return ret; } return irq_chip_set_type_parent(d, type); } Loading @@ -160,6 +222,8 @@ static struct irq_chip qcom_pdc_gic_chip = { .irq_eoi = irq_chip_eoi_parent, .irq_mask = qcom_pdc_gic_mask, .irq_unmask = qcom_pdc_gic_unmask, .irq_disable = qcom_pdc_gic_disable, .irq_enable = qcom_pdc_gic_enable, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_type = qcom_pdc_gic_set_type, .flags = IRQCHIP_MASK_ON_SUSPEND | Loading Loading @@ -233,6 +297,8 @@ static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq, parent_fwspec.param[1] = parent_hwirq; parent_fwspec.param[2] = type; ipc_log_string(pdc_ipc_log, "Alloc: PIN=%d GIC-SPI=%d", hwirq, parent_hwirq); return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); } Loading Loading @@ -271,6 +337,13 @@ static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq, qcom_fwspec->mask = true; /* Additionally, configure GPIO PDC in the f/w */ if (domain->host_data) { ret = spi_configure_type(parent_hwirq, type); if (ret) return ret; } if (type & IRQ_TYPE_EDGE_BOTH) type = IRQ_TYPE_EDGE_RISING; Loading @@ -283,6 +356,8 @@ static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq, parent_fwspec.param[1] = parent_hwirq; parent_fwspec.param[2] = type; ipc_log_string(pdc_ipc_log, "GPIO alloc: PIN=%d GIC-SPI=%d", hwirq, parent_hwirq); return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); } Loading Loading @@ -336,9 +411,19 @@ static int pdc_setup_pin_mapping(struct device_node *np) return 0; } static int __init qcom_pdc_early_init(void) { pdc_ipc_log = ipc_log_context_create(PDC_IPC_LOG_SZ, "pdc", 0); return 0; } core_initcall(qcom_pdc_early_init); static int qcom_pdc_init(struct device_node *node, struct device_node *parent) { struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain; struct resource res; int ret; pdc_base = of_iomap(node, 0); Loading Loading @@ -369,10 +454,17 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) goto fail; } ret = of_address_to_resource(node, 1, &res); if (!ret) { pdc_cfg_size = resource_size(&res); pdc_cfg_base = ioremap(res.start, pdc_cfg_size); } pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_GPIO_IRQS, of_fwnode_handle(node), &qcom_pdc_gpio_ops, NULL); &qcom_pdc_gpio_ops, pdc_cfg_base); if (!pdc_gpio_domain) { pr_err("GIC domain add failed for GPIO domain\n"); ret = -ENOMEM; Loading drivers/pinctrl/qcom/pinctrl-msm.c +60 −16 Original line number Diff line number Diff line Loading @@ -633,7 +633,7 @@ static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl, val, val2); } static void msm_gpio_irq_mask(struct irq_data *d) static void _msm_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); Loading @@ -643,13 +643,6 @@ static void msm_gpio_irq_mask(struct irq_data *d) g = &pctrl->soc->groups[d->hwirq]; if (d->parent_data) irq_chip_mask_parent(d); /* Monitored by parent wakeup controller? */ if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_cfg_reg); Loading Loading @@ -684,7 +677,7 @@ static void msm_gpio_irq_mask(struct irq_data *d) raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void msm_gpio_irq_unmask(struct irq_data *d) static void _msm_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); Loading @@ -694,13 +687,6 @@ static void msm_gpio_irq_unmask(struct irq_data *d) g = &pctrl->soc->groups[d->hwirq]; if (d->parent_data) irq_chip_unmask_parent(d); /* Monitored by parent wakeup controller? Keep masked */ if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_cfg_reg); Loading @@ -713,6 +699,62 @@ static void msm_gpio_irq_unmask(struct irq_data *d) raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void msm_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_mask_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_mask(d); } static void msm_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_unmask_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_unmask(d); } static void msm_gpio_irq_disable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_disable_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_mask(d); } static void msm_gpio_irq_enable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_enable_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_unmask(d); } static void msm_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); Loading Loading @@ -1034,6 +1076,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.name = "msmgpio"; pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent; pctrl->irq_chip.irq_enable = msm_gpio_irq_enable; pctrl->irq_chip.irq_disable = msm_gpio_irq_disable; pctrl->irq_chip.irq_mask = msm_gpio_irq_mask; pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask; pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; Loading Loading
drivers/irqchip/qcom-pdc.c +96 −4 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ #include <linux/err.h> #include <linux/init.h> #include <linux/ipc_logging.h> #include <linux/irq.h> #include <linux/irqchip.h> #include <linux/irqdomain.h> Loading @@ -18,6 +19,8 @@ #include <linux/slab.h> #include <linux/types.h> #define PDC_IPC_LOG_SZ 2 #define PDC_MAX_IRQS 138 #define PDC_MAX_GPIO_IRQS 256 Loading @@ -36,9 +39,11 @@ struct pdc_pin_region { }; static DEFINE_RAW_SPINLOCK(pdc_lock); static void __iomem *pdc_base; static void __iomem *pdc_base, *pdc_cfg_base; static struct pdc_pin_region *pdc_region; static int pdc_region_cnt; static resource_size_t pdc_cfg_size; static void *pdc_ipc_log; static void pdc_reg_write(int reg, u32 i, u32 val) { Loading @@ -63,15 +68,34 @@ static void pdc_enable_intr(struct irq_data *d, bool on) enable = pdc_reg_read(IRQ_ENABLE_BANK, index); enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask); pdc_reg_write(IRQ_ENABLE_BANK, index, enable); ipc_log_string(pdc_ipc_log, "PIN=%d enable=%d", d->hwirq, on); raw_spin_unlock(&pdc_lock); } static void qcom_pdc_gic_mask(struct irq_data *d) static void qcom_pdc_gic_disable(struct irq_data *d) { if (d->hwirq == GPIO_NO_WAKE_IRQ) return; pdc_enable_intr(d, false); irq_chip_disable_parent(d); } static void qcom_pdc_gic_enable(struct irq_data *d) { if (d->hwirq == GPIO_NO_WAKE_IRQ) return; pdc_enable_intr(d, true); irq_chip_enable_parent(d); } static void qcom_pdc_gic_mask(struct irq_data *d) { if (d->hwirq == GPIO_NO_WAKE_IRQ) return; ipc_log_string(pdc_ipc_log, "PIN=%d mask", d->hwirq); irq_chip_mask_parent(d); } Loading @@ -80,10 +104,37 @@ static void qcom_pdc_gic_unmask(struct irq_data *d) if (d->hwirq == GPIO_NO_WAKE_IRQ) return; pdc_enable_intr(d, true); ipc_log_string(pdc_ipc_log, "PIN=%d unmask", d->hwirq); irq_chip_unmask_parent(d); } static int spi_configure_type(irq_hw_number_t hwirq, unsigned int type) { int spi = hwirq - 32; unsigned int pin = spi / 32; unsigned int mask = BIT(spi % 32); void __iomem *cfg_reg = pdc_cfg_base + pin * 4; unsigned int val; unsigned long flags; if (pin * 4 > pdc_cfg_size) return -EFAULT; raw_spin_lock_irqsave(&pdc_lock, flags); val = readl_relaxed(cfg_reg); rmb(); /* Ensure the read is complete before modifying */ val &= ~mask; if (type & IRQ_TYPE_LEVEL_MASK) val |= mask; writel_relaxed(val, cfg_reg); ipc_log_string(pdc_ipc_log, "SPI config: GIC-SPI=%d (reg=%d,bit=%d) val=%d", spi, pin, spi % 32, type & IRQ_TYPE_LEVEL_MASK); raw_spin_unlock_irqrestore(&pdc_lock, flags); return 0; } /* * GIC does not handle falling edge or active low. To allow falling edge and * active low interrupts to be handled at GIC, PDC has an inverter that inverts Loading Loading @@ -121,7 +172,9 @@ enum pdc_irq_config_bits { static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) { int pin_out = d->hwirq; int parent_hwirq = d->parent_data->hwirq; enum pdc_irq_config_bits pdc_type; int ret; if (pin_out == GPIO_NO_WAKE_IRQ) return 0; Loading Loading @@ -151,6 +204,15 @@ static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type) } pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type); ipc_log_string(pdc_ipc_log, "Set type: PIN=%d pdc_type=%d gic_type=%d", pin_out, pdc_type, type); /* Additionally, configure (only) the GPIO in the f/w */ if (d->domain->host_data) { ret = spi_configure_type(parent_hwirq, type); if (ret) return ret; } return irq_chip_set_type_parent(d, type); } Loading @@ -160,6 +222,8 @@ static struct irq_chip qcom_pdc_gic_chip = { .irq_eoi = irq_chip_eoi_parent, .irq_mask = qcom_pdc_gic_mask, .irq_unmask = qcom_pdc_gic_unmask, .irq_disable = qcom_pdc_gic_disable, .irq_enable = qcom_pdc_gic_enable, .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_type = qcom_pdc_gic_set_type, .flags = IRQCHIP_MASK_ON_SUSPEND | Loading Loading @@ -233,6 +297,8 @@ static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq, parent_fwspec.param[1] = parent_hwirq; parent_fwspec.param[2] = type; ipc_log_string(pdc_ipc_log, "Alloc: PIN=%d GIC-SPI=%d", hwirq, parent_hwirq); return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); } Loading Loading @@ -271,6 +337,13 @@ static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq, qcom_fwspec->mask = true; /* Additionally, configure GPIO PDC in the f/w */ if (domain->host_data) { ret = spi_configure_type(parent_hwirq, type); if (ret) return ret; } if (type & IRQ_TYPE_EDGE_BOTH) type = IRQ_TYPE_EDGE_RISING; Loading @@ -283,6 +356,8 @@ static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq, parent_fwspec.param[1] = parent_hwirq; parent_fwspec.param[2] = type; ipc_log_string(pdc_ipc_log, "GPIO alloc: PIN=%d GIC-SPI=%d", hwirq, parent_hwirq); return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, &parent_fwspec); } Loading Loading @@ -336,9 +411,19 @@ static int pdc_setup_pin_mapping(struct device_node *np) return 0; } static int __init qcom_pdc_early_init(void) { pdc_ipc_log = ipc_log_context_create(PDC_IPC_LOG_SZ, "pdc", 0); return 0; } core_initcall(qcom_pdc_early_init); static int qcom_pdc_init(struct device_node *node, struct device_node *parent) { struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain; struct resource res; int ret; pdc_base = of_iomap(node, 0); Loading Loading @@ -369,10 +454,17 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent) goto fail; } ret = of_address_to_resource(node, 1, &res); if (!ret) { pdc_cfg_size = resource_size(&res); pdc_cfg_base = ioremap(res.start, pdc_cfg_size); } pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_GPIO_IRQS, of_fwnode_handle(node), &qcom_pdc_gpio_ops, NULL); &qcom_pdc_gpio_ops, pdc_cfg_base); if (!pdc_gpio_domain) { pr_err("GIC domain add failed for GPIO domain\n"); ret = -ENOMEM; Loading
drivers/pinctrl/qcom/pinctrl-msm.c +60 −16 Original line number Diff line number Diff line Loading @@ -633,7 +633,7 @@ static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl, val, val2); } static void msm_gpio_irq_mask(struct irq_data *d) static void _msm_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); Loading @@ -643,13 +643,6 @@ static void msm_gpio_irq_mask(struct irq_data *d) g = &pctrl->soc->groups[d->hwirq]; if (d->parent_data) irq_chip_mask_parent(d); /* Monitored by parent wakeup controller? */ if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_cfg_reg); Loading Loading @@ -684,7 +677,7 @@ static void msm_gpio_irq_mask(struct irq_data *d) raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void msm_gpio_irq_unmask(struct irq_data *d) static void _msm_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); Loading @@ -694,13 +687,6 @@ static void msm_gpio_irq_unmask(struct irq_data *d) g = &pctrl->soc->groups[d->hwirq]; if (d->parent_data) irq_chip_unmask_parent(d); /* Monitored by parent wakeup controller? Keep masked */ if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_cfg_reg); Loading @@ -713,6 +699,62 @@ static void msm_gpio_irq_unmask(struct irq_data *d) raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void msm_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_mask_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_mask(d); } static void msm_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_unmask_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_unmask(d); } static void msm_gpio_irq_disable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_disable_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_mask(d); } static void msm_gpio_irq_enable(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); if (d->parent_data) irq_chip_enable_parent(d); if (test_bit(d->hwirq, pctrl->wakeup_masked_irqs)) return; _msm_gpio_irq_unmask(d); } static void msm_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); Loading Loading @@ -1034,6 +1076,8 @@ static int msm_gpio_init(struct msm_pinctrl *pctrl) pctrl->irq_chip.name = "msmgpio"; pctrl->irq_chip.irq_eoi = irq_chip_eoi_parent; pctrl->irq_chip.irq_enable = msm_gpio_irq_enable; pctrl->irq_chip.irq_disable = msm_gpio_irq_disable; pctrl->irq_chip.irq_mask = msm_gpio_irq_mask; pctrl->irq_chip.irq_unmask = msm_gpio_irq_unmask; pctrl->irq_chip.irq_ack = msm_gpio_irq_ack; Loading