blob: 33ea04e59f0e86f2ceb52840537a41f3f2b6816e [file] [log] [blame]
Erik Gillingc5f80062010-01-21 16:53:02 -08001/*
Todd Poynor433cb7f2010-09-02 15:10:29 -07002 * arch/arm/mach-tegra/common.c
Erik Gillingc5f80062010-01-21 16:53:02 -08003 *
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
Dima Zavin7e158ac2010-11-11 15:28:46 -080020#include <linux/console.h>
Erik Gillingc5f80062010-01-21 16:53:02 -080021#include <linux/init.h>
22#include <linux/io.h>
Colin Cross4de3a8f2010-04-05 13:16:42 -070023#include <linux/clk.h>
24#include <linux/delay.h>
Colin Cross115467a2010-10-19 21:09:29 -070025#include <linux/highmem.h>
Colin Cross8e437c22010-11-28 22:36:08 -080026#include <linux/memblock.h>
Erik Gillingc5f80062010-01-21 16:53:02 -080027
28#include <asm/hardware/cache-l2x0.h>
Dima Zavin7e158ac2010-11-11 15:28:46 -080029#include <asm/system.h>
Erik Gillingc5f80062010-01-21 16:53:02 -080030
Colin Cross45a1ca02011-03-28 17:47:31 -070031#include <mach/gpio.h>
Erik Gillingc5f80062010-01-21 16:53:02 -080032#include <mach/iomap.h>
Colin Cross120c3562011-03-28 17:48:56 -070033#include <mach/pinmux.h>
Dima Zavin7db7cbc2010-09-16 17:58:05 -070034#include <mach/powergate.h>
Colin Cross699fe142010-08-23 18:37:25 -070035#include <mach/system.h>
Erik Gillingc5f80062010-01-21 16:53:02 -080036
Jon Mayo6ae77a92010-12-21 15:09:33 -080037#include "apbio.h"
Erik Gillingc5f80062010-01-21 16:53:02 -080038#include "board.h"
Colin Crossd8611962010-01-28 16:40:29 -080039#include "clock.h"
Colin Cross73625e32010-06-23 15:49:17 -070040#include "fuse.h"
Colin Cross8e437c22010-11-28 22:36:08 -080041#include "pm.h"
42
Scott Williams816ab052010-12-07 11:19:20 -080043#define MC_SECURITY_CFG2 0x7c
Colin Crossf9c9bde2010-10-19 16:12:33 -070044
Colin Cross838d7d62010-10-19 14:45:50 -070045unsigned long tegra_bootloader_fb_start;
46unsigned long tegra_bootloader_fb_size;
47unsigned long tegra_fb_start;
48unsigned long tegra_fb_size;
49unsigned long tegra_fb2_start;
50unsigned long tegra_fb2_size;
51unsigned long tegra_carveout_start;
52unsigned long tegra_carveout_size;
Colin Cross8e437c22010-11-28 22:36:08 -080053unsigned long tegra_lp0_vec_start;
54unsigned long tegra_lp0_vec_size;
Scott Williams03122532011-01-13 14:30:20 -080055unsigned long tegra_grhost_aperture = ~0ul;
Pradeep Goudagunta3dd04c42011-03-23 23:16:12 +053056static bool is_tegra_debug_uart_hsport;
Colin Crossd8611962010-01-28 16:40:29 -080057
Colin Cross699fe142010-08-23 18:37:25 -070058void (*arch_reset)(char mode, const char *cmd) = tegra_assert_system_reset;
59
60void tegra_assert_system_reset(char mode, const char *cmd)
61{
Deepesh Gujarathi43921782010-12-07 14:09:22 +053062 void __iomem *reset = IO_ADDRESS(TEGRA_PMC_BASE + 0x00);
Colin Cross699fe142010-08-23 18:37:25 -070063 u32 reg;
64
Simon Glass375b19c2011-02-17 08:13:57 -080065 /* use *_related to avoid spinlock since caches are off */
66 reg = readl_relaxed(reset);
Deepesh Gujarathi43921782010-12-07 14:09:22 +053067 reg |= 0x10;
Simon Glass375b19c2011-02-17 08:13:57 -080068 writel_relaxed(reg, reset);
Colin Cross699fe142010-08-23 18:37:25 -070069}
70
Nitin Kumbhar637ced42010-12-10 15:16:37 +053071static 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
Colin Crossd8611962010-01-28 16:40:29 -080079static __initdata struct tegra_clk_init_table common_clk_init_table[] = {
80 /* name parent rate enabled */
81 { "clk_m", NULL, 0, true },
Scott Williams816ab052010-12-07 11:19:20 -080082 { "pll_p", NULL, 216000000, true },
Colin Crossd8611962010-01-28 16:40:29 -080083 { "pll_p_out1", "pll_p", 28800000, true },
84 { "pll_p_out2", "pll_p", 48000000, true },
85 { "pll_p_out3", "pll_p", 72000000, true },
86 { "pll_p_out4", "pll_p", 108000000, true },
Alex Frid8b5ce662011-01-31 10:07:57 -080087#ifdef CONFIG_ARCH_TEGRA_3x_SOC
88 { "pll_m_out1", "pll_m", 275000000, true },
89 { "sclk", "pll_m_out1", 275000000, true },
90 { "hclk", "sclk", 275000000, true },
91 { "pclk", "hclk", 70000000, true },
92#else
Colin Cross170b2642010-11-03 11:42:20 -070093 { "pll_m_out1", "pll_m", 120000000, true },
94 { "sclk", "pll_m_out1", 120000000, true },
95 { "hclk", "sclk", 120000000, true },
96 { "pclk", "hclk", 60000000, true },
Alex Frid8b5ce662011-01-31 10:07:57 -080097#endif
Colin Crosscd51d0e2011-02-21 17:05:36 -080098 { "csite", NULL, 0, true },
99 { "emc", NULL, 0, true },
100 { "cpu", NULL, 0, true },
Jon Mayoa51a72a12011-01-05 11:17:30 -0800101 { "kfuse", NULL, 0, true },
Scott Williams816ab052010-12-07 11:19:20 -0800102 { "pll_u", NULL, 480000000, false },
Pavan Kunapulid75820e2011-01-28 19:17:33 -0800103 { "sdmmc1", "clk_m", 12000000, true},
Todd Poynor433cb7f2010-09-02 15:10:29 -0700104 { "sdmmc2", "pll_p", 48000000, false},
105 { "sdmmc3", "pll_p", 48000000, false},
Pavan Kunapuli18e8afc2011-01-26 11:14:53 -0800106 { "sdmmc4", "clk_m", 12000000, true},
Colin Crossd8611962010-01-28 16:40:29 -0800107 { NULL, NULL, 0, 0},
108};
Erik Gillingc5f80062010-01-21 16:53:02 -0800109
Colin Cross8e437c22010-11-28 22:36:08 -0800110void tegra_init_cache(void)
Erik Gillingc5f80062010-01-21 16:53:02 -0800111{
112#ifdef CONFIG_CACHE_L2X0
113 void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
Scott Williams191914c2010-12-27 19:03:57 -0800114 u32 aux_ctrl;
Erik Gillingc5f80062010-01-21 16:53:02 -0800115
Scott Williams816ab052010-12-07 11:19:20 -0800116#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
Colin Cross535371c2011-01-22 00:36:14 -0800117 writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
118 writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
Erik Gillingc5f80062010-01-21 16:53:02 -0800119
Scott Williams816ab052010-12-07 11:19:20 -0800120#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
121#ifdef CONFIG_TEGRA_FPGA_PLATFORM
122 writel(0x770, p + L2X0_TAG_LATENCY_CTRL);
123 writel(0x770, p + L2X0_DATA_LATENCY_CTRL);
Scott Williams816ab052010-12-07 11:19:20 -0800124#else
Scott Williams1245c8e2011-01-05 17:53:39 -0800125 /* PL310 RAM latency is CPU dependent. NOTE: Changes here
126 must also be reflected in __cortex_a9_l2x0_restart */
127
128 if (is_lp_cluster()) {
129 writel(0x221, p + L2X0_TAG_LATENCY_CTRL);
130 writel(0x221, p + L2X0_DATA_LATENCY_CTRL);
131 } else {
132 writel(0x331, p + L2X0_TAG_LATENCY_CTRL);
133 writel(0x441, p + L2X0_DATA_LATENCY_CTRL);
134 }
Scott Williams816ab052010-12-07 11:19:20 -0800135#endif
136
137 /* Enable PL310 double line fill feature. */
138 writel(((1<<30) | 7), p + L2X0_PREFETCH_CTRL);
139#endif
Scott Williams191914c2010-12-27 19:03:57 -0800140 aux_ctrl = readl(p + L2X0_CACHE_TYPE);
141 aux_ctrl = (aux_ctrl & 0x700) << (17-8);
142 aux_ctrl |= 0x6C000001;
143 l2x0_init(p, aux_ctrl, 0x8200c3fe);
Erik Gillingc5f80062010-01-21 16:53:02 -0800144#endif
145}
146
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700147static void __init tegra_init_power(void)
148{
149 tegra_powergate_power_off(TEGRA_POWERGATE_MPE);
150 tegra_powergate_power_off(TEGRA_POWERGATE_3D);
Roger Hsiehac108442011-03-21 16:51:36 +0800151 tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700152}
153
Dima Zavin7e158ac2010-11-11 15:28:46 -0800154static bool console_flushed;
155
156static void tegra_pm_flush_console(void)
157{
158 if (console_flushed)
159 return;
160 console_flushed = true;
161
162 printk("\n");
163 pr_emerg("Restarting %s\n", linux_banner);
Colin Crossfec84b22011-04-07 14:40:23 -0700164 if (console_trylock()) {
165 console_unlock();
Dima Zavin7e158ac2010-11-11 15:28:46 -0800166 return;
167 }
168
169 mdelay(50);
170
171 local_irq_disable();
Colin Crossfec84b22011-04-07 14:40:23 -0700172 if (!console_trylock())
Dima Zavin7e158ac2010-11-11 15:28:46 -0800173 pr_emerg("tegra_restart: Console was locked! Busting\n");
174 else
175 pr_emerg("tegra_restart: Console was locked!\n");
Colin Crossfec84b22011-04-07 14:40:23 -0700176 console_unlock();
Dima Zavin7e158ac2010-11-11 15:28:46 -0800177}
178
179static void tegra_pm_restart(char mode, const char *cmd)
180{
181 tegra_pm_flush_console();
182 arm_machine_restart(mode, cmd);
183}
184
Colin Cross0cf62302011-02-21 17:10:14 -0800185void __init tegra_init_early(void)
Erik Gillingc5f80062010-01-21 16:53:02 -0800186{
Dima Zavin7e158ac2010-11-11 15:28:46 -0800187 arm_pm_restart = tegra_pm_restart;
Colin Cross73625e32010-06-23 15:49:17 -0700188 tegra_init_fuse();
Colin Cross45a1ca02011-03-28 17:47:31 -0700189 tegra_gpio_resume_init();
Colin Crossd8611962010-01-28 16:40:29 -0800190 tegra_init_clock();
Colin Cross120c3562011-03-28 17:48:56 -0700191 tegra_init_pinmux();
Colin Crossd8611962010-01-28 16:40:29 -0800192 tegra_clk_init_from_table(common_clk_init_table);
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700193 tegra_init_power();
Erik Gillingc5f80062010-01-21 16:53:02 -0800194 tegra_init_cache();
Hiro Sugawarac00e4312011-01-19 13:57:30 -0800195#ifndef CONFIG_ARCH_TEGRA_2x_SOC
196 tegra_mc_init(); /* !!!FIXME!!! Change Tegra3 behavior to match Tegra2 */
197#endif
Erik Gillingc5f80062010-01-21 16:53:02 -0800198}
Colin Cross8e437c22010-11-28 22:36:08 -0800199
200static int __init tegra_lp0_vec_arg(char *options)
201{
202 char *p = options;
203
204 tegra_lp0_vec_size = memparse(p, &p);
205 if (*p == '@')
206 tegra_lp0_vec_start = memparse(p+1, &p);
Scott Williams03122532011-01-13 14:30:20 -0800207 if (!tegra_lp0_vec_size || !tegra_lp0_vec_start) {
208 tegra_lp0_vec_size = 0;
209 tegra_lp0_vec_start = 0;
210 }
Colin Cross8e437c22010-11-28 22:36:08 -0800211
212 return 0;
213}
214early_param("lp0_vec", tegra_lp0_vec_arg);
215
Colin Cross838d7d62010-10-19 14:45:50 -0700216static int __init tegra_bootloader_fb_arg(char *options)
217{
218 char *p = options;
Scott Williams03122532011-01-13 14:30:20 -0800219 unsigned long start;
220 unsigned long size;
Colin Cross838d7d62010-10-19 14:45:50 -0700221
222 tegra_bootloader_fb_size = memparse(p, &p);
223 if (*p == '@')
224 tegra_bootloader_fb_start = memparse(p+1, &p);
225
226 pr_info("Found tegra_fbmem: %08lx@%08lx\n",
227 tegra_bootloader_fb_size, tegra_bootloader_fb_start);
228
229 return 0;
230}
231early_param("tegra_fbmem", tegra_bootloader_fb_arg);
232
Nitin Kumbhar637ced42010-12-10 15:16:37 +0530233static int __init tegra_board_info_parse(char *info)
234{
235 char *p;
236 int pos = 0;
237 struct board_info *bi = &tegra_board_info;
238
239 while (info && *info) {
240 if ((p = strchr(info, ':')))
241 *p++ = '\0';
242
243 if (strlen(info) > 0) {
244 switch(pos) {
245 case 0:
246 bi->board_id = simple_strtol(info, NULL, 16);
247 break;
248 case 1:
249 bi->sku = simple_strtol(info, NULL, 16);
250 break;
251 case 2:
252 bi->fab = simple_strtol(info, NULL, 16);
253 break;
254 case 3:
255 bi->major_revision = simple_strtol(info, NULL, 16);
256 break;
257 case 4:
258 bi->minor_revision = simple_strtol(info, NULL, 16);
259 break;
260 default:
261 break;
262 }
263 }
264
265 info = p;
266 pos++;
267 }
268
269 pr_info("board info: Id:%d%2d SKU:%d Fab:%d Rev:%c MinRev:%d\n",
270 bi->board_id >> 8 & 0xFF, bi->board_id & 0xFF,
271 bi->sku, bi->fab, bi->major_revision, bi->minor_revision);
272
273 return 1;
274}
275
276__setup("board_info=", tegra_board_info_parse);
277
Pradeep Goudagunta3dd04c42011-03-23 23:16:12 +0530278static int __init tegra_debug_uartport(char *info)
279{
280 if (!strcmp(info, "hsport"))
281 is_tegra_debug_uart_hsport = true;
282 else if (!strcmp(info, "lsport"))
283 is_tegra_debug_uart_hsport = false;
284
285 return 1;
286}
287
288bool is_tegra_debug_uartport_hs(void)
289{
290 return is_tegra_debug_uart_hsport;
291}
292
293__setup("debug_uartport=", tegra_debug_uartport);
294
Nitin Kumbhar637ced42010-12-10 15:16:37 +0530295void tegra_get_board_info(struct board_info *bi)
296{
297 memcpy(bi, &tegra_board_info, sizeof(*bi));
298}
299
Colin Crossf9c9bde2010-10-19 16:12:33 -0700300/*
301 * Tegra has a protected aperture that prevents access by most non-CPU
302 * memory masters to addresses above the aperture value. Enabling it
303 * secures the CPU's memory from the GPU, except through the GART.
304 */
305void __init tegra_protected_aperture_init(unsigned long aperture)
306{
307#ifndef CONFIG_NVMAP_ALLOW_SYSMEM
308 void __iomem *mc_base = IO_ADDRESS(TEGRA_MC_BASE);
309 pr_info("Enabling Tegra protected aperture at 0x%08lx\n", aperture);
310 writel(aperture, mc_base + MC_SECURITY_CFG2);
311#else
312 pr_err("Tegra protected aperture disabled because nvmap is using "
313 "system memory\n");
314#endif
315}
316
Colin Cross115467a2010-10-19 21:09:29 -0700317/*
318 * Due to conflicting restrictions on the placement of the framebuffer,
319 * the bootloader is likely to leave the framebuffer pointed at a location
320 * in memory that is outside the grhost aperture. This function will move
321 * the framebuffer contents from a physical address that is anywher (lowmem,
322 * highmem, or outside the memory map) to a physical address that is outside
323 * the memory map.
324 */
325void tegra_move_framebuffer(unsigned long to, unsigned long from,
326 unsigned long size)
327{
328 struct page *page;
329 void __iomem *to_io;
330 void *from_virt;
331 unsigned long i;
332
333 BUG_ON(PAGE_ALIGN((unsigned long)to) != (unsigned long)to);
334 BUG_ON(PAGE_ALIGN(from) != from);
335 BUG_ON(PAGE_ALIGN(size) != size);
336
337 to_io = ioremap(to, size);
338 if (!to_io) {
339 pr_err("%s: Failed to map target framebuffer\n", __func__);
340 return;
341 }
342
Colin Cross115467a2010-10-19 21:09:29 -0700343 if (pfn_valid(page_to_pfn(phys_to_page(from)))) {
344 for (i = 0 ; i < size; i += PAGE_SIZE) {
345 page = phys_to_page(from + i);
346 from_virt = kmap(page);
347 memcpy_toio(to_io + i, from_virt, PAGE_SIZE);
348 kunmap(page);
349 }
350 } else {
351 void __iomem *from_io = ioremap(from, size);
352 if (!from_io) {
353 pr_err("%s: Failed to map source framebuffer\n",
354 __func__);
355 goto out;
356 }
357
358 for (i = 0; i < size; i+= 4)
359 writel(readl(from_io + i), to_io + i);
360
361 iounmap(from_io);
362 }
363out:
364 iounmap(to_io);
365}
366
Colin Cross838d7d62010-10-19 14:45:50 -0700367void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
368 unsigned long fb2_size)
369{
370 if (tegra_lp0_vec_size)
Scott Williams03122532011-01-13 14:30:20 -0800371 if (memblock_reserve(tegra_lp0_vec_start, tegra_lp0_vec_size)) {
Colin Cross838d7d62010-10-19 14:45:50 -0700372 pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
373 tegra_lp0_vec_size, tegra_lp0_vec_start);
Scott Williams03122532011-01-13 14:30:20 -0800374 tegra_lp0_vec_start = 0;
375 tegra_lp0_vec_size = 0;
376 }
Colin Cross838d7d62010-10-19 14:45:50 -0700377
Scott Williams03122532011-01-13 14:30:20 -0800378 if (carveout_size) {
379 tegra_carveout_start = memblock_end_of_DRAM() - carveout_size;
380 if (memblock_remove(tegra_carveout_start, carveout_size)) {
381 pr_err("Failed to remove carveout %08lx@%08lx "
382 "from memory map\n",
383 tegra_carveout_start, carveout_size);
384 tegra_carveout_start = 0;
385 tegra_carveout_size = 0;
386 }
387 else
388 tegra_carveout_size = carveout_size;
389 }
Colin Cross838d7d62010-10-19 14:45:50 -0700390
Scott Williams03122532011-01-13 14:30:20 -0800391 if (fb2_size) {
392 tegra_fb2_start = memblock_end_of_DRAM() - fb2_size;
393 if (memblock_remove(tegra_fb2_start, fb2_size)) {
394 pr_err("Failed to remove second framebuffer %08lx@%08lx "
395 "from memory map\n",
396 tegra_fb2_start, fb2_size);
397 tegra_fb2_start = 0;
398 tegra_fb2_size = 0;
399 } else
400 tegra_fb2_size = fb2_size;
401 }
Colin Cross838d7d62010-10-19 14:45:50 -0700402
Scott Williams03122532011-01-13 14:30:20 -0800403 if (fb_size) {
404 tegra_fb_start = memblock_end_of_DRAM() - fb_size;
405 if (memblock_remove(tegra_fb_start, fb_size)) {
406 pr_err("Failed to remove framebuffer %08lx@%08lx "
407 "from memory map\n",
408 tegra_fb_start, fb_size);
409 tegra_fb_start = 0;
410 tegra_fb_size = 0;
411 } else
412 tegra_fb_size = fb_size;
413 }
Colin Cross838d7d62010-10-19 14:45:50 -0700414
Colin Crossf9c9bde2010-10-19 16:12:33 -0700415 if (tegra_fb_size)
416 tegra_grhost_aperture = tegra_fb_start;
417
418 if (tegra_fb2_size && tegra_fb2_start < tegra_grhost_aperture)
419 tegra_grhost_aperture = tegra_fb2_start;
420
421 if (tegra_carveout_size && tegra_carveout_start < tegra_grhost_aperture)
422 tegra_grhost_aperture = tegra_carveout_start;
423
Colin Cross838d7d62010-10-19 14:45:50 -0700424 /*
425 * TODO: We should copy the bootloader's framebuffer to the framebuffer
426 * allocated above, and then free this one.
427 */
428 if (tegra_bootloader_fb_size)
429 if (memblock_reserve(tegra_bootloader_fb_start,
Scott Williams03122532011-01-13 14:30:20 -0800430 tegra_bootloader_fb_size)) {
431 pr_err("Failed to reserve bootloader frame buffer %08lx@%08lx\n",
432 tegra_bootloader_fb_size, tegra_bootloader_fb_start);
433 tegra_bootloader_fb_start = 0;
434 tegra_bootloader_fb_size = 0;
435 }
Colin Cross838d7d62010-10-19 14:45:50 -0700436
437 pr_info("Tegra reserved memory:\n"
438 "LP0: %08lx - %08lx\n"
439 "Bootloader framebuffer: %08lx - %08lx\n"
440 "Framebuffer: %08lx - %08lx\n"
Scott Williams22d51692011-01-11 10:50:52 -0800441 "2nd Framebuffer: %08lx - %08lx\n"
Colin Cross838d7d62010-10-19 14:45:50 -0700442 "Carveout: %08lx - %08lx\n",
443 tegra_lp0_vec_start,
Scott Williams03122532011-01-13 14:30:20 -0800444 tegra_lp0_vec_size ?
445 tegra_lp0_vec_start + tegra_lp0_vec_size - 1 : 0,
Colin Cross838d7d62010-10-19 14:45:50 -0700446 tegra_bootloader_fb_start,
Scott Williams03122532011-01-13 14:30:20 -0800447 tegra_bootloader_fb_size ?
448 tegra_bootloader_fb_start + tegra_bootloader_fb_size - 1 : 0,
Colin Cross838d7d62010-10-19 14:45:50 -0700449 tegra_fb_start,
Scott Williams03122532011-01-13 14:30:20 -0800450 tegra_fb_size ?
451 tegra_fb_start + tegra_fb_size - 1 : 0,
Colin Cross838d7d62010-10-19 14:45:50 -0700452 tegra_fb2_start,
Scott Williams03122532011-01-13 14:30:20 -0800453 tegra_fb2_size ?
454 tegra_fb2_start + tegra_fb2_size - 1 : 0,
Colin Cross838d7d62010-10-19 14:45:50 -0700455 tegra_carveout_start,
Scott Williams03122532011-01-13 14:30:20 -0800456 tegra_carveout_size ?
457 tegra_carveout_start + tegra_carveout_size - 1 : 0);
Colin Cross838d7d62010-10-19 14:45:50 -0700458}