0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/pci.h>
0012 #include <linux/device.h>
0013 #include <linux/dma/edma.h>
0014 #include <linux/pci-epf.h>
0015 #include <linux/msi.h>
0016 #include <linux/bitfield.h>
0017
0018 #include "dw-edma-core.h"
0019
0020 #define DW_PCIE_VSEC_DMA_ID 0x6
0021 #define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8)
0022 #define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0)
0023 #define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0)
0024 #define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16)
0025
0026 #define DW_BLOCK(a, b, c) \
0027 { \
0028 .bar = a, \
0029 .off = b, \
0030 .sz = c, \
0031 },
0032
0033 struct dw_edma_block {
0034 enum pci_barno bar;
0035 off_t off;
0036 size_t sz;
0037 };
0038
0039 struct dw_edma_pcie_data {
0040
0041 struct dw_edma_block rg;
0042
0043 struct dw_edma_block ll_wr[EDMA_MAX_WR_CH];
0044 struct dw_edma_block ll_rd[EDMA_MAX_RD_CH];
0045
0046 struct dw_edma_block dt_wr[EDMA_MAX_WR_CH];
0047 struct dw_edma_block dt_rd[EDMA_MAX_RD_CH];
0048
0049 enum dw_edma_map_format mf;
0050 u8 irqs;
0051 u16 wr_ch_cnt;
0052 u16 rd_ch_cnt;
0053 };
0054
0055 static const struct dw_edma_pcie_data snps_edda_data = {
0056
0057 .rg.bar = BAR_0,
0058 .rg.off = 0x00001000,
0059 .rg.sz = 0x00002000,
0060
0061 .ll_wr = {
0062
0063 DW_BLOCK(BAR_2, 0x00000000, 0x00000800)
0064
0065 DW_BLOCK(BAR_2, 0x00200000, 0x00000800)
0066 },
0067 .ll_rd = {
0068
0069 DW_BLOCK(BAR_2, 0x00400000, 0x00000800)
0070
0071 DW_BLOCK(BAR_2, 0x00600000, 0x00000800)
0072 },
0073
0074 .dt_wr = {
0075
0076 DW_BLOCK(BAR_2, 0x00800000, 0x00000800)
0077
0078 DW_BLOCK(BAR_2, 0x00900000, 0x00000800)
0079 },
0080 .dt_rd = {
0081
0082 DW_BLOCK(BAR_2, 0x00a00000, 0x00000800)
0083
0084 DW_BLOCK(BAR_2, 0x00b00000, 0x00000800)
0085 },
0086
0087 .mf = EDMA_MF_EDMA_UNROLL,
0088 .irqs = 1,
0089 .wr_ch_cnt = 2,
0090 .rd_ch_cnt = 2,
0091 };
0092
0093 static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
0094 {
0095 return pci_irq_vector(to_pci_dev(dev), nr);
0096 }
0097
0098 static const struct dw_edma_core_ops dw_edma_pcie_core_ops = {
0099 .irq_vector = dw_edma_pcie_irq_vector,
0100 };
0101
0102 static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
0103 struct dw_edma_pcie_data *pdata)
0104 {
0105 u32 val, map;
0106 u16 vsec;
0107 u64 off;
0108
0109 vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_SYNOPSYS,
0110 DW_PCIE_VSEC_DMA_ID);
0111 if (!vsec)
0112 return;
0113
0114 pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val);
0115 if (PCI_VNDR_HEADER_REV(val) != 0x00 ||
0116 PCI_VNDR_HEADER_LEN(val) != 0x18)
0117 return;
0118
0119 pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended Capability DMA\n");
0120 pci_read_config_dword(pdev, vsec + 0x8, &val);
0121 map = FIELD_GET(DW_PCIE_VSEC_DMA_MAP, val);
0122 if (map != EDMA_MF_EDMA_LEGACY &&
0123 map != EDMA_MF_EDMA_UNROLL &&
0124 map != EDMA_MF_HDMA_COMPAT)
0125 return;
0126
0127 pdata->mf = map;
0128 pdata->rg.bar = FIELD_GET(DW_PCIE_VSEC_DMA_BAR, val);
0129
0130 pci_read_config_dword(pdev, vsec + 0xc, &val);
0131 pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt,
0132 FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val));
0133 pdata->rd_ch_cnt = min_t(u16, pdata->rd_ch_cnt,
0134 FIELD_GET(DW_PCIE_VSEC_DMA_RD_CH, val));
0135
0136 pci_read_config_dword(pdev, vsec + 0x14, &val);
0137 off = val;
0138 pci_read_config_dword(pdev, vsec + 0x10, &val);
0139 off <<= 32;
0140 off |= val;
0141 pdata->rg.off = off;
0142 }
0143
0144 static int dw_edma_pcie_probe(struct pci_dev *pdev,
0145 const struct pci_device_id *pid)
0146 {
0147 struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
0148 struct dw_edma_pcie_data vsec_data;
0149 struct device *dev = &pdev->dev;
0150 struct dw_edma_chip *chip;
0151 int err, nr_irqs;
0152 int i, mask;
0153
0154
0155 err = pcim_enable_device(pdev);
0156 if (err) {
0157 pci_err(pdev, "enabling device failed\n");
0158 return err;
0159 }
0160
0161 memcpy(&vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
0162
0163
0164
0165
0166
0167 dw_edma_pcie_get_vsec_dma_data(pdev, &vsec_data);
0168
0169
0170 mask = BIT(vsec_data.rg.bar);
0171 for (i = 0; i < vsec_data.wr_ch_cnt; i++) {
0172 mask |= BIT(vsec_data.ll_wr[i].bar);
0173 mask |= BIT(vsec_data.dt_wr[i].bar);
0174 }
0175 for (i = 0; i < vsec_data.rd_ch_cnt; i++) {
0176 mask |= BIT(vsec_data.ll_rd[i].bar);
0177 mask |= BIT(vsec_data.dt_rd[i].bar);
0178 }
0179 err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
0180 if (err) {
0181 pci_err(pdev, "eDMA BAR I/O remapping failed\n");
0182 return err;
0183 }
0184
0185 pci_set_master(pdev);
0186
0187
0188 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
0189 if (err) {
0190 pci_err(pdev, "DMA mask 64 set failed\n");
0191 return err;
0192 }
0193
0194
0195 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
0196 if (!chip)
0197 return -ENOMEM;
0198
0199
0200 nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
0201 PCI_IRQ_MSI | PCI_IRQ_MSIX);
0202 if (nr_irqs < 1) {
0203 pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
0204 nr_irqs);
0205 return -EPERM;
0206 }
0207
0208
0209 chip->dev = dev;
0210 chip->id = pdev->devfn;
0211
0212 chip->mf = vsec_data.mf;
0213 chip->nr_irqs = nr_irqs;
0214 chip->ops = &dw_edma_pcie_core_ops;
0215
0216 chip->ll_wr_cnt = vsec_data.wr_ch_cnt;
0217 chip->ll_rd_cnt = vsec_data.rd_ch_cnt;
0218
0219 chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
0220 if (!chip->reg_base)
0221 return -ENOMEM;
0222
0223 for (i = 0; i < chip->ll_wr_cnt; i++) {
0224 struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
0225 struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
0226 struct dw_edma_block *ll_block = &vsec_data.ll_wr[i];
0227 struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
0228
0229 ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
0230 if (!ll_region->vaddr)
0231 return -ENOMEM;
0232
0233 ll_region->vaddr += ll_block->off;
0234 ll_region->paddr = pdev->resource[ll_block->bar].start;
0235 ll_region->paddr += ll_block->off;
0236 ll_region->sz = ll_block->sz;
0237
0238 dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
0239 if (!dt_region->vaddr)
0240 return -ENOMEM;
0241
0242 dt_region->vaddr += dt_block->off;
0243 dt_region->paddr = pdev->resource[dt_block->bar].start;
0244 dt_region->paddr += dt_block->off;
0245 dt_region->sz = dt_block->sz;
0246 }
0247
0248 for (i = 0; i < chip->ll_rd_cnt; i++) {
0249 struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
0250 struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
0251 struct dw_edma_block *ll_block = &vsec_data.ll_rd[i];
0252 struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
0253
0254 ll_region->vaddr = pcim_iomap_table(pdev)[ll_block->bar];
0255 if (!ll_region->vaddr)
0256 return -ENOMEM;
0257
0258 ll_region->vaddr += ll_block->off;
0259 ll_region->paddr = pdev->resource[ll_block->bar].start;
0260 ll_region->paddr += ll_block->off;
0261 ll_region->sz = ll_block->sz;
0262
0263 dt_region->vaddr = pcim_iomap_table(pdev)[dt_block->bar];
0264 if (!dt_region->vaddr)
0265 return -ENOMEM;
0266
0267 dt_region->vaddr += dt_block->off;
0268 dt_region->paddr = pdev->resource[dt_block->bar].start;
0269 dt_region->paddr += dt_block->off;
0270 dt_region->sz = dt_block->sz;
0271 }
0272
0273
0274 if (chip->mf == EDMA_MF_EDMA_LEGACY)
0275 pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
0276 else if (chip->mf == EDMA_MF_EDMA_UNROLL)
0277 pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
0278 else if (chip->mf == EDMA_MF_HDMA_COMPAT)
0279 pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
0280 else
0281 pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
0282
0283 pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
0284 vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
0285 chip->reg_base);
0286
0287
0288 for (i = 0; i < chip->ll_wr_cnt; i++) {
0289 pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
0290 i, vsec_data.ll_wr[i].bar,
0291 vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
0292 chip->ll_region_wr[i].vaddr, &chip->ll_region_wr[i].paddr);
0293
0294 pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
0295 i, vsec_data.dt_wr[i].bar,
0296 vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
0297 chip->dt_region_wr[i].vaddr, &chip->dt_region_wr[i].paddr);
0298 }
0299
0300 for (i = 0; i < chip->ll_rd_cnt; i++) {
0301 pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
0302 i, vsec_data.ll_rd[i].bar,
0303 vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
0304 chip->ll_region_rd[i].vaddr, &chip->ll_region_rd[i].paddr);
0305
0306 pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
0307 i, vsec_data.dt_rd[i].bar,
0308 vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
0309 chip->dt_region_rd[i].vaddr, &chip->dt_region_rd[i].paddr);
0310 }
0311
0312 pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
0313
0314
0315 if (!pci_dev_msi_enabled(pdev)) {
0316 pci_err(pdev, "enable interrupt failed\n");
0317 return -EPERM;
0318 }
0319
0320
0321 err = dw_edma_probe(chip);
0322 if (err) {
0323 pci_err(pdev, "eDMA probe failed\n");
0324 return err;
0325 }
0326
0327
0328 pci_set_drvdata(pdev, chip);
0329
0330 return 0;
0331 }
0332
0333 static void dw_edma_pcie_remove(struct pci_dev *pdev)
0334 {
0335 struct dw_edma_chip *chip = pci_get_drvdata(pdev);
0336 int err;
0337
0338
0339 err = dw_edma_remove(chip);
0340 if (err)
0341 pci_warn(pdev, "can't remove device properly: %d\n", err);
0342
0343
0344 pci_free_irq_vectors(pdev);
0345 }
0346
0347 static const struct pci_device_id dw_edma_pcie_id_table[] = {
0348 { PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
0349 { }
0350 };
0351 MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
0352
0353 static struct pci_driver dw_edma_pcie_driver = {
0354 .name = "dw-edma-pcie",
0355 .id_table = dw_edma_pcie_id_table,
0356 .probe = dw_edma_pcie_probe,
0357 .remove = dw_edma_pcie_remove,
0358 };
0359
0360 module_pci_driver(dw_edma_pcie_driver);
0361
0362 MODULE_LICENSE("GPL v2");
0363 MODULE_DESCRIPTION("Synopsys DesignWare eDMA PCIe driver");
0364 MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");