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