Merge "msm8960: Add 8960 platform specific defines in timer."
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index e574fb4..392bdae 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -47,6 +47,7 @@
 #include "recovery.h"
 #include "bootimg.h"
 #include "fastboot.h"
+#include "sparse_format.h"
 
 #define EXPAND(NAME) #NAME
 #define TARGET(NAME) EXPAND(NAME)
@@ -556,7 +557,7 @@
 }
 
 
-void cmd_flash_mmc(const char *arg, void *data, unsigned sz)
+void cmd_flash_mmc_img(const char *arg, void *data, unsigned sz)
 {
 	unsigned long long ptn = 0;
 	unsigned long long size = 0;
@@ -588,6 +589,122 @@
 	return;
 }
 
+void cmd_flash_mmc_sparse_img(const char *arg, void *data, unsigned sz)
+{
+	unsigned int chunk;
+	unsigned int chunk_data_sz;
+	sparse_header_t *sparse_header;
+	chunk_header_t *chunk_header;
+	uint32_t crc32 = 0;
+	uint32_t total_blocks = 0;
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+
+	ptn = mmc_ptn_offset(arg);
+	if(ptn == 0) {
+		fastboot_fail("partition table doesn't exist");
+		return;
+	}
+
+	/* Read and skip over sparse image header */
+	sparse_header = (sparse_header_t *) data;
+	data += sparse_header->file_hdr_sz;
+	if(sparse_header->file_hdr_sz > sizeof(sparse_header_t))
+	{
+		/* Skip the remaining bytes in a header that is longer than
+		 * we expected.
+		 */
+		data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
+	}
+
+	dprintf (INFO, "=== Sparse Image Header ===\n");
+	dprintf (INFO, "magic: 0x%x\n", sparse_header->magic);
+	dprintf (INFO, "major_version: 0x%x\n", sparse_header->major_version);
+	dprintf (INFO, "minor_version: 0x%x\n", sparse_header->minor_version);
+	dprintf (INFO, "file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
+	dprintf (INFO, "chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
+	dprintf (INFO, "blk_sz: %d\n", sparse_header->blk_sz);
+	dprintf (INFO, "total_blks: %d\n", sparse_header->total_blks);
+	dprintf (INFO, "total_chunks: %d\n", sparse_header->total_chunks);
+
+	/* Start processing chunks */
+	for (chunk=0; chunk<sparse_header->total_chunks; chunk++)
+	{
+		/* Read and skip over chunk header */
+		chunk_header = (chunk_header_t *) data;
+		data += sizeof(chunk_header_t);
+
+		dprintf (SPEW, "=== Chunk Header ===\n");
+		dprintf (SPEW, "chunk_type: 0x%x\n", chunk_header->chunk_type);
+		dprintf (SPEW, "chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
+		dprintf (SPEW, "total_size: 0x%x\n", chunk_header->total_sz);
+
+		if(sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
+		{
+			/* Skip the remaining bytes in a header that is longer than
+			 * we expected.
+			 */
+			data += (sparse_header->chunk_hdr_sz - sizeof(chunk_header_t));
+		}
+
+		chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
+		switch (chunk_header->chunk_type)
+		{
+			case CHUNK_TYPE_RAW:
+			if(chunk_header->total_sz != (sparse_header->chunk_hdr_sz +
+											chunk_data_sz))
+			{
+				fastboot_fail("Bogus chunk size for chunk type Raw");
+				return;
+			}
+
+			if(mmc_write(ptn + (total_blocks*sparse_header->blk_sz),
+								chunk_data_sz,
+								(unsigned int*)data))
+			{
+				fastboot_fail("flash write failure");
+				return;
+			}
+			total_blocks += chunk_header->chunk_sz;
+			data += chunk_data_sz;
+			break;
+
+			case CHUNK_TYPE_DONT_CARE:
+			case CHUNK_TYPE_CRC:
+			if(chunk_header->total_sz != sparse_header->chunk_hdr_sz)
+			{
+				fastboot_fail("Bogus chunk size for chunk type Dont Care");
+				return;
+			}
+			total_blocks += chunk_header->chunk_sz;
+			data += chunk_data_sz;
+			break;
+
+			fastboot_fail("Unknown chunk type");
+			return;
+		}
+	}
+
+    dprintf(INFO, "Wrote %d blocks, expected to write %d blocks\n",
+             total_blocks, sparse_header->total_blks);
+
+	fastboot_okay("");
+	return;
+}
+
+void cmd_flash_mmc(const char *arg, void *data, unsigned sz)
+{
+	sparse_header_t *sparse_header;
+	sparse_header = (sparse_header_t *) data;
+
+	if (sparse_header->magic != SPARSE_HEADER_MAGIC)
+		cmd_flash_mmc_img(arg, data, sz);
+	else
+		cmd_flash_mmc_sparse_img(arg, data, sz);
+
+	return;
+}
+
 void cmd_flash(const char *arg, void *data, unsigned sz)
 {
 	struct ptentry *ptn;
diff --git a/app/aboot/sparse_format.h b/app/aboot/sparse_format.h
new file mode 100644
index 0000000..9d995bf
--- /dev/null
+++ b/app/aboot/sparse_format.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct sparse_header {
+  uint32_t  magic;		/* 0xed26ff3a */
+  uint16_t	major_version;	/* (0x1) - reject images with higher major versions */
+  uint16_t	minor_version;	/* (0x0) - allow images with higer minor versions */
+  uint16_t	file_hdr_sz;	/* 28 bytes for first revision of the file format */
+  uint16_t	chunk_hdr_sz;	/* 12 bytes for first revision of the file format */
+  uint32_t	blk_sz;		/* block size in bytes, must be a multiple of 4 (4096) */
+  uint32_t	total_blks;	/* total blocks in the non-sparse output image */
+  uint32_t	total_chunks;	/* total chunks in the sparse input image */
+  uint32_t	image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+				/* as 0. Standard 802.3 polynomial, use a Public Domain */
+				/* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC	0xed26ff3a
+
+#define CHUNK_TYPE_RAW		0xCAC1
+#define CHUNK_TYPE_FILL		0xCAC2
+#define CHUNK_TYPE_DONT_CARE	0xCAC3
+#define CHUNK_TYPE_CRC		0xCAC4
+
+typedef struct chunk_header {
+  uint16_t	chunk_type;	/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+  uint16_t	reserved1;
+  uint32_t	chunk_sz;	/* in blocks in output image */
+  uint32_t	total_sz;	/* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill chunk is data.  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ *  For a Fill chunk, it's 4 bytes of the fill data.
+ */
+
diff --git a/platform/msm7x27a/gpio.c b/platform/msm7x27a/gpio.c
index a49efec..9615d33 100644
--- a/platform/msm7x27a/gpio.c
+++ b/platform/msm7x27a/gpio.c
@@ -40,6 +40,7 @@
 #define GPIO_OUT_2		 GPIO1_REG(0x04)  /* gpio  67-43 */
 #define GPIO_OUT_3		 GPIO1_REG(0x08)  /* gpio  94-68 */
 #define GPIO_OUT_4		 GPIO1_REG(0x0C)  /* gpio 106-95 */
+#define GPIO_OUT_5		 GPIO1_REG(0x50)  /* gpio 132-107 */
 
 /* same pin map as above, output enable */
 #define GPIO_OE_0		  GPIO1_REG(0x10)
@@ -47,6 +48,7 @@
 #define GPIO_OE_2		  GPIO1_REG(0x14)
 #define GPIO_OE_3		  GPIO1_REG(0x18)
 #define GPIO_OE_4		  GPIO1_REG(0x1C)
+#define GPIO_OE_5		  GPIO1_REG(0x54)
 
 /* same pin map as above, input read */
 #define GPIO_IN_0		  GPIO1_REG(0x34)
@@ -54,6 +56,7 @@
 #define GPIO_IN_2		  GPIO1_REG(0x38)
 #define GPIO_IN_3		  GPIO1_REG(0x3C)
 #define GPIO_IN_4		  GPIO1_REG(0x40)
+#define GPIO_IN_5		  GPIO1_REG(0x44)
 
 /* same pin map as above, 1=edge 0=level interrup */
 #define GPIO_INT_EDGE_0	GPIO1_REG(0x60)
@@ -61,6 +64,7 @@
 #define GPIO_INT_EDGE_2	GPIO1_REG(0x64)
 #define GPIO_INT_EDGE_3	GPIO1_REG(0x68)
 #define GPIO_INT_EDGE_4	GPIO1_REG(0x6C)
+#define GPIO_INT_EDGE_5	GPIO1_REG(0xC0)
 
 /* same pin map as above, 1=positive 0=negative */
 #define GPIO_INT_POS_0	 GPIO1_REG(0x70)
@@ -68,6 +72,7 @@
 #define GPIO_INT_POS_2	 GPIO1_REG(0x74)
 #define GPIO_INT_POS_3	 GPIO1_REG(0x78)
 #define GPIO_INT_POS_4	 GPIO1_REG(0x7C)
+#define GPIO_INT_POS_5	 GPIO1_REG(0xBC)
 
 /* same pin map as above, interrupt enable */
 #define GPIO_INT_EN_0	  GPIO1_REG(0x80)
@@ -75,6 +80,7 @@
 #define GPIO_INT_EN_2	  GPIO1_REG(0x84)
 #define GPIO_INT_EN_3	  GPIO1_REG(0x88)
 #define GPIO_INT_EN_4	  GPIO1_REG(0x8C)
+#define GPIO_INT_EN_5	  GPIO1_REG(0xB8)
 
 /* same pin map as above, write 1 to clear interrupt */
 #define GPIO_INT_CLEAR_0   GPIO1_REG(0x90)
@@ -82,6 +88,7 @@
 #define GPIO_INT_CLEAR_2   GPIO1_REG(0x94)
 #define GPIO_INT_CLEAR_3   GPIO1_REG(0x98)
 #define GPIO_INT_CLEAR_4   GPIO1_REG(0x9C)
+#define GPIO_INT_CLEAR_5   GPIO1_REG(0xB4)
 
 /* same pin map as above, 1=interrupt pending */
 #define GPIO_INT_STATUS_0  GPIO1_REG(0xA0)
@@ -89,6 +96,7 @@
 #define GPIO_INT_STATUS_2  GPIO1_REG(0xA4)
 #define GPIO_INT_STATUS_3  GPIO1_REG(0xA8)
 #define GPIO_INT_STATUS_4  GPIO1_REG(0xAC)
+#define GPIO_INT_STATUS_5  GPIO1_REG(0xB0)
 
 typedef struct gpioregs gpioregs;
 
@@ -155,12 +163,26 @@
 		.int_pos =	 GPIO_INT_POS_4,
 		.oe =		  GPIO_OE_4,
 	},
+	{
+		.out =		 GPIO_OUT_5,
+		.in =		  GPIO_IN_5,
+		.int_status =  GPIO_INT_STATUS_5,
+		.int_clear =   GPIO_INT_CLEAR_5,
+		.int_en =	  GPIO_INT_EN_5,
+		.int_edge =	GPIO_INT_EDGE_5,
+		.int_pos =	 GPIO_INT_POS_5,
+		.oe =		  GPIO_OE_5,
+	},
 };
 
 static gpioregs *find_gpio(unsigned n, unsigned *bit)
 {
-	if(n > 106)
+	if(n > 132)
 		return 0;
+	if(n > 106) {
+		*bit = 1 << (n - 107);
+		return GPIO_REGS + 5;
+	}
 	if(n > 94) {
 		*bit = 1 << (n - 95);
 		return GPIO_REGS + 4;
diff --git a/platform/msm7x27a/platform.c b/platform/msm7x27a/platform.c
index 43ea05b..a7e34c8 100644
--- a/platform/msm7x27a/platform.c
+++ b/platform/msm7x27a/platform.c
@@ -51,9 +51,10 @@
 
 void platform_early_init(void)
 {
-		//uart3_clock_init();
-	//uart_init();
-
+#if WITH_DEBUG_UART
+	uart1_clock_init();
+	uart_init();
+#endif
 	platform_init_interrupts();
 	platform_init_timer();
 }
diff --git a/platform/msm_shared/nand.c b/platform/msm_shared/nand.c
index af6d3ff..e69fa24 100644
--- a/platform/msm_shared/nand.c
+++ b/platform/msm_shared/nand.c
@@ -108,6 +108,8 @@
 static struct flash_info flash_info;
 static unsigned flash_pagesize = 0;
 static int interleaved_mode = 0;
+static unsigned num_pages_per_blk = 0;
+static unsigned num_pages_per_blk_mask = 0;
 
 struct flash_identification {
 	unsigned flash_id;
@@ -246,8 +248,8 @@
 	cwperpage = (flash_pagesize >> 9);
 
 	/* Check first page of this block */
-	if(page & 63)
-		page = page - (page & 63);
+	if(page & num_pages_per_blk_mask)
+		page = page - (page & num_pages_per_blk_mask);
 
 	/* Check bad block marker */
 	data[0] = NAND_CMD_PAGE_READ;	/* command */
@@ -493,13 +495,13 @@
 	int isbad = 0;
 
 	/* only allow erasing on block boundaries */
-	if(page & 63) return -1;
+	if(page & num_pages_per_blk_mask) return -1;
 
 	/* Check for bad block and erase only if block is not marked bad */
 	isbad = flash_nand_block_isbad(cmdlist, ptrlist, page);
 
 	if (isbad) {
-		dprintf(INFO, "skipping @ %d (bad block)\n", page >> 6);
+		dprintf(INFO, "skipping @ %d (bad block)\n", page / num_pages_per_blk);
 		return -1;
 	}
 
@@ -1692,8 +1694,8 @@
 {
   memset(empty_buf,0,528);
   /* Going to first page of the block */
-  if(page & 63)
-	page = page - (page & 63);
+  if(page & num_pages_per_blk_mask)
+	page = page - (page & num_pages_per_blk_mask);
   return _flash_nand_write_page(cmdlist, ptrlist, page, empty_buf, 0, 1);
 }
 
@@ -1887,8 +1889,8 @@
 	unsigned char *oobptr = &(page_data[2048]);
 
 	/* Going to first page of the block */
-	if(page & 63)
-		page = page - (page & 63);
+	if(page & num_pages_per_blk_mask)
+		page = page - (page & num_pages_per_blk_mask);
 
 	/* Reading page in raw mode */
 	if (_flash_onenand_read_page(cmdlist, ptrlist,page, page_data, 0, 1))
@@ -1913,7 +1915,7 @@
 	unsigned *ptr = ptrlist;
 	struct data_onenand_erase *data = (void *)ptrlist + 4;
 	int isbad = 0;
-	unsigned erasesize = (flash_pagesize << 6);
+	unsigned erasesize = (flash_pagesize * num_pages_per_blk);
 	unsigned onenand_startaddr1 = DEVICE_FLASHCORE_0 | (page * flash_pagesize)/erasesize;
 	unsigned onenand_startaddr8 = 0x0000;
 	unsigned onenand_startaddr2 = DEVICE_BUFFERRAM_0 << 15;
@@ -1929,7 +1931,7 @@
 	isbad = flash_onenand_block_isbad(cmdlist, ptrlist, page);
 	if (isbad)
 	{
-		dprintf(INFO, "skipping @ %d (bad block)\n", page >> 6);
+		dprintf(INFO, "skipping @ %d (bad block)\n", page / num_pages_per_blk);
 		return -1;
 	}
 
@@ -2223,7 +2225,7 @@
 	unsigned curr_addr = (unsigned) _addr;
 	unsigned spareaddr = (unsigned) _spareaddr;
 	unsigned i;
-	unsigned erasesize = (flash_pagesize<<6);
+	unsigned erasesize = (flash_pagesize * num_pages_per_blk);
 	unsigned writesize = flash_pagesize;
 
 	unsigned onenand_startaddr1 = DEVICE_FLASHCORE_0 |
@@ -2676,7 +2678,7 @@
 	char * spareaddr = (char *) _spareaddr;
 	unsigned i, j, k;
 
-	unsigned erasesize = (flash_pagesize<<6);
+	unsigned erasesize = (flash_pagesize * num_pages_per_blk);
 	unsigned writesize = flash_pagesize;
 
 	unsigned onenand_startaddr1 = (page * flash_pagesize) / erasesize;
@@ -3098,8 +3100,8 @@
 {
   memset(empty_buf,0,528);
   /* Going to first page of the block */
-  if(page & 63)
-	page = page - (page & 63);
+  if(page & num_pages_per_blk_mask)
+	page = page - (page & num_pages_per_blk_mask);
   return _flash_onenand_write_page(cmdlist, ptrlist, page, empty_buf, 0, 1);
 }
 
@@ -3176,6 +3178,9 @@
 			flash_info.num_blocks = 0;
 		}
 		ASSERT(flash_info.num_blocks);
+		// Use this for getting the next/current blocks
+		num_pages_per_blk = flash_info.block_size / flash_pagesize;
+		num_pages_per_blk_mask = num_pages_per_blk - 1;
 		return;
 	}
 
@@ -3300,7 +3305,7 @@
 
 	set_nand_configuration(ptn->type);
 	while(count-- > 0) {
-		if(flash_erase_block(flash_cmdlist, flash_ptrlist, block * 64)) {
+		if(flash_erase_block(flash_cmdlist, flash_ptrlist, block * num_pages_per_blk)) {
 			dprintf(INFO, "cannot erase @ %d (bad block?)\n", block);
 		}
 		block++;
@@ -3311,13 +3316,13 @@
 int flash_read_ext(struct ptentry *ptn, unsigned extra_per_page,
 			unsigned offset, void *data, unsigned bytes)
 {
-	unsigned page = (ptn->start * 64) + (offset / flash_pagesize);
-	unsigned lastpage = (ptn->start + ptn->length) * 64;
+	unsigned page = (ptn->start * num_pages_per_blk) + (offset / flash_pagesize);
+	unsigned lastpage = (ptn->start + ptn->length) * num_pages_per_blk;
 	unsigned count = (bytes + flash_pagesize - 1 + extra_per_page) / (flash_pagesize + extra_per_page);
 	unsigned *spare = (unsigned*) flash_spare;
 	unsigned errors = 0;
 	unsigned char *image = data;
-	unsigned current_block = (page - (page & 63)) >> 6;
+	unsigned current_block = (page - (page & num_pages_per_blk_mask)) / num_pages_per_blk;
 	unsigned start_block = ptn->start;
 	int result = 0;
 	int isbad = 0;
@@ -3334,9 +3339,9 @@
 	{
 		start_block_count = (current_block - start_block);
 		while (start_block_count && (start_block < (ptn->start + ptn->length))) {
-			isbad = _flash_block_isbad(flash_cmdlist, flash_ptrlist, start_block*64);
+			isbad = _flash_block_isbad(flash_cmdlist, flash_ptrlist, start_block*num_pages_per_blk);
 			if (isbad)
-				page += 64;
+				page += num_pages_per_blk;
 			else
 				start_block_count--;
 			start_block++;
@@ -3359,7 +3364,7 @@
 		}
 		else if (result == -2) {
 			// bad block, go to next block same offset
-			page += 64;
+			page += num_pages_per_blk;
 			errors++;
 			continue;
 		}
@@ -3379,8 +3384,8 @@
 int flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data,
 		unsigned bytes)
 {
-	unsigned page = ptn->start * 64;
-	unsigned lastpage = (ptn->start + ptn->length) * 64;
+	unsigned page = ptn->start * num_pages_per_blk;
+	unsigned lastpage = (ptn->start + ptn->length) * num_pages_per_blk;
 	unsigned *spare = (unsigned*) flash_spare;
 	const unsigned char *image = data;
 	unsigned wsize = flash_pagesize + extra_per_page;
@@ -3406,10 +3411,10 @@
 			return -1;
 		}
 
-		if((page & 63) == 0) {
+		if((page & num_pages_per_blk_mask) == 0) {
 			if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
-				dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
-				page += 64;
+				dprintf(INFO, "flash_write_image: bad block @ %d\n", page / num_pages_per_blk);
+				page += num_pages_per_blk;
 				continue;
 			}
 		}
@@ -3421,9 +3426,9 @@
 		}
 		if(r) {
 			dprintf(INFO, "flash_write_image: write failure @ page %d (src %d)\n", page, image - (const unsigned char *)data);
-			image -= (page & 63) * wsize;
-			bytes += (page & 63) * wsize;
-			page &= ~63;
+			image -= (page & num_pages_per_blk_mask) * wsize;
+			bytes += (page & num_pages_per_blk_mask) * wsize;
+			page &= ~num_pages_per_blk_mask;
 			if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
 				dprintf(INFO, "flash_write_image: erase failure @ page %d\n", page);
 			}
@@ -3431,7 +3436,7 @@
 				flash_mark_badblock(flash_cmdlist, flash_ptrlist, page);
 			}
 			dprintf(INFO, "flash_write_image: restart write @ page %d (src %d)\n", page, image - (const unsigned char *)data);
-			page += 64;
+			page += num_pages_per_blk;
 			continue;
 		}
 		page++;
@@ -3440,12 +3445,12 @@
 	}
 
 	/* erase any remaining pages in the partition */
-	page = (page + 63) & (~63);
+	page = (page + num_pages_per_blk_mask) & (~num_pages_per_blk_mask);
 	while(page < lastpage){
 		if(flash_erase_block(flash_cmdlist, flash_ptrlist, page)) {
-			dprintf(INFO, "flash_write_image: bad block @ %d\n", page >> 6);
+			dprintf(INFO, "flash_write_image: bad block @ %d\n", page / num_pages_per_blk);
 		}
-		page += 64;
+		page += num_pages_per_blk;
 	}
 
 	dprintf(INFO, "flash_write_image: success\n");
diff --git a/platform/msm_shared/proc_comm.c b/platform/msm_shared/proc_comm.c
index eff7a43..fca1358 100644
--- a/platform/msm_shared/proc_comm.c
+++ b/platform/msm_shared/proc_comm.c
@@ -257,6 +257,12 @@
 	clock_set_rate(UART2_CLK, 19200000);
 }
 
+void uart1_clock_init(void)
+{
+	clock_enable(UART1_CLK);
+	clock_set_rate(UART1_CLK, 19200000 / 4);
+}
+
 void mddi_clock_init(unsigned num, unsigned rate)
 {
 	unsigned clock_id;
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index 71da345..5dda467 100644
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -116,6 +116,11 @@
     MSM8260 = 70,
     MSM8660 = 71,
     APQ8060 = 86,
+    MSM7225A = 88,
+    MSM7625A = 89,
+    MSM7227A = 90,
+    MSM7627A = 91,
+    ESM7227A = 92,
 };
 
 enum platform
diff --git a/platform/msm_shared/uart.c b/platform/msm_shared/uart.c
index 7f5c7e2..af6dcd9 100644
--- a/platform/msm_shared/uart.c
+++ b/platform/msm_shared/uart.c
@@ -121,6 +121,8 @@
 static unsigned uart_ready = 0;
 #if PLATFORM_MSM7X30
 static unsigned uart_base = MSM_UART2_BASE;
+#elif PLATFORM_MSM7X27A
+static unsigned uart_base = MSM_UART1_BASE;
 #else
 static unsigned uart_base = MSM_UART3_BASE;
 #endif
@@ -136,7 +138,7 @@
 	uwr(0x10, UART_CR);  /* reset receiver */
 	uwr(0x20, UART_CR);  /* reset transmitter */
 	
-#if PLATFORM_QSD8K || PLATFORM_MSM7X30
+#if PLATFORM_QSD8K || PLATFORM_MSM7X30 || PLATFORM_MSM7X27A
 	/* TCXO */
 	uwr(0x06, UART_MREG);
 	uwr(0xF1, UART_NREG);
diff --git a/target/msm7627a/init.c b/target/msm7627a/init.c
index c6dbe3d..a591f46 100644
--- a/target/msm7627a/init.c
+++ b/target/msm7627a/init.c
@@ -48,6 +48,8 @@
 #define NUM_PAGES_PER_BLOCK	0x40
 
 static struct ptable flash_ptable;
+unsigned hw_platform = 0;
+unsigned target_msm_id = 0;
 
 /* for these partitions, start will be offset by either what we get from
  * smem, or from the above offset if smem is not useful. Also, we should
@@ -114,13 +116,10 @@
 
 	dprintf(INFO, "target_init()\n");
 
-/* TODO: Enable keypad support */
-#if 0
 #if (!ENABLE_NANDWRITE)
 	keys_init();
 	keypad_init();
 #endif
-#endif
 
 	if (target_is_emmc_boot())
 	{
@@ -179,9 +178,67 @@
 	flash_set_ptable(&flash_ptable);
 }
 
+void board_info(void)
+{
+	struct smem_board_info_v4 board_info_v4;
+	unsigned int board_info_len = 0;
+	unsigned smem_status;
+	unsigned format = 0;
+	unsigned id = 0;
+
+	if (hw_platform && target_msm_id)
+		return;
+
+	hw_platform = MSM7X27A_SURF;
+	target_msm_id = MSM7225A;
+
+	smem_status = smem_read_alloc_entry_offset(SMEM_BOARD_INFO_LOCATION,
+											&format, sizeof(format), 0);
+	if(!smem_status)
+	{
+		if(format == 4)
+		{
+			board_info_len = sizeof(board_info_v4);
+			smem_status = smem_read_alloc_entry(SMEM_BOARD_INFO_LOCATION,
+										&board_info_v4, board_info_len);
+			if(!smem_status)
+			{
+				id = board_info_v4.board_info_v3.hw_platform;
+				target_msm_id = board_info_v4.board_info_v3.msm_id;
+			}
+		}
+
+		/* Detect SURF v/s FFA v/s Fluid */
+		switch(id)
+		{
+			case 0x1:
+				hw_platform = MSM7X27A_SURF;
+				break;
+			case 0x2:
+				hw_platform = MSM7X27A_FFA;
+				break;
+			default:
+				hw_platform = MSM7X27A_SURF;
+		};
+
+		if ((target_msm_id < MSM7225A) || (target_msm_id > ESM7227A))
+		{
+			target_msm_id = MSM7225A;
+		}
+	}
+	return;
+}
+
 unsigned board_machtype(void)
 {
-	return LINUX_MACHTYPE;
+	board_info();
+	return hw_platform;
+}
+
+unsigned board_msm_id(void)
+{
+	board_info();
+	return target_msm_id;
 }
 
 void reboot_device(unsigned reboot_reason)
diff --git a/target/msm7627a/keypad.c b/target/msm7627a/keypad.c
index c51c015..354e632 100644
--- a/target/msm7627a/keypad.c
+++ b/target/msm7627a/keypad.c
@@ -38,61 +38,41 @@
 /* don't turn this on without updating the ffa support */
 #define SCAN_FUNCTION_KEYS 0
 
-static unsigned int halibut_row_gpios[] = {
-	31, 32, 33, 34, 35, 41
-#if SCAN_FUNCTION_KEYS
-	, 42
-#endif
-};
-
-static unsigned int halibut_col_gpios[] = { 36, 37, 38, 39, 40 };
+static unsigned int halibut_row_gpios[] = {31, 32, 33, 34, 35};
+static unsigned int halibut_col_gpios[] = {36, 37, 38, 39, 40};
 
 #define KEYMAP_INDEX(row, col) ((row)*ARRAY_SIZE(halibut_col_gpios) + (col))
 
 static const unsigned short halibut_keymap[ARRAY_SIZE(halibut_col_gpios) * ARRAY_SIZE(halibut_row_gpios)] = {
-	[KEYMAP_INDEX(0, 0)] = KEY_5,
-	[KEYMAP_INDEX(0, 1)] = KEY_9,
-	[KEYMAP_INDEX(0, 2)] = KEY_SOFT1,
-	[KEYMAP_INDEX(0, 3)] = KEY_6,
-	[KEYMAP_INDEX(0, 4)] = KEY_LEFT,
+	[KEYMAP_INDEX(0, 0)] = KEY_7,
+	[KEYMAP_INDEX(0, 1)] = KEY_DOWN,
+	[KEYMAP_INDEX(0, 2)] = KEY_UP,
+	[KEYMAP_INDEX(0, 3)] = KEY_RIGHT,
+	[KEYMAP_INDEX(0, 4)] = KEY_CENTER,
 
-	[KEYMAP_INDEX(1, 0)] = KEY_0,
-	[KEYMAP_INDEX(1, 1)] = KEY_RIGHT,
+	[KEYMAP_INDEX(1, 0)] = KEY_LEFT,
+	[KEYMAP_INDEX(1, 1)] = KEY_SEND,
 	[KEYMAP_INDEX(1, 2)] = KEY_1,
-	[KEYMAP_INDEX(1, 3)] = KEY_SHARP,
-	[KEYMAP_INDEX(1, 4)] = KEY_SEND,
+	[KEYMAP_INDEX(1, 3)] = KEY_4,
+	[KEYMAP_INDEX(1, 4)] = KEY_CLEAR,
 
-	[KEYMAP_INDEX(2, 0)] = KEY_VOLUMEUP,
-	[KEYMAP_INDEX(2, 1)] = KEY_HOME,	  /* FA   */
-	[KEYMAP_INDEX(2, 2)] = KEY_F8,		/* QCHT */
-	[KEYMAP_INDEX(2, 3)] = KEY_F6,		/* R+   */
-	[KEYMAP_INDEX(2, 4)] = KEY_F7,		/* R-   */
+	[KEYMAP_INDEX(2, 0)] = KEY_6,
+	[KEYMAP_INDEX(2, 1)] = KEY_5,
+	[KEYMAP_INDEX(2, 2)] = KEY_8,
+	[KEYMAP_INDEX(2, 3)] = KEY_3,
+	[KEYMAP_INDEX(2, 4)] = KEY_STAR,
 
-	[KEYMAP_INDEX(3, 0)] = KEY_UP,
-	[KEYMAP_INDEX(3, 1)] = KEY_CLEAR,
-	[KEYMAP_INDEX(3, 2)] = KEY_4,
-	[KEYMAP_INDEX(3, 3)] = KEY_MUTE,	  /* SPKR */
-	[KEYMAP_INDEX(3, 4)] = KEY_2,
+	[KEYMAP_INDEX(3, 0)] = KEY_9,
+	[KEYMAP_INDEX(3, 1)] = KEY_SOFT1,
+	[KEYMAP_INDEX(3, 2)] = KEY_0,
+	[KEYMAP_INDEX(3, 3)] = KEY_2,
+	[KEYMAP_INDEX(3, 4)] = KEY_SOFT2,
 
-	[KEYMAP_INDEX(4, 0)] = KEY_SOFT2,		   /* SOFT2 */
-	[KEYMAP_INDEX(4, 1)] = KEY_CENTER,	/* KEY_CENTER */
-	[KEYMAP_INDEX(4, 2)] = KEY_DOWN,
-	[KEYMAP_INDEX(4, 3)] = KEY_BACK,	  /* FB */
-	[KEYMAP_INDEX(4, 4)] = KEY_8,
-
-	[KEYMAP_INDEX(5, 0)] = KEY_VOLUMEDOWN,
-	[KEYMAP_INDEX(5, 1)] = KEY_STAR,	  /* KEY_STAR */
-	[KEYMAP_INDEX(5, 2)] = KEY_MAIL,	  /* MESG */
-	[KEYMAP_INDEX(5, 3)] = KEY_3,
-	[KEYMAP_INDEX(5, 4)] = KEY_7,
-
-#if SCAN_FUNCTION_KEYS
-	[KEYMAP_INDEX(6, 0)] = KEY_F5,
-	[KEYMAP_INDEX(6, 1)] = KEY_F4,
-	[KEYMAP_INDEX(6, 2)] = KEY_F3,
-	[KEYMAP_INDEX(6, 3)] = KEY_F2,
-	[KEYMAP_INDEX(6, 4)] = KEY_F1
-#endif
+	[KEYMAP_INDEX(4, 0)] = KEY_MENU,		/*R-*/
+	[KEYMAP_INDEX(4, 1)] = KEY_HOME,		/*L+*/
+	[KEYMAP_INDEX(4, 2)] = KEY_BACK,		/*L-*/
+	[KEYMAP_INDEX(4, 3)] = KEY_VOLUMEUP,
+	[KEYMAP_INDEX(4, 4)] = KEY_VOLUMEDOWN,
 };
 
 static struct gpio_keypad_info halibut_keypad_info = {
@@ -103,7 +83,7 @@
 	.ninputs	= ARRAY_SIZE(halibut_col_gpios),
 	.settle_time	= 5 /* msec */,
 	.poll_time	= 20 /* msec */,
-	.flags		= GPIOKPF_DRIVE_INACTIVE,
+	.flags		= (GPIOKPF_DRIVE_INACTIVE | GPIOKPF_ACTIVE_HIGH),
 };
 
 void keypad_init(void)