Commit 3f394f80 authored by Peter De Schrijver's avatar Peter De Schrijver Committed by Thierry Reding

ARM: tegra: export apb dma readl/writel

Export APB DMA readl and writel. These are needed because we can't
access the fuses directly on Tegra20 without potentially causing a
system hang. Also have the APB DMA readl and writel return an error in
case of a read failure instead of just returning zero or ignore write
failures.
Signed-off-by: default avatarPeter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 304664ea
...@@ -32,8 +32,8 @@ static u32 *tegra_apb_bb; ...@@ -32,8 +32,8 @@ static u32 *tegra_apb_bb;
static dma_addr_t tegra_apb_bb_phys; static dma_addr_t tegra_apb_bb_phys;
static DECLARE_COMPLETION(tegra_apb_wait); static DECLARE_COMPLETION(tegra_apb_wait);
static u32 tegra_apb_readl_direct(unsigned long offset); static int tegra_apb_readl_direct(unsigned long offset, u32 *value);
static void tegra_apb_writel_direct(u32 value, unsigned long offset); static int tegra_apb_writel_direct(u32 value, unsigned long offset);
static struct dma_chan *tegra_apb_dma_chan; static struct dma_chan *tegra_apb_dma_chan;
static struct dma_slave_config dma_sconfig; static struct dma_slave_config dma_sconfig;
...@@ -128,58 +128,64 @@ static int do_dma_transfer(unsigned long apb_add, ...@@ -128,58 +128,64 @@ static int do_dma_transfer(unsigned long apb_add,
return 0; return 0;
} }
static u32 tegra_apb_readl_using_dma(unsigned long offset) int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
{ {
int ret; int ret;
if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
return tegra_apb_readl_direct(offset); return tegra_apb_readl_direct(offset, value);
mutex_lock(&tegra_apb_dma_lock); mutex_lock(&tegra_apb_dma_lock);
ret = do_dma_transfer(offset, DMA_DEV_TO_MEM); ret = do_dma_transfer(offset, DMA_DEV_TO_MEM);
if (ret < 0) { if (ret < 0)
pr_err("error in reading offset 0x%08lx using dma\n", offset); pr_err("error in reading offset 0x%08lx using dma\n", offset);
*(u32 *)tegra_apb_bb = 0; else
} *value = *tegra_apb_bb;
mutex_unlock(&tegra_apb_dma_lock); mutex_unlock(&tegra_apb_dma_lock);
return *((u32 *)tegra_apb_bb);
return ret;
} }
static void tegra_apb_writel_using_dma(u32 value, unsigned long offset) int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
{ {
int ret; int ret;
if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) { if (!tegra_apb_dma_chan && !tegra_apb_dma_init())
tegra_apb_writel_direct(value, offset); return tegra_apb_writel_direct(value, offset);
return;
}
mutex_lock(&tegra_apb_dma_lock); mutex_lock(&tegra_apb_dma_lock);
*((u32 *)tegra_apb_bb) = value; *((u32 *)tegra_apb_bb) = value;
ret = do_dma_transfer(offset, DMA_MEM_TO_DEV); ret = do_dma_transfer(offset, DMA_MEM_TO_DEV);
mutex_unlock(&tegra_apb_dma_lock);
if (ret < 0) if (ret < 0)
pr_err("error in writing offset 0x%08lx using dma\n", offset); pr_err("error in writing offset 0x%08lx using dma\n", offset);
mutex_unlock(&tegra_apb_dma_lock);
return ret;
} }
#else #else
#define tegra_apb_readl_using_dma tegra_apb_readl_direct #define tegra_apb_readl_using_dma tegra_apb_readl_direct
#define tegra_apb_writel_using_dma tegra_apb_writel_direct #define tegra_apb_writel_using_dma tegra_apb_writel_direct
#endif #endif
typedef u32 (*apbio_read_fptr)(unsigned long offset); typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value);
typedef void (*apbio_write_fptr)(u32 value, unsigned long offset); typedef int (*apbio_write_fptr)(u32 value, unsigned long offset);
static apbio_read_fptr apbio_read; static apbio_read_fptr apbio_read;
static apbio_write_fptr apbio_write; static apbio_write_fptr apbio_write;
static u32 tegra_apb_readl_direct(unsigned long offset) static int tegra_apb_readl_direct(unsigned long offset, u32 *value)
{ {
return readl(IO_ADDRESS(offset)); *value = readl(IO_ADDRESS(offset));
return 0;
} }
static void tegra_apb_writel_direct(u32 value, unsigned long offset) static int tegra_apb_writel_direct(u32 value, unsigned long offset)
{ {
writel(value, IO_ADDRESS(offset)); writel(value, IO_ADDRESS(offset));
return 0;
} }
void tegra_apb_io_init(void) void tegra_apb_io_init(void)
...@@ -197,7 +203,12 @@ void tegra_apb_io_init(void) ...@@ -197,7 +203,12 @@ void tegra_apb_io_init(void)
u32 tegra_apb_readl(unsigned long offset) u32 tegra_apb_readl(unsigned long offset)
{ {
return apbio_read(offset); u32 val;
if (apbio_read(offset, &val) < 0)
return 0;
else
return val;
} }
void tegra_apb_writel(u32 value, unsigned long offset) void tegra_apb_writel(u32 value, unsigned long offset)
......
...@@ -27,6 +27,20 @@ ...@@ -27,6 +27,20 @@
u32 tegra_read_chipid(void); u32 tegra_read_chipid(void);
u8 tegra_get_chip_id(void); u8 tegra_get_chip_id(void);
#if defined(CONFIG_TEGRA20_APB_DMA)
int tegra_apb_readl_using_dma(unsigned long offset, u32 *value);
int tegra_apb_writel_using_dma(u32 value, unsigned long offset);
#else
static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value)
{
return -EINVAL;
}
static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset)
{
return -EINVAL;
}
#endif /* CONFIG_TEGRA20_APB_DMA */
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* __SOC_TEGRA_FUSE_H__ */ #endif /* __SOC_TEGRA_FUSE_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment