copper: load device tree blob

Update LK to find the device tree from the device tree
table present in the boot.img.

Change-Id: I097908c20a6db954e92965df748b1061ccba17dd
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index f81a44b..44e212b 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -60,6 +60,7 @@
 #include "sparse_format.h"
 #include "mmc.h"
 #include "devinfo.h"
+#include "board.h"
 
 #include "scm.h"
 
@@ -77,6 +78,27 @@
 #define FASTBOOT_MODE   0x77665500
 
 #if DEVICE_TREE
+#define DEV_TREE_SUCCESS        0
+#define DEV_TREE_MAGIC          "QCDT"
+#define DEV_TREE_VERSION        1
+#define DEV_TREE_HEADER_SIZE    12
+
+
+struct dt_entry{
+	uint32_t platform_id;
+	uint32_t variant_id;
+	uint32_t soc_rev;
+	uint32_t offset;
+	uint32_t size;
+};
+
+struct dt_table{
+	uint32_t magic;
+	uint32_t version;
+	unsigned num_entries;
+};
+
+struct dt_entry * get_device_tree_ptr(struct dt_table *);
 int update_device_tree(const void *, char *, void *, unsigned);
 #endif
 
@@ -406,6 +428,7 @@
 #define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
 
 static unsigned char buf[4096]; //Equal to max-supported pagesize
+static unsigned char dt_buf[4096];
 
 int boot_linux_from_mmc(void)
 {
@@ -421,6 +444,14 @@
 	unsigned kernel_actual;
 	unsigned ramdisk_actual;
 	unsigned imagesize_actual;
+	unsigned second_actual = 0;
+	unsigned dt_actual = 0;
+
+#if DEVICE_TREE
+	struct dt_table *table;
+	struct dt_entry *dt_entry_ptr;
+	unsigned dt_table_offset;
+#endif
 
 	uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
 	if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
@@ -466,7 +497,10 @@
 		image_addr = (unsigned char *)target_get_scratch_address();
 		kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
 		ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
-		imagesize_actual = (page_size + kernel_actual + ramdisk_actual);
+		second_actual = ROUND_TO_PAGE(hdr->second_size, page_mask);
+		dt_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
+		imagesize_actual = (page_size + kernel_actual + ramdisk_actual + second_actual +
+							dt_actual);
 
 		offset = 0;
 
@@ -500,10 +534,36 @@
 			}
 		}
 
-		/* Move kernel and ramdisk to correct address */
+		/* Move kernel, ramdisk and device tree to correct address */
 		memmove((void*) hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size);
 		memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);
 
+		#if DEVICE_TREE
+		if(hdr->dt_size) {
+			table = (struct dt_table*) dt_buf;
+			dt_table_offset = (image_addr + page_size + kernel_actual + ramdisk_actual + second_actual);
+
+			memmove((void *) dt_buf, (char *)dt_table_offset, page_size);
+
+			/* Restriction that the device tree entry table should be less than a page*/
+			ASSERT(((table->num_entries * sizeof(struct dt_entry))+ DEV_TREE_HEADER_SIZE) < hdr->page_size);
+
+			/* Validate the device tree table header */
+			if((table->magic != DEV_TREE_MAGIC) && (table->version != DEV_TREE_VERSION)) {
+				dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");
+				return -1;
+			}
+
+			/* Find index of device tree within device tree table */
+			if((dt_entry_ptr = get_device_tree_ptr(table)) == NULL){
+				dprintf(CRITICAL, "ERROR: Device Tree Blob cannot be found\n");
+				return -1;
+			}
+
+			/* Read device device tree in the "tags_add */
+			memmove((void *)hdr->tags_addr, (char *)dt_table_offset + dt_entry_ptr->offset, dt_entry_ptr->size);
+		}
+		#endif
 		/* Make sure everything from scratch address is read before next step!*/
 		if(device.is_tampered)
 		{
@@ -536,6 +596,46 @@
 			}
 		}
 		offset += n;
+
+		if(hdr->second_size != 0) {
+			n = ROUND_TO_PAGE(hdr->second_size, page_mask);
+			offset += n;
+		}
+
+		#if DEVICE_TREE
+		if(hdr->dt_size != 0) {
+
+			/* Read the device tree table into buffer */
+			if(mmc_read(ptn + offset,(unsigned int *) dt_buf, page_size)) {
+				dprintf(CRITICAL, "ERROR: Cannot read the Device Tree Table\n");
+				return -1;
+			}
+			table = (struct dt_table*) dt_buf;
+
+			/* Restriction that the device tree entry table should be less than a page*/
+			ASSERT(((table->num_entries * sizeof(struct dt_entry))+ DEV_TREE_HEADER_SIZE) < hdr->page_size);
+
+			/* Validate the device tree table header */
+			if((table->magic != DEV_TREE_MAGIC) && (table->version != DEV_TREE_VERSION)) {
+				dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");
+				return -1;
+			}
+
+			/* Calculate the offset of device tree within device tree table */
+			if((dt_entry_ptr = get_device_tree_ptr(table)) == NULL){
+				dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");
+				return -1;
+			}
+
+			/* Read device device tree in the "tags_add */
+			hdr->tags_addr = 0x8400000;
+			if(mmc_read(ptn + offset + dt_entry_ptr->offset,
+						 (void *)hdr->tags_addr, dt_entry_ptr->size)) {
+				dprintf(CRITICAL, "ERROR: Cannot read device tree\n");
+				return -1;
+			}
+		}
+		#endif
 	}
 
 unified_boot:
