379 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.4 * Synopsys DesignWare eDMA PCIe driver5 *6 * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>7 */8 9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/pci.h>12#include <linux/device.h>13#include <linux/dma/edma.h>14#include <linux/pci-epf.h>15#include <linux/msi.h>16#include <linux/bitfield.h>17 18#include "dw-edma-core.h"19 20#define DW_PCIE_VSEC_DMA_ID 0x621#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8)22#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0)23#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0)24#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16)25 26#define DW_BLOCK(a, b, c) \27 { \28 .bar = a, \29 .off = b, \30 .sz = c, \31 },32 33struct dw_edma_block {34 enum pci_barno bar;35 off_t off;36 size_t sz;37};38 39struct dw_edma_pcie_data {40 /* eDMA registers location */41 struct dw_edma_block rg;42 /* eDMA memory linked list location */43 struct dw_edma_block ll_wr[EDMA_MAX_WR_CH];44 struct dw_edma_block ll_rd[EDMA_MAX_RD_CH];45 /* eDMA memory data location */46 struct dw_edma_block dt_wr[EDMA_MAX_WR_CH];47 struct dw_edma_block dt_rd[EDMA_MAX_RD_CH];48 /* Other */49 enum dw_edma_map_format mf;50 u8 irqs;51 u16 wr_ch_cnt;52 u16 rd_ch_cnt;53};54 55static const struct dw_edma_pcie_data snps_edda_data = {56 /* eDMA registers location */57 .rg.bar = BAR_0,58 .rg.off = 0x00001000, /* 4 Kbytes */59 .rg.sz = 0x00002000, /* 8 Kbytes */60 /* eDMA memory linked list location */61 .ll_wr = {62 /* Channel 0 - BAR 2, offset 0 Mbytes, size 2 Kbytes */63 DW_BLOCK(BAR_2, 0x00000000, 0x00000800)64 /* Channel 1 - BAR 2, offset 2 Mbytes, size 2 Kbytes */65 DW_BLOCK(BAR_2, 0x00200000, 0x00000800)66 },67 .ll_rd = {68 /* Channel 0 - BAR 2, offset 4 Mbytes, size 2 Kbytes */69 DW_BLOCK(BAR_2, 0x00400000, 0x00000800)70 /* Channel 1 - BAR 2, offset 6 Mbytes, size 2 Kbytes */71 DW_BLOCK(BAR_2, 0x00600000, 0x00000800)72 },73 /* eDMA memory data location */74 .dt_wr = {75 /* Channel 0 - BAR 2, offset 8 Mbytes, size 2 Kbytes */76 DW_BLOCK(BAR_2, 0x00800000, 0x00000800)77 /* Channel 1 - BAR 2, offset 9 Mbytes, size 2 Kbytes */78 DW_BLOCK(BAR_2, 0x00900000, 0x00000800)79 },80 .dt_rd = {81 /* Channel 0 - BAR 2, offset 10 Mbytes, size 2 Kbytes */82 DW_BLOCK(BAR_2, 0x00a00000, 0x00000800)83 /* Channel 1 - BAR 2, offset 11 Mbytes, size 2 Kbytes */84 DW_BLOCK(BAR_2, 0x00b00000, 0x00000800)85 },86 /* Other */87 .mf = EDMA_MF_EDMA_UNROLL,88 .irqs = 1,89 .wr_ch_cnt = 2,90 .rd_ch_cnt = 2,91};92 93static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)94{95 return pci_irq_vector(to_pci_dev(dev), nr);96}97 98static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)99{100 struct pci_dev *pdev = to_pci_dev(dev);101 struct pci_bus_region region;102 struct resource res = {103 .flags = IORESOURCE_MEM,104 .start = cpu_addr,105 .end = cpu_addr,106 };107 108 pcibios_resource_to_bus(pdev->bus, ®ion, &res);109 return region.start;110}111 112static const struct dw_edma_plat_ops dw_edma_pcie_plat_ops = {113 .irq_vector = dw_edma_pcie_irq_vector,114 .pci_address = dw_edma_pcie_address,115};116 117static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,118 struct dw_edma_pcie_data *pdata)119{120 u32 val, map;121 u16 vsec;122 u64 off;123 124 vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_SYNOPSYS,125 DW_PCIE_VSEC_DMA_ID);126 if (!vsec)127 return;128 129 pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);130 if (PCI_VNDR_HEADER_REV(val) != 0x00 ||131 PCI_VNDR_HEADER_LEN(val) != 0x18)132 return;133 134 pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended Capability DMA\n");135 pci_read_config_dword(pdev, vsec + 0x8, &val);136 map = FIELD_GET(DW_PCIE_VSEC_DMA_MAP, val);137 if (map != EDMA_MF_EDMA_LEGACY &&138 map != EDMA_MF_EDMA_UNROLL &&139 map != EDMA_MF_HDMA_COMPAT)140 return;141 142 pdata->mf = map;143 pdata->rg.bar = FIELD_GET(DW_PCIE_VSEC_DMA_BAR, val);144 145 pci_read_config_dword(pdev, vsec + 0xc, &val);146 pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt,147 FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val));148 pdata->rd_ch_cnt = min_t(u16, pdata->rd_ch_cnt,149 FIELD_GET(DW_PCIE_VSEC_DMA_RD_CH, val));150 151 pci_read_config_dword(pdev, vsec + 0x14, &val);152 off = val;153 pci_read_config_dword(pdev, vsec + 0x10, &val);154 off <<= 32;155 off |= val;156 pdata->rg.off = off;157}158 159static int dw_edma_pcie_probe(struct pci_dev *pdev,160 const struct pci_device_id *pid)161{162 struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;163 struct dw_edma_pcie_data vsec_data;164 struct device *dev = &pdev->dev;165 struct dw_edma_chip *chip;166 int err, nr_irqs;167 int i, mask;168 169 /* Enable PCI device */170 err = pcim_enable_device(pdev);171 if (err) {172 pci_err(pdev, "enabling device failed\n");173 return err;174 }175 176 memcpy(&vsec_data, pdata, sizeof(struct dw_edma_pcie_data));177 178 /*179 * Tries to find if exists a PCIe Vendor-Specific Extended Capability180 * for the DMA, if one exists, then reconfigures it.181 */182 dw_edma_pcie_get_vsec_dma_data(pdev, &vsec_data);183 184 /* Mapping PCI BAR regions */185 mask = BIT(vsec_data.rg.bar);186 for (i = 0; i < vsec_data.wr_ch_cnt; i++) {187 mask |= BIT(vsec_data.ll_wr[i].bar);188 mask |= BIT(vsec_data.dt_wr[i].bar);189 }190 for (i = 0; i < vsec_data.rd_ch_cnt; i++) {191 mask |= BIT(vsec_data.ll_rd[i].bar);192 mask |= BIT(vsec_data.dt_rd[i].bar);193 }194 err = pcim_iomap_regions(pdev, mask, pci_name(pdev));195 if (err) {196 pci_err(pdev, "eDMA BAR I/O remapping failed\n");197 return err;198 }199 200 pci_set_master(pdev);201 202 /* DMA configuration */203 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));204 if (err) {205 pci_err(pdev, "DMA mask 64 set failed\n");206 return err;207 }208 209 /* Data structure allocation */210 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);211 if (!chip)212 return -ENOMEM;213 214 /* IRQs allocation */215 nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,216 PCI_IRQ_MSI | PCI_IRQ_MSIX);217 if (nr_irqs < 1) {218 pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",219 nr_irqs);220 return -EPERM;221 }222 223 /* Data structure initialization */224 chip->dev = dev;225 226 chip->mf = vsec_data.mf;227 chip->nr_irqs = nr_irqs;228 chip->ops = &dw_edma_pcie_plat_ops;229 230 chip->ll_wr_cnt = vsec_data.wr_ch_cnt;231 chip->ll_rd_cnt = vsec_data.rd_ch_cnt;232 233 chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];234 if (!chip->reg_base)235 return -ENOMEM;236 237 for (i = 0; i < chip->ll_wr_cnt; i++) {238 struct dw_edma_region *ll_region = &chip->ll_region_wr[i];239 struct dw_edma_region *dt_region = &chip->dt_region_wr[i];240 struct dw_edma_block *ll_block = &vsec_data.ll_wr[i];241 struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];242 243 ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];244 if (!ll_region->vaddr.io)245 return -ENOMEM;246 247 ll_region->vaddr.io += ll_block->off;248 ll_region->paddr = pci_bus_address(pdev, ll_block->bar);249 ll_region->paddr += ll_block->off;250 ll_region->sz = ll_block->sz;251 252 dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];253 if (!dt_region->vaddr.io)254 return -ENOMEM;255 256 dt_region->vaddr.io += dt_block->off;257 dt_region->paddr = pci_bus_address(pdev, dt_block->bar);258 dt_region->paddr += dt_block->off;259 dt_region->sz = dt_block->sz;260 }261 262 for (i = 0; i < chip->ll_rd_cnt; i++) {263 struct dw_edma_region *ll_region = &chip->ll_region_rd[i];264 struct dw_edma_region *dt_region = &chip->dt_region_rd[i];265 struct dw_edma_block *ll_block = &vsec_data.ll_rd[i];266 struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];267 268 ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];269 if (!ll_region->vaddr.io)270 return -ENOMEM;271 272 ll_region->vaddr.io += ll_block->off;273 ll_region->paddr = pci_bus_address(pdev, ll_block->bar);274 ll_region->paddr += ll_block->off;275 ll_region->sz = ll_block->sz;276 277 dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];278 if (!dt_region->vaddr.io)279 return -ENOMEM;280 281 dt_region->vaddr.io += dt_block->off;282 dt_region->paddr = pci_bus_address(pdev, dt_block->bar);283 dt_region->paddr += dt_block->off;284 dt_region->sz = dt_block->sz;285 }286 287 /* Debug info */288 if (chip->mf == EDMA_MF_EDMA_LEGACY)289 pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);290 else if (chip->mf == EDMA_MF_EDMA_UNROLL)291 pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);292 else if (chip->mf == EDMA_MF_HDMA_COMPAT)293 pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);294 else295 pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);296 297 pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",298 vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,299 chip->reg_base);300 301 302 for (i = 0; i < chip->ll_wr_cnt; i++) {303 pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",304 i, vsec_data.ll_wr[i].bar,305 vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,306 chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);307 308 pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",309 i, vsec_data.dt_wr[i].bar,310 vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,311 chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);312 }313 314 for (i = 0; i < chip->ll_rd_cnt; i++) {315 pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",316 i, vsec_data.ll_rd[i].bar,317 vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,318 chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);319 320 pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",321 i, vsec_data.dt_rd[i].bar,322 vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,323 chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);324 }325 326 pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);327 328 /* Validating if PCI interrupts were enabled */329 if (!pci_dev_msi_enabled(pdev)) {330 pci_err(pdev, "enable interrupt failed\n");331 return -EPERM;332 }333 334 /* Starting eDMA driver */335 err = dw_edma_probe(chip);336 if (err) {337 pci_err(pdev, "eDMA probe failed\n");338 return err;339 }340 341 /* Saving data structure reference */342 pci_set_drvdata(pdev, chip);343 344 return 0;345}346 347static void dw_edma_pcie_remove(struct pci_dev *pdev)348{349 struct dw_edma_chip *chip = pci_get_drvdata(pdev);350 int err;351 352 /* Stopping eDMA driver */353 err = dw_edma_remove(chip);354 if (err)355 pci_warn(pdev, "can't remove device properly: %d\n", err);356 357 /* Freeing IRQs */358 pci_free_irq_vectors(pdev);359}360 361static const struct pci_device_id dw_edma_pcie_id_table[] = {362 { PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },363 { }364};365MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);366 367static struct pci_driver dw_edma_pcie_driver = {368 .name = "dw-edma-pcie",369 .id_table = dw_edma_pcie_id_table,370 .probe = dw_edma_pcie_probe,371 .remove = dw_edma_pcie_remove,372};373 374module_pci_driver(dw_edma_pcie_driver);375 376MODULE_LICENSE("GPL v2");377MODULE_DESCRIPTION("Synopsys DesignWare eDMA PCIe driver");378MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");379