FILE
vdec_hevc.c
File preview with syntax highlighting.
linux-6.19.14/drivers/staging/media/meson/vdec/vdec_hevc.c
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@wanadoo.fr> 4 * 5 * VDEC_HEVC is a video decoding block that allows decoding of 6 * HEVC, VP9 7 */ 8 9#include <linux/firmware.h> 10#include <linux/clk.h> 11 12#include "vdec_1.h" 13#include "vdec_helpers.h" 14#include "vdec_hevc.h" 15#include "hevc_regs.h" 16#include "dos_regs.h" 17 18/* AO Registers */ 19#define AO_RTI_GEN_PWR_SLEEP0 0xe8 20#define AO_RTI_GEN_PWR_ISO0 0xec 21 #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6)) 22 #define GEN_PWR_VDEC_HEVC_SM1 (BIT(2)) 23 24#define MC_SIZE (4096 * 4) 25 26static int vdec_hevc_load_firmware(struct amvdec_session *sess, 27 const char *fwname) 28{ 29 struct amvdec_core *core = sess->core; 30 struct device *dev = core->dev_dec; 31 const struct firmware *fw; 32 static void *mc_addr; 33 static dma_addr_t mc_addr_map; 34 int ret; 35 u32 i = 100; 36 37 ret = request_firmware(&fw, fwname, dev); 38 if (ret < 0) { 39 dev_err(dev, "Unable to request firmware %s\n", fwname); 40 return ret; 41 } 42 43 if (fw->size < MC_SIZE) { 44 dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", 45 fw->size, MC_SIZE); 46 ret = -EINVAL; 47 goto release_firmware; 48 } 49 50 mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map, 51 GFP_KERNEL); 52 if (!mc_addr) { 53 ret = -ENOMEM; 54 goto release_firmware; 55 } 56 57 memcpy(mc_addr, fw->data, MC_SIZE); 58 59 amvdec_write_dos(core, HEVC_MPSR, 0); 60 amvdec_write_dos(core, HEVC_CPSR, 0); 61 62 amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map); 63 amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4); 64 amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); 65 66 while (i && (readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000)) 67 i--; 68 69 if (i == 0) { 70 dev_err(dev, "Firmware load fail (DMA hang?)\n"); 71 ret = -ENODEV; 72 } 73 74 dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); 75release_firmware: 76 release_firmware(fw); 77 return ret; 78} 79 80static void vdec_hevc_stbuf_init(struct amvdec_session *sess) 81{ 82 struct amvdec_core *core = sess->core; 83 84 amvdec_write_dos(core, HEVC_STREAM_CONTROL, 85 amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1); 86 amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr); 87 amvdec_write_dos(core, HEVC_STREAM_END_ADDR, 88 sess->vififo_paddr + sess->vififo_size); 89 amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr); 90 amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr); 91} 92 93/* VDEC_HEVC specific ESPARSER configuration */ 94static void vdec_hevc_conf_esparser(struct amvdec_session *sess) 95{ 96 struct amvdec_core *core = sess->core; 97 98 /* set vififo_vbuf_rp_sel=>vdec_hevc */ 99 amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1); 100 amvdec_write_dos(core, HEVC_STREAM_CONTROL, 101 amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3)); 102 amvdec_write_dos(core, HEVC_STREAM_CONTROL, 103 amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1); 104 amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL, 105 amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29)); 106} 107 108static u32 vdec_hevc_vififo_level(struct amvdec_session *sess) 109{ 110 return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL); 111} 112 113static void __vdec_hevc_stop(struct amvdec_session *sess) 114{ 115 struct amvdec_core *core = sess->core; 116 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 117 118 /* Disable interrupt */ 119 amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0); 120 /* Disable firmware processor */ 121 amvdec_write_dos(core, HEVC_MPSR, 0); 122 123 if (sess->priv) 124 codec_ops->stop(sess); 125 126 /* Enable VDEC_HEVC Isolation */ 127 if (core->platform->revision == VDEC_REVISION_SM1) 128 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 129 GEN_PWR_VDEC_HEVC_SM1, 130 GEN_PWR_VDEC_HEVC_SM1); 131 else 132 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 133 0xc00, 0xc00); 134 135 /* VDEC_HEVC Memories */ 136 amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL); 137 138 if (core->platform->revision == VDEC_REVISION_SM1) 139 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, 140 GEN_PWR_VDEC_HEVC_SM1, 141 GEN_PWR_VDEC_HEVC_SM1); 142 else 143 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, 144 GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); 145} 146 147static int vdec_hevc_stop(struct amvdec_session *sess) 148{ 149 struct amvdec_core *core = sess->core; 150 151 __vdec_hevc_stop(sess); 152 153 clk_disable_unprepare(core->vdec_hevc_clk); 154 if (core->platform->revision == VDEC_REVISION_G12A || 155 core->platform->revision == VDEC_REVISION_SM1) 156 clk_disable_unprepare(core->vdec_hevcf_clk); 157 158 return 0; 159} 160 161static int __vdec_hevc_start(struct amvdec_session *sess) 162{ 163 int ret; 164 struct amvdec_core *core = sess->core; 165 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 166 167 clk_set_rate(core->vdec_hevc_clk, 666666666); 168 ret = clk_prepare_enable(core->vdec_hevc_clk); 169 if (ret) { 170 if (core->platform->revision == VDEC_REVISION_G12A || 171 core->platform->revision == VDEC_REVISION_SM1) 172 clk_disable_unprepare(core->vdec_hevcf_clk); 173 return ret; 174 } 175 176 if (core->platform->revision == VDEC_REVISION_SM1) 177 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, 178 GEN_PWR_VDEC_HEVC_SM1, 0); 179 else 180 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, 181 GEN_PWR_VDEC_HEVC, 0); 182 usleep_range(10, 20); 183 184 /* Reset VDEC_HEVC*/ 185 amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); 186 amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); 187 188 amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff); 189 190 /* VDEC_HEVC Memories */ 191 amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000); 192 193 /* Remove VDEC_HEVC Isolation */ 194 if (core->platform->revision == VDEC_REVISION_SM1) 195 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 196 GEN_PWR_VDEC_HEVC_SM1, 0); 197 else 198 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 199 0xc00, 0); 200 201 amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); 202 amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); 203 204 vdec_hevc_stbuf_init(sess); 205 206 ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path); 207 if (ret) 208 goto stop; 209 210 ret = codec_ops->start(sess); 211 if (ret) 212 goto stop; 213 214 amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11)); 215 amvdec_write_dos(core, DOS_SW_RESET3, 0); 216 amvdec_read_dos(core, DOS_SW_RESET3); 217 218 amvdec_write_dos(core, HEVC_MPSR, 1); 219 /* Let the firmware settle */ 220 usleep_range(10, 20); 221 222 return 0; 223 224stop: 225 __vdec_hevc_stop(sess); 226 clk_disable_unprepare(core->vdec_hevc_clk); 227 return ret; 228} 229 230static int vdec_hevc_start(struct amvdec_session *sess) 231{ 232 struct amvdec_core *core = sess->core; 233 int ret; 234 235 if (core->platform->revision == VDEC_REVISION_G12A || 236 core->platform->revision == VDEC_REVISION_SM1) { 237 clk_set_rate(core->vdec_hevcf_clk, 666666666); 238 ret = clk_prepare_enable(core->vdec_hevcf_clk); 239 if (ret) 240 return ret; 241 242 ret = __vdec_hevc_start(sess); 243 if (ret) 244 clk_disable_unprepare(core->vdec_hevcf_clk); 245 return ret; 246 } 247 248 return __vdec_hevc_start(sess); 249} 250 251struct amvdec_ops vdec_hevc_ops = { 252 .start = vdec_hevc_start, 253 .stop = vdec_hevc_stop, 254 .conf_esparser = vdec_hevc_conf_esparser, 255 .vififo_level = vdec_hevc_vififo_level, 256};
~/
Read-only file preview.