summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/cx88/cx88-blackbird.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/cx88/cx88-blackbird.c')
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c598
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;
+}
+
+
+/* ------------------------------------------------------------------ */