File Index
Files and directories
Sign in
FILE

codec_mpeg12.c

File preview with syntax highlighting.

linux-6.19.14/drivers/staging/media/meson/vdec/codec_mpeg12.c C
  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
 39struct codec_mpeg12 {
 40	/* Buffer for the MPEG1/2 Workspace */
 41	void	  *workspace_vaddr;
 42	dma_addr_t workspace_paddr;
 43};
 44
 45static const u8 eos_sequence[SZ_1K] = { 0x00, 0x00, 0x01, 0xB7 };
 46
 47static const u8 *codec_mpeg12_eos_sequence(u32 *len)
 48{
 49	*len = ARRAY_SIZE(eos_sequence);
 50	return eos_sequence;
 51}
 52
 53static int codec_mpeg12_can_recycle(struct amvdec_core *core)
 54{
 55	return !amvdec_read_dos(core, MREG_BUFFERIN);
 56}
 57
 58static void codec_mpeg12_recycle(struct amvdec_core *core, u32 buf_idx)
 59{
 60	amvdec_write_dos(core, MREG_BUFFERIN, buf_idx + 1);
 61}
 62
 63static 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
108free_workspace:
109	dma_free_coherent(core->dev, SIZE_WORKSPACE, mpeg12->workspace_vaddr,
110			  mpeg12->workspace_paddr);
111free_mpeg12:
112	kfree(mpeg12);
113
114	return ret;
115}
116
117static 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
130static 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
153static 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
192end:
193	amvdec_write_dos(core, MREG_BUFFEROUT, 0);
194	return IRQ_HANDLED;
195}
196
197static irqreturn_t codec_mpeg12_isr(struct amvdec_session *sess)
198{
199	return IRQ_WAKE_THREAD;
200}
201
202struct 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};
~/ Read-only file preview.