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