@@ -1415,7 +1515,25 @@
 APP_END
 
 #if DEVICE_TREE
-/* Device Tree Stuff */
+struct dt_entry * get_device_tree_ptr(struct dt_table *table)
+{
+	unsigned i;
+	struct dt_entry *dt_entry_ptr;
+
+	dt_entry_ptr = (char *)table + DEV_TREE_HEADER_SIZE ;
+
+	for(i = 0; i < table->num_entries; i++)
+	{
+		if((dt_entry_ptr->platform_id == board_platform_id()) &&
+		   (dt_entry_ptr->variant_id == board_hardware_id()) &&
+		   (dt_entry_ptr->soc_rev == 0)){
+				return dt_entry_ptr;
+		}
+		dt_entry_ptr++;
+	}
+	return NULL;
+}
+
 int update_device_tree(const void * fdt, char *cmdline,
 					   void *ramdisk, unsigned ramdisk_size)
 {
diff --git a/app/aboot/bootimg.h b/app/aboot/bootimg.h
index 44fde92..f9966a1 100644
--- a/app/aboot/bootimg.h
+++ b/app/aboot/bootimg.h
@@ -51,7 +51,8 @@
 
     unsigned tags_addr;    /* physical addr for kernel tags */
     unsigned page_size;    /* flash page size we assume */
-    unsigned unused[2];    /* future expansion: should be 0 */
+    unsigned dt_size;      /* device_tree in bytes */
+    unsigned unused;    /* future expansion: should be 0 */
 
     unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
     
@@ -70,11 +71,13 @@
 ** +-----------------+
 ** | second stage    | o pages
 ** +-----------------+
+** | device tree     | p pages
+** +-----------------+
 **
 ** n = (kernel_size + page_size - 1) / page_size
 ** m = (ramdisk_size + page_size - 1) / page_size
 ** o = (second_size + page_size - 1) / page_size
-**
+** p = (dt_size + page_size - 1) / page_size
 ** 0. all entities are page_size aligned in flash
 ** 1. kernel and ramdisk are required (size != 0)
 ** 2. second is optional (second_size == 0 -> no second)
diff --git a/platform/copper/platform.c b/platform/copper/platform.c
index b8c7279..397bb84 100644
--- a/platform/copper/platform.c
+++ b/platform/copper/platform.c
@@ -38,6 +38,7 @@
 
 void platform_early_init(void)
 {
+	board_init();
 	platform_clock_init();
 	qgic_init();
 	qtimer_init();
diff --git a/platform/msm_shared/board.c b/platform/msm_shared/board.c
index fdc5ed0..5bc9996 100644
--- a/platform/msm_shared/board.c
+++ b/platform/msm_shared/board.c
@@ -31,7 +31,6 @@
 #include <board.h>
 #include <smem.h>
 #include <baseband.h>
-#include <board.h>
 
 static struct board_data board = {UNKNOWN,
 	HW_PLATFORM_UNKNOWN,
@@ -109,3 +108,8 @@
 {
 	return board.baseband;
 }
+
+uint32_t board_hardware_id()
+{
+	return board.platform_hw;
+}
diff --git a/platform/msm_shared/include/board.h b/platform/msm_shared/include/board.h
index 40c0897..9aca934 100644
--- a/platform/msm_shared/include/board.h
+++ b/platform/msm_shared/include/board.h
@@ -30,7 +30,7 @@
 #ifndef __BOARD_H
 #define __BOARD_H
 
-#include <target/board.h>
+#define LINUX_MACHTYPE_UNKNOWN 0
 
 struct board_data {
 	uint32_t platform;
@@ -46,5 +46,6 @@
 uint32_t board_platform_id();
 uint32_t board_target_id();
 uint32_t board_baseband();
+uint32_t board_hardware_id();
 
 #endif
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index a7f6c93..5df9e11 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -66,6 +66,7 @@
 			$(LOCAL_DIR)/clock_pll.o \
 			$(LOCAL_DIR)/clock_lib2.o \
 			$(LOCAL_DIR)/uart_dm.o \
+			$(LOCAL_DIR)/board.o \
 			$(LOCAL_DIR)/spmi.o
 endif
 
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index f36efe8..0d6069b 100644
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -217,12 +217,14 @@
 	MSM8660A = 122,
 	MSM8260A = 123,
 	APQ8060A = 124,
+    MSM8974 = 126,
 	MSM8225 = 127,
 	MSM8625 = 129,
 	MPQ8064 = 130,
 	MSM7225AB = 131,
 	MSM7625AB = 132,
 	ESM7225AB = 133,
+	MDM9625   = 134,
 	MSM7125A  = 135,
 	MSM7127A  = 136,
 	MSM8930AA = 142,
@@ -242,7 +244,9 @@
 	HW_PLATFORM_DRAGON = 10,
 	HW_PLATFORM_HRD = 13,
 	HW_PLATFORM_DTV = 14,
-	HW_PLATFORM_32BITS = 0x7FFFFFFF
+    HW_PLATFORM_RUMI   = 15,
+    HW_PLATFORM_VIRTIO = 16,
+	HW_PLATFORM_32BITS = 0x7FFFFFFF,
 };
 
 enum platform_subtype {
diff --git a/project/copper.mk b/project/copper.mk
index f3af929..e6e7b40 100644
--- a/project/copper.mk
+++ b/project/copper.mk
@@ -11,4 +11,4 @@
 #DEFINES += WITH_DEBUG_DCC=1
 DEFINES += WITH_DEBUG_UART=1
 #DEFINES += WITH_DEBUG_FBCON=1
-#DEFINES += DEVICE_TREE=1
+DEFINES += DEVICE_TREE=1
diff --git a/target/copper/init.c b/target/copper/init.c
index a2f3f14..2c812c7 100644
--- a/target/copper/init.c
+++ b/target/copper/init.c
@@ -36,13 +36,13 @@
 #include <uart_dm.h>
 #include <mmc.h>
 #include <spmi.h>
+#include <board.h>
+#include <smem.h>
+#include <baseband.h>
 
 
 static unsigned int target_id;
 
-static void target_detect(void);
-
-#define COPPER_TARGET_ID        0xffffffff
 #define PMIC_ARB_CHANNEL_NUM    0
 #define PMIC_ARB_OWNER_ID       0
 
@@ -63,7 +63,6 @@
 
 	dprintf(INFO, "target_init()\n");
 
-	target_id = COPPER_TARGET_ID;
 	spmi_init(PMIC_ARB_CHANNEL_NUM, PMIC_ARB_OWNER_ID);
 
 	/* Trying Slot 1*/
@@ -92,3 +91,19 @@
 {
 
 }
+
+/* Detect the target type */
+void target_detect(struct board_data *board)
+{
+	board->target = LINUX_MACHTYPE_UNKNOWN;
+}
+
+/* Detect the modem type */
+void target_baseband_detect(struct board_data *board)
+{
+	/* Check for baseband variants. Default to MSM */
+	if (board->platform_subtype == HW_PLATFORM_SUBTYPE_MDM)
+		board->baseband = BASEBAND_MDM;
+	else
+		board->baseband = BASEBAND_MSM;
+}
diff --git a/target/mdm9625/include/target/board.h b/target/mdm9625/include/target/board.h
index f9aef47..81faa85 100644
--- a/target/mdm9625/include/target/board.h
+++ b/target/mdm9625/include/target/board.h
@@ -30,7 +30,6 @@
 #ifndef __TARGET_BOARD_H
 #define __TARGET_BOARD_H
 
-#define LINUX_MACHTYPE_UNKNOWN       0
 
 #define LINUX_MACHTYPE_9625_CDP      0
 #define LINUX_MACHTYPE_9625_MTP      0
diff --git a/target/msm8960/include/target/board.h b/target/msm8960/include/target/board.h
index d40a7a0..906eb8a 100644
--- a/target/msm8960/include/target/board.h
+++ b/target/msm8960/include/target/board.h
@@ -30,7 +30,6 @@
 #ifndef __TARGET_BOARD_H
 #define __TARGET_BOARD_H
 
-#define LINUX_MACHTYPE_UNKNOWN     0
 
 /* 8960 */
 #define LINUX_MACHTYPE_8960_SIM     3230
diff --git a/target/msm8960/init.c b/target/msm8960/init.c
index c87652a..403957d 100644
--- a/target/msm8960/init.c
+++ b/target/msm8960/init.c
@@ -48,6 +48,7 @@
 #include <uart_dm.h>
 #include <crypto_hash.h>
 #include <board.h>
+#include <target/board.h>
 
 extern void dmb(void);
 extern void msm8960_keypad_init(void);
diff --git a/target/msm8960/target_display.c b/target/msm8960/target_display.c
index a25c3b8..81c8918 100644
--- a/target/msm8960/target_display.c
+++ b/target/msm8960/target_display.c
@@ -32,6 +32,7 @@
 #include <board.h>
 #include <mdp4.h>
 #include <target/display.h>
+#include <target/board.h>
 
 static struct msm_fb_panel_data panel;
 static uint8_t display_enable;