1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PCI driver for the Synopsys DesignWare DMA Controller 4 * 5 * Copyright (C) 2013 Intel Corporation 6 * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 7 */ 8 9 #include <linux/module.h> 10 #include <linux/pci.h> 11 #include <linux/device.h> 12 13 #include "internal.h" 14 15 struct dw_dma_pci_data { 16 const struct dw_dma_platform_data *pdata; 17 int (*probe)(struct dw_dma_chip *chip); 18 int (*remove)(struct dw_dma_chip *chip); 19 struct dw_dma_chip *chip; 20 }; 21 22 static const struct dw_dma_pci_data dw_pci_data = { 23 .probe = dw_dma_probe, 24 .remove = dw_dma_remove, 25 }; 26 27 static const struct dw_dma_platform_data idma32_pdata = { 28 .nr_channels = 8, 29 .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, 30 .chan_priority = CHAN_PRIORITY_ASCENDING, 31 .block_size = 131071, 32 .nr_masters = 1, 33 .data_width = {4}, 34 .multi_block = {1, 1, 1, 1, 1, 1, 1, 1}, 35 }; 36 37 static const struct dw_dma_pci_data idma32_pci_data = { 38 .pdata = &idma32_pdata, 39 .probe = idma32_dma_probe, 40 .remove = idma32_dma_remove, 41 }; 42 43 static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) 44 { 45 const struct dw_dma_pci_data *drv_data = (void *)pid->driver_data; 46 struct dw_dma_pci_data *data; 47 struct dw_dma_chip *chip; 48 int ret; 49 50 ret = pcim_enable_device(pdev); 51 if (ret) 52 return ret; 53 54 ret = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); 55 if (ret) { 56 dev_err(&pdev->dev, "I/O memory remapping failed\n"); 57 return ret; 58 } 59 60 pci_set_master(pdev); 61 pci_try_set_mwi(pdev); 62 63 ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 64 if (ret) 65 return ret; 66 67 ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 68 if (ret) 69 return ret; 70 71 data = devm_kmemdup(&pdev->dev, drv_data, sizeof(*drv_data), GFP_KERNEL); 72 if (!data) 73 return -ENOMEM; 74 75 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); 76 if (!chip) 77 return -ENOMEM; 78 79 chip->dev = &pdev->dev; 80 chip->id = pdev->devfn; 81 chip->regs = pcim_iomap_table(pdev)[0]; 82 chip->irq = pdev->irq; 83 chip->pdata = data->pdata; 84 85 data->chip = chip; 86 87 ret = data->probe(chip); 88 if (ret) 89 return ret; 90 91 pci_set_drvdata(pdev, data); 92 93 return 0; 94 } 95 96 static void dw_pci_remove(struct pci_dev *pdev) 97 { 98 struct dw_dma_pci_data *data = pci_get_drvdata(pdev); 99 struct dw_dma_chip *chip = data->chip; 100 int ret; 101 102 ret = data->remove(chip); 103 if (ret) 104 dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret); 105 } 106 107 #ifdef CONFIG_PM_SLEEP 108 109 static int dw_pci_suspend_late(struct device *dev) 110 { 111 struct dw_dma_pci_data *data = dev_get_drvdata(dev); 112 struct dw_dma_chip *chip = data->chip; 113 114 return do_dw_dma_disable(chip); 115 }; 116 117 static int dw_pci_resume_early(struct device *dev) 118 { 119 struct dw_dma_pci_data *data = dev_get_drvdata(dev); 120 struct dw_dma_chip *chip = data->chip; 121 122 return do_dw_dma_enable(chip); 123 }; 124 125 #endif /* CONFIG_PM_SLEEP */ 126 127 static const struct dev_pm_ops dw_pci_dev_pm_ops = { 128 SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_pci_suspend_late, dw_pci_resume_early) 129 }; 130 131 static const struct pci_device_id dw_pci_id_table[] = { 132 /* Medfield (GPDMA) */ 133 { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_data }, 134 135 /* BayTrail */ 136 { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_data }, 137 { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_data }, 138 139 /* Merrifield */ 140 { PCI_VDEVICE(INTEL, 0x11a2), (kernel_ulong_t)&idma32_pci_data }, 141 142 /* Braswell */ 143 { PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_data }, 144 { PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_data }, 145 146 /* Elkhart Lake iDMA 32-bit (PSE DMA) */ 147 { PCI_VDEVICE(INTEL, 0x4bb4), (kernel_ulong_t)&idma32_pci_data }, 148 { PCI_VDEVICE(INTEL, 0x4bb5), (kernel_ulong_t)&idma32_pci_data }, 149 { PCI_VDEVICE(INTEL, 0x4bb6), (kernel_ulong_t)&idma32_pci_data }, 150 151 /* Haswell */ 152 { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_data }, 153 154 /* Broadwell */ 155 { PCI_VDEVICE(INTEL, 0x9ce0), (kernel_ulong_t)&dw_pci_data }, 156 157 { } 158 }; 159 MODULE_DEVICE_TABLE(pci, dw_pci_id_table); 160 161 static struct pci_driver dw_pci_driver = { 162 .name = "dw_dmac_pci", 163 .id_table = dw_pci_id_table, 164 .probe = dw_pci_probe, 165 .remove = dw_pci_remove, 166 .driver = { 167 .pm = &dw_pci_dev_pm_ops, 168 }, 169 }; 170 171 module_pci_driver(dw_pci_driver); 172 173 MODULE_LICENSE("GPL v2"); 174 MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller PCI driver"); 175 MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); 176