diff options
Diffstat (limited to 'roms/u-boot/arch/arm/cpu/tegra-common')
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/Makefile | 16 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/ap.c | 166 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/board.c | 181 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/cache.c | 46 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/clock.c | 669 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/lowlevel_init.S | 26 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/pinmux-common.c | 508 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/tegra-common/sys_info.c | 31 | 
8 files changed, 1643 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/Makefile b/roms/u-boot/arch/arm/cpu/tegra-common/Makefile new file mode 100644 index 00000000..892556e6 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/Makefile @@ -0,0 +1,16 @@ +# +# (C) Copyright 2010,2011 Nvidia Corporation. +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +obj-y += ap.o +obj-y += board.o +obj-y += cache.o +obj-y += clock.o +obj-y += lowlevel_init.o +obj-y += pinmux-common.o +obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/ap.c b/roms/u-boot/arch/arm/cpu/tegra-common/ap.c new file mode 100644 index 00000000..91d70da6 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/ap.c @@ -0,0 +1,166 @@ +/* +* (C) Copyright 2010-2014 +* NVIDIA Corporation <www.nvidia.com> +* + * SPDX-License-Identifier:	GPL-2.0+ +*/ + +/* Tegra AP (Application Processor) code */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/gp_padctrl.h> +#include <asm/arch-tegra/ap.h> +#include <asm/arch-tegra/clock.h> +#include <asm/arch-tegra/fuse.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/scu.h> +#include <asm/arch-tegra/tegra.h> +#include <asm/arch-tegra/warmboot.h> + +int tegra_get_chip(void) +{ +	int rev; +	struct apb_misc_gp_ctlr *gp = +		(struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE; + +	/* +	 * This is undocumented, Chip ID is bits 15:8 of the register +	 * APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for +	 * Tegra30, 0x35 for T114, and 0x40 for Tegra124. +	 */ +	rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT; +	debug("%s: CHIPID is 0x%02X\n", __func__, rev); + +	return rev; +} + +int tegra_get_sku_info(void) +{ +	int sku_id; +	struct fuse_regs *fuse = (struct fuse_regs *)NV_PA_FUSE_BASE; + +	sku_id = readl(&fuse->sku_info) & 0xff; +	debug("%s: SKU info byte is 0x%02X\n", __func__, sku_id); + +	return sku_id; +} + +int tegra_get_chip_sku(void) +{ +	uint sku_id, chip_id; + +	chip_id = tegra_get_chip(); +	sku_id = tegra_get_sku_info(); + +	switch (chip_id) { +	case CHIPID_TEGRA20: +		switch (sku_id) { +		case SKU_ID_T20_7: +		case SKU_ID_T20: +			return TEGRA_SOC_T20; +		case SKU_ID_T25SE: +		case SKU_ID_AP25: +		case SKU_ID_T25: +		case SKU_ID_AP25E: +		case SKU_ID_T25E: +			return TEGRA_SOC_T25; +		} +		break; +	case CHIPID_TEGRA30: +		switch (sku_id) { +		case SKU_ID_T33: +		case SKU_ID_T30: +		case SKU_ID_TM30MQS_P_A3: +		default: +			return TEGRA_SOC_T30; +		} +		break; +	case CHIPID_TEGRA114: +		switch (sku_id) { +		case SKU_ID_T114_ENG: +		case SKU_ID_T114_1: +		default: +			return TEGRA_SOC_T114; +		} +		break; +	case CHIPID_TEGRA124: +		switch (sku_id) { +		case SKU_ID_T124_ENG: +		default: +			return TEGRA_SOC_T124; +		} +		break; +	} + +	/* unknown chip/sku id */ +	printf("%s: ERROR: UNKNOWN CHIP/SKU ID COMBO (0x%02X/0x%02X)\n", +		__func__, chip_id, sku_id); +	return TEGRA_SOC_UNKNOWN; +} + +static void enable_scu(void) +{ +	struct scu_ctlr *scu = (struct scu_ctlr *)NV_PA_ARM_PERIPHBASE; +	u32 reg; + +	/* Only enable the SCU on T20/T25 */ +	if (tegra_get_chip() != CHIPID_TEGRA20) +		return; + +	/* If SCU already setup/enabled, return */ +	if (readl(&scu->scu_ctrl) & SCU_CTRL_ENABLE) +		return; + +	/* Invalidate all ways for all processors */ +	writel(0xFFFF, &scu->scu_inv_all); + +	/* Enable SCU - bit 0 */ +	reg = readl(&scu->scu_ctrl); +	reg |= SCU_CTRL_ENABLE; +	writel(reg, &scu->scu_ctrl); +} + +static u32 get_odmdata(void) +{ +	/* +	 * ODMDATA is stored in the BCT in IRAM by the BootROM. +	 * The BCT start and size are stored in the BIT in IRAM. +	 * Read the data @ bct_start + (bct_size - 12). This works +	 * on BCTs for currently supported SoCs, which are locked down. +	 * If this changes in new chips, we can revisit this algorithm. +	 */ + +	u32 bct_start, odmdata; + +	bct_start = readl(NV_PA_BASE_SRAM + NVBOOTINFOTABLE_BCTPTR); +	odmdata = readl(bct_start + BCT_ODMDATA_OFFSET); + +	return odmdata; +} + +static void init_pmc_scratch(void) +{ +	struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 odmdata; +	int i; + +	/* SCRATCH0 is initialized by the boot ROM and shouldn't be cleared */ +	for (i = 0; i < 23; i++) +		writel(0, &pmc->pmc_scratch1+i); + +	/* ODMDATA is for kernel use to determine RAM size, LP config, etc. */ +	odmdata = get_odmdata(); +	writel(odmdata, &pmc->pmc_scratch20); +} + +void s_init(void) +{ +	/* Init PMC scratch memory */ +	init_pmc_scratch(); + +	enable_scu(); + +	/* init the cache */ +	config_cache(); +} diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/board.c b/roms/u-boot/arch/arm/cpu/tegra-common/board.c new file mode 100644 index 00000000..6a6faf4b --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/board.c @@ -0,0 +1,181 @@ +/* + *  (C) Copyright 2010-2014 + *  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/funcmux.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/board.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/sys_proto.h> +#include <asm/arch-tegra/warmboot.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { +	/* UARTs which we can enable */ +	UARTA	= 1 << 0, +	UARTB	= 1 << 1, +	UARTC	= 1 << 2, +	UARTD	= 1 << 3, +	UARTE	= 1 << 4, +	UART_COUNT = 5, +}; + +/* + * Boot ROM initializes the odmdata in APBDEV_PMC_SCRATCH20_0, + * so we are using this value to identify memory size. + */ + +unsigned int query_sdram_size(void) +{ +	struct pmc_ctlr *const pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; + +	reg = readl(&pmc->pmc_scratch20); +	debug("pmc->pmc_scratch20 (ODMData) = 0x%08x\n", reg); + +#if defined(CONFIG_TEGRA20) +	/* bits 30:28 in OdmData are used for RAM size on T20  */ +	reg &= 0x70000000; + +	switch ((reg) >> 28) { +	case 1: +		return 0x10000000;	/* 256 MB */ +	case 0: +	case 2: +	default: +		return 0x20000000;	/* 512 MB */ +	case 3: +		return 0x40000000;	/* 1GB */ +	} +#else	/* Tegra30/Tegra114 */ +	/* bits 31:28 in OdmData are used for RAM size on T30  */ +	switch ((reg) >> 28) { +	case 0: +	case 1: +	default: +		return 0x10000000;	/* 256 MB */ +	case 2: +		return 0x20000000;	/* 512 MB */ +	case 3: +		return 0x30000000;	/* 768 MB */ +	case 4: +		return 0x40000000;	/* 1GB */ +	case 8: +		return 0x7ff00000;	/* 2GB - 1MB */ +	} +#endif +} + +int dram_init(void) +{ +	/* We do not initialise DRAM here. We just query the size */ +	gd->ram_size = query_sdram_size(); +	return 0; +} + +#ifdef CONFIG_DISPLAY_BOARDINFO +int checkboard(void) +{ +	printf("Board: %s\n", sysinfo.board_string); +	return 0; +} +#endif	/* CONFIG_DISPLAY_BOARDINFO */ + +static int uart_configs[] = { +#if defined(CONFIG_TEGRA20) + #if defined(CONFIG_TEGRA_UARTA_UAA_UAB) +	FUNCMUX_UART1_UAA_UAB, + #elif defined(CONFIG_TEGRA_UARTA_GPU) +	FUNCMUX_UART1_GPU, + #elif defined(CONFIG_TEGRA_UARTA_SDIO1) +	FUNCMUX_UART1_SDIO1, + #else +	FUNCMUX_UART1_IRRX_IRTX, +#endif +	FUNCMUX_UART2_UAD, +	-1, +	FUNCMUX_UART4_GMC, +	-1, +#elif defined(CONFIG_TEGRA30) +	FUNCMUX_UART1_ULPI,	/* UARTA */ +	-1, +	-1, +	-1, +	-1, +#elif defined(CONFIG_TEGRA114) +	-1, +	-1, +	-1, +	FUNCMUX_UART4_GMI,	/* UARTD */ +	-1, +#else	/* Tegra124 */ +	FUNCMUX_UART1_KBC,	/* UARTA */ +	-1, +	-1, +	FUNCMUX_UART4_GPIO,	/* UARTD */ +	-1, +#endif +}; + +/** + * Set up the specified uarts + * + * @param uarts_ids	Mask containing UARTs to init (UARTx) + */ +static void setup_uarts(int uart_ids) +{ +	static enum periph_id id_for_uart[] = { +		PERIPH_ID_UART1, +		PERIPH_ID_UART2, +		PERIPH_ID_UART3, +		PERIPH_ID_UART4, +		PERIPH_ID_UART5, +	}; +	size_t i; + +	for (i = 0; i < UART_COUNT; i++) { +		if (uart_ids & (1 << i)) { +			enum periph_id id = id_for_uart[i]; + +			funcmux_select(id, uart_configs[i]); +			clock_ll_start_uart(id); +		} +	} +} + +void board_init_uart_f(void) +{ +	int uart_ids = 0;	/* bit mask of which UART ids to enable */ + +#ifdef CONFIG_TEGRA_ENABLE_UARTA +	uart_ids |= UARTA; +#endif +#ifdef CONFIG_TEGRA_ENABLE_UARTB +	uart_ids |= UARTB; +#endif +#ifdef CONFIG_TEGRA_ENABLE_UARTC +	uart_ids |= UARTC; +#endif +#ifdef CONFIG_TEGRA_ENABLE_UARTD +	uart_ids |= UARTD; +#endif +#ifdef CONFIG_TEGRA_ENABLE_UARTE +	uart_ids |= UARTE; +#endif +	setup_uarts(uart_ids); +} + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ +	/* Enable D-cache. I-cache is already enabled in start.S */ +	dcache_enable(); +} +#endif diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/cache.c b/roms/u-boot/arch/arm/cpu/tegra-common/cache.c new file mode 100644 index 00000000..94f5bce9 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/cache.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* Tegra cache routines */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch-tegra/ap.h> +#include <asm/arch/gp_padctrl.h> + +void config_cache(void) +{ +	u32 reg = 0; + +	/* enable SMP mode and FW for CPU0, by writing to Auxiliary Ctl reg */ +	asm volatile( +		"mrc p15, 0, r0, c1, c0, 1\n" +		"orr r0, r0, #0x41\n" +		"mcr p15, 0, r0, c1, c0, 1\n"); + +	/* Currently, only Tegra114+ needs this L2 cache change to boot Linux */ +	if (tegra_get_chip() < CHIPID_TEGRA114) +		return; + +	/* +	 * Systems with an architectural L2 cache must not use the PL310. +	 * Config L2CTLR here for a data RAM latency of 3 cycles. +	 */ +	asm("mrc p15, 1, %0, c9, c0, 2" : : "r" (reg)); +	reg &= ~7; +	reg |= 2; +	asm("mcr p15, 1, %0, c9, c0, 2" : : "r" (reg)); +} diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/clock.c b/roms/u-boot/arch/arm/cpu/tegra-common/clock.c new file mode 100644 index 00000000..11c74355 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/clock.c @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2010-2014, NVIDIA CORPORATION.  All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +/* Tegra SoC common 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> + +/* + * This is our record of the current clock rate of each clock. We don't + * fill all of these in since we are only really interested in clocks which + * we use as parents. + */ +static unsigned pll_rate[CLOCK_ID_COUNT]; + +/* + * The oscillator frequency is fixed to one of four set values. Based on this + * the other clocks are set up appropriately. + */ +static unsigned osc_freq[CLOCK_OSC_FREQ_COUNT] = { +	13000000, +	19200000, +	12000000, +	26000000, +}; + +/* return 1 if a peripheral ID is in range */ +#define clock_type_id_isvalid(id) ((id) >= 0 && \ +		(id) < CLOCK_TYPE_COUNT) + +char pllp_valid = 1;	/* PLLP is set up correctly */ + +/* return 1 if a periphc_internal_id is in range */ +#define periphc_internal_id_isvalid(id) ((id) >= 0 && \ +		(id) < PERIPHC_COUNT) + +/* number of clock outputs of a PLL */ +static const u8 pll_num_clkouts[] = { +	1,	/* PLLC */ +	1,	/* PLLM */ +	4,	/* PLLP */ +	1,	/* PLLA */ +	0,	/* PLLU */ +	0,	/* PLLD */ +}; + +int clock_get_osc_bypass(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_XOBP_MASK) >> OSC_XOBP_SHIFT; +} + +/* Returns a pointer to the registers of the given pll */ +static struct clk_pll *get_pll(enum clock_id clkid) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + +	assert(clock_id_is_pll(clkid)); +	return &clkrst->crc_pll[clkid]; +} + +int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn, +		u32 *divp, u32 *cpcon, u32 *lfcon) +{ +	struct clk_pll *pll = get_pll(clkid); +	u32 data; + +	assert(clkid != CLOCK_ID_USB); + +	/* Safety check, adds to code size but is small */ +	if (!clock_id_is_pll(clkid) || clkid == CLOCK_ID_USB) +		return -1; +	data = readl(&pll->pll_base); +	*divm = (data & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT; +	*divn = (data & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT; +	*divp = (data & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT; +	data = readl(&pll->pll_misc); +	*cpcon = (data & PLL_CPCON_MASK) >> PLL_CPCON_SHIFT; +	*lfcon = (data & PLL_LFCON_MASK) >> PLL_LFCON_SHIFT; + +	return 0; +} + +unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn, +		u32 divp, u32 cpcon, u32 lfcon) +{ +	struct clk_pll *pll = get_pll(clkid); +	u32 data; + +	/* +	 * We cheat by treating all PLL (except PLLU) in the same fashion. +	 * This works only because: +	 * - same fields are always mapped at same offsets, except DCCON +	 * - DCCON is always 0, doesn't conflict +	 * - M,N, P of PLLP values are ignored for PLLP +	 */ +	data = (cpcon << PLL_CPCON_SHIFT) | (lfcon << PLL_LFCON_SHIFT); +	writel(data, &pll->pll_misc); + +	data = (divm << PLL_DIVM_SHIFT) | (divn << PLL_DIVN_SHIFT) | +			(0 << PLL_BYPASS_SHIFT) | (1 << PLL_ENABLE_SHIFT); + +	if (clkid == CLOCK_ID_USB) +		data |= divp << PLLU_VCO_FREQ_SHIFT; +	else +		data |= divp << PLL_DIVP_SHIFT; +	writel(data, &pll->pll_base); + +	/* calculate the stable time */ +	return timer_get_us() + CLOCK_PLL_STABLE_DELAY_US; +} + +void clock_ll_set_source_divisor(enum periph_id periph_id, unsigned source, +			unsigned divisor) +{ +	u32 *reg = get_periph_source_reg(periph_id); +	u32 value; + +	value = readl(reg); + +	value &= ~OUT_CLK_SOURCE_31_30_MASK; +	value |= source << OUT_CLK_SOURCE_31_30_SHIFT; + +	value &= ~OUT_CLK_DIVISOR_MASK; +	value |= divisor << OUT_CLK_DIVISOR_SHIFT; + +	writel(value, reg); +} + +void clock_ll_set_source(enum periph_id periph_id, unsigned source) +{ +	u32 *reg = get_periph_source_reg(periph_id); + +	clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK, +			source << OUT_CLK_SOURCE_31_30_SHIFT); +} + +/** + * Given the parent's rate and the required rate for the children, this works + * out the peripheral clock divider to use, in 7.1 binary format. + * + * @param divider_bits	number of divider bits (8 or 16) + * @param parent_rate	clock rate of parent clock in Hz + * @param rate		required clock rate for this clock + * @return divider which should be used + */ +static int clk_get_divider(unsigned divider_bits, unsigned long parent_rate, +			   unsigned long rate) +{ +	u64 divider = parent_rate * 2; +	unsigned max_divider = 1 << divider_bits; + +	divider += rate - 1; +	do_div(divider, rate); + +	if ((s64)divider - 2 < 0) +		return 0; + +	if ((s64)divider - 2 >= max_divider) +		return -1; + +	return divider - 2; +} + +int clock_set_pllout(enum clock_id clkid, enum pll_out_id pllout, unsigned rate) +{ +	struct clk_pll *pll = get_pll(clkid); +	int data = 0, div = 0, offset = 0; + +	if (!clock_id_is_pll(clkid)) +		return -1; + +	if (pllout + 1 > pll_num_clkouts[clkid]) +		return -1; + +	div = clk_get_divider(8, pll_rate[clkid], rate); + +	if (div < 0) +		return -1; + +	/* out2 and out4 are in the high part of the register */ +	if (pllout == PLL_OUT2 || pllout == PLL_OUT4) +		offset = 16; + +	data = (div << PLL_OUT_RATIO_SHIFT) | +			PLL_OUT_OVRRIDE | PLL_OUT_CLKEN | PLL_OUT_RSTN; +	clrsetbits_le32(&pll->pll_out[pllout >> 1], +			PLL_OUT_RATIO_MASK << offset, data << offset); + +	return 0; +} + +/** + * Given the parent's rate and the divider in 7.1 format, this works out the + * resulting peripheral clock rate. + * + * @param parent_rate	clock rate of parent clock in Hz + * @param divider which should be used in 7.1 format + * @return effective clock rate of peripheral + */ +static unsigned long get_rate_from_divider(unsigned long parent_rate, +					   int divider) +{ +	u64 rate; + +	rate = (u64)parent_rate * 2; +	do_div(rate, divider + 2); +	return rate; +} + +unsigned long clock_get_periph_rate(enum periph_id periph_id, +		enum clock_id parent) +{ +	u32 *reg = get_periph_source_reg(periph_id); + +	return get_rate_from_divider(pll_rate[parent], +		(readl(reg) & OUT_CLK_DIVISOR_MASK) >> OUT_CLK_DIVISOR_SHIFT); +} + +/** + * Find the best available 7.1 format divisor given a parent clock rate and + * required child clock rate. This function assumes that a second-stage + * divisor is available which can divide by powers of 2 from 1 to 256. + * + * @param divider_bits	number of divider bits (8 or 16) + * @param parent_rate	clock rate of parent clock in Hz + * @param rate		required clock rate for this clock + * @param extra_div	value for the second-stage divisor (not set if this + *			function returns -1. + * @return divider which should be used, or -1 if nothing is valid + * + */ +static int find_best_divider(unsigned divider_bits, unsigned long parent_rate, +				unsigned long rate, int *extra_div) +{ +	int shift; +	int best_divider = -1; +	int best_error = rate; + +	/* try dividers from 1 to 256 and find closest match */ +	for (shift = 0; shift <= 8 && best_error > 0; shift++) { +		unsigned divided_parent = parent_rate >> shift; +		int divider = clk_get_divider(divider_bits, divided_parent, +						rate); +		unsigned effective_rate = get_rate_from_divider(divided_parent, +						divider); +		int error = rate - effective_rate; + +		/* Given a valid divider, look for the lowest error */ +		if (divider != -1 && error < best_error) { +			best_error = error; +			*extra_div = 1 << shift; +			best_divider = divider; +		} +	} + +	/* return what we found - *extra_div will already be set */ +	return best_divider; +} + +/** + * Adjust peripheral PLL to use the given divider and source. + * + * @param periph_id	peripheral to adjust + * @param source	Source number (0-3 or 0-7) + * @param mux_bits	Number of mux bits (2 or 4) + * @param divider	Required divider in 7.1 or 15.1 format + * @return 0 if ok, -1 on error (requesting a parent clock which is not valid + *		for this peripheral) + */ +static int adjust_periph_pll(enum periph_id periph_id, int source, +				int mux_bits, unsigned divider) +{ +	u32 *reg = get_periph_source_reg(periph_id); + +	clrsetbits_le32(reg, OUT_CLK_DIVISOR_MASK, +			divider << OUT_CLK_DIVISOR_SHIFT); +	udelay(1); + +	/* work out the source clock and set it */ +	if (source < 0) +		return -1; + +	switch (mux_bits) { +	case MASK_BITS_31_30: +		clrsetbits_le32(reg, OUT_CLK_SOURCE_31_30_MASK, +				source << OUT_CLK_SOURCE_31_30_SHIFT); +		break; + +	case MASK_BITS_31_29: +		clrsetbits_le32(reg, OUT_CLK_SOURCE_31_29_MASK, +				source << OUT_CLK_SOURCE_31_29_SHIFT); +		break; + +	case MASK_BITS_31_28: +		clrsetbits_le32(reg, OUT_CLK_SOURCE_31_28_MASK, +				source << OUT_CLK_SOURCE_31_28_SHIFT); +		break; + +	default: +		return -1; +	} + +	udelay(2); +	return 0; +} + +unsigned clock_adjust_periph_pll_div(enum periph_id periph_id, +		enum clock_id parent, unsigned rate, int *extra_div) +{ +	unsigned effective_rate; +	int mux_bits, divider_bits, source; +	int divider; +	int xdiv = 0; + +	/* work out the source clock and set it */ +	source = get_periph_clock_source(periph_id, parent, &mux_bits, +					 ÷r_bits); + +	divider = find_best_divider(divider_bits, pll_rate[parent], +				    rate, &xdiv); +	if (extra_div) +		*extra_div = xdiv; + +	assert(divider >= 0); +	if (adjust_periph_pll(periph_id, source, mux_bits, divider)) +		return -1U; +	debug("periph %d, rate=%d, reg=%p = %x\n", periph_id, rate, +		get_periph_source_reg(periph_id), +		readl(get_periph_source_reg(periph_id))); + +	/* Check what we ended up with. This shouldn't matter though */ +	effective_rate = clock_get_periph_rate(periph_id, parent); +	if (extra_div) +		effective_rate /= *extra_div; +	if (rate != effective_rate) +		debug("Requested clock rate %u not honored (got %u)\n", +			rate, effective_rate); +	return effective_rate; +} + +unsigned clock_start_periph_pll(enum periph_id periph_id, +		enum clock_id parent, unsigned rate) +{ +	unsigned effective_rate; + +	reset_set_enable(periph_id, 1); +	clock_enable(periph_id); + +	effective_rate = clock_adjust_periph_pll_div(periph_id, parent, rate, +						 NULL); + +	reset_set_enable(periph_id, 0); +	return effective_rate; +} + +void clock_enable(enum periph_id clkid) +{ +	clock_set_enable(clkid, 1); +} + +void clock_disable(enum periph_id clkid) +{ +	clock_set_enable(clkid, 0); +} + +void reset_periph(enum periph_id periph_id, int us_delay) +{ +	/* Put peripheral into reset */ +	reset_set_enable(periph_id, 1); +	udelay(us_delay); + +	/* Remove reset */ +	reset_set_enable(periph_id, 0); + +	udelay(us_delay); +} + +void reset_cmplx_set_enable(int cpu, int which, int reset) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 mask; + +	/* Form the mask, which depends on the cpu chosen (2 or 4) */ +	assert(cpu >= 0 && cpu < MAX_NUM_CPU); +	mask = which << cpu; + +	/* either enable or disable those reset for that CPU */ +	if (reset) +		writel(mask, &clkrst->crc_cpu_cmplx_set); +	else +		writel(mask, &clkrst->crc_cpu_cmplx_clr); +} + +unsigned clock_get_rate(enum clock_id clkid) +{ +	struct clk_pll *pll; +	u32 base; +	u32 divm; +	u64 parent_rate; +	u64 rate; + +	parent_rate = osc_freq[clock_get_osc_freq()]; +	if (clkid == CLOCK_ID_OSC) +		return parent_rate; + +	pll = get_pll(clkid); +	base = readl(&pll->pll_base); + +	/* Oh for bf_unpack()... */ +	rate = parent_rate * ((base & PLL_DIVN_MASK) >> PLL_DIVN_SHIFT); +	divm = (base & PLL_DIVM_MASK) >> PLL_DIVM_SHIFT; +	if (clkid == CLOCK_ID_USB) +		divm <<= (base & PLLU_VCO_FREQ_MASK) >> PLLU_VCO_FREQ_SHIFT; +	else +		divm <<= (base & PLL_DIVP_MASK) >> PLL_DIVP_SHIFT; +	do_div(rate, divm); +	return rate; +} + +/** + * Set the output frequency you want for each PLL clock. + * PLL output frequencies are programmed by setting their N, M and P values. + * The governing equations are: + *     VCO = (Fi / m) * n, Fo = VCO / (2^p) + *     where Fo is the output frequency from the PLL. + * Example: Set the output frequency to 216Mhz(Fo) with 12Mhz OSC(Fi) + *     216Mhz = ((12Mhz / m) * n) / (2^p) so n=432,m=12,p=1 + * Please see Tegra TRM section 5.3 to get the detail for PLL Programming + * + * @param n PLL feedback divider(DIVN) + * @param m PLL input divider(DIVN) + * @param p post divider(DIVP) + * @param cpcon base PLL charge pump(CPCON) + * @return 0 if ok, -1 on error (the requested PLL is incorrect and cannot + *		be overriden), 1 if PLL is already correct + */ +int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon) +{ +	u32 base_reg; +	u32 misc_reg; +	struct clk_pll *pll; + +	pll = get_pll(clkid); + +	base_reg = readl(&pll->pll_base); + +	/* Set BYPASS, m, n and p to PLL_BASE */ +	base_reg &= ~PLL_DIVM_MASK; +	base_reg |= m << PLL_DIVM_SHIFT; + +	base_reg &= ~PLL_DIVN_MASK; +	base_reg |= n << PLL_DIVN_SHIFT; + +	base_reg &= ~PLL_DIVP_MASK; +	base_reg |= p << PLL_DIVP_SHIFT; + +	if (clkid == CLOCK_ID_PERIPH) { +		/* +		 * If the PLL is already set up, check that it is correct +		 * and record this info for clock_verify() to check. +		 */ +		if (base_reg & PLL_BASE_OVRRIDE_MASK) { +			base_reg |= PLL_ENABLE_MASK; +			if (base_reg != readl(&pll->pll_base)) +				pllp_valid = 0; +			return pllp_valid ? 1 : -1; +		} +		base_reg |= PLL_BASE_OVRRIDE_MASK; +	} + +	base_reg |= PLL_BYPASS_MASK; +	writel(base_reg, &pll->pll_base); + +	/* Set cpcon to PLL_MISC */ +	misc_reg = readl(&pll->pll_misc); +	misc_reg &= ~PLL_CPCON_MASK; +	misc_reg |= cpcon << PLL_CPCON_SHIFT; +	writel(misc_reg, &pll->pll_misc); + +	/* Enable PLL */ +	base_reg |= PLL_ENABLE_MASK; +	writel(base_reg, &pll->pll_base); + +	/* Disable BYPASS */ +	base_reg &= ~PLL_BYPASS_MASK; +	writel(base_reg, &pll->pll_base); + +	return 0; +} + +void clock_ll_start_uart(enum periph_id periph_id) +{ +	/* Assert UART reset and enable clock */ +	reset_set_enable(periph_id, 1); +	clock_enable(periph_id); +	clock_ll_set_source(periph_id, 0); /* UARTx_CLK_SRC = 00, PLLP_OUT0 */ + +	/* wait for 2us */ +	udelay(2); + +	/* De-assert reset to UART */ +	reset_set_enable(periph_id, 0); +} + +#ifdef CONFIG_OF_CONTROL +int clock_decode_periph_id(const void *blob, int node) +{ +	enum periph_id id; +	u32 cell[2]; +	int err; + +	err = fdtdec_get_int_array(blob, node, "clocks", cell, +				   ARRAY_SIZE(cell)); +	if (err) +		return -1; +	id = clk_id_to_periph_id(cell[1]); +	assert(clock_periph_id_isvalid(id)); +	return id; +} +#endif /* CONFIG_OF_CONTROL */ + +int clock_verify(void) +{ +	struct clk_pll *pll = get_pll(CLOCK_ID_PERIPH); +	u32 reg = readl(&pll->pll_base); + +	if (!pllp_valid) { +		printf("Warning: PLLP %x is not correct\n", reg); +		return -1; +	} +	debug("PLLP %x is correct\n", reg); +	return 0; +} + +void clock_init(void) +{ +	pll_rate[CLOCK_ID_MEMORY] = clock_get_rate(CLOCK_ID_MEMORY); +	pll_rate[CLOCK_ID_PERIPH] = clock_get_rate(CLOCK_ID_PERIPH); +	pll_rate[CLOCK_ID_CGENERAL] = clock_get_rate(CLOCK_ID_CGENERAL); +	pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC); +	pll_rate[CLOCK_ID_SFROM32KHZ] = 32768; +	pll_rate[CLOCK_ID_XCPU] = clock_get_rate(CLOCK_ID_XCPU); +	debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]); +	debug("PLLM = %d\n", pll_rate[CLOCK_ID_MEMORY]); +	debug("PLLP = %d\n", pll_rate[CLOCK_ID_PERIPH]); +	debug("PLLC = %d\n", pll_rate[CLOCK_ID_CGENERAL]); +	debug("PLLX = %d\n", pll_rate[CLOCK_ID_XCPU]); + +	/* Do any special system timer/TSC setup */ +	arch_timer_init(); +} + +static void set_avp_clock_source(u32 src) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 val; + +	val = (src << SCLK_SWAKEUP_FIQ_SOURCE_SHIFT) | +		(src << SCLK_SWAKEUP_IRQ_SOURCE_SHIFT) | +		(src << SCLK_SWAKEUP_RUN_SOURCE_SHIFT) | +		(src << SCLK_SWAKEUP_IDLE_SOURCE_SHIFT) | +		(SCLK_SYS_STATE_RUN << SCLK_SYS_STATE_SHIFT); +	writel(val, &clkrst->crc_sclk_brst_pol); +	udelay(3); +} + +/* + * This function is useful on Tegra30, and any later SoCs that have compatible + * PLLP configuration registers. + */ +void tegra30_set_up_pllp(void) +{ +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	/* +	 * Based on the Tegra TRM, the system clock (which is the AVP clock) can +	 * run up to 275MHz. On power on, the default sytem clock source is set +	 * to PLLP_OUT0. This function sets PLLP's (hence PLLP_OUT0's) rate to +	 * 408MHz which is beyond system clock's upper limit. +	 * +	 * The fix is to set the system clock to CLK_M before initializing PLLP, +	 * and then switch back to PLLP_OUT4, which has an appropriate divider +	 * configured, after PLLP has been configured +	 */ +	set_avp_clock_source(SCLK_SOURCE_CLKM); + +	/* +	 * PLLP output frequency set to 408Mhz +	 * PLLC output frequency set to 228Mhz +	 */ +	switch (clock_get_osc_freq()) { +	case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ +		clock_set_rate(CLOCK_ID_PERIPH, 408, 12, 0, 8); +		clock_set_rate(CLOCK_ID_CGENERAL, 456, 12, 1, 8); +		break; + +	case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ +		clock_set_rate(CLOCK_ID_PERIPH, 408, 26, 0, 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, 408, 13, 0, 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; +	} + +	/* Set PLLP_OUT1, 2, 3 & 4 freqs to 9.6, 48, 102 & 204MHz */ + +	/* OUT1, 2 */ +	/* Assert RSTN before enable */ +	reg = PLLP_OUT2_RSTN_EN | PLLP_OUT1_RSTN_EN; +	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]); +	/* Set divisor and reenable */ +	reg = (IN_408_OUT_48_DIVISOR << PLLP_OUT2_RATIO) +		| PLLP_OUT2_OVR | PLLP_OUT2_CLKEN | PLLP_OUT2_RSTN_DIS +		| (IN_408_OUT_9_6_DIVISOR << PLLP_OUT1_RATIO) +		| PLLP_OUT1_OVR | PLLP_OUT1_CLKEN | PLLP_OUT1_RSTN_DIS; +	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[0]); + +	/* OUT3, 4 */ +	/* Assert RSTN before enable */ +	reg = PLLP_OUT4_RSTN_EN | PLLP_OUT3_RSTN_EN; +	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]); +	/* Set divisor and reenable */ +	reg = (IN_408_OUT_204_DIVISOR << PLLP_OUT4_RATIO) +		| PLLP_OUT4_OVR | PLLP_OUT4_CLKEN | PLLP_OUT4_RSTN_DIS +		| (IN_408_OUT_102_DIVISOR << PLLP_OUT3_RATIO) +		| PLLP_OUT3_OVR | PLLP_OUT3_CLKEN | PLLP_OUT3_RSTN_DIS; +	writel(reg, &clkrst->crc_pll[CLOCK_ID_PERIPH].pll_out[1]); + +	set_avp_clock_source(SCLK_SOURCE_PLLP_OUT4); +} diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/lowlevel_init.S b/roms/u-boot/arch/arm/cpu/tegra-common/lowlevel_init.S new file mode 100644 index 00000000..a211bb3b --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/lowlevel_init.S @@ -0,0 +1,26 @@ +/* + * SoC-specific setup info + * + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <config.h> +#include <version.h> +#include <linux/linkage.h> + +	.align	5 +ENTRY(reset_cpu) +	ldr	r1, rstctl			@ get addr for global reset +						@ reg +	ldr	r3, [r1] +	orr	r3, r3, #0x10 +	str	r3, [r1]			@ force reset +	mov	r0, r0 +_loop_forever: +	b	_loop_forever +rstctl: +	.word	PRM_RSTCTRL +ENDPROC(reset_cpu) diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/pinmux-common.c b/roms/u-boot/arch/arm/cpu/tegra-common/pinmux-common.c new file mode 100644 index 00000000..d62618cd --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/pinmux-common.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2010-2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2011 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/pinmux.h> + +/* return 1 if a pingrp is in range */ +#define pmux_pingrp_isvalid(pin) (((pin) >= 0) && ((pin) < PMUX_PINGRP_COUNT)) + +/* return 1 if a pmux_func is in range */ +#define pmux_func_isvalid(func) \ +	(((func) >= 0) && ((func) < PMUX_FUNC_COUNT)) + +/* return 1 if a pin_pupd_is in range */ +#define pmux_pin_pupd_isvalid(pupd) \ +	(((pupd) >= PMUX_PULL_NORMAL) && ((pupd) <= PMUX_PULL_UP)) + +/* return 1 if a pin_tristate_is in range */ +#define pmux_pin_tristate_isvalid(tristate) \ +	(((tristate) >= PMUX_TRI_NORMAL) && ((tristate) <= PMUX_TRI_TRISTATE)) + +#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC +/* return 1 if a pin_io_is in range */ +#define pmux_pin_io_isvalid(io) \ +	(((io) >= PMUX_PIN_OUTPUT) && ((io) <= PMUX_PIN_INPUT)) + +/* return 1 if a pin_lock is in range */ +#define pmux_pin_lock_isvalid(lock) \ +	(((lock) >= PMUX_PIN_LOCK_DISABLE) && ((lock) <= PMUX_PIN_LOCK_ENABLE)) + +/* return 1 if a pin_od is in range */ +#define pmux_pin_od_isvalid(od) \ +	(((od) >= PMUX_PIN_OD_DISABLE) && ((od) <= PMUX_PIN_OD_ENABLE)) + +/* return 1 if a pin_ioreset_is in range */ +#define pmux_pin_ioreset_isvalid(ioreset) \ +	(((ioreset) >= PMUX_PIN_IO_RESET_DISABLE) && \ +	 ((ioreset) <= PMUX_PIN_IO_RESET_ENABLE)) + +#ifdef TEGRA_PMX_HAS_RCV_SEL +/* return 1 if a pin_rcv_sel_is in range */ +#define pmux_pin_rcv_sel_isvalid(rcv_sel) \ +	(((rcv_sel) >= PMUX_PIN_RCV_SEL_NORMAL) && \ +	 ((rcv_sel) <= PMUX_PIN_RCV_SEL_HIGH)) +#endif /* TEGRA_PMX_HAS_RCV_SEL */ +#endif /* TEGRA_PMX_HAS_PIN_IO_BIT_ETC */ + +#define _R(offset)	(u32 *)(NV_PA_APB_MISC_BASE + (offset)) + +#if defined(CONFIG_TEGRA20) + +#define MUX_REG(grp)	_R(0x80 + ((tegra_soc_pingroups[grp].ctl_id / 16) * 4)) +#define MUX_SHIFT(grp)	((tegra_soc_pingroups[grp].ctl_id % 16) * 2) + +#define PULL_REG(grp)	_R(0xa0 + ((tegra_soc_pingroups[grp].pull_id / 16) * 4)) +#define PULL_SHIFT(grp)	((tegra_soc_pingroups[grp].pull_id % 16) * 2) + +#define TRI_REG(grp)	_R(0x14 + (((grp) / 32) * 4)) +#define TRI_SHIFT(grp)	((grp) % 32) + +#else + +#define REG(pin)	_R(0x3000 + ((pin) * 4)) + +#define MUX_REG(pin)	REG(pin) +#define MUX_SHIFT(pin)	0 + +#define PULL_REG(pin)	REG(pin) +#define PULL_SHIFT(pin)	2 + +#define TRI_REG(pin)	REG(pin) +#define TRI_SHIFT(pin)	4 + +#endif /* CONFIG_TEGRA20 */ + +#define DRV_REG(group)	_R(0x868 + ((group) * 4)) + +#define IO_SHIFT	5 +#define OD_SHIFT	6 +#define LOCK_SHIFT	7 +#define IO_RESET_SHIFT	8 +#define RCV_SEL_SHIFT	9 + +void pinmux_set_func(enum pmux_pingrp pin, enum pmux_func func) +{ +	u32 *reg = MUX_REG(pin); +	int i, mux = -1; +	u32 val; + +	/* Error check on pin and func */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_func_isvalid(func)); + +	if (func >= PMUX_FUNC_RSVD1) { +		mux = (func - PMUX_FUNC_RSVD1) & 3; +	} else { +		/* Search for the appropriate function */ +		for (i = 0; i < 4; i++) { +			if (tegra_soc_pingroups[pin].funcs[i] == func) { +				mux = i; +				break; +			} +		} +	} +	assert(mux != -1); + +	val = readl(reg); +	val &= ~(3 << MUX_SHIFT(pin)); +	val |= (mux << MUX_SHIFT(pin)); +	writel(val, reg); +} + +void pinmux_set_pullupdown(enum pmux_pingrp pin, enum pmux_pull pupd) +{ +	u32 *reg = PULL_REG(pin); +	u32 val; + +	/* Error check on pin and pupd */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_pin_pupd_isvalid(pupd)); + +	val = readl(reg); +	val &= ~(3 << PULL_SHIFT(pin)); +	val |= (pupd << PULL_SHIFT(pin)); +	writel(val, reg); +} + +static void pinmux_set_tristate(enum pmux_pingrp pin, int tri) +{ +	u32 *reg = TRI_REG(pin); +	u32 val; + +	/* Error check on pin */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_pin_tristate_isvalid(tri)); + +	val = readl(reg); +	if (tri == PMUX_TRI_TRISTATE) +		val |= (1 << TRI_SHIFT(pin)); +	else +		val &= ~(1 << TRI_SHIFT(pin)); +	writel(val, reg); +} + +void pinmux_tristate_enable(enum pmux_pingrp pin) +{ +	pinmux_set_tristate(pin, PMUX_TRI_TRISTATE); +} + +void pinmux_tristate_disable(enum pmux_pingrp pin) +{ +	pinmux_set_tristate(pin, PMUX_TRI_NORMAL); +} + +#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC +void pinmux_set_io(enum pmux_pingrp pin, enum pmux_pin_io io) +{ +	u32 *reg = REG(pin); +	u32 val; + +	if (io == PMUX_PIN_NONE) +		return; + +	/* Error check on pin and io */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_pin_io_isvalid(io)); + +	val = readl(reg); +	if (io == PMUX_PIN_INPUT) +		val |= (io & 1) << IO_SHIFT; +	else +		val &= ~(1 << IO_SHIFT); +	writel(val, reg); +} + +static void pinmux_set_lock(enum pmux_pingrp pin, enum pmux_pin_lock lock) +{ +	u32 *reg = REG(pin); +	u32 val; + +	if (lock == PMUX_PIN_LOCK_DEFAULT) +		return; + +	/* Error check on pin and lock */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_pin_lock_isvalid(lock)); + +	val = readl(reg); +	if (lock == PMUX_PIN_LOCK_ENABLE) { +		val |= (1 << LOCK_SHIFT); +	} else { +		if (val & (1 << LOCK_SHIFT)) +			printf("%s: Cannot clear LOCK bit!\n", __func__); +		val &= ~(1 << LOCK_SHIFT); +	} +	writel(val, reg); + +	return; +} + +static void pinmux_set_od(enum pmux_pingrp pin, enum pmux_pin_od od) +{ +	u32 *reg = REG(pin); +	u32 val; + +	if (od == PMUX_PIN_OD_DEFAULT) +		return; + +	/* Error check on pin and od */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_pin_od_isvalid(od)); + +	val = readl(reg); +	if (od == PMUX_PIN_OD_ENABLE) +		val |= (1 << OD_SHIFT); +	else +		val &= ~(1 << OD_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_set_ioreset(enum pmux_pingrp pin, +				enum pmux_pin_ioreset ioreset) +{ +	u32 *reg = REG(pin); +	u32 val; + +	if (ioreset == PMUX_PIN_IO_RESET_DEFAULT) +		return; + +	/* Error check on pin and ioreset */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_pin_ioreset_isvalid(ioreset)); + +	val = readl(reg); +	if (ioreset == PMUX_PIN_IO_RESET_ENABLE) +		val |= (1 << IO_RESET_SHIFT); +	else +		val &= ~(1 << IO_RESET_SHIFT); +	writel(val, reg); + +	return; +} + +#ifdef TEGRA_PMX_HAS_RCV_SEL +static void pinmux_set_rcv_sel(enum pmux_pingrp pin, +				enum pmux_pin_rcv_sel rcv_sel) +{ +	u32 *reg = REG(pin); +	u32 val; + +	if (rcv_sel == PMUX_PIN_RCV_SEL_DEFAULT) +		return; + +	/* Error check on pin and rcv_sel */ +	assert(pmux_pingrp_isvalid(pin)); +	assert(pmux_pin_rcv_sel_isvalid(rcv_sel)); + +	val = readl(reg); +	if (rcv_sel == PMUX_PIN_RCV_SEL_HIGH) +		val |= (1 << RCV_SEL_SHIFT); +	else +		val &= ~(1 << RCV_SEL_SHIFT); +	writel(val, reg); + +	return; +} +#endif /* TEGRA_PMX_HAS_RCV_SEL */ +#endif /* TEGRA_PMX_HAS_PIN_IO_BIT_ETC */ + +static void pinmux_config_pingrp(const struct pmux_pingrp_config *config) +{ +	enum pmux_pingrp pin = config->pingrp; + +	pinmux_set_func(pin, config->func); +	pinmux_set_pullupdown(pin, config->pull); +	pinmux_set_tristate(pin, config->tristate); +#ifdef TEGRA_PMX_HAS_PIN_IO_BIT_ETC +	pinmux_set_io(pin, config->io); +	pinmux_set_lock(pin, config->lock); +	pinmux_set_od(pin, config->od); +	pinmux_set_ioreset(pin, config->ioreset); +#ifdef TEGRA_PMX_HAS_RCV_SEL +	pinmux_set_rcv_sel(pin, config->rcv_sel); +#endif +#endif +} + +void pinmux_config_pingrp_table(const struct pmux_pingrp_config *config, +				int len) +{ +	int i; + +	for (i = 0; i < len; i++) +		pinmux_config_pingrp(&config[i]); +} + +#ifdef TEGRA_PMX_HAS_DRVGRPS + +#define pmux_drvgrp_isvalid(pd) (((pd) >= 0) && ((pd) < PMUX_DRVGRP_COUNT)) + +#define pmux_slw_isvalid(slw) \ +	(((slw) >= PMUX_SLWF_MIN) && ((slw) <= PMUX_SLWF_MAX)) + +#define pmux_drv_isvalid(drv) \ +	(((drv) >= PMUX_DRVUP_MIN) && ((drv) <= PMUX_DRVUP_MAX)) + +#define pmux_lpmd_isvalid(lpm) \ +	(((lpm) >= PMUX_LPMD_X8) && ((lpm) <= PMUX_LPMD_X)) + +#define pmux_schmt_isvalid(schmt) \ +	(((schmt) >= PMUX_SCHMT_DISABLE) && ((schmt) <= PMUX_SCHMT_ENABLE)) + +#define pmux_hsm_isvalid(hsm) \ +	(((hsm) >= PMUX_HSM_DISABLE) && ((hsm) <= PMUX_HSM_ENABLE)) + +#define HSM_SHIFT	2 +#define SCHMT_SHIFT	3 +#define LPMD_SHIFT	4 +#define LPMD_MASK	(3 << LPMD_SHIFT) +#define DRVDN_SHIFT	12 +#define DRVDN_MASK	(0x7F << DRVDN_SHIFT) +#define DRVUP_SHIFT	20 +#define DRVUP_MASK	(0x7F << DRVUP_SHIFT) +#define SLWR_SHIFT	28 +#define SLWR_MASK	(3 << SLWR_SHIFT) +#define SLWF_SHIFT	30 +#define SLWF_MASK	(3 << SLWF_SHIFT) + +static void pinmux_set_drvup_slwf(enum pmux_drvgrp grp, int slwf) +{ +	u32 *reg = DRV_REG(grp); +	u32 val; + +	/* NONE means unspecified/do not change/use POR value */ +	if (slwf == PMUX_SLWF_NONE) +		return; + +	/* Error check on pad and slwf */ +	assert(pmux_drvgrp_isvalid(grp)); +	assert(pmux_slw_isvalid(slwf)); + +	val = readl(reg); +	val &= ~SLWF_MASK; +	val |= (slwf << SLWF_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_set_drvdn_slwr(enum pmux_drvgrp grp, int slwr) +{ +	u32 *reg = DRV_REG(grp); +	u32 val; + +	/* NONE means unspecified/do not change/use POR value */ +	if (slwr == PMUX_SLWR_NONE) +		return; + +	/* Error check on pad and slwr */ +	assert(pmux_drvgrp_isvalid(grp)); +	assert(pmux_slw_isvalid(slwr)); + +	val = readl(reg); +	val &= ~SLWR_MASK; +	val |= (slwr << SLWR_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_set_drvup(enum pmux_drvgrp grp, int drvup) +{ +	u32 *reg = DRV_REG(grp); +	u32 val; + +	/* NONE means unspecified/do not change/use POR value */ +	if (drvup == PMUX_DRVUP_NONE) +		return; + +	/* Error check on pad and drvup */ +	assert(pmux_drvgrp_isvalid(grp)); +	assert(pmux_drv_isvalid(drvup)); + +	val = readl(reg); +	val &= ~DRVUP_MASK; +	val |= (drvup << DRVUP_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_set_drvdn(enum pmux_drvgrp grp, int drvdn) +{ +	u32 *reg = DRV_REG(grp); +	u32 val; + +	/* NONE means unspecified/do not change/use POR value */ +	if (drvdn == PMUX_DRVDN_NONE) +		return; + +	/* Error check on pad and drvdn */ +	assert(pmux_drvgrp_isvalid(grp)); +	assert(pmux_drv_isvalid(drvdn)); + +	val = readl(reg); +	val &= ~DRVDN_MASK; +	val |= (drvdn << DRVDN_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_set_lpmd(enum pmux_drvgrp grp, enum pmux_lpmd lpmd) +{ +	u32 *reg = DRV_REG(grp); +	u32 val; + +	/* NONE means unspecified/do not change/use POR value */ +	if (lpmd == PMUX_LPMD_NONE) +		return; + +	/* Error check pad and lpmd value */ +	assert(pmux_drvgrp_isvalid(grp)); +	assert(pmux_lpmd_isvalid(lpmd)); + +	val = readl(reg); +	val &= ~LPMD_MASK; +	val |= (lpmd << LPMD_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_set_schmt(enum pmux_drvgrp grp, enum pmux_schmt schmt) +{ +	u32 *reg = DRV_REG(grp); +	u32 val; + +	/* NONE means unspecified/do not change/use POR value */ +	if (schmt == PMUX_SCHMT_NONE) +		return; + +	/* Error check pad */ +	assert(pmux_drvgrp_isvalid(grp)); +	assert(pmux_schmt_isvalid(schmt)); + +	val = readl(reg); +	if (schmt == PMUX_SCHMT_ENABLE) +		val |= (1 << SCHMT_SHIFT); +	else +		val &= ~(1 << SCHMT_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_set_hsm(enum pmux_drvgrp grp, enum pmux_hsm hsm) +{ +	u32 *reg = DRV_REG(grp); +	u32 val; + +	/* NONE means unspecified/do not change/use POR value */ +	if (hsm == PMUX_HSM_NONE) +		return; + +	/* Error check pad */ +	assert(pmux_drvgrp_isvalid(grp)); +	assert(pmux_hsm_isvalid(hsm)); + +	val = readl(reg); +	if (hsm == PMUX_HSM_ENABLE) +		val |= (1 << HSM_SHIFT); +	else +		val &= ~(1 << HSM_SHIFT); +	writel(val, reg); + +	return; +} + +static void pinmux_config_drvgrp(const struct pmux_drvgrp_config *config) +{ +	enum pmux_drvgrp grp = config->drvgrp; + +	pinmux_set_drvup_slwf(grp, config->slwf); +	pinmux_set_drvdn_slwr(grp, config->slwr); +	pinmux_set_drvup(grp, config->drvup); +	pinmux_set_drvdn(grp, config->drvdn); +	pinmux_set_lpmd(grp, config->lpmd); +	pinmux_set_schmt(grp, config->schmt); +	pinmux_set_hsm(grp, config->hsm); +} + +void pinmux_config_drvgrp_table(const struct pmux_drvgrp_config *config, +				int len) +{ +	int i; + +	for (i = 0; i < len; i++) +		pinmux_config_drvgrp(&config[i]); +} +#endif /* TEGRA_PMX_HAS_DRVGRPS */ diff --git a/roms/u-boot/arch/arm/cpu/tegra-common/sys_info.c b/roms/u-boot/arch/arm/cpu/tegra-common/sys_info.c new file mode 100644 index 00000000..de20325e --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/tegra-common/sys_info.c @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <linux/ctype.h> + +void upstring(char *s) +{ +	while (*s) { +		*s = toupper(*s); +		s++; +	} +} + +/* Print CPU information */ +int print_cpuinfo(void) +{ +	char soc_name[10]; + +	strncpy(soc_name, CONFIG_SYS_SOC, 10); +	upstring(soc_name); +	puts(soc_name); +	puts("\n"); + +	/* TBD: Add printf of major/minor rev info, stepping, etc. */ +	return 0; +}  | 
