mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 21:07:02 +09:00
[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 <vwadekar@nvidia.com>
This commit is contained in:
committed by
Colin Cross
parent
1ff693aee0
commit
e8903adee3
@@ -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)
|
||||
|
||||
@@ -19,7 +19,13 @@
|
||||
|
||||
#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"
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user