[ARM] tegra: use APB DMA for accessing APB devices
Jon Mayo [Tue, 21 Dec 2010 23:09:33 +0000 (15:09 -0800)]
Change-Id: I165411a14342666cbac02fb8cb171580ab0826aa
Reviewed-on: http://git-master/r/14464
Reviewed-by: Jon Mayo <jmayo@nvidia.com>
Tested-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Signed-off-by: Jon Mayo <jmayo@nvidia.com>

arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/apbio.c [new file with mode: 0644]
arch/arm/mach-tegra/apbio.h [new file with mode: 0644]
arch/arm/mach-tegra/common.c
arch/arm/mach-tegra/fuse.c
arch/arm/mach-tegra/fuse.h

index 3864d2d..156ddae 100644 (file)
@@ -1,5 +1,6 @@
 obj-y                                   += common.o
 obj-y                                   += devices.o
+obj-y                                   += apbio.o
 obj-y                                   += io.o
 obj-y                                   += irq.o
 obj-y                                   += clock.o
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c
new file mode 100644 (file)
index 0000000..d6e08c9
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * arch/arm/mach-tegra/apbio.c
+ *
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+
+#include <mach/dma.h>
+#include <mach/iomap.h>
+
+#include "apbio.h"
+
+static DEFINE_MUTEX(tegra_apb_dma_lock);
+
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+static struct tegra_dma_channel *tegra_apb_dma;
+static u32 *tegra_apb_bb;
+static dma_addr_t tegra_apb_bb_phys;
+static DECLARE_COMPLETION(tegra_apb_wait);
+
+static void apb_dma_complete(struct tegra_dma_req *req)
+{
+       complete(&tegra_apb_wait);
+}
+
+static inline u32 apb_readl(unsigned long offset)
+{
+       struct tegra_dma_req req;
+       int ret;
+
+       if (!tegra_apb_dma)
+               return readl(IO_TO_VIRT(offset));
+
+       mutex_lock(&tegra_apb_dma_lock);
+       req.complete = apb_dma_complete;
+       req.to_memory = 1;
+       req.dest_addr = tegra_apb_bb_phys;
+       req.dest_bus_width = 32;
+       req.dest_wrap = 1;
+       req.source_addr = offset;
+       req.source_bus_width = 32;
+       req.source_wrap = 4;
+       req.req_sel = 0;
+       req.size = 4;
+
+       INIT_COMPLETION(tegra_apb_wait);
+
+       tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+       ret = wait_for_completion_timeout(&tegra_apb_wait,
+               msecs_to_jiffies(50));
+
+       if (WARN(ret == 0, "apb read dma timed out"))
+               *(u32 *)tegra_apb_bb = 0;
+
+       mutex_unlock(&tegra_apb_dma_lock);
+       return *((u32 *)tegra_apb_bb);
+}
+
+static inline void apb_writel(u32 value, unsigned long offset)
+{
+       struct tegra_dma_req req;
+       int ret;
+
+       if (!tegra_apb_dma) {
+               writel(value, IO_TO_VIRT(offset));
+               return;
+       }
+
+       mutex_lock(&tegra_apb_dma_lock);
+       *((u32 *)tegra_apb_bb) = value;
+       req.complete = apb_dma_complete;
+       req.to_memory = 0;
+       req.dest_addr = offset;
+       req.dest_wrap = 4;
+       req.dest_bus_width = 32;
+       req.source_addr = tegra_apb_bb_phys;
+       req.source_bus_width = 32;
+       req.source_wrap = 1;
+       req.req_sel = 0;
+       req.size = 4;
+
+       INIT_COMPLETION(tegra_apb_wait);
+
+       tegra_dma_enqueue_req(tegra_apb_dma, &req);
+
+       ret = wait_for_completion_timeout(&tegra_apb_wait,
+               msecs_to_jiffies(50));
+
+       mutex_unlock(&tegra_apb_dma_lock);
+}
+#else
+static inline u32 apb_readl(unsigned long offset)
+{
+       return readl(IO_TO_VIRT(offset));
+}
+
+static inline void apb_writel(u32 value, unsigned long offset)
+{
+       writel(value, IO_TO_VIRT(offset));
+}
+#endif
+
+u32 tegra_apb_readl(unsigned long offset)
+{
+       return apb_readl(offset);
+}
+
+void tegra_apb_writel(u32 value, unsigned long offset)
+{
+       apb_writel(value, offset);
+}
+
+void tegra_init_apb_dma(void)
+{
+#ifdef CONFIG_TEGRA_SYSTEM_DMA
+       tegra_apb_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
+               TEGRA_DMA_SHARED);
+       if (!tegra_apb_dma) {
+               pr_err("%s: can not allocate dma channel\n", __func__);
+               return;
+       }
+
+       tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32),
+               &tegra_apb_bb_phys, GFP_KERNEL);
+       if (!tegra_apb_bb) {
+               pr_err("%s: can not allocate bounce buffer\n", __func__);
+               tegra_dma_free_channel(tegra_apb_dma);
+               tegra_apb_dma = NULL;
+               return;
+       }
+#endif
+}
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h
new file mode 100644 (file)
index 0000000..a8b8250
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * arch/arm/mach-tegra/apbio.h
+ *
+ * Copyright (C) 2010 NVIDIA Corporation.
+ * Copyright (C) 2010 Google, Inc.
+ *
+ * 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.
+ *
+ */
+
+u32 tegra_apb_readl(unsigned long offset);
+void tegra_apb_writel(u32 value, unsigned long offset);
+void tegra_init_apb_dma(void);
index dc5ac9d..13a626c 100644 (file)
@@ -34,6 +34,7 @@
 #include <mach/powergate.h>
 #include <mach/system.h>
 
