[U-Boot] [PATCH v2 0/20] tegra: warmboot (suspend / resume) support

This series adds support for warm boot, allowing the device to suspend and resume. U-Boot sets up some 'warm boot' code in a special area such that the SOC can find it on a resume. This code is responsible for setting up memory and clocked and then allowing the OS to continue where it left off.
Also included here is support for the EMC, which allows setting the memory timings correctly in U-Boot for maximum speed operation.
Note: sign-offs are needed from Jimmy Zhang, Wei Ni and Yen Lin.
Changes in v2: - Add check of undocumented values in hidrev register - Add debug() output to EMC - Add new fdtdec_locate_array() function - Add patch to find DVC bus number - Check error return from pmu_set_nominal() in debug mode - Move EMC tables to device tree - Move structs shared between A9 and AVP into warmboot.h header file - New patch to add low-level clock functions - Rely on compiler to optimise out debug_print_vector() - Remove unused crypto code - Remove unused crypto code from crypto.c - Removed check for nominal voltage (not needed as it is done just before) - Split PMU code into separate TPS6586X driver - Tidy SDRAM range check in warmboot_prepare_code() - Tidy whitespace problems - Use const for sbox arrays - Use low-level clock functions in warmboot code instead of register access
Jimmy Zhang (3): tegra: Add EMC support for optimal memory timings tegra: Add PMU to manage power supplies tegra: Add EMC settings for Seaboard
Simon Glass (11): fdt: Add function to locate an array in the device tree i2c: Add TPS6586X driver tegra: Move ap20.h header into arch location tegra: Add functions to access low-level Osc/PLL details tegra: Add tegra_get_chip_type() to detect SKU tegra: Set up PMU for Nvidia boards tegra: Set up warmboot code on Nvidia boards fdt: tegra: Add EMC node to device tree tegra: i2c: Add function to find DVC bus tegra: fdt: Add EMC data for Tegra2 Seaboard tegra: Enable LP0 on Seaboard
Wei Ni (1): Tegra2: Turn off power detect in board init
Yen Lin (5): Add AES crypto library tegra: Add crypto library for warmboot code tegra: Add flow, gp_padctl, fuse, sdram headers tegra: Add warmboot implementation tegra: Setup PMC scratch info from ap20 setup
arch/arm/cpu/armv7/tegra2/Makefile | 4 + arch/arm/cpu/armv7/tegra2/ap20.c | 44 ++- arch/arm/cpu/armv7/tegra2/board.c | 4 +- arch/arm/cpu/armv7/tegra2/clock.c | 32 + arch/arm/cpu/armv7/tegra2/crypto.c | 230 ++++++++ arch/arm/cpu/armv7/tegra2/crypto.h | 36 ++ arch/arm/cpu/armv7/tegra2/emc.c | 192 +++++++ arch/arm/cpu/armv7/tegra2/pmu.c | 70 +++ arch/arm/cpu/armv7/tegra2/warmboot.c | 382 +++++++++++++ arch/arm/cpu/armv7/tegra2/warmboot_avp.c | 250 ++++++++ arch/arm/cpu/armv7/tegra2/warmboot_avp.h | 81 +++ arch/arm/dts/tegra20.dtsi | 7 + .../tegra2 => include/asm/arch-tegra2}/ap20.h | 7 + arch/arm/include/asm/arch-tegra2/clk_rst.h | 3 + arch/arm/include/asm/arch-tegra2/clock.h | 22 + arch/arm/include/asm/arch-tegra2/emc.h | 112 ++++ arch/arm/include/asm/arch-tegra2/flow.h | 36 ++ arch/arm/include/asm/arch-tegra2/fuse.h | 39 ++ arch/arm/include/asm/arch-tegra2/gp_padctrl.h | 73 +++ arch/arm/include/asm/arch-tegra2/pmu.h | 30 + arch/arm/include/asm/arch-tegra2/sdram_param.h | 148 +++++ arch/arm/include/asm/arch-tegra2/tegra2.h | 25 + arch/arm/include/asm/arch-tegra2/tegra2_i2c.h | 7 + arch/arm/include/asm/arch-tegra2/warmboot.h | 150 +++++ board/nvidia/common/Makefile | 1 + board/nvidia/common/board.c | 38 ++- board/nvidia/common/emc.c | 53 ++ board/nvidia/common/emc.h | 29 + board/nvidia/dts/tegra2-seaboard.dts | 73 +++ drivers/i2c/tegra2_i2c.c | 14 + drivers/power/Makefile | 1 + drivers/power/tps6586x.c | 293 ++++++++++ include/aes.h | 70 +++ include/configs/seaboard.h | 8 + include/configs/tegra2-common.h | 17 + include/fdtdec.h | 21 + include/tps6586x.h | 68 +++ lib/Makefile | 1 + lib/aes.c | 598 ++++++++++++++++++++ lib/fdtdec.c | 13 + 40 files changed, 3278 insertions(+), 4 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/crypto.c create mode 100644 arch/arm/cpu/armv7/tegra2/crypto.h create mode 100644 arch/arm/cpu/armv7/tegra2/emc.c create mode 100644 arch/arm/cpu/armv7/tegra2/pmu.c create mode 100644 arch/arm/cpu/armv7/tegra2/warmboot.c create mode 100644 arch/arm/cpu/armv7/tegra2/warmboot_avp.c create mode 100644 arch/arm/cpu/armv7/tegra2/warmboot_avp.h rename arch/arm/{cpu/armv7/tegra2 => include/asm/arch-tegra2}/ap20.h (96%) create mode 100644 arch/arm/include/asm/arch-tegra2/emc.h create mode 100644 arch/arm/include/asm/arch-tegra2/flow.h create mode 100644 arch/arm/include/asm/arch-tegra2/fuse.h create mode 100644 arch/arm/include/asm/arch-tegra2/gp_padctrl.h create mode 100644 arch/arm/include/asm/arch-tegra2/pmu.h create mode 100644 arch/arm/include/asm/arch-tegra2/sdram_param.h create mode 100644 arch/arm/include/asm/arch-tegra2/warmboot.h create mode 100644 board/nvidia/common/emc.c create mode 100644 board/nvidia/common/emc.h create mode 100644 drivers/power/tps6586x.c create mode 100644 include/aes.h create mode 100644 include/tps6586x.h create mode 100644 lib/aes.c

fdtdec_locate_array() locates an integer array but does not copy it. This saves the caller having to allocated wasted space.
Access to array elements should be through the fdt32_to_cpu() macro.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Add new fdtdec_locate_array() function
include/fdtdec.h | 19 +++++++++++++++++++ lib/fdtdec.c | 11 +++++++++++ 2 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/include/fdtdec.h b/include/fdtdec.h index 82264d4..42744f9 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -251,6 +251,25 @@ int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, u32 *array, int count);
/** + * Look up a property in a node and return a pointer to its contents as a + * unsigned int array of given length. The property must have at least enough + * data for the array ('count' cells). It may have more, but this will be + * ignored. The data is not copied. + * + * Note that you must access elements of the array with fdt32_to_cpu(), + * since the elements will be big endian even on a little endian machine. + * + * @param blob FDT blob + * @param node node to examine + * @param prop_name name of property to find + * @param count number of array elements + * @return pointer to array if found, or NULL if the property is not + * found or there is not enough data + */ +const u32 *fdtdec_locate_array(const void *blob, int node, + const char *prop_name, int count); + +/** * Look up a boolean property in a node and return it. * * A boolean properly is true if present in the device tree and false if not diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 3330edf..f1af878 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -341,6 +341,17 @@ int fdtdec_get_int_array(const void *blob, int node, const char *prop_name, return err; }
+const u32 *fdtdec_locate_array(const void *blob, int node, + const char *prop_name, int count) +{ + const u32 *cell; + int err; + + cell = get_prop_check_min_len(blob, node, prop_name, + sizeof(u32) * count, &err); + return err ? NULL : cell; +} + int fdtdec_get_bool(const void *blob, int node, const char *prop_name) { const s32 *cell;

This power management chip supports battery charging and a large number of power supplies. This initial driver only provides the ability to adjust the two synchronous buck converters SM0 and SM1 in a stepwise manner.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Split PMU code into separate TPS6586X driver
drivers/power/Makefile | 1 + drivers/power/tps6586x.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++ include/tps6586x.h | 68 +++++++++++ 3 files changed, 362 insertions(+), 0 deletions(-) create mode 100644 drivers/power/tps6586x.c create mode 100644 include/tps6586x.h
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ead00f8..9db8ea2 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libpower.o COBJS-$(CONFIG_FTPMU010_POWER) += ftpmu010.o COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o COBJS-$(CONFIG_TWL6030_POWER) += twl6030.o +COBJS-$(CONFIG_TPS6586X_POWER) += tps6586x.o
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c new file mode 100644 index 0000000..5915d6f --- /dev/null +++ b/drivers/power/tps6586x.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <tps6586x.h> +#include <asm/io.h> +#include <i2c.h> + +/* + * abs() handles unsigned ints, shorts and chars and returns a signed long. + * TODO: Move this into common? + */ +#define abs(x) ({ \ + long ret; \ + { \ + typeof((x)) __x = (x); \ + ret = (__x < 0) ? -__x : __x; \ + } \ + ret; \ + }) + +static int bus_num; /* I2C bus we are on */ +#define I2C_ADDRESS 0x34 /* chip requires this address */ +static char inited; /* 1 if we have been inited */ + +enum { + /* Registers that we access */ + SUPPLY_CONTROL1 = 0x20, + SUPPLY_CONTROL2, + SM1_VOLTAGE_V1 = 0x23, + SM1_VOLTAGE_V2, + SM0_VOLTAGE_V1 = 0x26, + SM0_VOLTAGE_V2, + PFM_MODE = 0x47, + + /* Bits in the supply control registers */ + CTRL_SM1_RAMP = 0x01, + CTRL_SM1_SUPPLY2 = 0x02, + CTRL_SM0_RAMP = 0x04, + CTRL_SM0_SUPPLY2 = 0x08, +}; + +#define MAX_I2C_RETRY 3 +int tps6586x_read(int reg) +{ + int i; + uchar data; + int retval = -1; + int old_bus_num; + + old_bus_num = i2c_get_bus_num(); + i2c_set_bus_num(bus_num); + + for (i = 0; i < MAX_I2C_RETRY; ++i) { + if (!i2c_read(I2C_ADDRESS, reg, 1, &data, 1)) { + retval = (int)data; + goto exit; + } + + /* i2c access failed, retry */ + udelay(100); + } + +exit: + i2c_set_bus_num(old_bus_num); + debug("pmu_read %x=%x\n", reg, retval); + if (retval < 0) + debug("%s: failed to read register %#x: %d\n", __func__, reg, + retval); + return retval; +} + +int tps6586x_write(int reg, uchar *data, uint len) +{ + int i; + int retval = -1; + int old_bus_num; + + old_bus_num = i2c_get_bus_num(); + i2c_set_bus_num(bus_num); + + for (i = 0; i < MAX_I2C_RETRY; ++i) { + if (!i2c_write(I2C_ADDRESS, reg, 1, data, len)) { + retval = 0; + goto exit; + } + + /* i2c access failed, retry */ + udelay(100); + } + +exit: + i2c_set_bus_num(old_bus_num); + debug("pmu_write %x=%x: ", reg, retval); + for (i = 0; i < len; i++) + debug("%x ", data[i]); + if (retval) + debug("%s: failed to write register %#x\n", __func__, reg); + return retval; +} + +/* + * Get current voltage of SM0 and SM1 + * + * @param sm0 Place to put SM0 voltage + * @param sm1 Place to put SM1 voltage + * @return 0 if ok, -1 on error + */ +static int read_voltages(int *sm0, int *sm1) +{ + int ctrl1, ctrl2; + int is_v2; + + /* + * Each vdd has two supply sources, ie, v1 and v2. + * The supply control reg1 and reg2 determine the current selection. + */ + ctrl1 = tps6586x_read(SUPPLY_CONTROL1); + ctrl2 = tps6586x_read(SUPPLY_CONTROL2); + if (ctrl1 == -1 || ctrl2 == -1) + return -1; + + /* Figure out whether V1 or V2 is selected */ + is_v2 = (ctrl1 | ctrl2) & CTRL_SM0_SUPPLY2; + *sm0 = tps6586x_read(is_v2 ? SM0_VOLTAGE_V2 : SM0_VOLTAGE_V1); + *sm1 = tps6586x_read(is_v2 ? SM1_VOLTAGE_V2 : SM1_VOLTAGE_V1); + if (*sm0 == -1 || *sm1 == -1) + return -1; + + return 0; +} + +static int set_voltage(int reg, int data, int rate) +{ + uchar control_bit; + uchar buff[3]; + + control_bit = (reg == SM0_VOLTAGE_V1 ? CTRL_SM0_RAMP : CTRL_SM1_RAMP); + + /* + * Only one supply is needed in u-boot. set both v1 and v2 to + * same value. + * + * When both v1 and v2 are set to same value, we just need to set + * control1 reg to trigger the supply selection. + */ + buff[0] = buff[1] = (uchar)data; + buff[2] = rate; + + /* write v1, v2 and rate, then trigger */ + if (tps6586x_write(reg, buff, 3) || + tps6586x_write(SUPPLY_CONTROL1, &control_bit, 1)) + return -1; + + return 0; +} + +static int calculate_next_voltage(int voltage, int target, int step) +{ + int diff = voltage < target ? step : -step; + + if (abs(target - voltage) > step) + voltage += diff; + else + voltage = target; + + return voltage; +} + +int tps6586x_set_pwm_mode(int mask) +{ + uchar val; + int ret; + + assert(inited); + ret = tps6586x_read(PFM_MODE); + if (ret != -1) { + val = (uchar)ret; + val |= mask; + + ret = tps6586x_write(PFM_MODE, &val, 1); + } + + if (ret == -1) + debug("%s: Failed to read/write PWM mode reg\n", __func__); + + return ret; +} + +int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, + int min_sm0_over_sm1) +{ + int sm0, sm1; + int bad; + + assert(inited); + + /* get current voltage settings */ + if (read_voltages(&sm0, &sm1)) { + debug("%s: Cannot read voltage settings\n", __func__); + return -1; + } + + /* + * if vdd_core < vdd_cpu + rel + * skip + * + * This condition may happen when system reboots due to kernel crash. + */ + if (min_sm0_over_sm1 != -1 && sm0 < sm1 + min_sm0_over_sm1) { + debug("%s: SM0 is %d, SM1 is %d, but min_sm0_over_sm1 is %d\n", + __func__, sm0, sm1, min_sm0_over_sm1); + return -1; + } + + /* + * Since vdd_core and vdd_cpu may both stand at either greater or less + * than their nominal voltage, the adjustment may go either directions. + * + * Make sure vdd_core is always higher than vdd_cpu with certain margin. + * So, find out which vdd to adjust first in each step. + * + * case 1: both sm0 and sm1 need to move up + * adjust sm0 before sm1 + * + * case 2: both sm0 and sm1 need to move down + * adjust sm1 before sm0 + * + * case 3: sm0 moves down and sm1 moves up + * adjusting either one first is fine. + * + * Adjust vdd_core and vdd_cpu one step at a time until they reach + * their nominal values. + */ + bad = 0; + while (!bad && (sm0 != sm0_target || sm1 != sm1_target)) { + int adjust_sm0_late = 0; /* flag to adjust vdd_core later */ + + debug("%d-%d %d-%d ", sm0, sm0_target, sm1, sm1_target); + + if (sm0 != sm0_target) { + /* + * if case 1 and case 3, set new sm0 first. + * otherwise, hold down until new sm1 is set. + */ + sm0 = calculate_next_voltage(sm0, sm0_target, step); + if (sm1 < sm1_target) + bad |= set_voltage(SM0_VOLTAGE_V1, sm0, rate); + else + adjust_sm0_late = 1; + } + + if (sm1 != sm1_target) { + sm1 = calculate_next_voltage(sm1, sm1_target, step); + bad |= set_voltage(SM1_VOLTAGE_V1, sm1, rate); + } + + if (adjust_sm0_late) + bad |= set_voltage(SM0_VOLTAGE_V1, sm0, rate); + debug("%d\n", adjust_sm0_late); + } + debug("%d-%d %d-%d done\n", sm0, sm0_target, sm1, sm1_target); + + return bad ? -1 : 0; +} + +int tps6586x_init(int bus) +{ + bus_num = bus; + inited = 1; + + return 0; +} diff --git a/include/tps6586x.h b/include/tps6586x.h new file mode 100644 index 0000000..ab88082 --- /dev/null +++ b/include/tps6586x.h @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __H_ +#define _TPS6586X_H_ + +enum { + /* SM0-2 PWM/PFM Mode Selection */ + TPS6586X_PWM_SM0 = 1 << 0, + TPS6586X_PWM_SM1 = 1 << 1, + TPS6586X_PWM_SM2 = 1 << 2, +}; + +/** + * Enable PWM mode for selected SM0-2 + * + * @param mask Mask of synchronous converter to enable (TPS6586X_PWM_...) + * @return 0 if ok, -1 on error + */ +int tps6586x_set_pwm_mode(int mask); + +/** + * Adjust SM0 and SM1 voltages to the given targets in incremental steps. + * + * @param sm0_target Target voltage for SM0 in 25mW units, 0=725mV, 31=1.5V + * @param sm1_target Target voltage for SM1 in 25mW units, 0=725mV, 31=1.5V + * @param step Amount to change voltage in each step, in 25mW units + * @param rate Slew ratein mV/us: 0=instantly, 1=0.11, 2=0.22, + * 3=0.44, 4=0.88, 5=1.76, 6=3.52, 7=7.04 + * @param min_sm0_over_sm1 Minimum amount by which sm0 must exceed sm1. + * If this condition is not met, no adjustment will be + * done and an error will be reported. Use -1 to skip + * this check. + * @return 0 if ok, -1 on error + */ +int tps6586x_adjust_sm0_sm1(int sm0_target, int sm1_target, int step, int rate, + int min_sm0_over_sm1); + +/** + * Set up the TPS6586X I2C bus number. This will be used for all operations + * on the device. This function must be called before using other functions. + * + * @param bus I2C bus number containing the TPS6586X chip + * @return 0 (always succeeds) + */ +int tps6586x_init(int bus); + +#endif /* _TPS6586X_H_ */

Hello Simon,
Simon Glass wrote:
This power management chip supports battery charging and a large number of power supplies. This initial driver only provides the ability to adjust the two synchronous buck converters SM0 and SM1 in a stepwise manner.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Split PMU code into separate TPS6586X driver
drivers/power/Makefile | 1 + drivers/power/tps6586x.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++ include/tps6586x.h | 68 +++++++++++ 3 files changed, 362 insertions(+), 0 deletions(-) create mode 100644 drivers/power/tps6586x.c create mode 100644 include/tps6586x.h
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ead00f8..9db8ea2 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libpower.o COBJS-$(CONFIG_FTPMU010_POWER) += ftpmu010.o COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o COBJS-$(CONFIG_TWL6030_POWER) += twl6030.o +COBJS-$(CONFIG_TPS6586X_POWER) += tps6586x.o
please hold lists sorted.
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c new file mode 100644 index 0000000..5915d6f --- /dev/null +++ b/drivers/power/tps6586x.c @@ -0,0 +1,293 @@ +/*
- Copyright (c) 2011 The Chromium OS Authors.
- (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com>
- See file CREDITS for list of people who contributed to this
- project.
- 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; either version 2 of
- the License, or (at your option) any later version.
- 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., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#include <common.h> +#include <tps6586x.h> +#include <asm/io.h> +#include <i2c.h>
+/*
- abs() handles unsigned ints, shorts and chars and returns a signed long.
- TODO: Move this into common?
- */
+#define abs(x) ({ \
long ret; \
{ \
typeof((x)) __x = (x); \
ret = (__x < 0) ? -__x : __x; \
} \
ret; \
- })
I thought we have such a define, but couldn't find it ... I vote for moving it to common ...
[...]
diff --git a/include/tps6586x.h b/include/tps6586x.h new file mode 100644 index 0000000..ab88082 --- /dev/null +++ b/include/tps6586x.h @@ -0,0 +1,68 @@
[...]
+/**
wrong comment style.
- Enable PWM mode for selected SM0-2
- @param mask Mask of synchronous converter to enable (TPS6586X_PWM_...)
- @return 0 if ok, -1 on error
- */
+int tps6586x_set_pwm_mode(int mask);
+/**
here too, please fix globally.
bye, Heiko

Hi Heiko,
On Sat, Jan 14, 2012 at 11:30 PM, Heiko Schocher hs@denx.de wrote:
Hello Simon,
Simon Glass wrote:
This power management chip supports battery charging and a large number of power supplies. This initial driver only provides the ability to adjust the two synchronous buck converters SM0 and SM1 in a stepwise manner.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Split PMU code into separate TPS6586X driver
drivers/power/Makefile | 1 + drivers/power/tps6586x.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++ include/tps6586x.h | 68 +++++++++++ 3 files changed, 362 insertions(+), 0 deletions(-) create mode 100644 drivers/power/tps6586x.c create mode 100644 include/tps6586x.h
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ead00f8..9db8ea2 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libpower.o COBJS-$(CONFIG_FTPMU010_POWER) += ftpmu010.o COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o COBJS-$(CONFIG_TWL6030_POWER) += twl6030.o +COBJS-$(CONFIG_TPS6586X_POWER) += tps6586x.o
please hold lists sorted.
Done
COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c new file mode 100644 index 0000000..5915d6f --- /dev/null +++ b/drivers/power/tps6586x.c @@ -0,0 +1,293 @@ +/*
- Copyright (c) 2011 The Chromium OS Authors.
- (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com>
- See file CREDITS for list of people who contributed to this
- project.
- 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; either version 2 of
- the License, or (at your option) any later version.
- 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., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- */
+#include <common.h> +#include <tps6586x.h> +#include <asm/io.h> +#include <i2c.h>
+/*
- abs() handles unsigned ints, shorts and chars and returns a signed long.
- TODO: Move this into common?
- */
+#define abs(x) ({ \
- long ret; \
- { \
- typeof((x)) __x = (x); \
- ret = (__x < 0) ? -__x : __x; \
- } \
- ret; \
- })
I thought we have such a define, but couldn't find it ... I vote for moving it to common ...
OK will do.
Re the comment style, hopefully we are ok with this now.
[snip]
Regards, Simon

From: Yen Lin yelin@nvidia.com
Add support for AES using an implementation form Karl Malbrain. This offers small code size (around 5KB on ARM) and supports 128-bit AES only.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Tidy whitespace problems - Use const for sbox arrays
include/aes.h | 70 +++++++ lib/Makefile | 1 + lib/aes.c | 598 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 669 insertions(+), 0 deletions(-) create mode 100644 include/aes.h create mode 100644 lib/aes.c
diff --git a/include/aes.h b/include/aes.h new file mode 100644 index 0000000..41b0db2 --- /dev/null +++ b/include/aes.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _AES_REF_H_ +#define _AES_REF_H_ + +/* + * AES encryption library, with small code size, supporting only 128-bit AES + * + * AES is a stream cipher which works a block at a time, with each block + * in this case being AES_KEY_LENGTH bytes. + */ + +enum { + AES_STATECOLS = 4, /* columns in the state & expanded key */ + AES_KEYCOLS = 4, /* columns in a key */ + AES_ROUNDS = 10, /* rounds in encryption */ + + AES_KEY_LENGTH = 128 / 8, + AES_EXPAND_KEY_LENGTH = 4 * AES_STATECOLS * (AES_ROUNDS + 1), +}; + +/** + * Expand a key into a key schedule, which is then used for the other + * operations. + * + * \param key Key, of length AES_KEY_LENGTH bytes + * \param expkey Buffer to place expanded key, AES_EXPAND_KEY_LENGTH + */ +void aes_expand_key(u8 *key, u8 *expkey); + +/** + * Encrypt a single block of data + * + * in Input data + * expkey Expanded key to use for encryption (from aes_expand_key()) + * out Output data + */ +void aes_encrypt(u8 *in, u8 *expkey, u8 *out); + +/** + * Decrypt a single block of data + * + * in Input data + * expkey Expanded key to use for decryption (from aes_expand_key()) + * out Output data + */ +void aes_decrypt(u8 *in, u8 *expkey, u8 *out); + +#endif /* _AES_REF_H_ */ diff --git a/lib/Makefile b/lib/Makefile index 421b7ac..684ed3a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -27,6 +27,7 @@ LIB = $(obj)libgeneric.o
ifndef CONFIG_SPL_BUILD COBJS-$(CONFIG_ADDR_MAP) += addr_map.o +COBJS-$(CONFIG_AES) += aes.o COBJS-$(CONFIG_BZIP2) += bzlib.o COBJS-$(CONFIG_BZIP2) += bzlib_crctable.o COBJS-$(CONFIG_BZIP2) += bzlib_decompress.o diff --git a/lib/aes.c b/lib/aes.c new file mode 100644 index 0000000..7da9edb --- /dev/null +++ b/lib/aes.c @@ -0,0 +1,598 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2011 NVIDIA Corporation www.nvidia.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * advanced encryption standard + * author: karl malbrain, malbrain@yahoo.com + * + * This work, including the source code, documentation + * and related data, is placed into the public domain. + * + * The orginal author is Karl Malbrain. + * + * THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY + * OF ANY KIND, NOT EVEN THE IMPLIED WARRANTY OF + * MERCHANTABILITY. THE AUTHOR OF THIS SOFTWARE, + * ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE + * RESULTING FROM THE USE, MODIFICATION, OR + * REDISTRIBUTION OF THIS SOFTWARE. +*/ + +#include <common.h> +#include "aes.h" + +/* forward s-box */ +static const u8 sbox[256] = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, + 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, + 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, + 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, + 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, + 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, + 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, + 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, + 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, + 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, + 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, + 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +}; + +/* inverse s-box */ +static const u8 inv_sbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, + 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, + 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, + 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, + 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, + 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, + 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, + 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, + 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, + 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, + 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, + 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, + 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, + 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, + 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, + 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +}; + +/* combined Xtimes2[Sbox[]] */ +static const u8 x2_sbox[256] = { + 0xc6, 0xf8, 0xee, 0xf6, 0xff, 0xd6, 0xde, 0x91, + 0x60, 0x02, 0xce, 0x56, 0xe7, 0xb5, 0x4d, 0xec, + 0x8f, 0x1f, 0x89, 0xfa, 0xef, 0xb2, 0x8e, 0xfb, + 0x41, 0xb3, 0x5f, 0x45, 0x23, 0x53, 0xe4, 0x9b, + 0x75, 0xe1, 0x3d, 0x4c, 0x6c, 0x7e, 0xf5, 0x83, + 0x68, 0x51, 0xd1, 0xf9, 0xe2, 0xab, 0x62, 0x2a, + 0x08, 0x95, 0x46, 0x9d, 0x30, 0x37, 0x0a, 0x2f, + 0x0e, 0x24, 0x1b, 0xdf, 0xcd, 0x4e, 0x7f, 0xea, + 0x12, 0x1d, 0x58, 0x34, 0x36, 0xdc, 0xb4, 0x5b, + 0xa4, 0x76, 0xb7, 0x7d, 0x52, 0xdd, 0x5e, 0x13, + 0xa6, 0xb9, 0x00, 0xc1, 0x40, 0xe3, 0x79, 0xb6, + 0xd4, 0x8d, 0x67, 0x72, 0x94, 0x98, 0xb0, 0x85, + 0xbb, 0xc5, 0x4f, 0xed, 0x86, 0x9a, 0x66, 0x11, + 0x8a, 0xe9, 0x04, 0xfe, 0xa0, 0x78, 0x25, 0x4b, + 0xa2, 0x5d, 0x80, 0x05, 0x3f, 0x21, 0x70, 0xf1, + 0x63, 0x77, 0xaf, 0x42, 0x20, 0xe5, 0xfd, 0xbf, + 0x81, 0x18, 0x26, 0xc3, 0xbe, 0x35, 0x88, 0x2e, + 0x93, 0x55, 0xfc, 0x7a, 0xc8, 0xba, 0x32, 0xe6, + 0xc0, 0x19, 0x9e, 0xa3, 0x44, 0x54, 0x3b, 0x0b, + 0x8c, 0xc7, 0x6b, 0x28, 0xa7, 0xbc, 0x16, 0xad, + 0xdb, 0x64, 0x74, 0x14, 0x92, 0x0c, 0x48, 0xb8, + 0x9f, 0xbd, 0x43, 0xc4, 0x39, 0x31, 0xd3, 0xf2, + 0xd5, 0x8b, 0x6e, 0xda, 0x01, 0xb1, 0x9c, 0x49, + 0xd8, 0xac, 0xf3, 0xcf, 0xca, 0xf4, 0x47, 0x10, + 0x6f, 0xf0, 0x4a, 0x5c, 0x38, 0x57, 0x73, 0x97, + 0xcb, 0xa1, 0xe8, 0x3e, 0x96, 0x61, 0x0d, 0x0f, + 0xe0, 0x7c, 0x71, 0xcc, 0x90, 0x06, 0xf7, 0x1c, + 0xc2, 0x6a, 0xae, 0x69, 0x17, 0x99, 0x3a, 0x27, + 0xd9, 0xeb, 0x2b, 0x22, 0xd2, 0xa9, 0x07, 0x33, + 0x2d, 0x3c, 0x15, 0xc9, 0x87, 0xaa, 0x50, 0xa5, + 0x03, 0x59, 0x09, 0x1a, 0x65, 0xd7, 0x84, 0xd0, + 0x82, 0x29, 0x5a, 0x1e, 0x7b, 0xa8, 0x6d, 0x2c +}; + +/* combined Xtimes3[Sbox[]] */ +static const u8 x3_sbox[256] = { + 0xa5, 0x84, 0x99, 0x8d, 0x0d, 0xbd, 0xb1, 0x54, + 0x50, 0x03, 0xa9, 0x7d, 0x19, 0x62, 0xe6, 0x9a, + 0x45, 0x9d, 0x40, 0x87, 0x15, 0xeb, 0xc9, 0x0b, + 0xec, 0x67, 0xfd, 0xea, 0xbf, 0xf7, 0x96, 0x5b, + 0xc2, 0x1c, 0xae, 0x6a, 0x5a, 0x41, 0x02, 0x4f, + 0x5c, 0xf4, 0x34, 0x08, 0x93, 0x73, 0x53, 0x3f, + 0x0c, 0x52, 0x65, 0x5e, 0x28, 0xa1, 0x0f, 0xb5, + 0x09, 0x36, 0x9b, 0x3d, 0x26, 0x69, 0xcd, 0x9f, + 0x1b, 0x9e, 0x74, 0x2e, 0x2d, 0xb2, 0xee, 0xfb, + 0xf6, 0x4d, 0x61, 0xce, 0x7b, 0x3e, 0x71, 0x97, + 0xf5, 0x68, 0x00, 0x2c, 0x60, 0x1f, 0xc8, 0xed, + 0xbe, 0x46, 0xd9, 0x4b, 0xde, 0xd4, 0xe8, 0x4a, + 0x6b, 0x2a, 0xe5, 0x16, 0xc5, 0xd7, 0x55, 0x94, + 0xcf, 0x10, 0x06, 0x81, 0xf0, 0x44, 0xba, 0xe3, + 0xf3, 0xfe, 0xc0, 0x8a, 0xad, 0xbc, 0x48, 0x04, + 0xdf, 0xc1, 0x75, 0x63, 0x30, 0x1a, 0x0e, 0x6d, + 0x4c, 0x14, 0x35, 0x2f, 0xe1, 0xa2, 0xcc, 0x39, + 0x57, 0xf2, 0x82, 0x47, 0xac, 0xe7, 0x2b, 0x95, + 0xa0, 0x98, 0xd1, 0x7f, 0x66, 0x7e, 0xab, 0x83, + 0xca, 0x29, 0xd3, 0x3c, 0x79, 0xe2, 0x1d, 0x76, + 0x3b, 0x56, 0x4e, 0x1e, 0xdb, 0x0a, 0x6c, 0xe4, + 0x5d, 0x6e, 0xef, 0xa6, 0xa8, 0xa4, 0x37, 0x8b, + 0x32, 0x43, 0x59, 0xb7, 0x8c, 0x64, 0xd2, 0xe0, + 0xb4, 0xfa, 0x07, 0x25, 0xaf, 0x8e, 0xe9, 0x18, + 0xd5, 0x88, 0x6f, 0x72, 0x24, 0xf1, 0xc7, 0x51, + 0x23, 0x7c, 0x9c, 0x21, 0xdd, 0xdc, 0x86, 0x85, + 0x90, 0x42, 0xc4, 0xaa, 0xd8, 0x05, 0x01, 0x12, + 0xa3, 0x5f, 0xf9, 0xd0, 0x91, 0x58, 0x27, 0xb9, + 0x38, 0x13, 0xb3, 0x33, 0xbb, 0x70, 0x89, 0xa7, + 0xb6, 0x22, 0x92, 0x20, 0x49, 0xff, 0x78, 0x7a, + 0x8f, 0xf8, 0x80, 0x17, 0xda, 0x31, 0xc6, 0xb8, + 0xc3, 0xb0, 0x77, 0x11, 0xcb, 0xfc, 0xd6, 0x3a +}; + +/* + * modular multiplication tables based on: + * + * Xtime2[x] = (x & 0x80 ? 0x1b : 0) ^ (x + x) + * Xtime3[x] = x^Xtime2[x]; + */ +static const u8 x_time_9[256] = { + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, + 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, + 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, + 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, + 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, + 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, + 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, + 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, + 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, + 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, + 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, + 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, + 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, + 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, + 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, + 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, + 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, + 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, + 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, + 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, + 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, + 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, + 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, + 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, + 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, + 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 +}; + +static const u8 x_time_b[256] = { + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, + 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, + 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, + 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, + 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, + 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, + 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, + 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, + 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, + 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, + 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, + 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, + 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, + 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, + 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, + 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, + 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, + 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, + 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, + 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, + 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, + 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, + 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, + 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, + 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, + 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, + 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 +}; + +static const u8 x_time_d[256] = { + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, + 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, + 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, + 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, + 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, + 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, + 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, + 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, + 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, + 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, + 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, + 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, + 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, + 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, + 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, + 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, + 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, + 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, + 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, + 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, + 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, + 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, + 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, + 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, + 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, + 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, + 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 +}; + +static const u8 x_time_e[256] = { + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, + 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, + 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, + 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, + 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, + 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, + 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, + 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, + 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, + 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, + 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, + 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, + 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, + 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, + 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, + 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, + 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, + 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, + 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, + 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, + 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, + 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, + 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, + 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, + 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, + 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, + 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d +}; + +/* + * Exchanges columns in each of 4 rows + * row0 - unchanged, row1- shifted left 1, + * row2 - shifted left 2 and row3 - shifted left 3 + */ +static void shift_rows(u8 *state) +{ + u8 tmp; + + /* just substitute row 0 */ + state[0] = sbox[state[0]]; + state[4] = sbox[state[4]]; + state[8] = sbox[state[8]]; + state[12] = sbox[state[12]]; + + /* rotate row 1 */ + tmp = sbox[state[1]]; + state[1] = sbox[state[5]]; + state[5] = sbox[state[9]]; + state[9] = sbox[state[13]]; + state[13] = tmp; + + /* rotate row 2 */ + tmp = sbox[state[2]]; + state[2] = sbox[state[10]]; + state[10] = tmp; + tmp = sbox[state[6]]; + state[6] = sbox[state[14]]; + state[14] = tmp; + + /* rotate row 3 */ + tmp = sbox[state[15]]; + state[15] = sbox[state[11]]; + state[11] = sbox[state[7]]; + state[7] = sbox[state[3]]; + state[3] = tmp; +} + +/* + * restores columns in each of 4 rows + * row0 - unchanged, row1- shifted right 1, + * row2 - shifted right 2 and row3 - shifted right 3 + */ +static void inv_shift_rows(u8 *state) +{ + u8 tmp; + + /* restore row 0 */ + state[0] = inv_sbox[state[0]]; + state[4] = inv_sbox[state[4]]; + state[8] = inv_sbox[state[8]]; + state[12] = inv_sbox[state[12]]; + + /* restore row 1 */ + tmp = inv_sbox[state[13]]; + state[13] = inv_sbox[state[9]]; + state[9] = inv_sbox[state[5]]; + state[5] = inv_sbox[state[1]]; + state[1] = tmp; + + /* restore row 2 */ + tmp = inv_sbox[state[2]]; + state[2] = inv_sbox[state[10]]; + state[10] = tmp; + tmp = inv_sbox[state[6]]; + state[6] = inv_sbox[state[14]]; + state[14] = tmp; + + /* restore row 3 */ + tmp = inv_sbox[state[3]]; + state[3] = inv_sbox[state[7]]; + state[7] = inv_sbox[state[11]]; + state[11] = inv_sbox[state[15]]; + state[15] = tmp; +} + +/* recombine and mix each row in a column */ +static void mix_sub_columns(u8 *state) +{ + u8 tmp[4 * AES_STATECOLS]; + + /* mixing column 0 */ + tmp[0] = x2_sbox[state[0]] ^ x3_sbox[state[5]] ^ + sbox[state[10]] ^ sbox[state[15]]; + tmp[1] = sbox[state[0]] ^ x2_sbox[state[5]] ^ + x3_sbox[state[10]] ^ sbox[state[15]]; + tmp[2] = sbox[state[0]] ^ sbox[state[5]] ^ + x2_sbox[state[10]] ^ x3_sbox[state[15]]; + tmp[3] = x3_sbox[state[0]] ^ sbox[state[5]] ^ + sbox[state[10]] ^ x2_sbox[state[15]]; + + /* mixing column 1 */ + tmp[4] = x2_sbox[state[4]] ^ x3_sbox[state[9]] ^ + sbox[state[14]] ^ sbox[state[3]]; + tmp[5] = sbox[state[4]] ^ x2_sbox[state[9]] ^ + x3_sbox[state[14]] ^ sbox[state[3]]; + tmp[6] = sbox[state[4]] ^ sbox[state[9]] ^ + x2_sbox[state[14]] ^ x3_sbox[state[3]]; + tmp[7] = x3_sbox[state[4]] ^ sbox[state[9]] ^ + sbox[state[14]] ^ x2_sbox[state[3]]; + + /* mixing column 2 */ + tmp[8] = x2_sbox[state[8]] ^ x3_sbox[state[13]] ^ + sbox[state[2]] ^ sbox[state[7]]; + tmp[9] = sbox[state[8]] ^ x2_sbox[state[13]] ^ + x3_sbox[state[2]] ^ sbox[state[7]]; + tmp[10] = sbox[state[8]] ^ sbox[state[13]] ^ + x2_sbox[state[2]] ^ x3_sbox[state[7]]; + tmp[11] = x3_sbox[state[8]] ^ sbox[state[13]] ^ + sbox[state[2]] ^ x2_sbox[state[7]]; + + /* mixing column 3 */ + tmp[12] = x2_sbox[state[12]] ^ x3_sbox[state[1]] ^ + sbox[state[6]] ^ sbox[state[11]]; + tmp[13] = sbox[state[12]] ^ x2_sbox[state[1]] ^ + x3_sbox[state[6]] ^ sbox[state[11]]; + tmp[14] = sbox[state[12]] ^ sbox[state[1]] ^ + x2_sbox[state[6]] ^ x3_sbox[state[11]]; + tmp[15] = x3_sbox[state[12]] ^ sbox[state[1]] ^ + sbox[state[6]] ^ x2_sbox[state[11]]; + + memcpy(state, tmp, sizeof(tmp)); +} + +/* restore and un-mix each row in a column */ +static void inv_mix_sub_columns(u8 *state) +{ + u8 tmp[4 * AES_STATECOLS]; + int i; + + /* restore column 0 */ + tmp[0] = x_time_e[state[0]] ^ x_time_b[state[1]] ^ + x_time_d[state[2]] ^ x_time_9[state[3]]; + tmp[5] = x_time_9[state[0]] ^ x_time_e[state[1]] ^ + x_time_b[state[2]] ^ x_time_d[state[3]]; + tmp[10] = x_time_d[state[0]] ^ x_time_9[state[1]] ^ + x_time_e[state[2]] ^ x_time_b[state[3]]; + tmp[15] = x_time_b[state[0]] ^ x_time_d[state[1]] ^ + x_time_9[state[2]] ^ x_time_e[state[3]]; + + /* restore column 1 */ + tmp[4] = x_time_e[state[4]] ^ x_time_b[state[5]] ^ + x_time_d[state[6]] ^ x_time_9[state[7]]; + tmp[9] = x_time_9[state[4]] ^ x_time_e[state[5]] ^ + x_time_b[state[6]] ^ x_time_d[state[7]]; + tmp[14] = x_time_d[state[4]] ^ x_time_9[state[5]] ^ + x_time_e[state[6]] ^ x_time_b[state[7]]; + tmp[3] = x_time_b[state[4]] ^ x_time_d[state[5]] ^ + x_time_9[state[6]] ^ x_time_e[state[7]]; + + /* restore column 2 */ + tmp[8] = x_time_e[state[8]] ^ x_time_b[state[9]] ^ + x_time_d[state[10]] ^ x_time_9[state[11]]; + tmp[13] = x_time_9[state[8]] ^ x_time_e[state[9]] ^ + x_time_b[state[10]] ^ x_time_d[state[11]]; + tmp[2] = x_time_d[state[8]] ^ x_time_9[state[9]] ^ + x_time_e[state[10]] ^ x_time_b[state[11]]; + tmp[7] = x_time_b[state[8]] ^ x_time_d[state[9]] ^ + x_time_9[state[10]] ^ x_time_e[state[11]]; + + /* restore column 3 */ + tmp[12] = x_time_e[state[12]] ^ x_time_b[state[13]] ^ + x_time_d[state[14]] ^ x_time_9[state[15]]; + tmp[1] = x_time_9[state[12]] ^ x_time_e[state[13]] ^ + x_time_b[state[14]] ^ x_time_d[state[15]]; + tmp[6] = x_time_d[state[12]] ^ x_time_9[state[13]] ^ + x_time_e[state[14]] ^ x_time_b[state[15]]; + tmp[11] = x_time_b[state[12]] ^ x_time_d[state[13]] ^ + x_time_9[state[14]] ^ x_time_e[state[15]]; + + for (i = 0; i < 4 * AES_STATECOLS; i++) + state[i] = inv_sbox[tmp[i]]; +} + +/* + * encrypt/decrypt columns of the key + * n.b. you can replace this with byte-wise xor if you wish. + */ +static void add_round_key(u32 *state, u32 *key) +{ + int idx; + + for (idx = 0; idx < 4; idx++) + state[idx] ^= key[idx]; +} + +static u8 rcon[11] = { + 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 +}; + +/* produce AES_STATECOLS bytes for each round */ +void aes_expand_key(u8 *key, u8 *expkey) +{ + u8 tmp0, tmp1, tmp2, tmp3, tmp4; + u32 idx; + + memcpy(expkey, key, AES_KEYCOLS * 4); + + for (idx = AES_KEYCOLS; idx < AES_STATECOLS * (AES_ROUNDS + 1); idx++) { + tmp0 = expkey[4*idx - 4]; + tmp1 = expkey[4*idx - 3]; + tmp2 = expkey[4*idx - 2]; + tmp3 = expkey[4*idx - 1]; + if (!(idx % AES_KEYCOLS)) { + tmp4 = tmp3; + tmp3 = sbox[tmp0]; + tmp0 = sbox[tmp1] ^ rcon[idx / AES_KEYCOLS]; + tmp1 = sbox[tmp2]; + tmp2 = sbox[tmp4]; + } else if ((AES_KEYCOLS > 6) && (idx % AES_KEYCOLS == 4)) { + tmp0 = sbox[tmp0]; + tmp1 = sbox[tmp1]; + tmp2 = sbox[tmp2]; + tmp3 = sbox[tmp3]; + } + + expkey[4*idx+0] = expkey[4*idx - 4*AES_KEYCOLS + 0] ^ tmp0; + expkey[4*idx+1] = expkey[4*idx - 4*AES_KEYCOLS + 1] ^ tmp1; + expkey[4*idx+2] = expkey[4*idx - 4*AES_KEYCOLS + 2] ^ tmp2; + expkey[4*idx+3] = expkey[4*idx - 4*AES_KEYCOLS + 3] ^ tmp3; + } +} + +/* encrypt one 128 bit block */ +void aes_encrypt(u8 *in, u8 *expkey, u8 *out) +{ + u8 state[AES_STATECOLS * 4]; + u32 round; + + memcpy(state, in, AES_STATECOLS * 4); + add_round_key((u32 *)state, (u32 *)expkey); + + for (round = 1; round < AES_ROUNDS + 1; round++) { + if (round < AES_ROUNDS) + mix_sub_columns(state); + else + shift_rows(state); + + add_round_key((u32 *)state, + (u32 *)expkey + round * AES_STATECOLS); + } + + memcpy(out, state, sizeof(state)); +} + +void aes_decrypt(u8 *in, u8 *expkey, u8 *out) +{ + u8 state[AES_STATECOLS * 4]; + int round; + + memcpy(state, in, sizeof(state)); + + add_round_key((u32 *)state, + (u32 *)expkey + AES_ROUNDS * AES_STATECOLS); + inv_shift_rows(state); + + for (round = AES_ROUNDS; round--; ) { + add_round_key((u32 *)state, + (u32 *)expkey + round * AES_STATECOLS); + if (round) + inv_mix_sub_columns(state); + } + + memcpy(out, state, sizeof(state)); +}

