All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/19] dddvb/ddbridge-0.9.33
@ 2018-04-09 16:47 Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 01/19] [media] dvb-frontends/stv0910: add init values for TSINSDELM/L Daniel Scheller
                   ` (18 more replies)
  0 siblings, 19 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

This series brings all relevant changes from the upstream dddvb-0.9.33
driver package to the in-kernel ddbridge and stv0910, though a few changes
were picked up and merged previously already.

Summary of changes:
* stv0910: initialisation fixes and fixed CNR reporting (uvalue vs.
  svalue)
* ddbridge: general code move, cleanups and fixups
* ddbridge: fixes and improvements to the IRQ setup and handling, and
  MSI-X support
* ddbridge: configurable DMA buffers (via modparam)
* ddbridge: dummy tuner option, useful for debugging and stress testing
  purposes
* ddbridge: support for the new MCI card types, and namely the new MaxSX8
  cards

Patches were build-tested in their order and are bisect safe. Besides the
modparam move, everything is picked up from dddvb-0.9.33.

The series adds the new ddbridge-mci.[c|h] files. Here, SPDX headers were
already put in place, but until things have been fully sorted out, the
original GPL boiler plate is kept in place for now.

Changes since v1:
* The "stv0910: increase parallel TS output speed" commit was deleted,
  as it causes non-working cineS2V7 cards with older card/FPGA firmware.

Please pick up and merge.

Daniel Scheller (19):
  [media] dvb-frontends/stv0910: add init values for TSINSDELM/L
  [media] dvb-frontends/stv0910: fix CNR reporting in read_snr()
  [media] ddbridge: move modparams to ddbridge-core.c
  [media] ddbridge: move ddb_wq and the wq+class initialisation to -core
  [media] ddbridge: move MSI IRQ cleanup to a helper function
  [media] ddbridge: request/free_irq using pci_irq_vector, enable MSI-X
  [media] ddbridge: add helper for IRQ handler setup
  [media] ddbridge: add macros to handle IRQs in nibble and byte blocks
  [media] ddbridge: improve separated MSI IRQ handling
  [media] ddbridge: use spin_lock_irqsave() in output_work()
  [media] ddbridge: fix output buffer check
  [media] ddbridge: set devid entry for link 0
  [media] ddbridge: make DMA buffer count and size modparam-configurable
  [media] ddbridge: support dummy tuners with 125MByte/s dummy data
    stream
  [media] ddbridge: initial support for MCI-based MaxSX8 cards
  [media] ddbridge/max: implement MCI/MaxSX8 attach function
  [media] ddbridge: add hardware defs and PCI IDs for MCI cards
  [media] ddbridge: recognize and attach the MaxSX8 cards
  [media] ddbridge: set driver version to 0.9.33-integrated

 drivers/media/dvb-frontends/stv0910.c      |   8 +-
 drivers/media/pci/ddbridge/Kconfig         |   1 +
 drivers/media/pci/ddbridge/Makefile        |   2 +-
 drivers/media/pci/ddbridge/ddbridge-core.c | 299 +++++++++++-----
 drivers/media/pci/ddbridge/ddbridge-hw.c   |  11 +
 drivers/media/pci/ddbridge/ddbridge-i2c.c  |   5 +-
 drivers/media/pci/ddbridge/ddbridge-main.c |  91 ++---
 drivers/media/pci/ddbridge/ddbridge-max.c  |  42 +++
 drivers/media/pci/ddbridge/ddbridge-max.h  |   1 +
 drivers/media/pci/ddbridge/ddbridge-mci.c  | 550 +++++++++++++++++++++++++++++
 drivers/media/pci/ddbridge/ddbridge-mci.h  | 152 ++++++++
 drivers/media/pci/ddbridge/ddbridge.h      |  50 +--
 12 files changed, 1029 insertions(+), 183 deletions(-)
 create mode 100644 drivers/media/pci/ddbridge/ddbridge-mci.c
 create mode 100644 drivers/media/pci/ddbridge/ddbridge-mci.h

-- 
2.16.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v2 01/19] [media] dvb-frontends/stv0910: add init values for TSINSDELM/L
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 02/19] [media] dvb-frontends/stv0910: fix CNR reporting in read_snr() Daniel Scheller
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

The TSINSDEL registers were lacking initialisation in the stv0910 demod
driver. Initialise them (both demods) in the probe() function.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/dvb-frontends/stv0910.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c
index 52355c14fd64..f5b5ce971c0c 100644
--- a/drivers/media/dvb-frontends/stv0910.c
+++ b/drivers/media/dvb-frontends/stv0910.c
@@ -1220,6 +1220,12 @@ static int probe(struct stv *state)
 	write_reg(state, RSTV0910_P1_I2CRPT, state->i2crpt);
 	write_reg(state, RSTV0910_P2_I2CRPT, state->i2crpt);
 
+	write_reg(state, RSTV0910_P1_TSINSDELM, 0x17);
+	write_reg(state, RSTV0910_P1_TSINSDELL, 0xff);
+
+	write_reg(state, RSTV0910_P2_TSINSDELM, 0x17);
+	write_reg(state, RSTV0910_P2_TSINSDELL, 0xff);
+
 	init_diseqc(state);
 	return 0;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 02/19] [media] dvb-frontends/stv0910: fix CNR reporting in read_snr()
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 01/19] [media] dvb-frontends/stv0910: add init values for TSINSDELM/L Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 03/19] [media] ddbridge: move modparams to ddbridge-core.c Daniel Scheller
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

The CNR value determined in read_snr() is reported via the wrong variable.
It uses FE_SCALE_DECIBEL, which implies the value to be reported in svalue
instead of uvalue. Fix this accordingly.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/dvb-frontends/stv0910.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c
index f5b5ce971c0c..1d96ae9f9f6e 100644
--- a/drivers/media/dvb-frontends/stv0910.c
+++ b/drivers/media/dvb-frontends/stv0910.c
@@ -1326,7 +1326,7 @@ static int read_snr(struct dvb_frontend *fe)
 
 	if (!get_signal_to_noise(state, &snrval)) {
 		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
-		p->cnr.stat[0].uvalue = 100 * snrval; /* fix scale */
+		p->cnr.stat[0].svalue = 100 * snrval; /* fix scale */
 	} else {
 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 	}
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 03/19] [media] ddbridge: move modparams to ddbridge-core.c
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 01/19] [media] dvb-frontends/stv0910: add init values for TSINSDELM/L Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 02/19] [media] dvb-frontends/stv0910: fix CNR reporting in read_snr() Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 04/19] [media] ddbridge: move ddb_wq and the wq+class initialisation to -core Daniel Scheller
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Besides the 'msi' module option, all options are used from within
ddbridge-core only, so move them over from ddbridge-main, and declare the
associated variables static. Since the prototypes in ddbridge.h aren't
necessary anymore now, remove them. As a side effect, this has the benefit
of aligning things more with the dddvb upstream.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 28 ++++++++++++++++++++++++++++
 drivers/media/pci/ddbridge/ddbridge-main.c | 28 ----------------------------
 drivers/media/pci/ddbridge/ddbridge.h      |  6 ------
 3 files changed, 28 insertions(+), 34 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 90687eff5909..933046d03db5 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -68,6 +68,34 @@ 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");
 
+static int ci_bitrate = 70000;
+module_param(ci_bitrate, int, 0444);
+MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI.");
+
+static int ts_loop = -1;
+module_param(ts_loop, int, 0444);
+MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop");
+
+static 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__
+static int alt_dma = 1;
+#else
+static int alt_dma;
+#endif
+module_param(alt_dma, int, 0444);
+MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling");
+
+static int no_init;
+module_param(no_init, int, 0444);
+MODULE_PARM_DESC(no_init, "do not initialize most devices");
+
+static int stv0910_single;
+module_param(stv0910_single, int, 0444);
+MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods");
+
 /****************************************************************************/
 
 static DEFINE_MUTEX(redirect_lock);
diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 26497d6b1395..bde04dc39080 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -55,34 +55,6 @@ MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable (default), 1-enable");
 #endif
 #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");
-
 /****************************************************************************/
 /****************************************************************************/
 /****************************************************************************/
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index f223dc6c9963..e22e67d7e0fe 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -369,12 +369,6 @@ int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
 /****************************************************************************/
 
 /* ddbridge-main.c (modparams) */
-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 */
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 04/19] [media] ddbridge: move ddb_wq and the wq+class initialisation to -core
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (2 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 03/19] [media] ddbridge: move modparams to ddbridge-core.c Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 05/19] [media] ddbridge: move MSI IRQ cleanup to a helper function Daniel Scheller
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Move the ddbridge module initialisation and cleanup code to ddbridge-core
and set up the ddb_wq workqueue there, and create and destroy the ddb
device class there aswell. Due to this, the prototypes for ddb_wq,
ddb_class_create() and ddb_class_destroy() aren't required in ddbridge.h
anymore, so remove them. Also, declare ddb_wq and the ddb_class_*()
functions static.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 32 +++++++++++++++++++++++++++---
 drivers/media/pci/ddbridge/ddbridge-main.c | 21 +++++++-------------
 drivers/media/pci/ddbridge/ddbridge.h      |  7 ++-----
 3 files changed, 38 insertions(+), 22 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 933046d03db5..fb9a2cb758e6 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -100,7 +100,7 @@ MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods");
 
 static DEFINE_MUTEX(redirect_lock);
 
-struct workqueue_struct *ddb_wq;
+static struct workqueue_struct *ddb_wq;
 
 static struct ddb *ddbs[DDB_MAX_ADAPTER];
 
@@ -3055,7 +3055,7 @@ static struct class ddb_class = {
 	.devnode        = ddb_devnode,
 };
 
-int ddb_class_create(void)
+static int ddb_class_create(void)
 {
 	ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops);
 	if (ddb_major < 0)
@@ -3065,7 +3065,7 @@ int ddb_class_create(void)
 	return 0;
 }
 
-void ddb_class_destroy(void)
+static void ddb_class_destroy(void)
 {
 	class_unregister(&ddb_class);
 	unregister_chrdev(ddb_major, DDB_NAME);
@@ -3337,3 +3337,29 @@ void ddb_unmap(struct ddb *dev)
 		iounmap(dev->regs);
 	vfree(dev);
 }
+
+int ddb_exit_ddbridge(int stage, int error)
+{
+	switch (stage) {
+	default:
+	case 2:
+		destroy_workqueue(ddb_wq);
+		/* fall-through */
+	case 1:
+		ddb_class_destroy();
+		break;
+	}
+
+	return error;
+}
+
+int ddb_init_ddbridge(void)
+{
+	if (ddb_class_create() < 0)
+		return -1;
+	ddb_wq = alloc_workqueue("ddbridge", 0, 0);
+	if (!ddb_wq)
+		return ddb_exit_ddbridge(1, -1);
+
+	return 0;
+}
diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index bde04dc39080..7088162af9d3 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -282,32 +282,25 @@ static struct pci_driver ddb_pci_driver = {
 
 static __init int module_init_ddbridge(void)
 {
-	int stat = -1;
+	int stat;
 
 	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)
-		goto exit1;
+	stat = ddb_init_ddbridge();
+	if (stat < 0)
+		return stat;
 	stat = pci_register_driver(&ddb_pci_driver);
 	if (stat < 0)
-		goto exit2;
-	return stat;
-exit2:
-	destroy_workqueue(ddb_wq);
-exit1:
-	ddb_class_destroy();
+		ddb_exit_ddbridge(0, stat);
+
 	return stat;
 }
 
 static __exit void module_exit_ddbridge(void)
 {
 	pci_unregister_driver(&ddb_pci_driver);
-	destroy_workqueue(ddb_wq);
-	ddb_class_destroy();
+	ddb_exit_ddbridge(0, 0);
 }
 
 module_init(module_init_ddbridge);
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index e22e67d7e0fe..dbd5f551ce76 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -368,9 +368,6 @@ int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
 
 /****************************************************************************/
 
-/* ddbridge-main.c (modparams) */
-extern struct workqueue_struct *ddb_wq;
-
 /* ddbridge-core.c */
 void ddb_ports_detach(struct ddb *dev);
 void ddb_ports_release(struct ddb *dev);
@@ -383,9 +380,9 @@ 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);
 void ddb_unmap(struct ddb *dev);
+int ddb_exit_ddbridge(int stage, int error);
+int ddb_init_ddbridge(void);
 
 #endif /* DDBRIDGE_H */
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 05/19] [media] ddbridge: move MSI IRQ cleanup to a helper function
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (3 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 04/19] [media] ddbridge: move ddb_wq and the wq+class initialisation to -core Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 06/19] [media] ddbridge: request/free_irq using pci_irq_vector, enable MSI-X Daniel Scheller
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Introduce the ddb_msi_exit() helper to be used for cleaning up previously
allocated MSI IRQ vectors. Deduplicates code and makes things look
cleaner as for all cleanup work the CONFIG_PCI_MSI ifdeffery is only
needed in the helper now. Also, replace the call to the deprecated
pci_disable_msi() function with pci_free_irq_vectors().

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-main.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 7088162af9d3..77089081db1f 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -65,16 +65,20 @@ static void ddb_irq_disable(struct ddb *dev)
 	ddbwritel(dev, 0, MSI1_ENABLE);
 }
 
+static void ddb_msi_exit(struct ddb *dev)
+{
+#ifdef CONFIG_PCI_MSI
+	if (dev->msi)
+		pci_free_irq_vectors(dev->pdev);
+#endif
+}
+
 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)
@@ -86,6 +90,7 @@ static void ddb_remove(struct pci_dev *pdev)
 	ddb_i2c_release(dev);
 
 	ddb_irq_exit(dev);
+	ddb_msi_exit(dev);
 	ddb_ports_release(dev);
 	ddb_buffers_free(dev);
 
@@ -230,8 +235,7 @@ static int ddb_probe(struct pci_dev *pdev,
 	ddb_irq_exit(dev);
 fail0:
 	dev_err(&pdev->dev, "fail0\n");
-	if (dev->msi)
-		pci_disable_msi(dev->pdev);
+	ddb_msi_exit(dev);
 fail:
 	dev_err(&pdev->dev, "fail\n");
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 06/19] [media] ddbridge: request/free_irq using pci_irq_vector, enable MSI-X
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (4 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 05/19] [media] ddbridge: move MSI IRQ cleanup to a helper function Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 07/19] [media] ddbridge: add helper for IRQ handler setup Daniel Scheller
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Instead of trying to manage IRQ numbers on itself, utilise the
pci_irq_vector() function to do this, which will take care of correct IRQ
numbering for MSI and non-MSI IRQs. While at it, request and enable MSI-X
interrupts for hardware (boards and cards) that support this.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-main.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 77089081db1f..008be9066814 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -77,8 +77,8 @@ 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);
+		free_irq(pci_irq_vector(dev->pdev, 1), dev);
+	free_irq(pci_irq_vector(dev->pdev, 0), dev);
 }
 
 static void ddb_remove(struct pci_dev *pdev)
@@ -105,7 +105,8 @@ static void ddb_irq_msi(struct ddb *dev, int nr)
 	int stat;
 
 	if (msi && pci_msi_enabled()) {
-		stat = pci_alloc_irq_vectors(dev->pdev, 1, nr, PCI_IRQ_MSI);
+		stat = pci_alloc_irq_vectors(dev->pdev, 1, nr,
+					     PCI_IRQ_MSI | PCI_IRQ_MSIX);
 		if (stat >= 1) {
 			dev->msi = stat;
 			dev_info(dev->dev, "using %d MSI interrupt(s)\n",
@@ -137,21 +138,24 @@ static int ddb_irq_init(struct ddb *dev)
 	if (dev->msi)
 		irq_flag = 0;
 	if (dev->msi == 2) {
-		stat = request_irq(dev->pdev->irq, ddb_irq_handler0,
-				   irq_flag, "ddbridge", (void *)dev);
+		stat = request_irq(pci_irq_vector(dev->pdev, 0),
+				   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);
+		stat = request_irq(pci_irq_vector(dev->pdev, 1),
+				   ddb_irq_handler1, irq_flag, "ddbridge",
+				   (void *)dev);
 		if (stat < 0) {
-			free_irq(dev->pdev->irq, dev);
+			free_irq(pci_irq_vector(dev->pdev, 0), dev);
 			return stat;
 		}
 	} else
 #endif
 	{
-		stat = request_irq(dev->pdev->irq, ddb_irq_handler,
-				   irq_flag, "ddbridge", (void *)dev);
+		stat = request_irq(pci_irq_vector(dev->pdev, 0),
+				   ddb_irq_handler, irq_flag, "ddbridge",
+				   (void *)dev);
 		if (stat < 0)
 			return stat;
 	}
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 07/19] [media] ddbridge: add helper for IRQ handler setup
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (5 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 06/19] [media] ddbridge: request/free_irq using pci_irq_vector, enable MSI-X Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 08/19] [media] ddbridge: add macros to handle IRQs in nibble and byte blocks Daniel Scheller
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Introduce the ddb_irq_set() helper function (along with a matching
prototype in ddbridge.h) to improve the set up of the IRQ handlers
and handler_data, and rework storing this data into the ddb_link
using a new ddb_irq struct. This also does the necessary rework
of affected variables. And while at it, always do queue_work in
input_handler() as there's not much of a difference to directly
calling input_work if there's no ptr at input->redi, or queueing
this call.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 53 +++++++++++++++++-------------
 drivers/media/pci/ddbridge/ddbridge-i2c.c  |  5 ++-
 drivers/media/pci/ddbridge/ddbridge.h      | 11 +++++--
 3 files changed, 41 insertions(+), 28 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index fb9a2cb758e6..be6935bd0cb5 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -108,6 +108,16 @@ static struct ddb *ddbs[DDB_MAX_ADAPTER];
 /****************************************************************************/
 /****************************************************************************/
 
+struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
+			    void (*handler)(void *), void *data)
+{
+	struct ddb_irq *irq = &dev->link[link].irq[nr];
+
+	irq->handler = handler;
+	irq->data = data;
+	return irq;
+}
+
 static void ddb_set_dma_table(struct ddb_io *io)
 {
 	struct ddb *dev = io->port->dev;
@@ -2109,26 +2119,18 @@ static void input_work(struct work_struct *work)
 	spin_unlock_irqrestore(&dma->lock, flags);
 }
 
-static void input_handler(unsigned long data)
+static void input_handler(void *data)
 {
 	struct ddb_input *input = (struct ddb_input *)data;
 	struct ddb_dma *dma = input->dma;
 
-	/*
-	 * If there is no input connected, input_tasklet() will
-	 * just copy pointers and ACK. So, there is no need to go
-	 * through the tasklet scheduler.
-	 */
-	if (input->redi)
-		queue_work(ddb_wq, &dma->work);
-	else
-		input_work(&dma->work);
+	queue_work(ddb_wq, &dma->work);
 }
 
-static void output_handler(unsigned long data)
+static void output_work(struct work_struct *work)
 {
-	struct ddb_output *output = (struct ddb_output *)data;
-	struct ddb_dma *dma = output->dma;
+	struct ddb_dma *dma = container_of(work, struct ddb_dma, work);
+	struct ddb_output *output = (struct ddb_output *)dma->io;
 	struct ddb *dev = output->port->dev;
 
 	spin_lock(&dma->lock);
@@ -2144,6 +2146,14 @@ static void output_handler(unsigned long data)
 	spin_unlock(&dma->lock);
 }
 
+static void output_handler(void *data)
+{
+	struct ddb_output *output = (struct ddb_output *)data;
+	struct ddb_dma *dma = output->dma;
+
+	queue_work(ddb_wq, &dma->work);
+}
+
 /****************************************************************************/
 /****************************************************************************/
 
@@ -2174,6 +2184,7 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out)
 	spin_lock_init(&dma->lock);
 	init_waitqueue_head(&dma->wq);
 	if (out) {
+		INIT_WORK(&dma->work, output_work);
 		dma->regs = rm->odma->base + rm->odma->size * nr;
 		dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr;
 		dma->num = OUTPUT_DMA_BUFS;
@@ -2218,8 +2229,7 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
 		dev_dbg(dev->dev, "init link %u, input %u, handler %u\n",
 			port->lnr, nr, dma_nr + base);
 
-		dev->handler[0][dma_nr + base] = input_handler;
-		dev->handler_data[0][dma_nr + base] = (unsigned long)input;
+		ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input);
 		ddb_dma_init(input, dma_nr, 0);
 	}
 }
@@ -2244,8 +2254,7 @@ static void ddb_output_init(struct ddb_port *port, int nr)
 		const struct ddb_regmap *rm0 = io_regmap(output, 0);
 		u32 base = rm0->irq_base_odma;
 
-		dev->handler[0][nr + base] = output_handler;
-		dev->handler_data[0][nr + base] = (unsigned long)output;
+		ddb_irq_set(dev, 0, nr + base, &output_handler, output);
 		ddb_dma_init(output, nr, 1);
 	}
 }
@@ -2389,8 +2398,9 @@ void ddb_ports_release(struct ddb *dev)
 /****************************************************************************/
 
 #define IRQ_HANDLE(_nr) \
-	do { if ((s & (1UL << ((_nr) & 0x1f))) && dev->handler[0][_nr]) \
-		dev->handler[0][_nr](dev->handler_data[0][_nr]); } \
+	do { if ((s & (1UL << ((_nr) & 0x1f))) && \
+		 dev->link[0].irq[_nr].handler) \
+		dev->link[0].irq[_nr].handler(dev->link[0].irq[_nr].data); } \
 	while (0)
 
 static void irq_handle_msg(struct ddb *dev, u32 s)
@@ -3201,7 +3211,7 @@ static void tempmon_setfan(struct ddb_link *link)
 	ddblwritel(link, (pwm << 8), TEMPMON_FANCONTROL);
 }
 
-static void temp_handler(unsigned long data)
+static void temp_handler(void *data)
 {
 	struct ddb_link *link = (struct ddb_link *)data;
 
@@ -3224,8 +3234,7 @@ static int tempmon_init(struct ddb_link *link, int first_time)
 		memcpy(link->temp_tab, temperature_table,
 		       sizeof(temperature_table));
 	}
-	dev->handler[l][link->info->tempmon_irq] = temp_handler;
-	dev->handler_data[l][link->info->tempmon_irq] = (unsigned long)link;
+	ddb_irq_set(dev, l, link->info->tempmon_irq, temp_handler, link);
 	ddblwritel(link, (TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN |
 			  TEMPMON_CONTROL_INTENABLE),
 		   TEMPMON_CONTROL);
diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.c b/drivers/media/pci/ddbridge/ddbridge-i2c.c
index 82a9a0e806fc..667340c86ea7 100644
--- a/drivers/media/pci/ddbridge/ddbridge-i2c.c
+++ b/drivers/media/pci/ddbridge/ddbridge-i2c.c
@@ -147,7 +147,7 @@ void ddb_i2c_release(struct ddb *dev)
 	}
 }
 
-static void i2c_handler(unsigned long priv)
+static void i2c_handler(void *priv)
 {
 	struct ddb_i2c *i2c = (struct ddb_i2c *)priv;
 
@@ -210,8 +210,7 @@ int ddb_i2c_init(struct ddb *dev)
 			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;
+			ddb_irq_set(dev, l, i + base, i2c_handler, i2c);
 			stat = ddb_i2c_add(dev, i2c, regmap, l, i, num);
 			if (stat)
 				break;
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index dbd5f551ce76..de9ddf1068bf 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -305,6 +305,11 @@ struct ddb_lnb {
 	u32                    fmode;
 };
 
+struct ddb_irq {
+	void                   (*handler)(void *);
+	void                  *data;
+};
+
 struct ddb_link {
 	struct ddb            *dev;
 	const struct ddb_info *info;
@@ -319,6 +324,7 @@ struct ddb_link {
 	spinlock_t             temp_lock; /* lock temp chip access */
 	int                    overtemperature_error;
 	u8                     temp_tab[11];
+	struct ddb_irq         irq[256];
 };
 
 struct ddb {
@@ -343,9 +349,6 @@ struct ddb {
 	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;
 	u32                      ddb_dev_users;
 	u32                      nr;
@@ -369,6 +372,8 @@ int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
 /****************************************************************************/
 
 /* ddbridge-core.c */
+struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
+			    void (*handler)(void *), void *data);
 void ddb_ports_detach(struct ddb *dev);
 void ddb_ports_release(struct ddb *dev);
 void ddb_buffers_free(struct ddb *dev);
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 08/19] [media] ddbridge: add macros to handle IRQs in nibble and byte blocks
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (6 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 07/19] [media] ddbridge: add helper for IRQ handler setup Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 09/19] [media] ddbridge: improve separated MSI IRQ handling Daniel Scheller
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Currently, each IRQ requires one IRQ_HANDLE() line to call each IRQ
handler that was set up. Add a IRQ_HANDLE_NIBBLE() and IRQ_HANDLE_BYTE()
macro to call all handlers in blocks of four (_NIBBLE) or eight (_BYTE)
handlers at a time, to make this construct more compact.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 67 ++++++++++++------------------
 1 file changed, 27 insertions(+), 40 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index be6935bd0cb5..5fbb0996a12c 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -2403,54 +2403,41 @@ void ddb_ports_release(struct ddb *dev)
 		dev->link[0].irq[_nr].handler(dev->link[0].irq[_nr].data); } \
 	while (0)
 
+#define IRQ_HANDLE_NIBBLE(_shift) {		     \
+	if (s & (0x0000000f << ((_shift) & 0x1f))) { \
+		IRQ_HANDLE(0 + (_shift));	     \
+		IRQ_HANDLE(1 + (_shift));	     \
+		IRQ_HANDLE(2 + (_shift));	     \
+		IRQ_HANDLE(3 + (_shift));	     \
+	}					     \
+}
+
+#define IRQ_HANDLE_BYTE(_shift) {		     \
+	if (s & (0x000000ff << ((_shift) & 0x1f))) { \
+		IRQ_HANDLE(0 + (_shift));	     \
+		IRQ_HANDLE(1 + (_shift));	     \
+		IRQ_HANDLE(2 + (_shift));	     \
+		IRQ_HANDLE(3 + (_shift));	     \
+		IRQ_HANDLE(4 + (_shift));	     \
+		IRQ_HANDLE(5 + (_shift));	     \
+		IRQ_HANDLE(6 + (_shift));	     \
+		IRQ_HANDLE(7 + (_shift));	     \
+	}					     \
+}
+
 static void irq_handle_msg(struct ddb *dev, u32 s)
 {
 	dev->i2c_irq++;
-	IRQ_HANDLE(0);
-	IRQ_HANDLE(1);
-	IRQ_HANDLE(2);
-	IRQ_HANDLE(3);
+	IRQ_HANDLE_NIBBLE(0);
 }
 
 static void irq_handle_io(struct ddb *dev, u32 s)
 {
 	dev->ts_irq++;
-	if ((s & 0x000000f0)) {
-		IRQ_HANDLE(4);
-		IRQ_HANDLE(5);
-		IRQ_HANDLE(6);
-		IRQ_HANDLE(7);
-	}
-	if ((s & 0x0000ff00)) {
-		IRQ_HANDLE(8);
-		IRQ_HANDLE(9);
-		IRQ_HANDLE(10);
-		IRQ_HANDLE(11);
-		IRQ_HANDLE(12);
-		IRQ_HANDLE(13);
-		IRQ_HANDLE(14);
-		IRQ_HANDLE(15);
-	}
-	if ((s & 0x00ff0000)) {
-		IRQ_HANDLE(16);
-		IRQ_HANDLE(17);
-		IRQ_HANDLE(18);
-		IRQ_HANDLE(19);
-		IRQ_HANDLE(20);
-		IRQ_HANDLE(21);
-		IRQ_HANDLE(22);
-		IRQ_HANDLE(23);
-	}
-	if ((s & 0xff000000)) {
-		IRQ_HANDLE(24);
-		IRQ_HANDLE(25);
-		IRQ_HANDLE(26);
-		IRQ_HANDLE(27);
-		IRQ_HANDLE(28);
-		IRQ_HANDLE(29);
-		IRQ_HANDLE(30);
-		IRQ_HANDLE(31);
-	}
+	IRQ_HANDLE_NIBBLE(4);
+	IRQ_HANDLE_BYTE(8);
+	IRQ_HANDLE_BYTE(16);
+	IRQ_HANDLE_BYTE(24);
 }
 
 irqreturn_t ddb_irq_handler0(int irq, void *dev_id)
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 09/19] [media] ddbridge: improve separated MSI IRQ handling
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (7 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 08/19] [media] ddbridge: add macros to handle IRQs in nibble and byte blocks Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 10/19] [media] ddbridge: use spin_lock_irqsave() in output_work() Daniel Scheller
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Improve IRQ handling in the separated MSG/I2C and IO/TSDATA handlers by
applying a mask for recognized bits immediately upon reading the IRQ mask
from the hardware, so only the bits/IRQs that actually were set will be
acked.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 5fbb0996a12c..9d91221dacc4 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -2443,16 +2443,17 @@ static void irq_handle_io(struct ddb *dev, u32 s)
 irqreturn_t ddb_irq_handler0(int irq, void *dev_id)
 {
 	struct ddb *dev = (struct ddb *)dev_id;
-	u32 s = ddbreadl(dev, INTERRUPT_STATUS);
+	u32 mask = 0x8fffff00;
+	u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS);
 
+	if (!s)
+		return IRQ_NONE;
 	do {
 		if (s & 0x80000000)
 			return IRQ_NONE;
-		if (!(s & 0xfffff00))
-			return IRQ_NONE;
-		ddbwritel(dev, s & 0xfffff00, INTERRUPT_ACK);
+		ddbwritel(dev, s, INTERRUPT_ACK);
 		irq_handle_io(dev, s);
-	} while ((s = ddbreadl(dev, INTERRUPT_STATUS)));
+	} while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS)));
 
 	return IRQ_HANDLED;
 }
@@ -2460,16 +2461,17 @@ irqreturn_t ddb_irq_handler0(int irq, void *dev_id)
 irqreturn_t ddb_irq_handler1(int irq, void *dev_id)
 {
 	struct ddb *dev = (struct ddb *)dev_id;
-	u32 s = ddbreadl(dev, INTERRUPT_STATUS);
+	u32 mask = 0x8000000f;
+	u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS);
 
+	if (!s)
+		return IRQ_NONE;
 	do {
 		if (s & 0x80000000)
 			return IRQ_NONE;
-		if (!(s & 0x0000f))
-			return IRQ_NONE;
-		ddbwritel(dev, s & 0x0000f, INTERRUPT_ACK);
+		ddbwritel(dev, s, INTERRUPT_ACK);
 		irq_handle_msg(dev, s);
-	} while ((s = ddbreadl(dev, INTERRUPT_STATUS)));
+	} while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS)));
 
 	return IRQ_HANDLED;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 10/19] [media] ddbridge: use spin_lock_irqsave() in output_work()
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (8 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 09/19] [media] ddbridge: improve separated MSI IRQ handling Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 11/19] [media] ddbridge: fix output buffer check Daniel Scheller
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Make sure to save IRQ states before taking the dma lock, as already done
in it's input_work() counterpart.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 9d91221dacc4..c22537eceee5 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -2132,18 +2132,18 @@ static void output_work(struct work_struct *work)
 	struct ddb_dma *dma = container_of(work, struct ddb_dma, work);
 	struct ddb_output *output = (struct ddb_output *)dma->io;
 	struct ddb *dev = output->port->dev;
+	unsigned long flags;
 
-	spin_lock(&dma->lock);
-	if (!dma->running) {
-		spin_unlock(&dma->lock);
-		return;
-	}
+	spin_lock_irqsave(&dma->lock, flags);
+	if (!dma->running)
+		goto unlock_exit;
 	dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
 	dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
 	if (output->redi)
 		output_ack_input(output, output->redi);
 	wake_up(&dma->wq);
-	spin_unlock(&dma->lock);
+unlock_exit:
+	spin_unlock_irqrestore(&dma->lock, flags);
 }
 
 static void output_handler(void *data)
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 11/19] [media] ddbridge: fix output buffer check
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (9 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 10/19] [media] ddbridge: use spin_lock_irqsave() in output_work() Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 12/19] [media] ddbridge: set devid entry for link 0 Daniel Scheller
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

A 188 byte gap has to be left between the writer and the consumer. This
requires 2*188 bytes available to be able to write to the output buffers.
So, change ddb_output_free() to report free bytes according to this rule.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index c22537eceee5..e9c2e3e5d64b 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -587,12 +587,12 @@ static u32 ddb_output_free(struct ddb_output *output)
 
 	if (output->dma->cbuf != idx) {
 		if ((((output->dma->cbuf + 1) % output->dma->num) == idx) &&
-		    (output->dma->size - output->dma->coff <= 188))
+		    (output->dma->size - output->dma->coff <= (2 * 188)))
 			return 0;
 		return 188;
 	}
 	diff = off - output->dma->coff;
-	if (diff <= 0 || diff > 188)
+	if (diff <= 0 || diff > (2 * 188))
 		return 188;
 	return 0;
 }
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 12/19] [media] ddbridge: set devid entry for link 0
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (10 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 11/19] [media] ddbridge: fix output buffer check Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 13/19] [media] ddbridge: make DMA buffer count and size modparam-configurable Daniel Scheller
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Currently, /sys/class/ddbridgeX/devid always reports 0 due to devid not
being set at all. Set the devid field alongside while storing all other
hardware ID data.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 008be9066814..6356b48b3874 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -198,6 +198,7 @@ static int ddb_probe(struct pci_dev *pdev,
 	dev->link[0].ids.device = id->device;
 	dev->link[0].ids.subvendor = id->subvendor;
 	dev->link[0].ids.subdevice = pdev->subsystem_device;
+	dev->link[0].ids.devid = (id->device << 16) | id->vendor;
 
 	dev->link[0].dev = dev;
 	dev->link[0].info = get_ddb_info(id->vendor, id->device,
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 13/19] [media] ddbridge: make DMA buffer count and size modparam-configurable
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (11 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 12/19] [media] ddbridge: set devid entry for link 0 Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 14/19] [media] ddbridge: support dummy tuners with 125MByte/s dummy data stream Daniel Scheller
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Make the number of DMA buffers and their size configurable using module
parameters. Being able to set these to a higher number might help on
busy systems when handling overall high data rates without having to
edit the driver sources and recompile things.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 30 ++++++++++++++++++++++++------
 drivers/media/pci/ddbridge/ddbridge.h      | 12 ------------
 2 files changed, 24 insertions(+), 18 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index e9c2e3e5d64b..8907551b02e4 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -96,6 +96,15 @@ static int stv0910_single;
 module_param(stv0910_single, int, 0444);
 MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods");
 
+static int dma_buf_num = 8;
+module_param(dma_buf_num, int, 0444);
+MODULE_PARM_DESC(dma_buf_num, "Number of DMA buffers, possible values: 8-32");
+
+static int dma_buf_size = 21;
+module_param(dma_buf_size, int, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+		 "DMA buffer size as multiple of 128*47, possible values: 1-43");
+
 /****************************************************************************/
 
 static DEFINE_MUTEX(redirect_lock);
@@ -2187,16 +2196,16 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out)
 		INIT_WORK(&dma->work, output_work);
 		dma->regs = rm->odma->base + rm->odma->size * nr;
 		dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr;
-		dma->num = OUTPUT_DMA_BUFS;
-		dma->size = OUTPUT_DMA_SIZE;
-		dma->div = OUTPUT_DMA_IRQ_DIV;
+		dma->num = dma_buf_num;
+		dma->size = dma_buf_size * 128 * 47;
+		dma->div = 1;
 	} else {
 		INIT_WORK(&dma->work, input_work);
 		dma->regs = rm->idma->base + rm->idma->size * nr;
 		dma->bufregs = rm->idma_buf->base + rm->idma_buf->size * nr;
-		dma->num = INPUT_DMA_BUFS;
-		dma->size = INPUT_DMA_SIZE;
-		dma->div = INPUT_DMA_IRQ_DIV;
+		dma->num = dma_buf_num;
+		dma->size = dma_buf_size * 128 * 47;
+		dma->div = 1;
 	}
 	ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma));
 	dev_dbg(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n",
@@ -3353,6 +3362,15 @@ int ddb_exit_ddbridge(int stage, int error)
 
 int ddb_init_ddbridge(void)
 {
+	if (dma_buf_num < 8)
+		dma_buf_num = 8;
+	if (dma_buf_num > 32)
+		dma_buf_num = 32;
+	if (dma_buf_size < 1)
+		dma_buf_size = 1;
+	if (dma_buf_size > 43)
+		dma_buf_size = 43;
+
 	if (ddb_class_create() < 0)
 		return -1;
 	ddb_wq = alloc_workqueue("ddbridge", 0, 0);
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index de9ddf1068bf..86db6f19369a 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -136,20 +136,8 @@ struct ddb_info {
 	const struct ddb_regmap *regmap;
 };
 
-/* 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_BUFS 8
-#define INPUT_DMA_SIZE (128 * 47 * 21)
-#define INPUT_DMA_IRQ_DIV 1
-
-#define OUTPUT_DMA_BUFS 8
-#define OUTPUT_DMA_SIZE (128 * 47 * 21)
-#define OUTPUT_DMA_IRQ_DIV 1
-
 struct ddb;
 struct ddb_port;
 
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 14/19] [media] ddbridge: support dummy tuners with 125MByte/s dummy data stream
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (12 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 13/19] [media] ddbridge: make DMA buffer count and size modparam-configurable Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 15/19] [media] ddbridge: initial support for MCI-based MaxSX8 cards Daniel Scheller
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

The Octopus V3 and Octopus Mini devices support set up of a dummy tuner
mode on port 0 that will deliver a continuous data stream of 125MBytes
per second while raising IRQs and filling the DMA buffers, which comes
handy for some stress, PCIe link and IRQ handling testing. The dummy
frontend is registered using dvb_dummy_fe's QAM dummy frontend. Set
ddbridge.dummy_tuner to 1 to enable this on the supported cards.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/Kconfig         |  1 +
 drivers/media/pci/ddbridge/ddbridge-core.c | 36 ++++++++++++++++++++++++++++++
 drivers/media/pci/ddbridge/ddbridge.h      |  1 +
 3 files changed, 38 insertions(+)

diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig
index a422dde2f34a..16faef265e97 100644
--- a/drivers/media/pci/ddbridge/Kconfig
+++ b/drivers/media/pci/ddbridge/Kconfig
@@ -14,6 +14,7 @@ config DVB_DDBRIDGE
 	select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT
 	select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
+	select DVB_DUMMY_FE if MEDIA_SUBDRV_AUTOSELECT
 	---help---
 	  Support for cards with the Digital Devices PCI express bridge:
 	  - Octopus PCIe Bridge
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 8907551b02e4..59e137516003 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -54,6 +54,7 @@
 #include "stv6111.h"
 #include "lnbh25.h"
 #include "cxd2099.h"
+#include "dvb_dummy_fe.h"
 
 /****************************************************************************/
 
@@ -105,6 +106,11 @@ module_param(dma_buf_size, int, 0444);
 MODULE_PARM_DESC(dma_buf_size,
 		 "DMA buffer size as multiple of 128*47, possible values: 1-43");
 
+static int dummy_tuner;
+module_param(dummy_tuner, int, 0444);
+MODULE_PARM_DESC(dummy_tuner,
+		 "attach dummy tuner to port 0 on Octopus V3 or Octopus Mini cards");
+
 /****************************************************************************/
 
 static DEFINE_MUTEX(redirect_lock);
@@ -548,6 +554,9 @@ static void ddb_input_start(struct ddb_input *input)
 
 	ddbwritel(dev, 0x09, TS_CONTROL(input));
 
+	if (input->port->type == DDB_TUNER_DUMMY)
+		ddbwritel(dev, 0x000fff01, TS_CONTROL2(input));
+
 	if (input->dma) {
 		input->dma->running = 1;
 		spin_unlock_irq(&input->dma->lock);
@@ -1255,6 +1264,20 @@ static int tuner_attach_stv6111(struct ddb_input *input, int type)
 	return 0;
 }
 
+static int demod_attach_dummy(struct ddb_input *input)
+{
+	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
+	struct device *dev = input->port->dev->dev;
+
+	dvb->fe = dvb_attach(dvb_dummy_fe_qam_attach);
+	if (!dvb->fe) {
+		dev_err(dev, "QAM dummy attach failed!\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
 static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
 {
 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@@ -1547,6 +1570,10 @@ static int dvb_input_attach(struct ddb_input *input)
 		if (tuner_attach_tda18212(input, port->type) < 0)
 			goto err_tuner;
 		break;
+	case DDB_TUNER_DUMMY:
+		if (demod_attach_dummy(input) < 0)
+			goto err_detach;
+		break;
 	default:
 		return 0;
 	}
@@ -1809,6 +1836,15 @@ static void ddb_port_probe(struct ddb_port *port)
 
 	/* Handle missing ports and ports without I2C */
 
+	if (dummy_tuner && !port->nr &&
+	    dev->link[0].ids.device == 0x0005) {
+		port->name = "DUMMY";
+		port->class = DDB_PORT_TUNER;
+		port->type = DDB_TUNER_DUMMY;
+		port->type_name = "DUMMY";
+		return;
+	}
+
 	if (port->nr == ts_loop) {
 		port->name = "TS LOOP";
 		port->class = DDB_PORT_LOOP;
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 86db6f19369a..cb69021a3443 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -236,6 +236,7 @@ struct ddb_port {
 	char                   *name;
 	char                   *type_name;
 	u32                     type;
+#define DDB_TUNER_DUMMY          0xffffffff
 #define DDB_TUNER_NONE           0
 #define DDB_TUNER_DVBS_ST        1
 #define DDB_TUNER_DVBS_ST_AA     2
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 15/19] [media] ddbridge: initial support for MCI-based MaxSX8 cards
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (13 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 14/19] [media] ddbridge: support dummy tuners with 125MByte/s dummy data stream Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-05-04 14:47   ` Mauro Carvalho Chehab
  2018-04-09 16:47 ` [PATCH v2 16/19] [media] ddbridge/max: implement MCI/MaxSX8 attach function Daniel Scheller
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

This adds initial support for the new MCI-based (micro-code interface)
DD cards, with the first one being the MaxSX8 eight-tuner DVB-S/S2/S2X
PCIe card. The MCI is basically a generalized interface implemented in
the card's FPGA firmware and usable for all kind of cards, without the
need to implement any demod/tuner drivers as this interface "hides" any
I2C interface to the actual ICs, in other words any required driver is
implemented in the card firmware.

At this stage, the MCI interface is quite rudimentary with things like
signal statistics reporting missing, but is already working to serve
DVB streams to DVB applications. Missing functionality will be enabled
over time.

This implements only the ddbridge-mci sub-object and hooks it up to the
Makefile so the object gets build. The upcoming commits hook this module
into all other ddbridge parts where required, including device IDs etc.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/Makefile       |   2 +-
 drivers/media/pci/ddbridge/ddbridge-mci.c | 550 ++++++++++++++++++++++++++++++
 drivers/media/pci/ddbridge/ddbridge-mci.h | 152 +++++++++
 3 files changed, 703 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/pci/ddbridge/ddbridge-mci.c
 create mode 100644 drivers/media/pci/ddbridge/ddbridge-mci.h

diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile
index 745b37d07558..9b9e35f171b7 100644
--- a/drivers/media/pci/ddbridge/Makefile
+++ b/drivers/media/pci/ddbridge/Makefile
@@ -4,7 +4,7 @@
 #
 
 ddbridge-objs := ddbridge-main.o ddbridge-core.o ddbridge-ci.o \
-		ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o
+		ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o ddbridge-mci.o
 
 obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
 
diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.c b/drivers/media/pci/ddbridge/ddbridge-mci.c
new file mode 100644
index 000000000000..214b301f30a5
--- /dev/null
+++ b/drivers/media/pci/ddbridge/ddbridge-mci.c
@@ -0,0 +1,550 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ddbridge-mci.c: Digital Devices microcode interface
+ *
+ * Copyright (C) 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.
+ */
+
+#include "ddbridge.h"
+#include "ddbridge-io.h"
+#include "ddbridge-mci.h"
+
+static LIST_HEAD(mci_list);
+
+static const u32 MCLK = (1550000000 / 12);
+static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
+static const u32 MAX_LDPC_BITRATE = (720000000);
+
+struct mci_base {
+	struct list_head     mci_list;
+	void                *key;
+	struct ddb_link     *link;
+	struct completion    completion;
+
+	struct device       *dev;
+	struct mutex         tuner_lock; /* concurrent tuner access lock */
+	u8                   adr;
+	struct mutex         mci_lock; /* concurrent MCI access lock */
+	int                  count;
+
+	u8                   tuner_use_count[4];
+	u8                   assigned_demod[8];
+	u32                  used_ldpc_bitrate[8];
+	u8                   demod_in_use[8];
+	u32                  iq_mode;
+};
+
+struct mci {
+	struct mci_base     *base;
+	struct dvb_frontend  fe;
+	int                  nr;
+	int                  demod;
+	int                  tuner;
+	int                  first_time_lock;
+	int                  started;
+	struct mci_result    signal_info;
+
+	u32                  bb_mode;
+};
+
+static int mci_reset(struct mci *state)
+{
+	struct ddb_link *link = state->base->link;
+	u32 status = 0;
+	u32 timeout = 40;
+
+	ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL);
+	ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */
+	msleep(300);
+	ddblwritel(link, 0, MCI_CONTROL);
+
+	while (1) {
+		status = ddblreadl(link, MCI_CONTROL);
+		if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
+			break;
+		if (--timeout == 0)
+			break;
+		msleep(50);
+	}
+	if ((status & MCI_CONTROL_READY) == 0)
+		return -1;
+	if (link->ids.device == 0x0009)
+		ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
+	return 0;
+}
+
+static int mci_config(struct mci *state, u32 config)
+{
+	struct ddb_link *link = state->base->link;
+
+	if (link->ids.device != 0x0009)
+		return -EINVAL;
+	ddblwritel(link, config, SX8_TSCONFIG);
+	return 0;
+}
+
+static int _mci_cmd_unlocked(struct mci *state,
+			     u32 *cmd, u32 cmd_len,
+			     u32 *res, u32 res_len)
+{
+	struct ddb_link *link = state->base->link;
+	u32 i, val;
+	unsigned long stat;
+
+	val = ddblreadl(link, MCI_CONTROL);
+	if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND))
+		return -EIO;
+	if (cmd && cmd_len)
+		for (i = 0; i < cmd_len; i++)
+			ddblwritel(link, cmd[i], MCI_COMMAND + i * 4);
+	val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT);
+	ddblwritel(link, val, MCI_CONTROL);
+
+	stat = wait_for_completion_timeout(&state->base->completion, HZ);
+	if (stat == 0) {
+		dev_warn(state->base->dev, "MCI-%d: MCI timeout\n", state->nr);
+		return -EIO;
+	}
+	if (res && res_len)
+		for (i = 0; i < res_len; i++)
+			res[i] = ddblreadl(link, MCI_RESULT + i * 4);
+	return 0;
+}
+
+static int mci_cmd(struct mci *state,
+		   struct mci_command *command,
+		   struct mci_result *result)
+{
+	int stat;
+
+	mutex_lock(&state->base->mci_lock);
+	stat = _mci_cmd_unlocked(state,
+				 (u32 *)command, sizeof(*command) / sizeof(u32),
+				 (u32 *)result, sizeof(*result) / sizeof(u32));
+	mutex_unlock(&state->base->mci_lock);
+	return stat;
+}
+
+static void mci_handler(void *priv)
+{
+	struct mci_base *base = (struct mci_base *)priv;
+
+	complete(&base->completion);
+}
+
+static void release(struct dvb_frontend *fe)
+{
+	struct mci *state = fe->demodulator_priv;
+
+	state->base->count--;
+	if (state->base->count == 0) {
+		list_del(&state->base->mci_list);
+		kfree(state->base);
+	}
+	kfree(state);
+}
+
+static int read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+	int stat;
+	struct mci *state = fe->demodulator_priv;
+	struct mci_command cmd;
+	struct mci_result res;
+
+	cmd.command = MCI_CMD_GETSTATUS;
+	cmd.demod = state->demod;
+	stat = mci_cmd(state, &cmd, &res);
+	if (stat)
+		return stat;
+	*status = 0x00;
+	if (res.status == SX8_DEMOD_WAIT_MATYPE)
+		*status = 0x0f;
+	if (res.status == SX8_DEMOD_LOCKED)
+		*status = 0x1f;
+	return stat;
+}
+
+static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
+{
+	struct mci *state = fe->demodulator_priv;
+	struct mci_command cmd;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.tuner = state->tuner;
+	cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
+	return mci_cmd(state, &cmd, NULL);
+}
+
+static int stop(struct dvb_frontend *fe)
+{
+	struct mci *state = fe->demodulator_priv;
+	struct mci_command cmd;
+	u32 input = state->tuner;
+
+	memset(&cmd, 0, sizeof(cmd));
+	if (state->demod != 0xff) {
+		cmd.command = MCI_CMD_STOP;
+		cmd.demod = state->demod;
+		mci_cmd(state, &cmd, NULL);
+		if (state->base->iq_mode) {
+			cmd.command = MCI_CMD_STOP;
+			cmd.demod = state->demod;
+			cmd.output = 0;
+			mci_cmd(state, &cmd, NULL);
+			mci_config(state, SX8_TSCONFIG_MODE_NORMAL);
+		}
+	}
+	mutex_lock(&state->base->tuner_lock);
+	state->base->tuner_use_count[input]--;
+	if (!state->base->tuner_use_count[input])
+		mci_set_tuner(fe, input, 0);
+	state->base->demod_in_use[state->demod] = 0;
+	state->base->used_ldpc_bitrate[state->nr] = 0;
+	state->demod = 0xff;
+	state->base->assigned_demod[state->nr] = 0xff;
+	state->base->iq_mode = 0;
+	mutex_unlock(&state->base->tuner_lock);
+	state->started = 0;
+	return 0;
+}
+
+static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
+{
+	struct mci *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 used_ldpc_bitrate = 0, free_ldpc_bitrate;
+	u32 used_demods = 0;
+	struct mci_command cmd;
+	u32 input = state->tuner;
+	u32 bits_per_symbol = 0;
+	int i, stat = 0;
+
+	if (p->symbol_rate >= (MCLK / 2))
+		flags &= ~1;
+	if ((flags & 3) == 0)
+		return -EINVAL;
+
+	if (flags & 2) {
+		u32 tmp = modmask;
+
+		bits_per_symbol = 1;
+		while (tmp & 1) {
+			tmp >>= 1;
+			bits_per_symbol++;
+		}
+	}
+
+	mutex_lock(&state->base->tuner_lock);
+	if (state->base->iq_mode) {
+		stat = -EBUSY;
+		goto unlock;
+	}
+	for (i = 0; i < 8; i++) {
+		used_ldpc_bitrate += state->base->used_ldpc_bitrate[i];
+		if (state->base->demod_in_use[i])
+			used_demods++;
+	}
+	if (used_ldpc_bitrate >= MAX_LDPC_BITRATE ||
+	    ((ts_config & SX8_TSCONFIG_MODE_MASK) >
+	     SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
+		stat = -EBUSY;
+		goto unlock;
+	}
+	free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
+	if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
+		free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
+
+	while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
+		bits_per_symbol--;
+
+	if (bits_per_symbol < 2) {
+		stat = -EBUSY;
+		goto unlock;
+	}
+	i = (p->symbol_rate > (MCLK / 2)) ? 3 : 7;
+	while (i >= 0 && state->base->demod_in_use[i])
+		i--;
+	if (i < 0) {
+		stat = -EBUSY;
+		goto unlock;
+	}
+	state->base->demod_in_use[i] = 1;
+	state->base->used_ldpc_bitrate[state->nr] = p->symbol_rate
+						    * bits_per_symbol;
+	state->demod = i;
+	state->base->assigned_demod[state->nr] = i;
+
+	if (!state->base->tuner_use_count[input])
+		mci_set_tuner(fe, input, 1);
+	state->base->tuner_use_count[input]++;
+	state->base->iq_mode = (ts_config > 1);
+unlock:
+	mutex_unlock(&state->base->tuner_lock);
+	if (stat)
+		return stat;
+	memset(&cmd, 0, sizeof(cmd));
+
+	if (state->base->iq_mode) {
+		cmd.command = SX8_CMD_SELECT_IQOUT;
+		cmd.demod = state->demod;
+		cmd.output = 0;
+		mci_cmd(state, &cmd, NULL);
+		mci_config(state, ts_config);
+	}
+	if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000)
+		flags |= 0x80;
+	dev_dbg(state->base->dev, "MCI-%d: tuner=%d demod=%d\n",
+		state->nr, state->tuner, state->demod);
+	cmd.command = MCI_CMD_SEARCH_DVBS;
+	cmd.dvbs2_search.flags = flags;
+	cmd.dvbs2_search.s2_modulation_mask =
+		modmask & ((1 << (bits_per_symbol - 1)) - 1);
+	cmd.dvbs2_search.retry = 2;
+	cmd.dvbs2_search.frequency = p->frequency * 1000;
+	cmd.dvbs2_search.symbol_rate = p->symbol_rate;
+	cmd.dvbs2_search.scrambling_sequence_index =
+		p->scrambling_sequence_index;
+	cmd.dvbs2_search.input_stream_id =
+		(p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0;
+	cmd.tuner = state->tuner;
+	cmd.demod = state->demod;
+	cmd.output = state->nr;
+	if (p->stream_id == 0x80000000)
+		cmd.output |= 0x80;
+	stat = mci_cmd(state, &cmd, NULL);
+	if (stat)
+		stop(fe);
+	return stat;
+}
+
+static int start_iq(struct dvb_frontend *fe, u32 ts_config)
+{
+	struct mci *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 used_demods = 0;
+	struct mci_command cmd;
+	u32 input = state->tuner;
+	int i, stat = 0;
+
+	mutex_lock(&state->base->tuner_lock);
+	if (state->base->iq_mode) {
+		stat = -EBUSY;
+		goto unlock;
+	}
+	for (i = 0; i < 8; i++)
+		if (state->base->demod_in_use[i])
+			used_demods++;
+	if (used_demods > 0) {
+		stat = -EBUSY;
+		goto unlock;
+	}
+	state->demod = 0;
+	state->base->assigned_demod[state->nr] = 0;
+	if (!state->base->tuner_use_count[input])
+		mci_set_tuner(fe, input, 1);
+	state->base->tuner_use_count[input]++;
+	state->base->iq_mode = (ts_config > 1);
+unlock:
+	mutex_unlock(&state->base->tuner_lock);
+	if (stat)
+		return stat;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.command = SX8_CMD_START_IQ;
+	cmd.dvbs2_search.frequency = p->frequency * 1000;
+	cmd.dvbs2_search.symbol_rate = p->symbol_rate;
+	cmd.tuner = state->tuner;
+	cmd.demod = state->demod;
+	cmd.output = 7;
+	mci_config(state, ts_config);
+	stat = mci_cmd(state, &cmd, NULL);
+	if (stat)
+		stop(fe);
+	return stat;
+}
+
+static int set_parameters(struct dvb_frontend *fe)
+{
+	int stat = 0;
+	struct mci *state = fe->demodulator_priv;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 ts_config, iq_mode = 0, isi;
+
+	if (state->started)
+		stop(fe);
+
+	isi = p->stream_id;
+	if (isi != NO_STREAM_ID_FILTER)
+		iq_mode = (isi & 0x30000000) >> 28;
+
+	switch (iq_mode) {
+	case 1:
+		ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
+		break;
+	case 2:
+		ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
+		break;
+	default:
+		ts_config = SX8_TSCONFIG_MODE_NORMAL;
+		break;
+	}
+
+	if (iq_mode != 2) {
+		u32 flags = 3;
+		u32 mask = 3;
+
+		if (p->modulation == APSK_16 ||
+		    p->modulation == APSK_32) {
+			flags = 2;
+			mask = 15;
+		}
+		stat = start(fe, flags, mask, ts_config);
+	} else {
+		stat = start_iq(fe, ts_config);
+	}
+
+	if (!stat) {
+		state->started = 1;
+		state->first_time_lock = 1;
+		state->signal_info.status = SX8_DEMOD_WAIT_SIGNAL;
+	}
+
+	return stat;
+}
+
+static int tune(struct dvb_frontend *fe, bool re_tune,
+		unsigned int mode_flags,
+		unsigned int *delay, enum fe_status *status)
+{
+	int r;
+
+	if (re_tune) {
+		r = set_parameters(fe);
+		if (r)
+			return r;
+	}
+	r = read_status(fe, status);
+	if (r)
+		return r;
+
+	if (*status & FE_HAS_LOCK)
+		return 0;
+	*delay = HZ / 10;
+	return 0;
+}
+
+static int get_algo(struct dvb_frontend *fe)
+{
+	return DVBFE_ALGO_HW;
+}
+
+static int set_input(struct dvb_frontend *fe, int input)
+{
+	struct mci *state = fe->demodulator_priv;
+
+	state->tuner = input;
+	dev_dbg(state->base->dev, "MCI-%d: input=%d\n", state->nr, input);
+	return 0;
+}
+
+static struct dvb_frontend_ops mci_ops = {
+	.delsys = { SYS_DVBS, SYS_DVBS2 },
+	.info = {
+		.name			= "Digital Devices MaxSX8 MCI DVB-S/S2/S2X",
+		.frequency_min		= 950000,
+		.frequency_max		= 2150000,
+		.frequency_stepsize	= 0,
+		.frequency_tolerance	= 0,
+		.symbol_rate_min	= 100000,
+		.symbol_rate_max	= 100000000,
+		.caps			= FE_CAN_INVERSION_AUTO |
+					  FE_CAN_FEC_AUTO       |
+					  FE_CAN_QPSK           |
+					  FE_CAN_2G_MODULATION  |
+					  FE_CAN_MULTISTREAM,
+	},
+	.get_frontend_algo		= get_algo,
+	.tune				= tune,
+	.release			= release,
+	.read_status			= read_status,
+};
+
+static struct mci_base *match_base(void *key)
+{
+	struct mci_base *p;
+
+	list_for_each_entry(p, &mci_list, mci_list)
+		if (p->key == key)
+			return p;
+	return NULL;
+}
+
+static int probe(struct mci *state)
+{
+	mci_reset(state);
+	return 0;
+}
+
+struct dvb_frontend
+*ddb_mci_attach(struct ddb_input *input,
+		int mci_type, int nr,
+		int (**fn_set_input)(struct dvb_frontend *, int))
+{
+	struct ddb_port *port = input->port;
+	struct ddb *dev = port->dev;
+	struct ddb_link *link = &dev->link[port->lnr];
+	struct mci_base *base;
+	struct mci *state;
+	void *key = mci_type ? (void *)port : (void *)link;
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return NULL;
+
+	base = match_base(key);
+	if (base) {
+		base->count++;
+		state->base = base;
+	} else {
+		base = kzalloc(sizeof(*base), GFP_KERNEL);
+		if (!base)
+			goto fail;
+		base->key = key;
+		base->count = 1;
+		base->link = link;
+		base->dev = dev->dev;
+		mutex_init(&base->mci_lock);
+		mutex_init(&base->tuner_lock);
+		ddb_irq_set(dev, link->nr, 0, mci_handler, base);
+		init_completion(&base->completion);
+		state->base = base;
+		if (probe(state) < 0) {
+			kfree(base);
+			goto fail;
+		}
+		list_add(&base->mci_list, &mci_list);
+	}
+	state->fe.ops = mci_ops;
+	state->fe.demodulator_priv = state;
+	state->nr = nr;
+	*fn_set_input = set_input;
+
+	state->tuner = nr;
+	state->demod = nr;
+
+	return &state->fe;
+fail:
+	kfree(state);
+	return NULL;
+}
diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.h b/drivers/media/pci/ddbridge/ddbridge-mci.h
new file mode 100644
index 000000000000..c4193c5ee095
--- /dev/null
+++ b/drivers/media/pci/ddbridge/ddbridge-mci.h
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ddbridge-mci.h: Digital Devices micro code interface
+ *
+ * Copyright (C) 2017 Digital Devices GmbH
+ *                    Marcus Metzler <mocm@metzlerbros.de>
+ *                    Ralph Metzler <rjkm@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.
+ */
+
+#ifndef _DDBRIDGE_MCI_H_
+#define _DDBRIDGE_MCI_H_
+
+#define MCI_CONTROL                         (0x500)
+#define MCI_COMMAND                         (0x600)
+#define MCI_RESULT                          (0x680)
+
+#define MCI_COMMAND_SIZE                    (0x80)
+#define MCI_RESULT_SIZE                     (0x80)
+
+#define MCI_CONTROL_START_COMMAND           (0x00000001)
+#define MCI_CONTROL_ENABLE_DONE_INTERRUPT   (0x00000002)
+#define MCI_CONTROL_RESET                   (0x00008000)
+#define MCI_CONTROL_READY                   (0x00010000)
+
+#define SX8_TSCONFIG                        (0x280)
+
+#define SX8_TSCONFIG_MODE_MASK              (0x00000003)
+#define SX8_TSCONFIG_MODE_OFF               (0x00000000)
+#define SX8_TSCONFIG_MODE_NORMAL            (0x00000001)
+#define SX8_TSCONFIG_MODE_IQ                (0x00000003)
+
+#define SX8_TSCONFIG_TSHEADER               (0x00000004)
+#define SX8_TSCONFIG_BURST                  (0x00000008)
+
+#define SX8_TSCONFIG_BURSTSIZE_MASK         (0x00000030)
+#define SX8_TSCONFIG_BURSTSIZE_2K           (0x00000000)
+#define SX8_TSCONFIG_BURSTSIZE_4K           (0x00000010)
+#define SX8_TSCONFIG_BURSTSIZE_8K           (0x00000020)
+#define SX8_TSCONFIG_BURSTSIZE_16K          (0x00000030)
+
+#define SX8_DEMOD_STOPPED       (0)
+#define SX8_DEMOD_IQ_MODE       (1)
+#define SX8_DEMOD_WAIT_SIGNAL   (2)
+#define SX8_DEMOD_WAIT_MATYPE   (3)
+#define SX8_DEMOD_TIMEOUT       (14)
+#define SX8_DEMOD_LOCKED        (15)
+
+#define MCI_CMD_STOP            (0x01)
+#define MCI_CMD_GETSTATUS       (0x02)
+#define MCI_CMD_GETSIGNALINFO   (0x03)
+#define MCI_CMD_RFPOWER         (0x04)
+
+#define MCI_CMD_SEARCH_DVBS     (0x10)
+
+#define MCI_CMD_GET_IQSYMBOL    (0x30)
+
+#define SX8_CMD_INPUT_ENABLE    (0x40)
+#define SX8_CMD_INPUT_DISABLE   (0x41)
+#define SX8_CMD_START_IQ        (0x42)
+#define SX8_CMD_STOP_IQ         (0x43)
+#define SX8_CMD_SELECT_IQOUT    (0x44)
+#define SX8_CMD_SELECT_TSOUT    (0x45)
+
+#define SX8_ERROR_UNSUPPORTED   (0x80)
+
+#define SX8_SUCCESS(status)     (status < SX8_ERROR_UNSUPPORTED)
+
+#define SX8_CMD_DIAG_READ8      (0xE0)
+#define SX8_CMD_DIAG_READ32     (0xE1)
+#define SX8_CMD_DIAG_WRITE8     (0xE2)
+#define SX8_CMD_DIAG_WRITE32    (0xE3)
+
+#define SX8_CMD_DIAG_READRF     (0xE8)
+#define SX8_CMD_DIAG_WRITERF    (0xE9)
+
+struct mci_command {
+	union {
+		u32 command_word;
+		struct {
+			u8 command;
+			u8 tuner;
+			u8 demod;
+			u8 output;
+		};
+	};
+	union {
+		u32 params[31];
+		struct {
+			u8  flags;
+			u8  s2_modulation_mask;
+			u8  rsvd1;
+			u8  retry;
+			u32 frequency;
+			u32 symbol_rate;
+			u8  input_stream_id;
+			u8  rsvd2[3];
+			u32 scrambling_sequence_index;
+		} dvbs2_search;
+	};
+};
+
+struct mci_result {
+	union {
+		u32 status_word;
+		struct {
+			u8 status;
+			u8 rsvd;
+			u16 time;
+		};
+	};
+	union {
+		u32 result[27];
+		struct {
+			u8  standard;
+			/* puncture rate for DVB-S */
+			u8  pls_code;
+			/* 7-6: rolloff, 5-2: rsrvd, 1:short, 0:pilots */
+			u8  roll_off;
+			u8  rsvd;
+			u32 frequency;
+			u32 symbol_rate;
+			s16 channel_power;
+			s16 band_power;
+			s16 signal_to_noise;
+			s16 rsvd2;
+			u32 packet_errors;
+			u32 ber_numerator;
+			u32 ber_denominator;
+		} dvbs2_signal_info;
+		struct {
+			u8 i_symbol;
+			u8 q_symbol;
+		} dvbs2_signal_iq;
+	};
+	u32 version[4];
+};
+
+struct dvb_frontend
+*ddb_mci_attach(struct ddb_input *input,
+		int mci_type, int nr,
+		int (**fn_set_input)(struct dvb_frontend *, int));
+
+#endif /* _DDBRIDGE_MCI_H_ */
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 16/19] [media] ddbridge/max: implement MCI/MaxSX8 attach function
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (14 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 15/19] [media] ddbridge: initial support for MCI-based MaxSX8 cards Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 17/19] [media] ddbridge: add hardware defs and PCI IDs for MCI cards Daniel Scheller
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Implement frontend attachment as ddb_fe_attach_mci() into the
ddbridge-max module. The MaxSX8 MCI cards are part of the Max card series
and make use of the LNB controller driven by the already existing lnb
functionality, so here's where this code belongs to.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-max.c | 42 +++++++++++++++++++++++++++++++
 drivers/media/pci/ddbridge/ddbridge-max.h |  1 +
 2 files changed, 43 insertions(+)

diff --git a/drivers/media/pci/ddbridge/ddbridge-max.c b/drivers/media/pci/ddbridge/ddbridge-max.c
index dc6b81488746..739e4b444cf4 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.c
+++ b/drivers/media/pci/ddbridge/ddbridge-max.c
@@ -33,6 +33,7 @@
 #include "ddbridge.h"
 #include "ddbridge-regs.h"
 #include "ddbridge-io.h"
+#include "ddbridge-mci.h"
 
 #include "ddbridge-max.h"
 #include "mxl5xx.h"
@@ -452,3 +453,44 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input)
 	dvb->input = tuner;
 	return 0;
 }
+
+/******************************************************************************/
+/* MAX MCI related functions */
+
+int ddb_fe_attach_mci(struct ddb_input *input)
+{
+	struct ddb *dev = input->port->dev;
+	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
+	struct ddb_port *port = input->port;
+	struct ddb_link *link = &dev->link[port->lnr];
+	int demod, tuner;
+
+	demod = input->nr;
+	tuner = demod & 3;
+	if (fmode == 3)
+		tuner = 0;
+	dvb->fe = ddb_mci_attach(input, 0, demod, &dvb->set_input);
+	if (!dvb->fe) {
+		dev_err(dev->dev, "No MAXSX8 found!\n");
+		return -ENODEV;
+	}
+	if (!dvb->set_input) {
+		dev_err(dev->dev, "No MCI set_input function pointer!\n");
+		return -ENODEV;
+	}
+	if (input->nr < 4) {
+		lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
+		lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
+	}
+	ddb_lnb_init_fmode(dev, link, fmode);
+
+	dvb->fe->ops.set_voltage = max_set_voltage;
+	dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
+	dvb->fe->ops.set_tone = max_set_tone;
+	dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
+	dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
+	dvb->fe->ops.diseqc_send_burst = max_send_burst;
+	dvb->fe->sec_priv = input;
+	dvb->input = tuner;
+	return 0;
+}
diff --git a/drivers/media/pci/ddbridge/ddbridge-max.h b/drivers/media/pci/ddbridge/ddbridge-max.h
index bf8bf38739f6..82efc53baa94 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.h
+++ b/drivers/media/pci/ddbridge/ddbridge-max.h
@@ -25,5 +25,6 @@
 
 int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm);
 int ddb_fe_attach_mxl5xx(struct ddb_input *input);
+int ddb_fe_attach_mci(struct ddb_input *input);
 
 #endif /* _DDBRIDGE_MAX_H */
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 17/19] [media] ddbridge: add hardware defs and PCI IDs for MCI cards
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (15 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 16/19] [media] ddbridge/max: implement MCI/MaxSX8 attach function Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 18/19] [media] ddbridge: recognize and attach the MaxSX8 cards Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 19/19] [media] ddbridge: set driver version to 0.9.33-integrated Daniel Scheller
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Add PCI IDs and ddb_info for the new MCI-based MaxSX8 cards. Also add
needed defines so the cards can be hooked up into ddbridge's probe and
attach handling.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-hw.c   | 11 +++++++++++
 drivers/media/pci/ddbridge/ddbridge-main.c |  1 +
 drivers/media/pci/ddbridge/ddbridge.h      | 11 +++++++----
 3 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.c b/drivers/media/pci/ddbridge/ddbridge-hw.c
index c6d14925e2fc..1d3ee6accdd5 100644
--- a/drivers/media/pci/ddbridge/ddbridge-hw.c
+++ b/drivers/media/pci/ddbridge/ddbridge-hw.c
@@ -311,6 +311,16 @@ static const struct ddb_info ddb_s2_48 = {
 	.tempmon_irq = 24,
 };
 
+static const struct ddb_info ddb_s2x_48 = {
+	.type     = DDB_OCTOPUS_MCI,
+	.name     = "Digital Devices MAX SX8",
+	.regmap   = &octopus_map,
+	.port_num = 4,
+	.i2c_mask = 0x00,
+	.tempmon_irq = 24,
+	.mci      = 4
+};
+
 /****************************************************************************/
 /****************************************************************************/
 /****************************************************************************/
@@ -346,6 +356,7 @@ static const struct ddb_device_id ddb_device_ids[] = {
 	DDB_DEVID(0x0008, 0x0036, ddb_isdbt_8),
 	DDB_DEVID(0x0008, 0x0037, ddb_c2t2i_v0_8),
 	DDB_DEVID(0x0008, 0x0038, ddb_c2t2i_8),
+	DDB_DEVID(0x0009, 0x0025, ddb_s2x_48),
 	DDB_DEVID(0x0006, 0x0039, ddb_ctv7),
 	DDB_DEVID(0x0011, 0x0040, ddb_ci),
 	DDB_DEVID(0x0011, 0x0041, ddb_cis),
diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 6356b48b3874..f4748cfd904b 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -264,6 +264,7 @@ static const struct pci_device_id ddb_id_table[] = {
 	DDB_DEVICE_ANY(0x0006),
 	DDB_DEVICE_ANY(0x0007),
 	DDB_DEVICE_ANY(0x0008),
+	DDB_DEVICE_ANY(0x0009),
 	DDB_DEVICE_ANY(0x0011),
 	DDB_DEVICE_ANY(0x0012),
 	DDB_DEVICE_ANY(0x0013),
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index cb69021a3443..72fe33cb72b9 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -112,11 +112,12 @@ struct ddb_ids {
 
 struct ddb_info {
 	int   type;
-#define DDB_NONE         0
-#define DDB_OCTOPUS      1
-#define DDB_OCTOPUS_CI   2
-#define DDB_OCTOPUS_MAX  5
+#define DDB_NONE            0
+#define DDB_OCTOPUS         1
+#define DDB_OCTOPUS_CI      2
+#define DDB_OCTOPUS_MAX     5
 #define DDB_OCTOPUS_MAX_CT  6
+#define DDB_OCTOPUS_MCI     9
 	char *name;
 	u32   i2c_mask;
 	u8    port_num;
@@ -133,6 +134,7 @@ struct ddb_info {
 #define TS_QUIRK_REVERSED 2
 #define TS_QUIRK_ALT_OSC  8
 	u32   tempmon_irq;
+	u8    mci;
 	const struct ddb_regmap *regmap;
 };
 
@@ -253,6 +255,7 @@ struct ddb_port {
 #define DDB_CI_EXTERNAL_XO2_B    13
 #define DDB_TUNER_DVBS_STV0910_PR 14
 #define DDB_TUNER_DVBC2T2I_SONY_P 15
+#define DDB_TUNER_MCI            16
 
 #define DDB_TUNER_XO2            32
 #define DDB_TUNER_DVBS_STV0910   (DDB_TUNER_XO2 + 0)
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 18/19] [media] ddbridge: recognize and attach the MaxSX8 cards
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (16 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 17/19] [media] ddbridge: add hardware defs and PCI IDs for MCI cards Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  2018-04-09 16:47 ` [PATCH v2 19/19] [media] ddbridge: set driver version to 0.9.33-integrated Daniel Scheller
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Add needed logic into dvb_input_attach(), ddb_port_probe() and
ddb_ports_init() to initialize and support these new cards.

Picked up from the upstream dddvb-0.9.33 release.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge-core.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 59e137516003..4a2819d3e225 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -1574,6 +1574,10 @@ static int dvb_input_attach(struct ddb_input *input)
 		if (demod_attach_dummy(input) < 0)
 			goto err_detach;
 		break;
+	case DDB_TUNER_MCI:
+		if (ddb_fe_attach_mci(input) < 0)
+			goto err_detach;
+		break;
 	default:
 		return 0;
 	}
@@ -1869,6 +1873,16 @@ static void ddb_port_probe(struct ddb_port *port)
 		return;
 	}
 
+	if (dev->link[l].info->type == DDB_OCTOPUS_MCI) {
+		if (port->nr >= dev->link[l].info->mci)
+			return;
+		port->name = "DUAL MCI";
+		port->type_name = "MCI";
+		port->class = DDB_PORT_TUNER;
+		port->type = DDB_TUNER_MCI;
+		return;
+	}
+
 	if (port->nr > 1 && dev->link[l].info->type == DDB_OCTOPUS_CI) {
 		port->name = "CI internal";
 		port->type_name = "INTERNAL";
@@ -2411,6 +2425,7 @@ void ddb_ports_init(struct ddb *dev)
 				break;
 			case DDB_OCTOPUS_MAX:
 			case DDB_OCTOPUS_MAX_CT:
+			case DDB_OCTOPUS_MCI:
 				ddb_input_init(port, 2 * i, 0, 2 * p);
 				ddb_input_init(port, 2 * i + 1, 1, 2 * p + 1);
 				break;
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v2 19/19] [media] ddbridge: set driver version to 0.9.33-integrated
  2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
                   ` (17 preceding siblings ...)
  2018-04-09 16:47 ` [PATCH v2 18/19] [media] ddbridge: recognize and attach the MaxSX8 cards Daniel Scheller
@ 2018-04-09 16:47 ` Daniel Scheller
  18 siblings, 0 replies; 21+ messages in thread
From: Daniel Scheller @ 2018-04-09 16:47 UTC (permalink / raw)
  To: linux-media, mchehab, mchehab

From: Daniel Scheller <d.scheller@gmx.net>

Set DDBRIDGE_VERSION in ddbridge.h to 0.9.33-integrated to reflect the
updated driver.

Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
---
 drivers/media/pci/ddbridge/ddbridge.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index 72fe33cb72b9..a66b1125cc74 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -63,7 +63,7 @@
 #include <media/dvb_ca_en50221.h>
 #include <media/dvb_net.h>
 
-#define DDBRIDGE_VERSION "0.9.32-integrated"
+#define DDBRIDGE_VERSION "0.9.33-integrated"
 
 #define DDB_MAX_I2C    32
 #define DDB_MAX_PORT   32
-- 
2.16.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v2 15/19] [media] ddbridge: initial support for MCI-based MaxSX8 cards
  2018-04-09 16:47 ` [PATCH v2 15/19] [media] ddbridge: initial support for MCI-based MaxSX8 cards Daniel Scheller
@ 2018-05-04 14:47   ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2018-05-04 14:47 UTC (permalink / raw)
  To: Daniel Scheller; +Cc: linux-media

Em Mon,  9 Apr 2018 18:47:48 +0200
Daniel Scheller <d.scheller.oss@gmail.com> escreveu:

> From: Daniel Scheller <d.scheller@gmx.net>
> 
> This adds initial support for the new MCI-based (micro-code interface)
> DD cards, with the first one being the MaxSX8 eight-tuner DVB-S/S2/S2X
> PCIe card. The MCI is basically a generalized interface implemented in
> the card's FPGA firmware and usable for all kind of cards, without the
> need to implement any demod/tuner drivers as this interface "hides" any
> I2C interface to the actual ICs, in other words any required driver is
> implemented in the card firmware.
> 
> At this stage, the MCI interface is quite rudimentary with things like
> signal statistics reporting missing, but is already working to serve
> DVB streams to DVB applications. Missing functionality will be enabled
> over time.
> 
> This implements only the ddbridge-mci sub-object and hooks it up to the
> Makefile so the object gets build. The upcoming commits hook this module
> into all other ddbridge parts where required, including device IDs etc.
> 
> Picked up from the upstream dddvb-0.9.33 release.

There are three checkpatch issues to be handled here:

WARNING: function definition argument 'int' should also have an identifier name
#764: FILE: drivers/media/pci/ddbridge/ddbridge-mci.h:147:
+struct dvb_frontend

WARNING: function definition argument 'struct dvb_frontend *' should also have an identifier name
#764: FILE: drivers/media/pci/ddbridge/ddbridge-mci.h:147:
+struct dvb_frontend

WARNING: function definition argument 'int' should also have an identifier name
#764: FILE: drivers/media/pci/ddbridge/ddbridge-mci.h:147:
+struct dvb_frontend

Please submit a patch later addressing it.

> 
> Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
> ---
>  drivers/media/pci/ddbridge/Makefile       |   2 +-
>  drivers/media/pci/ddbridge/ddbridge-mci.c | 550 ++++++++++++++++++++++++++++++
>  drivers/media/pci/ddbridge/ddbridge-mci.h | 152 +++++++++
>  3 files changed, 703 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/media/pci/ddbridge/ddbridge-mci.c
>  create mode 100644 drivers/media/pci/ddbridge/ddbridge-mci.h
> 
> diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile
> index 745b37d07558..9b9e35f171b7 100644
> --- a/drivers/media/pci/ddbridge/Makefile
> +++ b/drivers/media/pci/ddbridge/Makefile
> @@ -4,7 +4,7 @@
>  #
>  
>  ddbridge-objs := ddbridge-main.o ddbridge-core.o ddbridge-ci.o \
> -		ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o
> +		ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o ddbridge-mci.o
>  
>  obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
>  
> diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.c b/drivers/media/pci/ddbridge/ddbridge-mci.c
> new file mode 100644
> index 000000000000..214b301f30a5
> --- /dev/null
> +++ b/drivers/media/pci/ddbridge/ddbridge-mci.c
> @@ -0,0 +1,550 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * ddbridge-mci.c: Digital Devices microcode interface
> + *
> + * Copyright (C) 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.
> + */
> +
> +#include "ddbridge.h"
> +#include "ddbridge-io.h"
> +#include "ddbridge-mci.h"
> +
> +static LIST_HEAD(mci_list);
> +
> +static const u32 MCLK = (1550000000 / 12);
> +static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
> +static const u32 MAX_LDPC_BITRATE = (720000000);
> +
> +struct mci_base {
> +	struct list_head     mci_list;
> +	void                *key;
> +	struct ddb_link     *link;
> +	struct completion    completion;
> +
> +	struct device       *dev;
> +	struct mutex         tuner_lock; /* concurrent tuner access lock */
> +	u8                   adr;
> +	struct mutex         mci_lock; /* concurrent MCI access lock */
> +	int                  count;
> +
> +	u8                   tuner_use_count[4];
> +	u8                   assigned_demod[8];
> +	u32                  used_ldpc_bitrate[8];
> +	u8                   demod_in_use[8];
> +	u32                  iq_mode;
> +};
> +
> +struct mci {
> +	struct mci_base     *base;
> +	struct dvb_frontend  fe;
> +	int                  nr;
> +	int                  demod;
> +	int                  tuner;
> +	int                  first_time_lock;
> +	int                  started;
> +	struct mci_result    signal_info;
> +
> +	u32                  bb_mode;
> +};
> +
> +static int mci_reset(struct mci *state)
> +{
> +	struct ddb_link *link = state->base->link;
> +	u32 status = 0;
> +	u32 timeout = 40;
> +
> +	ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL);
> +	ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */
> +	msleep(300);
> +	ddblwritel(link, 0, MCI_CONTROL);
> +
> +	while (1) {
> +		status = ddblreadl(link, MCI_CONTROL);
> +		if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
> +			break;
> +		if (--timeout == 0)
> +			break;
> +		msleep(50);
> +	}
> +	if ((status & MCI_CONTROL_READY) == 0)
> +		return -1;
> +	if (link->ids.device == 0x0009)
> +		ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
> +	return 0;
> +}
> +
> +static int mci_config(struct mci *state, u32 config)
> +{
> +	struct ddb_link *link = state->base->link;
> +
> +	if (link->ids.device != 0x0009)
> +		return -EINVAL;
> +	ddblwritel(link, config, SX8_TSCONFIG);
> +	return 0;
> +}
> +
> +static int _mci_cmd_unlocked(struct mci *state,
> +			     u32 *cmd, u32 cmd_len,
> +			     u32 *res, u32 res_len)
> +{
> +	struct ddb_link *link = state->base->link;
> +	u32 i, val;
> +	unsigned long stat;
> +
> +	val = ddblreadl(link, MCI_CONTROL);
> +	if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND))
> +		return -EIO;
> +	if (cmd && cmd_len)
> +		for (i = 0; i < cmd_len; i++)
> +			ddblwritel(link, cmd[i], MCI_COMMAND + i * 4);
> +	val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT);
> +	ddblwritel(link, val, MCI_CONTROL);
> +
> +	stat = wait_for_completion_timeout(&state->base->completion, HZ);
> +	if (stat == 0) {
> +		dev_warn(state->base->dev, "MCI-%d: MCI timeout\n", state->nr);
> +		return -EIO;
> +	}
> +	if (res && res_len)
> +		for (i = 0; i < res_len; i++)
> +			res[i] = ddblreadl(link, MCI_RESULT + i * 4);
> +	return 0;
> +}
> +
> +static int mci_cmd(struct mci *state,
> +		   struct mci_command *command,
> +		   struct mci_result *result)
> +{
> +	int stat;
> +
> +	mutex_lock(&state->base->mci_lock);
> +	stat = _mci_cmd_unlocked(state,
> +				 (u32 *)command, sizeof(*command) / sizeof(u32),
> +				 (u32 *)result, sizeof(*result) / sizeof(u32));
> +	mutex_unlock(&state->base->mci_lock);
> +	return stat;
> +}
> +
> +static void mci_handler(void *priv)
> +{
> +	struct mci_base *base = (struct mci_base *)priv;
> +
> +	complete(&base->completion);
> +}
> +
> +static void release(struct dvb_frontend *fe)
> +{
> +	struct mci *state = fe->demodulator_priv;
> +
> +	state->base->count--;
> +	if (state->base->count == 0) {
> +		list_del(&state->base->mci_list);
> +		kfree(state->base);
> +	}
> +	kfree(state);
> +}
> +
> +static int read_status(struct dvb_frontend *fe, enum fe_status *status)
> +{
> +	int stat;
> +	struct mci *state = fe->demodulator_priv;
> +	struct mci_command cmd;
> +	struct mci_result res;
> +
> +	cmd.command = MCI_CMD_GETSTATUS;
> +	cmd.demod = state->demod;
> +	stat = mci_cmd(state, &cmd, &res);
> +	if (stat)
> +		return stat;
> +	*status = 0x00;
> +	if (res.status == SX8_DEMOD_WAIT_MATYPE)
> +		*status = 0x0f;
> +	if (res.status == SX8_DEMOD_LOCKED)
> +		*status = 0x1f;
> +	return stat;
> +}
> +
> +static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
> +{
> +	struct mci *state = fe->demodulator_priv;
> +	struct mci_command cmd;
> +
> +	memset(&cmd, 0, sizeof(cmd));
> +	cmd.tuner = state->tuner;
> +	cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
> +	return mci_cmd(state, &cmd, NULL);
> +}
> +
> +static int stop(struct dvb_frontend *fe)
> +{
> +	struct mci *state = fe->demodulator_priv;
> +	struct mci_command cmd;
> +	u32 input = state->tuner;
> +
> +	memset(&cmd, 0, sizeof(cmd));
> +	if (state->demod != 0xff) {
> +		cmd.command = MCI_CMD_STOP;
> +		cmd.demod = state->demod;
> +		mci_cmd(state, &cmd, NULL);
> +		if (state->base->iq_mode) {
> +			cmd.command = MCI_CMD_STOP;
> +			cmd.demod = state->demod;
> +			cmd.output = 0;
> +			mci_cmd(state, &cmd, NULL);
> +			mci_config(state, SX8_TSCONFIG_MODE_NORMAL);
> +		}
> +	}
> +	mutex_lock(&state->base->tuner_lock);
> +	state->base->tuner_use_count[input]--;
> +	if (!state->base->tuner_use_count[input])
> +		mci_set_tuner(fe, input, 0);
> +	state->base->demod_in_use[state->demod] = 0;
> +	state->base->used_ldpc_bitrate[state->nr] = 0;
> +	state->demod = 0xff;
> +	state->base->assigned_demod[state->nr] = 0xff;
> +	state->base->iq_mode = 0;
> +	mutex_unlock(&state->base->tuner_lock);
> +	state->started = 0;
> +	return 0;
> +}
> +
> +static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
> +{
> +	struct mci *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
> +	u32 used_ldpc_bitrate = 0, free_ldpc_bitrate;
> +	u32 used_demods = 0;
> +	struct mci_command cmd;
> +	u32 input = state->tuner;
> +	u32 bits_per_symbol = 0;
> +	int i, stat = 0;
> +
> +	if (p->symbol_rate >= (MCLK / 2))
> +		flags &= ~1;
> +	if ((flags & 3) == 0)
> +		return -EINVAL;
> +
> +	if (flags & 2) {
> +		u32 tmp = modmask;
> +
> +		bits_per_symbol = 1;
> +		while (tmp & 1) {
> +			tmp >>= 1;
> +			bits_per_symbol++;
> +		}
> +	}
> +
> +	mutex_lock(&state->base->tuner_lock);
> +	if (state->base->iq_mode) {
> +		stat = -EBUSY;
> +		goto unlock;
> +	}
> +	for (i = 0; i < 8; i++) {
> +		used_ldpc_bitrate += state->base->used_ldpc_bitrate[i];
> +		if (state->base->demod_in_use[i])
> +			used_demods++;
> +	}
> +	if (used_ldpc_bitrate >= MAX_LDPC_BITRATE ||
> +	    ((ts_config & SX8_TSCONFIG_MODE_MASK) >
> +	     SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
> +		stat = -EBUSY;
> +		goto unlock;
> +	}
> +	free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
> +	if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
> +		free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
> +
> +	while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
> +		bits_per_symbol--;
> +
> +	if (bits_per_symbol < 2) {
> +		stat = -EBUSY;
> +		goto unlock;
> +	}
> +	i = (p->symbol_rate > (MCLK / 2)) ? 3 : 7;
> +	while (i >= 0 && state->base->demod_in_use[i])
> +		i--;
> +	if (i < 0) {
> +		stat = -EBUSY;
> +		goto unlock;
> +	}
> +	state->base->demod_in_use[i] = 1;
> +	state->base->used_ldpc_bitrate[state->nr] = p->symbol_rate
> +						    * bits_per_symbol;
> +	state->demod = i;
> +	state->base->assigned_demod[state->nr] = i;
> +
> +	if (!state->base->tuner_use_count[input])
> +		mci_set_tuner(fe, input, 1);
> +	state->base->tuner_use_count[input]++;
> +	state->base->iq_mode = (ts_config > 1);
> +unlock:
> +	mutex_unlock(&state->base->tuner_lock);
> +	if (stat)
> +		return stat;
> +	memset(&cmd, 0, sizeof(cmd));
> +
> +	if (state->base->iq_mode) {
> +		cmd.command = SX8_CMD_SELECT_IQOUT;
> +		cmd.demod = state->demod;
> +		cmd.output = 0;
> +		mci_cmd(state, &cmd, NULL);
> +		mci_config(state, ts_config);
> +	}
> +	if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000)
> +		flags |= 0x80;
> +	dev_dbg(state->base->dev, "MCI-%d: tuner=%d demod=%d\n",
> +		state->nr, state->tuner, state->demod);
> +	cmd.command = MCI_CMD_SEARCH_DVBS;
> +	cmd.dvbs2_search.flags = flags;
> +	cmd.dvbs2_search.s2_modulation_mask =
> +		modmask & ((1 << (bits_per_symbol - 1)) - 1);
> +	cmd.dvbs2_search.retry = 2;
> +	cmd.dvbs2_search.frequency = p->frequency * 1000;
> +	cmd.dvbs2_search.symbol_rate = p->symbol_rate;
> +	cmd.dvbs2_search.scrambling_sequence_index =
> +		p->scrambling_sequence_index;
> +	cmd.dvbs2_search.input_stream_id =
> +		(p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0;
> +	cmd.tuner = state->tuner;
> +	cmd.demod = state->demod;
> +	cmd.output = state->nr;
> +	if (p->stream_id == 0x80000000)
> +		cmd.output |= 0x80;
> +	stat = mci_cmd(state, &cmd, NULL);
> +	if (stat)
> +		stop(fe);
> +	return stat;
> +}
> +
> +static int start_iq(struct dvb_frontend *fe, u32 ts_config)
> +{
> +	struct mci *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
> +	u32 used_demods = 0;
> +	struct mci_command cmd;
> +	u32 input = state->tuner;
> +	int i, stat = 0;
> +
> +	mutex_lock(&state->base->tuner_lock);
> +	if (state->base->iq_mode) {
> +		stat = -EBUSY;
> +		goto unlock;
> +	}
> +	for (i = 0; i < 8; i++)
> +		if (state->base->demod_in_use[i])
> +			used_demods++;
> +	if (used_demods > 0) {
> +		stat = -EBUSY;
> +		goto unlock;
> +	}
> +	state->demod = 0;
> +	state->base->assigned_demod[state->nr] = 0;
> +	if (!state->base->tuner_use_count[input])
> +		mci_set_tuner(fe, input, 1);
> +	state->base->tuner_use_count[input]++;
> +	state->base->iq_mode = (ts_config > 1);
> +unlock:
> +	mutex_unlock(&state->base->tuner_lock);
> +	if (stat)
> +		return stat;
> +
> +	memset(&cmd, 0, sizeof(cmd));
> +	cmd.command = SX8_CMD_START_IQ;
> +	cmd.dvbs2_search.frequency = p->frequency * 1000;
> +	cmd.dvbs2_search.symbol_rate = p->symbol_rate;
> +	cmd.tuner = state->tuner;
> +	cmd.demod = state->demod;
> +	cmd.output = 7;
> +	mci_config(state, ts_config);
> +	stat = mci_cmd(state, &cmd, NULL);
> +	if (stat)
> +		stop(fe);
> +	return stat;
> +}
> +
> +static int set_parameters(struct dvb_frontend *fe)
> +{
> +	int stat = 0;
> +	struct mci *state = fe->demodulator_priv;
> +	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
> +	u32 ts_config, iq_mode = 0, isi;
> +
> +	if (state->started)
> +		stop(fe);
> +
> +	isi = p->stream_id;
> +	if (isi != NO_STREAM_ID_FILTER)
> +		iq_mode = (isi & 0x30000000) >> 28;
> +
> +	switch (iq_mode) {
> +	case 1:
> +		ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
> +		break;
> +	case 2:
> +		ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
> +		break;
> +	default:
> +		ts_config = SX8_TSCONFIG_MODE_NORMAL;
> +		break;
> +	}
> +
> +	if (iq_mode != 2) {
> +		u32 flags = 3;
> +		u32 mask = 3;
> +
> +		if (p->modulation == APSK_16 ||
> +		    p->modulation == APSK_32) {
> +			flags = 2;
> +			mask = 15;
> +		}
> +		stat = start(fe, flags, mask, ts_config);
> +	} else {
> +		stat = start_iq(fe, ts_config);
> +	}
> +
> +	if (!stat) {
> +		state->started = 1;
> +		state->first_time_lock = 1;
> +		state->signal_info.status = SX8_DEMOD_WAIT_SIGNAL;
> +	}
> +
> +	return stat;
> +}
> +
> +static int tune(struct dvb_frontend *fe, bool re_tune,
> +		unsigned int mode_flags,
> +		unsigned int *delay, enum fe_status *status)
> +{
> +	int r;
> +
> +	if (re_tune) {
> +		r = set_parameters(fe);
> +		if (r)
> +			return r;
> +	}
> +	r = read_status(fe, status);
> +	if (r)
> +		return r;
> +
> +	if (*status & FE_HAS_LOCK)
> +		return 0;
> +	*delay = HZ / 10;
> +	return 0;
> +}
> +
> +static int get_algo(struct dvb_frontend *fe)
> +{
> +	return DVBFE_ALGO_HW;
> +}
> +
> +static int set_input(struct dvb_frontend *fe, int input)
> +{
> +	struct mci *state = fe->demodulator_priv;
> +
> +	state->tuner = input;
> +	dev_dbg(state->base->dev, "MCI-%d: input=%d\n", state->nr, input);
> +	return 0;
> +}
> +
> +static struct dvb_frontend_ops mci_ops = {
> +	.delsys = { SYS_DVBS, SYS_DVBS2 },
> +	.info = {
> +		.name			= "Digital Devices MaxSX8 MCI DVB-S/S2/S2X",
> +		.frequency_min		= 950000,
> +		.frequency_max		= 2150000,
> +		.frequency_stepsize	= 0,
> +		.frequency_tolerance	= 0,
> +		.symbol_rate_min	= 100000,
> +		.symbol_rate_max	= 100000000,
> +		.caps			= FE_CAN_INVERSION_AUTO |
> +					  FE_CAN_FEC_AUTO       |
> +					  FE_CAN_QPSK           |
> +					  FE_CAN_2G_MODULATION  |
> +					  FE_CAN_MULTISTREAM,
> +	},
> +	.get_frontend_algo		= get_algo,
> +	.tune				= tune,
> +	.release			= release,
> +	.read_status			= read_status,
> +};
> +
> +static struct mci_base *match_base(void *key)
> +{
> +	struct mci_base *p;
> +
> +	list_for_each_entry(p, &mci_list, mci_list)
> +		if (p->key == key)
> +			return p;
> +	return NULL;
> +}
> +
> +static int probe(struct mci *state)
> +{
> +	mci_reset(state);
> +	return 0;
> +}
> +
> +struct dvb_frontend
> +*ddb_mci_attach(struct ddb_input *input,
> +		int mci_type, int nr,
> +		int (**fn_set_input)(struct dvb_frontend *, int))
> +{
> +	struct ddb_port *port = input->port;
> +	struct ddb *dev = port->dev;
> +	struct ddb_link *link = &dev->link[port->lnr];
> +	struct mci_base *base;
> +	struct mci *state;
> +	void *key = mci_type ? (void *)port : (void *)link;
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return NULL;
> +
> +	base = match_base(key);
> +	if (base) {
> +		base->count++;
> +		state->base = base;
> +	} else {
> +		base = kzalloc(sizeof(*base), GFP_KERNEL);
> +		if (!base)
> +			goto fail;
> +		base->key = key;
> +		base->count = 1;
> +		base->link = link;
> +		base->dev = dev->dev;
> +		mutex_init(&base->mci_lock);
> +		mutex_init(&base->tuner_lock);
> +		ddb_irq_set(dev, link->nr, 0, mci_handler, base);
> +		init_completion(&base->completion);
> +		state->base = base;
> +		if (probe(state) < 0) {
> +			kfree(base);
> +			goto fail;
> +		}
> +		list_add(&base->mci_list, &mci_list);
> +	}
> +	state->fe.ops = mci_ops;
> +	state->fe.demodulator_priv = state;
> +	state->nr = nr;
> +	*fn_set_input = set_input;
> +
> +	state->tuner = nr;
> +	state->demod = nr;
> +
> +	return &state->fe;
> +fail:
> +	kfree(state);
> +	return NULL;
> +}
> diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.h b/drivers/media/pci/ddbridge/ddbridge-mci.h
> new file mode 100644
> index 000000000000..c4193c5ee095
> --- /dev/null
> +++ b/drivers/media/pci/ddbridge/ddbridge-mci.h
> @@ -0,0 +1,152 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * ddbridge-mci.h: Digital Devices micro code interface
> + *
> + * Copyright (C) 2017 Digital Devices GmbH
> + *                    Marcus Metzler <mocm@metzlerbros.de>
> + *                    Ralph Metzler <rjkm@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.
> + */
> +
> +#ifndef _DDBRIDGE_MCI_H_
> +#define _DDBRIDGE_MCI_H_
> +
> +#define MCI_CONTROL                         (0x500)
> +#define MCI_COMMAND                         (0x600)
> +#define MCI_RESULT                          (0x680)
> +
> +#define MCI_COMMAND_SIZE                    (0x80)
> +#define MCI_RESULT_SIZE                     (0x80)
> +
> +#define MCI_CONTROL_START_COMMAND           (0x00000001)
> +#define MCI_CONTROL_ENABLE_DONE_INTERRUPT   (0x00000002)
> +#define MCI_CONTROL_RESET                   (0x00008000)
> +#define MCI_CONTROL_READY                   (0x00010000)
> +
> +#define SX8_TSCONFIG                        (0x280)
> +
> +#define SX8_TSCONFIG_MODE_MASK              (0x00000003)
> +#define SX8_TSCONFIG_MODE_OFF               (0x00000000)
> +#define SX8_TSCONFIG_MODE_NORMAL            (0x00000001)
> +#define SX8_TSCONFIG_MODE_IQ                (0x00000003)
> +
> +#define SX8_TSCONFIG_TSHEADER               (0x00000004)
> +#define SX8_TSCONFIG_BURST                  (0x00000008)
> +
> +#define SX8_TSCONFIG_BURSTSIZE_MASK         (0x00000030)
> +#define SX8_TSCONFIG_BURSTSIZE_2K           (0x00000000)
> +#define SX8_TSCONFIG_BURSTSIZE_4K           (0x00000010)
> +#define SX8_TSCONFIG_BURSTSIZE_8K           (0x00000020)
> +#define SX8_TSCONFIG_BURSTSIZE_16K          (0x00000030)
> +
> +#define SX8_DEMOD_STOPPED       (0)
> +#define SX8_DEMOD_IQ_MODE       (1)
> +#define SX8_DEMOD_WAIT_SIGNAL   (2)
> +#define SX8_DEMOD_WAIT_MATYPE   (3)
> +#define SX8_DEMOD_TIMEOUT       (14)
> +#define SX8_DEMOD_LOCKED        (15)
> +
> +#define MCI_CMD_STOP            (0x01)
> +#define MCI_CMD_GETSTATUS       (0x02)
> +#define MCI_CMD_GETSIGNALINFO   (0x03)
> +#define MCI_CMD_RFPOWER         (0x04)
> +
> +#define MCI_CMD_SEARCH_DVBS     (0x10)
> +
> +#define MCI_CMD_GET_IQSYMBOL    (0x30)
> +
> +#define SX8_CMD_INPUT_ENABLE    (0x40)
> +#define SX8_CMD_INPUT_DISABLE   (0x41)
> +#define SX8_CMD_START_IQ        (0x42)
> +#define SX8_CMD_STOP_IQ         (0x43)
> +#define SX8_CMD_SELECT_IQOUT    (0x44)
> +#define SX8_CMD_SELECT_TSOUT    (0x45)
> +
> +#define SX8_ERROR_UNSUPPORTED   (0x80)
> +
> +#define SX8_SUCCESS(status)     (status < SX8_ERROR_UNSUPPORTED)
> +
> +#define SX8_CMD_DIAG_READ8      (0xE0)
> +#define SX8_CMD_DIAG_READ32     (0xE1)
> +#define SX8_CMD_DIAG_WRITE8     (0xE2)
> +#define SX8_CMD_DIAG_WRITE32    (0xE3)
> +
> +#define SX8_CMD_DIAG_READRF     (0xE8)
> +#define SX8_CMD_DIAG_WRITERF    (0xE9)
> +
> +struct mci_command {
> +	union {
> +		u32 command_word;
> +		struct {
> +			u8 command;
> +			u8 tuner;
> +			u8 demod;
> +			u8 output;
> +		};
> +	};
> +	union {
> +		u32 params[31];
> +		struct {
> +			u8  flags;
> +			u8  s2_modulation_mask;
> +			u8  rsvd1;
> +			u8  retry;
> +			u32 frequency;
> +			u32 symbol_rate;
> +			u8  input_stream_id;
> +			u8  rsvd2[3];
> +			u32 scrambling_sequence_index;
> +		} dvbs2_search;
> +	};
> +};
> +
> +struct mci_result {
> +	union {
> +		u32 status_word;
> +		struct {
> +			u8 status;
> +			u8 rsvd;
> +			u16 time;
> +		};
> +	};
> +	union {
> +		u32 result[27];
> +		struct {
> +			u8  standard;
> +			/* puncture rate for DVB-S */
> +			u8  pls_code;
> +			/* 7-6: rolloff, 5-2: rsrvd, 1:short, 0:pilots */
> +			u8  roll_off;
> +			u8  rsvd;
> +			u32 frequency;
> +			u32 symbol_rate;
> +			s16 channel_power;
> +			s16 band_power;
> +			s16 signal_to_noise;
> +			s16 rsvd2;
> +			u32 packet_errors;
> +			u32 ber_numerator;
> +			u32 ber_denominator;
> +		} dvbs2_signal_info;
> +		struct {
> +			u8 i_symbol;
> +			u8 q_symbol;
> +		} dvbs2_signal_iq;
> +	};
> +	u32 version[4];
> +};
> +
> +struct dvb_frontend
> +*ddb_mci_attach(struct ddb_input *input,
> +		int mci_type, int nr,
> +		int (**fn_set_input)(struct dvb_frontend *, int));
> +
> +#endif /* _DDBRIDGE_MCI_H_ */



Thanks,
Mauro

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2018-05-04 14:47 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-09 16:47 [PATCH v2 00/19] dddvb/ddbridge-0.9.33 Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 01/19] [media] dvb-frontends/stv0910: add init values for TSINSDELM/L Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 02/19] [media] dvb-frontends/stv0910: fix CNR reporting in read_snr() Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 03/19] [media] ddbridge: move modparams to ddbridge-core.c Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 04/19] [media] ddbridge: move ddb_wq and the wq+class initialisation to -core Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 05/19] [media] ddbridge: move MSI IRQ cleanup to a helper function Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 06/19] [media] ddbridge: request/free_irq using pci_irq_vector, enable MSI-X Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 07/19] [media] ddbridge: add helper for IRQ handler setup Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 08/19] [media] ddbridge: add macros to handle IRQs in nibble and byte blocks Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 09/19] [media] ddbridge: improve separated MSI IRQ handling Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 10/19] [media] ddbridge: use spin_lock_irqsave() in output_work() Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 11/19] [media] ddbridge: fix output buffer check Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 12/19] [media] ddbridge: set devid entry for link 0 Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 13/19] [media] ddbridge: make DMA buffer count and size modparam-configurable Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 14/19] [media] ddbridge: support dummy tuners with 125MByte/s dummy data stream Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 15/19] [media] ddbridge: initial support for MCI-based MaxSX8 cards Daniel Scheller
2018-05-04 14:47   ` Mauro Carvalho Chehab
2018-04-09 16:47 ` [PATCH v2 16/19] [media] ddbridge/max: implement MCI/MaxSX8 attach function Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 17/19] [media] ddbridge: add hardware defs and PCI IDs for MCI cards Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 18/19] [media] ddbridge: recognize and attach the MaxSX8 cards Daniel Scheller
2018-04-09 16:47 ` [PATCH v2 19/19] [media] ddbridge: set driver version to 0.9.33-integrated Daniel Scheller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.