+#include "apbio.h"
 #include "board.h"
 #include "clock.h"
 #include "fuse.h"
@@ -151,7 +152,7 @@ void __init tegra_init_early(void)
        tegra_init_power();
        tegra_init_cache();
        tegra_dma_init();
-       tegra_init_fuse_dma();
+       tegra_init_apb_dma();
 }
 
 static int __init tegra_lp0_vec_arg(char *options)
index fcb6d05..869860c 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/spinlock.h>
-#include <linux/completion.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
 
-#include <mach/dma.h>
 #include <mach/iomap.h>
 
 #include "fuse.h"
+#include "apbio.h"
 
 #define FUSE_UID_LOW           0x108
 #define FUSE_UID_HIGH          0x10c
 #define FUSE_SKU_INFO          0x110
 #define FUSE_SPARE_BIT         0x200
 
-static DEFINE_MUTEX(tegra_fuse_dma_lock);
-
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
-static struct tegra_dma_channel *tegra_fuse_dma;
-static u32 *tegra_fuse_bb;
-static dma_addr_t tegra_fuse_bb_phys;
-static DECLARE_COMPLETION(tegra_fuse_wait);
-
 static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
        [TEGRA_REVISION_UNKNOWN] = "unknown",
        [TEGRA_REVISION_A02] = "A02",
@@ -50,102 +37,19 @@ static const char *tegra_revision_name[TEGRA_REVISION_MAX] = {
        [TEGRA_REVISION_A03p] = "A03 prime",
 };
 
-static void fuse_dma_complete(struct tegra_dma_req *req)
-{
-       complete(&tegra_fuse_wait);
-}
-
-static inline u32 fuse_readl(unsigned long offset)
-{
-       struct tegra_dma_req req;
-       int ret;
-
-       if (!tegra_fuse_dma)
-               return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
-
-       mutex_lock(&tegra_fuse_dma_lock);
-       req.complete = fuse_dma_complete;
-       req.to_memory = 1;
-       req.dest_addr = tegra_fuse_bb_phys;
-       req.dest_bus_width = 32;
-       req.dest_wrap = 1;
-       req.source_addr = TEGRA_FUSE_BASE + offset;
-       req.source_bus_width = 32;
-       req.source_wrap = 4;
-       req.req_sel = 0;
-       req.size = 4;
-
-       INIT_COMPLETION(tegra_fuse_wait);
-
-       tegra_dma_enqueue_req(tegra_fuse_dma, &req);
-
-       ret = wait_for_completion_timeout(&tegra_fuse_wait,
-               msecs_to_jiffies(50));
-
-       if (WARN(ret == 0, "fuse read dma timed out"))
-               *(u32 *)tegra_fuse_bb = 0;
-
-       mutex_unlock(&tegra_fuse_dma_lock);
-       return *((u32 *)tegra_fuse_bb);
-}
-
-static inline void fuse_writel(u32 value, unsigned long offset)
-{
-       struct tegra_dma_req req;
-       int ret;
-
-       if (!tegra_fuse_dma) {
-               writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
-               return;
-       }
-
-       mutex_lock(&tegra_fuse_dma_lock);
-       *((u32 *)tegra_fuse_bb) = value;
-       req.complete = fuse_dma_complete;
-       req.to_memory = 0;
-       req.dest_addr = TEGRA_FUSE_BASE + offset;
-       req.dest_wrap = 4;
-       req.dest_bus_width = 32;
-       req.source_addr = tegra_fuse_bb_phys;
-       req.source_bus_width = 32;
-       req.source_wrap = 1;
-       req.req_sel = 0;
-       req.size = 4;
-
-       INIT_COMPLETION(tegra_fuse_wait);
-
-       tegra_dma_enqueue_req(tegra_fuse_dma, &req);
-
-       ret = wait_for_completion_timeout(&tegra_fuse_wait,
-               msecs_to_jiffies(50));
-
-       mutex_unlock(&tegra_fuse_dma_lock);
-}
-#else
-static inline u32 fuse_readl(unsigned long offset)
-{
-       return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
-}
-
-static inline void fuse_writel(u32 value, unsigned long offset)
-{
-       writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset));
-}
-#endif
-
 u32 tegra_fuse_readl(unsigned long offset)
 {
-       return fuse_readl(offset);
+       return tegra_apb_readl(TEGRA_FUSE_BASE + offset);
 }
 
 void tegra_fuse_writel(u32 value, unsigned long offset)
 {
-       fuse_writel(value, offset);
+       tegra_apb_writel(value, TEGRA_FUSE_BASE + offset);
 }
 
 static inline bool get_spare_fuse(int bit)
 {
-       return fuse_readl(FUSE_SPARE_BIT + bit * 4);
+       return tegra_apb_readl(FUSE_SPARE_BIT + bit * 4);
 }
 
 void tegra_init_fuse(void)
@@ -160,40 +64,19 @@ void tegra_init_fuse(void)
                tegra_core_process_id());
 }
 
-void tegra_init_fuse_dma(void)
-{
-#ifdef CONFIG_TEGRA_SYSTEM_DMA
-       tegra_fuse_dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT |
-               TEGRA_DMA_SHARED);
-       if (!tegra_fuse_dma) {
-               pr_err("%s: can not allocate dma channel\n", __func__);
-               return;
-       }
-
-       tegra_fuse_bb = dma_alloc_coherent(NULL, sizeof(u32),
-               &tegra_fuse_bb_phys, GFP_KERNEL);
-       if (!tegra_fuse_bb) {
-               pr_err("%s: can not allocate bounce buffer\n", __func__);
-               tegra_dma_free_channel(tegra_fuse_dma);
-               tegra_fuse_dma = NULL;
-               return;
-       }
-#endif
-}
-
 unsigned long long tegra_chip_uid(void)
 {
        unsigned long long lo, hi;
 
-       lo = fuse_readl(FUSE_UID_LOW);
-       hi = fuse_readl(FUSE_UID_HIGH);
+       lo = tegra_fuse_readl(FUSE_UID_LOW);
+       hi = tegra_fuse_readl(FUSE_UID_HIGH);
        return (hi << 32ull) | lo;
 }
 
 int tegra_sku_id(void)
 {
        int sku_id;
-       u32 reg = fuse_readl(FUSE_SKU_INFO);
+       u32 reg = tegra_fuse_readl(FUSE_SKU_INFO);
        sku_id = reg & 0xFF;
        return sku_id;
 }
@@ -201,7 +84,7 @@ int tegra_sku_id(void)
 int tegra_cpu_process_id(void)
 {
        int cpu_process_id;
-       u32 reg = fuse_readl(FUSE_SPARE_BIT);
+       u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
        cpu_process_id = (reg >> 6) & 3;
        return cpu_process_id;
 }
@@ -209,7 +92,7 @@ int tegra_cpu_process_id(void)
 int tegra_core_process_id(void)
 {
        int core_process_id;
-       u32 reg = fuse_readl(FUSE_SPARE_BIT);
+       u32 reg = tegra_fuse_readl(FUSE_SPARE_BIT);
        core_process_id = (reg >> 12) & 3;
        return core_process_id;
 }
index 8a90426..e48838e 100644 (file)
@@ -30,7 +30,6 @@ int tegra_sku_id(void);
 int tegra_cpu_process_id(void);
 int tegra_core_process_id(void);
 void tegra_init_fuse(void);
-void tegra_init_fuse_dma(void);
 u32 tegra_fuse_readl(unsigned long offset);
 void tegra_fuse_writel(u32 value, unsigned long offset);
 enum tegra_revision tegra_get_revision(void);