1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018 BayLibre, SAS 4 * Author: Maxime Jourdan <mjourdan@baylibre.com> 5 * 6 * VDEC_1 is a video decoding block that allows decoding of 7 * MPEG 1/2/4, H.263, H.264, MJPEG, VC1 8 */ 9 10 #include <linux/firmware.h> 11 #include <linux/clk.h> 12 13 #include "vdec_1.h" 14 #include "vdec_helpers.h" 15 #include "dos_regs.h" 16 17 /* AO Registers */ 18 #define AO_RTI_GEN_PWR_SLEEP0 0xe8 19 #define AO_RTI_GEN_PWR_ISO0 0xec 20 #define GEN_PWR_VDEC_1 (BIT(3) | BIT(2)) 21 22 #define MC_SIZE (4096 * 4) 23 24 static int 25 vdec_1_load_firmware(struct amvdec_session *sess, const char *fwname) 26 { 27 const struct firmware *fw; 28 struct amvdec_core *core = sess->core; 29 struct device *dev = core->dev_dec; 30 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 31 static void *mc_addr; 32 static dma_addr_t mc_addr_map; 33 int ret; 34 u32 i = 1000; 35 36 ret = request_firmware(&fw, fwname, dev); 37 if (ret < 0) 38 return -EINVAL; 39 40 if (fw->size < MC_SIZE) { 41 dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", 42 fw->size, MC_SIZE); 43 ret = -EINVAL; 44 goto release_firmware; 45 } 46 47 mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, 48 &mc_addr_map, GFP_KERNEL); 49 if (!mc_addr) { 50 ret = -ENOMEM; 51 goto release_firmware; 52 } 53 54 memcpy(mc_addr, fw->data, MC_SIZE); 55 56 amvdec_write_dos(core, MPSR, 0); 57 amvdec_write_dos(core, CPSR, 0); 58 59 amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); 60 61 amvdec_write_dos(core, IMEM_DMA_ADR, mc_addr_map); 62 amvdec_write_dos(core, IMEM_DMA_COUNT, MC_SIZE / 4); 63 amvdec_write_dos(core, IMEM_DMA_CTRL, (0x8000 | (7 << 16))); 64 65 while (--i && amvdec_read_dos(core, IMEM_DMA_CTRL) & 0x8000); 66 67 if (i == 0) { 68 dev_err(dev, "Firmware load fail (DMA hang?)\n"); 69 ret = -EINVAL; 70 goto free_mc; 71 } 72 73 if (codec_ops->load_extended_firmware) 74 ret = codec_ops->load_extended_firmware(sess, 75 fw->data + MC_SIZE, 76 fw->size - MC_SIZE); 77 78 free_mc: 79 dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); 80 release_firmware: 81 release_firmware(fw); 82 return ret; 83 } 84 85 static int vdec_1_stbuf_power_up(struct amvdec_session *sess) 86 { 87 struct amvdec_core *core = sess->core; 88 89 amvdec_write_dos(core, VLD_MEM_VIFIFO_CONTROL, 0); 90 amvdec_write_dos(core, VLD_MEM_VIFIFO_WRAP_COUNT, 0); 91 amvdec_write_dos(core, POWER_CTL_VLD, BIT(4)); 92 93 amvdec_write_dos(core, VLD_MEM_VIFIFO_START_PTR, sess->vififo_paddr); 94 amvdec_write_dos(core, VLD_MEM_VIFIFO_CURR_PTR, sess->vififo_paddr); 95 amvdec_write_dos(core, VLD_MEM_VIFIFO_END_PTR, 96 sess->vififo_paddr + sess->vififo_size - 8); 97 98 amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); 99 amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 1); 100 101 amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, MEM_BUFCTRL_MANUAL); 102 amvdec_write_dos(core, VLD_MEM_VIFIFO_WP, sess->vififo_paddr); 103 104 amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); 105 amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); 106 107 amvdec_write_dos_bits(core, VLD_MEM_VIFIFO_CONTROL, 108 (0x11 << MEM_FIFO_CNT_BIT) | MEM_FILL_ON_LEVEL | 109 MEM_CTRL_FILL_EN | MEM_CTRL_EMPTY_EN); 110 111 return 0; 112 } 113 114 static void vdec_1_conf_esparser(struct amvdec_session *sess) 115 { 116 struct amvdec_core *core = sess->core; 117 118 /* VDEC_1 specific ESPARSER stuff */ 119 amvdec_write_dos(core, DOS_GEN_CTRL0, 0); 120 amvdec_write_dos(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); 121 amvdec_clear_dos_bits(core, VLD_MEM_VIFIFO_BUF_CNTL, 1); 122 } 123 124 static u32 vdec_1_vififo_level(struct amvdec_session *sess) 125 { 126 struct amvdec_core *core = sess->core; 127 128 return amvdec_read_dos(core, VLD_MEM_VIFIFO_LEVEL); 129 } 130 131 static int vdec_1_stop(struct amvdec_session *sess) 132 { 133 struct amvdec_core *core = sess->core; 134 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 135 136 amvdec_write_dos(core, MPSR, 0); 137 amvdec_write_dos(core, CPSR, 0); 138 amvdec_write_dos(core, ASSIST_MBOX1_MASK, 0); 139 140 amvdec_write_dos(core, DOS_SW_RESET0, BIT(12) | BIT(11)); 141 amvdec_write_dos(core, DOS_SW_RESET0, 0); 142 amvdec_read_dos(core, DOS_SW_RESET0); 143 144 /* enable vdec1 isolation */ 145 regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0xc0); 146 /* power off vdec1 memories */ 147 amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0xffffffff); 148 /* power off vdec1 */ 149 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, 150 GEN_PWR_VDEC_1, GEN_PWR_VDEC_1); 151 152 clk_disable_unprepare(core->vdec_1_clk); 153 154 if (sess->priv) 155 codec_ops->stop(sess); 156 157 return 0; 158 } 159 160 static int vdec_1_start(struct amvdec_session *sess) 161 { 162 int ret; 163 struct amvdec_core *core = sess->core; 164 struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; 165 166 /* Configure the vdec clk to the maximum available */ 167 clk_set_rate(core->vdec_1_clk, 666666666); 168 ret = clk_prepare_enable(core->vdec_1_clk); 169 if (ret) 170 return ret; 171 172 /* Enable power for VDEC_1 */ 173 regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, 174 GEN_PWR_VDEC_1, 0); 175 usleep_range(10, 20); 176 177 /* Reset VDEC1 */ 178 amvdec_write_dos(core, DOS_SW_RESET0, 0xfffffffc); 179 amvdec_write_dos(core, DOS_SW_RESET0, 0x00000000); 180 181 amvdec_write_dos(core, DOS_GCLK_EN0, 0x3ff); 182 183 /* enable VDEC Memories */ 184 amvdec_write_dos(core, DOS_MEM_PD_VDEC, 0); 185 /* Remove VDEC1 Isolation */ 186 regmap_write(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, 0); 187 /* Reset DOS top registers */ 188 amvdec_write_dos(core, DOS_VDEC_MCRCC_STALL_CTRL, 0); 189 190 amvdec_write_dos(core, GCLK_EN, 0x3ff); 191 amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(31)); 192 193 vdec_1_stbuf_power_up(sess); 194 195 ret = vdec_1_load_firmware(sess, sess->fmt_out->firmware_path); 196 if (ret) 197 goto stop; 198 199 ret = codec_ops->start(sess); 200 if (ret) 201 goto stop; 202 203 /* Enable IRQ */ 204 amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1); 205 amvdec_write_dos(core, ASSIST_MBOX1_MASK, 1); 206 207 /* Enable 2-plane output */ 208 if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) 209 amvdec_write_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); 210 else 211 amvdec_clear_dos_bits(core, MDEC_PIC_DC_CTRL, BIT(17)); 212 213 /* Enable firmware processor */ 214 amvdec_write_dos(core, MPSR, 1); 215 /* Let the firmware settle */ 216 usleep_range(10, 20); 217 218 return 0; 219 220 stop: 221 vdec_1_stop(sess); 222 return ret; 223 } 224 225 struct amvdec_ops vdec_1_ops = { 226 .start = vdec_1_start, 227 .stop = vdec_1_stop, 228 .conf_esparser = vdec_1_conf_esparser, 229 .vififo_level = vdec_1_vififo_level, 230 }; 231