Commit 7c6785d2 authored by Yunfei Dong's avatar Yunfei Dong Committed by Mauro Carvalho Chehab
Browse files

media: mediatek: vcodec: Add vdec enable/disable hardware helpers



Lock, power and clock are highly coupled operations. Adds vdec
enable/disable hardware helpers and uses them.

Signed-off-by: default avatarYunfei Dong <yunfei.dong@mediatek.com>
Reviewed-by: default avatarTzung-Bi <Shih&lt;tzungbi@google.com>
Reviewed-by: default avatarAngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: default avatarNícolas F. R. A. Prado <nfraprado@collabora.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 08a83828
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -193,9 +193,6 @@ static int fops_vcodec_open(struct file *file)
	mtk_vcodec_dec_set_default_params(ctx);

	if (v4l2_fh_is_singular(&ctx->fh)) {
		ret = mtk_vcodec_dec_pw_on(dev, MTK_VDEC_LAT0);
		if (ret < 0)
			goto err_load_fw;
		/*
		 * Does nothing if firmware was already loaded.
		 */
@@ -252,8 +249,6 @@ static int fops_vcodec_release(struct file *file)
	v4l2_m2m_ctx_release(ctx->m2m_ctx);
	mtk_vcodec_dec_release(ctx);

	if (v4l2_fh_is_singular(&ctx->fh))
		mtk_vcodec_dec_pw_off(dev, MTK_VDEC_LAT0);
	v4l2_fh_del(&ctx->fh);
	v4l2_fh_exit(&ctx->fh);
	v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+106 −60
Original line number Diff line number Diff line
@@ -57,74 +57,31 @@ int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *
}
EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk);

int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
static int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
{
	struct mtk_vdec_hw_dev *subdev_dev;
	struct mtk_vcodec_pm *pm;
	int ret;

	if (vdec_dev->vdec_pdata->is_subdev_supported) {
		subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
		if (!subdev_dev) {
			mtk_v4l2_err("Failed to get hw dev\n");
			return -EINVAL;
		}
		pm = &subdev_dev->pm;
	} else {
		pm = &vdec_dev->pm;
	}

	ret = pm_runtime_resume_and_get(pm->dev);
	if (ret)
		mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);

	return ret;
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_on);

void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
{
	struct mtk_vdec_hw_dev *subdev_dev;
	struct mtk_vcodec_pm *pm;
	int ret;

	if (vdec_dev->vdec_pdata->is_subdev_supported) {
		subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
		if (!subdev_dev) {
			mtk_v4l2_err("Failed to get hw dev\n");
			return;
		}
		pm = &subdev_dev->pm;
	} else {
		pm = &vdec_dev->pm;
	}

	ret = pm_runtime_put_sync(pm->dev);
	if (ret)
		mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_off);

void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
{
	struct mtk_vdec_hw_dev *subdev_dev;
	struct mtk_vcodec_pm *pm;
	struct mtk_vcodec_clk *dec_clk;
	int ret, i;

	if (vdec_dev->vdec_pdata->is_subdev_supported) {
		subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
		if (!subdev_dev) {
			mtk_v4l2_err("Failed to get hw dev\n");
			return;
		}
		pm = &subdev_dev->pm;
		enable_irq(subdev_dev->dec_irq);
	} else {
		pm = &vdec_dev->pm;
		enable_irq(vdec_dev->dec_irq);
	}

	dec_clk = &pm->vdec_clk;
	for (i = 0; i < dec_clk->clk_num; i++) {
		ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk);
@@ -140,30 +97,119 @@ void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
	for (i -= 1; i >= 0; i--)
		clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_on);

void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
static void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm)
{
	struct mtk_vdec_hw_dev *subdev_dev;
	struct mtk_vcodec_pm *pm;
	struct mtk_vcodec_clk *dec_clk;
	int i;

	dec_clk = &pm->vdec_clk;
	for (i = dec_clk->clk_num - 1; i >= 0; i--)
		clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
}

