Merge "msm_shared: mmc_sdhci: Add support for sleep function"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 59f43dd..86cbadc 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -591,7 +591,7 @@
 
 #if DEVICE_TREE
 	struct dt_table *table;
-	struct dt_entry *dt_entry_ptr;
+	struct dt_entry dt_entry;
 	unsigned dt_table_offset;
 	uint32_t dt_actual;
 #endif
@@ -735,29 +735,24 @@
 
 			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)) {
+			if (dev_tree_validate(table, hdr->page_size) != 0) {
 				dprintf(CRITICAL, "ERROR: Cannot validate Device Tree Table \n");
 				return -1;
 			}
-
 			/* Find index of device tree within device tree table */
-			if((dt_entry_ptr = dev_tree_get_entry_ptr(table)) == NULL){
+			if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 				dprintf(CRITICAL, "ERROR: Device Tree Blob cannot be found\n");
 				return -1;
 			}
 
 			/* Validate and Read device device tree in the "tags_add */
-			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 			{
 				dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 				return -1;
 			}
 
-			memmove((void *)hdr->tags_addr, (char *)dt_table_offset + dt_entry_ptr->offset, dt_entry_ptr->size);
+			memmove((void *)hdr->tags_addr, (char *)dt_table_offset + dt_entry.offset, dt_entry.size);
 		} else {
 			/*
 			 * If appended dev tree is found, update the atags with
@@ -820,30 +815,26 @@
 			}
 			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)) {
+			if (dev_tree_validate(table, hdr->page_size) != 0) {
 				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 = dev_tree_get_entry_ptr(table)) == NULL){
+			/* Find index of device tree within device tree table */
+			if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 				dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");
 				return -1;
 			}
 
 			/* Validate and Read device device tree in the "tags_add */
-			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 			{
 				dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 				return -1;
 			}
 
-			if(mmc_read(ptn + offset + dt_entry_ptr->offset,
-						 (void *)hdr->tags_addr, dt_entry_ptr->size)) {
+			if(mmc_read(ptn + offset + dt_entry.offset,
+						 (void *)hdr->tags_addr, dt_entry.size)) {
 				dprintf(CRITICAL, "ERROR: Cannot read device tree\n");
 				return -1;
 			}
@@ -894,7 +885,7 @@
 
 #if DEVICE_TREE
 	struct dt_table *table;
-	struct dt_entry *dt_entry_ptr;
+	struct dt_entry dt_entry;
 	uint32_t dt_actual;
 #endif
 
@@ -1024,7 +1015,7 @@
 		memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);
 #if DEVICE_TREE
 		/* Validate and Read device device tree in the "tags_add */
-		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 		{
 			dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 			return -1;
@@ -1087,31 +1078,27 @@
 
 			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)) {
+			if (dev_tree_validate(table, hdr->page_size) != 0) {
 				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 = dev_tree_get_entry_ptr(table)) == NULL){
+			/* Find index of device tree within device tree table */
+			if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 				dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");
 				return -1;
 			}
 
 			/* Validate and Read device device tree in the "tags_add */
-			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+			if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 			{
 				dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 				return -1;
 			}
 
 			/* Read device device tree in the "tags_add */
-			if(flash_read(ptn, offset + dt_entry_ptr->offset,
-						 (void *)hdr->tags_addr, dt_entry_ptr->size)) {
+			if(flash_read(ptn, offset + dt_entry.offset,
+						 (void *)hdr->tags_addr, dt_entry.size)) {
 				dprintf(CRITICAL, "ERROR: Cannot read device tree\n");
 				return -1;
 			}
@@ -1298,7 +1285,7 @@
 	uint32 dt_image_offset = 0;
 	uint32_t n;
 	struct dt_table *table;
-	struct dt_entry *dt_entry_ptr;
+	struct dt_entry dt_entry;
 
 	struct boot_img_hdr *hdr = (struct boot_img_hdr *) (boot_image_start);
 
@@ -1322,23 +1309,18 @@
 		/* offset now point to start of dt.img */
 		table = (struct dt_table*)(boot_image_start + dt_image_offset);
 
-		/* 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)) {
+		if (dev_tree_validate(table, hdr->page_size) != 0) {
 			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 = dev_tree_get_entry_ptr(table)) == NULL){
+		/* Find index of device tree within device tree table */
+		if(dev_tree_get_entry_info(table, &dt_entry) != 0){
 			dprintf(CRITICAL, "ERROR: Getting device tree address failed\n");
 			return -1;
 		}
 
 		/* Validate and Read device device tree in the "tags_add */
-		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry_ptr->size))
+		if (check_aboot_addr_range_overlap(hdr->tags_addr, dt_entry.size))
 		{
 			dprintf(CRITICAL, "Device tree addresses overlap with aboot addresses.\n");
 			return -1;
@@ -1346,8 +1328,8 @@
 
 		/* Read device device tree in the "tags_add */
 		memmove((void*) hdr->tags_addr,
-				boot_image_start + dt_image_offset +  dt_entry_ptr->offset,
-				dt_entry_ptr->size);
+				boot_image_start + dt_image_offset +  dt_entry.offset,
+				dt_entry.size);
 	} else
 		return -1;
 
diff --git a/platform/msm_shared/board.c b/platform/msm_shared/board.c
index 58bf4a3..dcc750d 100644
--- a/platform/msm_shared/board.c
+++ b/platform/msm_shared/board.c
@@ -142,6 +142,11 @@
 	return board.platform_hw;
 }
 
+uint32_t board_hardware_subtype(void)
+{
+	return board.platform_subtype;
+}
+
 uint8_t board_pmic_info(struct board_pmic_data *info, uint8_t num_ent)
 {
 	uint8_t i;
diff --git a/platform/msm_shared/dev_tree.c b/platform/msm_shared/dev_tree.c
index f5dbb4e..de5384b 100644
--- a/platform/msm_shared/dev_tree.c
+++ b/platform/msm_shared/dev_tree.c
@@ -36,6 +36,15 @@
 #include <platform.h>
 #include <board.h>
 
+struct dt_entry_v1
+{
+	uint32_t platform_id;
+	uint32_t variant_id;
+	uint32_t soc_rev;
+	uint32_t offset;
+	uint32_t size;
+};
+
 extern int target_is_emmc_boot(void);
 extern uint32_t target_dev_tree_mem(void *fdt, uint32_t memory_node_offset);
 /* TODO: This function needs to be moved to target layer to check violations
@@ -98,47 +107,118 @@
 	return NULL;
 }
 
-/* Function to return the pointer to the start of the correct device tree
+/* Returns 0 if the device tree is valid. */
+int dev_tree_validate(struct dt_table *table, unsigned int page_size)
+{
+	int dt_entry_size;
+
+	/* Validate the device tree table header */
+	if(table->magic != DEV_TREE_MAGIC) {
+		dprintf(CRITICAL, "ERROR: Bad magic in device tree table \n");
+		return -1;
+	}
+
+	if (table->version == DEV_TREE_VERSION_V1) {
+		dt_entry_size = sizeof(struct dt_entry_v1);
+	} else if (table->version == DEV_TREE_VERSION_V2) {
+		dt_entry_size = sizeof(struct dt_entry);
+	} else {
+		dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
+				table->version);
+		return -1;
+	}
+
+	/* Restriction that the device tree entry table should be less than a page*/
+	ASSERT(((table->num_entries * dt_entry_size)+ DEV_TREE_HEADER_SIZE) < page_size);
+
+	return 0;
+}
+
+/* Function to obtain the index information for the correct device tree
  *  based on the platform data.
+ *  If a matching device tree is found, the information is returned in the
+ *  "dt_entry_info" out parameter and a function value of 0 is returned, otherwise
+ *  a non-zero function value is returned.
  */
