diff options
author | Peter De Schrijver <pdeschrijver@nvidia.com> | 2014-06-12 11:36:35 -0400 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2014-07-17 07:36:44 -0400 |
commit | 3f394f80645bf0c38a30042ba605c71663331035 (patch) | |
tree | 6acabf07689afc6b71bb0409d100ffb732fcb236 | |
parent | 304664eab93f9e95a8d28fbd9702ede88bb10cc5 (diff) |
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: Peter De Schrijver <pdeschrijver@nvidia.com>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/apbio.c | 51 | ||||
-rw-r--r-- | include/soc/tegra/fuse.h | 14 |
2 files changed, 45 insertions, 20 deletions
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c index 5f9647b3f81d..f2488722c79c 100644 --- a/arch/arm/mach-tegra/apbio.c +++ b/arch/arm/mach-tegra/apbio.c | |||
@@ -32,8 +32,8 @@ static u32 *tegra_apb_bb; | |||
32 | static dma_addr_t tegra_apb_bb_phys; | 32 | static dma_addr_t tegra_apb_bb_phys; |
33 | static DECLARE_COMPLETION(tegra_apb_wait); | 33 | static DECLARE_COMPLETION(tegra_apb_wait); |
34 | 34 | ||
35 | static u32 tegra_apb_readl_direct(unsigned long offset); | 35 | static int tegra_apb_readl_direct(unsigned long offset, u32 *value); |
36 | static void tegra_apb_writel_direct(u32 value, unsigned long offset); | 36 | static int tegra_apb_writel_direct(u32 value, unsigned long offset); |
37 | 37 | ||
38 | static struct dma_chan *tegra_apb_dma_chan; | 38 | static struct dma_chan *tegra_apb_dma_chan; |
39 | static struct dma_slave_config dma_sconfig; | 39 | static struct dma_slave_config dma_sconfig; |
@@ -128,58 +128,64 @@ static int do_dma_transfer(unsigned long apb_add, | |||
128 | return 0; | 128 | return 0; |
129 | } | 129 | } |
130 | 130 | ||
131 | static u32 tegra_apb_readl_using_dma(unsigned long offset) | 131 | int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) |
132 | { | 132 | { |
133 | int ret; | 133 | int ret; |
134 | 134 | ||
135 | if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) | 135 | if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) |
136 | return tegra_apb_readl_direct(offset); | 136 | return tegra_apb_readl_direct(offset, value); |
137 | 137 | ||
138 | mutex_lock(&tegra_apb_dma_lock); | 138 | mutex_lock(&tegra_apb_dma_lock); |
139 | ret = do_dma_transfer(offset, DMA_DEV_TO_MEM); | 139 | ret = do_dma_transfer(offset, DMA_DEV_TO_MEM); |
140 | if (ret < 0) { | 140 | if (ret < 0) |
141 | pr_err("error in reading offset 0x%08lx using dma\n", offset); | 141 | pr_err("error in reading offset 0x%08lx using dma\n", offset); |
142 | *(u32 *)tegra_apb_bb = 0; | 142 | else |
143 | } | 143 | *value = *tegra_apb_bb; |
144 | |||
144 | mutex_unlock(&tegra_apb_dma_lock); | 145 | mutex_unlock(&tegra_apb_dma_lock); |
145 | return *((u32 *)tegra_apb_bb); | 146 | |
147 | return ret; | ||
146 | } | 148 | } |
147 | 149 | ||
148 | static void tegra_apb_writel_using_dma(u32 value, unsigned long offset) | 150 | int tegra_apb_writel_using_dma(u32 value, unsigned long offset) |
149 | { | 151 | { |
150 | int ret; | 152 | int ret; |
151 | 153 | ||
152 | if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) { | 154 | if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) |
153 | tegra_apb_writel_direct(value, offset); | 155 | return tegra_apb_writel_direct(value, offset); |
154 | return; | ||
155 | } | ||
156 | 156 | ||
157 | mutex_lock(&tegra_apb_dma_lock); | 157 | mutex_lock(&tegra_apb_dma_lock); |
158 | *((u32 *)tegra_apb_bb) = value; | 158 | *((u32 *)tegra_apb_bb) = value; |
159 | ret = do_dma_transfer(offset, DMA_MEM_TO_DEV); | 159 | ret = do_dma_transfer(offset, DMA_MEM_TO_DEV); |
160 | mutex_unlock(&tegra_apb_dma_lock); | ||
160 | if (ret < 0) | 161 | if (ret < 0) |
161 | pr_err("error in writing offset 0x%08lx using dma\n", offset); | 162 | pr_err("error in writing offset 0x%08lx using dma\n", offset); |
162 | mutex_unlock(&tegra_apb_dma_lock); | 163 | |
164 | return ret; | ||
163 | } | 165 | } |
164 | #else | 166 | #else |
165 | #define tegra_apb_readl_using_dma tegra_apb_readl_direct | 167 | #define tegra_apb_readl_using_dma tegra_apb_readl_direct |
166 | #define tegra_apb_writel_using_dma tegra_apb_writel_direct | 168 | #define tegra_apb_writel_using_dma tegra_apb_writel_direct |
167 | #endif | 169 | #endif |
168 | 170 | ||
169 | typedef u32 (*apbio_read_fptr)(unsigned long offset); | 171 | typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value); |
170 | typedef void (*apbio_write_fptr)(u32 value, unsigned long offset); | 172 | typedef int (*apbio_write_fptr)(u32 value, unsigned long offset); |
171 | 173 | ||
172 | static apbio_read_fptr apbio_read; | 174 | static apbio_read_fptr apbio_read; |
173 | static apbio_write_fptr apbio_write; | 175 | static apbio_write_fptr apbio_write; |
174 | 176 | ||
175 | static u32 tegra_apb_readl_direct(unsigned long offset) | 177 | static int tegra_apb_readl_direct(unsigned long offset, u32 *value) |
176 | { | 178 | { |
177 | return readl(IO_ADDRESS(offset)); | 179 | *value = readl(IO_ADDRESS(offset)); |
180 | |||
181 | return 0; | ||
178 | } | 182 | } |
179 | 183 | ||
180 | static void tegra_apb_writel_direct(u32 value, unsigned long offset) | 184 | static int tegra_apb_writel_direct(u32 value, unsigned long offset) |
181 | { | 185 | { |
182 | writel(value, IO_ADDRESS(offset)); | 186 | writel(value, IO_ADDRESS(offset)); |
187 | |||
188 | return 0; | ||
183 | } | 189 | } |
184 | 190 | ||
185 | void tegra_apb_io_init(void) | 191 | void tegra_apb_io_init(void) |
@@ -197,7 +203,12 @@ void tegra_apb_io_init(void) | |||
197 | 203 | ||
198 | u32 tegra_apb_readl(unsigned long offset) | 204 | u32 tegra_apb_readl(unsigned long offset) |
199 | { | 205 | { |
200 | return apbio_read(offset); | 206 | u32 val; |
207 | |||
208 | if (apbio_read(offset, &val) < 0) | ||
209 | return 0; | ||
210 | else | ||
211 | return val; | ||
201 | } | 212 | } |
202 | 213 | ||
203 | void tegra_apb_writel(u32 value, unsigned long offset) | 214 | void tegra_apb_writel(u32 value, unsigned long offset) |
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 0e03f104fbf8..a43a750dd0a3 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h | |||
@@ -27,6 +27,20 @@ | |||
27 | u32 tegra_read_chipid(void); | 27 | u32 tegra_read_chipid(void); |
28 | u8 tegra_get_chip_id(void); | 28 | u8 tegra_get_chip_id(void); |
29 | 29 | ||
30 | #if defined(CONFIG_TEGRA20_APB_DMA) | ||
31 | int tegra_apb_readl_using_dma(unsigned long offset, u32 *value); | ||
32 | int tegra_apb_writel_using_dma(u32 value, unsigned long offset); | ||
33 | #else | ||
34 | static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) | ||
35 | { | ||
36 | return -EINVAL; | ||
37 | } | ||
38 | static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset) | ||
39 | { | ||
40 | return -EINVAL; | ||
41 | } | ||
42 | #endif /* CONFIG_TEGRA20_APB_DMA */ | ||
43 | |||
30 | #endif /* __ASSEMBLY__ */ | 44 | #endif /* __ASSEMBLY__ */ |
31 | 45 | ||
32 | #endif /* __SOC_TEGRA_FUSE_H__ */ | 46 | #endif /* __SOC_TEGRA_FUSE_H__ */ |