@@ -18,6 +18,7 @@
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/remoteproc.h>
#include <linux/workqueue.h>
@@ -333,6 +334,7 @@ static const struct imx_rproc_dcfg imx_rproc_cfg_imx7ulp = {
.att = imx_rproc_att_imx7ulp,
.att_size = ARRAY_SIZE(imx_rproc_att_imx7ulp),
.method = IMX_RPROC_NONE,
+ .flags = IMX_RPROC_NEED_SYSTEM_OFF,
};
static const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = {
@@ -1050,6 +1052,22 @@ static int imx_rproc_clk_enable(struct imx_rproc *priv)
return 0;
}
+static int imx_rproc_sys_off_handler(struct sys_off_data *data)
+{
+ struct rproc *rproc = data->cb_data;
+ int ret;
+
+ imx_rproc_free_mbox(rproc);
+
+ ret = imx_rproc_xtr_mbox_init(rproc, false);
+ if (ret) {
+ dev_err(&rproc->dev, "Failed to request non-blocking mbox\n");
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_DONE;
+}
+
static int imx_rproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1104,6 +1122,30 @@ static int imx_rproc_probe(struct platform_device *pdev)
if (rproc->state != RPROC_DETACHED)
rproc->auto_boot = of_property_read_bool(np, "fsl,auto-boot");
+ if (dcfg->flags & IMX_RPROC_NEED_SYSTEM_OFF) {
+ /*
+ * setup mailbox to non-blocking mode in
+ * [SYS_OFF_MODE_POWER_OFF_PREPARE, SYS_OFF_MODE_RESTART_PREPARE]
+ * phase before invoking [SYS_OFF_MODE_POWER_OFF, SYS_OFF_MODE_RESTART]
+ * atomic chain, see kernel/reboot.c.
+ */
+ ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF_PREPARE,
+ SYS_OFF_PRIO_DEFAULT,
+ imx_rproc_sys_off_handler, rproc);
+ if (ret) {
+ dev_err(dev, "register power off handler failure\n");
+ goto err_put_clk;
+ }
+
+ ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_RESTART_PREPARE,
+ SYS_OFF_PRIO_DEFAULT,
+ imx_rproc_sys_off_handler, rproc);
+ if (ret) {
+ dev_err(dev, "register restart handler failure\n");
+ goto err_put_clk;
+ }
+ }
+
ret = rproc_add(rproc);
if (ret) {
dev_err(dev, "rproc_add failed\n");
@@ -26,6 +26,9 @@ enum imx_rproc_method {
IMX_RPROC_SCU_API,
};
+/* dcfg flags */
+#define IMX_RPROC_NEED_SYSTEM_OFF BIT(0)
+
struct imx_rproc_dcfg {
u32 src_reg;
u32 src_mask;
@@ -36,6 +39,7 @@ struct imx_rproc_dcfg {
const struct imx_rproc_att *att;
size_t att_size;
enum imx_rproc_method method;
+ u32 flags;
};
#endif /* _IMX_RPROC_H */