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

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

DEFINITIONS

This source file includes following definitions.
  1. codec_mpeg12_eos_sequence
  2. codec_mpeg12_can_recycle
  3. codec_mpeg12_recycle
  4. codec_mpeg12_start
  5. codec_mpeg12_stop
  6. codec_mpeg12_update_dar
  7. codec_mpeg12_threaded_isr
  8. codec_mpeg12_isr

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright (C) 2018 BayLibre, SAS
   4  * Author: Maxime Jourdan <mjourdan@baylibre.com>
   5  */
   6 
   7 #include <media/v4l2-mem2mem.h>
   8 #include <media/videobuf2-dma-contig.h>
   9 
  10 #include "codec_mpeg12.h"
  11 #include "dos_regs.h"
  12 #include "vdec_helpers.h"
  13 
  14 #define SIZE_WORKSPACE          SZ_128K
  15 /* Offset substracted by the firmware from the workspace paddr */
  16 #define WORKSPACE_OFFSET        (5 * SZ_1K)
  17 
  18 /* map firmware registers to known MPEG1/2 functions */
  19 #define MREG_SEQ_INFO           AV_SCRATCH_4
  20         #define MPEG2_SEQ_DAR_MASK      GENMASK(3, 0)
  21         #define MPEG2_DAR_4_3           2
  22         #define MPEG2_DAR_16_9          3
  23         #define MPEG2_DAR_221_100       4
  24 #define MREG_PIC_INFO           AV_SCRATCH_5
  25 #define MREG_PIC_WIDTH          AV_SCRATCH_6
  26 #define MREG_PIC_HEIGHT         AV_SCRATCH_7
  27 #define MREG_BUFFERIN           AV_SCRATCH_8
  28 #define MREG_BUFFEROUT          AV_SCRATCH_9
  29 #define MREG_CMD                AV_SCRATCH_A
  30 #define MREG_CO_MV_START        AV_SCRATCH_B
  31 #define MREG_ERROR_COUNT        AV_SCRATCH_C
  32 #define MREG_FRAME_OFFSET       AV_SCRATCH_D
  33 #define MREG_WAIT_BUFFER        AV_SCRATCH_E
  34 #define MREG_FATAL_ERROR        AV_SCRATCH_F
  35 
  36 #define PICINFO_PROG            0x00008000
  37 #define PICINFO_TOP_FIRST       0x00002000
  38 
  39 struct codec_mpeg12 {
  40         /* Buffer for the MPEG1/2 Workspace */
  41         void      *workspace_vaddr;
  42         dma_addr_t workspace_paddr;
  43 };
  44 
  45 static const u8 eos_sequence[SZ_1K] = { 0x00, 0x00, 0x01, 0xB7 };
  46 
  47 static const u8 *codec_mpeg12_eos_sequence(u32 *len)
  48 {
  49         *len = ARRAY_SIZE(eos_sequence);
  50         return eos_sequence;
  51 }
  52 
  53 static int codec_mpeg12_can_recycle(struct amvdec_core *core)
  54 {
  55         return !amvdec_read_dos(core, MREG_BUFFERIN);
  56 }
  57 
  58 static void codec_mpeg12_recycle(struct amvdec_core *core, u32 buf_idx)
  59 {
  60         amvdec_write_dos(core, MREG_BUFFERIN, buf_idx + 1);
  61 }
  62 
  63 static int codec_mpeg12_start(struct amvdec_session *sess)
  64 {
  65         struct amvdec_core *core = sess->core;
  66         struct codec_mpeg12 *mpeg12;
  67         int ret;
  68 
  69         mpeg12 = kzalloc(sizeof(*mpeg12), GFP_KERNEL);
  70         if (!mpeg12)
  71                 return -ENOMEM;
  72 
  73         /* Allocate some memory for the MPEG1/2 decoder's state */
  74         mpeg12->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
  75                                                      &mpeg12->workspace_paddr,
  76                                                      GFP_KERNEL);
  77         if (!mpeg12->workspace_vaddr) {
  78                 dev_err(core->dev, "Failed to request MPEG 1/2 Workspace\n");
  79                 ret = -ENOMEM;
  80                 goto free_mpeg12;
  81         }
  82 
  83         ret = amvdec_set_canvases(sess, (u32[]){ AV_SCRATCH_0, 0 },
  84                                         (u32[]){ 8, 0 });
  85         if (ret)
  86                 goto free_workspace;
  87 
  88         amvdec_write_dos(core, POWER_CTL_VLD, BIT(4));
  89         amvdec_write_dos(core, MREG_CO_MV_START,
  90                          mpeg12->workspace_paddr + WORKSPACE_OFFSET);
  91 
  92         amvdec_write_dos(core, MPEG1_2_REG, 0);
  93         amvdec_write_dos(core, PSCALE_CTRL, 0);
  94         amvdec_write_dos(core, PIC_HEAD_INFO, 0x380);
  95         amvdec_write_dos(core, M4_CONTROL_REG, 0);
  96         amvdec_write_dos(core, MREG_BUFFERIN, 0);
  97         amvdec_write_dos(core, MREG_BUFFEROUT, 0);
  98         amvdec_write_dos(core, MREG_CMD, (sess->width << 16) | sess->height);
  99         amvdec_write_dos(core, MREG_ERROR_COUNT, 0);
 100         amvdec_write_dos(core, MREG_FATAL_ERROR, 0);
 101         amvdec_write_dos(core, MREG_WAIT_BUFFER, 0);
 102 
 103         sess->keyframe_found = 1;
 104         sess->priv = mpeg12;
 105 
 106         return 0;
 107 
 108 free_workspace:
 109         dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr,
 110                           mpeg12->workspace_paddr);
 111 free_mpeg12:
 112         kfree(mpeg12);
 113 
 114         return ret;
 115 }
 116 
 117 static int codec_mpeg12_stop(struct amvdec_session *sess)
 118 {
 119         struct codec_mpeg12 *mpeg12 = sess->priv;
 120         struct amvdec_core *core = sess->core;
 121 
 122         if (mpeg12->workspace_vaddr)
 123                 dma_free_coherent(core->dev, SIZE_WORKSPACE,
 124                                   mpeg12->workspace_vaddr,
 125                                   mpeg12->workspace_paddr);
 126 
 127         return 0;
 128 }
 129 
 130 static void codec_mpeg12_update_dar(struct amvdec_session *sess)
 131 {
 132         struct amvdec_core *core = sess->core;
 133         u32 seq = amvdec_read_dos(core, MREG_SEQ_INFO);
 134         u32 ar = seq & MPEG2_SEQ_DAR_MASK;
 135 
 136         switch (ar) {
 137         case MPEG2_DAR_4_3:
 138                 amvdec_set_par_from_dar(sess, 4, 3);
 139                 break;
 140         case MPEG2_DAR_16_9:
 141                 amvdec_set_par_from_dar(sess, 16, 9);
 142                 break;
 143         case MPEG2_DAR_221_100:
 144                 amvdec_set_par_from_dar(sess, 221, 100);
 145                 break;
 146         default:
 147                 sess->pixelaspect.numerator = 1;
 148                 sess->pixelaspect.denominator = 1;
 149                 break;
 150         }
 151 }
 152 
 153 static irqreturn_t codec_mpeg12_threaded_isr(struct amvdec_session *sess)
 154 {
 155         struct amvdec_core *core = sess->core;
 156         u32 reg;
 157         u32 pic_info;
 158         u32 is_progressive;
 159         u32 buffer_index;
 160         u32 field = V4L2_FIELD_NONE;
 161         u32 offset;
 162 
 163         amvdec_write_dos(core, ASSIST_MBOX1_CLR_REG, 1);
 164         reg = amvdec_read_dos(core, MREG_FATAL_ERROR);
 165         if (reg == 1) {
 166                 dev_err(core->dev, "MPEG1/2 fatal error\n");
 167                 amvdec_abort(sess);
 168                 return IRQ_HANDLED;
 169         }
 170 
 171         reg = amvdec_read_dos(core, MREG_BUFFEROUT);
 172         if (!reg)
 173                 return IRQ_HANDLED;
 174 
 175         /* Unclear what this means */
 176         if ((reg & GENMASK(23, 17)) == GENMASK(23, 17))
 177                 goto end;
 178 
 179         pic_info = amvdec_read_dos(core, MREG_PIC_INFO);
 180         is_progressive = pic_info & PICINFO_PROG;
 181 
 182         if (!is_progressive)
 183                 field = (pic_info & PICINFO_TOP_FIRST) ?
 184                         V4L2_FIELD_INTERLACED_TB :
 185                         V4L2_FIELD_INTERLACED_BT;
 186 
 187         codec_mpeg12_update_dar(sess);
 188         buffer_index = ((reg & 0xf) - 1) & 7;
 189         offset = amvdec_read_dos(core, MREG_FRAME_OFFSET);
 190         amvdec_dst_buf_done_idx(sess, buffer_index, offset, field);
 191 
 192 end:
 193         amvdec_write_dos(core, MREG_BUFFEROUT, 0);
 194         return IRQ_HANDLED;
 195 }
 196 
 197 static irqreturn_t codec_mpeg12_isr(struct amvdec_session *sess)
 198 {
 199         return IRQ_WAKE_THREAD;
 200 }
 201 
 202 struct amvdec_codec_ops codec_mpeg12_ops = {
 203         .start = codec_mpeg12_start,
 204         .stop = codec_mpeg12_stop,
 205         .isr = codec_mpeg12_isr,
 206         .threaded_isr = codec_mpeg12_threaded_isr,
 207         .can_recycle = codec_mpeg12_can_recycle,
 208         .recycle = codec_mpeg12_recycle,
 209         .eos_sequence = codec_mpeg12_eos_sequence,
 210 };

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