]>
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 | ||
fe263989 | 28 | #include <linux/kernel.h> |
c5f80065 EG |
29 | #include <linux/types.h> |
30 | #include <linux/serial_reg.h> | |
31 | ||
32 | #include <mach/iomap.h> | |
6d7d7b3e | 33 | #include <mach/irammap.h> |
c5f80065 | 34 | |
229c7b22 DA |
35 | #define DEBUG_UART_SHIFT 2 |
36 | ||
31bac137 DA |
37 | volatile u8 *uart; |
38 | ||
c5f80065 EG |
39 | static void putc(int c) |
40 | { | |
c5f80065 EG |
41 | if (uart == NULL) |
42 | return; | |
43 | ||
229c7b22 | 44 | while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE)) |
c5f80065 | 45 | barrier(); |
229c7b22 | 46 | uart[UART_TX << DEBUG_UART_SHIFT] = c; |
c5f80065 EG |
47 | } |
48 | ||
49 | static inline void flush(void) | |
50 | { | |
51 | } | |
52 | ||
6d7d7b3e SW |
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 | ||
fe263989 SW |
64 | /* |
65 | * Setup before decompression. This is where we do UART selection for | |
66 | * earlyprintk and init the uart_base register. | |
67 | */ | |
c5f80065 EG |
68 | static inline void arch_decomp_setup(void) |
69 | { | |
fe263989 SW |
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; | |
e53b7d87 SW |
108 | volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; |
109 | u32 chip, div; | |
c5f80065 | 110 | |
fe263989 SW |
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; | |
6d7d7b3e | 140 | save_uart_address(); |
c5f80065 EG |
141 | if (uart == NULL) |
142 | return; | |
143 | ||
e53b7d87 SW |
144 | chip = (apb_misc[0x804 / 4] >> 8) & 0xff; |
145 | if (chip == 0x20) | |
146 | div = 0x0075; | |
147 | else | |
148 | div = 0x00dd; | |
149 | ||
229c7b22 DA |
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; | |
c5f80065 EG |
154 | } |
155 | ||
156 | static inline void arch_decomp_wdog(void) | |
157 | { | |
158 | } | |
159 | ||
160 | #endif |