1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
4 * Synopsys DesignWare eDMA PCIe driver
5 *
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
17#include "dw-edma-core.h"
18
19struct dw_edma_pcie_data {
20	/* eDMA registers location */
21	enum pci_barno			rg_bar;
22	off_t				rg_off;
23	size_t				rg_sz;
24	/* eDMA memory linked list location */
25	enum pci_barno			ll_bar;
26	off_t				ll_off;
27	size_t				ll_sz;
28	/* eDMA memory data location */
29	enum pci_barno			dt_bar;
30	off_t				dt_off;
31	size_t				dt_sz;
32	/* Other */
33	u32				version;
34	enum dw_edma_mode		mode;
35	u8				irqs;
36};
37
38static const struct dw_edma_pcie_data snps_edda_data = {
39	/* eDMA registers location */
40	.rg_bar				= BAR_0,
41	.rg_off				= 0x00001000,	/*  4 Kbytes */
42	.rg_sz				= 0x00002000,	/*  8 Kbytes */
43	/* eDMA memory linked list location */
44	.ll_bar				= BAR_2,
45	.ll_off				= 0x00000000,	/*  0 Kbytes */
46	.ll_sz				= 0x00800000,	/*  8 Mbytes */
47	/* eDMA memory data location */
48	.dt_bar				= BAR_2,
49	.dt_off				= 0x00800000,	/*  8 Mbytes */
50	.dt_sz				= 0x03800000,	/* 56 Mbytes */
51	/* Other */
52	.version			= 0,
53	.mode				= EDMA_MODE_UNROLL,
54	.irqs				= 1,
55};
56
57static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
58{
59	return pci_irq_vector(to_pci_dev(dev), nr);
60}
61
62static const struct dw_edma_core_ops dw_edma_pcie_core_ops = {
63	.irq_vector = dw_edma_pcie_irq_vector,
64};
65
66static int dw_edma_pcie_probe(struct pci_dev *pdev,
67			      const struct pci_device_id *pid)
68{
69	const struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
70	struct device *dev = &pdev->dev;
71	struct dw_edma_chip *chip;
72	int err, nr_irqs;
73	struct dw_edma *dw;
74
75	/* Enable PCI device */
76	err = pcim_enable_device(pdev);
77	if (err) {
78		pci_err(pdev, "enabling device failed\n");
79		return err;
80	}
81
82	/* Mapping PCI BAR regions */
83	err = pcim_iomap_regions(pdev, BIT(pdata->rg_bar) |
84				       BIT(pdata->ll_bar) |
85				       BIT(pdata->dt_bar),
86				 pci_name(pdev));
87	if (err) {
88		pci_err(pdev, "eDMA BAR I/O remapping failed\n");
89		return err;
90	}
91
92	pci_set_master(pdev);
93
94	/* DMA configuration */
95	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
96	if (!err) {
97		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
98		if (err) {
99			pci_err(pdev, "consistent DMA mask 64 set failed\n");
100			return err;
101		}
102	} else {
103		pci_err(pdev, "DMA mask 64 set failed\n");
104
105		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
106		if (err) {
107			pci_err(pdev, "DMA mask 32 set failed\n");
108			return err;
109		}
110
111		err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
112		if (err) {
113			pci_err(pdev, "consistent DMA mask 32 set failed\n");
114			return err;
115		}
116	}
117
118	/* Data structure allocation */
119	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
120	if (!chip)
121		return -ENOMEM;
122
123	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
124	if (!dw)
125		return -ENOMEM;
126
127	/* IRQs allocation */
128	nr_irqs = pci_alloc_irq_vectors(pdev, 1, pdata->irqs,
129					PCI_IRQ_MSI | PCI_IRQ_MSIX);
130	if (nr_irqs < 1) {
131		pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
132			nr_irqs);
133		return -EPERM;
134	}
135
136	/* Data structure initialization */
137	chip->dw = dw;
138	chip->dev = dev;
139	chip->id = pdev->devfn;
140	chip->irq = pdev->irq;
141
142	dw->rg_region.vaddr = pcim_iomap_table(pdev)[pdata->rg_bar];
143	dw->rg_region.vaddr += pdata->rg_off;
144	dw->rg_region.paddr = pdev->resource[pdata->rg_bar].start;
145	dw->rg_region.paddr += pdata->rg_off;
146	dw->rg_region.sz = pdata->rg_sz;
147
148	dw->ll_region.vaddr = pcim_iomap_table(pdev)[pdata->ll_bar];
149	dw->ll_region.vaddr += pdata->ll_off;
150	dw->ll_region.paddr = pdev->resource[pdata->ll_bar].start;
151	dw->ll_region.paddr += pdata->ll_off;
152	dw->ll_region.sz = pdata->ll_sz;
153
154	dw->dt_region.vaddr = pcim_iomap_table(pdev)[pdata->dt_bar];
155	dw->dt_region.vaddr += pdata->dt_off;
156	dw->dt_region.paddr = pdev->resource[pdata->dt_bar].start;
157	dw->dt_region.paddr += pdata->dt_off;
158	dw->dt_region.sz = pdata->dt_sz;
159
160	dw->version = pdata->version;
161	dw->mode = pdata->mode;
162	dw->nr_irqs = nr_irqs;
163	dw->ops = &dw_edma_pcie_core_ops;
164
165	/* Debug info */
166	pci_dbg(pdev, "Version:\t%u\n", dw->version);
167
168	pci_dbg(pdev, "Mode:\t%s\n",
169		dw->mode == EDMA_MODE_LEGACY ? "Legacy" : "Unroll");
170
171	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
172		pdata->rg_bar, pdata->rg_off, pdata->rg_sz,
173		dw->rg_region.vaddr, &dw->rg_region.paddr);
174
175	pci_dbg(pdev, "L. List:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
176		pdata->ll_bar, pdata->ll_off, pdata->ll_sz,
177		dw->ll_region.vaddr, &dw->ll_region.paddr);
178
179	pci_dbg(pdev, "Data:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
180		pdata->dt_bar, pdata->dt_off, pdata->dt_sz,
181		dw->dt_region.vaddr, &dw->dt_region.paddr);
182
183	pci_dbg(pdev, "Nr. IRQs:\t%u\n", dw->nr_irqs);
184
185	/* Validating if PCI interrupts were enabled */
186	if (!pci_dev_msi_enabled(pdev)) {
187		pci_err(pdev, "enable interrupt failed\n");
188		return -EPERM;
189	}
190
191	dw->irq = devm_kcalloc(dev, nr_irqs, sizeof(*dw->irq), GFP_KERNEL);
192	if (!dw->irq)
193		return -ENOMEM;
194
195	/* Starting eDMA driver */
196	err = dw_edma_probe(chip);
197	if (err) {
198		pci_err(pdev, "eDMA probe failed\n");
199		return err;
200	}
201
202	/* Saving data structure reference */
203	pci_set_drvdata(pdev, chip);
204
205	return 0;
206}
207
208static void dw_edma_pcie_remove(struct pci_dev *pdev)
209{
210	struct dw_edma_chip *chip = pci_get_drvdata(pdev);
211	int err;
212
213	/* Stopping eDMA driver */
214	err = dw_edma_remove(chip);
215	if (err)
216		pci_warn(pdev, "can't remove device properly: %d\n", err);
217
218	/* Freeing IRQs */
219	pci_free_irq_vectors(pdev);
220}
221
222static const struct pci_device_id dw_edma_pcie_id_table[] = {
223	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
224	{ }
225};
226MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
227
228static struct pci_driver dw_edma_pcie_driver = {
229	.name		= "dw-edma-pcie",
230	.id_table	= dw_edma_pcie_id_table,
231	.probe		= dw_edma_pcie_probe,
232	.remove		= dw_edma_pcie_remove,
233};
234
235module_pci_driver(dw_edma_pcie_driver);
236
237MODULE_LICENSE("GPL v2");
238MODULE_DESCRIPTION("Synopsys DesignWare eDMA PCIe driver");
239MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
240