We want to include this from board code, so move the header into an easily-accessible location.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/armv7/tegra2/ap20.c | 2 +- arch/arm/cpu/armv7/tegra2/board.c | 4 ++-- .../tegra2 => include/asm/arch-tegra2}/ap20.h | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename arch/arm/{cpu/armv7/tegra2 => include/asm/arch-tegra2}/ap20.h (100%)
diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c index 3ea2e26..da7128c 100644 --- a/arch/arm/cpu/armv7/tegra2/ap20.c +++ b/arch/arm/cpu/armv7/tegra2/ap20.c @@ -21,9 +21,9 @@ * MA 02111-1307 USA */
-#include "ap20.h" #include <asm/io.h> #include <asm/arch/tegra2.h> +#include <asm/arch/ap20.h> #include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> #include <asm/arch/pmc.h> diff --git a/arch/arm/cpu/armv7/tegra2/board.c b/arch/arm/cpu/armv7/tegra2/board.c index 77a627d..249473a 100644 --- a/arch/arm/cpu/armv7/tegra2/board.c +++ b/arch/arm/cpu/armv7/tegra2/board.c @@ -23,12 +23,12 @@
#include <common.h> #include <asm/io.h> -#include "ap20.h" +#include <asm/arch/ap20.h> #include <asm/arch/clock.h> #include <asm/arch/funcmux.h> +#include <asm/arch/pmc.h> #include <asm/arch/sys_proto.h> #include <asm/arch/tegra2.h> -#include <asm/arch/pmc.h>
DECLARE_GLOBAL_DATA_PTR;
diff --git a/arch/arm/cpu/armv7/tegra2/ap20.h b/arch/arm/include/asm/arch-tegra2/ap20.h similarity index 100% rename from arch/arm/cpu/armv7/tegra2/ap20.h rename to arch/arm/include/asm/arch-tegra2/ap20.h

