mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-08 21:22:09 -04:00
Merge "irqchip: qcom-pdc: Add IPC logging support"
This commit is contained in:
commit
bbb789f449
2 changed files with 132 additions and 0 deletions
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/irqdomain.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
|
|
@ -19,7 +20,11 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <linux/ipc_logging.h>
|
||||
|
||||
#define PDC_MAX_IRQS 168
|
||||
#define PDC_IPC_LOG_SZ 2
|
||||
#define PDC_MAX_GPIO_IRQS 256
|
||||
|
||||
#define CLEAR_INTR(reg, intr) (reg & ~(1 << intr))
|
||||
|
|
@ -36,10 +41,19 @@ struct pdc_pin_region {
|
|||
u32 cnt;
|
||||
};
|
||||
|
||||
struct spi_cfg_regs {
|
||||
u64 start;
|
||||
void __iomem *base;
|
||||
resource_size_t size;
|
||||
bool scm_io;
|
||||
};
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(pdc_lock);
|
||||
static void __iomem *pdc_base;
|
||||
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 void pdc_reg_write(int reg, u32 i, u32 val)
|
||||
{
|
||||
|
|
@ -84,6 +98,7 @@ 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);
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +125,7 @@ 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);
|
||||
}
|
||||
|
||||
|
|
@ -118,9 +134,64 @@ static void qcom_pdc_gic_unmask(struct irq_data *d)
|
|||
if (d->hwirq == GPIO_NO_WAKE_IRQ)
|
||||
return;
|
||||
|
||||
ipc_log_string(pdc_ipc_log, "PIN=%d unmask", d->hwirq);
|
||||
irq_chip_unmask_parent(d);
|
||||
}
|
||||
|
||||
static u32 __spi_pin_read(unsigned int pin)
|
||||
{
|
||||
void __iomem *cfg_reg = spi_cfg->base + pin * 4;
|
||||
u64 scm_cfg_reg = spi_cfg->start + pin * 4;
|
||||
|
||||
if (spi_cfg->scm_io) {
|
||||
unsigned int val;
|
||||
|
||||
qcom_scm_io_readl(scm_cfg_reg, &val);
|
||||
return val;
|
||||
} else {
|
||||
return readl_relaxed(cfg_reg);
|
||||
}
|
||||
}
|
||||
|
||||
static void __spi_pin_write(unsigned int pin, unsigned int val)
|
||||
{
|
||||
void __iomem *cfg_reg = spi_cfg->base + pin * 4;
|
||||
u64 scm_cfg_reg = spi_cfg->start + pin * 4;
|
||||
|
||||
if (spi_cfg->scm_io)
|
||||
qcom_scm_io_writel(scm_cfg_reg, val);
|
||||
else
|
||||
writel_relaxed(val, cfg_reg);
|
||||
}
|
||||
|
||||
static int spi_configure_type(irq_hw_number_t hwirq, unsigned int type)
|
||||
{
|
||||
int spi = hwirq - 32;
|
||||
u32 pin = spi / 32;
|
||||
u32 mask = BIT(spi % 32);
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
if (!spi_cfg)
|
||||
return 0;
|
||||
|
||||
if (pin * 4 > spi_cfg->size)
|
||||
return -EFAULT;
|
||||
|
||||
raw_spin_lock_irqsave(&pdc_lock, flags);
|
||||
val = __spi_pin_read(pin);
|
||||
val &= ~mask;
|
||||
if (type & IRQ_TYPE_LEVEL_MASK)
|
||||
val |= mask;
|
||||
__spi_pin_write(pin, val);
|
||||
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
|
||||
|
|
@ -158,7 +229,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;
|
||||
|
|
@ -188,6 +261,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 (irq_domain_qcom_handle_wakeup(d->domain)) {
|
||||
ret = spi_configure_type(parent_hwirq, type);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return irq_chip_set_type_parent(d, type);
|
||||
}
|
||||
|
|
@ -274,6 +356,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);
|
||||
}
|
||||
|
|
@ -321,6 +405,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);
|
||||
}
|
||||
|
|
@ -374,9 +460,18 @@ 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;
|
||||
}
|
||||
module_init(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);
|
||||
|
|
@ -407,6 +502,27 @@ 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) {
|
||||
spi_cfg = kcalloc(1, sizeof(*spi_cfg), GFP_KERNEL);
|
||||
if (!spi_cfg) {
|
||||
ret = -ENOMEM;
|
||||
goto remove;
|
||||
}
|
||||
spi_cfg->scm_io = of_find_property(node,
|
||||
"qcom,scm-spi-cfg", NULL);
|
||||
spi_cfg->size = resource_size(&res);
|
||||
if (spi_cfg->scm_io) {
|
||||
spi_cfg->start = res.start;
|
||||
} else {
|
||||
spi_cfg->base = ioremap(res.start, spi_cfg->size);
|
||||
if (!spi_cfg->base) {
|
||||
ret = -ENOMEM;
|
||||
goto remove;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdc_gpio_domain = irq_domain_create_hierarchy(parent_domain,
|
||||
IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP,
|
||||
PDC_MAX_GPIO_IRQS,
|
||||
|
|
@ -424,6 +540,7 @@ static int qcom_pdc_init(struct device_node *node, struct device_node *parent)
|
|||
|
||||
remove:
|
||||
irq_domain_remove(pdc_domain);
|
||||
kfree(spi_cfg);
|
||||
fail:
|
||||
kfree(pdc_region);
|
||||
iounmap(pdc_base);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
#ifndef __QCOM_IRQ_H
|
||||
#define __QCOM_IRQ_H
|
||||
|
||||
struct irq_domain;
|
||||
|
||||
#define GPIO_NO_WAKE_IRQ ~0U
|
||||
|
||||
/**
|
||||
|
|
@ -16,4 +18,17 @@
|
|||
#define IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP (IRQ_DOMAIN_FLAG_NONCORE << 0)
|
||||
#define IRQ_DOMAIN_FLAG_QCOM_MPM_WAKEUP (IRQ_DOMAIN_FLAG_NONCORE << 1)
|
||||
|
||||
/**
|
||||
* irq_domain_qcom_handle_wakeup: Return if the domain handles interrupt
|
||||
* configuration
|
||||
* @d: irq domain
|
||||
*
|
||||
* This QCOM specific irq domain call returns if the interrupt controller
|
||||
* requires the interrupt be masked at the child interrupt controller.
|
||||
*/
|
||||
static inline bool irq_domain_qcom_handle_wakeup(struct irq_domain *d)
|
||||
{
|
||||
return (d->flags & IRQ_DOMAIN_FLAG_QCOM_PDC_WAKEUP);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue