Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.1-rc3 145 lines 3.6 kB view raw
1/* 2 * Copyright (c) 2016 MediaTek Inc. 3 * Author: Tiffany Lin <tiffany.lin@mediatek.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 */ 14 15#include <linux/clk.h> 16#include <linux/of_address.h> 17#include <linux/of_platform.h> 18#include <linux/pm_runtime.h> 19#include <soc/mediatek/smi.h> 20 21#include "mtk_vcodec_dec_pm.h" 22#include "mtk_vcodec_util.h" 23#include "mtk_vpu.h" 24 25int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) 26{ 27 struct device_node *node; 28 struct platform_device *pdev; 29 struct mtk_vcodec_pm *pm; 30 struct mtk_vcodec_clk *dec_clk; 31 struct mtk_vcodec_clk_info *clk_info; 32 int i = 0, ret = 0; 33 34 pdev = mtkdev->plat_dev; 35 pm = &mtkdev->pm; 36 pm->mtkdev = mtkdev; 37 dec_clk = &pm->vdec_clk; 38 node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0); 39 if (!node) { 40 mtk_v4l2_err("of_parse_phandle mediatek,larb fail!"); 41 return -1; 42 } 43 44 pdev = of_find_device_by_node(node); 45 if (WARN_ON(!pdev)) { 46 of_node_put(node); 47 return -1; 48 } 49 pm->larbvdec = &pdev->dev; 50 pdev = mtkdev->plat_dev; 51 pm->dev = &pdev->dev; 52 53 dec_clk->clk_num = 54 of_property_count_strings(pdev->dev.of_node, "clock-names"); 55 if (dec_clk->clk_num > 0) { 56 dec_clk->clk_info = devm_kcalloc(&pdev->dev, 57 dec_clk->clk_num, sizeof(*clk_info), 58 GFP_KERNEL); 59 if (!dec_clk->clk_info) 60 return -ENOMEM; 61 } else { 62 mtk_v4l2_err("Failed to get vdec clock count"); 63 return -EINVAL; 64 } 65 66 for (i = 0; i < dec_clk->clk_num; i++) { 67 clk_info = &dec_clk->clk_info[i]; 68 ret = of_property_read_string_index(pdev->dev.of_node, 69 "clock-names", i, &clk_info->clk_name); 70 if (ret) { 71 mtk_v4l2_err("Failed to get clock name id = %d", i); 72 return ret; 73 } 74 clk_info->vcodec_clk = devm_clk_get(&pdev->dev, 75 clk_info->clk_name); 76 if (IS_ERR(clk_info->vcodec_clk)) { 77 mtk_v4l2_err("devm_clk_get (%d)%s fail", i, 78 clk_info->clk_name); 79 return PTR_ERR(clk_info->vcodec_clk); 80 } 81 } 82 83 pm_runtime_enable(&pdev->dev); 84 85 return ret; 86} 87 88void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev) 89{ 90 pm_runtime_disable(dev->pm.dev); 91} 92 93void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) 94{ 95 int ret; 96 97 ret = pm_runtime_get_sync(pm->dev); 98 if (ret) 99 mtk_v4l2_err("pm_runtime_get_sync fail %d", ret); 100} 101 102void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) 103{ 104 int ret; 105 106 ret = pm_runtime_put_sync(pm->dev); 107 if (ret) 108 mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); 109} 110 111void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) 112{ 113 struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk; 114 int ret, i = 0; 115 116 for (i = 0; i < dec_clk->clk_num; i++) { 117 ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk); 118 if (ret) { 119 mtk_v4l2_err("clk_prepare_enable %d %s fail %d", i, 120 dec_clk->clk_info[i].clk_name, ret); 121 goto error; 122 } 123 } 124 125 ret = mtk_smi_larb_get(pm->larbvdec); 126 if (ret) { 127 mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret); 128 goto error; 129 } 130 return; 131 132error: 133 for (i -= 1; i >= 0; i--) 134 clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); 135} 136 137void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) 138{ 139 struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk; 140 int i = 0; 141 142 mtk_smi_larb_put(pm->larbvdec); 143 for (i = dec_clk->clk_num - 1; i >= 0; i--) 144 clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); 145}