Commit 04bde674 authored by Yunfei Dong's avatar Yunfei Dong Committed by Mauro Carvalho Chehab
Browse files

media: mtk-vcodec: Using common interface to manage vdec/venc clock



Vdec: Using standard CCF interface to set parent clock and
clock rate in dtsi and using common interface to open/close
video decoder clock.
Venc: Using standard CCF interface to set parent clock in dtsi
and using common interface to open/close video encoder clock.

Signed-off-by: default avatarYunfei Dong <yunfei.dong@mediatek.com>
Signed-off-by: default avatarQianqian Yan <qianqian.yan@mediatek.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent d8501cc8
Loading
Loading
Loading
Loading
+53 −110
Original line number Diff line number Diff line
@@ -27,11 +27,14 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
	struct device_node *node;
	struct platform_device *pdev;
	struct mtk_vcodec_pm *pm;
	int ret = 0;
	struct mtk_vcodec_clk *dec_clk;
	struct mtk_vcodec_clk_info *clk_info;
	int i = 0, ret = 0;

	pdev = mtkdev->plat_dev;
	pm = &mtkdev->pm;
	pm->mtkdev = mtkdev;
	dec_clk = &pm->vdec_clk;
	node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0);
	if (!node) {
		mtk_v4l2_err("of_parse_phandle mediatek,larb fail!");
@@ -47,52 +50,34 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
	pdev = mtkdev->plat_dev;
	pm->dev = &pdev->dev;

	pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll");
	if (IS_ERR(pm->vcodecpll)) {
		mtk_v4l2_err("devm_clk_get vcodecpll fail");
		ret = PTR_ERR(pm->vcodecpll);
	}

	pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2");
	if (IS_ERR(pm->univpll_d2)) {
		mtk_v4l2_err("devm_clk_get univpll_d2 fail");
		ret = PTR_ERR(pm->univpll_d2);
	}

	pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel");
	if (IS_ERR(pm->clk_cci400_sel)) {
		mtk_v4l2_err("devm_clk_get clk_cci400_sel fail");
		ret = PTR_ERR(pm->clk_cci400_sel);
	}

	pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel");
	if (IS_ERR(pm->vdec_sel)) {
		mtk_v4l2_err("devm_clk_get vdec_sel fail");
		ret = PTR_ERR(pm->vdec_sel);
	}

	pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll");
	if (IS_ERR(pm->vdecpll)) {
		mtk_v4l2_err("devm_clk_get vdecpll fail");
		ret = PTR_ERR(pm->vdecpll);
	}

	pm->vencpll = devm_clk_get(&pdev->dev, "vencpll");
	if (IS_ERR(pm->vencpll)) {
		mtk_v4l2_err("devm_clk_get vencpll fail");
		ret = PTR_ERR(pm->vencpll);
	dec_clk->clk_num =
		of_property_count_strings(pdev->dev.of_node, "clock-names");
	if (dec_clk->clk_num > 0) {
		dec_clk->clk_info = devm_kcalloc(&pdev->dev,
			dec_clk->clk_num, sizeof(*clk_info),
			GFP_KERNEL);
		if (!dec_clk->clk_info)
			return -ENOMEM;
	} else {
		mtk_v4l2_err("Failed to get vdec clock count");
		return -EINVAL;
	}

	for (i = 0; i < dec_clk->clk_num; i++) {
		clk_info = &dec_clk->clk_info[i];
		ret = of_property_read_string_index(pdev->dev.of_node,
			"clock-names", i, &clk_info->clk_name);
		if (ret) {
			mtk_v4l2_err("Failed to get clock name id = %d", i);
			return ret;
		}

	pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
	if (IS_ERR(pm->venc_lt_sel)) {
		mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
		ret = PTR_ERR(pm->venc_lt_sel);
		clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
			clk_info->clk_name);
		if (IS_ERR(clk_info->vcodec_clk)) {
			mtk_v4l2_err("devm_clk_get (%d)%s fail", i,
				clk_info->clk_name);
			return PTR_ERR(clk_info->vcodec_clk);
		}

	pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src");
	if (IS_ERR(pm->vdec_bus_clk_src)) {
		mtk_v4l2_err("devm_clk_get vdec_bus_clk_src");
		ret = PTR_ERR(pm->vdec_bus_clk_src);
	}

	pm_runtime_enable(&pdev->dev);
@@ -125,78 +110,36 @@ void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)

void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
{
	int ret;

	ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000);
	if (ret)
		mtk_v4l2_err("clk_set_rate vcodecpll fail %d", ret);

	ret = clk_set_rate(pm->vencpll, 800 * 1000000);
	if (ret)
		mtk_v4l2_err("clk_set_rate vencpll fail %d", ret);

	ret = clk_prepare_enable(pm->vcodecpll);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret);

	ret = clk_prepare_enable(pm->vencpll);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable vencpll fail %d", ret);
	struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk;
	int ret, i = 0;

	ret = clk_prepare_enable(pm->vdec_bus_clk_src);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d",
				ret);

	ret = clk_prepare_enable(pm->venc_lt_sel);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret);

	ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src);
	if (ret)
		mtk_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d",
				ret);

	ret = clk_prepare_enable(pm->univpll_d2);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret);

	ret = clk_prepare_enable(pm->clk_cci400_sel);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret);

	ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2);
	if (ret)
		mtk_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d",
				ret);

	ret = clk_prepare_enable(pm->vdecpll);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable vdecpll fail %d", ret);

	ret = clk_prepare_enable(pm->vdec_sel);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret);

	ret = clk_set_parent(pm->vdec_sel, pm->vdecpll);
	if (ret)
		mtk_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret);
	for (i = 0; i < dec_clk->clk_num; i++) {
		ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk);
		if (ret) {
			mtk_v4l2_err("clk_prepare_enable %d %s fail %d", i,
				dec_clk->clk_info[i].clk_name, ret);
			goto error;
		}
	}

	ret = mtk_smi_larb_get(pm->larbvdec);
	if (ret)
	if (ret) {
		mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret);
		goto error;
	}
	return;