Add clock_ll_read_pll() to read PLL parameters and clock_get_osc_bypass() to find out if the Oscillator is bypassed. These are needed by warmboot.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - New patch to add low-level clock functions
arch/arm/cpu/armv7/tegra2/clock.c | 32 ++++++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra2/clk_rst.h | 3 ++ arch/arm/include/asm/arch-tegra2/clock.h | 22 +++++++++++++++++++ 3 files changed, 57 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/tegra2/clock.c b/arch/arm/cpu/armv7/tegra2/clock.c index 11d2346..82444dc 100644 --- a/arch/arm/cpu/armv7/tegra2/clock.c +++ b/arch/arm/cpu/armv7/tegra2/clock.c @@ -407,6 +407,16 @@ enum clock_osc_freq clock_get_osc_freq(void) return (reg & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; }
+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) { @@ -417,6 +427,28 @@ static struct clk_pll *get_pll(enum clock_id 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_isvalid(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) { diff --git a/arch/arm/include/asm/arch-tegra2/clk_rst.h b/arch/arm/include/asm/arch-tegra2/clk_rst.h index 0b6e004..e13b7f7 100644 --- a/arch/arm/include/asm/arch-tegra2/clk_rst.h +++ b/arch/arm/include/asm/arch-tegra2/clk_rst.h @@ -117,6 +117,7 @@ struct clk_rst_ctlr { #define PLL_CPCON_MASK (15U << PLL_CPCON_SHIFT)
#define PLL_LFCON_SHIFT 4 +#define PLL_LFCON_MASK (15U << PLL_LFCON_SHIFT)
#define PLLU_VCO_FREQ_SHIFT 20 #define PLLU_VCO_FREQ_MASK (1U << PLLU_VCO_FREQ_SHIFT) @@ -124,6 +125,8 @@ struct clk_rst_ctlr { /* CLK_RST_CONTROLLER_OSC_CTRL_0 */ #define OSC_FREQ_SHIFT 30 #define OSC_FREQ_MASK (3U << OSC_FREQ_SHIFT) +#define OSC_XOBP_SHIFT 1 +#define OSC_XOBP_MASK (1U << OSC_XOBP_SHIFT)
/* CLK_RST_CONTROLLER_CLK_SOURCE_x_OUT_0 */ #define OUT_CLK_DIVISOR_SHIFT 0 diff --git a/arch/arm/include/asm/arch-tegra2/clock.h b/arch/arm/include/asm/arch-tegra2/clock.h index 080ef18..f5899a6 100644 --- a/arch/arm/include/asm/arch-tegra2/clock.h +++ b/arch/arm/include/asm/arch-tegra2/clock.h @@ -209,6 +209,21 @@ enum clock_osc_freq clock_get_osc_freq(void); unsigned long clock_start_pll(enum clock_id id, u32 divm, u32 divn, u32 divp, u32 cpcon, u32 lfcon);
+/** + * Read low-level parameters of a PLL. + * + * @param id clock id to read (note: USB is not supported) + * @param divm returns input divider + * @param divn returns feedback divider + * @param divp returns post divider 2^n + * @param cpcon returns charge pump setup control + * @param lfcon returns loop filter setup control + * + * @returns 0 if ok, -1 on error (invalid clock id) + */ +int clock_ll_read_pll(enum clock_id clkid, u32 *divm, u32 *divn, + u32 *divp, u32 *cpcon, u32 *lfcon); + /* * Enable a clock * @@ -355,6 +370,13 @@ unsigned clock_get_rate(enum clock_id clkid); */ void clock_ll_start_uart(enum periph_id periph_id);
+/** + * Checks if the oscillator bypass is enabled (XOBP bit) + * + * @return 1 if bypass is enabled, 0 if not + */ +int clock_get_osc_bypass(void); + /* * Checks that clocks are valid and prints a warning if not *

From: Yen Lin yelin@nvidia.com
Provides an interface to aes.c for the warmboot code.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Rely on compiler to optimise out debug_print_vector() - Remove unused crypto code from crypto.c
arch/arm/cpu/armv7/tegra2/crypto.c | 230 ++++++++++++++++++++++++++++++++++++ arch/arm/cpu/armv7/tegra2/crypto.h | 36 ++++++ 2 files changed, 266 insertions(+), 0 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/crypto.c create mode 100644 arch/arm/cpu/armv7/tegra2/crypto.h
diff --git a/arch/arm/cpu/armv7/tegra2/crypto.c b/arch/arm/cpu/armv7/tegra2/crypto.c new file mode 100644 index 0000000..5f0b240 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/crypto.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/errno.h> +#include "crypto.h" +#include "aes.h" + +static u8 zero_key[16]; + +#define AES_CMAC_CONST_RB 0x87 /* from RFC 4493, Figure 2.2 */ + +enum security_op { + SECURITY_SIGN = 1 << 0, /* Sign the data */ + SECURITY_ENCRYPT = 1 << 1, /* Encrypt the data */ +}; + +static void debug_print_vector(char *name, u32 num_bytes, u8 *data) +{ + u32 i; + + debug("%s [%d] @0x%08x", name, num_bytes, (u32)data); + for (i = 0; i < num_bytes; i++) { + if (i % 16 == 0) + debug(" = "); + debug("%02x", data[i]); + if ((i+1) % 16 != 0) + debug(" "); + } + debug("\n"); +} + +/** + * Apply chain data to the destination using EOR + * + * Each array is of length AES_AES_KEY_LENGTH. + * + * \param cbc_chain_data Chain data + * \param src Source data + * \param dst Destination data, which is modified here + */ +static void apply_cbc_chain_data(u8 *cbc_chain_data, u8 *src, u8 *dst) +{ + int i; + + for (i = 0; i < 16; i++) + *dst++ = *src++ ^ *cbc_chain_data++; +} + +/** + * Encrypt some data with AES. + * + * \param key_schedule Expanded key to use + * \param src Source data to encrypt + * \param dst Destination buffer + * \param num_aes_blocks Number of AES blocks to encrypt + */ +static void encrypt_object(u8 *key_schedule, u8 *src, u8 *dst, + u32 num_aes_blocks) +{ + u8 tmp_data[AES_KEY_LENGTH]; + u8 *cbc_chain_data; + u32 i; + + cbc_chain_data = zero_key; /* Convenient array of 0's for IV */ + + for (i = 0; i < num_aes_blocks; i++) { + debug("encrypt_object: block %d of %d\n", i, num_aes_blocks); + debug_print_vector("AES Src", AES_KEY_LENGTH, src); + + /* Apply the chain data */ + apply_cbc_chain_data(cbc_chain_data, src, tmp_data); + debug_print_vector("AES Xor", AES_KEY_LENGTH, tmp_data); + + /* encrypt the AES block */ + aes_encrypt(tmp_data, key_schedule, dst); + debug_print_vector("AES Dst", AES_KEY_LENGTH, dst); + + /* Update pointers for next loop. */ + cbc_chain_data = dst; + src += AES_KEY_LENGTH; + dst += AES_KEY_LENGTH; + } +} + +/** + * Shift a vector left by one bit + * + * \param in Input vector + * \param out Output vector + * \param size Length of vector in bytes + */ +static void left_shift_vector(u8 *in, u8 *out, int size) +{ + int carry = 0; + int i; + + for (i = size - 1; i >= 0; i--) { + out[i] = (in[i] << 1) | carry; + carry = in[i] >> 7; /* get most significant bit */ + } +} + +/** + * Sign a block of data, putting the result into dst. + * + * \param key Input AES key, length AES_KEY_LENGTH + * \param key_schedule Expanded key to use + * \param src Source data of length 'num_aes_blocks' blocks + * \param dst Destination buffer, length AES_KEY_LENGTH + * \param num_aes_blocks Number of AES blocks to encrypt + */ +static void sign_object(u8 *key, u8 *key_schedule, u8 *src, u8 *dst, + u32 num_aes_blocks) +{ + u8 tmp_data[AES_KEY_LENGTH]; + u8 left[AES_KEY_LENGTH]; + u8 k1[AES_KEY_LENGTH]; + u8 *cbc_chain_data; + unsigned i; + + cbc_chain_data = zero_key; /* Convenient array of 0's for IV */ + + /* compute K1 constant needed by AES-CMAC calculation */ + for (i = 0; i < AES_KEY_LENGTH; i++) + tmp_data[i] = 0; + + encrypt_object(key_schedule, tmp_data, left, 1); + debug_print_vector("AES(key, nonce)", AES_KEY_LENGTH, left); + + left_shift_vector(left, k1, sizeof(left)); + debug_print_vector("L", AES_KEY_LENGTH, left); + + if ((left[0] >> 7) != 0) /* get MSB of L */ + k1[AES_KEY_LENGTH-1] ^= AES_CMAC_CONST_RB; + debug_print_vector("K1", AES_KEY_LENGTH, k1); + + /* compute the AES-CMAC value */ + for (i = 0; i < num_aes_blocks; i++) { + /* Apply the chain data */ + apply_cbc_chain_data(cbc_chain_data, src, tmp_data); + + /* for the final block, XOR K1 into the IV */ + if (i == num_aes_blocks - 1) + apply_cbc_chain_data(tmp_data, k1, tmp_data); + + /* encrypt the AES block */ + aes_encrypt(tmp_data, key_schedule, dst); + + debug("sign_obj: block %d of %d\n", i, num_aes_blocks); + debug_print_vector("AES-CMAC Src", AES_KEY_LENGTH, src); + debug_print_vector("AES-CMAC Xor", AES_KEY_LENGTH, tmp_data); + debug_print_vector("AES-CMAC Dst", AES_KEY_LENGTH, dst); + + /* Update pointers for next loop. */ + cbc_chain_data = dst; + src += AES_KEY_LENGTH; + } + + debug_print_vector("AES-CMAC Hash", AES_KEY_LENGTH, dst); +} + +/** + * Encrypt and sign a block of data (depending on security mode). + * + * \param key Input AES key, length AES_KEY_LENGTH + * \param oper Security operations mask to perform (enum security_op) + * \param src Source data + * \param length Size of source data + * \param sig_dst Destination address for signature, AES_KEY_LENGTH bytes + */ +static int encrypt_and_sign(u8 *key, enum security_op oper, u8 *src, + u32 length, u8 *sig_dst) +{ + u32 num_aes_blocks; + u8 key_schedule[AES_EXPAND_KEY_LENGTH]; + + debug("encrypt_and_sign: length = %d\n", length); + debug_print_vector("AES key", AES_KEY_LENGTH, key); + + /* + * The only need for a key is for signing/checksum purposes, so + * if not encrypting, expand a key of 0s. + */ + aes_expand_key(oper & SECURITY_ENCRYPT ? key : zero_key, key_schedule); + + num_aes_blocks = (length + AES_KEY_LENGTH - 1) / AES_KEY_LENGTH; + + if (oper & SECURITY_ENCRYPT) { + /* Perform this in place, resulting in src being encrypted. */ + debug("encrypt_and_sign: begin encryption\n"); + encrypt_object(key_schedule, src, src, num_aes_blocks); + debug("encrypt_and_sign: end encryption\n"); + } + + if (oper & SECURITY_SIGN) { + /* encrypt the data, overwriting the result in signature. */ + debug("encrypt_and_sign: begin signing\n"); + sign_object(key, key_schedule, src, sig_dst, num_aes_blocks); + debug("encrypt_and_sign: end signing\n"); + } + + return 0; +} + +int sign_data_block(u8 *source, unsigned length, u8 *signature) +{ + return encrypt_and_sign(zero_key, SECURITY_SIGN, source, + length, signature); +} diff --git a/arch/arm/cpu/armv7/tegra2/crypto.h b/arch/arm/cpu/armv7/tegra2/crypto.h new file mode 100644 index 0000000..aff67e7 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/crypto.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010 - 2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _CRYPTO_H_ +#define _CRYPTO_H_ + +/** + * Sign a block of data + * + * \param source Source data + * \param length Size of source data + * \param signature Destination address for signature, AES_KEY_LENGTH bytes + */ +int sign_data_block(u8 *source, unsigned length, u8 *signature); + +#endif /* #ifndef _CRYPTO_H_ */

From: Yen Lin yelin@nvidia.com
These headers provide access to additional Tegra features.
flow - start/stop CPUs sdram - parameters for SDRAM fuse - access to on-chip fuses / security settings gp_padctl - pad control and general purpose registers
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/include/asm/arch-tegra2/flow.h | 36 ++++++ arch/arm/include/asm/arch-tegra2/fuse.h | 39 ++++++ arch/arm/include/asm/arch-tegra2/gp_padctrl.h | 64 ++++++++++ arch/arm/include/asm/arch-tegra2/sdram_param.h | 148 ++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra2/tegra2.h | 1 + 5 files changed, 288 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra2/flow.h create mode 100644 arch/arm/include/asm/arch-tegra2/fuse.h create mode 100644 arch/arm/include/asm/arch-tegra2/gp_padctrl.h create mode 100644 arch/arm/include/asm/arch-tegra2/sdram_param.h
diff --git a/arch/arm/include/asm/arch-tegra2/flow.h b/arch/arm/include/asm/arch-tegra2/flow.h new file mode 100644 index 0000000..cce6cbf --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/flow.h @@ -0,0 +1,36 @@ +/* + * (C) Copyright 2010, 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _FLOW_H_ +#define _FLOW_H_ + +struct flow_ctlr { + u32 halt_cpu_events; + u32 halt_cop_events; + u32 cpu_csr; + u32 cop_csr; + u32 halt_cpu1_events; + u32 cpu1_csr; +}; + +#endif diff --git a/arch/arm/include/asm/arch-tegra2/fuse.h b/arch/arm/include/asm/arch-tegra2/fuse.h new file mode 100644 index 0000000..b7e3808 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/fuse.h @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _FUSE_H_ +#define _FUSE_H_ + +/* FUSE registers */ +struct fuse_regs { + u32 reserved0[64]; /* 0x00 - 0xFC: */ + u32 production_mode; /* 0x100: FUSE_PRODUCTION_MODE */ + u32 reserved1[3]; /* 0x104 - 0x10c: */ + u32 sku_info; /* 0x110 */ + u32 reserved2[13]; /* 0x114 - 0x144: */ + u32 fa; /* 0x148: FUSE_FA */ + u32 reserved3[21]; /* 0x14C - 0x19C: */ + u32 security_mode; /* 0x1A0: FUSE_SECURITY_MODE */ +}; + +#endif /* ifndef _FUSE_H_ */ diff --git a/arch/arm/include/asm/arch-tegra2/gp_padctrl.h b/arch/arm/include/asm/arch-tegra2/gp_padctrl.h new file mode 100644 index 0000000..25bb46d --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/gp_padctrl.h @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _GP_PADCTRL_H_ +#define _GP_PADCTRL_H_ + +/* APB_MISC_GP and padctrl registers */ +struct apb_misc_gp_ctlr { + u32 modereg; /* 0x00: APB_MISC_GP_MODEREG */ + u32 hidrev; /* 0x04: APB_MISC_GP_HIDREV */ + u32 reserved0[22]; /* 0x08 - 0x5C: */ + u32 emu_revid; /* 0x60: APB_MISC_GP_EMU_REVID */ + u32 xactor_scratch; /* 0x64: APB_MISC_GP_XACTOR_SCRATCH */ + u32 aocfg1; /* 0x68: APB_MISC_GP_AOCFG1PADCTRL */ + u32 aocfg2; /* 0x6c: APB_MISC_GP_AOCFG2PADCTRL */ + u32 atcfg1; /* 0x70: APB_MISC_GP_ATCFG1PADCTRL */ + u32 atcfg2; /* 0x74: APB_MISC_GP_ATCFG2PADCTRL */ + u32 cdevcfg1; /* 0x78: APB_MISC_GP_CDEV1CFGPADCTRL */ + u32 cdevcfg2; /* 0x7C: APB_MISC_GP_CDEV2CFGPADCTRL */ + u32 csuscfg; /* 0x80: APB_MISC_GP_CSUSCFGPADCTRL */ + u32 dap1cfg; /* 0x84: APB_MISC_GP_DAP1CFGPADCTRL */ + u32 dap2cfg; /* 0x88: APB_MISC_GP_DAP2CFGPADCTRL */ + u32 dap3cfg; /* 0x8C: APB_MISC_GP_DAP3CFGPADCTRL */ + u32 dap4cfg; /* 0x90: APB_MISC_GP_DAP4CFGPADCTRL */ + u32 dbgcfg; /* 0x94: APB_MISC_GP_DBGCFGPADCTRL */ + u32 lcdcfg1; /* 0x98: APB_MISC_GP_LCDCFG1PADCTRL */ + u32 lcdcfg2; /* 0x9C: APB_MISC_GP_LCDCFG2PADCTRL */ + u32 sdmmc2_cfg; /* 0xA0: APB_MISC_GP_SDMMC2CFGPADCTRL */ + u32 sdmmc3_cfg; /* 0xA4: APB_MISC_GP_SDMMC3CFGPADCTRL */ + u32 spicfg; /* 0xA8: APB_MISC_GP_SPICFGPADCTRL */ + u32 uaacfg; /* 0xAC: APB_MISC_GP_UAACFGPADCTRL */ + u32 uabcfg; /* 0xB0: APB_MISC_GP_UABCFGPADCTRL */ + u32 uart2cfg; /* 0xB4: APB_MISC_GP_UART2CFGPADCTRL */ + u32 uart3cfg; /* 0xB8: APB_MISC_GP_UART3CFGPADCTRL */ + u32 vicfg1; /* 0xBC: APB_MISC_GP_VICFG1PADCTRL */ + u32 vicfg2; /* 0xC0: APB_MISC_GP_VICFG2PADCTRL */ + u32 xm2cfga; /* 0xC4: APB_MISC_GP_XM2CFGAPADCTRL */ + u32 xm2cfgc; /* 0xC8: APB_MISC_GP_XM2CFGCPADCTRL */ + u32 xm2cfgd; /* 0xCC: APB_MISC_GP_XM2CFGDPADCTRL */ + u32 xm2clkcfg; /* 0xD0: APB_MISC_GP_XM2CLKCFGPADCTRL */ + u32 memcomp; /* 0xD4: APB_MISC_GP_MEMCOMPPADCTRL */ +}; + +#endif diff --git a/arch/arm/include/asm/arch-tegra2/sdram_param.h b/arch/arm/include/asm/arch-tegra2/sdram_param.h new file mode 100644 index 0000000..6c427d0 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/sdram_param.h @@ -0,0 +1,148 @@ +/* + * (C) Copyright 2010, 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _SDRAM_PARAM_H_ +#define _SDRAM_PARAM_H_ + +/* + * Defines the number of 32-bit words provided in each set of SDRAM parameters + * for arbitration configuration data. + */ +#define BCT_SDRAM_ARB_CONFIG_WORDS 27 + +enum memory_type { + MEMORY_TYPE_NONE = 0, + MEMORY_TYPE_DDR, + MEMORY_TYPE_LPDDR, + MEMORY_TYPE_DDR2, + MEMORY_TYPE_LPDDR2, + MEMORY_TYPE_NUM, + MEMORY_TYPE_FORCE32 = 0x7FFFFFFF +}; + +/* Defines the SDRAM parameter structure */ +struct sdram_params { + enum memory_type memory_type; + u32 pllm_charge_pump_setup_control; + u32 pllm_loop_filter_setup_control; + u32 pllm_input_divider; + u32 pllm_feedback_divider; + u32 pllm_post_divider; + u32 pllm_stable_time; + u32 emc_clock_divider; + u32 emc_auto_cal_interval; + u32 emc_auto_cal_config; + u32 emc_auto_cal_wait; + u32 emc_pin_program_wait; + u32 emc_rc; + u32 emc_rfc; + u32 emc_ras; + u32 emc_rp; + u32 emc_r2w; + u32 emc_w2r; + u32 emc_r2p; + u32 emc_w2p; + u32 emc_rd_rcd; + u32 emc_wr_rcd; + u32 emc_rrd; + u32 emc_rext; + u32 emc_wdv; + u32 emc_quse; + u32 emc_qrst; + u32 emc_qsafe; + u32 emc_rdv; + u32 emc_refresh; + u32 emc_burst_refresh_num; + u32 emc_pdex2wr; + u32 emc_pdex2rd; + u32 emc_pchg2pden; + u32 emc_act2pden; + u32 emc_ar2pden; + u32 emc_rw2pden; + u32 emc_txsr; + u32 emc_tcke; + u32 emc_tfaw; + u32 emc_trpab; + u32 emc_tclkstable; + u32 emc_tclkstop; + u32 emc_trefbw; + u32 emc_quseextra; + u32 emc_fbioc_fg1; + u32 emc_fbio_dqsib_dly; + u32 emc_fbio_dqsib_dly_msb; + u32 emc_fbio_quse_dly; + u32 emc_fbio_quse_dly_msb; + u32 emc_fbio_cfg5; + u32 emc_fbio_cfg6; + u32 emc_fbio_spare; + u32 emc_mrs; + u32 emc_emrs; + u32 emc_mrw1; + u32 emc_mrw2; + u32 emc_mrw3; + u32 emc_mrw_reset_command; + u32 emc_mrw_reset_init_wait; + u32 emc_adr_cfg; + u32 emc_adr_cfg1; + u32 emc_emem_cfg; + u32 emc_low_latency_config; + u32 emc_cfg; + u32 emc_cfg2; + u32 emc_dbg; + u32 ahb_arbitration_xbar_ctrl; + u32 emc_cfg_dig_dll; + u32 emc_dll_xform_dqs; + u32 emc_dll_xform_quse; + u32 warm_boot_wait; + u32 emc_ctt_term_ctrl; + u32 emc_odt_write; + u32 emc_odt_read; + u32 emc_zcal_ref_cnt; + u32 emc_zcal_wait_cnt; + u32 emc_zcal_mrw_cmd; + u32 emc_mrs_reset_dll; + u32 emc_mrw_zq_init_dev0; + u32 emc_mrw_zq_init_dev1; + u32 emc_mrw_zq_init_wait; + u32 emc_mrs_reset_dll_wait; + u32 emc_emrs_emr2; + u32 emc_emrs_emr3; + u32 emc_emrs_ddr2_dll_enable; + u32 emc_mrs_ddr2_dll_reset; + u32 emc_emrs_ddr2_ocd_calib; + u32 emc_edr2_wait; + u32 emc_cfg_clktrim0; + u32 emc_cfg_clktrim1; + u32 emc_cfg_clktrim2; + u32 pmc_ddr_pwr; + u32 apb_misc_gp_xm2cfga_padctrl; + u32 apb_misc_gp_xm2cfgc_padctrl; + u32 apb_misc_gp_xm2cfgc_padctrl2; + u32 apb_misc_gp_xm2cfgd_padctrl; + u32 apb_misc_gp_xm2cfgd_padctrl2; + u32 apb_misc_gp_xm2clkcfg_padctrl; + u32 apb_misc_gp_xm2comp_padctrl; + u32 apb_misc_gp_xm2vttgen_padctrl; + u32 arbitration_config[BCT_SDRAM_ARB_CONFIG_WORDS]; +}; +#endif diff --git a/arch/arm/include/asm/arch-tegra2/tegra2.h b/arch/arm/include/asm/arch-tegra2/tegra2.h index ca1881e..2e152fd 100644 --- a/arch/arm/include/asm/arch-tegra2/tegra2.h +++ b/arch/arm/include/asm/arch-tegra2/tegra2.h @@ -40,6 +40,7 @@ #define NV_PA_APB_UARTE_BASE (NV_PA_APB_MISC_BASE + 0x6400) #define TEGRA2_SPI_BASE (NV_PA_APB_MISC_BASE + 0xC380) #define TEGRA2_PMC_BASE (NV_PA_APB_MISC_BASE + 0xE400) +#define TEGRA2_FUSE_BASE (NV_PA_APB_MISC_BASE + 0xF800) #define NV_PA_CSITE_BASE 0x70040000 #define TEGRA_USB1_BASE 0xC5000000 #define TEGRA_USB3_BASE 0xC5008000

We want to know which type of chip we are running on - the Tegra family has several SKUs. This can be determined by reading a fuse register, so add this function to ap20.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Add check of undocumented values in hidrev register
arch/arm/cpu/armv7/tegra2/ap20.c | 36 +++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra2/ap20.h | 7 +++++ arch/arm/include/asm/arch-tegra2/gp_padctrl.h | 9 ++++++ arch/arm/include/asm/arch-tegra2/tegra2.h | 24 ++++++++++++++++ 4 files changed, 76 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c index da7128c..fadce15 100644 --- a/arch/arm/cpu/armv7/tegra2/ap20.c +++ b/arch/arm/cpu/armv7/tegra2/ap20.c @@ -26,11 +26,47 @@ #include <asm/arch/ap20.h> #include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> +#include <asm/arch/fuse.h> +#include <asm/arch/gp_padctrl.h> #include <asm/arch/pmc.h> #include <asm/arch/pinmux.h> #include <asm/arch/scu.h> #include <common.h>
+int tegra_get_chip_type(void) +{ + struct apb_misc_gp_ctlr *gp; + struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE; + uint tegra_sku_id, rev; + + /* + * This is undocumented, Chip ID is bits 15:8 of the register + * APB_MISC + 0x804, and has value 0x20 for Tegra20, 0x30 for + * Tegra30 + */ + gp = (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE; + rev = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> HIDREV_CHIPID_SHIFT; + + tegra_sku_id = readl(&fuse->sku_info) & 0xff; + + switch (rev) { + case CHIPID_TEGRA2: + switch (tegra_sku_id) { + 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; + } + /* unknown sku id */ + return TEGRA_SOC_UNKNOWN; +} + /* Returns 1 if the current CPU executing is a Cortex-A9, else 0 */ static int ap20_cpu_is_cortexa9(void) { diff --git a/arch/arm/include/asm/arch-tegra2/ap20.h b/arch/arm/include/asm/arch-tegra2/ap20.h index a4b4d73..d222c44 100644 --- a/arch/arm/include/asm/arch-tegra2/ap20.h +++ b/arch/arm/include/asm/arch-tegra2/ap20.h @@ -100,3 +100,10 @@ void tegra2_start(void);
/* This is the main entry into U-Boot, used by the Cortex-A9 */ extern void _start(void); + +/** + * Works out the SOC type used for clocks settings + * + * @return SOC type - see TEGRA_SOC... + */ +int tegra_get_chip_type(void); diff --git a/arch/arm/include/asm/arch-tegra2/gp_padctrl.h b/arch/arm/include/asm/arch-tegra2/gp_padctrl.h index 25bb46d..1755ab2 100644 --- a/arch/arm/include/asm/arch-tegra2/gp_padctrl.h +++ b/arch/arm/include/asm/arch-tegra2/gp_padctrl.h @@ -61,4 +61,13 @@ struct apb_misc_gp_ctlr { u32 memcomp; /* 0xD4: APB_MISC_GP_MEMCOMPPADCTRL */ };
+/* bit fields definitions for APB_MISC_GP_HIDREV register */ +#define HIDREV_CHIPID_SHIFT 8 +#define HIDREV_CHIPID_MASK (0xff << HIDREV_CHIPID_SHIFT) +#define HIDREV_MAJORPREV_SHIFT 4 +#define HIDREV_MAJORPREV_MASK (0xf << HIDREV_MAJORPREV_SHIFT) + +/* CHIPID field returned from APB_MISC_GP_HIDREV register */ +#define CHIPID_TEGRA2 0x20 + #endif diff --git a/arch/arm/include/asm/arch-tegra2/tegra2.h b/arch/arm/include/asm/arch-tegra2/tegra2.h index 2e152fd..d4ada10 100644 --- a/arch/arm/include/asm/arch-tegra2/tegra2.h +++ b/arch/arm/include/asm/arch-tegra2/tegra2.h @@ -33,6 +33,7 @@ #define NV_PA_GPIO_BASE 0x6000D000 #define NV_PA_EVP_BASE 0x6000F000 #define NV_PA_APB_MISC_BASE 0x70000000 +#define TEGRA2_APB_MISC_GP_BASE (NV_PA_APB_MISC_BASE + 0x0800) #define NV_PA_APB_UARTA_BASE (NV_PA_APB_MISC_BASE + 0x6000) #define NV_PA_APB_UARTB_BASE (NV_PA_APB_MISC_BASE + 0x6040) #define NV_PA_APB_UARTC_BASE (NV_PA_APB_MISC_BASE + 0x6200) @@ -55,6 +56,29 @@ struct timerus { unsigned int cntr_1us; }; + +/* Address at which WB code runs, it must not overlap Bootrom's IRAM usage */ +#define AP20_WB_RUN_ADDRESS 0x40020000 + +/* These are the available SKUs (product types) for Tegra */ +enum { + SKU_ID_T20 = 0x8, + SKU_ID_T25SE = 0x14, + SKU_ID_AP25 = 0x17, + SKU_ID_T25 = 0x18, + SKU_ID_AP25E = 0x1b, + SKU_ID_T25E = 0x1c, +}; + +/* These are the SOC categories that affect clocking */ +enum { + TEGRA_SOC_T20, + TEGRA_SOC_T25, + + TEGRA_SOC_COUNT, + TEGRA_SOC_UNKNOWN = -1, +}; + #else /* __ASSEMBLY__ */ #define PRM_RSTCTRL TEGRA2_PMC_BASE #endif

On 01/13/2012 02:35 PM, Simon Glass wrote:
We want to know which type of chip we are running on - the Tegra family has several SKUs. This can be determined by reading a fuse register, so add this function to ap20.
Signed-off-by: Simon Glass sjg@chromium.org
Acked-by: Stephen Warren swarren@nvidia.com

From: Jimmy Zhang jimmzhang@nvidia.com
Add support for setting up the memory controller parameters. Boards can set up an appropriate table in the device tree.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Add debug() output to EMC - Move EMC tables to device tree
arch/arm/cpu/armv7/tegra2/Makefile | 1 + arch/arm/cpu/armv7/tegra2/emc.c | 192 ++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra2/emc.h | 112 +++++++++++++++++++ include/fdtdec.h | 2 + lib/fdtdec.c | 2 + 5 files changed, 309 insertions(+), 0 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/emc.c create mode 100644 arch/arm/include/asm/arch-tegra2/emc.h
diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile index e9ac6c9..dcd6329 100644 --- a/arch/arm/cpu/armv7/tegra2/Makefile +++ b/arch/arm/cpu/armv7/tegra2/Makefile @@ -34,6 +34,7 @@ LIB = $(obj)lib$(SOC).o
SOBJS := lowlevel_init.o COBJS-y := ap20.o board.o clock.o funcmux.o pinmux.o sys_info.o timer.o +COBJS-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o
COBJS := $(COBJS-y) diff --git a/arch/arm/cpu/armv7/tegra2/emc.c b/arch/arm/cpu/armv7/tegra2/emc.c new file mode 100644 index 0000000..10e20c7 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/emc.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <fdtdec.h> +#include <asm/io.h> +#include <asm/arch/ap20.h> +#include <asm/arch/clock.h> +#include <asm/arch/emc.h> +#include <asm/arch/tegra2.h> + +/* + * The EMC registers have shadow registers. When the EMC clock is updated + * in the clock controller, the shadow registers are copied to the active + * registers, allowing glitchless memory bus frequency changes. + * This function updates the shadow registers for a new clock frequency, + * and relies on the clock lock on the emc clock to avoid races between + * multiple frequency changes + */ + +/* + * This table defines the ordering of the registers provided to + * tegra_set_mmc() + * TODO: Convert to fdt version once available + */ +static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { + 0x2c, /* RC */ + 0x30, /* RFC */ + 0x34, /* RAS */ + 0x38, /* RP */ + 0x3c, /* R2W */ + 0x40, /* W2R */ + 0x44, /* R2P */ + 0x48, /* W2P */ + 0x4c, /* RD_RCD */ + 0x50, /* WR_RCD */ + 0x54, /* RRD */ + 0x58, /* REXT */ + 0x5c, /* WDV */ + 0x60, /* QUSE */ + 0x64, /* QRST */ + 0x68, /* QSAFE */ + 0x6c, /* RDV */ + 0x70, /* REFRESH */ + 0x74, /* BURST_REFRESH_NUM */ + 0x78, /* PDEX2WR */ + 0x7c, /* PDEX2RD */ + 0x80, /* PCHG2PDEN */ + 0x84, /* ACT2PDEN */ + 0x88, /* AR2PDEN */ + 0x8c, /* RW2PDEN */ + 0x90, /* TXSR */ + 0x94, /* TCKE */ + 0x98, /* TFAW */ + 0x9c, /* TRPAB */ + 0xa0, /* TCLKSTABLE */ + 0xa4, /* TCLKSTOP */ + 0xa8, /* TREFBW */ + 0xac, /* QUSE_EXTRA */ + 0x114, /* FBIO_CFG6 */ + 0xb0, /* ODT_WRITE */ + 0xb4, /* ODT_READ */ + 0x104, /* FBIO_CFG5 */ + 0x2bc, /* CFG_DIG_DLL */ + 0x2c0, /* DLL_XFORM_DQS */ + 0x2c4, /* DLL_XFORM_QUSE */ + 0x2e0, /* ZCAL_REF_CNT */ + 0x2e4, /* ZCAL_WAIT_CNT */ + 0x2a8, /* AUTO_CAL_INTERVAL */ + 0x2d0, /* CFG_CLKTRIM_0 */ + 0x2d4, /* CFG_CLKTRIM_1 */ + 0x2d8, /* CFG_CLKTRIM_2 */ +}; + +struct emc_ctlr *emc_get_controller(const void *blob) +{ + fdt_addr_t addr; + int node; + + node = fdtdec_next_compatible(blob, 0, COMPAT_NVIDIA_TEGRA20_EMC); + if (node > 0) { + addr = fdtdec_get_addr(blob, node, "reg"); + if (addr != FDT_ADDR_T_NONE) + return (struct emc_ctlr *)addr; + } + return NULL; +} + +/* + * Decode the EMC node of the device tree, returning a pointer to the emc + * controller and the table to be used for the given rate. + * + * @param blob Device tree blob + * @param rate Clock speed of memory controller in Hz (=2x memory bus rate) + * @param tablep Returns pointer to table to program into EMC. There are + * TEGRA_EMC_NUM_REGS entries, destined for offsets as per the + * emc_reg_addr array. + * @return 0 if ok, otherwise a +ve error code which will allow someone to + * figure out roughly what went wrong by looking at this code. + */ +static int decode_emc(const void *blob, unsigned rate, const u32 **tablep) +{ + int node; + + /* + * The EMC clock rate is twice the bus rate, and the bus rate is + * measured in kHz + */ + rate = rate / 2 / 1000; + + for (node = 0; ; ) { + int node_rate; + + node = fdtdec_next_compatible(blob, node, + COMPAT_NVIDIA_TEGRA20_EMC_TABLE); + if (node < 0) + break; + node_rate = fdtdec_get_int(blob, node, "clock-frequency", -1); + if (node_rate == -1) + return 1; /* we expect this property */ + + if (node_rate == rate) + break; + } + if (node < 0) + return 2; + + *tablep = fdtdec_locate_array(blob, node, "nvidia,emc-registers", + TEGRA_EMC_NUM_REGS); + if (!*tablep) { + debug("%s: node '%s' array missing / wrong size\n", __func__, + fdt_get_name(blob, node, NULL)); + return 3; + } + + /* All seems well */ + return 0; +} + +int tegra_set_emc(const void *blob, unsigned rate) +{ + struct emc_ctlr *emc; + const u32 *table; + int err, i; + + emc = emc_get_controller(blob); + if (!emc) + err = -1; + else + err = decode_emc(blob, rate, &table); + if (err) { + debug("Warning: no valid EMC (%d), memory timings unset\n", + err); + return -1; + } + + debug("%s: Table found, setting EMC values as follows:\n", __func__); + for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) { + u32 value = fdt32_to_cpu(table[i]); + u32 addr = (uintptr_t)emc + emc_reg_addr[i]; + + debug(" %#x: %#x\n", addr, value); + writel(value, addr); + } + + /* trigger emc with new settings */ + clock_adjust_periph_pll_div(PERIPH_ID_EMC, CLOCK_ID_MEMORY, + clock_get_rate(CLOCK_ID_MEMORY), NULL); + debug("EMC clock set to %lu\n", + clock_get_periph_rate(PERIPH_ID_EMC, CLOCK_ID_MEMORY)); + + return 0; +} diff --git a/arch/arm/include/asm/arch-tegra2/emc.h b/arch/arm/include/asm/arch-tegra2/emc.h new file mode 100644 index 0000000..1c749e4 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/emc.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _ARCH_EMC_H_ +#define _ARCH_EMC_H_ + +#include <asm/types.h> + +#define TEGRA_EMC_NUM_REGS 46 + +/* EMC Registers */ +struct emc_ctlr { + u32 cfg; /* 0x00: EMC_CFG */ + u32 reserved0[3]; /* 0x04 ~ 0x0C */ + u32 adr_cfg; /* 0x10: EMC_ADR_CFG */ + u32 adr_cfg1; /* 0x14: EMC_ADR_CFG_1 */ + u32 reserved1[2]; /* 0x18 ~ 0x18 */ + u32 refresh_ctrl; /* 0x20: EMC_REFCTRL */ + u32 pin; /* 0x24: EMC_PIN */ + u32 timing_ctrl; /* 0x28: EMC_TIMING_CONTROL */ + u32 rc; /* 0x2C: EMC_RC */ + u32 rfc; /* 0x30: EMC_RFC */ + u32 ras; /* 0x34: EMC_RAS */ + u32 rp; /* 0x38: EMC_RP */ + u32 r2w; /* 0x3C: EMC_R2W */ + u32 w2r; /* 0x40: EMC_W2R */ + u32 r2p; /* 0x44: EMC_R2P */ + u32 w2p; /* 0x48: EMC_W2P */ + u32 rd_rcd; /* 0x4C: EMC_RD_RCD */ + u32 wd_rcd; /* 0x50: EMC_WD_RCD */ + u32 rrd; /* 0x54: EMC_RRD */ + u32 rext; /* 0x58: EMC_REXT */ + u32 wdv; /* 0x5C: EMC_WDV */ + u32 quse; /* 0x60: EMC_QUSE */ + u32 qrst; /* 0x64: EMC_QRST */ + u32 qsafe; /* 0x68: EMC_QSAFE */ + u32 rdv; /* 0x6C: EMC_RDV */ + u32 refresh; /* 0x70: EMC_REFRESH */ + u32 burst_refresh_num; /* 0x74: EMC_BURST_REFRESH_NUM */ + u32 pdex2wr; /* 0x78: EMC_PDEX2WR */ + u32 pdex2rd; /* 0x7c: EMC_PDEX2RD */ + u32 pchg2pden; /* 0x80: EMC_PCHG2PDEN */ + u32 act2pden; /* 0x84: EMC_ACT2PDEN */ + u32 ar2pden; /* 0x88: EMC_AR2PDEN */ + u32 rw2pden; /* 0x8C: EMC_RW2PDEN */ + u32 txsr; /* 0x90: EMC_TXSR */ + u32 tcke; /* 0x94: EMC_TCKE */ + u32 tfaw; /* 0x98: EMC_TFAW */ + u32 trpab; /* 0x9C: EMC_TRPAB */ + u32 tclkstable; /* 0xA0: EMC_TCLKSTABLE */ + u32 tclkstop; /* 0xA4: EMC_TCLKSTOP */ + u32 trefbw; /* 0xA8: EMC_TREFBW */ + u32 quse_extra; /* 0xAC: EMC_QUSE_EXTRA */ + u32 odt_write; /* 0xB0: EMC_ODT_WRITE */ + u32 odt_read; /* 0xB4: EMC_ODT_READ */ + u32 reserved2[5]; /* 0xB8 ~ 0xC8 */ + u32 mrs; /* 0xCC: EMC_MRS */ + u32 emrs; /* 0xD0: EMC_EMRS */ + u32 ref; /* 0xD4: EMC_REF */ + u32 pre; /* 0xD8: EMC_PRE */ + u32 nop; /* 0xDC: EMC_NOP */ + u32 self_ref; /* 0xE0: EMC_SELF_REF */ + u32 dpd; /* 0xE4: EMC_DPD */ + u32 mrw; /* 0xE8: EMC_MRW */ + u32 mrr; /* 0xEC: EMC_MRR */ + u32 reserved3; /* 0xF0: */ + u32 fbio_cfg1; /* 0xF4: EMC_FBIO_CFG1 */ + u32 fbio_dqsib_dly; /* 0xF8: EMC_FBIO_DQSIB_DLY */ + u32 fbio_dqsib_dly_msb; /* 0xFC: EMC_FBIO_DQSIB_DLY_MSG */ + u32 fbio_spare; /* 0x100: SBIO_SPARE */ + /* There are more registers ... */ +}; + +/** + * Set up the EMC for the given rate. The timing parameters are retrieved + * from the device tree "nvidia,tegra20-emc" node and its + * "nvidia,tegra20-emc-table" sub-nodes. + * + * @param blob Device tree blob + * @param rate Clock speed of memory controller in Hz (=2x memory bus rate) + */ +int tegra_set_emc(const void *blob, unsigned rate); + +/** + * Get a pointer to the EMC controller from the device tree. + * + * @param blob Device tree blob + * @return pointer to EMC controller + */ +struct emc_ctlr *emc_get_controller(const void *blob); + +#endif diff --git a/include/fdtdec.h b/include/fdtdec.h index 42744f9..a14f2d7 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -60,6 +60,8 @@ enum fdt_compat_id { COMPAT_NVIDIA_TEGRA20_USB, /* Tegra2 USB port */ COMPAT_NVIDIA_TEGRA20_I2C, /* Tegra2 i2c */ COMPAT_NVIDIA_TEGRA20_DVC, /* Tegra2 dvc (really just i2c) */ + COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra2 memory controller */ + COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra2 memory timing table */
COMPAT_COUNT, }; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index f1af878..f08bfca 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -40,6 +40,8 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"), COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"), COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"), + COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"), + COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"), };
const char *fdtdec_get_compatible(enum fdt_compat_id id)

On 01/13/2012 02:35 PM, Simon Glass wrote:
From: Jimmy Zhang jimmzhang@nvidia.com
Add support for setting up the memory controller parameters. Boards can set up an appropriate table in the device tree.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add debug() output to EMC
- Move EMC tables to device tree
This patch doesn't fully handle the device tree binding. There are two alternatives:
two-level:
emc { ... emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; };
three-level:
emc { ... nvidia,use-ram-code; emc-tables { nvidia,ram-code = <0>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; emc-tables { nvidia,ram-code = <1>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; };
Even if we don't fully implement support for both, we should detect the unsupported and flag an explicit error. But, it's pretty easy to support the other format.
BTW, does:
+ node = fdtdec_next_compatible(blob, node, + COMPAT_NVIDIA_TEGRA20_EMC_TABLE);
limit itself to searching child nodes?

Hi Stephen,
On Thu, Jan 19, 2012 at 1:58 PM, Stephen Warren swarren@nvidia.com wrote:
On 01/13/2012 02:35 PM, Simon Glass wrote:
From: Jimmy Zhang jimmzhang@nvidia.com
Add support for setting up the memory controller parameters. Boards can set up an appropriate table in the device tree.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add debug() output to EMC
- Move EMC tables to device tree
This patch doesn't fully handle the device tree binding. There are two alternatives:
two-level:
emc { ... emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; };
three-level:
emc { ... nvidia,use-ram-code; emc-tables { nvidia,ram-code = <0>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; emc-tables { nvidia,ram-code = <1>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; };
Even if we don't fully implement support for both, we should detect the unsupported and flag an explicit error. But, it's pretty easy to support the other format.
OK I will look at which way to jump on this.
BTW, does:
- node = fdtdec_next_compatible(blob, node,
- COMPAT_NVIDIA_TEGRA20_EMC_TABLE);
limit itself to searching child nodes?
No; I will add that to the docs.
Regards, Simon
-- nvpublic

On 01/19/2012 04:59 PM, Simon Glass wrote:
Hi Stephen,
On Thu, Jan 19, 2012 at 1:58 PM, Stephen Warren swarren@nvidia.com wrote:
On 01/13/2012 02:35 PM, Simon Glass wrote:
From: Jimmy Zhang jimmzhang@nvidia.com
Add support for setting up the memory controller parameters. Boards can set up an appropriate table in the device tree.
...
emc { ... nvidia,use-ram-code; emc-tables { nvidia,ram-code = <0>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; emc-tables { nvidia,ram-code = <1>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; };
...
BTW, does:
node = fdtdec_next_compatible(blob, node,
COMPAT_NVIDIA_TEGRA20_EMC_TABLE);
limit itself to searching child nodes?
No; I will add that to the docs.
OK, in that case, you'll probably want to augment the EMC DT parsing code to validate that the node returned by fdtdec_next_compatible is underneath the same parent node (or perhaps add a new utility function to do this). Otherwise, if you search RAM code 0's node and there's no match, you could end up using a table from under RAM code 1's node.

Hi Stephen,
On Thu, Jan 19, 2012 at 4:10 PM, Stephen Warren swarren@nvidia.com wrote:
On 01/19/2012 04:59 PM, Simon Glass wrote:
Hi Stephen,
On Thu, Jan 19, 2012 at 1:58 PM, Stephen Warren swarren@nvidia.com wrote:
On 01/13/2012 02:35 PM, Simon Glass wrote:
From: Jimmy Zhang jimmzhang@nvidia.com
Add support for setting up the memory controller parameters. Boards can set up an appropriate table in the device tree.
...
emc { ... nvidia,use-ram-code; emc-tables { nvidia,ram-code = <0>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; emc-tables { nvidia,ram-code = <1>; emc-table@190000 { compatible = "nvidia,tegra20-emc-table"; ... }; emc-table@380000 { compatible = "nvidia,tegra20-emc-table"; ... }; }; };
...
BTW, does:
- node = fdtdec_next_compatible(blob, node,
- COMPAT_NVIDIA_TEGRA20_EMC_TABLE);
limit itself to searching child nodes?
No; I will add that to the docs.
OK, in that case, you'll probably want to augment the EMC DT parsing code to validate that the node returned by fdtdec_next_compatible is underneath the same parent node (or perhaps add a new utility function to do this). Otherwise, if you search RAM code 0's node and there's no match, you could end up using a table from under RAM code 1's node.
I forgot to mention that I did this in later versions (v4 and v5).
Regards, Simon
-- nvpublic

From: Jimmy Zhang jimmzhang@nvidia.com
Power supplies must be adjusted in line with clock frequency. This code provides a simple routine to set the voltage to allow operation at maximum frequency.
- Split PMU code into separate TPS6586X driver
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/armv7/tegra2/Makefile | 1 + arch/arm/cpu/armv7/tegra2/pmu.c | 70 ++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-tegra2/pmu.h | 30 ++++++++++++++ 3 files changed, 101 insertions(+), 0 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/pmu.c create mode 100644 arch/arm/include/asm/arch-tegra2/pmu.h
diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile index dcd6329..dba684d 100644 --- a/arch/arm/cpu/armv7/tegra2/Makefile +++ b/arch/arm/cpu/armv7/tegra2/Makefile @@ -35,6 +35,7 @@ LIB = $(obj)lib$(SOC).o SOBJS := lowlevel_init.o COBJS-y := ap20.o board.o clock.o funcmux.o pinmux.o sys_info.o timer.o COBJS-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o +COBJS-$(CONFIG_TEGRA_PMU) += pmu.o COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o
COBJS := $(COBJS-y) diff --git a/arch/arm/cpu/armv7/tegra2/pmu.c b/arch/arm/cpu/armv7/tegra2/pmu.c new file mode 100644 index 0000000..b3837ec --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/pmu.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <tps6586x.h> +#include <asm/io.h> +#include <asm/arch/ap20.h> +#include <asm/arch/tegra2.h> +#include <asm/arch/tegra2_i2c.h> +#include <asm/arch/sys_proto.h> + +#define VDD_CORE_NOMINAL_T25 0x17 /* 1.3v */ +#define VDD_CPU_NOMINAL_T25 0x10 /* 1.125v */ + +#define VDD_CORE_NOMINAL_T20 0x16 /* 1.275v */ +#define VDD_CPU_NOMINAL_T20 0x0f /* 1.1v */ + +#define VDD_RELATION 0x02 /* 50mv */ +#define VDD_TRANSITION_STEP 0x06 /* 150mv */ +#define VDD_TRANSITION_RATE 0x06 /* 3.52mv/us */ + +int pmu_set_nominal(void) +{ + int core, cpu, bus; + + /* by default, the table has been filled with T25 settings */ + switch (tegra_get_chip_type()) { + case TEGRA_SOC_T20: + core = VDD_CORE_NOMINAL_T20; + cpu = VDD_CPU_NOMINAL_T20; + break; + case TEGRA_SOC_T25: + core = VDD_CORE_NOMINAL_T25; + cpu = VDD_CPU_NOMINAL_T25; + break; + default: + debug("%s: Unknown chip type\n", __func__); + return -1; + } + + bus = tegra_i2c_get_dvc_bus_num(); + if (bus == -1) { + debug("%s: Cannot find DVC I2C bus\n", __func__); + return -1; + } + tps6586x_init(bus); + tps6586x_set_pwm_mode(TPS6586X_PWM_SM1); + return tps6586x_adjust_sm0_sm1(core, cpu, VDD_TRANSITION_STEP, + VDD_TRANSITION_RATE, VDD_RELATION); +} diff --git a/arch/arm/include/asm/arch-tegra2/pmu.h b/arch/arm/include/asm/arch-tegra2/pmu.h new file mode 100644 index 0000000..390815f --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/pmu.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2010,2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _ARCH_PMU_H_ +#define _ARCH_PMU_H_ + +/* Set core and CPU voltages to nominal levels */ +int pmu_set_nominal(void); + +#endif /* _ARCH_PMU_H_ */

Adjust PMU to permit maximum frequency operation.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Check error return from pmu_set_nominal() in debug mode
board/nvidia/common/board.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index ddcfcf4..ea68090 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -31,6 +31,8 @@ #include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> #include <asm/arch/pinmux.h> +#include <asm/arch/pmc.h> +#include <asm/arch/pmu.h> #include <asm/arch/uart.h> #include <spi.h> #include <asm/arch/usb.h> @@ -75,6 +77,10 @@ int board_init(void) #error "You must define CONFIG_SYS_I2C_INIT_BOARD to use i2c on Nvidia boards" #endif i2c_init_board(); +# ifdef CONFIG_TEGRA_PMU + if (pmu_set_nominal()) + debug("Failed to select nominal voltages\n"); +# endif #endif
#ifdef CONFIG_USB_EHCI_TEGRA

From: Yen Lin yelin@nvidia.com
Add code to set up the warm boot area in the Tegra CPU ready for a resume after suspend.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Move structs shared between A9 and AVP into warmboot.h header file - Remove unused crypto code - Tidy SDRAM range check in warmboot_prepare_code() - Use low-level clock functions in warmboot code instead of register access
arch/arm/cpu/armv7/tegra2/Makefile | 2 + arch/arm/cpu/armv7/tegra2/warmboot.c | 382 +++++++++++++++++++++++++++ arch/arm/cpu/armv7/tegra2/warmboot_avp.c | 250 +++++++++++++++++ arch/arm/cpu/armv7/tegra2/warmboot_avp.h | 81 ++++++ arch/arm/include/asm/arch-tegra2/warmboot.h | 150 +++++++++++ 5 files changed, 865 insertions(+), 0 deletions(-) create mode 100644 arch/arm/cpu/armv7/tegra2/warmboot.c create mode 100644 arch/arm/cpu/armv7/tegra2/warmboot_avp.c create mode 100644 arch/arm/cpu/armv7/tegra2/warmboot_avp.h create mode 100644 arch/arm/include/asm/arch-tegra2/warmboot.h
diff --git a/arch/arm/cpu/armv7/tegra2/Makefile b/arch/arm/cpu/armv7/tegra2/Makefile index dba684d..08c4137 100644 --- a/arch/arm/cpu/armv7/tegra2/Makefile +++ b/arch/arm/cpu/armv7/tegra2/Makefile @@ -27,6 +27,7 @@ # flags for any startup files it might use. CFLAGS_arch/arm/cpu/armv7/tegra2/ap20.o += -march=armv4t CFLAGS_arch/arm/cpu/armv7/tegra2/clock.o += -march=armv4t +CFLAGS_arch/arm/cpu/armv7/tegra2/warmboot_avp.o += -march=armv4t
include $(TOPDIR)/config.mk
@@ -37,6 +38,7 @@ COBJS-y := ap20.o board.o clock.o funcmux.o pinmux.o sys_info.o timer.o COBJS-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o COBJS-$(CONFIG_TEGRA_PMU) += pmu.o COBJS-$(CONFIG_USB_EHCI_TEGRA) += usb.o +COBJS-$(CONFIG_TEGRA2_LP0) += crypto.o warmboot.o warmboot_avp.o
COBJS := $(COBJS-y) SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/arch/arm/cpu/armv7/tegra2/warmboot.c b/arch/arm/cpu/armv7/tegra2/warmboot.c new file mode 100644 index 0000000..fdfcf2e --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/warmboot.c @@ -0,0 +1,382 @@ +/* + * (C) Copyright 2010 - 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/ap20.h> +#include <asm/arch/clk_rst.h> +#include <asm/arch/clock.h> +#include <asm/arch/pmc.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/tegra2.h> +#include <asm/arch/fuse.h> +#include <asm/arch/emc.h> +#include <asm/arch/gp_padctrl.h> +#include <asm/arch/warmboot.h> +#include <asm/arch/sdram_param.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * This is the place in SRAM where the SDRAM parameters are stored. There + * are 4 blocks, one for each RAM code + */ +#define SDRAM_PARAMS_BASE (AP20_BASE_PA_SRAM + 0x188) + +/* TODO: If we later add support for the Misc GP controller, refactor this */ +union xm2cfga_reg { + struct { + u32 reserved0:2; + u32 hsm_en:1; + u32 reserved1:2; + u32 preemp_en:1; + u32 vref_en:1; + u32 reserved2:5; + u32 cal_drvdn:5; + u32 reserved3:3; + u32 cal_drvup:5; + u32 reserved4:3; + u32 cal_drvdn_slwr:2; + u32 cal_drvup_slwf:2; + }; + u32 word; +}; + +union xm2cfgd_reg { + struct { + u32 reserved0:2; + u32 hsm_en:1; + u32 schmt_en:1; + u32 lpmd:2; + u32 vref_en:1; + u32 reserved1:5; + u32 cal_drvdn:5; + u32 reserved2:3; + u32 cal_drvup:5; + u32 reserved3:3; + u32 cal_drvdn_slwr:2; + u32 cal_drvup_slwf:2; + }; + u32 word; +}; + +/* + * TODO: This register is not documented in the TRM yet. We could move this + * into the EMC and give it a proper interface, but not while it is + * undocumented. + */ +union fbio_spare_reg { + struct { + u32 reserved:24; + u32 cfg_wb0:8; + }; + u32 word; +}; + +/* We pack the resume information into these unions for later */ +union scratch2_reg { + struct { + u32 pllm_base_divm:5; + u32 pllm_base_divn:10; + u32 pllm_base_divp:3; + u32 pllm_misc_lfcon:4; + u32 pllm_misc_cpcon:4; + u32 gp_xm2cfga_padctrl_preemp:1; + u32 gp_xm2cfgd_padctrl_schmt:1; + u32 osc_ctrl_xobp:1; + u32 memory_type:3; + }; + u32 word; +}; + +union scratch4_reg { + struct { + u32 emc_clock_divider:8; + u32 pllm_stable_time:8; + u32 pllx_stable_time:8; + u32 emc_fbio_spare_cfg_wb0:8; + }; + u32 word; +}; + +union scratch24_reg { + struct { + u32 emc_auto_cal_wait:8; + u32 emc_pin_program_wait:8; + u32 warmboot_wait:8; + u32 reserved:8; + }; + u32 word; +}; + +int warmboot_save_sdram_params(void) +{ + u32 ram_code; + struct sdram_params sdram; + struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; + struct apb_misc_gp_ctlr *gp = + (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE; + struct emc_ctlr *emc = emc_get_controller(gd->fdt_blob); + union scratch2_reg scratch2; + union scratch4_reg scratch4; + union scratch24_reg scratch24; + union xm2cfga_reg xm2cfga; + union xm2cfgd_reg xm2cfgd; + union fbio_spare_reg fbio_spare; + + /* get ram code that is used as index to array sdram_params in BCT */ + ram_code = (readl(&pmt->pmt_strap_opt_a) >> + STRAP_OPT_A_RAM_CODE_SHIFT) & 3; + memcpy(&sdram, + (char *)((struct sdram_params *)SDRAM_PARAMS_BASE + ram_code), + sizeof(sdram)); + + xm2cfga.word = readl(&gp->xm2cfga); + xm2cfgd.word = readl(&gp->xm2cfgd); + + scratch2.word = 0; + scratch2.osc_ctrl_xobp = clock_get_osc_bypass(); + + /* Get the memory PLL settings */ + { + u32 divm, divn, divp, cpcon, lfcon; + + if (clock_ll_read_pll(CLOCK_ID_MEMORY, &divm, &divn, &divp, + &cpcon, &lfcon)) + return -1; + scratch2.pllm_base_divm = divm; + scratch2.pllm_base_divn = divn; + scratch2.pllm_base_divp = divp; + scratch2.pllm_misc_cpcon = cpcon; + scratch2.pllm_misc_lfcon = lfcon; + } + + scratch2.gp_xm2cfga_padctrl_preemp = xm2cfga.preemp_en; + scratch2.gp_xm2cfgd_padctrl_schmt = xm2cfgd.schmt_en; + scratch2.memory_type = sdram.memory_type; + writel(scratch2.word, &pmc->pmc_scratch2); + + /* collect data from various sources for pmc_scratch4 */ + fbio_spare.word = readl(&emc->fbio_spare); + scratch4.word = 0; + scratch4.emc_fbio_spare_cfg_wb0 = fbio_spare.cfg_wb0; + scratch4.emc_clock_divider = sdram.emc_clock_divider; + scratch4.pllm_stable_time = -1; + scratch4.pllx_stable_time = -1; + writel(scratch4.word, &pmc->pmc_scratch4); + + /* collect various data from sdram for pmc_scratch24 */ + scratch24.word = 0; + scratch24.emc_pin_program_wait = sdram.emc_pin_program_wait; + scratch24.emc_auto_cal_wait = sdram.emc_auto_cal_wait; + scratch24.warmboot_wait = sdram.warm_boot_wait; + writel(scratch24.word, &pmc->pmc_scratch24); + + return 0; +} + +static u32 get_major_version(void) +{ + u32 major_id; + struct apb_misc_gp_ctlr *gp = + (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE; + + major_id = (readl(&gp->hidrev) & HIDREV_MAJORPREV_MASK) >> + HIDREV_MAJORPREV_SHIFT; + return major_id; +} + +static int is_production_mode_fuse_set(struct fuse_regs *fuse) +{ + return readl(&fuse->production_mode); +} + +static int is_odm_production_mode_fuse_set(struct fuse_regs *fuse) +{ + return readl(&fuse->security_mode); +} + +static int is_failure_analysis_mode(struct fuse_regs *fuse) +{ + return readl(&fuse->fa); +} + +static int ap20_is_odm_production_mode(void) +{ + struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE; + + if (!is_failure_analysis_mode(fuse) && + is_odm_production_mode_fuse_set(fuse)) + return 1; + else + return 0; +} + +static int ap20_is_production_mode(void) +{ + struct fuse_regs *fuse = (struct fuse_regs *)TEGRA2_FUSE_BASE; + + if (get_major_version() == 0) + return 1; + + if (!is_failure_analysis_mode(fuse) && + is_production_mode_fuse_set(fuse) && + !is_odm_production_mode_fuse_set(fuse)) + return 1; + else + return 0; +} + +static enum fuse_operating_mode fuse_get_operation_mode(void) +{ + u32 chip_id; + struct apb_misc_gp_ctlr *gp = + (struct apb_misc_gp_ctlr *)TEGRA2_APB_MISC_GP_BASE; + + chip_id = (readl(&gp->hidrev) & HIDREV_CHIPID_MASK) >> + HIDREV_CHIPID_SHIFT; + if (chip_id == CHIPID_TEGRA2) { + if (ap20_is_odm_production_mode()) { + printf("!! odm_production_mode is not supported !!\n"); + return MODE_UNDEFINED; + } else + if (ap20_is_production_mode()) + return MODE_PRODUCTION; + else + return MODE_UNDEFINED; + } + return MODE_UNDEFINED; +} + +static void determine_crypto_options(int *is_encrypted, int *is_signed, + int *use_zero_key) +{ + switch (fuse_get_operation_mode()) { + case MODE_PRODUCTION: + *is_encrypted = 0; + *is_signed = 1; + *use_zero_key = 1; + break; + case MODE_UNDEFINED: + default: + *is_encrypted = 0; + *is_signed = 0; + *use_zero_key = 0; + break; + } +} + +static int sign_wb_code(u32 start, u32 length, int use_zero_key) +{ + int err; + u8 *source; /* Pointer to source */ + u8 *hash; + + /* Calculate AES block parameters. */ + source = (u8 *)(start + offsetof(struct wb_header, random_aes_block)); + length -= offsetof(struct wb_header, random_aes_block); + hash = (u8 *)(start + offsetof(struct wb_header, hash)); + err = sign_data_block(source, length, hash); + + return err; +} + +int warmboot_prepare_code(u32 seg_address, u32 seg_length) +{ + int err = 0; + u32 length; /* length of the signed/encrypt code */ + struct wb_header *dst_header; /* Pointer to dest WB header */ + int is_encrypted; /* Segment is encrypted */ + int is_signed; /* Segment is signed */ + int use_zero_key; /* Use key of all zeros */ + + /* Determine crypto options. */ + determine_crypto_options(&is_encrypted, &is_signed, &use_zero_key); + + /* Get the actual code limits. */ + length = roundup(((u32)wb_end - (u32)wb_start), 16); + + /* + * The region specified by seg_address must be in SDRAM and must be + * nonzero in length. + */ + if (seg_length == 0 || seg_address < NV_PA_SDRAM_BASE || + seg_address + seg_length >= NV_PA_SDRAM_BASE + gd->ram_size) { + err = -EFAULT; + goto fail; + } + + /* Things must be 16-byte aligned. */ + if ((seg_length & 0xF) || (seg_address & 0xF)) { + err = -EINVAL; + goto fail; + } + + /* Will the code fit? (destination includes wb_header + wb code) */ + if (seg_length < (length + sizeof(struct wb_header))) { + err = -EINVAL; + goto fail; + } + + dst_header = (struct wb_header *)seg_address; + memset((char *)dst_header, 0, sizeof(struct wb_header)); + + /* Populate the random_aes_block as requested. */ + { + u32 *aes_block = (u32 *)&(dst_header->random_aes_block); + u32 *end = (u32 *)(((u32)aes_block) + + sizeof(dst_header->random_aes_block)); + + do { + *aes_block++ = 0; + } while (aes_block < end); + } + + /* Populate the header. */ + dst_header->length_insecure = length + sizeof(struct wb_header); + dst_header->length_secure = length + sizeof(struct wb_header); + dst_header->destination = AP20_WB_RUN_ADDRESS; + dst_header->entry_point = AP20_WB_RUN_ADDRESS; + dst_header->code_length = length; + + if (is_encrypted) { + printf("!!!! Encryption is not supported !!!!\n"); + dst_header->length_insecure = 0; + err = -EACCES; + goto fail; + } else + /* copy the wb code directly following dst_header. */ + memcpy((char *)(dst_header+1), (char *)wb_start, length); + + if (is_signed) + err = sign_wb_code(seg_address, dst_header->length_insecure, + use_zero_key); + +fail: + if (err) + printf("Warning: warmboot code copy failed (error=%d)\n", err); + + return err; +} diff --git a/arch/arm/cpu/armv7/tegra2/warmboot_avp.c b/arch/arm/cpu/armv7/tegra2/warmboot_avp.c new file mode 100644 index 0000000..70bcd8e --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/warmboot_avp.c @@ -0,0 +1,250 @@ +/* + * (C) Copyright 2010 - 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/ap20.h> +#include <asm/arch/clk_rst.h> +#include <asm/arch/clock.h> +#include <asm/arch/flow.h> +#include <asm/arch/pinmux.h> +#include <asm/arch/pmc.h> +#include <asm/arch/tegra2.h> +#include <asm/arch/warmboot.h> +#include "warmboot_avp.h" + +#define DEBUG_RESET_CORESIGHT + +void wb_start(void) +{ + struct pmux_tri_ctlr *pmt = (struct pmux_tri_ctlr *)NV_PA_APB_MISC_BASE; + struct pmc_ctlr *pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; + struct flow_ctlr *flow = (struct flow_ctlr *)NV_PA_FLOW_BASE; + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + union osc_ctrl_reg osc_ctrl; + union pllx_base_reg pllx_base; + union pllx_misc_reg pllx_misc; + union scratch3_reg scratch3; + u32 reg; + + /* enable JTAG & TBE */ + writel(CONFIG_CTL_TBE | CONFIG_CTL_JTAG, &pmt->pmt_cfg_ctl); + + /* Are we running where we're supposed to be? */ + asm volatile ( + "adr %0, wb_start;" /* reg: wb_start address */ + : "=r"(reg) /* output */ + /* no input, no clobber list */ + ); + + if (reg != AP20_WB_RUN_ADDRESS) + goto do_reset; + + /* Are we running with AVP? */ + if (readl(NV_PA_PG_UP_BASE + PG_UP_TAG_0) != PG_UP_TAG_AVP) + goto do_reset; + +#ifdef DEBUG_RESET_CORESIGHT + /* Assert CoreSight reset */ + reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]); + reg |= SWR_CSITE_RST; + writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]); +#endif + + /* TODO: Set the drive strength - maybe make this a board parameter? */ + osc_ctrl.word = readl(&clkrst->crc_osc_ctrl); + osc_ctrl.xofs = 4; + osc_ctrl.xoe = 1; + writel(osc_ctrl.word, &clkrst->crc_osc_ctrl); + + /* Power up the CPU complex if necessary */ + if (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU)) { + reg = PWRGATE_TOGGLE_PARTID_CPU | PWRGATE_TOGGLE_START; + writel(reg, &pmc->pmc_pwrgate_toggle); + while (!(readl(&pmc->pmc_pwrgate_status) & PWRGATE_STATUS_CPU)) + ; + } + + /* Remove the I/O clamps from the CPU power partition. */ + reg = readl(&pmc->pmc_remove_clamping); + reg |= CPU_CLMP; + writel(reg, &pmc->pmc_remove_clamping); + + reg = EVENT_ZERO_VAL_20 | EVENT_MSEC | EVENT_MODE_STOP; + writel(reg, &flow->halt_cop_events); + + /* Assert CPU complex reset */ + reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]); + reg |= CPU_RST; + writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]); + + /* Hold both CPUs in reset */ + reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_CPURESET1 | CPU_CMPLX_DERESET0 | + CPU_CMPLX_DERESET1 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DBGRESET1; + writel(reg, &clkrst->crc_cpu_cmplx_set); + + /* Halt CPU1 at the flow controller for uni-processor configurations */ + writel(EVENT_MODE_STOP, &flow->halt_cpu1_events); + + /* + * Set the CPU reset vector. SCRATCH41 contains the physical + * address of the CPU-side restoration code. + */ + reg = readl(&pmc->pmc_scratch41); + writel(reg, EXCEP_VECTOR_CPU_RESET_VECTOR); + + /* Select CPU complex clock source */ + writel(CCLK_PLLP_BURST_POLICY, &clkrst->crc_cclk_brst_pol); + + /* Start the CPU0 clock and stop the CPU1 clock */ + reg = CPU_CMPLX_CPU_BRIDGE_CLKDIV_4 | CPU_CMPLX_CPU0_CLK_STP_RUN | + CPU_CMPLX_CPU1_CLK_STP_STOP; + writel(reg, &clkrst->crc_clk_cpu_cmplx); + + /* Enable the CPU complex clock */ + reg = readl(&clkrst->crc_clk_out_enb[TEGRA_DEV_L]); + reg |= CLK_ENB_CPU; + writel(reg, &clkrst->crc_clk_out_enb[TEGRA_DEV_L]); + + /* Make sure the resets were held for at least 2 microseconds */ + reg = readl(TIMER_USEC_CNTR); + while (readl(TIMER_USEC_CNTR) <= (reg + 2)) + ; + +#ifdef DEBUG_RESET_CORESIGHT + /* + * De-assert CoreSight reset. + * NOTE: We're leaving the CoreSight clock on the oscillator for + * now. It will be restored to its original clock source + * when the CPU-side restoration code runs. + */ + reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_U]); + reg &= ~SWR_CSITE_RST; + writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_U]); +#endif + + /* Unlock the CPU CoreSight interfaces */ + reg = 0xC5ACCE55; + writel(reg, CSITE_CPU_DBG0_LAR); + writel(reg, CSITE_CPU_DBG1_LAR); + + /* + * Sample the microsecond timestamp again. This is the time we must + * use when returning from LP0 for PLL stabilization delays. + */ + reg = readl(TIMER_USEC_CNTR); + writel(reg, &pmc->pmc_scratch1); + + pllx_base.word = 0; + pllx_misc.word = 0; + scratch3.word = readl(&pmc->pmc_scratch3); + + /* Get the OSC. For 19.2 MHz, use 19 to make the calculations easier */ + reg = (readl(TIMER_USEC_CFG) & USEC_CFG_DIVISOR_MASK) + 1; + + /* + * According to the TRM, for 19.2MHz OSC, the USEC_DIVISOR is 0x5f, and + * USEC_DIVIDEND is 0x04. So, if USEC_DIVISOR > 26, OSC is 19.2 MHz. + * + * reg is used to calculate the pllx freq, which is used to determine if + * to set dccon or not. + */ + if (reg > 26) + reg = 19; + + /* PLLX_BASE.PLLX_DIVM */ + if (scratch3.pllx_base_divm == reg) + reg = 0; + else + reg = 1; + + /* PLLX_BASE.PLLX_DIVN */ + pllx_base.divn = scratch3.pllx_base_divn; + reg = scratch3.pllx_base_divn << reg; + + /* PLLX_BASE.PLLX_DIVP */ + pllx_base.divp = scratch3.pllx_base_divp; + reg = reg >> scratch3.pllx_base_divp; + + pllx_base.bypass = 1; + + /* PLLX_MISC_DCCON must be set for pllx frequency > 600 MHz. */ + if (reg > 600) + pllx_misc.dccon = 1; + + /* PLLX_MISC_LFCON */ + pllx_misc.lfcon = scratch3.pllx_misc_lfcon; + + /* PLLX_MISC_CPCON */ + pllx_misc.cpcon = scratch3.pllx_misc_cpcon; + + writel(pllx_misc.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_misc); + writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); + + pllx_base.enable = 1; + writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); + pllx_base.bypass = 0; + writel(pllx_base.word, &clkrst->crc_pll_simple[SIMPLE_PLLX].pll_base); + + writel(0, flow->halt_cpu_events); + + reg = CPU_CMPLX_CPURESET0 | CPU_CMPLX_DBGRESET0 | CPU_CMPLX_DERESET0; + writel(reg, &clkrst->crc_cpu_cmplx_clr); + + reg = PLLM_OUT1_RSTN_RESET_DISABLE | PLLM_OUT1_CLKEN_ENABLE | + PLLM_OUT1_RATIO_VAL_8; + writel(reg, &clkrst->crc_pll[CLOCK_ID_MEMORY].pll_out); + + reg = SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 | SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 | + SCLK_SWAKE_RUN_SRC_PLLM_OUT1 | SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 | + SCLK_SYS_STATE_IDLE; + writel(reg, &clkrst->crc_sclk_brst_pol); + + /* avp_resume: no return after the write */ + reg = readl(&clkrst->crc_rst_dev[TEGRA_DEV_L]); + reg &= ~CPU_RST; + writel(reg, &clkrst->crc_rst_dev[TEGRA_DEV_L]); + + /* avp_halt: */ +avp_halt: + reg = EVENT_MODE_STOP | EVENT_JTAG; + writel(reg, flow->halt_cop_events); + goto avp_halt; + +do_reset: + /* + * Execution comes here if something goes wrong. The chip is reset and + * a cold boot is performed. + */ + writel(SWR_TRIG_SYS_RST, &clkrst->crc_rst_dev[TEGRA_DEV_L]); + goto do_reset; +} + +/* + * wb_end() is a dummy function, and must be directly following wb_start(), + * and is used to calculate the size of wb_start(). + */ +void wb_end(void) +{ +} diff --git a/arch/arm/cpu/armv7/tegra2/warmboot_avp.h b/arch/arm/cpu/armv7/tegra2/warmboot_avp.h new file mode 100644 index 0000000..4b71c07 --- /dev/null +++ b/arch/arm/cpu/armv7/tegra2/warmboot_avp.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2010, 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _WARMBOOT_AVP_H_ +#define _WARMBOOT_AVP_H_ + +#define TEGRA_DEV_L 0 +#define TEGRA_DEV_H 1 +#define TEGRA_DEV_U 2 + +#define SIMPLE_PLLX (CLOCK_ID_XCPU - CLOCK_ID_FIRST_SIMPLE) +#define SIMPLE_PLLE (CLOCK_ID_EPCI - CLOCK_ID_FIRST_SIMPLE) + +#define TIMER_USEC_CNTR (NV_PA_TMRUS_BASE + 0) +#define TIMER_USEC_CFG (NV_PA_TMRUS_BASE + 4) + +#define USEC_CFG_DIVISOR_MASK 0xffff + +#define CONFIG_CTL_TBE (1 << 7) +#define CONFIG_CTL_JTAG (1 << 6) + +#define CPU_RST (1 << 0) +#define CLK_ENB_CPU (1 << 0) +#define SWR_TRIG_SYS_RST (1 << 2) +#define SWR_CSITE_RST (1 << 9) + +#define PWRGATE_STATUS_CPU (1 << 0) +#define PWRGATE_TOGGLE_PARTID_CPU (0 << 0) +#define PWRGATE_TOGGLE_START (1 << 8) + +#define CPU_CMPLX_CPU_BRIDGE_CLKDIV_4 (3 << 0) +#define CPU_CMPLX_CPU0_CLK_STP_STOP (1 << 8) +#define CPU_CMPLX_CPU0_CLK_STP_RUN (0 << 8) +#define CPU_CMPLX_CPU1_CLK_STP_STOP (1 << 9) +#define CPU_CMPLX_CPU1_CLK_STP_RUN (0 << 9) + +#define CPU_CMPLX_CPURESET0 (1 << 0) +#define CPU_CMPLX_CPURESET1 (1 << 1) +#define CPU_CMPLX_DERESET0 (1 << 4) +#define CPU_CMPLX_DERESET1 (1 << 5) +#define CPU_CMPLX_DBGRESET0 (1 << 12) +#define CPU_CMPLX_DBGRESET1 (1 << 13) + +#define PLLM_OUT1_RSTN_RESET_DISABLE (1 << 0) +#define PLLM_OUT1_CLKEN_ENABLE (1 << 1) +#define PLLM_OUT1_RATIO_VAL_8 (8 << 8) + +#define SCLK_SYS_STATE_IDLE (1 << 28) +#define SCLK_SWAKE_FIQ_SRC_PLLM_OUT1 (7 << 12) +#define SCLK_SWAKE_IRQ_SRC_PLLM_OUT1 (7 << 8) +#define SCLK_SWAKE_RUN_SRC_PLLM_OUT1 (7 << 4) +#define SCLK_SWAKE_IDLE_SRC_PLLM_OUT1 (7 << 0) + +#define EVENT_ZERO_VAL_20 (20 << 0) +#define EVENT_MSEC (1 << 24) +#define EVENT_JTAG (1 << 28) +#define EVENT_MODE_STOP (2 << 29) + +#define CCLK_PLLP_BURST_POLICY 0x20004444 + +#endif diff --git a/arch/arm/include/asm/arch-tegra2/warmboot.h b/arch/arm/include/asm/arch-tegra2/warmboot.h new file mode 100644 index 0000000..99ac2e7 --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/warmboot.h @@ -0,0 +1,150 @@ +/* + * (C) Copyright 2010, 2011 + * NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _WARM_BOOT_H_ +#define _WARM_BOOT_H_ + +#define STRAP_OPT_A_RAM_CODE_SHIFT 4 +#define STRAP_OPT_A_RAM_CODE_MASK (0xf << STRAP_OPT_A_RAM_CODE_SHIFT) + +/* Defines the supported operating modes */ +enum fuse_operating_mode { + MODE_PRODUCTION = 3, + MODE_UNDEFINED, +}; + +/* Defines the CMAC-AES-128 hash length in 32 bit words. (128 bits = 4 words) */ +enum { + HASH_LENGTH = 4 +}; + +/* Defines the storage for a hash value (128 bits) */ +struct hash { + u32 hash[HASH_LENGTH]; +}; + +/* + * Defines the code header information for the boot rom. + * + * The code immediately follows the code header. + * + * Note that the code header needs to be 16 bytes aligned to preserve + * the alignment of relevant data for hash and decryption computations without + * requiring extra copies to temporary memory areas. + */ +struct wb_header { + u32 length_insecure; /* length of the code header */ + u32 reserved[3]; + struct hash hash; /* hash of header+code, starts next field*/ + struct hash random_aes_block; /* a data block to aid security. */ + u32 length_secure; /* length of the code header */ + u32 destination; /* destination address to put the wb code */ + u32 entry_point; /* execution address of the wb code */ + u32 code_length; /* length of the code */ +}; + +/* + * The warm boot code needs direct access to these registers since it runs in + * SRAM and cannot call other U-Boot code. + */ +union osc_ctrl_reg { + struct { + u32 xoe:1; + u32 xobp:1; + u32 reserved0:2; + u32 xofs:6; + u32 reserved1:2; + u32 xods:5; + u32 reserved2:3; + u32 oscfi_spare:8; + u32 pll_ref_div:2; + u32 osc_freq:2; + }; + u32 word; +}; + +union pllx_base_reg { + struct { + u32 divm:5; + u32 reserved0:3; + u32 divn:10; + u32 reserved1:2; + u32 divp:3; + u32 reserved2:4; + u32 lock:1; + u32 reserved3:1; + u32 ref_dis:1; + u32 enable:1; + u32 bypass:1; + }; + u32 word; +}; + +union pllx_misc_reg { + struct { + u32 vcocon:4; + u32 lfcon:4; + u32 cpcon:4; + u32 lock_sel:6; + u32 reserved0:1; + u32 lock_enable:1; + u32 reserved1:1; + u32 dccon:1; + u32 pts:2; + u32 reserved2:6; + u32 out1_div_byp:1; + u32 out1_inv_clk:1; + }; + u32 word; +}; + +/* + * TODO: This register is not documented in the TRM yet. We could move this + * into the EMC and give it a proper interface, but not while it is + * undocumented. + */ +union scratch3_reg { + struct { + u32 pllx_base_divm:5; + u32 pllx_base_divn:10; + u32 pllx_base_divp:3; + u32 pllx_misc_lfcon:4; + u32 pllx_misc_cpcon:4; + }; + u32 word; +}; + + +/** + * Save warmboot memory settings for a later resume + * + * @return 0 if ok, -1 on error + */ +int warmboot_save_sdram_params(void); + +int warmboot_prepare_code(u32 seg_address, u32 seg_length); +int sign_data_block(u8 *source, u32 length, u8 *signature); +void wb_start(void); /* Start of WB assembly code */ +void wb_end(void); /* End of WB assembly code */ + +#endif

On 01/13/2012 02:35 PM, Simon Glass wrote:
From: Yen Lin yelin@nvidia.com
Add code to set up the warm boot area in the Tegra CPU ready for a resume after suspend.
Signed-off-by: Simon Glass sjg@chromium.org
Acked-by: Stephen Warren swarren@nvidia.com

From: Yen Lin yelin@nvidia.com
Save SDRAM parameters into the warmboot scratch registers
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/cpu/armv7/tegra2/ap20.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/arch/arm/cpu/armv7/tegra2/ap20.c b/arch/arm/cpu/armv7/tegra2/ap20.c index fadce15..c36cb70 100644 --- a/arch/arm/cpu/armv7/tegra2/ap20.c +++ b/arch/arm/cpu/armv7/tegra2/ap20.c @@ -31,6 +31,7 @@ #include <asm/arch/pmc.h> #include <asm/arch/pinmux.h> #include <asm/arch/scu.h> +#include <asm/arch/warmboot.h> #include <common.h>
int tegra_get_chip_type(void) @@ -322,6 +323,11 @@ void init_pmc_scratch(void)
/* ODMDATA is for kernel use to determine RAM size, LP config, etc. */ writel(CONFIG_SYS_BOARD_ODMDATA, &pmc->pmc_scratch20); + +#ifdef CONFIG_TEGRA2_LP0 + /* save Sdram params to PMC 2, 4, and 24 for WB0 */ + warmboot_save_sdram_params(); +#endif }
void tegra2_start(void)

Call the function to put warmboot boot in a suitable place for resume.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/nvidia/common/board.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index ea68090..d2eee6e 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -34,6 +34,7 @@ #include <asm/arch/pmc.h> #include <asm/arch/pmu.h> #include <asm/arch/uart.h> +#include <asm/arch/warmboot.h> #include <spi.h> #include <asm/arch/usb.h> #include <i2c.h> @@ -90,6 +91,11 @@ int board_init(void) board_usb_init(gd->fdt_blob); #endif
+#ifdef CONFIG_TEGRA2_LP0 + /* prepare the WB code to LP0 location */ + warmboot_prepare_code(TEGRA_LP0_ADDR, TEGRA_LP0_SIZE); +#endif + return 0; }

From: Wei Ni wni@nvidia.com
Tegra core power rail has leakage voltage around 0.2V while system in suspend mode. The source of the leakage should be coming from PMC power detect logic for IO rails power detection. That can be disabled by writing a '0' to PWR_DET_LATCH followed by writing '0' to PWR_DET (APBDEV_PMC_PWR_DET_0).
Signed-off-by: Simon Glass sjg@chromium.org ---
board/nvidia/common/board.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index d2eee6e..4e6a505 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -56,6 +56,21 @@ int timer_init(void) }
/* + * Routine: power_det_init + * Description: turn off power detects + */ +static void power_det_init(void) +{ +#if defined(CONFIG_TEGRA2) + struct pmc_ctlr *const pmc = (struct pmc_ctlr *)TEGRA2_PMC_BASE; + + /* turn off power detects */ + writel(0, &pmc->pmc_pwr_det_latch); + writel(0, &pmc->pmc_pwr_det); +#endif +} + +/* * Routine: board_init * Description: Early hardware init. */ @@ -73,6 +88,9 @@ int board_init(void) #endif /* boot param addr */ gd->bd->bi_boot_params = (NV_PA_SDRAM_BASE + 0x100); + + power_det_init(); + #ifdef CONFIG_TEGRA2_I2C #ifndef CONFIG_SYS_I2C_INIT_BOARD #error "You must define CONFIG_SYS_I2C_INIT_BOARD to use i2c on Nvidia boards"

From: Jimmy Zhang jimmzhang@nvidia.com
Set Seaboard to optimal memory settings based on the SOC in use (T20 or T25).
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Move EMC tables to device tree - Removed check for nominal voltage (not needed as it is done just before)
board/nvidia/common/Makefile | 1 + board/nvidia/common/board.c | 10 ++++++- board/nvidia/common/emc.c | 53 ++++++++++++++++++++++++++++++++++++++++++ board/nvidia/common/emc.h | 29 +++++++++++++++++++++++ 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 board/nvidia/common/emc.c create mode 100644 board/nvidia/common/emc.h
diff --git a/board/nvidia/common/Makefile b/board/nvidia/common/Makefile index 3e748fd..a93d458 100644 --- a/board/nvidia/common/Makefile +++ b/board/nvidia/common/Makefile @@ -27,6 +27,7 @@ LIB = $(obj)lib$(VENDOR).o
COBJS-y += board.o COBJS-$(CONFIG_SPI_UART_SWITCH) += uart-spi-switch.o +COBJS-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
COBJS := $(COBJS-y) SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c index 4e6a505..04990bf 100644 --- a/board/nvidia/common/board.c +++ b/board/nvidia/common/board.c @@ -30,6 +30,7 @@ #include <asm/arch/board.h> #include <asm/arch/clk_rst.h> #include <asm/arch/clock.h> +#include <asm/arch/emc.h> #include <asm/arch/pinmux.h> #include <asm/arch/pmc.h> #include <asm/arch/pmu.h> @@ -39,6 +40,7 @@ #include <asm/arch/usb.h> #include <i2c.h> #include "board.h" +#include "emc.h"
DECLARE_GLOBAL_DATA_PTR;
@@ -99,8 +101,12 @@ int board_init(void) # ifdef CONFIG_TEGRA_PMU if (pmu_set_nominal()) debug("Failed to select nominal voltages\n"); -# endif -#endif +# ifdef CONFIG_TEGRA_CLOCK_SCALING + if (board_emc_init()) + debug("Memory controller init failed\n"); +# endif +# endif /* CONFIG_TEGRA_PMU */ +#endif /* CONFIG_TEGRA2_I2C */
#ifdef CONFIG_USB_EHCI_TEGRA /* For USB GPIO PD0. for now, since we have no pinmux in fdt */ diff --git a/board/nvidia/common/emc.c b/board/nvidia/common/emc.c new file mode 100644 index 0000000..8e4290c --- /dev/null +++ b/board/nvidia/common/emc.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/ap20.h> +#include <asm/arch/clk_rst.h> +#include <asm/arch/clock.h> +#include <asm/arch/emc.h> +#include <asm/arch/pmu.h> +#include <asm/arch/sys_proto.h> +#include <asm/arch/tegra2.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* These rates are hard-coded for now, until fdt provides them */ +#define EMC_SDRAM_RATE_T20 (333000 * 2 * 1000) +#define EMC_SDRAM_RATE_T25 (380000 * 2 * 1000) + +int board_emc_init(void) +{ + unsigned rate; + + switch (tegra_get_chip_type()) { + default: + case TEGRA_SOC_T20: + rate = EMC_SDRAM_RATE_T20; + break; + case TEGRA_SOC_T25: + rate = EMC_SDRAM_RATE_T25; + break; + } + return tegra_set_emc(gd->fdt_blob, rate); +} diff --git a/board/nvidia/common/emc.h b/board/nvidia/common/emc.h new file mode 100644 index 0000000..ec1b115 --- /dev/null +++ b/board/nvidia/common/emc.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * (C) Copyright 2010,2011 NVIDIA Corporation <www.nvidia.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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; either version 2 of + * the License, or (at your option) any later version. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _NVIDIA_EMC_H_ +#define _NVIDIA_EMC_H_ + +int board_emc_init(void); + +#endif

Add a definition of the memory controller node according to the bindings here:
http://patchwork.ozlabs.org/patch/132928/
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/arm/dts/tegra20.dtsi | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index 963cf27..c009f16 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -203,5 +203,12 @@ clocks = <&periph_clk 59>; // PERIPH_ID_USB3 };
+ emc@7000f400 { + #address-cells = < 1 >; + #size-cells = < 0 >; + compatible = "nvidia,tegra20-emc"; + reg = <0x7000f400 0x200>; + }; + };

Add tegra_i2c_get_dvc_bus_num() to obtain the I2C bus number of DVC bus. This allows us to talk to the PMU.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Add patch to find DVC bus number
arch/arm/include/asm/arch-tegra2/tegra2_i2c.h | 7 +++++++ drivers/i2c/tegra2_i2c.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h index 86f6a01..4816cc7 100644 --- a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h +++ b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h @@ -157,4 +157,11 @@ struct i2c_ctlr { #define I2C_INT_ARBITRATION_LOST_SHIFT 2 #define I2C_INT_ARBITRATION_LOST_MASK (1 << I2C_INT_ARBITRATION_LOST_SHIFT)
+/** + * Returns the bus number of the DVC controller + * + * @return number of bus, or -1 if there is no DVC active + */ +int tegra_i2c_get_dvc_bus_num(void); + #endif diff --git a/drivers/i2c/tegra2_i2c.c b/drivers/i2c/tegra2_i2c.c index b57a050..b42d9ac 100644 --- a/drivers/i2c/tegra2_i2c.c +++ b/drivers/i2c/tegra2_i2c.c @@ -549,3 +549,17 @@ int i2c_set_bus_num(unsigned int bus) return 0; } #endif + +int tegra_i2c_get_dvc_bus_num(void) +{ + int i; + + for (i = 0; i < CONFIG_SYS_MAX_I2C_BUS; i++) { + struct i2c_bus *bus = &i2c_controllers[i]; + + if (bus->inited && bus->is_dvc) + return i; + } + + return -1; +}

Hello Simon,
Simon Glass wrote:
Add tegra_i2c_get_dvc_bus_num() to obtain the I2C bus number of DVC bus. This allows us to talk to the PMU.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add patch to find DVC bus number
arch/arm/include/asm/arch-tegra2/tegra2_i2c.h | 7 +++++++ drivers/i2c/tegra2_i2c.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)
just one minor comment, beside of this:
Acked-by: Heiko Schocher hs@denx.de
diff --git a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h index 86f6a01..4816cc7 100644 --- a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h +++ b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h @@ -157,4 +157,11 @@ struct i2c_ctlr { #define I2C_INT_ARBITRATION_LOST_SHIFT 2 #define I2C_INT_ARBITRATION_LOST_MASK (1 << I2C_INT_ARBITRATION_LOST_SHIFT)
+/**
wrong comment style ...
bye, Heiko

Hi Heiko,
On Jan 14, 2012 11:28 PM, "Heiko Schocher" hs@denx.de wrote:
Hello Simon,
Simon Glass wrote:
Add tegra_i2c_get_dvc_bus_num() to obtain the I2C bus number of DVC bus. This allows us to talk to the PMU.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add patch to find DVC bus number
arch/arm/include/asm/arch-tegra2/tegra2_i2c.h | 7 +++++++ drivers/i2c/tegra2_i2c.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)
just one minor comment, beside of this:
Acked-by: Heiko Schocher hs@denx.de
diff --git a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h
b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h
index 86f6a01..4816cc7 100644 --- a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h +++ b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h @@ -157,4 +157,11 @@ struct i2c_ctlr { #define I2C_INT_ARBITRATION_LOST_SHIFT 2 #define I2C_INT_ARBITRATION_LOST_MASK (1 <<
I2C_INT_ARBITRATION_LOST_SHIFT)
+/**
wrong comment style ...
I am trying to follow the Doxygen convention. Many editors like this also and display the parameters etc. nicely highlighted. Does yours? Hoping it encourages more function prototype comments in U-Boot and reduce the time I need to spend wading through code to see what a function is supposed to do.
regards, Simon
bye, Heiko -- DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

Hello Simon,
Simon Glass wrote:
Hi Heiko,
On Jan 14, 2012 11:28 PM, "Heiko Schocher" hs@denx.de wrote:
Hello Simon,
Simon Glass wrote:
Add tegra_i2c_get_dvc_bus_num() to obtain the I2C bus number of DVC bus. This allows us to talk to the PMU.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
- Add patch to find DVC bus number
arch/arm/include/asm/arch-tegra2/tegra2_i2c.h | 7 +++++++ drivers/i2c/tegra2_i2c.c | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 0 deletions(-)
just one minor comment, beside of this:
Acked-by: Heiko Schocher hs@denx.de
diff --git a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h
b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h
index 86f6a01..4816cc7 100644 --- a/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h +++ b/arch/arm/include/asm/arch-tegra2/tegra2_i2c.h @@ -157,4 +157,11 @@ struct i2c_ctlr { #define I2C_INT_ARBITRATION_LOST_SHIFT 2 #define I2C_INT_ARBITRATION_LOST_MASK (1 <<
I2C_INT_ARBITRATION_LOST_SHIFT)
+/**
wrong comment style ...
I am trying to follow the Doxygen convention. Many editors like this also and display the parameters etc. nicely highlighted. Does yours? Hoping it encourages more function prototype comments in U-Boot and reduce the time I need to spend wading through code to see what a function is supposed to do.
added Wolfgang to cc:
Do we want to accept this? If so, it must be documented somewhere!
bye, Heiko

This adds timings for T20 and T25 Seaboards, using the bindings found here:
http://patchwork.ozlabs.org/patch/132928/
We supply both full speed options for normal running, and half speed options for testing / development.
Signed-off-by: Simon Glass sjg@chromium.org ---
board/nvidia/dts/tegra2-seaboard.dts | 73 ++++++++++++++++++++++++++++++++++ 1 files changed, 73 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/dts/tegra2-seaboard.dts b/board/nvidia/dts/tegra2-seaboard.dts index d2cc428..b114f5f 100644 --- a/board/nvidia/dts/tegra2-seaboard.dts +++ b/board/nvidia/dts/tegra2-seaboard.dts @@ -54,4 +54,77 @@ status = "disabled"; };
+ emc@7000f400 { + emc-table@166500 { + reg = <166500>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 166500 >; + nvidia,emc-registers = < 0x0000000a 0x00000021 + 0x00000008 0x00000003 0x00000004 0x00000004 + 0x00000002 0x0000000c 0x00000003 0x00000003 + 0x00000002 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x000004df + 0x00000000 0x00000003 0x00000003 0x00000003 + 0x00000003 0x00000001 0x0000000a 0x000000c8 + 0x00000003 0x00000006 0x00000004 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xa04004ae + 0x007fd010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 >; + }; + emc-table@333000 { + reg = <333000>; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 333000 >; + nvidia,emc-registers = < 0x00000014 0x00000041 + 0x0000000f 0x00000005 0x00000004 0x00000005 + 0x00000003 0x0000000c 0x00000005 0x00000005 + 0x00000003 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x000009ff + 0x00000000 0x00000003 0x00000003 0x00000005 + 0x00000005 0x00000001 0x0000000f 0x000000c8 + 0x00000003 0x0000000c 0x00000006 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xe034048b + 0x007e8010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000>; + }; + + emc-table@190000 { + reg = < 190000 >; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 190000 >; + nvidia,emc-registers = < 0x0000000c 0x00000026 + 0x00000009 0x00000003 0x00000004 0x00000004 + 0x00000002 0x0000000c 0x00000003 0x00000003 + 0x00000002 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x0000059f + 0x00000000 0x00000003 0x00000003 0x00000003 + 0x00000003 0x00000001 0x0000000b 0x000000c8 + 0x00000003 0x00000007 0x00000004 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xa06204ae + 0x007dc010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 >; + }; + emc-table@380000 { + reg = < 380000 >; + compatible = "nvidia,tegra20-emc-table"; + clock-frequency = < 380000 >; + nvidia,emc-registers = < 0x00000017 0x0000004b + 0x00000012 0x00000006 0x00000004 0x00000005 + 0x00000003 0x0000000c 0x00000006 0x00000006 + 0x00000003 0x00000001 0x00000004 0x00000005 + 0x00000004 0x00000009 0x0000000d 0x00000b5f + 0x00000000 0x00000003 0x00000003 0x00000006 + 0x00000006 0x00000001 0x00000011 0x000000c8 + 0x00000003 0x0000000e 0x00000007 0x0000000f + 0x00000002 0x00000000 0x00000000 0x00000002 + 0x00000000 0x00000000 0x00000083 0xe044048b + 0x007d8010 0x00000000 0x00000000 0x00000000 + 0x00000000 0x00000000 0x00000000 0x00000000 >; emc-table@190000 { + }; + }; +}; + };

On Fri, Jan 13, 2012 at 1:35 PM, Simon Glass sjg@chromium.org wrote:
This adds timings for T20 and T25 Seaboards, using the bindings found here:
http://patchwork.ozlabs.org/patch/132928/
We supply both full speed options for normal running, and half speed options for testing / development.
Signed-off-by: Simon Glass sjg@chromium.org
board/nvidia/dts/tegra2-seaboard.dts | 73 ++++++++++++++++++++++++++++++++++ 1 files changed, 73 insertions(+), 0 deletions(-)
diff --git a/board/nvidia/dts/tegra2-seaboard.dts b/board/nvidia/dts/tegra2-seaboard.dts index d2cc428..b114f5f 100644 --- a/board/nvidia/dts/tegra2-seaboard.dts +++ b/board/nvidia/dts/tegra2-seaboard.dts @@ -54,4 +54,77 @@ status = "disabled"; };
- emc@7000f400 {
- emc-table@166500 {
- reg = <166500>;
- compatible = "nvidia,tegra20-emc-table";
- clock-frequency = < 166500 >;
- nvidia,emc-registers = < 0x0000000a 0x00000021
- 0x00000008 0x00000003 0x00000004 0x00000004
- 0x00000002 0x0000000c 0x00000003 0x00000003
- 0x00000002 0x00000001 0x00000004 0x00000005
- 0x00000004 0x00000009 0x0000000d 0x000004df
- 0x00000000 0x00000003 0x00000003 0x00000003
- 0x00000003 0x00000001 0x0000000a 0x000000c8
- 0x00000003 0x00000006 0x00000004 0x0000000f
- 0x00000002 0x00000000 0x00000000 0x00000002
- 0x00000000 0x00000000 0x00000083 0xa04004ae
- 0x007fd010 0x00000000 0x00000000 0x00000000
- 0x00000000 0x00000000 0x00000000 0x00000000 >;
- };
- emc-table@333000 {
- reg = <333000>;
- compatible = "nvidia,tegra20-emc-table";
- clock-frequency = < 333000 >;
- nvidia,emc-registers = < 0x00000014 0x00000041
- 0x0000000f 0x00000005 0x00000004 0x00000005
- 0x00000003 0x0000000c 0x00000005 0x00000005
- 0x00000003 0x00000001 0x00000004 0x00000005
- 0x00000004 0x00000009 0x0000000d 0x000009ff
- 0x00000000 0x00000003 0x00000003 0x00000005
- 0x00000005 0x00000001 0x0000000f 0x000000c8
- 0x00000003 0x0000000c 0x00000006 0x0000000f
- 0x00000002 0x00000000 0x00000000 0x00000002
- 0x00000000 0x00000000 0x00000083 0xe034048b
- 0x007e8010 0x00000000 0x00000000 0x00000000
- 0x00000000 0x00000000 0x00000000 0x00000000>;
- };
- emc-table@190000 {
- reg = < 190000 >;
- compatible = "nvidia,tegra20-emc-table";
- clock-frequency = < 190000 >;
- nvidia,emc-registers = < 0x0000000c 0x00000026
- 0x00000009 0x00000003 0x00000004 0x00000004
- 0x00000002 0x0000000c 0x00000003 0x00000003
- 0x00000002 0x00000001 0x00000004 0x00000005
- 0x00000004 0x00000009 0x0000000d 0x0000059f
- 0x00000000 0x00000003 0x00000003 0x00000003
- 0x00000003 0x00000001 0x0000000b 0x000000c8
- 0x00000003 0x00000007 0x00000004 0x0000000f
- 0x00000002 0x00000000 0x00000000 0x00000002
- 0x00000000 0x00000000 0x00000083 0xa06204ae
- 0x007dc010 0x00000000 0x00000000 0x00000000
- 0x00000000 0x00000000 0x00000000 0x00000000 >;
- };
- emc-table@380000 {
- reg = < 380000 >;
- compatible = "nvidia,tegra20-emc-table";
- clock-frequency = < 380000 >;
- nvidia,emc-registers = < 0x00000017 0x0000004b
- 0x00000012 0x00000006 0x00000004 0x00000005
- 0x00000003 0x0000000c 0x00000006 0x00000006
- 0x00000003 0x00000001 0x00000004 0x00000005
- 0x00000004 0x00000009 0x0000000d 0x00000b5f
- 0x00000000 0x00000003 0x00000003 0x00000006
- 0x00000006 0x00000001 0x00000011 0x000000c8
- 0x00000003 0x0000000e 0x00000007 0x0000000f
- 0x00000002 0x00000000 0x00000000 0x00000002
- 0x00000000 0x00000000 0x00000083 0xe044048b
- 0x007d8010 0x00000000 0x00000000 0x00000000
- 0x00000000 0x00000000 0x00000000 0x00000000 >; emc-table@190000 {
Oh dear. I will fix this next revision...
- };
- };
+};
};
1.7.7.3

This enables LP0 to support suspend / resume on Seaboard.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/configs/seaboard.h | 8 ++++++++ include/configs/tegra2-common.h | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h index 1494fc0..7b6f92a 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -25,6 +25,14 @@ #define __CONFIG_H
#include <asm/sizes.h> + +/* LP0 suspend / resume */ +#define CONFIG_TEGRA2_LP0 +#define CONFIG_AES +#define CONFIG_TEGRA_PMU +#define CONFIG_TPS6586X_POWER +#define CONFIG_TEGRA_CLOCK_SCALING + #include "tegra2-common.h"
#define CONFIG_SYS_DCACHE_OFF diff --git a/include/configs/tegra2-common.h b/include/configs/tegra2-common.h index 6549d00..6c38f51 100644 --- a/include/configs/tegra2-common.h +++ b/include/configs/tegra2-common.h @@ -26,6 +26,14 @@ #include <asm/sizes.h>
/* + * QUOTE(m) will evaluate to a string version of the value of the macro m + * passed in. The extra level of indirection here is to first evaluate the + * macro m before applying the quoting operator. + */ +#define QUOTE_(m) #m +#define QUOTE(m) QUOTE_(m) + +/* * High Level Configuration Options */ #define CONFIG_ARMCORTEXA9 /* This is an ARM V7 CPU core */ @@ -50,6 +58,15 @@ #define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */ #define CONFIG_OF_LIBFDT /* enable passing of devicetree */
+#ifdef CONFIG_TEGRA2_LP0 +#define TEGRA_LP0_ADDR 0x1C406000 +#define TEGRA_LP0_SIZE 0x2000 +#define TEGRA_LP0_VEC \ + "lp0_vec=" QUOTE(TEGRA_LP0_SIZE) "@" QUOTE(TEGRA_LP0_ADDR) " " +#else +#define TEGRA_LP0_VEC +#endif + /* Environment */ #define CONFIG_ENV_SIZE 0x2000 /* Total Size Environment */

On Friday 13 January 2012 16:35:35 Simon Glass wrote:
--- a/include/configs/tegra2-common.h +++ b/include/configs/tegra2-common.h
/*
- QUOTE(m) will evaluate to a string version of the value of the macro m
- passed in. The extra level of indirection here is to first evaluate
- the macro m before applying the quoting operator.
- */
+#define QUOTE_(m) #m +#define QUOTE(m) QUOTE_(m)
we uses to have MK_STR/XMK_STR in common code, but that seems to have gone by the wayside. but arches/boards still have it, so might as well use that naming convention. -mike

On 01/13/2012 02:35 PM, Simon Glass wrote:
This enables LP0 to support suspend / resume on Seaboard.
Signed-off-by: Simon Glass sjg@chromium.org
FYI, I've read through all the patches in this series and besides the comments I've already made, I think they're OK. I didn't review some of the changes that weren't Tegra-specific, and didn't do a super-detailed review, but I think it's all OK.
Out of curiosity, have you tested this warm boot within a mainline U-Boot with the ChromeOS kernels? I know we don't support LP modes in mainline kernels yet.

there are a few patches here where the Author hasn't provided his s-o-b tag, so that'll need fixing ... -mike

+Nvidia warmboot authors
Hi Tom,
On Sat, Jan 14, 2012 at 8:06 PM, Mike Frysinger vapier@gentoo.org wrote:
there are a few patches here where the Author hasn't provided his s-o-b tag, so that'll need fixing ... -mike
I am going to post a new v3 series - can you please organise people to replace to each patch they write with their s-o-b tags if they are happy with it?
Regards, Simon

Will do.
Jimmy/Wei/Yen - I'll send you an update when Simon posts v3 to u-boot@lists.denx.de, and you'll have to respond with a review (Acked-by) and Signed-off-by for each part of the patch series you originally authored.
Thanks,
Tom
-----Original Message----- From: sjg@google.com [mailto:sjg@google.com] On Behalf Of Simon Glass Sent: Friday, March 30, 2012 12:24 PM To: Mike Frysinger Cc: u-boot@lists.denx.de; Tom Warren; Jimmy Zhang; Yen Lin; Wei Ni Subject: Re: [U-Boot] [PATCH v2 0/20] tegra: warmboot (suspend / resume) support
+Nvidia warmboot authors
Hi Tom,
On Sat, Jan 14, 2012 at 8:06 PM, Mike Frysinger vapier@gentoo.org wrote:
there are a few patches here where the Author hasn't provided his s-o-b tag, so that'll need fixing ... -mike
I am going to post a new v3 series - can you please organise people to replace to each patch they write with their s-o-b tags if they are happy with it?
Regards, Simon
----------------------------------------------------------------------------------- This email message is for the sole use of the intended recipient(s) and may contain confidential information. Any unauthorized review, use, disclosure or distribution is prohibited. If you are not the intended recipient, please contact the sender by reply email and destroy all copies of the original message. -----------------------------------------------------------------------------------
participants (5)
-
Heiko Schocher
-
Mike Frysinger
-
Simon Glass
-
Stephen Warren
-
Tom Warren