2 * cx18 mailbox functions
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
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.
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.
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
24 #include "cx18-driver.h"
27 #include "cx18-mailbox.h"
29 #define API_FAST (1 << 2) /* Short timeout */
30 #define API_SLOW (1 << 3) /* Additional 300ms timeout */
37 struct cx18_api_info
{
39 u8 flags
; /* Flags, see above */
40 u8 rpu
; /* Processing unit */
41 const char *name
; /* The name of the command */
44 #define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
46 static 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
),
87 static const struct cx18_api_info
*find_api_info(u32 cmd
)
91 for (i
= 0; api_info
[i
].cmd
; i
++)
92 if (api_info
[i
].cmd
== cmd
)
97 static struct cx18_mailbox __iomem
*cx18_mb_is_complete(struct cx18
*cx
, int rpu
,
98 u32
*state
, u32
*irq
, u32
*req
)
100 struct cx18_mailbox __iomem
*mb
= NULL
;
106 mb
= &cx
->scb
->epu2apu_mb
;
107 *state
= readl(&cx
->scb
->apu_state
);
108 *irq
= readl(&cx
->scb
->epu2apu_irq
);
112 mb
= &cx
->scb
->epu2cpu_mb
;
113 *state
= readl(&cx
->scb
->cpu_state
);
114 *irq
= readl(&cx
->scb
->epu2cpu_irq
);
118 mb
= &cx
->scb
->epu2hpu_mb
;
119 *state
= readl(&cx
->scb
->hpu_state
);
120 *irq
= readl(&cx
->scb
->epu2hpu_irq
);
128 *req
= readl(&mb
->request
);
129 ack
= readl(&mb
->ack
);
131 } while (*req
!= ack
&& wait_count
< 600);
135 if (*req
== 0 || *req
== 0xffffffff)
142 long cx18_mb_ack(struct cx18
*cx
, const struct cx18_mailbox
*mb
)
144 const struct cx18_api_info
*info
= find_api_info(mb
->cmd
);
145 struct cx18_mailbox __iomem
*ack_mb
;
149 if (info
== NULL
&& mb
->cmd
) {
150 CX18_WARN("Cannot ack unknown command %x\n", mb
->cmd
);
158 ack_irq
= IRQ_EPU_TO_HPU_ACK
;
159 ack_mb
= &cx
->scb
->hpu2epu_mb
;
162 ack_irq
= IRQ_EPU_TO_APU_ACK
;
163 ack_mb
= &cx
->scb
->apu2epu_mb
;
166 ack_irq
= IRQ_EPU_TO_CPU_ACK
;
167 ack_mb
= &cx
->scb
->cpu2epu_mb
;
170 CX18_WARN("Unknown RPU for command %x\n", mb
->cmd
);
174 setup_page(SCB_OFFSET
);
175 write_sync(mb
->request
, &ack_mb
->ack
);
176 write_reg(ack_irq
, SW2_INT_SET
);
181 static int cx18_api_call(struct cx18
*cx
, u32 cmd
, int args
, u32 data
[])
183 const struct cx18_api_info
*info
= find_api_info(cmd
);
184 u32 state
= 0, irq
= 0, req
, oldreq
, err
;
185 struct cx18_mailbox __iomem
*mb
;
186 wait_queue_head_t
*waitq
;
193 CX18_WARN("unknown cmd %x\n", cmd
);
197 if (cmd
== CX18_CPU_DE_SET_MDL
)
198 CX18_DEBUG_HI_API("%s\n", info
->name
);
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
);
205 CX18_ERR("mb %s busy\n", info
->name
);
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
);
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
;
223 if (info
->flags
& API_FAST
)
225 write_reg(irq
, SW1_INT_SET
);
227 while (!sig
&& readl(&mb
->ack
) != readl(&mb
->request
) && cnt
< 660) {
228 if (cnt
> 200 && !in_atomic())
229 sig
= cx18_msleep_timeout(10, 1);
235 writel(oldreq
, &mb
->request
);
236 CX18_ERR("mb %s failed\n", info
->name
);
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);
245 CX18_DEBUG_API("mailbox error %08x for command %s\n", err
,
247 return err
? -EIO
: 0;
250 int cx18_api(struct cx18
*cx
, u32 cmd
, int args
, u32 data
[])
252 int res
= cx18_api_call(cx
, cmd
, args
, data
);
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
;
260 static int cx18_set_filter_param(struct cx18_stream
*s
)
262 struct cx18
*cx
= s
->cx
;
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);
277 int cx18_api_func(void *priv
, u32 cmd
, int in
, int out
,
278 u32 data
[CX2341X_MBOX_MAX_DATA
])
280 struct cx18
*cx
= priv
;
281 struct cx18_stream
*s
= &cx
->streams
[CX18_ENC_STREAM_TYPE_MPG
];
284 case CX2341X_ENC_SET_OUTPUT_PORT
:
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,
295 case CX2341X_ENC_SET_ASPECT_RATIO
:
296 return cx18_vapi(cx
, CX18_CPU_SET_ASPECT_RATIO
, 2,
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
:
304 case CX2341X_ENC_SET_AUDIO_PROPERTIES
:
305 return cx18_vapi(cx
, CX18_CPU_SET_AUDIO_PARAMETERS
, 2,
307 case CX2341X_ENC_MUTE_AUDIO
:
308 return cx18_vapi(cx
, CX18_CPU_SET_AUDIO_MUTE
, 2,
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,
316 case CX2341X_ENC_SET_FRAME_DROP_RATE
:
317 return cx18_vapi(cx
, CX18_CPU_SET_SKIP_INPUT_FRAME
, 2,
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]);
336 CX18_WARN("Unknown cmd %x\n", cmd
);
340 int cx18_vapi_result(struct cx18
*cx
, u32 data
[MAX_MB_ARGUMENTS
],
341 u32 cmd
, int args
, ...)
347 for (i
= 0; i
< args
; i
++)
348 data
[i
] = va_arg(ap
, u32
);
350 return cx18_api(cx
, cmd
, args
, data
);
353 int cx18_vapi(struct cx18
*cx
, u32 cmd
, int args
, ...)
355 u32 data
[MAX_MB_ARGUMENTS
];
360 CX18_ERR("cx == NULL (cmd=%x)\n", cmd
);
363 if (args
> MAX_MB_ARGUMENTS
) {
364 CX18_ERR("args too big (cmd=%x)\n", cmd
);
365 args
= MAX_MB_ARGUMENTS
;
368 for (i
= 0; i
< args
; i
++)
369 data
[i
] = va_arg(ap
, u32
);
371 return cx18_api(cx
, cmd
, args
, data
);