| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2016 MediaTek Inc. |
|---|
| 3 | 4 | * 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 | 5 | */ |
|---|
| 14 | 6 | |
|---|
| 15 | 7 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 20 | 12 | |
|---|
| 21 | 13 | #include "mtk_vcodec_dec_pm.h" |
|---|
| 22 | 14 | #include "mtk_vcodec_util.h" |
|---|
| 23 | | -#include "mtk_vpu.h" |
|---|
| 24 | 15 | |
|---|
| 25 | 16 | int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) |
|---|
| 26 | 17 | { |
|---|
| 27 | 18 | struct device_node *node; |
|---|
| 28 | 19 | struct platform_device *pdev; |
|---|
| 29 | 20 | struct mtk_vcodec_pm *pm; |
|---|
| 30 | | - int ret = 0; |
|---|
| 21 | + struct mtk_vcodec_clk *dec_clk; |
|---|
| 22 | + struct mtk_vcodec_clk_info *clk_info; |
|---|
| 23 | + int i = 0, ret = 0; |
|---|
| 31 | 24 | |
|---|
| 32 | 25 | pdev = mtkdev->plat_dev; |
|---|
| 33 | 26 | pm = &mtkdev->pm; |
|---|
| 34 | 27 | pm->mtkdev = mtkdev; |
|---|
| 28 | + dec_clk = &pm->vdec_clk; |
|---|
| 35 | 29 | node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0); |
|---|
| 36 | 30 | if (!node) { |
|---|
| 37 | 31 | mtk_v4l2_err("of_parse_phandle mediatek,larb fail!"); |
|---|
| .. | .. |
|---|
| 39 | 33 | } |
|---|
| 40 | 34 | |
|---|
| 41 | 35 | pdev = of_find_device_by_node(node); |
|---|
| 36 | + of_node_put(node); |
|---|
| 42 | 37 | if (WARN_ON(!pdev)) { |
|---|
| 43 | | - of_node_put(node); |
|---|
| 44 | 38 | return -1; |
|---|
| 45 | 39 | } |
|---|
| 46 | 40 | pm->larbvdec = &pdev->dev; |
|---|
| 47 | 41 | pdev = mtkdev->plat_dev; |
|---|
| 48 | 42 | pm->dev = &pdev->dev; |
|---|
| 49 | 43 | |
|---|
| 50 | | - pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll"); |
|---|
| 51 | | - if (IS_ERR(pm->vcodecpll)) { |
|---|
| 52 | | - mtk_v4l2_err("devm_clk_get vcodecpll fail"); |
|---|
| 53 | | - ret = PTR_ERR(pm->vcodecpll); |
|---|
| 44 | + dec_clk->clk_num = |
|---|
| 45 | + of_property_count_strings(pdev->dev.of_node, "clock-names"); |
|---|
| 46 | + if (dec_clk->clk_num > 0) { |
|---|
| 47 | + dec_clk->clk_info = devm_kcalloc(&pdev->dev, |
|---|
| 48 | + dec_clk->clk_num, sizeof(*clk_info), |
|---|
| 49 | + GFP_KERNEL); |
|---|
| 50 | + if (!dec_clk->clk_info) { |
|---|
| 51 | + ret = -ENOMEM; |
|---|
| 52 | + goto put_device; |
|---|
| 53 | + } |
|---|
| 54 | + } else { |
|---|
| 55 | + mtk_v4l2_err("Failed to get vdec clock count"); |
|---|
| 56 | + ret = -EINVAL; |
|---|
| 57 | + goto put_device; |
|---|
| 54 | 58 | } |
|---|
| 55 | 59 | |
|---|
| 56 | | - pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2"); |
|---|
| 57 | | - if (IS_ERR(pm->univpll_d2)) { |
|---|
| 58 | | - mtk_v4l2_err("devm_clk_get univpll_d2 fail"); |
|---|
| 59 | | - ret = PTR_ERR(pm->univpll_d2); |
|---|
| 60 | | - } |
|---|
| 61 | | - |
|---|
| 62 | | - pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel"); |
|---|
| 63 | | - if (IS_ERR(pm->clk_cci400_sel)) { |
|---|
| 64 | | - mtk_v4l2_err("devm_clk_get clk_cci400_sel fail"); |
|---|
| 65 | | - ret = PTR_ERR(pm->clk_cci400_sel); |
|---|
| 66 | | - } |
|---|
| 67 | | - |
|---|
| 68 | | - pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel"); |
|---|
| 69 | | - if (IS_ERR(pm->vdec_sel)) { |
|---|
| 70 | | - mtk_v4l2_err("devm_clk_get vdec_sel fail"); |
|---|
| 71 | | - ret = PTR_ERR(pm->vdec_sel); |
|---|
| 72 | | - } |
|---|
| 73 | | - |
|---|
| 74 | | - pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll"); |
|---|
| 75 | | - if (IS_ERR(pm->vdecpll)) { |
|---|
| 76 | | - mtk_v4l2_err("devm_clk_get vdecpll fail"); |
|---|
| 77 | | - ret = PTR_ERR(pm->vdecpll); |
|---|
| 78 | | - } |
|---|
| 79 | | - |
|---|
| 80 | | - pm->vencpll = devm_clk_get(&pdev->dev, "vencpll"); |
|---|
| 81 | | - if (IS_ERR(pm->vencpll)) { |
|---|
| 82 | | - mtk_v4l2_err("devm_clk_get vencpll fail"); |
|---|
| 83 | | - ret = PTR_ERR(pm->vencpll); |
|---|
| 84 | | - } |
|---|
| 85 | | - |
|---|
| 86 | | - pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel"); |
|---|
| 87 | | - if (IS_ERR(pm->venc_lt_sel)) { |
|---|
| 88 | | - mtk_v4l2_err("devm_clk_get venc_lt_sel fail"); |
|---|
| 89 | | - ret = PTR_ERR(pm->venc_lt_sel); |
|---|
| 90 | | - } |
|---|
| 91 | | - |
|---|
| 92 | | - pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src"); |
|---|
| 93 | | - if (IS_ERR(pm->vdec_bus_clk_src)) { |
|---|
| 94 | | - mtk_v4l2_err("devm_clk_get vdec_bus_clk_src"); |
|---|
| 95 | | - ret = PTR_ERR(pm->vdec_bus_clk_src); |
|---|
| 60 | + for (i = 0; i < dec_clk->clk_num; i++) { |
|---|
| 61 | + clk_info = &dec_clk->clk_info[i]; |
|---|
| 62 | + ret = of_property_read_string_index(pdev->dev.of_node, |
|---|
| 63 | + "clock-names", i, &clk_info->clk_name); |
|---|
| 64 | + if (ret) { |
|---|
| 65 | + mtk_v4l2_err("Failed to get clock name id = %d", i); |
|---|
| 66 | + goto put_device; |
|---|
| 67 | + } |
|---|
| 68 | + clk_info->vcodec_clk = devm_clk_get(&pdev->dev, |
|---|
| 69 | + clk_info->clk_name); |
|---|
| 70 | + if (IS_ERR(clk_info->vcodec_clk)) { |
|---|
| 71 | + mtk_v4l2_err("devm_clk_get (%d)%s fail", i, |
|---|
| 72 | + clk_info->clk_name); |
|---|
| 73 | + ret = PTR_ERR(clk_info->vcodec_clk); |
|---|
| 74 | + goto put_device; |
|---|
| 75 | + } |
|---|
| 96 | 76 | } |
|---|
| 97 | 77 | |
|---|
| 98 | 78 | pm_runtime_enable(&pdev->dev); |
|---|
| 99 | | - |
|---|
| 79 | + return 0; |
|---|
| 80 | +put_device: |
|---|
| 81 | + put_device(pm->larbvdec); |
|---|
| 100 | 82 | return ret; |
|---|
| 101 | 83 | } |
|---|
| 102 | 84 | |
|---|
| .. | .. |
|---|
| 106 | 88 | put_device(dev->pm.larbvdec); |
|---|
| 107 | 89 | } |
|---|
| 108 | 90 | |
|---|
| 109 | | -void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) |
|---|
| 91 | +int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) |
|---|
| 110 | 92 | { |
|---|
| 111 | 93 | int ret; |
|---|
| 112 | 94 | |
|---|
| 113 | | - ret = pm_runtime_get_sync(pm->dev); |
|---|
| 95 | + ret = pm_runtime_resume_and_get(pm->dev); |
|---|
| 114 | 96 | if (ret) |
|---|
| 115 | | - mtk_v4l2_err("pm_runtime_get_sync fail %d", ret); |
|---|
| 97 | + mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret); |
|---|
| 98 | + |
|---|
| 99 | + return ret; |
|---|
| 116 | 100 | } |
|---|
| 117 | 101 | |
|---|
| 118 | 102 | void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) |
|---|
| .. | .. |
|---|
| 126 | 110 | |
|---|
| 127 | 111 | void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) |
|---|
| 128 | 112 | { |
|---|
| 129 | | - int ret; |
|---|
| 113 | + struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk; |
|---|
| 114 | + int ret, i = 0; |
|---|
| 130 | 115 | |
|---|
| 131 | | - ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000); |
|---|
| 132 | | - if (ret) |
|---|
| 133 | | - mtk_v4l2_err("clk_set_rate vcodecpll fail %d", ret); |
|---|
| 134 | | - |
|---|
| 135 | | - ret = clk_set_rate(pm->vencpll, 800 * 1000000); |
|---|
| 136 | | - if (ret) |
|---|
| 137 | | - mtk_v4l2_err("clk_set_rate vencpll fail %d", ret); |
|---|
| 138 | | - |
|---|
| 139 | | - ret = clk_prepare_enable(pm->vcodecpll); |
|---|
| 140 | | - if (ret) |
|---|
| 141 | | - mtk_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret); |
|---|
| 142 | | - |
|---|
| 143 | | - ret = clk_prepare_enable(pm->vencpll); |
|---|
| 144 | | - if (ret) |
|---|
| 145 | | - mtk_v4l2_err("clk_prepare_enable vencpll fail %d", ret); |
|---|
| 146 | | - |
|---|
| 147 | | - ret = clk_prepare_enable(pm->vdec_bus_clk_src); |
|---|
| 148 | | - if (ret) |
|---|
| 149 | | - mtk_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d", |
|---|
| 150 | | - ret); |
|---|
| 151 | | - |
|---|
| 152 | | - ret = clk_prepare_enable(pm->venc_lt_sel); |
|---|
| 153 | | - if (ret) |
|---|
| 154 | | - mtk_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret); |
|---|
| 155 | | - |
|---|
| 156 | | - ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src); |
|---|
| 157 | | - if (ret) |
|---|
| 158 | | - mtk_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d", |
|---|
| 159 | | - ret); |
|---|
| 160 | | - |
|---|
| 161 | | - ret = clk_prepare_enable(pm->univpll_d2); |
|---|
| 162 | | - if (ret) |
|---|
| 163 | | - mtk_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret); |
|---|
| 164 | | - |
|---|
| 165 | | - ret = clk_prepare_enable(pm->clk_cci400_sel); |
|---|
| 166 | | - if (ret) |
|---|
| 167 | | - mtk_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret); |
|---|
| 168 | | - |
|---|
| 169 | | - ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2); |
|---|
| 170 | | - if (ret) |
|---|
| 171 | | - mtk_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d", |
|---|
| 172 | | - ret); |
|---|
| 173 | | - |
|---|
| 174 | | - ret = clk_prepare_enable(pm->vdecpll); |
|---|
| 175 | | - if (ret) |
|---|
| 176 | | - mtk_v4l2_err("clk_prepare_enable vdecpll fail %d", ret); |
|---|
| 177 | | - |
|---|
| 178 | | - ret = clk_prepare_enable(pm->vdec_sel); |
|---|
| 179 | | - if (ret) |
|---|
| 180 | | - mtk_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret); |
|---|
| 181 | | - |
|---|
| 182 | | - ret = clk_set_parent(pm->vdec_sel, pm->vdecpll); |
|---|
| 183 | | - if (ret) |
|---|
| 184 | | - mtk_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret); |
|---|
| 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 | + } |
|---|
| 185 | 124 | |
|---|
| 186 | 125 | ret = mtk_smi_larb_get(pm->larbvdec); |
|---|
| 187 | | - if (ret) |
|---|
| 126 | + if (ret) { |
|---|
| 188 | 127 | mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret); |
|---|
| 128 | + goto error; |
|---|
| 129 | + } |
|---|
| 130 | + return; |
|---|
| 189 | 131 | |
|---|
| 132 | +error: |
|---|
| 133 | + for (i -= 1; i >= 0; i--) |
|---|
| 134 | + clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); |
|---|
| 190 | 135 | } |
|---|
| 191 | 136 | |
|---|
| 192 | 137 | void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) |
|---|
| 193 | 138 | { |
|---|
| 139 | + struct mtk_vcodec_clk *dec_clk = &pm->vdec_clk; |
|---|
| 140 | + int i = 0; |
|---|
| 141 | + |
|---|
| 194 | 142 | mtk_smi_larb_put(pm->larbvdec); |
|---|
| 195 | | - clk_disable_unprepare(pm->vdec_sel); |
|---|
| 196 | | - clk_disable_unprepare(pm->vdecpll); |
|---|
| 197 | | - clk_disable_unprepare(pm->univpll_d2); |
|---|
| 198 | | - clk_disable_unprepare(pm->clk_cci400_sel); |
|---|
| 199 | | - clk_disable_unprepare(pm->venc_lt_sel); |
|---|
| 200 | | - clk_disable_unprepare(pm->vdec_bus_clk_src); |
|---|
| 201 | | - clk_disable_unprepare(pm->vencpll); |
|---|
| 202 | | - clk_disable_unprepare(pm->vcodecpll); |
|---|
| 143 | + for (i = dec_clk->clk_num - 1; i >= 0; i--) |
|---|
| 144 | + clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); |
|---|
| 203 | 145 | } |
|---|