summaryrefslogtreecommitdiff
authorNanxin Qin <nanxin.qin@amlogic.com>2020-04-02 07:32:33 (GMT)
committer Nanxin Qin <nanxin.qin@amlogic.com>2020-06-04 09:06:33 (GMT)
commitdeb35d45d697c28f18bfa406e4eabbdd430be88a (patch)
tree93b005a6ad962321d76202af844fc006e486b43e
parent92a6ea7cdafe3717c7e05c1282a8d24dbbd90216 (diff)
downloadmedia_modules-deb35d45d697c28f18bfa406e4eabbdd430be88a.zip
media_modules-deb35d45d697c28f18bfa406e4eabbdd430be88a.tar.gz
media_modules-deb35d45d697c28f18bfa406e4eabbdd430be88a.tar.bz2
vdec: support power domain to ctrl power on/off. [2/2]
PD#SWPL-23135 Problem: support the power domain for the video decoder on kernel 5.4. Solution: support power domain to ctrl power on/off. Verify: u212 Change-Id: I7154066ef08997a05155fa58fc9a2a1640dbe23a Signed-off-by: Nanxin Qin <nanxin.qin@amlogic.com>
Diffstat
-rwxr-xr-xMedia.mk2
-rw-r--r--drivers/frame_provider/decoder/utils/vdec.c155
2 files changed, 156 insertions, 1 deletions
diff --git a/Media.mk b/Media.mk
index 6d4d156..58db63b 100755
--- a/Media.mk
+++ b/Media.mk
@@ -92,7 +92,7 @@ endif
modules:
CCACHE_NODIRECT="true" PATH=$(KERNEL_TOOLPATHS):$$PATH \
- $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) $(KERNEL_ARGS) $(CONFIGS) \
+ $(MAKE) -C $(KDIR) M=$(MEDIA_DRIVERS) ARCH=$(KERNEL_ARCH) $(KERNEL_ARGS) $(CONFIGS) \
EXTRA_CFLAGS+=-I$(INCLUDE) -j64
copy-modules:
diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c
index 92e16e0..983869f 100644
--- a/drivers/frame_provider/decoder/utils/vdec.c
+++ b/drivers/frame_provider/decoder/utils/vdec.c
@@ -83,6 +83,9 @@
#ifdef CONFIG_AMLOGIC_IONVIDEO
#include <linux/amlogic/media/video_sink/ionvideo_ext.h>
#endif
+#include <linux/pm.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
/* wait other module to support this function */
#define is_support_power_ctrl() 0
@@ -133,6 +136,8 @@ static int enable_mvdec_info = 1;
int decode_underflow = 0;
+static bool disable_power_domain;
+
#define CANVAS_MAX_SIZE (AMVDEC_CANVAS_MAX1 - AMVDEC_CANVAS_START_INDEX + 1 + AMVDEC_CANVAS_MAX2 + 1)
struct am_reg {
@@ -156,6 +161,27 @@ struct decode_fps_s {
u32 fps;
};
+enum vdec_pd_e {
+ PD_VDEC,
+ PD_HCODEC,
+ PD_HEVC,
+ PD_WAVE,
+ PD_MAX
+};
+
+struct vdec_pwrc_s {
+ u8 *name;
+ struct device *dev;
+ struct device_link *link;
+};
+
+static struct vdec_pwrc_s vdec_pd[] = {
+ { .name = "pwrc-vdec", },
+ { .name = "pwrc-hcodec",},
+ { .name = "pwrc-hevc", },
+ { .name = "pwrc-wave", },
+};
+
struct vdec_core_s {
struct list_head connected_vdec_list;
spinlock_t lock;
@@ -184,6 +210,7 @@ struct vdec_core_s {
struct decode_fps_s decode_fps[MAX_INSTANCE_MUN];
unsigned long buff_flag;
unsigned long stream_buff_flag;
+ struct vdec_pwrc_s *pd;
};
struct canvas_status_s {
@@ -3233,6 +3260,8 @@ void vdec_power_reset(void)
}
EXPORT_SYMBOL(vdec_power_reset);
+static void vdec_power_switch(struct vdec_pwrc_s *pd, int id, bool on);
+
void vdec_poweron(enum vdec_type_e core)
{
void *decomp_addr = NULL;
@@ -3258,6 +3287,33 @@ void vdec_poweron(enum vdec_type_e core)
return;
}
+ /* power domain check. */
+ if (!disable_power_domain && vdec_core->pd) {
+ int pd_id = 0;
+
+ if (core == VDEC_1) {
+ amports_switch_gate("clk_vdec_mux", 1);
+ vdec_clock_hi_enable();
+ pd_id = PD_VDEC;
+ } else if (core == VDEC_HCODEC) {
+ hcodec_clock_enable();
+ pd_id = PD_HCODEC;
+ } else if (core == VDEC_HEVC) {
+ /* enable hevc clock */
+ amports_switch_gate("clk_hevc_mux", 1);
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ amports_switch_gate("clk_hevcb_mux", 1);
+ hevc_clock_hi_enable();
+ hevc_back_clock_hi_enable();
+ pd_id = PD_HEVC;
+ }
+
+ vdec_power_switch(vdec_core->pd, pd_id, true);
+ mutex_unlock(&vdec_mutex);
+
+ return;
+ }
+
is_power_ctrl_ver2 =
((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
@@ -3515,6 +3571,30 @@ void vdec_poweroff(enum vdec_type_e core)
return;
}
+ /* power domain check. */
+ if (!disable_power_domain && vdec_core->pd) {
+ int pd_id = 0;
+
+ if (core == VDEC_1) {
+ vdec_clock_off();
+ pd_id = PD_VDEC;
+ } else if (core == VDEC_HCODEC) {
+ hcodec_clock_off();
+ pd_id = PD_HCODEC;
+ } else if (core == VDEC_HEVC) {
+ /* disable hevc clock */
+ hevc_clock_off();
+ if (get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A)
+ hevc_back_clock_off();
+ pd_id = PD_HEVC;
+ }
+
+ vdec_power_switch(vdec_core->pd, pd_id, false);
+ mutex_unlock(&vdec_mutex);
+
+ return;
+ }
+
is_power_ctrl_ver2 =
((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_SM1) &&
(get_cpu_major_id() != AM_MESON_CPU_MAJOR_ID_TL1)) ? true : false;
@@ -4902,6 +4982,65 @@ struct device *get_vdec_device(void)
}
EXPORT_SYMBOL(get_vdec_device);
+static void vdec_power_switch(struct vdec_pwrc_s *pd, int id, bool on)
+{
+ struct device *dev = pd[id].dev;
+
+ if (on)
+ pm_runtime_get_sync(dev);
+ else
+ pm_runtime_put_sync(dev);
+
+ pr_debug("the %-15s power %s\n",
+ pd[id].name, on ? "on" : "off");
+}
+
+static int vdec_power_domain_init(struct device *dev,
+ struct vdec_pwrc_s **pd_out)
+{
+ int i, err;
+ struct vdec_pwrc_s *pd = vdec_pd;
+
+ for (i = 0; i < ARRAY_SIZE(vdec_pd); i++) {
+ pd[i].dev = dev_pm_domain_attach_by_name(dev, pd[i].name);
+ if (IS_ERR_OR_NULL(pd[i].dev)) {
+ err = PTR_ERR(pd[i].dev);
+ dev_err(dev, "Get %s failed, pm-domain: %d\n",
+ pd[i].name, err);
+ continue;
+ }
+
+ pd[i].link = device_link_add(dev, pd[i].dev,
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_STATELESS);
+ if (IS_ERR_OR_NULL(pd[i].link)) {
+ dev_err(dev, "Adding %s device link failed!\n",
+ pd[i].name);
+ return -ENODEV;
+ }
+
+ pr_debug("power domain: name: %s, dev: %px, link: %px\n",
+ pd[i].name, pd[i].dev, pd[i].link);
+ }
+
+ *pd_out = pd;
+
+ return 0;
+}
+
+static void vdec_power_domain_remove(struct vdec_pwrc_s *pd)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vdec_pd); i++) {
+ if (!IS_ERR_OR_NULL(pd[i].link))
+ device_link_del(pd[i].link);
+
+ if (!IS_ERR_OR_NULL(pd[i].dev))
+ dev_pm_domain_detach(pd[i].dev, true);
+ }
+}
+
static int vdec_probe(struct platform_device *pdev)
{
s32 i, r;
@@ -4981,6 +5120,17 @@ static int vdec_probe(struct platform_device *pdev)
vdec_core->vdec_core_wq = alloc_ordered_workqueue("%s",__WQ_LEGACY |
WQ_MEM_RECLAIM |WQ_HIGHPRI/*high priority*/, "vdec-work");
/*work queue priority lower than vdec-core.*/
+
+ /* init power domains. */
+ if (of_property_read_bool(pdev->dev.of_node, "power-domains")) {
+ r = vdec_power_domain_init(&pdev->dev, &vdec_core->pd);
+ if (r) {
+ vdec_power_domain_remove(vdec_core->pd);
+ pr_err("vdec power domain init failed\n");
+ return r;
+ }
+ }
+
return 0;
}
@@ -5002,6 +5152,10 @@ static int vdec_remove(struct platform_device *pdev)
kthread_stop(vdec_core->thread);
destroy_workqueue(vdec_core->vdec_core_wq);
+
+ if (vdec_core->pd)
+ vdec_power_domain_remove(vdec_core->pd);
+
class_unregister(&vdec_class);
return 0;
@@ -5216,6 +5370,7 @@ module_param(fps_detection, int, 0664);
module_param(fps_clear, int, 0664);
module_param(force_nosecure_even_drm, int, 0664);
module_param(disable_switch_single_to_mult, int, 0664);
+module_param(disable_power_domain, bool, 0664);
module_param(frameinfo_flag, int, 0664);
MODULE_PARM_DESC(frameinfo_flag,