Messages in this thread | | | Subject | Re: [PATCH 6/6] driver: soc: xilinx: register for power events in zynqmp power driver | From | Michal Simek <> | Date | Mon, 21 Jun 2021 14:00:27 +0200 |
| |
On 5/28/21 5:59 PM, Abhyuday Godhasara wrote: > With Xilinx Event Management driver, all types of events like power and > error gets handled from single place as part of event management driver. > > So power events(SUSPEND_POWER_REQUEST and SUSPEND_SYSTEM_SHUTDOWN) > also gets handled by event management driver instead of zynqmp_power > driver. > > zynqmp-power driver use event management driver and provide callback > function for Suspend and shutdown handler, which will be called by event > management driver when respective event is arrived. > > If event management driver is not available than use ipi-mailbox rx channel > or IPI interrupt IRQ handler for power events (suspend/shutdown) same as > current zynqmp-power driver. > > Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com> > Signed-off-by: Abhyuday Godhasara <abhyuday.godhasara@xilinx.com> > --- > drivers/soc/xilinx/zynqmp_power.c | 48 ++++++++++++++++++++++++++++++++++++++- > 1 file changed, 47 insertions(+), 1 deletion(-) > > diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c > index 76478fe..fe7be17 100644 > --- a/drivers/soc/xilinx/zynqmp_power.c > +++ b/drivers/soc/xilinx/zynqmp_power.c > @@ -16,6 +16,7 @@ > #include <linux/suspend.h> > > #include <linux/firmware/xlnx-zynqmp.h> > +#include <linux/firmware/xlnx-event-manager.h> > #include <linux/mailbox/zynqmp-ipi-message.h> > > /** > @@ -30,6 +31,7 @@ struct zynqmp_pm_work_struct { > > static struct zynqmp_pm_work_struct *zynqmp_pm_init_suspend_work; > static struct mbox_chan *rx_chan; > +static bool event_registered; > > enum pm_suspend_mode { > PM_SUSPEND_MODE_FIRST = 0, > @@ -51,6 +53,19 @@ static void zynqmp_pm_get_callback_data(u32 *buf) > zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, 0, 0, 0, 0, buf); > } > > +static void suspend_event_callback(const u32 *payload, void *data) > +{ > + /* First element is callback API ID, others are callback arguments */ > + if (work_pending(&zynqmp_pm_init_suspend_work->callback_work)) > + return; > + > + /* Copy callback arguments into work's structure */ > + memcpy(zynqmp_pm_init_suspend_work->args, &payload[1], > + sizeof(zynqmp_pm_init_suspend_work->args)); > + > + queue_work(system_unbound_wq, &zynqmp_pm_init_suspend_work->callback_work); > +} > + > static irqreturn_t zynqmp_pm_isr(int irq, void *data) > { > u32 payload[CB_PAYLOAD_SIZE]; > @@ -179,7 +194,32 @@ static int zynqmp_pm_probe(struct platform_device *pdev) > if (pm_api_version < ZYNQMP_PM_VERSION) > return -ENODEV; > > - if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { > + /* > + * First try to use Xilinx Event Manager by registering suspend_event_callback > + * for suspend/shutdown event. > + * If xlnx_register_event() returns -EACCES (Xilinx Event Manager > + * is not available to use) or -ENODEV(Xilinx Event Manager not compiled), > + * then use ipi-mailbox or interrupt method. > + */ > + ret = xlnx_register_event(PM_INIT_SUSPEND_CB, 0, 0, false, > + suspend_event_callback, NULL); > + if (!ret) { > + zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev, > + sizeof(struct zynqmp_pm_work_struct), > + GFP_KERNEL); > + if (!zynqmp_pm_init_suspend_work) { > + xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, > + suspend_event_callback); > + return -ENOMEM; > + } > + event_registered = true; > + > + INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work, > + zynqmp_pm_init_suspend_work_fn); > + } else if (ret != -EACCES && ret != -ENODEV) { > + dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n", ret); > + return ret; > + } else if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { > zynqmp_pm_init_suspend_work = > devm_kzalloc(&pdev->dev, > sizeof(struct zynqmp_pm_work_struct), > @@ -223,6 +263,10 @@ static int zynqmp_pm_probe(struct platform_device *pdev) > > ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr); > if (ret) { > + if (event_registered) { > + xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback); > + event_registered = false; > + } > dev_err(&pdev->dev, "unable to create sysfs interface\n"); > return ret; > } > @@ -233,6 +277,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev) > static int zynqmp_pm_remove(struct platform_device *pdev) > { > sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr); > + if (event_registered) > + xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback); > > if (!rx_chan) > mbox_free_channel(rx_chan); >
Acked-by: Michal Simek <michal.simek@xilinx.com>
Thanks, Michal
| |