aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2012-01-06 05:43:21 -0500
committerOlof Johansson <olof@lixom.net>2012-02-06 21:25:00 -0500
commitfe2639892cb618d5c42ea4570feea8dc497d0487 (patch)
tree8d545ebb7ab0c39aa24ca1963a103e918c49e8ec
parent31bac1375bda9787f18b2f60e0e1ca62258ea09c (diff)
ARM: tegra: uncompress.h: Choose a UART at runtime
With this change we automatically detect which UART to use for for printing during decompression. The detection involves coordination with the bootloader: it's expected that the bootloader will leave a 'D' (for [D]ebug) in the UART scratchpad register for whichever UART we should use for debugging. If we don't find any such UART, we fall back to the UART that was specified during config time: CONFIG_TEGRA_DEBUG_UART_XXX. As a side effect of this change, uncompress debug messages will work if you've specified CONFIG_TEGRA_DEBUG_UART_NONE, provided the bootloader obeys the protocol. This change is in line with what is documented in Documentation/arm/Booting. Other approaches considered: * Hardcode based on machine ID (as many other ARM boards do). OK, but nice to not have yet another place to add per-board code. Better to have bootloader parse device tree and pass us this info. * Check for TXE bit (like SA1110). Nice (and doesn't require a bootloader change), but a little less explicit. Also: if bootloader (for some reason) uses another UART, it needs to remember to turn it off before jumping to the kernel or we may print to it. NOTE: adapting this patch to check TXE too would be easy if desired. Signed-off-by: Doug Anderson <dianders@chromium.org> [swarren: Added clock/reset condition checks] Signed-off-by: Stephen Warren <swarren@nvidia.com> Tested-by: Doug Anderson <dianders@chromium.org> Acked-by: Doug Anderson <dianders@chromium.org> Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--arch/arm/mach-tegra/include/mach/uncompress.h75
1 files changed, 74 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/include/mach/uncompress.h b/arch/arm/mach-tegra/include/mach/uncompress.h
index bb3fd359f9fa..6c087b6974b2 100644
--- a/arch/arm/mach-tegra/include/mach/uncompress.h
+++ b/arch/arm/mach-tegra/include/mach/uncompress.h
@@ -3,11 +3,13 @@
3 * 3 *
4 * Copyright (C) 2010 Google, Inc. 4 * Copyright (C) 2010 Google, Inc.
5 * Copyright (C) 2011 Google, Inc. 5 * Copyright (C) 2011 Google, Inc.
6 * Copyright (C) 2011 NVIDIA CORPORATION. All Rights Reserved.
6 * 7 *
7 * Author: 8 * Author:
8 * Colin Cross <ccross@google.com> 9 * Colin Cross <ccross@google.com>
9 * Erik Gilling <konkers@google.com> 10 * Erik Gilling <konkers@google.com>
10 * Doug Anderson <dianders@chromium.org> 11 * Doug Anderson <dianders@chromium.org>
12 * Stephen Warren <swarren@nvidia.com>
11 * 13 *
12 * This software is licensed under the terms of the GNU General Public 14 * This software is licensed under the terms of the GNU General Public
13 * License version 2, as published by the Free Software Foundation, and 15 * License version 2, as published by the Free Software Foundation, and
@@ -23,6 +25,7 @@
23#ifndef __MACH_TEGRA_UNCOMPRESS_H 25#ifndef __MACH_TEGRA_UNCOMPRESS_H
24#define __MACH_TEGRA_UNCOMPRESS_H 26#define __MACH_TEGRA_UNCOMPRESS_H
25 27
28#include <linux/kernel.h>
26#include <linux/types.h> 29#include <linux/types.h>
27#include <linux/serial_reg.h> 30#include <linux/serial_reg.h>
28 31
@@ -46,12 +49,82 @@ static inline void flush(void)
46{ 49{
47} 50}
48 51
52/*
53 * Setup before decompression. This is where we do UART selection for
54 * earlyprintk and init the uart_base register.
55 */
49static inline void arch_decomp_setup(void) 56static inline void arch_decomp_setup(void)
50{ 57{
58 static const struct {
59 u32 base;
60 u32 reset_reg;
61 u32 clock_reg;
62 u32 bit;
63 } uarts[] = {
64 {
65 TEGRA_UARTA_BASE,
66 TEGRA_CLK_RESET_BASE + 0x04,
67 TEGRA_CLK_RESET_BASE + 0x10,
68 6,
69 },
70 {
71 TEGRA_UARTB_BASE,
72 TEGRA_CLK_RESET_BASE + 0x04,
73 TEGRA_CLK_RESET_BASE + 0x10,
74 7,
75 },
76 {
77 TEGRA_UARTC_BASE,
78 TEGRA_CLK_RESET_BASE + 0x08,
79 TEGRA_CLK_RESET_BASE + 0x14,
80 23,
81 },
82 {
83 TEGRA_UARTD_BASE,
84 TEGRA_CLK_RESET_BASE + 0x0c,
85 TEGRA_CLK_RESET_BASE + 0x18,
86 1,
87 },
88 {
89 TEGRA_UARTE_BASE,
90 TEGRA_CLK_RESET_BASE + 0x0c,
91 TEGRA_CLK_RESET_BASE + 0x18,
92 2,
93 },
94 };
95 int i;
51 volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE; 96 volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
52 u32 chip, div; 97 u32 chip, div;
53 98
54 uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE; 99 /*
100 * Look for the first UART that:
101 * a) Is not in reset.
102 * b) Is clocked.
103 * c) Has a 'D' in the scratchpad register.
104 *
105 * Note that on Tegra30, the first two conditions are required, since
106 * if not true, accesses to the UART scratch register will hang.
107 * Tegra20 doesn't have this issue.
108 *
109 * The intent is that the bootloader will tell the kernel which UART
110 * to use by setting up those conditions. If nothing found, we'll fall
111 * back to what's specified in TEGRA_DEBUG_UART_BASE.
112 */
113 for (i = 0; i < ARRAY_SIZE(uarts); i++) {
114 if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
115 continue;
116
117 if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
118 continue;
119
120 uart = (volatile u8 *)uarts[i].base;
121 if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
122 continue;
123
124 break;
125 }
126 if (i == ARRAY_SIZE(uarts))
127 uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
55 if (uart == NULL) 128 if (uart == NULL)
56 return; 129 return;
57 130