From 308c399692246ee41f6e94e18b88ec56b94d6c66 Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Thu, 9 Apr 2020 18:03:43 +0530 Subject: [PATCH 1/2] defconfig: Enable RPM_SMD driver for Holi Enable RPM-SMD driver to APSS-RPM communication. Change-Id: I988a99a3ac3b5016808826fa945d996d18af2ce0 Signed-off-by: Raghavendra Kakarla --- arch/arm64/configs/vendor/holi_GKI.config | 1 + arch/arm64/configs/vendor/holi_QGKI.config | 1 + arch/arm64/configs/vendor/holi_debug.config | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm64/configs/vendor/holi_GKI.config b/arch/arm64/configs/vendor/holi_GKI.config index 863b3627d038..c70bdd04072b 100644 --- a/arch/arm64/configs/vendor/holi_GKI.config +++ b/arch/arm64/configs/vendor/holi_GKI.config @@ -111,3 +111,4 @@ CONFIG_BTFM_SLIM=m CONFIG_USB_ROLE_SWITCH=m # CONFIG_QCOM_MINIDUMP is not set CONFIG_QCOM_EUD=m +CONFIG_MSM_RPM_SMD=m diff --git a/arch/arm64/configs/vendor/holi_QGKI.config b/arch/arm64/configs/vendor/holi_QGKI.config index 47d1a38f8459..363abd06e44c 100644 --- a/arch/arm64/configs/vendor/holi_QGKI.config +++ b/arch/arm64/configs/vendor/holi_QGKI.config @@ -122,3 +122,4 @@ CONFIG_QCOM_MINIDUMP=y CONFIG_ARM_QCOM_DEVFREQ_QOSLAT=y CONFIG_IPC_LOGGING=y # CONFIG_FTRACE_STARTUP_TEST is not set +CONFIG_MSM_RPM_SMD=y diff --git a/arch/arm64/configs/vendor/holi_debug.config b/arch/arm64/configs/vendor/holi_debug.config index 07e8bd315915..b91baca2dbdc 100644 --- a/arch/arm64/configs/vendor/holi_debug.config +++ b/arch/arm64/configs/vendor/holi_debug.config @@ -100,3 +100,4 @@ CONFIG_CRC8=y CONFIG_MSM_REMOTEQDSS=y CONFIG_LKDTM=y CONFIG_MSM_GCC_HOLI=y +CONFIG_MSM_RPM_SMD=y From 67371f6ddcc517f88869d8da3c9d425180d46e5e Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Thu, 1 Aug 2019 11:14:24 +0530 Subject: [PATCH 2/2] drivers: irqchip: mpm: Add QTI SoC interrupt controller Add the mpm as the wakeup capable interrupt controller. Change-Id: Ibd437ecd4efe4db134a0a026404f9b3170685db5 Signed-off-by: Raghavendra Kakarla --- drivers/irqchip/Kconfig | 11 + drivers/irqchip/Makefile | 1 + drivers/irqchip/qcom-mpm.c | 623 +++++++++++++++++++++++++++++++++++++ include/soc/qcom/mpm.h | 17 + include/trace/events/mpm.h | 77 +++++ 5 files changed, 729 insertions(+) create mode 100644 drivers/irqchip/qcom-mpm.c create mode 100644 include/soc/qcom/mpm.h create mode 100644 include/trace/events/mpm.h diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 37092f877fae..2b7582eb7b04 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -493,6 +493,17 @@ config TI_SCI_INTA_IRQCHIP If you wish to use interrupt aggregator irq resources managed by the TI System Controller, say Y here. Otherwise, say N. +config QCOM_MPM + bool "QCOM MPM" + depends on ARCH_QCOM + select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY + help + MSM Power Manager driver to manage and configure wakeup + IRQs for Qualcomm Technologies Inc (QTI) mobile chips. + Say yes here to enable the MSM Power Manager interrupt + controller to use as a wakeup interrupt controller. + config SIFIVE_PLIC bool "SiFive Platform-Level Interrupt Controller" depends on RISCV diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c0c84a6be011..35355b5cb1e5 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_NDS32) += irq-ativic32.o obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o +obj-$(CONFIG_QCOM_MPM) += qcom-mpm.o obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o obj-$(CONFIG_MADERA_IRQ) += irq-madera.o diff --git a/drivers/irqchip/qcom-mpm.c b/drivers/irqchip/qcom-mpm.c new file mode 100644 index 000000000000..e4f2d0a6a6ff --- /dev/null +++ b/drivers/irqchip/qcom-mpm.c @@ -0,0 +1,623 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2010-2020, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define CREATE_TRACE_POINTS +#include "trace/events/mpm.h" + +#define ARCH_TIMER_HZ (19200000) +#define MAX_MPM_PIN_PER_IRQ 2 +#define CLEAR_INTR(reg, intr) (reg & ~(1 << intr)) +#define ENABLE_INTR(reg, intr) (reg | (1 << intr)) +#define CLEAR_TYPE(reg, type) (reg & ~(1 << type)) +#define ENABLE_TYPE(reg, type) (reg | (1 << type)) +#define MPM_REG_ENABLE 0 +#define MPM_REG_FALLING_EDGE 1 +#define MPM_REG_RISING_EDGE 2 +#define MPM_REG_POLARITY 3 +#define MPM_REG_STATUS 4 +#define MPM_GPIO 0 +#define MPM_GIC 1 + +#define QCOM_MPM_REG_WIDTH DIV_ROUND_UP(num_mpm_irqs, 32) +#define MPM_REGISTER(reg, index) ((reg * QCOM_MPM_REG_WIDTH + index + 2) * (4)) +#define GPIO_NO_WAKE_IRQ ~0U + +struct msm_mpm_device_data { + struct device *dev; + void __iomem *mpm_request_reg_base; + void __iomem *mpm_ipc_reg; + irq_hw_number_t ipc_irq; + struct irq_domain *gic_chip_domain; + struct irq_domain *gpio_chip_domain; +}; + +static int num_mpm_irqs = 64; +static struct msm_mpm_device_data msm_mpm_dev_data; +static unsigned int *mpm_to_irq; +static DEFINE_SPINLOCK(mpm_lock); + +static void msm_get_mpm_pin(struct irq_data *d, int *mpm_pin, bool is_mpmgic) +{ + struct mpm_pin *mpm_data = NULL; + int i = 0, j = 0; + + if (!d) + return; + + if (is_mpmgic && d->domain->host_data) { + mpm_data = d->domain->host_data; + for (i = 0; (mpm_data[i].pin >= 0) && + (j < MAX_MPM_PIN_PER_IRQ); i++) { + if (mpm_data[i].hwirq == d->hwirq) { + mpm_pin[j] = mpm_data[i].pin; + mpm_to_irq[mpm_data[i].pin] = d->irq; + j++; + } + } + } else if (!is_mpmgic) { + mpm_pin[j] = d->hwirq; + mpm_to_irq[d->hwirq] = d->irq; + } +} + +static inline uint32_t msm_mpm_read(unsigned int reg, unsigned int subreg_index) +{ + unsigned int offset = MPM_REGISTER(reg, subreg_index); + + return readl_relaxed(msm_mpm_dev_data.mpm_request_reg_base + offset); +} + +static inline void msm_mpm_write(unsigned int reg, + unsigned int subreg_index, + uint32_t value) +{ + void __iomem *mpm_reg_base = msm_mpm_dev_data.mpm_request_reg_base; + /* + * Add 2 to offset to account for the 64 bit timer in the vMPM + * mapping + */ + unsigned int offset = MPM_REGISTER(reg, subreg_index); + u32 r_value; + + writel_relaxed(value, mpm_reg_base + offset); + + do { + r_value = readl_relaxed(mpm_reg_base + offset); + udelay(5); + } while (r_value != value); +} + +static inline void msm_mpm_enable_irq(struct irq_data *d, bool on, + bool is_mpmgic) +{ + int mpm_pin[MAX_MPM_PIN_PER_IRQ] = {-1, -1}; + unsigned long flags; + int i = 0; + u32 enable; + unsigned int index, mask; + unsigned int reg; + + reg = MPM_REG_ENABLE; + msm_get_mpm_pin(d, mpm_pin, is_mpmgic); + for (i = 0; i < MAX_MPM_PIN_PER_IRQ; i++) { + if (mpm_pin[i] < 0) + return; + + index = mpm_pin[i]/32; + mask = mpm_pin[i]%32; + spin_lock_irqsave(&mpm_lock, flags); + enable = msm_mpm_read(reg, index); + + if (on) + enable = ENABLE_INTR(enable, mask); + else + enable = CLEAR_INTR(enable, mask); + + msm_mpm_write(reg, index, enable); + spin_unlock_irqrestore(&mpm_lock, flags); + } +} + +static void msm_mpm_program_set_type(bool set, unsigned int reg, + unsigned int index, unsigned int mask) +{ + u32 type; + + type = msm_mpm_read(reg, index); + if (set) + type = ENABLE_TYPE(type, mask); + else + type = CLEAR_TYPE(type, mask); + + msm_mpm_write(reg, index, type); +} + +static void msm_mpm_set_type(struct irq_data *d, + unsigned int flowtype, bool is_mpmgic) +{ + int mpm_pin[MAX_MPM_PIN_PER_IRQ] = {-1, -1}; + unsigned long flags; + int i = 0; + unsigned int index, mask; + unsigned int reg = 0; + + msm_get_mpm_pin(d, mpm_pin, is_mpmgic); + for (i = 0; i < MAX_MPM_PIN_PER_IRQ; i++) { + if (mpm_pin[i] < 0) + return; + + index = mpm_pin[i]/32; + mask = mpm_pin[i]%32; + + spin_lock_irqsave(&mpm_lock, flags); + reg = MPM_REG_RISING_EDGE; + if (flowtype & IRQ_TYPE_EDGE_RISING) + msm_mpm_program_set_type(1, reg, index, mask); + else + msm_mpm_program_set_type(0, reg, index, mask); + + reg = MPM_REG_FALLING_EDGE; + if (flowtype & IRQ_TYPE_EDGE_FALLING) + msm_mpm_program_set_type(1, reg, index, mask); + else + msm_mpm_program_set_type(0, reg, index, mask); + + reg = MPM_REG_POLARITY; + if (flowtype & IRQ_TYPE_LEVEL_HIGH) + msm_mpm_program_set_type(1, reg, index, mask); + else + msm_mpm_program_set_type(0, reg, index, mask); + spin_unlock_irqrestore(&mpm_lock, flags); + } +} + +static void msm_mpm_gpio_chip_mask(struct irq_data *d) +{ + if (d->hwirq == GPIO_NO_WAKE_IRQ) + return; + + msm_mpm_enable_irq(d, false, MPM_GPIO); +} + +static void msm_mpm_gpio_chip_unmask(struct irq_data *d) +{ + if (d->hwirq == GPIO_NO_WAKE_IRQ) + return; + + msm_mpm_enable_irq(d, true, MPM_GPIO); +} + +static int msm_mpm_gpio_chip_set_type(struct irq_data *d, unsigned int type) +{ + if (d->hwirq == GPIO_NO_WAKE_IRQ) + return 0; + + msm_mpm_set_type(d, type, MPM_GPIO); + + return 0; +} + +static void msm_mpm_gic_chip_mask(struct irq_data *d) +{ + msm_mpm_enable_irq(d, false, MPM_GIC); + irq_chip_mask_parent(d); +} + +static void msm_mpm_gic_chip_unmask(struct irq_data *d) +{ + msm_mpm_enable_irq(d, true, MPM_GIC); + irq_chip_unmask_parent(d); +} + +static int msm_mpm_gic_chip_set_type(struct irq_data *d, unsigned int type) +{ + msm_mpm_set_type(d, type, MPM_GIC); + return irq_chip_set_type_parent(d, type); +} + +static struct irq_chip msm_mpm_gic_chip = { + .name = "mpm-gic", + .irq_eoi = irq_chip_eoi_parent, + .irq_mask = msm_mpm_gic_chip_mask, + .irq_disable = msm_mpm_gic_chip_mask, + .irq_unmask = msm_mpm_gic_chip_unmask, + .irq_retrigger = irq_chip_retrigger_hierarchy, + .irq_set_type = msm_mpm_gic_chip_set_type, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, + .irq_set_affinity = irq_chip_set_affinity_parent, +}; + +static struct irq_chip msm_mpm_gpio_chip = { + .name = "mpm-gpio", + .irq_mask = msm_mpm_gpio_chip_mask, + .irq_disable = msm_mpm_gpio_chip_mask, + .irq_unmask = msm_mpm_gpio_chip_unmask, + .irq_set_type = msm_mpm_gpio_chip_set_type, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, + .irq_retrigger = irq_chip_retrigger_hierarchy, +}; + +static int msm_mpm_gpio_chip_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 2) + return -EINVAL; + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + return 0; + } + return -EINVAL; +} + +static int msm_mpm_gpio_chip_alloc(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs, + void *data) +{ + int ret = 0; + struct irq_fwspec *fwspec = data; + irq_hw_number_t hwirq; + unsigned int type = IRQ_TYPE_NONE; + + ret = msm_mpm_gpio_chip_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + &msm_mpm_gpio_chip, NULL); + + return 0; +} + +static const struct irq_domain_ops msm_mpm_gpio_chip_domain_ops = { + .translate = msm_mpm_gpio_chip_translate, + .alloc = msm_mpm_gpio_chip_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int msm_mpm_gic_chip_translate(struct irq_domain *d, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count < 3) + return -EINVAL; + + switch (fwspec->param[0]) { + case 0: /* SPI */ + *hwirq = fwspec->param[1] + 32; + break; + case 1: /* PPI */ + *hwirq = fwspec->param[1] + 16; + break; + case GIC_IRQ_TYPE_LPI: /* LPI */ + *hwirq = fwspec->param[1]; + break; + default: + return -EINVAL; + } + + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + return 0; + } + + if (is_fwnode_irqchip(fwspec->fwnode)) { + if (fwspec->param_count != 2) + return -EINVAL; + + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + return 0; + } + + return -EINVAL; +} + +static int msm_mpm_gic_chip_alloc(struct irq_domain *domain, + unsigned int virq, + unsigned int nr_irqs, + void *data) +{ + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; + irq_hw_number_t hwirq; + unsigned int type; + int ret; + + ret = msm_mpm_gic_chip_translate(domain, fwspec, &hwirq, &type); + if (ret) + return ret; + + irq_domain_set_hwirq_and_chip(domain, virq, hwirq, + &msm_mpm_gic_chip, NULL); + + parent_fwspec = *fwspec; + parent_fwspec.fwnode = domain->parent->fwnode; + return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, + &parent_fwspec); +} + +static const struct irq_domain_ops msm_mpm_gic_chip_domain_ops = { + .translate = msm_mpm_gic_chip_translate, + .alloc = msm_mpm_gic_chip_alloc, + .free = irq_domain_free_irqs_common, +}; + +static inline void msm_mpm_send_interrupt(void) +{ + writel_relaxed(2, msm_mpm_dev_data.mpm_ipc_reg); + /* Ensure the write is complete before returning. */ + wmb(); +} + +static inline void msm_mpm_timer_write(uint32_t *expiry) +{ + writel_relaxed(expiry[0], msm_mpm_dev_data.mpm_request_reg_base); + writel_relaxed(expiry[1], msm_mpm_dev_data.mpm_request_reg_base + 0x4); +} + +static void msm_mpm_enter_sleep(struct cpumask *cpumask) +{ + msm_mpm_send_interrupt(); + irq_set_affinity(msm_mpm_dev_data.ipc_irq, cpumask); +} + +static void system_pm_exit_sleep(bool success) +{ + msm_rpm_exit_sleep(); +} + +static int system_pm_update_wakeup(bool from_idle) +{ + uint32_t lo = ~0U, hi = ~0U; + u64 wakeup; + + /* Read the hardware to get the most accurate value */ + arch_timer_mem_get_cval(&lo, &hi); + wakeup = lo; + wakeup |= ((uint64_t)(hi) << 32); + msm_mpm_timer_write((uint32_t *)&wakeup); + trace_mpm_wakeup_time(from_idle, wakeup, arch_counter_get_cntvct()); + + return 0; +} + +static int system_pm_enter_sleep(struct cpumask *mask) +{ + int ret = 0, i = 0; + + ret = msm_rpm_enter_sleep(0, mask); + if (ret) + return ret; + + for (i = 0; i < QCOM_MPM_REG_WIDTH; i++) + msm_mpm_write(MPM_REG_STATUS, i, 0); + + msm_mpm_enter_sleep(mask); + + return ret; +} + +static bool system_pm_sleep_allowed(void) +{ + return !msm_rpm_waiting_for_ack(); +} + +static struct system_pm_ops pm_ops = { + .enter = system_pm_enter_sleep, + .exit = system_pm_exit_sleep, + .update_wakeup = system_pm_update_wakeup, + .sleep_allowed = system_pm_sleep_allowed, +}; + +/* + * Triggered by RPM when system resumes from deep sleep + */ +static irqreturn_t msm_mpm_irq(int irq, void *dev_id) +{ + unsigned long pending; + uint32_t value[3]; + int i, k, apps_irq; + unsigned int mpm_irq; + struct irq_desc *desc = NULL; + unsigned int reg = MPM_REG_ENABLE; + + for (i = 0; i < QCOM_MPM_REG_WIDTH; i++) { + value[i] = msm_mpm_read(reg, i); + trace_mpm_wakeup_enable_irqs(i, value[i]); + } + + for (i = 0; i < QCOM_MPM_REG_WIDTH; i++) { + pending = msm_mpm_read(MPM_REG_STATUS, i); + pending &= (unsigned long)value[i]; + + trace_mpm_wakeup_pending_irqs(i, pending); + for_each_set_bit(k, &pending, 32) { + mpm_irq = 32 * i + k; + apps_irq = mpm_to_irq[mpm_irq]; + desc = apps_irq ? + irq_to_desc(apps_irq) : NULL; + + if (desc && !irqd_is_level_type(&desc->irq_data)) + irq_set_irqchip_state(apps_irq, + IRQCHIP_STATE_PENDING, true); + + } + + } + return IRQ_HANDLED; +} + +static int msm_mpm_init(struct device_node *node) +{ + struct msm_mpm_device_data *dev = &msm_mpm_dev_data; + int ret = 0; + int irq, index; + + index = of_property_match_string(node, "reg-names", "vmpm"); + if (index < 0) { + ret = -EADDRNOTAVAIL; + goto reg_base_err; + } + + dev->mpm_request_reg_base = of_iomap(node, index); + if (!dev->mpm_request_reg_base) { + pr_err("Unable to iomap\n"); + ret = -EADDRNOTAVAIL; + goto reg_base_err; + } + + index = of_property_match_string(node, "reg-names", "ipc"); + if (index < 0) { + ret = -EADDRNOTAVAIL; + goto reg_base_err; + } + + dev->mpm_ipc_reg = of_iomap(node, index); + if (!dev->mpm_ipc_reg) { + pr_err("Unable to iomap IPC register\n"); + ret = -EADDRNOTAVAIL; + goto ipc_reg_err; + } + + irq = of_irq_get(node, 0); + if (irq <= 0) { + pr_err("no IRQ resource info\n"); + ret = irq; + goto ipc_irq_err; + } + dev->ipc_irq = irq; + + ret = request_irq(dev->ipc_irq, msm_mpm_irq, + IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND, "mpm", + msm_mpm_irq); + if (ret) { + pr_err("request_irq failed errno: %d\n", ret); + goto ipc_irq_err; + } + + ret = irq_set_irq_wake(dev->ipc_irq, 1); + if (ret) { + pr_err("failed to set wakeup irq %lu: %d\n", + dev->ipc_irq, ret); + goto set_wake_irq_err; + } + + return register_system_pm_ops(&pm_ops); + +set_wake_irq_err: + free_irq(dev->ipc_irq, msm_mpm_irq); +ipc_irq_err: + iounmap(dev->mpm_ipc_reg); +ipc_reg_err: + iounmap(dev->mpm_request_reg_base); +reg_base_err: + return ret; +} + +static const struct of_device_id mpm_gic_chip_data_table[] = { + {} +}; +MODULE_DEVICE_TABLE(of, mpm_gic_chip_data_table); + +static int __init mpm_gic_chip_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain; + const struct of_device_id *id; + int ret; + + if (!parent) { + pr_err("%s(): no parent for mpm-gic\n", node->full_name); + return -ENXIO; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("unable to obtain gic parent domain\n"); + return -ENXIO; + } + + of_property_read_u32(node, "qcom,num-mpm-irqs", &num_mpm_irqs); + + mpm_to_irq = kcalloc(num_mpm_irqs, sizeof(*mpm_to_irq), GFP_KERNEL); + if (!mpm_to_irq) + return -ENOMEM; + + id = of_match_node(mpm_gic_chip_data_table, node); + if (!id) { + pr_err("can not find mpm_gic_data_table of_node\n"); + ret = -ENODEV; + goto mpm_map_err; + } + + msm_mpm_dev_data.gic_chip_domain = irq_domain_add_hierarchy( + parent_domain, 0, num_mpm_irqs, node, + &msm_mpm_gic_chip_domain_ops, (void *)id->data); + if (!msm_mpm_dev_data.gic_chip_domain) { + pr_err("gic domain add failed\n"); + ret = -ENOMEM; + goto mpm_map_err; + } + + msm_mpm_dev_data.gic_chip_domain->name = "qcom,mpm-gic"; + + ret = msm_mpm_init(node); + if (!ret) + return ret; + irq_domain_remove(msm_mpm_dev_data.gic_chip_domain); + +mpm_map_err: + kfree(mpm_to_irq); + return ret; +} +IRQCHIP_DECLARE(mpm_gic_chip, "qcom,mpm-gic", mpm_gic_chip_init); + +static int __init mpm_gpio_chip_init(struct device_node *node, + struct device_node *parent) +{ + msm_mpm_dev_data.gpio_chip_domain = irq_domain_create_linear( + of_node_to_fwnode(node), num_mpm_irqs, + &msm_mpm_gpio_chip_domain_ops, NULL); + + if (!msm_mpm_dev_data.gpio_chip_domain) + return -ENOMEM; + + irq_domain_update_bus_token(msm_mpm_dev_data.gpio_chip_domain, + DOMAIN_BUS_WAKEUP); + msm_mpm_dev_data.gpio_chip_domain->name = "qcom,mpm-gpio"; + + return 0; +} +IRQCHIP_DECLARE(mpm_gpio_chip, "qcom,mpm-gpio", mpm_gpio_chip_init); diff --git a/include/soc/qcom/mpm.h b/include/soc/qcom/mpm.h new file mode 100644 index 000000000000..05061d12359a --- /dev/null +++ b/include/soc/qcom/mpm.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __QCOM_MPM_H__ +#define __QCOM_MPM_H__ + +#include +#include + +struct mpm_pin { + int pin; + irq_hw_number_t hwirq; +}; + +#endif /* __QCOM_MPM_H__ */ diff --git a/include/trace/events/mpm.h b/include/trace/events/mpm.h new file mode 100644 index 000000000000..9134de148220 --- /dev/null +++ b/include/trace/events/mpm.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mpm + +#if !defined(_TRACE_MPM_) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MPM_H_ + +#include + +TRACE_EVENT(mpm_wakeup_enable_irqs, + + TP_PROTO(uint32_t index, uint32_t irqs), + + TP_ARGS(index, irqs), + + TP_STRUCT__entry( + __field(uint32_t, index) + __field(uint32_t, irqs) + ), + + TP_fast_assign( + __entry->index = index; + __entry->irqs = irqs; + ), + + TP_printk("index:%u wakeup_capable_irqs:0x%x", + __entry->index, __entry->irqs) +); + +TRACE_EVENT(mpm_wakeup_pending_irqs, + + TP_PROTO(uint32_t index, uint32_t irqs), + + TP_ARGS(index, irqs), + + TP_STRUCT__entry( + __field(uint32_t, index) + __field(uint32_t, irqs) + ), + + TP_fast_assign( + __entry->index = index; + __entry->irqs = irqs; + ), + + TP_printk("index:%u wakeup_irqs:0x%x", __entry->index, __entry->irqs) +); + +TRACE_EVENT(mpm_wakeup_time, + + TP_PROTO(bool from_idle, u64 wakeup, u64 current_ticks), + + TP_ARGS(from_idle, wakeup, current_ticks), + + TP_STRUCT__entry( + __field(bool, from_idle) + __field(u64, wakeup) + __field(u64, current_ticks) + ), + + TP_fast_assign( + __entry->from_idle = from_idle; + __entry->wakeup = wakeup; + __entry->current_ticks = current_ticks; + ), + + TP_printk("idle:%d wakeup:0x%llx current:0x%llx", __entry->from_idle, + __entry->wakeup, __entry->current_ticks) +); + +#endif +#define TRACE_INCLUDE_FILE mpm +#include