blob: 13a626c05b2531e2b002b3eaefc127599b767530 [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
Colin Crossf9c9bde2010-10-19 16:12:33 -070043#define MC_SECURITY_CFG2 0x7c
44
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;
Colin Crossd8611962010-01-28 16:40:29 -080056
Colin Cross699fe142010-08-23 18:37:25 -070057void (*arch_reset)(char mode, const char *cmd) = tegra_assert_system_reset;
58
59void 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
Simon Glass375b19c2011-02-17 08:13:57 -080064 /* use *_related to avoid spinlock since caches are off */
65 reg = readl_relaxed(reset);
Colin Cross699fe142010-08-23 18:37:25 -070066 reg |= 0x04;
Simon Glass375b19c2011-02-17 08:13:57 -080067 writel_relaxed(reg, reset);
Colin Cross699fe142010-08-23 18:37:25 -070068}
69
Colin Crossd8611962010-01-28 16:40:29 -080070static __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 },
Colin Cross170b2642010-11-03 11:42:20 -070078 { "pll_m_out1", "pll_m", 120000000, true },
79 { "sclk", "pll_m_out1", 120000000, true },
80 { "hclk", "sclk", 120000000, true },
81 { "pclk", "hclk", 60000000, true },
Colin Crosscd51d0e2011-02-21 17:05:36 -080082 { "csite", NULL, 0, true },
83 { "emc", NULL, 0, true },
84 { "cpu", NULL, 0, true },
Jon Mayoa51a72a12011-01-05 11:17:30 -080085 { "kfuse", NULL, 0, true },
Benoit Goby73f00712010-08-02 20:18:11 -070086 { "pll_u", "clk_m", 480000000, false },
Todd Poynor433cb7f2010-09-02 15:10:29 -070087 { "sdmmc1", "pll_p", 48000000, false},
88 { "sdmmc2", "pll_p", 48000000, false},
89 { "sdmmc3", "pll_p", 48000000, false},
90 { "sdmmc4", "pll_p", 48000000, false},
Colin Crossd8611962010-01-28 16:40:29 -080091 { NULL, NULL, 0, 0},
92};
Erik Gillingc5f80062010-01-21 16:53:02 -080093
Colin Cross8e437c22010-11-28 22:36:08 -080094void tegra_init_cache(void)
Erik Gillingc5f80062010-01-21 16:53:02 -080095{
96#ifdef CONFIG_CACHE_L2X0
97 void __iomem *p = IO_ADDRESS(TEGRA_ARM_PERIF_BASE) + 0x3000;
98
Colin Cross535371c2011-01-22 00:36:14 -080099 writel_relaxed(0x331, p + L2X0_TAG_LATENCY_CTRL);
100 writel_relaxed(0x441, p + L2X0_DATA_LATENCY_CTRL);
Erik Gillingc5f80062010-01-21 16:53:02 -0800101
Gary Kingf56081e2010-10-12 18:55:07 -0700102 l2x0_init(p, 0x6C480001, 0x8200c3fe);
Erik Gillingc5f80062010-01-21 16:53:02 -0800103#endif
Colin Cross4de3a8f2010-04-05 13:16:42 -0700104
Erik Gillingc5f80062010-01-21 16:53:02 -0800105}
106
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700107static 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
Dima Zavin7e158ac2010-11-11 15:28:46 -0800113static bool console_flushed;
114
115static 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
138static void tegra_pm_restart(char mode, const char *cmd)
139{
140 tegra_pm_flush_console();
141 arm_machine_restart(mode, cmd);
142}
143
Colin Cross0cf62302011-02-21 17:10:14 -0800144void __init tegra_init_early(void)
Erik Gillingc5f80062010-01-21 16:53:02 -0800145{
Dima Zavin7e158ac2010-11-11 15:28:46 -0800146 arm_pm_restart = tegra_pm_restart;
Colin Cross73625e32010-06-23 15:49:17 -0700147 tegra_init_fuse();
Colin Cross45a1ca02011-03-28 17:47:31 -0700148 tegra_gpio_resume_init();
Colin Crossd8611962010-01-28 16:40:29 -0800149 tegra_init_clock();
Colin Cross120c3562011-03-28 17:48:56 -0700150 tegra_init_pinmux();
Colin Crossd8611962010-01-28 16:40:29 -0800151 tegra_clk_init_from_table(common_clk_init_table);
Dima Zavin7db7cbc2010-09-16 17:58:05 -0700152 tegra_init_power();
Erik Gillingc5f80062010-01-21 16:53:02 -0800153 tegra_init_cache();
Colin Cross0b297932010-11-24 14:52:02 -0800154 tegra_dma_init();
Jon Mayo6ae77a92010-12-21 15:09:33 -0800155 tegra_init_apb_dma();
Erik Gillingc5f80062010-01-21 16:53:02 -0800156}
Colin Cross8e437c22010-11-28 22:36:08 -0800157
158static 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}
168early_param("lp0_vec", tegra_lp0_vec_arg);
169
170void __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}
Colin Cross838d7d62010-10-19 14:45:50 -0700182
183static 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}
196early_param("tegra_fbmem", tegra_bootloader_fb_arg);
197
Colin Crossf9c9bde2010-10-19 16:12:33 -0700198/*
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 */
203void __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
Colin Cross115467a2010-10-19 21:09:29 -0700215/*
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 */
223void 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
Colin Cross115467a2010-10-19 21:09:29 -0700241 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 }
261out:
262 iounmap(to_io);
263}
264
Colin Cross838d7d62010-10-19 14:45:50 -0700265void __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
Colin Crossf9c9bde2010-10-19 16:12:33 -0700298 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
Colin Cross838d7d62010-10-19 14:45:50 -0700307 /*
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}