linux/drivers/irqchip/qcom-pdc.c
<<
>>
Prefs
   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_device.h>
  18#include <linux/of_irq.h>
  19#include <linux/soc/qcom/irq.h>
  20#include <linux/spinlock.h>
  21#include <linux/slab.h>
  22#include <linux/types.h>
  23
  24#define PDC_MAX_IRQS            168
  25#define PDC_MAX_GPIO_IRQS       256
  26
  27#define CLEAR_INTR(reg, intr)   (reg & ~(1 << intr))
  28#define ENABLE_INTR(reg, intr)  (reg | (1 << intr))
  29
  30#define IRQ_ENABLE_BANK         0x10
  31#define IRQ_i_CFG               0x110
  32
  33#define PDC_NO_PARENT_IRQ       ~0UL
  34
  35struct pdc_pin_region {
  36        u32 pin_base;
  37        u32 parent_base;
  38        u32 cnt;
  39};
  40
  41static DEFINE_RAW_SPINLOCK(pdc_lock);
  42static void __iomem *pdc_base;
  43static struct pdc_pin_region *pdc_region;
  44static int pdc_region_cnt;
  45
  46static void pdc_reg_write(int reg, u32 i, u32 val)
  47{
  48        writel_relaxed(val, pdc_base + reg + i * sizeof(u32));
  49}
  50
  51static u32 pdc_reg_read(int reg, u32 i)
  52{
  53        return readl_relaxed(pdc_base + reg + i * sizeof(u32));
  54}
  55
  56static int qcom_pdc_gic_get_irqchip_state(struct irq_data *d,
  57                                          enum irqchip_irq_state which,
  58                                          bool *state)
  59{
  60        if (d->hwirq == GPIO_NO_WAKE_IRQ)
  61                return 0;
  62
  63        return irq_chip_get_parent_state(d, which, state);
  64}
  65
  66static int qcom_pdc_gic_set_irqchip_state(struct irq_data *d,
  67                                          enum irqchip_irq_state which,
  68                                          bool value)
  69{
  70        if (d->hwirq == GPIO_NO_WAKE_IRQ)
  71                return 0;
  72
  73        return irq_chip_set_parent_state(d, which, value);
  74}
  75
  76static void pdc_enable_intr(struct irq_data *d, bool on)
  77{
  78        int pin_out = d->hwirq;
  79        u32 index, mask;
  80        u32 enable;
  81
  82        index = pin_out / 32;
  83        mask = pin_out % 32;
  84
  85        raw_spin_lock(&pdc_lock);
  86        enable = pdc_reg_read(IRQ_ENABLE_BANK, index);
  87        enable = on ? ENABLE_INTR(enable, mask) : CLEAR_INTR(enable, mask);
  88        pdc_reg_write(IRQ_ENABLE_BANK, index, enable);
  89        raw_spin_unlock(&pdc_lock);
  90}
  91
  92static void qcom_pdc_gic_disable(struct irq_data *d)
  93{
  94        if (d->hwirq == GPIO_NO_WAKE_IRQ)
  95                return;
  96
  97        pdc_enable_intr(d, false);
  98        irq_chip_disable_parent(d);
  99}
 100
 101static void qcom_pdc_gic_enable(struct irq_data *d)
 102{
 103        if (d->hwirq == GPIO_NO_WAKE_IRQ)
 104                return;
 105
 106        pdc_enable_intr(d, true);
 107        irq_chip_enable_parent(d);
 108}
 109
 110static void qcom_pdc_gic_mask(struct irq_data *d)
 111{
 112        if (d->hwirq == GPIO_NO_WAKE_IRQ)
 113                return;
 114
 115        irq_chip_mask_parent(d);
 116}
 117
 118static void qcom_pdc_gic_unmask(struct irq_data *d)
 119{
 120        if (d->hwirq == GPIO_NO_WAKE_IRQ)
 121                return;
 122
 123        irq_chip_unmask_parent(d);
 124}
 125
 126/*
 127 * GIC does not handle falling edge or active low. To allow falling edge and
 128 * active low interrupts to be handled at GIC, PDC has an inverter that inverts
 129 * falling edge into a rising edge and active low into an active high.
 130 * For the inverter to work, the polarity bit in the IRQ_CONFIG register has to
 131 * set as per the table below.
 132 * Level sensitive active low    LOW
 133 * Rising edge sensitive         NOT USED
 134 * Falling edge sensitive        LOW
 135 * Dual Edge sensitive           NOT USED
 136 * Level sensitive active High   HIGH
 137 * Falling Edge sensitive        NOT USED
 138 * Rising edge sensitive         HIGH
 139 * Dual Edge sensitive           HIGH
 140 */
 141enum pdc_irq_config_bits {
 142        PDC_LEVEL_LOW           = 0b000,
 143        PDC_EDGE_FALLING        = 0b010,
 144        PDC_LEVEL_HIGH          = 0b100,
 145        PDC_EDGE_RISING         = 0b110,
 146        PDC_EDGE_DUAL           = 0b111,
 147};
 148
 149/**
 150 * qcom_pdc_gic_set_type: Configure PDC for the interrupt
 151 *
 152 * @d: the interrupt data
 153 * @type: the interrupt type
 154 *
 155 * If @type is edge triggered, forward that as Rising edge as PDC
 156 * takes care of converting falling edge to rising edge signal
 157 * If @type is level, then forward that as level high as PDC
 158 * takes care of converting falling edge to rising edge signal
 159 */
 160static int qcom_pdc_gic_set_type(struct irq_data *d, unsigned int type)
 161{
 162        int pin_out = d->hwirq;
 163        enum pdc_irq_config_bits pdc_type;
 164        enum pdc_irq_config_bits old_pdc_type;
 165        int ret;
 166
 167        if (pin_out == GPIO_NO_WAKE_IRQ)
 168                return 0;
 169
 170        switch (type) {
 171        case IRQ_TYPE_EDGE_RISING:
 172                pdc_type = PDC_EDGE_RISING;
 173                break;
 174        case IRQ_TYPE_EDGE_FALLING:
 175                pdc_type = PDC_EDGE_FALLING;
 176                type = IRQ_TYPE_EDGE_RISING;
 177                break;
 178        case IRQ_TYPE_EDGE_BOTH:
 179                pdc_type = PDC_EDGE_DUAL;
 180                type = IRQ_TYPE_EDGE_RISING;
 181                break;
 182        case IRQ_TYPE_LEVEL_HIGH:
 183                pdc_type = PDC_LEVEL_HIGH;
 184                break;
 185        case IRQ_TYPE_LEVEL_LOW:
 186                pdc_type = PDC_LEVEL_LOW;
 187                type = IRQ_TYPE_LEVEL_HIGH;
 188                break;
 189        default:
 190                WARN_ON(1);
 191                return -EINVAL;
 192        }
 193
 194        old_pdc_type = pdc_reg_read(IRQ_i_CFG, pin_out);
 195        pdc_reg_write(IRQ_i_CFG, pin_out, pdc_type);
 196
 197        ret = irq_chip_set_type_parent(d, type);
 198        if (ret)
 199                return ret;
 200
 201        /*
 202         * When we change types the PDC can give a phantom interrupt.
 203         * Clear it.  Specifically the phantom shows up when reconfiguring
 204         * polarity of interrupt without changing the state of the signal
 205         * but let's be consistent and clear it always.
 206         *
 207         * Doing this works because we have IRQCHIP_SET_TYPE_MASKED so the
 208         * interrupt will be cleared before the rest of the system sees it.
 209         */
 210        if (old_pdc_type != pdc_type)
 211                irq_chip_set_parent_state(d, IRQCHIP_STATE_PENDING, false);
 212
 213        return 0;
 214}
 215
 216static struct irq_chip qcom_pdc_gic_chip = {
 217        .name                   = "PDC",
 218        .irq_eoi                = irq_chip_eoi_parent,
 219        .irq_mask               = qcom_pdc_gic_mask,
 220        .irq_unmask             = qcom_pdc_gic_unmask,
 221        .irq_disable            = qcom_pdc_gic_disable,
 222        .irq_enable             = qcom_pdc_gic_enable,
 223        .irq_get_irqchip_state  = qcom_pdc_gic_get_irqchip_state,
 224        .irq_set_irqchip_state  = qcom_pdc_gic_set_irqchip_state,
 225        .irq_retrigger          = irq_chip_retrigger_hierarchy,
 226        .irq_set_type           = qcom_pdc_gic_set_type,
 227        .flags                  = IRQCHIP_MASK_ON_SUSPEND |
 228                                  IRQCHIP_SET_TYPE_MASKED |
 229                                  IRQCHIP_SKIP_SET_WAKE |
 230                                  IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND,
 231        .irq_set_vcpu_affinity  = irq_chip_set_vcpu_affinity_parent,
 232        .irq_set_affinity       = irq_chip_set_affinity_parent,
 233};
 234
 235static irq_hw_number_t get_parent_hwirq(int pin)
 236{
 237        int i;
 238        struct pdc_pin_region *region;
 239
 240        for (i = 0; i < pdc_region_cnt; i++) {
 241                region = &pdc_region[i];
 242                if (pin >= region->pin_base &&
 243                    pin < region->pin_base + region->cnt)
 244                        return (region->parent_base + pin - region->pin_base);
 245        }
 246
 247        return PDC_NO_PARENT_IRQ;
 248}
 249
 250static int qcom_pdc_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
 251                              unsigned long *hwirq, unsigned int *type)
 252{
 253        if (is_of_node(fwspec->fwnode)) {
 254                if (fwspec->param_count != 2)
 255                        return -EINVAL;
 256
 257                *hwirq = fwspec->param[0];
 258                *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
 259                return 0;
 260        }
 261
 262        return -EINVAL;
 263}
 264
 265static int qcom_pdc_alloc(struct irq_domain *domain, unsigned int virq,
 266                          unsigned int nr_irqs, void *data)
 267{
 268        struct irq_fwspec *fwspec = data;
 269        struct irq_fwspec parent_fwspec;
 270        irq_hw_number_t hwirq, parent_hwirq;
 271        unsigned int type;
 272        int ret;
 273
 274        ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
 275        if (ret)
 276                return ret;
 277
 278        ret  = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
 279                                             &qcom_pdc_gic_chip, NULL);
 280        if (ret)
 281                return ret;
 282
 283        parent_hwirq = get_parent_hwirq(hwirq);
 284        if (parent_hwirq == PDC_NO_PARENT_IRQ)
 285                return 0;
 286
 287        if (type & IRQ_TYPE_EDGE_BOTH)
 288                type = IRQ_TYPE_EDGE_RISING;
 289
 290        if (type & IRQ_TYPE_LEVEL_MASK)
 291                type = IRQ_TYPE_LEVEL_HIGH;
 292
 293        parent_fwspec.fwnode      = domain->parent->fwnode;
 294        parent_fwspec.param_count = 3;
 295        parent_fwspec.param[0]    = 0;
 296        parent_fwspec.param[1]    = parent_hwirq;
 297        parent_fwspec.param[2]    = type;
 298
 299        return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
 300                                            &parent_fwspec);
 301}
 302
 303static const struct irq_domain_ops qcom_pdc_ops = {
 304        .translate      = qcom_pdc_translate,
 305        .alloc          = qcom_pdc_alloc,
 306        .free           = irq_domain_free_irqs_common,
 307};
 308
 309static int qcom_pdc_gpio_alloc(struct irq_domain *domain, unsigned int virq,
 310                               unsigned int nr_irqs, void *data)
 311{
 312        struct irq_fwspec *fwspec = data;
 313        struct irq_fwspec parent_fwspec;
 314        irq_hw_number_t hwirq, parent_hwirq;
 315        unsigned int type;
 316        int ret;
 317
 318        ret = qcom_pdc_translate(domain, fwspec, &hwirq, &type);
 319        if (ret)
 320                return ret;
 321
 322        ret = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
 323                                            &qcom_pdc_gic_chip, NULL);
 324        if (ret)
 325                return ret;
 326
 327        if (hwirq == GPIO_NO_WAKE_IRQ)
 328                return 0;
 329
 330        parent_hwirq = get_parent_hwirq(hwirq);
 331        if (parent_hwirq == PDC_NO_PARENT_IRQ)
 332                return 0;
 333
 334        if (type & IRQ_TYPE_EDGE_BOTH)
 335                type = IRQ_TYPE_EDGE_RISING;
 336
 337        if (type & IRQ_TYPE_LEVEL_MASK)
 338                type = IRQ_TYPE_LEVEL_HIGH;
 339
 340        parent_fwspec.fwnode      = domain->parent->fwnode;
 341        parent_fwspec.param_count = 3;
 342        parent_fwspec.param[0]    = 0;
 343        parent_fwspec.param[1]    = parent_hwirq;
 344        parent_fwspec.param[2]    = type;
 345
 346        return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
 347                                            &parent_fwspec);
 348}
 349
 350static int qcom_pdc_gpio_domain_select(struct irq_domain *d,
 351                                       struct irq_fwspec *fwspec,
 352                                       enum irq_domain_bus_token bus_token)
 353{
 354        return bus_token == DOMAIN_BUS_WAKEUP;
 355}
 356
 357static const struct irq_domain_ops qcom_pdc_gpio_ops = {
 358        .select         = qcom_pdc_gpio_domain_select,
 359        .alloc          = qcom_pdc_gpio_alloc,
 360        .free           = irq_domain_free_irqs_common,
 361};
 362
 363static int pdc_setup_pin_mapping(struct device_node *np)
 364{
 365        int ret, n, i;
 366        u32 irq_index, reg_index, val;
 367
 368        n = of_property_count_elems_of_size(np, "qcom,pdc-ranges", sizeof(u32));
 369        if (n <= 0 || n % 3)
 370                return -EINVAL;
 371
 372        pdc_region_cnt = n / 3;
 373        pdc_region = kcalloc(pdc_region_cnt, sizeof(*pdc_region), GFP_KERNEL);
 374        if (!pdc_region) {
 375                pdc_region_cnt = 0;
 376                return -ENOMEM;
 377        }
 378
 379        for (n = 0; n < pdc_region_cnt; n++) {
 380                ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
 381                                                 n * 3 + 0,
 382                                                 &pdc_region[n].pin_base);
 383                if (ret)
 384                        return ret;
 385                ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
 386                                                 n * 3 + 1,
 387                                                 &pdc_region[n].parent_base);
 388                if (ret)
 389                        return ret;
 390                ret = of_property_read_u32_index(np, "qcom,pdc-ranges",
 391                                                 n * 3 + 2,
 392                                                 &pdc_region[n].cnt);
 393                if (ret)
 394                        return ret;
 395
 396                for (i = 0; i < pdc_region[n].cnt; i++) {
 397                        reg_index = (i + pdc_region[n].pin_base) >> 5;
 398                        irq_index = (i + pdc_region[n].pin_base) & 0x1f;
 399                        val = pdc_reg_read(IRQ_ENABLE_BANK, reg_index);
 400                        val &= ~BIT(irq_index);
 401                        pdc_reg_write(IRQ_ENABLE_BANK, reg_index, val);
 402                }
 403        }
 404
 405        return 0;
 406}
 407
 408static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
 409{
 410        struct irq_domain *parent_domain, *pdc_domain, *pdc_gpio_domain;
 411        int ret;
 412
 413        pdc_base = of_iomap(node, 0);
 414        if (!pdc_base) {
 415                pr_err("%pOF: unable to map PDC registers\n", node);
 416                return -ENXIO;
 417        }
 418
 419        parent_domain = irq_find_host(parent);
 420        if (!parent_domain) {
 421                pr_err("%pOF: unable to find PDC's parent domain\n", node);
 422                ret = -ENXIO;
 423                goto fail;
 424        }
 425
 426        ret = pdc_setup_pin_mapping(node);
 427        if (ret) {
 428                pr_err("%pOF: failed to init PDC pin-hwirq mapping\n", node);
 429                goto fail;
 430        }
 431
 432        pdc_domain = irq_domain_create_hierarchy(parent_domain, 0, PDC_MAX_IRQS,
 433                                                 of_fwnode_handle(node),
 434                                                 &qcom_pdc_ops, NULL);
 435        if (!pdc_domain) {
 436                pr_err("%pOF: GIC domain add failed\n", node);
 437                ret = -ENOMEM;
 438                goto fail;
 439        }
 440
 441        pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain,
 442                                        IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP,
 443                                        PDC_MAX_GPIO_IRQS,
 444                                        of_fwnode_handle(node),
 445                                        &qcom_pdc_gpio_ops, NULL);
 446        if (!pdc_gpio_domain) {
 447                pr_err("%pOF: PDC domain add failed for GPIO domain\n", node);
 448                ret = -ENOMEM;
 449                goto remove;
 450        }
 451
 452        irq_domain_update_bus_token(pdc_gpio_domain, DOMAIN_BUS_WAKEUP);
 453
 454        return 0;
 455
 456remove:
 457        irq_domain_remove(pdc_domain);
 458fail:
 459        kfree(pdc_region);
 460        iounmap(pdc_base);
 461        return ret;
 462}
 463
 464IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc)
 465IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init)
 466IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc)
 467MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
 468MODULE_LICENSE("GPL v2");
 469