diff options
| author | fishsoupisgood <github@madingley.org> | 2019-04-29 01:17:54 +0100 | 
|---|---|---|
| committer | fishsoupisgood <github@madingley.org> | 2019-05-27 03:43:43 +0100 | 
| commit | 3f2546b2ef55b661fd8dd69682b38992225e86f6 (patch) | |
| tree | 65ca85f13617aee1dce474596800950f266a456c /roms/u-boot/arch/arm/cpu/tegra20-common | |
| download | qemu-master.tar.gz qemu-master.tar.bz2 qemu-master.zip  | |
Diffstat (limited to 'roms/u-boot/arch/arm/cpu/tegra20-common')
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/Makefile | 17 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/clock.c | 550 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/crypto.c | 137 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/crypto.h | 20 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/emc.c | 270 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/funcmux.c | 296 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/pinmux.c | 425 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/pmu.c | 54 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/warmboot.c | 372 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.c | 236 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.h | 65 | 
11 files changed, 2442 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/Makefile b/roms/u-boot/arch/arm/cpu/tegra20-common/Makefile new file mode 100644 index 00000000..0e4b3fc1 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/Makefile @@ -0,0 +1,17 @@ +# +# (C) Copyright 2010,2011 Nvidia Corporation. +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +# The AVP is ARMv4T architecture so we must use special compiler +# flags for any startup files it might use. +CFLAGS_warmboot_avp.o += -march=armv4t + +obj-y	+= clock.o funcmux.o pinmux.o +obj-$(CONFIG_TEGRA_LP0) += warmboot.o crypto.o warmboot_avp.o +obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o +obj-$(CONFIG_TEGRA_PMU) += pmu.o diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/clock.c b/roms/u-boot/arch/arm/cpu/tegra20-common/clock.c new file mode 100644 index 00000000..0c4f5fb2 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/clock.c @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +/* Tegra20 Clock control functions */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/timer.h> +#include <div64.h> +#include <fdtdec.h> + +/* + * Clock types that we can use as a source. The Tegra20 has muxes for the + * peripheral clocks, and in most cases there are four options for the clock + * source. This gives us a clock 'type' and exploits what commonality exists + * in the device. + * + * Letters are obvious, except for T which means CLK_M, and S which means the + * clock derived from 32KHz. Beware that CLK_M (also called OSC in the + * datasheet) and PLL_M are different things. The former is the basic + * clock supplied to the SOC from an external oscillator. The latter is the + * memory clock PLL. + * + * See definitions in clock_id in the header file. + */ +enum clock_type_id { +	CLOCK_TYPE_AXPT,	/* PLL_A, PLL_X, PLL_P, CLK_M */ +	CLOCK_TYPE_MCPA,	/* and so on */ +	CLOCK_TYPE_MCPT, +	CLOCK_TYPE_PCM, +	CLOCK_TYPE_PCMT, +	CLOCK_TYPE_PCMT16,	/* CLOCK_TYPE_PCMT with 16-bit divider */ +	CLOCK_TYPE_PCXTS, +	CLOCK_TYPE_PDCT, + +	CLOCK_TYPE_COUNT, +	CLOCK_TYPE_NONE = -1,	/* invalid clock type */ +}; + +enum { +	CLOCK_MAX_MUX	= 4	/* number of source options for each clock */ +}; + +/* + * Clock source mux for each clock type. This just converts our enum into + * a list of mux sources for use by the code. Note that CLOCK_TYPE_PCXTS + * is special as it has 5 sources. Since it also has a different number of + * bits in its register for the source, we just handle it with a special + * case in the code. + */ +#define CLK(x) CLOCK_ID_ ## x +static enum clock_id clock_source[CLOCK_TYPE_COUNT][CLOCK_MAX_MUX] = { +	{ CLK(AUDIO),	CLK(XCPU),	CLK(PERIPH),	CLK(OSC)	}, +	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(AUDIO)	}, +	{ CLK(MEMORY),	CLK(CGENERAL),	CLK(PERIPH),	CLK(OSC)	}, +	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(NONE)	}, +	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC)	}, +	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(MEMORY),	CLK(OSC)	}, +	{ CLK(PERIPH),	CLK(CGENERAL),	CLK(XCPU),	CLK(OSC)	}, +	{ CLK(PERIPH),	CLK(DISPLAY),	CLK(CGENERAL),	CLK(OSC)	}, +}; + +/* + * Clock peripheral IDs which sadly don't match up with PERIPH_ID. This is + * not in the header file since it is for purely internal use - we want + * callers to use the PERIPH_ID for all access to peripheral clocks to avoid + * confusion bewteen PERIPH_ID_... and PERIPHC_... + * + * We don't call this CLOCK_PERIPH_ID or PERIPH_CLOCK_ID as it would just be + * confusing. + * + * Note to SOC vendors: perhaps define a unified numbering for peripherals and + * use it for reset, clock enable, clock source/divider and even pinmuxing + * if you can. + */ +enum periphc_internal_id { +	/* 0x00 */ +	PERIPHC_I2S1, +	PERIPHC_I2S2, +	PERIPHC_SPDIF_OUT, +	PERIPHC_SPDIF_IN, +	PERIPHC_PWM, +	PERIPHC_SPI1, +	PERIPHC_SPI2, +	PERIPHC_SPI3, + +	/* 0x08 */ +	PERIPHC_XIO, +	PERIPHC_I2C1, +	PERIPHC_DVC_I2C, +	PERIPHC_TWC, +	PERIPHC_0c, +	PERIPHC_10,	/* PERIPHC_SPI1, what is this really? */ +	PERIPHC_DISP1, +	PERIPHC_DISP2, + +	/* 0x10 */ +	PERIPHC_CVE, +	PERIPHC_IDE0, +	PERIPHC_VI, +	PERIPHC_1c, +	PERIPHC_SDMMC1, +	PERIPHC_SDMMC2, +	PERIPHC_G3D, +	PERIPHC_G2D, + +	/* 0x18 */ +	PERIPHC_NDFLASH, +	PERIPHC_SDMMC4, +	PERIPHC_VFIR, +	PERIPHC_EPP, +	PERIPHC_MPE, +	PERIPHC_MIPI, +	PERIPHC_UART1, +	PERIPHC_UART2, + +	/* 0x20 */ +	PERIPHC_HOST1X, +	PERIPHC_21, +	PERIPHC_TVO, +	PERIPHC_HDMI, +	PERIPHC_24, +	PERIPHC_TVDAC, +	PERIPHC_I2C2, +	PERIPHC_EMC, + +	/* 0x28 */ +	PERIPHC_UART3, +	PERIPHC_29, +	PERIPHC_VI_SENSOR, +	PERIPHC_2b, +	PERIPHC_2c, +	PERIPHC_SPI4, +	PERIPHC_I2C3, +	PERIPHC_SDMMC3, + +	/* 0x30 */ +	PERIPHC_UART4, +	PERIPHC_UART5, +	PERIPHC_VDE, +	PERIPHC_OWR, +	PERIPHC_NOR, +	PERIPHC_CSITE, + +	PERIPHC_COUNT, + +	PERIPHC_NONE = -1, +}; + +/* + * Clock type for each peripheral clock source. We put the name in each + * record just so it is easy to match things up + */ +#define TYPE(name, type) type +static enum clock_type_id clock_periph_type[PERIPHC_COUNT] = { +	/* 0x00 */ +	TYPE(PERIPHC_I2S1,	CLOCK_TYPE_AXPT), +	TYPE(PERIPHC_I2S2,	CLOCK_TYPE_AXPT), +	TYPE(PERIPHC_SPDIF_OUT,	CLOCK_TYPE_AXPT), +	TYPE(PERIPHC_SPDIF_IN,	CLOCK_TYPE_PCM), +	TYPE(PERIPHC_PWM,	CLOCK_TYPE_PCXTS), +	TYPE(PERIPHC_SPI1,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_SPI22,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_SPI3,	CLOCK_TYPE_PCMT), + +	/* 0x08 */ +	TYPE(PERIPHC_XIO,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_I2C1,	CLOCK_TYPE_PCMT16), +	TYPE(PERIPHC_DVC_I2C,	CLOCK_TYPE_PCMT16), +	TYPE(PERIPHC_TWC,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE), +	TYPE(PERIPHC_SPI1,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_DISP1,	CLOCK_TYPE_PDCT), +	TYPE(PERIPHC_DISP2,	CLOCK_TYPE_PDCT), + +	/* 0x10 */ +	TYPE(PERIPHC_CVE,	CLOCK_TYPE_PDCT), +	TYPE(PERIPHC_IDE0,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA), +	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE), +	TYPE(PERIPHC_SDMMC1,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_SDMMC2,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_G3D,	CLOCK_TYPE_MCPA), +	TYPE(PERIPHC_G2D,	CLOCK_TYPE_MCPA), + +	/* 0x18 */ +	TYPE(PERIPHC_NDFLASH,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_SDMMC4,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_VFIR,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_EPP,	CLOCK_TYPE_MCPA), +	TYPE(PERIPHC_MPE,	CLOCK_TYPE_MCPA), +	TYPE(PERIPHC_MIPI,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_UART1,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_UART2,	CLOCK_TYPE_PCMT), + +	/* 0x20 */ +	TYPE(PERIPHC_HOST1X,	CLOCK_TYPE_MCPA), +	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE), +	TYPE(PERIPHC_TVO,	CLOCK_TYPE_PDCT), +	TYPE(PERIPHC_HDMI,	CLOCK_TYPE_PDCT), +	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE), +	TYPE(PERIPHC_TVDAC,	CLOCK_TYPE_PDCT), +	TYPE(PERIPHC_I2C2,	CLOCK_TYPE_PCMT16), +	TYPE(PERIPHC_EMC,	CLOCK_TYPE_MCPT), + +	/* 0x28 */ +	TYPE(PERIPHC_UART3,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE), +	TYPE(PERIPHC_VI,	CLOCK_TYPE_MCPA), +	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE), +	TYPE(PERIPHC_NONE,	CLOCK_TYPE_NONE), +	TYPE(PERIPHC_SPI4,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_I2C3,	CLOCK_TYPE_PCMT16), +	TYPE(PERIPHC_SDMMC3,	CLOCK_TYPE_PCMT), + +	/* 0x30 */ +	TYPE(PERIPHC_UART4,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_UART5,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_VDE,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_OWR,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_NOR,	CLOCK_TYPE_PCMT), +	TYPE(PERIPHC_CSITE,	CLOCK_TYPE_PCMT), +}; + +/* + * This array translates a periph_id to a periphc_internal_id + * + * Not present/matched up: + *	uint vi_sensor;	 _VI_SENSOR_0,		0x1A8 + *	SPDIF - which is both 0x08 and 0x0c + * + */ +#define NONE(name) (-1) +#define OFFSET(name, value) PERIPHC_ ## name +static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = { +	/* Low word: 31:0 */ +	NONE(CPU), +	NONE(RESERVED1), +	NONE(RESERVED2), +	NONE(AC97), +	NONE(RTC), +	NONE(TMR), +	PERIPHC_UART1, +	PERIPHC_UART2,	/* and vfir 0x68 */ + +	/* 0x08 */ +	NONE(GPIO), +	PERIPHC_SDMMC2, +	NONE(SPDIF),		/* 0x08 and 0x0c, unclear which to use */ +	PERIPHC_I2S1, +	PERIPHC_I2C1, +	PERIPHC_NDFLASH, +	PERIPHC_SDMMC1, +	PERIPHC_SDMMC4, + +	/* 0x10 */ +	PERIPHC_TWC, +	PERIPHC_PWM, +	PERIPHC_I2S2, +	PERIPHC_EPP, +	PERIPHC_VI, +	PERIPHC_G2D, +	NONE(USBD), +	NONE(ISP), + +	/* 0x18 */ +	PERIPHC_G3D, +	PERIPHC_IDE0, +	PERIPHC_DISP2, +	PERIPHC_DISP1, +	PERIPHC_HOST1X, +	NONE(VCP), +	NONE(RESERVED30), +	NONE(CACHE2), + +	/* Middle word: 63:32 */ +	NONE(MEM), +	NONE(AHBDMA), +	NONE(APBDMA), +	NONE(RESERVED35), +	NONE(KBC), +	NONE(STAT_MON), +	NONE(PMC), +	NONE(FUSE), + +	/* 0x28 */ +	NONE(KFUSE), +	NONE(SBC1),	/* SBC1, 0x34, is this SPI1? */ +	PERIPHC_NOR, +	PERIPHC_SPI1, +	PERIPHC_SPI2, +	PERIPHC_XIO, +	PERIPHC_SPI3, +	PERIPHC_DVC_I2C, + +	/* 0x30 */ +	NONE(DSI), +	PERIPHC_TVO,	/* also CVE 0x40 */ +	PERIPHC_MIPI, +	PERIPHC_HDMI, +	PERIPHC_CSITE, +	PERIPHC_TVDAC, +	PERIPHC_I2C2, +	PERIPHC_UART3, + +	/* 0x38 */ +	NONE(RESERVED56), +	PERIPHC_EMC, +	NONE(USB2), +	NONE(USB3), +	PERIPHC_MPE, +	PERIPHC_VDE, +	NONE(BSEA), +	NONE(BSEV), + +	/* Upper word 95:64 */ +	NONE(SPEEDO), +	PERIPHC_UART4, +	PERIPHC_UART5, +	PERIPHC_I2C3, +	PERIPHC_SPI4, +	PERIPHC_SDMMC3, +	NONE(PCIE), +	PERIPHC_OWR, + +	/* 0x48 */ +	NONE(AFI), +	NONE(CORESIGHT), +	NONE(RESERVED74), +	NONE(AVPUCQ), +	NONE(RESERVED76), +	NONE(RESERVED77), +	NONE(RESERVED78), +	NONE(RESERVED79), + +	/* 0x50 */ +	NONE(RESERVED80), +	NONE(RESERVED81), +	NONE(RESERVED82), +	NONE(RESERVED83), +	NONE(IRAMA), +	NONE(IRAMB), +	NONE(IRAMC), +	NONE(IRAMD), + +	/* 0x58 */ +	NONE(CRAM2), +}; + +/* + * Get the oscillator frequency, from the corresponding hardware configuration + * field. T20 has 4 frequencies that it supports. + */ +enum clock_osc_freq clock_get_osc_freq(void) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	reg = readl(&clkrst->crc_osc_ctrl); +	return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; +} + +/* Returns a pointer to the clock source register for a peripheral */ +u32 *get_periph_source_reg(enum periph_id periph_id) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	enum periphc_internal_id internal_id; + +	assert(clock_periph_id_isvalid(periph_id)); +	internal_id = periph_id_to_internal_id[periph_id]; +	assert(internal_id != -1); +	return &clkrst->crc_clk_src[internal_id]; +} + +/** + * Given a peripheral ID and the required source clock, this returns which + * value should be programmed into the source mux for that peripheral. + * + * There is special code here to handle the one source type with 5 sources. + * + * @param periph_id	peripheral to start + * @param source	PLL id of required parent clock + * @param mux_bits	Set to number of bits in mux register: 2 or 4 + * @param divider_bits	Set to number of divider bits (8 or 16) + * @return mux value (0-4, or -1 if not found) + */ +int get_periph_clock_source(enum periph_id periph_id, +		enum clock_id parent, int *mux_bits, int *divider_bits) +{ +	enum clock_type_id type; +	enum periphc_internal_id internal_id; +	int mux; + +	assert(clock_periph_id_isvalid(periph_id)); + +	internal_id = periph_id_to_internal_id[periph_id]; +	assert(periphc_internal_id_isvalid(internal_id)); + +	type = clock_periph_type[internal_id]; +	assert(clock_type_id_isvalid(type)); + +	/* +	 * Special cases here for the clock with a 4-bit source mux and I2C +	 * with its 16-bit divisor +	 */ +	if (type == CLOCK_TYPE_PCXTS) +		*mux_bits = MASK_BITS_31_28; +	else +		*mux_bits = MASK_BITS_31_30; +	if (type == CLOCK_TYPE_PCMT16) +		*divider_bits = 16; +	else +		*divider_bits = 8; + +	for (mux = 0; mux < CLOCK_MAX_MUX; mux++) +		if (clock_source[type][mux] == parent) +			return mux; + +	/* +	 * Not found: it might be looking for the 'S' in CLOCK_TYPE_PCXTS +	 * which is not in our table. If not, then they are asking for a +	 * source which this peripheral can't access through its mux. +	 */ +	assert(type == CLOCK_TYPE_PCXTS); +	assert(parent == CLOCK_ID_SFROM32KHZ); +	if (type == CLOCK_TYPE_PCXTS && parent == CLOCK_ID_SFROM32KHZ) +		return 4;	/* mux value for this clock */ + +	/* if we get here, either us or the caller has made a mistake */ +	printf("Caller requested bad clock: periph=%d, parent=%d\n", periph_id, +		parent); +	return -1; +} + +void clock_set_enable(enum periph_id periph_id, int enable) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 *clk = &clkrst->crc_clk_out_enb[PERIPH_REG(periph_id)]; +	u32 reg; + +	/* Enable/disable the clock to this peripheral */ +	assert(clock_periph_id_isvalid(periph_id)); +	reg = readl(clk); +	if (enable) +		reg |= PERIPH_MASK(periph_id); +	else +		reg &= ~PERIPH_MASK(periph_id); +	writel(reg, clk); +} + +void reset_set_enable(enum periph_id periph_id, int enable) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 *reset = &clkrst->crc_rst_dev[PERIPH_REG(periph_id)]; +	u32 reg; + +	/* Enable/disable reset to the peripheral */ +	assert(clock_periph_id_isvalid(periph_id)); +	reg = readl(reset); +	if (enable) +		reg |= PERIPH_MASK(periph_id); +	else +		reg &= ~PERIPH_MASK(periph_id); +	writel(reg, reset); +} + +#ifdef CONFIG_OF_CONTROL +/* + * Convert a device tree clock ID to our peripheral ID. They are mostly + * the same but we are very cautious so we check that a valid clock ID is + * provided. + * + * @param clk_id	Clock ID according to tegra20 device tree binding + * @return peripheral ID, or PERIPH_ID_NONE if the clock ID is invalid + */ +enum periph_id clk_id_to_periph_id(int clk_id) +{ +	if (clk_id > PERIPH_ID_COUNT) +		return PERIPH_ID_NONE; + +	switch (clk_id) { +	case PERIPH_ID_RESERVED1: +	case PERIPH_ID_RESERVED2: +	case PERIPH_ID_RESERVED30: +	case PERIPH_ID_RESERVED35: +	case PERIPH_ID_RESERVED56: +	case PERIPH_ID_RESERVED74: +	case PERIPH_ID_RESERVED76: +	case PERIPH_ID_RESERVED77: +	case PERIPH_ID_RESERVED78: +	case PERIPH_ID_RESERVED79: +	case PERIPH_ID_RESERVED80: +	case PERIPH_ID_RESERVED81: +	case PERIPH_ID_RESERVED82: +	case PERIPH_ID_RESERVED83: +	case PERIPH_ID_RESERVED91: +		return PERIPH_ID_NONE; +	default: +		return clk_id; +	} +} +#endif /* CONFIG_OF_CONTROL */ + +void clock_early_init(void) +{ +	/* +	 * PLLP output frequency set to 216MHz +	 * PLLC output frequency set to 600Mhz +	 * +	 * TODO: Can we calculate these values instead of hard-coding? +	 */ +	switch (clock_get_osc_freq()) { +	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ +		clock_set_rate(CLOCK_ID_PERIPH, 432, 12, 1, 8); +		clock_set_rate(CLOCK_ID_CGENERAL, 600, 12, 0, 8); +		break; + +	case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ +		clock_set_rate(CLOCK_ID_PERIPH, 432, 26, 1, 8); +		clock_set_rate(CLOCK_ID_CGENERAL, 600, 26, 0, 8); +		break; + +	case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ +		clock_set_rate(CLOCK_ID_PERIPH, 432, 13, 1, 8); +		clock_set_rate(CLOCK_ID_CGENERAL, 600, 13, 0, 8); +		break; +	case CLOCK_OSC_FREQ_19_2: +	default: +		/* +		 * These are not supported. It is too early to print a +		 * message and the UART likely won't work anyway due to the +		 * oscillator being wrong. +		 */ +		break; +	} +} + +void arch_timer_init(void) +{ +} diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/crypto.c b/roms/u-boot/arch/arm/cpu/tegra20-common/crypto.c new file mode 100644 index 00000000..ec95d7ce --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/crypto.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <asm/errno.h> +#include "crypto.h" +#include "aes.h" + +static u8 zero_key[16]; + +#define AES_CMAC_CONST_RB 0x87  /* from RFC 4493, Figure 2.2 */ + +enum security_op { +	SECURITY_SIGN		= 1 << 0,	/* Sign the data */ +	SECURITY_ENCRYPT	= 1 << 1,	/* Encrypt the data */ +}; + +/** + * Shift a vector left by one bit + * + * \param in	Input vector + * \param out	Output vector + * \param size	Length of vector in bytes + */ +static void left_shift_vector(u8 *in, u8 *out, int size) +{ +	int carry = 0; +	int i; + +	for (i = size - 1; i >= 0; i--) { +		out[i] = (in[i] << 1) | carry; +		carry = in[i] >> 7;	/* get most significant bit */ +	} +} + +/** + * Sign a block of data, putting the result into dst. + * + * \param key			Input AES key, length AES_KEY_LENGTH + * \param key_schedule		Expanded key to use + * \param src			Source data of length 'num_aes_blocks' blocks + * \param dst			Destination buffer, length AES_KEY_LENGTH + * \param num_aes_blocks	Number of AES blocks to encrypt + */ +static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst, +			u32 num_aes_blocks) +{ +	u8 tmp_data[AES_KEY_LENGTH]; +	u8 left[AES_KEY_LENGTH]; +	u8 k1[AES_KEY_LENGTH]; +	u8 *cbc_chain_data; +	unsigned i; + +	cbc_chain_data = zero_key;	/* Convenient array of 0's for IV */ + +	/* compute K1 constant needed by AES-CMAC calculation */ +	for (i = 0; i < AES_KEY_LENGTH; i++) +		tmp_data[i] = 0; + +	aes_cbc_encrypt_blocks(key_schedule, tmp_data, left, 1); + +	left_shift_vector(left, k1, sizeof(left)); + +	if ((left[0] >> 7) != 0) /* get MSB of L */ +		k1[AES_KEY_LENGTH-1] ^= AES_CMAC_CONST_RB; + +	/* compute the AES-CMAC value */ +	for (i = 0; i < num_aes_blocks; i++) { +		/* Apply the chain data */ +		aes_apply_cbc_chain_data(cbc_chain_data, src, tmp_data); + +		/* for the final block, XOR K1 into the IV */ +		if (i == num_aes_blocks - 1) +			aes_apply_cbc_chain_data(tmp_data, k1, tmp_data); + +		/* encrypt the AES block */ +		aes_encrypt(tmp_data, key_schedule, dst); + +		debug("sign_obj: block %d of %d\n", i, num_aes_blocks); + +		/* Update pointers for next loop. */ +		cbc_chain_data = dst; +		src += AES_KEY_LENGTH; +	} +} + +/** + * Encrypt and sign a block of data (depending on security mode). + * + * \param key		Input AES key, length AES_KEY_LENGTH + * \param oper		Security operations mask to perform (enum security_op) + * \param src		Source data + * \param length	Size of source data + * \param sig_dst	Destination address for signature, AES_KEY_LENGTH bytes + */ +static int encrypt_and_sign(u8 *key, enum security_op oper, u8 *src, +			    u32 length, u8 *sig_dst) +{ +	u32 num_aes_blocks; +	u8 key_schedule[AES_EXPAND_KEY_LENGTH]; + +	debug("encrypt_and_sign: length = %d\n", length); + +	/* +	 * The only need for a key is for signing/checksum purposes, so +	 * if not encrypting, expand a key of 0s. +	 */ +	aes_expand_key(oper & SECURITY_ENCRYPT ? key : zero_key, key_schedule); + +	num_aes_blocks = (length + AES_KEY_LENGTH - 1) / AES_KEY_LENGTH; + +	if (oper & SECURITY_ENCRYPT) { +		/* Perform this in place, resulting in src being encrypted. */ +		debug("encrypt_and_sign: begin encryption\n"); +		aes_cbc_encrypt_blocks(key_schedule, src, src, num_aes_blocks); +		debug("encrypt_and_sign: end encryption\n"); +	} + +	if (oper & SECURITY_SIGN) { +		/* encrypt the data, overwriting the result in signature. */ +		debug("encrypt_and_sign: begin signing\n"); +		sign_object(key, key_schedule, src, sig_dst, num_aes_blocks); +		debug("encrypt_and_sign: end signing\n"); +	} + +	return 0; +} + +int sign_data_block(u8 *source, unsigned length, u8 *signature) +{ +	return encrypt_and_sign(zero_key, SECURITY_SIGN, source, +				length, signature); +} diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/crypto.h b/roms/u-boot/arch/arm/cpu/tegra20-common/crypto.h new file mode 100644 index 00000000..f59b9276 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/crypto.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#ifndef _CRYPTO_H_ +#define _CRYPTO_H_ + +/** + * Sign a block of data + * + * \param source	Source data + * \param length	Size of source data + * \param signature	Destination address for signature, AES_KEY_LENGTH bytes + */ +int sign_data_block(u8 *source, unsigned length, u8 *signature); + +#endif /* #ifndef _CRYPTO_H_ */ diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/emc.c b/roms/u-boot/arch/arm/cpu/tegra20-common/emc.c new file mode 100644 index 00000000..ed2462ab --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/emc.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <fdtdec.h> +#include <asm/io.h> +#include <asm/arch-tegra/ap.h> +#include <asm/arch-tegra/apb_misc.h> +#include <asm/arch/clock.h> +#include <asm/arch/emc.h> +#include <asm/arch/tegra.h> + +/* + * The EMC registers have shadow registers.  When the EMC clock is updated + * in the clock controller, the shadow registers are copied to the active + * registers, allowing glitchless memory bus frequency changes. + * This function updates the shadow registers for a new clock frequency, + * and relies on the clock lock on the emc clock to avoid races between + * multiple frequency changes + */ + +/* + * This table defines the ordering of the registers provided to + * tegra_set_mmc() + * TODO: Convert to fdt version once available + */ +static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { +	0x2c,	/* RC */ +	0x30,	/* RFC */ +	0x34,	/* RAS */ +	0x38,	/* RP */ +	0x3c,	/* R2W */ +	0x40,	/* W2R */ +	0x44,	/* R2P */ +	0x48,	/* W2P */ +	0x4c,	/* RD_RCD */ +	0x50,	/* WR_RCD */ +	0x54,	/* RRD */ +	0x58,	/* REXT */ +	0x5c,	/* WDV */ +	0x60,	/* QUSE */ +	0x64,	/* QRST */ +	0x68,	/* QSAFE */ +	0x6c,	/* RDV */ +	0x70,	/* REFRESH */ +	0x74,	/* BURST_REFRESH_NUM */ +	0x78,	/* PDEX2WR */ +	0x7c,	/* PDEX2RD */ +	0x80,	/* PCHG2PDEN */ +	0x84,	/* ACT2PDEN */ +	0x88,	/* AR2PDEN */ +	0x8c,	/* RW2PDEN */ +	0x90,	/* TXSR */ +	0x94,	/* TCKE */ +	0x98,	/* TFAW */ +	0x9c,	/* TRPAB */ +	0xa0,	/* TCLKSTABLE */ +	0xa4,	/* TCLKSTOP */ +	0xa8,	/* TREFBW */ +	0xac,	/* QUSE_EXTRA */ +	0x114,	/* FBIO_CFG6 */ +	0xb0,	/* ODT_WRITE */ +	0xb4,	/* ODT_READ */ +	0x104,	/* FBIO_CFG5 */ +	0x2bc,	/* CFG_DIG_DLL */ +	0x2c0,	/* DLL_XFORM_DQS */ +	0x2c4,	/* DLL_XFORM_QUSE */ +	0x2e0,	/* ZCAL_REF_CNT */ +	0x2e4,	/* ZCAL_WAIT_CNT */ +	0x2a8,	/* AUTO_CAL_INTERVAL */ +	0x2d0,	/* CFG_CLKTRIM_0 */ +	0x2d4,	/* CFG_CLKTRIM_1 */ +	0x2d8,	/* CFG_CLKTRIM_2 */ +}; + +struct emc_ctlr *emc_get_controller(const void *blob) +{ +	fdt_addr_t addr; +	int node; + +	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_EMC); +	if (node > 0) { +		addr = fdtdec_get_addr(blob, node, "reg"); +		if (addr != FDT_ADDR_T_NONE) +			return (struct emc_ctlr *)addr; +	} +	return NULL; +} + +/* Error codes we use */ +enum { +	ERR_NO_EMC_NODE = -10, +	ERR_NO_EMC_REG, +	ERR_NO_FREQ, +	ERR_FREQ_NOT_FOUND, +	ERR_BAD_REGS, +	ERR_NO_RAM_CODE, +	ERR_RAM_CODE_NOT_FOUND, +}; + +/** + * Find EMC tables for the given ram code. + * + * The tegra EMC binding has two options, one using the ram code and one not. + * We detect which is in use by looking for the nvidia,use-ram-code property. + * If this is not present, then the EMC tables are directly below 'node', + * otherwise we select the correct emc-tables subnode based on the 'ram_code' + * value. + * + * @param blob		Device tree blob + * @param node		EMC node (nvidia,tegra20-emc compatible string) + * @param ram_code	RAM code to select (0-3, or -1 if unknown) + * @return 0 if ok, otherwise a -ve ERR_ code (see enum above) + */ +static int find_emc_tables(const void *blob, int node, int ram_code) +{ +	int need_ram_code; +	int depth; +	int offset; + +	/* If we are using RAM codes, scan through the tables for our code */ +	need_ram_code = fdtdec_get_bool(blob, node, "nvidia,use-ram-code"); +	if (!need_ram_code) +		return node; +	if (ram_code == -1) { +		debug("%s: RAM code required but not supplied\n", __func__); +		return ERR_NO_RAM_CODE; +	} + +	offset = node; +	depth = 0; +	do { +		/* +		 * Sadly there is no compatible string so we cannot use +		 * fdtdec_next_compatible_subnode(). +		 */ +		offset = fdt_next_node(blob, offset, &depth); +		if (depth <= 0) +			break; + +		/* Make sure this is a direct subnode */ +		if (depth != 1) +			continue; +		if (strcmp("emc-tables", fdt_get_name(blob, offset, NULL))) +			continue; + +		if (fdtdec_get_int(blob, offset, "nvidia,ram-code", -1) +				== ram_code) +			return offset; +	} while (1); + +	debug("%s: Could not find tables for RAM code %d\n", __func__, +	      ram_code); +	return ERR_RAM_CODE_NOT_FOUND; +} + +/** + * Decode the EMC node of the device tree, returning a pointer to the emc + * controller and the table to be used for the given rate. + * + * @param blob	Device tree blob + * @param rate	Clock speed of memory controller in Hz (=2x memory bus rate) + * @param emcp	Returns address of EMC controller registers + * @param tablep Returns pointer to table to program into EMC. There are + *		TEGRA_EMC_NUM_REGS entries, destined for offsets as per the + *		emc_reg_addr array. + * @return 0 if ok, otherwise a -ve error code which will allow someone to + * figure out roughly what went wrong by looking at this code. + */ +static int decode_emc(const void *blob, unsigned rate, struct emc_ctlr **emcp, +		      const u32 **tablep) +{ +	struct apb_misc_pp_ctlr *pp = +		(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE; +	int ram_code; +	int depth; +	int node; + +	ram_code = (readl(&pp->strapping_opt_a) & RAM_CODE_MASK) +			>> RAM_CODE_SHIFT; +	/* +	 * The EMC clock rate is twice the bus rate, and the bus rate is +	 * measured in kHz +	 */ +	rate = rate / 2 / 1000; + +	node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_EMC); +	if (node < 0) { +		debug("%s: No EMC node found in FDT\n", __func__); +		return ERR_NO_EMC_NODE; +	} +	*emcp = (struct emc_ctlr *)fdtdec_get_addr(blob, node, "reg"); +	if (*emcp == (struct emc_ctlr *)FDT_ADDR_T_NONE) { +		debug("%s: No EMC node reg property\n", __func__); +		return ERR_NO_EMC_REG; +	} + +	/* Work out the parent node which contains our EMC tables */ +	node = find_emc_tables(blob, node, ram_code & 3); +	if (node < 0) +		return node; + +	depth = 0; +	for (;;) { +		int node_rate; + +		node = fdtdec_next_compatible_subnode(blob, node, +				COMPAT_NVIDIA_TEGRA20_EMC_TABLE, &depth); +		if (node < 0) +			break; +		node_rate = fdtdec_get_int(blob, node, "clock-frequency", -1); +		if (node_rate == -1) { +			debug("%s: Missing clock-frequency\n", __func__); +			return ERR_NO_FREQ; /* we expect this property */ +		} + +		if (node_rate == rate) +			break; +	} +	if (node < 0) { +		debug("%s: No node found for clock frequency %d\n", __func__, +		      rate); +		return ERR_FREQ_NOT_FOUND; +	} + +	*tablep = fdtdec_locate_array(blob, node, "nvidia,emc-registers", +				      TEGRA_EMC_NUM_REGS); +	if (!*tablep) { +		debug("%s: node '%s' array missing / wrong size\n", __func__, +		      fdt_get_name(blob, node, NULL)); +		return ERR_BAD_REGS; +	} + +	/* All seems well */ +	return 0; +} + +int tegra_set_emc(const void *blob, unsigned rate) +{ +	struct emc_ctlr *emc; +	const u32 *table = NULL; +	int err, i; + +	err = decode_emc(blob, rate, &emc, &table); +	if (err) { +		debug("Warning: no valid EMC (%d), memory timings unset\n", +		       err); +		return err; +	} + +	debug("%s: Table found, setting EMC values as follows:\n", __func__); +	for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) { +		u32 value = fdt32_to_cpu(table[i]); +		u32 addr = (uintptr_t)emc + emc_reg_addr[i]; + +		debug("   %#x: %#x\n", addr, value); +		writel(value, addr); +	} + +	/* trigger emc with new settings */ +	clock_adjust_periph_pll_div(PERIPH_ID_EMC, CLOCK_ID_MEMORY, +				clock_get_rate(CLOCK_ID_MEMORY), NULL); +	debug("EMC clock set to %lu\n", +	      clock_get_periph_rate(PERIPH_ID_EMC, CLOCK_ID_MEMORY)); + +	return 0; +} diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/funcmux.c b/roms/u-boot/arch/arm/cpu/tegra20-common/funcmux.c new file mode 100644 index 00000000..0df4a073 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/funcmux.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +/* Tegra20 high-level function multiplexing */ +#include <common.h> +#include <asm/arch/clock.h> +#include <asm/arch/funcmux.h> +#include <asm/arch/pinmux.h> + +/* + * The PINMUX macro is used to set up pinmux tables. + */ +#define PINMUX(grp, mux, pupd, tri)                   \ +	{PMUX_PINGRP_##grp, PMUX_FUNC_##mux, PMUX_PULL_##pupd, PMUX_TRI_##tri} + +static const struct pmux_pingrp_config disp1_default[] = { +	PINMUX(LDI,   DISPA,      NORMAL,    NORMAL), +	PINMUX(LHP0,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LHP1,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LHP2,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LHS,   DISPA,      NORMAL,    NORMAL), +	PINMUX(LM0,   RSVD4,      NORMAL,    NORMAL), +	PINMUX(LPP,   DISPA,      NORMAL,    NORMAL), +	PINMUX(LPW0,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LPW2,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LSC0,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LSPI,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LVP1,  DISPA,      NORMAL,    NORMAL), +	PINMUX(LVS,   DISPA,      NORMAL,    NORMAL), +	PINMUX(SLXD,  SPDIF,      NORMAL,    NORMAL), +}; + + +int funcmux_select(enum periph_id id, int config) +{ +	int bad_config = config != FUNCMUX_DEFAULT; + +	switch (id) { +	case PERIPH_ID_UART1: +		switch (config) { +		case FUNCMUX_UART1_IRRX_IRTX: +			pinmux_set_func(PMUX_PINGRP_IRRX, PMUX_FUNC_UARTA); +			pinmux_set_func(PMUX_PINGRP_IRTX, PMUX_FUNC_UARTA); +			pinmux_tristate_disable(PMUX_PINGRP_IRRX); +			pinmux_tristate_disable(PMUX_PINGRP_IRTX); +			break; +		case FUNCMUX_UART1_UAA_UAB: +			pinmux_set_func(PMUX_PINGRP_UAA, PMUX_FUNC_UARTA); +			pinmux_set_func(PMUX_PINGRP_UAB, PMUX_FUNC_UARTA); +			pinmux_tristate_disable(PMUX_PINGRP_UAA); +			pinmux_tristate_disable(PMUX_PINGRP_UAB); +			bad_config = 0; +			break; +		case FUNCMUX_UART1_GPU: +			pinmux_set_func(PMUX_PINGRP_GPU, PMUX_FUNC_UARTA); +			pinmux_tristate_disable(PMUX_PINGRP_GPU); +			bad_config = 0; +			break; +		case FUNCMUX_UART1_SDIO1: +			pinmux_set_func(PMUX_PINGRP_SDIO1, PMUX_FUNC_UARTA); +			pinmux_tristate_disable(PMUX_PINGRP_SDIO1); +			bad_config = 0; +			break; +		} +		if (!bad_config) { +			/* +			 * Tegra appears to boot with function UARTA pre- +			 * selected on mux group SDB. If two mux groups are +			 * both set to the same function, it's unclear which +			 * group's pins drive the RX signals into the HW. +			 * For UARTA, SDB certainly overrides group IRTX in +			 * practice. To solve this, configure some alternative +			 * function on SDB to avoid the conflict. Also, tri- +			 * state the group to avoid driving any signal onto it +			 * until we know what's connected. +			 */ +			pinmux_tristate_enable(PMUX_PINGRP_SDB); +			pinmux_set_func(PMUX_PINGRP_SDB,  PMUX_FUNC_SDIO3); +		} +		break; + +	case PERIPH_ID_UART2: +		if (config == FUNCMUX_UART2_UAD) { +			pinmux_set_func(PMUX_PINGRP_UAD, PMUX_FUNC_UARTB); +			pinmux_tristate_disable(PMUX_PINGRP_UAD); +		} +		break; + +	case PERIPH_ID_UART4: +		if (config == FUNCMUX_UART4_GMC) { +			pinmux_set_func(PMUX_PINGRP_GMC, PMUX_FUNC_UARTD); +			pinmux_tristate_disable(PMUX_PINGRP_GMC); +		} +		break; + +	case PERIPH_ID_DVC_I2C: +		/* there is only one selection, pinmux_config is ignored */ +		if (config == FUNCMUX_DVC_I2CP) { +			pinmux_set_func(PMUX_PINGRP_I2CP, PMUX_FUNC_I2C); +			pinmux_tristate_disable(PMUX_PINGRP_I2CP); +		} +		break; + +	case PERIPH_ID_I2C1: +		/* support pinmux_config of 0 for now, */ +		if (config == FUNCMUX_I2C1_RM) { +			pinmux_set_func(PMUX_PINGRP_RM, PMUX_FUNC_I2C); +			pinmux_tristate_disable(PMUX_PINGRP_RM); +		} +		break; +	case PERIPH_ID_I2C2: /* I2C2 */ +		switch (config) { +		case FUNCMUX_I2C2_DDC:	/* DDC pin group, select I2C2 */ +			pinmux_set_func(PMUX_PINGRP_DDC, PMUX_FUNC_I2C2); +			/* PTA to HDMI */ +			pinmux_set_func(PMUX_PINGRP_PTA, PMUX_FUNC_HDMI); +			pinmux_tristate_disable(PMUX_PINGRP_DDC); +			break; +		case FUNCMUX_I2C2_PTA:	/* PTA pin group, select I2C2 */ +			pinmux_set_func(PMUX_PINGRP_PTA, PMUX_FUNC_I2C2); +			/* set DDC_SEL to RSVDx (RSVD2 works for now) */ +			pinmux_set_func(PMUX_PINGRP_DDC, PMUX_FUNC_RSVD2); +			pinmux_tristate_disable(PMUX_PINGRP_PTA); +			bad_config = 0; +			break; +		} +		break; +	case PERIPH_ID_I2C3: /* I2C3 */ +		/* support pinmux_config of 0 for now */ +		if (config == FUNCMUX_I2C3_DTF) { +			pinmux_set_func(PMUX_PINGRP_DTF, PMUX_FUNC_I2C3); +			pinmux_tristate_disable(PMUX_PINGRP_DTF); +		} +		break; + +	case PERIPH_ID_SDMMC1: +		if (config == FUNCMUX_SDMMC1_SDIO1_4BIT) { +			pinmux_set_func(PMUX_PINGRP_SDIO1, PMUX_FUNC_SDIO1); +			pinmux_tristate_disable(PMUX_PINGRP_SDIO1); +		} +		break; + +	case PERIPH_ID_SDMMC2: +		if (config == FUNCMUX_SDMMC2_DTA_DTD_8BIT) { +			pinmux_set_func(PMUX_PINGRP_DTA, PMUX_FUNC_SDIO2); +			pinmux_set_func(PMUX_PINGRP_DTD, PMUX_FUNC_SDIO2); + +			pinmux_tristate_disable(PMUX_PINGRP_DTA); +			pinmux_tristate_disable(PMUX_PINGRP_DTD); +		} +		break; + +	case PERIPH_ID_SDMMC3: +		switch (config) { +		case FUNCMUX_SDMMC3_SDB_SLXA_8BIT: +			pinmux_set_func(PMUX_PINGRP_SLXA, PMUX_FUNC_SDIO3); +			pinmux_set_func(PMUX_PINGRP_SLXC, PMUX_FUNC_SDIO3); +			pinmux_set_func(PMUX_PINGRP_SLXD, PMUX_FUNC_SDIO3); +			pinmux_set_func(PMUX_PINGRP_SLXK, PMUX_FUNC_SDIO3); + +			pinmux_tristate_disable(PMUX_PINGRP_SLXA); +			pinmux_tristate_disable(PMUX_PINGRP_SLXC); +			pinmux_tristate_disable(PMUX_PINGRP_SLXD); +			pinmux_tristate_disable(PMUX_PINGRP_SLXK); +			/* fall through */ + +		case FUNCMUX_SDMMC3_SDB_4BIT: +			pinmux_set_func(PMUX_PINGRP_SDB, PMUX_FUNC_SDIO3); +			pinmux_set_func(PMUX_PINGRP_SDC, PMUX_FUNC_SDIO3); +			pinmux_set_func(PMUX_PINGRP_SDD, PMUX_FUNC_SDIO3); + +			pinmux_tristate_disable(PMUX_PINGRP_SDB); +			pinmux_tristate_disable(PMUX_PINGRP_SDC); +			pinmux_tristate_disable(PMUX_PINGRP_SDD); +			bad_config = 0; +			break; +		} +		break; + +	case PERIPH_ID_SDMMC4: +		switch (config) { +		case FUNCMUX_SDMMC4_ATC_ATD_8BIT: +			pinmux_set_func(PMUX_PINGRP_ATC, PMUX_FUNC_SDIO4); +			pinmux_set_func(PMUX_PINGRP_ATD, PMUX_FUNC_SDIO4); + +			pinmux_tristate_disable(PMUX_PINGRP_ATC); +			pinmux_tristate_disable(PMUX_PINGRP_ATD); +			break; + +		case FUNCMUX_SDMMC4_ATB_GMA_GME_8_BIT: +			pinmux_set_func(PMUX_PINGRP_GME, PMUX_FUNC_SDIO4); +			pinmux_tristate_disable(PMUX_PINGRP_GME); +			/* fall through */ + +		case FUNCMUX_SDMMC4_ATB_GMA_4_BIT: +			pinmux_set_func(PMUX_PINGRP_ATB, PMUX_FUNC_SDIO4); +			pinmux_set_func(PMUX_PINGRP_GMA, PMUX_FUNC_SDIO4); + +			pinmux_tristate_disable(PMUX_PINGRP_ATB); +			pinmux_tristate_disable(PMUX_PINGRP_GMA); +			bad_config = 0; +			break; +		} +		break; + +	case PERIPH_ID_KBC: +		if (config == FUNCMUX_DEFAULT) { +			enum pmux_pingrp grp[] = {PMUX_PINGRP_KBCA, +				PMUX_PINGRP_KBCB, PMUX_PINGRP_KBCC, +				PMUX_PINGRP_KBCD, PMUX_PINGRP_KBCE, +				PMUX_PINGRP_KBCF}; +			int i; + +			for (i = 0; i < ARRAY_SIZE(grp); i++) { +				pinmux_tristate_disable(grp[i]); +				pinmux_set_func(grp[i], PMUX_FUNC_KBC); +				pinmux_set_pullupdown(grp[i], PMUX_PULL_UP); +			} +		} +		break; + +	case PERIPH_ID_USB2: +		if (config == FUNCMUX_USB2_ULPI) { +			pinmux_set_func(PMUX_PINGRP_UAA, PMUX_FUNC_ULPI); +			pinmux_set_func(PMUX_PINGRP_UAB, PMUX_FUNC_ULPI); +			pinmux_set_func(PMUX_PINGRP_UDA, PMUX_FUNC_ULPI); + +			pinmux_tristate_disable(PMUX_PINGRP_UAA); +			pinmux_tristate_disable(PMUX_PINGRP_UAB); +			pinmux_tristate_disable(PMUX_PINGRP_UDA); +		} +		break; + +	case PERIPH_ID_SPI1: +		if (config == FUNCMUX_SPI1_GMC_GMD) { +			pinmux_set_func(PMUX_PINGRP_GMC, PMUX_FUNC_SFLASH); +			pinmux_set_func(PMUX_PINGRP_GMD, PMUX_FUNC_SFLASH); + +			pinmux_tristate_disable(PMUX_PINGRP_GMC); +			pinmux_tristate_disable(PMUX_PINGRP_GMD); +		} +		break; + +	case PERIPH_ID_NDFLASH: +		switch (config) { +		case FUNCMUX_NDFLASH_ATC: +			pinmux_set_func(PMUX_PINGRP_ATC, PMUX_FUNC_NAND); +			pinmux_tristate_disable(PMUX_PINGRP_ATC); +			break; +		case FUNCMUX_NDFLASH_KBC_8_BIT: +			pinmux_set_func(PMUX_PINGRP_KBCA, PMUX_FUNC_NAND); +			pinmux_set_func(PMUX_PINGRP_KBCC, PMUX_FUNC_NAND); +			pinmux_set_func(PMUX_PINGRP_KBCD, PMUX_FUNC_NAND); +			pinmux_set_func(PMUX_PINGRP_KBCE, PMUX_FUNC_NAND); +			pinmux_set_func(PMUX_PINGRP_KBCF, PMUX_FUNC_NAND); + +			pinmux_tristate_disable(PMUX_PINGRP_KBCA); +			pinmux_tristate_disable(PMUX_PINGRP_KBCC); +			pinmux_tristate_disable(PMUX_PINGRP_KBCD); +			pinmux_tristate_disable(PMUX_PINGRP_KBCE); +			pinmux_tristate_disable(PMUX_PINGRP_KBCF); + +			bad_config = 0; +			break; +		} +		break; +	case PERIPH_ID_DISP1: +		if (config == FUNCMUX_DEFAULT) { +			int i; + +			for (i = PMUX_PINGRP_LD0; i <= PMUX_PINGRP_LD17; i++) { +				pinmux_set_func(i, PMUX_FUNC_DISPA); +				pinmux_tristate_disable(i); +				pinmux_set_pullupdown(i, PMUX_PULL_NORMAL); +			} +			pinmux_config_pingrp_table(disp1_default, +						   ARRAY_SIZE(disp1_default)); +		} +		break; + +	default: +		debug("%s: invalid periph_id %d", __func__, id); +		return -1; +	} + +	if (bad_config) { +		debug("%s: invalid config %d for periph_id %d", __func__, +		      config, id); +		return -1; +	} + +	return 0; +} diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/pinmux.c b/roms/u-boot/arch/arm/cpu/tegra20-common/pinmux.c new file mode 100644 index 00000000..e484f991 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/pinmux.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +/* Tegra20 pin multiplexing functions */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/pinmux.h> + +/* + * This defines the order of the pin mux control bits in the registers. For + * some reason there is no correspendence between the tristate, pin mux and + * pullup/pulldown registers. + */ +enum pmux_ctlid { +	/* 0: APB_MISC_PP_PIN_MUX_CTL_A_0 */ +	MUXCTL_UAA, +	MUXCTL_UAB, +	MUXCTL_UAC, +	MUXCTL_UAD, +	MUXCTL_UDA, +	MUXCTL_RESERVED5, +	MUXCTL_ATE, +	MUXCTL_RM, + +	MUXCTL_ATB, +	MUXCTL_RESERVED9, +	MUXCTL_ATD, +	MUXCTL_ATC, +	MUXCTL_ATA, +	MUXCTL_KBCF, +	MUXCTL_KBCE, +	MUXCTL_SDMMC1, + +	/* 16: APB_MISC_PP_PIN_MUX_CTL_B_0 */ +	MUXCTL_GMA, +	MUXCTL_GMC, +	MUXCTL_HDINT, +	MUXCTL_SLXA, +	MUXCTL_OWC, +	MUXCTL_SLXC, +	MUXCTL_SLXD, +	MUXCTL_SLXK, + +	MUXCTL_UCA, +	MUXCTL_UCB, +	MUXCTL_DTA, +	MUXCTL_DTB, +	MUXCTL_RESERVED28, +	MUXCTL_DTC, +	MUXCTL_DTD, +	MUXCTL_DTE, + +	/* 32: APB_MISC_PP_PIN_MUX_CTL_C_0 */ +	MUXCTL_DDC, +	MUXCTL_CDEV1, +	MUXCTL_CDEV2, +	MUXCTL_CSUS, +	MUXCTL_I2CP, +	MUXCTL_KBCA, +	MUXCTL_KBCB, +	MUXCTL_KBCC, + +	MUXCTL_IRTX, +	MUXCTL_IRRX, +	MUXCTL_DAP1, +	MUXCTL_DAP2, +	MUXCTL_DAP3, +	MUXCTL_DAP4, +	MUXCTL_GMB, +	MUXCTL_GMD, + +	/* 48: APB_MISC_PP_PIN_MUX_CTL_D_0 */ +	MUXCTL_GME, +	MUXCTL_GPV, +	MUXCTL_GPU, +	MUXCTL_SPDO, +	MUXCTL_SPDI, +	MUXCTL_SDB, +	MUXCTL_SDC, +	MUXCTL_SDD, + +	MUXCTL_SPIH, +	MUXCTL_SPIG, +	MUXCTL_SPIF, +	MUXCTL_SPIE, +	MUXCTL_SPID, +	MUXCTL_SPIC, +	MUXCTL_SPIB, +	MUXCTL_SPIA, + +	/* 64: APB_MISC_PP_PIN_MUX_CTL_E_0 */ +	MUXCTL_LPW0, +	MUXCTL_LPW1, +	MUXCTL_LPW2, +	MUXCTL_LSDI, +	MUXCTL_LSDA, +	MUXCTL_LSPI, +	MUXCTL_LCSN, +	MUXCTL_LDC, + +	MUXCTL_LSCK, +	MUXCTL_LSC0, +	MUXCTL_LSC1, +	MUXCTL_LHS, +	MUXCTL_LVS, +	MUXCTL_LM0, +	MUXCTL_LM1, +	MUXCTL_LVP0, + +	/* 80: APB_MISC_PP_PIN_MUX_CTL_F_0 */ +	MUXCTL_LD0, +	MUXCTL_LD1, +	MUXCTL_LD2, +	MUXCTL_LD3, +	MUXCTL_LD4, +	MUXCTL_LD5, +	MUXCTL_LD6, +	MUXCTL_LD7, + +	MUXCTL_LD8, +	MUXCTL_LD9, +	MUXCTL_LD10, +	MUXCTL_LD11, +	MUXCTL_LD12, +	MUXCTL_LD13, +	MUXCTL_LD14, +	MUXCTL_LD15, + +	/* 96: APB_MISC_PP_PIN_MUX_CTL_G_0 */ +	MUXCTL_LD16, +	MUXCTL_LD17, +	MUXCTL_LHP1, +	MUXCTL_LHP2, +	MUXCTL_LVP1, +	MUXCTL_LHP0, +	MUXCTL_RESERVED102, +	MUXCTL_LPP, + +	MUXCTL_LDI, +	MUXCTL_PMC, +	MUXCTL_CRTP, +	MUXCTL_PTA, +	MUXCTL_RESERVED108, +	MUXCTL_KBCD, +	MUXCTL_GPU7, +	MUXCTL_DTF, + +	MUXCTL_NONE = -1, +}; + +/* + * And this defines the order of the pullup/pulldown controls which are again + * in a different order + */ +enum pmux_pullid { +	/* 0: APB_MISC_PP_PULLUPDOWN_REG_A_0 */ +	PUCTL_ATA, +	PUCTL_ATB, +	PUCTL_ATC, +	PUCTL_ATD, +	PUCTL_ATE, +	PUCTL_DAP1, +	PUCTL_DAP2, +	PUCTL_DAP3, + +	PUCTL_DAP4, +	PUCTL_DTA, +	PUCTL_DTB, +	PUCTL_DTC, +	PUCTL_DTD, +	PUCTL_DTE, +	PUCTL_DTF, +	PUCTL_GPV, + +	/* 16: APB_MISC_PP_PULLUPDOWN_REG_B_0 */ +	PUCTL_RM, +	PUCTL_I2CP, +	PUCTL_PTA, +	PUCTL_GPU7, +	PUCTL_KBCA, +	PUCTL_KBCB, +	PUCTL_KBCC, +	PUCTL_KBCD, + +	PUCTL_SPDI, +	PUCTL_SPDO, +	PUCTL_GPSLXAU, +	PUCTL_CRTP, +	PUCTL_SLXC, +	PUCTL_SLXD, +	PUCTL_SLXK, + +	/* 32: APB_MISC_PP_PULLUPDOWN_REG_C_0 */ +	PUCTL_CDEV1, +	PUCTL_CDEV2, +	PUCTL_SPIA, +	PUCTL_SPIB, +	PUCTL_SPIC, +	PUCTL_SPID, +	PUCTL_SPIE, +	PUCTL_SPIF, + +	PUCTL_SPIG, +	PUCTL_SPIH, +	PUCTL_IRTX, +	PUCTL_IRRX, +	PUCTL_GME, +	PUCTL_RESERVED45, +	PUCTL_XM2D, +	PUCTL_XM2C, + +	/* 48: APB_MISC_PP_PULLUPDOWN_REG_D_0 */ +	PUCTL_UAA, +	PUCTL_UAB, +	PUCTL_UAC, +	PUCTL_UAD, +	PUCTL_UCA, +	PUCTL_UCB, +	PUCTL_LD17, +	PUCTL_LD19_18, + +	PUCTL_LD21_20, +	PUCTL_LD23_22, +	PUCTL_LS, +	PUCTL_LC, +	PUCTL_CSUS, +	PUCTL_DDRC, +	PUCTL_SDC, +	PUCTL_SDD, + +	/* 64: APB_MISC_PP_PULLUPDOWN_REG_E_0 */ +	PUCTL_KBCF, +	PUCTL_KBCE, +	PUCTL_PMCA, +	PUCTL_PMCB, +	PUCTL_PMCC, +	PUCTL_PMCD, +	PUCTL_PMCE, +	PUCTL_CK32, + +	PUCTL_UDA, +	PUCTL_SDMMC1, +	PUCTL_GMA, +	PUCTL_GMB, +	PUCTL_GMC, +	PUCTL_GMD, +	PUCTL_DDC, +	PUCTL_OWC, + +	PUCTL_NONE = -1 +}; + +/* Convenient macro for defining pin group properties */ +#define PINALL(pingrp, f0, f1, f2, f3, mux, pupd)	\ +	{						\ +		.funcs = {				\ +			PMUX_FUNC_ ## f0,		\ +			PMUX_FUNC_ ## f1,		\ +			PMUX_FUNC_ ## f2,		\ +			PMUX_FUNC_ ## f3,		\ +		},					\ +		.ctl_id = mux,				\ +		.pull_id = pupd				\ +	} + +/* A normal pin group where the mux name and pull-up name match */ +#define PIN(pingrp, f0, f1, f2, f3) \ +	PINALL(pingrp, f0, f1, f2, f3, MUXCTL_##pingrp, PUCTL_##pingrp) + +/* A pin group where the pull-up name doesn't have a 1-1 mapping */ +#define PINP(pingrp, f0, f1, f2, f3, pupd) \ +	PINALL(pingrp, f0, f1, f2, f3, MUXCTL_##pingrp, PUCTL_##pupd) + +/* A pin group number which is not used */ +#define PIN_RESERVED \ +	PIN(NONE, RSVD1, RSVD2, RSVD3, RSVD4) + +#define DRVGRP(drvgrp) \ +	PINALL(drvgrp, RSVD1, RSVD2, RSVD3, RSVD4, MUXCTL_NONE, PUCTL_NONE) + +static const struct pmux_pingrp_desc tegra20_pingroups[] = { +	PIN(ATA,    IDE,       NAND,      GMI,       RSVD4), +	PIN(ATB,    IDE,       NAND,      GMI,       SDIO4), +	PIN(ATC,    IDE,       NAND,      GMI,       SDIO4), +	PIN(ATD,    IDE,       NAND,      GMI,       SDIO4), +	PIN(CDEV1,  OSC,       PLLA_OUT,  PLLM_OUT1, AUDIO_SYNC), +	PIN(CDEV2,  OSC,       AHB_CLK,   APB_CLK,   PLLP_OUT4), +	PIN(CSUS,   PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK), +	PIN(DAP1,   DAP1,      RSVD2,     GMI,       SDIO2), + +	PIN(DAP2,   DAP2,      TWC,       RSVD3,     GMI), +	PIN(DAP3,   DAP3,      RSVD2,     RSVD3,     RSVD4), +	PIN(DAP4,   DAP4,      RSVD2,     GMI,       RSVD4), +	PIN(DTA,    RSVD1,     SDIO2,     VI,        RSVD4), +	PIN(DTB,    RSVD1,     RSVD2,     VI,        SPI1), +	PIN(DTC,    RSVD1,     RSVD2,     VI,        RSVD4), +	PIN(DTD,    RSVD1,     SDIO2,     VI,        RSVD4), +	PIN(DTE,    RSVD1,     RSVD2,     VI,        SPI1), + +	PINP(GPU,   PWM,       UARTA,     GMI,       RSVD4,         GPSLXAU), +	PIN(GPV,    PCIE,      RSVD2,     RSVD3,     RSVD4), +	PIN(I2CP,   I2C,       RSVD2,     RSVD3,     RSVD4), +	PIN(IRTX,   UARTA,     UARTB,     GMI,       SPI4), +	PIN(IRRX,   UARTA,     UARTB,     GMI,       SPI4), +	PIN(KBCB,   KBC,       NAND,      SDIO2,     MIO), +	PIN(KBCA,   KBC,       NAND,      SDIO2,     EMC_TEST0_DLL), +	PINP(PMC,   PWR_ON,    PWR_INTR,  RSVD3,     RSVD4,         NONE), + +	PIN(PTA,    I2C2,      HDMI,      GMI,       RSVD4), +	PIN(RM,     I2C,       RSVD2,     RSVD3,     RSVD4), +	PIN(KBCE,   KBC,       NAND,      OWR,       RSVD4), +	PIN(KBCF,   KBC,       NAND,      TRACE,     MIO), +	PIN(GMA,    UARTE,     SPI3,      GMI,       SDIO4), +	PIN(GMC,    UARTD,     SPI4,      GMI,       SFLASH), +	PIN(SDMMC1, SDIO1,     RSVD2,     UARTE,     UARTA), +	PIN(OWC,    OWR,       RSVD2,     RSVD3,     RSVD4), + +	PIN(GME,    RSVD1,     DAP5,      GMI,       SDIO4), +	PIN(SDC,    PWM,       TWC,       SDIO3,     SPI3), +	PIN(SDD,    UARTA,     PWM,       SDIO3,     SPI3), +	PIN_RESERVED, +	PINP(SLXA,  PCIE,      SPI4,      SDIO3,     SPI2,          CRTP), +	PIN(SLXC,   SPDIF,     SPI4,      SDIO3,     SPI2), +	PIN(SLXD,   SPDIF,     SPI4,      SDIO3,     SPI2), +	PIN(SLXK,   PCIE,      SPI4,      SDIO3,     SPI2), + +	PIN(SPDI,   SPDIF,     RSVD2,     I2C,       SDIO2), +	PIN(SPDO,   SPDIF,     RSVD2,     I2C,       SDIO2), +	PIN(SPIA,   SPI1,      SPI2,      SPI3,      GMI), +	PIN(SPIB,   SPI1,      SPI2,      SPI3,      GMI), +	PIN(SPIC,   SPI1,      SPI2,      SPI3,      GMI), +	PIN(SPID,   SPI2,      SPI1,      SPI2_ALT,  GMI), +	PIN(SPIE,   SPI2,      SPI1,      SPI2_ALT,  GMI), +	PIN(SPIF,   SPI3,      SPI1,      SPI2,      RSVD4), + +	PIN(SPIG,   SPI3,      SPI2,      SPI2_ALT,  I2C), +	PIN(SPIH,   SPI3,      SPI2,      SPI2_ALT,  I2C), +	PIN(UAA,    SPI3,      MIPI_HS,   UARTA,     ULPI), +	PIN(UAB,    SPI2,      MIPI_HS,   UARTA,     ULPI), +	PIN(UAC,    OWR,       RSVD2,     RSVD3,     RSVD4), +	PIN(UAD,    UARTB,     SPDIF,     UARTA,     SPI4), +	PIN(UCA,    UARTC,     RSVD2,     GMI,       RSVD4), +	PIN(UCB,    UARTC,     PWM,       GMI,       RSVD4), + +	PIN_RESERVED, +	PIN(ATE,    IDE,       NAND,      GMI,       RSVD4), +	PIN(KBCC,   KBC,       NAND,      TRACE,     EMC_TEST1_DLL), +	PIN_RESERVED, +	PIN_RESERVED, +	PIN(GMB,    IDE,       NAND,      GMI,       GMI_INT), +	PIN(GMD,    RSVD1,     NAND,      GMI,       SFLASH), +	PIN(DDC,    I2C2,      RSVD2,     RSVD3,     RSVD4), + +	/* 64 */ +	PINP(LD0,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD1,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD2,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD3,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD4,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD5,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD6,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD7,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), + +	PINP(LD8,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD9,   DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD10,  DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD11,  DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD12,  DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD13,  DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD14,  DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD15,  DISPA,     DISPB,     XIO,       RSVD4,         LD17), + +	PINP(LD16,  DISPA,     DISPB,     XIO,       RSVD4,         LD17), +	PINP(LD17,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD17), +	PINP(LHP0,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD21_20), +	PINP(LHP1,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD19_18), +	PINP(LHP2,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD19_18), +	PINP(LVP0,  DISPA,     DISPB,     RSVD3,     RSVD4,         LC), +	PINP(LVP1,  DISPA,     DISPB,     RSVD3,     RSVD4,         LD21_20), +	PINP(HDINT, HDMI,      RSVD2,     RSVD3,     RSVD4,         LC), + +	PINP(LM0,   DISPA,     DISPB,     SPI3,      RSVD4,         LC), +	PINP(LM1,   DISPA,     DISPB,     RSVD3,     CRT,           LC), +	PINP(LVS,   DISPA,     DISPB,     XIO,       RSVD4,         LC), +	PINP(LSC0,  DISPA,     DISPB,     XIO,       RSVD4,         LC), +	PINP(LSC1,  DISPA,     DISPB,     SPI3,      HDMI,          LS), +	PINP(LSCK,  DISPA,     DISPB,     SPI3,      HDMI,          LS), +	PINP(LDC,   DISPA,     DISPB,     RSVD3,     RSVD4,         LS), +	PINP(LCSN,  DISPA,     DISPB,     SPI3,      RSVD4,         LS), + +	/* 96 */ +	PINP(LSPI,  DISPA,     DISPB,     XIO,       HDMI,          LC), +	PINP(LSDA,  DISPA,     DISPB,     SPI3,      HDMI,          LS), +	PINP(LSDI,  DISPA,     DISPB,     SPI3,      RSVD4,         LS), +	PINP(LPW0,  DISPA,     DISPB,     SPI3,      HDMI,          LS), +	PINP(LPW1,  DISPA,     DISPB,     RSVD3,     RSVD4,         LS), +	PINP(LPW2,  DISPA,     DISPB,     SPI3,      HDMI,          LS), +	PINP(LDI,   DISPA,     DISPB,     RSVD3,     RSVD4,         LD23_22), +	PINP(LHS,   DISPA,     DISPB,     XIO,       RSVD4,         LC), + +	PINP(LPP,   DISPA,     DISPB,     RSVD3,     RSVD4,         LD23_22), +	PIN_RESERVED, +	PIN(KBCD,   KBC,       NAND,      SDIO2,     MIO), +	PIN(GPU7,   RTCK,      RSVD2,     RSVD3,     RSVD4), +	PIN(DTF,    I2C3,      RSVD2,     VI,        RSVD4), +	PIN(UDA,    SPI1,      RSVD2,     UARTD,     ULPI), +	PIN(CRTP,   CRT,       RSVD2,     RSVD3,     RSVD4), +	PINP(SDB,   UARTA,     PWM,       SDIO3,     SPI2,          NONE), + +	/* these pin groups only have pullup and pull down control */ +	DRVGRP(CK32), +	DRVGRP(DDRC), +	DRVGRP(PMCA), +	DRVGRP(PMCB), +	DRVGRP(PMCC), +	DRVGRP(PMCD), +	DRVGRP(PMCE), +	DRVGRP(XM2C), +	DRVGRP(XM2D), +}; +const struct pmux_pingrp_desc *tegra_soc_pingroups = tegra20_pingroups; diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/pmu.c b/roms/u-boot/arch/arm/cpu/tegra20-common/pmu.c new file mode 100644 index 00000000..c595f70e --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/pmu.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <tps6586x.h> +#include <asm/io.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/ap.h> +#include <asm/arch-tegra/tegra_i2c.h> +#include <asm/arch-tegra/sys_proto.h> + +#define VDD_CORE_NOMINAL_T25	0x17	/* 1.3v */ +#define VDD_CPU_NOMINAL_T25	0x10	/* 1.125v */ + +#define VDD_CORE_NOMINAL_T20	0x16	/* 1.275v */ +#define VDD_CPU_NOMINAL_T20	0x0f	/* 1.1v */ + +#define VDD_RELATION		0x02	/*  50mv */ +#define VDD_TRANSITION_STEP	0x06	/* 150mv */ +#define VDD_TRANSITION_RATE	0x06	/* 3.52mv/us */ + +int pmu_set_nominal(void) +{ +	int core, cpu, bus; + +	/* by default, the table has been filled with T25 settings */ +	switch (tegra_get_chip_sku()) { +	case TEGRA_SOC_T20: +		core = VDD_CORE_NOMINAL_T20; +		cpu = VDD_CPU_NOMINAL_T20; +		break; +	case TEGRA_SOC_T25: +		core = VDD_CORE_NOMINAL_T25; +		cpu = VDD_CPU_NOMINAL_T25; +		break; +	default: +		debug("%s: Unknown SKU id\n", __func__); +		return -1; +	} + +	bus = tegra_i2c_get_dvc_bus_num(); +	if (bus == -1) { +		debug("%s: Cannot find DVC I2C bus\n", __func__); +		return -1; +	} +	tps6586x_init(bus); +	tps6586x_set_pwm_mode(TPS6586X_PWM_SM1); +	return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP, +				VDD_TRANSITION_RATE, VDD_RELATION); +} diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot.c b/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot.c new file mode 100644 index 00000000..5fdc4bbb --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot.c @@ -0,0 +1,372 @@ +/* + * (C) Copyright 2010 - 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/clock.h> +#include <asm/arch/emc.h> +#include <asm/arch/gp_padctrl.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/sdram_param.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/ap.h> +#include <asm/arch-tegra/apb_misc.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/fuse.h> +#include <asm/arch-tegra/warmboot.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_TEGRA_CLOCK_SCALING +#error "You must enable CONFIG_TEGRA_CLOCK_SCALING to use CONFIG_TEGRA_LP0" +#endif + +/* + * This is the place in SRAM where the SDRAM parameters are stored. There + * are 4 blocks, one for each RAM code + */ +#define SDRAM_PARAMS_BASE	(NV_PA_BASE_SRAM + 0x188) + +/* TODO: If we later add support for the Misc GP controller, refactor this */ +union xm2cfga_reg { +	struct { +		u32 reserved0:2; +		u32 hsm_en:1; +		u32 reserved1:2; +		u32 preemp_en:1; +		u32 vref_en:1; +		u32 reserved2:5; +		u32 cal_drvdn:5; +		u32 reserved3:3; +		u32 cal_drvup:5; +		u32 reserved4:3; +		u32 cal_drvdn_slwr:2; +		u32 cal_drvup_slwf:2; +	}; +	u32 word; +}; + +union xm2cfgd_reg { +	struct { +		u32 reserved0:2; +		u32 hsm_en:1; +		u32 schmt_en:1; +		u32 lpmd:2; +		u32 vref_en:1; +		u32 reserved1:5; +		u32 cal_drvdn:5; +		u32 reserved2:3; +		u32 cal_drvup:5; +		u32 reserved3:3; +		u32 cal_drvdn_slwr:2; +		u32 cal_drvup_slwf:2; +	}; +	u32 word; +}; + +/* + * TODO: This register is not documented in the TRM yet. We could move this + * into the EMC and give it a proper interface, but not while it is + * undocumented. + */ +union fbio_spare_reg { +	struct { +		u32 reserved:24; +		u32 cfg_wb0:8; +	}; +	u32 word; +}; + +/* We pack the resume information into these unions for later */ +union scratch2_reg { +	struct { +		u32 pllm_base_divm:5; +		u32 pllm_base_divn:10; +		u32 pllm_base_divp:3; +		u32 pllm_misc_lfcon:4; +		u32 pllm_misc_cpcon:4; +		u32 gp_xm2cfga_padctrl_preemp:1; +		u32 gp_xm2cfgd_padctrl_schmt:1; +		u32 osc_ctrl_xobp:1; +		u32 memory_type:3; +	}; +	u32 word; +}; + +union scratch4_reg { +	struct { +		u32 emc_clock_divider:8; +		u32 pllm_stable_time:8; +		u32 pllx_stable_time:8; +		u32 emc_fbio_spare_cfg_wb0:8; +	}; +	u32 word; +}; + +union scratch24_reg { +	struct { +		u32 emc_auto_cal_wait:8; +		u32 emc_pin_program_wait:8; +		u32 warmboot_wait:8; +		u32 reserved:8; +	}; +	u32 word; +}; + +int warmboot_save_sdram_params(void) +{ +	u32 ram_code; +	struct sdram_params sdram; +	struct apb_misc_pp_ctlr *apb_misc = +				(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE; +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	struct apb_misc_gp_ctlr *gp = +			(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE; +	struct emc_ctlr *emc = emc_get_controller(gd->fdt_blob); +	union scratch2_reg scratch2; +	union scratch4_reg scratch4; +	union scratch24_reg scratch24; +	union xm2cfga_reg xm2cfga; +	union xm2cfgd_reg xm2cfgd; +	union fbio_spare_reg fbio_spare; + +	/* get ram code that is used as index to array sdram_params in BCT */ +	ram_code = (readl(&apb_misc->strapping_opt_a) >> +			  STRAP_OPT_A_RAM_CODE_SHIFT) & 3; +	memcpy(&sdram, +	       (char *)((struct sdram_params *)SDRAM_PARAMS_BASE + ram_code), +	       sizeof(sdram)); + +	xm2cfga.word = readl(&gp->xm2cfga); +	xm2cfgd.word = readl(&gp->xm2cfgd); + +	scratch2.word = 0; +	scratch2.osc_ctrl_xobp = clock_get_osc_bypass(); + +	/* Get the memory PLL settings */ +	{ +		u32 divm, divn, divp, cpcon, lfcon; + +		if (clock_ll_read_pll(CLOCK_ID_MEMORY, &divm, &divn, &divp, +					&cpcon, &lfcon)) +			return -1; +		scratch2.pllm_base_divm = divm; +		scratch2.pllm_base_divn = divn; +		scratch2.pllm_base_divp = divp; +		scratch2.pllm_misc_cpcon = cpcon; +		scratch2.pllm_misc_lfcon = lfcon; +	} + +	scratch2.gp_xm2cfga_padctrl_preemp = xm2cfga.preemp_en; +	scratch2.gp_xm2cfgd_padctrl_schmt = xm2cfgd.schmt_en; +	scratch2.memory_type = sdram.memory_type; +	writel(scratch2.word, &pmc->pmc_scratch2); + +	/* collect data from various sources for pmc_scratch4 */ +	fbio_spare.word = readl(&emc->fbio_spare); +	scratch4.word = 0; +	scratch4.emc_fbio_spare_cfg_wb0 = fbio_spare.cfg_wb0; +	scratch4.emc_clock_divider = sdram.emc_clock_divider; +	scratch4.pllm_stable_time = -1; +	scratch4.pllx_stable_time = -1; +	writel(scratch4.word, &pmc->pmc_scratch4); + +	/* collect various data from sdram for pmc_scratch24 */ +	scratch24.word = 0; +	scratch24.emc_pin_program_wait = sdram.emc_pin_program_wait; +	scratch24.emc_auto_cal_wait = sdram.emc_auto_cal_wait; +	scratch24.warmboot_wait = sdram.warm_boot_wait; +	writel(scratch24.word, &pmc->pmc_scratch24); + +	return 0; +} + +static u32 get_major_version(void) +{ +	u32 major_id; +	struct apb_misc_gp_ctlr *gp = +		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE; + +	major_id = (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >> +			HIDREV_MAJORPREV_SHIFT; +	return major_id; +} + +static int is_production_mode_fuse_set(struct fuse_regs *fuse) +{ +	return readl(&fuse->production_mode); +} + +static int is_odm_production_mode_fuse_set(struct fuse_regs *fuse) +{ +	return readl(&fuse->security_mode); +} + +static int is_failure_analysis_mode(struct fuse_regs *fuse) +{ +	return readl(&fuse->fa); +} + +static int ap20_is_odm_production_mode(void) +{ +	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE; + +	if (!is_failure_analysis_mode(fuse) && +	    is_odm_production_mode_fuse_set(fuse)) +		return 1; +	else +		return 0; +} + +static int ap20_is_production_mode(void) +{ +	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE; + +	if (get_major_version() == 0) +		return 1; + +	if (!is_failure_analysis_mode(fuse) && +	    is_production_mode_fuse_set(fuse) && +	    !is_odm_production_mode_fuse_set(fuse)) +		return 1; +	else +		return 0; +} + +static enum fuse_operating_mode fuse_get_operation_mode(void) +{ +	u32 chip_id; +	struct apb_misc_gp_ctlr *gp = +		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE; + +	chip_id = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> +			HIDREV_CHIPID_SHIFT; +	if (chip_id == CHIPID_TEGRA20) { +		if (ap20_is_odm_production_mode()) { +			printf("!! odm_production_mode is not supported !!\n"); +			return MODE_UNDEFINED; +		} else +			if (ap20_is_production_mode()) +				return MODE_PRODUCTION; +			else +				return MODE_UNDEFINED; +	} +	return MODE_UNDEFINED; +} + +static void determine_crypto_options(int *is_encrypted, int *is_signed, +				     int *use_zero_key) +{ +	switch (fuse_get_operation_mode()) { +	case MODE_PRODUCTION: +		*is_encrypted = 0; +		*is_signed = 1; +		*use_zero_key = 1; +		break; +	case MODE_UNDEFINED: +	default: +		*is_encrypted = 0; +		*is_signed = 0; +		*use_zero_key  = 0; +		break; +	} +} + +static int sign_wb_code(u32 start, u32 length, int use_zero_key) +{ +	int err; +	u8 *source;		/* Pointer to source */ +	u8 *hash; + +	/* Calculate AES block parameters. */ +	source = (u8 *)(start + offsetof(struct wb_header, random_aes_block)); +	length -= offsetof(struct wb_header, random_aes_block); +	hash = (u8 *)(start + offsetof(struct wb_header, hash)); +	err = sign_data_block(source, length, hash); + +	return err; +} + +int warmboot_prepare_code(u32 seg_address, u32 seg_length) +{ +	int err = 0; +	u32 length;			/* length of the signed/encrypt code */ +	struct wb_header *dst_header;	/* Pointer to dest WB header */ +	int is_encrypted;		/* Segment is encrypted */ +	int is_signed;			/* Segment is signed */ +	int use_zero_key;		/* Use key of all zeros */ + +	/* Determine crypto options. */ +	determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key); + +	/* Get the actual code limits. */ +	length = roundup(((u32)wb_end - (u32)wb_start), 16); + +	/* +	 * The region specified by seg_address must be in SDRAM and must be +	 * nonzero in length. +	 */ +	if (seg_length == 0 || seg_address < NV_PA_SDRAM_BASE || +		seg_address + seg_length >= NV_PA_SDRAM_BASE + gd->ram_size) { +		err = -EFAULT; +		goto fail; +	} + +	/* Things must be 16-byte aligned. */ +	if ((seg_length & 0xF) || (seg_address & 0xF)) { +		err = -EINVAL; +		goto fail; +	} + +	/* Will the code fit? (destination includes wb_header + wb code) */ +	if (seg_length < (length + sizeof(struct wb_header))) { +		err = -EINVAL; +		goto fail; +	} + +	dst_header = (struct wb_header *)seg_address; +	memset((char *)dst_header, 0, sizeof(struct wb_header)); + +	/* Populate the random_aes_block as requested. */ +	{ +		u32 *aes_block = (u32 *)&(dst_header->random_aes_block); +		u32 *end = (u32 *)(((u32)aes_block) + +				   sizeof(dst_header->random_aes_block)); + +		do { +			*aes_block++ = 0; +		} while (aes_block < end); +	} + +	/* Populate the header. */ +	dst_header->length_insecure = length + sizeof(struct wb_header); +	dst_header->length_secure = length + sizeof(struct wb_header); +	dst_header->destination = NV_WB_RUN_ADDRESS; +	dst_header->entry_point = NV_WB_RUN_ADDRESS; +	dst_header->code_length = length; + +	if (is_encrypted) { +		printf("!!!! Encryption is not supported !!!!\n"); +		dst_header->length_insecure = 0; +		err = -EACCES; +		goto fail; +	} else +		/* copy the wb code directly following dst_header. */ +		memcpy((char *)(dst_header+1), (char *)wb_start, length); + +	if (is_signed) +		err = sign_wb_code(seg_address, dst_header->length_insecure, +				   use_zero_key); + +fail: +	if (err) +		printf("Warning: warmboot code copy failed (error=%d)\n", err); + +	return err; +} diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.c b/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.c new file mode 100644 index 00000000..27ce5f48 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.c @@ -0,0 +1,236 @@ +/* + * (C) Copyright 2010 - 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/flow.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/ap.h> +#include <asm/arch-tegra/apb_misc.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/warmboot.h> +#include "warmboot_avp.h" + +#define DEBUG_RESET_CORESIGHT + +void wb_start(void) +{ +	struct apb_misc_pp_ctlr *apb_misc = +				(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE; +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE; +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	union osc_ctrl_reg osc_ctrl; +	union pllx_base_reg pllx_base; +	union pllx_misc_reg pllx_misc; +	union scratch3_reg scratch3; +	u32 reg; + +	/* enable JTAG & TBE */ +	writel(CONFIG_CTL_TBE | CONFIG_CTL_JTAG, &apb_misc->cfg_ctl); + +	/* Are we running where we're supposed to be? */ +	asm volatile ( +		"adr	%0, wb_start;"	/* reg: wb_start address */ +		: "=r"(reg)		/* output */ +					/* no input, no clobber list */ +	); + +	if (reg != NV_WB_RUN_ADDRESS) +		goto do_reset; + +	/* Are we running with AVP? */ +	if (readl(NV_PA_PG_UP_BASE + PG_UP_TAG_0) != PG_UP_TAG_AVP) +		goto do_reset; + +#ifdef DEBUG_RESET_CORESIGHT +	/* Assert CoreSight reset */ +	reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]); +	reg |= SWR_CSITE_RST; +	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]); +#endif + +	/* TODO: Set the drive strength - maybe make this a board parameter? */ +	osc_ctrl.word = readl(&clkrst->crc_osc_ctrl); +	osc_ctrl.xofs = 4; +	osc_ctrl.xoe = 1; +	writel(osc_ctrl.word, &clkrst->crc_osc_ctrl); + +	/* Power up the CPU complex if necessary */ +	if (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU)) { +		reg = PWRGATE_TOGGLE_PARTID_CPU | PWRGATE_TOGGLE_START; +		writel(reg, &pmc->pmc_pwrgate_toggle); +		while (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU)) +			; +	} + +	/* Remove the I/O clamps from the CPU power partition. */ +	reg = readl(&pmc->pmc_remove_clamping); +	reg |= CPU_CLMP; +	writel(reg, &pmc->pmc_remove_clamping); + +	reg = EVENT_ZERO_VAL_20 | EVENT_MSEC | EVENT_MODE_STOP; +	writel(reg, &flow->halt_cop_events); + +	/* Assert CPU complex reset */ +	reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]); +	reg |= CPU_RST; +	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]); + +	/* Hold both CPUs in reset */ +	reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_CPURESET1 | CPU_CMPLX_DERESET0 | +	      CPU_CMPLX_DERESET1 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DBGRESET1; +	writel(reg, &clkrst->crc_cpu_cmplx_set); + +	/* Halt CPU1 at the flow controller for uni-processor configurations */ +	writel(EVENT_MODE_STOP, &flow->halt_cpu1_events); + +	/* +	 * Set the CPU reset vector. SCRATCH41 contains the physical +	 * address of the CPU-side restoration code. +	 */ +	reg = readl(&pmc->pmc_scratch41); +	writel(reg, EXCEP_VECTOR_CPU_RESET_VECTOR); + +	/* Select CPU complex clock source */ +	writel(CCLK_PLLP_BURST_POLICY, &clkrst->crc_cclk_brst_pol); + +	/* Start the CPU0 clock and stop the CPU1 clock */ +	reg = CPU_CMPLX_CPU_BRIDGE_CLKDIV_4 | CPU_CMPLX_CPU0_CLK_STP_RUN | +	      CPU_CMPLX_CPU1_CLK_STP_STOP; +	writel(reg, &clkrst->crc_clk_cpu_cmplx); + +	/* Enable the CPU complex clock */ +	reg = readl(&clkrst->crc_clk_out_enb[TEGRA_DEV_L]); +	reg |= CLK_ENB_CPU; +	writel(reg, &clkrst->crc_clk_out_enb[TEGRA_DEV_L]); + +	/* Make sure the resets were held for at least 2 microseconds */ +	reg = readl(TIMER_USEC_CNTR); +	while (readl(TIMER_USEC_CNTR) <= (reg + 2)) +		; + +#ifdef DEBUG_RESET_CORESIGHT +	/* +	 * De-assert CoreSight reset. +	 * NOTE: We're leaving the CoreSight clock on the oscillator for +	 *	now. It will be restored to its original clock source +	 *	when the CPU-side restoration code runs. +	 */ +	reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]); +	reg &= ~SWR_CSITE_RST; +	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]); +#endif + +	/* Unlock the CPU CoreSight interfaces */ +	reg = 0xC5ACCE55; +	writel(reg, CSITE_CPU_DBG0_LAR); +	writel(reg, CSITE_CPU_DBG1_LAR); + +	/* +	 * Sample the microsecond timestamp again. This is the time we must +	 * use when returning from LP0 for PLL stabilization delays. +	 */ +	reg = readl(TIMER_USEC_CNTR); +	writel(reg, &pmc->pmc_scratch1); + +	pllx_base.word = 0; +	pllx_misc.word = 0; +	scratch3.word = readl(&pmc->pmc_scratch3); + +	/* Get the OSC. For 19.2 MHz, use 19 to make the calculations easier */ +	reg = (readl(TIMER_USEC_CFG) & USEC_CFG_DIVISOR_MASK) + 1; + +	/* +	 * According to the TRM, for 19.2MHz OSC, the USEC_DIVISOR is 0x5f, and +	 * USEC_DIVIDEND is 0x04. So, if USEC_DIVISOR > 26, OSC is 19.2 MHz. +	 * +	 * reg is used to calculate the pllx freq, which is used to determine if +	 * to set dccon or not. +	 */ +	if (reg > 26) +		reg = 19; + +	/* PLLX_BASE.PLLX_DIVM */ +	if (scratch3.pllx_base_divm == reg) +		reg = 0; +	else +		reg = 1; + +	/* PLLX_BASE.PLLX_DIVN */ +	pllx_base.divn = scratch3.pllx_base_divn; +	reg = scratch3.pllx_base_divn << reg; + +	/* PLLX_BASE.PLLX_DIVP */ +	pllx_base.divp = scratch3.pllx_base_divp; +	reg = reg >> scratch3.pllx_base_divp; + +	pllx_base.bypass = 1; + +	/* PLLX_MISC_DCCON must be set for pllx frequency > 600 MHz. */ +	if (reg > 600) +		pllx_misc.dccon = 1; + +	/* PLLX_MISC_LFCON */ +	pllx_misc.lfcon = scratch3.pllx_misc_lfcon; + +	/* PLLX_MISC_CPCON */ +	pllx_misc.cpcon = scratch3.pllx_misc_cpcon; + +	writel(pllx_misc.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_misc); +	writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); + +	pllx_base.enable = 1; +	writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); +	pllx_base.bypass = 0; +	writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); + +	writel(0, flow->halt_cpu_events); + +	reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DERESET0; +	writel(reg, &clkrst->crc_cpu_cmplx_clr); + +	reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE | +	      PLLM_OUT1_RATIO_VAL_8; +	writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out[0]); + +	reg = SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 | SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 | +	      SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 | +	      SCLK_SYS_STATE_IDLE; +	writel(reg, &clkrst->crc_sclk_brst_pol); + +	/* avp_resume: no return after the write */ +	reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]); +	reg &= ~CPU_RST; +	writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]); + +	/* avp_halt: */ +avp_halt: +	reg = EVENT_MODE_STOP | EVENT_JTAG; +	writel(reg, flow->halt_cop_events); +	goto avp_halt; + +do_reset: +	/* +	 * Execution comes here if something goes wrong. The chip is reset and +	 * a cold boot is performed. +	 */ +	writel(SWR_TRIG_SYS_RST, &clkrst->crc_rst_dev[TEGRA_DEV_L]); +	goto do_reset; +} + +/* + * wb_end() is a dummy function, and must be directly following wb_start(), + * and is used to calculate the size of wb_start(). + */ +void wb_end(void) +{ +} diff --git a/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.h b/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.h new file mode 100644 index 00000000..7b86acb1 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra20-common/warmboot_avp.h @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2010, 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#ifndef _WARMBOOT_AVP_H_ +#define _WARMBOOT_AVP_H_ + +#define TEGRA_DEV_L			0 +#define TEGRA_DEV_H			1 +#define TEGRA_DEV_U			2 + +#define SIMPLE_PLLX			(CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE) +#define SIMPLE_PLLE			(CLOCK_ID_EPCI - CLOCK_ID_FIRST_SIMPLE) + +#define TIMER_USEC_CNTR			(NV_PA_TMRUS_BASE + 0) +#define TIMER_USEC_CFG			(NV_PA_TMRUS_BASE + 4) + +#define USEC_CFG_DIVISOR_MASK		0xffff + +#define CONFIG_CTL_TBE			(1 << 7) +#define CONFIG_CTL_JTAG			(1 << 6) + +#define CPU_RST				(1 << 0) +#define CLK_ENB_CPU			(1 << 0) +#define SWR_TRIG_SYS_RST		(1 << 2) +#define SWR_CSITE_RST			(1 << 9) + +#define PWRGATE_STATUS_CPU		(1 << 0) +#define PWRGATE_TOGGLE_PARTID_CPU	(0 << 0) +#define PWRGATE_TOGGLE_START		(1 << 8) + +#define CPU_CMPLX_CPU_BRIDGE_CLKDIV_4	(3 << 0) +#define CPU_CMPLX_CPU0_CLK_STP_STOP	(1 << 8) +#define CPU_CMPLX_CPU0_CLK_STP_RUN	(0 << 8) +#define CPU_CMPLX_CPU1_CLK_STP_STOP	(1 << 9) +#define CPU_CMPLX_CPU1_CLK_STP_RUN	(0 << 9) + +#define CPU_CMPLX_CPURESET0		(1 << 0) +#define CPU_CMPLX_CPURESET1		(1 << 1) +#define CPU_CMPLX_DERESET0		(1 << 4) +#define CPU_CMPLX_DERESET1		(1 << 5) +#define CPU_CMPLX_DBGRESET0		(1 << 12) +#define CPU_CMPLX_DBGRESET1		(1 << 13) + +#define PLLM_OUT1_RSTN_RESET_DISABLE	(1 << 0) +#define PLLM_OUT1_CLKEN_ENABLE		(1 << 1) +#define PLLM_OUT1_RATIO_VAL_8		(8 << 8) + +#define SCLK_SYS_STATE_IDLE		(1 << 28) +#define SCLK_SWAKE_FIQ_SRC_PLLM_OUT1	(7 << 12) +#define SCLK_SWAKE_IRQ_SRC_PLLM_OUT1	(7 << 8) +#define SCLK_SWAKE_RUN_SRC_PLLM_OUT1	(7 << 4) +#define SCLK_SWAKE_IDLE_SRC_PLLM_OUT1	(7 << 0) + +#define EVENT_ZERO_VAL_20		(20 << 0) +#define EVENT_MSEC			(1 << 24) +#define EVENT_JTAG			(1 << 28) +#define EVENT_MODE_STOP			(2 << 29) + +#define CCLK_PLLP_BURST_POLICY		0x20004444 + +#endif  | 
