aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/stradis.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/video/stradis.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/media/video/stradis.c')
-rw-r--r--drivers/media/video/stradis.c2258
1 files changed, 2258 insertions, 0 deletions
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
new file mode 100644
index 00000000000..b5774357108
--- /dev/null
+++ b/drivers/media/video/stradis.c
@@ -0,0 +1,2258 @@
+/*
+ * stradis.c - stradis 4:2:2 mpeg decoder driver
+ *
+ * Stradis 4:2:2 MPEG-2 Decoder Driver
+ * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <asm/types.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev.h>
+
+#include "saa7146.h"
+#include "saa7146reg.h"
+#include "ibmmpeg2.h"
+#include "saa7121.h"
+#include "cs8420.h"
+
+#define DEBUG(x) /* debug driver */
+#undef IDEBUG /* debug irq handler */
+#undef MDEBUG /* debug memory management */
+
+#define SAA7146_MAX 6
+
+static struct saa7146 saa7146s[SAA7146_MAX];
+
+static int saa_num = 0; /* number of SAA7146s in use */
+
+static int video_nr = -1;
+module_param(video_nr, int, 0);
+MODULE_LICENSE("GPL");
+
+
+#define nDebNormal 0x00480000
+#define nDebNoInc 0x00480000
+#define nDebVideo 0xd0480000
+#define nDebAudio 0xd0400000
+#define nDebDMA 0x02c80000
+
+#define oDebNormal 0x13c80000
+#define oDebNoInc 0x13c80000
+#define oDebVideo 0xd1080000
+#define oDebAudio 0xd1080000
+#define oDebDMA 0x03080000
+
+#define NewCard (saa->boardcfg[3])
+#define ChipControl (saa->boardcfg[1])
+#define NTSCFirstActive (saa->boardcfg[4])
+#define PALFirstActive (saa->boardcfg[5])
+#define NTSCLastActive (saa->boardcfg[54])
+#define PALLastActive (saa->boardcfg[55])
+#define Have2MB (saa->boardcfg[18] & 0x40)
+#define HaveCS8420 (saa->boardcfg[18] & 0x04)
+#define IBMMPEGCD20 (saa->boardcfg[18] & 0x20)
+#define HaveCS3310 (saa->boardcfg[18] & 0x01)
+#define CS3310MaxLvl ((saa->boardcfg[30] << 8) | saa->boardcfg[31])
+#define HaveCS4341 (saa->boardcfg[40] == 2)
+#define SDIType (saa->boardcfg[27])
+#define CurrentMode (saa->boardcfg[2])
+
+#define debNormal (NewCard ? nDebNormal : oDebNormal)
+#define debNoInc (NewCard ? nDebNoInc : oDebNoInc)
+#define debVideo (NewCard ? nDebVideo : oDebVideo)
+#define debAudio (NewCard ? nDebAudio : oDebAudio)
+#define debDMA (NewCard ? nDebDMA : oDebDMA)
+
+#ifdef USE_RESCUE_EEPROM_SDM275
+static unsigned char rescue_eeprom[64] = {
+0x00,0x01,0x04,0x13,0x26,0x0f,0x10,0x00,0x00,0x00,0x43,0x63,0x22,0x01,0x29,0x15,0x73,0x00,0x1f, 'd', 'e', 'c', 'x', 'l', 'd', 'v', 'a',0x02,0x00,0x01,0x00,0xcc,0xa4,0x63,0x09,0xe2,0x10,0x00,0x0a,0x00,0x02,0x02, 'd', 'e', 'c', 'x', 'l', 'a',0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
+#endif
+
+/* ----------------------------------------------------------------------- */
+/* Hardware I2C functions */
+static void I2CWipe(struct saa7146 *saa)
+{
+ int i;
+ /* set i2c to ~=100kHz, abort transfer, clear busy */
+ saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ saawrite(0x600, SAA7146_I2C_STATUS);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ saawrite(0x600, SAA7146_I2C_STATUS);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+}
+
+/* read I2C */
+static int I2CRead(struct saa7146 *saa, unsigned char addr,
+ unsigned char subaddr, int dosub)
+{
+ int i;
+
+ if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+ I2CWipe(saa);
+ for (i = 0; i < 1000 &&
+ (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+ schedule();
+ if (i == 1000)
+ I2CWipe(saa);
+ if (dosub)
+ saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) |
+ ((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER);
+ else
+ saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) |
+ 0xf1, SAA7146_I2C_TRANSFER);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ /* wait for valid data */
+ for (i = 0; i < 1000 &&
+ (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+ schedule();
+ if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR)
+ return -1;
+ if (i == 1000)
+ printk("i2c setup read timeout\n");
+ saawrite(0x41, SAA7146_I2C_TRANSFER);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) |
+ SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
+ /* wait for i2c registers to be programmed */
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
+ schedule();
+ /* wait for valid data */
+ for (i = 0; i < 1000 &&
+ (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++)
+ schedule();
+ if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR)
+ return -1;
+ if (i == 1000)
+ printk("i2c read timeout\n");
+ return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff);
+}
+
+/* set both to write both bytes, reset it to write only b1 */
+
+static int I2CWrite(struct saa7146 *saa, unsigned char addr, unsigned char b1,
+ unsigned char b2, int both)
+{
+ int i;
+ u32 data;
+
+ if (saaread(SAA7146_I2C_STATUS) & 0x3c)
+ I2CWipe(saa);
+ for (i = 0; i < 1000 &&
+ (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
+ schedule();
+ if (i == 1000)
+ I2CWipe(saa);
+ data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16);
+ if (both)
+ data |= ((b2 & 0xff) << 8) | 0xe5;
+ else
+ data |= 0xd1;
+ saawrite(data, SAA7146_I2C_TRANSFER);
+ saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C,
+ SAA7146_MC2);
+ return 0;
+}
+
+static void attach_inform(struct saa7146 *saa, int id)
+{
+ int i;
+
+ DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr, id));
+ if (id == 0xa0) { /* we have rev2 or later board, fill in info */
+ for (i = 0; i < 64; i++)
+ saa->boardcfg[i] = I2CRead(saa, 0xa0, i, 1);
+#ifdef USE_RESCUE_EEPROM_SDM275
+ if (saa->boardcfg[0] != 0) {
+ printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE BEEN IGNORED\n", saa->nr);
+ for (i = 0; i < 64; i++)
+ saa->boardcfg[i] = rescue_eeprom[i];
+ }
+#endif
+ printk("stradis%d: config =", saa->nr);
+ for (i = 0; i < 51; i++) {
+ printk(" %02x",saa->boardcfg[i]);
+ }
+ printk("\n");
+ }
+}
+
+static void I2CBusScan(struct saa7146 *saa)
+{
+ int i;
+ for (i = 0; i < 0xff; i += 2)
+ if ((I2CRead(saa, i, 0, 0)) >= 0)
+ attach_inform(saa, i);
+}
+
+static int debiwait_maxwait = 0;
+
+static int wait_for_debi_done(struct saa7146 *saa)
+{
+ int i;
+
+ /* wait for registers to be programmed */
+ for (i = 0; i < 100000 &&
+ !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++)
+ saaread(SAA7146_MC2);
+ /* wait for transfer to complete */
+ for (i = 0; i < 500000 &&
+ (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++)
+ saaread(SAA7146_MC2);
+ if (i > debiwait_maxwait)
+ printk("wait-for-debi-done maxwait: %d\n",
+ debiwait_maxwait = i);
+
+ if (i == 500000)
+ return -1;
+ return 0;
+}
+
+static int debiwrite(struct saa7146 *saa, u32 config, int addr,
+ u32 val, int count)
+{
+ u32 cmd;
+ if (count <= 0 || count > 32764)
+ return -1;
+ if (wait_for_debi_done(saa) < 0)
+ return -1;
+ saawrite(config, SAA7146_DEBI_CONFIG);
+ if (count <= 4) /* immediate transfer */
+ saawrite(val, SAA7146_DEBI_AD);
+ else /* block transfer */
+ saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+ saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND);
+ saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+ SAA7146_MC2);
+ return 0;
+}
+
+static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
+{
+ u32 result = 0;
+
+ if (count > 32764 || count <= 0)
+ return 0;
+ if (wait_for_debi_done(saa) < 0)
+ return 0;
+ saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
+ saawrite((count << 17) | 0x10000 | (addr & 0xffff),
+ SAA7146_DEBI_COMMAND);
+ saawrite(config, SAA7146_DEBI_CONFIG);
+ saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
+ SAA7146_MC2);
+ if (count > 4) /* not an immediate transfer */
+ return count;
+ wait_for_debi_done(saa);
+ result = saaread(SAA7146_DEBI_AD);
+ if (count == 1)
+ result &= 0xff;
+ if (count == 2)
+ result &= 0xffff;
+ if (count == 3)
+ result &= 0xffffff;
+ return result;
+}
+
+#if 0 /* unused */
+/* MUST be a multiple of 8 bytes and 8-byte aligned and < 32768 bytes */
+/* data copied into saa->dmadebi buffer, caller must re-enable interrupts */
+static void ibm_block_dram_read(struct saa7146 *saa, int address, int bytes)
+{
+ int i, j;
+ u32 *buf;
+ buf = (u32 *) saa->dmadebi;
+ if (bytes > 0x7000)
+ bytes = 0x7000;
+ saawrite(0, SAA7146_IER); /* disable interrupts */
+ for (i=0; i < 10000 &&
+ (debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2)
+ & 0x8000); i++)
+ saaread(SAA7146_MC2);
+ if (i == 10000)
+ printk(KERN_ERR "stradis%d: dram_busy never cleared\n",
+ saa->nr);
+ debiwrite(saa, debNormal, IBM_MP2_SRC_ADDR, (address<<16) |
+ (address>>16), 4);
+ debiwrite(saa, debNormal, IBM_MP2_BLOCK_SIZE, bytes, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 0x8a10, 2);
+ for (j = 0; j < bytes/4; j++) {
+ for (i = 0; i < 10000 &&
+ (!(debiread(saa, debNormal, IBM_MP2_DRAM_CMD_STAT, 2)
+ & 0x4000)); i++)
+ saaread(SAA7146_MC2);
+ if (i == 10000)
+ printk(KERN_ERR "stradis%d: dram_ready never set\n",
+ saa->nr);
+ buf[j] = debiread(saa, debNormal, IBM_MP2_DRAM_DATA, 4);
+ }
+}
+#endif /* unused */
+
+static void do_irq_send_data(struct saa7146 *saa)
+{
+ int split, audbytes, vidbytes;
+
+ saawrite(SAA7146_PSR_PIN1, SAA7146_IER);
+ /* if special feature mode in effect, disable audio sending */
+ if (saa->playmode != VID_PLAY_NORMAL)
+ saa->audtail = saa->audhead = 0;
+ if (saa->audhead <= saa->audtail)
+ audbytes = saa->audtail - saa->audhead;
+ else
+ audbytes = 65536 - (saa->audhead - saa->audtail);
+ if (saa->vidhead <= saa->vidtail)
+ vidbytes = saa->vidtail - saa->vidhead;
+ else
+ vidbytes = 524288 - (saa->vidhead - saa->vidtail);
+ if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) {
+ saawrite(0, SAA7146_IER);
+ return;
+ }
+ /* if at least 1 block audio waiting and audio fifo isn't full */
+ if (audbytes >= 2048 && (debiread(saa, debNormal,
+ IBM_MP2_AUD_FIFO, 2) & 0xff) < 60) {
+ if (saa->audhead > saa->audtail)
+ split = 65536 - saa->audhead;
+ else
+ split = 0;
+ audbytes = 2048;
+ if (split > 0 && split < 2048) {
+ memcpy(saa->dmadebi, saa->audbuf + saa->audhead,
+ split);
+ saa->audhead = 0;
+ audbytes -= split;
+ } else
+ split = 0;
+ memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead,
+ audbytes);
+ saa->audhead += audbytes;
+ saa->audhead &= 0xffff;
+ debiwrite(saa, debAudio, (NewCard? IBM_MP2_AUD_FIFO :
+ IBM_MP2_AUD_FIFOW), 0, 2048);
+ wake_up_interruptible(&saa->audq);
+ /* if at least 1 block video waiting and video fifo isn't full */
+ } else if (vidbytes >= 30720 && (debiread(saa, debNormal,
+ IBM_MP2_FIFO, 2)) < 16384) {
+ if (saa->vidhead > saa->vidtail)
+ split = 524288 - saa->vidhead;
+ else
+ split = 0;
+ vidbytes = 30720;
+ if (split > 0 && split < 30720) {
+ memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead,
+ split);
+ saa->vidhead = 0;
+ vidbytes -= split;
+ } else
+ split = 0;
+ memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead,
+ vidbytes);
+ saa->vidhead += vidbytes;
+ saa->vidhead &= 0x7ffff;
+ debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO :
+ IBM_MP2_FIFOW), 0, 30720);
+ wake_up_interruptible(&saa->vidq);
+ }
+ saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER);
+}
+
+static void send_osd_data(struct saa7146 *saa)
+{
+ int size = saa->osdtail - saa->osdhead;
+ if (size > 30720)
+ size = 30720;
+ /* ensure some multiple of 8 bytes is transferred */
+ size = 8 * ((size + 8)>>3);
+ if (size) {
+ debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR,
+ (saa->osdhead>>3), 2);
+ memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size);
+ saa->osdhead += size;
+ /* block transfer of next 8 bytes to ~32k bytes */
+ debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size);
+ }
+ if (saa->osdhead >= saa->osdtail) {
+ saa->osdhead = saa->osdtail = 0;
+ debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
+ }
+}
+
+static irqreturn_t saa7146_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct saa7146 *saa = (struct saa7146 *) dev_id;
+ u32 stat, astat;
+ int count;
+ int handled = 0;
+
+ count = 0;
+ while (1) {
+ /* get/clear interrupt status bits */
+ stat = saaread(SAA7146_ISR);
+ astat = stat & saaread(SAA7146_IER);
+ if (!astat)
+ break;
+ handled = 1;
+ saawrite(astat, SAA7146_ISR);
+ if (astat & SAA7146_PSR_DEBI_S) {
+ do_irq_send_data(saa);
+ }
+ if (astat & SAA7146_PSR_PIN1) {
+ int istat;
+ /* the following read will trigger DEBI_S */
+ istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
+ if (istat & 1) {
+ saawrite(0, SAA7146_IER);
+ send_osd_data(saa);
+ saawrite(SAA7146_PSR_DEBI_S |
+ SAA7146_PSR_PIN1, SAA7146_IER);
+ }
+ if (istat & 0x20) { /* Video Start */
+ saa->vidinfo.frame_count++;
+ }
+ if (istat & 0x400) { /* Picture Start */
+ /* update temporal reference */
+ }
+ if (istat & 0x200) { /* Picture Resolution Change */
+ /* read new resolution */
+ }
+ if (istat & 0x100) { /* New User Data found */
+ /* read new user data */
+ }
+ if (istat & 0x1000) { /* new GOP/SMPTE */
+ /* read new SMPTE */
+ }
+ if (istat & 0x8000) { /* Sequence Start Code */
+ /* reset frame counter, load sizes */
+ saa->vidinfo.frame_count = 0;
+ saa->vidinfo.h_size = 704;
+ saa->vidinfo.v_size = 480;
+#if 0
+ if (saa->endmarkhead != saa->endmarktail) {
+ saa->audhead =
+ saa->endmark[saa->endmarkhead];
+ saa->endmarkhead++;
+ if (saa->endmarkhead >= MAX_MARKS)
+ saa->endmarkhead = 0;
+ }
+#endif
+ }
+ if (istat & 0x4000) { /* Sequence Error Code */
+ if (saa->endmarkhead != saa->endmarktail) {
+ saa->audhead =
+ saa->endmark[saa->endmarkhead];
+ saa->endmarkhead++;
+ if (saa->endmarkhead >= MAX_MARKS)
+ saa->endmarkhead = 0;
+ }
+ }
+ }
+#ifdef IDEBUG
+ if (astat & SAA7146_PSR_PPEF) {
+ IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PABO) {
+ IDEBUG(printk("stradis%d irq: PABO\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PPED) {
+ IDEBUG(printk("stradis%d irq: PPED\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_I1) {
+ IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_I0) {
+ IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_LATE1) {
+ IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_LATE0) {
+ IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_E1) {
+ IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_E0) {
+ IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_TO1) {
+ IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_RPS_TO0) {
+ IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_UPLD) {
+ IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_DEBI_E) {
+ IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_I2C_S) {
+ IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_I2C_E) {
+ IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A2_IN) {
+ IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A2_OUT) {
+ IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A1_IN) {
+ IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_A1_OUT) {
+ IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_AFOU) {
+ IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_V_PE) {
+ IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_VFOU) {
+ IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_FIDA) {
+ IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_FIDB) {
+ IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PIN3) {
+ IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PIN2) {
+ IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_PIN0) {
+ IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_ECS) {
+ IDEBUG(printk("stradis%d irq: ECS\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_EC3S) {
+ IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr));
+ }
+ if (astat & SAA7146_PSR_EC0S) {
+ IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr));
+ }
+#endif
+ count++;
+ if (count > 15)
+ printk(KERN_WARNING "stradis%d: irq loop %d\n",
+ saa->nr, count);
+ if (count > 20) {
+ saawrite(0, SAA7146_IER);
+ printk(KERN_ERR
+ "stradis%d: IRQ loop cleared\n", saa->nr);
+ }
+ }
+ return IRQ_RETVAL(handled);
+}
+
+static int ibm_send_command(struct saa7146 *saa,
+ int command, int data, int chain)
+{
+ int i;
+
+ if (chain)
+ debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1) | 1, 2);
+ else
+ debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2);
+ for (i = 0; i < 100 &&
+ (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++)
+ schedule();
+ if (i == 100)
+ return -1;
+ return 0;
+}
+
+static void cs4341_setlevel(struct saa7146 *saa, int left, int right)
+{
+ I2CWrite(saa, 0x22, 0x03, left > 94 ? 94 : left, 2);
+ I2CWrite(saa, 0x22, 0x04, right > 94 ? 94 : right, 2);
+}
+
+static void initialize_cs4341(struct saa7146 *saa)
+{
+ int i;
+ for (i = 0; i < 200; i++) {
+ /* auto mute off, power on, no de-emphasis */
+ /* I2S data up to 24-bit 64xFs internal SCLK */
+ I2CWrite(saa, 0x22, 0x01, 0x11, 2);
+ /* ATAPI mixer settings */
+ I2CWrite(saa, 0x22, 0x02, 0x49, 2);
+ /* attenuation left 3db */
+ I2CWrite(saa, 0x22, 0x03, 0x00, 2);
+ /* attenuation right 3db */
+ I2CWrite(saa, 0x22, 0x04, 0x00, 2);
+ I2CWrite(saa, 0x22, 0x01, 0x10, 2);
+ if (I2CRead(saa, 0x22, 0x02, 1) == 0x49)
+ break;
+ schedule();
+ }
+ printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i);
+ return;
+}
+
+static void initialize_cs8420(struct saa7146 *saa, int pro)
+{
+ int i;
+ u8 *sequence;
+ if (pro)
+ sequence = mode8420pro;
+ else
+ sequence = mode8420con;
+ for (i = 0; i < INIT8420LEN; i++)
+ I2CWrite(saa, 0x20, init8420[i * 2],
+ init8420[i * 2 + 1], 2);
+ for (i = 0; i < MODE8420LEN; i++)
+ I2CWrite(saa, 0x20, sequence[i * 2],
+ sequence[i * 2 + 1], 2);
+ printk("stradis%d: CS8420 initialized\n", saa->nr);
+}
+
+static void initialize_saa7121(struct saa7146 *saa, int dopal)
+{
+ int i, mod;
+ u8 *sequence;
+ if (dopal)
+ sequence = init7121pal;
+ else
+ sequence = init7121ntsc;
+ mod = saaread(SAA7146_PSR) & 0x08;
+ /* initialize PAL/NTSC video encoder */
+ for (i = 0; i < INIT7121LEN; i++) {
+ if (NewCard) { /* handle new card encoder differences */
+ if (sequence[i*2] == 0x3a)
+ I2CWrite(saa, 0x88, 0x3a, 0x13, 2);
+ else if (sequence[i*2] == 0x6b)
+ I2CWrite(saa, 0x88, 0x6b, 0x20, 2);
+ else if (sequence[i*2] == 0x6c)
+ I2CWrite(saa, 0x88, 0x6c,
+ dopal ? 0x09 : 0xf5, 2);
+ else if (sequence[i*2] == 0x6d)
+ I2CWrite(saa, 0x88, 0x6d,
+ dopal ? 0x20 : 0x00, 2);
+ else if (sequence[i*2] == 0x7a)
+ I2CWrite(saa, 0x88, 0x7a,
+ dopal ? (PALFirstActive - 1) :
+ (NTSCFirstActive - 4), 2);
+ else if (sequence[i*2] == 0x7b)
+ I2CWrite(saa, 0x88, 0x7b,
+ dopal ? PALLastActive :
+ NTSCLastActive, 2);
+ else I2CWrite(saa, 0x88, sequence[i * 2],
+ sequence[i * 2 + 1], 2);
+ } else {
+ if (sequence[i*2] == 0x6b && mod)
+ I2CWrite(saa, 0x88, 0x6b,
+ (sequence[i * 2 + 1] ^ 0x09), 2);
+ else if (sequence[i*2] == 0x7a)
+ I2CWrite(saa, 0x88, 0x7a,
+ dopal ? (PALFirstActive - 1) :
+ (NTSCFirstActive - 4), 2);
+ else if (sequence[i*2] == 0x7b)
+ I2CWrite(saa, 0x88, 0x7b,
+ dopal ? PALLastActive :
+ NTSCLastActive, 2);
+ else
+ I2CWrite(saa, 0x88, sequence[i * 2],
+ sequence[i * 2 + 1], 2);
+ }
+ }
+}
+
+static void set_genlock_offset(struct saa7146 *saa, int noffset)
+{
+ int nCode;
+ int PixelsPerLine = 858;
+ if (CurrentMode == VIDEO_MODE_PAL)
+ PixelsPerLine = 864;
+ if (noffset > 500)
+ noffset = 500;
+ else if (noffset < -500)
+ noffset = -500;
+ nCode = noffset + 0x100;
+ if (nCode == 1)
+ nCode = 0x401;
+ else if (nCode < 1) nCode = 0x400 + PixelsPerLine + nCode;
+ debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2);
+}
+
+static void set_out_format(struct saa7146 *saa, int mode)
+{
+ initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1));
+ saa->boardcfg[2] = mode;
+ /* do not adjust analog video parameters here, use saa7121 init */
+ /* you will affect the SDI output on the new card */
+ if (mode == VIDEO_MODE_PAL) { /* PAL */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2);
+ mdelay(50);
+ saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1);
+ if (NewCard) {
+ debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+ 0xe100, 2);
+ mdelay(50);
+ }
+ debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+ NewCard ? 0xe500: 0x6500, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+ (1 << 8) |
+ (NewCard ? PALFirstActive : PALFirstActive-6), 2);
+ } else { /* NTSC */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2);
+ mdelay(50);
+ saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
+ NewCard ? 0xe100: 0x6100, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
+ (1 << 8) |
+ (NewCard ? NTSCFirstActive : NTSCFirstActive-6), 2);
+ }
+}
+
+
+/* Intialize bitmangler to map from a byte value to the mangled word that
+ * must be output to program the Xilinx part through the DEBI port.
+ * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0
+ * transfer FPGA code, init IBM chip, transfer IBM microcode
+ * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0
+ */
+static u16 bitmangler[256];
+
+static int initialize_fpga(struct video_code *bitdata)
+{
+ int i, num, startindex, failure = 0, loadtwo, loadfile = 0;
+ u16 *dmabuf;
+ u8 *newdma;
+ struct saa7146 *saa;
+
+ /* verify fpga code */
+ for (startindex = 0; startindex < bitdata->datasize; startindex++)
+ if (bitdata->data[startindex] == 255)
+ break;
+ if (startindex == bitdata->datasize) {
+ printk(KERN_INFO "stradis: bad fpga code\n");
+ return -1;
+ }
+ /* initialize all detected cards */
+ for (num = 0; num < saa_num; num++) {
+ saa = &saa7146s[num];
+ if (saa->boardcfg[0] > 20)
+ continue; /* card was programmed */
+ loadtwo = (saa->boardcfg[18] & 0x10);
+ if (!NewCard) /* we have an old board */
+ for (i = 0; i < 256; i++)
+ bitmangler[i] = ((i & 0x01) << 15) |
+ ((i & 0x02) << 6) | ((i & 0x04) << 4) |
+ ((i & 0x08) << 9) | ((i & 0x10) << 7) |
+ ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+ ((i & 0x80) >> 7);
+ else /* else we have a new board */
+ for (i = 0; i < 256; i++)
+ bitmangler[i] = ((i & 0x01) << 7) |
+ ((i & 0x02) << 5) | ((i & 0x04) << 3) |
+ ((i & 0x08) << 1) | ((i & 0x10) >> 1) |
+ ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
+ ((i & 0x80) >> 7);
+
+ dmabuf = (u16 *) saa->dmadebi;
+ newdma = (u8 *) saa->dmadebi;
+ if (NewCard) { /* SDM2xxx */
+ if (!strncmp(bitdata->loadwhat, "decoder2", 8))
+ continue; /* fpga not for this card */
+ if (!strncmp(&saa->boardcfg[42],
+ bitdata->loadwhat, 8)) {
+ loadfile = 1;
+ } else if (loadtwo && !strncmp(&saa->boardcfg[19],
+ bitdata->loadwhat, 8)) {
+ loadfile = 2;
+ } else if (!saa->boardcfg[42] && /* special */
+ !strncmp("decxl", bitdata->loadwhat, 8)) {
+ loadfile = 1;
+ } else
+ continue; /* fpga not for this card */
+ if (loadfile != 1 && loadfile != 2) {
+ continue; /* skip to next card */
+ }
+ if (saa->boardcfg[0] && loadfile == 1 )
+ continue; /* skip to next card */
+ if (saa->boardcfg[0] != 1 && loadfile == 2)
+ continue; /* skip to next card */
+ saa->boardcfg[0]++; /* mark fpga handled */
+ printk("stradis%d: loading %s\n", saa->nr,
+ bitdata->loadwhat);
+ if (loadtwo && loadfile == 2)
+ goto send_fpga_stuff;
+ /* turn on the Audio interface to set PROG low */
+ saawrite(0x00400040, SAA7146_GPIO_CTRL);
+ saaread(SAA7146_PSR); /* ensure posted write */
+ /* wait for everyone to reset */
+ mdelay(10);
+ saawrite(0x00400000, SAA7146_GPIO_CTRL);
+ } else { /* original card */
+ if (strncmp(bitdata->loadwhat, "decoder2", 8))
+ continue; /* fpga not for this card */
+ /* Pull the Xilinx PROG signal WS3 low */
+ saawrite(0x02000200, SAA7146_MC1);
+ /* Turn on the Audio interface so can set PROG low */
+ saawrite(0x000000c0, SAA7146_ACON1);
+ /* Pull the Xilinx INIT signal (GPIO2) low */
+ saawrite(0x00400000, SAA7146_GPIO_CTRL);
+ /* Make sure everybody resets */
+ saaread(SAA7146_PSR); /* ensure posted write */
+ mdelay(10);
+ /* Release the Xilinx PROG signal */
+ saawrite(0x00000000, SAA7146_ACON1);
+ /* Turn off the Audio interface */
+ saawrite(0x02000000, SAA7146_MC1);
+ }
+ /* Release Xilinx INIT signal (WS2) */
+ saawrite(0x00000000, SAA7146_GPIO_CTRL);
+ /* Wait for the INIT to go High */
+ for (i = 0; i < 10000 &&
+ !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++)
+ schedule();
+ if (i == 1000) {
+ printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr);
+ return -1;
+ }
+send_fpga_stuff:
+ if (NewCard) {
+ for (i = startindex; i < bitdata->datasize; i++)
+ newdma[i - startindex] =
+ bitmangler[bitdata->data[i]];
+ debiwrite(saa, 0x01420000, 0, 0,
+ ((bitdata->datasize - startindex) + 5));
+ if (loadtwo) {
+ if (loadfile == 1) {
+ printk("stradis%d: "
+ "awaiting 2nd FPGA bitfile\n",
+ saa->nr);
+ continue; /* skip to next card */
+ }
+
+ }
+ } else {
+ for (i = startindex; i < bitdata->datasize; i++)
+ dmabuf[i - startindex] =
+ bitmangler[bitdata->data[i]];
+ debiwrite(saa, 0x014a0000, 0, 0,
+ ((bitdata->datasize - startindex) + 5) * 2);
+ }
+ for (i = 0; i < 1000 &&
+ !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2); i++)
+ schedule();
+ if (i == 1000) {
+ printk(KERN_INFO "stradis%d: FPGA load failed\n",
+ saa->nr);
+ failure++;
+ continue;
+ }
+ if (!NewCard) {
+ /* Pull the Xilinx INIT signal (GPIO2) low */
+ saawrite(0x00400000, SAA7146_GPIO_CTRL);
+ saaread(SAA7146_PSR); /* ensure posted write */
+ mdelay(2);
+ saawrite(0x00000000, SAA7146_GPIO_CTRL);
+ mdelay(2);
+ }
+ printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr);
+ saa->boardcfg[0] = 26; /* mark fpga programmed */
+ /* set VXCO to its lowest frequency */
+ debiwrite(saa, debNormal, XILINX_PWM, 0, 2);
+ if (NewCard) {
+ /* mute CS3310 */
+ if (HaveCS3310)
+ debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
+ 0, 2);
+ /* set VXCO to PWM mode, release reset, blank on */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2);
+ mdelay(10);
+ /* unmute CS3310 */
+ if (HaveCS3310)
+ debiwrite(saa, debNormal, XILINX_CTL0,
+ 0x2020, 2);
+ }
+ /* set source Black */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+ saa->boardcfg[4] = 22; /* set NTSC First Active Line */
+ saa->boardcfg[5] = 23; /* set PAL First Active Line */
+ saa->boardcfg[54] = 2; /* set NTSC Last Active Line - 256 */
+ saa->boardcfg[55] = 54; /* set PAL Last Active Line - 256 */
+ set_out_format(saa, VIDEO_MODE_NTSC);
+ mdelay(50);
+ /* begin IBM chip init */
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+ saaread(SAA7146_PSR); /* wait for reset */
+ mdelay(5);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+ debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+ if (NewCard) {
+ mdelay(5);
+ /* set i2s rate converter to 48KHz */
+ debiwrite(saa, debNormal, 0x80c0, 6, 2);
+ /* we must init CS8420 first since rev b pulls i2s */
+ /* master clock low and CS4341 needs i2s master to */
+ /* run the i2c port. */
+ if (HaveCS8420) {
+ /* 0=consumer, 1=pro */
+ initialize_cs8420(saa, 0);
+ }
+ mdelay(5);
+ if (HaveCS4341)
+ initialize_cs4341(saa);
+ }
+ debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+ debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+ if (NewCard)
+ set_genlock_offset(saa, 0);
+ debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+#if 0
+ /* enable genlock */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2);
+#else
+ /* disable genlock */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2);
+#endif
+ }
+ return failure;
+}
+
+static int do_ibm_reset(struct saa7146 *saa)
+{
+ /* failure if decoder not previously programmed */
+ if (saa->boardcfg[0] < 37)
+ return -EIO;
+ /* mute CS3310 */
+ if (HaveCS3310)
+ debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2);
+ /* disable interrupts */
+ saawrite(0, SAA7146_IER);
+ saa->audhead = saa->audtail = 0;
+ saa->vidhead = saa->vidtail = 0;
+ /* tristate debi bus, disable debi transfers */
+ saawrite(0x00880000, SAA7146_MC1);
+ /* ensure posted write */
+ saaread(SAA7146_MC1);
+ mdelay(50);
+ /* re-enable debi transfers */
+ saawrite(0x00880088, SAA7146_MC1);
+ /* set source Black */
+ debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
+ /* begin IBM chip init */
+ set_out_format(saa, CurrentMode);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
+ saaread(SAA7146_PSR); /* wait for reset */
+ mdelay(5);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
+ debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
+ if (NewCard) {
+ mdelay(5);
+ /* set i2s rate converter to 48KHz */
+ debiwrite(saa, debNormal, 0x80c0, 6, 2);
+ /* we must init CS8420 first since rev b pulls i2s */
+ /* master clock low and CS4341 needs i2s master to */
+ /* run the i2c port. */
+ if (HaveCS8420) {
+ /* 0=consumer, 1=pro */
+ initialize_cs8420(saa, 1);
+ }
+ mdelay(5);
+ if (HaveCS4341)
+ initialize_cs4341(saa);
+ }
+ debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
+ debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
+ if (NewCard)
+ set_genlock_offset(saa, 0);
+ debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
+ debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
+ debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
+ if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
+ (ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) {
+ printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr);
+ }
+ if (HaveCS3310) {
+ int i = CS3310MaxLvl;
+ debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i<<8)|i), 2);
+ }
+ /* start video decoder */
+ debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
+ /* 256k vid, 3520 bytes aud */
+ debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2);
+ debiwrite(saa, debNo