aboutsummaryrefslogtreecommitdiff
path: root/drivers/amba
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/amba')
-rw-r--r--drivers/amba/Makefile4
-rw-r--r--drivers/amba/bus.c309
-rw-r--r--drivers/amba/tegra-ahb.c289
3 files changed, 529 insertions, 73 deletions
diff --git a/drivers/amba/Makefile b/drivers/amba/Makefile
index 40fe74097be..66e81c2f1e3 100644
--- a/drivers/amba/Makefile
+++ b/drivers/amba/Makefile
@@ -1,2 +1,2 @@
-obj-y += bus.o
-
+obj-$(CONFIG_ARM_AMBA) += bus.o
+obj-$(CONFIG_TEGRA_AHB) += tegra-ahb.o
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 2737b975220..3cf61a127ee 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -13,16 +13,17 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/amba/bus.h>
+#include <linux/sizes.h>
#include <asm/irq.h>
-#include <asm/sizes.h>
-#define to_amba_device(d) container_of(d, struct amba_device, dev)
#define to_amba_driver(d) container_of(d, struct amba_driver, drv)
-static struct amba_id *
-amba_lookup(struct amba_id *table, struct amba_device *dev)
+static const struct amba_id *
+amba_lookup(const struct amba_id *table, struct amba_device *dev)
{
int ret = 0;
@@ -44,37 +45,17 @@ static int amba_match(struct device *dev, struct device_driver *drv)
return amba_lookup(pcdrv->id_table, pcdev) != NULL;
}
-#ifdef CONFIG_HOTPLUG
static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct amba_device *pcdev = to_amba_device(dev);
int retval = 0;
retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
- return retval;
-}
-#else
-#define amba_uevent NULL
-#endif
-
-static int amba_suspend(struct device *dev, pm_message_t state)
-{
- struct amba_driver *drv = to_amba_driver(dev->driver);
- int ret = 0;
-
- if (dev->driver && drv->suspend)
- ret = drv->suspend(to_amba_device(dev), state);
- return ret;
-}
-
-static int amba_resume(struct device *dev)
-{
- struct amba_driver *drv = to_amba_driver(dev->driver);
- int ret = 0;
+ if (retval)
+ return retval;
- if (dev->driver && drv->resume)
- ret = drv->resume(to_amba_device(dev));
- return ret;
+ retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid);
+ return retval;
}
#define amba_attr_func(name,fmt,arg...) \
@@ -102,17 +83,63 @@ static struct device_attribute amba_dev_attrs[] = {
__ATTR_NULL,
};
+#ifdef CONFIG_PM
+/*
+ * Hooks to provide runtime PM of the pclk (bus clock). It is safe to
+ * enable/disable the bus clock at runtime PM suspend/resume as this
+ * does not result in loss of context.
+ */
+static int amba_pm_runtime_suspend(struct device *dev)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+ int ret = pm_generic_runtime_suspend(dev);
+
+ if (ret == 0 && dev->driver)
+ clk_disable_unprepare(pcdev->pclk);
+
+ return ret;
+}
+
+static int amba_pm_runtime_resume(struct device *dev)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+ int ret;
+
+ if (dev->driver) {
+ ret = clk_prepare_enable(pcdev->pclk);
+ /* Failure is probably fatal to the system, but... */
+ if (ret)
+ return ret;
+ }
+
+ return pm_generic_runtime_resume(dev);
+}
+#endif
+
+static const struct dev_pm_ops amba_pm = {
+ .suspend = pm_generic_suspend,
+ .resume = pm_generic_resume,
+ .freeze = pm_generic_freeze,
+ .thaw = pm_generic_thaw,
+ .poweroff = pm_generic_poweroff,
+ .restore = pm_generic_restore,
+ SET_PM_RUNTIME_PM_OPS(
+ amba_pm_runtime_suspend,
+ amba_pm_runtime_resume,
+ NULL
+ )
+};
+
/*
* Primecells are part of the Advanced Microcontroller Bus Architecture,
* so we call the bus "amba".
*/
-static struct bus_type amba_bustype = {
+struct bus_type amba_bustype = {
.name = "amba",
.dev_attrs = amba_dev_attrs,
.match = amba_match,
.uevent = amba_uevent,
- .suspend = amba_suspend,
- .resume = amba_resume,
+ .pm = &amba_pm,
};
static int __init amba_init(void)
@@ -124,27 +151,23 @@ postcore_initcall(amba_init);
static int amba_get_enable_pclk(struct amba_device *pcdev)
{
- struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
int ret;
- pcdev->pclk = pclk;
+ pcdev->pclk = clk_get(&pcdev->dev, "apb_pclk");
+ if (IS_ERR(pcdev->pclk))
+ return PTR_ERR(pcdev->pclk);
- if (IS_ERR(pclk))
- return PTR_ERR(pclk);
-
- ret = clk_enable(pclk);
+ ret = clk_prepare_enable(pcdev->pclk);
if (ret)
- clk_put(pclk);
+ clk_put(pcdev->pclk);
return ret;
}
static void amba_put_disable_pclk(struct amba_device *pcdev)
{
- struct clk *pclk = pcdev->pclk;
-
- clk_disable(pclk);
- clk_put(pclk);
+ clk_disable_unprepare(pcdev->pclk);
+ clk_put(pcdev->pclk);
}
/*
@@ -155,7 +178,7 @@ static int amba_probe(struct device *dev)
{
struct amba_device *pcdev = to_amba_device(dev);
struct amba_driver *pcdrv = to_amba_driver(dev->driver);
- struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
+ const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
int ret;
do {
@@ -163,10 +186,18 @@ static int amba_probe(struct device *dev)
if (ret)
break;
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+
ret = pcdrv->probe(pcdev, id);
if (ret == 0)
break;
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
+
amba_put_disable_pclk(pcdev);
} while (0);
@@ -177,7 +208,16 @@ static int amba_remove(struct device *dev)
{
struct amba_device *pcdev = to_amba_device(dev);
struct amba_driver *drv = to_amba_driver(dev->driver);
- int ret = drv->remove(pcdev);
+ int ret;
+
+ pm_runtime_get_sync(dev);
+ ret = drv->remove(pcdev);
+ pm_runtime_put_noidle(dev);
+
+ /* Undo the runtime PM settings in amba_probe() */
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_put_noidle(dev);
amba_put_disable_pclk(pcdev);
@@ -234,42 +274,31 @@ static void amba_device_release(struct device *dev)
}
/**
- * amba_device_register - register an AMBA device
- * @dev: AMBA device to register
- * @parent: parent memory resource
+ * amba_device_add - add a previously allocated AMBA device structure
+ * @dev: AMBA device allocated by amba_device_alloc
+ * @parent: resource parent for this devices resources
*
- * Setup the AMBA device, reading the cell ID if present.
- * Claim the resource, and register the AMBA device with
- * the Linux device manager.
+ * Claim the resource, and read the device cell ID if not already
+ * initialized. Register the AMBA device with the Linux device
+ * manager.
*/
-int amba_device_register(struct amba_device *dev, struct resource *parent)
+int amba_device_add(struct amba_device *dev, struct resource *parent)
{
u32 size;
void __iomem *tmp;
int i, ret;
- device_initialize(&dev->dev);
-
- /*
- * Copy from device_add
- */
- if (dev->dev.init_name) {
- dev_set_name(&dev->dev, "%s", dev->dev.init_name);
- dev->dev.init_name = NULL;
- }
-
- dev->dev.release = amba_device_release;
- dev->dev.bus = &amba_bustype;
- dev->dev.dma_mask = &dev->dma_mask;
- dev->res.name = dev_name(&dev->dev);
-
- if (!dev->dev.coherent_dma_mask && dev->dma_mask)
- dev_warn(&dev->dev, "coherent dma mask is unset\n");
+ WARN_ON(dev->irq[0] == (unsigned int)-1);
+ WARN_ON(dev->irq[1] == (unsigned int)-1);
ret = request_resource(parent, &dev->res);
if (ret)
goto err_out;
+ /* Hard-coded primecell ID instead of plug-n-play */
+ if (dev->periphid != 0)
+ goto skip_probe;
+
/*
* Dynamically calculate the size of the resource
* and use this for iomap
@@ -310,13 +339,14 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
if (ret)
goto err_release;
+ skip_probe:
ret = device_add(&dev->dev);
if (ret)
goto err_release;
- if (dev->irq[0] != NO_IRQ)
+ if (dev->irq[0])
ret = device_create_file(&dev->dev, &dev_attr_irq0);
- if (ret == 0 && dev->irq[1] != NO_IRQ)
+ if (ret == 0 && dev->irq[1])
ret = device_create_file(&dev->dev, &dev_attr_irq1);
if (ret == 0)
return ret;
@@ -328,6 +358,143 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
err_out:
return ret;
}
+EXPORT_SYMBOL_GPL(amba_device_add);
+
+static struct amba_device *
+amba_aphb_device_add(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1, int irq2,
+ void *pdata, unsigned int periphid, u64 dma_mask,
+ struct resource *resbase)
+{
+ struct amba_device *dev;
+ int ret;
+
+ dev = amba_device_alloc(name, base, size);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ dev->dev.coherent_dma_mask = dma_mask;
+ dev->irq[0] = irq1;
+ dev->irq[1] = irq2;
+ dev->periphid = periphid;
+ dev->dev.platform_data = pdata;
+ dev->dev.parent = parent;
+
+ ret = amba_device_add(dev, resbase);
+ if (ret) {
+ amba_device_put(dev);
+ return ERR_PTR(ret);
+ }
+
+ return dev;
+}
+
+struct amba_device *
+amba_apb_device_add(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1, int irq2,
+ void *pdata, unsigned int periphid)
+{
+ return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
+ periphid, 0, &iomem_resource);
+}
+EXPORT_SYMBOL_GPL(amba_apb_device_add);
+
+struct amba_device *
+amba_ahb_device_add(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1, int irq2,
+ void *pdata, unsigned int periphid)
+{
+ return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
+ periphid, ~0ULL, &iomem_resource);
+}
+EXPORT_SYMBOL_GPL(amba_ahb_device_add);
+
+struct amba_device *
+amba_apb_device_add_res(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1,
+ int irq2, void *pdata, unsigned int periphid,
+ struct resource *resbase)
+{
+ return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
+ periphid, 0, resbase);
+}
+EXPORT_SYMBOL_GPL(amba_apb_device_add_res);
+
+struct amba_device *
+amba_ahb_device_add_res(struct device *parent, const char *name,
+ resource_size_t base, size_t size, int irq1,
+ int irq2, void *pdata, unsigned int periphid,
+ struct resource *resbase)
+{
+ return amba_aphb_device_add(parent, name, base, size, irq1, irq2, pdata,
+ periphid, ~0ULL, resbase);
+}
+EXPORT_SYMBOL_GPL(amba_ahb_device_add_res);
+
+
+static void amba_device_initialize(struct amba_device *dev, const char *name)
+{
+ device_initialize(&dev->dev);
+ if (name)
+ dev_set_name(&dev->dev, "%s", name);
+ dev->dev.release = amba_device_release;
+ dev->dev.bus = &amba_bustype;
+ dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
+ dev->res.name = dev_name(&dev->dev);
+}
+
+/**
+ * amba_device_alloc - allocate an AMBA device
+ * @name: sysfs name of the AMBA device
+ * @base: base of AMBA device
+ * @size: size of AMBA device
+ *
+ * Allocate and initialize an AMBA device structure. Returns %NULL
+ * on failure.
+ */
+struct amba_device *amba_device_alloc(const char *name, resource_size_t base,
+ size_t size)
+{
+ struct amba_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev) {
+ amba_device_initialize(dev, name);
+ dev->res.start = base;
+ dev->res.end = base + size - 1;
+ dev->res.flags = IORESOURCE_MEM;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(amba_device_alloc);
+
+/**
+ * amba_device_register - register an AMBA device
+ * @dev: AMBA device to register
+ * @parent: parent memory resource
+ *
+ * Setup the AMBA device, reading the cell ID if present.
+ * Claim the resource, and register the AMBA device with
+ * the Linux device manager.
+ */
+int amba_device_register(struct amba_device *dev, struct resource *parent)
+{
+ amba_device_initialize(dev, dev->dev.init_name);
+ dev->dev.init_name = NULL;
+
+ return amba_device_add(dev, parent);
+}
+
+/**
+ * amba_device_put - put an AMBA device
+ * @dev: AMBA device to put
+ */
+void amba_device_put(struct amba_device *dev)
+{
+ put_device(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(amba_device_put);
/**
* amba_device_unregister - unregister an AMBA device
@@ -427,7 +594,7 @@ int amba_request_regions(struct amba_device *dev, const char *name)
}
/**
- * amba_release_regions - release mem regions assoicated with device
+ * amba_release_regions - release mem regions associated with device
* @dev: amba_device structure for device
*
* Release regions claimed by a successful call to amba_request_regions.
diff --git a/drivers/amba/tegra-ahb.c b/drivers/amba/tegra-ahb.c
new file mode 100644
index 00000000000..558a239954e
--- /dev/null
+++ b/drivers/amba/tegra-ahb.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ * Jay Cheng <jacheng@nvidia.com>
+ * James Wylder <james.wylder@motorola.com>
+ * Benoit Goby <benoit@android.com>
+ * Colin Cross <ccross@android.com>
+ * Hiroshi DOYU <hdoyu@nvidia.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/tegra-ahb.h>
+
+#define DRV_NAME "tegra-ahb"
+
+#define AHB_ARBITRATION_DISABLE 0x00
+#define AHB_ARBITRATION_PRIORITY_CTRL 0x04
+#define AHB_PRIORITY_WEIGHT(x) (((x) & 0x7) << 29)
+#define PRIORITY_SELECT_USB BIT(6)
+#define PRIORITY_SELECT_USB2 BIT(18)
+#define PRIORITY_SELECT_USB3 BIT(17)
+
+#define AHB_GIZMO_AHB_MEM 0x0c
+#define ENB_FAST_REARBITRATE BIT(2)
+#define DONT_SPLIT_AHB_WR BIT(7)
+
+#define AHB_GIZMO_APB_DMA 0x10
+#define AHB_GIZMO_IDE 0x18
+#define AHB_GIZMO_USB 0x1c
+#define AHB_GIZMO_AHB_XBAR_BRIDGE 0x20
+#define AHB_GIZMO_CPU_AHB_BRIDGE 0x24
+#define AHB_GIZMO_COP_AHB_BRIDGE 0x28
+#define AHB_GIZMO_XBAR_APB_CTLR 0x2c
+#define AHB_GIZMO_VCP_AHB_BRIDGE 0x30
+#define AHB_GIZMO_NAND 0x3c
+#define AHB_GIZMO_SDMMC4 0x44
+#define AHB_GIZMO_XIO 0x48
+#define AHB_GIZMO_BSEV 0x60
+#define AHB_GIZMO_BSEA 0x70
+#define AHB_GIZMO_NOR 0x74
+#define AHB_GIZMO_USB2 0x78
+#define AHB_GIZMO_USB3 0x7c
+#define IMMEDIATE BIT(18)
+
+#define AHB_GIZMO_SDMMC1 0x80
+#define AHB_GIZMO_SDMMC2 0x84
+#define AHB_GIZMO_SDMMC3 0x88
+#define AHB_MEM_PREFETCH_CFG_X 0xd8
+#define AHB_ARBITRATION_XBAR_CTRL 0xdc
+#define AHB_MEM_PREFETCH_CFG3 0xe0
+#define AHB_MEM_PREFETCH_CFG4 0xe4
+#define AHB_MEM_PREFETCH_CFG1 0xec
+#define AHB_MEM_PREFETCH_CFG2 0xf0
+#define PREFETCH_ENB BIT(31)
+#define MST_ID(x) (((x) & 0x1f) << 26)
+#define AHBDMA_MST_ID MST_ID(5)
+#define USB_MST_ID MST_ID(6)
+#define USB2_MST_ID MST_ID(18)
+#define USB3_MST_ID MST_ID(17)
+#define ADDR_BNDRY(x) (((x) & 0xf) << 21)
+#define INACTIVITY_TIMEOUT(x) (((x) & 0xffff) << 0)
+
+#define AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID 0xf8
+
+#define AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE BIT(17)
+
+static struct platform_driver tegra_ahb_driver;
+
+static const u32 tegra_ahb_gizmo[] = {
+ AHB_ARBITRATION_DISABLE,
+ AHB_ARBITRATION_PRIORITY_CTRL,
+ AHB_GIZMO_AHB_MEM,
+ AHB_GIZMO_APB_DMA,
+ AHB_GIZMO_IDE,
+ AHB_GIZMO_USB,
+ AHB_GIZMO_AHB_XBAR_BRIDGE,
+ AHB_GIZMO_CPU_AHB_BRIDGE,
+ AHB_GIZMO_COP_AHB_BRIDGE,
+ AHB_GIZMO_XBAR_APB_CTLR,
+ AHB_GIZMO_VCP_AHB_BRIDGE,
+ AHB_GIZMO_NAND,
+ AHB_GIZMO_SDMMC4,
+ AHB_GIZMO_XIO,
+ AHB_GIZMO_BSEV,
+ AHB_GIZMO_BSEA,
+ AHB_GIZMO_NOR,
+ AHB_GIZMO_USB2,
+ AHB_GIZMO_USB3,
+ AHB_GIZMO_SDMMC1,
+ AHB_GIZMO_SDMMC2,
+ AHB_GIZMO_SDMMC3,
+ AHB_MEM_PREFETCH_CFG_X,
+ AHB_ARBITRATION_XBAR_CTRL,
+ AHB_MEM_PREFETCH_CFG3,
+ AHB_MEM_PREFETCH_CFG4,
+ AHB_MEM_PREFETCH_CFG1,
+ AHB_MEM_PREFETCH_CFG2,
+ AHB_ARBITRATION_AHB_MEM_WRQUE_MST_ID,
+};
+
+struct tegra_ahb {
+ void __iomem *regs;
+ struct device *dev;
+ u32 ctx[0];
+};
+
+static inline u32 gizmo_readl(struct tegra_ahb *ahb, u32 offset)
+{
+ return readl(ahb->regs + offset);
+}
+
+static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset)
+{
+ writel(value, ahb->regs + offset);
+}
+
+#ifdef CONFIG_TEGRA_IOMMU_SMMU
+static int tegra_ahb_match_by_smmu(struct device *dev, void *data)
+{
+ struct tegra_ahb *ahb = dev_get_drvdata(dev);
+ struct device_node *dn = data;
+
+ return (ahb->dev->of_node == dn) ? 1 : 0;
+}
+
+int tegra_ahb_enable_smmu(struct device_node *dn)
+{
+ struct device *dev;
+ u32 val;
+ struct tegra_ahb *ahb;
+
+ dev = driver_find_device(&tegra_ahb_driver.driver, NULL, dn,
+ tegra_ahb_match_by_smmu);
+ if (!dev)
+ return -EPROBE_DEFER;
+ ahb = dev_get_drvdata(dev);
+ val = gizmo_readl(ahb, AHB_ARBITRATION_XBAR_CTRL);
+ val |= AHB_ARBITRATION_XBAR_CTRL_SMMU_INIT_DONE;
+ gizmo_writel(ahb, val, AHB_ARBITRATION_XBAR_CTRL);
+ return 0;
+}
+EXPORT_SYMBOL(tegra_ahb_enable_smmu);
+#endif
+
+#ifdef CONFIG_PM
+static int tegra_ahb_suspend(struct device *dev)
+{
+ int i;
+ struct tegra_ahb *ahb = dev_get_drvdata(dev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++)
+ ahb->ctx[i] = gizmo_readl(ahb, tegra_ahb_gizmo[i]);
+ return 0;
+}
+
+static int tegra_ahb_resume(struct device *dev)
+{
+ int i;
+ struct tegra_ahb *ahb = dev_get_drvdata(dev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra_ahb_gizmo); i++)
+ gizmo_writel(ahb, ahb->ctx[i], tegra_ahb_gizmo[i]);
+ return 0;
+}
+#endif
+
+static UNIVERSAL_DEV_PM_OPS(tegra_ahb_pm,
+ tegra_ahb_suspend,
+ tegra_ahb_resume, NULL);
+
+static void tegra_ahb_gizmo_init(struct tegra_ahb *ahb)
+{
+ u32 val;
+
+ val = gizmo_readl(ahb, AHB_GIZMO_AHB_MEM);
+ val |= ENB_FAST_REARBITRATE | IMMEDIATE | DONT_SPLIT_AHB_WR;
+ gizmo_writel(ahb, val, AHB_GIZMO_AHB_MEM);
+
+ val = gizmo_readl(ahb, AHB_GIZMO_USB);
+ val |= IMMEDIATE;
+ gizmo_writel(ahb, val, AHB_GIZMO_USB);
+
+ val = gizmo_readl(ahb, AHB_GIZMO_USB2);
+ val |= IMMEDIATE;
+ gizmo_writel(ahb, val, AHB_GIZMO_USB2);
+
+ val = gizmo_readl(ahb, AHB_GIZMO_USB3);
+ val |= IMMEDIATE;
+ gizmo_writel(ahb, val, AHB_GIZMO_USB3);
+
+ val = gizmo_readl(ahb, AHB_ARBITRATION_PRIORITY_CTRL);
+ val |= PRIORITY_SELECT_USB |
+ PRIORITY_SELECT_USB2 |
+ PRIORITY_SELECT_USB3 |
+ AHB_PRIORITY_WEIGHT(7);
+ gizmo_writel(ahb, val, AHB_ARBITRATION_PRIORITY_CTRL);
+
+ val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG1);
+ val &= ~MST_ID(~0);
+ val |= PREFETCH_ENB |
+ AHBDMA_MST_ID |
+ ADDR_BNDRY(0xc) |
+ INACTIVITY_TIMEOUT(0x1000);
+ gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG1);
+
+ val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG2);
+ val &= ~MST_ID(~0);
+ val |= PREFETCH_ENB |
+ USB_MST_ID |
+ ADDR_BNDRY(0xc) |
+ INACTIVITY_TIMEOUT(0x1000);
+ gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG2);
+
+ val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG3);
+ val &= ~MST_ID(~0);
+ val |= PREFETCH_ENB |
+ USB3_MST_ID |
+ ADDR_BNDRY(0xc) |
+ INACTIVITY_TIMEOUT(0x1000);
+ gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG3);
+
+ val = gizmo_readl(ahb, AHB_MEM_PREFETCH_CFG4);
+ val &= ~MST_ID(~0);
+ val |= PREFETCH_ENB |
+ USB2_MST_ID |
+ ADDR_BNDRY(0xc) |
+ INACTIVITY_TIMEOUT(0x1000);
+ gizmo_writel(ahb, val, AHB_MEM_PREFETCH_CFG4);
+}
+
+static int tegra_ahb_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct tegra_ahb *ahb;
+ size_t bytes;
+
+ bytes = sizeof(*ahb) + sizeof(u32) * ARRAY_SIZE(tegra_ahb_gizmo);
+ ahb = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);
+ if (!ahb)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ahb->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ahb->regs))
+ return PTR_ERR(ahb->regs);
+
+ ahb->dev = &pdev->dev;
+ platform_set_drvdata(pdev, ahb);
+ tegra_ahb_gizmo_init(ahb);
+ return 0;
+}
+
+static const struct of_device_id tegra_ahb_of_match[] = {
+ { .compatible = "nvidia,tegra30-ahb", },
+ { .compatible = "nvidia,tegra20-ahb", },
+ {},
+};
+
+static struct platform_driver tegra_ahb_driver = {
+ .probe = tegra_ahb_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra_ahb_of_match,
+ .pm = &tegra_ahb_pm,
+ },
+};
+module_platform_driver(tegra_ahb_driver);
+
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_DESCRIPTION("Tegra AHB driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);