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