aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-03-26 14:49:57 -0400
committerStephen Warren <swarren@nvidia.com>2012-04-10 15:41:36 -0400
commit80881dae52d05d3d6c920624157d68006390f01e (patch)
tree513fcf053618f5ef83908e24c1a33d5efb2f75d6 /arch/arm/mach-tegra
parent0034102808e0dbbf3a2394b82b1bb40b5778de9e (diff)
ARM: tegra: uncompress.h: Implement TEGRA_DEBUG_UART_AUTO_ODMDATA
Tegra has 5 UARTS which could be used for low-level debug output. Commit fe26398 "ARM: tegra: uncompress.h: Choose a UART at runtime" implemented one method for the kernel to automatically determine which of these to use at run-time, so that the same DEBUG_LL-enabled kernel image could be used across multiple Tegra boards. The required bootloader-side setup for that option is implemented in NVIDIA's various downstream U-Boot branches, but the U-Boot maintainers have refused to accept it upstream. This change implements an alternative automatic UART selection option using ODMDATA. This is a 32-bit value programmed into Tegra's boot memory which provides a few pieces of basic board-specific information, including a field that indicates the console UART. Setting up this value is part of the standard Tegra boot architecture, and so requires no Tegra-specific hacks in the bootloader's UART driver. Note that in theory, the format of ODMDATA is board-specific. However, in practice all boards use the same location/size/values for the UART field. ODMDATA[19:18] (which drive the type of debug console) is more problematic, since some boards use value 2 for UART and others use 3. This patch just accepts either value; if this doesn't work well for a given board, I'd suggest simply not enabling this debug option when building for that board. Note that the kernel assumes the bootloader has already set up any required pinmux settings for the UART; there is no way the kernel can do this for itself prior to knowing which board it's running on. In practice, people using this feature are highly likely to be using bootloaders that have indeed configured the pinmux. This assumption existed prior to this patch. Signed-off-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Kconfig29
-rw-r--r--arch/arm/mach-tegra/include/mach/uncompress.h176
2 files changed, 153 insertions, 52 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index d0f2546706ca..204d3d4d7388 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -111,7 +111,7 @@ config MACH_VENTANA
111 Support for the nVidia Ventana development platform 111 Support for the nVidia Ventana development platform
112 112
113choice 113choice
114 prompt "Low-level debug console UART" 114 prompt "Default low-level debug console UART"
115 default TEGRA_DEBUG_UART_NONE 115 default TEGRA_DEBUG_UART_NONE
116 116
117config TEGRA_DEBUG_UART_NONE 117config TEGRA_DEBUG_UART_NONE
@@ -134,6 +134,33 @@ config TEGRA_DEBUG_UARTE
134 134
135endchoice 135endchoice
136 136
137choice
138 prompt "Automatic low-level debug console UART"
139 default TEGRA_DEBUG_UART_AUTO_NONE
140
141config TEGRA_DEBUG_UART_AUTO_NONE
142 bool "None"
143
144config TEGRA_DEBUG_UART_AUTO_ODMDATA
145 bool "Via ODMDATA"
146 help
147 Automatically determines which UART to use for low-level debug based
148 on the ODMDATA value. This value is part of the BCT, and is written
149 to the boot memory device using nvflash, or other flashing tool.
150 When bits 19:18 are 3, then bits 17:15 indicate which UART to use;
151 0/1/2/3/4 are UART A/B/C/D/E.
152
153config TEGRA_DEBUG_UART_AUTO_SCRATCH
154 bool "Via UART scratch register"
155 help
156 Automatically determines which UART to use for low-level debug based
157 on the UART scratch register value. Some bootloaders put ASCII 'D'
158 in this register when they initialize their own console UART output.
159 Using this option allows the kernel to automatically pick the same
160 UART.
161
162endchoice
163
137config TEGRA_SYSTEM_DMA 164config TEGRA_SYSTEM_DMA
138 bool "Enable system DMA driver for NVIDIA Tegra SoCs" 165 bool "Enable system DMA driver for NVIDIA Tegra SoCs"
139 default y 166 default y
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
index 5a440f315e57..937c4c50219e 100644
--- a/arch/arm/mach-tegra/include/mach/uncompress.h
+++ b/arch/arm/mach-tegra/include/mach/uncompress.h
@@ -63,52 +63,86 @@ static inline void save_uart_address(void)
63 buf[0] = 0; 63 buf[0] = 0;
64} 64}
65 65
66/* 66static const struct {
67 * Setup before decompression. This is where we do UART selection for 67 u32 base;
68 * earlyprintk and init the uart_base register. 68 u32 reset_reg;
69 */ 69 u32 clock_reg;
70static inline void arch_decomp_setup(void) 70 u32 bit;
71} uarts[] = {
72 {
73 TEGRA_UARTA_BASE,
74 TEGRA_CLK_RESET_BASE + 0x04,
75 TEGRA_CLK_RESET_BASE + 0x10,
76 6,
77 },
78 {
79 TEGRA_UARTB_BASE,
80 TEGRA_CLK_RESET_BASE + 0x04,
81 TEGRA_CLK_RESET_BASE + 0x10,
82 7,
83 },
84 {
85 TEGRA_UARTC_BASE,
86 TEGRA_CLK_RESET_BASE + 0x08,
87 TEGRA_CLK_RESET_BASE + 0x14,
88 23,
89 },
90 {
91 TEGRA_UARTD_BASE,
92 TEGRA_CLK_RESET_BASE + 0x0c,
93 TEGRA_CLK_RESET_BASE + 0x18,
94 1,
95 },
96 {
97 TEGRA_UARTE_BASE,
98 TEGRA_CLK_RESET_BASE + 0x0c,
99 TEGRA_CLK_RESET_BASE + 0x18,
100 2,
101 },
102};
103
104static inline bool uart_clocked(int i)
105{
106 if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
107 return false;
108
109 if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
110 return false;
111
112 return true;
113}
114
115#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA
116int auto_odmdata(void)
117{
118 volatile u32 *pmc = (volatile u32 *)TEGRA_PMC_BASE;
119 u32 odmdata = pmc[0xa0 / 4];
120
121 /*
122 * Bits 19:18 are the console type: 0=default, 1=none, 2==DCC, 3==UART
123 * Some boards apparently swap the last two values, but we don't have
124 * any way of catering for that here, so we just accept either. If this
125 * doesn't make sense for your board, just don't enable this feature.
126 *
127 * Bits 17:15 indicate the UART to use, 0/1/2/3/4 are UART A/B/C/D/E.
128 */
129
130 switch ((odmdata >> 18) & 3) {
131 case 2:
132 case 3:
133 break;
134 default:
135 return -1;
136 }
137
138 return (odmdata >> 15) & 7;
139}
140#endif
141
142#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH
143int auto_scratch(void)
71{ 144{
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; 145 int i;
110 volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
111 u32 chip, div;
112 146
113 /* 147 /*
114 * Look for the first UART that: 148 * Look for the first UART that:
@@ -125,20 +159,60 @@ static inline void arch_decomp_setup(void)
125 * back to what's specified in TEGRA_DEBUG_UART_BASE. 159 * back to what's specified in TEGRA_DEBUG_UART_BASE.
126 */ 160 */
127 for (i = 0; i < ARRAY_SIZE(uarts); i++) { 161 for (i = 0; i < ARRAY_SIZE(uarts); i++) {
128 if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit)) 162 if (!uart_clocked(i))
129 continue;
130
131 if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
132 continue; 163 continue;
133 164
134 uart = (volatile u8 *)uarts[i].base; 165 uart = (volatile u8 *)uarts[i].base;
135 if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D') 166 if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
136 continue; 167 continue;
137 168
138 break; 169 return i;
139 } 170 }
140 if (i == ARRAY_SIZE(uarts)) 171
141 uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; 172 return -1;
173}
174#endif
175
176/*
177 * Setup before decompression. This is where we do UART selection for
178 * earlyprintk and init the uart_base register.
179 */
180static inline void arch_decomp_setup(void)
181{
182 int uart_id, auto_uart_id;
183 volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
184 u32 chip, div;
185
186#if defined(CONFIG_TEGRA_DEBUG_UARTA)
187 uart_id = 0;
188#elif defined(CONFIG_TEGRA_DEBUG_UARTB)
189 uart_id = 1;
190#elif defined(CONFIG_TEGRA_DEBUG_UARTC)
191 uart_id = 2;
192#elif defined(CONFIG_TEGRA_DEBUG_UARTD)
193 uart_id = 3;
194#elif defined(CONFIG_TEGRA_DEBUG_UARTE)
195 uart_id = 4;
196#else
197 uart_id = -1;
198#endif
199
200#if defined(CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA)
201 auto_uart_id = auto_odmdata();
202#elif defined(CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH)
203 auto_uart_id = auto_scratch();
204#else
205 auto_uart_id = -1;
206#endif
207 if (auto_uart_id != -1)
208 uart_id = auto_uart_id;
209
210 if (uart_id < 0 || uart_id >= ARRAY_SIZE(uarts) ||
211 !uart_clocked(uart_id))
212 uart = NULL;
213 else
214 uart = (volatile u8 *)uarts[uart_id].base;
215
142 save_uart_address(); 216 save_uart_address();
143 if (uart == NULL) 217 if (uart == NULL)
144 return; 218 return;