[coreboot-gerrit] Patch set updated for coreboot: 908ef64 tegra132: Add tegra_lp0_resume code

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Mar 27 12:44:47 CET 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9102

-gerrit

commit 908ef64fbc2ebb1283848ca5767d6e5d3156b27d
Author: Yen Lin <yelin at nvidia.com>
Date:   Wed Aug 27 14:35:08 2014 -0700

    tegra132: Add tegra_lp0_resume code
    
    BUG=chrome-os-partner:32015
    BRANCH=None
    TEST=successfully suspend/resume on Rush/Ryu
    
    Signed-off-by: Yen Lin <yelin at nvidia.com>
    
    Change-Id: I279e42fd055805f0060951d272571bda66514ea6
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: a02452e431d9aa6245fb2421773d66fc416d0a6e
    Original-Change-Id: I11cca0a8f5e7a36c1fff690c8070c74706348949
    Original-Reviewed-on: https://chromium-review.googlesource.com/214580
    Original-Reviewed-by: Aaron Durbin <adurbin at chromium.org>
    Original-Commit-Queue: Yen Lin <yelin at nvidia.com>
    Original-Tested-by: Yen Lin <yelin at nvidia.com>
---
 src/soc/nvidia/tegra132/lp0/Makefile            |  58 +++
 src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.c  | 656 ++++++++++++++++++++++++
 src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.ld |  73 +++
 3 files changed, 787 insertions(+)