-struct dt_entry * dev_tree_get_entry_ptr(struct dt_table *table)
+int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info)
 {
 	uint32_t i;
-	struct dt_entry *dt_entry_ptr;
-	struct dt_entry *latest_dt_entry = NULL;
+	unsigned char *table_ptr;
+	struct dt_entry dt_entry_buf_1;
+	struct dt_entry dt_entry_buf_2;
+	struct dt_entry *cur_dt_entry;
+	struct dt_entry *best_match_dt_entry;
+	struct dt_entry_v1 *dt_entry_v1;
 
-	dt_entry_ptr = (struct dt_entry *)((char *)table + DEV_TREE_HEADER_SIZE);
+	if (!dt_entry_info) {
+		dprintf(CRITICAL, "ERROR: Bad parameter passed to %s \n",
+				__func__);
+		return -1;
+	}
+
+	table_ptr = (unsigned char *)table + DEV_TREE_HEADER_SIZE;
+	cur_dt_entry = &dt_entry_buf_1;
+	best_match_dt_entry = NULL;
 
 	for(i = 0; i < table->num_entries; i++)
 	{
+		memset(cur_dt_entry, 0, sizeof(struct dt_entry));
+		switch(table->version) {
+		case DEV_TREE_VERSION_V1:
+			dt_entry_v1 = (struct dt_entry_v1 *)table_ptr;
+			cur_dt_entry->platform_id = dt_entry_v1->platform_id;
+			cur_dt_entry->variant_id = dt_entry_v1->variant_id;
+			cur_dt_entry->soc_rev = dt_entry_v1->soc_rev;
+			cur_dt_entry->board_hw_subtype = board_hardware_subtype();
+			cur_dt_entry->offset = dt_entry_v1->offset;
+			cur_dt_entry->size = dt_entry_v1->size;
+			table_ptr += sizeof(struct dt_entry_v1);
+			break;
+		case DEV_TREE_VERSION_V2:
+			memcpy(cur_dt_entry, (struct dt_entry *)table_ptr,
+				   sizeof(struct dt_entry));
+			table_ptr += sizeof(struct dt_entry);
+			break;
+		default:
+			dprintf(CRITICAL, "ERROR: Unsupported version (%d) in DT table \n",
+					table->version);
+			return -1;
+		}
+
 		/* DTBs are stored in the ascending order of soc revision.
 		 * For eg: Rev0..Rev1..Rev2 & so on.
 		 * we pickup the DTB with highest soc rev number which is less
 		 * than or equal to actual hardware
 		 */
-		if((dt_entry_ptr->platform_id == board_platform_id()) &&
-		   (dt_entry_ptr->variant_id == board_hardware_id()) &&
-		   (dt_entry_ptr->soc_rev == board_soc_version()))
-			{
-				return dt_entry_ptr;
+		if((cur_dt_entry->platform_id == board_platform_id()) &&
+		   (cur_dt_entry->variant_id == board_hardware_id()) &&
+		   (cur_dt_entry->board_hw_subtype == board_hardware_subtype()))
+		{
+			if(cur_dt_entry->soc_rev == board_soc_version()) {
+				/* copy structure */
+				*dt_entry_info = *cur_dt_entry;
+				return 0;
+			} else if (cur_dt_entry->soc_rev < board_soc_version()){
+				/* Keep this as the next best candidate. */
+				if (!best_match_dt_entry) {
+					best_match_dt_entry = cur_dt_entry;
+					cur_dt_entry = &dt_entry_buf_2;
+				} else {
+					/* Swap dt_entry buffers */
+					struct dt_entry *temp = cur_dt_entry;
+					cur_dt_entry = best_match_dt_entry;
+					best_match_dt_entry = temp;
+				}
 			}
-		/* if the exact match not found, return the closest match
-		 * assuming it to be the nearest soc version
-		 */
-		if((dt_entry_ptr->platform_id == board_platform_id()) &&
-		  (dt_entry_ptr->variant_id == board_hardware_id()) &&
-		  (dt_entry_ptr->soc_rev <= board_soc_version())) {
-			latest_dt_entry = dt_entry_ptr;
 		}
-		dt_entry_ptr++;
 	}
 
-	if (latest_dt_entry) {
-		dprintf(SPEW, "Loading DTB with SOC version:%x\n", latest_dt_entry->soc_rev);
-		return latest_dt_entry;
+	if (best_match_dt_entry) {
+		*dt_entry_info = *best_match_dt_entry;
+		return 0;
 	}
 
-	return NULL;
+	return -1;
 }
 
 /* Function to add the first RAM partition info to the device tree.
diff --git a/platform/msm_shared/include/board.h b/platform/msm_shared/include/board.h
index f863a26..ffc65e8 100644
--- a/platform/msm_shared/include/board.h
+++ b/platform/msm_shared/include/board.h
@@ -60,5 +60,5 @@
 uint32_t board_hardware_id();
 uint8_t board_pmic_info(struct board_pmic_data *, uint8_t num_ent);
 uint32_t board_soc_version();
-
+uint32_t board_hardware_subtype(void);
 #endif
diff --git a/platform/msm_shared/include/dev_tree.h b/platform/msm_shared/include/dev_tree.h
index 2c216aa..d0b0ca8 100644
--- a/platform/msm_shared/include/dev_tree.h
+++ b/platform/msm_shared/include/dev_tree.h
@@ -34,7 +34,8 @@
 #define DEV_TREE_SUCCESS        0
 #define DEV_TREE_MAGIC          0x54444351 /* "QCDT" */
 #define DEV_TREE_MAGIC_LEN      4
-#define DEV_TREE_VERSION        1
+#define DEV_TREE_VERSION_V1     1
+#define DEV_TREE_VERSION_V2     2
 #define DEV_TREE_HEADER_SIZE    12
 
 #define DTB_MAGIC               0xedfe0dd0
@@ -46,6 +47,7 @@
 {
 	uint32_t platform_id;
 	uint32_t variant_id;
+	uint32_t board_hw_subtype;
 	uint32_t soc_rev;
 	uint32_t offset;
 	uint32_t size;
@@ -64,7 +66,8 @@
 	DT_OP_FAILURE = -1,
 };
 
-struct dt_entry * dev_tree_get_entry_ptr(struct dt_table *);
+int dev_tree_validate(struct dt_table *table, unsigned int page_size);
+int dev_tree_get_entry_info(struct dt_table *table, struct dt_entry *dt_entry_info);
 int update_device_tree(void *, const char *, void *, unsigned);
 int dev_tree_add_mem_info(void *fdt, uint32_t offset, uint32_t size, uint32_t addr);
 void *dev_tree_appended(void *kernel, void *tags, uint32_t kernel_size);
diff --git a/platform/msm_shared/include/mmc.h b/platform/msm_shared/include/mmc.h
index f1c9762..12181b3 100644
--- a/platform/msm_shared/include/mmc.h
+++ b/platform/msm_shared/include/mmc.h
@@ -284,6 +284,7 @@
 #define CMD2_ALL_SEND_CID                2
 #define CMD3_SEND_RELATIVE_ADDR          3
 #define CMD4_SET_DSR                     4
+#define CMD5_SLEEP_AWAKE                 5
 #define CMD6_SWITCH_FUNC                 6
 #define ACMD6_SET_BUS_WIDTH              6	/* SD card */
 #define CMD7_SELECT_DESELECT_CARD        7
@@ -422,6 +423,9 @@
 #define MMC_BOOT_SD_DEV_READY             0x80000000
 #define MMC_BOOT_SD_SWITCH_HS             0x80FFFFF1
 
+/* Put the card to sleep */
+#define MMC_CARD_SLEEP                    (1 << 15)
+
 /* Data structure definitions */
 struct mmc_boot_command {
 	unsigned int cmd_index;
@@ -562,6 +566,7 @@
 #define MAX_FILE_ENTRIES          20
 
 #define MMC_RCA 2
+#define MMC_CARD_RCA_BIT                  16
 
 /* Can be used to unpack array of upto 32 bits data */
 #define UNPACK_BITS(array, start, len, size_of)                               \
@@ -618,5 +623,6 @@
 uint8_t card_supports_ddr_mode();
 uint8_t card_supports_hs200_mode();
 uint64_t mmc_get_device_capacity();
+void mmc_put_card_to_sleep(void);
 #endif
 #endif
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index b555d76..20861fc 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -262,7 +262,7 @@
 #define SDHCI_ADMA_MASK                           BIT(9)
 #define SDHCI_READ_MODE                           BIT(4)
 #define SDHCI_SWITCH_CMD                          6
-#define SDHCI_CMD_TIMEOUT                         0xE
+#define SDHCI_CMD_TIMEOUT                         0xF
 #define SDHCI_MAX_CMD_RETRY                       10000
 #define SDHCI_MAX_TRANS_RETRY                     100000
 
diff --git a/platform/msm_shared/mmc.c b/platform/msm_shared/mmc.c
index 851bb08..7783f10 100644
--- a/platform/msm_shared/mmc.c
+++ b/platform/msm_shared/mmc.c
@@ -552,8 +552,10 @@
 	/* 2a. Write command index in CMD_INDEX field */
 	cmd_index = cmd->cmd_index;
 	mmc_cmd |= cmd->cmd_index;
-	/* 2b. Set RESPONSE bit to 1 for all cmds except CMD0 */
-	if (cmd_index != CMD0_GO_IDLE_STATE) {
+	/* 2b. Set RESPONSE bit to 1 for all cmds except CMD0
+	 * And dont set RESPONSE bit for commands with no response
+	 */
+	if (cmd_index != CMD0_GO_IDLE_STATE && cmd->resp_type != MMC_BOOT_RESP_NONE) {
 		mmc_cmd |= MMC_BOOT_MCI_CMD_RESPONSE;
 	}
 
@@ -3405,3 +3407,32 @@
 {
 	return mmc_card.capacity;
 }
+
+void mmc_put_card_to_sleep(void)
+{
+	uint32_t mmc_ret;
+	struct mmc_boot_command cmd = {0};
+
+	cmd.cmd_index = CMD7_SELECT_DESELECT_CARD;
+	cmd.argument = 0x00000000;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_NONE;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS)
+	{
+		dprintf(CRITICAL, "card deselect error: %d\n", mmc_ret);
+		return;
+	}
+
+	cmd.cmd_index = CMD5_SLEEP_AWAKE;
+	cmd.argument = (mmc_card.rca << MMC_CARD_RCA_BIT) | MMC_CARD_SLEEP;
+	cmd.cmd_type = MMC_BOOT_CMD_ADDRESS;
+	cmd.resp_type = MMC_BOOT_RESP_R1B;
+
+	/* send command */
+	mmc_ret = mmc_boot_send_command(&cmd);
+	if (mmc_ret != MMC_BOOT_E_SUCCESS)
+		dprintf(CRITICAL, "card sleep error: %d\n", mmc_ret);
+}