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