Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     mailbox functions
0004     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
0005     Copyright (C) 2004  Chris Kennedy <c@groovy.org>
0006     Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
0007 
0008  */
0009 
0010 #include "ivtv-driver.h"
0011 #include "ivtv-mailbox.h"
0012 
0013 /* Firmware mailbox flags*/
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 /* Firmware mailbox standard timeout */
0020 #define IVTV_API_STD_TIMEOUT    0x02000000
0021 
0022 #define API_CACHE    (1 << 0)   /* Allow the command to be stored in the cache */
0023 #define API_RESULT   (1 << 1)   /* Allow 1 second for this cmd to end */
0024 #define API_FAST_RESULT  (3 << 1)   /* Allow 0.1 second for this cmd to end */
0025 #define API_DMA      (1 << 3)   /* DMA mailbox, has special handling */
0026 #define API_HIGH_VOL     (1 << 5)   /* High volume command (i.e. called during encoding or decoding) */
0027 #define API_NO_WAIT_MB   (1 << 4)   /* Command may not wait for a free mailbox */
0028 #define API_NO_WAIT_RES  (1 << 5)   /* Command may not wait for the result */
0029 #define API_NO_POLL  (1 << 6)   /* Avoid pointless polling */
0030 
0031 struct ivtv_api_info {
0032     int flags;      /* Flags, see above */
0033     const char *name;   /* The name of the command */
0034 };
0035 
0036 #define API_ENTRY(x, f) [x] = { (f), #x }
0037 
0038 static const struct ivtv_api_info api_info[256] = {
0039     /* MPEG encoder API */
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     /* Obsolete PULLDOWN API command */
0082     API_ENTRY(0xb1,                 API_CACHE),
0083 
0084     /* MPEG decoder API */
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 /*| API_NO_WAIT_RES*/),
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     /* OSD API */
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     /* if the mailbox is free, then try to claim it */
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 /* Try to find a free mailbox. Note mailbox 0 is reserved for DMA and so is not
0145    attempted here. */
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     /* All slow commands use the same mailbox, serializing them and also
0154        leaving the other mailbox free for simple fast commands. */
0155     if ((flags & API_FAST_RESULT) == API_RESULT)
0156         max_mbox = 1;
0157 
0158     /* find free non-DMA mailbox */
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         /* Sleep before a retry, if not atomic */
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     /* sanity checks */
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     /* clear possibly uninitialized part of data array */
0227     for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
0228         data[i] = 0;
0229 
0230     /* If this command was issued within the last 30 minutes and with identical
0231        data, then just return 0 as there is no need to issue this command again.
0232        Just an optimization to prevent unnecessary use of mailboxes. */
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     /* Get results */
0281     then = jiffies;
0282 
0283     if (!(flags & API_NO_POLL)) {
0284         /* First try to poll, then switch to delays */
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             /* reset the mailbox, but it is likely too late already */
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     /* Allow a single retry, probably already too late though.
0320        If there is no free mailbox then that is usually an indication
0321        of a more serious problem. */
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 /* This one is for stuff that can't sleep.. irq handlers, etc.. */
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 /* Wipe api cache */
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 }