diff options
author | Ranjani Vaidyanathan <ranjani.vaidyanathan@nxp.com> | 2021-10-06 11:54:26 -0500 |
---|---|---|
committer | Philippe Schenker <philippe.schenker@toradex.com> | 2022-05-18 16:41:20 +0200 |
commit | 16dca2c7b2822eb3e0bec15e6a16a7d2ba434395 (patch) | |
tree | ec56605fe1047a2b2e25f7be376c388026471ff3 | |
parent | f04bac0476413576c8f5047c74325ecd7fd05b7a (diff) |
MLK-25649-1 firmware: imx: imx-scu-irq: Add support for identifying SCU wakeup source from sysfs
Record SCU wakeup interrupt in /sys/power/pm_wakeup_irq
The user can further identify the exact wakeup source by using the
following interface:
cat /sys/firmware/scu_wakeup_source/wakeup_src
The above will print the wake groups and the irqs that could have
contributed to waking up the kernel. For example if ON/OFF button was the
wakeup source:
cat /sys/firmware/scu_wakeup_source/wakeup_src
Wakeup source group = 3, irq = 0x1
The user can refer to the SCFW API documentation to identify all the
wake groups and irqs.
Signed-off-by: Ranjani Vaidyanathan <ranjani.vaidyanathan@nxp.com>
(cherry picked from commit d49daabfb43eddf94144560fc2eef58015311454)
(cherry picked from commit fed9f95ad512fd4b4cca7c8bfd08a78ddcaebeb9)
-rw-r--r-- | drivers/firmware/imx/imx-scu-irq.c | 60 | ||||
-rw-r--r-- | include/linux/firmware/imx/sci.h | 24 |
2 files changed, 81 insertions, 3 deletions
diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 369621c14105..b4272a75a315 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -10,10 +10,11 @@ #include <linux/firmware/imx/sci.h> #include <linux/mailbox_client.h> #include <linux/suspend.h> +#include <linux/sysfs.h> +#include <linux/kobject.h> #define IMX_SC_IRQ_FUNC_ENABLE 1 #define IMX_SC_IRQ_FUNC_STATUS 2 -#define IMX_SC_IRQ_NUM_GROUP 7 static u32 mu_resource_id; @@ -39,6 +40,20 @@ struct imx_sc_msg_irq_enable { u8 enable; } __packed; +struct scu_wakeup { + u32 mask; + u32 wakeup_src; + bool valid; +}; + +/* Sysfs functions */ +struct kobject *wakeup_obj; +static ssize_t wakeup_source_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); +static struct kobj_attribute wakeup_source_attr = __ATTR(wakeup_src, 0660, wakeup_source_show, NULL); + +static struct scu_wakeup scu_irq_wakeup[IMX_SC_IRQ_NUM_GROUP]; + + static struct imx_sc_ipc *imx_sc_irq_ipc_handle; static struct work_struct imx_sc_irq_work; static BLOCKING_NOTIFIER_HEAD(imx_scu_irq_notifier_chain); @@ -70,6 +85,10 @@ static void imx_scu_irq_work_handler(struct work_struct *work) u8 i; for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { + if (scu_irq_wakeup[i].mask) { + scu_irq_wakeup[i].valid = false; + scu_irq_wakeup[i].wakeup_src = 0; + } ret = imx_scu_irq_get_status(i, &irq_status); if (ret) { pr_err("get irq group %d status failed, ret %d\n", @@ -79,7 +98,12 @@ static void imx_scu_irq_work_handler(struct work_struct *work) if (!irq_status) continue; - + if (scu_irq_wakeup[i].mask & irq_status) { + scu_irq_wakeup[i].valid = true; + scu_irq_wakeup[i].wakeup_src = irq_status & scu_irq_wakeup[i].mask; + } else { + scu_irq_wakeup[i].wakeup_src = irq_status; + } pm_system_wakeup(); imx_scu_irq_notifier_call_chain(irq_status, &i); } @@ -134,6 +158,11 @@ int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) pr_err("enable irq failed, group %d, mask %d, ret %d\n", group, mask, ret); + if (enable) + scu_irq_wakeup[group].mask |= mask; + else + scu_irq_wakeup[group].mask &= ~mask; + return ret; } EXPORT_SYMBOL(imx_scu_irq_group_enable); @@ -143,6 +172,24 @@ static void imx_scu_irq_callback(struct mbox_client *c, void *msg) schedule_work(&imx_sc_irq_work); } +static ssize_t wakeup_source_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + u8 i = 0, size = 0; + + for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { + if (scu_irq_wakeup[i].wakeup_src != 0) { + if (scu_irq_wakeup[i].valid) + size += sprintf(buf + size, "Wakeup source group = %d, irq = 0x%x\n", + i, scu_irq_wakeup[i].wakeup_src); + else + size += sprintf(buf + size, "Spurious SCU wakeup, group = %d, irq = 0x%x\n", + i, scu_irq_wakeup[i].wakeup_src); + } + } + return strlen(buf); +} + int imx_scu_enable_general_irq_channel(struct device *dev) { struct of_phandle_args spec; @@ -182,6 +229,15 @@ int imx_scu_enable_general_irq_channel(struct device *dev) mu_resource_id = IMX_SC_R_MU_0A + i; + /* Create directory under /sysfs/firmware */ + wakeup_obj = kobject_create_and_add("scu_wakeup_source", firmware_kobj); + + if (sysfs_create_file(wakeup_obj, &wakeup_source_attr.attr)) { + pr_err("Cannot create sysfs file......\n"); + kobject_put(wakeup_obj); + sysfs_remove_file(firmware_kobj, &wakeup_source_attr.attr); + } + return ret; } EXPORT_SYMBOL(imx_scu_enable_general_irq_channel); diff --git a/include/linux/firmware/imx/sci.h b/include/linux/firmware/imx/sci.h index e749594436bb..70fe789aa842 100644 --- a/include/linux/firmware/imx/sci.h +++ b/include/linux/firmware/imx/sci.h @@ -17,12 +17,34 @@ #include <linux/firmware/imx/svc/rm.h> #include <linux/firmware/imx/svc/seco.h> -#define IMX_SC_IRQ_GROUP_WAKE 3U /* Wakeup interrupts */ +#define IMX_SC_IRQ_NUM_GROUP 9 + +#define IMX_SC_IRQ_GROUP_TEMP 0 /* Temp interrupts */ +#define IMX_SC_IRQ_GROUP_WDOG 1 /* Watchdog interrupts */ +#define IMX_SC_IRQ_GROUP_RTC 2 /* RTC interrupts */ +#define IMX_SC_IRQ_GROUP_WAKE 3 /* Wakeup interrupts */ +#define IMX_SC_IRQ_GROUP_SYSCTR 4 /* System counter interrupts */ +#define IMX_SC_IRQ_GROUP_REBOOTED 5 /* Partition reboot complete */ +#define IMX_SC_IRQ_GROUP_REBOOT 6 /* Partition reboot starting */ +#define IMX_SC_IRQ_GROUP_OFFED 7 /* Partition off complete */ +#define IMX_SC_IRQ_GROUP_OFF 8 /* Partition off starting */ + +#define IMX_SC_IRQ_RTC BIT(0) /* RTC interrupt */ +#define IMX_SC_IRQ_WDOG BIT(0) /* Watch Dog interrupt */ +#define IMX_SC_IRQ_SYSCTR BIT(0) /* System Counter interrupt */ +#define IMX_SC_IRQ_BUTTON BIT(0) /* Button interrupt */ +#define IMX_SC_IRQ_PAD BIT(1) /* Pad wakeup */ +#define IMX_SC_IRQ_USR1 BIT(2) /* User defined 1 */ +#define IMX_SC_IRQ_USR2 BIT(3) /* User defined 2 */ +#define IMX_SC_IRQ_BC_PAD BIT(4) /* Pad wakeup (broadcast to all partitions) */ +#define IMX_SC_IRQ_SW_WAKE BIT(5) /* Software requested wake */ #define IMX_SC_IRQ_SECVIO BIT(6) /* Security violation */ +#define IMX_SC_IRQ_V2X_RESET BIT(7) /* V2X reset */ int imx_scu_enable_general_irq_channel(struct device *dev); int imx_scu_irq_register_notifier(struct notifier_block *nb); int imx_scu_irq_unregister_notifier(struct notifier_block *nb); int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable); int imx_scu_irq_get_status(u8 group, u32 *irq_status); + #endif /* _SC_SCI_H */ |