diff options
Diffstat (limited to 'roms/u-boot/arch/arm/cpu/arm720t')
17 files changed, 1768 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/cpu/arm720t/Makefile b/roms/u-boot/arch/arm/cpu/arm720t/Makefile new file mode 100644 index 00000000..6badb3bb --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/Makefile @@ -0,0 +1,11 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +extra-y	= start.o +obj-y	= interrupts.o cpu.o + +obj-$(CONFIG_TEGRA) += tegra-common/ diff --git a/roms/u-boot/arch/arm/cpu/arm720t/config.mk b/roms/u-boot/arch/arm/cpu/arm720t/config.mk new file mode 100644 index 00000000..772fb413 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/config.mk @@ -0,0 +1,9 @@ +# +# (C) Copyright 2002 +# Sysgo Real-Time Solutions, GmbH <www.elinos.com> +# Marius Groeger <mgroeger@sysgo.de> +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -march=armv4 -mtune=arm7tdmi diff --git a/roms/u-boot/arch/arm/cpu/arm720t/cpu.c b/roms/u-boot/arch/arm/cpu/arm720t/cpu.c new file mode 100644 index 00000000..745fccdf --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/cpu.c @@ -0,0 +1,22 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +/* + * cleanup_before_linux() - Prepare the CPU to jump to Linux + * + * This function is called just before we call Linux, it + * prepares the processor for linux + */ +int cleanup_before_linux(void) +{ +	return 0; +} diff --git a/roms/u-boot/arch/arm/cpu/arm720t/interrupts.c b/roms/u-boot/arch/arm/cpu/arm720t/interrupts.c new file mode 100644 index 00000000..e8ba1ae0 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/interrupts.c @@ -0,0 +1,33 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> + +#ifdef CONFIG_USE_IRQ +void do_irq (struct pt_regs *pt_regs) +{ +} +#endif + +#if defined(CONFIG_TEGRA) +static ulong timestamp; +static ulong lastdec; + +int timer_init (void) +{ +	/* No timer routines for tegra as yet */ +	lastdec = 0; +	timestamp = 0; + +	return 0; +} +#endif diff --git a/roms/u-boot/arch/arm/cpu/arm720t/start.S b/roms/u-boot/arch/arm/cpu/arm720t/start.S new file mode 100644 index 00000000..1a348426 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/start.S @@ -0,0 +1,307 @@ +/* + *  armboot - Startup Code for ARM720 CPU-core + * + *  Copyright (c) 2001	Marius Gröger <mag@sysgo.de> + *  Copyright (c) 2002	Alex Züpke <azu@sysgo.de> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <version.h> +#include <asm/hardware.h> + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + + +.globl _start +_start: b	reset +	ldr	pc, _undefined_instruction +	ldr	pc, _software_interrupt +	ldr	pc, _prefetch_abort +	ldr	pc, _data_abort +	ldr	pc, _not_used +	ldr	pc, _irq +	ldr	pc, _fiq + +#ifdef CONFIG_SPL_BUILD +_undefined_instruction: .word _undefined_instruction +_software_interrupt:	.word _software_interrupt +_prefetch_abort:	.word _prefetch_abort +_data_abort:		.word _data_abort +_not_used:		.word _not_used +_irq:			.word _irq +_fiq:			.word _fiq +_pad:			.word 0x12345678 /* now 16*4=64 */ +#else +_undefined_instruction: .word undefined_instruction +_software_interrupt:	.word software_interrupt +_prefetch_abort:	.word prefetch_abort +_data_abort:		.word data_abort +_not_used:		.word not_used +_irq:			.word irq +_fiq:			.word fiq +_pad:			.word 0x12345678 /* now 16*4=64 */ +#endif	/* CONFIG_SPL_BUILD */ + +	.balignl 16,0xdeadbeef + + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from RAM! + * relocate armboot to ram + * setup stack + * jump to second stage + * + ************************************************************************* + */ + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: +	.word	0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: +	.word 0x0badc0de +#endif + +/* IRQ stack memory (calculated at run-time) + 8 bytes */ +.globl IRQ_STACK_START_IN +IRQ_STACK_START_IN: +	.word	0x0badc0de + +/* + * the actual reset code + */ + +reset: +	/* +	 * set the cpu to SVC32 mode +	 */ +	mrs	r0,cpsr +	bic	r0,r0,#0x1f +	orr	r0,r0,#0xd3 +	msr	cpsr,r0 + +	/* +	 * we do sys-critical inits only at reboot, +	 * not when booting from ram! +	 */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +	bl	cpu_init_crit +#endif + +	bl	_main + +/*------------------------------------------------------------------------------*/ + +	.globl	c_runtime_cpu_setup +c_runtime_cpu_setup: + +	mov	pc, lr + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ + +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +cpu_init_crit: + +	mov	ip, lr +	/* +	 * before relocating, we have to setup RAM timing +	 * because memory timing is board-dependent, you will +	 * find a lowlevel_init.S in your board directory. +	 */ +	bl	lowlevel_init +	mov	lr, ip + +	mov	pc, lr +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */ + + +#ifndef CONFIG_SPL_BUILD +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ + +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE	72 + +#define S_OLD_R0	68 +#define S_PSR		64 +#define S_PC		60 +#define S_LR		56 +#define S_SP		52 + +#define S_IP		48 +#define S_FP		44 +#define S_R10		40 +#define S_R9		36 +#define S_R8		32 +#define S_R7		28 +#define S_R6		24 +#define S_R5		20 +#define S_R4		16 +#define S_R3		12 +#define S_R2		8 +#define S_R1		4 +#define S_R0		0 + +#define MODE_SVC 0x13 +#define I_BIT	 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + +	.macro	bad_save_user_regs +	sub	sp, sp, #S_FRAME_SIZE +	stmia	sp, {r0 - r12}			@ Calling r0-r12 +	add	r8, sp, #S_PC + +	ldr	r2, IRQ_STACK_START_IN +	ldmia	r2, {r2 - r4}			@ get pc, cpsr, old_r0 +	add	r0, sp, #S_FRAME_SIZE		@ restore sp_SVC + +	add	r5, sp, #S_SP +	mov	r1, lr +	stmia	r5, {r0 - r4}			@ save sp_SVC, lr_SVC, pc, cpsr, old_r +	mov	r0, sp +	.endm + +	.macro	irq_save_user_regs +	sub	sp, sp, #S_FRAME_SIZE +	stmia	sp, {r0 - r12}			@ Calling r0-r12 +	add	r8, sp, #S_PC +	stmdb	r8, {sp, lr}^			@ Calling SP, LR +	str	lr, [r8, #0]			@ Save calling PC +	mrs	r6, spsr +	str	r6, [r8, #4]			@ Save CPSR +	str	r0, [r8, #8]			@ Save OLD_R0 +	mov	r0, sp +	.endm + +	.macro	irq_restore_user_regs +	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr +	mov	r0, r0 +	ldr	lr, [sp, #S_PC]			@ Get PC +	add	sp, sp, #S_FRAME_SIZE +	subs	pc, lr, #4			@ return & move spsr_svc into cpsr +	.endm + +	.macro get_bad_stack +	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack + +	str	lr, [r13]			@ save caller lr / spsr +	mrs	lr, spsr +	str	lr, [r13, #4] + +	mov	r13, #MODE_SVC			@ prepare SVC-Mode +	msr	spsr_c, r13 +	mov	lr, pc +	movs	pc, lr +	.endm + +	.macro get_irq_stack			@ setup IRQ stack +	ldr	sp, IRQ_STACK_START +	.endm + +	.macro get_fiq_stack			@ setup FIQ stack +	ldr	sp, FIQ_STACK_START +	.endm + +/* + * exception handlers + */ +	.align	5 +undefined_instruction: +	get_bad_stack +	bad_save_user_regs +	bl	do_undefined_instruction + +	.align	5 +software_interrupt: +	get_bad_stack +	bad_save_user_regs +	bl	do_software_interrupt + +	.align	5 +prefetch_abort: +	get_bad_stack +	bad_save_user_regs +	bl	do_prefetch_abort + +	.align	5 +data_abort: +	get_bad_stack +	bad_save_user_regs +	bl	do_data_abort + +	.align	5 +not_used: +	get_bad_stack +	bad_save_user_regs +	bl	do_not_used + +#ifdef CONFIG_USE_IRQ + +	.align	5 +irq: +	get_irq_stack +	irq_save_user_regs +	bl	do_irq +	irq_restore_user_regs + +	.align	5 +fiq: +	get_fiq_stack +	/* someone ought to write a more effiction fiq_save_user_regs */ +	irq_save_user_regs +	bl	do_fiq +	irq_restore_user_regs + +#else + +	.align	5 +irq: +	get_bad_stack +	bad_save_user_regs +	bl	do_irq + +	.align	5 +fiq: +	get_bad_stack +	bad_save_user_regs +	bl	do_fiq + +#endif +#endif /* CONFIG_SPL_BUILD */ diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/Makefile b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/Makefile new file mode 100644 index 00000000..a9c2b675 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/Makefile @@ -0,0 +1,11 @@ +# +# (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-$(CONFIG_SPL_BUILD) += spl.o +obj-y	+= cpu.o diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/cpu.c b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/cpu.c new file mode 100644 index 00000000..168f525e --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/cpu.c @@ -0,0 +1,384 @@ +/* + * 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/>. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/gp_padctrl.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/scu.h> +#include "cpu.h" + +int get_num_cpus(void) +{ +	struct apb_misc_gp_ctlr *gp; +	uint rev; + +	gp = (struct apb_misc_gp_ctlr *)NV_PA_APB_MISC_GP_BASE; +	rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT; + +	switch (rev) { +	case CHIPID_TEGRA20: +		return 2; +		break; +	case CHIPID_TEGRA30: +	case CHIPID_TEGRA114: +	default: +		return 4; +		break; +	} +} + +/* + * Timing tables for each SOC for all four oscillator options. + */ +struct clk_pll_table tegra_pll_x_table[TEGRA_SOC_CNT][CLOCK_OSC_FREQ_COUNT] = { +	/* +	 * T20: 1 GHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      22:20    3 +	 * PLLX_BASE  n      17: 8   10 +	 * PLLX_BASE  m       4: 0    5 +	 * PLLX_MISC  cpcon  11: 8    4 +	 */ +	{ +		{ .n = 1000, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */ +		{ .n =  625, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */ +		{ .n = 1000, .m = 12, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */ +		{ .n = 1000, .m = 26, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */ +	}, +	/* +	 * T25: 1.2 GHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      22:20    3 +	 * PLLX_BASE  n      17: 8   10 +	 * PLLX_BASE  m       4: 0    5 +	 * PLLX_MISC  cpcon  11: 8    4 +	 */ +	{ +		{ .n = 923, .m = 10, .p = 0, .cpcon = 12 }, /* OSC: 13.0 MHz */ +		{ .n = 750, .m = 12, .p = 0, .cpcon =  8 }, /* OSC: 19.2 MHz */ +		{ .n = 600, .m =  6, .p = 0, .cpcon = 12 }, /* OSC: 12.0 MHz */ +		{ .n = 600, .m = 13, .p = 0, .cpcon = 12 }, /* OSC: 26.0 MHz */ +	}, +	/* +	 * T30: 1.4 GHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      22:20    3 +	 * PLLX_BASE  n      17: 8   10 +	 * PLLX_BASE  m       4: 0    5 +	 * PLLX_MISC  cpcon  11: 8    4 +	 */ +	{ +		{ .n = 862, .m =  8, .p = 0, .cpcon = 8 }, /* OSC: 13.0 MHz */ +		{ .n = 583, .m =  8, .p = 0, .cpcon = 4 }, /* OSC: 19.2 MHz */ +		{ .n = 700, .m =  6, .p = 0, .cpcon = 8 }, /* OSC: 12.0 MHz */ +		{ .n = 700, .m = 13, .p = 0, .cpcon = 8 }, /* OSC: 26.0 MHz */ +	}, +	/* +	 * T114: 700 MHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      23:20    4 +	 * PLLX_BASE  n      15: 8    8 +	 * PLLX_BASE  m       7: 0    8 +	 */ +	{ +		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */ +		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */ +		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */ +		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */ +	}, + +	/* +	 * T124: 700 MHz +	 * +	 * Register   Field  Bits   Width +	 * ------------------------------ +	 * PLLX_BASE  p      23:20    4 +	 * PLLX_BASE  n      15: 8    8 +	 * PLLX_BASE  m       7: 0    8 +	 */ +	{ +		{ .n = 108, .m = 1, .p = 1 }, /* OSC: 13.0 MHz */ +		{ .n =  73, .m = 1, .p = 1 }, /* OSC: 19.2 MHz */ +		{ .n = 116, .m = 1, .p = 1 }, /* OSC: 12.0 MHz */ +		{ .n = 108, .m = 2, .p = 1 }, /* OSC: 26.0 MHz */ +	}, +}; + +static inline void pllx_set_iddq(void) +{ +#if defined(CONFIG_TEGRA124) +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	/* Disable IDDQ */ +	reg = readl(&clkrst->crc_pllx_misc3); +	reg &= ~PLLX_IDDQ_MASK; +	writel(reg, &clkrst->crc_pllx_misc3); +	udelay(2); +	debug("%s: IDDQ: PLLX IDDQ = 0x%08X\n", __func__, +	      readl(&clkrst->crc_pllx_misc3)); +#endif +} + +int pllx_set_rate(struct clk_pll_simple *pll , u32 divn, u32 divm, +		u32 divp, u32 cpcon) +{ +	int chip = tegra_get_chip(); +	u32 reg; + +	/* If PLLX is already enabled, just return */ +	if (readl(&pll->pll_base) & PLL_ENABLE_MASK) { +		debug("pllx_set_rate: PLLX already enabled, returning\n"); +		return 0; +	} + +	debug(" pllx_set_rate entry\n"); + +	pllx_set_iddq(); + +	/* Set BYPASS, m, n and p to PLLX_BASE */ +	reg = PLL_BYPASS_MASK | (divm << PLL_DIVM_SHIFT); +	reg |= ((divn << PLL_DIVN_SHIFT) | (divp << PLL_DIVP_SHIFT)); +	writel(reg, &pll->pll_base); + +	/* Set cpcon to PLLX_MISC */ +	if (chip == CHIPID_TEGRA20 || chip == CHIPID_TEGRA30) +		reg = (cpcon << PLL_CPCON_SHIFT); +	else +		reg = 0; + +	/* Set dccon to PLLX_MISC if freq > 600MHz */ +	if (divn > 600) +		reg |= (1 << PLL_DCCON_SHIFT); +	writel(reg, &pll->pll_misc); + +	/* Disable BYPASS */ +	reg = readl(&pll->pll_base); +	reg &= ~PLL_BYPASS_MASK; +	writel(reg, &pll->pll_base); +	debug("pllx_set_rate: base = 0x%08X\n", reg); + +	/* Set lock_enable to PLLX_MISC */ +	reg = readl(&pll->pll_misc); +	reg |= PLL_LOCK_ENABLE_MASK; +	writel(reg, &pll->pll_misc); +	debug("pllx_set_rate: misc = 0x%08X\n", reg); + +	/* Enable PLLX last, once it's all configured */ +	reg = readl(&pll->pll_base); +	reg |= PLL_ENABLE_MASK; +	writel(reg, &pll->pll_base); +	debug("pllx_set_rate: base final = 0x%08X\n", reg); + +	return 0; +} + +void init_pllx(void) +{ +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	struct clk_pll_simple *pll = &clkrst->crc_pll_simple[SIMPLE_PLLX]; +	int soc_type, sku_info, chip_sku; +	enum clock_osc_freq osc; +	struct clk_pll_table *sel; + +	debug("init_pllx entry\n"); + +	/* get SOC (chip) type */ +	soc_type = tegra_get_chip(); +	debug(" init_pllx: SoC = 0x%02X\n", soc_type); + +	/* get SKU info */ +	sku_info = tegra_get_sku_info(); +	debug(" init_pllx: SKU info byte = 0x%02X\n", sku_info); + +	/* get chip SKU, combo of the above info */ +	chip_sku = tegra_get_chip_sku(); +	debug(" init_pllx: Chip SKU = %d\n", chip_sku); + +	/* get osc freq */ +	osc = clock_get_osc_freq(); +	debug(" init_pllx: osc = %d\n", osc); + +	/* set pllx */ +	sel = &tegra_pll_x_table[chip_sku][osc]; +	pllx_set_rate(pll, sel->n, sel->m, sel->p, sel->cpcon); +} + +void enable_cpu_clock(int enable) +{ +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 clk; + +	/* +	 * NOTE: +	 * Regardless of whether the request is to enable or disable the CPU +	 * clock, every processor in the CPU complex except the master (CPU 0) +	 * will have it's clock stopped because the AVP only talks to the +	 * master. +	 */ + +	if (enable) { +		/* Initialize PLLX */ +		init_pllx(); + +		/* Wait until all clocks are stable */ +		udelay(PLL_STABILIZATION_DELAY); + +		writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); +		writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); +	} + +	/* +	 * Read the register containing the individual CPU clock enables and +	 * always stop the clocks to CPUs > 0. +	 */ +	clk = readl(&clkrst->crc_clk_cpu_cmplx); +	clk |= 1 << CPU1_CLK_STP_SHIFT; +	if (get_num_cpus() == 4) +		clk |= (1 << CPU2_CLK_STP_SHIFT) + (1 << CPU3_CLK_STP_SHIFT); + +	/* Stop/Unstop the CPU clock */ +	clk &= ~CPU0_CLK_STP_MASK; +	clk |= !enable << CPU0_CLK_STP_SHIFT; +	writel(clk, &clkrst->crc_clk_cpu_cmplx); + +	clock_enable(PERIPH_ID_CPU); +} + +static int is_cpu_powered(void) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + +	return (readl(&pmc->pmc_pwrgate_status) & CPU_PWRED) ? 1 : 0; +} + +static void remove_cpu_io_clamps(void) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; + +	/* Remove the clamps on the CPU I/O signals */ +	reg = readl(&pmc->pmc_remove_clamping); +	reg |= CPU_CLMP; +	writel(reg, &pmc->pmc_remove_clamping); + +	/* Give I/O signals time to stabilize */ +	udelay(IO_STABILIZATION_DELAY); +} + +void powerup_cpu(void) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; +	int timeout = IO_STABILIZATION_DELAY; + +	if (!is_cpu_powered()) { +		/* Toggle the CPU power state (OFF -> ON) */ +		reg = readl(&pmc->pmc_pwrgate_toggle); +		reg &= PARTID_CP; +		reg |= START_CP; +		writel(reg, &pmc->pmc_pwrgate_toggle); + +		/* Wait for the power to come up */ +		while (!is_cpu_powered()) { +			if (timeout-- == 0) +				printf("CPU failed to power up!\n"); +			else +				udelay(10); +		} + +		/* +		 * Remove the I/O clamps from CPU power partition. +		 * Recommended only on a Warm boot, if the CPU partition gets +		 * power gated. Shouldn't cause any harm when called after a +		 * cold boot according to HW, probably just redundant. +		 */ +		remove_cpu_io_clamps(); +	} +} + +void reset_A9_cpu(int reset) +{ +	/* +	* NOTE:  Regardless of whether the request is to hold the CPU in reset +	*        or take it out of reset, every processor in the CPU complex +	*        except the master (CPU 0) will be held in reset because the +	*        AVP only talks to the master. The AVP does not know that there +	*        are multiple processors in the CPU complex. +	*/ +	int mask = crc_rst_cpu | crc_rst_de | crc_rst_debug; +	int num_cpus = get_num_cpus(); +	int cpu; + +	debug("reset_a9_cpu entry\n"); +	/* Hold CPUs 1 onwards in reset, and CPU 0 if asked */ +	for (cpu = 1; cpu < num_cpus; cpu++) +		reset_cmplx_set_enable(cpu, mask, 1); +	reset_cmplx_set_enable(0, mask, reset); + +	/* Enable/Disable master CPU reset */ +	reset_set_enable(PERIPH_ID_CPU, reset); +} + +void clock_enable_coresight(int enable) +{ +	u32 rst, src = 2; + +	debug("clock_enable_coresight entry\n"); +	clock_set_enable(PERIPH_ID_CORESIGHT, enable); +	reset_set_enable(PERIPH_ID_CORESIGHT, !enable); + +	if (enable) { +		/* +		 * Put CoreSight on PLLP_OUT0 and divide it down as per +		 * PLLP base frequency based on SoC type (T20/T30+). +		 * Clock divider request would setup CSITE clock as 144MHz +		 * for PLLP base 216MHz and 204MHz for PLLP base 408MHz +		 */ +		src = CLK_DIVIDER(NVBL_PLLP_KHZ, CSITE_KHZ); +		clock_ll_set_source_divisor(PERIPH_ID_CSI, 0, src); + +		/* Unlock the CPU CoreSight interfaces */ +		rst = CORESIGHT_UNLOCK; +		writel(rst, CSITE_CPU_DBG0_LAR); +		writel(rst, CSITE_CPU_DBG1_LAR); +		if (get_num_cpus() == 4) { +			writel(rst, CSITE_CPU_DBG2_LAR); +			writel(rst, CSITE_CPU_DBG3_LAR); +		} +	} +} + +void halt_avp(void) +{ +	for (;;) { +		writel(HALT_COP_EVENT_JTAG | (FLOW_MODE_STOP << 29), +		       FLOW_CTLR_HALT_COP_EVENTS); +	} +} diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/cpu.h b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/cpu.h new file mode 100644 index 00000000..b4ca44fc --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/cpu.h @@ -0,0 +1,74 @@ +/* + * (C) Copyright 2010-2014 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ +#include <asm/types.h> + +/* Stabilization delays, in usec */ +#define PLL_STABILIZATION_DELAY (300) +#define IO_STABILIZATION_DELAY	(1000) + +#if defined(CONFIG_TEGRA20) +#define NVBL_PLLP_KHZ	216000 +#define CSITE_KHZ	144000 +#elif defined(CONFIG_TEGRA30) || defined(CONFIG_TEGRA114) || \ +	defined(CONFIG_TEGRA124) +#define NVBL_PLLP_KHZ	408000 +#define CSITE_KHZ	204000 +#else +#error "Unknown Tegra chip!" +#endif + +#define PLLX_ENABLED		(1 << 30) +#define CCLK_BURST_POLICY	0x20008888 +#define SUPER_CCLK_DIVIDER	0x80000000 + +/* Calculate clock fractional divider value from ref and target frequencies */ +#define CLK_DIVIDER(REF, FREQ)  ((((REF) * 2) / FREQ) - 2) + +/* Calculate clock frequency value from reference and clock divider value */ +#define CLK_FREQUENCY(REF, REG)  (((REF) * 2) / (REG + 2)) + +/* AVP/CPU ID */ +#define PG_UP_TAG_0_PID_CPU	0x55555555	/* CPU aka "a9" aka "mpcore" */ +#define PG_UP_TAG_0             0x0 + +#define CORESIGHT_UNLOCK	0xC5ACCE55; + +#define EXCEP_VECTOR_CPU_RESET_VECTOR	(NV_PA_EVP_BASE + 0x100) +#define CSITE_CPU_DBG0_LAR		(NV_PA_CSITE_BASE + 0x10FB0) +#define CSITE_CPU_DBG1_LAR		(NV_PA_CSITE_BASE + 0x12FB0) +#define CSITE_CPU_DBG2_LAR		(NV_PA_CSITE_BASE + 0x14FB0) +#define CSITE_CPU_DBG3_LAR		(NV_PA_CSITE_BASE + 0x16FB0) + +#define FLOW_CTLR_HALT_COP_EVENTS	(NV_PA_FLOW_BASE + 4) +#define FLOW_MODE_STOP			2 +#define HALT_COP_EVENT_JTAG		(1 << 28) +#define HALT_COP_EVENT_IRQ_1		(1 << 11) +#define HALT_COP_EVENT_FIQ_1		(1 << 9) + +#define FLOW_MODE_NONE		0 + +#define SIMPLE_PLLX     (CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE) + +struct clk_pll_table { +	u16	n; +	u16	m; +	u8	p; +	u8	cpcon; +}; + +void clock_enable_coresight(int enable); +void enable_cpu_clock(int enable); +void halt_avp(void)  __attribute__ ((noreturn)); +void init_pllx(void); +void powerup_cpu(void); +void reset_A9_cpu(int reset); +void start_cpu(u32 reset_vector); +int tegra_get_chip(void); +int tegra_get_sku_info(void); +int tegra_get_chip_sku(void); +void adjust_pllp_out_freqs(void); +void pmic_enable_cpu_vdd(void); diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/spl.c b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/spl.c new file mode 100644 index 00000000..34795410 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra-common/spl.c @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2012 + * NVIDIA Inc, <www.nvidia.com> + * + * Allen Martin <amartin@nvidia.com> + * + * SPDX-License-Identifier:	GPL-2.0+ + */ +#include <common.h> +#include <spl.h> + +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/apb_misc.h> +#include <asm/arch-tegra/board.h> +#include <asm/arch/spl.h> +#include "cpu.h" + +void spl_board_init(void) +{ +	struct apb_misc_pp_ctlr *apb_misc = +				(struct apb_misc_pp_ctlr *)NV_PA_APB_MISC_BASE; + +	/* enable JTAG */ +	writel(0xC0, &apb_misc->cfg_ctl); + +	board_init_uart_f(); + +	/* Initialize periph GPIOs */ +	gpio_early_init_uart(); + +	clock_early_init(); +	preloader_console_init(); +} + +u32 spl_boot_device(void) +{ +	return BOOT_DEVICE_RAM; +} + +void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) +{ +	debug("image entry point: 0x%X\n", spl_image->entry_point); + +	start_cpu((u32)spl_image->entry_point); +	halt_avp(); +} diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra114/Makefile b/roms/u-boot/arch/arm/cpu/arm720t/tegra114/Makefile new file mode 100644 index 00000000..ea3e55ea --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra114/Makefile @@ -0,0 +1,21 @@ +# +# Copyright (c) 2010-2013, NVIDIA CORPORATION.  All rights reserved. +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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/>. +# + +#obj-y	+= cpu.o t11x.o +obj-y	+= cpu.o diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra114/cpu.c b/roms/u-boot/arch/arm/cpu/arm720t/tegra114/cpu.c new file mode 100644 index 00000000..5ed3bb9d --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra114/cpu.c @@ -0,0 +1,310 @@ +/* + * 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/>. + */ + +#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/clk_rst.h> +#include <asm/arch-tegra/pmc.h> +#include "../tegra-common/cpu.h" + +/* Tegra114-specific CPU init code */ +static void enable_cpu_power_rail(void) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	debug("enable_cpu_power_rail entry\n"); + +	/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */ +	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SCL_PZ6); +	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SDA_PZ7); + +	/* +	 * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz), +	 * set it for 25ms (102MHz * .025) +	 */ +	reg = 0x26E8F0; +	writel(reg, &pmc->pmc_cpupwrgood_timer); + +	/* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */ +	clrbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_POL); +	setbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_OE); + +	/* +	 * Set CLK_RST_CONTROLLER_CPU_SOFTRST_CTRL2_0_CAR2PMC_CPU_ACK_WIDTH +	 * to 408 to satisfy the requirement of having at least 16 CPU clock +	 * cycles before clamp removal. +	 */ + +	clrbits_le32(&clkrst->crc_cpu_softrst_ctrl2, 0xFFF); +	setbits_le32(&clkrst->crc_cpu_softrst_ctrl2, 408); +} + +static void enable_cpu_clocks(void) +{ +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	debug("enable_cpu_clocks entry\n"); + +	/* Wait for PLL-X to lock */ +	do { +		reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); +	} while ((reg & PLL_LOCK_MASK) == 0); + +	/* Wait until all clocks are stable */ +	udelay(PLL_STABILIZATION_DELAY); + +	writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); +	writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); + +	/* Always enable the main CPU complex clocks */ +	clock_enable(PERIPH_ID_CPU); +	clock_enable(PERIPH_ID_CPULP); +	clock_enable(PERIPH_ID_CPUG); +} + +static void remove_cpu_resets(void) +{ +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	debug("remove_cpu_resets entry\n"); +	/* Take the slow non-CPU partition out of reset */ +	reg = readl(&clkrst->crc_rst_cpulp_cmplx_clr); +	writel((reg | CLR_NONCPURESET), &clkrst->crc_rst_cpulp_cmplx_clr); + +	/* Take the fast non-CPU partition out of reset */ +	reg = readl(&clkrst->crc_rst_cpug_cmplx_clr); +	writel((reg | CLR_NONCPURESET), &clkrst->crc_rst_cpug_cmplx_clr); + +	/* Clear the SW-controlled reset of the slow cluster */ +	reg = readl(&clkrst->crc_rst_cpulp_cmplx_clr); +	reg |= (CLR_CPURESET0+CLR_DBGRESET0+CLR_CORERESET0+CLR_CXRESET0); +	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr); + +	/* Clear the SW-controlled reset of the fast cluster */ +	reg = readl(&clkrst->crc_rst_cpug_cmplx_clr); +	reg |= (CLR_CPURESET0+CLR_DBGRESET0+CLR_CORERESET0+CLR_CXRESET0); +	reg |= (CLR_CPURESET1+CLR_DBGRESET1+CLR_CORERESET1+CLR_CXRESET1); +	reg |= (CLR_CPURESET2+CLR_DBGRESET2+CLR_CORERESET2+CLR_CXRESET2); +	reg |= (CLR_CPURESET3+CLR_DBGRESET3+CLR_CORERESET3+CLR_CXRESET3); +	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr); +} + +/** + * The T114 requires some special clock initialization, including setting up + * the DVC I2C, turning on MSELECT and selecting the G CPU cluster + */ +void t114_init_clocks(void) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE; +	u32 val; + +	debug("t114_init_clocks entry\n"); + +	/* Set active CPU cluster to G */ +	clrbits_le32(&flow->cluster_control, 1); + +	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div); + +	debug("Setting up PLLX\n"); +	init_pllx(); + +	val = (1 << CLK_SYS_RATE_AHB_RATE_SHIFT); +	writel(val, &clkrst->crc_clk_sys_rate); + +	/* Enable clocks to required peripherals. TBD - minimize this list */ +	debug("Enabling clocks\n"); + +	clock_set_enable(PERIPH_ID_CACHE2, 1); +	clock_set_enable(PERIPH_ID_GPIO, 1); +	clock_set_enable(PERIPH_ID_TMR, 1); +	clock_set_enable(PERIPH_ID_RTC, 1); +	clock_set_enable(PERIPH_ID_CPU, 1); +	clock_set_enable(PERIPH_ID_EMC, 1); +	clock_set_enable(PERIPH_ID_I2C5, 1); +	clock_set_enable(PERIPH_ID_FUSE, 1); +	clock_set_enable(PERIPH_ID_PMC, 1); +	clock_set_enable(PERIPH_ID_APBDMA, 1); +	clock_set_enable(PERIPH_ID_MEM, 1); +	clock_set_enable(PERIPH_ID_IRAMA, 1); +	clock_set_enable(PERIPH_ID_IRAMB, 1); +	clock_set_enable(PERIPH_ID_IRAMC, 1); +	clock_set_enable(PERIPH_ID_IRAMD, 1); +	clock_set_enable(PERIPH_ID_CORESIGHT, 1); +	clock_set_enable(PERIPH_ID_MSELECT, 1); +	clock_set_enable(PERIPH_ID_EMC1, 1); +	clock_set_enable(PERIPH_ID_MC1, 1); +	clock_set_enable(PERIPH_ID_DVFS, 1); + +	/* +	 * Set MSELECT clock source as PLLP (00), and ask for a clock +	 * divider that would set the MSELECT clock at 102MHz for a +	 * PLLP base of 408MHz. +	 */ +	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0, +		CLK_DIVIDER(NVBL_PLLP_KHZ, 102000)); + +	/* I2C5 (DVC) gets CLK_M and a divisor of 17 */ +	clock_ll_set_source_divisor(PERIPH_ID_I2C5, 3, 16); + +	/* Give clocks time to stabilize */ +	udelay(1000); + +	/* Take required peripherals out of reset */ +	debug("Taking periphs out of reset\n"); +	reset_set_enable(PERIPH_ID_CACHE2, 0); +	reset_set_enable(PERIPH_ID_GPIO, 0); +	reset_set_enable(PERIPH_ID_TMR, 0); +	reset_set_enable(PERIPH_ID_COP, 0); +	reset_set_enable(PERIPH_ID_EMC, 0); +	reset_set_enable(PERIPH_ID_I2C5, 0); +	reset_set_enable(PERIPH_ID_FUSE, 0); +	reset_set_enable(PERIPH_ID_APBDMA, 0); +	reset_set_enable(PERIPH_ID_MEM, 0); +	reset_set_enable(PERIPH_ID_CORESIGHT, 0); +	reset_set_enable(PERIPH_ID_MSELECT, 0); +	reset_set_enable(PERIPH_ID_EMC1, 0); +	reset_set_enable(PERIPH_ID_MC1, 0); +	reset_set_enable(PERIPH_ID_DVFS, 0); + +	debug("t114_init_clocks exit\n"); +} + +static bool is_partition_powered(u32 partid) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; + +	/* Get power gate status */ +	reg = readl(&pmc->pmc_pwrgate_status); +	return !!(reg & (1 << partid)); +} + +static bool is_clamp_enabled(u32 partid) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; + +	/* Get clamp status. */ +	reg = readl(&pmc->pmc_clamp_status); +	return !!(reg & (1 << partid)); +} + +static void power_partition(u32 partid) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + +	debug("%s: part ID = %08X\n", __func__, partid); +	/* Is the partition already on? */ +	if (!is_partition_powered(partid)) { +		/* No, toggle the partition power state (OFF -> ON) */ +		debug("power_partition, toggling state\n"); +		writel(START_CP | partid, &pmc->pmc_pwrgate_toggle); + +		/* Wait for the power to come up */ +		while (!is_partition_powered(partid)) +			; + +		/* Wait for the clamp status to be cleared */ +		while (is_clamp_enabled(partid)) +			; + +		/* Give I/O signals time to stabilize */ +		udelay(IO_STABILIZATION_DELAY); +	} +} + +void powerup_cpus(void) +{ +	debug("powerup_cpus entry\n"); + +	/* We boot to the fast cluster */ +	debug("powerup_cpus entry: G cluster\n"); +	/* Power up the fast cluster rail partition */ +	power_partition(CRAIL); + +	/* Power up the fast cluster non-CPU partition */ +	power_partition(C0NC); + +	/* Power up the fast cluster CPU0 partition */ +	power_partition(CE0); +} + +void start_cpu(u32 reset_vector) +{ +	u32 imme, inst; + +	debug("start_cpu entry, reset_vector = %x\n", reset_vector); + +	t114_init_clocks(); + +	/* Enable VDD_CPU */ +	enable_cpu_power_rail(); + +	/* Get the CPU(s) running */ +	enable_cpu_clocks(); + +	/* Enable CoreSight */ +	clock_enable_coresight(1); + +	/* Take CPU(s) out of reset */ +	remove_cpu_resets(); + +	/* Set the entry point for CPU execution from reset */ + +	/* +	 * A01P with patched boot ROM; vector hard-coded to 0x4003fffc. +	 * See nvbug 1193357 for details. +	 */ + +	/* mov r0, #lsb(reset_vector) */ +	imme = reset_vector & 0xffff; +	inst = imme & 0xfff; +	inst |= ((imme >> 12) << 16); +	inst |= 0xe3000000; +	writel(inst, 0x4003fff0); + +	/* movt r0, #msb(reset_vector) */ +	imme = (reset_vector >> 16) & 0xffff; +	inst = imme & 0xfff; +	inst |= ((imme >> 12) << 16); +	inst |= 0xe3400000; +	writel(inst, 0x4003fff4); + +	/* bx r0 */ +	writel(0xe12fff10, 0x4003fff8); + +	/* b -12 */ +	imme = (u32)-20; +	inst = (imme >> 2) & 0xffffff; +	inst |= 0xea000000; +	writel(inst, 0x4003fffc); + +	/* Write to orignal location for compatibility */ +	writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); + +	/* If the CPU(s) don't already have power, power 'em up */ +	powerup_cpus(); +} diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra124/Makefile b/roms/u-boot/arch/arm/cpu/arm720t/tegra124/Makefile new file mode 100644 index 00000000..61abf45d --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra124/Makefile @@ -0,0 +1,8 @@ +# +# (C) Copyright 2013-2014 +# NVIDIA Corporation <www.nvidia.com> +# +# SPDX-License-Identifier:     GPL-2.0+ +# + +obj-y	+= cpu.o diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra124/cpu.c b/roms/u-boot/arch/arm/cpu/arm720t/tegra124/cpu.c new file mode 100644 index 00000000..6ff6aeb5 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra124/cpu.c @@ -0,0 +1,265 @@ +/* + * (C) Copyright 2013 + * NVIDIA Corporation <www.nvidia.com> + * + * SPDX-License-Identifier:     GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/ahb.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/clk_rst.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/ap.h> +#include "../tegra-common/cpu.h" + +/* Tegra124-specific CPU init code */ + +static void enable_cpu_power_rail(void) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + +	debug("enable_cpu_power_rail entry\n"); + +	/* un-tristate PWR_I2C SCL/SDA, rest of the defaults are correct */ +	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SCL_PZ6); +	pinmux_tristate_disable(PMUX_PINGRP_PWR_I2C_SDA_PZ7); + +	pmic_enable_cpu_vdd(); + +	/* +	 * Set CPUPWRGOOD_TIMER - APB clock is 1/2 of SCLK (102MHz), +	 * set it for 5ms as per SysEng (102MHz*5ms = 510000 (7C830h). +	 */ +	writel(0x7C830, &pmc->pmc_cpupwrgood_timer); + +	/* Set polarity to 0 (normal) and enable CPUPWRREQ_OE */ +	clrbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_POL); +	setbits_le32(&pmc->pmc_cntrl, CPUPWRREQ_OE); +} + +static void enable_cpu_clocks(void) +{ +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	debug("enable_cpu_clocks entry\n"); + +	/* Wait for PLL-X to lock */ +	do { +		reg = readl(&clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); +		debug("%s: PLLX base = 0x%08X\n", __func__, reg); +	} while ((reg & PLL_LOCK_MASK) == 0); + +	debug("%s: PLLX locked, delay for stable clocks\n", __func__); +	/* Wait until all clocks are stable */ +	udelay(PLL_STABILIZATION_DELAY); + +	debug("%s: Setting CCLK_BURST and DIVIDER\n", __func__); +	writel(CCLK_BURST_POLICY, &clkrst->crc_cclk_brst_pol); +	writel(SUPER_CCLK_DIVIDER, &clkrst->crc_super_cclk_div); + +	debug("%s: Enabling clock to all CPUs\n", __func__); +	/* Enable the clock to all CPUs */ +	reg = CLR_CPU3_CLK_STP | CLR_CPU2_CLK_STP | CLR_CPU1_CLK_STP | +		CLR_CPU0_CLK_STP; +	writel(reg, &clkrst->crc_clk_cpu_cmplx_clr); + +	debug("%s: Enabling main CPU complex clocks\n", __func__); +	/* Always enable the main CPU complex clocks */ +	clock_enable(PERIPH_ID_CPU); +	clock_enable(PERIPH_ID_CPULP); +	clock_enable(PERIPH_ID_CPUG); + +	debug("%s: Done\n", __func__); +} + +static void remove_cpu_resets(void) +{ +	struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 reg; + +	debug("remove_cpu_resets entry\n"); + +	/* Take the slow and fast partitions out of reset */ +	reg = CLR_NONCPURESET; +	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr); +	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr); + +	/* Clear the SW-controlled reset of the slow cluster */ +	reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 | +		CLR_L2RESET | CLR_PRESETDBG; +	writel(reg, &clkrst->crc_rst_cpulp_cmplx_clr); + +	/* Clear the SW-controlled reset of the fast cluster */ +	reg = CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0 | +		CLR_CPURESET1 | CLR_DBGRESET1 | CLR_CORERESET1 | CLR_CXRESET1 | +		CLR_CPURESET2 | CLR_DBGRESET2 | CLR_CORERESET2 | CLR_CXRESET2 | +		CLR_CPURESET3 | CLR_DBGRESET3 | CLR_CORERESET3 | CLR_CXRESET3 | +		CLR_L2RESET | CLR_PRESETDBG; +	writel(reg, &clkrst->crc_rst_cpug_cmplx_clr); +} + +/** + * The Tegra124 requires some special clock initialization, including setting up + * the DVC I2C, turning on MSELECT and selecting the G CPU cluster + */ +void tegra124_init_clocks(void) +{ +	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE; +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	u32 val; + +	debug("tegra124_init_clocks entry\n"); + +	/* Set active CPU cluster to G */ +	clrbits_le32(&flow->cluster_control, 1); + +	/* Change the oscillator drive strength */ +	val = readl(&clkrst->crc_osc_ctrl); +	val &= ~OSC_XOFS_MASK; +	val |= (OSC_DRIVE_STRENGTH << OSC_XOFS_SHIFT); +	writel(val, &clkrst->crc_osc_ctrl); + +	/* Update same value in PMC_OSC_EDPD_OVER XOFS field for warmboot */ +	val = readl(&pmc->pmc_osc_edpd_over); +	val &= ~PMC_XOFS_MASK; +	val |= (OSC_DRIVE_STRENGTH << PMC_XOFS_SHIFT); +	writel(val, &pmc->pmc_osc_edpd_over); + +	/* Set HOLD_CKE_LOW_EN to 1 */ +	setbits_le32(&pmc->pmc_cntrl2, HOLD_CKE_LOW_EN); + +	debug("Setting up PLLX\n"); +	init_pllx(); + +	val = (1 << CLK_SYS_RATE_AHB_RATE_SHIFT); +	writel(val, &clkrst->crc_clk_sys_rate); + +	/* Enable clocks to required peripherals. TBD - minimize this list */ +	debug("Enabling clocks\n"); + +	clock_set_enable(PERIPH_ID_CACHE2, 1); +	clock_set_enable(PERIPH_ID_GPIO, 1); +	clock_set_enable(PERIPH_ID_TMR, 1); +	clock_set_enable(PERIPH_ID_CPU, 1); +	clock_set_enable(PERIPH_ID_EMC, 1); +	clock_set_enable(PERIPH_ID_I2C5, 1); +	clock_set_enable(PERIPH_ID_APBDMA, 1); +	clock_set_enable(PERIPH_ID_MEM, 1); +	clock_set_enable(PERIPH_ID_CORESIGHT, 1); +	clock_set_enable(PERIPH_ID_MSELECT, 1); +	clock_set_enable(PERIPH_ID_DVFS, 1); + +	/* +	 * Set MSELECT clock source as PLLP (00), and ask for a clock +	 * divider that would set the MSELECT clock at 102MHz for a +	 * PLLP base of 408MHz. +	 */ +	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0, +				    CLK_DIVIDER(NVBL_PLLP_KHZ, 102000)); + +	/* Give clock time to stabilize */ +	udelay(IO_STABILIZATION_DELAY); + +	/* I2C5 (DVC) gets CLK_M and a divisor of 17 */ +	clock_ll_set_source_divisor(PERIPH_ID_I2C5, 3, 16); + +	/* Give clock time to stabilize */ +	udelay(IO_STABILIZATION_DELAY); + +	/* Take required peripherals out of reset */ +	debug("Taking periphs out of reset\n"); +	reset_set_enable(PERIPH_ID_CACHE2, 0); +	reset_set_enable(PERIPH_ID_GPIO, 0); +	reset_set_enable(PERIPH_ID_TMR, 0); +	reset_set_enable(PERIPH_ID_COP, 0); +	reset_set_enable(PERIPH_ID_EMC, 0); +	reset_set_enable(PERIPH_ID_I2C5, 0); +	reset_set_enable(PERIPH_ID_APBDMA, 0); +	reset_set_enable(PERIPH_ID_MEM, 0); +	reset_set_enable(PERIPH_ID_CORESIGHT, 0); +	reset_set_enable(PERIPH_ID_MSELECT, 0); +	reset_set_enable(PERIPH_ID_DVFS, 0); + +	debug("tegra124_init_clocks exit\n"); +} + +static bool is_partition_powered(u32 partid) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; + +	/* Get power gate status */ +	reg = readl(&pmc->pmc_pwrgate_status); +	return !!(reg & (1 << partid)); +} + +static void power_partition(u32 partid) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + +	debug("%s: part ID = %08X\n", __func__, partid); +	/* Is the partition already on? */ +	if (!is_partition_powered(partid)) { +		/* No, toggle the partition power state (OFF -> ON) */ +		debug("power_partition, toggling state\n"); +		writel(START_CP | partid, &pmc->pmc_pwrgate_toggle); + +		/* Wait for the power to come up */ +		while (!is_partition_powered(partid)) +			; + +		/* Give I/O signals time to stabilize */ +		udelay(IO_STABILIZATION_DELAY); +	} +} + +void powerup_cpus(void) +{ +	debug("powerup_cpus entry\n"); + +	/* We boot to the fast cluster */ +	debug("powerup_cpus entry: G cluster\n"); + +	/* Power up the fast cluster rail partition */ +	debug("powerup_cpus: CRAIL\n"); +	power_partition(CRAIL); + +	/* Power up the fast cluster non-CPU partition */ +	debug("powerup_cpus: C0NC\n"); +	power_partition(C0NC); + +	/* Power up the fast cluster CPU0 partition */ +	debug("powerup_cpus: CE0\n"); +	power_partition(CE0); + +	debug("powerup_cpus: done\n"); +} + +void start_cpu(u32 reset_vector) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; + +	debug("start_cpu entry, reset_vector = %x\n", reset_vector); + +	tegra124_init_clocks(); + +	/* Set power-gating timer multiplier */ +	writel((MULT_8 << TIMER_MULT_SHIFT) | (MULT_8 << TIMER_MULT_CPU_SHIFT), +	       &pmc->pmc_pwrgate_timer_mult); + +	enable_cpu_power_rail(); +	enable_cpu_clocks(); +	clock_enable_coresight(1); +	remove_cpu_resets(); +	writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); +	powerup_cpus(); +	debug("start_cpu exit, should continue @ reset_vector\n"); +} diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra20/Makefile b/roms/u-boot/arch/arm/cpu/arm720t/tegra20/Makefile new file mode 100644 index 00000000..12243fa9 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra20/Makefile @@ -0,0 +1,10 @@ +# +# (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	+= cpu.o diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra20/cpu.c b/roms/u-boot/arch/arm/cpu/arm720t/tegra20/cpu.c new file mode 100644 index 00000000..25338995 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra20/cpu.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010-2012, 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/>. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/pmc.h> +#include "../tegra-common/cpu.h" + +static void enable_cpu_power_rail(void) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; + +	reg = readl(&pmc->pmc_cntrl); +	reg |= CPUPWRREQ_OE; +	writel(reg, &pmc->pmc_cntrl); + +	/* +	 * The TI PMU65861C needs a 3.75ms delay between enabling +	 * the power rail and enabling the CPU clock.  This delay +	 * between SM1EN and SM1 is for switching time + the ramp +	 * up of the voltage to the CPU (VDD_CPU from PMU). +	 */ +	udelay(3750); +} + +void start_cpu(u32 reset_vector) +{ +	/* Enable VDD_CPU */ +	enable_cpu_power_rail(); + +	/* Hold the CPUs in reset */ +	reset_A9_cpu(1); + +	/* Disable the CPU clock */ +	enable_cpu_clock(0); + +	/* Enable CoreSight */ +	clock_enable_coresight(1); + +	/* +	 * Set the entry point for CPU execution from reset, +	 *  if it's a non-zero value. +	 */ +	if (reset_vector) +		writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); + +	/* Enable the CPU clock */ +	enable_cpu_clock(1); + +	/* If the CPU doesn't already have power, power it up */ +	powerup_cpu(); + +	/* Take the CPU out of reset */ +	reset_A9_cpu(0); +} diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra30/Makefile b/roms/u-boot/arch/arm/cpu/arm720t/tegra30/Makefile new file mode 100644 index 00000000..6ff4c552 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra30/Makefile @@ -0,0 +1,20 @@ +# +# Copyright (c) 2010-2012, NVIDIA CORPORATION.  All rights reserved. +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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/>. +# + +obj-y	+= cpu.o diff --git a/roms/u-boot/arch/arm/cpu/arm720t/tegra30/cpu.c b/roms/u-boot/arch/arm/cpu/arm720t/tegra30/cpu.c new file mode 100644 index 00000000..a8064838 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/arm720t/tegra30/cpu.c @@ -0,0 +1,164 @@ +/* + * 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/>. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/flow.h> +#include <asm/arch/tegra.h> +#include <asm/arch-tegra/clk_rst.h> +#include <asm/arch-tegra/pmc.h> +#include <asm/arch-tegra/tegra_i2c.h> +#include "../tegra-common/cpu.h" + +/* Tegra30-specific CPU init code */ +void tegra_i2c_ll_write_addr(uint addr, uint config) +{ +	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; + +	writel(addr, ®->cmd_addr0); +	writel(config, ®->cnfg); +} + +void tegra_i2c_ll_write_data(uint data, uint config) +{ +	struct i2c_ctlr *reg = (struct i2c_ctlr *)TEGRA_DVC_BASE; + +	writel(data, ®->cmd_data1); +	writel(config, ®->cnfg); +} + +#define TPS65911_I2C_ADDR		0x5A +#define TPS65911_VDDCTRL_OP_REG		0x28 +#define TPS65911_VDDCTRL_SR_REG		0x27 +#define TPS65911_VDDCTRL_OP_DATA	(0x2300 | TPS65911_VDDCTRL_OP_REG) +#define TPS65911_VDDCTRL_SR_DATA	(0x0100 | TPS65911_VDDCTRL_SR_REG) +#define I2C_SEND_2_BYTES		0x0A02 + +static void enable_cpu_power_rail(void) +{ +	struct pmc_ctlr *pmc = (struct pmc_ctlr *)NV_PA_PMC_BASE; +	u32 reg; + +	debug("enable_cpu_power_rail entry\n"); +	reg = readl(&pmc->pmc_cntrl); +	reg |= CPUPWRREQ_OE; +	writel(reg, &pmc->pmc_cntrl); + +	/* +	 * Bring up CPU VDD via the TPS65911x PMIC on the DVC I2C bus. +	 * First set VDD to 1.4V, then enable the VDD regulator. +	 */ +	tegra_i2c_ll_write_addr(TPS65911_I2C_ADDR, 2); +	tegra_i2c_ll_write_data(TPS65911_VDDCTRL_OP_DATA, I2C_SEND_2_BYTES); +	udelay(1000); +	tegra_i2c_ll_write_data(TPS65911_VDDCTRL_SR_DATA, I2C_SEND_2_BYTES); +	udelay(10 * 1000); +} + +/** + * The T30 requires some special clock initialization, including setting up + * the dvc i2c, turning on mselect and selecting the G CPU cluster + */ +void t30_init_clocks(void) +{ +	struct clk_rst_ctlr *clkrst = +			(struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; +	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE; +	u32 val; + +	debug("t30_init_clocks entry\n"); +	/* Set active CPU cluster to G */ +	clrbits_le32(flow->cluster_control, 1 << 0); + +	writel(SUPER_SCLK_ENB_MASK, &clkrst->crc_super_sclk_div); + +	val = (0 << CLK_SYS_RATE_HCLK_DISABLE_SHIFT) | +		(1 << CLK_SYS_RATE_AHB_RATE_SHIFT) | +		(0 << CLK_SYS_RATE_PCLK_DISABLE_SHIFT) | +		(0 << CLK_SYS_RATE_APB_RATE_SHIFT); +	writel(val, &clkrst->crc_clk_sys_rate); + +	/* Put i2c, mselect in reset and enable clocks */ +	reset_set_enable(PERIPH_ID_DVC_I2C, 1); +	clock_set_enable(PERIPH_ID_DVC_I2C, 1); +	reset_set_enable(PERIPH_ID_MSELECT, 1); +	clock_set_enable(PERIPH_ID_MSELECT, 1); + +	/* Switch MSELECT clock to PLLP (00) and use a divisor of 2 */ +	clock_ll_set_source_divisor(PERIPH_ID_MSELECT, 0, 2); + +	/* +	 * Our high-level clock routines are not available prior to +	 * relocation. We use the low-level functions which require a +	 * hard-coded divisor. Use CLK_M with divide by (n + 1 = 17) +	 */ +	clock_ll_set_source_divisor(PERIPH_ID_DVC_I2C, 3, 16); + +	/* +	 * Give clocks time to stabilize, then take i2c and mselect out of +	 * reset +	 */ +	udelay(1000); +	reset_set_enable(PERIPH_ID_DVC_I2C, 0); +	reset_set_enable(PERIPH_ID_MSELECT, 0); +} + +static void set_cpu_running(int run) +{ +	struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE; + +	debug("set_cpu_running entry, run = %d\n", run); +	writel(run ? FLOW_MODE_NONE : FLOW_MODE_STOP, &flow->halt_cpu_events); +} + +void start_cpu(u32 reset_vector) +{ +	debug("start_cpu entry, reset_vector = %x\n", reset_vector); +	t30_init_clocks(); + +	/* Enable VDD_CPU */ +	enable_cpu_power_rail(); + +	set_cpu_running(0); + +	/* Hold the CPUs in reset */ +	reset_A9_cpu(1); + +	/* Disable the CPU clock */ +	enable_cpu_clock(0); + +	/* Enable CoreSight */ +	clock_enable_coresight(1); + +	/* +	 * Set the entry point for CPU execution from reset, +	 *  if it's a non-zero value. +	 */ +	if (reset_vector) +		writel(reset_vector, EXCEP_VECTOR_CPU_RESET_VECTOR); + +	/* Enable the CPU clock */ +	enable_cpu_clock(1); + +	/* If the CPU doesn't already have power, power it up */ +	powerup_cpu(); + +	/* Take the CPU out of reset */ +	reset_A9_cpu(0); + +	set_cpu_running(1); +}  | 
