1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
*/
#include <linux/clk.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <soc/mediatek/smi.h>
#include "mtk_vcodec_dec_pm.h"
#include "mtk_vcodec_util.h"
int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
{
struct device_node *node;
struct platform_device *pdev;
struct mtk_vcodec_pm *pm;
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!");
return -1;
}
pdev = of_find_device_by_node(node);
of_node_put(node);
if (WARN_ON(!pdev)) {
return -1;
}
pm->larbvdec = &pdev->dev;
pdev = mtkdev->plat_dev;
pm->dev = &pdev->dev;
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) {
ret = -ENOMEM;
goto put_device;
}
} else {
mtk_v4l2_err("Failed to get vdec clock count");
ret = -EINVAL;
goto put_device;
}
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);
goto put_device;
}
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);
ret = PTR_ERR(clk_info->vcodec_clk);
goto put_device;
}
}
pm_runtime_enable(&pdev->dev);
return 0;
put_device:
put_device(pm->larbvdec);
return ret;
}
void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev)
{
pm_runtime_disable(dev->pm.dev);
put_device(dev->pm.larbvdec);
}
int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
{
int ret;
ret = pm_runtime_resume_and_get(pm->dev);
if (ret)
mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret);
return ret;
}
void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
{
int ret;
ret = pm_runtime_put_sync(pm->dev);
if (ret)
mtk_v4l2_err("pm_runtime_put_sync fail %d", ret);
}
void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
{
struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk;
int ret, i = 0;
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) {
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);
for (i = dec_clk->clk_num - 1; i >= 0; i--)
clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
}
|