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