Merge branch 'samsung/exynos5' into next/soc2
[linux-2.6.git] / arch / arm / mach-tegra / include / mach / uncompress.h
1 /*
2  * arch/arm/mach-tegra/include/mach/uncompress.h
3  *
4  * Copyright (C) 2010 Google, Inc.
5  * Copyright (C) 2011 Google, Inc.
6  * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
7  *
8  * Author:
9  *      Colin Cross <ccross@google.com>
10  *      Erik Gilling <konkers@google.com>
11  *      Doug Anderson <dianders@chromium.org>
12  *      Stephen Warren <swarren@nvidia.com>
13  *
14  * This software is licensed under the terms of the GNU General Public
15  * License version 2, as published by the Free Software Foundation, and
16  * may be copied, distributed, and modified under those terms.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  */
24
25 #ifndef __MACH_TEGRA_UNCOMPRESS_H
26 #define __MACH_TEGRA_UNCOMPRESS_H
27
28 #include <linux/kernel.h>
29 #include <linux/types.h>
30 #include <linux/serial_reg.h>
31
32 #include <mach/iomap.h>
33 #include <mach/irammap.h>
34
35 #define DEBUG_UART_SHIFT 2
36
37 volatile u8 *uart;
38
39 static void putc(int c)
40 {
41         if (uart == NULL)
42                 return;
43
44         while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
45                 barrier();
46         uart[UART_TX << DEBUG_UART_SHIFT] = c;
47 }
48
49 static inline void flush(void)
50 {
51 }
52
53 static inline void save_uart_address(void)
54 {
55         u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET);
56
57         if (uart) {
58                 buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE;
59                 buf[1] = (u32)uart;
60         } else
61                 buf[0] = 0;
62 }
63
64 /*
65  * Setup before decompression.  This is where we do UART selection for
66  * earlyprintk and init the uart_base register.
67  */
68 static inline void arch_decomp_setup(void)
69 {
70         static const struct {
71                 u32 base;
72                 u32 reset_reg;
73                 u32 clock_reg;
74                 u32 bit;
75         } uarts[] = {
76                 {
77                         TEGRA_UARTA_BASE,
78                         TEGRA_CLK_RESET_BASE + 0x04,
79                         TEGRA_CLK_RESET_BASE + 0x10,
80                         6,
81                 },
82                 {
83                         TEGRA_UARTB_BASE,
84                         TEGRA_CLK_RESET_BASE + 0x04,
85                         TEGRA_CLK_RESET_BASE + 0x10,
86                         7,
87                 },
88                 {
89                         TEGRA_UARTC_BASE,
90                         TEGRA_CLK_RESET_BASE + 0x08,
91                         TEGRA_CLK_RESET_BASE + 0x14,
92                         23,
93                 },
94                 {
95                         TEGRA_UARTD_BASE,
96                         TEGRA_CLK_RESET_BASE + 0x0c,
97                         TEGRA_CLK_RESET_BASE + 0x18,
98                         1,
99                 },
100                 {
101                         TEGRA_UARTE_BASE,
102                         TEGRA_CLK_RESET_BASE + 0x0c,
103                         TEGRA_CLK_RESET_BASE + 0x18,
104                         2,
105                 },
106         };
107         int i;
108         volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
109         u32 chip, div;
110
111         /*
112          * Look for the first UART that:
113          * a) Is not in reset.
114          * b) Is clocked.
115          * c) Has a 'D' in the scratchpad register.
116          *
117          * Note that on Tegra30, the first two conditions are required, since
118          * if not true, accesses to the UART scratch register will hang.
119          * Tegra20 doesn't have this issue.
120          *
121          * The intent is that the bootloader will tell the kernel which UART
122          * to use by setting up those conditions. If nothing found, we'll fall
123          * back to what's specified in TEGRA_DEBUG_UART_BASE.
124          */
125         for (i = 0; i < ARRAY_SIZE(uarts); i++) {
126                 if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
127                         continue;
128
129                 if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
130                         continue;
131
132                 uart = (volatile u8 *)uarts[i].base;
133                 if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
134                         continue;
135
136                 break;
137         }
138         if (i == ARRAY_SIZE(uarts))
139                 uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
140         save_uart_address();
141         if (uart == NULL)
142                 return;
143
144         chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
145         if (chip == 0x20)
146                 div = 0x0075;
147         else
148                 div = 0x00dd;
149
150         uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
151         uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
152         uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
153         uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
154 }
155
156 static inline void arch_decomp_wdog(void)
157 {
158 }
159
160 #endif