Loading...
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 | // 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" #include "mtk_vpu.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) 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; } 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_runtime_enable(&pdev->dev); return ret; } void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev) { pm_runtime_disable(dev->pm.dev); } void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) { int ret; ret = pm_runtime_get_sync(pm->dev); if (ret) mtk_v4l2_err("pm_runtime_get_sync fail %d", 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); } |