uncompress.h 5.0 KB
Newer Older
1 2 3 4
/*
 * arch/arm/mach-tegra/include/mach/uncompress.h
 *
 * Copyright (C) 2010 Google, Inc.
5
 * Copyright (C) 2011 Google, Inc.
6
 * Copyright (C) 2011-2012 NVIDIA CORPORATION. All Rights Reserved.
7 8 9 10
 *
 * Author:
 *	Colin Cross <ccross@google.com>
 *	Erik Gilling <konkers@google.com>
11
 *	Doug Anderson <dianders@chromium.org>
12
 *	Stephen Warren <swarren@nvidia.com>
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#ifndef __MACH_TEGRA_UNCOMPRESS_H
#define __MACH_TEGRA_UNCOMPRESS_H

#include <linux/types.h>
#include <linux/serial_reg.h>

31
#include <mach/irammap.h>
32

33 34
#include "../../iomap.h"

35 36 37
#define BIT(x) (1 << (x))
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))

38 39
#define DEBUG_UART_SHIFT 2

40 41
volatile u8 *uart;

42 43 44 45 46
static void putc(int c)
{
	if (uart == NULL)
		return;

47
	while (!(uart[UART_LSR << DEBUG_UART_SHIFT] & UART_LSR_THRE))
48
		barrier();
49
	uart[UART_TX << DEBUG_UART_SHIFT] = c;
50 51 52 53 54 55
}

static inline void flush(void)
{
}

56 57 58 59 60 61 62 63 64 65 66
static inline void save_uart_address(void)
{
	u32 *buf = (u32 *)(TEGRA_IRAM_BASE + TEGRA_IRAM_DEBUG_UART_OFFSET);

	if (uart) {
		buf[0] = TEGRA_IRAM_DEBUG_UART_COOKIE;
		buf[1] = (u32)uart;
	} else
		buf[0] = 0;
}

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
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,
	},
};

static inline bool uart_clocked(int i)
{
	if (*(u8 *)uarts[i].reset_reg & BIT(uarts[i].bit))
		return false;

	if (!(*(u8 *)uarts[i].clock_reg & BIT(uarts[i].bit)))
		return false;

	return true;
}

#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA
int auto_odmdata(void)
{
	volatile u32 *pmc = (volatile u32 *)TEGRA_PMC_BASE;
	u32 odmdata = pmc[0xa0 / 4];

	/*
	 * Bits 19:18 are the console type: 0=default, 1=none, 2==DCC, 3==UART
	 * Some boards apparently swap the last two values, but we don't have
	 * any way of catering for that here, so we just accept either. If this
	 * doesn't make sense for your board, just don't enable this feature.
	 *
	 * Bits 17:15 indicate the UART to use, 0/1/2/3/4 are UART A/B/C/D/E.
	 */

	switch  ((odmdata >> 18) & 3) {
	case 2:
	case 3:
		break;
	default:
		return -1;
	}

	return (odmdata >> 15) & 7;
}
#endif

#ifdef CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH
int auto_scratch(void)
145
{
146
	int i;
147

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	/*
	 * 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++) {
163
		if (!uart_clocked(i))
164 165 166 167 168 169
			continue;

		uart = (volatile u8 *)uarts[i].base;
		if (uart[UART_SCR << DEBUG_UART_SHIFT] != 'D')
			continue;

170
		return i;
171
	}
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

	return -1;
}
#endif

/*
 * 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)
{
	int uart_id, auto_uart_id;
	volatile u32 *apb_misc = (volatile u32 *)TEGRA_APB_MISC_BASE;
	u32 chip, div;

#if defined(CONFIG_TEGRA_DEBUG_UARTA)
	uart_id = 0;
#elif defined(CONFIG_TEGRA_DEBUG_UARTB)
	uart_id = 1;
#elif defined(CONFIG_TEGRA_DEBUG_UARTC)
	uart_id = 2;
#elif defined(CONFIG_TEGRA_DEBUG_UARTD)
	uart_id = 3;
#elif defined(CONFIG_TEGRA_DEBUG_UARTE)
	uart_id = 4;
#else
	uart_id = -1;
#endif

#if defined(CONFIG_TEGRA_DEBUG_UART_AUTO_ODMDATA)
	auto_uart_id = auto_odmdata();
#elif defined(CONFIG_TEGRA_DEBUG_UART_AUTO_SCRATCH)
	auto_uart_id = auto_scratch();
#else
	auto_uart_id = -1;
#endif
	if (auto_uart_id != -1)
		uart_id = auto_uart_id;

	if (uart_id < 0 || uart_id >= ARRAY_SIZE(uarts) ||
	    !uart_clocked(uart_id))
		uart = NULL;
	else
		uart = (volatile u8 *)uarts[uart_id].base;

217
	save_uart_address();
218 219 220
	if (uart == NULL)
		return;

221 222 223 224 225 226
	chip = (apb_misc[0x804 / 4] >> 8) & 0xff;
	if (chip == 0x20)
		div = 0x0075;
	else
		div = 0x00dd;

227 228 229 230
	uart[UART_LCR << DEBUG_UART_SHIFT] |= UART_LCR_DLAB;
	uart[UART_DLL << DEBUG_UART_SHIFT] = div & 0xff;
	uart[UART_DLM << DEBUG_UART_SHIFT] = div >> 8;
	uart[UART_LCR << DEBUG_UART_SHIFT] = 3;
231 232 233 234 235 236 237
}

static inline void arch_decomp_wdog(void)
{
}

#endif