[ARM] tegra: use APB DMA for accessing APB devices
[linux-2.6.git] / arch / arm / mach-tegra / common.c
1 /*
2  * arch/arm/mach-tegra/common.c
3  *
4  * Copyright (C) 2010 Google, Inc.
5  *
6  * Author:
7  *      Colin Cross <ccross@android.com>
8  *
9  * This software is licensed under the terms of the GNU General Public
10  * License version 2, as published by the Free Software Foundation, and
11  * may be copied, distributed, and modified under those terms.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  */
19
20 #include <linux/console.h>
21 #include <linux/init.h>
22 #include <linux/io.h>
23 #include <linux/clk.h>
24 #include <linux/delay.h>
25 #include <linux/highmem.h>
26 #include <linux/memblock.h>
27
28 #include <asm/hardware/cache-l2x0.h>
29 #include <asm/system.h>
30
31 #include <mach/gpio.h>
32 #include <mach/iomap.h>
33 #include <mach/pinmux.h>
34 #include <mach/powergate.h>
35 #include <mach/system.h>
36
37 #include "apbio.h"
38 #include "board.h"
39 #include "clock.h"
40 #include "fuse.h"
41 #include "pm.h"
42
43 #define MC_SECURITY_CFG2 0x7c
44
45 unsigned long tegra_bootloader_fb_start;
46 unsigned long tegra_bootloader_fb_size;
47 unsigned long tegra_fb_start;
48 unsigned long tegra_fb_size;
49 unsigned long tegra_fb2_start;
50 unsigned long tegra_fb2_size;
51 unsigned long tegra_carveout_start;
52 unsigned long tegra_carveout_size;
53 unsigned long tegra_lp0_vec_start;
54 unsigned long tegra_lp0_vec_size;
55 unsigned long tegra_grhost_aperture;
56
57 void (*arch_reset)(char mode, const char *cmd) = tegra_assert_system_reset;
58
59 void tegra_assert_system_reset(char mode, const char *cmd)
60 {
61         void __iomem *reset = IO_ADDRESS(TEGRA_CLK_RESET_BASE + 0x04);
62         u32 reg;
63
64         /* use *_related to avoid spinlock since caches are off */
65         reg = readl_relaxed(reset);
66         reg |= 0x04;
67         writel_relaxed(reg, reset);
68 }
69
70 static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
71         /* name         parent          rate            enabled */
72         { "clk_m",      NULL,           0,              true },
73         { "pll_p",      "clk_m",        216000000,      true },
74         { "pll_p_out1", "pll_p",        28800000,       true },
75         { "pll_p_out2", "pll_p",        48000000,       true },
76         { "pll_p_out3", "pll_p",        72000000,       true },
77         { "pll_p_out4", "pll_p",        108000000,      true },
78         { "pll_m_out1", "pll_m",        120000000,      true },
79         { "sclk",       "pll_m_out1",   120000000,      true },
80         { "hclk",       "sclk",         120000000,      true },
81         { "pclk",       "hclk",         60000000,       true },
82         { "csite",      NULL,           0,              true },
83         { "emc",        NULL,           0,              true },
84         { "cpu",        NULL,           0,              true },
85         { "kfuse",      NULL,           0,              true },
86         { "pll_u",      "clk_m",        480000000,      false },
87         { "sdmmc1",     "pll_p",        48000000,       false},
88         { "sdmmc2",     "pll_p",        48000000,       false},
89         { "sdmmc3",     "pll_p",        48000000,       false},
90         { "sdmmc4",     "pll_p",        48000000,       false},
91         { NULL,         NULL,           0,              0},
92 };
93
94 void tegra_init_cache(void)
95 {
96 #ifdef CONFIG_CACHE_L2X0
97         void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
98
99         writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
100         writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
101
102         l2x0_init(p, 0x6C480001, 0x8200c3fe);
103 #endif
104
105 }
106
107 static void __init tegra_init_power(void)
108 {
109         tegra_powergate_power_off(TEGRA_POWERGATE_MPE);
110         tegra_powergate_power_off(TEGRA_POWERGATE_3D);
111 }
112
113 static bool console_flushed;
114
115 static void tegra_pm_flush_console(void)
116 {
117         if (console_flushed)
118                 return;
119         console_flushed = true;
120
121         printk("\n");
122         pr_emerg("Restarting %s\n", linux_banner);
123         if (!try_acquire_console_sem()) {
124                 release_console_sem();
125                 return;
126         }
127
128         mdelay(50);
129
130         local_irq_disable();
131         if (try_acquire_console_sem())
132                 pr_emerg("tegra_restart: Console was locked! Busting\n");
133         else
134                 pr_emerg("tegra_restart: Console was locked!\n");
135         release_console_sem();
136 }
137
138 static void tegra_pm_restart(char mode, const char *cmd)
139 {
140         tegra_pm_flush_console();
141         arm_machine_restart(mode, cmd);
142 }
143
144 void __init tegra_init_early(void)
145 {
146         arm_pm_restart = tegra_pm_restart;
147         tegra_init_fuse();
148         tegra_gpio_resume_init();
149         tegra_init_clock();
150         tegra_init_pinmux();
151         tegra_clk_init_from_table(common_clk_init_table);
152         tegra_init_power();
153         tegra_init_cache();
154         tegra_dma_init();
155         tegra_init_apb_dma();
156 }
157
158 static int __init tegra_lp0_vec_arg(char *options)
159 {
160         char *p = options;
161
162         tegra_lp0_vec_size = memparse(p, &p);
163         if (*p == '@')
164                 tegra_lp0_vec_start = memparse(p+1, &p);
165
166         return 0;
167 }
168 early_param("lp0_vec", tegra_lp0_vec_arg);
169
170 void __init tegra_reserve(void)
171 {
172         if (tegra_lp0_vec_size)
173                 if (memblock_reserve(tegra_lp0_vec_start, tegra_lp0_vec_size))
174                         pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
175                                 tegra_lp0_vec_size, tegra_lp0_vec_start);
176
177         pr_info("Tegra reserved memory:\n"
178                 "LP0:                    %08lx - %08lx\n",
179                 tegra_lp0_vec_start,
180                 tegra_lp0_vec_start + tegra_lp0_vec_size - 1);
181 }
182
183 static int __init tegra_bootloader_fb_arg(char *options)
184 {
185         char *p = options;
186
187         tegra_bootloader_fb_size = memparse(p, &p);
188         if (*p == '@')
189                 tegra_bootloader_fb_start = memparse(p+1, &p);
190
191         pr_info("Found tegra_fbmem: %08lx@%08lx\n",
192                 tegra_bootloader_fb_size, tegra_bootloader_fb_start);
193
194         return 0;
195 }
196 early_param("tegra_fbmem", tegra_bootloader_fb_arg);
197
198 /*
199  * Tegra has a protected aperture that prevents access by most non-CPU
200  * memory masters to addresses above the aperture value.  Enabling it
201  * secures the CPU's memory from the GPU, except through the GART.
202  */
203 void __init tegra_protected_aperture_init(unsigned long aperture)
204 {
205 #ifndef CONFIG_NVMAP_ALLOW_SYSMEM
206         void __iomem *mc_base = IO_ADDRESS(TEGRA_MC_BASE);
207         pr_info("Enabling Tegra protected aperture at 0x%08lx\n", aperture);
208         writel(aperture, mc_base + MC_SECURITY_CFG2);
209 #else
210         pr_err("Tegra protected aperture disabled because nvmap is using "
211                 "system memory\n");
212 #endif
213 }
214
215 /*
216  * Due to conflicting restrictions on the placement of the framebuffer,
217  * the bootloader is likely to leave the framebuffer pointed at a location
218  * in memory that is outside the grhost aperture.  This function will move
219  * the framebuffer contents from a physical address that is anywher (lowmem,
220  * highmem, or outside the memory map) to a physical address that is outside
221  * the memory map.
222  */
223 void tegra_move_framebuffer(unsigned long to, unsigned long from,
224         unsigned long size)
225 {
226         struct page *page;
227         void __iomem *to_io;
228         void *from_virt;
229         unsigned long i;
230
231         BUG_ON(PAGE_ALIGN((unsigned long)to) != (unsigned long)to);
232         BUG_ON(PAGE_ALIGN(from) != from);
233         BUG_ON(PAGE_ALIGN(size) != size);
234
235         to_io = ioremap(to, size);
236         if (!to_io) {
237                 pr_err("%s: Failed to map target framebuffer\n", __func__);
238                 return;
239         }
240
241         if (pfn_valid(page_to_pfn(phys_to_page(from)))) {
242                 for (i = 0 ; i < size; i += PAGE_SIZE) {
243                         page = phys_to_page(from + i);
244                         from_virt = kmap(page);
245                         memcpy_toio(to_io + i, from_virt, PAGE_SIZE);
246                         kunmap(page);
247                 }
248         } else {
249                 void __iomem *from_io = ioremap(from, size);
250                 if (!from_io) {
251                         pr_err("%s: Failed to map source framebuffer\n",
252                                 __func__);
253                         goto out;
254                 }
255
256                 for (i = 0; i < size; i+= 4)
257                         writel(readl(from_io + i), to_io + i);
258
259                 iounmap(from_io);
260         }
261 out:
262         iounmap(to_io);
263 }
264
265 void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
266         unsigned long fb2_size)
267 {
268         if (tegra_lp0_vec_size)
269                 if (memblock_reserve(tegra_lp0_vec_start, tegra_lp0_vec_size))
270                         pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
271                                 tegra_lp0_vec_size, tegra_lp0_vec_start);
272
273
274         tegra_carveout_start = memblock_end_of_DRAM() - carveout_size;
275         if (memblock_remove(tegra_carveout_start, carveout_size))
276                 pr_err("Failed to remove carveout %08lx@%08lx from memory "
277                         "map\n",
278                         tegra_carveout_start, carveout_size);
279         else
280                 tegra_carveout_size = carveout_size;
281
282         tegra_fb2_start = memblock_end_of_DRAM() - fb2_size;
283         if (memblock_remove(tegra_fb2_start, fb2_size))
284                 pr_err("Failed to remove second framebuffer %08lx@%08lx from "
285                         "memory map\n",
286                         tegra_fb2_start, fb2_size);
287         else
288                 tegra_fb2_size = fb2_size;
289
290         tegra_fb_start = memblock_end_of_DRAM() - fb_size;
291         if (memblock_remove(tegra_fb_start, fb_size))
292                 pr_err("Failed to remove framebuffer %08lx@%08lx from memory "
293                         "map\n",
294                         tegra_fb_start, fb_size);
295         else
296                 tegra_fb_size = fb_size;
297
298         if (tegra_fb_size)
299                 tegra_grhost_aperture = tegra_fb_start;
300
301         if (tegra_fb2_size && tegra_fb2_start < tegra_grhost_aperture)
302                 tegra_grhost_aperture = tegra_fb2_start;
303
304         if (tegra_carveout_size && tegra_carveout_start < tegra_grhost_aperture)
305                 tegra_grhost_aperture = tegra_carveout_start;
306
307         /*
308          * TODO: We should copy the bootloader's framebuffer to the framebuffer
309          * allocated above, and then free this one.
310          */
311         if (tegra_bootloader_fb_size)
312                 if (memblock_reserve(tegra_bootloader_fb_start,
313                                 tegra_bootloader_fb_size))
314                         pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
315                                 tegra_lp0_vec_size, tegra_lp0_vec_start);
316
317         pr_info("Tegra reserved memory:\n"
318                 "LP0:                    %08lx - %08lx\n"
319                 "Bootloader framebuffer: %08lx - %08lx\n"
320                 "Framebuffer:            %08lx - %08lx\n"
321                 "2nd Framebuffer:         %08lx - %08lx\n"
322                 "Carveout:               %08lx - %08lx\n",
323                 tegra_lp0_vec_start,
324                 tegra_lp0_vec_start + tegra_lp0_vec_size - 1,
325                 tegra_bootloader_fb_start,
326                 tegra_bootloader_fb_start + tegra_bootloader_fb_size - 1,
327                 tegra_fb_start,
328                 tegra_fb_start + tegra_fb_size - 1,
329                 tegra_fb2_start,
330                 tegra_fb2_start + tegra_fb2_size - 1,
331                 tegra_carveout_start,
332                 tegra_carveout_start + tegra_carveout_size - 1);
333 }