From e8903adee3e814b72170d183b3b16653e48612a8 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Sun, 24 Oct 2010 16:25:32 +0530 Subject: [PATCH] [ARM] tegra: use dma to read/write fuse registers tegra2 hangs if fuse registers are accessed during an apb dma operation. war is to use apb dma to read/write fuse registers instead. Change-Id: I4d99a1ad56115c0d73e9cd0679cf38f70f922f3d Signed-off-by: Varun Wadekar --- arch/arm/mach-tegra/common.c | 7 ++- arch/arm/mach-tegra/fuse.c | 99 ++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 12ce86b7ab9c..f98189c89d04 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -134,15 +134,14 @@ static void tegra_pm_restart(char mode, const char *cmd) void __init tegra_common_init(void) { arm_pm_restart = tegra_pm_restart; - +#ifdef CONFIG_TEGRA_SYSTEM_DMA + tegra_dma_init(); +#endif tegra_init_fuse(); tegra_init_clock(); tegra_clk_init_from_table(common_clk_init_table); tegra_init_power(); tegra_init_cache(); -#ifdef CONFIG_TEGRA_SYSTEM_DMA - tegra_dma_init(); -#endif } static int __init tegra_bootloader_fb_arg(char *options) diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 1fa26d9a1a68..3c0d89c934d4 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -19,7 +19,13 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include "fuse.h" @@ -29,6 +35,79 @@ #define FUSE_SKU_INFO 0x110 #define FUSE_SPARE_BIT 0x200 +DEFINE_MUTEX(lock); + +#ifdef CONFIG_TEGRA_SYSTEM_DMA +struct tegra_dma_channel *dma; +u32 *fuse_bb; +dma_addr_t fuse_bb_phys; +struct completion rd_wait; +struct completion wr_wait; + +static void fuse_dma_complete(struct tegra_dma_req *req) +{ + if (req) + req->to_memory ? complete(&rd_wait) : complete(&wr_wait); +} + +static inline u32 fuse_readl(unsigned long offset) +{ + struct tegra_dma_req req; + + if (!dma) + return -EINVAL; + + mutex_lock(&lock); + req.complete = fuse_dma_complete; + req.to_memory = 1; + req.dest_addr = 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(&rd_wait); + tegra_dma_enqueue_req(dma, &req); + if (wait_for_completion_timeout(&rd_wait, msecs_to_jiffies(50)) == 0) { + WARN_ON(1); + mutex_unlock(&lock); + return 0; + } + + mutex_unlock(&lock); + return *((u32 *)fuse_bb); +} + +static inline void fuse_writel(u32 value, unsigned long offset) +{ + struct tegra_dma_req req; + + if (!dma || !fuse_bb) + return; + + mutex_lock(&lock); + *((u32 *)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 = fuse_bb_phys; + req.source_bus_width = 32; + req.source_wrap = 1; + req.req_sel = 0; + req.size = 4; + + init_completion(&wr_wait); + tegra_dma_enqueue_req(dma, &req); + if (wait_for_completion_timeout(&wr_wait, msecs_to_jiffies(50)) == 0) + WARN_ON(1); + mutex_unlock(&lock); +} +#else static inline u32 fuse_readl(unsigned long offset) { return readl(IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); @@ -38,6 +117,7 @@ static inline void fuse_writel(u32 value, unsigned long offset) { writel(value, IO_TO_VIRT(TEGRA_FUSE_BASE + offset)); } +#endif void tegra_init_fuse(void) { @@ -45,6 +125,25 @@ void tegra_init_fuse(void) reg |= 1 << 28; writel(reg, IO_TO_VIRT(TEGRA_CLK_RESET_BASE + 0x48)); +#ifdef CONFIG_TEGRA_SYSTEM_DMA + dma = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT | + TEGRA_DMA_SHARED); + if (!dma) { + pr_err("%s: can not allocate dma channel\n", __func__); + return; + } + + fuse_bb = dma_alloc_coherent(NULL, sizeof(u32), + &fuse_bb_phys, GFP_KERNEL); + if (!fuse_bb) { + pr_err("%s: can not allocate bounce buffer\n", __func__); + tegra_dma_free_channel(dma); + dma = NULL; + return; + } + mutex_init(&lock); +#endif + pr_info("Tegra SKU: %d CPU Process: %d Core Process: %d\n", tegra_sku_id(), tegra_cpu_process_id(), tegra_core_process_id()); -- 2.34.1