189ee7f4fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
225aee3deSMauro Carvalho Chehab /*
325aee3deSMauro Carvalho Chehab * ngene.c: nGene PCIe bridge driver
425aee3deSMauro Carvalho Chehab *
525aee3deSMauro Carvalho Chehab * Copyright (C) 2005-2007 Micronas
625aee3deSMauro Carvalho Chehab *
725aee3deSMauro Carvalho Chehab * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
825aee3deSMauro Carvalho Chehab * Modifications for new nGene firmware,
925aee3deSMauro Carvalho Chehab * support for EEPROM-copying,
1025aee3deSMauro Carvalho Chehab * support for new dual DVB-S2 card prototype
1125aee3deSMauro Carvalho Chehab */
1225aee3deSMauro Carvalho Chehab
1325aee3deSMauro Carvalho Chehab #include <linux/module.h>
1425aee3deSMauro Carvalho Chehab #include <linux/init.h>
1525aee3deSMauro Carvalho Chehab #include <linux/delay.h>
1625aee3deSMauro Carvalho Chehab #include <linux/poll.h>
1725aee3deSMauro Carvalho Chehab #include <linux/io.h>
1825aee3deSMauro Carvalho Chehab #include <asm/div64.h>
1925aee3deSMauro Carvalho Chehab #include <linux/pci.h>
2025aee3deSMauro Carvalho Chehab #include <linux/timer.h>
2125aee3deSMauro Carvalho Chehab #include <linux/byteorder/generic.h>
2225aee3deSMauro Carvalho Chehab #include <linux/firmware.h>
2325aee3deSMauro Carvalho Chehab #include <linux/vmalloc.h>
2425aee3deSMauro Carvalho Chehab
2525aee3deSMauro Carvalho Chehab #include "ngene.h"
2625aee3deSMauro Carvalho Chehab
2725aee3deSMauro Carvalho Chehab static int one_adapter;
2825aee3deSMauro Carvalho Chehab module_param(one_adapter, int, 0444);
2925aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(one_adapter, "Use only one adapter.");
3025aee3deSMauro Carvalho Chehab
3125aee3deSMauro Carvalho Chehab static int shutdown_workaround;
3225aee3deSMauro Carvalho Chehab module_param(shutdown_workaround, int, 0644);
3325aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(shutdown_workaround, "Activate workaround for shutdown problem with some chipsets.");
3425aee3deSMauro Carvalho Chehab
3525aee3deSMauro Carvalho Chehab static int debug;
3625aee3deSMauro Carvalho Chehab module_param(debug, int, 0444);
3725aee3deSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "Print debugging information.");
3825aee3deSMauro Carvalho Chehab
3925aee3deSMauro Carvalho Chehab DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
4025aee3deSMauro Carvalho Chehab
41c463c979SHans Verkuil #define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr))
42c463c979SHans Verkuil #define ngwritel(dat, adr) writel((dat), dev->iomem + (adr))
43c463c979SHans Verkuil #define ngwriteb(dat, adr) writeb((dat), dev->iomem + (adr))
4425aee3deSMauro Carvalho Chehab #define ngreadl(adr) readl(dev->iomem + (adr))
4525aee3deSMauro Carvalho Chehab #define ngreadb(adr) readb(dev->iomem + (adr))
46c463c979SHans Verkuil #define ngcpyto(adr, src, count) memcpy_toio(dev->iomem + (adr), (src), (count))
47c463c979SHans Verkuil #define ngcpyfrom(dst, adr, count) memcpy_fromio((dst), dev->iomem + (adr), (count))
4825aee3deSMauro Carvalho Chehab
4925aee3deSMauro Carvalho Chehab /****************************************************************************/
5025aee3deSMauro Carvalho Chehab /* nGene interrupt handler **************************************************/
5125aee3deSMauro Carvalho Chehab /****************************************************************************/
5225aee3deSMauro Carvalho Chehab
event_tasklet(struct tasklet_struct * t)536027ff6bSAllen Pais static void event_tasklet(struct tasklet_struct *t)
5425aee3deSMauro Carvalho Chehab {
556027ff6bSAllen Pais struct ngene *dev = from_tasklet(dev, t, event_tasklet);
5625aee3deSMauro Carvalho Chehab
5725aee3deSMauro Carvalho Chehab while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
5825aee3deSMauro Carvalho Chehab struct EVENT_BUFFER Event =
5925aee3deSMauro Carvalho Chehab dev->EventQueue[dev->EventQueueReadIndex];
6025aee3deSMauro Carvalho Chehab dev->EventQueueReadIndex =
6125aee3deSMauro Carvalho Chehab (dev->EventQueueReadIndex + 1) & (EVENT_QUEUE_SIZE - 1);
6225aee3deSMauro Carvalho Chehab
6325aee3deSMauro Carvalho Chehab if ((Event.UARTStatus & 0x01) && (dev->TxEventNotify))
6425aee3deSMauro Carvalho Chehab dev->TxEventNotify(dev, Event.TimeStamp);
6525aee3deSMauro Carvalho Chehab if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify))
6625aee3deSMauro Carvalho Chehab dev->RxEventNotify(dev, Event.TimeStamp,
6725aee3deSMauro Carvalho Chehab Event.RXCharacter);
6825aee3deSMauro Carvalho Chehab }
6925aee3deSMauro Carvalho Chehab }
7025aee3deSMauro Carvalho Chehab
demux_tasklet(struct tasklet_struct * t)716027ff6bSAllen Pais static void demux_tasklet(struct tasklet_struct *t)
7225aee3deSMauro Carvalho Chehab {
736027ff6bSAllen Pais struct ngene_channel *chan = from_tasklet(chan, t, demux_tasklet);
746795bf62SDaniel Scheller struct device *pdev = &chan->dev->pci_dev->dev;
7525aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = chan->nextBuffer;
7625aee3deSMauro Carvalho Chehab
7725aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock);
7825aee3deSMauro Carvalho Chehab
7925aee3deSMauro Carvalho Chehab while (Cur->ngeneBuffer.SR.Flags & 0x80) {
8025aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) {
8125aee3deSMauro Carvalho Chehab u32 Flags = chan->DataFormatFlags;
8225aee3deSMauro Carvalho Chehab if (Cur->ngeneBuffer.SR.Flags & 0x20)
8325aee3deSMauro Carvalho Chehab Flags |= BEF_OVERFLOW;
8425aee3deSMauro Carvalho Chehab if (chan->pBufferExchange) {
8525aee3deSMauro Carvalho Chehab if (!chan->pBufferExchange(chan,
8625aee3deSMauro Carvalho Chehab Cur->Buffer1,
8725aee3deSMauro Carvalho Chehab chan->Capture1Length,
8825aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.
8925aee3deSMauro Carvalho Chehab Clock, Flags)) {
9025aee3deSMauro Carvalho Chehab /*
9125aee3deSMauro Carvalho Chehab We didn't get data
9225aee3deSMauro Carvalho Chehab Clear in service flag to make sure we
9325aee3deSMauro Carvalho Chehab get called on next interrupt again.
9425aee3deSMauro Carvalho Chehab leave fill/empty (0x80) flag alone
9525aee3deSMauro Carvalho Chehab to avoid hardware running out of
9625aee3deSMauro Carvalho Chehab buffers during startup, we hold only
9725aee3deSMauro Carvalho Chehab in run state ( the source may be late
9825aee3deSMauro Carvalho Chehab delivering data )
9925aee3deSMauro Carvalho Chehab */
10025aee3deSMauro Carvalho Chehab
10125aee3deSMauro Carvalho Chehab if (chan->HWState == HWSTATE_RUN) {
10225aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Flags &=
10325aee3deSMauro Carvalho Chehab ~0x40;
10425aee3deSMauro Carvalho Chehab break;
10525aee3deSMauro Carvalho Chehab /* Stop processing stream */
10625aee3deSMauro Carvalho Chehab }
10725aee3deSMauro Carvalho Chehab } else {
10825aee3deSMauro Carvalho Chehab /* We got a valid buffer,
10925aee3deSMauro Carvalho Chehab so switch to run state */
11025aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_RUN;
11125aee3deSMauro Carvalho Chehab }
11225aee3deSMauro Carvalho Chehab } else {
1136795bf62SDaniel Scheller dev_err(pdev, "OOPS\n");
11425aee3deSMauro Carvalho Chehab if (chan->HWState == HWSTATE_RUN) {
11525aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Flags &= ~0x40;
11625aee3deSMauro Carvalho Chehab break; /* Stop processing stream */
11725aee3deSMauro Carvalho Chehab }
11825aee3deSMauro Carvalho Chehab }
11925aee3deSMauro Carvalho Chehab if (chan->AudioDTOUpdated) {
1206795bf62SDaniel Scheller dev_info(pdev, "Update AudioDTO = %d\n",
12125aee3deSMauro Carvalho Chehab chan->AudioDTOValue);
12225aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.DTOUpdate =
12325aee3deSMauro Carvalho Chehab chan->AudioDTOValue;
12425aee3deSMauro Carvalho Chehab chan->AudioDTOUpdated = 0;
12525aee3deSMauro Carvalho Chehab }
12625aee3deSMauro Carvalho Chehab } else {
12725aee3deSMauro Carvalho Chehab if (chan->HWState == HWSTATE_RUN) {
12825aee3deSMauro Carvalho Chehab u32 Flags = chan->DataFormatFlags;
12925aee3deSMauro Carvalho Chehab IBufferExchange *exch1 = chan->pBufferExchange;
13025aee3deSMauro Carvalho Chehab IBufferExchange *exch2 = chan->pBufferExchange2;
13125aee3deSMauro Carvalho Chehab if (Cur->ngeneBuffer.SR.Flags & 0x01)
13225aee3deSMauro Carvalho Chehab Flags |= BEF_EVEN_FIELD;
13325aee3deSMauro Carvalho Chehab if (Cur->ngeneBuffer.SR.Flags & 0x20)
13425aee3deSMauro Carvalho Chehab Flags |= BEF_OVERFLOW;
13525aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
13625aee3deSMauro Carvalho Chehab if (exch1)
13725aee3deSMauro Carvalho Chehab exch1(chan, Cur->Buffer1,
13825aee3deSMauro Carvalho Chehab chan->Capture1Length,
13925aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Clock,
14025aee3deSMauro Carvalho Chehab Flags);
14125aee3deSMauro Carvalho Chehab if (exch2)
14225aee3deSMauro Carvalho Chehab exch2(chan, Cur->Buffer2,
14325aee3deSMauro Carvalho Chehab chan->Capture2Length,
14425aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Clock,
14525aee3deSMauro Carvalho Chehab Flags);
14625aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock);
14725aee3deSMauro Carvalho Chehab } else if (chan->HWState != HWSTATE_STOP)
14825aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_RUN;
14925aee3deSMauro Carvalho Chehab }
15025aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.SR.Flags = 0x00;
15125aee3deSMauro Carvalho Chehab Cur = Cur->Next;
15225aee3deSMauro Carvalho Chehab }
15325aee3deSMauro Carvalho Chehab chan->nextBuffer = Cur;
15425aee3deSMauro Carvalho Chehab
15525aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
15625aee3deSMauro Carvalho Chehab }
15725aee3deSMauro Carvalho Chehab
irq_handler(int irq,void * dev_id)15825aee3deSMauro Carvalho Chehab static irqreturn_t irq_handler(int irq, void *dev_id)
15925aee3deSMauro Carvalho Chehab {
16025aee3deSMauro Carvalho Chehab struct ngene *dev = (struct ngene *)dev_id;
1616795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev;
16225aee3deSMauro Carvalho Chehab u32 icounts = 0;
16325aee3deSMauro Carvalho Chehab irqreturn_t rc = IRQ_NONE;
16425aee3deSMauro Carvalho Chehab u32 i = MAX_STREAM;
16525aee3deSMauro Carvalho Chehab u8 *tmpCmdDoneByte;
16625aee3deSMauro Carvalho Chehab
16725aee3deSMauro Carvalho Chehab if (dev->BootFirmware) {
16825aee3deSMauro Carvalho Chehab icounts = ngreadl(NGENE_INT_COUNTS);
16925aee3deSMauro Carvalho Chehab if (icounts != dev->icounts) {
17025aee3deSMauro Carvalho Chehab ngwritel(0, FORCE_NMI);
17125aee3deSMauro Carvalho Chehab dev->cmd_done = 1;
17225aee3deSMauro Carvalho Chehab wake_up(&dev->cmd_wq);
17325aee3deSMauro Carvalho Chehab dev->icounts = icounts;
17425aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED;
17525aee3deSMauro Carvalho Chehab }
17625aee3deSMauro Carvalho Chehab return rc;
17725aee3deSMauro Carvalho Chehab }
17825aee3deSMauro Carvalho Chehab
17925aee3deSMauro Carvalho Chehab ngwritel(0, FORCE_NMI);
18025aee3deSMauro Carvalho Chehab
18125aee3deSMauro Carvalho Chehab spin_lock(&dev->cmd_lock);
18225aee3deSMauro Carvalho Chehab tmpCmdDoneByte = dev->CmdDoneByte;
18325aee3deSMauro Carvalho Chehab if (tmpCmdDoneByte &&
18425aee3deSMauro Carvalho Chehab (*tmpCmdDoneByte ||
18525aee3deSMauro Carvalho Chehab (dev->ngenetohost[0] == 1 && dev->ngenetohost[1] != 0))) {
18625aee3deSMauro Carvalho Chehab dev->CmdDoneByte = NULL;
18725aee3deSMauro Carvalho Chehab dev->cmd_done = 1;
18825aee3deSMauro Carvalho Chehab wake_up(&dev->cmd_wq);
18925aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED;
19025aee3deSMauro Carvalho Chehab }
19125aee3deSMauro Carvalho Chehab spin_unlock(&dev->cmd_lock);
19225aee3deSMauro Carvalho Chehab
19325aee3deSMauro Carvalho Chehab if (dev->EventBuffer->EventStatus & 0x80) {
19425aee3deSMauro Carvalho Chehab u8 nextWriteIndex =
19525aee3deSMauro Carvalho Chehab (dev->EventQueueWriteIndex + 1) &
19625aee3deSMauro Carvalho Chehab (EVENT_QUEUE_SIZE - 1);
19725aee3deSMauro Carvalho Chehab if (nextWriteIndex != dev->EventQueueReadIndex) {
19825aee3deSMauro Carvalho Chehab dev->EventQueue[dev->EventQueueWriteIndex] =
19925aee3deSMauro Carvalho Chehab *(dev->EventBuffer);
20025aee3deSMauro Carvalho Chehab dev->EventQueueWriteIndex = nextWriteIndex;
20125aee3deSMauro Carvalho Chehab } else {
2026795bf62SDaniel Scheller dev_err(pdev, "event overflow\n");
20325aee3deSMauro Carvalho Chehab dev->EventQueueOverflowCount += 1;
20425aee3deSMauro Carvalho Chehab dev->EventQueueOverflowFlag = 1;
20525aee3deSMauro Carvalho Chehab }
20625aee3deSMauro Carvalho Chehab dev->EventBuffer->EventStatus &= ~0x80;
20725aee3deSMauro Carvalho Chehab tasklet_schedule(&dev->event_tasklet);
20825aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED;
20925aee3deSMauro Carvalho Chehab }
21025aee3deSMauro Carvalho Chehab
21125aee3deSMauro Carvalho Chehab while (i > 0) {
21225aee3deSMauro Carvalho Chehab i--;
21325aee3deSMauro Carvalho Chehab spin_lock(&dev->channel[i].state_lock);
21425aee3deSMauro Carvalho Chehab /* if (dev->channel[i].State>=KSSTATE_RUN) { */
21525aee3deSMauro Carvalho Chehab if (dev->channel[i].nextBuffer) {
21625aee3deSMauro Carvalho Chehab if ((dev->channel[i].nextBuffer->
21725aee3deSMauro Carvalho Chehab ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
21825aee3deSMauro Carvalho Chehab dev->channel[i].nextBuffer->
21925aee3deSMauro Carvalho Chehab ngeneBuffer.SR.Flags |= 0x40;
22025aee3deSMauro Carvalho Chehab tasklet_schedule(
22125aee3deSMauro Carvalho Chehab &dev->channel[i].demux_tasklet);
22225aee3deSMauro Carvalho Chehab rc = IRQ_HANDLED;
22325aee3deSMauro Carvalho Chehab }
22425aee3deSMauro Carvalho Chehab }
22525aee3deSMauro Carvalho Chehab spin_unlock(&dev->channel[i].state_lock);
22625aee3deSMauro Carvalho Chehab }
22725aee3deSMauro Carvalho Chehab
22825aee3deSMauro Carvalho Chehab /* Request might have been processed by a previous call. */
22925aee3deSMauro Carvalho Chehab return IRQ_HANDLED;
23025aee3deSMauro Carvalho Chehab }
23125aee3deSMauro Carvalho Chehab
23225aee3deSMauro Carvalho Chehab /****************************************************************************/
23325aee3deSMauro Carvalho Chehab /* nGene command interface **************************************************/
23425aee3deSMauro Carvalho Chehab /****************************************************************************/
23525aee3deSMauro Carvalho Chehab
dump_command_io(struct ngene * dev)23625aee3deSMauro Carvalho Chehab static void dump_command_io(struct ngene *dev)
23725aee3deSMauro Carvalho Chehab {
2386795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev;
23925aee3deSMauro Carvalho Chehab u8 buf[8], *b;
24025aee3deSMauro Carvalho Chehab
24125aee3deSMauro Carvalho Chehab ngcpyfrom(buf, HOST_TO_NGENE, 8);
2426795bf62SDaniel Scheller dev_err(pdev, "host_to_ngene (%04x): %*ph\n", HOST_TO_NGENE, 8, buf);
24325aee3deSMauro Carvalho Chehab
24425aee3deSMauro Carvalho Chehab ngcpyfrom(buf, NGENE_TO_HOST, 8);
2456795bf62SDaniel Scheller dev_err(pdev, "ngene_to_host (%04x): %*ph\n", NGENE_TO_HOST, 8, buf);
24625aee3deSMauro Carvalho Chehab
24725aee3deSMauro Carvalho Chehab b = dev->hosttongene;
2486795bf62SDaniel Scheller dev_err(pdev, "dev->hosttongene (%p): %*ph\n", b, 8, b);
24925aee3deSMauro Carvalho Chehab
25025aee3deSMauro Carvalho Chehab b = dev->ngenetohost;
2516795bf62SDaniel Scheller dev_err(pdev, "dev->ngenetohost (%p): %*ph\n", b, 8, b);
25225aee3deSMauro Carvalho Chehab }
25325aee3deSMauro Carvalho Chehab
ngene_command_mutex(struct ngene * dev,struct ngene_command * com)25425aee3deSMauro Carvalho Chehab static int ngene_command_mutex(struct ngene *dev, struct ngene_command *com)
25525aee3deSMauro Carvalho Chehab {
2566795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev;
25725aee3deSMauro Carvalho Chehab int ret;
25825aee3deSMauro Carvalho Chehab u8 *tmpCmdDoneByte;
25925aee3deSMauro Carvalho Chehab
26025aee3deSMauro Carvalho Chehab dev->cmd_done = 0;
26125aee3deSMauro Carvalho Chehab
26225aee3deSMauro Carvalho Chehab if (com->cmd.hdr.Opcode == CMD_FWLOAD_PREPARE) {
26325aee3deSMauro Carvalho Chehab dev->BootFirmware = 1;
26425aee3deSMauro Carvalho Chehab dev->icounts = ngreadl(NGENE_INT_COUNTS);
26525aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND);
26625aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND_HI);
26725aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS);
26825aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS_HI);
26925aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT);
27025aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT_HI);
27125aee3deSMauro Carvalho Chehab } else if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH) {
27225aee3deSMauro Carvalho Chehab u64 fwio = dev->PAFWInterfaceBuffer;
27325aee3deSMauro Carvalho Chehab
27425aee3deSMauro Carvalho Chehab ngwritel(fwio & 0xffffffff, NGENE_COMMAND);
27525aee3deSMauro Carvalho Chehab ngwritel(fwio >> 32, NGENE_COMMAND_HI);
27625aee3deSMauro Carvalho Chehab ngwritel((fwio + 256) & 0xffffffff, NGENE_STATUS);
27725aee3deSMauro Carvalho Chehab ngwritel((fwio + 256) >> 32, NGENE_STATUS_HI);
27825aee3deSMauro Carvalho Chehab ngwritel((fwio + 512) & 0xffffffff, NGENE_EVENT);
27925aee3deSMauro Carvalho Chehab ngwritel((fwio + 512) >> 32, NGENE_EVENT_HI);
28025aee3deSMauro Carvalho Chehab }
28125aee3deSMauro Carvalho Chehab
28225aee3deSMauro Carvalho Chehab memcpy(dev->FWInterfaceBuffer, com->cmd.raw8, com->in_len + 2);
28325aee3deSMauro Carvalho Chehab
28425aee3deSMauro Carvalho Chehab if (dev->BootFirmware)
28525aee3deSMauro Carvalho Chehab ngcpyto(HOST_TO_NGENE, com->cmd.raw8, com->in_len + 2);
28625aee3deSMauro Carvalho Chehab
28725aee3deSMauro Carvalho Chehab spin_lock_irq(&dev->cmd_lock);
28825aee3deSMauro Carvalho Chehab tmpCmdDoneByte = dev->ngenetohost + com->out_len;
28925aee3deSMauro Carvalho Chehab if (!com->out_len)
29025aee3deSMauro Carvalho Chehab tmpCmdDoneByte++;
29125aee3deSMauro Carvalho Chehab *tmpCmdDoneByte = 0;
29225aee3deSMauro Carvalho Chehab dev->ngenetohost[0] = 0;
29325aee3deSMauro Carvalho Chehab dev->ngenetohost[1] = 0;
29425aee3deSMauro Carvalho Chehab dev->CmdDoneByte = tmpCmdDoneByte;
29525aee3deSMauro Carvalho Chehab spin_unlock_irq(&dev->cmd_lock);
29625aee3deSMauro Carvalho Chehab
29725aee3deSMauro Carvalho Chehab /* Notify 8051. */
29825aee3deSMauro Carvalho Chehab ngwritel(1, FORCE_INT);
29925aee3deSMauro Carvalho Chehab
30025aee3deSMauro Carvalho Chehab ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ);
30125aee3deSMauro Carvalho Chehab if (!ret) {
30225aee3deSMauro Carvalho Chehab /*ngwritel(0, FORCE_NMI);*/
30325aee3deSMauro Carvalho Chehab
3046795bf62SDaniel Scheller dev_err(pdev, "Command timeout cmd=%02x prev=%02x\n",
30525aee3deSMauro Carvalho Chehab com->cmd.hdr.Opcode, dev->prev_cmd);
30625aee3deSMauro Carvalho Chehab dump_command_io(dev);
30725aee3deSMauro Carvalho Chehab return -1;
30825aee3deSMauro Carvalho Chehab }
30925aee3deSMauro Carvalho Chehab if (com->cmd.hdr.Opcode == CMD_FWLOAD_FINISH)
31025aee3deSMauro Carvalho Chehab dev->BootFirmware = 0;
31125aee3deSMauro Carvalho Chehab
31225aee3deSMauro Carvalho Chehab dev->prev_cmd = com->cmd.hdr.Opcode;
31325aee3deSMauro Carvalho Chehab
31425aee3deSMauro Carvalho Chehab if (!com->out_len)
31525aee3deSMauro Carvalho Chehab return 0;
31625aee3deSMauro Carvalho Chehab
31725aee3deSMauro Carvalho Chehab memcpy(com->cmd.raw8, dev->ngenetohost, com->out_len);
31825aee3deSMauro Carvalho Chehab
31925aee3deSMauro Carvalho Chehab return 0;
32025aee3deSMauro Carvalho Chehab }
32125aee3deSMauro Carvalho Chehab
ngene_command(struct ngene * dev,struct ngene_command * com)32225aee3deSMauro Carvalho Chehab int ngene_command(struct ngene *dev, struct ngene_command *com)
32325aee3deSMauro Carvalho Chehab {
32425aee3deSMauro Carvalho Chehab int result;
32525aee3deSMauro Carvalho Chehab
3261439cdb0SBinoy Jayan mutex_lock(&dev->cmd_mutex);
32725aee3deSMauro Carvalho Chehab result = ngene_command_mutex(dev, com);
3281439cdb0SBinoy Jayan mutex_unlock(&dev->cmd_mutex);
32925aee3deSMauro Carvalho Chehab return result;
33025aee3deSMauro Carvalho Chehab }
33125aee3deSMauro Carvalho Chehab
33225aee3deSMauro Carvalho Chehab
ngene_command_load_firmware(struct ngene * dev,u8 * ngene_fw,u32 size)33325aee3deSMauro Carvalho Chehab static int ngene_command_load_firmware(struct ngene *dev,
33425aee3deSMauro Carvalho Chehab u8 *ngene_fw, u32 size)
33525aee3deSMauro Carvalho Chehab {
33625aee3deSMauro Carvalho Chehab #define FIRSTCHUNK (1024)
33725aee3deSMauro Carvalho Chehab u32 cleft;
33825aee3deSMauro Carvalho Chehab struct ngene_command com;
33925aee3deSMauro Carvalho Chehab
34025aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_FWLOAD_PREPARE;
34125aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 0;
34225aee3deSMauro Carvalho Chehab com.in_len = 0;
34325aee3deSMauro Carvalho Chehab com.out_len = 0;
34425aee3deSMauro Carvalho Chehab
34525aee3deSMauro Carvalho Chehab ngene_command(dev, &com);
34625aee3deSMauro Carvalho Chehab
34725aee3deSMauro Carvalho Chehab cleft = (size + 3) & ~3;
34825aee3deSMauro Carvalho Chehab if (cleft > FIRSTCHUNK) {
34925aee3deSMauro Carvalho Chehab ngcpyto(PROGRAM_SRAM + FIRSTCHUNK, ngene_fw + FIRSTCHUNK,
35025aee3deSMauro Carvalho Chehab cleft - FIRSTCHUNK);
35125aee3deSMauro Carvalho Chehab cleft = FIRSTCHUNK;
35225aee3deSMauro Carvalho Chehab }
35325aee3deSMauro Carvalho Chehab ngcpyto(DATA_FIFO_AREA, ngene_fw, cleft);
35425aee3deSMauro Carvalho Chehab
35525aee3deSMauro Carvalho Chehab memset(&com, 0, sizeof(struct ngene_command));
35625aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_FWLOAD_FINISH;
35725aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 4;
35825aee3deSMauro Carvalho Chehab com.cmd.FWLoadFinish.Address = DATA_FIFO_AREA;
35925aee3deSMauro Carvalho Chehab com.cmd.FWLoadFinish.Length = (unsigned short)cleft;
36025aee3deSMauro Carvalho Chehab com.in_len = 4;
36125aee3deSMauro Carvalho Chehab com.out_len = 0;
36225aee3deSMauro Carvalho Chehab
36325aee3deSMauro Carvalho Chehab return ngene_command(dev, &com);
36425aee3deSMauro Carvalho Chehab }
36525aee3deSMauro Carvalho Chehab
36625aee3deSMauro Carvalho Chehab
ngene_command_config_buf(struct ngene * dev,u8 config)36725aee3deSMauro Carvalho Chehab static int ngene_command_config_buf(struct ngene *dev, u8 config)
36825aee3deSMauro Carvalho Chehab {
36925aee3deSMauro Carvalho Chehab struct ngene_command com;
37025aee3deSMauro Carvalho Chehab
37125aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_CONFIGURE_BUFFER;
37225aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 1;
37325aee3deSMauro Carvalho Chehab com.cmd.ConfigureBuffers.config = config;
37425aee3deSMauro Carvalho Chehab com.in_len = 1;
37525aee3deSMauro Carvalho Chehab com.out_len = 0;
37625aee3deSMauro Carvalho Chehab
37725aee3deSMauro Carvalho Chehab if (ngene_command(dev, &com) < 0)
37825aee3deSMauro Carvalho Chehab return -EIO;
37925aee3deSMauro Carvalho Chehab return 0;
38025aee3deSMauro Carvalho Chehab }
38125aee3deSMauro Carvalho Chehab
ngene_command_config_free_buf(struct ngene * dev,u8 * config)38225aee3deSMauro Carvalho Chehab static int ngene_command_config_free_buf(struct ngene *dev, u8 *config)
38325aee3deSMauro Carvalho Chehab {
38425aee3deSMauro Carvalho Chehab struct ngene_command com;
38525aee3deSMauro Carvalho Chehab
38625aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_CONFIGURE_FREE_BUFFER;
38725aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 6;
3888d4abca9SGustavo A. R. Silva memcpy(&com.cmd.ConfigureFreeBuffers.config, config, 6);
38925aee3deSMauro Carvalho Chehab com.in_len = 6;
39025aee3deSMauro Carvalho Chehab com.out_len = 0;
39125aee3deSMauro Carvalho Chehab
39225aee3deSMauro Carvalho Chehab if (ngene_command(dev, &com) < 0)
39325aee3deSMauro Carvalho Chehab return -EIO;
39425aee3deSMauro Carvalho Chehab
39525aee3deSMauro Carvalho Chehab return 0;
39625aee3deSMauro Carvalho Chehab }
39725aee3deSMauro Carvalho Chehab
ngene_command_gpio_set(struct ngene * dev,u8 select,u8 level)39825aee3deSMauro Carvalho Chehab int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level)
39925aee3deSMauro Carvalho Chehab {
40025aee3deSMauro Carvalho Chehab struct ngene_command com;
40125aee3deSMauro Carvalho Chehab
40225aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_SET_GPIO_PIN;
40325aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 1;
40425aee3deSMauro Carvalho Chehab com.cmd.SetGpioPin.select = select | (level << 7);
40525aee3deSMauro Carvalho Chehab com.in_len = 1;
40625aee3deSMauro Carvalho Chehab com.out_len = 0;
40725aee3deSMauro Carvalho Chehab
40825aee3deSMauro Carvalho Chehab return ngene_command(dev, &com);
40925aee3deSMauro Carvalho Chehab }
41025aee3deSMauro Carvalho Chehab
41125aee3deSMauro Carvalho Chehab
41225aee3deSMauro Carvalho Chehab /*
41325aee3deSMauro Carvalho Chehab 02000640 is sample on rising edge.
41425aee3deSMauro Carvalho Chehab 02000740 is sample on falling edge.
41525aee3deSMauro Carvalho Chehab 02000040 is ignore "valid" signal
41625aee3deSMauro Carvalho Chehab
41725aee3deSMauro Carvalho Chehab 0: FD_CTL1 Bit 7,6 must be 0,1
41825aee3deSMauro Carvalho Chehab 7 disable(fw controlled)
41925aee3deSMauro Carvalho Chehab 6 0-AUX,1-TS
42025aee3deSMauro Carvalho Chehab 5 0-par,1-ser
42125aee3deSMauro Carvalho Chehab 4 0-lsb/1-msb
42225aee3deSMauro Carvalho Chehab 3,2 reserved
42325aee3deSMauro Carvalho Chehab 1,0 0-no sync, 1-use ext. start, 2-use 0x47, 3-both
42425aee3deSMauro Carvalho Chehab 1: FD_CTL2 has 3-valid must be hi, 2-use valid, 1-edge
42525aee3deSMauro Carvalho Chehab 2: FD_STA is read-only. 0-sync
42625aee3deSMauro Carvalho Chehab 3: FD_INSYNC is number of 47s to trigger "in sync".
42725aee3deSMauro Carvalho Chehab 4: FD_OUTSYNC is number of 47s to trigger "out of sync".
42825aee3deSMauro Carvalho Chehab 5: FD_MAXBYTE1 is low-order of bytes per packet.
42925aee3deSMauro Carvalho Chehab 6: FD_MAXBYTE2 is high-order of bytes per packet.
43025aee3deSMauro Carvalho Chehab 7: Top byte is unused.
43125aee3deSMauro Carvalho Chehab */
43225aee3deSMauro Carvalho Chehab
43325aee3deSMauro Carvalho Chehab /****************************************************************************/
43425aee3deSMauro Carvalho Chehab
43525aee3deSMauro Carvalho Chehab static u8 TSFeatureDecoderSetup[8 * 5] = {
43625aee3deSMauro Carvalho Chehab 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00,
43725aee3deSMauro Carvalho Chehab 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */
43825aee3deSMauro Carvalho Chehab 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */
43925aee3deSMauro Carvalho Chehab 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */
44025aee3deSMauro Carvalho Chehab 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */
44125aee3deSMauro Carvalho Chehab };
44225aee3deSMauro Carvalho Chehab
44325aee3deSMauro Carvalho Chehab /* Set NGENE I2S Config to 16 bit packed */
44425aee3deSMauro Carvalho Chehab static u8 I2SConfiguration[] = {
44525aee3deSMauro Carvalho Chehab 0x00, 0x10, 0x00, 0x00,
44625aee3deSMauro Carvalho Chehab 0x80, 0x10, 0x00, 0x00,
44725aee3deSMauro Carvalho Chehab };
44825aee3deSMauro Carvalho Chehab
44925aee3deSMauro Carvalho Chehab static u8 SPDIFConfiguration[10] = {
45025aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
45125aee3deSMauro Carvalho Chehab };
45225aee3deSMauro Carvalho Chehab
45325aee3deSMauro Carvalho Chehab /* Set NGENE I2S Config to transport stream compatible mode */
45425aee3deSMauro Carvalho Chehab
45525aee3deSMauro Carvalho Chehab static u8 TS_I2SConfiguration[4] = { 0x3E, 0x18, 0x00, 0x00 };
45625aee3deSMauro Carvalho Chehab
45725aee3deSMauro Carvalho Chehab static u8 TS_I2SOutConfiguration[4] = { 0x80, 0x04, 0x00, 0x00 };
45825aee3deSMauro Carvalho Chehab
45925aee3deSMauro Carvalho Chehab static u8 ITUDecoderSetup[4][16] = {
46025aee3deSMauro Carvalho Chehab {0x1c, 0x13, 0x01, 0x68, 0x3d, 0x90, 0x14, 0x20, /* SDTV */
46125aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x01, 0xb0, 0x9c, 0x00, 0x00, 0x00},
46225aee3deSMauro Carvalho Chehab {0x9c, 0x03, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00,
46325aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
46425aee3deSMauro Carvalho Chehab {0x9f, 0x00, 0x23, 0xC0, 0x60, 0x0F, 0x13, 0x00, /* HDTV 1080i50 */
46525aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
46625aee3deSMauro Carvalho Chehab {0x9c, 0x01, 0x23, 0xC0, 0x60, 0x0E, 0x13, 0x00, /* HDTV 1080i60 */
46725aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x01, 0xB0, 0x00, 0x00, 0x00},
46825aee3deSMauro Carvalho Chehab };
46925aee3deSMauro Carvalho Chehab
47025aee3deSMauro Carvalho Chehab /*
47125aee3deSMauro Carvalho Chehab * 50 48 60 gleich
47225aee3deSMauro Carvalho Chehab * 27p50 9f 00 22 80 42 69 18 ...
47325aee3deSMauro Carvalho Chehab * 27p60 93 00 22 80 82 69 1c ...
47425aee3deSMauro Carvalho Chehab */
47525aee3deSMauro Carvalho Chehab
47625aee3deSMauro Carvalho Chehab /* Maxbyte to 1144 (for raw data) */
47725aee3deSMauro Carvalho Chehab static u8 ITUFeatureDecoderSetup[8] = {
47825aee3deSMauro Carvalho Chehab 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x04, 0x00
47925aee3deSMauro Carvalho Chehab };
48025aee3deSMauro Carvalho Chehab
FillTSBuffer(void * Buffer,int Length,u32 Flags)48125aee3deSMauro Carvalho Chehab void FillTSBuffer(void *Buffer, int Length, u32 Flags)
48225aee3deSMauro Carvalho Chehab {
48325aee3deSMauro Carvalho Chehab u32 *ptr = Buffer;
48425aee3deSMauro Carvalho Chehab
48525aee3deSMauro Carvalho Chehab memset(Buffer, TS_FILLER, Length);
48625aee3deSMauro Carvalho Chehab while (Length > 0) {
48725aee3deSMauro Carvalho Chehab if (Flags & DF_SWAP32)
48825aee3deSMauro Carvalho Chehab *ptr = 0x471FFF10;
48925aee3deSMauro Carvalho Chehab else
49025aee3deSMauro Carvalho Chehab *ptr = 0x10FF1F47;
49125aee3deSMauro Carvalho Chehab ptr += (188 / 4);
49225aee3deSMauro Carvalho Chehab Length -= 188;
49325aee3deSMauro Carvalho Chehab }
49425aee3deSMauro Carvalho Chehab }
49525aee3deSMauro Carvalho Chehab
49625aee3deSMauro Carvalho Chehab
flush_buffers(struct ngene_channel * chan)49725aee3deSMauro Carvalho Chehab static void flush_buffers(struct ngene_channel *chan)
49825aee3deSMauro Carvalho Chehab {
49925aee3deSMauro Carvalho Chehab u8 val;
50025aee3deSMauro Carvalho Chehab
50125aee3deSMauro Carvalho Chehab do {
50225aee3deSMauro Carvalho Chehab msleep(1);
50325aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock);
50425aee3deSMauro Carvalho Chehab val = chan->nextBuffer->ngeneBuffer.SR.Flags & 0x80;
50525aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
50625aee3deSMauro Carvalho Chehab } while (val);
50725aee3deSMauro Carvalho Chehab }
50825aee3deSMauro Carvalho Chehab
clear_buffers(struct ngene_channel * chan)50925aee3deSMauro Carvalho Chehab static void clear_buffers(struct ngene_channel *chan)
51025aee3deSMauro Carvalho Chehab {
51125aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = chan->nextBuffer;
51225aee3deSMauro Carvalho Chehab
51325aee3deSMauro Carvalho Chehab do {
51425aee3deSMauro Carvalho Chehab memset(&Cur->ngeneBuffer.SR, 0, sizeof(Cur->ngeneBuffer.SR));
51525aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT)
51625aee3deSMauro Carvalho Chehab FillTSBuffer(Cur->Buffer1,
51725aee3deSMauro Carvalho Chehab chan->Capture1Length,
51825aee3deSMauro Carvalho Chehab chan->DataFormatFlags);
51925aee3deSMauro Carvalho Chehab Cur = Cur->Next;
52025aee3deSMauro Carvalho Chehab } while (Cur != chan->nextBuffer);
52125aee3deSMauro Carvalho Chehab
52225aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) {
52325aee3deSMauro Carvalho Chehab chan->nextBuffer->ngeneBuffer.SR.DTOUpdate =
52425aee3deSMauro Carvalho Chehab chan->AudioDTOValue;
52525aee3deSMauro Carvalho Chehab chan->AudioDTOUpdated = 0;
52625aee3deSMauro Carvalho Chehab
52725aee3deSMauro Carvalho Chehab Cur = chan->TSIdleBuffer.Head;
52825aee3deSMauro Carvalho Chehab
52925aee3deSMauro Carvalho Chehab do {
53025aee3deSMauro Carvalho Chehab memset(&Cur->ngeneBuffer.SR, 0,
53125aee3deSMauro Carvalho Chehab sizeof(Cur->ngeneBuffer.SR));
53225aee3deSMauro Carvalho Chehab FillTSBuffer(Cur->Buffer1,
53325aee3deSMauro Carvalho Chehab chan->Capture1Length,
53425aee3deSMauro Carvalho Chehab chan->DataFormatFlags);
53525aee3deSMauro Carvalho Chehab Cur = Cur->Next;
53625aee3deSMauro Carvalho Chehab } while (Cur != chan->TSIdleBuffer.Head);
53725aee3deSMauro Carvalho Chehab }
53825aee3deSMauro Carvalho Chehab }
53925aee3deSMauro Carvalho Chehab
ngene_command_stream_control(struct ngene * dev,u8 stream,u8 control,u8 mode,u8 flags)54025aee3deSMauro Carvalho Chehab static int ngene_command_stream_control(struct ngene *dev, u8 stream,
54125aee3deSMauro Carvalho Chehab u8 control, u8 mode, u8 flags)
54225aee3deSMauro Carvalho Chehab {
5436795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev;
54425aee3deSMauro Carvalho Chehab struct ngene_channel *chan = &dev->channel[stream];
54525aee3deSMauro Carvalho Chehab struct ngene_command com;
54625aee3deSMauro Carvalho Chehab u16 BsUVI = ((stream & 1) ? 0x9400 : 0x9300);
54725aee3deSMauro Carvalho Chehab u16 BsSDI = ((stream & 1) ? 0x9600 : 0x9500);
54825aee3deSMauro Carvalho Chehab u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
54925aee3deSMauro Carvalho Chehab u16 BsSDO = 0x9B00;
55025aee3deSMauro Carvalho Chehab
55125aee3deSMauro Carvalho Chehab memset(&com, 0, sizeof(com));
55225aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_CONTROL;
55325aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
55425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream = stream | (control ? 8 : 0);
55525aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT)
55625aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream |= 0x07;
55725aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Control = control |
55825aee3deSMauro Carvalho Chehab (flags & SFLAG_ORDER_LUMA_CHROMA);
55925aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Mode = mode;
56025aee3deSMauro Carvalho Chehab com.in_len = sizeof(struct FW_STREAM_CONTROL);
56125aee3deSMauro Carvalho Chehab com.out_len = 0;
56225aee3deSMauro Carvalho Chehab
5636795bf62SDaniel Scheller dev_dbg(pdev, "Stream=%02x, Control=%02x, Mode=%02x\n",
56425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream, com.cmd.StreamControl.Control,
56525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Mode);
56625aee3deSMauro Carvalho Chehab
56725aee3deSMauro Carvalho Chehab chan->Mode = mode;
56825aee3deSMauro Carvalho Chehab
56925aee3deSMauro Carvalho Chehab if (!(control & 0x80)) {
57025aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock);
57125aee3deSMauro Carvalho Chehab if (chan->State == KSSTATE_RUN) {
57225aee3deSMauro Carvalho Chehab chan->State = KSSTATE_ACQUIRE;
57325aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_STOP;
57425aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
57590979f04SBinoy Jayan if (ngene_command(dev, &com) < 0)
57625aee3deSMauro Carvalho Chehab return -1;
57725aee3deSMauro Carvalho Chehab /* clear_buffers(chan); */
57825aee3deSMauro Carvalho Chehab flush_buffers(chan);
57925aee3deSMauro Carvalho Chehab return 0;
58025aee3deSMauro Carvalho Chehab }
58125aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
58225aee3deSMauro Carvalho Chehab return 0;
58325aee3deSMauro Carvalho Chehab }
58425aee3deSMauro Carvalho Chehab
58525aee3deSMauro Carvalho Chehab if (mode & SMODE_AUDIO_CAPTURE) {
58625aee3deSMauro Carvalho Chehab com.cmd.StreamControl.CaptureBlockCount =
58725aee3deSMauro Carvalho Chehab chan->Capture1Length / AUDIO_BLOCK_SIZE;
58825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
58925aee3deSMauro Carvalho Chehab } else if (mode & SMODE_TRANSPORT_STREAM) {
59025aee3deSMauro Carvalho Chehab com.cmd.StreamControl.CaptureBlockCount =
59125aee3deSMauro Carvalho Chehab chan->Capture1Length / TS_BLOCK_SIZE;
59225aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MaxLinesPerField =
59325aee3deSMauro Carvalho Chehab chan->Capture1Length / TS_BLOCK_SIZE;
59425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Buffer_Address =
59525aee3deSMauro Carvalho Chehab chan->TSRingBuffer.PAHead;
59625aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) {
59725aee3deSMauro Carvalho Chehab com.cmd.StreamControl.BytesPerVBILine =
59825aee3deSMauro Carvalho Chehab chan->Capture1Length / TS_BLOCK_SIZE;
59925aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream |= 0x07;
60025aee3deSMauro Carvalho Chehab }
60125aee3deSMauro Carvalho Chehab } else {
60225aee3deSMauro Carvalho Chehab com.cmd.StreamControl.BytesPerVideoLine = chan->nBytesPerLine;
60325aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MaxLinesPerField = chan->nLines;
60425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MinLinesPerField = 100;
60525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Buffer_Address = chan->RingBuffer.PAHead;
60625aee3deSMauro Carvalho Chehab
60725aee3deSMauro Carvalho Chehab if (mode & SMODE_VBI_CAPTURE) {
60825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MaxVBILinesPerField =
60925aee3deSMauro Carvalho Chehab chan->nVBILines;
61025aee3deSMauro Carvalho Chehab com.cmd.StreamControl.MinVBILinesPerField = 0;
61125aee3deSMauro Carvalho Chehab com.cmd.StreamControl.BytesPerVBILine =
61225aee3deSMauro Carvalho Chehab chan->nBytesPerVBILine;
61325aee3deSMauro Carvalho Chehab }
61425aee3deSMauro Carvalho Chehab if (flags & SFLAG_COLORBAR)
61525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.Stream |= 0x04;
61625aee3deSMauro Carvalho Chehab }
61725aee3deSMauro Carvalho Chehab
61825aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock);
61925aee3deSMauro Carvalho Chehab if (mode & SMODE_AUDIO_CAPTURE) {
62025aee3deSMauro Carvalho Chehab chan->nextBuffer = chan->RingBuffer.Head;
62125aee3deSMauro Carvalho Chehab if (mode & SMODE_AUDIO_SPDIF) {
62225aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen =
62325aee3deSMauro Carvalho Chehab sizeof(SPDIFConfiguration);
62425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSPI;
62525aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData,
62625aee3deSMauro Carvalho Chehab SPDIFConfiguration, sizeof(SPDIFConfiguration));
62725aee3deSMauro Carvalho Chehab } else {
62825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 4;
62925aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSDI;
63025aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData,
63125aee3deSMauro Carvalho Chehab I2SConfiguration +
63225aee3deSMauro Carvalho Chehab 4 * dev->card_info->i2s[stream], 4);
63325aee3deSMauro Carvalho Chehab }
63425aee3deSMauro Carvalho Chehab } else if (mode & SMODE_TRANSPORT_STREAM) {
63525aee3deSMauro Carvalho Chehab chan->nextBuffer = chan->TSRingBuffer.Head;
63625aee3deSMauro Carvalho Chehab if (stream >= STREAM_AUDIOIN1) {
63725aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) {
63825aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen =
63925aee3deSMauro Carvalho Chehab sizeof(TS_I2SOutConfiguration);
64025aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSDO;
64125aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData,
64225aee3deSMauro Carvalho Chehab TS_I2SOutConfiguration,
64325aee3deSMauro Carvalho Chehab sizeof(TS_I2SOutConfiguration));
64425aee3deSMauro Carvalho Chehab } else {
64525aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen =
64625aee3deSMauro Carvalho Chehab sizeof(TS_I2SConfiguration);
64725aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsSDI;
64825aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData,
64925aee3deSMauro Carvalho Chehab TS_I2SConfiguration,
65025aee3deSMauro Carvalho Chehab sizeof(TS_I2SConfiguration));
65125aee3deSMauro Carvalho Chehab }
65225aee3deSMauro Carvalho Chehab } else {
65325aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen = 8;
65425aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsUVI + 0x10;
65525aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData,
65625aee3deSMauro Carvalho Chehab TSFeatureDecoderSetup +
65725aee3deSMauro Carvalho Chehab 8 * dev->card_info->tsf[stream], 8);
65825aee3deSMauro Carvalho Chehab }
65925aee3deSMauro Carvalho Chehab } else {
66025aee3deSMauro Carvalho Chehab chan->nextBuffer = chan->RingBuffer.Head;
66125aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataLen =
66225aee3deSMauro Carvalho Chehab 16 + sizeof(ITUFeatureDecoderSetup);
66325aee3deSMauro Carvalho Chehab com.cmd.StreamControl.SetupDataAddr = BsUVI;
66425aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData,
66525aee3deSMauro Carvalho Chehab ITUDecoderSetup[chan->itumode], 16);
66625aee3deSMauro Carvalho Chehab memcpy(com.cmd.StreamControl.SetupData + 16,
66725aee3deSMauro Carvalho Chehab ITUFeatureDecoderSetup, sizeof(ITUFeatureDecoderSetup));
66825aee3deSMauro Carvalho Chehab }
66925aee3deSMauro Carvalho Chehab clear_buffers(chan);
67025aee3deSMauro Carvalho Chehab chan->State = KSSTATE_RUN;
67125aee3deSMauro Carvalho Chehab if (mode & SMODE_TRANSPORT_STREAM)
67225aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_RUN;
67325aee3deSMauro Carvalho Chehab else
67425aee3deSMauro Carvalho Chehab chan->HWState = HWSTATE_STARTUP;
67525aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
67625aee3deSMauro Carvalho Chehab
67790979f04SBinoy Jayan if (ngene_command(dev, &com) < 0)
67825aee3deSMauro Carvalho Chehab return -1;
67990979f04SBinoy Jayan
68025aee3deSMauro Carvalho Chehab return 0;
68125aee3deSMauro Carvalho Chehab }
68225aee3deSMauro Carvalho Chehab
set_transfer(struct ngene_channel * chan,int state)68325aee3deSMauro Carvalho Chehab void set_transfer(struct ngene_channel *chan, int state)
68425aee3deSMauro Carvalho Chehab {
6856795bf62SDaniel Scheller struct device *pdev = &chan->dev->pci_dev->dev;
68625aee3deSMauro Carvalho Chehab u8 control = 0, mode = 0, flags = 0;
68725aee3deSMauro Carvalho Chehab struct ngene *dev = chan->dev;
68825aee3deSMauro Carvalho Chehab int ret;
68925aee3deSMauro Carvalho Chehab
69025aee3deSMauro Carvalho Chehab /*
6916795bf62SDaniel Scheller dev_info(pdev, "st %d\n", state);
69225aee3deSMauro Carvalho Chehab msleep(100);
69325aee3deSMauro Carvalho Chehab */
69425aee3deSMauro Carvalho Chehab
69525aee3deSMauro Carvalho Chehab if (state) {
69625aee3deSMauro Carvalho Chehab if (chan->running) {
6976795bf62SDaniel Scheller dev_info(pdev, "already running\n");
69825aee3deSMauro Carvalho Chehab return;
69925aee3deSMauro Carvalho Chehab }
70025aee3deSMauro Carvalho Chehab } else {
70125aee3deSMauro Carvalho Chehab if (!chan->running) {
7026795bf62SDaniel Scheller dev_info(pdev, "already stopped\n");
70325aee3deSMauro Carvalho Chehab return;
70425aee3deSMauro Carvalho Chehab }
70525aee3deSMauro Carvalho Chehab }
70625aee3deSMauro Carvalho Chehab
70725aee3deSMauro Carvalho Chehab if (dev->card_info->switch_ctrl)
70825aee3deSMauro Carvalho Chehab dev->card_info->switch_ctrl(chan, 1, state ^ 1);
70925aee3deSMauro Carvalho Chehab
71025aee3deSMauro Carvalho Chehab if (state) {
71125aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock);
71225aee3deSMauro Carvalho Chehab
7136795bf62SDaniel Scheller /* dev_info(pdev, "lock=%08x\n",
71425aee3deSMauro Carvalho Chehab ngreadl(0x9310)); */
71525aee3deSMauro Carvalho Chehab dvb_ringbuffer_flush(&dev->tsout_rbuf);
71625aee3deSMauro Carvalho Chehab control = 0x80;
71725aee3deSMauro Carvalho Chehab if (chan->mode & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
71825aee3deSMauro Carvalho Chehab chan->Capture1Length = 512 * 188;
71925aee3deSMauro Carvalho Chehab mode = SMODE_TRANSPORT_STREAM;
72025aee3deSMauro Carvalho Chehab }
72125aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSOUT) {
72225aee3deSMauro Carvalho Chehab chan->pBufferExchange = tsout_exchange;
72325aee3deSMauro Carvalho Chehab /* 0x66666666 = 50MHz *2^33 /250MHz */
72425aee3deSMauro Carvalho Chehab chan->AudioDTOValue = 0x80000000;
72525aee3deSMauro Carvalho Chehab chan->AudioDTOUpdated = 1;
72625aee3deSMauro Carvalho Chehab }
72725aee3deSMauro Carvalho Chehab if (chan->mode & NGENE_IO_TSIN)
72825aee3deSMauro Carvalho Chehab chan->pBufferExchange = tsin_exchange;
72925aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
7302827a440SMauro Carvalho Chehab }
7316795bf62SDaniel Scheller /* else dev_info(pdev, "lock=%08x\n",
73225aee3deSMauro Carvalho Chehab ngreadl(0x9310)); */
73325aee3deSMauro Carvalho Chehab
73490979f04SBinoy Jayan mutex_lock(&dev->stream_mutex);
73525aee3deSMauro Carvalho Chehab ret = ngene_command_stream_control(dev, chan->number,
73625aee3deSMauro Carvalho Chehab control, mode, flags);
73790979f04SBinoy Jayan mutex_unlock(&dev->stream_mutex);
73890979f04SBinoy Jayan
73925aee3deSMauro Carvalho Chehab if (!ret)
74025aee3deSMauro Carvalho Chehab chan->running = state;
74125aee3deSMauro Carvalho Chehab else
7426795bf62SDaniel Scheller dev_err(pdev, "%s %d failed\n", __func__, state);
74325aee3deSMauro Carvalho Chehab if (!state) {
74425aee3deSMauro Carvalho Chehab spin_lock_irq(&chan->state_lock);
74525aee3deSMauro Carvalho Chehab chan->pBufferExchange = NULL;
74625aee3deSMauro Carvalho Chehab dvb_ringbuffer_flush(&dev->tsout_rbuf);
74725aee3deSMauro Carvalho Chehab spin_unlock_irq(&chan->state_lock);
74825aee3deSMauro Carvalho Chehab }
74925aee3deSMauro Carvalho Chehab }
75025aee3deSMauro Carvalho Chehab
75125aee3deSMauro Carvalho Chehab
75225aee3deSMauro Carvalho Chehab /****************************************************************************/
75325aee3deSMauro Carvalho Chehab /* nGene hardware init and release functions ********************************/
75425aee3deSMauro Carvalho Chehab /****************************************************************************/
75525aee3deSMauro Carvalho Chehab
free_ringbuffer(struct ngene * dev,struct SRingBufferDescriptor * rb)75625aee3deSMauro Carvalho Chehab static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb)
75725aee3deSMauro Carvalho Chehab {
75825aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = rb->Head;
75925aee3deSMauro Carvalho Chehab u32 j;
76025aee3deSMauro Carvalho Chehab
76125aee3deSMauro Carvalho Chehab if (!Cur)
76225aee3deSMauro Carvalho Chehab return;
76325aee3deSMauro Carvalho Chehab
76425aee3deSMauro Carvalho Chehab for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) {
76525aee3deSMauro Carvalho Chehab if (Cur->Buffer1)
766efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev,
767efb8225cSChristophe JAILLET rb->Buffer1Length, Cur->Buffer1,
76825aee3deSMauro Carvalho Chehab Cur->scList1->Address);
76925aee3deSMauro Carvalho Chehab
77025aee3deSMauro Carvalho Chehab if (Cur->Buffer2)
771efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev,
772efb8225cSChristophe JAILLET rb->Buffer2Length, Cur->Buffer2,
77325aee3deSMauro Carvalho Chehab Cur->scList2->Address);
77425aee3deSMauro Carvalho Chehab }
77525aee3deSMauro Carvalho Chehab
77625aee3deSMauro Carvalho Chehab if (rb->SCListMem)
777efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, rb->SCListMemSize,
77825aee3deSMauro Carvalho Chehab rb->SCListMem, rb->PASCListMem);
77925aee3deSMauro Carvalho Chehab
780efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, rb->MemSize, rb->Head,
781efb8225cSChristophe JAILLET rb->PAHead);
78225aee3deSMauro Carvalho Chehab }
78325aee3deSMauro Carvalho Chehab
free_idlebuffer(struct ngene * dev,struct SRingBufferDescriptor * rb,struct SRingBufferDescriptor * tb)78425aee3deSMauro Carvalho Chehab static void free_idlebuffer(struct ngene *dev,
78525aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *rb,
78625aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *tb)
78725aee3deSMauro Carvalho Chehab {
78825aee3deSMauro Carvalho Chehab int j;
78925aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = tb->Head;
79025aee3deSMauro Carvalho Chehab
79125aee3deSMauro Carvalho Chehab if (!rb->Head)
79225aee3deSMauro Carvalho Chehab return;
79325aee3deSMauro Carvalho Chehab free_ringbuffer(dev, rb);
79425aee3deSMauro Carvalho Chehab for (j = 0; j < tb->NumBuffers; j++, Cur = Cur->Next) {
79525aee3deSMauro Carvalho Chehab Cur->Buffer2 = NULL;
79625aee3deSMauro Carvalho Chehab Cur->scList2 = NULL;
79725aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_2 = 0;
79825aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_2 = 0;
79925aee3deSMauro Carvalho Chehab }
80025aee3deSMauro Carvalho Chehab }
80125aee3deSMauro Carvalho Chehab
free_common_buffers(struct ngene * dev)80225aee3deSMauro Carvalho Chehab static void free_common_buffers(struct ngene *dev)
80325aee3deSMauro Carvalho Chehab {
80425aee3deSMauro Carvalho Chehab u32 i;
80525aee3deSMauro Carvalho Chehab struct ngene_channel *chan;
80625aee3deSMauro Carvalho Chehab
80725aee3deSMauro Carvalho Chehab for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
80825aee3deSMauro Carvalho Chehab chan = &dev->channel[i];
80925aee3deSMauro Carvalho Chehab free_idlebuffer(dev, &chan->TSIdleBuffer, &chan->TSRingBuffer);
81025aee3deSMauro Carvalho Chehab free_ringbuffer(dev, &chan->RingBuffer);
81125aee3deSMauro Carvalho Chehab free_ringbuffer(dev, &chan->TSRingBuffer);
81225aee3deSMauro Carvalho Chehab }
81325aee3deSMauro Carvalho Chehab
81425aee3deSMauro Carvalho Chehab if (dev->OverflowBuffer)
815efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, OVERFLOW_BUFFER_SIZE,
81625aee3deSMauro Carvalho Chehab dev->OverflowBuffer, dev->PAOverflowBuffer);
81725aee3deSMauro Carvalho Chehab
81825aee3deSMauro Carvalho Chehab if (dev->FWInterfaceBuffer)
819efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, 4096,
82025aee3deSMauro Carvalho Chehab dev->FWInterfaceBuffer,
82125aee3deSMauro Carvalho Chehab dev->PAFWInterfaceBuffer);
82225aee3deSMauro Carvalho Chehab }
82325aee3deSMauro Carvalho Chehab
82425aee3deSMauro Carvalho Chehab /****************************************************************************/
82525aee3deSMauro Carvalho Chehab /* Ring buffer handling *****************************************************/
82625aee3deSMauro Carvalho Chehab /****************************************************************************/
82725aee3deSMauro Carvalho Chehab
create_ring_buffer(struct pci_dev * pci_dev,struct SRingBufferDescriptor * descr,u32 NumBuffers)82825aee3deSMauro Carvalho Chehab static int create_ring_buffer(struct pci_dev *pci_dev,
82925aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *descr, u32 NumBuffers)
83025aee3deSMauro Carvalho Chehab {
83125aee3deSMauro Carvalho Chehab dma_addr_t tmp;
83225aee3deSMauro Carvalho Chehab struct SBufferHeader *Head;
83325aee3deSMauro Carvalho Chehab u32 i;
83425aee3deSMauro Carvalho Chehab u32 MemSize = SIZEOF_SBufferHeader * NumBuffers;
83525aee3deSMauro Carvalho Chehab u64 PARingBufferHead;
83625aee3deSMauro Carvalho Chehab u64 PARingBufferCur;
83725aee3deSMauro Carvalho Chehab u64 PARingBufferNext;
83825aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur, *Next;
83925aee3deSMauro Carvalho Chehab
84025aee3deSMauro Carvalho Chehab descr->Head = NULL;
84125aee3deSMauro Carvalho Chehab descr->MemSize = 0;
84225aee3deSMauro Carvalho Chehab descr->PAHead = 0;
84325aee3deSMauro Carvalho Chehab descr->NumBuffers = 0;
84425aee3deSMauro Carvalho Chehab
84525aee3deSMauro Carvalho Chehab if (MemSize < 4096)
84625aee3deSMauro Carvalho Chehab MemSize = 4096;
84725aee3deSMauro Carvalho Chehab
848efb8225cSChristophe JAILLET Head = dma_alloc_coherent(&pci_dev->dev, MemSize, &tmp, GFP_KERNEL);
84925aee3deSMauro Carvalho Chehab PARingBufferHead = tmp;
85025aee3deSMauro Carvalho Chehab
85125aee3deSMauro Carvalho Chehab if (!Head)
85225aee3deSMauro Carvalho Chehab return -ENOMEM;
85325aee3deSMauro Carvalho Chehab
85425aee3deSMauro Carvalho Chehab PARingBufferCur = PARingBufferHead;
85525aee3deSMauro Carvalho Chehab Cur = Head;
85625aee3deSMauro Carvalho Chehab
85725aee3deSMauro Carvalho Chehab for (i = 0; i < NumBuffers - 1; i++) {
85825aee3deSMauro Carvalho Chehab Next = (struct SBufferHeader *)
85925aee3deSMauro Carvalho Chehab (((u8 *) Cur) + SIZEOF_SBufferHeader);
86025aee3deSMauro Carvalho Chehab PARingBufferNext = PARingBufferCur + SIZEOF_SBufferHeader;
86125aee3deSMauro Carvalho Chehab Cur->Next = Next;
86225aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Next = PARingBufferNext;
86325aee3deSMauro Carvalho Chehab Cur = Next;
86425aee3deSMauro Carvalho Chehab PARingBufferCur = PARingBufferNext;
86525aee3deSMauro Carvalho Chehab }
86625aee3deSMauro Carvalho Chehab /* Last Buffer points back to first one */
86725aee3deSMauro Carvalho Chehab Cur->Next = Head;
86825aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Next = PARingBufferHead;
86925aee3deSMauro Carvalho Chehab
87025aee3deSMauro Carvalho Chehab descr->Head = Head;
87125aee3deSMauro Carvalho Chehab descr->MemSize = MemSize;
87225aee3deSMauro Carvalho Chehab descr->PAHead = PARingBufferHead;
87325aee3deSMauro Carvalho Chehab descr->NumBuffers = NumBuffers;
87425aee3deSMauro Carvalho Chehab
87525aee3deSMauro Carvalho Chehab return 0;
87625aee3deSMauro Carvalho Chehab }
87725aee3deSMauro Carvalho Chehab
AllocateRingBuffers(struct pci_dev * pci_dev,dma_addr_t of,struct SRingBufferDescriptor * pRingBuffer,u32 Buffer1Length,u32 Buffer2Length)87825aee3deSMauro Carvalho Chehab static int AllocateRingBuffers(struct pci_dev *pci_dev,
87925aee3deSMauro Carvalho Chehab dma_addr_t of,
88025aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *pRingBuffer,
88125aee3deSMauro Carvalho Chehab u32 Buffer1Length, u32 Buffer2Length)
88225aee3deSMauro Carvalho Chehab {
88325aee3deSMauro Carvalho Chehab dma_addr_t tmp;
88425aee3deSMauro Carvalho Chehab u32 i, j;
88525aee3deSMauro Carvalho Chehab u32 SCListMemSize = pRingBuffer->NumBuffers
88625aee3deSMauro Carvalho Chehab * ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
88725aee3deSMauro Carvalho Chehab NUM_SCATTER_GATHER_ENTRIES)
88825aee3deSMauro Carvalho Chehab * sizeof(struct HW_SCATTER_GATHER_ELEMENT);
88925aee3deSMauro Carvalho Chehab
89025aee3deSMauro Carvalho Chehab u64 PASCListMem;
89125aee3deSMauro Carvalho Chehab struct HW_SCATTER_GATHER_ELEMENT *SCListEntry;
89225aee3deSMauro Carvalho Chehab u64 PASCListEntry;
89325aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur;
89425aee3deSMauro Carvalho Chehab void *SCListMem;
89525aee3deSMauro Carvalho Chehab
89625aee3deSMauro Carvalho Chehab if (SCListMemSize < 4096)
89725aee3deSMauro Carvalho Chehab SCListMemSize = 4096;
89825aee3deSMauro Carvalho Chehab
899efb8225cSChristophe JAILLET SCListMem = dma_alloc_coherent(&pci_dev->dev, SCListMemSize, &tmp,
900efb8225cSChristophe JAILLET GFP_KERNEL);
90125aee3deSMauro Carvalho Chehab
90225aee3deSMauro Carvalho Chehab PASCListMem = tmp;
90325aee3deSMauro Carvalho Chehab if (SCListMem == NULL)
90425aee3deSMauro Carvalho Chehab return -ENOMEM;
90525aee3deSMauro Carvalho Chehab
90625aee3deSMauro Carvalho Chehab pRingBuffer->SCListMem = SCListMem;
90725aee3deSMauro Carvalho Chehab pRingBuffer->PASCListMem = PASCListMem;
90825aee3deSMauro Carvalho Chehab pRingBuffer->SCListMemSize = SCListMemSize;
90925aee3deSMauro Carvalho Chehab pRingBuffer->Buffer1Length = Buffer1Length;
91025aee3deSMauro Carvalho Chehab pRingBuffer->Buffer2Length = Buffer2Length;
91125aee3deSMauro Carvalho Chehab
91225aee3deSMauro Carvalho Chehab SCListEntry = SCListMem;
91325aee3deSMauro Carvalho Chehab PASCListEntry = PASCListMem;
91425aee3deSMauro Carvalho Chehab Cur = pRingBuffer->Head;
91525aee3deSMauro Carvalho Chehab
91625aee3deSMauro Carvalho Chehab for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) {
91725aee3deSMauro Carvalho Chehab u64 PABuffer;
91825aee3deSMauro Carvalho Chehab
919efb8225cSChristophe JAILLET void *Buffer = dma_alloc_coherent(&pci_dev->dev,
920efb8225cSChristophe JAILLET Buffer1Length, &tmp, GFP_KERNEL);
92125aee3deSMauro Carvalho Chehab PABuffer = tmp;
92225aee3deSMauro Carvalho Chehab
92325aee3deSMauro Carvalho Chehab if (Buffer == NULL)
92425aee3deSMauro Carvalho Chehab return -ENOMEM;
92525aee3deSMauro Carvalho Chehab
92625aee3deSMauro Carvalho Chehab Cur->Buffer1 = Buffer;
92725aee3deSMauro Carvalho Chehab
92825aee3deSMauro Carvalho Chehab SCListEntry->Address = PABuffer;
92925aee3deSMauro Carvalho Chehab SCListEntry->Length = Buffer1Length;
93025aee3deSMauro Carvalho Chehab
93125aee3deSMauro Carvalho Chehab Cur->scList1 = SCListEntry;
93225aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_1 = PASCListEntry;
93325aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_1 =
93425aee3deSMauro Carvalho Chehab NUM_SCATTER_GATHER_ENTRIES;
93525aee3deSMauro Carvalho Chehab
93625aee3deSMauro Carvalho Chehab SCListEntry += 1;
93725aee3deSMauro Carvalho Chehab PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
93825aee3deSMauro Carvalho Chehab
93925aee3deSMauro Carvalho Chehab #if NUM_SCATTER_GATHER_ENTRIES > 1
94025aee3deSMauro Carvalho Chehab for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j += 1) {
94125aee3deSMauro Carvalho Chehab SCListEntry->Address = of;
94225aee3deSMauro Carvalho Chehab SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
94325aee3deSMauro Carvalho Chehab SCListEntry += 1;
94425aee3deSMauro Carvalho Chehab PASCListEntry +=
94525aee3deSMauro Carvalho Chehab sizeof(struct HW_SCATTER_GATHER_ELEMENT);
94625aee3deSMauro Carvalho Chehab }
94725aee3deSMauro Carvalho Chehab #endif
94825aee3deSMauro Carvalho Chehab
94925aee3deSMauro Carvalho Chehab if (!Buffer2Length)
95025aee3deSMauro Carvalho Chehab continue;
95125aee3deSMauro Carvalho Chehab
952efb8225cSChristophe JAILLET Buffer = dma_alloc_coherent(&pci_dev->dev, Buffer2Length,
953efb8225cSChristophe JAILLET &tmp, GFP_KERNEL);
95425aee3deSMauro Carvalho Chehab PABuffer = tmp;
95525aee3deSMauro Carvalho Chehab
95625aee3deSMauro Carvalho Chehab if (Buffer == NULL)
95725aee3deSMauro Carvalho Chehab return -ENOMEM;
95825aee3deSMauro Carvalho Chehab
95925aee3deSMauro Carvalho Chehab Cur->Buffer2 = Buffer;
96025aee3deSMauro Carvalho Chehab
96125aee3deSMauro Carvalho Chehab SCListEntry->Address = PABuffer;
96225aee3deSMauro Carvalho Chehab SCListEntry->Length = Buffer2Length;
96325aee3deSMauro Carvalho Chehab
96425aee3deSMauro Carvalho Chehab Cur->scList2 = SCListEntry;
96525aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_2 = PASCListEntry;
96625aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_2 =
96725aee3deSMauro Carvalho Chehab NUM_SCATTER_GATHER_ENTRIES;
96825aee3deSMauro Carvalho Chehab
96925aee3deSMauro Carvalho Chehab SCListEntry += 1;
97025aee3deSMauro Carvalho Chehab PASCListEntry += sizeof(struct HW_SCATTER_GATHER_ELEMENT);
97125aee3deSMauro Carvalho Chehab
97225aee3deSMauro Carvalho Chehab #if NUM_SCATTER_GATHER_ENTRIES > 1
97325aee3deSMauro Carvalho Chehab for (j = 0; j < NUM_SCATTER_GATHER_ENTRIES - 1; j++) {
97425aee3deSMauro Carvalho Chehab SCListEntry->Address = of;
97525aee3deSMauro Carvalho Chehab SCListEntry->Length = OVERFLOW_BUFFER_SIZE;
97625aee3deSMauro Carvalho Chehab SCListEntry += 1;
97725aee3deSMauro Carvalho Chehab PASCListEntry +=
97825aee3deSMauro Carvalho Chehab sizeof(struct HW_SCATTER_GATHER_ELEMENT);
97925aee3deSMauro Carvalho Chehab }
98025aee3deSMauro Carvalho Chehab #endif
98125aee3deSMauro Carvalho Chehab
98225aee3deSMauro Carvalho Chehab }
98325aee3deSMauro Carvalho Chehab
9844df16f70SPeter Senna Tschudin return 0;
98525aee3deSMauro Carvalho Chehab }
98625aee3deSMauro Carvalho Chehab
FillTSIdleBuffer(struct SRingBufferDescriptor * pIdleBuffer,struct SRingBufferDescriptor * pRingBuffer)98725aee3deSMauro Carvalho Chehab static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
98825aee3deSMauro Carvalho Chehab struct SRingBufferDescriptor *pRingBuffer)
98925aee3deSMauro Carvalho Chehab {
99025aee3deSMauro Carvalho Chehab /* Copy pointer to scatter gather list in TSRingbuffer
99125aee3deSMauro Carvalho Chehab structure for buffer 2
99225aee3deSMauro Carvalho Chehab Load number of buffer
99325aee3deSMauro Carvalho Chehab */
99425aee3deSMauro Carvalho Chehab u32 n = pRingBuffer->NumBuffers;
99525aee3deSMauro Carvalho Chehab
99625aee3deSMauro Carvalho Chehab /* Point to first buffer entry */
99725aee3deSMauro Carvalho Chehab struct SBufferHeader *Cur = pRingBuffer->Head;
99825aee3deSMauro Carvalho Chehab int i;
99916790554SMauro Carvalho Chehab /* Loop through all buffer and set Buffer 2 pointers to TSIdlebuffer */
100025aee3deSMauro Carvalho Chehab for (i = 0; i < n; i++) {
100125aee3deSMauro Carvalho Chehab Cur->Buffer2 = pIdleBuffer->Head->Buffer1;
100225aee3deSMauro Carvalho Chehab Cur->scList2 = pIdleBuffer->Head->scList1;
100325aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Address_of_first_entry_2 =
100425aee3deSMauro Carvalho Chehab pIdleBuffer->Head->ngeneBuffer.
100525aee3deSMauro Carvalho Chehab Address_of_first_entry_1;
100625aee3deSMauro Carvalho Chehab Cur->ngeneBuffer.Number_of_entries_2 =
100725aee3deSMauro Carvalho Chehab pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
100825aee3deSMauro Carvalho Chehab Cur = Cur->Next;
100925aee3deSMauro Carvalho Chehab }
10104df16f70SPeter Senna Tschudin return 0;
101125aee3deSMauro Carvalho Chehab }
101225aee3deSMauro Carvalho Chehab
101325aee3deSMauro Carvalho Chehab static u32 RingBufferSizes[MAX_STREAM] = {
101425aee3deSMauro Carvalho Chehab RING_SIZE_VIDEO,
101525aee3deSMauro Carvalho Chehab RING_SIZE_VIDEO,
101625aee3deSMauro Carvalho Chehab RING_SIZE_AUDIO,
101725aee3deSMauro Carvalho Chehab RING_SIZE_AUDIO,
101825aee3deSMauro Carvalho Chehab RING_SIZE_AUDIO,
101925aee3deSMauro Carvalho Chehab };
102025aee3deSMauro Carvalho Chehab
102125aee3deSMauro Carvalho Chehab static u32 Buffer1Sizes[MAX_STREAM] = {
102225aee3deSMauro Carvalho Chehab MAX_VIDEO_BUFFER_SIZE,
102325aee3deSMauro Carvalho Chehab MAX_VIDEO_BUFFER_SIZE,
102425aee3deSMauro Carvalho Chehab MAX_AUDIO_BUFFER_SIZE,
102525aee3deSMauro Carvalho Chehab MAX_AUDIO_BUFFER_SIZE,
102625aee3deSMauro Carvalho Chehab MAX_AUDIO_BUFFER_SIZE
102725aee3deSMauro Carvalho Chehab };
102825aee3deSMauro Carvalho Chehab
102925aee3deSMauro Carvalho Chehab static u32 Buffer2Sizes[MAX_STREAM] = {
103025aee3deSMauro Carvalho Chehab MAX_VBI_BUFFER_SIZE,
103125aee3deSMauro Carvalho Chehab MAX_VBI_BUFFER_SIZE,
103225aee3deSMauro Carvalho Chehab 0,
103325aee3deSMauro Carvalho Chehab 0,
103425aee3deSMauro Carvalho Chehab 0
103525aee3deSMauro Carvalho Chehab };
103625aee3deSMauro Carvalho Chehab
103725aee3deSMauro Carvalho Chehab
AllocCommonBuffers(struct ngene * dev)103825aee3deSMauro Carvalho Chehab static int AllocCommonBuffers(struct ngene *dev)
103925aee3deSMauro Carvalho Chehab {
104025aee3deSMauro Carvalho Chehab int status = 0, i;
104125aee3deSMauro Carvalho Chehab
1042efb8225cSChristophe JAILLET dev->FWInterfaceBuffer = dma_alloc_coherent(&dev->pci_dev->dev, 4096,
1043efb8225cSChristophe JAILLET &dev->PAFWInterfaceBuffer,
1044efb8225cSChristophe JAILLET GFP_KERNEL);
104525aee3deSMauro Carvalho Chehab if (!dev->FWInterfaceBuffer)
104625aee3deSMauro Carvalho Chehab return -ENOMEM;
104725aee3deSMauro Carvalho Chehab dev->hosttongene = dev->FWInterfaceBuffer;
104825aee3deSMauro Carvalho Chehab dev->ngenetohost = dev->FWInterfaceBuffer + 256;
104925aee3deSMauro Carvalho Chehab dev->EventBuffer = dev->FWInterfaceBuffer + 512;
105025aee3deSMauro Carvalho Chehab
1051efb8225cSChristophe JAILLET dev->OverflowBuffer = dma_alloc_coherent(&dev->pci_dev->dev,
105225aee3deSMauro Carvalho Chehab OVERFLOW_BUFFER_SIZE,
1053efb8225cSChristophe JAILLET &dev->PAOverflowBuffer, GFP_KERNEL);
105425aee3deSMauro Carvalho Chehab if (!dev->OverflowBuffer)
105525aee3deSMauro Carvalho Chehab return -ENOMEM;
105625aee3deSMauro Carvalho Chehab
105725aee3deSMauro Carvalho Chehab for (i = STREAM_VIDEOIN1; i < MAX_STREAM; i++) {
105825aee3deSMauro Carvalho Chehab int type = dev->card_info->io_type[i];
105925aee3deSMauro Carvalho Chehab
106025aee3deSMauro Carvalho Chehab dev->channel[i].State = KSSTATE_STOP;
106125aee3deSMauro Carvalho Chehab
106225aee3deSMauro Carvalho Chehab if (type & (NGENE_IO_TV | NGENE_IO_HDTV | NGENE_IO_AIN)) {
106325aee3deSMauro Carvalho Chehab status = create_ring_buffer(dev->pci_dev,
106425aee3deSMauro Carvalho Chehab &dev->channel[i].RingBuffer,
106525aee3deSMauro Carvalho Chehab RingBufferSizes[i]);
106625aee3deSMauro Carvalho Chehab if (status < 0)
106725aee3deSMauro Carvalho Chehab break;
106825aee3deSMauro Carvalho Chehab
106925aee3deSMauro Carvalho Chehab if (type & (NGENE_IO_TV | NGENE_IO_AIN)) {
107025aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev,
107125aee3deSMauro Carvalho Chehab dev->
107225aee3deSMauro Carvalho Chehab PAOverflowBuffer,
107325aee3deSMauro Carvalho Chehab &dev->channel[i].
107425aee3deSMauro Carvalho Chehab RingBuffer,
107525aee3deSMauro Carvalho Chehab Buffer1Sizes[i],
107625aee3deSMauro Carvalho Chehab Buffer2Sizes[i]);
107725aee3deSMauro Carvalho Chehab if (status < 0)
107825aee3deSMauro Carvalho Chehab break;
107925aee3deSMauro Carvalho Chehab } else if (type & NGENE_IO_HDTV) {
108025aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev,
108125aee3deSMauro Carvalho Chehab dev->
108225aee3deSMauro Carvalho Chehab PAOverflowBuffer,
108325aee3deSMauro Carvalho Chehab &dev->channel[i].
108425aee3deSMauro Carvalho Chehab RingBuffer,
108525aee3deSMauro Carvalho Chehab MAX_HDTV_BUFFER_SIZE,
108625aee3deSMauro Carvalho Chehab 0);
108725aee3deSMauro Carvalho Chehab if (status < 0)
108825aee3deSMauro Carvalho Chehab break;
108925aee3deSMauro Carvalho Chehab }
109025aee3deSMauro Carvalho Chehab }
109125aee3deSMauro Carvalho Chehab
109225aee3deSMauro Carvalho Chehab if (type & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
109325aee3deSMauro Carvalho Chehab
109425aee3deSMauro Carvalho Chehab status = create_ring_buffer(dev->pci_dev,
109525aee3deSMauro Carvalho Chehab &dev->channel[i].
109625aee3deSMauro Carvalho Chehab TSRingBuffer, RING_SIZE_TS);
109725aee3deSMauro Carvalho Chehab if (status < 0)
109825aee3deSMauro Carvalho Chehab break;
109925aee3deSMauro Carvalho Chehab
110025aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev,
110125aee3deSMauro Carvalho Chehab dev->PAOverflowBuffer,
110225aee3deSMauro Carvalho Chehab &dev->channel[i].
110325aee3deSMauro Carvalho Chehab TSRingBuffer,
110425aee3deSMauro Carvalho Chehab MAX_TS_BUFFER_SIZE, 0);
110525aee3deSMauro Carvalho Chehab if (status)
110625aee3deSMauro Carvalho Chehab break;
110725aee3deSMauro Carvalho Chehab }
110825aee3deSMauro Carvalho Chehab
110925aee3deSMauro Carvalho Chehab if (type & NGENE_IO_TSOUT) {
111025aee3deSMauro Carvalho Chehab status = create_ring_buffer(dev->pci_dev,
111125aee3deSMauro Carvalho Chehab &dev->channel[i].
111225aee3deSMauro Carvalho Chehab TSIdleBuffer, 1);
111325aee3deSMauro Carvalho Chehab if (status < 0)
111425aee3deSMauro Carvalho Chehab break;
111525aee3deSMauro Carvalho Chehab status = AllocateRingBuffers(dev->pci_dev,
111625aee3deSMauro Carvalho Chehab dev->PAOverflowBuffer,
111725aee3deSMauro Carvalho Chehab &dev->channel[i].
111825aee3deSMauro Carvalho Chehab TSIdleBuffer,
111925aee3deSMauro Carvalho Chehab MAX_TS_BUFFER_SIZE, 0);
112025aee3deSMauro Carvalho Chehab if (status)
112125aee3deSMauro Carvalho Chehab break;
112225aee3deSMauro Carvalho Chehab FillTSIdleBuffer(&dev->channel[i].TSIdleBuffer,
112325aee3deSMauro Carvalho Chehab &dev->channel[i].TSRingBuffer);
112425aee3deSMauro Carvalho Chehab }
112525aee3deSMauro Carvalho Chehab }
112625aee3deSMauro Carvalho Chehab return status;
112725aee3deSMauro Carvalho Chehab }
112825aee3deSMauro Carvalho Chehab
ngene_release_buffers(struct ngene * dev)112925aee3deSMauro Carvalho Chehab static void ngene_release_buffers(struct ngene *dev)
113025aee3deSMauro Carvalho Chehab {
113125aee3deSMauro Carvalho Chehab if (dev->iomem)
113225aee3deSMauro Carvalho Chehab iounmap(dev->iomem);
113325aee3deSMauro Carvalho Chehab free_common_buffers(dev);
113425aee3deSMauro Carvalho Chehab vfree(dev->tsout_buf);
113525aee3deSMauro Carvalho Chehab vfree(dev->tsin_buf);
113625aee3deSMauro Carvalho Chehab vfree(dev->ain_buf);
113725aee3deSMauro Carvalho Chehab vfree(dev->vin_buf);
113825aee3deSMauro Carvalho Chehab vfree(dev);
113925aee3deSMauro Carvalho Chehab }
114025aee3deSMauro Carvalho Chehab
ngene_get_buffers(struct ngene * dev)114125aee3deSMauro Carvalho Chehab static int ngene_get_buffers(struct ngene *dev)
114225aee3deSMauro Carvalho Chehab {
114325aee3deSMauro Carvalho Chehab if (AllocCommonBuffers(dev))
114425aee3deSMauro Carvalho Chehab return -ENOMEM;
114525aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[4] & NGENE_IO_TSOUT) {
114625aee3deSMauro Carvalho Chehab dev->tsout_buf = vmalloc(TSOUT_BUF_SIZE);
114725aee3deSMauro Carvalho Chehab if (!dev->tsout_buf)
114825aee3deSMauro Carvalho Chehab return -ENOMEM;
114925aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->tsout_rbuf,
115025aee3deSMauro Carvalho Chehab dev->tsout_buf, TSOUT_BUF_SIZE);
115125aee3deSMauro Carvalho Chehab }
115225aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[2]&NGENE_IO_TSIN) {
115325aee3deSMauro Carvalho Chehab dev->tsin_buf = vmalloc(TSIN_BUF_SIZE);
115425aee3deSMauro Carvalho Chehab if (!dev->tsin_buf)
115525aee3deSMauro Carvalho Chehab return -ENOMEM;
115625aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->tsin_rbuf,
115725aee3deSMauro Carvalho Chehab dev->tsin_buf, TSIN_BUF_SIZE);
115825aee3deSMauro Carvalho Chehab }
115925aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[2] & NGENE_IO_AIN) {
116025aee3deSMauro Carvalho Chehab dev->ain_buf = vmalloc(AIN_BUF_SIZE);
116125aee3deSMauro Carvalho Chehab if (!dev->ain_buf)
116225aee3deSMauro Carvalho Chehab return -ENOMEM;
116325aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->ain_rbuf, dev->ain_buf, AIN_BUF_SIZE);
116425aee3deSMauro Carvalho Chehab }
116525aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[0] & NGENE_IO_HDTV) {
116625aee3deSMauro Carvalho Chehab dev->vin_buf = vmalloc(VIN_BUF_SIZE);
116725aee3deSMauro Carvalho Chehab if (!dev->vin_buf)
116825aee3deSMauro Carvalho Chehab return -ENOMEM;
116925aee3deSMauro Carvalho Chehab dvb_ringbuffer_init(&dev->vin_rbuf, dev->vin_buf, VIN_BUF_SIZE);
117025aee3deSMauro Carvalho Chehab }
117125aee3deSMauro Carvalho Chehab dev->iomem = ioremap(pci_resource_start(dev->pci_dev, 0),
117225aee3deSMauro Carvalho Chehab pci_resource_len(dev->pci_dev, 0));
117325aee3deSMauro Carvalho Chehab if (!dev->iomem)
117425aee3deSMauro Carvalho Chehab return -ENOMEM;
117525aee3deSMauro Carvalho Chehab
117625aee3deSMauro Carvalho Chehab return 0;
117725aee3deSMauro Carvalho Chehab }
117825aee3deSMauro Carvalho Chehab
ngene_init(struct ngene * dev)117925aee3deSMauro Carvalho Chehab static void ngene_init(struct ngene *dev)
118025aee3deSMauro Carvalho Chehab {
11816795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev;
118225aee3deSMauro Carvalho Chehab int i;
118325aee3deSMauro Carvalho Chehab
11846027ff6bSAllen Pais tasklet_setup(&dev->event_tasklet, event_tasklet);
118525aee3deSMauro Carvalho Chehab
118625aee3deSMauro Carvalho Chehab memset_io(dev->iomem + 0xc000, 0x00, 0x220);
118725aee3deSMauro Carvalho Chehab memset_io(dev->iomem + 0xc400, 0x00, 0x100);
118825aee3deSMauro Carvalho Chehab
118925aee3deSMauro Carvalho Chehab for (i = 0; i < MAX_STREAM; i++) {
119025aee3deSMauro Carvalho Chehab dev->channel[i].dev = dev;
119125aee3deSMauro Carvalho Chehab dev->channel[i].number = i;
119225aee3deSMauro Carvalho Chehab }
119325aee3deSMauro Carvalho Chehab
119425aee3deSMauro Carvalho Chehab dev->fw_interface_version = 0;
119525aee3deSMauro Carvalho Chehab
119625aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE);
119725aee3deSMauro Carvalho Chehab
119825aee3deSMauro Carvalho Chehab dev->icounts = ngreadl(NGENE_INT_COUNTS);
119925aee3deSMauro Carvalho Chehab
120025aee3deSMauro Carvalho Chehab dev->device_version = ngreadl(DEV_VER) & 0x0f;
12016795bf62SDaniel Scheller dev_info(pdev, "Device version %d\n", dev->device_version);
120225aee3deSMauro Carvalho Chehab }
120325aee3deSMauro Carvalho Chehab
ngene_load_firm(struct ngene * dev)120425aee3deSMauro Carvalho Chehab static int ngene_load_firm(struct ngene *dev)
120525aee3deSMauro Carvalho Chehab {
12066795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev;
120725aee3deSMauro Carvalho Chehab u32 size;
120825aee3deSMauro Carvalho Chehab const struct firmware *fw = NULL;
120925aee3deSMauro Carvalho Chehab u8 *ngene_fw;
121025aee3deSMauro Carvalho Chehab char *fw_name;
121125aee3deSMauro Carvalho Chehab int err, version;
121225aee3deSMauro Carvalho Chehab
121325aee3deSMauro Carvalho Chehab version = dev->card_info->fw_version;
121425aee3deSMauro Carvalho Chehab
121525aee3deSMauro Carvalho Chehab switch (version) {
121625aee3deSMauro Carvalho Chehab default:
121725aee3deSMauro Carvalho Chehab case 15:
121825aee3deSMauro Carvalho Chehab version = 15;
121925aee3deSMauro Carvalho Chehab size = 23466;
122025aee3deSMauro Carvalho Chehab fw_name = "ngene_15.fw";
122125aee3deSMauro Carvalho Chehab dev->cmd_timeout_workaround = true;
122225aee3deSMauro Carvalho Chehab break;
122325aee3deSMauro Carvalho Chehab case 16:
122425aee3deSMauro Carvalho Chehab size = 23498;
122525aee3deSMauro Carvalho Chehab fw_name = "ngene_16.fw";
122625aee3deSMauro Carvalho Chehab dev->cmd_timeout_workaround = true;
122725aee3deSMauro Carvalho Chehab break;
122825aee3deSMauro Carvalho Chehab case 17:
122925aee3deSMauro Carvalho Chehab size = 24446;
123025aee3deSMauro Carvalho Chehab fw_name = "ngene_17.fw";
123125aee3deSMauro Carvalho Chehab dev->cmd_timeout_workaround = true;
123225aee3deSMauro Carvalho Chehab break;
123325aee3deSMauro Carvalho Chehab case 18:
123425aee3deSMauro Carvalho Chehab size = 0;
123525aee3deSMauro Carvalho Chehab fw_name = "ngene_18.fw";
123625aee3deSMauro Carvalho Chehab break;
123725aee3deSMauro Carvalho Chehab }
123825aee3deSMauro Carvalho Chehab
123925aee3deSMauro Carvalho Chehab if (request_firmware(&fw, fw_name, &dev->pci_dev->dev) < 0) {
12406795bf62SDaniel Scheller dev_err(pdev, "Could not load firmware file %s.\n", fw_name);
12416795bf62SDaniel Scheller dev_info(pdev, "Copy %s to your hotplug directory!\n",
12426795bf62SDaniel Scheller fw_name);
124325aee3deSMauro Carvalho Chehab return -1;
124425aee3deSMauro Carvalho Chehab }
124525aee3deSMauro Carvalho Chehab if (size == 0)
124625aee3deSMauro Carvalho Chehab size = fw->size;
124725aee3deSMauro Carvalho Chehab if (size != fw->size) {
12486795bf62SDaniel Scheller dev_err(pdev, "Firmware %s has invalid size!", fw_name);
124925aee3deSMauro Carvalho Chehab err = -1;
125025aee3deSMauro Carvalho Chehab } else {
12516795bf62SDaniel Scheller dev_info(pdev, "Loading firmware file %s.\n", fw_name);
125225aee3deSMauro Carvalho Chehab ngene_fw = (u8 *) fw->data;
125325aee3deSMauro Carvalho Chehab err = ngene_command_load_firmware(dev, ngene_fw, size);
125425aee3deSMauro Carvalho Chehab }
125525aee3deSMauro Carvalho Chehab
125625aee3deSMauro Carvalho Chehab release_firmware(fw);
125725aee3deSMauro Carvalho Chehab
125825aee3deSMauro Carvalho Chehab return err;
125925aee3deSMauro Carvalho Chehab }
126025aee3deSMauro Carvalho Chehab
ngene_stop(struct ngene * dev)126125aee3deSMauro Carvalho Chehab static void ngene_stop(struct ngene *dev)
126225aee3deSMauro Carvalho Chehab {
12631439cdb0SBinoy Jayan mutex_destroy(&dev->cmd_mutex);
126425aee3deSMauro Carvalho Chehab i2c_del_adapter(&(dev->channel[0].i2c_adapter));
126525aee3deSMauro Carvalho Chehab i2c_del_adapter(&(dev->channel[1].i2c_adapter));
126625aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE);
126725aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND);
126825aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_COMMAND_HI);
126925aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS);
127025aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_STATUS_HI);
127125aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT);
127225aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_EVENT_HI);
127325aee3deSMauro Carvalho Chehab free_irq(dev->pci_dev->irq, dev);
127425aee3deSMauro Carvalho Chehab #ifdef CONFIG_PCI_MSI
127525aee3deSMauro Carvalho Chehab if (dev->msi_enabled)
127625aee3deSMauro Carvalho Chehab pci_disable_msi(dev->pci_dev);
127725aee3deSMauro Carvalho Chehab #endif
127825aee3deSMauro Carvalho Chehab }
127925aee3deSMauro Carvalho Chehab
ngene_buffer_config(struct ngene * dev)128025aee3deSMauro Carvalho Chehab static int ngene_buffer_config(struct ngene *dev)
128125aee3deSMauro Carvalho Chehab {
128225aee3deSMauro Carvalho Chehab int stat;
128325aee3deSMauro Carvalho Chehab
128425aee3deSMauro Carvalho Chehab if (dev->card_info->fw_version >= 17) {
128525aee3deSMauro Carvalho Chehab u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 };
128625aee3deSMauro Carvalho Chehab u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 };
128725aee3deSMauro Carvalho Chehab u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 };
128825aee3deSMauro Carvalho Chehab u8 *bconf = tsin12_config;
128925aee3deSMauro Carvalho Chehab
129025aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[2]&NGENE_IO_TSIN &&
129125aee3deSMauro Carvalho Chehab dev->card_info->io_type[3]&NGENE_IO_TSIN) {
129225aee3deSMauro Carvalho Chehab bconf = tsin1234_config;
129325aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[4]&NGENE_IO_TSOUT &&
129425aee3deSMauro Carvalho Chehab dev->ci.en)
129525aee3deSMauro Carvalho Chehab bconf = tsio1235_config;
129625aee3deSMauro Carvalho Chehab }
129725aee3deSMauro Carvalho Chehab stat = ngene_command_config_free_buf(dev, bconf);
129825aee3deSMauro Carvalho Chehab } else {
129925aee3deSMauro Carvalho Chehab int bconf = BUFFER_CONFIG_4422;
130025aee3deSMauro Carvalho Chehab
130125aee3deSMauro Carvalho Chehab if (dev->card_info->io_type[3] == NGENE_IO_TSIN)
130225aee3deSMauro Carvalho Chehab bconf = BUFFER_CONFIG_3333;
130325aee3deSMauro Carvalho Chehab stat = ngene_command_config_buf(dev, bconf);
130425aee3deSMauro Carvalho Chehab }
130525aee3deSMauro Carvalho Chehab return stat;
130625aee3deSMauro Carvalho Chehab }
130725aee3deSMauro Carvalho Chehab
130825aee3deSMauro Carvalho Chehab
ngene_start(struct ngene * dev)130925aee3deSMauro Carvalho Chehab static int ngene_start(struct ngene *dev)
131025aee3deSMauro Carvalho Chehab {
131125aee3deSMauro Carvalho Chehab int stat;
131225aee3deSMauro Carvalho Chehab int i;
131325aee3deSMauro Carvalho Chehab
131425aee3deSMauro Carvalho Chehab pci_set_master(dev->pci_dev);
131525aee3deSMauro Carvalho Chehab ngene_init(dev);
131625aee3deSMauro Carvalho Chehab
131725aee3deSMauro Carvalho Chehab stat = request_irq(dev->pci_dev->irq, irq_handler,
131825aee3deSMauro Carvalho Chehab IRQF_SHARED, "nGene",
131925aee3deSMauro Carvalho Chehab (void *)dev);
132025aee3deSMauro Carvalho Chehab if (stat < 0)
132125aee3deSMauro Carvalho Chehab return stat;
132225aee3deSMauro Carvalho Chehab
132325aee3deSMauro Carvalho Chehab init_waitqueue_head(&dev->cmd_wq);
132425aee3deSMauro Carvalho Chehab init_waitqueue_head(&dev->tx_wq);
132525aee3deSMauro Carvalho Chehab init_waitqueue_head(&dev->rx_wq);
13261439cdb0SBinoy Jayan mutex_init(&dev->cmd_mutex);
132790979f04SBinoy Jayan mutex_init(&dev->stream_mutex);
132825aee3deSMauro Carvalho Chehab sema_init(&dev->pll_mutex, 1);
1329bd7a85d3SBinoy Jayan mutex_init(&dev->i2c_switch_mutex);
133025aee3deSMauro Carvalho Chehab spin_lock_init(&dev->cmd_lock);
133125aee3deSMauro Carvalho Chehab for (i = 0; i < MAX_STREAM; i++)
133225aee3deSMauro Carvalho Chehab spin_lock_init(&dev->channel[i].state_lock);
133325aee3deSMauro Carvalho Chehab ngwritel(1, TIMESTAMPS);
133425aee3deSMauro Carvalho Chehab
133525aee3deSMauro Carvalho Chehab ngwritel(1, NGENE_INT_ENABLE);
133625aee3deSMauro Carvalho Chehab
133725aee3deSMauro Carvalho Chehab stat = ngene_load_firm(dev);
133825aee3deSMauro Carvalho Chehab if (stat < 0)
133925aee3deSMauro Carvalho Chehab goto fail;
134025aee3deSMauro Carvalho Chehab
134125aee3deSMauro Carvalho Chehab #ifdef CONFIG_PCI_MSI
134225aee3deSMauro Carvalho Chehab /* enable MSI if kernel and card support it */
134325aee3deSMauro Carvalho Chehab if (pci_msi_enabled() && dev->card_info->msi_supported) {
1344492b183bSArnd Bergmann struct device *pdev = &dev->pci_dev->dev;
134525aee3deSMauro Carvalho Chehab unsigned long flags;
134625aee3deSMauro Carvalho Chehab
134725aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE);
134825aee3deSMauro Carvalho Chehab free_irq(dev->pci_dev->irq, dev);
134925aee3deSMauro Carvalho Chehab stat = pci_enable_msi(dev->pci_dev);
135025aee3deSMauro Carvalho Chehab if (stat) {
13516795bf62SDaniel Scheller dev_info(pdev, "MSI not available\n");
135225aee3deSMauro Carvalho Chehab flags = IRQF_SHARED;
135325aee3deSMauro Carvalho Chehab } else {
135425aee3deSMauro Carvalho Chehab flags = 0;
135525aee3deSMauro Carvalho Chehab dev->msi_enabled = true;
135625aee3deSMauro Carvalho Chehab }
135725aee3deSMauro Carvalho Chehab stat = request_irq(dev->pci_dev->irq, irq_handler,
135825aee3deSMauro Carvalho Chehab flags, "nGene", dev);
135925aee3deSMauro Carvalho Chehab if (stat < 0)
136025aee3deSMauro Carvalho Chehab goto fail2;
136125aee3deSMauro Carvalho Chehab ngwritel(1, NGENE_INT_ENABLE);
136225aee3deSMauro Carvalho Chehab }
136325aee3deSMauro Carvalho Chehab #endif
136425aee3deSMauro Carvalho Chehab
136525aee3deSMauro Carvalho Chehab stat = ngene_i2c_init(dev, 0);
136625aee3deSMauro Carvalho Chehab if (stat < 0)
136725aee3deSMauro Carvalho Chehab goto fail;
136825aee3deSMauro Carvalho Chehab
136925aee3deSMauro Carvalho Chehab stat = ngene_i2c_init(dev, 1);
137025aee3deSMauro Carvalho Chehab if (stat < 0)
137125aee3deSMauro Carvalho Chehab goto fail;
137225aee3deSMauro Carvalho Chehab
137325aee3deSMauro Carvalho Chehab return 0;
137425aee3deSMauro Carvalho Chehab
137525aee3deSMauro Carvalho Chehab fail:
137625aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE);
137725aee3deSMauro Carvalho Chehab free_irq(dev->pci_dev->irq, dev);
137825aee3deSMauro Carvalho Chehab #ifdef CONFIG_PCI_MSI
137925aee3deSMauro Carvalho Chehab fail2:
138025aee3deSMauro Carvalho Chehab if (dev->msi_enabled)
138125aee3deSMauro Carvalho Chehab pci_disable_msi(dev->pci_dev);
138225aee3deSMauro Carvalho Chehab #endif
138325aee3deSMauro Carvalho Chehab return stat;
138425aee3deSMauro Carvalho Chehab }
138525aee3deSMauro Carvalho Chehab
138625aee3deSMauro Carvalho Chehab /****************************************************************************/
138725aee3deSMauro Carvalho Chehab /****************************************************************************/
138825aee3deSMauro Carvalho Chehab /****************************************************************************/
138925aee3deSMauro Carvalho Chehab
release_channel(struct ngene_channel * chan)139025aee3deSMauro Carvalho Chehab static void release_channel(struct ngene_channel *chan)
139125aee3deSMauro Carvalho Chehab {
139225aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdemux = &chan->demux;
139325aee3deSMauro Carvalho Chehab struct ngene *dev = chan->dev;
139425aee3deSMauro Carvalho Chehab
139525aee3deSMauro Carvalho Chehab if (chan->running)
139625aee3deSMauro Carvalho Chehab set_transfer(chan, 0);
139725aee3deSMauro Carvalho Chehab
139825aee3deSMauro Carvalho Chehab tasklet_kill(&chan->demux_tasklet);
139925aee3deSMauro Carvalho Chehab
140025aee3deSMauro Carvalho Chehab if (chan->ci_dev) {
140125aee3deSMauro Carvalho Chehab dvb_unregister_device(chan->ci_dev);
140225aee3deSMauro Carvalho Chehab chan->ci_dev = NULL;
140325aee3deSMauro Carvalho Chehab }
140425aee3deSMauro Carvalho Chehab
140525aee3deSMauro Carvalho Chehab if (chan->fe2)
140625aee3deSMauro Carvalho Chehab dvb_unregister_frontend(chan->fe2);
140725aee3deSMauro Carvalho Chehab
140825aee3deSMauro Carvalho Chehab if (chan->fe) {
140925aee3deSMauro Carvalho Chehab dvb_unregister_frontend(chan->fe);
14101c2ad82eSDaniel Scheller
14111c2ad82eSDaniel Scheller /* release I2C client (tuner) if needed */
141278c4e082SDaniel Scheller if (chan->i2c_client_fe) {
141378c4e082SDaniel Scheller dvb_module_release(chan->i2c_client[0]);
14141c2ad82eSDaniel Scheller chan->i2c_client[0] = NULL;
14151c2ad82eSDaniel Scheller }
14161c2ad82eSDaniel Scheller
141725aee3deSMauro Carvalho Chehab dvb_frontend_detach(chan->fe);
141825aee3deSMauro Carvalho Chehab chan->fe = NULL;
141925aee3deSMauro Carvalho Chehab }
142025aee3deSMauro Carvalho Chehab
142125aee3deSMauro Carvalho Chehab if (chan->has_demux) {
142225aee3deSMauro Carvalho Chehab dvb_net_release(&chan->dvbnet);
142325aee3deSMauro Carvalho Chehab dvbdemux->dmx.close(&dvbdemux->dmx);
142425aee3deSMauro Carvalho Chehab dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
142525aee3deSMauro Carvalho Chehab &chan->hw_frontend);
142625aee3deSMauro Carvalho Chehab dvbdemux->dmx.remove_frontend(&dvbdemux->dmx,
142725aee3deSMauro Carvalho Chehab &chan->mem_frontend);
142825aee3deSMauro Carvalho Chehab dvb_dmxdev_release(&chan->dmxdev);
142925aee3deSMauro Carvalho Chehab dvb_dmx_release(&chan->demux);
143025aee3deSMauro Carvalho Chehab chan->has_demux = false;
143125aee3deSMauro Carvalho Chehab }
143225aee3deSMauro Carvalho Chehab
143325aee3deSMauro Carvalho Chehab if (chan->has_adapter) {
143425aee3deSMauro Carvalho Chehab dvb_unregister_adapter(&dev->adapter[chan->number]);
143525aee3deSMauro Carvalho Chehab chan->has_adapter = false;
143625aee3deSMauro Carvalho Chehab }
143725aee3deSMauro Carvalho Chehab }
143825aee3deSMauro Carvalho Chehab
init_channel(struct ngene_channel * chan)143925aee3deSMauro Carvalho Chehab static int init_channel(struct ngene_channel *chan)
144025aee3deSMauro Carvalho Chehab {
144125aee3deSMauro Carvalho Chehab int ret = 0, nr = chan->number;
144225aee3deSMauro Carvalho Chehab struct dvb_adapter *adapter = NULL;
144325aee3deSMauro Carvalho Chehab struct dvb_demux *dvbdemux = &chan->demux;
144425aee3deSMauro Carvalho Chehab struct ngene *dev = chan->dev;
144525aee3deSMauro Carvalho Chehab struct ngene_info *ni = dev->card_info;
144625aee3deSMauro Carvalho Chehab int io = ni->io_type[nr];
144725aee3deSMauro Carvalho Chehab
14486027ff6bSAllen Pais tasklet_setup(&chan->demux_tasklet, demux_tasklet);
144925aee3deSMauro Carvalho Chehab chan->users = 0;
145025aee3deSMauro Carvalho Chehab chan->type = io;
145125aee3deSMauro Carvalho Chehab chan->mode = chan->type; /* for now only one mode */
14521c2ad82eSDaniel Scheller chan->i2c_client_fe = 0; /* be sure this is set to zero */
145325aee3deSMauro Carvalho Chehab
145425aee3deSMauro Carvalho Chehab if (io & NGENE_IO_TSIN) {
145525aee3deSMauro Carvalho Chehab chan->fe = NULL;
145625aee3deSMauro Carvalho Chehab if (ni->demod_attach[nr]) {
145725aee3deSMauro Carvalho Chehab ret = ni->demod_attach[nr](chan);
145825aee3deSMauro Carvalho Chehab if (ret < 0)
145925aee3deSMauro Carvalho Chehab goto err;
146025aee3deSMauro Carvalho Chehab }
146125aee3deSMauro Carvalho Chehab if (chan->fe && ni->tuner_attach[nr]) {
146225aee3deSMauro Carvalho Chehab ret = ni->tuner_attach[nr](chan);
146325aee3deSMauro Carvalho Chehab if (ret < 0)
146425aee3deSMauro Carvalho Chehab goto err;
146525aee3deSMauro Carvalho Chehab }
146625aee3deSMauro Carvalho Chehab }
146725aee3deSMauro Carvalho Chehab
146825aee3deSMauro Carvalho Chehab if (!dev->ci.en && (io & NGENE_IO_TSOUT))
146925aee3deSMauro Carvalho Chehab return 0;
147025aee3deSMauro Carvalho Chehab
147125aee3deSMauro Carvalho Chehab if (io & (NGENE_IO_TSIN | NGENE_IO_TSOUT)) {
147225aee3deSMauro Carvalho Chehab if (nr >= STREAM_AUDIOIN1)
147325aee3deSMauro Carvalho Chehab chan->DataFormatFlags = DF_SWAP32;
147425aee3deSMauro Carvalho Chehab
147525aee3deSMauro Carvalho Chehab if (nr == 0 || !one_adapter || dev->first_adapter == NULL) {
147625aee3deSMauro Carvalho Chehab adapter = &dev->adapter[nr];
147725aee3deSMauro Carvalho Chehab ret = dvb_register_adapter(adapter, "nGene",
147825aee3deSMauro Carvalho Chehab THIS_MODULE,
147925aee3deSMauro Carvalho Chehab &chan->dev->pci_dev->dev,
148025aee3deSMauro Carvalho Chehab adapter_nr);
148125aee3deSMauro Carvalho Chehab if (ret < 0)
148225aee3deSMauro Carvalho Chehab goto err;
148325aee3deSMauro Carvalho Chehab if (dev->first_adapter == NULL)
148425aee3deSMauro Carvalho Chehab dev->first_adapter = adapter;
148525aee3deSMauro Carvalho Chehab chan->has_adapter = true;
148625aee3deSMauro Carvalho Chehab } else
148725aee3deSMauro Carvalho Chehab adapter = dev->first_adapter;
148825aee3deSMauro Carvalho Chehab }
148925aee3deSMauro Carvalho Chehab
149025aee3deSMauro Carvalho Chehab if (dev->ci.en && (io & NGENE_IO_TSOUT)) {
1491f987b53cSAleksandr Burakov ret = dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1);
1492f987b53cSAleksandr Burakov if (ret != 0)
1493f987b53cSAleksandr Burakov goto err;
149425aee3deSMauro Carvalho Chehab set_transfer(chan, 1);
149525aee3deSMauro Carvalho Chehab chan->dev->channel[2].DataFormatFlags = DF_SWAP32;
149625aee3deSMauro Carvalho Chehab set_transfer(&chan->dev->channel[2], 1);
149725aee3deSMauro Carvalho Chehab dvb_register_device(adapter, &chan->ci_dev,
149825aee3deSMauro Carvalho Chehab &ngene_dvbdev_ci, (void *) chan,
1499df2f94e5SMauro Carvalho Chehab DVB_DEVICE_SEC, 0);
150025aee3deSMauro Carvalho Chehab if (!chan->ci_dev)
150125aee3deSMauro Carvalho Chehab goto err;
150225aee3deSMauro Carvalho Chehab }
150325aee3deSMauro Carvalho Chehab
150425aee3deSMauro Carvalho Chehab if (chan->fe) {
150525aee3deSMauro Carvalho Chehab if (dvb_register_frontend(adapter, chan->fe) < 0)
150625aee3deSMauro Carvalho Chehab goto err;
150725aee3deSMauro Carvalho Chehab chan->has_demux = true;
150825aee3deSMauro Carvalho Chehab }
150925aee3deSMauro Carvalho Chehab if (chan->fe2) {
151025aee3deSMauro Carvalho Chehab if (dvb_register_frontend(adapter, chan->fe2) < 0)
151125aee3deSMauro Carvalho Chehab goto err;
15125a4faee2SMauro Carvalho Chehab if (chan->fe) {
151325aee3deSMauro Carvalho Chehab chan->fe2->tuner_priv = chan->fe->tuner_priv;
151425aee3deSMauro Carvalho Chehab memcpy(&chan->fe2->ops.tuner_ops,
151525aee3deSMauro Carvalho Chehab &chan->fe->ops.tuner_ops,
151625aee3deSMauro Carvalho Chehab sizeof(struct dvb_tuner_ops));
151725aee3deSMauro Carvalho Chehab }
15185a4faee2SMauro Carvalho Chehab }
151925aee3deSMauro Carvalho Chehab
152025aee3deSMauro Carvalho Chehab if (chan->has_demux) {
152125aee3deSMauro Carvalho Chehab ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
152225aee3deSMauro Carvalho Chehab ngene_start_feed,
152325aee3deSMauro Carvalho Chehab ngene_stop_feed, chan);
152425aee3deSMauro Carvalho Chehab ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux,
152525aee3deSMauro Carvalho Chehab &chan->hw_frontend,
152625aee3deSMauro Carvalho Chehab &chan->mem_frontend, adapter);
152725aee3deSMauro Carvalho Chehab ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx);
152825aee3deSMauro Carvalho Chehab }
152925aee3deSMauro Carvalho Chehab
153025aee3deSMauro Carvalho Chehab return ret;
153125aee3deSMauro Carvalho Chehab
153225aee3deSMauro Carvalho Chehab err:
153325aee3deSMauro Carvalho Chehab if (chan->fe) {
153425aee3deSMauro Carvalho Chehab dvb_frontend_detach(chan->fe);
153525aee3deSMauro Carvalho Chehab chan->fe = NULL;
153625aee3deSMauro Carvalho Chehab }
153725aee3deSMauro Carvalho Chehab release_channel(chan);
153825aee3deSMauro Carvalho Chehab return 0;
153925aee3deSMauro Carvalho Chehab }
154025aee3deSMauro Carvalho Chehab
init_channels(struct ngene * dev)154125aee3deSMauro Carvalho Chehab static int init_channels(struct ngene *dev)
154225aee3deSMauro Carvalho Chehab {
154325aee3deSMauro Carvalho Chehab int i, j;
154425aee3deSMauro Carvalho Chehab
154525aee3deSMauro Carvalho Chehab for (i = 0; i < MAX_STREAM; i++) {
154625aee3deSMauro Carvalho Chehab dev->channel[i].number = i;
154725aee3deSMauro Carvalho Chehab if (init_channel(&dev->channel[i]) < 0) {
154825aee3deSMauro Carvalho Chehab for (j = i - 1; j >= 0; j--)
154925aee3deSMauro Carvalho Chehab release_channel(&dev->channel[j]);
155025aee3deSMauro Carvalho Chehab return -1;
155125aee3deSMauro Carvalho Chehab }
155225aee3deSMauro Carvalho Chehab }
155325aee3deSMauro Carvalho Chehab return 0;
155425aee3deSMauro Carvalho Chehab }
155525aee3deSMauro Carvalho Chehab
1556d19e3a72SDaniel Scheller static const struct cxd2099_cfg cxd_cfgtmpl = {
155725aee3deSMauro Carvalho Chehab .bitrate = 62000,
155825aee3deSMauro Carvalho Chehab .polarity = 0,
155925aee3deSMauro Carvalho Chehab .clock_mode = 0,
156025aee3deSMauro Carvalho Chehab };
156125aee3deSMauro Carvalho Chehab
cxd_attach(struct ngene * dev)156225aee3deSMauro Carvalho Chehab static void cxd_attach(struct ngene *dev)
156325aee3deSMauro Carvalho Chehab {
15646795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev;
156525aee3deSMauro Carvalho Chehab struct ngene_ci *ci = &dev->ci;
1566d19e3a72SDaniel Scheller struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl;
1567d19e3a72SDaniel Scheller struct i2c_client *client;
1568e39b8e94SDaniel Scheller int ret;
1569e39b8e94SDaniel Scheller u8 type;
1570e39b8e94SDaniel Scheller
1571e39b8e94SDaniel Scheller /* check for CXD2099AR presence before attaching */
1572e39b8e94SDaniel Scheller ret = ngene_port_has_cxd2099(&dev->channel[0].i2c_adapter, &type);
1573e39b8e94SDaniel Scheller if (!ret) {
1574e39b8e94SDaniel Scheller dev_dbg(pdev, "No CXD2099AR found\n");
1575e39b8e94SDaniel Scheller return;
1576e39b8e94SDaniel Scheller }
1577e39b8e94SDaniel Scheller
1578e39b8e94SDaniel Scheller if (type != 1) {
1579e39b8e94SDaniel Scheller dev_warn(pdev, "CXD2099AR is uninitialized!\n");
1580e39b8e94SDaniel Scheller return;
1581e39b8e94SDaniel Scheller }
158225aee3deSMauro Carvalho Chehab
1583d19e3a72SDaniel Scheller cxd_cfg.en = &ci->en;
158478c4e082SDaniel Scheller client = dvb_module_probe("cxd2099", NULL,
158578c4e082SDaniel Scheller &dev->channel[0].i2c_adapter,
158678c4e082SDaniel Scheller 0x40, &cxd_cfg);
158778c4e082SDaniel Scheller if (!client)
158878c4e082SDaniel Scheller goto err;
1589d19e3a72SDaniel Scheller
159025aee3deSMauro Carvalho Chehab ci->dev = dev;
1591d19e3a72SDaniel Scheller dev->channel[0].i2c_client[0] = client;
1592d19e3a72SDaniel Scheller return;
1593d19e3a72SDaniel Scheller
159478c4e082SDaniel Scheller err:
15956795bf62SDaniel Scheller dev_err(pdev, "CXD2099AR attach failed\n");
159625aee3deSMauro Carvalho Chehab return;
159725aee3deSMauro Carvalho Chehab }
159825aee3deSMauro Carvalho Chehab
cxd_detach(struct ngene * dev)159925aee3deSMauro Carvalho Chehab static void cxd_detach(struct ngene *dev)
160025aee3deSMauro Carvalho Chehab {
160125aee3deSMauro Carvalho Chehab struct ngene_ci *ci = &dev->ci;
160225aee3deSMauro Carvalho Chehab
160325aee3deSMauro Carvalho Chehab dvb_ca_en50221_release(ci->en);
1604d19e3a72SDaniel Scheller
160578c4e082SDaniel Scheller dvb_module_release(dev->channel[0].i2c_client[0]);
160678c4e082SDaniel Scheller dev->channel[0].i2c_client[0] = NULL;
1607c463c979SHans Verkuil ci->en = NULL;
160825aee3deSMauro Carvalho Chehab }
160925aee3deSMauro Carvalho Chehab
161025aee3deSMauro Carvalho Chehab /***********************************/
161125aee3deSMauro Carvalho Chehab /* workaround for shutdown failure */
161225aee3deSMauro Carvalho Chehab /***********************************/
161325aee3deSMauro Carvalho Chehab
ngene_unlink(struct ngene * dev)161425aee3deSMauro Carvalho Chehab static void ngene_unlink(struct ngene *dev)
161525aee3deSMauro Carvalho Chehab {
161625aee3deSMauro Carvalho Chehab struct ngene_command com;
161725aee3deSMauro Carvalho Chehab
161825aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_MEM_WRITE;
161925aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 3;
162025aee3deSMauro Carvalho Chehab com.cmd.MemoryWrite.address = 0x910c;
162125aee3deSMauro Carvalho Chehab com.cmd.MemoryWrite.data = 0xff;
162225aee3deSMauro Carvalho Chehab com.in_len = 3;
162325aee3deSMauro Carvalho Chehab com.out_len = 1;
162425aee3deSMauro Carvalho Chehab
16251439cdb0SBinoy Jayan mutex_lock(&dev->cmd_mutex);
162625aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE);
162725aee3deSMauro Carvalho Chehab ngene_command_mutex(dev, &com);
16281439cdb0SBinoy Jayan mutex_unlock(&dev->cmd_mutex);
162925aee3deSMauro Carvalho Chehab }
163025aee3deSMauro Carvalho Chehab
ngene_shutdown(struct pci_dev * pdev)163125aee3deSMauro Carvalho Chehab void ngene_shutdown(struct pci_dev *pdev)
163225aee3deSMauro Carvalho Chehab {
16330e7e4d26SJingoo Han struct ngene *dev = pci_get_drvdata(pdev);
163425aee3deSMauro Carvalho Chehab
163525aee3deSMauro Carvalho Chehab if (!dev || !shutdown_workaround)
163625aee3deSMauro Carvalho Chehab return;
163725aee3deSMauro Carvalho Chehab
16386795bf62SDaniel Scheller dev_info(&pdev->dev, "shutdown workaround...\n");
163925aee3deSMauro Carvalho Chehab ngene_unlink(dev);
164025aee3deSMauro Carvalho Chehab pci_disable_device(pdev);
164125aee3deSMauro Carvalho Chehab }
164225aee3deSMauro Carvalho Chehab
164325aee3deSMauro Carvalho Chehab /****************************************************************************/
164425aee3deSMauro Carvalho Chehab /* device probe/remove calls ************************************************/
164525aee3deSMauro Carvalho Chehab /****************************************************************************/
164625aee3deSMauro Carvalho Chehab
ngene_remove(struct pci_dev * pdev)16474c62e976SGreg Kroah-Hartman void ngene_remove(struct pci_dev *pdev)
164825aee3deSMauro Carvalho Chehab {
164925aee3deSMauro Carvalho Chehab struct ngene *dev = pci_get_drvdata(pdev);
165025aee3deSMauro Carvalho Chehab int i;
165125aee3deSMauro Carvalho Chehab
165225aee3deSMauro Carvalho Chehab tasklet_kill(&dev->event_tasklet);
165325aee3deSMauro Carvalho Chehab for (i = MAX_STREAM - 1; i >= 0; i--)
165425aee3deSMauro Carvalho Chehab release_channel(&dev->channel[i]);
165525aee3deSMauro Carvalho Chehab if (dev->ci.en)
165625aee3deSMauro Carvalho Chehab cxd_detach(dev);
165725aee3deSMauro Carvalho Chehab ngene_stop(dev);
165825aee3deSMauro Carvalho Chehab ngene_release_buffers(dev);
165925aee3deSMauro Carvalho Chehab pci_disable_device(pdev);
166025aee3deSMauro Carvalho Chehab }
166125aee3deSMauro Carvalho Chehab
ngene_probe(struct pci_dev * pci_dev,const struct pci_device_id * id)16624c62e976SGreg Kroah-Hartman int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
166325aee3deSMauro Carvalho Chehab {
166425aee3deSMauro Carvalho Chehab struct ngene *dev;
166525aee3deSMauro Carvalho Chehab int stat = 0;
166625aee3deSMauro Carvalho Chehab
166725aee3deSMauro Carvalho Chehab if (pci_enable_device(pci_dev) < 0)
166825aee3deSMauro Carvalho Chehab return -ENODEV;
166925aee3deSMauro Carvalho Chehab
167025aee3deSMauro Carvalho Chehab dev = vzalloc(sizeof(struct ngene));
167125aee3deSMauro Carvalho Chehab if (dev == NULL) {
167225aee3deSMauro Carvalho Chehab stat = -ENOMEM;
167325aee3deSMauro Carvalho Chehab goto fail0;
167425aee3deSMauro Carvalho Chehab }
167525aee3deSMauro Carvalho Chehab
167625aee3deSMauro Carvalho Chehab dev->pci_dev = pci_dev;
167725aee3deSMauro Carvalho Chehab dev->card_info = (struct ngene_info *)id->driver_data;
16786795bf62SDaniel Scheller dev_info(&pci_dev->dev, "Found %s\n", dev->card_info->name);
167925aee3deSMauro Carvalho Chehab
168025aee3deSMauro Carvalho Chehab pci_set_drvdata(pci_dev, dev);
168125aee3deSMauro Carvalho Chehab
168225aee3deSMauro Carvalho Chehab /* Alloc buffers and start nGene */
168325aee3deSMauro Carvalho Chehab stat = ngene_get_buffers(dev);
168425aee3deSMauro Carvalho Chehab if (stat < 0)
168525aee3deSMauro Carvalho Chehab goto fail1;
168625aee3deSMauro Carvalho Chehab stat = ngene_start(dev);
168725aee3deSMauro Carvalho Chehab if (stat < 0)
168825aee3deSMauro Carvalho Chehab goto fail1;
168925aee3deSMauro Carvalho Chehab
169025aee3deSMauro Carvalho Chehab cxd_attach(dev);
169125aee3deSMauro Carvalho Chehab
169225aee3deSMauro Carvalho Chehab stat = ngene_buffer_config(dev);
169325aee3deSMauro Carvalho Chehab if (stat < 0)
169425aee3deSMauro Carvalho Chehab goto fail1;
169525aee3deSMauro Carvalho Chehab
169625aee3deSMauro Carvalho Chehab
169725aee3deSMauro Carvalho Chehab dev->i2c_current_bus = -1;
169825aee3deSMauro Carvalho Chehab
169925aee3deSMauro Carvalho Chehab /* Register DVB adapters and devices for both channels */
1700bd6973eaSPeter Senna Tschudin stat = init_channels(dev);
1701bd6973eaSPeter Senna Tschudin if (stat < 0)
170225aee3deSMauro Carvalho Chehab goto fail2;
170325aee3deSMauro Carvalho Chehab
170425aee3deSMauro Carvalho Chehab return 0;
170525aee3deSMauro Carvalho Chehab
170625aee3deSMauro Carvalho Chehab fail2:
170725aee3deSMauro Carvalho Chehab ngene_stop(dev);
170825aee3deSMauro Carvalho Chehab fail1:
170925aee3deSMauro Carvalho Chehab ngene_release_buffers(dev);
171025aee3deSMauro Carvalho Chehab fail0:
171125aee3deSMauro Carvalho Chehab pci_disable_device(pci_dev);
171225aee3deSMauro Carvalho Chehab return stat;
171325aee3deSMauro Carvalho Chehab }
1714