From 7b95e20e32c9169d6232d097c26de825839872e8 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 6 Jul 2023 09:46:29 +0200 Subject: [PATCH 01/11] soc: imx: imx93-blk-ctrl: Add dedicated lockdep class for nested genpd locks This is the same approach as being used within imx8mp-blk-ctrl. This fixes the lockdep warning about 'possible recursive locking detected' with the following (reduced) backtrace: genpd_lock_mtx+0x14/0x1c genpd_runtime_resume+0x108/0x308 __rpm_callback+0x44/0x19c rpm_callback+0x64/0x70 rpm_resume+0x438/0x6d8 __pm_runtime_resume+0x54/0xb0 imx93_blk_ctrl_power_on+0x100/0x294 _genpd_power_on+0x8c/0x16c genpd_power_on.part.0+0xa0/0x1a0 __genpd_dev_pm_attach+0x14c/0x2e4 genpd_dev_pm_attach+0x58/0x64 dev_pm_domain_attach+0x1c/0x2c Signed-off-by: Alexander Stein Signed-off-by: Shawn Guo --- drivers/soc/imx/imx93-blk-ctrl.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/soc/imx/imx93-blk-ctrl.c b/drivers/soc/imx/imx93-blk-ctrl.c index 2c600329436c..14eb991a670e 100644 --- a/drivers/soc/imx/imx93-blk-ctrl.c +++ b/drivers/soc/imx/imx93-blk-ctrl.c @@ -187,6 +187,8 @@ static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd) return 0; } +static struct lock_class_key blk_ctrl_genpd_lock_class; + static int imx93_blk_ctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -269,6 +271,19 @@ static int imx93_blk_ctrl_probe(struct platform_device *pdev) goto cleanup_pds; } + /* + * We use runtime PM to trigger power on/off of the upstream GPC + * domain, as a strict hierarchical parent/child power domain + * setup doesn't allow us to meet the sequencing requirements. + * This means we have nested locking of genpd locks, without the + * nesting being visible at the genpd level, so we need a + * separate lock class to make lockdep aware of the fact that + * this are separate domain locks that can be nested without a + * self-deadlock. + */ + lockdep_set_class(&domain->genpd.mlock, + &blk_ctrl_genpd_lock_class); + bc->onecell_data.domains[i] = &domain->genpd; } From 0e40e5fe87f11a8d282afc0dacc8c8b4f8a57630 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 9 Jul 2023 15:39:44 +0200 Subject: [PATCH 02/11] bus: imx-weim: use devm_platform_ioremap_resource devm_platform_get_and_ioremap_resource maps a resource and returns its physical address. If we don't need the physical address, we should call devm_platform_ioremap_resource instead. Signed-off-by: Martin Kaiser Signed-off-by: Shawn Guo --- drivers/bus/imx-weim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c index 52a5d0447390..42c9386a7b42 100644 --- a/drivers/bus/imx-weim.c +++ b/drivers/bus/imx-weim.c @@ -273,7 +273,7 @@ static int weim_probe(struct platform_device *pdev) return -ENOMEM; /* get the resource */ - base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); From ef2c1c84bcb98b66565facbba8dd32ce797b97eb Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 14 Jul 2023 11:51:33 -0600 Subject: [PATCH 03/11] soc: imx: Explicitly include correct DT includes The DT of_device.h and of_platform.h date back to the separate of_platform_bus_type before it as merged into the regular platform bus. As part of that merge prepping Arm DT support 13 years ago, they "temporarily" include each other. They also include platform_device.h and of.h. As a result, there's a pretty much random mix of those include files used throughout the tree. In order to detangle these headers and replace the implicit includes with struct declarations, users need to explicitly include the correct includes. Signed-off-by: Rob Herring Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 2 +- drivers/soc/imx/imx8m-blk-ctrl.c | 3 ++- drivers/soc/imx/imx8mp-blk-ctrl.c | 2 +- drivers/soc/imx/imx93-blk-ctrl.c | 2 +- drivers/soc/imx/imx93-pd.c | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 4b3300b090a8..fbd3d92f8cd8 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c index afbca0d48c14..cc5ef6e2f0a8 100644 --- a/drivers/soc/imx/imx8m-blk-ctrl.c +++ b/drivers/soc/imx/imx8m-blk-ctrl.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include #include #include diff --git a/drivers/soc/imx/imx8mp-blk-ctrl.c b/drivers/soc/imx/imx8mp-blk-ctrl.c index 870aecc0202a..5a9f5ece43d9 100644 --- a/drivers/soc/imx/imx8mp-blk-ctrl.c +++ b/drivers/soc/imx/imx8mp-blk-ctrl.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/soc/imx/imx93-blk-ctrl.c b/drivers/soc/imx/imx93-blk-ctrl.c index 14eb991a670e..40bd90f8b977 100644 --- a/drivers/soc/imx/imx93-blk-ctrl.c +++ b/drivers/soc/imx/imx93-blk-ctrl.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/soc/imx/imx93-pd.c b/drivers/soc/imx/imx93-pd.c index 832deeed8fd6..b9e60d136875 100644 --- a/drivers/soc/imx/imx93-pd.c +++ b/drivers/soc/imx/imx93-pd.c @@ -5,8 +5,8 @@ #include #include -#include #include +#include #include #include #include From 22420dc71e8d735799cdadf106a420b3ce25aca3 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Mon, 7 Aug 2023 20:14:25 +0800 Subject: [PATCH 04/11] firmware: imx: scu: change init level to subsys_initcall_sync Change firmware init level to subsys_initcall_sync to ensure it's probed before most devices to avoid unnecessary defer probe. Signed-off-by: Dong Aisheng Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/imx-scu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 47db49911e7b..2d24359420d8 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -353,7 +353,12 @@ static struct platform_driver imx_scu_driver = { }, .probe = imx_scu_probe, }; -builtin_platform_driver(imx_scu_driver); + +static int __init imx_scu_driver_init(void) +{ + return platform_driver_register(&imx_scu_driver); +} +subsys_initcall_sync(imx_scu_driver_init); MODULE_AUTHOR("Dong Aisheng "); MODULE_DESCRIPTION("IMX SCU firmware protocol driver"); From 4b9ccf041e3971427784870ac5b607a5cb38d43a Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Mon, 7 Aug 2023 20:14:26 +0800 Subject: [PATCH 05/11] firmware: imx: scu: increase RPC timeout When system loading is high, we can meet some command timeout issue occasionally, so increase the timeout to a safe value. Signed-off-by: Dong Aisheng Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/imx-scu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 2d24359420d8..14ff9d3504bf 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -20,7 +20,7 @@ #include #define SCU_MU_CHAN_NUM 8 -#define MAX_RX_TIMEOUT (msecs_to_jiffies(30)) +#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000)) struct imx_sc_chan { struct imx_sc_ipc *sc_ipc; From 150019dea22afa2ea9ebe28078fe36271defa9c4 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 7 Aug 2023 20:14:27 +0800 Subject: [PATCH 06/11] firmware: imx: scu: use soc name for soc_id Same as soc-imx8m and soc-imx driver, use soc name for soc_id which is user friendly. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/imx-scu-soc.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/imx/imx-scu-soc.c b/drivers/firmware/imx/imx-scu-soc.c index 2f32353de2c9..497192320562 100644 --- a/drivers/firmware/imx/imx-scu-soc.c +++ b/drivers/firmware/imx/imx-scu-soc.c @@ -78,6 +78,22 @@ static int imx_scu_soc_id(void) return msg.data.resp.id; } +static const char *imx_scu_soc_name(u32 id) +{ + switch (id) { + case 0x1: + return "i.MX8QM"; + case 0x2: + return "i.MX8QXP"; + case 0xe: + return "i.MX8DXL"; + default: + break; + } + + return "NULL"; +} + int imx_scu_soc_init(struct device *dev) { struct soc_device_attribute *soc_dev_attr; @@ -113,9 +129,7 @@ int imx_scu_soc_init(struct device *dev) /* format soc_id value passed from SCU firmware */ val = id & 0x1f; - soc_dev_attr->soc_id = devm_kasprintf(dev, GFP_KERNEL, "0x%x", val); - if (!soc_dev_attr->soc_id) - return -ENOMEM; + soc_dev_attr->soc_id = imx_scu_soc_name(val); /* format revision value passed from SCU firmware */ val = (id >> 5) & 0xf; From 8314aa8af4f9905dded47e53b3e283e632736d41 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 7 Aug 2023 20:14:28 +0800 Subject: [PATCH 07/11] firmware: imx: scu: use EOPNOTSUPP Per checkpatch.pl, "ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP" So use EOPNOTSUPP to replace ENOTSUPP. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- include/linux/firmware/imx/sci.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/firmware/imx/sci.h b/include/linux/firmware/imx/sci.h index 5cc63fe7e84d..7fa0f3b329b5 100644 --- a/include/linux/firmware/imx/sci.h +++ b/include/linux/firmware/imx/sci.h @@ -25,27 +25,27 @@ int imx_scu_soc_init(struct device *dev); #else static inline int imx_scu_soc_init(struct device *dev) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_enable_general_irq_channel(struct device *dev) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_irq_register_notifier(struct notifier_block *nb) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_irq_unregister_notifier(struct notifier_block *nb) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) { - return -ENOTSUPP; + return -EOPNOTSUPP; } #endif #endif /* _SC_SCI_H */ From 19a72e0cb06de380c6259d1ca02aea2c99c1e175 Mon Sep 17 00:00:00 2001 From: Robin Gong Date: Mon, 7 Aug 2023 20:14:29 +0800 Subject: [PATCH 08/11] firmware: imx: scu-irq: fix RCU complaint after M4 partition reset Use blocking_notifier_chain instead of atomic_notifier_chain, otherwise there will be RCU complaint, because unregister/register_virtio_device() will issue mbox message. mbox_send_message() is blocking again after received M4 partition reset. Actually, no need atomic notifier for scu irq notification since this notifier is called in worker instead of interrupt handler. [ 389.706645] i2c-rpmsg virtio0.rpmsg-i2c-channel.-1.2: i2c rpmsg driver is removed [ 389.767362] Wait for remote ready timeout, use first_notify. [ 389.774084] ------------[ cut here ]------------ [ 389.778729] WARNING: CPU: 0 PID: 397 at kernel/rcu/tree_plugin.h:293 rcu_note_context_switch+0x34/0x338 [ 389.788131] Modules linked in: [ 389.791195] CPU: 0 PID: 397 Comm: kworker/0:13 Not tainted 5.4.0-rc5-02977-g08f78722f07b #26 [ 389.799633] Hardware name: Freescale i.MX8DXL MEK (DT) [ 389.805481] Workqueue: events imx_scu_irq_work_handler Signed-off-by: Robin Gong Reviewed-by: Dong Aisheng Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/imx-scu-irq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index d9dcc20945c6..4408f150b3d5 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -42,25 +42,25 @@ struct imx_sc_msg_irq_enable { static struct imx_sc_ipc *imx_sc_irq_ipc_handle; static struct work_struct imx_sc_irq_work; -static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain); +static BLOCKING_NOTIFIER_HEAD(imx_scu_irq_notifier_chain); int imx_scu_irq_register_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_register( + return blocking_notifier_chain_register( &imx_scu_irq_notifier_chain, nb); } EXPORT_SYMBOL(imx_scu_irq_register_notifier); int imx_scu_irq_unregister_notifier(struct notifier_block *nb) { - return atomic_notifier_chain_unregister( + return blocking_notifier_chain_unregister( &imx_scu_irq_notifier_chain, nb); } EXPORT_SYMBOL(imx_scu_irq_unregister_notifier); static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group) { - return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain, + return blocking_notifier_call_chain(&imx_scu_irq_notifier_chain, status, (void *)group); } From d2bd250cefabd2ce51a77bf69435e28f1fa47176 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 7 Aug 2023 20:14:30 +0800 Subject: [PATCH 09/11] firmware: imx: scu-irq: add imx_scu_irq_get_status Extract the scu irq get status code from imx_scu_irq_work_handler and make into a new function imx_scu_irq_get_status which could be used by others, such as SECO. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/imx-scu-irq.c | 40 ++++++++++++++++++++---------- include/linux/firmware/imx/sci.h | 6 +++++ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 4408f150b3d5..6549f3792a0f 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2019 NXP + * Copyright 2019,2023 NXP * * Implementation of the SCU IRQ functions using MU. * @@ -66,29 +66,18 @@ static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group) static void imx_scu_irq_work_handler(struct work_struct *work) { - struct imx_sc_msg_irq_get_status msg; - struct imx_sc_rpc_msg *hdr = &msg.hdr; u32 irq_status; int ret; u8 i; for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { - hdr->ver = IMX_SC_RPC_VERSION; - hdr->svc = IMX_SC_RPC_SVC_IRQ; - hdr->func = IMX_SC_IRQ_FUNC_STATUS; - hdr->size = 2; - - msg.data.req.resource = mu_resource_id; - msg.data.req.group = i; - - ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); + ret = imx_scu_irq_get_status(i, &irq_status); if (ret) { pr_err("get irq group %d status failed, ret %d\n", i, ret); return; } - irq_status = msg.data.resp.status; if (!irq_status) continue; @@ -97,6 +86,31 @@ static void imx_scu_irq_work_handler(struct work_struct *work) } } +int imx_scu_irq_get_status(u8 group, u32 *irq_status) +{ + struct imx_sc_msg_irq_get_status msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_IRQ; + hdr->func = IMX_SC_IRQ_FUNC_STATUS; + hdr->size = 2; + + msg.data.req.resource = mu_resource_id; + msg.data.req.group = group; + + ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); + if (ret) + return ret; + + if (irq_status) + *irq_status = msg.data.resp.status; + + return 0; +} +EXPORT_SYMBOL(imx_scu_irq_get_status); + int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) { struct imx_sc_msg_irq_enable msg; diff --git a/include/linux/firmware/imx/sci.h b/include/linux/firmware/imx/sci.h index 7fa0f3b329b5..df17196df5ff 100644 --- a/include/linux/firmware/imx/sci.h +++ b/include/linux/firmware/imx/sci.h @@ -21,6 +21,7 @@ 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); int imx_scu_soc_init(struct device *dev); #else static inline int imx_scu_soc_init(struct device *dev) @@ -47,5 +48,10 @@ static inline int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) { return -EOPNOTSUPP; } + +static inline int imx_scu_irq_get_status(u8 group, u32 *irq_status) +{ + return -EOPNOTSUPP; +} #endif #endif /* _SC_SCI_H */ From 6c59ce485fd0015db160b913903c5f1e8c586d38 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 7 Aug 2023 20:14:31 +0800 Subject: [PATCH 10/11] firmware: imx: scu-irq: enlarge the IMX_SC_IRQ_NUM_GROUP Per SCFW update, update the IMX_SC_IRQ_NUM_GROUP to 9. Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/imx-scu-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 6549f3792a0f..8d902db1daf2 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -14,7 +14,7 @@ #define IMX_SC_IRQ_FUNC_ENABLE 1 #define IMX_SC_IRQ_FUNC_STATUS 2 -#define IMX_SC_IRQ_NUM_GROUP 4 +#define IMX_SC_IRQ_NUM_GROUP 9 static u32 mu_resource_id; From c081197a33a2813881b534c44666024c97fb025d Mon Sep 17 00:00:00 2001 From: Ranjani Vaidyanathan Date: Mon, 7 Aug 2023 20:14:32 +0800 Subject: [PATCH 11/11] firmware: imx: scu-irq: support 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 Signed-off-by: Peng Fan Signed-off-by: Shawn Guo --- drivers/firmware/imx/imx-scu-irq.c | 70 ++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index 8d902db1daf2..7cc0dec04587 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #define IMX_SC_IRQ_FUNC_ENABLE 1 #define IMX_SC_IRQ_FUNC_STATUS 2 @@ -40,6 +42,20 @@ struct imx_sc_msg_irq_enable { u8 enable; } __packed; +struct scu_wakeup { + u32 mask; + u32 wakeup_src; + bool valid; +}; + +/* Sysfs functions */ +static 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); @@ -71,6 +87,11 @@ 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", @@ -80,6 +101,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); @@ -135,6 +162,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); @@ -144,6 +176,25 @@ 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) +{ + int i; + + for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { + if (!scu_irq_wakeup[i].wakeup_src) + continue; + + if (scu_irq_wakeup[i].valid) + sprintf(buf, "Wakeup source group = %d, irq = 0x%x\n", + i, scu_irq_wakeup[i].wakeup_src); + else + sprintf(buf, "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; @@ -183,6 +234,25 @@ 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 (!wakeup_obj) { + ret = -ENOMEM; + goto free_ch; + } + + ret = sysfs_create_file(wakeup_obj, &wakeup_source_attr.attr); + if (ret) { + dev_err(dev, "Cannot create wakeup source src file......\n"); + kobject_put(wakeup_obj); + goto free_ch; + } + + return 0; + +free_ch: + mbox_free_channel(ch); + return ret; } EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);