aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/pci/cx23885/cx23885-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/pci/cx23885/cx23885-core.c')
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c132
1 files changed, 114 insertions, 18 deletions
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 019fac49db5b..94b996ff12a9 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -422,19 +422,30 @@ static void cx23885_wakeup(struct cx23885_tsport *port,
struct cx23885_dmaqueue *q, u32 count)
{
struct cx23885_buffer *buf;
-
- if (list_empty(&q->active))
- return;
- buf = list_entry(q->active.next,
- struct cx23885_buffer, queue);
-
- buf->vb.vb2_buf.timestamp = ktime_get_ns();
- buf->vb.sequence = q->count++;
- dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
- buf->vb.vb2_buf.index,
- count, q->count);
- list_del(&buf->queue);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ int count_delta;
+ int max_buf_done = 5; /* service maximum five buffers */
+
+ do {
+ if (list_empty(&q->active))
+ return;
+ buf = list_entry(q->active.next,
+ struct cx23885_buffer, queue);
+
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ buf->vb.sequence = q->count++;
+ if (count != (q->count % 65536)) {
+ dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
+ buf->vb.vb2_buf.index, count, q->count);
+ } else {
+ dprintk(7, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
+ buf->vb.vb2_buf.index, count, q->count);
+ }
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ max_buf_done--;
+ /* count register is 16 bits so apply modulo appropriately */
+ count_delta = ((int)count - (int)(q->count % 65536));
+ } while ((count_delta > 0) && (max_buf_done > 0));
}
int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -590,6 +601,25 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
}
}
+static void cx23885_clear_bridge_error(struct cx23885_dev *dev)
+{
+ uint32_t reg1_val = cx_read(TC_REQ); /* read-only */
+ uint32_t reg2_val = cx_read(TC_REQ_SET);
+
+ if (reg1_val && reg2_val) {
+ cx_write(TC_REQ, reg1_val);
+ cx_write(TC_REQ_SET, reg2_val);
+ cx_read(VID_B_DMA);
+ cx_read(VBI_B_DMA);
+ cx_read(VID_C_DMA);
+ cx_read(VBI_C_DMA);
+
+ dev_info(&dev->pci->dev,
+ "dma in progress detected 0x%08x 0x%08x, clearing\n",
+ reg1_val, reg2_val);
+ }
+}
+
static void cx23885_shutdown(struct cx23885_dev *dev)
{
/* disable RISC controller */
@@ -635,6 +665,8 @@ static void cx23885_reset(struct cx23885_dev *dev)
cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
cx_write(PAD_CTRL, 0x00500300);
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
mdelay(100);
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
@@ -651,6 +683,11 @@ static void cx23885_reset(struct cx23885_dev *dev)
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH09], 128, 0);
cx23885_gpio_setup(dev);
+
+ cx23885_irq_get_mask(dev);
+
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
}
@@ -665,6 +702,8 @@ static int cx23885_pci_quirks(struct cx23885_dev *dev)
if (dev->bridge == CX23885_BRIDGE_885)
cx_clear(RDR_TLCTL0, 1 << 4);
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
return 0;
}
@@ -1329,6 +1368,18 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__,
port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
+ dprintk(1, "%s() ts_int_status(0x%08X) 0x%08x\n", __func__,
+ port->reg_ts_int_stat, cx_read(port->reg_ts_int_stat));
+ dprintk(1, "%s() PCI_INT_STAT 0x%08X\n", __func__,
+ cx_read(PCI_INT_STAT));
+ dprintk(1, "%s() VID_B_INT_MSTAT 0x%08X\n", __func__,
+ cx_read(VID_B_INT_MSTAT));
+ dprintk(1, "%s() VID_B_INT_SSTAT 0x%08X\n", __func__,
+ cx_read(VID_B_INT_SSTAT));
+ dprintk(1, "%s() VID_C_INT_MSTAT 0x%08X\n", __func__,
+ cx_read(VID_C_INT_MSTAT));
+ dprintk(1, "%s() VID_C_INT_SSTAT 0x%08X\n", __func__,
+ cx_read(VID_C_INT_SSTAT));
}
int cx23885_start_dma(struct cx23885_tsport *port,
@@ -1341,6 +1392,9 @@ int cx23885_start_dma(struct cx23885_tsport *port,
dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
dev->width, dev->height, dev->field);
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
+
/* Stop the fifo and risc engine for this port */
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
@@ -1410,8 +1464,15 @@ int cx23885_start_dma(struct cx23885_tsport *port,
reg = reg | 0xa;
cx_write(PAD_CTRL, reg);
- /* FIXME and these two registers should be documented. */
+ /* Sets MOE_CLK_DIS to disable MoE clock */
+ /* sets MCLK_DLY_SEL/BCLK_DLY_SEL to 1 buffer delay each */
cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011);
+
+ /* ALT_GPIO_ALT_SET: GPIO[0]
+ * IR_ALT_TX_SEL: GPIO[1]
+ * GPIO1_ALT_SEL: VIP_656_DATA[0]
+ * GPIO0_ALT_SEL: VIP_656_CLK
+ */
cx_write(ALT_PIN_OUT_SEL, 0x10100045);
}
@@ -1421,16 +1482,26 @@ int cx23885_start_dma(struct cx23885_tsport *port,
case CX23885_BRIDGE_888:
/* enable irqs */
dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_set(port->reg_dma_ctl, port->dma_ctl_val);
+
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
cx23885_irq_add(dev, port->pci_irqmask);
cx23885_irq_enable_all(dev);
+
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
break;
default:
BUG();
}
cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
cx23885_av_clk(dev, 1);
@@ -1438,6 +1509,11 @@ int cx23885_start_dma(struct cx23885_tsport *port,
if (debug > 4)
cx23885_tsport_reg_dump(port);
+ cx23885_irq_get_mask(dev);
+
+ /* clear dma in progress */
+ cx23885_clear_bridge_error(dev);
+
return 0;
}
@@ -1445,15 +1521,28 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
u32 reg;
+ int delay = 0;
+ uint32_t reg1_val;
+ uint32_t reg2_val;
dprintk(1, "%s()\n", __func__);
/* Stop interrupts and DMA */
cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+ /* just in case wait for any dma to complete before allowing dealloc */
+ mdelay(20);
+ for (delay = 0; delay < 100; delay++) {
+ reg1_val = cx_read(TC_REQ);
+ reg2_val = cx_read(TC_REQ_SET);
+ if (reg1_val == 0 || reg2_val == 0)
+ break;
+ mdelay(1);
+ }
+ dev_dbg(&dev->pci->dev, "delay=%d reg1=0x%08x reg2=0x%08x\n",
+ delay, reg1_val, reg2_val);
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
-
reg = cx_read(PAD_CTRL);
/* Set TS1_OE */
@@ -1464,7 +1553,6 @@ static int cx23885_stop_dma(struct cx23885_tsport *port)
cx_write(PAD_CTRL, reg);
cx_write(port->reg_src_sel, 0);
cx_write(port->reg_gen_ctrl, 8);
-
}
if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
@@ -1693,6 +1781,12 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
pci_status = cx_read(PCI_INT_STAT);
pci_mask = cx23885_irq_get_mask(dev);
+ if ((pci_status & pci_mask) == 0) {
+ dprintk(7, "pci_status: 0x%08x pci_mask: 0x%08x\n",
+ pci_status, pci_mask);
+ goto out;
+ }
+
vida_status = cx_read(VID_A_INT_STAT);
vida_mask = cx_read(VID_A_INT_MSK);
audint_status = cx_read(AUDIO_INT_INT_STAT);
@@ -1702,7 +1796,9 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
ts2_status = cx_read(VID_C_INT_STAT);
ts2_mask = cx_read(VID_C_INT_MSK);
- if ((pci_status == 0) && (ts2_status == 0) && (ts1_status == 0))
+ if (((pci_status & pci_mask) == 0) &&
+ ((ts2_status & ts2_mask) == 0) &&
+ ((ts1_status & ts1_mask) == 0))
goto out;
vida_count = cx_read(VID_A_GPCNT);
@@ -1829,7 +1925,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
}
if (handled)
- cx_write(PCI_INT_STAT, pci_status);
+ cx_write(PCI_INT_STAT, pci_status & pci_mask);
out:
return IRQ_RETVAL(handled);
}