Merge remote-tracking branch 'goog/android-master' into HEAD
diff --git a/MAINTAINERS b/MAINTAINERS
index 2f60a60..cba893b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -888,6 +888,10 @@
hawkboard ARM926EJS (OMAP-L138)
+Mike J. Chen <mjchen@google.com>
+
+ omap4_tungsten ARM ARMV7 (OMAP4xx SoC)
+
-------------------------------------------------------------------------
Unknown / orphaned boards:
diff --git a/arch/arm/cpu/armv7/omap-common/gpio.c b/arch/arm/cpu/armv7/omap-common/gpio.c
index e62c6f4..d16ebd7 100644
--- a/arch/arm/cpu/armv7/omap-common/gpio.c
+++ b/arch/arm/cpu/armv7/omap-common/gpio.c
@@ -234,9 +234,25 @@
/**
* Reset and free the gpio after using it.
+ *
+ * Note: do not actually do this in manufacturing builds. The Tungsten
+ * project uses the uboot gpio console during factory line diagnostics to do
+ * basic pin IO tests. The consoles code follows the pattern of
+ *
+ * 1) Request target gpio
+ * 2) Get/Set/Toggle target gpio
+ * 3) Free target gpio
+ *
+ * Allowing the implementation of free to reset a given GPIO back to being an
+ * input causes the console's pattern to break the diags which need the pin to
+ * hold its state after the command has been issued until the external test rig
+ * can verify the pin state. For now, we just #if this out; but there probably
+ * should be a more general fix applied to the console commands at some future
+ * point in time.
*/
void gpio_free(unsigned gpio)
{
+#ifndef CONFIG_MFG
const struct gpio_bank *bank;
if (check_gpio(gpio) < 0)
@@ -244,4 +260,5 @@
bank = get_gpio_bank(gpio);
_set_gpio_direction(bank, get_gpio_index(gpio), 1);
+#endif
}
diff --git a/arch/arm/cpu/armv7/omap4/omap4_mux_data.h b/arch/arm/cpu/armv7/omap4/omap4_mux_data.h
index 00c52f8..bf69700 100644
--- a/arch/arm/cpu/armv7/omap4/omap4_mux_data.h
+++ b/arch/arm/cpu/armv7/omap4/omap4_mux_data.h
@@ -30,6 +30,7 @@
const struct pad_conf_entry core_padconf_array_essential[] = {
+#ifndef CONFIG_TUNGSTEN
{GPMC_AD0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat0 */
{GPMC_AD1, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat1 */
{GPMC_AD2, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat2 */
@@ -40,6 +41,7 @@
{GPMC_AD7, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_dat7 */
{GPMC_NOE, (PTU | IEN | OFF_EN | OFF_OUT_PTD | M1)}, /* sdmmc2_clk */
{GPMC_NWE, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* sdmmc2_cmd */
+#endif
{SDMMC1_CLK, (PTU | OFF_EN | OFF_OUT_PTD | M0)}, /* sdmmc1_clk */
{SDMMC1_CMD, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_cmd */
{SDMMC1_DAT0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat0 */
@@ -50,6 +52,7 @@
{SDMMC1_DAT5, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat5 */
{SDMMC1_DAT6, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat6 */
{SDMMC1_DAT7, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat7 */
+#ifndef CONFIG_TUNGSTEN
{I2C1_SCL, (PTU | IEN | M0)}, /* i2c1_scl */
{I2C1_SDA, (PTU | IEN | M0)}, /* i2c1_sda */
{I2C2_SCL, (PTU | IEN | M0)}, /* i2c2_scl */
@@ -60,6 +63,7 @@
{I2C4_SDA, (PTU | IEN | M0)}, /* i2c4_sda */
{UART3_CTS_RCTX, (PTU | IEN | M0)}, /* uart3_tx */
{UART3_RTS_SD, (M0)}, /* uart3_rts_sd */
+#endif
{UART3_RX_IRRX, (IEN | M0)}, /* uart3_rx */
{UART3_TX_IRTX, (M0)} /* uart3_tx */
diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
index a1fd03a..d732450 100644
--- a/arch/arm/include/asm/mach-types.h
+++ b/arch/arm/include/asm/mach-types.h
@@ -3312,6 +3312,7 @@
#define MACH_TYPE_T5388P 3336
#define MACH_TYPE_DINGO 3337
#define MACH_TYPE_GOFLEXHOME 3338
+#define MACH_TYPE_STEELHEAD 3533
#ifdef CONFIG_ARCH_EBSA110
# ifdef machine_arch_type
@@ -36433,6 +36434,18 @@
# define machine_is_omap4_panda() (0)
#endif
+#ifdef CONFIG_MACH_STEELHEAD
+# ifdef machine_arch_type
+# undef machine_arch_type
+# define machine_arch_type __machine_arch_type
+# else
+# define machine_arch_type MACH_TYPE_STEELHEAD
+# endif
+# define machine_is_steelhead() (machine_arch_type == MACH_TYPE_STEELHEAD)
+#else
+# define machine_is_steelhead() (0)
+#endif
+
#ifdef CONFIG_MACH_DF7220
# ifdef machine_arch_type
# undef machine_arch_type
diff --git a/board/google/tungsten/Makefile b/board/google/tungsten/Makefile
new file mode 100644
index 0000000..25b3dc0
--- /dev/null
+++ b/board/google/tungsten/Makefile
@@ -0,0 +1,51 @@
+#
+# (C) Copyright 2000, 2001, 2002
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# 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 $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(BOARD).o
+
+ifndef CONFIG_SPL_BUILD
+COBJS := $(BOARD).o steelhead_avr.o pseudorandom_ids.o
+endif
+
+SRCS := $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS))
+
+$(LIB): $(obj).depend $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+clean:
+ rm -f $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak $(obj).depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/google/tungsten/config.mk b/board/google/tungsten/config.mk
new file mode 100644
index 0000000..3bc935a
--- /dev/null
+++ b/board/google/tungsten/config.mk
@@ -0,0 +1 @@
+PLATFORM_CPPFLAGS += -Werror
diff --git a/board/google/tungsten/pseudorandom_ids.c b/board/google/tungsten/pseudorandom_ids.c
new file mode 100644
index 0000000..81a8305
--- /dev/null
+++ b/board/google/tungsten/pseudorandom_ids.c
@@ -0,0 +1,106 @@
+/*
+ * (C) Copyright 2011
+ * Google, Inc.
+ *
+ * Author :
+ * John Grossman <johngro@google.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/arch/mem.h>
+#include <asm/arch/sys_proto.h>
+
+#include "pseudorandom_ids.h"
+
+#define DIE_ID_REG_BASE (OMAP44XX_L4_CORE_BASE + 0x2000)
+#define DIE_ID_REG_OFFSET 0x200
+
+/* Implements a variation of a 64 bit Galois LFSR with the generator
+ *
+ * gp(x) = x^64 + x^63 + x^61 + x^60 + 1
+ *
+ * This variant will actually blend in the bits of data by xor'ing with the
+ * output of the register before feeding back. Returned data is taken before
+ * this XOR operation. Passing data = 0 will result in the traditional Galois
+ * LFSR behavior, suitable for a PRNG.
+ *
+ */
+static u32 hash_lfsr_data(u64* state, u32 data) {
+ static const u64 taps = 0xD800000000000000ull;
+ u32 i, ret = 0;
+
+ for (i=0; i < (sizeof(ret) << 3); ++i) {
+ ret <<= 1;
+ ret |= (((u32)(*state)) & 0x1);
+
+ *state >>= 1;
+ if ((ret ^ data) & 0x1)
+ *state ^= taps;
+ data >>= 1;
+ }
+
+ return ret;
+}
+
+static void init_dieid_lfsr(u64* state, u32 salt) {
+ unsigned int reg = DIE_ID_REG_BASE + DIE_ID_REG_OFFSET;
+ int i;
+
+ /* prime the core of the LFSR with the lower 64 bits of the die ID */
+ *state = ((u64)readl(reg + 0x8) << 32) | /* dieid bits [63:32] */
+ (u64)readl(reg); /* dieid bits [31:0] */
+
+ /* hash in the upper 64 bits of the die ID to finish initializing the
+ * state
+ */
+ hash_lfsr_data(state, readl(reg + 0xC));
+ hash_lfsr_data(state, readl(reg + 0x10));
+
+ /* Add the salt */
+ hash_lfsr_data(state, salt);
+
+ /* Blend up the core state a bunch and we are ready to go */
+ for (i = 0; i < 32; ++i)
+ hash_lfsr_data(state, 0);
+}
+
+void generate_default_mac_addr(u32 salt, u8* mac_out) {
+ u64 lfsr_state;
+ u32 rand;
+
+ init_dieid_lfsr(&lfsr_state, salt);
+
+ mac_out[5] = 0x00;
+ mac_out[4] = 0x1A;
+ mac_out[3] = 0x11;
+
+ rand = hash_lfsr_data(&lfsr_state, 0);
+ mac_out[2] = (u8)(rand & 0xFF);
+ mac_out[1] = (u8)((rand >> 8) & 0xFF);
+ mac_out[0] = (u8)((rand >> 16) & 0xFF);
+}
+
+void generate_default_64bit_id(u32 salt, u64* id_64) {
+ u64 lfsr_state;
+ init_dieid_lfsr(&lfsr_state, salt);
+ *id_64 = ((u64)hash_lfsr_data(&lfsr_state, 0) << 32) |
+ (u64)hash_lfsr_data(&lfsr_state, 0);
+}
diff --git a/board/google/tungsten/pseudorandom_ids.h b/board/google/tungsten/pseudorandom_ids.h
new file mode 100644
index 0000000..06258a8
--- /dev/null
+++ b/board/google/tungsten/pseudorandom_ids.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2011
+ * Google, Inc.
+ *
+ * Author :
+ * John Grossman <johngro@google.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
+ */
+
+extern void generate_default_mac_addr(u32 salt, u8* mac_out);
+extern void generate_default_64bit_id(u32 salt, u64* id_64);
diff --git a/board/google/tungsten/steelhead_avr.c b/board/google/tungsten/steelhead_avr.c
new file mode 100644
index 0000000..4c19fb3
--- /dev/null
+++ b/board/google/tungsten/steelhead_avr.c
@@ -0,0 +1,664 @@
+/* board/google/tungsten/steelhead_avr.c
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * This is a driver that communicates with an Atmel AVR ATmega328P
+ * subboard in the Android@Home device via gpios and i2c. This subboard
+ * is Arduino-Compatible and the firmware in it is developed using the
+ * Arduino SDK.
+ *
+ * The functionality implemented by the subboard is a set of capacitive touch
+ * keys and many leds. To keep things simple for now, we have just
+ * one driver that implements two input_device exposing the keys and
+ * a misc_device exposing custom ioctls for controlling the leds. We don't
+ * use the Linux led driver API because we have too many leds and want
+ * a more custom API to be more efficient. Also, the subboard firmware
+ * implements some macro led modes (like volume mode) which doesn't make
+ * sense in the led API.
+ */
+
+#include <common.h>
+#include <config.h>
+#include <command.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fastboot.h>
+#include <linux/ctype.h>
+
+#include "steelhead_avr.h"
+#include "steelhead_avr_regs.h"
+
+#define LED_BYTE_SZ 3
+
+#define AVR_I2C_CLIENT_ID (0x20) /* 7 bit i2c id */
+#define AVR_I2C_BUS_ID (0x1)
+
+static struct avr_driver_state {
+ int avr_detected;
+
+ /* device info */
+ u16 firmware_rev;
+ u8 hardware_type;
+ u8 hardware_rev;
+ u16 led_count;
+
+ /* Current LED state. */
+ u8 led_mode;
+ u8 mute_threshold;
+} state;
+
+/* the AVR can be temporarily busy doing other things and be unable
+ * to respond to a i2c request (it's not multi-threaded) so we need
+ * to retry on failure a few times.
+ */
+#define MAX_I2C_ATTEMPTS 5
+static int avr_i2c_write(u8 cmd, u8* buf, u16 len)
+{
+ int rc, try;
+
+ rc = i2c_set_bus_num(AVR_I2C_BUS_ID);
+ if (rc) {
+ printf("Failed in i2c_set_bus_num(%d), error %d\n",
+ AVR_I2C_BUS_ID, rc);
+ return rc;
+ }
+
+ for (try = 0; try < MAX_I2C_ATTEMPTS; try++) {
+ rc = i2c_write(AVR_I2C_CLIENT_ID, cmd, 1, buf, len);
+ if (rc == 0)
+ break;
+ }
+ if (rc) {
+ printf("%s: write to reg %d failed after %d attempts\n",
+ __func__, cmd, MAX_I2C_ATTEMPTS);
+ }
+ return rc;
+}
+
+/* the AVR can't do a normal i2c_read() with the
+ * register address passed in one transfer.
+ * it needs a delay between sending the register
+ * address and the read transfer.
+ */
+static int avr_i2c_read(u8 cmd, u16 len, u8 *buf)
+{
+ int rc, try;
+
+ rc = i2c_set_bus_num(AVR_I2C_BUS_ID);
+ if (rc) {
+ printf("Failed in i2c_set_bus_num(%d), error %d\n",
+ AVR_I2C_BUS_ID, rc);
+ return rc;
+ }
+
+ for (try = 0; try < MAX_I2C_ATTEMPTS; try++) {
+ rc = i2c_write(AVR_I2C_CLIENT_ID, cmd, 1, NULL, 0);
+ if (rc == 0)
+ break;
+ }
+ if (rc) {
+ printf("%s: error writing reg addr %u\n", __func__, cmd);
+ return rc;
+ }
+
+ /* Need to wait a little bit between the write of the register ID
+ * and the read of the actual data. Failure to do so will not
+ * result in a NAK, only corrupt data.
+ */
+ udelay(50);
+
+ for (try = 0; try < MAX_I2C_ATTEMPTS; try++) {
+ rc = i2c_read(AVR_I2C_CLIENT_ID, 0, 0, buf, len);
+ if (rc == 0)
+ return 0;
+ }
+ printf("%s: error reading reg %u, failed after %d attempts\n",
+ __func__, cmd, MAX_I2C_ATTEMPTS);
+ return -1;
+}
+
+static int avr_get_firmware_rev(void)
+{
+ u8 buf[2];
+ int rc = avr_i2c_read(AVR_FW_VERSION_REG_ADDR, sizeof(buf), buf);
+
+ state.firmware_rev = ((u16)buf[0] << 8) | (u16)buf[1];
+ return rc;
+}
+
+static int avr_get_hardware_type(void)
+{
+ return avr_i2c_read(AVR_HW_TYPE_REG_ADDR, 1, &state.hardware_type);
+}
+
+static int avr_get_hardware_rev(void)
+{
+ return avr_i2c_read(AVR_HW_REVISION_REG_ADDR, 1, &state.hardware_rev);
+}
+
+static int avr_get_led_count(void)
+{
+ u8 buf[2];
+ int rc = avr_i2c_read(AVR_LED_GET_COUNT_ADDR, sizeof(buf), buf);
+
+ state.led_count = ((u16)buf[0] << 8) | (u16)buf[1];
+ return rc;
+}
+
+int avr_led_set_all(const struct avr_led_rgb_vals *req)
+{
+ if (!req)
+ return -EFAULT;
+
+ return avr_i2c_write(AVR_LED_SET_ALL_REG_ADDR,
+ (uchar *)req->rgb, sizeof(req->rgb));
+}
+
+int avr_led_set_mute(const struct avr_led_rgb_vals *req)
+{
+ if (!req)
+ return -EFAULT;
+
+ return avr_i2c_write(AVR_LED_SET_MUTE_ADDR,
+ (uchar *)req->rgb, sizeof(req->rgb));
+}
+
+int avr_set_mute_threshold(u8 mute_threshold)
+{
+ return avr_i2c_write(AVR_KEY_MUTE_THRESHOLD_REG_ADDR,
+ &mute_threshold, sizeof(mute_threshold));
+
+}
+
+static int avr_get_mute_threshold(void)
+{
+ return avr_i2c_read(AVR_KEY_MUTE_THRESHOLD_REG_ADDR,
+ 1, &state.mute_threshold);
+}
+
+int avr_led_set_range(struct avr_led_set_range_vals *req)
+{
+ if (!req)
+ return -EFAULT;
+ printf("Sending i2c set range packet, %d bytes\n", 3 + (req->rgb_triples * 3));
+ {
+ int i;
+ for (i = 0; i < (3 + (req->rgb_triples * 3)); i++) {
+ printf("0x%x\n", ((uint8_t*)req)[i]);
+ }
+ }
+ return avr_i2c_write(AVR_LED_SET_RANGE_REG_ADDR,
+ (uint8_t*)req, 3 + (req->rgb_triples * 3));
+}
+
+int avr_led_set_mode(u8 mode)
+{
+ int rc = avr_i2c_write(AVR_LED_MODE_REG_ADDR, &mode, 1);
+ /* If the command failed, then skip the update of our internal
+ * bookkeeping and just get out.
+ */
+ if (rc)
+ return rc;
+
+ state.led_mode = mode;
+ return rc;
+}
+
+int avr_led_commit_led_state(u8 val)
+{
+ return avr_i2c_write(AVR_LED_COMMIT_REG_ADDR, &val, 1);
+}
+
+static int avr_read_event_fifo(u8 *next_event)
+{
+ if (!next_event)
+ return -EFAULT;
+
+ return avr_i2c_read(AVR_KEY_EVENT_FIFO_REG_ADDR, 1, next_event);
+}
+
+int detect_avr(void)
+{
+ int rc;
+ struct avr_led_rgb_vals clear_led_req;
+
+ printf("%s\n", __func__);
+
+ /* Cache the firmware revision (also checks to be sure the AVR is
+ * actually there and talking to us).
+ */
+ rc = avr_get_firmware_rev();
+ if (rc) {
+ printf("Failed to fetch AVR firmware revision (rc = %d)\n", rc);
+ goto error;
+ }
+
+ /* Cache the hardware type and revision.
+ */
+ rc = avr_get_hardware_type();
+ if (rc) {
+ printf("Failed to fetch AVR hardware type (rc = %d)\n", rc);
+ goto error;
+ }
+
+ rc = avr_get_hardware_rev();
+ if (rc) {
+ printf("Failed to fetch AVR hardware revision (rc = %d)\n", rc);
+ goto error;
+ }
+
+ rc = avr_get_led_count();
+ if (rc) {
+ printf("Failed to fetch AVR led count (rc = %d)\n", rc);
+ goto error;
+ }
+
+ /* Set the LED state to all off in order to match the internal state we
+ * just established.
+ */
+ clear_led_req.rgb[0] = 0x00;
+ clear_led_req.rgb[1] = 0x00;
+ clear_led_req.rgb[2] = 0x00;
+ rc = avr_led_set_all(&clear_led_req);
+ if (rc) {
+ printf("Failed to clear LEDs on AVR (rc = %d)\n", rc);
+ goto error;
+ }
+
+ printf("Steelhead AVR detected and initialized\n");
+
+ state.avr_detected = 1;
+ return 0;
+ error:
+ return rc;
+}
+
+
+static int do_avr_reinit(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ /* force redetect */
+ if (detect_avr()) {
+ puts("Could not detect avr\n");
+ return 1;
+ }
+ return 0;
+}
+
+static int do_avr_commit_state(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ if (avr_led_commit_led_state(1)) {
+ printf("Error committing led state\n");
+ return 1;
+ }
+ printf("Succeeded committing led state\n");
+ return 0;
+}
+
+int avr_get_key(u8 *key_code)
+{
+ u8 next_event;
+ int rc = i2c_set_bus_num(AVR_I2C_BUS_ID);
+ if (rc) {
+ printf("Failed in i2c_set_bus_num(%d), error %d\n",
+ AVR_I2C_BUS_ID, rc);
+ return rc;
+ }
+ rc = avr_read_event_fifo(&next_event);
+ if (rc) {
+ printf("Failed to read event fifo, err = %d\n", rc);
+ return 1;
+ }
+ *key_code = next_event;
+ if (next_event != AVR_KEY_EVENT_EMPTY) {
+ printf("%s returning 0x%x\n", __func__, next_event);
+ }
+ return 0;
+}
+
+static int do_avr_get_key(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ int saw_key = 0;
+ int rc;
+ u8 next_event;
+
+ while (1) {
+ rc = avr_get_key(&next_event);
+ if (rc)
+ return 1;
+ if (next_event == AVR_KEY_EVENT_EMPTY) {
+ if (saw_key)
+ printf("done\n");
+ else
+ printf("avr returned no key events\n");
+ break;
+ } else {
+ int was_down = next_event & AVR_KEY_EVENT_DOWN;
+ u8 key_code = next_event & AVR_KEY_EVENT_CODE_MASK;
+ char *key_string[3] = {"UNKNOWN", "VOLUME_UP",
+ "VOLUME_DOWN"};
+ saw_key = 1;
+ printf("avr returned key raw = %d, '%s' %s\n",
+ next_event,
+ key_code < ARRAY_SIZE(key_string) ?
+ key_string[key_code] : "BAD CODE",
+ was_down ? "down" : "up");
+ }
+ }
+ return 0;
+}
+
+static int do_avr_get_info(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ printf("avr info:\n");
+ printf(" firmware_rev = %d.%d\n",
+ state.firmware_rev >> 8,
+ state.firmware_rev & 0xFF);
+ printf(" hardware_type = %d\n", state.hardware_type);
+ printf(" hardware_rev = %d\n", state.hardware_rev);
+ printf(" led_mode = %d\n", state.led_mode);
+ printf(" led_count = %d\n", state.led_count);
+ avr_get_mute_threshold();
+ printf(" mute_threshold = %d\n", state.mute_threshold);
+ return 0;
+}
+
+static int do_avr_set_mode(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ ulong raw;
+ const char *mode_names[] = {"BOOT_ANIMATION", "HOST_AUTO_COMMIT", "HOST"};
+ if (argc != 2) {
+ printf("usage: avr set mode "
+ "[0=boot_animation,1=host_auto_commit,2=host]\n");
+ return 1;
+ }
+ raw = simple_strtoul(argv[1], NULL, 10);
+ if (raw > AVR_LED_MODE_HOST) {
+ printf("invalid mode %lu, must be 0 to %d\n",
+ raw, AVR_LED_MODE_HOST);
+ return 1;
+ }
+ if (avr_led_set_mode(raw)) {
+ printf("Error setting mode [%lu:%s]\n",
+ raw, mode_names[raw]);
+ } else {
+ printf("Succeeded setting mode [%lu:%s]\n",
+ raw, mode_names[raw]);
+ }
+ return 0;
+}
+
+static int do_avr_set_all(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct avr_led_rgb_vals req;
+ ulong raw;
+ if (argc != 2) {
+ printf("usage: avr set all rgb888_value\n");
+ return 1;
+ }
+ raw = simple_strtoul(argv[1], NULL, 16);
+ if (raw > 0x00ffffff) {
+ printf("rgb888_value 0x%lx too large\n", raw);
+ return 1;
+ }
+ req.rgb[0] = (raw >> 16) & 0xff;
+ req.rgb[1] = (raw >> 8) & 0xff;
+ req.rgb[2] = (raw >> 0) & 0xff;
+ if (avr_led_set_all(&req)) {
+ printf("Error setting all led values\n");
+ return 1;
+ }
+ printf("Succeeded setting all led values\n");
+ return 0;
+}
+
+static int do_avr_set_mute(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct avr_led_rgb_vals req;
+ ulong raw;
+ if (argc != 2) {
+ printf("usage: avr set mute rgb888_value\n");
+ return 1;
+ }
+ raw = simple_strtoul(argv[1], NULL, 16);
+ if (raw > 0x00ffffff) {
+ printf("rgb888_value 0x%lx too large\n", raw);
+ return 1;
+ }
+ req.rgb[0] = (raw >> 16) & 0xff;
+ req.rgb[1] = (raw >> 8) & 0xff;
+ req.rgb[2] = (raw >> 0) & 0xff;
+ if (avr_led_set_mute(&req)) {
+ printf("Error setting mute led values\n");
+ return 1;
+ }
+ printf("Succeeded setting mute led values\n");
+ return 0;
+}
+
+static int do_avr_set_mute_threshold(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ ulong raw;
+ if (argc != 2) {
+ printf("usage: avr set mute_threshold value\n");
+ return 1;
+ }
+ raw = simple_strtoul(argv[1], NULL, 10);
+ if (raw > 0xff) {
+ printf("mute_threshold_value 0x%lx too large\n", raw);
+ return 1;
+ }
+ if (avr_set_mute_threshold((u8)raw)) {
+ printf("Error setting mute_threshold\n");
+ return 1;
+ }
+ printf("Succeeded setting mute_threshold\n");
+ return 0;
+}
+
+/* examples:
+ 1) to set 4 leds starting at 0 to white, red, green, blue:
+ avr set range 0 4 ffffffff000000ff000000ff
+ 2) to set all first led to green and rest to white:
+ avr set range 0 32 00ff00ffffff
+*/
+static int do_avr_set_range(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ struct avr_led_set_range_vals req;
+ ulong start, count, rgb_triples, end;
+ ulong value, i;
+ char *cp;
+ if (argc != 4) {
+ printf("usage: avr set range start count rgb888_hex_string\n");
+ return 1;
+ }
+ start = simple_strtoul(argv[1], NULL, 10);
+ if (start > state.led_count) {
+ printf("start %lu too large, must be between 0 and %u\n",
+ start, state.led_count);
+ return 1;
+ }
+ count = simple_strtoul(argv[2], NULL, 10);
+ if (count == 0) {
+ printf("0 count invalid\n");
+ return 1;
+ }
+ end = start + count - 1;
+ if (end >= state.led_count) {
+ printf("count %lu too large, must be between 1 and %lu\n",
+ count, state.led_count - start);
+ return 1;
+ }
+ rgb_triples = strlen(argv[3]);
+ /* the length of the string must be a multiple of 6 bytes
+ (two bytes each for red, green, and blue */
+ if (rgb_triples % 6) {
+ printf("rgb888_hex_string is invalid, must have a multiple of 6 characters,"
+ "two each for red, green, and blue\n");
+ return 1;
+ }
+ rgb_triples /= 6;
+
+ req.start = start;
+ req.count = count;
+ req.rgb_triples = rgb_triples;
+ cp = argv[3];
+ for (i = 0; i < rgb_triples; i++) {
+ int j;
+ for (j = 0; j < 3; j++) {
+ value = (isdigit(*cp) ? *cp - '0' : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) * 16;
+ cp++;
+ value += (isdigit(*cp) ? *cp - '0' : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10);
+ cp++;
+
+ req.rgb[i][j] = value;
+ }
+ }
+ if (avr_led_set_range(&req)) {
+ printf("Error setting range led values\n");
+ return 1;
+ }
+ printf("Succeeded setting range led values\n");
+ return 0;
+}
+
+static cmd_tbl_t cmd_avr_get_sub[] = {
+ U_BOOT_CMD_MKENT(info, 1, 1, do_avr_get_info, "", ""),
+ U_BOOT_CMD_MKENT(key, 1, 1, do_avr_get_key, "", ""),
+};
+
+static int do_avr_get(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ cmd_tbl_t *c;
+
+ if (argc < 2) {
+ printf("Too few arguments\n");
+ return cmd_usage(cmdtp);
+ }
+
+ /* Strip off leading 'get' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_avr_get_sub[0],
+ ARRAY_SIZE(cmd_avr_get_sub));
+
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else {
+ printf("unknown command %s\n", argv[2]);
+ return cmd_usage(cmdtp);
+ }
+}
+
+static cmd_tbl_t cmd_avr_set_sub[] = {
+ U_BOOT_CMD_MKENT(mode, 2, 1, do_avr_set_mode, "", ""),
+ U_BOOT_CMD_MKENT(all, 2, 1, do_avr_set_all, "", ""),
+ U_BOOT_CMD_MKENT(mute, 2, 1, do_avr_set_mute, "", ""),
+ U_BOOT_CMD_MKENT(mute_threshold, 2, 1, do_avr_set_mute_threshold, "", ""),
+ U_BOOT_CMD_MKENT(range, 4, 1, do_avr_set_range, "", ""),
+};
+
+static int do_avr_set(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ cmd_tbl_t *c;
+
+ if (argc < 2) {
+ printf("Too few arguments\n");
+ return cmd_usage(cmdtp);
+ }
+
+ /* Strip off leading 'set' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_avr_set_sub[0],
+ ARRAY_SIZE(cmd_avr_set_sub));
+
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else {
+ printf("unknown command %s\n", argv[2]);
+ return cmd_usage(cmdtp);
+ }
+}
+
+static cmd_tbl_t cmd_avr_sub[] = {
+ U_BOOT_CMD_MKENT(reinit, 1, 1, do_avr_reinit, "", ""),
+ U_BOOT_CMD_MKENT(commit_state, 1, 1, do_avr_commit_state, "", ""),
+ U_BOOT_CMD_MKENT(get, 5, 1, do_avr_get, "", ""),
+ U_BOOT_CMD_MKENT(set, 6, 1, do_avr_set, "", ""),
+};
+
+#ifdef CONFIG_NEEDS_MANUAL_RELOC
+void avr_reloc(void)
+{
+ fixup_cmdtable(cmd_avr_sub, ARRAY_SIZE(cmd_avr_sub));
+ fixup_cmdtable(cmd_avr_get_sub, ARRAY_SIZE(cmd_avr_get_sub));
+ fixup_cmdtable(cmd_avr_set_sub, ARRAY_SIZE(cmd_avr_set_sub));
+}
+#endif
+
+static int do_avr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *c;
+
+ if (argc < 2) {
+ printf("Too few arguments\n");
+ return cmd_usage(cmdtp);
+ }
+
+ if (!state.avr_detected) {
+ if (detect_avr()) {
+ puts("Could not detect avr\n");
+ return 1;
+ }
+ }
+
+ /* Strip off leading 'avr' command argument */
+ argc--;
+ argv++;
+
+ c = find_cmd_tbl(argv[0], &cmd_avr_sub[0], ARRAY_SIZE(cmd_avr_sub));
+
+ if (c)
+ return c->cmd(cmdtp, flag, argc, argv);
+ else {
+ printf("unknown command %s\n", argv[2]);
+ return cmd_usage(cmdtp);
+ }
+}
+
+U_BOOT_CMD(
+ avr, 6, 1, do_avr,
+ "steelhead avr sub system",
+ "avr reinit\n"
+ "avr commit_state\n"
+ "avr get key\n"
+ "avr get info\n"
+ "avr set mode [0=boot_animation,1=host_auto_commit,2=host]\n"
+ "avr set all rgb888_hex\n"
+ "avr set mute rgb888_hex\n"
+ "avr set mute_threshold value\n"
+ "avr set range start count rgb888_hex_string\n");
+
diff --git a/board/google/tungsten/steelhead_avr.h b/board/google/tungsten/steelhead_avr.h
new file mode 100644
index 0000000..4d369b3
--- /dev/null
+++ b/board/google/tungsten/steelhead_avr.h
@@ -0,0 +1,50 @@
+/* board/google/tungsten/steelhead_avr.h
+ *
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ * This is a driver that communicates with an Atmel AVR ATmega328P
+ * subboard in the Android@Home device via gpios and i2c. This subboard
+ * is Arduino-Compatible and the firmware in it is developed using the
+ * Arduino SDK.
+ *
+ * The functionality implemented by the subboard is a set of capacitive touch
+ * keys and many leds. To keep things simple for now, we have just
+ * one driver that implements two input_device exposing the keys and
+ * a misc_device exposing custom ioctls for controlling the leds. We don't
+ * use the Linux led driver API because we have too many leds and want
+ * a more custom API to be more efficient. Also, the subboard firmware
+ * implements some macro led modes (like volume mode) which doesn't make
+ * sense in the led API.
+ */
+#ifndef _STEELHEAD_AVR_H_
+#define _STEELHEAD_AVR_H_
+
+struct avr_led_rgb_vals {
+ u8 rgb[3];
+};
+
+struct avr_led_set_range_vals {
+ u8 start;
+ u8 count;
+ u8 rgb_triples;
+ u8 rgb[32][3]; /* maximum number for now */
+};
+
+extern int detect_avr(void);
+extern int avr_led_set_all(const struct avr_led_rgb_vals *req);
+extern int avr_led_set_mute(const struct avr_led_rgb_vals *req);
+extern int avr_led_commit_led_state(u8 val);
+extern int avr_led_set_mode(u8 mode);
+extern int avr_get_key(u8 *key_code);
+extern int avr_set_mute_threshold(u8 mute_threshold);
+
+#endif /* _STEELHEAD_AVR_H_ */
diff --git a/board/google/tungsten/steelhead_avr_regs.h b/board/google/tungsten/steelhead_avr_regs.h
new file mode 100644
index 0000000..56da1d2
--- /dev/null
+++ b/board/google/tungsten/steelhead_avr_regs.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+
+#ifndef __STEELHEAD_AVR_REGS_H
+#define __STEELHEAD_AVR_REGS_H
+
+/* key event registers */
+#define AVR_KEY_EVENT_FIFO_REG_ADDR 0x00
+#define AVR_KEY_EVENT_DOWN 0x80 /* set when key down */
+#define AVR_KEY_EVENT_CODE_MASK 0x3F /* mask for key code
+ * (keeping bit unused)
+ */
+#define AVR_KEY_EVENT_EMPTY 0xFF /* key event value returned
+ * when fifo empty
+ */
+
+#define AVR_KEY_MUTE_THRESHOLD_REG_ADDR 0x01
+
+#define AVR_KEY_MUTE 0x00
+#define AVR_KEY_VOLUME_UP (AVR_KEY_MUTE + 1)
+#define AVR_KEY_VOLUME_DOWN (AVR_KEY_VOLUME_UP + 1)
+#define AVR_KEYCODE_COUNT (AVR_KEY_VOLUME_DOWN + 1)
+
+/* led registers */
+#define AVR_LED_MODE_REG_ADDR 0x02
+#define AVR_LED_MODE_BOOT_ANIMATION 0x00
+#define AVR_LED_MODE_HOST_AUTO_COMMIT 0x01
+#define AVR_LED_MODE_HOST 0x02
+
+#define AVR_LED_SET_ALL_REG_ADDR 0x03
+
+#define AVR_LED_SET_RANGE_REG_ADDR 0x04
+
+#define AVR_LED_COMMIT_REG_ADDR 0x05 /* push the buffered host led
+ * values to active display
+ */
+#define AVR_LED_COMMMIT_IMMEDIATELY 0x00 /* update the active led's
+ * immediately
+ */
+#define AVR_LED_COMMMIT_INTERPOLATE 0x01 /* animate from the current
+ * led state to the new one?
+ * Later!
+ */
+
+#define AVR_LED_SET_MUTE_ADDR 0x06 /* set mute led color */
+#define AVR_LED_GET_COUNT_ADDR 0x07 /* get # of leds */
+
+
+/* fw registers */
+#define AVR_HW_TYPE_REG_ADDR 0x08
+#define AVR_HE_TYPE_UNKNOWN 0x00
+#define AVR_HE_TYPE_SPHERE 0x01
+#define AVR_HE_TYPE_RHOMBUS 0x02
+
+#define AVR_HW_REVISION_REG_ADDR 0x09
+
+#define AVR_FW_VERSION_REG_ADDR 0x0a /* 16 bit register 8.8 */
+
+#endif /* __STEELHEAD_AVR_REGS_H */
diff --git a/board/google/tungsten/tungsten.c b/board/google/tungsten/tungsten.c
new file mode 100644
index 0000000..6a790b7
--- /dev/null
+++ b/board/google/tungsten/tungsten.c
@@ -0,0 +1,895 @@
+/*
+ * (C) Copyright 2011
+ * Google, Inc.
+ * (C) Copyright 2010
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Author :
+ * Mike J Chen <mjchen@google.com>
+ *
+ * Derived from Panda Board code by
+ * Steve Sakoman <steve@sakoman.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/gpio.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/mmc_host_def.h>
+#include <fastboot.h>
+#include <mmc.h>
+#include <malloc.h>
+#include <linux/string.h>
+
+#include "steelhead_avr.h"
+#include "steelhead_avr_regs.h"
+#include "tungsten_mux_data.h"
+#include "pseudorandom_ids.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum steelhead_rev {
+ STEELHEAD_REV_ALPHA = 0x0,
+ STEELHEAD_REV_EVT = 0x1,
+ STEELHEAD_REV_EVT2 = 0x2,
+ STEELHEAD_REV_DVT = 0x3,
+ STEELHEAD_REV_DVT1_5 = 0x4,
+ STEELHEAD_REV_DVT2 = 0x5,
+ STEELHEAD_REV_DVT3 = 0x6,
+ STEELHEAD_REV_DVT4 = 0x7,
+ STEELHEAD_REV_DVT5 = 0x8,
+ STEELHEAD_REV_PVT = 0x9,
+ STEELHEAD_REV_PROD = 0xA,
+};
+
+static const char const *steelhead_hw_name[] = {
+ [STEELHEAD_REV_ALPHA] = "Steelhead ALPHA",
+ [STEELHEAD_REV_EVT] = "Steelhead EVT",
+ [STEELHEAD_REV_EVT2] = "Steelhead EVT2",
+ [STEELHEAD_REV_DVT] = "Steelhead DVT",
+ [STEELHEAD_REV_DVT1_5] = "Steelhead DVT1.5",
+ [STEELHEAD_REV_DVT2] = "Steelhead DVT2",
+ [STEELHEAD_REV_DVT3] = "Steelhead DVT3",
+ [STEELHEAD_REV_DVT4] = "Steelhead DVT4",
+ [STEELHEAD_REV_DVT5] = "Steelhead DVT5",
+ [STEELHEAD_REV_PVT] = "Steelhead PVT",
+ [STEELHEAD_REV_PROD] = "Steelhead PROD",
+};
+int hwrev_gpios[] = {
+ 182, /* board_id_0 */
+ 101, /* board_id_1 */
+ 171, /* board_id_2 */
+};
+/* We have 3 bits of board-id to track revision. Older
+ * revisions started to get deprecated and their board-id
+ * values reused, so we use a mapping table to converet
+ * the raw board-id values to the enum values.
+ */
+static const enum steelhead_rev board_id_to_steelhead_rev[8] = {
+ STEELHEAD_REV_DVT5, /* board_id: 0x0 */
+ STEELHEAD_REV_PVT, /* board_id: 0x1 */
+ STEELHEAD_REV_PROD, /* board_id: 0x2 */
+ STEELHEAD_REV_DVT, /* board_id: 0x3 */
+ STEELHEAD_REV_DVT1_5, /* board_id: 0x4 */
+ STEELHEAD_REV_DVT2, /* board_id: 0x5 */
+ STEELHEAD_REV_DVT3, /* board_id: 0x6 */
+ STEELHEAD_REV_DVT4 /* board_id: 0x7 */
+};
+
+enum steelhead_rev steelhead_hw_rev;
+int avr_detected;
+
+static unsigned long key_pressed_start_time;
+static unsigned long last_time;
+#define KEY_CHECK_POLLING_INTERVAL_MS 100
+#define RECOVERY_KEY_HOLD_TIME_SECS 10
+
+static int force_fastboot = 0;
+
+const struct omap_sysinfo sysinfo = {
+ "Board: OMAP4 Tungsten\n"
+};
+
+struct mac_generator {
+ const u32 salt;
+ const char* name;
+};
+
+#define MAKE_SALT(a, b, c, d) (((u32)a << 24) | ((u32)b << 16) | \
+ ((u32)c << 8) | ((u32)d))
+static const struct mac_generator mac_defaults[] = {
+ { MAKE_SALT('W','i','F','i'), "androidboot.wifi_macaddr" },
+ { MAKE_SALT('W','i','r','e'), "smsc95xx.mac_addr" },
+ { MAKE_SALT('B','l','u','T'), "board_steelhead_bluetooth.btaddr" },
+};
+static const u32 serial_no_salt = MAKE_SALT('S','e','r','#');
+#undef MAKE_SALT
+
+static const char *steelhead_hw_rev_name(void)
+{
+ int num = ARRAY_SIZE(steelhead_hw_name);
+
+ if (steelhead_hw_rev >= num ||
+ !steelhead_hw_name[steelhead_hw_rev])
+ return "Steelhead unknown version";
+
+ return steelhead_hw_name[steelhead_hw_rev];
+}
+
+static void init_hw_rev(void)
+{
+ int i;
+ int board_id;
+
+ do_set_mux(CONTROL_PADCONF_CORE, core_padconf_array_non_essential,
+ sizeof(core_padconf_array_non_essential) /
+ sizeof(struct pad_conf_entry));
+
+ board_id = 0;
+
+ for (i = 0; i < ARRAY_SIZE(hwrev_gpios); i++)
+ board_id |= gpio_get_value(hwrev_gpios[i]) << i;
+
+ /* put board_id pins into safe mode to save power */
+ do_set_mux(CONTROL_PADCONF_CORE, core_padconf_array_disable_board_id,
+ sizeof(core_padconf_array_disable_board_id) /
+ sizeof(struct pad_conf_entry));
+
+ /* not absolutely necessary but good in case the size of the
+ array ever changes */
+ if (board_id < ARRAY_SIZE(board_id_to_steelhead_rev)) {
+ steelhead_hw_rev = board_id_to_steelhead_rev[board_id];
+ printf("HW revision: 0x%x = \"%s\" (board_id 0x%x)\n",
+ steelhead_hw_rev, steelhead_hw_rev_name(), board_id);
+ } else {
+ /* default to the highest rev we know of */
+ steelhead_hw_rev = STEELHEAD_REV_PROD;
+ printf("board_id 0x%x invalid, setting steelhead_hw_rev to "
+ "0x%x = \"%s\"", board_id,
+ steelhead_hw_rev, steelhead_hw_rev_name());
+ }
+}
+
+/**
+ * @brief board_init
+ *
+ * @return 0
+ */
+int board_init(void)
+{
+ /* gpmc_init() touches bss, which cannot be used until
+ * after relocation.
+ */
+ gpmc_init();
+ gd->bd->bi_arch_number = MACH_TYPE_STEELHEAD;
+ gd->bd->bi_boot_params = (0x80000000 + 0x100); /* boot param addr */
+ init_hw_rev();
+ return 0;
+}
+
+int board_eth_init(bd_t *bis)
+{
+ return 0;
+}
+
+/**
+ * @brief set_muxconf_regs Setting up the configuration Mux registers
+ * specific to the board.
+ */
+void set_muxconf_regs_non_essential(void)
+{
+ do_set_mux(CONTROL_PADCONF_CORE, core_padconf_array_non_essential,
+ sizeof(core_padconf_array_non_essential) /
+ sizeof(struct pad_conf_entry));
+ do_set_mux(CONTROL_PADCONF_WKUP, wkup_padconf_array_non_essential,
+ sizeof(wkup_padconf_array_non_essential) /
+ sizeof(struct pad_conf_entry));
+}
+
+#ifdef CONFIG_GENERIC_MMC
+static int samsung_mmc_cmd(struct mmc *mmc, uint mode)
+{
+ struct mmc_cmd cmd;
+ int ret;
+
+ cmd.cmdidx = 62; /* Samsung OEM command */
+ cmd.cmdarg = 0xEFAC62EC; /* Magic value */
+ cmd.resp_type = MMC_RSP_R1b;
+ cmd.flags = 0;
+ ret = mmc->send_cmd(mmc, &cmd, NULL);
+ if (ret) {
+ printf("%s: Error %d sending magic.\n", __func__, ret);
+ return 1;
+ }
+ cmd.cmdarg = mode;
+ ret = mmc->send_cmd(mmc, &cmd, NULL);
+ if (ret) {
+ printf("%s: Error %d sending mode 0x%08X.\n",
+ __func__, ret, mode);
+ return 1;
+ }
+ return 0;
+}
+static int samsung_mmc_mem(struct mmc *mmc, uint addr, uint val)
+{
+ struct mmc_cmd cmd;
+ int ret;
+
+ cmd.cmdidx = MMC_CMD_ERASE_GROUP_START;
+ cmd.cmdarg = addr;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.flags = 0;
+ ret = mmc->send_cmd(mmc, &cmd, NULL);
+ if (ret) {
+ printf("%s: Error %d sending addr 0x%08X.\n",
+ __func__, ret, addr);
+ return 1;
+ }
+ cmd.cmdidx = MMC_CMD_ERASE_GROUP_END;
+ cmd.cmdarg = val;
+ ret = mmc->send_cmd(mmc, &cmd, NULL);
+ if (ret) {
+ printf("%s: Error %d sending val 0x%08X.\n",
+ __func__, ret, val);
+ return 1;
+ }
+ cmd.cmdidx = MMC_CMD_ERASE;
+ cmd.cmdarg = 0;
+ ret = mmc->send_cmd(mmc, &cmd, NULL);
+ if (ret) {
+ printf("%s: Error %d latching 0x%08X:0x%08X.\n",
+ __func__, ret, addr, val);
+ return 1;
+ }
+ return 0;
+}
+static int samsung_mmc_read_word(struct mmc *mmc, uint *val)
+{
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+ uint *dst;
+ int ret;
+
+ cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.flags = 0;
+
+ dst = malloc(mmc->read_bl_len);
+ if (!dst) {
+ printf("%s: Error allocating read buffer.\n", __func__);
+ return 1;
+ }
+ data.dest = (char *)dst;
+ data.blocks = 1;
+ data.blocksize = mmc->read_bl_len;
+ data.flags = MMC_DATA_READ;
+
+ ret = mmc->send_cmd(mmc, &cmd, &data);
+ if (ret)
+ printf("%s: Error %d reading.\n", __func__, ret);
+ else
+ *val = dst[0];
+
+ free(dst);
+ return ret;
+}
+
+int board_mmc_init(bd_t *bis)
+{
+ struct mmc *mmc;
+ uint8_t mmc_manufacturer;
+ uint8_t mmc_firmware_version;
+ int err;
+
+ omap_mmc_init(CONFIG_MMC_DEV);
+
+ mmc = find_mmc_device(CONFIG_MMC_DEV);
+ if (!mmc) {
+ printf("mmc device not found!!\n");
+ /* Having mmc_initialize() invoke cpu_mmc_init() won't help. */
+ return 0;
+ }
+
+ err = mmc_init(mmc);
+ if (err)
+ printf("mmc init failed: err - %d\n", err);
+
+ printf("cid = %x%08x%08x%08x\n", mmc->cid[0], mmc->cid[1],
+ mmc->cid[2], mmc->cid[3]);
+ mmc_manufacturer = (mmc->cid[0] >> 24) & 0xff;
+ mmc_firmware_version = (mmc->cid[2] >> 16) & 0xff;
+ if ((mmc_manufacturer == 0x15) && (mmc_firmware_version == 0x12)) {
+ /* Unfortunately, we have units deployed with old
+ * eMMC firmware (Samsung version 1.2) though there
+ * may be one or more good versions. Units with
+ * this eMMC firmware eventually stop erasing. Instead
+ * of letting users keep using them until they fail and
+ * then reporting an issue, force a stop if we detect
+ * this old firmware and force them to update right away
+ * instead of getting a constant trickle of these failed
+ * units coming in one at a time.
+ */
+ printf("\tSamsung eMMC firmware %x.%x is bad, must update\n",
+ mmc_firmware_version >> 4,
+ mmc_firmware_version & 0xf);
+ force_fastboot = 1;
+ } else if ((mmc_manufacturer == 0x15)
+ && (mmc_firmware_version == 0x25)) {
+ uint val1 = 0, val2 = 0;
+ /* Samsung e-MMC firmware has a bug that can be worked around
+ * by changing the Write Buffer Block (LDB) Wear Level Policy
+ * from page to block unit. Do that with a Vendor Command
+ * sequence.
+ */
+ printf("\tWorkaround check on Samsung eMMC firmware %x.%x\n",
+ mmc_firmware_version >> 4,
+ mmc_firmware_version & 0xf);
+
+ /* Fetch and verify the prior values. */
+ err = samsung_mmc_cmd(mmc, 0x10210002) ||
+ samsung_mmc_mem(mmc, 0x04DD9C, 4) ||
+ samsung_mmc_read_word(mmc, &val1) ||
+ samsung_mmc_mem(mmc, 0x0379A4, 4) ||
+ samsung_mmc_read_word(mmc, &val2);
+ err = samsung_mmc_cmd(mmc, 0xDECCEE) || err;
+ if (!err && val1 == 0x000000FF && val2 == 0xD20228FF) {
+ printf("\tWorkaround already applied\n");
+ return 0;
+ }
+
+ if (err) {
+ printf("Reading eMMC RAM failed (%d)\n", err);
+ force_fastboot = 1; /* Fatal */
+ return 0;
+ }
+
+ if (val1 != 0x00000000 || val2 != 0xD2022820) {
+ printf("Assuming workaround not needed for "
+ "values (0x%08X 0x%08X)\n", val1, val2);
+ /* We didn't see what we expected. Don't write to
+ * the RAM, and consider it success assuming that
+ * the version number got reused but the firmware
+ * does not need the workaround.
+ */
+ return 0;
+ }
+
+ printf("\tApplying block LDB Wear Level Policy workaround\n");
+ /* Write the new values. */
+ err = samsung_mmc_cmd(mmc, 0x10210000) ||
+ samsung_mmc_mem(mmc, 0x04DD9C, 0x000000FF) ||
+ samsung_mmc_mem(mmc, 0x0379A4, 0xD20228FF);
+ err = samsung_mmc_cmd(mmc, 0xDECCEE) || err;
+ if (err) {
+ printf("Writing workaround failed (%d)\n", err);
+ force_fastboot = 1; /* Fatal */
+ return 0;
+ }
+
+ /* Verify the new values. */
+ err = samsung_mmc_cmd(mmc, 0x10210002) ||
+ samsung_mmc_mem(mmc, 0x04DD9C, 4) ||
+ samsung_mmc_read_word(mmc, &val1) ||
+ samsung_mmc_mem(mmc, 0x0379A4, 4) ||
+ samsung_mmc_read_word(mmc, &val2);
+ err = samsung_mmc_cmd(mmc, 0xDECCEE) || err;
+ if (err || val1 != 0x000000FF || val2 != 0xD20228FF) {
+ printf("Verifying workaround failed "
+ "(%d 0x%08X 0x%08X)\n",
+ err, val1, val2);
+ force_fastboot = 1; /* Fatal */
+ return 0;
+ }
+ } else {
+ printf("\teMMC manufacturer 0x%02X version %x.%x\n",
+ mmc_manufacturer,
+ mmc_firmware_version >> 4,
+ mmc_firmware_version & 0xf);
+ }
+
+ return 0;
+}
+#endif
+
+static const struct avr_led_rgb_vals red = {
+ .rgb[0] = 128, .rgb[1] = 0, .rgb[2] = 0
+};
+static const struct avr_led_rgb_vals black = {
+ .rgb[0] = 0, .rgb[1] = 0, .rgb[2] = 0
+};
+
+int board_fbt_key_pressed(void)
+{
+ int is_pressed = 0;
+ u8 key_code;
+ unsigned long start_time = get_timer(0);
+
+#define DETECT_AVR_DELAY_MSEC 2000 /* 2 seconds */
+
+ /* If we power up with USB cable connected, the ROM bootloader
+ * delays the OMAP boot long enough (as it checks for peripheral
+ * boot) that the AVR will be ready at this point for us to
+ * query. If we power up with no USB cable, we will most likely
+ * be here before the AVR is ready. If we don't detect
+ * the AVR right away, sleep a few seconds and try again.
+ * We don't just poll until the AVR can respond because even
+ * after we detect the AVR, it might not quite be ready to
+ * do key detection so need to wait a bit more.
+ */
+ avr_detected = !detect_avr();
+ if (!avr_detected) {
+ printf("\tavr not detected\n");
+ printf("\tdelaying %d milliseconds until we try again\n",
+ DETECT_AVR_DELAY_MSEC);
+ while((get_timer(0) - start_time) < DETECT_AVR_DELAY_MSEC)
+ ; /* spin on purpose */
+ avr_detected = !detect_avr();
+ }
+ if (!avr_detected) {
+ /* always start fastboot if we're forcing it, even
+ * if we can't show we're in fastboot mode with the LEDs
+ */
+ if (force_fastboot) {
+ printf("Forcing fastboot even with no avr\n");
+ return 1;
+ }
+
+ /* This might happen if avr_updater got interrupted
+ * while an avr firmware update was in progress.
+ * It's better to allow regular booting instead of
+ * stopping in fastboot mode because the OS might
+ * be able to recovery it by doing the update again.
+ * It's also not good to stop in fastboot because we
+ * can't use the LEDs to indicate to the user we're
+ * in this state.
+ */
+ printf("%s: avr not detected, returning false\n", __func__);
+ return 0;
+ }
+
+ /* If we got here from a warm reset, AVR could be in some
+ * other state than host mode so just make sure it is
+ * in host mode.
+ */
+ avr_led_set_mode(AVR_LED_MODE_HOST_AUTO_COMMIT);
+
+ if (force_fastboot) {
+ printf("Forcing fastboot\n");
+ return 1;
+ }
+
+ /* check for the mute key to be pressed as an indicator
+ * to enter fastboot mode in preboot mode. since the
+ * AVR sends an initial boot indication key, we have to
+ * filter that out first. we also filter out and volume
+ * up/down keys and don't care if we spin until those
+ * stop (it's almost impossible to make the volume
+ * up/down key events repeat indefinitely since they
+ * involve actually rotating the top of the sphere
+ * without pause).
+ */
+ while (1) {
+ if (avr_get_key(&key_code))
+ break;
+ if (key_code == AVR_KEY_EVENT_EMPTY)
+ break;
+ if (key_code == (AVR_KEY_MUTE | AVR_KEY_EVENT_DOWN)) {
+ avr_led_set_all(&red);
+ avr_led_set_mute(&red);
+ is_pressed = 1;
+ key_pressed_start_time = get_timer(0);
+ /* don't wait for key release */
+ break;
+ }
+ }
+
+ /* All black to indicate we've made our decision to boot. */
+ if (!is_pressed) {
+ serial_printf("\tsetting to black\n");
+ avr_led_set_all(&black);
+ avr_led_set_mute(&black);
+ }
+
+ printf("Returning key pressed %s\n", is_pressed ? "true" : "false");
+ return is_pressed;
+}
+
+/* we only check for a long press of mute as an indicator to
+ * go into recovery. due to i2c errors if we poll too fast,
+ * we only poll every 100ms right now.
+ */
+enum fbt_reboot_type board_fbt_key_command(void)
+{
+ unsigned long time_elapsed;
+
+ if (!avr_detected)
+ return FASTBOOT_REBOOT_NONE;
+
+ time_elapsed = get_timer(last_time);
+ if (time_elapsed > KEY_CHECK_POLLING_INTERVAL_MS) {
+ u8 key_code;
+
+ last_time = get_timer(0);
+
+ if (avr_get_key(&key_code))
+ return FASTBOOT_REBOOT_NONE;
+
+ if (key_code == (AVR_KEY_MUTE | AVR_KEY_EVENT_DOWN)) {
+ /* key down start */
+ key_pressed_start_time = last_time;
+ printf("%s: mute key down starting at time %lu\n",
+ __func__, key_pressed_start_time);
+ } else if (key_code == AVR_KEY_MUTE) {
+ /* key down end, before hold time satisfied */
+ printf("%s: mute key released within %lu ms\n",
+ __func__, last_time - key_pressed_start_time);
+ key_pressed_start_time = 0;
+ avr_led_set_all(&red);
+ } else if (key_pressed_start_time) {
+ unsigned long time_down;
+ time_down = last_time - key_pressed_start_time;
+
+ if (time_down > (RECOVERY_KEY_HOLD_TIME_SECS * 1000)) {
+ printf("%s: mute key down more than %u seconds,"
+ " starting recovery\n",
+ __func__, RECOVERY_KEY_HOLD_TIME_SECS);
+ return FASTBOOT_REBOOT_RECOVERY_WIPE_DATA;
+ }
+ printf("%s: mute key still down after %lu ms\n",
+ __func__, time_down);
+ /* toggle led ring red and black while down
+ to give user some feedback */
+ if ((time_down / KEY_CHECK_POLLING_INTERVAL_MS) & 1)
+ avr_led_set_all(&red);
+ else
+ avr_led_set_all(&black);
+ }
+ }
+ return FASTBOOT_REBOOT_NONE;
+}
+
+void board_fbt_start(void)
+{
+ /* in case we entered fastboot by request from ADB or other
+ * means that we couldn't detect in board_fbt_key_command(),
+ * make sure the LEDs are set to red to indicate fastboot mode
+ */
+ if (avr_detected) {
+ avr_led_set_mute(&red);
+ avr_led_set_all(&red);
+ }
+}
+
+void board_fbt_end(void)
+{
+ if (avr_detected) {
+ /* to match spec, put avr into boot animation mode. */
+ avr_led_set_mode(AVR_LED_MODE_BOOT_ANIMATION);
+ }
+}
+
+struct fbt_partition {
+ const char *name;
+ const char *type;
+ unsigned size_kb;
+};
+
+/* For the 16GB eMMC part used in Tungsten, the erase group size is 512KB.
+ * So every partition should be at least 512KB to make it possible to use
+ * the mmc erase operation when doing 'fastboot erase'.
+ * However, the xloader is an exception because in order for the OMAP4 ROM
+ * bootloader to find it, it must be at offset 0KB, 128KB, 256KB, or 384KB.
+ * Since the partition table is at 0KB, we choose 128KB. Special care
+ * must be kept to prevent erase the partition table when/if the xloader
+ * partition is being erased.
+ */
+struct fbt_partition fbt_partitions[] = {
+ { "--ptable", NULL, 17}, /* partition table in
+ * first 34 sectors */
+ { "environment", "raw", 95 }, /* partition used to u-boot environment,
+ * which is also where we store
+ * oem lock/unlock state. size
+ * must match CONFIG_ENV_SIZE.
+ */
+ { "crypto", "raw", 16}, /* 16KB partition for crypto keys.
+ * used when userdata is encrypted.
+ */
+ { "xloader", "raw", 384 }, /* must start at 128KB offset into eMMC
+ * for ROM bootloader to find it.
+ * pad out to fill whole erase group */
+ { "bootloader", "raw", 512 }, /* u-boot, one erase group in size */
+ { "device_info", "raw", 512 }, /* device specific info like MAC
+ * addresses. read-only once it has
+ * been written to. bootloader parses
+ * this at boot and sends the contents
+ * to the kernel via cmdline args.
+ */
+ { "bootloader2", "raw", 512 }, /* u-boot, alternate copy */
+ { "misc", "raw", 512 }, /* misc partition used by recovery for
+ * storing parameters in the case of a
+ * power failure during recovery
+ * operation.
+ */
+ { "recovery", "boot", 8*1024 },
+ { "boot", "boot", 8*1024 },
+ { "efs", "ext4", 8*1024 }, /* for factory programmed keys,
+ * minimum size for a ext4 fs is
+ * about 8MB
+ */
+ { "system", "ext4", 1024*1024 },
+ { "cache", "ext4", 512*1024 },
+ { "userdata", "ext4", 0},
+ { 0, 0, 0 },
+};
+
+void board_fbt_finalize_bootargs(char* args, size_t buf_sz) {
+ int used = strlen(args);
+ int i;
+ int bgap_threshold_t_hot = 83000; /* 83 deg C */
+ int bgap_threshold_t_cold = 76000; /* 76 deg C */
+
+ for (i = 0; i < ARRAY_SIZE(mac_defaults); ++i) {
+ u8 m[6];
+ char mac[18];
+
+ if (strstr(args, mac_defaults[i].name))
+ continue;
+
+ generate_default_mac_addr(mac_defaults[i].salt, m);
+ snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+ m[5], m[4], m[3], m[2], m[1], m[0]);
+ mac[sizeof(mac) - 1] = 0;
+ used += snprintf(args + used,
+ buf_sz - used,
+ " %s=%s",
+ mac_defaults[i].name,
+ mac);
+ }
+
+ /* Add board_id */
+ used += snprintf(args + used,
+ buf_sz - used,
+ " board_steelhead.steelhead_hw_rev=%d",
+ steelhead_hw_rev);
+
+ /* Add bandgap threshold temperature based on board_id.
+ * Units before DVT2 didn't have a thermal rework so
+ * we'll throttle at a lower temperature to try to
+ * prevent damage to the OMAP.
+ */
+ if (steelhead_hw_rev < STEELHEAD_REV_DVT2) {
+ bgap_threshold_t_hot = 64000; /* 64 deg C */
+ bgap_threshold_t_cold = 61000; /* 61 deg C */
+ }
+ snprintf(args + used,
+ buf_sz - used,
+ " omap_temp_sensor.bgap_threshold_t_hot=%d"
+ " omap_temp_sensor.bgap_threshold_t_cold=%d",
+ bgap_threshold_t_hot, bgap_threshold_t_cold);
+
+ args[buf_sz-1] = 0;
+
+ /* this is called just before booting normal image. we
+ * use opportunity to start boot animation.
+ */
+ board_fbt_end();
+}
+
+struct TOC_entry {
+ uint32_t start_offset;
+ uint32_t size;
+ uint8_t reserved[8];
+ uint32_t load_address;
+ char filename[12];
+};
+
+#define NUM_MPKH_REGISTERS 8
+struct MPKH_info {
+ char tag[4];
+ uint32_t mpkh[NUM_MPKH_REGISTERS];
+};
+
+int board_fbt_handle_flash(disk_partition_t *ptn,
+ struct cmd_fastboot_interface *priv)
+{
+ struct TOC_entry *toc_p;
+ void *end_ptr;
+ void *image_ptr;
+ struct MPKH_info *mpkh_ptr;
+ struct MPKH_info my_mpkh;
+ struct ctrl_id *ctrl;
+ int i;
+
+ /* We support flashing a MLO "package" that has more than one
+ * MLO image, each signed with a different MPK for a different
+ * HS part. We check if the MLO image has a MPKH_info structure
+ * appended to it that has the tag, and the 8 MPKH values for
+ * us to compare against our own MPKH register. If no MPKH_info,
+ * we'll just go ahead and accept it presuming the user knows
+ * what they're doing or it's an old MLO file. If the MPKH_info
+ * structure exists, we'll compare the MPK info and if no
+ * match, we'll try the next image in the downloaded file if
+ * there is one.
+ */
+ if ((get_device_type() != HS_DEVICE) ||
+ (strcmp((char *)ptn->name, "xloader"))) {
+ /* not an HS part, or not flashing the xloader, just
+ * go ahead and flash it.
+ */
+ return 0;
+ }
+
+
+ /* read the MPKH registers into a local struct for easy comparison
+ * with the MKPH_info we expect to find appended to the end
+ * of the MLO image, if any.
+ */
+ ctrl = (struct ctrl_id *)CTRL_BASE;
+ my_mpkh.tag[0] = 'M';
+ my_mpkh.tag[1] = 'P';
+ my_mpkh.tag[2] = 'K';
+ my_mpkh.tag[3] = 'H';
+ for (i = 0; i < NUM_MPKH_REGISTERS; i++) {
+ my_mpkh.mpkh[i] = ((uint32_t*)&ctrl->core_std_fuse_mpk_0)[i];
+ }
+
+ end_ptr = priv->transfer_buffer + priv->d_bytes;
+ image_ptr = priv->transfer_buffer;
+
+ printf("Verifying xloader image before flashing\n");
+ do {
+ printf("Checking image at offset 0x%x... ",
+ image_ptr - (void*)priv->transfer_buffer);
+ toc_p = (struct TOC_entry *)image_ptr;
+ if ((void*)(toc_p + 1) >= end_ptr) {
+ printf("Image too small, not flashing\n");
+ snprintf(priv->response, sizeof(priv->response),
+ "FAILImage too small\n");
+ return -1;
+ }
+ if (strcmp("MLO", toc_p->filename)) {
+ /* downloaded image does not have the MLO as the first
+ * TOC entry like we expect, or is too small,
+ * return error
+ */
+ printf("Not an MLO image, not flashing\n");
+ snprintf(priv->response, sizeof(priv->response),
+ "FAILxloader requires MLO image");
+ return -1;
+ }
+ /* check for special case of a simple MLO image with
+ * no MPKH_info appended to it.
+ */
+ if (toc_p->start_offset + toc_p->size == priv->d_bytes) {
+ printf(" No MPKH_info in image, "
+ "accepting unconditionally\n");
+ return 0;
+ }
+ mpkh_ptr = (struct MPKH_info *)(image_ptr +
+ toc_p->start_offset +
+ toc_p->size);
+ if ((void*)(mpkh_ptr + 1) <= end_ptr) {
+ if (memcmp(&my_mpkh, mpkh_ptr, sizeof(my_mpkh)) == 0) {
+ printf(" MPKH match, using this image\n");
+ priv->image_start_ptr = image_ptr;
+ priv->d_bytes = (toc_p->start_offset +
+ toc_p->size);
+ return 0;
+ }
+ printf(" MPKH mismatch, not using this image\n");
+#ifdef DEBUG
+ for (i = 0; i < NUM_MPKH_REGISTERS; i++) {
+ printf("MPKH[%d]: 0x%08x %s 0x%08x\n",
+ i, my_mpkh.mpkh[i],
+ (my_mpkh.mpkh[i] == mpkh_ptr->mpkh[i]) ?
+ "==" : "!=", mpkh_ptr->mpkh[i]);
+ }
+#endif
+ }
+ /* go to the next image, if there is one */
+ image_ptr += (toc_p->start_offset + toc_p->size +
+ sizeof(*mpkh_ptr));
+ } while (image_ptr < end_ptr);
+ snprintf(priv->response, sizeof(priv->response),
+ "FAILMLO verification failed");
+ return -1;
+}
+
+
+#ifdef CONFIG_MFG
+static void set_default_mac_env_vars(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mac_defaults); ++i) {
+ u8 m[6];
+ char tmp_buf[18];
+ generate_default_mac_addr(mac_defaults[i].salt, m);
+ snprintf(tmp_buf, sizeof(tmp_buf),
+ "%02x:%02x:%02x:%02x:%02x:%02x",
+ m[5], m[4], m[3], m[2], m[1], m[0]);
+ tmp_buf[sizeof(tmp_buf) - 1] = 0;
+ setenv(mac_defaults[i].name, tmp_buf);
+ }
+}
+#endif
+
+int board_late_init(void)
+{
+ char tmp_buf[17];
+ u64 id_64;
+
+ dieid_num_r();
+
+ generate_default_64bit_id(serial_no_salt, &id_64);
+ snprintf(tmp_buf, sizeof(tmp_buf), "%016llx", id_64);
+ tmp_buf[sizeof(tmp_buf)-1] = 0;
+ setenv("fbt_id#", tmp_buf);
+
+#ifdef CONFIG_MFG
+ set_default_mac_env_vars();
+#endif
+
+ fbt_preboot();
+
+ return 0;
+}
+
+struct gpio_name_mapping {
+ const char* name;
+ int num;
+};
+
+int name_to_gpio(const char* name) {
+ static const struct gpio_name_mapping map[] = {
+ { "aud_intfc_en", 40 },
+ { "hdmi_ls_oe", 41 },
+ { "aud_rstn", 42 },
+ { "wlan_en", 43 },
+ { "aud_pdn", 44 },
+ { "bt_host_wake_bt", 45 },
+ { "bt_en", 46 },
+ { "bt_wakeup_host", 47 },
+ { "ui_avr_rst_n_a", 48 },
+ { "ui_avr_int_n", 49 },
+ { "bt_rst_n", 52 },
+ { "wlan_irq_n", 53 },
+ { "hdmi_ct_cp_hpd", 60 },
+ { "hdmi_hpd", 63 },
+ { "hdmi_cec", 64 },
+ { "spdif", 111 },
+ { "nfc_dl_mode", 162 },
+ { "nfc_en", 163 },
+ { "nfc_irq", 164 },
+ };
+ int i;
+ const char* tmp;
+
+ for (i = 0; i < ARRAY_SIZE(map); ++i) {
+ if (!strcmp(name, map[i].name))
+ return map[i].num;
+ }
+
+ for (tmp = name; *tmp; ++tmp)
+ if ((*tmp < '0') || (*tmp > '9'))
+ return -1;
+
+ return simple_strtoul(name, NULL, 10);
+}
diff --git a/board/google/tungsten/tungsten_mux_data.h b/board/google/tungsten/tungsten_mux_data.h
new file mode 100644
index 0000000..7e80ae3
--- /dev/null
+++ b/board/google/tungsten/tungsten_mux_data.h
@@ -0,0 +1,95 @@
+/*
+ * (C) Copyright 2011
+ * Google, Inc.
+ * (C) Copyright 2010
+ * Texas Instruments Incorporated, <www.ti.com>
+ *
+ * Author :
+ * Mike J Chen <mjchen@google.com>
+ *
+ * Balaji Krishnamoorthy <balajitk@ti.com>
+ * Aneesh V <aneesh@ti.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 _TUNGSTEN_MUX_DATA_H_
+#define _TUNGSTEN_MUX_DATA_H_
+
+#include <asm/arch/mux_omap4.h>
+
+static const struct pad_conf_entry core_padconf_array_non_essential[] = {
+ /* Needed in both regular and MFG build, to communicate
+ * with the AVR and proximity sensor. For now, we're
+ * going to let the kernel setup the mux conf for anything
+ * it uses and do the minimum in the bootloader.
+ */
+ {I2C2_SCL, (IEN | M0)},
+ {I2C2_SDA, (IEN | M0)},
+ {GPMC_A24, (M3)}, /* gpio_48 - UI_AVR_RST_N_A */
+ {FREF_CLK2_OUT, (IEN | PTD | M3)}, /* gpio_182 - board_id_0 */
+ {GPMC_NCS4, (IEN | PTD | M3)}, /* gpio_101 - board_id_1 */
+ {KPD_COL3, (IEN | PTD | M3)}, /* gpio_171 - board_id_2 */
+
+#ifdef CONFIG_MFG
+ /* during the first stage of manufacturing diagnostics, many pins are
+ * configured as GPIOs for basic connectivity testing. This section
+ * makes sure pins are properly configured as either inputs or outputs
+ * for diagnostics. */
+ {GPMC_A16, (PTD | M3)}, /* gpio_40 - aud_intfc_en */
+ {GPMC_A17, (PTD | M3)}, /* gpio_41 - hdmi_ls_oe */
+ {GPMC_A18, (PTD | M3)}, /* gpio_42 - aud_rstn */
+ {GPMC_A19, (PTD | M3)}, /* gpio_43 - wlan_en */
+ {GPMC_A20, (PTD | M3)}, /* gpio_44 - aud_pdn */
+ {GPMC_A21, (PTD | M3)}, /* gpio_45 - bt_host_wake_bt */
+ {GPMC_A22, (PTD | M3)}, /* gpio_46 - bt_en */
+ {GPMC_A23, (IEN | PTD | M3)}, /* gpio_47 - bt_wakeup_host */
+ {GPMC_A24, (M3)}, /* gpio_48 - ui_avr_rst_n_a */
+ {GPMC_A25, (IEN | PTU | M3)}, /* gpio_49 - ui_avr_int_n */
+ {GPMC_NCS2, (PTD | M3)}, /* gpio_52 - bt_rst_n */
+ {GPMC_NCS3, (IEN | PTU | M3)}, /* gpio_53 - wlan_irq_n */
+ {GPMC_NBE1, (PTD | M3)}, /* gpio_60 - hdmi_ct_cp_hpd */
+ {HDMI_HPD, (IEN | PTD | M3)}, /* gpio_63 - hdmi_hpd */
+ {HDMI_CEC, (IEN | PTU | M3)}, /* gpio_64 - hdmi_cec */
+ {ABE_MCBSP2_DR, (PTD | M3)}, /* gpio_111 - spdif */
+ {USBB2_ULPITLL_DAT1, (PTD | M3)}, /* gpio_162 - nfc_dl_mode */
+ {USBB2_ULPITLL_DAT2, (PTD | M3)}, /* gpio_163 - nfc_en */
+ {USBB2_ULPITLL_DAT3, (PTD | M3)}, /* gpio_164 - nfc_irq */
+
+ /* during mfg diags, all I2C pins should be set up for I2C. No need to
+ * set up I2C1 pins. It's power on reset state is to be I2C and they
+ * can have no other mode.
+ */
+ {I2C3_SCL, (IEN | M0)},
+ {I2C3_SDA, (IEN | M0)},
+ {I2C4_SCL, (IEN | M0)},
+ {I2C4_SDA, (IEN | M0)},
+#endif
+};
+
+static const struct pad_conf_entry core_padconf_array_disable_board_id[] = {
+ {FREF_CLK2_OUT, (SAFE_MODE)}, /* gpio_182 - board_id_0 */
+ {GPMC_NCS4, (SAFE_MODE)}, /* gpio_101 - board_id_1 */
+ {KPD_COL3, (SAFE_MODE)}, /* gpio_171 - board_id_2 */
+};
+
+static const struct pad_conf_entry wkup_padconf_array_non_essential[] = {
+};
+
+#endif /* _TUNGSTEN_MUX_DATA_H_ */
diff --git a/boards.cfg b/boards.cfg
index 8a5bfc1..3d47843 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -178,6 +178,7 @@
devkit8000 arm armv7 devkit8000 timll omap3
omap4_panda arm armv7 panda ti omap4
omap4_sdp4430 arm armv7 sdp4430 ti omap4
+omap4_tungsten arm armv7 tungsten google omap4
s5p_goni arm armv7 goni samsung s5pc1xx
smdkc100 arm armv7 smdkc100 samsung s5pc1xx
origen arm armv7 origen samsung s5pc2xx
diff --git a/build_server.sh b/build_server.sh
new file mode 100755
index 0000000..9363826
--- /dev/null
+++ b/build_server.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+# This build script is used by the build server.
+# It's supposed to be executed in the directory where it lives.
+
+set -x -e
+
+if [ -z $BUILD_CONFIG ]; then
+ echo "Please set BUILD_CONFIG!"
+ exit 2
+fi
+
+if [ -z $BUILD_OUTPUT ]; then
+ echo "Please set output dir BUILD_OUTPUT!"
+ exit 2
+fi
+
+if [ -z $BUILD_JOBS ]; then
+ BUILD_JOBS=10
+fi
+
+FILES_TO_ARCHIVE="u-boot.bin"
+if [ "$BUILD_CONFIG" = "omap4_tungsten_config" ]; then
+FILES_TO_ARCHIVE="u-boot.img MLO spl/u-boot-spl.bin"
+fi
+
+export ARCH=arm
+export CROSS_COMPILE=arm-eabi-
+
+make clean
+make $BUILD_CONFIG
+make -j $BUILD_JOBS
+mkdir -p $BUILD_OUTPUT
+cp -f $FILES_TO_ARCHIVE $BUILD_OUTPUT
+
+if [ "$BUILD_CONFIG" = "omap4_tungsten_config" ]; then
+make clean
+make MFG=1 $BUILD_CONFIG
+make MFG=1 -j $BUILD_JOBS
+cp -f u-boot.img $BUILD_OUTPUT/factory_u-boot.img
+fi
+
+
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index f96563b..3469a63 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -443,7 +443,7 @@
return 0;
}
-static void wait_for_bb(void)
+static void wait_for_bb (void)
{
int timeout = I2C_TIMEOUT;
u16 stat;
diff --git a/include/configs/omap4_tungsten.h b/include/configs/omap4_tungsten.h
new file mode 100644
index 0000000..2c72139
--- /dev/null
+++ b/include/configs/omap4_tungsten.h
@@ -0,0 +1,358 @@
+/*
+ * (C) Copyright 2011
+ * Google, Inc.
+ *
+ * Based on omap4_panda.h:
+ * (C) Copyright 2010
+ * Texas Instruments Incorporated.
+ * Steve Sakoman <steve@sakoman.com>
+ *
+ * Configuration settings for the Google OMAP4 Tungsten board.
+ * Based on Panda board settings.
+ *
+ * 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 __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * High Level Configuration Options
+ */
+#define CONFIG_ARMV7 1 /* This is an ARM V7 CPU core */
+#define CONFIG_OMAP 1 /* in a TI OMAP core */
+#define CONFIG_OMAP44XX 1 /* which is a 44XX */
+#define CONFIG_OMAP4430 1 /* which is in a 4430 */
+#define CONFIG_ARCH_CPU_INIT
+
+#define CONFIG_TUNGSTEN 1 /* working with Tungsten */
+#define CONFIG_FASTBOOT /* Android fast boot */
+
+/* Get CPU defs */
+#include <asm/arch/cpu.h>
+#include <asm/arch/omap4.h>
+#include <asm/sizes.h>
+
+/* Display CPU and Board Info */
+#define CONFIG_DISPLAY_CPUINFO 1
+#define CONFIG_DISPLAY_BOARDINFO 1
+
+/* Clock Defines */
+#define V_OSCK 38400000 /* Clock output from T2 */
+#define V_SCLK V_OSCK
+
+#undef CONFIG_USE_IRQ /* no support for IRQs */
+
+#define CONFIG_OF_LIBFDT 1
+
+#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS 1
+#define CONFIG_INITRD_TAG 1
+
+/*
+ * Size of malloc() pool
+ * Total Size Environment - 95KB - must match partition table
+ * Malloc - add 128KB
+ */
+#define CONFIG_ENV_IS_IN_BLKDEV
+#define CONFIG_SYS_ENV_BLKDEV "mmc0"
+#define CONFIG_ENV_SIZE_KB (95)
+#define CONFIG_ENV_SIZE ((CONFIG_ENV_SIZE_KB) << 10)
+#define CONFIG_MALLOC_SIZE_KB (128)
+#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + ((CONFIG_MALLOC_SIZE_KB) << 10))
+/* Vector Base */
+#define CONFIG_SYS_CA9_VECTOR_BASE SRAM_ROM_VECT_BASE
+
+/*
+ * Hardware drivers
+ */
+
+/*
+ * serial port - NS16550 compatible
+ */
+#define V_NS16550_CLK 48000000
+
+#define CONFIG_SYS_NS16550
+#define CONFIG_SYS_NS16550_SERIAL
+#define CONFIG_SYS_NS16550_REG_SIZE (-4)
+#define CONFIG_SYS_NS16550_CLK V_NS16550_CLK
+#define CONFIG_CONS_INDEX 3
+#define CONFIG_SYS_NS16550_COM3 UART3_BASE
+
+/*
+ * select serial console configuration
+ */
+#define CONFIG_SERIAL3 3 /* UART3 on Tungsten */
+#define CONFIG_BAUDRATE 115200
+#define CONFIG_SYS_BAUDRATE_TABLE {4800, 9600, 19200, 38400, 57600,\
+ 115200}
+
+/* I2C */
+#define CONFIG_HARD_I2C 1
+#define CONFIG_SYS_I2C_SPEED 400000
+#define CONFIG_SYS_I2C_SLAVE 1
+#define CONFIG_SYS_I2C_BUS 0
+#define CONFIG_SYS_I2C_BUS_SELECT 1
+#define CONFIG_DRIVER_OMAP34XX_I2C 1
+#define CONFIG_I2C_MULTI_BUS 1
+
+/* TWL6030 - initialize musb detection */
+#define CONFIG_TWL6030_POWER
+
+/* MMC */
+#define CONFIG_GENERIC_MMC 1
+#define CONFIG_MMC 1
+#define CONFIG_OMAP_HSMMC 1
+#define CONFIG_EFI_PARTITION 1
+#define CONFIG_MIN_PARTITION_NUM 1
+#define CONFIG_MMC_DEV 0
+#define CONFIG_OMAP_MMC_USE_DMA_WRITES
+
+/* USB */
+#define CONFIG_MUSB_UDC 1
+#define CONFIG_USB_OMAP3 1
+#define CONFIG_MUSB_RXFIFO_DOUBLE 1
+#define CONFIG_MUSB_DMA_MODE1 1
+
+/* Disable some non-essential dpll and clock setup because it
+ * increases power consumption and heat significantly. We'll let
+ * the kernel initialize these.
+ */
+#define CONFIG_SKIP_NON_ESSENTIAL_CLOCKS 1
+
+/* Specify lower MPU DPLL freq to reduce power consumption and heat
+ * in the bootloader or else it's way unstable with TI's default settings.
+ */
+#define CONFIG_FORCE_TPS62361 /* always use TPS62361, don't do runtime
+ check of omap4430 vs omap4460 */
+#define CONFIG_OMAP4460_MPU_DPLL mpu_dpll_params_700mhz
+#define CONFIG_OMAP4430_ES1_0_MPU_DPLL mpu_dpll_params_700mhz
+#define CONFIG_OMAP4430_non_ES1_0_MPU_DPLL mpu_dpll_params_700mhz
+
+/* Make sure that the ABE is clocked off the sysclk and not the 32KHz clock.
+ * Timers used for remote synchronization as well as the external fref fed to
+ * the TAS5713 can only source from sysclk, and must be phase locked with the
+ * McBSP output (which is fed from the ABE)
+ */
+#define CONFIG_SYS_OMAP4_ABE_SYSCK 1
+
+/* Fastboot settings
+ */
+/* Another macro may also be used or instead used to take care of the case
+ * where fastboot is started at boot (to be incorporated) based on key press
+ */
+#define CONFIG_CMD_FASTBOOT
+#define CONFIG_FASTBOOT_TRANSFER_BUFFER (OMAP44XX_DRAM_ADDR_SPACE_START + SZ_16M)
+#define CONFIG_FASTBOOT_TRANSFER_BUFFER_SIZE (SZ_512M - SZ_16M)
+/* Fastboot product name */
+#define FASTBOOT_PRODUCT_NAME "steelhead"
+/* Fastboot reboot paramenter address, it's currently put at
+ * PUBLIC_SAR_RAM1_FREE
+ */
+#define FASTBOOT_REBOOT_PARAMETER_ADDR (0x4a326000 + 0xA0C)
+/* Address of the kernel's ramconsole so we can dump it. This is
+ * used by the 'fastboot oem kmsg' command. It needs to be done
+ * early in fastboot (before large amount of transfer buffer is used,
+ * since they overlap).
+ */
+#define CONFIG_FASTBOOT_RAMCONSOLE_START (OMAP44XX_DRAM_ADDR_SPACE_START + SZ_512M)
+
+/* device to use */
+#define FASTBOOT_BLKDEV "mmc0"
+/* Use HS */
+#define USB_BCD_VERSION 0x0200
+
+#define CONFIG_USB_DEVICE 1
+/* Change these to suit your needs */
+#define CONFIG_USBD_VENDORID 0x18d1
+#define CONFIG_USBD_PRODUCTID 0x2c10
+#define CONFIG_USBD_MANUFACTURER "Google"
+#define CONFIG_USBD_PRODUCT_NAME "Tungsten"
+
+/* Flash */
+#define CONFIG_SYS_NO_FLASH 1
+
+/* commands to include */
+#include <config_cmd_default.h>
+
+/* Enabled commands */
+#define CONFIG_CMD_I2C /* I2C serial bus support */
+#define CONFIG_CMD_MMC /* MMC support */
+#define CONFIG_CMD_ENV /* Environment support */
+
+/* Disabled commands */
+#undef CONFIG_CMD_EXT2 /* EXT2 Support */
+#undef CONFIG_CMD_FAT /* FAT support */
+#undef CONFIG_CMD_NET
+#undef CONFIG_CMD_NFS
+#undef CONFIG_CMD_FPGA /* FPGA configuration Support */
+#undef CONFIG_CMD_IMLS /* List all found images */
+#undef CONFIG_CMD_LOADB /* don't need loading binary over serial */
+#undef CONFIG_CMD_LOADS /* don't need loading s-record over serial */
+
+/*
+ * Environment setup
+ */
+#define CONFIG_BOOTDELAY 0
+/* use preboot to detect key press for fastboot */
+#define CONFIG_PREBOOT
+#define CONFIG_BOOTCOMMAND "booti"
+#ifdef CONFIG_MFG
+/*
+ * Manufacturing build:
+ * + Force the system into fastboot mode initially, and make sure that fastboot
+ * will never load a kernel from MMC. The test harness can then force the
+ * system into the diagnostic console by either executing "fastboot continue"
+ * from the host, or by sending a CTRL-C via the serial console.
+ *
+ * Note: this was originally being done by manipulating CONFIG_BOOTCOMMAND and
+ * CONFIG_PREBOOT, but that led to unforseen issues with the MFG bootcmd and
+ * preboot settings getting saved in the environment. Rather than attempting
+ * to layer hack after hack on top of that approach trying to get things to
+ * behave, we just introduce a new #def which gets obeyed by main.c
+ *
+ * + Turn on the gpio console commands.
+ */
+#define CONFIG_BOOTCOMMAND_FORCE_OVERRIDE "fastboot"
+#define CONFIG_CMD_GPIO
+#define CONFIG_MMC_SAMSUNG_SMART
+#define CONFIG_CMD_BLK
+#define CONFIG_SYS_LONGHELP 1
+#else
+#undef CONFIG_SYS_LONGHELP /* undef to save memory */
+#endif
+
+/* overloaded in board/google/tungsten/tungsten.c */
+#ifndef __ASSEMBLY__
+int name_to_gpio(const char *name);
+#endif
+#define name_to_gpio(name) name_to_gpio(name)
+
+#define CONFIG_ENV_OVERWRITE
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "console=ttyS2,115200n8\0" \
+ "usbtty=cdc_acm\0" \
+ "fastboot_unlocked=1\0"
+
+#define CONFIG_AUTO_COMPLETE 1
+
+/*
+ * Miscellaneous configurable options
+ */
+
+#undef CONFIG_SYS_HUSH_PARSER /* use "hush" command parser */
+#undef CONFIG_SYS_PROMPT_HUSH_PS2
+#define CONFIG_SYS_PROMPT "Tungsten # "
+#define CONFIG_SYS_CBSIZE 256
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
+ sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_MAXARGS 16
+/* Boot Argument Buffer Size */
+#define CONFIG_SYS_BARGSIZE (CONFIG_SYS_CBSIZE)
+
+/*
+ * memtest setup
+ */
+#define CONFIG_SYS_MEMTEST_START 0x80000000
+#define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + (32 << 20))
+
+/* Default load address */
+#define CONFIG_SYS_LOAD_ADDR 0x80000000
+
+/* Use General purpose timer 1 */
+#define CONFIG_SYS_TIMERBASE GPT2_BASE
+#define CONFIG_SYS_PTV 2 /* Divisor: 2^(PTV+1) => 8 */
+#define CONFIG_SYS_HZ 1000
+
+/*
+ * Stack sizes
+ *
+ * The stack sizes are set up in start.S using the settings below
+ */
+#define CONFIG_STACKSIZE (128 << 10) /* Regular stack */
+#ifdef CONFIG_USE_IRQ
+#define CONFIG_STACKSIZE_IRQ (4 << 10) /* IRQ stack */
+#define CONFIG_STACKSIZE_FIQ (4 << 10) /* FIQ stack */
+#endif
+
+/* which initialization functions to call for this board */
+#define BOARD_LATE_INIT 1
+
+/*
+ * SDRAM Memory Map
+ * Even though we use two CS all the memory
+ * is mapped to one contiguous block
+ */
+#define CONFIG_NR_DRAM_BANKS 1
+
+#define CONFIG_SYS_SDRAM_BASE 0x80000000
+#define CONFIG_SYS_INIT_RAM_ADDR 0x4030D800
+#define CONFIG_SYS_INIT_RAM_SIZE 0x800
+#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \
+ CONFIG_SYS_INIT_RAM_SIZE - \
+ GENERATED_GBL_DATA_SIZE)
+
+#ifndef CONFIG_SYS_L2CACHE_OFF
+#define CONFIG_SYS_L2_PL310 1
+#define CONFIG_SYS_PL310_BASE 0x48242000
+#endif
+
+/* Defines for SDRAM init */
+#ifndef CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS
+#define CONFIG_SYS_AUTOMATIC_SDRAM_DETECTION
+#define CONFIG_SYS_DEFAULT_LPDDR2_TIMINGS
+#endif
+
+/* Defines for SPL */
+#define CONFIG_SPL
+#define CONFIG_SPL_TEXT_BASE 0x40304350
+#define CONFIG_SPL_MAX_SIZE (38 * 1024)
+#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK
+
+#define CONFIG_SPL_BSS_START_ADDR 0x80000000
+#define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KB */
+
+#define CONFIG_SPL_VERIFY_IMAGE
+
+/* These values need to match the partition table in tungsten.c */
+/* emmc offset: 0x80000 */
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 0x400
+/* emmc offset: 0x180000 */
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_ALTERNATE_SECTOR 0xc00
+#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS 0x400 /* 512 KB */
+
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_LIBDISK_SUPPORT
+#define CONFIG_SPL_I2C_SUPPORT
+#define CONFIG_SPL_MMC_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_LDSCRIPT "arch/arm/cpu/armv7/omap-common/u-boot-spl.lds"
+
+/*
+ * 1MB into the SDRAM to allow for SPL's bss at the beginning of SDRAM
+ * 64 bytes before this address should be set aside for u-boot.img's
+ * header. That is 0x800FFFC0--0x80100000 should not be used for any
+ * other needs.
+ */
+#define CONFIG_SYS_TEXT_BASE 0x80100000
+
+#endif /* __CONFIG_H */