static void mtk_vcodec_dec_enable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
{
	struct mtk_vdec_hw_dev *subdev_dev;

	if (!test_bit(hw_idx, vdec_dev->subdev_bitmap))
		return;

	if (vdec_dev->vdec_pdata->is_subdev_supported) {
		subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
		if (!subdev_dev) {
		if (subdev_dev)
			enable_irq(subdev_dev->dec_irq);
		else
			mtk_v4l2_err("Failed to get hw dev\n");
			return;
	} else {
		enable_irq(vdec_dev->dec_irq);
	}
}
		pm = &subdev_dev->pm;

static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx)
{
	struct mtk_vdec_hw_dev *subdev_dev;

	if (!test_bit(hw_idx, vdec_dev->subdev_bitmap))
		return;

	if (vdec_dev->vdec_pdata->is_subdev_supported) {
		subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
		if (subdev_dev)
			disable_irq(subdev_dev->dec_irq);
		else
			mtk_v4l2_err("Failed to get hw dev\n");
	} else {
		pm = &vdec_dev->pm;
		disable_irq(vdec_dev->dec_irq);
	}
}

	dec_clk = &pm->vdec_clk;
	for (i = dec_clk->clk_num - 1; i >= 0; i--)
		clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev,
						   int hw_idx)
{
	struct mtk_vdec_hw_dev *subdev_dev;

	if (!test_bit(hw_idx, vdec_dev->subdev_bitmap))
		return NULL;

	if (vdec_dev->vdec_pdata->is_subdev_supported) {
		subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
		if (subdev_dev)
			return &subdev_dev->pm;

		mtk_v4l2_err("Failed to get hw dev\n");
		return NULL;
	}

	return &vdec_dev->pm;
}

static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev,
					int hw_idx)
{
	struct mtk_vcodec_pm *pm;

	pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx);
	if (pm) {
		mtk_vcodec_dec_pw_on(pm);
		mtk_vcodec_dec_clock_on(pm);
	}
}

static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev,
					 int hw_idx)
{
	struct mtk_vcodec_pm *pm;

	pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx);
	if (pm) {
		mtk_vcodec_dec_clock_off(pm);
		mtk_vcodec_dec_pw_off(pm);
	}
}

void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx)
{
	mutex_lock(&ctx->dev->dec_mutex[hw_idx]);

	if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) &&
	    hw_idx == MTK_VDEC_CORE)
		mtk_vcodec_dec_child_dev_on(ctx->dev, MTK_VDEC_LAT0);
	mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx);

	mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware);

void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx)
{
	mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx);

	mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx);
	if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) &&
	    hw_idx == MTK_VDEC_CORE)
		mtk_vcodec_dec_child_dev_off(ctx->dev, MTK_VDEC_LAT0);

	mutex_unlock(&ctx->dev->dec_mutex[hw_idx]);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_off);
EXPORT_SYMBOL_GPL(mtk_vcodec_dec_disable_hardware);
+2 −4
Original line number Diff line number Diff line
@@ -11,9 +11,7 @@

int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm);

int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx);
void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx);
void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx);

#endif /* _MTK_VCODEC_DEC_PM_H_ */
+6 −14
Original line number Diff line number Diff line
@@ -38,11 +38,9 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
		return -EINVAL;
	}

	mtk_vdec_lock(ctx);
	mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
	mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id);
	ret = ctx->dec_if->init(ctx);
	mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
	mtk_vdec_unlock(ctx);
	mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id);

	return ret;
}
@@ -70,15 +68,11 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs,
	if (!ctx->drv_handle)
		return -EIO;

	mtk_vdec_lock(ctx);

	mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id);
	mtk_vcodec_set_curr_ctx(ctx->dev, ctx, ctx->hw_id);
	mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
	ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg);
	mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
	mtk_vcodec_set_curr_ctx(ctx->dev, NULL, ctx->hw_id);

	mtk_vdec_unlock(ctx);
	mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id);

	return ret;
}
@@ -103,11 +97,9 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx)
	if (!ctx->drv_handle)
		return;

	mtk_vdec_lock(ctx);
	mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id);
	mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id);
	ctx->dec_if->deinit(ctx->drv_handle);
	mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id);
	mtk_vdec_unlock(ctx);
	mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id);

	ctx->drv_handle = NULL;
}
+2 −0
Original line number Diff line number Diff line
@@ -212,11 +212,13 @@ static void vdec_msg_queue_core_work(struct work_struct *work)
		return;

	ctx = lat_buf->ctx;
	mtk_vcodec_dec_enable_hardware(ctx, MTK_VDEC_CORE);
	mtk_vcodec_set_curr_ctx(dev, ctx, MTK_VDEC_CORE);

	lat_buf->core_decode(lat_buf);

	mtk_vcodec_set_curr_ctx(dev, NULL, MTK_VDEC_CORE);
	mtk_vcodec_dec_disable_hardware(ctx, MTK_VDEC_CORE);
	vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf);

	if (!list_empty(&ctx->msg_queue.lat_ctx.ready_queue)) {