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 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 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 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 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 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 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 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 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 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; 38825aee3deSMauro Carvalho Chehab memcpy(&com.cmd.ConfigureBuffers.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 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 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 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 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 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 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 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) 766*efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, 767*efb8225cSChristophe JAILLET rb->Buffer1Length, Cur->Buffer1, 76825aee3deSMauro Carvalho Chehab Cur->scList1->Address); 76925aee3deSMauro Carvalho Chehab 77025aee3deSMauro Carvalho Chehab if (Cur->Buffer2) 771*efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, 772*efb8225cSChristophe JAILLET rb->Buffer2Length, Cur->Buffer2, 77325aee3deSMauro Carvalho Chehab Cur->scList2->Address); 77425aee3deSMauro Carvalho Chehab } 77525aee3deSMauro Carvalho Chehab 77625aee3deSMauro Carvalho Chehab if (rb->SCListMem) 777*efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, rb->SCListMemSize, 77825aee3deSMauro Carvalho Chehab rb->SCListMem, rb->PASCListMem); 77925aee3deSMauro Carvalho Chehab 780*efb8225cSChristophe JAILLET dma_free_coherent(&dev->pci_dev->dev, rb->MemSize, rb->Head, 781*efb8225cSChristophe JAILLET rb->PAHead); 78225aee3deSMauro Carvalho Chehab } 78325aee3deSMauro Carvalho Chehab 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 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) 815*efb8225cSChristophe 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) 819*efb8225cSChristophe 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 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 848*efb8225cSChristophe 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 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 899*efb8225cSChristophe JAILLET SCListMem = dma_alloc_coherent(&pci_dev->dev, SCListMemSize, &tmp, 900*efb8225cSChristophe 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 919*efb8225cSChristophe JAILLET void *Buffer = dma_alloc_coherent(&pci_dev->dev, 920*efb8225cSChristophe 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 952*efb8225cSChristophe JAILLET Buffer = dma_alloc_coherent(&pci_dev->dev, Buffer2Length, 953*efb8225cSChristophe 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 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 103825aee3deSMauro Carvalho Chehab static int AllocCommonBuffers(struct ngene *dev) 103925aee3deSMauro Carvalho Chehab { 104025aee3deSMauro Carvalho Chehab int status = 0, i; 104125aee3deSMauro Carvalho Chehab 1042*efb8225cSChristophe JAILLET dev->FWInterfaceBuffer = dma_alloc_coherent(&dev->pci_dev->dev, 4096, 1043*efb8225cSChristophe JAILLET &dev->PAFWInterfaceBuffer, 1044*efb8225cSChristophe 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 1051*efb8225cSChristophe JAILLET dev->OverflowBuffer = dma_alloc_coherent(&dev->pci_dev->dev, 105225aee3deSMauro Carvalho Chehab OVERFLOW_BUFFER_SIZE, 1053*efb8225cSChristophe 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 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 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 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 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 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 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 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 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 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)) { 149125aee3deSMauro Carvalho Chehab dvb_ca_en50221_init(adapter, dev->ci.en, 0, 1); 149225aee3deSMauro Carvalho Chehab set_transfer(chan, 1); 149325aee3deSMauro Carvalho Chehab chan->dev->channel[2].DataFormatFlags = DF_SWAP32; 149425aee3deSMauro Carvalho Chehab set_transfer(&chan->dev->channel[2], 1); 149525aee3deSMauro Carvalho Chehab dvb_register_device(adapter, &chan->ci_dev, 149625aee3deSMauro Carvalho Chehab &ngene_dvbdev_ci, (void *) chan, 1497df2f94e5SMauro Carvalho Chehab DVB_DEVICE_SEC, 0); 149825aee3deSMauro Carvalho Chehab if (!chan->ci_dev) 149925aee3deSMauro Carvalho Chehab goto err; 150025aee3deSMauro Carvalho Chehab } 150125aee3deSMauro Carvalho Chehab 150225aee3deSMauro Carvalho Chehab if (chan->fe) { 150325aee3deSMauro Carvalho Chehab if (dvb_register_frontend(adapter, chan->fe) < 0) 150425aee3deSMauro Carvalho Chehab goto err; 150525aee3deSMauro Carvalho Chehab chan->has_demux = true; 150625aee3deSMauro Carvalho Chehab } 150725aee3deSMauro Carvalho Chehab if (chan->fe2) { 150825aee3deSMauro Carvalho Chehab if (dvb_register_frontend(adapter, chan->fe2) < 0) 150925aee3deSMauro Carvalho Chehab goto err; 15105a4faee2SMauro Carvalho Chehab if (chan->fe) { 151125aee3deSMauro Carvalho Chehab chan->fe2->tuner_priv = chan->fe->tuner_priv; 151225aee3deSMauro Carvalho Chehab memcpy(&chan->fe2->ops.tuner_ops, 151325aee3deSMauro Carvalho Chehab &chan->fe->ops.tuner_ops, 151425aee3deSMauro Carvalho Chehab sizeof(struct dvb_tuner_ops)); 151525aee3deSMauro Carvalho Chehab } 15165a4faee2SMauro Carvalho Chehab } 151725aee3deSMauro Carvalho Chehab 151825aee3deSMauro Carvalho Chehab if (chan->has_demux) { 151925aee3deSMauro Carvalho Chehab ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", 152025aee3deSMauro Carvalho Chehab ngene_start_feed, 152125aee3deSMauro Carvalho Chehab ngene_stop_feed, chan); 152225aee3deSMauro Carvalho Chehab ret = my_dvb_dmxdev_ts_card_init(&chan->dmxdev, &chan->demux, 152325aee3deSMauro Carvalho Chehab &chan->hw_frontend, 152425aee3deSMauro Carvalho Chehab &chan->mem_frontend, adapter); 152525aee3deSMauro Carvalho Chehab ret = dvb_net_init(adapter, &chan->dvbnet, &chan->demux.dmx); 152625aee3deSMauro Carvalho Chehab } 152725aee3deSMauro Carvalho Chehab 152825aee3deSMauro Carvalho Chehab return ret; 152925aee3deSMauro Carvalho Chehab 153025aee3deSMauro Carvalho Chehab err: 153125aee3deSMauro Carvalho Chehab if (chan->fe) { 153225aee3deSMauro Carvalho Chehab dvb_frontend_detach(chan->fe); 153325aee3deSMauro Carvalho Chehab chan->fe = NULL; 153425aee3deSMauro Carvalho Chehab } 153525aee3deSMauro Carvalho Chehab release_channel(chan); 153625aee3deSMauro Carvalho Chehab return 0; 153725aee3deSMauro Carvalho Chehab } 153825aee3deSMauro Carvalho Chehab 153925aee3deSMauro Carvalho Chehab static int init_channels(struct ngene *dev) 154025aee3deSMauro Carvalho Chehab { 154125aee3deSMauro Carvalho Chehab int i, j; 154225aee3deSMauro Carvalho Chehab 154325aee3deSMauro Carvalho Chehab for (i = 0; i < MAX_STREAM; i++) { 154425aee3deSMauro Carvalho Chehab dev->channel[i].number = i; 154525aee3deSMauro Carvalho Chehab if (init_channel(&dev->channel[i]) < 0) { 154625aee3deSMauro Carvalho Chehab for (j = i - 1; j >= 0; j--) 154725aee3deSMauro Carvalho Chehab release_channel(&dev->channel[j]); 154825aee3deSMauro Carvalho Chehab return -1; 154925aee3deSMauro Carvalho Chehab } 155025aee3deSMauro Carvalho Chehab } 155125aee3deSMauro Carvalho Chehab return 0; 155225aee3deSMauro Carvalho Chehab } 155325aee3deSMauro Carvalho Chehab 1554d19e3a72SDaniel Scheller static const struct cxd2099_cfg cxd_cfgtmpl = { 155525aee3deSMauro Carvalho Chehab .bitrate = 62000, 155625aee3deSMauro Carvalho Chehab .polarity = 0, 155725aee3deSMauro Carvalho Chehab .clock_mode = 0, 155825aee3deSMauro Carvalho Chehab }; 155925aee3deSMauro Carvalho Chehab 156025aee3deSMauro Carvalho Chehab static void cxd_attach(struct ngene *dev) 156125aee3deSMauro Carvalho Chehab { 15626795bf62SDaniel Scheller struct device *pdev = &dev->pci_dev->dev; 156325aee3deSMauro Carvalho Chehab struct ngene_ci *ci = &dev->ci; 1564d19e3a72SDaniel Scheller struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; 1565d19e3a72SDaniel Scheller struct i2c_client *client; 1566e39b8e94SDaniel Scheller int ret; 1567e39b8e94SDaniel Scheller u8 type; 1568e39b8e94SDaniel Scheller 1569e39b8e94SDaniel Scheller /* check for CXD2099AR presence before attaching */ 1570e39b8e94SDaniel Scheller ret = ngene_port_has_cxd2099(&dev->channel[0].i2c_adapter, &type); 1571e39b8e94SDaniel Scheller if (!ret) { 1572e39b8e94SDaniel Scheller dev_dbg(pdev, "No CXD2099AR found\n"); 1573e39b8e94SDaniel Scheller return; 1574e39b8e94SDaniel Scheller } 1575e39b8e94SDaniel Scheller 1576e39b8e94SDaniel Scheller if (type != 1) { 1577e39b8e94SDaniel Scheller dev_warn(pdev, "CXD2099AR is uninitialized!\n"); 1578e39b8e94SDaniel Scheller return; 1579e39b8e94SDaniel Scheller } 158025aee3deSMauro Carvalho Chehab 1581d19e3a72SDaniel Scheller cxd_cfg.en = &ci->en; 158278c4e082SDaniel Scheller client = dvb_module_probe("cxd2099", NULL, 158378c4e082SDaniel Scheller &dev->channel[0].i2c_adapter, 158478c4e082SDaniel Scheller 0x40, &cxd_cfg); 158578c4e082SDaniel Scheller if (!client) 158678c4e082SDaniel Scheller goto err; 1587d19e3a72SDaniel Scheller 158825aee3deSMauro Carvalho Chehab ci->dev = dev; 1589d19e3a72SDaniel Scheller dev->channel[0].i2c_client[0] = client; 1590d19e3a72SDaniel Scheller return; 1591d19e3a72SDaniel Scheller 159278c4e082SDaniel Scheller err: 15936795bf62SDaniel Scheller dev_err(pdev, "CXD2099AR attach failed\n"); 159425aee3deSMauro Carvalho Chehab return; 159525aee3deSMauro Carvalho Chehab } 159625aee3deSMauro Carvalho Chehab 159725aee3deSMauro Carvalho Chehab static void cxd_detach(struct ngene *dev) 159825aee3deSMauro Carvalho Chehab { 159925aee3deSMauro Carvalho Chehab struct ngene_ci *ci = &dev->ci; 160025aee3deSMauro Carvalho Chehab 160125aee3deSMauro Carvalho Chehab dvb_ca_en50221_release(ci->en); 1602d19e3a72SDaniel Scheller 160378c4e082SDaniel Scheller dvb_module_release(dev->channel[0].i2c_client[0]); 160478c4e082SDaniel Scheller dev->channel[0].i2c_client[0] = NULL; 1605c463c979SHans Verkuil ci->en = NULL; 160625aee3deSMauro Carvalho Chehab } 160725aee3deSMauro Carvalho Chehab 160825aee3deSMauro Carvalho Chehab /***********************************/ 160925aee3deSMauro Carvalho Chehab /* workaround for shutdown failure */ 161025aee3deSMauro Carvalho Chehab /***********************************/ 161125aee3deSMauro Carvalho Chehab 161225aee3deSMauro Carvalho Chehab static void ngene_unlink(struct ngene *dev) 161325aee3deSMauro Carvalho Chehab { 161425aee3deSMauro Carvalho Chehab struct ngene_command com; 161525aee3deSMauro Carvalho Chehab 161625aee3deSMauro Carvalho Chehab com.cmd.hdr.Opcode = CMD_MEM_WRITE; 161725aee3deSMauro Carvalho Chehab com.cmd.hdr.Length = 3; 161825aee3deSMauro Carvalho Chehab com.cmd.MemoryWrite.address = 0x910c; 161925aee3deSMauro Carvalho Chehab com.cmd.MemoryWrite.data = 0xff; 162025aee3deSMauro Carvalho Chehab com.in_len = 3; 162125aee3deSMauro Carvalho Chehab com.out_len = 1; 162225aee3deSMauro Carvalho Chehab 16231439cdb0SBinoy Jayan mutex_lock(&dev->cmd_mutex); 162425aee3deSMauro Carvalho Chehab ngwritel(0, NGENE_INT_ENABLE); 162525aee3deSMauro Carvalho Chehab ngene_command_mutex(dev, &com); 16261439cdb0SBinoy Jayan mutex_unlock(&dev->cmd_mutex); 162725aee3deSMauro Carvalho Chehab } 162825aee3deSMauro Carvalho Chehab 162925aee3deSMauro Carvalho Chehab void ngene_shutdown(struct pci_dev *pdev) 163025aee3deSMauro Carvalho Chehab { 16310e7e4d26SJingoo Han struct ngene *dev = pci_get_drvdata(pdev); 163225aee3deSMauro Carvalho Chehab 163325aee3deSMauro Carvalho Chehab if (!dev || !shutdown_workaround) 163425aee3deSMauro Carvalho Chehab return; 163525aee3deSMauro Carvalho Chehab 16366795bf62SDaniel Scheller dev_info(&pdev->dev, "shutdown workaround...\n"); 163725aee3deSMauro Carvalho Chehab ngene_unlink(dev); 163825aee3deSMauro Carvalho Chehab pci_disable_device(pdev); 163925aee3deSMauro Carvalho Chehab } 164025aee3deSMauro Carvalho Chehab 164125aee3deSMauro Carvalho Chehab /****************************************************************************/ 164225aee3deSMauro Carvalho Chehab /* device probe/remove calls ************************************************/ 164325aee3deSMauro Carvalho Chehab /****************************************************************************/ 164425aee3deSMauro Carvalho Chehab 16454c62e976SGreg Kroah-Hartman void ngene_remove(struct pci_dev *pdev) 164625aee3deSMauro Carvalho Chehab { 164725aee3deSMauro Carvalho Chehab struct ngene *dev = pci_get_drvdata(pdev); 164825aee3deSMauro Carvalho Chehab int i; 164925aee3deSMauro Carvalho Chehab 165025aee3deSMauro Carvalho Chehab tasklet_kill(&dev->event_tasklet); 165125aee3deSMauro Carvalho Chehab for (i = MAX_STREAM - 1; i >= 0; i--) 165225aee3deSMauro Carvalho Chehab release_channel(&dev->channel[i]); 165325aee3deSMauro Carvalho Chehab if (dev->ci.en) 165425aee3deSMauro Carvalho Chehab cxd_detach(dev); 165525aee3deSMauro Carvalho Chehab ngene_stop(dev); 165625aee3deSMauro Carvalho Chehab ngene_release_buffers(dev); 165725aee3deSMauro Carvalho Chehab pci_disable_device(pdev); 165825aee3deSMauro Carvalho Chehab } 165925aee3deSMauro Carvalho Chehab 16604c62e976SGreg Kroah-Hartman int ngene_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) 166125aee3deSMauro Carvalho Chehab { 166225aee3deSMauro Carvalho Chehab struct ngene *dev; 166325aee3deSMauro Carvalho Chehab int stat = 0; 166425aee3deSMauro Carvalho Chehab 166525aee3deSMauro Carvalho Chehab if (pci_enable_device(pci_dev) < 0) 166625aee3deSMauro Carvalho Chehab return -ENODEV; 166725aee3deSMauro Carvalho Chehab 166825aee3deSMauro Carvalho Chehab dev = vzalloc(sizeof(struct ngene)); 166925aee3deSMauro Carvalho Chehab if (dev == NULL) { 167025aee3deSMauro Carvalho Chehab stat = -ENOMEM; 167125aee3deSMauro Carvalho Chehab goto fail0; 167225aee3deSMauro Carvalho Chehab } 167325aee3deSMauro Carvalho Chehab 167425aee3deSMauro Carvalho Chehab dev->pci_dev = pci_dev; 167525aee3deSMauro Carvalho Chehab dev->card_info = (struct ngene_info *)id->driver_data; 16766795bf62SDaniel Scheller dev_info(&pci_dev->dev, "Found %s\n", dev->card_info->name); 167725aee3deSMauro Carvalho Chehab 167825aee3deSMauro Carvalho Chehab pci_set_drvdata(pci_dev, dev); 167925aee3deSMauro Carvalho Chehab 168025aee3deSMauro Carvalho Chehab /* Alloc buffers and start nGene */ 168125aee3deSMauro Carvalho Chehab stat = ngene_get_buffers(dev); 168225aee3deSMauro Carvalho Chehab if (stat < 0) 168325aee3deSMauro Carvalho Chehab goto fail1; 168425aee3deSMauro Carvalho Chehab stat = ngene_start(dev); 168525aee3deSMauro Carvalho Chehab if (stat < 0) 168625aee3deSMauro Carvalho Chehab goto fail1; 168725aee3deSMauro Carvalho Chehab 168825aee3deSMauro Carvalho Chehab cxd_attach(dev); 168925aee3deSMauro Carvalho Chehab 169025aee3deSMauro Carvalho Chehab stat = ngene_buffer_config(dev); 169125aee3deSMauro Carvalho Chehab if (stat < 0) 169225aee3deSMauro Carvalho Chehab goto fail1; 169325aee3deSMauro Carvalho Chehab 169425aee3deSMauro Carvalho Chehab 169525aee3deSMauro Carvalho Chehab dev->i2c_current_bus = -1; 169625aee3deSMauro Carvalho Chehab 169725aee3deSMauro Carvalho Chehab /* Register DVB adapters and devices for both channels */ 1698bd6973eaSPeter Senna Tschudin stat = init_channels(dev); 1699bd6973eaSPeter Senna Tschudin if (stat < 0) 170025aee3deSMauro Carvalho Chehab goto fail2; 170125aee3deSMauro Carvalho Chehab 170225aee3deSMauro Carvalho Chehab return 0; 170325aee3deSMauro Carvalho Chehab 170425aee3deSMauro Carvalho Chehab fail2: 170525aee3deSMauro Carvalho Chehab ngene_stop(dev); 170625aee3deSMauro Carvalho Chehab fail1: 170725aee3deSMauro Carvalho Chehab ngene_release_buffers(dev); 170825aee3deSMauro Carvalho Chehab fail0: 170925aee3deSMauro Carvalho Chehab pci_disable_device(pci_dev); 171025aee3deSMauro Carvalho Chehab return stat; 171125aee3deSMauro Carvalho Chehab } 1712