root/drivers/staging/media/meson/vdec/vdec_1.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. vdec_1_load_firmware
  2. vdec_1_stbuf_power_up
  3. vdec_1_conf_esparser
  4. vdec_1_vififo_level
  5. vdec_1_stop
  6. vdec_1_start

   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 };

/* [<][>][^][v][top][bottom][index][help] */