0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "ivtv-driver.h"
0011 #include "ivtv-mailbox.h"
0012
0013
0014 #define IVTV_MBOX_FIRMWARE_DONE 0x00000004
0015 #define IVTV_MBOX_DRIVER_DONE 0x00000002
0016 #define IVTV_MBOX_DRIVER_BUSY 0x00000001
0017 #define IVTV_MBOX_FREE 0x00000000
0018
0019
0020 #define IVTV_API_STD_TIMEOUT 0x02000000
0021
0022 #define API_CACHE (1 << 0)
0023 #define API_RESULT (1 << 1)
0024 #define API_FAST_RESULT (3 << 1)
0025 #define API_DMA (1 << 3)
0026 #define API_HIGH_VOL (1 << 5)
0027 #define API_NO_WAIT_MB (1 << 4)
0028 #define API_NO_WAIT_RES (1 << 5)
0029 #define API_NO_POLL (1 << 6)
0030
0031 struct ivtv_api_info {
0032 int flags;
0033 const char *name;
0034 };
0035
0036 #define API_ENTRY(x, f) [x] = { (f), #x }
0037
0038 static const struct ivtv_api_info api_info[256] = {
0039
0040 API_ENTRY(CX2341X_ENC_PING_FW, API_FAST_RESULT),
0041 API_ENTRY(CX2341X_ENC_START_CAPTURE, API_RESULT | API_NO_POLL),
0042 API_ENTRY(CX2341X_ENC_STOP_CAPTURE, API_RESULT),
0043 API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, API_CACHE),
0044 API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, API_CACHE),
0045 API_ENTRY(CX2341X_ENC_SET_PCR_ID, API_CACHE),
0046 API_ENTRY(CX2341X_ENC_SET_FRAME_RATE, API_CACHE),
0047 API_ENTRY(CX2341X_ENC_SET_FRAME_SIZE, API_CACHE),
0048 API_ENTRY(CX2341X_ENC_SET_BIT_RATE, API_CACHE),
0049 API_ENTRY(CX2341X_ENC_SET_GOP_PROPERTIES, API_CACHE),
0050 API_ENTRY(CX2341X_ENC_SET_ASPECT_RATIO, API_CACHE),
0051 API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_MODE, API_CACHE),
0052 API_ENTRY(CX2341X_ENC_SET_DNR_FILTER_PROPS, API_CACHE),
0053 API_ENTRY(CX2341X_ENC_SET_CORING_LEVELS, API_CACHE),
0054 API_ENTRY(CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, API_CACHE),
0055 API_ENTRY(CX2341X_ENC_SET_VBI_LINE, API_RESULT),
0056 API_ENTRY(CX2341X_ENC_SET_STREAM_TYPE, API_CACHE),
0057 API_ENTRY(CX2341X_ENC_SET_OUTPUT_PORT, API_CACHE),
0058 API_ENTRY(CX2341X_ENC_SET_AUDIO_PROPERTIES, API_CACHE),
0059 API_ENTRY(CX2341X_ENC_HALT_FW, API_FAST_RESULT),
0060 API_ENTRY(CX2341X_ENC_GET_VERSION, API_FAST_RESULT),
0061 API_ENTRY(CX2341X_ENC_SET_GOP_CLOSURE, API_CACHE),
0062 API_ENTRY(CX2341X_ENC_GET_SEQ_END, API_RESULT),
0063 API_ENTRY(CX2341X_ENC_SET_PGM_INDEX_INFO, API_FAST_RESULT),
0064 API_ENTRY(CX2341X_ENC_SET_VBI_CONFIG, API_RESULT),
0065 API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE),
0066 API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT),
0067 API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT),
0068 API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA | API_HIGH_VOL),
0069 API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT),
0070 API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE),
0071 API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT),
0072 API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB | API_HIGH_VOL),
0073 API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE),
0074 API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT),
0075 API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE),
0076 API_ENTRY(CX2341X_ENC_SET_PLACEHOLDER, API_CACHE),
0077 API_ENTRY(CX2341X_ENC_MUTE_VIDEO, API_RESULT),
0078 API_ENTRY(CX2341X_ENC_MUTE_AUDIO, API_RESULT),
0079 API_ENTRY(CX2341X_ENC_SET_VERT_CROP_LINE, API_FAST_RESULT),
0080 API_ENTRY(CX2341X_ENC_MISC, API_FAST_RESULT),
0081
0082 API_ENTRY(0xb1, API_CACHE),
0083
0084
0085 API_ENTRY(CX2341X_DEC_PING_FW, API_FAST_RESULT),
0086 API_ENTRY(CX2341X_DEC_START_PLAYBACK, API_RESULT | API_NO_POLL),
0087 API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, API_RESULT),
0088 API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, API_RESULT),
0089 API_ENTRY(CX2341X_DEC_STEP_VIDEO, API_RESULT),
0090 API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE),
0091 API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT),
0092 API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT),
0093 API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA | API_HIGH_VOL),
0094 API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT),
0095 API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT),
0096 API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE),
0097 API_ENTRY(CX2341X_DEC_GET_VERSION, API_FAST_RESULT),
0098 API_ENTRY(CX2341X_DEC_SET_STREAM_INPUT, API_CACHE),
0099 API_ENTRY(CX2341X_DEC_GET_TIMING_INFO, API_RESULT ),
0100 API_ENTRY(CX2341X_DEC_SET_AUDIO_MODE, API_CACHE),
0101 API_ENTRY(CX2341X_DEC_SET_EVENT_NOTIFICATION, API_RESULT),
0102 API_ENTRY(CX2341X_DEC_SET_DISPLAY_BUFFERS, API_CACHE),
0103 API_ENTRY(CX2341X_DEC_EXTRACT_VBI, API_RESULT),
0104 API_ENTRY(CX2341X_DEC_SET_DECODER_SOURCE, API_FAST_RESULT),
0105 API_ENTRY(CX2341X_DEC_SET_PREBUFFERING, API_CACHE),
0106
0107
0108 API_ENTRY(CX2341X_OSD_GET_FRAMEBUFFER, API_FAST_RESULT),
0109 API_ENTRY(CX2341X_OSD_GET_PIXEL_FORMAT, API_FAST_RESULT),
0110 API_ENTRY(CX2341X_OSD_SET_PIXEL_FORMAT, API_CACHE),
0111 API_ENTRY(CX2341X_OSD_GET_STATE, API_FAST_RESULT),
0112 API_ENTRY(CX2341X_OSD_SET_STATE, API_CACHE),
0113 API_ENTRY(CX2341X_OSD_GET_OSD_COORDS, API_FAST_RESULT),
0114 API_ENTRY(CX2341X_OSD_SET_OSD_COORDS, API_CACHE),
0115 API_ENTRY(CX2341X_OSD_GET_SCREEN_COORDS, API_FAST_RESULT),
0116 API_ENTRY(CX2341X_OSD_SET_SCREEN_COORDS, API_CACHE),
0117 API_ENTRY(CX2341X_OSD_GET_GLOBAL_ALPHA, API_FAST_RESULT),
0118 API_ENTRY(CX2341X_OSD_SET_GLOBAL_ALPHA, API_CACHE),
0119 API_ENTRY(CX2341X_OSD_SET_BLEND_COORDS, API_CACHE),
0120 API_ENTRY(CX2341X_OSD_GET_FLICKER_STATE, API_FAST_RESULT),
0121 API_ENTRY(CX2341X_OSD_SET_FLICKER_STATE, API_CACHE),
0122 API_ENTRY(CX2341X_OSD_BLT_COPY, API_RESULT),
0123 API_ENTRY(CX2341X_OSD_BLT_FILL, API_RESULT),
0124 API_ENTRY(CX2341X_OSD_BLT_TEXT, API_RESULT),
0125 API_ENTRY(CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, API_CACHE),
0126 API_ENTRY(CX2341X_OSD_SET_CHROMA_KEY, API_CACHE),
0127 API_ENTRY(CX2341X_OSD_GET_ALPHA_CONTENT_INDEX, API_FAST_RESULT),
0128 API_ENTRY(CX2341X_OSD_SET_ALPHA_CONTENT_INDEX, API_CACHE)
0129 };
0130
0131 static int try_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int mb)
0132 {
0133 u32 flags = readl(&mbdata->mbox[mb].flags);
0134 int is_free = flags == IVTV_MBOX_FREE || (flags & IVTV_MBOX_FIRMWARE_DONE);
0135
0136
0137 if (is_free && !test_and_set_bit(mb, &mbdata->busy)) {
0138 write_sync(IVTV_MBOX_DRIVER_BUSY, &mbdata->mbox[mb].flags);
0139 return 1;
0140 }
0141 return 0;
0142 }
0143
0144
0145
0146 static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int flags)
0147 {
0148 unsigned long then = jiffies;
0149 int i, mb;
0150 int max_mbox = mbdata->max_mbox;
0151 int retries = 100;
0152
0153
0154
0155 if ((flags & API_FAST_RESULT) == API_RESULT)
0156 max_mbox = 1;
0157
0158
0159 for (i = 0; i < retries; i++) {
0160 for (mb = 1; mb <= max_mbox; mb++)
0161 if (try_mailbox(itv, mbdata, mb))
0162 return mb;
0163
0164
0165 if (!(flags & API_NO_WAIT_MB)) {
0166 if (time_after(jiffies,
0167 then + msecs_to_jiffies(10*retries)))
0168 break;
0169 ivtv_msleep_timeout(10, 0);
0170 }
0171 }
0172 return -ENODEV;
0173 }
0174
0175 static void write_mailbox(volatile struct ivtv_mailbox __iomem *mbox, int cmd, int args, u32 data[])
0176 {
0177 int i;
0178
0179 write_sync(cmd, &mbox->cmd);
0180 write_sync(IVTV_API_STD_TIMEOUT, &mbox->timeout);
0181
0182 for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
0183 write_sync(data[i], &mbox->data[i]);
0184
0185 write_sync(IVTV_MBOX_DRIVER_DONE | IVTV_MBOX_DRIVER_BUSY, &mbox->flags);
0186 }
0187
0188 static void clear_all_mailboxes(struct ivtv *itv, struct ivtv_mailbox_data *mbdata)
0189 {
0190 int i;
0191
0192 for (i = 0; i <= mbdata->max_mbox; i++) {
0193 IVTV_DEBUG_WARN("Clearing mailbox %d: cmd 0x%08x flags 0x%08x\n",
0194 i, readl(&mbdata->mbox[i].cmd), readl(&mbdata->mbox[i].flags));
0195 write_sync(0, &mbdata->mbox[i].flags);
0196 clear_bit(i, &mbdata->busy);
0197 }
0198 }
0199
0200 static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
0201 {
0202 struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
0203 volatile struct ivtv_mailbox __iomem *mbox;
0204 int api_timeout = msecs_to_jiffies(1000);
0205 int flags, mb, i;
0206 unsigned long then;
0207
0208
0209 if (NULL == mbdata) {
0210 IVTV_ERR("No mailbox allocated\n");
0211 return -ENODEV;
0212 }
0213 if (args < 0 || args > CX2341X_MBOX_MAX_DATA ||
0214 cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) {
0215 IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args);
0216 return -EINVAL;
0217 }
0218
0219 if (api_info[cmd].flags & API_HIGH_VOL) {
0220 IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name);
0221 }
0222 else {
0223 IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name);
0224 }
0225
0226
0227 for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
0228 data[i] = 0;
0229
0230
0231
0232
0233 if (itv->api_cache[cmd].last_jiffies &&
0234 time_before(jiffies,
0235 itv->api_cache[cmd].last_jiffies +
0236 msecs_to_jiffies(1800000)) &&
0237 !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
0238 itv->api_cache[cmd].last_jiffies = jiffies;
0239 return 0;
0240 }
0241
0242 flags = api_info[cmd].flags;
0243
0244 if (flags & API_DMA) {
0245 for (i = 0; i < 100; i++) {
0246 mb = i % (mbdata->max_mbox + 1);
0247 if (try_mailbox(itv, mbdata, mb)) {
0248 write_mailbox(&mbdata->mbox[mb], cmd, args, data);
0249 clear_bit(mb, &mbdata->busy);
0250 return 0;
0251 }
0252 IVTV_DEBUG_WARN("%s: mailbox %d not free %08x\n",
0253 api_info[cmd].name, mb, readl(&mbdata->mbox[mb].flags));
0254 }
0255 IVTV_WARN("Could not find free DMA mailbox for %s\n", api_info[cmd].name);
0256 clear_all_mailboxes(itv, mbdata);
0257 return -EBUSY;
0258 }
0259
0260 if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
0261 api_timeout = msecs_to_jiffies(100);
0262
0263 mb = get_mailbox(itv, mbdata, flags);
0264 if (mb < 0) {
0265 IVTV_DEBUG_WARN("No free mailbox found (%s)\n", api_info[cmd].name);
0266 clear_all_mailboxes(itv, mbdata);
0267 return -EBUSY;
0268 }
0269 mbox = &mbdata->mbox[mb];
0270 write_mailbox(mbox, cmd, args, data);
0271 if (flags & API_CACHE) {
0272 memcpy(itv->api_cache[cmd].data, data, sizeof(itv->api_cache[cmd].data));
0273 itv->api_cache[cmd].last_jiffies = jiffies;
0274 }
0275 if ((flags & API_RESULT) == 0) {
0276 clear_bit(mb, &mbdata->busy);
0277 return 0;
0278 }
0279
0280
0281 then = jiffies;
0282
0283 if (!(flags & API_NO_POLL)) {
0284
0285 for (i = 0; i < 100; i++) {
0286 if (readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)
0287 break;
0288 }
0289 }
0290 while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
0291 if (time_after(jiffies, then + api_timeout)) {
0292 IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
0293
0294 write_sync(0, &mbox->flags);
0295 clear_bit(mb, &mbdata->busy);
0296 return -EIO;
0297 }
0298 if (flags & API_NO_WAIT_RES)
0299 mdelay(1);
0300 else
0301 ivtv_msleep_timeout(1, 0);
0302 }
0303 if (time_after(jiffies, then + msecs_to_jiffies(100)))
0304 IVTV_DEBUG_WARN("%s took %u jiffies\n",
0305 api_info[cmd].name,
0306 jiffies_to_msecs(jiffies - then));
0307
0308 for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
0309 data[i] = readl(&mbox->data[i]);
0310 write_sync(0, &mbox->flags);
0311 clear_bit(mb, &mbdata->busy);
0312 return 0;
0313 }
0314
0315 int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[])
0316 {
0317 int res = ivtv_api_call(itv, cmd, args, data);
0318
0319
0320
0321
0322 return (res == -EBUSY) ? ivtv_api_call(itv, cmd, args, data) : res;
0323 }
0324
0325 int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
0326 {
0327 return ivtv_api(priv, cmd, in, data);
0328 }
0329
0330 int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...)
0331 {
0332 va_list ap;
0333 int i;
0334
0335 va_start(ap, args);
0336 for (i = 0; i < args; i++) {
0337 data[i] = va_arg(ap, u32);
0338 }
0339 va_end(ap);
0340 return ivtv_api(itv, cmd, args, data);
0341 }
0342
0343 int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...)
0344 {
0345 u32 data[CX2341X_MBOX_MAX_DATA];
0346 va_list ap;
0347 int i;
0348
0349 va_start(ap, args);
0350 for (i = 0; i < args; i++) {
0351 data[i] = va_arg(ap, u32);
0352 }
0353 va_end(ap);
0354 return ivtv_api(itv, cmd, args, data);
0355 }
0356
0357
0358 void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
0359 int argc, u32 data[])
0360 {
0361 volatile u32 __iomem *p = mbdata->mbox[mb].data;
0362 int i;
0363 for (i = 0; i < argc; i++, p++)
0364 data[i] = readl(p);
0365 }
0366
0367
0368 void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
0369 {
0370 int i;
0371 for (i = 0; i < 256; i++)
0372 itv->api_cache[i].last_jiffies = 0;
0373 }