Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
0005  *  Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
0006  */
0007 
0008 #include <linux/device.h>   // for linux/firmware.h
0009 #include <linux/firmware.h>
0010 #include "pvrusb2-util.h"
0011 #include "pvrusb2-encoder.h"
0012 #include "pvrusb2-hdw-internal.h"
0013 #include "pvrusb2-debug.h"
0014 #include "pvrusb2-fx2-cmd.h"
0015 
0016 
0017 
0018 /* Firmware mailbox flags - definitions found from ivtv */
0019 #define IVTV_MBOX_FIRMWARE_DONE 0x00000004
0020 #define IVTV_MBOX_DRIVER_DONE 0x00000002
0021 #define IVTV_MBOX_DRIVER_BUSY 0x00000001
0022 
0023 #define MBOX_BASE 0x44
0024 
0025 
0026 static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
0027                     unsigned int offs,
0028                     const u32 *data, unsigned int dlen)
0029 {
0030     unsigned int idx,addr;
0031     unsigned int bAddr;
0032     int ret;
0033     unsigned int chunkCnt;
0034 
0035     /*
0036 
0037     Format: First byte must be 0x01.  Remaining 32 bit words are
0038     spread out into chunks of 7 bytes each, with the first 4 bytes
0039     being the data word (little endian), and the next 3 bytes
0040     being the address where that data word is to be written (big
0041     endian).  Repeat request for additional words, with offset
0042     adjusted accordingly.
0043 
0044     */
0045     while (dlen) {
0046         chunkCnt = 8;
0047         if (chunkCnt > dlen) chunkCnt = dlen;
0048         memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
0049         bAddr = 0;
0050         hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD;
0051         for (idx = 0; idx < chunkCnt; idx++) {
0052             addr = idx + offs;
0053             hdw->cmd_buffer[bAddr+6] = (addr & 0xffu);
0054             hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu);
0055             hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu);
0056             PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]);
0057             bAddr += 7;
0058         }
0059         ret = pvr2_send_request(hdw,
0060                     hdw->cmd_buffer,1+(chunkCnt*7),
0061                     NULL,0);
0062         if (ret) return ret;
0063         data += chunkCnt;
0064         dlen -= chunkCnt;
0065         offs += chunkCnt;
0066     }
0067 
0068     return 0;
0069 }
0070 
0071 
0072 static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
0073                    unsigned int offs,
0074                    u32 *data, unsigned int dlen)
0075 {
0076     unsigned int idx;
0077     int ret;
0078     unsigned int chunkCnt;
0079 
0080     /*
0081 
0082     Format: First byte must be 0x02 (status check) or 0x28 (read
0083     back block of 32 bit words).  Next 6 bytes must be zero,
0084     followed by a single byte of MBOX_BASE+offset for portion to
0085     be read.  Returned data is packed set of 32 bits words that
0086     were read.
0087 
0088     */
0089 
0090     while (dlen) {
0091         chunkCnt = 16;
0092         if (chunkCnt > dlen) chunkCnt = dlen;
0093         if (chunkCnt < 16) chunkCnt = 1;
0094         hdw->cmd_buffer[0] =
0095             ((chunkCnt == 1) ?
0096              FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES);
0097         hdw->cmd_buffer[1] = 0;
0098         hdw->cmd_buffer[2] = 0;
0099         hdw->cmd_buffer[3] = 0;
0100         hdw->cmd_buffer[4] = 0;
0101         hdw->cmd_buffer[5] = ((offs>>16) & 0xffu);
0102         hdw->cmd_buffer[6] = ((offs>>8) & 0xffu);
0103         hdw->cmd_buffer[7] = (offs & 0xffu);
0104         ret = pvr2_send_request(hdw,
0105                     hdw->cmd_buffer,8,
0106                     hdw->cmd_buffer,
0107                     (chunkCnt == 1 ? 4 : 16 * 4));
0108         if (ret) return ret;
0109 
0110         for (idx = 0; idx < chunkCnt; idx++) {
0111             data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
0112         }
0113         data += chunkCnt;
0114         dlen -= chunkCnt;
0115         offs += chunkCnt;
0116     }
0117 
0118     return 0;
0119 }
0120 
0121 
0122 /* This prototype is set up to be compatible with the
0123    cx2341x_mbox_func prototype in cx2341x.h, which should be in
0124    kernels 2.6.18 or later.  We do this so that we can enable
0125    cx2341x.ko to write to our encoder (by handing it a pointer to this
0126    function).  For earlier kernels this doesn't really matter. */
0127 static int pvr2_encoder_cmd(void *ctxt,
0128                 u32 cmd,
0129                 int arg_cnt_send,
0130                 int arg_cnt_recv,
0131                 u32 *argp)
0132 {
0133     unsigned int poll_count;
0134     unsigned int try_count = 0;
0135     int retry_flag;
0136     int ret = 0;
0137     unsigned int idx;
0138     /* These sizes look to be limited by the FX2 firmware implementation */
0139     u32 wrData[16];
0140     u32 rdData[16];
0141     struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
0142 
0143 
0144     /*
0145 
0146     The encoder seems to speak entirely using blocks 32 bit words.
0147     In ivtv driver terms, this is a mailbox at MBOX_BASE which we
0148     populate with data and watch what the hardware does with it.
0149     The first word is a set of flags used to control the
0150     transaction, the second word is the command to execute, the
0151     third byte is zero (ivtv driver suggests that this is some
0152     kind of return value), and the fourth byte is a specified
0153     timeout (windows driver always uses 0x00060000 except for one
0154     case when it is zero).  All successive words are the argument
0155     words for the command.
0156 
0157     First, write out the entire set of words, with the first word
0158     being zero.
0159 
0160     Next, write out just the first word again, but set it to
0161     IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
0162     probably means "go").
0163 
0164     Next, read back the return count words.  Check the first word,
0165     which should have IVTV_MBOX_FIRMWARE_DONE set.  If however
0166     that bit is not set, then the command isn't done so repeat the
0167     read until it is set.
0168 
0169     Finally, write out just the first word again, but set it to
0170     0x0 this time (which probably means "idle").
0171 
0172     */
0173 
0174     if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {
0175         pvr2_trace(
0176             PVR2_TRACE_ERROR_LEGS,
0177             "Failed to write cx23416 command - too many input arguments (was given %u limit %lu)",
0178             arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4);
0179         return -EINVAL;
0180     }
0181 
0182     if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {
0183         pvr2_trace(
0184             PVR2_TRACE_ERROR_LEGS,
0185             "Failed to write cx23416 command - too many return arguments (was given %u limit %lu)",
0186             arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4);
0187         return -EINVAL;
0188     }
0189 
0190 
0191     LOCK_TAKE(hdw->ctl_lock);
0192     while (1) {
0193         if (!hdw->state_encoder_ok) {
0194             ret = -EIO;
0195             break;
0196         }
0197 
0198         retry_flag = 0;
0199         try_count++;
0200         ret = 0;
0201         wrData[0] = 0;
0202         wrData[1] = cmd;
0203         wrData[2] = 0;
0204         wrData[3] = 0x00060000;
0205         for (idx = 0; idx < arg_cnt_send; idx++) {
0206             wrData[idx+4] = argp[idx];
0207         }
0208         for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {
0209             wrData[idx+4] = 0;
0210         }
0211 
0212         ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx);
0213         if (ret) break;
0214         wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
0215         ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
0216         if (ret) break;
0217         poll_count = 0;
0218         while (1) {
0219             poll_count++;
0220             ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData,
0221                               arg_cnt_recv+4);
0222             if (ret) {
0223                 break;
0224             }
0225             if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
0226                 break;
0227             }
0228             if (rdData[0] && (poll_count < 1000)) continue;
0229             if (!rdData[0]) {
0230                 retry_flag = !0;
0231                 pvr2_trace(
0232                     PVR2_TRACE_ERROR_LEGS,
0233                     "Encoder timed out waiting for us; arranging to retry");
0234             } else {
0235                 pvr2_trace(
0236                     PVR2_TRACE_ERROR_LEGS,
0237                     "***WARNING*** device's encoder appears to be stuck (status=0x%08x)",
0238 rdData[0]);
0239             }
0240             pvr2_trace(
0241                 PVR2_TRACE_ERROR_LEGS,
0242                 "Encoder command: 0x%02x",cmd);
0243             for (idx = 4; idx < arg_cnt_send; idx++) {
0244                 pvr2_trace(
0245                     PVR2_TRACE_ERROR_LEGS,
0246                     "Encoder arg%d: 0x%08x",
0247                     idx-3,wrData[idx]);
0248             }
0249             ret = -EBUSY;
0250             break;
0251         }
0252         if (retry_flag) {
0253             if (try_count < 20) continue;
0254             pvr2_trace(
0255                 PVR2_TRACE_ERROR_LEGS,
0256                 "Too many retries...");
0257             ret = -EBUSY;
0258         }
0259         if (ret) {
0260             del_timer_sync(&hdw->encoder_run_timer);
0261             hdw->state_encoder_ok = 0;
0262             pvr2_trace(PVR2_TRACE_STBITS,
0263                    "State bit %s <-- %s",
0264                    "state_encoder_ok",
0265                    (hdw->state_encoder_ok ? "true" : "false"));
0266             if (hdw->state_encoder_runok) {
0267                 hdw->state_encoder_runok = 0;
0268                 pvr2_trace(PVR2_TRACE_STBITS,
0269                    "State bit %s <-- %s",
0270                        "state_encoder_runok",
0271                        (hdw->state_encoder_runok ?
0272                         "true" : "false"));
0273             }
0274             pvr2_trace(
0275                 PVR2_TRACE_ERROR_LEGS,
0276                 "Giving up on command.  This is normally recovered via a firmware reload and re-initialization; concern is only warranted if this happens repeatedly and rapidly.");
0277             break;
0278         }
0279         wrData[0] = 0x7;
0280         for (idx = 0; idx < arg_cnt_recv; idx++) {
0281             argp[idx] = rdData[idx+4];
0282         }
0283 
0284         wrData[0] = 0x0;
0285         ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
0286         break;
0287     }
0288     LOCK_GIVE(hdw->ctl_lock);
0289 
0290     return ret;
0291 }
0292 
0293 
0294 static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
0295                  int args, ...)
0296 {
0297     va_list vl;
0298     unsigned int idx;
0299     u32 data[12];
0300 
0301     if (args > ARRAY_SIZE(data)) {
0302         pvr2_trace(
0303             PVR2_TRACE_ERROR_LEGS,
0304             "Failed to write cx23416 command - too many arguments (was given %u limit %lu)",
0305             args, (long unsigned) ARRAY_SIZE(data));
0306         return -EINVAL;
0307     }
0308 
0309     va_start(vl, args);
0310     for (idx = 0; idx < args; idx++) {
0311         data[idx] = va_arg(vl, u32);
0312     }
0313     va_end(vl);
0314 
0315     return pvr2_encoder_cmd(hdw,cmd,args,0,data);
0316 }
0317 
0318 
0319 /* This implements some extra setup for the encoder that seems to be
0320    specific to the PVR USB2 hardware. */
0321 static int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
0322 {
0323     int ret = 0;
0324     int encMisc3Arg = 0;
0325 
0326 #if 0
0327     /* This inexplicable bit happens in the Hauppauge windows
0328        driver (for both 24xxx and 29xxx devices).  However I
0329        currently see no difference in behavior with or without
0330        this stuff.  Leave this here as a note of its existence,
0331        but don't use it. */
0332     LOCK_TAKE(hdw->ctl_lock); do {
0333         u32 dat[1];
0334         dat[0] = 0x80000640;
0335         pvr2_encoder_write_words(hdw,0x01fe,dat,1);
0336         pvr2_encoder_write_words(hdw,0x023e,dat,1);
0337     } while(0); LOCK_GIVE(hdw->ctl_lock);
0338 #endif
0339 
0340     /* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver
0341        sends the following list of ENC_MISC commands (for both
0342        24xxx and 29xxx devices).  Meanings are not entirely clear,
0343        however without the ENC_MISC(3,1) command then we risk
0344        random perpetual video corruption whenever the video input
0345        breaks up for a moment (like when switching channels). */
0346 
0347 
0348 #if 0
0349     /* This ENC_MISC(5,0) command seems to hurt 29xxx sync
0350        performance on channel changes, but is not a problem on
0351        24xxx devices. */
0352     ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
0353 #endif
0354 
0355     /* This ENC_MISC(3,encMisc3Arg) command is critical - without
0356        it there will eventually be video corruption.  Also, the
0357        saa7115 case is strange - the Windows driver is passing 1
0358        regardless of device type but if we have 1 for saa7115
0359        devices the video turns sluggish.  */
0360     if (hdw->hdw_desc->flag_has_cx25840) {
0361         encMisc3Arg = 1;
0362     } else {
0363         encMisc3Arg = 0;
0364     }
0365     ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
0366                  encMisc3Arg,0,0);
0367 
0368     ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
0369 
0370 #if 0
0371     /* This ENC_MISC(4,1) command is poisonous, so it is commented
0372        out.  But I'm leaving it here anyway to document its
0373        existence in the Windows driver.  The effect of this
0374        command is that apps displaying the stream become sluggish
0375        with stuttering video. */
0376     ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
0377 #endif
0378 
0379     ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
0380     ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
0381 
0382     /* prevent the PTSs from slowly drifting away in the generated
0383        MPEG stream */
0384     ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC, 2, 4, 1);
0385 
0386     return ret;
0387 }
0388 
0389 int pvr2_encoder_adjust(struct pvr2_hdw *hdw)
0390 {
0391     int ret;
0392     ret = cx2341x_update(hdw,pvr2_encoder_cmd,
0393                  (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
0394                  &hdw->enc_ctl_state);
0395     if (ret) {
0396         pvr2_trace(PVR2_TRACE_ERROR_LEGS,
0397                "Error from cx2341x module code=%d",ret);
0398     } else {
0399         hdw->enc_cur_state = hdw->enc_ctl_state;
0400         hdw->enc_cur_valid = !0;
0401     }
0402     return ret;
0403 }
0404 
0405 
0406 int pvr2_encoder_configure(struct pvr2_hdw *hdw)
0407 {
0408     int ret;
0409     int val;
0410     pvr2_trace(PVR2_TRACE_ENCODER, "pvr2_encoder_configure (cx2341x module)");
0411     hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING;
0412     hdw->enc_ctl_state.width = hdw->res_hor_val;
0413     hdw->enc_ctl_state.height = hdw->res_ver_val;
0414     hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur & V4L2_STD_525_60) ?
0415                       0 : 1);
0416 
0417     ret = 0;
0418 
0419     ret |= pvr2_encoder_prep_config(hdw);
0420 
0421     /* saa7115: 0xf0 */
0422     val = 0xf0;
0423     if (hdw->hdw_desc->flag_has_cx25840) {
0424         /* ivtv cx25840: 0x140 */
0425         val = 0x140;
0426     }
0427 
0428     if (!ret) ret = pvr2_encoder_vcmd(
0429         hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
0430         val, val);
0431 
0432     /* setup firmware to notify us about some events (don't know why...) */
0433     if (!ret) ret = pvr2_encoder_vcmd(
0434         hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
0435         0, 0, 0x10000000, 0xffffffff);
0436 
0437     if (!ret) ret = pvr2_encoder_vcmd(
0438         hdw,CX2341X_ENC_SET_VBI_LINE, 5,
0439         0xffffffff,0,0,0,0);
0440 
0441     if (ret) {
0442         pvr2_trace(PVR2_TRACE_ERROR_LEGS,
0443                "Failed to configure cx23416");
0444         return ret;
0445     }
0446 
0447     ret = pvr2_encoder_adjust(hdw);
0448     if (ret) return ret;
0449 
0450     ret = pvr2_encoder_vcmd(
0451         hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
0452 
0453     if (ret) {
0454         pvr2_trace(PVR2_TRACE_ERROR_LEGS,
0455                "Failed to initialize cx23416 video input");
0456         return ret;
0457     }
0458 
0459     return 0;
0460 }
0461 
0462 
0463 int pvr2_encoder_start(struct pvr2_hdw *hdw)
0464 {
0465     int status;
0466 
0467     /* unmask some interrupts */
0468     pvr2_write_register(hdw, 0x0048, 0xbfffffff);
0469 
0470     pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
0471               hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
0472 
0473     switch (hdw->active_stream_type) {
0474     case pvr2_config_vbi:
0475         status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0476                        0x01,0x14);
0477         break;
0478     case pvr2_config_mpeg:
0479         status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0480                        0,0x13);
0481         break;
0482     default: /* Unhandled cases for now */
0483         status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
0484                        0,0x13);
0485         break;
0486     }
0487     return status;
0488 }
0489 
0490 int pvr2_encoder_stop(struct pvr2_hdw *hdw)
0491 {
0492     int status;
0493 
0494     /* mask all interrupts */
0495     pvr2_write_register(hdw, 0x0048, 0xffffffff);
0496 
0497     switch (hdw->active_stream_type) {
0498     case pvr2_config_vbi:
0499         status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0500                        0x01,0x01,0x14);
0501         break;
0502     case pvr2_config_mpeg:
0503         status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0504                        0x01,0,0x13);
0505         break;
0506     default: /* Unhandled cases for now */
0507         status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
0508                        0x01,0,0x13);
0509         break;
0510     }
0511 
0512     return status;
0513 }