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
),
84 API_ENTRY(CPU
, CX18_APU_RESETAI
, API_FAST
),
88 static const struct cx18_api_info
*find_api_info(u32 cmd
)
92 for (i
= 0; api_info
[i
].cmd
; i
++)
93 if (api_info
[i
].cmd
== cmd
)
98 static struct cx18_mailbox __iomem
*cx18_mb_is_complete(struct cx18
*cx
, int rpu
,
99 u32
*state
, u32
*irq
, u32
*req
)
101 struct cx18_mailbox __iomem
*mb
= NULL
;
107 mb
= &cx
->scb
->epu2apu_mb
;
108 *state
= readl(&cx
->scb
->apu_state
);
109 *irq
= readl(&cx
->scb
->epu2apu_irq
);
113 mb
= &cx
->scb
->epu2cpu_mb
;
114 *state
= readl(&cx
->scb
->cpu_state
);
115 *irq
= readl(&cx
->scb
->epu2cpu_irq
);
119 mb
= &cx
->scb
->epu2hpu_mb
;
120 *state
= readl(&cx
->scb
->hpu_state
);
121 *irq
= readl(&cx
->scb
->epu2hpu_irq
);
129 *req
= readl(&mb
->request
);
130 ack
= readl(&mb
->ack
);
132 } while (*req
!= ack
&& wait_count
< 600);
136 if (*req
== 0 || *req
== 0xffffffff)
143 long cx18_mb_ack(struct cx18
*cx
, const struct cx18_mailbox
*mb
)
145 const struct cx18_api_info
*info
= find_api_info(mb
->cmd
);
146 struct cx18_mailbox __iomem
*ack_mb
;
150 if (info
== NULL
&& mb
->cmd
) {
151 CX18_WARN("Cannot ack unknown command %x\n", mb
->cmd
);
159 ack_irq
= IRQ_EPU_TO_HPU_ACK
;
160 ack_mb
= &cx
->scb
->hpu2epu_mb
;
163 ack_irq
= IRQ_EPU_TO_APU_ACK
;
164 ack_mb
= &cx
->scb
->apu2epu_mb
;
167 ack_irq
= IRQ_EPU_TO_CPU_ACK
;
168 ack_mb
= &cx
->scb
->cpu2epu_mb
;
171 CX18_WARN("Unknown RPU for command %x\n", mb
->cmd
);
175 setup_page(SCB_OFFSET
);
176 write_sync(mb
->request
, &ack_mb
->ack
);
177 write_reg(ack_irq
, SW2_INT_SET
);
182 static int cx18_api_call(struct cx18
*cx
, u32 cmd
, int args
, u32 data
[])
184 const struct cx18_api_info
*info
= find_api_info(cmd
);
185 u32 state
= 0, irq
= 0, req
, oldreq
, err
;
186 struct cx18_mailbox __iomem
*mb
;
187 wait_queue_head_t
*waitq
;
194 CX18_WARN("unknown cmd %x\n", cmd
);
198 if (cmd
== CX18_CPU_DE_SET_MDL
)
199 CX18_DEBUG_HI_API("%s\n", info
->name
);
201 CX18_DEBUG_API("%s\n", info
->name
);
202 setup_page(SCB_OFFSET
);
203 mb
= cx18_mb_is_complete(cx
, info
->rpu
, &state
, &irq
, &req
);
206 CX18_ERR("mb %s busy\n", info
->name
);
211 writel(cmd
, &mb
->cmd
);
212 for (i
= 0; i
< args
; i
++)
213 writel(data
[i
], &mb
->args
[i
]);
214 writel(0, &mb
->error
);
215 writel(req
, &mb
->request
);
218 case APU
: waitq
= &cx
->mb_apu_waitq
; break;
219 case CPU
: waitq
= &cx
->mb_cpu_waitq
; break;
220 case EPU
: waitq
= &cx
->mb_epu_waitq
; break;
221 case HPU
: waitq
= &cx
->mb_hpu_waitq
; break;
222 default: return -EINVAL
;
224 if (info
->flags
& API_FAST
)
226 write_reg(irq
, SW1_INT_SET
);
228 while (!sig
&& readl(&mb
->ack
) != readl(&mb
->request
) && cnt
< 660) {
229 if (cnt
> 200 && !in_atomic())
230 sig
= cx18_msleep_timeout(10, 1);
236 writel(oldreq
, &mb
->request
);
237 CX18_ERR("mb %s failed\n", info
->name
);
240 for (i
= 0; i
< MAX_MB_ARGUMENTS
; i
++)
241 data
[i
] = readl(&mb
->args
[i
]);
242 err
= readl(&mb
->error
);
243 if (!in_atomic() && (info
->flags
& API_SLOW
))
244 cx18_msleep_timeout(300, 0);
246 CX18_DEBUG_API("mailbox error %08x for command %s\n", err
,
248 return err
? -EIO
: 0;
251 int cx18_api(struct cx18
*cx
, u32 cmd
, int args
, u32 data
[])
253 int res
= cx18_api_call(cx
, cmd
, args
, data
);
255 /* Allow a single retry, probably already too late though.
256 If there is no free mailbox then that is usually an indication
257 of a more serious problem. */
258 return (res
== -EBUSY
) ? cx18_api_call(cx
, cmd
, args
, data
) : res
;
261 static int cx18_set_filter_param(struct cx18_stream
*s
)
263 struct cx18
*cx
= s
->cx
;
267 mode
= (cx
->filter_mode
& 1) ? 2 : (cx
->spatial_strength
? 1 : 0);
268 ret
= cx18_vapi(cx
, CX18_CPU_SET_FILTER_PARAM
, 4,
269 s
->handle
, 1, mode
, cx
->spatial_strength
);
270 mode
= (cx
->filter_mode
& 2) ? 2 : (cx
->temporal_strength
? 1 : 0);
271 ret
= ret
? ret
: cx18_vapi(cx
, CX18_CPU_SET_FILTER_PARAM
, 4,
272 s
->handle
, 0, mode
, cx
->temporal_strength
);
273 ret
= ret
? ret
: cx18_vapi(cx
, CX18_CPU_SET_FILTER_PARAM
, 4,
274 s
->handle
, 2, cx
->filter_mode
>> 2, 0);
278 int cx18_api_func(void *priv
, u32 cmd
, int in
, int out
,
279 u32 data
[CX2341X_MBOX_MAX_DATA
])
281 struct cx18
*cx
= priv
;
282 struct cx18_stream
*s
= &cx
->streams
[CX18_ENC_STREAM_TYPE_MPG
];
285 case CX2341X_ENC_SET_OUTPUT_PORT
:
287 case CX2341X_ENC_SET_FRAME_RATE
:
288 return cx18_vapi(cx
, CX18_CPU_SET_VIDEO_IN
, 6,
289 s
->handle
, 0, 0, 0, 0, data
[0]);
290 case CX2341X_ENC_SET_FRAME_SIZE
:
291 return cx18_vapi(cx
, CX18_CPU_SET_VIDEO_RESOLUTION
, 3,
292 s
->handle
, data
[1], data
[0]);
293 case CX2341X_ENC_SET_STREAM_TYPE
:
294 return cx18_vapi(cx
, CX18_CPU_SET_STREAM_OUTPUT_TYPE
, 2,
296 case CX2341X_ENC_SET_ASPECT_RATIO
:
297 return cx18_vapi(cx
, CX18_CPU_SET_ASPECT_RATIO
, 2,
300 case CX2341X_ENC_SET_GOP_PROPERTIES
:
301 return cx18_vapi(cx
, CX18_CPU_SET_GOP_STRUCTURE
, 3,
302 s
->handle
, data
[0], data
[1]);
303 case CX2341X_ENC_SET_GOP_CLOSURE
:
305 case CX2341X_ENC_SET_AUDIO_PROPERTIES
:
306 return cx18_vapi(cx
, CX18_CPU_SET_AUDIO_PARAMETERS
, 2,
308 case CX2341X_ENC_MUTE_AUDIO
:
309 return cx18_vapi(cx
, CX18_CPU_SET_AUDIO_MUTE
, 2,
311 case CX2341X_ENC_SET_BIT_RATE
:
312 return cx18_vapi(cx
, CX18_CPU_SET_VIDEO_RATE
, 5,
313 s
->handle
, data
[0], data
[1], data
[2], data
[3]);
314 case CX2341X_ENC_MUTE_VIDEO
:
315 return cx18_vapi(cx
, CX18_CPU_SET_VIDEO_MUTE
, 2,
317 case CX2341X_ENC_SET_FRAME_DROP_RATE
:
318 return cx18_vapi(cx
, CX18_CPU_SET_SKIP_INPUT_FRAME
, 2,
320 case CX2341X_ENC_MISC
:
321 return cx18_vapi(cx
, CX18_CPU_SET_MISC_PARAMETERS
, 4,
322 s
->handle
, data
[0], data
[1], data
[2]);
323 case CX2341X_ENC_SET_DNR_FILTER_MODE
:
324 cx
->filter_mode
= (data
[0] & 3) | (data
[1] << 2);
325 return cx18_set_filter_param(s
);
326 case CX2341X_ENC_SET_DNR_FILTER_PROPS
:
327 cx
->spatial_strength
= data
[0];
328 cx
->temporal_strength
= data
[1];
329 return cx18_set_filter_param(s
);
330 case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE
:
331 return cx18_vapi(cx
, CX18_CPU_SET_SPATIAL_FILTER_TYPE
, 3,
332 s
->handle
, data
[0], data
[1]);
333 case CX2341X_ENC_SET_CORING_LEVELS
:
334 return cx18_vapi(cx
, CX18_CPU_SET_MEDIAN_CORING
, 5,
335 s
->handle
, data
[0], data
[1], data
[2], data
[3]);
337 CX18_WARN("Unknown cmd %x\n", cmd
);
341 int cx18_vapi_result(struct cx18
*cx
, u32 data
[MAX_MB_ARGUMENTS
],
342 u32 cmd
, int args
, ...)
348 for (i
= 0; i
< args
; i
++)
349 data
[i
] = va_arg(ap
, u32
);
351 return cx18_api(cx
, cmd
, args
, data
);
354 int cx18_vapi(struct cx18
*cx
, u32 cmd
, int args
, ...)
356 u32 data
[MAX_MB_ARGUMENTS
];
361 CX18_ERR("cx == NULL (cmd=%x)\n", cmd
);
364 if (args
> MAX_MB_ARGUMENTS
) {
365 CX18_ERR("args too big (cmd=%x)\n", cmd
);
366 args
= MAX_MB_ARGUMENTS
;
369 for (i
= 0; i
< args
; i
++)
370 data
[i
] = va_arg(ap
, u32
);
372 return cx18_api(cx
, cmd
, args
, data
);