blob: de994b2d5e4f40be196effbb02148c0e2a64430a [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;
Colin Crossf9c9bde2010-10-19 16:12:33 -070055unsigned long tegra_grhost_aperture;
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 },
Tom Cherry15933782010-12-21 18:03:06 -080082 { "pll_m", "clk_m", 600000000, true },
Scott Williams816ab052010-12-07 11:19:20 -080083 { "pll_p", NULL, 216000000, true },
Colin Crossd8611962010-01-28 16:40:29 -080084 { "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 },
Colin Cross170b2642010-11-03 11:42:20 -070088 { "pll_m_out1", "pll_m", 120000000, true },
89 { "sclk", "pll_m_out1", 120000000, true },
90 { "hclk", "sclk", 120000000, true },
91 { "pclk", "hclk", 60000000, true },
Colin Crosscd51d0e2011-02-21 17:05:36 -080092 { "csite", NULL, 0, true },
93 { "emc", NULL, 0, true },
94 { "cpu", NULL, 0, true },
Jon Mayoa51a72a12011-01-05 11:17:30 -080095 { "kfuse", NULL, 0, true },
Scott Williams816ab052010-12-07 11:19:20 -080096 { "pll_u", NULL, 480000000, false },
Todd Poynor433cb7f2010-09-02 15:10:29 -070097 { "sdmmc1", "pll_p", 48000000, false},
98 { "sdmmc2", "pll_p", 48000000, false},
99 { "sdmmc3", "pll_p", 48000000, false},
100 { "sdmmc4", "pll_p", 48000000, false},
Colin Crossd8611962010-01-28 16:40:29 -0800101 { NULL, NULL, 0, 0},
102};
Erik Gillingc5f80062010-01-21 16:53:02 -0800103
Colin Cross8e437c22010-11-28 22:36:08 -0800104void tegra_init_cache(void)
Erik Gillingc5f80062010-01-21 16:53:02 -0800105{
106#ifdef CONFIG_CACHE_L2X0
107 void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
Scott Williams191914c2010-12-27 19:03:57 -0800108 u32 aux_ctrl;
Erik Gillingc5f80062010-01-21 16:53:02 -0800109
Scott Williams816ab052010-12-07 11:19:20 -0800110#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
Colin Cross535371c2011-01-22 00:36:14 -0800111 writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
112 writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
Erik Gillingc5f80062010-01-21 16:53:02 -0800113
Scott Williams816ab052010-12-07 11:19:20 -0800114#elif defined(CONFIG_ARCH_TEGRA_3x_SOC)
115#ifdef CONFIG_TEGRA_FPGA_PLATFORM
116 writel(0x770, p + L2X0_TAG_LATENCY_CTRL);
117 writel(0x770, p + L2X0_DATA_LATENCY_CTRL);
Scott Williams816ab052010-12-07 11:19:20 -0800118#else
Scott Williams1245c8e2011-01-05 17:53:39 -0800119 /* PL310 RAM latency is CPU dependent. NOTE: Changes here
120 must also be reflected in __cortex_a9_l2x0_restart */
121
122 if (is_lp_cluster()) {
123 writel(0x221, p + L2X0_TAG_LATENCY_CTRL);
124 writel(0x221, p + L2X0_DATA_LATENCY_CTRL);
125 } else {
126 writel(0x331, p + L2X0_TAG_LATENCY_CTRL);
127 writel(0x441, p + L2X0_DATA_LATENCY_CTRL);
128 }
Scott Williams816ab052010-12-07 11:19:20 -0800129#endif
130
131 /* Enable PL310 double line fill feature. */
132 writel(((1<<30) | 7), p + L2X0_PREFETCH_CTRL);
133#endif
Scott Williams191914c2010-12-27 19:03:57 -0800134 aux_ctrl = readl(p + L2X0_CACHE_TYPE);
135 aux_ctrl = (aux_ctrl & 0x700) << (17-8);
136 aux_ctrl |= 0x6C000001;
137 l2x0_init(p, aux_ctrl, 0x8200c3fe);
Erik Gillingc5f80062010-01-21 16:53:02 -0800138#endif
139}
140
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700141static void __init tegra_init_power(void)
142{
143 tegra_powergate_power_off(TEGRA_POWERGATE_MPE);
144 tegra_powergate_power_off(TEGRA_POWERGATE_3D);
Roger Hsiehac108442011-03-21 16:51:36 +0800145 tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700146}
147
Dima Zavin7e158ac2010-11-11 15:28:46 -0800148static bool console_flushed;
149
150static void tegra_pm_flush_console(void)
151{
152 if (console_flushed)
153 return;
154 console_flushed = true;
155
156 printk("\n");
157 pr_emerg("Restarting %s\n", linux_banner);
Colin Crossfec84b22011-04-07 14:40:23 -0700158 if (console_trylock()) {
159 console_unlock();
Dima Zavin7e158ac2010-11-11 15:28:46 -0800160 return;
161 }
162
163 mdelay(50);
164
165 local_irq_disable();
Colin Crossfec84b22011-04-07 14:40:23 -0700166 if (!console_trylock())
Dima Zavin7e158ac2010-11-11 15:28:46 -0800167 pr_emerg("tegra_restart: Console was locked! Busting\n");
168 else
169 pr_emerg("tegra_restart: Console was locked!\n");
Colin Crossfec84b22011-04-07 14:40:23 -0700170 console_unlock();
Dima Zavin7e158ac2010-11-11 15:28:46 -0800171}
172
173static void tegra_pm_restart(char mode, const char *cmd)
174{
175 tegra_pm_flush_console();
176 arm_machine_restart(mode, cmd);
177}
178
Colin Cross0cf62302011-02-21 17:10:14 -0800179void __init tegra_init_early(void)
Erik Gillingc5f80062010-01-21 16:53:02 -0800180{
Dima Zavin7e158ac2010-11-11 15:28:46 -0800181 arm_pm_restart = tegra_pm_restart;
Colin Cross73625e32010-06-23 15:49:17 -0700182 tegra_init_fuse();
Colin Cross45a1ca02011-03-28 17:47:31 -0700183 tegra_gpio_resume_init();
Colin Crossd8611962010-01-28 16:40:29 -0800184 tegra_init_clock();
Colin Cross120c3562011-03-28 17:48:56 -0700185 tegra_init_pinmux();
Colin Crossd8611962010-01-28 16:40:29 -0800186 tegra_clk_init_from_table(common_clk_init_table);
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700187 tegra_init_power();
Erik Gillingc5f80062010-01-21 16:53:02 -0800188 tegra_init_cache();
Erik Gillingc5f80062010-01-21 16:53:02 -0800189}
Colin Cross8e437c22010-11-28 22:36:08 -0800190
191static int __init tegra_lp0_vec_arg(char *options)
192{
193 char *p = options;
194
195 tegra_lp0_vec_size = memparse(p, &p);
196 if (*p == '@')
197 tegra_lp0_vec_start = memparse(p+1, &p);
198
199 return 0;
200}
201early_param("lp0_vec", tegra_lp0_vec_arg);
202
Colin Cross838d7d62010-10-19 14:45:50 -0700203static int __init tegra_bootloader_fb_arg(char *options)
204{
205 char *p = options;
206
207 tegra_bootloader_fb_size = memparse(p, &p);
208 if (*p == '@')
209 tegra_bootloader_fb_start = memparse(p+1, &p);
210
211 pr_info("Found tegra_fbmem: %08lx@%08lx\n",
212 tegra_bootloader_fb_size, tegra_bootloader_fb_start);
213
214 return 0;
215}
216early_param("tegra_fbmem", tegra_bootloader_fb_arg);
217
Nitin Kumbhar637ced42010-12-10 15:16:37 +0530218static int __init tegra_board_info_parse(char *info)
219{
220 char *p;
221 int pos = 0;
222 struct board_info *bi = &tegra_board_info;
223
224 while (info && *info) {
225 if ((p = strchr(info, ':')))
226 *p++ = '\0';
227
228 if (strlen(info) > 0) {
229 switch(pos) {
230 case 0:
231 bi->board_id = simple_strtol(info, NULL, 16);
232 break;
233 case 1:
234 bi->sku = simple_strtol(info, NULL, 16);
235 break;
236 case 2:
237 bi->fab = simple_strtol(info, NULL, 16);
238 break;
239 case 3:
240 bi->major_revision = simple_strtol(info, NULL, 16);
241 break;
242 case 4:
243 bi->minor_revision = simple_strtol(info, NULL, 16);
244 break;
245 default:
246 break;
247 }
248 }
249
250 info = p;
251 pos++;
252 }
253
254 pr_info("board info: Id:%d%2d SKU:%d Fab:%d Rev:%c MinRev:%d\n",
255 bi->board_id >> 8 & 0xFF, bi->board_id & 0xFF,
256 bi->sku, bi->fab, bi->major_revision, bi->minor_revision);
257
258 return 1;
259}
260
261__setup("board_info=", tegra_board_info_parse);
262
Pradeep Goudagunta3dd04c42011-03-23 23:16:12 +0530263static int __init tegra_debug_uartport(char *info)
264{
265 if (!strcmp(info, "hsport"))
266 is_tegra_debug_uart_hsport = true;
267 else if (!strcmp(info, "lsport"))
268 is_tegra_debug_uart_hsport = false;
269
270 return 1;
271}
272
273bool is_tegra_debug_uartport_hs(void)
274{
275 return is_tegra_debug_uart_hsport;
276}
277
278__setup("debug_uartport=", tegra_debug_uartport);
279
Nitin Kumbhar637ced42010-12-10 15:16:37 +0530280void tegra_get_board_info(struct board_info *bi)
281{
282 memcpy(bi, &tegra_board_info, sizeof(*bi));
283}
284
Colin Crossf9c9bde2010-10-19 16:12:33 -0700285/*
286 * Tegra has a protected aperture that prevents access by most non-CPU
287 * memory masters to addresses above the aperture value. Enabling it
288 * secures the CPU's memory from the GPU, except through the GART.
289 */
290void __init tegra_protected_aperture_init(unsigned long aperture)
291{
292#ifndef CONFIG_NVMAP_ALLOW_SYSMEM
293 void __iomem *mc_base = IO_ADDRESS(TEGRA_MC_BASE);
294 pr_info("Enabling Tegra protected aperture at 0x%08lx\n", aperture);
295 writel(aperture, mc_base + MC_SECURITY_CFG2);
296#else
297 pr_err("Tegra protected aperture disabled because nvmap is using "
298 "system memory\n");
299#endif
300}
301
Colin Cross115467a2010-10-19 21:09:29 -0700302/*
303 * Due to conflicting restrictions on the placement of the framebuffer,
304 * the bootloader is likely to leave the framebuffer pointed at a location
305 * in memory that is outside the grhost aperture. This function will move
306 * the framebuffer contents from a physical address that is anywher (lowmem,
307 * highmem, or outside the memory map) to a physical address that is outside
308 * the memory map.
309 */
310void tegra_move_framebuffer(unsigned long to, unsigned long from,
311 unsigned long size)
312{
313 struct page *page;
314 void __iomem *to_io;
315 void *from_virt;
316 unsigned long i;
317
318 BUG_ON(PAGE_ALIGN((unsigned long)to) != (unsigned long)to);
319 BUG_ON(PAGE_ALIGN(from) != from);
320 BUG_ON(PAGE_ALIGN(size) != size);
321
322 to_io = ioremap(to, size);
323 if (!to_io) {
324 pr_err("%s: Failed to map target framebuffer\n", __func__);
325 return;
326 }
327
Colin Cross115467a2010-10-19 21:09:29 -0700328 if (pfn_valid(page_to_pfn(phys_to_page(from)))) {
329 for (i = 0 ; i < size; i += PAGE_SIZE) {
330 page = phys_to_page(from + i);
331 from_virt = kmap(page);
332 memcpy_toio(to_io + i, from_virt, PAGE_SIZE);
333 kunmap(page);
334 }
335 } else {
336 void __iomem *from_io = ioremap(from, size);
337 if (!from_io) {
338 pr_err("%s: Failed to map source framebuffer\n",
339 __func__);
340 goto out;
341 }
342
343 for (i = 0; i < size; i+= 4)
344 writel(readl(from_io + i), to_io + i);
345
346 iounmap(from_io);
347 }
348out:
349 iounmap(to_io);
350}
351
Colin Cross838d7d62010-10-19 14:45:50 -0700352void __init tegra_reserve(unsigned long carveout_size, unsigned long fb_size,
353 unsigned long fb2_size)
354{
355 if (tegra_lp0_vec_size)
356 if (memblock_reserve(tegra_lp0_vec_start, tegra_lp0_vec_size))
357 pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
358 tegra_lp0_vec_size, tegra_lp0_vec_start);
359
360
361 tegra_carveout_start = memblock_end_of_DRAM() - carveout_size;
362 if (memblock_remove(tegra_carveout_start, carveout_size))
363 pr_err("Failed to remove carveout %08lx@%08lx from memory "
364 "map\n",
365 tegra_carveout_start, carveout_size);
366 else
367 tegra_carveout_size = carveout_size;
368
369 tegra_fb2_start = memblock_end_of_DRAM() - fb2_size;
370 if (memblock_remove(tegra_fb2_start, fb2_size))
371 pr_err("Failed to remove second framebuffer %08lx@%08lx from "
372 "memory map\n",
373 tegra_fb2_start, fb2_size);
374 else
375 tegra_fb2_size = fb2_size;
376
377 tegra_fb_start = memblock_end_of_DRAM() - fb_size;
378 if (memblock_remove(tegra_fb_start, fb_size))
379 pr_err("Failed to remove framebuffer %08lx@%08lx from memory "
380 "map\n",
381 tegra_fb_start, fb_size);
382 else
383 tegra_fb_size = fb_size;
384
Colin Crossf9c9bde2010-10-19 16:12:33 -0700385 if (tegra_fb_size)
386 tegra_grhost_aperture = tegra_fb_start;
387
388 if (tegra_fb2_size && tegra_fb2_start < tegra_grhost_aperture)
389 tegra_grhost_aperture = tegra_fb2_start;
390
391 if (tegra_carveout_size && tegra_carveout_start < tegra_grhost_aperture)
392 tegra_grhost_aperture = tegra_carveout_start;
393
Colin Cross838d7d62010-10-19 14:45:50 -0700394 /*
395 * TODO: We should copy the bootloader's framebuffer to the framebuffer
396 * allocated above, and then free this one.
397 */
398 if (tegra_bootloader_fb_size)
399 if (memblock_reserve(tegra_bootloader_fb_start,
400 tegra_bootloader_fb_size))
401 pr_err("Failed to reserve lp0_vec %08lx@%08lx\n",
402 tegra_lp0_vec_size, tegra_lp0_vec_start);
403
404 pr_info("Tegra reserved memory:\n"
405 "LP0: %08lx - %08lx\n"
406 "Bootloader framebuffer: %08lx - %08lx\n"
407 "Framebuffer: %08lx - %08lx\n"
Scott Williams22d51692011-01-11 10:50:52 -0800408 "2nd Framebuffer: %08lx - %08lx\n"
Colin Cross838d7d62010-10-19 14:45:50 -0700409 "Carveout: %08lx - %08lx\n",
410 tegra_lp0_vec_start,
411 tegra_lp0_vec_start + tegra_lp0_vec_size - 1,
412 tegra_bootloader_fb_start,
413 tegra_bootloader_fb_start + tegra_bootloader_fb_size - 1,
414 tegra_fb_start,
415 tegra_fb_start + tegra_fb_size - 1,
416 tegra_fb2_start,
417 tegra_fb2_start + tegra_fb2_size - 1,
418 tegra_carveout_start,
419 tegra_carveout_start + tegra_carveout_size - 1);
420}