diff options
-rw-r--r-- | arch/arm/mach-tegra/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/apbio.c | 217 | ||||
-rw-r--r-- | arch/arm/mach-tegra/apbio.h | 22 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra.c | 2 | ||||
-rw-r--r-- | drivers/soc/tegra/fuse/fuse-tegra20.c | 79 | ||||
-rw-r--r-- | include/soc/tegra/fuse.h | 14 |
6 files changed, 76 insertions, 259 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index e8601bb56f98..c303b55de22e 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile | |||
@@ -5,7 +5,6 @@ obj-y += irq.o | |||
5 | obj-y += pmc.o | 5 | obj-y += pmc.o |
6 | obj-y += flowctrl.o | 6 | obj-y += flowctrl.o |
7 | obj-y += powergate.o | 7 | obj-y += powergate.o |
8 | obj-y += apbio.o | ||
9 | obj-y += pm.o | 8 | obj-y += pm.o |
10 | obj-y += reset.o | 9 | obj-y += reset.o |
11 | obj-y += reset-handler.o | 10 | obj-y += reset-handler.o |
diff --git a/arch/arm/mach-tegra/apbio.c b/arch/arm/mach-tegra/apbio.c deleted file mode 100644 index f2488722c79c..000000000000 --- a/arch/arm/mach-tegra/apbio.c +++ /dev/null | |||
@@ -1,217 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 NVIDIA Corporation. | ||
3 | * Copyright (C) 2010 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/completion.h> | ||
17 | #include <linux/dmaengine.h> | ||
18 | #include <linux/dma-mapping.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | |||
26 | #include "apbio.h" | ||
27 | #include "iomap.h" | ||
28 | |||
29 | #if defined(CONFIG_TEGRA20_APB_DMA) | ||
30 | static DEFINE_MUTEX(tegra_apb_dma_lock); | ||
31 | static u32 *tegra_apb_bb; | ||
32 | static dma_addr_t tegra_apb_bb_phys; | ||
33 | static DECLARE_COMPLETION(tegra_apb_wait); | ||
34 | |||
35 | static int tegra_apb_readl_direct(unsigned long offset, u32 *value); | ||
36 | static int tegra_apb_writel_direct(u32 value, unsigned long offset); | ||
37 | |||
38 | static struct dma_chan *tegra_apb_dma_chan; | ||
39 | static struct dma_slave_config dma_sconfig; | ||
40 | |||
41 | static bool tegra_apb_dma_init(void) | ||
42 | { | ||
43 | dma_cap_mask_t mask; | ||
44 | |||
45 | mutex_lock(&tegra_apb_dma_lock); | ||
46 | |||
47 | /* Check to see if we raced to setup */ | ||
48 | if (tegra_apb_dma_chan) | ||
49 | goto skip_init; | ||
50 | |||
51 | dma_cap_zero(mask); | ||
52 | dma_cap_set(DMA_SLAVE, mask); | ||
53 | tegra_apb_dma_chan = dma_request_channel(mask, NULL, NULL); | ||
54 | if (!tegra_apb_dma_chan) { | ||
55 | /* | ||
56 | * This is common until the device is probed, so don't | ||
57 | * shout about it. | ||
58 | */ | ||
59 | pr_debug("%s: can not allocate dma channel\n", __func__); | ||
60 | goto err_dma_alloc; | ||
61 | } | ||
62 | |||
63 | tegra_apb_bb = dma_alloc_coherent(NULL, sizeof(u32), | ||
64 | &tegra_apb_bb_phys, GFP_KERNEL); | ||
65 | if (!tegra_apb_bb) { | ||
66 | pr_err("%s: can not allocate bounce buffer\n", __func__); | ||
67 | goto err_buff_alloc; | ||
68 | } | ||
69 | |||
70 | dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
71 | dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
72 | dma_sconfig.src_maxburst = 1; | ||
73 | dma_sconfig.dst_maxburst = 1; | ||
74 | |||
75 | skip_init: | ||
76 | mutex_unlock(&tegra_apb_dma_lock); | ||
77 | return true; | ||
78 | |||
79 | err_buff_alloc: | ||
80 | dma_release_channel(tegra_apb_dma_chan); | ||
81 | tegra_apb_dma_chan = NULL; | ||
82 | |||
83 | err_dma_alloc: | ||
84 | mutex_unlock(&tegra_apb_dma_lock); | ||
85 | return false; | ||
86 | } | ||
87 | |||
88 | static void apb_dma_complete(void *args) | ||
89 | { | ||
90 | complete(&tegra_apb_wait); | ||
91 | } | ||
92 | |||
93 | static int do_dma_transfer(unsigned long apb_add, | ||
94 | enum dma_transfer_direction dir) | ||
95 | { | ||
96 | struct dma_async_tx_descriptor *dma_desc; | ||
97 | int ret; | ||
98 | |||
99 | if (dir == DMA_DEV_TO_MEM) | ||
100 | dma_sconfig.src_addr = apb_add; | ||
101 | else | ||
102 | dma_sconfig.dst_addr = apb_add; | ||
103 | |||
104 | ret = dmaengine_slave_config(tegra_apb_dma_chan, &dma_sconfig); | ||
105 | if (ret) | ||
106 | return ret; | ||
107 | |||
108 | dma_desc = dmaengine_prep_slave_single(tegra_apb_dma_chan, | ||
109 | tegra_apb_bb_phys, sizeof(u32), dir, | ||
110 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
111 | if (!dma_desc) | ||
112 | return -EINVAL; | ||
113 | |||
114 | dma_desc->callback = apb_dma_complete; | ||
115 | dma_desc->callback_param = NULL; | ||
116 | |||
117 | reinit_completion(&tegra_apb_wait); | ||
118 | |||
119 | dmaengine_submit(dma_desc); | ||
120 | dma_async_issue_pending(tegra_apb_dma_chan); | ||
121 | ret = wait_for_completion_timeout(&tegra_apb_wait, | ||
122 | msecs_to_jiffies(50)); | ||
123 | |||
124 | if (WARN(ret == 0, "apb read dma timed out")) { | ||
125 | dmaengine_terminate_all(tegra_apb_dma_chan); | ||
126 | return -EFAULT; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) | ||
132 | { | ||
133 | int ret; | ||
134 | |||
135 | if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) | ||
136 | return tegra_apb_readl_direct(offset, value); | ||
137 | |||
138 | mutex_lock(&tegra_apb_dma_lock); | ||
139 | ret = do_dma_transfer(offset, DMA_DEV_TO_MEM); | ||
140 | if (ret < 0) | ||
141 | pr_err("error in reading offset 0x%08lx using dma\n", offset); | ||
142 | else | ||
143 | *value = *tegra_apb_bb; | ||
144 | |||
145 | mutex_unlock(&tegra_apb_dma_lock); | ||
146 | |||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | int tegra_apb_writel_using_dma(u32 value, unsigned long offset) | ||
151 | { | ||
152 | int ret; | ||
153 | |||
154 | if (!tegra_apb_dma_chan && !tegra_apb_dma_init()) | ||
155 | return tegra_apb_writel_direct(value, offset); | ||
156 | |||
157 | mutex_lock(&tegra_apb_dma_lock); | ||
158 | *((u32 *)tegra_apb_bb) = value; | ||
159 | ret = do_dma_transfer(offset, DMA_MEM_TO_DEV); | ||
160 | mutex_unlock(&tegra_apb_dma_lock); | ||
161 | if (ret < 0) | ||
162 | pr_err("error in writing offset 0x%08lx using dma\n", offset); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | #else | ||
167 | #define tegra_apb_readl_using_dma tegra_apb_readl_direct | ||
168 | #define tegra_apb_writel_using_dma tegra_apb_writel_direct | ||
169 | #endif | ||
170 | |||
171 | typedef int (*apbio_read_fptr)(unsigned long offset, u32 *value); | ||
172 | typedef int (*apbio_write_fptr)(u32 value, unsigned long offset); | ||
173 | |||
174 | static apbio_read_fptr apbio_read; | ||
175 | static apbio_write_fptr apbio_write; | ||
176 | |||
177 | static int tegra_apb_readl_direct(unsigned long offset, u32 *value) | ||
178 | { | ||
179 | *value = readl(IO_ADDRESS(offset)); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int tegra_apb_writel_direct(u32 value, unsigned long offset) | ||
185 | { | ||
186 | writel(value, IO_ADDRESS(offset)); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | void tegra_apb_io_init(void) | ||
192 | { | ||
193 | /* Need to use dma only when it is Tegra20 based platform */ | ||
194 | if (of_machine_is_compatible("nvidia,tegra20") || | ||
195 | !of_have_populated_dt()) { | ||
196 | apbio_read = tegra_apb_readl_using_dma; | ||
197 | apbio_write = tegra_apb_writel_using_dma; | ||
198 | } else { | ||
199 | apbio_read = tegra_apb_readl_direct; | ||
200 | apbio_write = tegra_apb_writel_direct; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | u32 tegra_apb_readl(unsigned long offset) | ||
205 | { | ||
206 | u32 val; | ||
207 | |||
208 | if (apbio_read(offset, &val) < 0) | ||
209 | return 0; | ||
210 | else | ||
211 | return val; | ||
212 | } | ||
213 | |||
214 | void tegra_apb_writel(u32 value, unsigned long offset) | ||
215 | { | ||
216 | apbio_write(value, offset); | ||
217 | } | ||
diff --git a/arch/arm/mach-tegra/apbio.h b/arch/arm/mach-tegra/apbio.h deleted file mode 100644 index f05d71c303c7..000000000000 --- a/arch/arm/mach-tegra/apbio.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 NVIDIA Corporation. | ||
3 | * Copyright (C) 2010 Google, Inc. | ||
4 | * | ||
5 | * This software is licensed under the terms of the GNU General Public | ||
6 | * License version 2, as published by the Free Software Foundation, and | ||
7 | * may be copied, distributed, and modified under those terms. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #ifndef __MACH_TEGRA_APBIO_H | ||
17 | #define __MACH_TEGRA_APBIO_H | ||
18 | |||
19 | void tegra_apb_io_init(void); | ||
20 | u32 tegra_apb_readl(unsigned long offset); | ||
21 | void tegra_apb_writel(u32 value, unsigned long offset); | ||
22 | #endif | ||
diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index c0faae8c0822..6ccbc8ca1db5 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c | |||
@@ -44,7 +44,6 @@ | |||
44 | #include <asm/setup.h> | 44 | #include <asm/setup.h> |
45 | #include <asm/trusted_foundations.h> | 45 | #include <asm/trusted_foundations.h> |
46 | 46 | ||
47 | #include "apbio.h" | ||
48 | #include "board.h" | 47 | #include "board.h" |
49 | #include "common.h" | 48 | #include "common.h" |
50 | #include "cpuidle.h" | 49 | #include "cpuidle.h" |
@@ -74,7 +73,6 @@ u32 tegra_uart_config[3] = { | |||
74 | static void __init tegra_init_early(void) | 73 | static void __init tegra_init_early(void) |
75 | { | 74 | { |
76 | of_register_trusted_foundations(); | 75 | of_register_trusted_foundations(); |
77 | tegra_apb_io_init(); | ||
78 | tegra_init_fuse(); | 76 | tegra_init_fuse(); |
79 | tegra_cpu_reset_handler_init(); | 77 | tegra_cpu_reset_handler_init(); |
80 | tegra_powergate_init(); | 78 | tegra_powergate_init(); |
diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 7a9d0e045490..7cb63ab6aac2 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c | |||
@@ -18,6 +18,9 @@ | |||
18 | 18 | ||
19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
20 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
21 | #include <linux/completion.h> | ||
22 | #include <linux/dmaengine.h> | ||
23 | #include <linux/dma-mapping.h> | ||
21 | #include <linux/err.h> | 24 | #include <linux/err.h> |
22 | #include <linux/io.h> | 25 | #include <linux/io.h> |
23 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
@@ -39,18 +42,58 @@ static phys_addr_t fuse_phys; | |||
39 | static struct clk *fuse_clk; | 42 | static struct clk *fuse_clk; |
40 | static void __iomem __initdata *fuse_base; | 43 | static void __iomem __initdata *fuse_base; |
41 | 44 | ||
45 | static DEFINE_MUTEX(apb_dma_lock); | ||
46 | static DECLARE_COMPLETION(apb_dma_wait); | ||
47 | static struct dma_chan *apb_dma_chan; | ||
48 | static struct dma_slave_config dma_sconfig; | ||
49 | static u32 *apb_buffer; | ||
50 | static dma_addr_t apb_buffer_phys; | ||
51 | |||
52 | static void apb_dma_complete(void *args) | ||
53 | { | ||
54 | complete(&apb_dma_wait); | ||
55 | } | ||
56 | |||
42 | static u32 tegra20_fuse_readl(const unsigned int offset) | 57 | static u32 tegra20_fuse_readl(const unsigned int offset) |
43 | { | 58 | { |
44 | int ret; | 59 | int ret; |
45 | u32 val; | 60 | u32 val = 0; |
61 | struct dma_async_tx_descriptor *dma_desc; | ||
62 | |||
63 | mutex_lock(&apb_dma_lock); | ||
64 | |||
65 | dma_sconfig.src_addr = fuse_phys + FUSE_BEGIN + offset; | ||
66 | ret = dmaengine_slave_config(apb_dma_chan, &dma_sconfig); | ||
67 | if (ret) | ||
68 | goto out; | ||
69 | |||
70 | dma_desc = dmaengine_prep_slave_single(apb_dma_chan, apb_buffer_phys, | ||
71 | sizeof(u32), DMA_DEV_TO_MEM, | ||
72 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
73 | if (!dma_desc) | ||
74 | goto out; | ||
75 | |||
76 | dma_desc->callback = apb_dma_complete; | ||
77 | dma_desc->callback_param = NULL; | ||
78 | |||
79 | reinit_completion(&apb_dma_wait); | ||
46 | 80 | ||
47 | clk_prepare_enable(fuse_clk); | 81 | clk_prepare_enable(fuse_clk); |
48 | 82 | ||
49 | ret = tegra_apb_readl_using_dma(fuse_phys + FUSE_BEGIN + offset, &val); | 83 | dmaengine_submit(dma_desc); |
84 | dma_async_issue_pending(apb_dma_chan); | ||
85 | ret = wait_for_completion_timeout(&apb_dma_wait, msecs_to_jiffies(50)); | ||
86 | |||
87 | if (WARN(ret == 0, "apb read dma timed out")) | ||
88 | dmaengine_terminate_all(apb_dma_chan); | ||
89 | else | ||
90 | val = *apb_buffer; | ||
50 | 91 | ||
51 | clk_disable_unprepare(fuse_clk); | 92 | clk_disable_unprepare(fuse_clk); |
93 | out: | ||
94 | mutex_unlock(&apb_dma_lock); | ||
52 | 95 | ||
53 | return (ret < 0) ? 0 : val; | 96 | return val; |
54 | } | 97 | } |
55 | 98 | ||
56 | static const struct of_device_id tegra20_fuse_of_match[] = { | 99 | static const struct of_device_id tegra20_fuse_of_match[] = { |
@@ -58,9 +101,35 @@ static const struct of_device_id tegra20_fuse_of_match[] = { | |||
58 | {}, | 101 | {}, |
59 | }; | 102 | }; |
60 | 103 | ||
104 | static int apb_dma_init(void) | ||
105 | { | ||
106 | dma_cap_mask_t mask; | ||
107 | |||
108 | dma_cap_zero(mask); | ||
109 | dma_cap_set(DMA_SLAVE, mask); | ||
110 | apb_dma_chan = dma_request_channel(mask, NULL, NULL); | ||
111 | if (!apb_dma_chan) | ||
112 | return -EPROBE_DEFER; | ||
113 | |||
114 | apb_buffer = dma_alloc_coherent(NULL, sizeof(u32), &apb_buffer_phys, | ||
115 | GFP_KERNEL); | ||
116 | if (!apb_buffer) { | ||
117 | dma_release_channel(apb_dma_chan); | ||
118 | return -ENOMEM; | ||
119 | } | ||
120 | |||
121 | dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
122 | dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
123 | dma_sconfig.src_maxburst = 1; | ||
124 | dma_sconfig.dst_maxburst = 1; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
61 | static int tegra20_fuse_probe(struct platform_device *pdev) | 129 | static int tegra20_fuse_probe(struct platform_device *pdev) |
62 | { | 130 | { |
63 | struct resource *res; | 131 | struct resource *res; |
132 | int err; | ||
64 | 133 | ||
65 | fuse_clk = devm_clk_get(&pdev->dev, NULL); | 134 | fuse_clk = devm_clk_get(&pdev->dev, NULL); |
66 | if (IS_ERR(fuse_clk)) { | 135 | if (IS_ERR(fuse_clk)) { |
@@ -73,6 +142,10 @@ static int tegra20_fuse_probe(struct platform_device *pdev) | |||
73 | return -EINVAL; | 142 | return -EINVAL; |
74 | fuse_phys = res->start; | 143 | fuse_phys = res->start; |
75 | 144 | ||
145 | err = apb_dma_init(); | ||
146 | if (err) | ||
147 | return err; | ||
148 | |||
76 | if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl)) | 149 | if (tegra_fuse_create_sysfs(&pdev->dev, FUSE_SIZE, tegra20_fuse_readl)) |
77 | return -ENODEV; | 150 | return -ENODEV; |
78 | 151 | ||
diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 51ac804deba5..738712d75cfe 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h | |||
@@ -61,20 +61,6 @@ int tegra_fuse_readl(unsigned long offset, u32 *value); | |||
61 | 61 | ||
62 | extern struct tegra_sku_info tegra_sku_info; | 62 | extern struct tegra_sku_info tegra_sku_info; |
63 | 63 | ||
64 | #if defined(CONFIG_TEGRA20_APB_DMA) | ||
65 | int tegra_apb_readl_using_dma(unsigned long offset, u32 *value); | ||
66 | int tegra_apb_writel_using_dma(u32 value, unsigned long offset); | ||
67 | #else | ||
68 | static inline int tegra_apb_readl_using_dma(unsigned long offset, u32 *value) | ||
69 | { | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | static inline int tegra_apb_writel_using_dma(u32 value, unsigned long offset) | ||
73 | { | ||
74 | return -EINVAL; | ||
75 | } | ||
76 | #endif /* CONFIG_TEGRA20_APB_DMA */ | ||
77 | |||
78 | #endif /* __ASSEMBLY__ */ | 64 | #endif /* __ASSEMBLY__ */ |
79 | 65 | ||
80 | #endif /* __SOC_TEGRA_FUSE_H__ */ | 66 | #endif /* __SOC_TEGRA_FUSE_H__ */ |