@@ -110,6 +110,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,
@@ -151,6 +153,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);
@@ -80,6 +80,8 @@ static const struct mtk_ddp_comp_funcs merge = {
};
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,
};
@@ -201,21 +203,72 @@ void mtk_ovl_adaptor_stop(struct device *dev)
mtk_ethdr_stop(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0]);
}
-int mtk_ovl_adaptor_clk_enable(struct device *dev)
+/**
+ * power_off - Power off the devices in OVL adaptor
+ * @dev: Device to be powered off
+ * @num: Number of the devices to be powered off
+ *
+ * Calls the .power_off() ovl_adaptor component callback if it is present.
+ */
+static inline void power_off(struct device *dev, int num)
{
struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
- struct device *comp;
- int ret;
int i;
- for (i = 0; i < OVL_ADAPTOR_MERGE0; i++) {
- comp = ovl_adaptor->ovl_adaptor_comp[i];
- ret = pm_runtime_get_sync(comp);
+ if (num > OVL_ADAPTOR_ID_MAX)
+ num = OVL_ADAPTOR_ID_MAX;
+
+ for (i = num - 1; i >= 0; i--) {
+ if (!ovl_adaptor->ovl_adaptor_comp[i] ||
+ !comp_matches[i].funcs->power_off)
+ continue;
+
+ comp_matches[i].funcs->power_off(ovl_adaptor->ovl_adaptor_comp[i]);
+ }
+}
+
+/**
+ * mtk_ovl_adaptor_power_on - Power on the 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.
+ *
+ * Return: Zero for success or negative number for failure.
+ */
+int mtk_ovl_adaptor_power_on(struct device *dev)
+{
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+ int i, ret;
+
+ for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
+ if (!ovl_adaptor->ovl_adaptor_comp[i] ||
+ !comp_matches[i].funcs->power_on)
+ continue;
+
+ ret = comp_matches[i].funcs->power_on(ovl_adaptor->ovl_adaptor_comp[i]);
if (ret < 0) {
dev_err(dev, "Failed to enable power domain %d, err %d\n", i, ret);
- goto error;
+ power_off(dev, i);
+ return ret;
}
}
+ return 0;
+}
+
+void mtk_ovl_adaptor_power_off(struct device *dev)
+{
+ power_off(dev, OVL_ADAPTOR_ID_MAX);
+}
+
+int mtk_ovl_adaptor_clk_enable(struct device *dev)
+{
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+ struct device *comp;
+ int ret;
+ int i;
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
comp = ovl_adaptor->ovl_adaptor_comp[i];
@@ -226,16 +279,10 @@ int mtk_ovl_adaptor_clk_enable(struct device *dev)
dev_err(dev, "Failed to enable clock %d, err %d\n", i, ret);
while (--i >= 0)
comp_matches[i].funcs->clk_disable(comp);
- i = OVL_ADAPTOR_MERGE0;
- goto error;
+ return ret;
}
}
return 0;
-error:
- while (--i >= 0)
- pm_runtime_put(ovl_adaptor->ovl_adaptor_comp[i]);
-
- return ret;
}
void mtk_ovl_adaptor_clk_disable(struct device *dev)
@@ -721,7 +721,7 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc,
DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
- ret = pm_runtime_resume_and_get(comp->dev);
+ ret = mtk_ddp_comp_power_on(comp);
if (ret < 0) {
DRM_DEV_ERROR(comp->dev, "Failed to enable power domain: %d\n", ret);
return;
@@ -731,7 +731,7 @@ static void mtk_drm_crtc_atomic_enable(struct drm_crtc *crtc,
ret = mtk_crtc_ddp_hw_init(mtk_crtc);
if (ret) {
- pm_runtime_put(comp->dev);
+ mtk_ddp_comp_power_off(comp);
return;
}
@@ -744,7 +744,7 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc,
{
struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
- int i, ret;
+ int i;
DRM_DEBUG_DRIVER("%s %d\n", __func__, crtc->base.id);
if (!mtk_crtc->enabled)
@@ -774,9 +774,7 @@ static void mtk_drm_crtc_atomic_disable(struct drm_crtc *crtc,
drm_crtc_vblank_off(crtc);
mtk_crtc_ddp_hw_fini(mtk_crtc);
- ret = pm_runtime_put(comp->dev);
- if (ret < 0)
- DRM_DEV_ERROR(comp->dev, "Failed to disable power domain: %d\n", ret);
+ mtk_ddp_comp_power_off(comp);
mtk_crtc->enabled = false;
}
@@ -398,6 +398,8 @@ static const struct mtk_ddp_comp_funcs ddp_ufoe = {
};
static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = {
+ .power_on = mtk_ovl_adaptor_power_on,
+ .power_off = mtk_ovl_adaptor_power_off,
.clk_enable = mtk_ovl_adaptor_clk_enable,
.clk_disable = mtk_ovl_adaptor_clk_disable,
.config = mtk_ovl_adaptor_config,
@@ -7,6 +7,7 @@
#define MTK_DRM_DDP_COMP_H
#include <linux/io.h>
+#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
@@ -46,6 +47,8 @@ enum mtk_ddp_comp_type {
struct mtk_ddp_comp;
struct cmdq_pkt;
struct mtk_ddp_comp_funcs {
+ int (*power_on)(struct device *dev);
+ void (*power_off)(struct device *dev);
int (*clk_enable)(struct device *dev);
void (*clk_disable)(struct device *dev);
void (*config)(struct device *dev, unsigned int w,
@@ -92,6 +95,23 @@ struct mtk_ddp_comp {
const struct mtk_ddp_comp_funcs *funcs;
};
+static inline int mtk_ddp_comp_power_on(struct mtk_ddp_comp *comp)
+{
+ if (comp->funcs && comp->funcs->power_on)
+ return comp->funcs->power_on(comp->dev);
+ else
+ return pm_runtime_resume_and_get(comp->dev);
+ return 0;
+}
+
+static inline void mtk_ddp_comp_power_off(struct mtk_ddp_comp *comp)
+{
+ if (comp->funcs && comp->funcs->power_off)
+ comp->funcs->power_off(comp->dev);
+ else
+ pm_runtime_put(comp->dev);
+}
+
static inline int mtk_ddp_comp_clk_enable(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->clk_enable)
@@ -242,6 +242,22 @@ size_t mtk_mdp_rdma_get_num_formats(struct device *dev)
return ARRAY_SIZE(formats);
}
+int mtk_mdp_rdma_power_on(struct device *dev)
+{
+ int ret = pm_runtime_resume_and_get(dev);
+
+ if (ret < 0) {
+ dev_err(dev, "Failed to power on: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+void mtk_mdp_rdma_power_off(struct device *dev)
+{
+ pm_runtime_put(dev);
+}
+
int mtk_mdp_rdma_clk_enable(struct device *dev)
{
struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev);