1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * ddbridge.c: Digital Devices PCIe bridge driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2010-2017 Digital Devices GmbH
6*4882a593Smuzhiyun * Ralph Metzler <rjkm@metzlerbros.de>
7*4882a593Smuzhiyun * Marcus Metzler <mocm@metzlerbros.de>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
10*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License
11*4882a593Smuzhiyun * version 2 only, as published by the Free Software Foundation.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * This program is distributed in the hope that it will be useful,
14*4882a593Smuzhiyun * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*4882a593Smuzhiyun * GNU General Public License for more details.
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/module.h>
22*4882a593Smuzhiyun #include <linux/init.h>
23*4882a593Smuzhiyun #include <linux/interrupt.h>
24*4882a593Smuzhiyun #include <linux/delay.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/poll.h>
27*4882a593Smuzhiyun #include <linux/io.h>
28*4882a593Smuzhiyun #include <linux/pci.h>
29*4882a593Smuzhiyun #include <linux/pci_ids.h>
30*4882a593Smuzhiyun #include <linux/timer.h>
31*4882a593Smuzhiyun #include <linux/i2c.h>
32*4882a593Smuzhiyun #include <linux/swab.h>
33*4882a593Smuzhiyun #include <linux/vmalloc.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #include "ddbridge.h"
36*4882a593Smuzhiyun #include "ddbridge-i2c.h"
37*4882a593Smuzhiyun #include "ddbridge-regs.h"
38*4882a593Smuzhiyun #include "ddbridge-hw.h"
39*4882a593Smuzhiyun #include "ddbridge-io.h"
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /****************************************************************************/
42*4882a593Smuzhiyun /* module parameters */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #ifdef CONFIG_PCI_MSI
45*4882a593Smuzhiyun #ifdef CONFIG_DVB_DDBRIDGE_MSIENABLE
46*4882a593Smuzhiyun static int msi = 1;
47*4882a593Smuzhiyun #else
48*4882a593Smuzhiyun static int msi;
49*4882a593Smuzhiyun #endif
50*4882a593Smuzhiyun module_param(msi, int, 0444);
51*4882a593Smuzhiyun #ifdef CONFIG_DVB_DDBRIDGE_MSIENABLE
52*4882a593Smuzhiyun MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable, 1-enable (default)");
53*4882a593Smuzhiyun #else
54*4882a593Smuzhiyun MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable (default), 1-enable");
55*4882a593Smuzhiyun #endif
56*4882a593Smuzhiyun #endif
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /****************************************************************************/
59*4882a593Smuzhiyun /****************************************************************************/
60*4882a593Smuzhiyun /****************************************************************************/
61*4882a593Smuzhiyun
ddb_irq_disable(struct ddb * dev)62*4882a593Smuzhiyun static void ddb_irq_disable(struct ddb *dev)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun ddbwritel(dev, 0, INTERRUPT_ENABLE);
65*4882a593Smuzhiyun ddbwritel(dev, 0, MSI1_ENABLE);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
ddb_msi_exit(struct ddb * dev)68*4882a593Smuzhiyun static void ddb_msi_exit(struct ddb *dev)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun #ifdef CONFIG_PCI_MSI
71*4882a593Smuzhiyun if (dev->msi)
72*4882a593Smuzhiyun pci_free_irq_vectors(dev->pdev);
73*4882a593Smuzhiyun #endif
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
ddb_irq_exit(struct ddb * dev)76*4882a593Smuzhiyun static void ddb_irq_exit(struct ddb *dev)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun ddb_irq_disable(dev);
79*4882a593Smuzhiyun if (dev->msi == 2)
80*4882a593Smuzhiyun free_irq(pci_irq_vector(dev->pdev, 1), dev);
81*4882a593Smuzhiyun free_irq(pci_irq_vector(dev->pdev, 0), dev);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
ddb_remove(struct pci_dev * pdev)84*4882a593Smuzhiyun static void ddb_remove(struct pci_dev *pdev)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun struct ddb *dev = (struct ddb *)pci_get_drvdata(pdev);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun ddb_device_destroy(dev);
89*4882a593Smuzhiyun ddb_ports_detach(dev);
90*4882a593Smuzhiyun ddb_i2c_release(dev);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun ddb_irq_exit(dev);
93*4882a593Smuzhiyun ddb_msi_exit(dev);
94*4882a593Smuzhiyun ddb_ports_release(dev);
95*4882a593Smuzhiyun ddb_buffers_free(dev);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun ddb_unmap(dev);
98*4882a593Smuzhiyun pci_set_drvdata(pdev, NULL);
99*4882a593Smuzhiyun pci_disable_device(pdev);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun #ifdef CONFIG_PCI_MSI
ddb_irq_msi(struct ddb * dev,int nr)103*4882a593Smuzhiyun static void ddb_irq_msi(struct ddb *dev, int nr)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun int stat;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (msi && pci_msi_enabled()) {
108*4882a593Smuzhiyun stat = pci_alloc_irq_vectors(dev->pdev, 1, nr,
109*4882a593Smuzhiyun PCI_IRQ_MSI | PCI_IRQ_MSIX);
110*4882a593Smuzhiyun if (stat >= 1) {
111*4882a593Smuzhiyun dev->msi = stat;
112*4882a593Smuzhiyun dev_info(dev->dev, "using %d MSI interrupt(s)\n",
113*4882a593Smuzhiyun dev->msi);
114*4882a593Smuzhiyun } else {
115*4882a593Smuzhiyun dev_info(dev->dev, "MSI not available.\n");
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun #endif
120*4882a593Smuzhiyun
ddb_irq_init(struct ddb * dev)121*4882a593Smuzhiyun static int ddb_irq_init(struct ddb *dev)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun int stat;
124*4882a593Smuzhiyun int irq_flag = IRQF_SHARED;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
127*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI1_ENABLE);
128*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI2_ENABLE);
129*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI3_ENABLE);
130*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI4_ENABLE);
131*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI5_ENABLE);
132*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI6_ENABLE);
133*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI7_ENABLE);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun #ifdef CONFIG_PCI_MSI
136*4882a593Smuzhiyun ddb_irq_msi(dev, 2);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (dev->msi)
139*4882a593Smuzhiyun irq_flag = 0;
140*4882a593Smuzhiyun if (dev->msi == 2) {
141*4882a593Smuzhiyun stat = request_irq(pci_irq_vector(dev->pdev, 0),
142*4882a593Smuzhiyun ddb_irq_handler0, irq_flag, "ddbridge",
143*4882a593Smuzhiyun (void *)dev);
144*4882a593Smuzhiyun if (stat < 0)
145*4882a593Smuzhiyun return stat;
146*4882a593Smuzhiyun stat = request_irq(pci_irq_vector(dev->pdev, 1),
147*4882a593Smuzhiyun ddb_irq_handler1, irq_flag, "ddbridge",
148*4882a593Smuzhiyun (void *)dev);
149*4882a593Smuzhiyun if (stat < 0) {
150*4882a593Smuzhiyun free_irq(pci_irq_vector(dev->pdev, 0), dev);
151*4882a593Smuzhiyun return stat;
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun } else
154*4882a593Smuzhiyun #endif
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun stat = request_irq(pci_irq_vector(dev->pdev, 0),
157*4882a593Smuzhiyun ddb_irq_handler, irq_flag, "ddbridge",
158*4882a593Smuzhiyun (void *)dev);
159*4882a593Smuzhiyun if (stat < 0)
160*4882a593Smuzhiyun return stat;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun if (dev->msi == 2) {
163*4882a593Smuzhiyun ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE);
164*4882a593Smuzhiyun ddbwritel(dev, 0x0000000f, MSI1_ENABLE);
165*4882a593Smuzhiyun } else {
166*4882a593Smuzhiyun ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
167*4882a593Smuzhiyun ddbwritel(dev, 0x00000000, MSI1_ENABLE);
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun return stat;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
ddb_probe(struct pci_dev * pdev,const struct pci_device_id * id)172*4882a593Smuzhiyun static int ddb_probe(struct pci_dev *pdev,
173*4882a593Smuzhiyun const struct pci_device_id *id)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun struct ddb *dev;
176*4882a593Smuzhiyun int stat = 0;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun if (pci_enable_device(pdev) < 0)
179*4882a593Smuzhiyun return -ENODEV;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun pci_set_master(pdev);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
184*4882a593Smuzhiyun if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))
185*4882a593Smuzhiyun return -ENODEV;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun dev = vzalloc(sizeof(*dev));
188*4882a593Smuzhiyun if (!dev)
189*4882a593Smuzhiyun return -ENOMEM;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun mutex_init(&dev->mutex);
192*4882a593Smuzhiyun dev->has_dma = 1;
193*4882a593Smuzhiyun dev->pdev = pdev;
194*4882a593Smuzhiyun dev->dev = &pdev->dev;
195*4882a593Smuzhiyun pci_set_drvdata(pdev, dev);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun dev->link[0].ids.vendor = id->vendor;
198*4882a593Smuzhiyun dev->link[0].ids.device = id->device;
199*4882a593Smuzhiyun dev->link[0].ids.subvendor = id->subvendor;
200*4882a593Smuzhiyun dev->link[0].ids.subdevice = pdev->subsystem_device;
201*4882a593Smuzhiyun dev->link[0].ids.devid = (id->device << 16) | id->vendor;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun dev->link[0].dev = dev;
204*4882a593Smuzhiyun dev->link[0].info = get_ddb_info(id->vendor, id->device,
205*4882a593Smuzhiyun id->subvendor, pdev->subsystem_device);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun dev_info(&pdev->dev, "detected %s\n", dev->link[0].info->name);
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun dev->regs_len = pci_resource_len(dev->pdev, 0);
210*4882a593Smuzhiyun dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
211*4882a593Smuzhiyun pci_resource_len(dev->pdev, 0));
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (!dev->regs) {
214*4882a593Smuzhiyun dev_err(&pdev->dev, "not enough memory for register map\n");
215*4882a593Smuzhiyun stat = -ENOMEM;
216*4882a593Smuzhiyun goto fail;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun if (ddbreadl(dev, 0) == 0xffffffff) {
219*4882a593Smuzhiyun dev_err(&pdev->dev, "cannot read registers\n");
220*4882a593Smuzhiyun stat = -ENODEV;
221*4882a593Smuzhiyun goto fail;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun dev->link[0].ids.hwid = ddbreadl(dev, 0);
225*4882a593Smuzhiyun dev->link[0].ids.regmapid = ddbreadl(dev, 4);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun dev_info(&pdev->dev, "HW %08x REGMAP %08x\n",
228*4882a593Smuzhiyun dev->link[0].ids.hwid, dev->link[0].ids.regmapid);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun ddbwritel(dev, 0, DMA_BASE_READ);
231*4882a593Smuzhiyun ddbwritel(dev, 0, DMA_BASE_WRITE);
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun stat = ddb_irq_init(dev);
234*4882a593Smuzhiyun if (stat < 0)
235*4882a593Smuzhiyun goto fail0;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (ddb_init(dev) == 0)
238*4882a593Smuzhiyun return 0;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun ddb_irq_exit(dev);
241*4882a593Smuzhiyun fail0:
242*4882a593Smuzhiyun dev_err(&pdev->dev, "fail0\n");
243*4882a593Smuzhiyun ddb_msi_exit(dev);
244*4882a593Smuzhiyun fail:
245*4882a593Smuzhiyun dev_err(&pdev->dev, "fail\n");
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun ddb_unmap(dev);
248*4882a593Smuzhiyun pci_set_drvdata(pdev, NULL);
249*4882a593Smuzhiyun pci_disable_device(pdev);
250*4882a593Smuzhiyun return -1;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /****************************************************************************/
254*4882a593Smuzhiyun /****************************************************************************/
255*4882a593Smuzhiyun /****************************************************************************/
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun #define DDB_DEVICE_ANY(_device) \
258*4882a593Smuzhiyun { PCI_DEVICE_SUB(DDVID, _device, DDVID, PCI_ANY_ID) }
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun static const struct pci_device_id ddb_id_table[] = {
261*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0002),
262*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0003),
263*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0005),
264*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0006),
265*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0007),
266*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0008),
267*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0009),
268*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0011),
269*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0012),
270*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0013),
271*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0201),
272*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0203),
273*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0210),
274*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0220),
275*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0320),
276*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0321),
277*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0322),
278*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0323),
279*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0328),
280*4882a593Smuzhiyun DDB_DEVICE_ANY(0x0329),
281*4882a593Smuzhiyun {0}
282*4882a593Smuzhiyun };
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, ddb_id_table);
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun static struct pci_driver ddb_pci_driver = {
287*4882a593Smuzhiyun .name = "ddbridge",
288*4882a593Smuzhiyun .id_table = ddb_id_table,
289*4882a593Smuzhiyun .probe = ddb_probe,
290*4882a593Smuzhiyun .remove = ddb_remove,
291*4882a593Smuzhiyun };
292*4882a593Smuzhiyun
module_init_ddbridge(void)293*4882a593Smuzhiyun static __init int module_init_ddbridge(void)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun int stat;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun pr_info("Digital Devices PCIE bridge driver "
298*4882a593Smuzhiyun DDBRIDGE_VERSION
299*4882a593Smuzhiyun ", Copyright (C) 2010-17 Digital Devices GmbH\n");
300*4882a593Smuzhiyun stat = ddb_init_ddbridge();
301*4882a593Smuzhiyun if (stat < 0)
302*4882a593Smuzhiyun return stat;
303*4882a593Smuzhiyun stat = pci_register_driver(&ddb_pci_driver);
304*4882a593Smuzhiyun if (stat < 0)
305*4882a593Smuzhiyun ddb_exit_ddbridge(0, stat);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun return stat;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
module_exit_ddbridge(void)310*4882a593Smuzhiyun static __exit void module_exit_ddbridge(void)
311*4882a593Smuzhiyun {
312*4882a593Smuzhiyun pci_unregister_driver(&ddb_pci_driver);
313*4882a593Smuzhiyun ddb_exit_ddbridge(0, 0);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun module_init(module_init_ddbridge);
317*4882a593Smuzhiyun module_exit(module_exit_ddbridge);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
320*4882a593Smuzhiyun MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
321*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
322*4882a593Smuzhiyun MODULE_VERSION(DDBRIDGE_VERSION);
323