aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-mailbox.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2008-04-28 19:24:33 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-29 17:41:41 -0400
commit1c1e45d17b663d4749af456ab7c2fc1f36405ef8 (patch)
tree03704d6fd888c4c617baa81a60df0d80815b2607 /drivers/media/video/cx18/cx18-mailbox.c
parentd74bee8b4776b5051c650a90f49a2022d46d8588 (diff)
V4L/DVB (7786): cx18: new driver for the Conexant CX23418 MPEG encoder chip
Many thanks to Steve Toth from Hauppauge and Nattu Dakshinamurthy from Conexant for their support. I am in particular thankful to Hauppauge since without their help this driver would not exist. It should also be noted that Steve did the work to get the DVB part up and running. Thank you! Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Steven Toth <stoth@hauppauge.com> Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: G. Andrew Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx18/cx18-mailbox.c')
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c372
1 files changed, 372 insertions, 0 deletions
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
new file mode 100644
index 000000000000..0c5f328bca54
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -0,0 +1,372 @@
1/*
2 * cx18 mailbox functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#include <stdarg.h>
23
24#include "cx18-driver.h"
25#include "cx18-scb.h"
26#include "cx18-irq.h"
27#include "cx18-mailbox.h"
28
29#define API_FAST (1 << 2) /* Short timeout */
30#define API_SLOW (1 << 3) /* Additional 300ms timeout */
31
32#define APU 0
33#define CPU 1
34#define EPU 2
35#define HPU 3
36
37struct cx18_api_info {
38 u32 cmd;
39 u8 flags; /* Flags, see above */
40 u8 rpu; /* Processing unit */
41 const char *name; /* The name of the command */
42};
43
44#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
45
46static const struct cx18_api_info api_info[] = {
47 /* MPEG encoder API */
48 API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
49 API_ENTRY(CPU, CX18_EPU_DEBUG, 0),
50 API_ENTRY(CPU, CX18_CREATE_TASK, 0),
51 API_ENTRY(CPU, CX18_DESTROY_TASK, 0),
52 API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW),
53 API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW),
54 API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0),
55 API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0),
56 API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
57 API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0),
58 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0),
59 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0),
60 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0),
61 API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0),
62 API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0),
63 API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0),
64 API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0),
65 API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0),
66 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0),
67 API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0),
68 API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0),
69 API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW),
70 API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0),
71 API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0),
72 API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0),
73 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0),
74 API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0),
75 API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0),
76 API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0),
77 API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0),
78 API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0),
79 API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
80 API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
81 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
82 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
83 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
84 API_ENTRY(0, 0, 0),
85};
86
87static const struct cx18_api_info *find_api_info(u32 cmd)
88{
89 int i;
90
91 for (i = 0; api_info[i].cmd; i++)
92 if (api_info[i].cmd == cmd)
93 return &api_info[i];
94 return NULL;
95}
96
97static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
98 u32 *state, u32 *irq, u32 *req)
99{
100 struct cx18_mailbox *mb = NULL;
101 int wait_count = 0;
102 u32 ack;
103
104 switch (rpu) {
105 case APU:
106 mb = &cx->scb->epu2apu_mb;
107 *state = readl(&cx->scb->apu_state);
108 *irq = readl(&cx->scb->epu2apu_irq);
109 break;
110
111 case CPU:
112 mb = &cx->scb->epu2cpu_mb;
113 *state = readl(&cx->scb->cpu_state);
114 *irq = readl(&cx->scb->epu2cpu_irq);
115 break;
116
117 case HPU:
118 mb = &cx->scb->epu2hpu_mb;
119 *state = readl(&cx->scb->hpu_state);
120 *irq = readl(&cx->scb->epu2hpu_irq);
121 break;
122 }
123
124 if (mb == NULL)
125 return mb;
126
127 do {
128 *req = readl(&mb->request);
129 ack = readl(&mb->ack);
130 wait_count++;
131 } while (*req != ack && wait_count < 600);
132
133 if (*req == ack) {
134 (*req)++;
135 if (*req == 0 || *req == 0xffffffff)
136 *req = 1;
137 return mb;
138 }
139 return NULL;
140}
141
142long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
143{
144 const struct cx18_api_info *info = find_api_info(mb->cmd);
145 struct cx18_mailbox *ack_mb;
146 u32 ack_irq;
147 u8 rpu = CPU;
148
149 if (info == NULL && mb->cmd) {
150 CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
151 return -EINVAL;
152 }
153 if (info)
154 rpu = info->rpu;
155
156 switch (rpu) {
157 case HPU:
158 ack_irq = IRQ_EPU_TO_HPU_ACK;
159 ack_mb = &cx->scb->hpu2epu_mb;
160 break;
161 case APU:
162 ack_irq = IRQ_EPU_TO_APU_ACK;
163 ack_mb = &cx->scb->apu2epu_mb;
164 break;
165 case CPU:
166 ack_irq = IRQ_EPU_TO_CPU_ACK;
167 ack_mb = &cx->scb->cpu2epu_mb;
168 break;
169 default:
170 CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
171 return -EINVAL;
172 }
173
174 setup_page(SCB_OFFSET);
175 write_sync(mb->request, &ack_mb->ack);
176 write_reg(ack_irq, SW2_INT_SET);
177 return 0;
178}
179
180
181static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
182{
183 const struct cx18_api_info *info = find_api_info(cmd);
184 u32 state = 0, irq = 0, req, oldreq, err;
185 struct cx18_mailbox *mb;
186 wait_queue_head_t *waitq;
187 int timeout = 100;
188 int cnt = 0;
189 int sig = 0;
190 int i;
191
192 if (info == NULL) {
193 CX18_WARN("unknown cmd %x\n", cmd);
194 return -EINVAL;
195 }
196
197 if (cmd == CX18_CPU_DE_SET_MDL)
198 CX18_DEBUG_HI_API("%s\n", info->name);
199 else
200 CX18_DEBUG_API("%s\n", info->name);
201 setup_page(SCB_OFFSET);
202 mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
203
204 if (mb == NULL) {
205 CX18_ERR("mb %s busy\n", info->name);
206 return -EBUSY;
207 }
208
209 oldreq = req - 1;
210 writel(cmd, &mb->cmd);
211 for (i = 0; i < args; i++)
212 writel(data[i], &mb->args[i]);
213 writel(0, &mb->error);
214 writel(req, &mb->request);
215
216 switch (info->rpu) {
217 case APU: waitq = &cx->mb_apu_waitq; break;
218 case CPU: waitq = &cx->mb_cpu_waitq; break;
219 case EPU: waitq = &cx->mb_epu_waitq; break;
220 case HPU: waitq = &cx->mb_hpu_waitq; break;
221 default: return -EINVAL;
222 }
223 if (info->flags & API_FAST)
224 timeout /= 2;
225 write_reg(irq, SW1_INT_SET);
226
227 while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
228 if (cnt > 200 && !in_atomic())
229 sig = cx18_msleep_timeout(10, 1);
230 cnt++;
231 }
232 if (sig)
233 return -EINTR;
234 if (cnt == 660) {
235 writel(oldreq, &mb->request);
236 CX18_ERR("mb %s failed\n", info->name);
237 return -EINVAL;
238 }
239 for (i = 0; i < MAX_MB_ARGUMENTS; i++)
240 data[i] = readl(&mb->args[i]);
241 err = readl(&mb->error);
242 if (!in_atomic() && (info->flags & API_SLOW))
243 cx18_msleep_timeout(300, 0);
244 if (err)
245 CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
246 info->name);
247 return err ? -EIO : 0;
248}
249
250int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
251{
252 int res = cx18_api_call(cx, cmd, args, data);
253
254 /* Allow a single retry, probably already too late though.
255 If there is no free mailbox then that is usually an indication
256 of a more serious problem. */
257 return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
258}
259
260static int cx18_set_filter_param(struct cx18_stream *s)
261{
262 struct cx18 *cx = s->cx;
263 u32 mode;
264 int ret;
265
266 mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0);
267 ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
268 s->handle, 1, mode, cx->spatial_strength);
269 mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0);
270 ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
271 s->handle, 0, mode, cx->temporal_strength);
272 ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
273 s->handle, 2, cx->filter_mode >> 2, 0);
274 return ret;
275}
276
277int cx18_api_func(void *priv, u32 cmd, int in, int out,
278 u32 data[CX2341X_MBOX_MAX_DATA])
279{
280 struct cx18 *cx = priv;
281 struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
282
283 switch (cmd) {
284 case CX2341X_ENC_SET_OUTPUT_PORT:
285 return 0;
286 case CX2341X_ENC_SET_FRAME_RATE:
287 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6,
288 s->handle, 0, 0, 0, 0, data[0]);
289 case CX2341X_ENC_SET_FRAME_SIZE:
290 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3,
291 s->handle, data[1], data[0]);
292 case CX2341X_ENC_SET_STREAM_TYPE:
293 return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2,
294 s->handle, data[0]);
295 case CX2341X_ENC_SET_ASPECT_RATIO:
296 return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2,
297 s->handle, data[0]);
298
299 case CX2341X_ENC_SET_GOP_PROPERTIES:
300 return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3,
301 s->handle, data[0], data[1]);
302 case CX2341X_ENC_SET_GOP_CLOSURE:
303 return 0;
304 case CX2341X_ENC_SET_AUDIO_PROPERTIES:
305 return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
306 s->handle, data[0]);
307 case CX2341X_ENC_MUTE_AUDIO:
308 return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
309 s->handle, data[0]);
310 case CX2341X_ENC_SET_BIT_RATE:
311 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5,
312 s->handle, data[0], data[1], data[2], data[3]);
313 case CX2341X_ENC_MUTE_VIDEO:
314 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
315 s->handle, data[0]);
316 case CX2341X_ENC_SET_FRAME_DROP_RATE:
317 return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2,
318 s->handle, data[0]);
319 case CX2341X_ENC_MISC:
320 return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4,
321 s->handle, data[0], data[1], data[2]);
322 case CX2341X_ENC_SET_DNR_FILTER_MODE:
323 cx->filter_mode = (data[0] & 3) | (data[1] << 2);
324 return cx18_set_filter_param(s);
325 case CX2341X_ENC_SET_DNR_FILTER_PROPS:
326 cx->spatial_strength = data[0];
327 cx->temporal_strength = data[1];
328 return cx18_set_filter_param(s);
329 case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
330 return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3,
331 s->handle, data[0], data[1]);
332 case CX2341X_ENC_SET_CORING_LEVELS:
333 return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5,
334 s->handle, data[0], data[1], data[2], data[3]);
335 }
336 CX18_WARN("Unknown cmd %x\n", cmd);
337 return 0;
338}
339
340int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS],
341 u32 cmd, int args, ...)
342{
343 va_list ap;
344 int i;
345
346 va_start(ap, args);
347 for (i = 0; i < args; i++)
348 data[i] = va_arg(ap, u32);
349 va_end(ap);
350 return cx18_api(cx, cmd, args, data);
351}
352
353int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...)
354{
355 u32 data[MAX_MB_ARGUMENTS];
356 va_list ap;
357 int i;
358
359 if (cx == NULL) {
360 CX18_ERR("cx == NULL (cmd=%x)\n", cmd);
361 return 0;
362 }
363 if (args > MAX_MB_ARGUMENTS) {
364 CX18_ERR("args too big (cmd=%x)\n", cmd);
365 args = MAX_MB_ARGUMENTS;
366 }
367 va_start(ap, args);
368 for (i = 0; i < args; i++)
369 data[i] = va_arg(ap, u32);
370 va_end(ap);
371 return cx18_api(cx, cmd, args, data);
372}