Different from OVL, OVL adaptor is a pseudo device so we didn't
define it in the device tree, consequently, pm_runtime_resume_and_get()
called by .atomic_enable() powers on no device in OVL adaptor and
leads to power outage in the corresponding IOMMU.
To resolve the issue, we implement a function to power on the RDMAs
in OVL adaptor, and the system will make sure the IOMMU is powered on
as well because of the device link (iommus) in the RDMA nodes in DTS.
Fixes: 5db12f5d843b ("media: drm/mediatek: Add pm runtime support for ovl and rdma")
Signed-off-by: Hsiao Chien Sung <shawn.sung@xxxxxxxxxxxx>
---
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 4 ++
.../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 62 +++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_crtc.c | 28 +++------
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c | 2 +
drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.h | 20 ++++++
drivers/gpu/drm/mediatek/mtk_mdp_rdma.c | 16 +++++
6 files changed, 111 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index e2b602037ac3..c44f5b31bab5 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -109,6 +109,8 @@ void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev,
unsigned int next);
void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev,
unsigned int next);
+int mtk_ovl_adaptor_power_on(struct device *dev);
+void mtk_ovl_adaptor_power_off(struct device *dev);
int mtk_ovl_adaptor_clk_enable(struct device *dev);
void mtk_ovl_adaptor_clk_disable(struct device *dev);
void mtk_ovl_adaptor_config(struct device *dev, unsigned int w,
@@ -150,6 +152,8 @@ void mtk_rdma_disable_vblank(struct device *dev);
const u32 *mtk_rdma_get_formats(struct device *dev);
size_t mtk_rdma_get_num_formats(struct device *dev);
+int mtk_mdp_rdma_power_on(struct device *dev);
+void mtk_mdp_rdma_power_off(struct device *dev);
int mtk_mdp_rdma_clk_enable(struct device *dev);
void mtk_mdp_rdma_clk_disable(struct device *dev);
void mtk_mdp_rdma_start(struct device *dev, struct cmdq_pkt *cmdq_pkt);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index b80425360e76..8de57a5f5518 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -98,6 +98,8 @@ static const struct mtk_ddp_comp_funcs _padding = {
};
static const struct mtk_ddp_comp_funcs _rdma = {
+ .power_on = mtk_mdp_rdma_power_on,
+ .power_off = mtk_mdp_rdma_power_off,
.clk_enable = mtk_mdp_rdma_clk_enable,
.clk_disable = mtk_mdp_rdma_clk_disable,
};
@@ -241,6 +243,66 @@ void mtk_ovl_adaptor_stop(struct device *dev)
}
}
+/**
+ * mtk_ovl_adaptor_power_on - Power on devices in OVL adaptor
+ * @dev: device to be powered on
+ *
+ * Different from OVL, OVL adaptor is a pseudo device so
+ * we didn't define it in the device tree, pm_runtime_resume_and_get()
+ * called by .atomic_enable() power on no device in OVL adaptor,
+ * we have to implement a function to do the job instead.
+ *
+ * returns:
+ * zero on success, errno on failures.
+ */
+int mtk_ovl_adaptor_power_on(struct device *dev)
+{
+ int i, ret;
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+
+ for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
+ if (!ovl_adaptor->ovl_adaptor_comp[i] ||
+ !comp_matches[i].funcs->power_on)
+ continue;
+
+ /*
+ * do not power on the devices that don't define
+ * .power_off() function
+ */
+ if (!comp_matches[i].funcs->power_off) {
+ dev_warn(dev, ".power_off() is undefined\n");
+ continue;
+ }
+
+ ret = comp_matches[i].funcs->power_on(ovl_adaptor->ovl_adaptor_comp[i]);
+ if (ret < 0) {
+ mtk_ovl_adaptor_power_off(dev);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+/**
+ * mtk_ovl_adaptor_power_off - Power off devices in OVL adaptor
+ * @dev: device to be powered off
+ *
+ * call .power_off() function if defined
+ */