mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
28
drivers/dma/dw/Kconfig
Normal file
28
drivers/dma/dw/Kconfig
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# DMA engine configuration for dw
|
||||
#
|
||||
|
||||
config DW_DMAC_CORE
|
||||
tristate "Synopsys DesignWare AHB DMA support"
|
||||
select DMA_ENGINE
|
||||
|
||||
config DW_DMAC
|
||||
tristate "Synopsys DesignWare AHB DMA platform driver"
|
||||
select DW_DMAC_CORE
|
||||
select DW_DMAC_BIG_ENDIAN_IO if AVR32
|
||||
default y if CPU_AT32AP7000
|
||||
help
|
||||
Support the Synopsys DesignWare AHB DMA controller. This
|
||||
can be integrated in chips such as the Atmel AT32ap7000.
|
||||
|
||||
config DW_DMAC_PCI
|
||||
tristate "Synopsys DesignWare AHB DMA PCI driver"
|
||||
depends on PCI
|
||||
select DW_DMAC_CORE
|
||||
help
|
||||
Support the Synopsys DesignWare AHB DMA controller on the
|
||||
platfroms that enumerate it as a PCI device. For example,
|
||||
Intel Medfield has integrated this GPDMA controller.
|
||||
|
||||
config DW_DMAC_BIG_ENDIAN_IO
|
||||
bool
|
8
drivers/dma/dw/Makefile
Normal file
8
drivers/dma/dw/Makefile
Normal file
|
@ -0,0 +1,8 @@
|
|||
obj-$(CONFIG_DW_DMAC_CORE) += dw_dmac_core.o
|
||||
dw_dmac_core-objs := core.o
|
||||
|
||||
obj-$(CONFIG_DW_DMAC) += dw_dmac.o
|
||||
dw_dmac-objs := platform.o
|
||||
|
||||
obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o
|
||||
dw_dmac_pci-objs := pci.o
|
1721
drivers/dma/dw/core.c
Normal file
1721
drivers/dma/dw/core.c
Normal file
File diff suppressed because it is too large
Load diff
23
drivers/dma/dw/internal.h
Normal file
23
drivers/dma/dw/internal.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Driver for the Synopsys DesignWare DMA Controller
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _DMA_DW_INTERNAL_H
|
||||
#define _DMA_DW_INTERNAL_H
|
||||
|
||||
#include <linux/dma/dw.h>
|
||||
|
||||
#include "regs.h"
|
||||
|
||||
int dw_dma_disable(struct dw_dma_chip *chip);
|
||||
int dw_dma_enable(struct dw_dma_chip *chip);
|
||||
|
||||
extern bool dw_dma_filter(struct dma_chan *chan, void *param);
|
||||
|
||||
#endif /* _DMA_DW_INTERNAL_H */
|
135
drivers/dma/dw/pci.c
Normal file
135
drivers/dma/dw/pci.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* PCI driver for the Synopsys DesignWare DMA Controller
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
* Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
static struct dw_dma_platform_data dw_pci_pdata = {
|
||||
.is_private = 1,
|
||||
.chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
|
||||
.chan_priority = CHAN_PRIORITY_ASCENDING,
|
||||
};
|
||||
|
||||
static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
|
||||
{
|
||||
struct dw_dma_chip *chip;
|
||||
struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
|
||||
int ret;
|
||||
|
||||
ret = pcim_enable_device(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "I/O memory remapping failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pci_set_master(pdev);
|
||||
pci_try_set_mwi(pdev);
|
||||
|
||||
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->dev = &pdev->dev;
|
||||
chip->regs = pcim_iomap_table(pdev)[0];
|
||||
chip->irq = pdev->irq;
|
||||
|
||||
ret = dw_dma_probe(chip, pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pci_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_pci_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct dw_dma_chip *chip = pci_get_drvdata(pdev);
|
||||
int ret;
|
||||
|
||||
ret = dw_dma_remove(chip);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int dw_pci_suspend_late(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
struct dw_dma_chip *chip = pci_get_drvdata(pci);
|
||||
|
||||
return dw_dma_disable(chip);
|
||||
};
|
||||
|
||||
static int dw_pci_resume_early(struct device *dev)
|
||||
{
|
||||
struct pci_dev *pci = to_pci_dev(dev);
|
||||
struct dw_dma_chip *chip = pci_get_drvdata(pci);
|
||||
|
||||
return dw_dma_enable(chip);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops dw_pci_dev_pm_ops = {
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_pci_suspend_late, dw_pci_resume_early)
|
||||
};
|
||||
|
||||
static const struct pci_device_id dw_pci_id_table[] = {
|
||||
/* Medfield */
|
||||
{ PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_pdata },
|
||||
{ PCI_VDEVICE(INTEL, 0x0830), (kernel_ulong_t)&dw_pci_pdata },
|
||||
|
||||
/* BayTrail */
|
||||
{ PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_pdata },
|
||||
{ PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_pdata },
|
||||
|
||||
/* Braswell */
|
||||
{ PCI_VDEVICE(INTEL, 0x2286), (kernel_ulong_t)&dw_pci_pdata },
|
||||
{ PCI_VDEVICE(INTEL, 0x22c0), (kernel_ulong_t)&dw_pci_pdata },
|
||||
|
||||
/* Haswell */
|
||||
{ PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_pdata },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, dw_pci_id_table);
|
||||
|
||||
static struct pci_driver dw_pci_driver = {
|
||||
.name = "dw_dmac_pci",
|
||||
.id_table = dw_pci_id_table,
|
||||
.probe = dw_pci_probe,
|
||||
.remove = dw_pci_remove,
|
||||
.driver = {
|
||||
.pm = &dw_pci_dev_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
module_pci_driver(dw_pci_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller PCI driver");
|
||||
MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
|
305
drivers/dma/dw/platform.c
Normal file
305
drivers/dma/dw/platform.c
Normal file
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Platform driver for the Synopsys DesignWare DMA Controller
|
||||
*
|
||||
* Copyright (C) 2007-2008 Atmel Corporation
|
||||
* Copyright (C) 2010-2011 ST Microelectronics
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* Some parts of this driver are derived from the original dw_dmac.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_dma.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/acpi_dma.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define DRV_NAME "dw_dmac"
|
||||
|
||||
static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
|
||||
struct of_dma *ofdma)
|
||||
{
|
||||
struct dw_dma *dw = ofdma->of_dma_data;
|
||||
struct dw_dma_slave slave = {
|
||||
.dma_dev = dw->dma.dev,
|
||||
};
|
||||
dma_cap_mask_t cap;
|
||||
|
||||
if (dma_spec->args_count != 3)
|
||||
return NULL;
|
||||
|
||||
slave.src_id = dma_spec->args[0];
|
||||
slave.dst_id = dma_spec->args[0];
|
||||
slave.src_master = dma_spec->args[1];
|
||||
slave.dst_master = dma_spec->args[2];
|
||||
|
||||
if (WARN_ON(slave.src_id >= DW_DMA_MAX_NR_REQUESTS ||
|
||||
slave.dst_id >= DW_DMA_MAX_NR_REQUESTS ||
|
||||
slave.src_master >= dw->nr_masters ||
|
||||
slave.dst_master >= dw->nr_masters))
|
||||
return NULL;
|
||||
|
||||
dma_cap_zero(cap);
|
||||
dma_cap_set(DMA_SLAVE, cap);
|
||||
|
||||
/* TODO: there should be a simpler way to do this */
|
||||
return dma_request_channel(cap, dw_dma_filter, &slave);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct acpi_dma_spec *dma_spec = param;
|
||||
struct dw_dma_slave slave = {
|
||||
.dma_dev = dma_spec->dev,
|
||||
.src_id = dma_spec->slave_id,
|
||||
.dst_id = dma_spec->slave_id,
|
||||
.src_master = 1,
|
||||
.dst_master = 0,
|
||||
};
|
||||
|
||||
return dw_dma_filter(chan, &slave);
|
||||
}
|
||||
|
||||
static void dw_dma_acpi_controller_register(struct dw_dma *dw)
|
||||
{
|
||||
struct device *dev = dw->dma.dev;
|
||||
struct acpi_dma_filter_info *info;
|
||||
int ret;
|
||||
|
||||
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
dma_cap_zero(info->dma_cap);
|
||||
dma_cap_set(DMA_SLAVE, info->dma_cap);
|
||||
info->filter_fn = dw_dma_acpi_filter;
|
||||
|
||||
ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
|
||||
info);
|
||||
if (ret)
|
||||
dev_err(dev, "could not register acpi_dma_controller\n");
|
||||
}
|
||||
#else /* !CONFIG_ACPI */
|
||||
static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
|
||||
#endif /* !CONFIG_ACPI */
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct dw_dma_platform_data *
|
||||
dw_dma_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct dw_dma_platform_data *pdata;
|
||||
u32 tmp, arr[4];
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Missing DT data\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return NULL;
|
||||
|
||||
if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
|
||||
return NULL;
|
||||
|
||||
if (of_property_read_bool(np, "is_private"))
|
||||
pdata->is_private = true;
|
||||
|
||||
if (!of_property_read_u32(np, "chan_allocation_order", &tmp))
|
||||
pdata->chan_allocation_order = (unsigned char)tmp;
|
||||
|
||||
if (!of_property_read_u32(np, "chan_priority", &tmp))
|
||||
pdata->chan_priority = tmp;
|
||||
|
||||
if (!of_property_read_u32(np, "block_size", &tmp))
|
||||
pdata->block_size = tmp;
|
||||
|
||||
if (!of_property_read_u32(np, "dma-masters", &tmp)) {
|
||||
if (tmp > 4)
|
||||
return NULL;
|
||||
|
||||
pdata->nr_masters = tmp;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32_array(np, "data_width", arr,
|
||||
pdata->nr_masters))
|
||||
for (tmp = 0; tmp < pdata->nr_masters; tmp++)
|
||||
pdata->data_width[tmp] = arr[tmp];
|
||||
|
||||
return pdata;
|
||||
}
|
||||
#else
|
||||
static inline struct dw_dma_platform_data *
|
||||
dw_dma_parse_dt(struct platform_device *pdev)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dw_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_dma_chip *chip;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *mem;
|
||||
struct dw_dma_platform_data *pdata;
|
||||
int err;
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->irq = platform_get_irq(pdev, 0);
|
||||
if (chip->irq < 0)
|
||||
return chip->irq;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
chip->regs = devm_ioremap_resource(dev, mem);
|
||||
if (IS_ERR(chip->regs))
|
||||
return PTR_ERR(chip->regs);
|
||||
|
||||
err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pdata = dev_get_platdata(dev);
|
||||
if (!pdata)
|
||||
pdata = dw_dma_parse_dt(pdev);
|
||||
|
||||
chip->dev = dev;
|
||||
|
||||
chip->clk = devm_clk_get(chip->dev, "hclk");
|
||||
if (IS_ERR(chip->clk))
|
||||
return PTR_ERR(chip->clk);
|
||||
err = clk_prepare_enable(chip->clk);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = dw_dma_probe(chip, pdata);
|
||||
if (err)
|
||||
goto err_dw_dma_probe;
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
err = of_dma_controller_register(pdev->dev.of_node,
|
||||
dw_dma_of_xlate, chip->dw);
|
||||
if (err)
|
||||
dev_err(&pdev->dev,
|
||||
"could not register of_dma_controller\n");
|
||||
}
|
||||
|
||||
if (ACPI_HANDLE(&pdev->dev))
|
||||
dw_dma_acpi_controller_register(chip->dw);
|
||||
|
||||
return 0;
|
||||
|
||||
err_dw_dma_probe:
|
||||
clk_disable_unprepare(chip->clk);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dw_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
if (pdev->dev.of_node)
|
||||
of_dma_controller_free(pdev->dev.of_node);
|
||||
|
||||
dw_dma_remove(chip);
|
||||
clk_disable_unprepare(chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
dw_dma_disable(chip);
|
||||
clk_disable_unprepare(chip->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id dw_dma_of_id_table[] = {
|
||||
{ .compatible = "snps,dma-spear1340" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id dw_dma_acpi_id_table[] = {
|
||||
{ "INTL9C60", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int dw_suspend_late(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
dw_dma_disable(chip);
|
||||
clk_disable_unprepare(chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_resume_early(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
clk_prepare_enable(chip->clk);
|
||||
return dw_dma_enable(chip);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static const struct dev_pm_ops dw_dev_pm_ops = {
|
||||
SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_suspend_late, dw_resume_early)
|
||||
};
|
||||
|
||||
static struct platform_driver dw_driver = {
|
||||
.probe = dw_probe,
|
||||
.remove = dw_remove,
|
||||
.shutdown = dw_shutdown,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.pm = &dw_dev_pm_ops,
|
||||
.of_match_table = of_match_ptr(dw_dma_of_id_table),
|
||||
.acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init dw_init(void)
|
||||
{
|
||||
return platform_driver_register(&dw_driver);
|
||||
}
|
||||
subsys_initcall(dw_init);
|
||||
|
||||
static void __exit dw_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&dw_driver);
|
||||
}
|
||||
module_exit(dw_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
345
drivers/dma/dw/regs.h
Normal file
345
drivers/dma/dw/regs.h
Normal file
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Driver for the Synopsys DesignWare AHB DMA Controller
|
||||
*
|
||||
* Copyright (C) 2005-2007 Atmel Corporation
|
||||
* Copyright (C) 2010-2011 ST Microelectronics
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#define DW_DMA_MAX_NR_CHANNELS 8
|
||||
#define DW_DMA_MAX_NR_REQUESTS 16
|
||||
|
||||
/* flow controller */
|
||||
enum dw_dma_fc {
|
||||
DW_DMA_FC_D_M2M,
|
||||
DW_DMA_FC_D_M2P,
|
||||
DW_DMA_FC_D_P2M,
|
||||
DW_DMA_FC_D_P2P,
|
||||
DW_DMA_FC_P_P2M,
|
||||
DW_DMA_FC_SP_P2P,
|
||||
DW_DMA_FC_P_M2P,
|
||||
DW_DMA_FC_DP_P2P,
|
||||
};
|
||||
|
||||
/*
|
||||
* Redefine this macro to handle differences between 32- and 64-bit
|
||||
* addressing, big vs. little endian, etc.
|
||||
*/
|
||||
#define DW_REG(name) u32 name; u32 __pad_##name
|
||||
|
||||
/* Hardware register definitions. */
|
||||
struct dw_dma_chan_regs {
|
||||
DW_REG(SAR); /* Source Address Register */
|
||||
DW_REG(DAR); /* Destination Address Register */
|
||||
DW_REG(LLP); /* Linked List Pointer */
|
||||
u32 CTL_LO; /* Control Register Low */
|
||||
u32 CTL_HI; /* Control Register High */
|
||||
DW_REG(SSTAT);
|
||||
DW_REG(DSTAT);
|
||||
DW_REG(SSTATAR);
|
||||
DW_REG(DSTATAR);
|
||||
u32 CFG_LO; /* Configuration Register Low */
|
||||
u32 CFG_HI; /* Configuration Register High */
|
||||
DW_REG(SGR);
|
||||
DW_REG(DSR);
|
||||
};
|
||||
|
||||
struct dw_dma_irq_regs {
|
||||
DW_REG(XFER);
|
||||
DW_REG(BLOCK);
|
||||
DW_REG(SRC_TRAN);
|
||||
DW_REG(DST_TRAN);
|
||||
DW_REG(ERROR);
|
||||
};
|
||||
|
||||
struct dw_dma_regs {
|
||||
/* per-channel registers */
|
||||
struct dw_dma_chan_regs CHAN[DW_DMA_MAX_NR_CHANNELS];
|
||||
|
||||
/* irq handling */
|
||||
struct dw_dma_irq_regs RAW; /* r */
|
||||
struct dw_dma_irq_regs STATUS; /* r (raw & mask) */
|
||||
struct dw_dma_irq_regs MASK; /* rw (set = irq enabled) */
|
||||
struct dw_dma_irq_regs CLEAR; /* w (ack, affects "raw") */
|
||||
|
||||
DW_REG(STATUS_INT); /* r */
|
||||
|
||||
/* software handshaking */
|
||||
DW_REG(REQ_SRC);
|
||||
DW_REG(REQ_DST);
|
||||
DW_REG(SGL_REQ_SRC);
|
||||
DW_REG(SGL_REQ_DST);
|
||||
DW_REG(LAST_SRC);
|
||||
DW_REG(LAST_DST);
|
||||
|
||||
/* miscellaneous */
|
||||
DW_REG(CFG);
|
||||
DW_REG(CH_EN);
|
||||
DW_REG(ID);
|
||||
DW_REG(TEST);
|
||||
|
||||
/* reserved */
|
||||
DW_REG(__reserved0);
|
||||
DW_REG(__reserved1);
|
||||
|
||||
/* optional encoded params, 0x3c8..0x3f7 */
|
||||
u32 __reserved;
|
||||
|
||||
/* per-channel configuration registers */
|
||||
u32 DWC_PARAMS[DW_DMA_MAX_NR_CHANNELS];
|
||||
u32 MULTI_BLK_TYPE;
|
||||
u32 MAX_BLK_SIZE;
|
||||
|
||||
/* top-level parameters */
|
||||
u32 DW_PARAMS;
|
||||
};
|
||||
|
||||
/*
|
||||
* Big endian I/O access when reading and writing to the DMA controller
|
||||
* registers. This is needed on some platforms, like the Atmel AVR32
|
||||
* architecture.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
|
||||
#define dma_readl_native ioread32be
|
||||
#define dma_writel_native iowrite32be
|
||||
#else
|
||||
#define dma_readl_native readl
|
||||
#define dma_writel_native writel
|
||||
#endif
|
||||
|
||||
/* To access the registers in early stage of probe */
|
||||
#define dma_read_byaddr(addr, name) \
|
||||
dma_readl_native((addr) + offsetof(struct dw_dma_regs, name))
|
||||
|
||||
/* Bitfields in DW_PARAMS */
|
||||
#define DW_PARAMS_NR_CHAN 8 /* number of channels */
|
||||
#define DW_PARAMS_NR_MASTER 11 /* number of AHB masters */
|
||||
#define DW_PARAMS_DATA_WIDTH(n) (15 + 2 * (n))
|
||||
#define DW_PARAMS_DATA_WIDTH1 15 /* master 1 data width */
|
||||
#define DW_PARAMS_DATA_WIDTH2 17 /* master 2 data width */
|
||||
#define DW_PARAMS_DATA_WIDTH3 19 /* master 3 data width */
|
||||
#define DW_PARAMS_DATA_WIDTH4 21 /* master 4 data width */
|
||||
#define DW_PARAMS_EN 28 /* encoded parameters */
|
||||
|
||||
/* Bitfields in DWC_PARAMS */
|
||||
#define DWC_PARAMS_MBLK_EN 11 /* multi block transfer */
|
||||
|
||||
/* bursts size */
|
||||
enum dw_dma_msize {
|
||||
DW_DMA_MSIZE_1,
|
||||
DW_DMA_MSIZE_4,
|
||||
DW_DMA_MSIZE_8,
|
||||
DW_DMA_MSIZE_16,
|
||||
DW_DMA_MSIZE_32,
|
||||
DW_DMA_MSIZE_64,
|
||||
DW_DMA_MSIZE_128,
|
||||
DW_DMA_MSIZE_256,
|
||||
};
|
||||
|
||||
/* Bitfields in CTL_LO */
|
||||
#define DWC_CTLL_INT_EN (1 << 0) /* irqs enabled? */
|
||||
#define DWC_CTLL_DST_WIDTH(n) ((n)<<1) /* bytes per element */
|
||||
#define DWC_CTLL_SRC_WIDTH(n) ((n)<<4)
|
||||
#define DWC_CTLL_DST_INC (0<<7) /* DAR update/not */
|
||||
#define DWC_CTLL_DST_DEC (1<<7)
|
||||
#define DWC_CTLL_DST_FIX (2<<7)
|
||||
#define DWC_CTLL_SRC_INC (0<<7) /* SAR update/not */
|
||||
#define DWC_CTLL_SRC_DEC (1<<9)
|
||||
#define DWC_CTLL_SRC_FIX (2<<9)
|
||||
#define DWC_CTLL_DST_MSIZE(n) ((n)<<11) /* burst, #elements */
|
||||
#define DWC_CTLL_SRC_MSIZE(n) ((n)<<14)
|
||||
#define DWC_CTLL_S_GATH_EN (1 << 17) /* src gather, !FIX */
|
||||
#define DWC_CTLL_D_SCAT_EN (1 << 18) /* dst scatter, !FIX */
|
||||
#define DWC_CTLL_FC(n) ((n) << 20)
|
||||
#define DWC_CTLL_FC_M2M (0 << 20) /* mem-to-mem */
|
||||
#define DWC_CTLL_FC_M2P (1 << 20) /* mem-to-periph */
|
||||
#define DWC_CTLL_FC_P2M (2 << 20) /* periph-to-mem */
|
||||
#define DWC_CTLL_FC_P2P (3 << 20) /* periph-to-periph */
|
||||
/* plus 4 transfer types for peripheral-as-flow-controller */
|
||||
#define DWC_CTLL_DMS(n) ((n)<<23) /* dst master select */
|
||||
#define DWC_CTLL_SMS(n) ((n)<<25) /* src master select */
|
||||
#define DWC_CTLL_LLP_D_EN (1 << 27) /* dest block chain */
|
||||
#define DWC_CTLL_LLP_S_EN (1 << 28) /* src block chain */
|
||||
|
||||
/* Bitfields in CTL_HI */
|
||||
#define DWC_CTLH_DONE 0x00001000
|
||||
#define DWC_CTLH_BLOCK_TS_MASK 0x00000fff
|
||||
|
||||
/* Bitfields in CFG_LO */
|
||||
#define DWC_CFGL_CH_PRIOR_MASK (0x7 << 5) /* priority mask */
|
||||
#define DWC_CFGL_CH_PRIOR(x) ((x) << 5) /* priority */
|
||||
#define DWC_CFGL_CH_SUSP (1 << 8) /* pause xfer */
|
||||
#define DWC_CFGL_FIFO_EMPTY (1 << 9) /* pause xfer */
|
||||
#define DWC_CFGL_HS_DST (1 << 10) /* handshake w/dst */
|
||||
#define DWC_CFGL_HS_SRC (1 << 11) /* handshake w/src */
|
||||
#define DWC_CFGL_LOCK_CH_XFER (0 << 12) /* scope of LOCK_CH */
|
||||
#define DWC_CFGL_LOCK_CH_BLOCK (1 << 12)
|
||||
#define DWC_CFGL_LOCK_CH_XACT (2 << 12)
|
||||
#define DWC_CFGL_LOCK_BUS_XFER (0 << 14) /* scope of LOCK_BUS */
|
||||
#define DWC_CFGL_LOCK_BUS_BLOCK (1 << 14)
|
||||
#define DWC_CFGL_LOCK_BUS_XACT (2 << 14)
|
||||
#define DWC_CFGL_LOCK_CH (1 << 15) /* channel lockout */
|
||||
#define DWC_CFGL_LOCK_BUS (1 << 16) /* busmaster lockout */
|
||||
#define DWC_CFGL_HS_DST_POL (1 << 18) /* dst handshake active low */
|
||||
#define DWC_CFGL_HS_SRC_POL (1 << 19) /* src handshake active low */
|
||||
#define DWC_CFGL_MAX_BURST(x) ((x) << 20)
|
||||
#define DWC_CFGL_RELOAD_SAR (1 << 30)
|
||||
#define DWC_CFGL_RELOAD_DAR (1 << 31)
|
||||
|
||||
/* Bitfields in CFG_HI */
|
||||
#define DWC_CFGH_FCMODE (1 << 0)
|
||||
#define DWC_CFGH_FIFO_MODE (1 << 1)
|
||||
#define DWC_CFGH_PROTCTL(x) ((x) << 2)
|
||||
#define DWC_CFGH_DS_UPD_EN (1 << 5)
|
||||
#define DWC_CFGH_SS_UPD_EN (1 << 6)
|
||||
#define DWC_CFGH_SRC_PER(x) ((x) << 7)
|
||||
#define DWC_CFGH_DST_PER(x) ((x) << 11)
|
||||
|
||||
/* Bitfields in SGR */
|
||||
#define DWC_SGR_SGI(x) ((x) << 0)
|
||||
#define DWC_SGR_SGC(x) ((x) << 20)
|
||||
|
||||
/* Bitfields in DSR */
|
||||
#define DWC_DSR_DSI(x) ((x) << 0)
|
||||
#define DWC_DSR_DSC(x) ((x) << 20)
|
||||
|
||||
/* Bitfields in CFG */
|
||||
#define DW_CFG_DMA_EN (1 << 0)
|
||||
|
||||
enum dw_dmac_flags {
|
||||
DW_DMA_IS_CYCLIC = 0,
|
||||
DW_DMA_IS_SOFT_LLP = 1,
|
||||
};
|
||||
|
||||
struct dw_dma_chan {
|
||||
struct dma_chan chan;
|
||||
void __iomem *ch_regs;
|
||||
u8 mask;
|
||||
u8 priority;
|
||||
enum dma_transfer_direction direction;
|
||||
bool paused;
|
||||
bool initialized;
|
||||
|
||||
/* software emulation of the LLP transfers */
|
||||
struct list_head *tx_node_active;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
/* these other elements are all protected by lock */
|
||||
unsigned long flags;
|
||||
struct list_head active_list;
|
||||
struct list_head queue;
|
||||
struct list_head free_list;
|
||||
u32 residue;
|
||||
struct dw_cyclic_desc *cdesc;
|
||||
|
||||
unsigned int descs_allocated;
|
||||
|
||||
/* hardware configuration */
|
||||
unsigned int block_size;
|
||||
bool nollp;
|
||||
|
||||
/* custom slave configuration */
|
||||
u8 src_id;
|
||||
u8 dst_id;
|
||||
u8 src_master;
|
||||
u8 dst_master;
|
||||
|
||||
/* configuration passed via DMA_SLAVE_CONFIG */
|
||||
struct dma_slave_config dma_sconfig;
|
||||
};
|
||||
|
||||
static inline struct dw_dma_chan_regs __iomem *
|
||||
__dwc_regs(struct dw_dma_chan *dwc)
|
||||
{
|
||||
return dwc->ch_regs;
|
||||
}
|
||||
|
||||
#define channel_readl(dwc, name) \
|
||||
dma_readl_native(&(__dwc_regs(dwc)->name))
|
||||
#define channel_writel(dwc, name, val) \
|
||||
dma_writel_native((val), &(__dwc_regs(dwc)->name))
|
||||
|
||||
static inline struct dw_dma_chan *to_dw_dma_chan(struct dma_chan *chan)
|
||||
{
|
||||
return container_of(chan, struct dw_dma_chan, chan);
|
||||
}
|
||||
|
||||
struct dw_dma {
|
||||
struct dma_device dma;
|
||||
void __iomem *regs;
|
||||
struct dma_pool *desc_pool;
|
||||
struct tasklet_struct tasklet;
|
||||
|
||||
/* channels */
|
||||
struct dw_dma_chan *chan;
|
||||
u8 all_chan_mask;
|
||||
u8 in_use;
|
||||
|
||||
/* hardware configuration */
|
||||
unsigned char nr_masters;
|
||||
unsigned char data_width[4];
|
||||
};
|
||||
|
||||
static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
|
||||
{
|
||||
return dw->regs;
|
||||
}
|
||||
|
||||
#define dma_readl(dw, name) \
|
||||
dma_readl_native(&(__dw_regs(dw)->name))
|
||||
#define dma_writel(dw, name, val) \
|
||||
dma_writel_native((val), &(__dw_regs(dw)->name))
|
||||
|
||||
#define channel_set_bit(dw, reg, mask) \
|
||||
dma_writel(dw, reg, ((mask) << 8) | (mask))
|
||||
#define channel_clear_bit(dw, reg, mask) \
|
||||
dma_writel(dw, reg, ((mask) << 8) | 0)
|
||||
|
||||
static inline struct dw_dma *to_dw_dma(struct dma_device *ddev)
|
||||
{
|
||||
return container_of(ddev, struct dw_dma, dma);
|
||||
}
|
||||
|
||||
/* LLI == Linked List Item; a.k.a. DMA block descriptor */
|
||||
struct dw_lli {
|
||||
/* values that are not changed by hardware */
|
||||
u32 sar;
|
||||
u32 dar;
|
||||
u32 llp; /* chain to next lli */
|
||||
u32 ctllo;
|
||||
/* values that may get written back: */
|
||||
u32 ctlhi;
|
||||
/* sstat and dstat can snapshot peripheral register state.
|
||||
* silicon config may discard either or both...
|
||||
*/
|
||||
u32 sstat;
|
||||
u32 dstat;
|
||||
};
|
||||
|
||||
struct dw_desc {
|
||||
/* FIRST values the hardware uses */
|
||||
struct dw_lli lli;
|
||||
|
||||
/* THEN values for driver housekeeping */
|
||||
struct list_head desc_node;
|
||||
struct list_head tx_list;
|
||||
struct dma_async_tx_descriptor txd;
|
||||
size_t len;
|
||||
size_t total_len;
|
||||
};
|
||||
|
||||
#define to_dw_desc(h) list_entry(h, struct dw_desc, desc_node)
|
||||
|
||||
static inline struct dw_desc *
|
||||
txd_to_dw_desc(struct dma_async_tx_descriptor *txd)
|
||||
{
|
||||
return container_of(txd, struct dw_desc, txd);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue