*
  * Copyright (C) 2010 Google, Inc.
  * Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011 NVIDIA CORPORATION. All Rights Reserved.
  *
  * Author:
  *     Colin Cross <ccross@google.com>
  *     Erik Gilling <konkers@google.com>
  *     Doug Anderson <dianders@chromium.org>
+ *     Stephen Warren <swarren@nvidia.com>
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
 #ifndef __MACH_TEGRA_UNCOMPRESS_H
 #define __MACH_TEGRA_UNCOMPRESS_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/serial_reg.h>
 
 {
 }
 
+/*
+ * Setup before decompression.  This is where we do UART selection for
+ * earlyprintk and init the uart_base register.
+ */
 static inline void arch_decomp_setup(void)
 {
+       static const struct {
+               u32 base;
+               u32 reset_reg;
+               u32 clock_reg;
+               u32 bit;
+       } uarts[] = {
+               {
+                       TEGRA_UARTA_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x04,
+                       TEGRA_CLK_RESET_BASE + 0x10,
+                       6,
+               },
+               {
+                       TEGRA_UARTB_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x04,
+                       TEGRA_CLK_RESET_BASE + 0x10,
+                       7,
+               },
+               {
+                       TEGRA_UARTC_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x08,
+                       TEGRA_CLK_RESET_BASE + 0x14,
+                       23,
+               },
+               {
+                       TEGRA_UARTD_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x0c,
+                       TEGRA_CLK_RESET_BASE + 0x18,
+                       1,
+               },
+               {
+                       TEGRA_UARTE_BASE,
+                       TEGRA_CLK_RESET_BASE + 0x0c,
+                       TEGRA_CLK_RESET_BASE + 0x18,
+                       2,
+               },
+       };
+       int i;
        volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
        u32 chip, div;
 
-       uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
+       /*
+        * Look for the first UART that:
+        * a) Is not in reset.
+        * b) Is clocked.
+        * c) Has a 'D' in the scratchpad register.
+        *
+        * Note that on Tegra30, the first two conditions are required, since
+        * if not true, accesses to the UART scratch register will hang.
+        * Tegra20 doesn't have this issue.
+        *
+        * The intent is that the bootloader will tell the kernel which UART
+        * to use by setting up those conditions. If nothing found, we'll fall
+        * back to what's specified in TEGRA_DEBUG_UART_BASE.
+        */
+       for (i = 0; i < ARRAY_SIZE(uarts); i++) {
+               if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
+                       continue;
+
+               if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
+                       continue;
+
+               uart = (volatile u8 *)uarts[i].base;
+               if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
+                       continue;
+
+               break;
+       }
+       if (i == ARRAY_SIZE(uarts))
+               uart = (volatile u8 *)TEGRA_DEBUG_UART_BASE;
        if (uart == NULL)
                return;