error:
	for (i -= 1; i >= 0; i--)
		clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
}

void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm)
{
	struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk;
	int i = 0;

	mtk_smi_larb_put(pm->larbvdec);
	clk_disable_unprepare(pm->vdec_sel);
	clk_disable_unprepare(pm->vdecpll);
	clk_disable_unprepare(pm->univpll_d2);
	clk_disable_unprepare(pm->clk_cci400_sel);
	clk_disable_unprepare(pm->venc_lt_sel);
	clk_disable_unprepare(pm->vdec_bus_clk_src);
	clk_disable_unprepare(pm->vencpll);
	clk_disable_unprepare(pm->vcodecpll);
	for (i = dec_clk->clk_num - 1; i >= 0; i--)
		clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
}
+19 −12
Original line number Diff line number Diff line
@@ -175,23 +175,30 @@ struct mtk_enc_params {
	unsigned int	force_intra;
};

/**
 * struct mtk_vcodec_clk_info - Structure used to store clock name
 */
struct mtk_vcodec_clk_info {
	const char	*clk_name;
	struct clk	*vcodec_clk;
};

/**
 * struct mtk_vcodec_clk - Structure used to store vcodec clock information
 */
struct mtk_vcodec_clk {
	struct mtk_vcodec_clk_info	*clk_info;
	int	clk_num;
};

/**
 * struct mtk_vcodec_pm - Power management data structure
 */
struct mtk_vcodec_pm {
	struct clk	*vdec_bus_clk_src;
	struct clk	*vencpll;

	struct clk	*vcodecpll;
	struct clk	*univpll_d2;
	struct clk	*clk_cci400_sel;
	struct clk	*vdecpll;
	struct clk	*vdec_sel;
	struct clk	*vencpll_d2;
	struct clk	*venc_sel;
	struct clk	*univpll1_d2;
	struct clk	*venc_lt_sel;
	struct mtk_vcodec_clk	vdec_clk;
	struct device	*larbvdec;

