]>
Commit | Line | Data |
---|---|---|
c5f80065 EG |
1 | /* |
2 | * arch/arm/mach-tegra/include/mach/uncompress.h | |
3 | * | |
4 | * Copyright (C) 2010 Google, Inc. | |
229c7b22 | 5 | * Copyright (C) 2011 Google, Inc. |
6d7d7b3e | 6 | * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved. |
c5f80065 EG |
7 | * |
8 | * Author: | |
9 | * Colin Cross <ccross@google.com> | |
10 | * Erik Gilling <konkers@google.com> | |
229c7b22 | 11 | * Doug Anderson <dianders@chromium.org> |
fe263989 | 12 | * Stephen Warren <swarren@nvidia.com> |
c5f80065 EG |
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/types.h> | |
29 | #include <linux/serial_reg.h> | |
30 | ||
31 | #include <mach/iomap.h> | |
6d7d7b3e | 32 | #include <mach/irammap.h> |
c5f80065 | 33 | |
e77a6b31 SW |
34 | #define BIT(x) (1 << (x)) |
35 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | |
36 | ||
229c7b22 DA |
37 | #define DEBUG_UART_SHIFT 2 |
38 | ||
31bac137 DA |
39 | volatile u8 *uart; |
40 | ||
c5f80065 EG |
41 | static void putc(int c) |
42 | { | |
c5f80065 EG |
43 | if (uart == NULL) |
44 | return; | |
45 | ||
229c7b22 | 46 | while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE)) |
c5f80065 | 47 | barrier(); |
229c7b22 | 48 | uart[UART_TX << DEBUG_UART_SHIFT] = c; |
c5f80065 EG |
49 | } |
50 | ||
51 | static inline void flush(void) | |
52 | { | |
53 | } | |
54 | ||
6d7d7b3e SW |
55 | static inline void save_uart_address(void) |
56 | { | |
57 | u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET); | |
58 | ||
59 | if (uart) { | |
60 | buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE; | |
61 | buf[1] = (u32)uart; | |
62 | } else | |
63 | buf[0] = 0; | |
64 | } | |
65 | ||
fe263989 SW |
66 | /* |
67 | * Setup before decompression. This is where we do UART selection for | |
68 | * earlyprintk and init the uart_base register. | |
69 | */ | |
c5f80065 EG |
70 | static inline void arch_decomp_setup(void) |
71 | { | |
fe263989 SW |
72 | static const struct { |
73 | u32 base; | |
74 | u32 reset_reg; | |
75 | u32 clock_reg; | |
76 | u32 bit; | |
77 | } uarts[] = { | |
78 | { | |
79 | TEGRA_UARTA_BASE, | |
80 | TEGRA_CLK_RESET_BASE + 0x04, | |
81 | TEGRA_CLK_RESET_BASE + 0x10, | |
82 | 6, | |
83 | }, | |
84 | { | |
85 | TEGRA_UARTB_BASE, | |
86 | TEGRA_CLK_RESET_BASE + 0x04, | |
87 | TEGRA_CLK_RESET_BASE + 0x10, | |
88 | 7, | |
89 | }, | |
90 | { | |
91 | TEGRA_UARTC_BASE, | |
92 | TEGRA_CLK_RESET_BASE + 0x08, | |
93 | TEGRA_CLK_RESET_BASE + 0x14, | |
94 | 23, | |
95 | }, | |
96 | { | |
97 | TEGRA_UARTD_BASE, | |
98 | TEGRA_CLK_RESET_BASE + 0x0c, | |
99 | TEGRA_CLK_RESET_BASE + 0x18, | |
100 | 1, | |
101 | }, | |
102 | { | |
103 | TEGRA_UARTE_BASE, | |
104 | TEGRA_CLK_RESET_BASE + 0x0c, | |
105 | TEGRA_CLK_RESET_BASE + 0x18, | |
106 | 2, | |
107 | }, | |
108 | }; | |
109 | int i; | |
e53b7d87 SW |
110 | volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; |
111 | u32 chip, div; | |
c5f80065 | 112 | |
fe263989 SW |
113 | /* |
114 | * Look for the first UART that: | |
115 | * a) Is not in reset. | |
116 | * b) Is clocked. | |
117 | * c) Has a 'D' in the scratchpad register. | |
118 | * | |
119 | * Note that on Tegra30, the first two conditions are required, since | |
120 | * if not true, accesses to the UART scratch register will hang. | |
121 | * Tegra20 doesn't have this issue. | |
122 | * | |
123 | * The intent is that the bootloader will tell the kernel which UART | |
124 | * to use by setting up those conditions. If nothing found, we'll fall | |
125 | * back to what's specified in TEGRA_DEBUG_UART_BASE. | |
126 | */ | |
127 | for (i = 0; i < ARRAY_SIZE(uarts); i++) { | |
128 | if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit)) | |
129 | continue; | |
130 | ||
131 | if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit))) | |
132 | continue; | |
133 | ||
134 | uart = (volatile u8 *)uarts[i].base; | |
135 | if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D') | |
136 | continue; | |
137 | ||
138 | break; | |
139 | } | |
140 | if (i == ARRAY_SIZE(uarts)) | |
141 | uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; | |
6d7d7b3e | 142 | save_uart_address(); |
c5f80065 EG |
143 | if (uart == NULL) |
144 | return; | |
145 | ||
e53b7d87 SW |
146 | chip = (apb_misc[0x804 / 4] >> 8) & 0xff; |
147 | if (chip == 0x20) | |
148 | div = 0x0075; | |
149 | else | |
150 | div = 0x00dd; | |
151 | ||
229c7b22 DA |
152 | uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB; |
153 | uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff; | |
154 | uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8; | |
155 | uart[UART_LCR << DEBUG_UART_SHIFT] = 3; | |
c5f80065 EG |
156 | } |
157 | ||
158 | static inline void arch_decomp_wdog(void) | |
159 | { | |
160 | } | |
161 | ||
162 | #endif |