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