diff --git a/src/soc/nvidia/tegra132/lp0/Makefile b/src/soc/nvidia/tegra132/lp0/Makefile
new file mode 100644
index 0000000..57680c5
--- /dev/null
+++ b/src/soc/nvidia/tegra132/lp0/Makefile
@@ -0,0 +1,58 @@
+################################################################################
+##
+## Copyright 2014 Google Inc.
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; version 2 of the License.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+##
+################################################################################
+
+CC = $(GCC_PREFIX)gcc
+NM = $(GCC_PREFIX)nm
+OBJCOPY = $(GCC_PREFIX)objcopy
+
+OPENSSL = openssl
+DD = dd
+CP = cp
+MV = mv
+RM = rm
+
+SIGKEY = 00000000000000000000000000000000
+
+.PHONY: all
+all: tegra_lp0_resume.fw
+
+tegra_lp0_resume.elf: tegra_lp0_resume.ld tegra_lp0_resume.c
+	$(CC) -marm -march=armv4t -mno-unaligned-access -nostdlib -static \
+		-Os -fpie -Wl,--build-id=none -ggdb3 -T tegra_lp0_resume.ld \
+		-o $@ $(filter %.c,$+)
+
+tegra_lp0_resume.fw: tegra_lp0_resume.elf
+	@# Get rid of any files we're about to create.
+	$(RM) -f $@.nosig $@.sig $@.tosig
+	@# Convert the ELF image into a binary image.
+	$(OBJCOPY) -O binary $< $@.nosig
+	@# Extract the part of the binary which needs to be signed.
+	$(DD) bs=1 skip=544 if=$@.nosig of=$@.tosig
+	@# Calculate a signature for that part.
+	$(OPENSSL) dgst -mac cmac -macopt cipher:aes-128-cbc \
+		-macopt hexkey:$(SIGKEY) -md5 -binary \
+		$@.tosig > $@.sig
+	@# Inject the signature into the binary image's header.
+	$(DD) conv=notrunc bs=1 seek=272 count=16 if=$@.sig of=$@.nosig
+	@# Copy the signed binary to the target file name.
+	$(MV) $@.nosig $@
+
+clean:
+	$(RM) -f tegra_lp0_resume.fw tegra_lp0_resume.fw.sig
+	$(RM) -f tegra_lp0_resume.fw.tosig tegra_lp0_resume.elf
diff --git a/src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.c b/src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.c
new file mode 100644
index 0000000..87c3ccb
--- /dev/null
+++ b/src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.c
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2014 Google Inc.
+ * Copyright 2013, 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 <stdint.h>
+
+/* Function unit addresses. */
+enum {
+	UP_TAG_BASE = 0X60000000,
+	TIMER_BASE = 0X60005000,
+	CLK_RST_BASE = 0X60006000,
+	FLOW_CTLR_BASE = 0X60007000,
+	TEGRA_EVP_BASE = 0x6000f000,
+	APB_MISC_BASE = 0x70000000,
+	PMC_CTLR_BASE = 0X7000e400,
+	MC_CTLR_BASE = 0X70019000,
+};
+
+
+
+/* UP tag registers. */
+static uint32_t *up_tag_ptr = (void *)(UP_TAG_BASE + 0x0);
+enum {
+	UP_TAG_AVP = 0xaaaaaaaa
+};
+
+
+/*  APB Misc JTAG Configuration Register */
+static uint32_t *misc_pp_config_ctl_ptr = (void *)(APB_MISC_BASE + 0x24);
+enum {
+	PP_CONFIG_CTL_JTAG = 0x1 << 6
+};
+
+
+/* Timer registers. */
+static uint32_t *timer_us_ptr = (void *)(TIMER_BASE + 0x10);
+
+
+
+/* Clock and reset controller registers. */
+static uint32_t *clk_rst_rst_devices_l_ptr = (void *)(CLK_RST_BASE + 0x4);
+enum {
+	SWR_TRIG_SYS_RST = 0x1 << 2
+};
+
+static uint32_t *clk_rst_cclk_burst_policy_ptr = (void *)(CLK_RST_BASE + 0x20);
+enum {
+	CCLK_PLLP_BURST_POLICY = 0x20004444
+};
+
+static uint32_t *clk_rst_super_cclk_div_ptr = (void *)(CLK_RST_BASE + 0x24);
+enum {
+	SUPER_CDIV_ENB = 0x1 << 31
+};
+
+static uint32_t *clk_rst_osc_ctrl_ptr = (void *)(CLK_RST_BASE + 0x50);
+enum {
+	OSC_XOE = 0x1 << 0,
+	OSC_XOFS_SHIFT = 4,
+	OSC_XOFS_MASK = 0x3f << OSC_XOFS_SHIFT,
+	OSC_FREQ_SHIFT = 28,
+	OSC_FREQ_MASK = 0xf << OSC_FREQ_SHIFT
+};
+enum {
+	OSC_FREQ_13 = 0,
+	OSC_FREQ_16P8 = 1,
+	OSC_FREQ_19P2 = 4,
+	OSC_FREQ_38P4 = 5,
+	OSC_FREQ_12 = 8,
+	OSC_FREQ_48 = 9,
+	OSC_FREQ_26 = 12
+};
+
+static uint32_t *clk_rst_pllu_base_ptr = (void *)(CLK_RST_BASE + 0xc0);
+enum {
+	PLLU_DIVM_SHIFT = 0,
+	PLLU_DIVN_SHIFT = 8,
+	PLLU_OVERRIDE = 0x1 << 24,
+	PLLU_ENABLE = 0x1 << 30,
+	PLLU_BYPASS = 0x1 << 31
+};
+
+static uint32_t *clk_rst_pllu_misc_ptr = (void *)(CLK_RST_BASE + 0xcc);
+enum {
+	PLLU_LFCON_SHIFT = 4,
+	PLLU_CPCON_SHIFT = 8,
+	PLLU_LOCK_ENABLE = 22
+};
+
+static uint32_t *clk_rst_pllx_base_ptr = (void *)(CLK_RST_BASE + 0xe0);
+enum {
+	PLLX_ENABLE = 0x1 << 30
+};
+
+static uint32_t *clk_rst_rst_dev_u_clr_ptr = (void *)(CLK_RST_BASE + 0x314);
+enum {
+	SWR_CSITE_RST = 0x1 << 9
+};
+
+static uint32_t *clk_rst_clk_enb_l_set_ptr = (void *)(CLK_RST_BASE + 0x320);
+enum {
+	CLK_ENB_CPU = 0x1 << 0
+};
+
+static uint32_t *clk_rst_clk_out_enb_u_set_ptr =
+	(void *)(CLK_RST_BASE + 0x330);
+enum {
+	CLK_ENB_CSITE = 0x1 << 9
+};
+
+static uint32_t *clk_rst_cpu_softrst_ctrl2_ptr =
+	(void *)(CLK_RST_BASE + 0x388);
+enum {
+	CAR2PMC_CPU_ACK_WIDTH_SHIFT = 0,
+	CAR2PMC_CPU_ACK_WIDTH_MASK = 0xfff << CAR2PMC_CPU_ACK_WIDTH_SHIFT
+};
+
+static uint32_t *clk_rst_clk_enb_v_set_ptr = (void *)(CLK_RST_BASE + 0x440);
+enum {
+	CLK_ENB_CPUG = 0x1 << 0,
+	CLK_ENB_CPULP = 0x1 << 1,
+};
+
+static uint32_t *clk_rst_rst_cpulp_cmplx_set_ptr =
+	(void *)(CLK_RST_BASE + 0x450);
+enum {
+	SET_CXRESET0 = 0x1 << 20,
+	SET_CXRESET1 = 0x1 << 21
+};
+static uint32_t *clk_rst_rst_cpug_cmplx_clr_ptr =
+	(void *)(CLK_RST_BASE + 0x454);
+enum {
+	CLR_CPURESET0 = 0x1 << 0,
+	CLR_CPURESET1 = 0x1 << 1,
+	CLR_CPURESET2 = 0x1 << 2,
+	CLR_CPURESET3 = 0x1 << 3,
+	CLR_DBGRESET0 = 0x1 << 12,
+	CLR_DBGRESET1 = 0x1 << 13,
+	CLR_DBGRESET2 = 0x1 << 14,
+	CLR_DBGRESET3 = 0x1 << 15,
+	CLR_CORERESET0 = 0x1 << 16,
+	CLR_CORERESET1 = 0x1 << 17,
+	CLR_CORERESET2 = 0x1 << 18,
+	CLR_CORERESET3 = 0x1 << 19,
+	CLR_CXRESET0 = 0x1 << 20,
+	CLR_CXRESET1 = 0x1 << 21,
+	CLR_CXRESET2 = 0x1 << 22,
+	CLR_CXRESET3 = 0x1 << 23,
+	CLR_L2RESET = 0x1 << 24,
+	CLR_NONCPURESET = 0x1 << 29,
+	CLR_PRESETDBG = 0x1 << 30
+};
+
+
+/* Reset vector. */
+
+static uint32_t *evp_cpu_reset_ptr = (void *)(TEGRA_EVP_BASE + 0x100);
+
+
+
+/* Flow controller registers. */
+static uint32_t *flow_ctlr_halt_cop_events_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x4);
+enum {
+	EVENT_MSEC = 0x1 << 24,
+	EVENT_JTAG = 0x1 << 28,
+	FLOW_MODE_SHIFT = 29,
+	FLOW_MODE_STOP = 2 << FLOW_MODE_SHIFT,
+};
+
+static uint32_t *flow_ctlr_cluster_control_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x2c);
+enum {
+	FLOW_CLUSTER_ACTIVE_LP = 0x1 << 0
+};
+
+static uint32_t *flow_ctlr_ram_repair_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x40);
+static uint32_t *flow_ctlr_ram_repair_cluster1_ptr =
+	(void *)(FLOW_CTLR_BASE + 0x58);
+enum {
+	RAM_REPAIR_REQ = 0x1 << 0,
+	RAM_REPAIR_STS = 0x1 << 1,
+};
+
+
+/* Power management controller registers. */
+enum {
+	PARTID_CRAIL = 0,
+	PARTID_CE0 = 14,
+	PARTID_C0NC = 15,
+};
+
+static uint32_t *pmc_ctlr_clamp_status_ptr = (void *)(PMC_CTLR_BASE + 0x2c);
+
+static uint32_t *pmc_ctlr_pwrgate_toggle_ptr = (void *)(PMC_CTLR_BASE + 0x30);
+enum {
+	PWRGATE_TOGGLE_START = 0x1 << 8
+};
+
+static uint32_t *pmc_ctlr_pwrgate_status_ptr = (void *)(PMC_CTLR_BASE + 0x38);
+
+static uint32_t *pmc_ctlr_cpupwrgood_timer_ptr =
+	(void *)(PMC_CTLR_BASE + 0xc8);
+
+static uint32_t *pmc_odmdata_ptr = (void *)(PMC_CTLR_BASE + 0xa0);
+
+static uint32_t *pmc_ctlr_scratch41_ptr = (void *)(PMC_CTLR_BASE + 0x140);
+static uint32_t *pmc_ctlr_secure_scratch34_ptr = (void *)(PMC_CTLR_BASE + 0x368);
+static uint32_t *pmc_ctlr_secure_scratch35_ptr = (void *)(PMC_CTLR_BASE + 0x36c);
+
+static uint32_t *pmc_ctlr_osc_edpd_over_ptr = (void *)(PMC_CTLR_BASE + 0x1a4);
+enum {
+	PMC_XOFS_SHIFT = 1,
+	PMC_XOFS_MASK = 0x3f << PMC_XOFS_SHIFT
+};
+
+
+
+/* Memory controller registers. */
+static uint32_t *mc_video_protect_size_mb_ptr = (void *)(MC_CTLR_BASE + 0x64c);
+
+static uint32_t *mc_video_protect_reg_ctrl_ptr =
+	(void *)(MC_CTLR_BASE + 0x650);
+enum {
+	VIDEO_PROTECT_WRITE_ACCESS_DISABLE = 0x1 << 0,
+	VIDEO_PROTECT_ALLOW_TZ_WRITE_ACCESS = 0x1 << 1
+};
+
+
+/* Utility functions. */
+
+static inline void __attribute__((always_inline))
+		   __attribute__((noreturn)) halt(void)
+{
+	for (;;);
+}
+
+inline static uint32_t read32(const void *addr)
+{
+	return *(volatile uint32_t *)addr;
+}
+
+inline static void write32(uint32_t val, void *addr)
+{
+	*(volatile uint32_t *)addr = val;
+}
+
+inline static void setbits32(uint32_t bits, void *addr)
+{
+	write32(read32(addr) | bits, addr);
+}
+
+inline static void clrbits32(uint32_t bits, void *addr)
+{
+	write32(read32(addr) & ~bits, addr);
+}
+
+static void __attribute__((noreturn)) reset(void)
+{
+	write32(SWR_TRIG_SYS_RST, clk_rst_rst_devices_l_ptr);
+	halt();
+}
+
+static void udelay(unsigned usecs)
+{
+	uint32_t start = read32(timer_us_ptr);
+	while (read32(timer_us_ptr) - start < usecs)
+		;
+}
+
+/* UART related defines */
+static uint32_t *uart_clk_out_enb_regs[4] = {
+	(uint32_t *)0x60006010,
+	(uint32_t *)0x60006010,
+	(uint32_t *)0x60006014,
+	(uint32_t *)0x60006018
+};
+
+static uint32_t *uart_rst_devices_regs[4] = {
+	(uint32_t *)0x60006004,
+	(uint32_t *)0x60006004,
+	(uint32_t *)0x60006008,
+	(uint32_t *)0x6000600c
+};
+
+static uint32_t uart_enable_mask[4] = {
+	1 << 6,
+	1 << 7,
+	1 << 23,
+	1 << 1
+};
+
+static uint32_t *uart_clk_source_regs[4] = {
+	(uint32_t *)0x60006178,
+	(uint32_t *)0x6000617c,
+	(uint32_t *)0x600061a0,
+	(uint32_t *)0x600061c0,
+};
+
+static void enable_uart(void)
+{
+	uint32_t *uart_clk_enb_reg;
+	uint32_t *uart_rst_reg;
+	uint32_t *uart_clk_source;
+	uint32_t uart_port;
+	uint32_t uart_mask;
+
+	/*
+	 * Read odmdata (stored in pmc->odmdata) to determine debug uart port.
+	 *
+	 * Bits 15-17 of odmdata contains debug uart port.
+	 *  0 : UARTA
+	 *  1 : UARTB
+	 *  2 : UARTC
+	 *  3 : UARTD
+	 */
+	uart_port = (read32(pmc_odmdata_ptr) >> 15) & 0x7;
+
+	/* Default to UARTA, since pmc_odmdata is not programmed yet. */
+	/* TODO: if (uart_port >= 4) */
+		uart_port = 0;
+
+	uart_clk_enb_reg = uart_clk_out_enb_regs[uart_port];
+	uart_rst_reg = uart_rst_devices_regs[uart_port];
+	uart_mask = uart_enable_mask[uart_port];
+	uart_clk_source = uart_clk_source_regs[uart_port];
+
+	/* Enable UART clock */
+	setbits32(uart_mask, uart_clk_enb_reg);
+
+	/* Reset and unreset UART */
+	setbits32(uart_mask, uart_rst_reg);
+	clrbits32(uart_mask, uart_rst_reg);
+
+	/* Program UART clock source: PLLP (408000000) */
+	write32(0, uart_clk_source);
+}
+
+/* Accessors. */
+
+static uint32_t get_wakeup_vector(void)
+{
+	return read32(pmc_ctlr_scratch41_ptr);
+}
+
+static unsigned get_osc_freq(void)
+{
+	return (read32(clk_rst_osc_ctrl_ptr) & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT;
+}
+
+
+/* Jtag configuration. */
+
+static void enable_jtag(void)
+{
+	write32(PP_CONFIG_CTL_JTAG, misc_pp_config_ctl_ptr);
+}
+
+/* Clock configuration. */
+
+static void config_oscillator(void)
+{
+	// Read oscillator drive strength from OSC_EDPD_OVER.XOFS and copy
+	// to OSC_CTRL.XOFS and set XOE.
+	uint32_t xofs = (read32(pmc_ctlr_osc_edpd_over_ptr) &
+		    PMC_XOFS_MASK) >> PMC_XOFS_SHIFT;
+
+	uint32_t osc_ctrl = read32(clk_rst_osc_ctrl_ptr);
+	osc_ctrl &= ~OSC_XOFS_MASK;
+	osc_ctrl |= (xofs << OSC_XOFS_SHIFT);
+	osc_ctrl |= OSC_XOE;
+	write32(osc_ctrl, clk_rst_osc_ctrl_ptr);
+}
+
+static void config_pllu(void)
+{
+	// Figure out what parameters to use for PLLU.
+	uint32_t divm, divn, cpcon, lfcon;
+	switch (get_osc_freq()) {
+	case OSC_FREQ_12:
+	case OSC_FREQ_48:
+		divm = 0x0c;
+		divn = 0x3c0;
+		cpcon = 0x0c;
+		lfcon = 0x02;
+		break;
+	case OSC_FREQ_16P8:
+		divm = 0x07;
+		divn = 0x190;
+		cpcon = 0x05;
+		lfcon = 0x02;
+		break;
+	case OSC_FREQ_19P2:
+	case OSC_FREQ_38P4:
+		divm = 0x04;
+		divn = 0xc8;
+		cpcon = 0x03;
+		lfcon = 0x02;
+		break;
+	case OSC_FREQ_26:
+		divm = 0x1a;
+		divn = 0x3c0;
+		cpcon = 0x0c;
+		lfcon = 0x02;
+		break;
+	default:
+		// Map anything that's not recognized to 13MHz.
+		divm = 0x0d;
+		divn = 0x3c0;
+		cpcon = 0x0c;
+		lfcon = 0x02;
+	}
+
+	// Configure PLLU.
+	uint32_t base = PLLU_BYPASS | PLLU_OVERRIDE |
+			(divn << PLLU_DIVN_SHIFT) | (divm << PLLU_DIVM_SHIFT);
+	write32(base, clk_rst_pllu_base_ptr);
+	uint32_t misc = (cpcon << PLLU_CPCON_SHIFT) |
+			(lfcon << PLLU_LFCON_SHIFT);
+	write32(misc, clk_rst_pllu_misc_ptr);
+
+	// Enable PLLU.
+	base &= ~PLLU_BYPASS;
+	base |= PLLU_ENABLE;
+	write32(base, clk_rst_pllu_base_ptr);
+	misc |= PLLU_LOCK_ENABLE;
+	write32(misc, clk_rst_pllu_misc_ptr);
+}
+
+static void enable_cpu_clocks(void)
+{
+	// Enable the CPU complex clock.
+	write32(CLK_ENB_CPU, clk_rst_clk_enb_l_set_ptr);
+	write32(CLK_ENB_CPUG | CLK_ENB_CPULP, clk_rst_clk_enb_v_set_ptr);
+}
+
+
+
+/* Function unit configuration. */
+
+static void config_core_sight(void)
+{
+	// Enable the CoreSight clock.
+	write32(CLK_ENB_CSITE, clk_rst_clk_out_enb_u_set_ptr);
+
+	/*
+	 * De-assert CoreSight reset.
+	 * NOTE: We're leaving the CoreSight clock on the oscillator for
+	 *       now. It will be restored to its original clock source
+	 *       when the CPU-side restoration code runs.
+	 */
+	write32(SWR_CSITE_RST, clk_rst_rst_dev_u_clr_ptr);
+}
+
+
+/* Resets. */
+
+static void clear_cpu_resets(void)
+{
+	/* Hold CPU1 in reset */
+	setbits32(SET_CXRESET1, clk_rst_rst_cpulp_cmplx_set_ptr);
+
+	write32(CLR_NONCPURESET | CLR_L2RESET | CLR_PRESETDBG,
+		clk_rst_rst_cpug_cmplx_clr_ptr);
+
+	write32(CLR_CPURESET0 | CLR_DBGRESET0 | CLR_CORERESET0 | CLR_CXRESET0,
+		clk_rst_rst_cpug_cmplx_clr_ptr);
+}
+
+
+
+/* RAM repair */
+
+void ram_repair(void)
+{
+	// Request Cluster0 RAM repair.
+	setbits32(RAM_REPAIR_REQ, flow_ctlr_ram_repair_ptr);
+	// Poll for Cluster0 RAM repair status.
+	while (!(read32(flow_ctlr_ram_repair_ptr) & RAM_REPAIR_STS))
+		;
+
+	// Request Cluster1 RAM repair.
+	setbits32(RAM_REPAIR_REQ, flow_ctlr_ram_repair_cluster1_ptr);
+	// Poll for Cluster1 RAM repair status.
+	while (!(read32(flow_ctlr_ram_repair_cluster1_ptr) & RAM_REPAIR_STS))
+		;
+}
+
+
+/* Power. */
+
+static void power_on_partition(unsigned id)
+{
+	uint32_t bit = 0x1 << id;
+	if (!(read32(pmc_ctlr_pwrgate_status_ptr) & bit)) {
+		// Partition is not on. Turn it on.
+		write32(id | PWRGATE_TOGGLE_START, pmc_ctlr_pwrgate_toggle_ptr);
+
+		// Wait until the partition is powerd on.
+		while (!(read32(pmc_ctlr_pwrgate_status_ptr) & bit))
+			;
+
+		// Wait until clamp is off.
+		while (read32(pmc_ctlr_clamp_status_ptr) & bit)
+			;
+	}
+}
+
+static void power_on_main_cpu(void)
+{
+	/*
+	 * Reprogram PMC_CPUPWRGOOD_TIMER register:
+	 *
+	 * XXX This is a fragile assumption. XXX
+	 * The kernel prepares PMC_CPUPWRGOOD_TIMER based on a 32768Hz clock.
+	 * Note that PMC_CPUPWRGOOD_TIMER is running at pclk.
+	 *
+	 * We need to reprogram PMC_CPUPWRGOOD_TIMER based on the current pclk
+	 * which is at 204Mhz (pclk = sclk = pllp_out2) after BootROM. Multiply
+	 * PMC_CPUPWRGOOD_TIMER by 204M / 32K.
+	 *
+	 * Save the original PMC_CPUPWRGOOD_TIMER register which we need to
+	 * restore after the CPU is powered up.
+	 */
+	uint32_t orig_timer = read32(pmc_ctlr_cpupwrgood_timer_ptr);
+
+	write32(orig_timer * (204000000 / 32768),
+		pmc_ctlr_cpupwrgood_timer_ptr);
+
+	power_on_partition(PARTID_CRAIL);
+	power_on_partition(PARTID_C0NC);
+	power_on_partition(PARTID_CE0);
+
+	// Restore the original PMC_CPUPWRGOOD_TIMER.
+	write32(orig_timer, pmc_ctlr_cpupwrgood_timer_ptr);
+}
+
+
+static void aarch64_trampoline(void)
+{
+	uint32_t val = 3;	/* bit1: to warm reset; bit0: AARCH64*/
+
+	asm volatile ("mcr p15, 0, %0, c12, c0, 2" : : "r" (val));
+
+	/* unreachable */
+	halt();
+}
+
+
+/* Entry point. */
+
+void lp0_resume(void)
+{
+	// If not on the AVP, reset.
+	if (read32(up_tag_ptr) != UP_TAG_AVP)
+		reset();
+
+	// Enable JTAG
+	enable_jtag();
+
+	config_oscillator();
+
+	// Program SUPER_CCLK_DIVIDER.
+	write32(SUPER_CDIV_ENB, clk_rst_super_cclk_div_ptr);
+
+	config_core_sight();
+
+	enable_uart();
+
+	config_pllu();
+
+	/*
+	 * Set the CPU reset vector.
+	 *
+	 * T132 always resets to AARCH32 and SW needs to write RMR_EL3
+	 * to bootstrap into AARCH64.
+	 */
+	write32(get_wakeup_vector(), pmc_ctlr_secure_scratch34_ptr);
+	write32(0, pmc_ctlr_secure_scratch35_ptr);
+	write32((uint32_t)aarch64_trampoline, evp_cpu_reset_ptr);
+
+	// Select CPU complex clock source.
+	write32(CCLK_PLLP_BURST_POLICY, clk_rst_cclk_burst_policy_ptr);
+
+	// Disable PLLX since it isn't used as CPU clock source.
+	clrbits32(PLLX_ENABLE, clk_rst_pllx_base_ptr);
+
+	// Set CAR2PMC_CPU_ACK_WIDTH to 408.
+	uint32_t ack_width = read32(clk_rst_cpu_softrst_ctrl2_ptr);
+	ack_width &= ~CAR2PMC_CPU_ACK_WIDTH_MASK;
+	ack_width |= 408 << CAR2PMC_CPU_ACK_WIDTH_SHIFT;
+	write32(ack_width, clk_rst_cpu_softrst_ctrl2_ptr);
+
+	// Disable VPR.
+	write32(0, mc_video_protect_size_mb_ptr);
+	write32(VIDEO_PROTECT_WRITE_ACCESS_DISABLE,
+		mc_video_protect_reg_ctrl_ptr);
+
+	enable_cpu_clocks();
+
+	power_on_main_cpu();
+
+	// Perform ram repair after cpu is powered on.
+	ram_repair();
+
+	clear_cpu_resets();
+
+	// Halt the AVP.
+	while (1)
+		write32(FLOW_MODE_STOP | EVENT_JTAG,
+			flow_ctlr_halt_cop_events_ptr);
+}
+
+
+
+/* Header. */
+
+extern uint8_t blob_data;
+extern uint8_t blob_data_size;
+extern uint8_t blob_total_size;
+
+struct lp0_header {
+	uint32_t length_insecure;	// Insecure total length.
+	uint32_t reserved[3];
+	uint8_t rsa_modulus[256];	// RSA key modulus.
+	uint8_t aes_signature[16];	// AES signature.
+	uint8_t rsa_signature[256];	// RSA-PSS signature.
+	uint8_t random_aes_block[16];	// Random data, may be zero.
+	uint32_t length_secure;		// Secure total length.
+	uint32_t destination;		// Where to load the blob in iRAM.
+	uint32_t entry_point;		// Entry point for the blob.
+	uint32_t code_length;		// Length of just the data.
+} __attribute__((packed));
+
+struct lp0_header header __attribute__((section(".header"))) =
+{
+	.length_insecure = (uintptr_t)&blob_total_size,
+	.length_secure = (uintptr_t)&blob_total_size,
+	.destination = (uintptr_t)&blob_data,
+	.entry_point = (uintptr_t)&lp0_resume,
+	.code_length = (uintptr_t)&blob_data_size
+};
diff --git a/src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.ld b/src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.ld
new file mode 100644
index 0000000..c4c508f
--- /dev/null
+++ b/src/soc/nvidia/tegra132/lp0/tegra_lp0_resume.ld
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* We use ELF as output format. So that we can debug the code in some form. */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+PHDRS
+{
+	to_load PT_LOAD;
+}
+
+ENTRY(lp0_resume)
+SECTIONS
+{
+	. = 0x40020000 - 0x240;
+
+	/*
+	 * The lp0 blob header is built as a static data structure and put
+	 * in the .header section.
+	 */
+	.header_start = .;
+	.header . : {
+		*(.header);
+	} : to_load = 0xff
+	.header_end = .;
+
+	. = 0x40020000;
+
+	/* The actual lp0 blob code. */
+	.data_start = .;
+	.data . : {
+		*(.text);
+		*(.text.*);
+		*(.rodata);
+		*(.rodata.*);
+		*(.data);
+		*(.data.*);
+		*(.bss);
+		*(.bss.*);
+		*(.sbss);
+		*(.sbss.*);
+		. = ALIGN(16);
+	}
+	.data_end = .;
+
+	/* Some values we need in the header. */
+	blob_data = .data_start;
+	blob_data_size = .data_end - .data_start;
+	blob_total_size = .data_end - .header_start;
+
+	/DISCARD/ : {
+		*(.comment)
+		*(.note)
+		*(.comment.*)
+		*(.note.*)
+		*(.ARM.*)
+	}
+}



More information about the coreboot-gerrit mailing list