ee23ecdd2a9b8a5ca3f6e01ad85a23fa82e7c269
[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 static   bool is_tegra_debug_uart_hsport;
57
58 void (*arch_reset)(char mode, const char *cmd) = tegra_assert_system_reset;
59
60 void tegra_assert_system_reset(char mode, const char *cmd)
61 {
62         void __iomem *reset = IO_ADDRESS(TEGRA_PMC_BASE + 0x00);
63         u32 reg;
64
65         /* use *_related to avoid spinlock since caches are off */
66         reg = readl_relaxed(reset);
67         reg |= 0x10;
68         writel_relaxed(reg, reset);
69 }
70
71 static struct board_info tegra_board_info = {
72         .board_id = -1,
73         .sku = -1,
74         .fab = -1,
75         .major_revision = -1,
76         .minor_revision = -1,
77 };
78
79 static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
80         /* name         parent          rate            enabled */
81         { "clk_m",      NULL,           0,              true },
82         { "pll_m",      "clk_m",        600000000,      true },
83         { "pll_p",      "clk_m",        216000000,      true },
84         { "pll_p_out1", "pll_p",        28800000,       true },
85         { "pll_p_out2", "pll_p",        48000000,       true },
86         { "pll_p_out3", "pll_p",        72000000,       true },
87         { "pll_p_out4", "pll_p",        108000000,      true },
88         { "pll_m_out1", "pll_m",        120000000,      true },
89         { "sclk",       "pll_m_out1",   120000000,      true },
90         { "hclk",       "sclk",         120000000,      true },
91         { "pclk",       "hclk",         60000000,       true },
92         { "csite",      NULL,           0,              true },
93         { "emc",        NULL,           0,              true },
94         { "cpu",        NULL,           0,              true },
95         { "kfuse",      NULL,           0,              true },
96         { "pll_u",      "clk_m",        480000000,      false },
97         { "sdmmc1",     "pll_p",        48000000,       false},
98         { "sdmmc2",     "pll_p",        48000000,       false},
99         { "sdmmc3",     "pll_p",        48000000,       false},
100         { "sdmmc4",     "pll_p",        48000000,       false},
101         { NULL,         NULL,           0,              0},
102 };
103
104 void tegra_init_cache(void)
105 {
106 #ifdef CONFIG_CACHE_L2X0
107         void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
108
109         writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
110         writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
111
112         l2x0_init(p, 0x6C480001, 0x8200c3fe);
113 #endif
114
115 }
116
117 static void __init tegra_init_power(void)
118 {
119         tegra_powergate_power_off(TEGRA_POWERGATE_MPE);
120         tegra_powergate_power_off(TEGRA_POWERGATE_3D);
121         tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
122 }
123
124 static bool console_flushed;
125
126 static void tegra_pm_flush_console(void)
127 {
128         if (console_flushed)
129                 return;
130         console_flushed = true;
131
132         printk("\n");
133         pr_emerg("Restarting %s\n", linux_banner);
134         if (console_trylock()) {
135                 console_unlock();
136                 return;
137         }
138
139         mdelay(50);
140
141         local_irq_disable();
142         if (!console_trylock())
143                 pr_emerg("tegra_restart: Console was locked! Busting\n");
144         else
145                 pr_emerg("tegra_restart: Console was locked!\n");
146         console_unlock();
147 }
148
149 static void tegra_pm_restart(char mode, const char *cmd)
150 {
151         tegra_pm_flush_console();
152         arm_machine_restart(mode, cmd);
153 }
154
155 void __init tegra_init_early(void)
156 {
157         arm_pm_restart = tegra_pm_restart;
158         tegra_init_fuse();
159         tegra_gpio_resume_init();
160         tegra_init_clock();
161         tegra_init_pinmux();
162         tegra_clk_init_from_table(common_clk_init_table);
163         tegra_init_power();
164         tegra_init_cache();
165 }
166
167 static int __init tegra_lp0_vec_arg(char *options)
168 {
169         char *p = options;
170
171         tegra_lp0_vec_size = memparse(p, &p);
172         if (*p == '@')
173                 tegra_lp0_vec_start = memparse(p+1, &p);
174
175         return 0;
176 }
177 early_param("lp0_vec", tegra_lp0_vec_arg);
178
179 static int __init tegra_bootloader_fb_arg(char *options)
180 {
181         char *p = options;
182
183         tegra_bootloader_fb_size = memparse(p, &p);
184         if (*p == '@')
185                 tegra_bootloader_fb_start = memparse(p+1, &p);
186
187         pr_info("Found tegra_fbmem: %08lx@%08lx\n",
188                 tegra_bootloader_fb_size, tegra_bootloader_fb_start);
189
190         return 0;
191 }
192 early_param("tegra_fbmem", tegra_bootloader_fb_arg);
193
194 static int __init tegra_board_info_parse(char *info)
195 {
196         char *p;
197         int pos = 0;
198         struct board_info *bi = &tegra_board_info;
199
200         while (info && *info) {
201                 if ((p = strchr(info, ':')))
202                         *p++ = '\0';
203
204                 if (strlen(info) > 0) {
205                         switch(pos) {
206                         case 0:
207                                 bi->board_id = simple_strtol(info, NULL, 16);
208                                 break;
209                         case 1:
210                                 bi->sku = simple_strtol(info, NULL, 16);
211                                 break;
212                         case 2:
213                                 bi->fab = simple_strtol(info, NULL, 16);
214                                 break;
215                         case 3:
216                                 bi->major_revision = simple_strtol(info, NULL, 16);
217                                 break;
218                         case 4:
219                                 bi->minor_revision = simple_strtol(info, NULL, 16);
220                                 break;
221                         default:
222                                 break;
223                         }
224                 }
225
226                 info = p;
227                 pos++;
228         }
229
230         pr_info("board info: Id:%d%2d SKU:%d Fab:%d Rev:%c MinRev:%d\n",
231                         bi->board_id >> 8 & 0xFF, bi->board_id & 0xFF,
232                         bi->sku, bi->fab, bi->major_revision, bi->minor_revision);
233
234         return 1;
235 }
236
237 __setup("board_info=", tegra_board_info_parse);
238
239 static int __init tegra_debug_uartport(char *info)
240 {
241         if (!strcmp(info, "hsport"))
242                 is_tegra_debug_uart_hsport = true;
243         else if (!strcmp(info, "lsport"))
244                 is_tegra_debug_uart_hsport = false;
245
246         return 1;
247 }
248
249 bool is_tegra_debug_uartport_hs(void)
250 {
251         return is_tegra_debug_uart_hsport;
252 }
253
254 __setup("debug_uartport=", tegra_debug_uartport);
255
256 void tegra_get_board_info(struct board_info *bi)
257 {
258         memcpy(bi, &tegra_board_info, sizeof(*bi));
259 }
260
261 /*
262  * Tegra has a protected aperture that prevents access by most non-CPU
263  * memory masters to addresses above the aperture value.  Enabling it
264  * secures the CPU's memory from the GPU, except through the GART.
265  */
266 void __init tegra_protected_aperture_init(unsigned long aperture)
267 {
268 #ifndef CONFIG_NVMAP_ALLOW_SYSMEM
269         void __iomem *mc_base = IO_ADDRESS(TEGRA_MC_BASE);
270         pr_info("Enabling Tegra protected aperture at 0x%08lx\n", aperture);
271         writel(aperture, mc_base + MC_SECURITY_CFG2);
272 #else
273         pr_err("Tegra protected aperture disabled because nvmap is using "
274                 "system memory\n");
275 #endif
276 }
277
278 /*
279  * Due to conflicting restrictions on the placement of the framebuffer,
280  * the bootloader is likely to leave the framebuffer pointed at a location
281  * in memory that is outside the grhost aperture.  This function will move
282  * the framebuffer contents from a physical address that is anywher (lowmem,
283  * highmem, or outside the memory map) to a physical address that is outside
284  * the memory map.
285  */
286 void tegra_move_framebuffer(unsigned long to, unsigned long from,
287         unsigned long size)
288 {
289         struct page *page;
290         void __iomem *to_io;
291         void *from_virt;
292         unsigned long i;
293
294         BUG_ON(PAGE_ALIGN((unsigned long)to) != (unsigned long)to);
295         BUG_ON(PAGE_ALIGN(from) != from);
296         BUG_ON(PAGE_ALIGN(size) != size);
297
298         to_io = ioremap(to, size);
299         if (!to_io) {
300                 pr_err("%s: Failed to map target framebuffer\n", __func__);
301                 return;
302         }
303
304         if (pfn_valid(page_to_pfn(phys_to_page(from)))) {
305                 for (i = 0 ; i < size; i += PAGE_SIZE) {
306                         page = phys_to_page(from + i);
307                         from_virt = kmap(page);
308                         memcpy_toio(to_io + i, from_virt, PAGE_SIZE);
309                         kunmap(page);
310                 }
311         } else {
312                 void __iomem *from_io = ioremap(from, size);
313                 if (!from_io) {
314                         pr_err("%s: Failed to map source framebuffer\n",
315                                 __func__);
316                         goto out;
317                 }
318
319                 for (i = 0; i < size; i+= 4)
320                         writel(readl(from_io + i), to_io + i);
321
322                 iounmap(from_io);
323         }
324 out:
325         iounmap(to_io);
326 }
327
328 void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
329         unsigned long fb2_size)
330 {
331         if (tegra_lp0_vec_size)
332                 if (memblock_reserve(tegra_lp0_vec_start, tegra_lp0_vec_size))
333                         pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
334                                 tegra_lp0_vec_size, tegra_lp0_vec_start);
335
336
337         tegra_carveout_start = memblock_end_of_DRAM() - carveout_size;
338         if (memblock_remove(tegra_carveout_start, carveout_size))
339                 pr_err("Failed to remove carveout %08lx@%08lx from memory "
340                         "map\n",
341                         tegra_carveout_start, carveout_size);
342         else
343                 tegra_carveout_size = carveout_size;
344
345         tegra_fb2_start = memblock_end_of_DRAM() - fb2_size;
346         if (memblock_remove(tegra_fb2_start, fb2_size))
347                 pr_err("Failed to remove second framebuffer %08lx@%08lx from "
348                         "memory map\n",
349                         tegra_fb2_start, fb2_size);
350         else
351                 tegra_fb2_size = fb2_size;
352
353         tegra_fb_start = memblock_end_of_DRAM() - fb_size;
354         if (memblock_remove(tegra_fb_start, fb_size))
355                 pr_err("Failed to remove framebuffer %08lx@%08lx from memory "
356                         "map\n",
357                         tegra_fb_start, fb_size);
358         else
359                 tegra_fb_size = fb_size;
360
361         if (tegra_fb_size)
362                 tegra_grhost_aperture = tegra_fb_start;
363
364         if (tegra_fb2_size && tegra_fb2_start < tegra_grhost_aperture)
365                 tegra_grhost_aperture = tegra_fb2_start;
366
367         if (tegra_carveout_size && tegra_carveout_start < tegra_grhost_aperture)
368                 tegra_grhost_aperture = tegra_carveout_start;
369
370         /*
371          * TODO: We should copy the bootloader's framebuffer to the framebuffer
372          * allocated above, and then free this one.
373          */
374         if (tegra_bootloader_fb_size)
375                 if (memblock_reserve(tegra_bootloader_fb_start,
376                                 tegra_bootloader_fb_size))
377                         pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
378                                 tegra_lp0_vec_size, tegra_lp0_vec_start);
379
380         pr_info("Tegra reserved memory:\n"
381                 "LP0:                    %08lx - %08lx\n"
382                 "Bootloader framebuffer: %08lx - %08lx\n"
383                 "Framebuffer:            %08lx - %08lx\n"
384                 "2nd Framebuffer:         %08lx - %08lx\n"
385                 "Carveout:               %08lx - %08lx\n",
386                 tegra_lp0_vec_start,
387                 tegra_lp0_vec_start + tegra_lp0_vec_size - 1,
388                 tegra_bootloader_fb_start,
389                 tegra_bootloader_fb_start + tegra_bootloader_fb_size - 1,
390                 tegra_fb_start,
391                 tegra_fb_start + tegra_fb_size - 1,
392                 tegra_fb2_start,
393                 tegra_fb2_start + tegra_fb2_size - 1,
394                 tegra_carveout_start,
395                 tegra_carveout_start + tegra_carveout_size - 1);
396 }