media: ddbridge: bump ddbridge code to version 0.9.29

This huge patch bumps the ddbridge driver to version 0.9.29. Compared to
the vendor driver package, DD OctoNET including GTL link support, and all
DVB-C Modulator card support has been removed since this requires large
changes to the underlying DVB core API, which should eventually be done
separately, and, after that, the functionality/device support can be added
back rather easy.

While the diff is rather large, the bump is mostly a big refactor of all
data structures. Yet, the MSI support (message signaled interrupts) is
greatly improved, also all currently available CI single/duo bridge cards
are fully supported.

More changes compared to the upstream driver:
 - the DDB_USE_WORKER flag/define was removed, kernel worker functionality
   will be used.
 - coding style is properly fixed (zero complaints from checkpatch)
 - all (not much though) CamelCase has been fixed to kernel_case
 - (private) IOCTLs temporarily removed (which are mainly used to provide
   rarely-used FPGA update functionality)

Great care has been taken to keep all previous changes and fixes (e.g.
kernel logging via dev_*(), pointer annotations and such) intact.

Permission to reuse and mainline the driver code was formally granted by
Ralph Metzler <rjkm@metzlerbros.de>.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
Tested-by: Richard Scobie <r.scobie@clear.net.nz>
Tested-by: Jasmin Jessich <jasmin@anw.at>
Tested-by: Dietmar Spingler <d_spingler@freenet.de>
Tested-by: Manfred Knick <Manfred.Knick@t-online.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
This commit is contained in:
Daniel Scheller 2017-08-12 07:55:52 -04:00 committed by Mauro Carvalho Chehab
parent a96e5ab8a7
commit 22e743898d
6 changed files with 3380 additions and 1167 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,24 +1,21 @@
/*
* ddbridge.c: Digital Devices PCIe bridge driver
* ddbridge-i2c.c: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2011 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* To obtain the license, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@ -34,30 +31,47 @@
#include <linux/vmalloc.h>
#include "ddbridge.h"
#include "ddbridge-regs.h"
#include "ddbridge-i2c.h"
#include "ddbridge-regs.h"
/******************************************************************************/
static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
{
struct ddb *dev = i2c->dev;
long stat;
unsigned long stat;
u32 val;
i2c->done = 0;
ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND);
stat = wait_for_completion_timeout(&i2c->completion, HZ);
val = ddbreadl(dev, i2c->regs + I2C_COMMAND);
if (stat == 0) {
dev_err(&dev->pdev->dev, "I2C timeout\n");
{ /* MSI debugging*/
u32 istat = ddbreadl(INTERRUPT_STATUS);
dev_err(&dev->pdev->dev, "IRS %08x\n", istat);
ddbwritel(istat, INTERRUPT_ACK);
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
dev->nr, i2c->nr, i2c->link);
{
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
dev_err(dev->dev, "DDBridge IRS %08x\n", istat);
if (i2c->link) {
u32 listat = ddbreadl(dev,
DDB_LINK_TAG(i2c->link) |
INTERRUPT_STATUS);
dev_err(dev->dev, "DDBridge link %u IRS %08x\n",
i2c->link, listat);
}
if (istat & 1) {
ddbwritel(dev, istat & 1, INTERRUPT_ACK);
} else {
u32 mon = ddbreadl(dev,
i2c->regs + I2C_MONITOR);
dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n",
val, mon);
}
}
return -EIO;
}
val = ddbreadl(i2c->regs+I2C_COMMAND);
if (val & 0x70000)
return -EIO;
return 0;
@ -66,48 +80,54 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
static int ddb_i2c_master_xfer(struct i2c_adapter *adapter,
struct i2c_msg msg[], int num)
{
struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter);
struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter);
struct ddb *dev = i2c->dev;
u8 addr = 0;
if (num)
addr = msg[0].addr;
if (num == 2 && msg[1].flags & I2C_M_RD &&
!(msg[0].flags & I2C_M_RD)) {
memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf,
msg[0].buf, msg[0].len);
ddbwritel(msg[0].len|(msg[1].len << 16),
i2c->regs+I2C_TASKLENGTH);
if (!ddb_i2c_cmd(i2c, addr, 1)) {
memcpy_fromio(msg[1].buf,
dev->regs + I2C_TASKMEM_BASE + i2c->rbuf,
msg[1].len);
return num;
}
}
if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len);
ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH);
if (!ddb_i2c_cmd(i2c, addr, 2))
return num;
}
if (num == 1 && (msg[0].flags & I2C_M_RD)) {
ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
if (!ddb_i2c_cmd(i2c, addr, 3)) {
ddbcpyfrom(msg[0].buf,
I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len);
addr = msg[0].addr;
if (msg[0].len > i2c->bsize)
return -EIO;
switch (num) {
case 1:
if (msg[0].flags & I2C_M_RD) {
ddbwritel(dev, msg[0].len << 16,
i2c->regs + I2C_TASKLENGTH);
if (ddb_i2c_cmd(i2c, addr, 3))
break;
ddbcpyfrom(dev, msg[0].buf,
i2c->rbuf, msg[0].len);
return num;
}
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH);
if (ddb_i2c_cmd(i2c, addr, 2))
break;
return num;
case 2:
if ((msg[0].flags & I2C_M_RD) == I2C_M_RD)
break;
if ((msg[1].flags & I2C_M_RD) != I2C_M_RD)
break;
if (msg[1].len > i2c->bsize)
break;
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
ddbwritel(dev, msg[0].len | (msg[1].len << 16),
i2c->regs + I2C_TASKLENGTH);
if (ddb_i2c_cmd(i2c, addr, 1))
break;
ddbcpyfrom(dev, msg[1].buf,
i2c->rbuf,
msg[1].len);
return num;
default:
break;
}
return -EIO;
}
static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_SMBUS_EMUL;
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm ddb_i2c_algo = {
@ -119,55 +139,90 @@ void ddb_i2c_release(struct ddb *dev)
{
int i;
struct ddb_i2c *i2c;
for (i = 0; i < dev->i2c_num; i++) {
i2c = &dev->i2c[i];
i2c_del_adapter(&i2c->adap);
}
}
static void i2c_handler(unsigned long priv)
{
struct ddb_i2c *i2c = (struct ddb_i2c *) priv;
complete(&i2c->completion);
}
static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
struct ddb_regmap *regmap, int link, int i, int num)
{
struct i2c_adapter *adap;
for (i = 0; i < dev->info->port_num; i++) {
i2c = &dev->i2c[i];
adap = &i2c->adap;
i2c_del_adapter(adap);
}
i2c->nr = i;
i2c->dev = dev;
i2c->link = link;
i2c->bsize = regmap->i2c_buf->size;
i2c->wbuf = DDB_LINK_TAG(link) |
(regmap->i2c_buf->base + i2c->bsize * i);
i2c->rbuf = i2c->wbuf; /* + i2c->bsize / 2 */
i2c->regs = DDB_LINK_TAG(link) |
(regmap->i2c->base + regmap->i2c->size * i);
ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING);
ddbwritel(dev, ((i2c->rbuf & 0xffff) << 16) | (i2c->wbuf & 0xffff),
i2c->regs + I2C_TASKADDRESS);
init_completion(&i2c->completion);
adap = &i2c->adap;
i2c_set_adapdata(adap, i2c);
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
#else
#ifdef I2C_CLASS_TV_ANALOG
adap->class = I2C_CLASS_TV_ANALOG;
#endif
#endif
snprintf(adap->name, I2C_NAME_SIZE, "ddbridge_%02x.%x.%x",
dev->nr, i2c->link, i);
adap->algo = &ddb_i2c_algo;
adap->algo_data = (void *)i2c;
adap->dev.parent = dev->dev;
return i2c_add_adapter(adap);
}
int ddb_i2c_init(struct ddb *dev)
{
int i, j, stat = 0;
int stat = 0;
u32 i, j, num = 0, l, base;
struct ddb_i2c *i2c;
struct i2c_adapter *adap;
struct ddb_regmap *regmap;
for (i = 0; i < dev->info->port_num; i++) {
i2c = &dev->i2c[i];
i2c->dev = dev;
i2c->nr = i;
i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4);
i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8);
i2c->regs = 0x80 + i * 0x20;
ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING);
ddbwritel((i2c->rbuf << 16) | i2c->wbuf,
i2c->regs + I2C_TASKADDRESS);
init_waitqueue_head(&i2c->wq);
adap = &i2c->adap;
i2c_set_adapdata(adap, i2c);
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
#else
#ifdef I2C_CLASS_TV_ANALOG
adap->class = I2C_CLASS_TV_ANALOG;
#endif
#endif
strcpy(adap->name, "ddbridge");
adap->algo = &ddb_i2c_algo;
adap->algo_data = (void *)i2c;
adap->dev.parent = &dev->pdev->dev;
stat = i2c_add_adapter(adap);
if (stat)
break;
for (l = 0; l < DDB_MAX_LINK; l++) {
if (!dev->link[l].info)
continue;
regmap = dev->link[l].info->regmap;
if (!regmap || !regmap->i2c)
continue;
base = regmap->irq_base_i2c;
for (i = 0; i < regmap->i2c->num; i++) {
if (!(dev->link[l].info->i2c_mask & (1 << i)))
continue;
i2c = &dev->i2c[num];
dev->handler_data[l][i + base] = (unsigned long) i2c;
dev->handler[l][i + base] = i2c_handler;
stat = ddb_i2c_add(dev, i2c, regmap, l, i, num);
if (stat)
break;
num++;
}
}
if (stat)
for (j = 0; j < i; j++) {
if (stat) {
for (j = 0; j < num; j++) {
i2c = &dev->i2c[j];
adap = &i2c->adap;
i2c_del_adapter(adap);
}
} else
dev->i2c_num = num;
return stat;
}

View file

@ -1,20 +1,19 @@
/*
* ddbridge.c: Digital Devices PCIe bridge driver
* ddbridge-i2c.c: Digital Devices bridge i2c driver
*
* Copyright (C) 2010-2011 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* To obtain the license, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef __DDBRIDGE_I2C_H__
@ -70,24 +69,26 @@ static int __maybe_unused i2c_read_regs(struct i2c_adapter *adapter,
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
}
static int __maybe_unused i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
u8 reg, u8 *val)
{
return i2c_read_regs(adapter, adr, reg, val, 1);
}
static int __maybe_unused i2c_read_reg16(struct i2c_adapter *adapter,
u8 adr, u16 reg, u8 *val)
static int __maybe_unused i2c_read_regs16(struct i2c_adapter *adapter,
u8 adr, u16 reg, u8 *val, u8 len)
{
u8 msg[2] = { reg >> 8, reg & 0xff };
struct i2c_msg msgs[2] = { { .addr = adr, .flags = 0,
.buf = msg, .len = 2 },
{ .addr = adr, .flags = I2C_M_RD,
.buf = val, .len = 1 } };
.buf = val, .len = len } };
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
}
static int __maybe_unused i2c_write_reg16(struct i2c_adapter *adap,
u8 adr, u16 reg, u8 val)
{
u8 msg[3] = { reg >> 8, reg & 0xff, val };
return i2c_write(adap, adr, msg, 3);
}
static int __maybe_unused i2c_write_reg(struct i2c_adapter *adap,
u8 adr, u8 reg, u8 val)
{
@ -96,4 +97,16 @@ static int __maybe_unused i2c_write_reg(struct i2c_adapter *adap,
return i2c_write(adap, adr, msg, 2);
}
static int __maybe_unused i2c_read_reg16(struct i2c_adapter *adapter,
u8 adr, u16 reg, u8 *val)
{
return i2c_read_regs16(adapter, adr, reg, val, 1);
}
static int __maybe_unused i2c_read_reg(struct i2c_adapter *adapter,
u8 adr, u8 reg, u8 *val)
{
return i2c_read_regs(adapter, adr, reg, val, 1);
}
#endif /* __DDBRIDGE_I2C_H__ */

View file

@ -1,20 +1,19 @@
/*
* ddbridge.c: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2011 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 only, as published by the Free Software Foundation.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* To obtain the license, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@ -37,15 +36,56 @@
#include "ddbridge-i2c.h"
#include "ddbridge-regs.h"
/****************************************************************************/
/* module parameters */
int adapter_alloc;
module_param(adapter_alloc, int, 0444);
MODULE_PARM_DESC(adapter_alloc,
"0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all");
#ifdef CONFIG_PCI_MSI
int msi = 1;
module_param(msi, int, 0444);
MODULE_PARM_DESC(msi,
" Control MSI interrupts: 0-disable, 1-enable (default)");
#endif
int ci_bitrate = 70000;
module_param(ci_bitrate, int, 0444);
MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI.");
int ts_loop = -1;
module_param(ts_loop, int, 0444);
MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop");
int xo2_speed = 2;
module_param(xo2_speed, int, 0444);
MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards");
#ifdef __arm__
int alt_dma = 1;
#else
int alt_dma;
#endif
module_param(alt_dma, int, 0444);
MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling");
int no_init;
module_param(no_init, int, 0444);
MODULE_PARM_DESC(no_init, "do not initialize most devices");
int stv0910_single;
module_param(stv0910_single, int, 0444);
MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods");
/******************************************************************************/
/****************************************************************************/
struct workqueue_struct *ddb_wq;
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static void ddb_unmap(struct ddb *dev)
{
@ -54,170 +94,261 @@ static void ddb_unmap(struct ddb *dev)
vfree(dev);
}
static void ddb_remove(struct pci_dev *pdev)
static void ddb_irq_disable(struct ddb *dev)
{
struct ddb *dev = pci_get_drvdata(pdev);
ddbwritel(dev, 0, INTERRUPT_ENABLE);
ddbwritel(dev, 0, MSI1_ENABLE);
}
ddb_ports_detach(dev);
ddb_i2c_release(dev);
ddbwritel(0, INTERRUPT_ENABLE);
static void ddb_irq_exit(struct ddb *dev)
{
ddb_irq_disable(dev);
if (dev->msi == 2)
free_irq(dev->pdev->irq + 1, dev);
free_irq(dev->pdev->irq, dev);
#ifdef CONFIG_PCI_MSI
if (dev->msi)
pci_disable_msi(dev->pdev);
#endif
}
static void ddb_remove(struct pci_dev *pdev)
{
struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
ddb_device_destroy(dev);
ddb_ports_detach(dev);
ddb_i2c_release(dev);
ddb_irq_exit(dev);
ddb_ports_release(dev);
ddb_buffers_free(dev);
ddb_device_destroy(dev);
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
#ifdef CONFIG_PCI_MSI
static void ddb_irq_msi(struct ddb *dev, int nr)
{
int stat;
static int ddb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (msi && pci_msi_enabled()) {
stat = pci_alloc_irq_vectors(dev->pdev, 1, nr, PCI_IRQ_MSI);
if (stat >= 1) {
dev->msi = stat;
dev_info(dev->dev, "using %d MSI interrupt(s)\n",
dev->msi);
} else
dev_info(dev->dev, "MSI not available.\n");
}
}
#endif
static int ddb_irq_init(struct ddb *dev)
{
int stat;
int irq_flag = IRQF_SHARED;
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
ddbwritel(dev, 0x00000000, MSI2_ENABLE);
ddbwritel(dev, 0x00000000, MSI3_ENABLE);
ddbwritel(dev, 0x00000000, MSI4_ENABLE);
ddbwritel(dev, 0x00000000, MSI5_ENABLE);
ddbwritel(dev, 0x00000000, MSI6_ENABLE);
ddbwritel(dev, 0x00000000, MSI7_ENABLE);
#ifdef CONFIG_PCI_MSI
ddb_irq_msi(dev, 2);
if (dev->msi)
irq_flag = 0;
if (dev->msi == 2) {
stat = request_irq(dev->pdev->irq, ddb_irq_handler0,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0)
return stat;
stat = request_irq(dev->pdev->irq + 1, ddb_irq_handler1,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0) {
free_irq(dev->pdev->irq, dev);
return stat;
}
} else
#endif
{
stat = request_irq(dev->pdev->irq, ddb_irq_handler,
irq_flag, "ddbridge", (void *) dev);
if (stat < 0)
return stat;
}
if (dev->msi == 2) {
ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE);
ddbwritel(dev, 0x0000000f, MSI1_ENABLE);
} else {
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
}
return stat;
}
static int ddb_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct ddb *dev;
int stat = 0;
int irq_flag = IRQF_SHARED;
if (pci_enable_device(pdev) < 0)
return -ENODEV;
pci_set_master(pdev);
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
return -ENODEV;
dev = vzalloc(sizeof(struct ddb));
if (dev == NULL)
return -ENOMEM;
mutex_init(&dev->mutex);
dev->has_dma = 1;
dev->pdev = pdev;
dev->dev = &pdev->dev;
pci_set_drvdata(pdev, dev);
dev->info = (struct ddb_info *) id->driver_data;
dev_info(&pdev->dev, "Detected %s\n", dev->info->name);
dev->link[0].ids.vendor = id->vendor;
dev->link[0].ids.device = id->device;
dev->link[0].ids.subvendor = id->subvendor;
dev->link[0].ids.subdevice = id->subdevice;
dev->link[0].dev = dev;
dev->link[0].info = (struct ddb_info *) id->driver_data;
dev_info(&pdev->dev, "detected %s\n", dev->link[0].info->name);
dev->regs_len = pci_resource_len(dev->pdev, 0);
dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
pci_resource_len(dev->pdev, 0));
if (!dev->regs) {
dev_err(&pdev->dev, "not enough memory for register map\n");
stat = -ENOMEM;
goto fail;
}
dev_info(&pdev->dev, "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4));
#ifdef CONFIG_PCI_MSI
if (pci_msi_enabled())
stat = pci_enable_msi(dev->pdev);
if (stat) {
dev_info(&pdev->dev, "MSI not available.\n");
} else {
irq_flag = 0;
dev->msi = 1;
if (ddbreadl(dev, 0) == 0xffffffff) {
dev_err(&pdev->dev, "cannot read registers\n");
stat = -ENODEV;
goto fail;
}
#endif
stat = request_irq(dev->pdev->irq, irq_handler,
irq_flag, "DDBridge", (void *) dev);
dev->link[0].ids.hwid = ddbreadl(dev, 0);
dev->link[0].ids.regmapid = ddbreadl(dev, 4);
dev_info(&pdev->dev, "HW %08x REGMAP %08x\n",
dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
ddbwritel(dev, 0, DMA_BASE_READ);
ddbwritel(dev, 0, DMA_BASE_WRITE);
stat = ddb_irq_init(dev);
if (stat < 0)
goto fail1;
ddbwritel(0, DMA_BASE_WRITE);
ddbwritel(0, DMA_BASE_READ);
ddbwritel(0xffffffff, INTERRUPT_ACK);
ddbwritel(0xfff0f, INTERRUPT_ENABLE);
ddbwritel(0, MSI1_ENABLE);
goto fail0;
/* board control */
if (dev->info->board_control) {
ddbwritel(0, DDB_LINK_TAG(0) | BOARD_CONTROL);
msleep(100);
ddbwritel(dev->info->board_control_2,
DDB_LINK_TAG(0) | BOARD_CONTROL);
usleep_range(2000, 3000);
ddbwritel(dev->info->board_control_2
| dev->info->board_control,
DDB_LINK_TAG(0) | BOARD_CONTROL);
usleep_range(2000, 3000);
}
if (ddb_init(dev) == 0)
return 0;
if (ddb_i2c_init(dev) < 0)
goto fail1;
ddb_ports_init(dev);
if (ddb_buffers_alloc(dev) < 0) {
dev_err(&pdev->dev, "Could not allocate buffer memory\n");
goto fail2;
}
if (ddb_ports_attach(dev) < 0)
goto fail3;
ddb_device_create(dev);
return 0;
fail3:
ddb_ports_detach(dev);
dev_err(&pdev->dev, "fail3\n");
ddb_ports_release(dev);
fail2:
dev_err(&pdev->dev, "fail2\n");
ddb_buffers_free(dev);
fail1:
dev_err(&pdev->dev, "fail1\n");
ddb_irq_exit(dev);
fail0:
dev_err(&pdev->dev, "fail0\n");
if (dev->msi)
pci_disable_msi(dev->pdev);
if (stat == 0)
free_irq(dev->pdev->irq, dev);
fail:
dev_err(&pdev->dev, "fail\n");
ddb_unmap(dev);
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
return -1;
}
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
static const struct ddb_info ddb_none = {
.type = DDB_NONE,
.name = "Digital Devices PCIe bridge",
.name = "unknown Digital Devices PCIe card, install newer driver",
.regmap = &octopus_map,
};
static const struct ddb_info ddb_octopus = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static const struct ddb_info ddb_octopusv3 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus V3 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static const struct ddb_info ddb_octopus_le = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus LE DVB adapter",
.regmap = &octopus_map,
.port_num = 2,
.i2c_mask = 0x03,
};
static const struct ddb_info ddb_octopus_oem = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus OEM",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.led_num = 1,
.fan_num = 1,
.temp_num = 1,
.temp_bus = 0,
};
static const struct ddb_info ddb_octopus_mini = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus Mini",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static const struct ddb_info ddb_v6 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V6 DVB adapter",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x07,
};
static const struct ddb_info ddb_v6_5 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V6.5 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
};
static const struct ddb_info ddb_v7 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V7 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 2,
.board_control_2 = 4,
.ts_quirks = TS_QUIRK_REVERSED,
@ -226,22 +357,20 @@ static const struct ddb_info ddb_v7 = {
static const struct ddb_info ddb_v7a = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V7 Advanced DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 2,
.board_control_2 = 4,
.ts_quirks = TS_QUIRK_REVERSED,
};
static const struct ddb_info ddb_dvbct = {
.type = DDB_OCTOPUS,
.name = "Digital Devices DVBCT V6.1 DVB adapter",
.port_num = 3,
};
static const struct ddb_info ddb_ctv7 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine CT V7 DVB adapter",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 3,
.board_control_2 = 4,
};
@ -249,134 +378,217 @@ static const struct ddb_info ddb_ctv7 = {
static const struct ddb_info ddb_satixS2v3 = {
.type = DDB_OCTOPUS,
.name = "Mystique SaTiX-S2 V3 DVB adapter",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x07,
};
static const struct ddb_info ddb_octopusv3 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Octopus V3 DVB adapter",
static const struct ddb_info ddb_ci = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x03,
};
/*** MaxA8 adapters ***********************************************************/
static const struct ddb_info ddb_cis = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI single",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x03,
};
static const struct ddb_info ddb_ci_s2_pro = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI S2 Pro",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 2,
.board_control_2 = 4,
};
static const struct ddb_info ddb_ci_s2_pro_a = {
.type = DDB_OCTOPUS_CI,
.name = "Digital Devices Octopus CI S2 Pro Advanced",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x01,
.board_control = 2,
.board_control_2 = 4,
};
static const struct ddb_info ddb_dvbct = {
.type = DDB_OCTOPUS,
.name = "Digital Devices DVBCT V6.1 DVB adapter",
.regmap = &octopus_map,
.port_num = 3,
.i2c_mask = 0x07,
};
/****************************************************************************/
static struct ddb_info ddb_ct2_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 CT2",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
static struct ddb_info ddb_c2t2_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 C2T2",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
static struct ddb_info ddb_isdbt_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 ISDBT",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
static struct ddb_info ddb_c2t2i_v0_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 C2T2I V0",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL | TS_QUIRK_ALT_OSC,
.tempmon_irq = 24,
};
static struct ddb_info ddb_c2t2i_8 = {
.type = DDB_OCTOPUS_MAX_CT,
.name = "Digital Devices MAX A8 C2T2I",
.regmap = &octopus_map,
.port_num = 4,
.i2c_mask = 0x0f,
.board_control = 0x0ff,
.board_control_2 = 0xf00,
.ts_quirks = TS_QUIRK_SERIAL,
.tempmon_irq = 24,
};
/******************************************************************************/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
#define DDVID 0xdd01 /* Digital Devices Vendor ID */
#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \
.vendor = _vend, .device = _dev, \
.subvendor = _subvend, .subdevice = _subdev, \
.driver_data = (unsigned long)&_driverdata }
#define DDB_DEVICE(_device, _subdevice, _driver_data) { \
PCI_DEVICE_SUB(DDVID, _device, DDVID, _subdevice), \
.driver_data = (kernel_ulong_t) &_driver_data }
static const struct pci_device_id ddb_id_tbl[] = {
DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
DDB_ID(DDVID, 0x0005, DDVID, 0x0004, ddb_octopusv3),
DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem),
DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini),
DDB_ID(DDVID, 0x0005, DDVID, 0x0011, ddb_octopus_mini),
DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
DDB_ID(DDVID, 0x0003, DDVID, 0x0021, ddb_v6_5),
DDB_ID(DDVID, 0x0006, DDVID, 0x0022, ddb_v7),
DDB_ID(DDVID, 0x0006, DDVID, 0x0024, ddb_v7a),
DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct),
DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3),
DDB_ID(DDVID, 0x0006, DDVID, 0x0031, ddb_ctv7),
DDB_ID(DDVID, 0x0006, DDVID, 0x0032, ddb_ctv7),
DDB_ID(DDVID, 0x0006, DDVID, 0x0033, ddb_ctv7),
DDB_ID(DDVID, 0x0008, DDVID, 0x0034, ddb_ct2_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0035, ddb_c2t2_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0036, ddb_isdbt_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0037, ddb_c2t2i_v0_8),
DDB_ID(DDVID, 0x0008, DDVID, 0x0038, ddb_c2t2i_8),
DDB_ID(DDVID, 0x0006, DDVID, 0x0039, ddb_ctv7),
#define DDB_DEVICE_ANY(_device) { \
PCI_DEVICE_SUB(DDVID, _device, DDVID, PCI_ANY_ID), \
.driver_data = (kernel_ulong_t) &ddb_none }
static const struct pci_device_id ddb_id_table[] = {
DDB_DEVICE(0x0002, 0x0001, ddb_octopus),
DDB_DEVICE(0x0003, 0x0001, ddb_octopus),
DDB_DEVICE(0x0005, 0x0004, ddb_octopusv3),
DDB_DEVICE(0x0003, 0x0002, ddb_octopus_le),
DDB_DEVICE(0x0003, 0x0003, ddb_octopus_oem),
DDB_DEVICE(0x0003, 0x0010, ddb_octopus_mini),
DDB_DEVICE(0x0005, 0x0011, ddb_octopus_mini),
DDB_DEVICE(0x0003, 0x0020, ddb_v6),
DDB_DEVICE(0x0003, 0x0021, ddb_v6_5),
DDB_DEVICE(0x0006, 0x0022, ddb_v7),
DDB_DEVICE(0x0006, 0x0024, ddb_v7a),
DDB_DEVICE(0x0003, 0x0030, ddb_dvbct),
DDB_DEVICE(0x0003, 0xdb03, ddb_satixS2v3),
DDB_DEVICE(0x0006, 0x0031, ddb_ctv7),
DDB_DEVICE(0x0006, 0x0032, ddb_ctv7),
DDB_DEVICE(0x0006, 0x0033, ddb_ctv7),
DDB_DEVICE(0x0008, 0x0034, ddb_ct2_8),
DDB_DEVICE(0x0008, 0x0035, ddb_c2t2_8),
DDB_DEVICE(0x0008, 0x0036, ddb_isdbt_8),
DDB_DEVICE(0x0008, 0x0037, ddb_c2t2i_v0_8),
DDB_DEVICE(0x0008, 0x0038, ddb_c2t2i_8),
DDB_DEVICE(0x0006, 0x0039, ddb_ctv7),
DDB_DEVICE(0x0011, 0x0040, ddb_ci),
DDB_DEVICE(0x0011, 0x0041, ddb_cis),
DDB_DEVICE(0x0012, 0x0042, ddb_ci),
DDB_DEVICE(0x0013, 0x0043, ddb_ci_s2_pro),
DDB_DEVICE(0x0013, 0x0044, ddb_ci_s2_pro_a),
/* in case sub-ids got deleted in flash */
DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0005, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0006, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0007, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0008, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0011, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0013, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0201, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
DDB_DEVICE_ANY(0x0003),
DDB_DEVICE_ANY(0x0005),
DDB_DEVICE_ANY(0x0006),
DDB_DEVICE_ANY(0x0007),
DDB_DEVICE_ANY(0x0008),
DDB_DEVICE_ANY(0x0011),
DDB_DEVICE_ANY(0x0012),
DDB_DEVICE_ANY(0x0013),
DDB_DEVICE_ANY(0x0201),
DDB_DEVICE_ANY(0x0203),
DDB_DEVICE_ANY(0x0210),
DDB_DEVICE_ANY(0x0220),
DDB_DEVICE_ANY(0x0320),
DDB_DEVICE_ANY(0x0321),
DDB_DEVICE_ANY(0x0322),
DDB_DEVICE_ANY(0x0323),
DDB_DEVICE_ANY(0x0328),
DDB_DEVICE_ANY(0x0329),
{0}
};
MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
MODULE_DEVICE_TABLE(pci, ddb_id_table);
static struct pci_driver ddb_pci_driver = {
.name = "DDBridge",
.id_table = ddb_id_tbl,
.name = "ddbridge",
.id_table = ddb_id_table,
.probe = ddb_probe,
.remove = ddb_remove,
};
static __init int module_init_ddbridge(void)
{
int ret;
int stat = -1;
pr_info("Digital Devices PCIE bridge driver, Copyright (C) 2010-11 Digital Devices GmbH\n");
ret = ddb_class_create();
if (ret < 0)
return ret;
ret = pci_register_driver(&ddb_pci_driver);
if (ret < 0)
ddb_class_destroy();
return ret;
pr_info("Digital Devices PCIE bridge driver "
DDBRIDGE_VERSION
", Copyright (C) 2010-17 Digital Devices GmbH\n");
if (ddb_class_create() < 0)
return -1;
ddb_wq = create_workqueue("ddbridge");
if (ddb_wq == NULL)
goto exit1;
stat = pci_register_driver(&ddb_pci_driver);
if (stat < 0)
goto exit2;
return stat;
exit2:
destroy_workqueue(ddb_wq);
exit1:
ddb_class_destroy();
return stat;
}
static __exit void module_exit_ddbridge(void)
{
pci_unregister_driver(&ddb_pci_driver);
destroy_workqueue(ddb_wq);
ddb_class_destroy();
}
@ -384,6 +596,6 @@ module_init(module_init_ddbridge);
module_exit(module_exit_ddbridge);
MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
MODULE_AUTHOR("Ralph Metzler");
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.5");
MODULE_VERSION(DDBRIDGE_VERSION);

View file

@ -1,7 +1,7 @@
/*
* ddbridge-regs.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2011 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,35 +17,41 @@
* http://www.gnu.org/copyleft/gpl.html
*/
/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */
/* Register Definitions */
#define CUR_REGISTERMAP_VERSION 0x10000
#define HARDWARE_VERSION 0x00
#define REGISTERMAP_VERSION 0x04
/* ------------------------------------------------------------------------- */
/* SPI Controller */
#define SPI_CONTROL 0x10
#define SPI_DATA 0x14
/* ------------------------------------------------------------------------- */
/* GPIO */
#define GPIO_OUTPUT 0x20
#define GPIO_INPUT 0x24
#define GPIO_DIRECTION 0x28
/* ------------------------------------------------------------------------- */
/* MDIO */
#define MDIO_CTRL 0x20
#define MDIO_ADR 0x24
#define MDIO_REG 0x28
#define MDIO_VAL 0x2C
/* ------------------------------------------------------------------------- */
#define BOARD_CONTROL 0x30
/* ------------------------------------------------------------------------- */
/* Interrupt controller */
/* How many MSI's are available depends on HW (Min 2 max 8) */
/* How many are usable also depends on Host platform */
/* Interrupt controller
* How many MSI's are available depends on HW (Min 2 max 8)
* How many are usable also depends on Host platform
*/
#define INTERRUPT_BASE (0x40)
#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00)
#define MSI0_ENABLE (INTERRUPT_BASE + 0x00)
#define MSI1_ENABLE (INTERRUPT_BASE + 0x04)
#define MSI2_ENABLE (INTERRUPT_BASE + 0x08)
#define MSI3_ENABLE (INTERRUPT_BASE + 0x0C)
@ -57,59 +63,31 @@
#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20)
#define INTERRUPT_ACK (INTERRUPT_BASE + 0x20)
#define INTMASK_I2C1 (0x00000001)
#define INTMASK_I2C2 (0x00000002)
#define INTMASK_I2C3 (0x00000004)
#define INTMASK_I2C4 (0x00000008)
/* Temperature Monitor ( 2x LM75A @ 0x90,0x92 I2c ) */
#define TEMPMON_BASE (0x1c0)
#define TEMPMON_CONTROL (TEMPMON_BASE + 0x00)
#define INTMASK_CIRQ1 (0x00000010)
#define INTMASK_CIRQ2 (0x00000020)
#define INTMASK_CIRQ3 (0x00000040)
#define INTMASK_CIRQ4 (0x00000080)
#define TEMPMON_CONTROL_AUTOSCAN (0x00000002)
#define TEMPMON_CONTROL_INTENABLE (0x00000004)
#define TEMPMON_CONTROL_OVERTEMP (0x00008000)
#define INTMASK_TSINPUT1 (0x00000100)
#define INTMASK_TSINPUT2 (0x00000200)
#define INTMASK_TSINPUT3 (0x00000400)
#define INTMASK_TSINPUT4 (0x00000800)
#define INTMASK_TSINPUT5 (0x00001000)
#define INTMASK_TSINPUT6 (0x00002000)
#define INTMASK_TSINPUT7 (0x00004000)
#define INTMASK_TSINPUT8 (0x00008000)
/* SHORT Temperature in Celsius x 256 */
#define TEMPMON_SENSOR0 (TEMPMON_BASE + 0x04)
#define TEMPMON_SENSOR1 (TEMPMON_BASE + 0x08)
#define INTMASK_TSOUTPUT1 (0x00010000)
#define INTMASK_TSOUTPUT2 (0x00020000)
#define INTMASK_TSOUTPUT3 (0x00040000)
#define INTMASK_TSOUTPUT4 (0x00080000)
#define TEMPMON_FANCONTROL (TEMPMON_BASE + 0x10)
/* ------------------------------------------------------------------------- */
/* I2C Master Controller */
#define I2C_BASE (0x80) /* Byte offset */
#define I2C_COMMAND (0x00)
#define I2C_TIMING (0x04)
#define I2C_TASKLENGTH (0x08) /* High read, low write */
#define I2C_TASKADDRESS (0x0C) /* High read, low write */
#define I2C_MONITOR (0x1C)
#define I2C_BASE_1 (I2C_BASE + 0x00)
#define I2C_BASE_2 (I2C_BASE + 0x20)
#define I2C_BASE_3 (I2C_BASE + 0x40)
#define I2C_BASE_4 (I2C_BASE + 0x60)
#define I2C_BASE_N(i) (I2C_BASE + (i) * 0x20)
#define I2C_TASKMEM_BASE (0x1000) /* Byte offset */
#define I2C_TASKMEM_SIZE (0x1000)
#define I2C_SPEED_400 (0x04030404)
#define I2C_SPEED_200 (0x09080909)
#define I2C_SPEED_154 (0x0C0B0C0C)
#define I2C_SPEED_100 (0x13121313)
#define I2C_SPEED_77 (0x19181919)
#define I2C_SPEED_50 (0x27262727)
/* ------------------------------------------------------------------------- */
/* DMA Controller */
@ -117,35 +95,41 @@
#define DMA_BASE_WRITE (0x100)
#define DMA_BASE_READ (0x140)
#define DMA_CONTROL (0x00) /* 64 */
#define DMA_ERROR (0x04) /* 65 ( only read instance ) */
#define DMA_DIAG_CONTROL (0x1C) /* 71 */
#define DMA_DIAG_PACKETCOUNTER_LOW (0x20) /* 72 */
#define DMA_DIAG_PACKETCOUNTER_HIGH (0x24) /* 73 */
#define DMA_DIAG_TIMECOUNTER_LOW (0x28) /* 74 */
#define DMA_DIAG_TIMECOUNTER_HIGH (0x2C) /* 75 */
#define DMA_DIAG_RECHECKCOUNTER (0x30) /* 76 ( Split completions on read ) */
#define DMA_DIAG_WAITTIMEOUTINIT (0x34) /* 77 */
#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38) /* 78 */
#define DMA_DIAG_WAITCOUNTER (0x3C) /* 79 */
#define TS_CONTROL(_io) (_io->regs + 0x00)
#define TS_CONTROL2(_io) (_io->regs + 0x04)
/* ------------------------------------------------------------------------- */
/* DMA Buffer */
#define TS_INPUT_BASE (0x200)
#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 16 + 0x00)
#define DMA_BUFFER_CONTROL(_dma) (_dma->regs + 0x00)
#define DMA_BUFFER_ACK(_dma) (_dma->regs + 0x04)
#define DMA_BUFFER_CURRENT(_dma) (_dma->regs + 0x08)
#define DMA_BUFFER_SIZE(_dma) (_dma->regs + 0x0c)
#define TS_OUTPUT_BASE (0x280)
#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 16 + 0x00)
/* ------------------------------------------------------------------------- */
/* CI Interface (only CI-Bridge) */
#define DMA_BUFFER_BASE (0x300)
#define CI_BASE (0x400)
#define CI_CONTROL(i) (CI_BASE + (i) * 32 + 0x00)
#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 16 + 0x00)
#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 16 + 0x04)
#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 16 + 0x08)
#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 16 + 0x0c)
#define CI_DO_ATTRIBUTE_RW(i) (CI_BASE + (i) * 32 + 0x04)
#define CI_DO_IO_RW(i) (CI_BASE + (i) * 32 + 0x08)
#define CI_READDATA(i) (CI_BASE + (i) * 32 + 0x0c)
#define CI_DO_READ_ATTRIBUTES(i) (CI_BASE + (i) * 32 + 0x10)
#define DMA_BASE_ADDRESS_TABLE (0x2000)
#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512)
#define CI_RESET_CAM (0x00000001)
#define CI_POWER_ON (0x00000002)
#define CI_ENABLE (0x00000004)
#define CI_BYPASS_DISABLE (0x00000010)
#define CI_CAM_READY (0x00010000)
#define CI_CAM_DETECT (0x00020000)
#define CI_READY (0x80000000)
#define CI_READ_CMD (0x40000000)
#define CI_WRITE_CMD (0x80000000)
#define CI_BUFFER_BASE (0x3000)
#define CI_BUFFER_SIZE (0x0800)
#define CI_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE)

View file

@ -1,7 +1,8 @@
/*
* ddbridge.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2011 Digital Devices GmbH
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rmetzler@digitaldevices.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -20,15 +21,39 @@
#ifndef _DDBRIDGE_H_
#define _DDBRIDGE_H_
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <linux/i2c.h>
#include <linux/swab.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/completion.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <asm/dma.h>
#include <linux/dvb/frontend.h>
#include <asm/irq.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/dvb/ca.h>
#include <linux/socket.h>
#include <linux/device.h>
#include <linux/io.h>
#include "dmxdev.h"
#include "dvbdev.h"
@ -37,72 +62,121 @@
#include "dvb_ringbuffer.h"
#include "dvb_ca_en50221.h"
#include "dvb_net.h"
#include "cxd2099.h"
/* MSI had problems with lost interrupts, fixed but needs testing */
#undef CONFIG_PCI_MSI
#define DDBRIDGE_VERSION "0.9.29-integrated"
#define DDB_MAX_I2C 4
#define DDB_MAX_PORT 4
#define DDB_MAX_INPUT 8
#define DDB_MAX_OUTPUT 4
#define DDB_MAX_I2C 32
#define DDB_MAX_PORT 32
#define DDB_MAX_INPUT 64
#define DDB_MAX_OUTPUT 32
#define DDB_MAX_LINK 4
#define DDB_LINK_SHIFT 28
#define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT)
#define DDB_XO2_TYPE_NONE 0
#define DDB_XO2_TYPE_DUOFLEX 1
#define DDB_XO2_TYPE_CI 2
struct ddb_regset {
u32 base;
u32 num;
u32 size;
};
struct ddb_regmap {
u32 irq_base_i2c;
u32 irq_base_idma;
u32 irq_base_odma;
struct ddb_regset *i2c;
struct ddb_regset *i2c_buf;
struct ddb_regset *idma;
struct ddb_regset *idma_buf;
struct ddb_regset *odma;
struct ddb_regset *odma_buf;
struct ddb_regset *input;
struct ddb_regset *output;
struct ddb_regset *channel;
};
struct ddb_ids {
u16 vendor;
u16 device;
u16 subvendor;
u16 subdevice;
u32 hwid;
u32 regmapid;
u32 devid;
u32 mac;
};
struct ddb_info {
int type;
#define DDB_NONE 0
#define DDB_OCTOPUS 1
#define DDB_OCTOPUS_MAX_CT 6
#define DDB_NONE 0
#define DDB_OCTOPUS 1
#define DDB_OCTOPUS_CI 2
#define DDB_OCTOPUS_MAX_CT 6
char *name;
int port_num;
u32 port_type[DDB_MAX_PORT];
u32 i2c_mask;
u8 port_num;
u8 led_num;
u8 fan_num;
u8 temp_num;
u8 temp_bus;
u32 board_control;
u32 board_control_2;
u8 mdio_num;
u8 con_clock; /* use a continuous clock */
u8 ts_quirks;
#define TS_QUIRK_SERIAL 1
#define TS_QUIRK_REVERSED 2
#define TS_QUIRK_ALT_OSC 8
u32 tempmon_irq;
struct ddb_regmap *regmap;
};
/* DMA_SIZE MUST be divisible by 188 and 128 !!! */
/* DMA_SIZE MUST be smaller than 256k and
* MUST be divisible by 188 and 128 !!!
*/
#define DMA_MAX_BUFS 32 /* hardware table limit */
#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */
#define INPUT_DMA_BUFS 8
#define INPUT_DMA_SIZE (128*47*21)
#define INPUT_DMA_IRQ_DIV 1
#define OUTPUT_DMA_MAX_BUFS 32
#define OUTPUT_DMA_BUFS 8
#define OUTPUT_DMA_SIZE (128*47*21)
#define OUTPUT_DMA_IRQ_DIV 1
struct ddb;
struct ddb_port;
struct ddb_input {
struct ddb_port *port;
u32 nr;
int attached;
struct ddb_dma {
void *io;
u32 regs;
u32 bufregs;
dma_addr_t pbuf[INPUT_DMA_MAX_BUFS];
u8 *vbuf[INPUT_DMA_MAX_BUFS];
u32 dma_buf_num;
u32 dma_buf_size;
dma_addr_t pbuf[DMA_MAX_BUFS];
u8 *vbuf[DMA_MAX_BUFS];
u32 num;
u32 size;
u32 div;
u32 bufval;
struct tasklet_struct tasklet;
struct work_struct work;
spinlock_t lock;
wait_queue_head_t wq;
int running;
u32 stat;
u32 ctrl;
u32 cbuf;
u32 coff;
};
struct dvb_adapter adap;
struct ddb_dvb {
struct dvb_adapter *adap;
int adap_registered;
struct dvb_device *dev;
struct i2c_client *i2c_client[1];
struct dvb_frontend *fe;
@ -113,131 +187,245 @@ struct ddb_input {
struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend;
int users;
int (*gate_ctrl)(struct dvb_frontend *, int);
u32 attached;
u8 input;
enum fe_sec_tone_mode tone;
enum fe_sec_voltage voltage;
int (*i2c_gate_ctrl)(struct dvb_frontend *, int);
int (*set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage);
int (*set_input)(struct dvb_frontend *fe, int input);
int (*diseqc_send_master_cmd)(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd);
};
struct ddb_output {
struct ddb_ci {
struct dvb_ca_en50221 en;
struct ddb_port *port;
u32 nr;
dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS];
u8 *vbuf[OUTPUT_DMA_MAX_BUFS];
u32 dma_buf_num;
u32 dma_buf_size;
struct tasklet_struct tasklet;
spinlock_t lock;
wait_queue_head_t wq;
int running;
u32 stat;
u32 cbuf;
u32 coff;
struct dvb_adapter adap;
struct dvb_device *dev;
struct mutex lock;
};
struct ddb_io {
struct ddb_port *port;
u32 nr;
u32 regs;
struct ddb_dma *dma;
struct ddb_io *redo;
struct ddb_io *redi;
};
#define ddb_output ddb_io
#define ddb_input ddb_io
struct ddb_i2c {
struct ddb *dev;
u32 nr;
struct i2c_adapter adap;
struct i2c_adapter adap2;
u32 regs;
u32 link;
struct i2c_adapter adap;
u32 rbuf;
u32 wbuf;
int done;
wait_queue_head_t wq;
u32 bsize;
struct completion completion;
};
struct ddb_port {
struct ddb *dev;
u32 nr;
u32 pnr;
u32 regs;
u32 lnr;
struct ddb_i2c *i2c;
struct mutex i2c_gate_lock;
u32 class;
#define DDB_PORT_NONE 0
#define DDB_PORT_CI 1
#define DDB_PORT_TUNER 2
u32 type;
#define DDB_TUNER_NONE 0
#define DDB_TUNER_DVBS_ST 1
#define DDB_TUNER_DVBS_ST_AA 2
#define DDB_TUNER_DVBCT2_SONY_P 7
#define DDB_TUNER_DVBC2T2_SONY_P 8
#define DDB_TUNER_ISDBT_SONY_P 9
#define DDB_TUNER_DVBS_STV0910_P 10
#define DDB_TUNER_DVBS_STV0910_PR 14
#define DDB_TUNER_DVBC2T2I_SONY_P 15
#define DDB_TUNER_DVBCT_TR 16
#define DDB_TUNER_DVBCT_ST 17
#define DDB_TUNER_XO2_DVBS_STV0910 32
#define DDB_TUNER_XO2_DVBCT2_SONY 33
#define DDB_TUNER_XO2_ISDBT_SONY 34
#define DDB_TUNER_XO2_DVBC2T2_SONY 35
#define DDB_TUNER_XO2_ATSC_ST 36
#define DDB_TUNER_XO2_DVBC2T2I_SONY 37
#define DDB_PORT_LOOP 3
char *name;
char *type_name;
u32 type;
#define DDB_TUNER_NONE 0
#define DDB_TUNER_DVBS_ST 1
#define DDB_TUNER_DVBS_ST_AA 2
#define DDB_TUNER_DVBCT_TR 3
#define DDB_TUNER_DVBCT_ST 4
#define DDB_CI_INTERNAL 5
#define DDB_CI_EXTERNAL_SONY 6
#define DDB_TUNER_DVBCT2_SONY_P 7
#define DDB_TUNER_DVBC2T2_SONY_P 8
#define DDB_TUNER_ISDBT_SONY_P 9
#define DDB_TUNER_DVBS_STV0910_P 10
#define DDB_TUNER_MXL5XX 11
#define DDB_CI_EXTERNAL_XO2 12
#define DDB_CI_EXTERNAL_XO2_B 13
#define DDB_TUNER_DVBS_STV0910_PR 14
#define DDB_TUNER_DVBC2T2I_SONY_P 15
u32 adr;
#define DDB_TUNER_XO2 32
#define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0)
#define DDB_TUNER_DVBCT2_SONY (DDB_TUNER_XO2 + 1)
#define DDB_TUNER_ISDBT_SONY (DDB_TUNER_XO2 + 2)
#define DDB_TUNER_DVBC2T2_SONY (DDB_TUNER_XO2 + 3)
#define DDB_TUNER_ATSC_ST (DDB_TUNER_XO2 + 4)
#define DDB_TUNER_DVBC2T2I_SONY (DDB_TUNER_XO2 + 5)
struct ddb_input *input[2];
struct ddb_output *output;
struct dvb_ca_en50221 *en;
struct ddb_dvb dvb[2];
u32 gap;
u32 obr;
u8 creg;
};
#define CM_STARTUP_DELAY 2
#define CM_AVERAGE 20
#define CM_GAIN 10
#define HW_LSB_SHIFT 12
#define HW_LSB_MASK 0x1000
#define CM_IDLE 0
#define CM_STARTUP 1
#define CM_ADJUST 2
#define TS_CAPTURE_LEN (4096)
struct ddb_link {
struct ddb *dev;
struct ddb_info *info;
u32 nr;
u32 regs;
spinlock_t lock;
struct mutex flash_mutex;
struct tasklet_struct tasklet;
struct ddb_ids ids;
spinlock_t temp_lock;
int overtemperature_error;
u8 temp_tab[11];
};
struct ddb {
struct pci_dev *pdev;
struct platform_device *pfdev;
struct device *dev;
int msi;
struct workqueue_struct *wq;
u32 has_dma;
struct ddb_link link[DDB_MAX_LINK];
unsigned char __iomem *regs;
u32 regs_len;
u32 port_num;
struct ddb_port port[DDB_MAX_PORT];
u32 i2c_num;
struct ddb_i2c i2c[DDB_MAX_I2C];
struct ddb_input input[DDB_MAX_INPUT];
struct ddb_output output[DDB_MAX_OUTPUT];
struct dvb_adapter adap[DDB_MAX_INPUT];
struct ddb_dma idma[DDB_MAX_INPUT];
struct ddb_dma odma[DDB_MAX_OUTPUT];
void (*handler[4][256])(unsigned long);
unsigned long handler_data[4][256];
struct device *ddb_dev;
int nr;
u32 ddb_dev_users;
u32 nr;
u8 iobuf[1028];
struct ddb_info *info;
int msi;
u8 leds;
u32 ts_irq;
u32 i2c_irq;
struct mutex mutex;
u8 tsbuf[TS_CAPTURE_LEN];
};
/****************************************************************************/
static inline u32 ddblreadl(struct ddb_link *link, u32 adr)
{
return readl((char *) (link->dev->regs + (adr)));
}
#define ddbwritel(_val, _adr) writel((_val), \
dev->regs+(_adr))
#define ddbreadl(_adr) readl(dev->regs+(_adr))
#define ddbcpyto(_adr, _src, _count) memcpy_toio(dev->regs+(_adr), (_src), (_count))
#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), dev->regs+(_adr), (_count))
static inline void ddblwritel(struct ddb_link *link, u32 val, u32 adr)
{
writel(val, (char *) (link->dev->regs + (adr)));
}
/****************************************************************************/
static inline u32 ddbreadl(struct ddb *dev, u32 adr)
{
return readl((char *) (dev->regs + (adr)));
}
static inline void ddbwritel(struct ddb *dev, u32 val, u32 adr)
{
writel(val, (char *) (dev->regs + (adr)));
}
static inline void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
{
return memcpy_toio((char *) (dev->regs + adr), src, count);
}
static inline void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
{
return memcpy_fromio(dst, (char *) (dev->regs + adr), count);
}
static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr)
{
u32 val = ddbreadl(adr);
u32 val = ddbreadl(dev, adr);
/* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */
if (val == ~0) {
dev_err(&dev->pdev->dev, "ddbreadl failure, adr=%08x\n", adr);
return 0;
}
/* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */
if (val == ~0) {
dev_err(&dev->pdev->dev, "ddbreadl failure, adr=%08x\n", adr);
return 0;
}
return val;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
/****************************************************************************/
/* ddbridge-main.c (modparams) */
extern int adapter_alloc;
extern int msi;
extern int ci_bitrate;
extern int ts_loop;
extern int xo2_speed;
extern int alt_dma;
extern int no_init;
extern int stv0910_single;
extern struct workqueue_struct *ddb_wq;
/* ddbridge-core.c */
extern struct ddb_regmap octopus_map;
void ddb_ports_detach(struct ddb *dev);
void ddb_ports_release(struct ddb *dev);
void ddb_buffers_free(struct ddb *dev);
void ddb_device_destroy(struct ddb *dev);
irqreturn_t irq_handler(int irq, void *dev_id);
irqreturn_t ddb_irq_handler0(int irq, void *dev_id);
irqreturn_t ddb_irq_handler1(int irq, void *dev_id);
irqreturn_t ddb_irq_handler(int irq, void *dev_id);
void ddb_ports_init(struct ddb *dev);
int ddb_buffers_alloc(struct ddb *dev);
int ddb_ports_attach(struct ddb *dev);
int ddb_device_create(struct ddb *dev);
int ddb_class_create(void);
void ddb_class_destroy(void);
int ddb_init(struct ddb *dev);
#endif
#endif /* DDBRIDGE_H */