mtk_vcodec_dec_pm.c (5238B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2016 MediaTek Inc. 4 * Author: Tiffany Lin <tiffany.lin@mediatek.com> 5 */ 6 7#include <linux/clk.h> 8#include <linux/interrupt.h> 9#include <linux/of_address.h> 10#include <linux/of_platform.h> 11#include <linux/pm_runtime.h> 12 13#include "mtk_vcodec_dec_hw.h" 14#include "mtk_vcodec_dec_pm.h" 15#include "mtk_vcodec_util.h" 16 17int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm) 18{ 19 struct mtk_vcodec_clk *dec_clk; 20 struct mtk_vcodec_clk_info *clk_info; 21 int i = 0, ret; 22 23 dec_clk = &pm->vdec_clk; 24 pm->dev = &pdev->dev; 25 26 dec_clk->clk_num = 27 of_property_count_strings(pdev->dev.of_node, "clock-names"); 28 if (dec_clk->clk_num > 0) { 29 dec_clk->clk_info = devm_kcalloc(&pdev->dev, 30 dec_clk->clk_num, sizeof(*clk_info), 31 GFP_KERNEL); 32 if (!dec_clk->clk_info) 33 return -ENOMEM; 34 } else { 35 mtk_v4l2_err("Failed to get vdec clock count"); 36 return -EINVAL; 37 } 38 39 for (i = 0; i < dec_clk->clk_num; i++) { 40 clk_info = &dec_clk->clk_info[i]; 41 ret = of_property_read_string_index(pdev->dev.of_node, 42 "clock-names", i, &clk_info->clk_name); 43 if (ret) { 44 mtk_v4l2_err("Failed to get clock name id = %d", i); 45 return ret; 46 } 47 clk_info->vcodec_clk = devm_clk_get(&pdev->dev, 48 clk_info->clk_name); 49 if (IS_ERR(clk_info->vcodec_clk)) { 50 mtk_v4l2_err("devm_clk_get (%d)%s fail", i, 51 clk_info->clk_name); 52 return PTR_ERR(clk_info->vcodec_clk); 53 } 54 } 55 56 return 0; 57} 58EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk); 59 60static int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) 61{ 62 int ret; 63 64 ret = pm_runtime_resume_and_get(pm->dev); 65 if (ret) 66 mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret); 67 68 return ret; 69} 70 71static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) 72{ 73 int ret; 74 75 ret = pm_runtime_put_sync(pm->dev); 76 if (ret) 77 mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); 78} 79 80static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) 81{ 82 struct mtk_vcodec_clk *dec_clk; 83 int ret, i; 84 85 dec_clk = &pm->vdec_clk; 86 for (i = 0; i < dec_clk->clk_num; i++) { 87 ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk); 88 if (ret) { 89 mtk_v4l2_err("clk_prepare_enable %d %s fail %d", i, 90 dec_clk->clk_info[i].clk_name, ret); 91 goto error; 92 } 93 } 94 95 return; 96error: 97 for (i -= 1; i >= 0; i--) 98 clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); 99} 100 101static void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) 102{ 103 struct mtk_vcodec_clk *dec_clk; 104 int i; 105 106 dec_clk = &pm->vdec_clk; 107 for (i = dec_clk->clk_num - 1; i >= 0; i--) 108 clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); 109} 110 111static void mtk_vcodec_dec_enable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) 112{ 113 struct mtk_vdec_hw_dev *subdev_dev; 114 115 if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) 116 return; 117 118 if (vdec_dev->vdec_pdata->is_subdev_supported) { 119 subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); 120 if (subdev_dev) 121 enable_irq(subdev_dev->dec_irq); 122 else 123 mtk_v4l2_err("Failed to get hw dev\n"); 124 } else { 125 enable_irq(vdec_dev->dec_irq); 126 } 127} 128 129static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) 130{ 131 struct mtk_vdec_hw_dev *subdev_dev; 132 133 if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) 134 return; 135 136 if (vdec_dev->vdec_pdata->is_subdev_supported) { 137 subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); 138 if (subdev_dev) 139 disable_irq(subdev_dev->dec_irq); 140 else 141 mtk_v4l2_err("Failed to get hw dev\n"); 142 } else { 143 disable_irq(vdec_dev->dec_irq); 144 } 145} 146 147static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev, 148 int hw_idx) 149{ 150 struct mtk_vdec_hw_dev *subdev_dev; 151 152 if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) 153 return NULL; 154 155 if (vdec_dev->vdec_pdata->is_subdev_supported) { 156 subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); 157 if (subdev_dev) 158 return &subdev_dev->pm; 159 160 mtk_v4l2_err("Failed to get hw dev\n"); 161 return NULL; 162 } 163 164 return &vdec_dev->pm; 165} 166 167static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev, 168 int hw_idx) 169{ 170 struct mtk_vcodec_pm *pm; 171 172 pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); 173 if (pm) { 174 mtk_vcodec_dec_pw_on(pm); 175 mtk_vcodec_dec_clock_on(pm); 176 } 177} 178 179static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, 180 int hw_idx) 181{ 182 struct mtk_vcodec_pm *pm; 183 184 pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); 185 if (pm) { 186 mtk_vcodec_dec_clock_off(pm); 187 mtk_vcodec_dec_pw_off(pm); 188 } 189} 190 191void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) 192{ 193 mutex_lock(&ctx->dev->dec_mutex[hw_idx]); 194 195 if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && 196 hw_idx == MTK_VDEC_CORE) 197 mtk_vcodec_dec_child_dev_on(ctx->dev, MTK_VDEC_LAT0); 198 mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx); 199 200 mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx); 201} 202EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware); 203 204void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) 205{ 206 mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx); 207 208 mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx); 209 if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && 210 hw_idx == MTK_VDEC_CORE) 211 mtk_vcodec_dec_child_dev_off(ctx->dev, MTK_VDEC_LAT0); 212 213 mutex_unlock(&ctx->dev->dec_mutex[hw_idx]); 214} 215EXPORT_SYMBOL_GPL(mtk_vcodec_dec_disable_hardware);