	struct mtk_vcodec_clk	venc_clk;
	struct device	*larbvenc;
	struct device	*larbvenclt;
	struct device	*dev;
+60 −44
Original line number Diff line number Diff line
@@ -27,9 +27,11 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
{
	struct device_node *node;
	struct platform_device *pdev;
	struct device *dev;
	struct mtk_vcodec_pm *pm;
	int ret = 0;
	struct mtk_vcodec_clk *enc_clk;
	struct mtk_vcodec_clk_info *clk_info;
	int ret = 0, i = 0;
	struct device *dev;

	pdev = mtkdev->plat_dev;
	pm = &mtkdev->pm;
@@ -37,6 +39,7 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
	pm->mtkdev = mtkdev;
	pm->dev = &pdev->dev;
	dev = &pdev->dev;
	enc_clk = &pm->venc_clk;

	node = of_parse_phandle(dev->of_node, "mediatek,larb", 0);
	if (!node) {
@@ -68,28 +71,34 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
	pdev = mtkdev->plat_dev;
	pm->dev = &pdev->dev;

	pm->vencpll_d2 = devm_clk_get(&pdev->dev, "venc_sel_src");
	if (IS_ERR(pm->vencpll_d2)) {
		mtk_v4l2_err("devm_clk_get vencpll_d2 fail");
		ret = PTR_ERR(pm->vencpll_d2);
	enc_clk->clk_num = of_property_count_strings(pdev->dev.of_node,
		"clock-names");
	if (enc_clk->clk_num > 0) {
		enc_clk->clk_info = devm_kcalloc(&pdev->dev,
			enc_clk->clk_num, sizeof(*clk_info),
			GFP_KERNEL);
		if (!enc_clk->clk_info)
			return -ENOMEM;
	} else {
		mtk_v4l2_err("Failed to get venc clock count");
		return -EINVAL;
	}

	pm->venc_sel = devm_clk_get(&pdev->dev, "venc_sel");
	if (IS_ERR(pm->venc_sel)) {
		mtk_v4l2_err("devm_clk_get venc_sel fail");
		ret = PTR_ERR(pm->venc_sel);
	for (i = 0; i < enc_clk->clk_num; i++) {
		clk_info = &enc_clk->clk_info[i];
		ret = of_property_read_string_index(pdev->dev.of_node,
			"clock-names", i, &clk_info->clk_name);
		if (ret) {
			mtk_v4l2_err("venc failed to get clk name %d", i);
			return ret;
		}

	pm->univpll1_d2 = devm_clk_get(&pdev->dev, "venc_lt_sel_src");
	if (IS_ERR(pm->univpll1_d2)) {
		mtk_v4l2_err("devm_clk_get univpll1_d2 fail");
		ret = PTR_ERR(pm->univpll1_d2);
		clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
			clk_info->clk_name);
		if (IS_ERR(clk_info->vcodec_clk)) {
			mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i,
				clk_info->clk_name);
			return PTR_ERR(clk_info->vcodec_clk);
		}

	pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel");
	if (IS_ERR(pm->venc_lt_sel)) {
		mtk_v4l2_err("devm_clk_get venc_lt_sel fail");
		ret = PTR_ERR(pm->venc_lt_sel);
	}

	return ret;
@@ -102,38 +111,45 @@ void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *mtkdev)

void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm)
{
	int ret;

	ret = clk_prepare_enable(pm->venc_sel);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable fail %d", ret);

	ret = clk_set_parent(pm->venc_sel, pm->vencpll_d2);
	if (ret)
		mtk_v4l2_err("clk_set_parent fail %d", ret);

	ret = clk_prepare_enable(pm->venc_lt_sel);
	if (ret)
		mtk_v4l2_err("clk_prepare_enable fail %d", ret);

	ret = clk_set_parent(pm->venc_lt_sel, pm->univpll1_d2);
	if (ret)
		mtk_v4l2_err("clk_set_parent fail %d", ret);
	struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
	int ret, i = 0;

	for (i = 0; i < enc_clk->clk_num; i++) {
		ret = clk_prepare_enable(enc_clk->clk_info[i].vcodec_clk);
		if (ret) {
			mtk_v4l2_err("venc clk_prepare_enable %d %s fail %d", i,
				enc_clk->clk_info[i].clk_name, ret);
			goto clkerr;
		}
	}

	ret = mtk_smi_larb_get(pm->larbvenc);
	if (ret)
	if (ret) {
		mtk_v4l2_err("mtk_smi_larb_get larb3 fail %d", ret);

		goto larbvencerr;
	}
	ret = mtk_smi_larb_get(pm->larbvenclt);
	if (ret)
	if (ret) {
		mtk_v4l2_err("mtk_smi_larb_get larb4 fail %d", ret);
		goto larbvenclterr;
	}
	return;

larbvenclterr:
	mtk_smi_larb_put(pm->larbvenc);
larbvencerr:
clkerr:
	for (i -= 1; i >= 0; i--)
		clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
}

void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm)
{
	struct mtk_vcodec_clk *enc_clk = &pm->venc_clk;
	int i = 0;

	mtk_smi_larb_put(pm->larbvenc);
	mtk_smi_larb_put(pm->larbvenclt);
	clk_disable_unprepare(pm->venc_lt_sel);
	clk_disable_unprepare(pm->venc_sel);
	for (i = enc_clk->clk_num - 1; i >= 0; i--)
		clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk);
}