diff options
Diffstat (limited to 'linux/drivers/media/video/cx88/cx88-blackbird.c')
-rw-r--r-- | linux/drivers/media/video/cx88/cx88-blackbird.c | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c new file mode 100644 index 000000000..b0f3a1005 --- /dev/null +++ b/linux/drivers/media/video/cx88/cx88-blackbird.c @@ -0,0 +1,598 @@ +/* + * $Id: cx88-blackbird.c,v 1.1 2004/07/29 21:35:48 kraxel Exp $ + * + * Support for a cx23416 mpeg encoder via cx2388x host port (PCI function #4). + * "blackbird" reference design. + * + * (c) 2004 Jelle Foks <jelle@foks.8m.com> + * (c) 2004 Gerd Knorr <kraxel@bytesex.org> + * + * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin" +#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024 + +/* defines below are from ivtv-driver.h */ + +#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF + +/*Firmware API commands*/ +#define IVTV_API_ENC_PING_FW 0x00000080 +#define IVTV_API_ENC_GETVER 0x000000C4 +#define IVTV_API_ENC_HALT_FW 0x000000C3 +#define IVTV_API_STD_TIMEOUT 0x00010000 /*units??*/ +//#define IVTV_API_ASSIGN_PGM_INDEX_INFO 0x000000c7 +#define IVTV_API_ASSIGN_STREAM_TYPE 0x000000b9 +#define IVTV_API_ASSIGN_OUTPUT_PORT 0x000000bb +#define IVTV_API_ASSIGN_FRAMERATE 0x0000008f +#define IVTV_API_ASSIGN_FRAME_SIZE 0x00000091 +#define IVTV_API_ASSIGN_ASPECT_RATIO 0x00000099 +#define IVTV_API_ASSIGN_BITRATES 0x00000095 +#define IVTV_API_ASSIGN_GOP_PROPERTIES 0x00000097 +#define IVTV_API_ASSIGN_3_2_PULLDOWN 0x000000b1 +#define IVTV_API_ASSIGN_GOP_CLOSURE 0x000000c5 +#define IVTV_API_ASSIGN_AUDIO_PROPERTIES 0x000000bd +#define IVTV_API_ASSIGN_DNR_FILTER_MODE 0x0000009b +#define IVTV_API_ASSIGN_DNR_FILTER_PROPS 0x0000009d +#define IVTV_API_ASSIGN_CORING_LEVELS 0x0000009f +#define IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1 +#define IVTV_API_ASSIGN_FRAME_DROP_RATE 0x000000d0 +#define IVTV_API_ASSIGN_PLACEHOLDER 0x000000d8 +#define IVTV_API_MUTE_VIDEO 0x000000d9 +#define IVTV_API_MUTE_AUDIO 0x000000da +#define IVTV_API_INITIALIZE_INPUT 0x000000cd +#define IVTV_API_REFRESH_INPUT 0x000000d3 +#define IVTV_API_ASSIGN_NUM_VSYNC_LINES 0x000000d6 +#define IVTV_API_BEGIN_CAPTURE 0x00000081 +//#define IVTV_API_PAUSE_ENCODER 0x000000d2 +//#define IVTV_API_EVENT_NOTIFICATION 0x000000d5 +#define IVTV_API_END_CAPTURE 0x00000082 + +/* Registers */ +#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_SPU (0x9050 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_HW_BLOCKS (0x9054 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_VPU (0x9058 /*| IVTV_REG_OFFSET*/) +#define IVTV_REG_APU (0xA064 /*| IVTV_REG_OFFSET*/) + + +/* initialize the dma for the mpegport, called from cx88-video.c:cx8800_initdev */ +int cx8800_mpegport_init_dma(struct cx8800_dev *dev) +{ + dprintk(1,"cx88_mpegport_init_dma\n"); + + /* toggle reset of the host */ + cx_write(MO_GPHST_SOFT_RST, 1); + udelay(100); + cx_write(MO_GPHST_SOFT_RST, 0); + udelay(100); + + /* host port setup */ + cx_write(MO_GPHST_WSC, 0x44444444U); + cx_write(MO_GPHST_XFR, 0); + cx_write(MO_GPHST_WDTH, 15); + cx_write(MO_GPHST_HDSHK, 0); + cx_write(MO_GPHST_MUX16, 0x44448888U); + cx_write(MO_GPHST_MODE, 0); + + cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ + + cx_write(MO_DEV_CNTRL2, 0x20); /* enable the RISC controller */ + cx_set(MO_PCI_INTMSK, 0x4); /* enable ts_int */ + + cx_write(TS_F2_CMD_STAT_MM, 0x2900106); /* F2_CMD_STAT_MM defaults + master + memory space */ + cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ + cx_write(MO_TS_LNGTH, MD_TS_LNGHT_VAL); + + udelay(100); + INIT_LIST_HEAD(&dev->mpegq.active); + INIT_LIST_HEAD(&dev->mpegq.queued); + dev->mpegq.timeout.function = cx8800_mpegport_timeout; + dev->mpegq.timeout.data = (unsigned long)dev; + init_timer(&dev->mpegq.timeout); + cx88_risc_stopper(dev->pci,&dev->mpegq.stopper, + MO_TS_DMACNTRL,0x11,0x00); + udelay(100); + + cx_write(MO_TS_INTMSK, 0); + cx_set(MO_TS_INTSTAT, 0); + cx_write(MO_TS_INTMSK, 0x1f1101); /* all except the irq2 bit */ + + cx_write(MO_TS_GPCNTRL, 3); /* reset gp counter to 0 */ + cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */ + //cx_write(TS_HW_SOP_CNTRL, 0x2F0BC0); /* mpeg start byte ts: 0x2F0BC0 ? */ + cx_write(TS_VALERR_CNTRL, 0x2000); + + cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ + udelay(100); + + return 0; +} + +/* ------------------------------------------------------------------ */ + +int wait_ready_gpio0_bit1_high(struct cx8800_dev *dev) +{ + int timeout = 1000; + do { timeout--; udelay(1); } while (!(cx_readb(MO_GP0_IO) & 2) && (timeout >= 0)); + if (timeout < 0) return -1; + return 0; +} + +int wait_ready_gpio0_bit1_low(struct cx8800_dev *dev) +{ + int timeout = 1000; + do { timeout--; udelay(1); } while ((cx_readb(MO_GP0_IO) & 2) && (timeout >= 0)); + if (timeout < 0) return -1; + return 0; +} + +#define P1_MDATA0 0x390000 +#define P1_MDATA1 0x390001 +#define P1_MDATA2 0x390002 +#define P1_MDATA3 0x390003 +#define P1_MADDR2 0x390004 +#define P1_MADDR1 0x390005 +#define P1_MADDR0 0x390006 +#define P1_RDATA0 0x390008 +#define P1_RDATA1 0x390009 +#define P1_RDATA2 0x39000A +#define P1_RDATA3 0x39000B +#define P1_RADDR0 0x39000C +#define P1_RADDR1 0x39000D +#define P1_RRDWR 0x39000E + +/* Warning: address is dword address (4 bytes) */ +static int memory_write(struct cx8800_dev *dev, int address, int value) +{ + int retval; + + //retval = wait_ready_gpio0_bit1_low(dev); + + cx_writeb(P1_MDATA0, (unsigned int)value); + cx_writeb(P1_MDATA1, (unsigned int)(value >> 8)); + cx_writeb(P1_MDATA2, (unsigned int)(value >> 16)); + cx_writeb(P1_MDATA3, (unsigned int)(value >> 24)); + cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) | 0x40); + cx_writeb(P1_MADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_MADDR0, (unsigned int)address); + + retval = wait_ready_gpio0_bit1_high(dev); + return retval; +} + +/* Warning: address is dword address (4 bytes) */ +static int memory_read(struct cx8800_dev *dev, int address, int *value) +{ + int retval; + + cx_writeb(P1_MADDR2, (unsigned int)(address >> 16) & ~0xC0); + cx_writeb(P1_MADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_MADDR0, (unsigned int)address); + + retval = wait_ready_gpio0_bit1_high(dev); + + int val; + cx_writeb(P1_MDATA3, 0); + val = (unsigned char)cx_read(P1_MDATA3) << 24; + cx_writeb(P1_MDATA2, 0); + val |= (unsigned char)cx_read(P1_MDATA2) << 16; + cx_writeb(P1_MDATA1, 0); + val |= (unsigned char)cx_read(P1_MDATA1) << 8; + cx_writeb(P1_MDATA0, 0); + val |= (unsigned char)cx_read(P1_MDATA0); + *value = val; + + return retval; +} + + +static int register_write(struct cx8800_dev *dev, int address, int value) +{ + int retval; + cx_writeb(P1_RDATA0, (unsigned int)value); + cx_writeb(P1_RDATA1, (unsigned int)(value >> 8)); + cx_writeb(P1_RDATA2, (unsigned int)(value >> 16)); + cx_writeb(P1_RDATA3, (unsigned int)(value >> 24)); + cx_writeb(P1_RADDR0, (unsigned int)address); + cx_writeb(P1_RADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_RRDWR, 1); + + retval = wait_ready_gpio0_bit1_high(dev); + udelay(1000); /* without this, things don't go right (subsequent memory_write()'s don't get through */ + /* ? would this be safe here? set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); */ + return retval; +} + + +static int register_read(struct cx8800_dev *dev, int address, int *value) +{ + int retval; + cx_writeb(P1_RADDR0, (unsigned int)address); + cx_writeb(P1_RADDR1, (unsigned int)(address >> 8)); + cx_writeb(P1_RRDWR, 0); + + retval = wait_ready_gpio0_bit1_high(dev); + + int val; + val = (unsigned char)cx_read(P1_RDATA0); + val |= (unsigned char)cx_read(P1_RDATA1) << 8; + val |= (unsigned char)cx_read(P1_RDATA2) << 16; + val |= (unsigned char)cx_read(P1_RDATA3) << 24; + *value = val; + + return retval; +} + +/* We don't need to call the API often, so using just one mailbox will probably suffice */ +int mpegport_api_cmd(struct cx8800_dev *dev, u32 command, u32 inputcnt, u32 outputcnt, ...) +{ + va_list args; + va_start(args, outputcnt); + int i; + u32 value; + + dprintk(1,"API Command 0x%X\n", command); + + /* this may not be 100% safe if we can't read any memory location without side effects */ + memory_read(dev, dev->mpegport_mailbox - 4, &value); + if (value != 0x12345678) { + dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n"); + return -1; + } + + u32 flag; + memory_read(dev, dev->mpegport_mailbox, &flag); + if (flag) { + dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag); + return -1; + } + + flag |= 1; /* tell 'em we're working on it */ + memory_write(dev, dev->mpegport_mailbox, flag); + + memory_write(dev, dev->mpegport_mailbox + 1, command); /* command code */ + memory_write(dev, dev->mpegport_mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */ + + /* write input values */ + for (i = 0; i < inputcnt ; i++) { + u32 value = va_arg(args, int); + memory_write(dev, dev->mpegport_mailbox + 4 + i, value); + dprintk(1, "API Input %d = %d\n", i, value); + } + + /* fill with zeroes (ivtv does it, but is this necessary?) */ + for (; i < 16 ; i++) { + u32 value = 0; + memory_write(dev, dev->mpegport_mailbox + 4 + i, value); + } + + flag |= 3; /* tell 'em we're done writing */ + memory_write(dev, dev->mpegport_mailbox, flag); + + /* wait for firmware to handle the API command */ + int timeoutcnt = 500; /* trial and error plus a margin (longest command I've seen is capture start) */ + do { + udelay(10); + timeoutcnt--; + memory_read(dev, dev->mpegport_mailbox, &flag); + } while (timeoutcnt && ((flag & 4)==0)); + + if (!timeoutcnt) { + dprintk(0, "ERROR: API Mailbox timeout\n"); + flag = 0; + memory_write(dev, dev->mpegport_mailbox, flag); + return -1; + } + + /* read output values */ + for (i = 0; i < outputcnt ; i++) { + u32 *value = va_arg(args, int *); + memory_read(dev, dev->mpegport_mailbox + 4 + i, value); + dprintk(1, "API Output %d = %d\n", i, *value); + } + + va_end(args); + + u32 retval; + memory_read(dev, dev->mpegport_mailbox + 2, &retval); + dprintk(1, "API result = %d (timeoutcnt=%d)\n",retval, timeoutcnt); + flag = 0; + memory_write(dev, dev->mpegport_mailbox, flag); + return retval; +} + + +int mpegport_find_mailbox(struct cx8800_dev *dev) +{ + u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456}; + int signaturecnt=0; + int i; + for (i = 0; (i < BLACKBIRD_FIRM_IMAGE_SIZE) && (signaturecnt < 4) ; i++) + { + u32 value; + memory_read(dev, i, &value); + if (value == signature[signaturecnt]) + signaturecnt++; + else + signaturecnt = 0; + } + if (signaturecnt == 4) + { + dprintk(1, "Mailbox signature found\n"); + return i; + } + else + { + dprintk(0, "Mailbox signature values not found!\n"); + return -1; + } +} + +int mpegport_load_firmware(struct cx8800_dev *dev) +{ + dprintk(1,"Loading firmware\n"); + int i, retval = 0; + u32 value = 0; + const struct firmware *blackbird_firmware; + + retval = register_write(dev, IVTV_REG_VPU, 0xFFFFFFED); + //retval = register_write(dev, IVTV_REG_VPU, 0xFFFFFFEF); + retval |= register_write(dev, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); + retval |= register_write(dev, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640); + retval |= register_write(dev, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); + udelay(500); + retval |= register_write(dev, IVTV_REG_APU, 0); + + if (retval < 0) dprintk(0, "Error with register_write\n"); + + /* without this, the encoder chip is just a dead chip */ + + /* for this to work, 'apt-get install hotplug' and copy the firmware binary to /usr/lib/hotplug/firmware */ + retval = request_firmware(&blackbird_firmware, BLACKBIRD_FIRM_ENC_FILENAME, &dev->pci->dev); + + if (retval != 0) { + dprintk(0, "ERROR: Hotplug firmware request failed! Fatal for mpegport support!\n"); + dprintk(0, "********** Perhaps hotplug utilities or the firmware file is not installed?\n"); + dprintk(0, "********** Or kernel hotplug support of Firmware loading support is not enabled?\n"); + dprintk(0, "********** - Kernel setup: Your kernel needs the following options:\n"); + dprintk(0, "********** 1) enable CONFIG_HOTPLUG from \"General Setup\"/\"Support for hot-pluggable devices\"\n"); + dprintk(0, "********** 2) enable CONFIG_FW_LOADER from \"Device Drivers\"/\"Generic Driver Options\"/\"Hotplug firmware loading support\"\n"); + dprintk(0, "********** - Hotplug support utilities:\n"); + dprintk(0, "********** 1) make sure sysfs is mounted on /sys\n"); + dprintk(0, "********** 2) copy the firmware binary to /usr/lib/hotplug/firmware/" BLACKBIRD_FIRM_ENC_FILENAME "\n"); + dprintk(0, "********** 3) Debian: 'apt-get install hotplug'\n"); + dprintk(0, "********** Others: Unknown (ask your vendor) or go here http://linux-hotplug.sourceforge.net/\n"); + dprintk(0, "********** You will also probably want to have a /etc/hotplug/firmware.agent\n"); + return -1; + } + + if (blackbird_firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) { + dprintk(0, "ERROR: Firmware is %d bytes long, which should be %d bytes.\n", blackbird_firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); + return -1; + } + + if ((blackbird_firmware->data[0] != 0xA7) || + (blackbird_firmware->data[1] != 0x0D) || + (blackbird_firmware->data[2] != 0x00) || + (blackbird_firmware->data[3] != 0x00) || + (blackbird_firmware->data[4] != 0x66) || + (blackbird_firmware->data[5] != 0xBB) || + (blackbird_firmware->data[6] != 0x55) || + (blackbird_firmware->data[7] != 0xAA)) { + dprintk(0, "ERROR: Firmware is corrupt or not for an encoder chip\n"); + return -1; + } + + /* transfer to the chip */ + u32 checksum = 0; + u32 *dataptr = (u32 *)blackbird_firmware->data; + for (i = 0; i < (blackbird_firmware->size >> 2); i++) { + value = *dataptr; + checksum += ~value; + memory_write(dev, i, value); + dataptr++; + } + + release_firmware(blackbird_firmware); + + /* this takes a whole second, but it ensures the upload worked (maybe some hw needs other RAM timings, etc) */ + /* read back to verify with the checksum */ + for (i--; i >= 0; i--) { + memory_read(dev, i, &value); + checksum -= ~value; + } + + if (checksum) { + dprintk(0, "ERROR: Firmware Upload Failed (memory checksums don't match).\n"); + return -1; + } + + dprintk(0, "Firmware upload successful.\n"); + +#if 0 + for (i = 0; i < 1024; i+=4) { + //u32 value; + memory_read(dev, (i>>2), &value); + if (0 == (i % 16)) + printk(KERN_INFO "cx88 fw: %02x:",i); + printk(" %02x %02x %02x %02x",(value & 0xFF),((value>>8) & 0xFF),((value>>16) & 0xFF),((value>>24) & 0xFF)); + if (12 == (i % 16)) + printk("\n"); + } +#endif + + retval |= register_write(dev, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); + retval |= register_read(dev, IVTV_REG_SPU, &value); + retval |= register_write(dev, IVTV_REG_SPU, value & 0xFFFFFFFE); + + udelay(1000); + + retval |= register_read(dev, IVTV_REG_VPU, &value); + retval |= register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8UL); + //retval |= register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFFB); + + if (retval < 0) dprintk(0, "Error with register_write\n"); + return 0; +} + +void mpegport_codec_settings(struct cx8800_dev *dev) +{ + /* assign stream type */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 0); /* program stream */ + //mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 2); /* MPEG1 stream */ + //mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 3); /* PES A/V */ + //mpegport_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 10); /* DVD stream */ + + /* assign output port */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_OUTPUT_PORT, 1, 0, 1); /* 1 = Host */ + + /* assign framerate */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0); + + /* assign frame size */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0, 480, 720); + + /* assign aspect ratio */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2); + + int bitrate_mode = 1; + int bitrate = 7500000; + int bitrate_peak = 7500000; + /* assign bitrates */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_BITRATES, 5, 0, + bitrate_mode, /* mode */ + bitrate, /* bps */ + bitrate_peak / 400, /* peak/400 */ + 0, 0x70); /* encoding buffer, ckennedy */ + + /* assign gop properties */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 15, 3); + //mpegport_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 2, 1); + + /* assign 3 2 pulldown */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_3_2_PULLDOWN, 1, 0, 0); + + /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4)); + + /* assign gop closure */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_GOP_CLOSURE, 1, 0, 0); + + /* assign audio properties */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4)); + + /* assign dnr filter mode */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_MODE, 2, 0, 0, 0); + + /* assign dnr filter props*/ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_PROPS, 2, 0, 0, 0); + + /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_CORING_LEVELS, 4, 0, 0, 255, 0, 255); + + /* assign spatial filter type: luma_t: 1 = horiz_only, chroma_t: 1 = horiz_only */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, 2, 0, 1, 1); + + /* assign frame drop rate */ + mpegport_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); +} + +int mpegport_initialize_codec(struct cx8800_dev *dev) +{ + int retval; + dprintk(1,"Initialize codec\n"); + + retval = mpegport_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */ + if (retval < 0) { + /* ping was not successful, reset and upload firmware */ + + cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */ + udelay(300); + cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */ + udelay(100); + + retval = mpegport_load_firmware(dev); + if (retval < 0) { dprintk(0, "Error with firmware load!\n"); return retval; } + + dev->mpegport_mailbox = mpegport_find_mailbox(dev); + if (dev->mpegport_mailbox < 0) { dprintk(0, "Error with mailbox search!\n"); return dev->mpegport_mailbox; } + + retval = mpegport_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */ + if (retval < 0) { + dprintk(0, "ERROR: Firmware ping failed!\n"); + return -1; + } + + int firmware_version; + retval = mpegport_api_cmd(dev, IVTV_API_ENC_GETVER, 0, 1, &firmware_version); + if (retval < 0) { + dprintk(0, "ERROR: Firmware get encoder version failed!\n"); + return -1; + } + dprintk(0, "Encoder revision: 0x%08x\n", firmware_version); + + } + else + { + dprintk(1, "Firmware already present and responding to ping (not reloading)\n"); + } + + udelay(500); + + cx_write(MO_PINMUX_IO, 0x88); /* 656-8bit IO and enable MPEG parallel IO */ + cx_clear(MO_INPUT_FORMAT, 0x100); /* chroma subcarrier lock to normal? */ + cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */ + + cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */ + + /* this seems to be necessary, because otherwise the picture isn't always correct, + even though I think the scaler in the cx23880 should not change the itu656 output. + maybe it's a pll or something? */ + set_scale(dev, 720, 480, V4L2_FIELD_INTERLACED); + + udelay(500); + + mpegport_codec_settings(dev); + + //mpegport_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef); + mpegport_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0); + //mpegport_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); + mpegport_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + mpegport_api_cmd(dev, IVTV_API_INITIALIZE_INPUT, 0, 0); /* initialize the video input */ + + udelay(500); + + mpegport_api_cmd(dev, IVTV_API_MUTE_VIDEO, 1, 0, 0); + udelay(500); + mpegport_api_cmd(dev, IVTV_API_MUTE_AUDIO, 1, 0, 0); + udelay(500); + + mpegport_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); /* start capturing to the host interface */ + //mpegport_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0); /* start capturing to the host interface */ + + udelay(500); + + mpegport_api_cmd(dev, IVTV_API_REFRESH_INPUT, 0,0); + return retval; +} + + +/* ------------------------------------------------------------------ */ |