1 // SPDX-License-Identifier: GPL-2.0-or-later
4 Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com>
5 Copyright (C) 2004 Chris Kennedy <c@groovy.org>
6 Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl>
10 #include "ivtv-driver.h"
11 #include "ivtv-mailbox.h"
13 /* Firmware mailbox flags*/
14 #define IVTV_MBOX_FIRMWARE_DONE 0x00000004
15 #define IVTV_MBOX_DRIVER_DONE 0x00000002
16 #define IVTV_MBOX_DRIVER_BUSY 0x00000001
17 #define IVTV_MBOX_FREE 0x00000000
19 /* Firmware mailbox standard timeout */
20 #define IVTV_API_STD_TIMEOUT 0x02000000
22 #define API_CACHE (1 << 0) /* Allow the command to be stored in the cache */
23 #define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */
24 #define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */
25 #define API_DMA (1 << 3) /* DMA mailbox, has special handling */
26 #define API_HIGH_VOL (1 << 5) /* High volume command (i.e. called during encoding or decoding) */
27 #define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */
28 #define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */
29 #define API_NO_POLL (1 << 6) /* Avoid pointless polling */
31 struct ivtv_api_info
{
32 int flags
; /* Flags, see above */
33 const char *name
; /* The name of the command */
36 #define API_ENTRY(x, f) [x] = { (f), #x }
38 static const struct ivtv_api_info api_info
[256] = {
39 /* MPEG encoder API */
40 API_ENTRY(CX2341X_ENC_PING_FW
, API_FAST_RESULT
),
41 API_ENTRY(CX2341X_ENC_START_CAPTURE
, API_RESULT
| API_NO_POLL
),
42 API_ENTRY(CX2341X_ENC_STOP_CAPTURE
, API_RESULT
),
43 API_ENTRY(CX2341X_ENC_SET_AUDIO_ID
, API_CACHE
),
44 API_ENTRY(CX2341X_ENC_SET_VIDEO_ID
, API_CACHE
),
45 API_ENTRY(CX2341X_ENC_SET_PCR_ID
, API_CACHE
),
46 API_ENTRY(CX2341X_ENC_SET_FRAME_RATE
, API_CACHE
),
47 API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE
, API_CACHE
),
48 API_ENTRY(CX2341X_ENC_SET_BIT_RATE
, API_CACHE
),
49 API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES
, API_CACHE
),
50 API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO
, API_CACHE
),
51 API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE
, API_CACHE
),
52 API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS
, API_CACHE
),
53 API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS
, API_CACHE
),
54 API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE
, API_CACHE
),
55 API_ENTRY(CX2341X_ENC_SET_VBI_LINE
, API_RESULT
),
56 API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE
, API_CACHE
),
57 API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT
, API_CACHE
),
58 API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES
, API_CACHE
),
59 API_ENTRY(CX2341X_ENC_HALT_FW
, API_FAST_RESULT
),
60 API_ENTRY(CX2341X_ENC_GET_VERSION
, API_FAST_RESULT
),
61 API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE
, API_CACHE
),
62 API_ENTRY(CX2341X_ENC_GET_SEQ_END
, API_RESULT
),
63 API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO
, API_FAST_RESULT
),
64 API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG
, API_RESULT
),
65 API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE
, API_CACHE
),
66 API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10
, API_FAST_RESULT
),
67 API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9
, API_FAST_RESULT
),
68 API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST
, API_DMA
| API_HIGH_VOL
),
69 API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT
, API_RESULT
),
70 API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE
, API_CACHE
),
71 API_ENTRY(CX2341X_ENC_PAUSE_ENCODER
, API_RESULT
),
72 API_ENTRY(CX2341X_ENC_REFRESH_INPUT
, API_NO_WAIT_MB
| API_HIGH_VOL
),
73 API_ENTRY(CX2341X_ENC_SET_COPYRIGHT
, API_CACHE
),
74 API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION
, API_RESULT
),
75 API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES
, API_CACHE
),
76 API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER
, API_CACHE
),
77 API_ENTRY(CX2341X_ENC_MUTE_VIDEO
, API_RESULT
),
78 API_ENTRY(CX2341X_ENC_MUTE_AUDIO
, API_RESULT
),
79 API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE
, API_FAST_RESULT
),
80 API_ENTRY(CX2341X_ENC_MISC
, API_FAST_RESULT
),
81 /* Obsolete PULLDOWN API command */
82 API_ENTRY(0xb1, API_CACHE
),
84 /* MPEG decoder API */
85 API_ENTRY(CX2341X_DEC_PING_FW
, API_FAST_RESULT
),
86 API_ENTRY(CX2341X_DEC_START_PLAYBACK
, API_RESULT
| API_NO_POLL
),
87 API_ENTRY(CX2341X_DEC_STOP_PLAYBACK
, API_RESULT
),
88 API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED
, API_RESULT
),
89 API_ENTRY(CX2341X_DEC_STEP_VIDEO
, API_RESULT
),
90 API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE
, API_CACHE
),
91 API_ENTRY(CX2341X_DEC_GET_XFER_INFO
, API_FAST_RESULT
),
92 API_ENTRY(CX2341X_DEC_GET_DMA_STATUS
, API_FAST_RESULT
),
93 API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST
, API_DMA
| API_HIGH_VOL
),
94 API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK
, API_RESULT
),
95 API_ENTRY(CX2341X_DEC_HALT_FW
, API_FAST_RESULT
),
96 API_ENTRY(CX2341X_DEC_SET_STANDARD
, API_CACHE
),
97 API_ENTRY(CX2341X_DEC_GET_VERSION
, API_FAST_RESULT
),
98 API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT
, API_CACHE
),
99 API_ENTRY(CX2341X_DEC_GET_TIMING_INFO
, API_RESULT
/*| API_NO_WAIT_RES*/),
100 API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE
, API_CACHE
),
101 API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION
, API_RESULT
),
102 API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS
, API_CACHE
),
103 API_ENTRY(CX2341X_DEC_EXTRACT_VBI
, API_RESULT
),
104 API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE
, API_FAST_RESULT
),
105 API_ENTRY(CX2341X_DEC_SET_PREBUFFERING
, API_CACHE
),
108 API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER
, API_FAST_RESULT
),
109 API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT
, API_FAST_RESULT
),
110 API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT
, API_CACHE
),
111 API_ENTRY(CX2341X_OSD_GET_STATE
, API_FAST_RESULT
),
112 API_ENTRY(CX2341X_OSD_SET_STATE
, API_CACHE
),
113 API_ENTRY(CX2341X_OSD_GET_OSD_COORDS
, API_FAST_RESULT
),
114 API_ENTRY(CX2341X_OSD_SET_OSD_COORDS
, API_CACHE
),
115 API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS
, API_FAST_RESULT
),
116 API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS
, API_CACHE
),
117 API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA
, API_FAST_RESULT
),
118 API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA
, API_CACHE
),
119 API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS
, API_CACHE
),
120 API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE
, API_FAST_RESULT
),
121 API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE
, API_CACHE
),
122 API_ENTRY(CX2341X_OSD_BLT_COPY
, API_RESULT
),
123 API_ENTRY(CX2341X_OSD_BLT_FILL
, API_RESULT
),
124 API_ENTRY(CX2341X_OSD_BLT_TEXT
, API_RESULT
),
125 API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW
, API_CACHE
),
126 API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY
, API_CACHE
),
127 API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX
, API_FAST_RESULT
),
128 API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX
, API_CACHE
)
131 static int try_mailbox(struct ivtv
*itv
, struct ivtv_mailbox_data
*mbdata
, int mb
)
133 u32 flags
= readl(&mbdata
->mbox
[mb
].flags
);
134 int is_free
= flags
== IVTV_MBOX_FREE
|| (flags
& IVTV_MBOX_FIRMWARE_DONE
);
136 /* if the mailbox is free, then try to claim it */
137 if (is_free
&& !test_and_set_bit(mb
, &mbdata
->busy
)) {
138 write_sync(IVTV_MBOX_DRIVER_BUSY
, &mbdata
->mbox
[mb
].flags
);
144 /* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not
146 static int get_mailbox(struct ivtv
*itv
, struct ivtv_mailbox_data
*mbdata
, int flags
)
148 unsigned long then
= jiffies
;
150 int max_mbox
= mbdata
->max_mbox
;
153 /* All slow commands use the same mailbox, serializing them and also
154 leaving the other mailbox free for simple fast commands. */
155 if ((flags
& API_FAST_RESULT
) == API_RESULT
)
158 /* find free non-DMA mailbox */
159 for (i
= 0; i
< retries
; i
++) {
160 for (mb
= 1; mb
<= max_mbox
; mb
++)
161 if (try_mailbox(itv
, mbdata
, mb
))
164 /* Sleep before a retry, if not atomic */
165 if (!(flags
& API_NO_WAIT_MB
)) {
166 if (time_after(jiffies
,
167 then
+ msecs_to_jiffies(10*retries
)))
169 ivtv_msleep_timeout(10, 0);
175 static void write_mailbox(volatile struct ivtv_mailbox __iomem
*mbox
, int cmd
, int args
, u32 data
[])
179 write_sync(cmd
, &mbox
->cmd
);
180 write_sync(IVTV_API_STD_TIMEOUT
, &mbox
->timeout
);
182 for (i
= 0; i
< CX2341X_MBOX_MAX_DATA
; i
++)
183 write_sync(data
[i
], &mbox
->data
[i
]);
185 write_sync(IVTV_MBOX_DRIVER_DONE
| IVTV_MBOX_DRIVER_BUSY
, &mbox
->flags
);
188 static void clear_all_mailboxes(struct ivtv
*itv
, struct ivtv_mailbox_data
*mbdata
)
192 for (i
= 0; i
<= mbdata
->max_mbox
; i
++) {
193 IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n",
194 i
, readl(&mbdata
->mbox
[i
].cmd
), readl(&mbdata
->mbox
[i
].flags
));
195 write_sync(0, &mbdata
->mbox
[i
].flags
);
196 clear_bit(i
, &mbdata
->busy
);
200 static int ivtv_api_call(struct ivtv
*itv
, int cmd
, int args
, u32 data
[])
202 struct ivtv_mailbox_data
*mbdata
= (cmd
>= 128) ? &itv
->enc_mbox
: &itv
->dec_mbox
;
203 volatile struct ivtv_mailbox __iomem
*mbox
;
204 int api_timeout
= msecs_to_jiffies(1000);
209 if (NULL
== mbdata
) {
210 IVTV_ERR("No mailbox allocated\n");
213 if (args
< 0 || args
> CX2341X_MBOX_MAX_DATA
||
214 cmd
< 0 || cmd
> 255 || api_info
[cmd
].name
== NULL
) {
215 IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd
, args
);
219 if (api_info
[cmd
].flags
& API_HIGH_VOL
) {
220 IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info
[cmd
].name
);
223 IVTV_DEBUG_MB("MB Call: %s\n", api_info
[cmd
].name
);
226 /* clear possibly uninitialized part of data array */
227 for (i
= args
; i
< CX2341X_MBOX_MAX_DATA
; i
++)
230 /* If this command was issued within the last 30 minutes and with identical
231 data, then just return 0 as there is no need to issue this command again.
232 Just an optimization to prevent unnecessary use of mailboxes. */
233 if (itv
->api_cache
[cmd
].last_jiffies
&&
235 itv
->api_cache
[cmd
].last_jiffies
+
236 msecs_to_jiffies(1800000)) &&
237 !memcmp(data
, itv
->api_cache
[cmd
].data
, sizeof(itv
->api_cache
[cmd
].data
))) {
238 itv
->api_cache
[cmd
].last_jiffies
= jiffies
;
242 flags
= api_info
[cmd
].flags
;
244 if (flags
& API_DMA
) {
245 for (i
= 0; i
< 100; i
++) {
246 mb
= i
% (mbdata
->max_mbox
+ 1);
247 if (try_mailbox(itv
, mbdata
, mb
)) {
248 write_mailbox(&mbdata
->mbox
[mb
], cmd
, args
, data
);
249 clear_bit(mb
, &mbdata
->busy
);
252 IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n",
253 api_info
[cmd
].name
, mb
, readl(&mbdata
->mbox
[mb
].flags
));
255 IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info
[cmd
].name
);
256 clear_all_mailboxes(itv
, mbdata
);
260 if ((flags
& API_FAST_RESULT
) == API_FAST_RESULT
)
261 api_timeout
= msecs_to_jiffies(100);
263 mb
= get_mailbox(itv
, mbdata
, flags
);
265 IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info
[cmd
].name
);
266 clear_all_mailboxes(itv
, mbdata
);
269 mbox
= &mbdata
->mbox
[mb
];
270 write_mailbox(mbox
, cmd
, args
, data
);
271 if (flags
& API_CACHE
) {
272 memcpy(itv
->api_cache
[cmd
].data
, data
, sizeof(itv
->api_cache
[cmd
].data
));
273 itv
->api_cache
[cmd
].last_jiffies
= jiffies
;
275 if ((flags
& API_RESULT
) == 0) {
276 clear_bit(mb
, &mbdata
->busy
);
283 if (!(flags
& API_NO_POLL
)) {
284 /* First try to poll, then switch to delays */
285 for (i
= 0; i
< 100; i
++) {
286 if (readl(&mbox
->flags
) & IVTV_MBOX_FIRMWARE_DONE
)
290 while (!(readl(&mbox
->flags
) & IVTV_MBOX_FIRMWARE_DONE
)) {
291 if (time_after(jiffies
, then
+ api_timeout
)) {
292 IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info
[cmd
].name
);
293 /* reset the mailbox, but it is likely too late already */
294 write_sync(0, &mbox
->flags
);
295 clear_bit(mb
, &mbdata
->busy
);
298 if (flags
& API_NO_WAIT_RES
)
301 ivtv_msleep_timeout(1, 0);
303 if (time_after(jiffies
, then
+ msecs_to_jiffies(100)))
304 IVTV_DEBUG_WARN("%s took %u jiffies\n",
306 jiffies_to_msecs(jiffies
- then
));
308 for (i
= 0; i
< CX2341X_MBOX_MAX_DATA
; i
++)
309 data
[i
] = readl(&mbox
->data
[i
]);
310 write_sync(0, &mbox
->flags
);
311 clear_bit(mb
, &mbdata
->busy
);
315 int ivtv_api(struct ivtv
*itv
, int cmd
, int args
, u32 data
[])
317 int res
= ivtv_api_call(itv
, cmd
, args
, data
);
319 /* Allow a single retry, probably already too late though.
320 If there is no free mailbox then that is usually an indication
321 of a more serious problem. */
322 return (res
== -EBUSY
) ? ivtv_api_call(itv
, cmd
, args
, data
) : res
;
325 int ivtv_api_func(void *priv
, u32 cmd
, int in
, int out
, u32 data
[CX2341X_MBOX_MAX_DATA
])
327 return ivtv_api(priv
, cmd
, in
, data
);
330 int ivtv_vapi_result(struct ivtv
*itv
, u32 data
[CX2341X_MBOX_MAX_DATA
], int cmd
, int args
, ...)
336 for (i
= 0; i
< args
; i
++) {
337 data
[i
] = va_arg(ap
, u32
);
340 return ivtv_api(itv
, cmd
, args
, data
);
343 int ivtv_vapi(struct ivtv
*itv
, int cmd
, int args
, ...)
345 u32 data
[CX2341X_MBOX_MAX_DATA
];
350 for (i
= 0; i
< args
; i
++) {
351 data
[i
] = va_arg(ap
, u32
);
354 return ivtv_api(itv
, cmd
, args
, data
);
357 /* This one is for stuff that can't sleep.. irq handlers, etc.. */
358 void ivtv_api_get_data(struct ivtv_mailbox_data
*mbdata
, int mb
,
359 int argc
, u32 data
[])
361 volatile u32 __iomem
*p
= mbdata
->mbox
[mb
].data
;
363 for (i
= 0; i
< argc
; i
++, p
++)
368 void ivtv_mailbox_cache_invalidate(struct ivtv
*itv
)
371 for (i
= 0; i
< 256; i
++)
372 itv
->api_cache
[i
].last_jiffies
= 0;