lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20231013083320.10279-1-liuchang_125125@163.com>
Date:   Fri, 13 Oct 2023 16:33:20 +0800
From:   liuchang_125125@....com
To:     jejb@...ux.ibm.com, martin.petersen@...cle.com,
        linux-scsi@...r.kernel.org, linux-kernel@...r.kernel.org
Cc:     mark.tao@...hubtech.com, shaper.liu@...hubtech.com,
        thomas.hu@...hubtech.com, chevron.li@...hubtech.com,
        charl.liu@...hubtech.com, Charl Liu <liuchang_125125@....com>
Subject: [PATCH 3/9] scsi: bht: card: Add the source files related to card initialization

From: Charl Liu <liuchang_125125@....com>

1.card_ddr200_support: check whether the card supports DDR200/DDR225 mode
2.cardcommon: define common functions related to card initialization
3.cardinterface: implement card initialization main flow and define
the functions related to card operations
4.mmc: define the functions related to MMC/eMMC card initialization
5.output_tuning: implement card tuning flow and related functions
6.sd: implement SD legacy card initialization flow and related functions
7.thermal: define the functions related to thermal control
8.uhs2: implement SD UHS2 card initialization flow and related functions

Signed-off-by: Charl Liu <liuchang_125125@....com>
---
Change in V1:
Add the source files related to card initialization.
---
 drivers/scsi/bht/card/card_ddr200_support.c |  195 ++
 drivers/scsi/bht/card/card_ddr200_support.h |   38 +
 drivers/scsi/bht/card/cardcommon.c          |  961 ++++++
 drivers/scsi/bht/card/cardcommon.h          |  123 +
 drivers/scsi/bht/card/cardinterface.c       | 2448 +++++++++++++++
 drivers/scsi/bht/card/mmc.c                 | 1666 ++++++++++
 drivers/scsi/bht/card/output_tuning.c       |  756 +++++
 drivers/scsi/bht/card/sd.c                  | 3029 +++++++++++++++++++
 drivers/scsi/bht/card/thermal.c             |  348 +++
 drivers/scsi/bht/card/uhs2.c                | 1228 ++++++++
 10 files changed, 10792 insertions(+)
 create mode 100644 drivers/scsi/bht/card/card_ddr200_support.c
 create mode 100644 drivers/scsi/bht/card/card_ddr200_support.h
 create mode 100644 drivers/scsi/bht/card/cardcommon.c
 create mode 100644 drivers/scsi/bht/card/cardcommon.h
 create mode 100644 drivers/scsi/bht/card/cardinterface.c
 create mode 100644 drivers/scsi/bht/card/mmc.c
 create mode 100644 drivers/scsi/bht/card/output_tuning.c
 create mode 100644 drivers/scsi/bht/card/sd.c
 create mode 100644 drivers/scsi/bht/card/thermal.c
 create mode 100644 drivers/scsi/bht/card/uhs2.c

diff --git a/drivers/scsi/bht/card/card_ddr200_support.c b/drivers/scsi/bht/card/card_ddr200_support.c
new file mode 100644
index 000000000000..b7fb935d700c
--- /dev/null
+++ b/drivers/scsi/bht/card/card_ddr200_support.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: card_ddr200_support.c
+ *
+ * Abstract: check whether the card supports DDR200/DDR225 mode
+ *
+ * Version: 1.00
+ *
+ * Author: Fred
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 12/17/2021   Creation    Fred
+ */
+
+#include "../include/basic.h"
+#include "../include/hostapi.h"
+#include "../include/debug.h"
+#include "card_ddr200_support.h"
+
+bool sandisk_ddr_support(sd_card_t *card, bool ddr_mode)
+{
+	bool ret = FALSE;
+	u32 prv_tmp;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"oemid is 0x%04x,\n"
+		"prod_name[0] is %x,\n"
+		"prod_name[1] is %x,\n"
+		"prod_name[2] is %x,\n"
+		"prod_name[3] is %x,\n"
+		"prod_name[4] is %x,\n"
+		"prv is 0x%x\n", card->info.cid.oemid,
+		card->info.cid.prod_name[0], card->info.cid.prod_name[1],
+		card->info.cid.prod_name[2], card->info.cid.prod_name[3],
+		card->info.cid.prod_name[4], card->info.cid.prv);
+
+	/*
+	 * check whether support DDR200 or DDR225
+	 * support DDR200 mode if prv is 0x85
+	 * support DDR225 mode if prv is 0x86
+	 */
+	if (ddr_mode)
+		prv_tmp = 0x85;
+	else
+		prv_tmp = 0x86;
+
+	if (card->info.cid.oemid == 0x4453
+	    && card->info.cid.prod_name[0] == 0x53
+	    && (card->info.cid.prod_name[1] == 0x4E
+		|| card->info.cid.prod_name[1] == 0x46
+		|| card->info.cid.prod_name[1] == 0x52))
+		ret = TRUE;
+	else if ((card->info.cid.oemid == 0x4453
+		  || card->info.cid.oemid == 0x5744)
+		 && card->info.cid.prv == prv_tmp)
+		ret = TRUE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool lexar_transend_ddr200_support(sd_card_t *card)
+{
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"reserved is 0x%x, Group 2 vendor spcific is 0x%x\n",
+		card->info.cid.reserved,
+		card_info->sw_func_cap.sd_command_system);
+
+	if ((card->info.cid.reserved == 0xA)
+	    && ((card_info->sw_func_cap.sd_command_system) & (1 << 6)))
+		ret = TRUE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool phison_kingston_ddr200_support(sd_card_t *card)
+{
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"sd_specx is 0x%04x, reserved_B0 is 0x%04x, reserved_B1 is 0x%04x\n",
+		card_info->scr.sd_specx, card_info->scr.reserved_B0,
+		card_info->scr.reserved_B1);
+
+	if ((card_info->scr.sd_specx >= 2)
+	    && (card_info->scr.reserved_B0 == 0x32)
+	    && (card_info->scr.reserved_B1 == 0x64))
+		ret = TRUE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool manuefecture_ddr200_support(sd_card_t *card, u32 check_methood)
+{
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	card->ddr225_card_flag = FALSE;
+
+	if (card->info.cid.prv == 0x86) {
+		ret = sandisk_ddr_support(card, FALSE);
+		if (ret) {
+			card->ddr225_card_flag = TRUE;
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"DDR225 Check Stag: host support DDR225 mode\n");
+		} else {
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"DDR225 Check Stag: host not support DDR225 mode\n");
+		}
+
+		goto exit;
+	}
+
+	switch (check_methood) {
+	case SANDISK:
+		ret = sandisk_ddr_support(card, TRUE);
+		break;
+	case LEXAR:
+	case TRANSEND:
+		ret = lexar_transend_ddr200_support(card);
+		break;
+	case PHISON:
+	case KINGSTON:
+		ret = phison_kingston_ddr200_support(card);
+		break;
+	default:
+		break;
+	}
+
+exit:
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool sd_ddr_support(sd_card_t *card)
+{
+	byte i = 0;
+	bool ret = FALSE;
+	sd_host_t *host = card->host;
+	card_info_t *card_info = &(card->info);
+	cfg_item_t *cfg = card->host->cfg;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if ((sdhci_readl(host, 0x110) & (1 << 16)) &&
+	    (sdhci_readl(host, 0x3e) & (1 << 3))) {
+		if ((card_info->sw_func_cap.sd_access_mode & (1 << 3)) &&
+		    (card_info->sw_func_cap.sd_command_system) & (1 << 6)) {
+			while (i <= MAX_DDR200_CHECK_METHOD) {
+				ret = manuefecture_ddr200_support(card, i);
+				if (ret)
+					break;
+
+				i++;
+			}
+		}
+	}
+
+	/*
+	 * 1.card support DDR200
+	 * 2.driver registry control
+	 */
+	if (ret && (cfg->card_item.test_max_access_mode.value == 0x5))
+		ret = TRUE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+
+	return ret;
+}
diff --git a/drivers/scsi/bht/card/card_ddr200_support.h b/drivers/scsi/bht/card/card_ddr200_support.h
new file mode 100644
index 000000000000..a984a0dc01b4
--- /dev/null
+++ b/drivers/scsi/bht/card/card_ddr200_support.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: card_ddr200_support.h
+ *
+ * Abstract: the functon declaration about checking whether the card supports DDR200/DDR225 mode
+ *
+ * Version: 1.00
+ *
+ * Author: Fred
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 12/17/2021   Creation    Fred
+ */
+
+#ifndef _CARD_DDR200_SUPPORT_H
+#define _CARD_DDR200_SUPPORT_H
+
+#include "../include/card.h"
+
+#define MAX_DDR200_CHECK_METHOD 0x4
+#define SANDISK		0x0
+#define LEXAR		0x1
+#define TRANSEND	0x2
+#define PHISON		0x3
+#define KINGSTON	0x4
+
+bool sandisk_ddr_support(sd_card_t *card, bool ddr_mode);
+bool lexar_transend_ddr200_support(sd_card_t *card);
+bool phison_kingston_ddr200_support(sd_card_t *card);
+bool sd_ddr_support(sd_card_t *card);
+bool manuefecture_ddr200_support(sd_card_t *card, u32 check_methood);
+
+#endif
diff --git a/drivers/scsi/bht/card/cardcommon.c b/drivers/scsi/bht/card/cardcommon.c
new file mode 100644
index 000000000000..7a5d4a444b0c
--- /dev/null
+++ b/drivers/scsi/bht/card/cardcommon.c
@@ -0,0 +1,961 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: cardcommon.c
+ *
+ * Abstract: define card related common functions
+ *
+ * Version: 1.00
+ *
+ * Author: Samuel
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 9/2/2014   Creation    Samuel
+ */
+
+#include "../include/basic.h"
+#include "../include/hostapi.h"
+#include "../include/cmdhandler.h"
+#include "../include/debug.h"
+#include "../include/util.h"
+#include "../include/tqapi.h"
+#include "../include/transhapi.h"
+#include "cardcommon.h"
+
+bool card_need_get_info(sd_card_t *card)
+{
+	if ((card->quick_init) && (card->initialized_once))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+bool card_send_command12(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool ret = FALSE;
+	u32 status = 0;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	ret = card_send_sdcmd(card, sd_cmd, SD_CMD12, 0,
+			      CMD_FLG_R1B | CMD_FLG_RESCHK, DATA_DIR_NONE, NULL,
+			      0);
+
+	if (ret == FALSE) {
+		if ((sd_cmd->err.resp_err & RESP_ERR_TYPE_OUT_OF_RANGE) ==
+		    RESP_ERR_TYPE_OUT_OF_RANGE) {
+			ret = card_get_card_status(card, sd_cmd, &status);
+		}
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool card_send_sdcmd_timeout(sd_card_t *card,
+			     sd_command_t *sd_cmd,
+			     byte cmd_index,
+			     u32 argument,
+			     u32 cmdflag,
+			     e_data_dir dir,
+			     byte *data, u32 datalen, u32 timeout)
+{
+
+	sd_data_t sd_data;
+	bool ret;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Enter %s cmd=0x%02X arg=0x%08X\n", __func__, cmd_index,
+		argument);
+
+	/* Avoid  recursion call */
+	if (card->has_built_inf && cmd_index != SD_CMD12) {
+		ret = card_send_command12(card, sd_cmd);
+		if (ret == FALSE)
+			goto exit;
+	}
+
+	os_memset(sd_cmd, 0, sizeof(sd_command_t));
+
+	sd_cmd->cmd_flag = cmdflag;
+	sd_cmd->cmd_index = cmd_index;
+	sd_cmd->argument = argument;
+	sd_cmd->sd_cmd = 1;
+	sd_cmd->timeout = timeout;
+
+	if (dir == DATA_DIR_NONE)
+		sd_cmd->data = NULL;
+	else {
+		os_memset(&sd_data, 0, sizeof(sd_data_t));
+		sd_cmd->data = &sd_data;
+		sd_data.dir = dir;
+		sd_data.data_mng.driver_buff = data;
+		sd_data.data_mng.total_bytess = datalen;
+		if (cmdflag & CMD_FLG_ADMA_SDMA) {
+			ret =
+			    build_dma_ctx(card->host->pdx, &sd_data, cmdflag,
+					  dir, data, datalen, 0, 0);
+			if (ret == FALSE) {
+				DbgErr("build adma io error\n");
+				ret = FALSE;
+				goto exit;
+			}
+		}
+
+		if (sd_cmd->cmd_flag & CMD_FLG_DDR200_WORK_AROUND)
+			sd_cmd->gg8_ddr200_workaround = 1;
+	}
+
+	ret = cmd_generate_reg(card, sd_cmd);
+	if (ret == FALSE)
+		goto exit;
+
+	ret = cmd_execute_sync(card, sd_cmd, NULL);
+
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Exit(%d) %s\n", ret, __func__);
+	return ret;
+
+}
+
+bool card_send_sdcmd_dma_timeout(sd_card_t *card,
+				 sd_command_t *sd_cmd,
+				 sd_data_t *sd_data,
+				 byte cmd_index,
+				 u32 argument,
+				 u32 cmdflag,
+				 e_data_dir dir,
+				 byte *data, u32 datalen, u32 timeout)
+{
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Enter %s cmd=0x%02X arg=0x%08X\n", __func__, cmd_index,
+		argument);
+
+	/* Avoid recursion call */
+	if (card->has_built_inf && cmd_index != SD_CMD12) {
+		ret = card_send_command12(card, sd_cmd);
+		if (ret == FALSE)
+			goto exit;
+	}
+
+	os_memset(sd_cmd, 0, sizeof(sd_command_t));
+
+	sd_cmd->cmd_flag = cmdflag;
+	sd_cmd->cmd_index = cmd_index;
+	sd_cmd->argument = argument;
+	sd_cmd->sd_cmd = 1;
+	sd_cmd->timeout = timeout;
+
+	if (dir == DATA_DIR_NONE)
+		sd_cmd->data = NULL;
+	else {
+		sd_cmd->data = sd_data;
+		sd_data->dir = dir;
+		/* sd_data->data_mng.driver_buff = data; */
+		sd_data->data_mng.total_bytess = datalen;
+	}
+
+	ret = cmd_generate_reg(card, sd_cmd);
+	if (ret == FALSE)
+		goto exit;
+
+	ret = cmd_execute_sync(card, sd_cmd, NULL);
+
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Exit(%d) %s\n", ret, __func__);
+	return ret;
+
+}
+
+/*
+ * Function Name: card_send_sdcmd
+ *
+ * Abstract: Issue command
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to the sd command structure. the caller need to check it's status.
+ * byte cmd_index: Command Index
+ * u32 argument: Command argument
+ * u32 cmdflag: Command flags, like response tpye, DMA or PIO
+ * e_data_dir dir: data direction: NONE/IN/OUT
+ * byte *data: Pointer to the data buffer for data command
+ * u32 datalen: Data length for transfer.
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if command successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller:
+ *
+ */
+
+bool card_send_sdcmd(sd_card_t *card,
+		     sd_command_t *sd_cmd,
+		     byte cmd_index,
+		     u32 argument,
+		     u32 cmdflag, e_data_dir dir, byte *data, u32 datalen)
+{
+	return card_send_sdcmd_timeout(card, sd_cmd, cmd_index, argument,
+				       cmdflag, dir, data, datalen, 0);
+}
+
+bool card_wr_protect(sd_card_t *card)
+{
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	if (card_info->csd.temp_protect || card_info->csd.parm_protect)
+		ret = TRUE;
+
+	return ret;
+}
+
+bool card_reset_card(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	byte cmd_index = (byte) (SD_CMD0);
+	u32 argument = 0;
+	u32 cmdflag = 0;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool card_all_send_cid(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD2;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R2;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	card_info_t *card_info = &(card->info);
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue CMD2 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		os_memcpy(&(card_info->raw_cid[0]), &(sd_cmd->response[0]), 16);
+		card_info->cid.manfid = card_info->raw_cid[0];
+		card_info->cid.oemid =
+		    card_info->raw_cid[1] | (card_info->raw_cid[2] << 8);
+		os_memcpy(card_info->cid.prod_name, &(card_info->raw_cid[3]), 5);
+		card_info->cid.prv = card_info->raw_cid[8];
+		card_info->cid.serial =
+		    card_info->raw_cid[9] |
+			(card_info->raw_cid[10] << 8) |
+		    (card_info->raw_cid[11] << 16) |
+			(card_info->raw_cid[12] << 24);
+		card_info->cid.reserved = card_info->raw_cid[13] >> 4;
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ * Function Name: card_get_rca
+ *
+ * Abstract: Ask the card to publish a new relative address RCA (CMD3)
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: sd_card_identify
+ *
+ */
+
+bool card_get_rca(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD3;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R6 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+
+	bool ret = FALSE;
+
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue CMD3 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		/* Update the card RCA */
+		card_info->rca = (sd_cmd->response[0] & 0xFFFF0000) >> 16;
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ * Function Name: card_select_card
+ *
+ * Abstract: Select card (CMD7)
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: sd_card_select
+ *
+ */
+
+bool card_select_card(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD7;
+	u32 argument = 0;
+	u32 cmdflag = 0;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->card_type == CARD_UHS2)
+		cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	else
+		cmdflag = CMD_FLG_R1B | CMD_FLG_RESCHK;
+	argument = (card_info->rca) << 16;
+
+	/* Issue CMD7 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret == TRUE) {
+		/* Get Lock/Unlock status, CMD7 Response [25].
+		 * Check bit 25 of CMD7 response.
+		 */
+		if (sd_cmd->response[0] & BIT25)
+			card->locked = TRUE;
+		else
+			card->locked = FALSE;
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit(%d) %s locked=%d\n", ret, __func__, card->locked);
+	return ret;
+}
+
+/*
+ * Function Name: card_deselect_card
+ *
+ * Abstract: De-Select card (CMD7)
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: sd_read_csd
+ *
+ */
+
+bool card_deselect_card(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD7;
+	u32 argument = 0;
+	u32 cmdflag = 0;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	cmdflag = 0;
+	argument = 0;
+
+	/* Issue CMD7 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit(%d) %s locked=%d\n", ret, __func__, card->locked);
+	return ret;
+}
+
+/*
+ * Function Name: card_set_csd_info
+ *
+ * Abstract: Acquired CSD Data, to be stored into Struct of CSD and Card.
+ *			Save some contents of CSD Register into Struct of CSD,
+ *			and generate(calcurate) necessary Data to save into Struct of Card.
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * unsigned char  *csdbuff: CSD Buffer Pointer
+ * csd_t *csd_info: CSD information Pointer
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: card_get_csd
+ *
+ */
+
+static void card_set_csd_info(sd_card_t *card, unsigned char *csdbuff,
+csd_t *csd_info)
+{
+	u32 blocknr, mult, block_len, dummy1, dummy2;
+	byte i;
+	u32 value, unit;
+	byte taac_value, taac_unit;
+	u64 tmpsize;
+
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	value = unit = taac_value = taac_unit = 0;
+	mult = block_len = 1;
+	blocknr = dummy1 = dummy2 = 0;
+
+	/* Store the CSD information to Struct of CSD */
+
+	/* Get "CSD Structure" */
+	csd_info->csd_structure = ((csdbuff[0] & 0xC0) >> 6);
+
+	/* Get MMC "Spec_Vers" ( = System Specification version ) */
+	csd_info->mmc_spec_vers = ((csdbuff[0] & 0x3C) >> 2);
+
+	/* Get "TRAN SPEED" */
+	csd_info->tran_speed = csdbuff[3];
+
+	/* Get "TAAC" */
+	csd_info->taac = csdbuff[1];
+
+	/* Get "NSAC" */
+	csd_info->nsac = csdbuff[2];
+
+	/* Get "read_bl_len" */
+	csd_info->read_bl_len = (csdbuff[5] & 0x0F);
+
+	/* Get "PERM_WRITE_PROTECT" */
+	csd_info->parm_protect = (csdbuff[14] & 0x20) >> 5;
+
+	/* Get "TMP_WRITE_PROTECT" */
+	csd_info->temp_protect = (csdbuff[14] & 0x10) >> 4;
+
+	/* Get "c_size" */
+	csd_info->c_size = 0;
+
+	if (card->card_type == CARD_SD || card->card_type == CARD_UHS2) {
+		if (csd_info->csd_structure == 0) {
+			/* CSD Version 1.0 (Standard Capacity) */
+			dummy1 = (csdbuff[6] & 0x03);
+			dummy1 = (dummy1 << 10);
+			dummy2 = csdbuff[7];
+			dummy2 = (dummy2 << 2);
+			dummy2 = (dummy1 | dummy2);
+			csd_info->c_size =
+			    (dummy2 | ((csdbuff[8] & 0xC0) >> 6));
+		} else {
+			/* CSD Version 2.0 (High Capacity and Extended Capacity) */
+			dummy1 = (csdbuff[7] & 0x3F);
+			dummy1 = (dummy1 << 16);
+			dummy2 = csdbuff[8];
+			dummy2 = (dummy2 << 8);
+			dummy2 = (dummy1 | dummy2);
+			csd_info->c_size = (dummy2 | (csdbuff[9] & 0xFF));
+		}
+	} else if ((card->card_type == CARD_MMC) ||
+		   (card->card_type == CARD_EMMC)
+	    ) {
+		if (card_info->card_ccs == 0) {
+			/* (Standard Capacity) */
+			dummy1 = (csdbuff[6] & 0x03);
+			dummy1 = (dummy1 << 10);
+			dummy2 = csdbuff[7];
+			dummy2 = (dummy2 << 2);
+			dummy2 = (dummy1 | dummy2);
+			csd_info->c_size =
+			    (dummy2 | ((csdbuff[8] & 0xC0) >> 6));
+		} else {
+			/* (High Capacity and Extended Capacity) */
+			dummy1 = (csdbuff[7] & 0x3F);
+			dummy1 = (dummy1 << 16);
+			dummy2 = csdbuff[8];
+			dummy2 = (dummy2 << 8);
+			dummy2 = (dummy1 | dummy2);
+			csd_info->c_size = (dummy2 | (csdbuff[9] & 0xFF));
+		}
+
+	}
+
+	/* Get "sect_size" */
+	if ((card->card_type == CARD_MMC) || (card->card_type == CARD_EMMC)
+	    ) {
+		/* MMC */
+		csd_info->sector_size = ((csdbuff[10] & 0x7C) >> 2);
+	} else {
+		/* SD Memory Card */
+		csd_info->sector_size = (((csdbuff[10] & 0x3f) << 1) |
+					 ((csdbuff[11] & 0x80) >> 7));
+	}
+
+	/* Get "c_size_mult" */
+	if (card->card_type == CARD_SD || card->card_type == CARD_UHS2) {
+		if (csd_info->csd_structure == 0) {
+			/* CSD Version 1.0 (Standard Capacity) */
+			csd_info->c_size_mult = (((csdbuff[9] & 0x03) << 1) |
+						 ((csdbuff[10] & 0x80) >> 7));
+		} else {
+			/* CSD Version 2.0 (High Capacity and Extended Capacity) */
+			/* not exist */
+			;
+		}
+	} else if ((card->card_type == CARD_MMC) ||
+		   (card->card_type == CARD_EMMC)
+	    ) {
+
+		if (card_info->card_ccs == 0) {
+			/* CSD Version 1.0 (Standard Capacity) */
+			csd_info->c_size_mult = (((csdbuff[9] & 0x03) << 1) |
+						 ((csdbuff[10] & 0x80) >> 7));
+		} else {
+			/* CSD Version 2.0 (High Capacity and Extended Capacity) */
+			/* not exist */
+			;
+		}
+	}
+
+	/*
+	 * Acquired CSD Data, to be stored into Struct of CSD and Card
+	 * Save some contents of CSD Register into Struct of CSD, and
+	 * generate(calcurate) necessary Data to save into Struct of Card
+	 */
+
+	/* Calcuration of Total Sector count & Card Size */
+	if (card->card_type == CARD_SD || card->card_type == CARD_UHS2) {
+		if (csd_info->csd_structure == 0) {
+			/* CSD Version 1.0 (Standard Capacity) */
+			for (i = 0; i < (csd_info->c_size_mult + 2); i++)
+				mult = mult * 2;
+			for (i = 0; i < csd_info->read_bl_len; i++)
+				block_len = block_len * 2;
+			blocknr = (csd_info->c_size + 1) * mult;
+			/* Card Size (Byte) */
+
+			card->sec_count = ((u64) (blocknr) * (u64) (block_len));
+		} else {
+			/* CSD Version 2.0 (High Capacity and Extended Capacity) */
+
+			/* Card Size (Byte) */
+
+			/* (c_size + 1) * 512K */
+			tmpsize = ((u64) csd_info->c_size) + 1;
+			card->sec_count = tmpsize * 524288;
+		}
+	} else if ((card->card_type == CARD_MMC) ||
+		   (card->card_type == CARD_EMMC)
+	    ) {
+		if (card_info->card_ccs == 0) {
+			/* CSD Version 1.0 (Standard Capacity) */
+			for (i = 0; i < (csd_info->c_size_mult + 2); i++)
+				mult = mult * 2;
+			for (i = 0; i < csd_info->read_bl_len; i++)
+				block_len = block_len * 2;
+			blocknr = (csd_info->c_size + 1) * mult;
+
+			/* Card Size (Byte) */
+
+			card->sec_count = ((u64) (blocknr) * (u64) (block_len));
+		} else {
+			/* sector size will calculate at MMC_Set_CSDEXT() */
+			;
+		}
+	}
+
+	/* Total sector count of Card */
+	card->sec_count = ((card->sec_count) / (SD_BLOCK_LEN));
+	/* SD_INFO_PRINTF("Card_Info.sect_num = %x\n", Card_Info.sect_num); */
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s CardSectors: %d, %dGB\n", __func__,
+		card->sec_count, card->sec_count / 2 / 1024 / 1024);
+
+}
+
+/*
+ * Function Name: card_get_csd
+ *
+ * Abstract: Addressed card sends its card-specific data (CSD) on the CMD line (CMD9)
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: sd_read_csd
+ *
+ */
+
+bool card_get_csd(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD9;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R2;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	argument = card_info->rca << 16;
+
+	/* Issue CMD9 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		/* Set the card CSD info */
+		os_memcpy(&(card_info->raw_csd[0]), &(sd_cmd->response[0]), 16);
+		/* Parse the CSD info */
+		card_set_csd_info(card, card_info->raw_csd, &(card_info->csd));
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ * Function Name: card_get_card_status
+ *
+ * Abstract: Read the SD Status Register (SSR) (ACMD13)
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: card_check_rw_ready
+ *
+ */
+
+bool card_get_card_status(sd_card_t *card,
+			  sd_command_t *sd_cmd, u32 *card_status)
+{
+
+	byte cmd_index = SD_CMD13;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue CMD13 */
+	argument = (card_info->rca << 16);
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		/* Send the card status */
+		os_memcpy(card_status, &(sd_cmd->response[0]), 4);
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool card_check_rw_ready(sd_card_t *card, sd_command_t *sd_cmd,
+			 int timeout_ms)
+{
+	bool result = FALSE;
+	u32 card_status = 0;
+	loop_wait_t wait;
+	u32 delay_us = 10;
+
+	util_init_waitloop(card->host->pdx, timeout_ms, delay_us, &wait);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM,
+		"Enter %s, timeout_ms=%d\n", __func__, timeout_ms);
+
+	do {
+		result = card_get_card_status(card, sd_cmd, &card_status);
+		if (result == FALSE)
+			goto exit;
+
+		os_udelay(delay_us);
+	} while (((card_status & 0x900) != 0x900) && (!util_is_timeout(&wait)));
+
+	if ((card_status & 0x900) != 0x900)
+		result = FALSE;
+
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ * Function Name: card_set_block_len
+ *
+ * Abstract: Set the block length for all following block commands (ACMD6, block length = 5126)
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ * u32 arg: SD_BLOCK_LEN
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: sd_init_get_info
+ *
+ */
+
+bool card_set_block_len(sd_card_t *card, sd_command_t *sd_cmd, u32 arg)
+{
+	byte cmd_index = SD_CMD16;
+	u32 argument = arg;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, arg=0x%x\n", __func__, arg);
+
+	/* Issue CMD16 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (!ret)
+		DbgErr("Set Block Length(CMD6) %d Error!!", argument);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ * Function Name: card_get_legacy_freq
+ *
+ * Abstract:
+ *           1. Set the specific clock frequency
+ *           2. Set DM/DN and Clock Divider
+ *
+ * Input:
+ *
+ * sd_card_t *card: Pointer to the card structure
+ * u32 clk_freq_khz: clock frequency to be set (KHz)
+ * bool ddr_mode: if it is DDR50 mode (100MHz same as SDR50), need to check max frequency for DDR50
+ *
+ * Output: DMDN Values
+ *
+ * Return value: BIT[31:16]:dmdn BIT[14:0] basediv
+ *
+ * Notes:
+ *
+ * Caller: card_legacy_change_clock
+ *
+ */
+
+static u32 card_get_legacy_freq(sd_card_t *card, u32 clk_freq_khz,
+				bool ddr_mode)
+{
+	u32 value = 0;
+	u16 index = 0;
+	sd_host_t *host = card->host;
+	u16 freq_level = card->degrade_freq_level;
+	/* cfg_max_freq_item_t  * freq = &(host->cfg->host_item.max_freq_item); */
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, Clock frequency %d KHz, ddr50_mode=%\n",
+		__func__, clk_freq_khz, ddr_mode);
+	if (host->cfg == NULL || host->cfg->dmdn_tbl == NULL) {
+		DbgErr("host cfg is null\n");
+		return 0;
+	}
+
+	/* Set DM/DN according to the clock frequency */
+	switch (clk_freq_khz) {
+	case SD_CLK_ID_400K:
+		value = host->cfg->dmdn_tbl[FREQ_400K_START_INDEX];
+		break;
+	case SD_CLK_50M:
+		if (ddr_mode)
+			value = host->cfg->dmdn_tbl[FREQ_DDR50M_START_INDEX];
+		else
+			value = host->cfg->dmdn_tbl[FREQ_50M_START_INDEX];
+		break;
+
+	case SD_CLK_100M:
+		index = (u16) FREQ_100M_START_INDEX + freq_level;
+		if (index > (u16) FREQ_100M_DEGRE_INDEX)
+			index = (u16) FREQ_100M_DEGRE_INDEX;
+		value = host->cfg->dmdn_tbl[index];
+		break;
+
+	case SD_CLK_200M:
+		if (ddr_mode) {
+			index = (u16) FREQ_DDR200M_START_INDEX + freq_level;
+			if (index > (u16) FREQ_DDR200M_DEGRE_INDEX)
+				index = (u16) FREQ_DDR200M_DEGRE_INDEX;
+			value = host->cfg->dmdn_tbl[index];
+		} else {
+			index = (u16) FREQ_200M_START_INDEX + freq_level;
+			if (index > (u16) FREQ_200M_DEGRE_INDEX)
+				index = (u16) FREQ_200M_DEGRE_INDEX;
+			value = host->cfg->dmdn_tbl[index];
+		}
+		break;
+	case SD_CLK_225M:
+		index = (u16) FREQ_DDR225M_START_INDEX + freq_level;
+		if (index > (u16) FREQ_DDR225M_DEGRE_INDEX)
+			index = (u16) FREQ_DDR225M_DEGRE_INDEX;
+		value = host->cfg->dmdn_tbl[index];
+		break;
+
+	case SD_CLK_75M:
+		value = host->cfg->dmdn_tbl[FREQ_75M_START_INDEX];
+		break;
+
+	default:
+		value = host->cfg->dmdn_tbl[FREQ_25M_START_INDEX];
+		break;
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, TO_RAM,
+		"%s Exit  Clock=%d (KHz): value=0x%08X\n", __func__,
+		clk_freq_khz, value);
+
+	return value;
+
+}
+
+/*
+ * Function Name: card_legacy_change_clock
+ *
+ * Abstract:
+ *           1. Stop clock
+ *           2. Set the clock frequency (DM/DN, clk divider)
+ *           3. Start the clock
+ *
+ * Input:
+ *
+ * sd_card_t *card: Pointer to the card structure
+ * u32 clk_freq_khz: clock frequency to be set (KHz)
+ * bool ddr_mode: if it is DDR200/DDR50 mode (100MHz same as SDR50),
+ *					need to check max frequency for DDR200/DDR50
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: sd_init_stage2
+ *
+ */
+
+void card_legacy_change_clock(sd_card_t *card, u32 clk_freq_khz, bool ddr_mode)
+{
+	u32 value;
+	sd_host_t *host = card->host;
+
+	value = card_get_legacy_freq(card, clk_freq_khz, ddr_mode);
+	host_change_clock(host, value);
+
+}
diff --git a/drivers/scsi/bht/card/cardcommon.h b/drivers/scsi/bht/card/cardcommon.h
new file mode 100644
index 000000000000..985411bb0802
--- /dev/null
+++ b/drivers/scsi/bht/card/cardcommon.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: cardcommon.h
+ *
+ * Abstract: Include card related common functions.
+ *
+ * Version: 1.00
+ *
+ * Author: Samuel
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 9/2/2014   Creation    Samuel
+ */
+
+#ifndef _CARDCOMMON_H
+#define _CARDCOMMON_H
+
+#include "../include/card.h"
+
+/* SD Legacy (UHSI, HS, DS) card initialization */
+bool sd_legacy_init(sd_card_t *card);
+
+/* MMC or eMMC card initialization */
+bool emmc_init(sd_card_t *card, bool bemmc);
+bool emmc_init_stage2(sd_card_t *card);
+bool emmc_tuning(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool sd_tuning(sd_card_t *card, sd_command_t *sd_cmd, u32 timeout);
+
+bool card_get_card_status(sd_card_t *card,
+			  sd_command_t *sd_cmd, u32 *card_status);
+
+bool card_reset_card(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool card_all_send_cid(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool card_get_rca(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool card_select_card(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool card_get_csd(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool card_send_command12(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool card_set_block_len(sd_card_t *card, sd_command_t *sd_cmd, u32 arg);
+
+bool uhs2_card_init(sd_card_t *card);
+void card_power_on(sd_card_t *card);
+
+/*
+ * (1) If uhs2 call uhs2 cmd handler
+ * (2) generate sd_cmd_t structure and sd_data structure(pio only)
+ * (3) call cmd_generate_reg(sd_cmd)
+ * (4) call cmd_execute
+ * (5) do error recover if necessary
+ * (6) return result
+ */
+
+bool card_send_sdcmd(sd_card_t *card,
+		     sd_command_t *sd_cmd,
+		     byte cmd_index,
+		     u32 argument,
+		     u32 cmdflag, e_data_dir dir, byte *data, u32 datalen);
+
+bool uhs2_native_ccmd(sd_card_t *card, sd_command_t *sd_cmd,
+		      u16 ioaddr, bool broadcast, bool rwcmd, byte payload_num,
+		      u32 *payload);
+
+bool card_send_sdcmd_dma_timeout(sd_card_t *card,
+				 sd_command_t *sd_cmd,
+				 sd_data_t *sd_data,
+				 byte cmd_index,
+				 u32 argument,
+				 u32 cmdflag,
+				 e_data_dir dir,
+				 byte *data, u32 datalen, u32 timeout);
+
+bool card_select_card(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool sd_switch_function_check(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool sd_switch_function_set_pl(sd_card_t *card,
+			       sd_command_t *sd_cmd, byte power_limit);
+
+bool card_wr_protect(sd_card_t *card);
+
+bool sd_card_identify(sd_card_t *card);
+
+bool sd_init_get_info(sd_card_t *card);
+
+bool sd_init_stage2(sd_card_t *card);
+
+bool uhs2_enter_dmt(sd_card_t *card, sd_command_t *sd_cmd, sd_host_t *host,
+		    bool hbr);
+bool uhs2_resume_dmt(sd_card_t *card, sd_command_t *sd_cmd, sd_host_t *host,
+		     bool hbr);
+
+bool sd_card_select(sd_card_t *card);
+bool uhs2_init_stage2(sd_card_t *card);
+bool uhs2_full_reset_card(sd_card_t *card);
+
+bool sd_switch_power_limit(sd_card_t *card, sd_command_t *sd_cmd, bool *bchg);
+
+bool card_check_rw_ready(sd_card_t *card, sd_command_t *sd_cmd,
+			 int timeout_ms);
+
+void card_legacy_change_clock(sd_card_t *card, u32 clk_freq_khz,
+			      bool ddr50_mode);
+
+bool card_need_get_info(sd_card_t *card);
+
+bool card_deselect_card(sd_card_t *card, sd_command_t *sd_cmd);
+
+bool sd_program_csd(sd_card_t *card, sd_command_t *sd_cmd, byte *data);
+
+bool sd_read_csd(sd_card_t *card, sd_command_t *sd_cmd, byte *data);
+
+#endif
diff --git a/drivers/scsi/bht/card/cardinterface.c b/drivers/scsi/bht/card/cardinterface.c
new file mode 100644
index 000000000000..6c8ee43f2e11
--- /dev/null
+++ b/drivers/scsi/bht/card/cardinterface.c
@@ -0,0 +1,2448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: cardinterface.c
+ *
+ * Abstract:
+ *           1. Card initialization main entry
+ *           2. Interface for card operations
+ *
+ * Version: 1.00
+ *
+ * Author: Samuel
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 9/3/2014   Creation    Samuel
+ */
+
+#include "../include/basic.h"
+#include "../include/card.h"
+#include "../include/cardapi.h"
+#include "../include/hostapi.h"
+#include "../include/transhapi.h"
+#include "../include/hostvenapi.h"
+#include "../include/util.h"
+#include "../include/debug.h"
+#include "../include/cmdhandler.h"
+#include "../host/hostven.h"
+#include "../include/card.h"
+#include "../host/hostreg.h"
+#include "../include/funcapi.h"
+#include "../tagqueue/tq_trans_api.h"
+#include "../include/cmdhandler.h"
+#include "cardcommon.h"
+
+/* Thomas add for direct remove 7.0 */
+extern void bht_sd_remove(struct pci_dev *pdev);
+
+bool sd_thermal_control(sd_card_t *card);
+void uhs2_degrade_policy(sd_card_t *card, sd_command_t *sd_cmd);
+bool uhs2_sd_error_recovery(sd_card_t *card, sd_command_t *sd_cmd);
+void sd_degrade_policy(sd_card_t *card);
+void mmc_degrade_policy(sd_card_t *card);
+u32 card_get_uhs2_freq(sd_card_t *card);
+u32 sdr104_sdr50_output_tuning(sd_card_t *card, u32 address);
+u32 ddr200_output_tuning(sd_card_t *card, u32 address);
+
+bool sd_dll_divider(sd_card_t *card, sd_command_t *pcmd);
+
+byte tuning_address_content_buf[512] = { 0 };
+
+bool store_tuning_address_content(sd_card_t *card, u64 tuning_address)
+{
+	bool ret = 0;
+	sd_command_t sd_cmd;
+	u32 cmdflag;
+	sd_host_t *host = card->host;
+
+	card->read_signal_block_flag = TRUE;
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	/* Save Current DMA mode */
+	host_transfer_init(card->host, FALSE, TRUE);
+	cmdflag = CMD_FLG_RESCHK | CMD_FLG_R1 | CMD_FLG_ADMA_SDMA;
+
+	ret =
+	    card_send_sdcmd_timeout(card, &sd_cmd, SD_CMD17,
+				    (u32) tuning_address, (cmdflag),
+				    DATA_DIR_IN, tuning_address_content_buf,
+				    512, 500);
+	if (ret == FALSE) {
+		host_reset(host, SDHCI_RESET_CMD);
+		host_reset(host, SDHCI_RESET_DATA);
+		card->read_signal_block_flag = FALSE;
+		DbgErr("Read data FAILED when store tuning address content\n");
+	}
+
+	/* Resorte current DMA mode */
+	host_transfer_init(card->host, card->inf_trans_enable, FALSE);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return ret;
+}
+
+bool restore_tuning_address_content(sd_card_t *card, u64 tuning_address)
+{
+	bool ret = 0;
+	int i = 0;
+	sd_command_t sd_cmd;
+	u32 cmdflag;
+	byte tuning_temp_buf[512];
+	bool gg8_ddr200 = 0;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->host->chip_type == CHIP_GG8
+	    && card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_DDR200) {
+		/* Save Current DMA mode */
+		host_transfer_init(card->host, TRUE, FALSE);
+		gg8_ddr200 = 1;
+		cmdflag =
+		    CMD_FLG_RESCHK | CMD_FLG_R1 | CMD_FLG_ADMA_SDMA |
+		    CMD_FLG_DDR200_WORK_AROUND | CMD_FLG_INF_BUILD;
+	} else {
+		/* Save Current DMA mode */
+		host_transfer_init(card->host, FALSE, TRUE);
+		cmdflag = CMD_FLG_RESCHK | CMD_FLG_R1 | CMD_FLG_ADMA_SDMA;
+	}
+
+	ret =
+	    card_send_sdcmd_timeout(card, &sd_cmd,
+				    gg8_ddr200 ? SD_CMD25 : SD_CMD24,
+				    (u32) tuning_address, (cmdflag),
+				    DATA_DIR_OUT, tuning_address_content_buf,
+				    512, 500);
+	if (ret == FALSE) {
+		DbgErr
+		    ("Write data FAILED when restore tuning address content\n");
+		goto exit;
+	}
+
+	ret =
+	    card_send_sdcmd_timeout(card, &sd_cmd,
+				    gg8_ddr200 ? SD_CMD18 : SD_CMD17,
+				    (u32) tuning_address,
+				    (cmdflag | CMD_FLG_ADMA_SDMA), DATA_DIR_IN,
+				    tuning_temp_buf, 512, 500);
+	if (ret == FALSE) {
+		DbgErr("Read data FAILED when store tuning address content\n");
+		goto exit;
+	}
+
+	for (i = 0; i < 512; i++) {
+		if (tuning_temp_buf[i] != tuning_address_content_buf[i]) {
+			DbgErr("Tuning address compare err!!!Write data 0x%x, Read out data 0x%x, Offset %d\n",
+			tuning_address_content_buf[i], tuning_temp_buf[i], i);
+			ret = FALSE;
+			break;
+		}
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"Write data 0x%x, Read out data 0x%x, Offset %d\n",
+			tuning_address_content_buf[i], tuning_temp_buf[i], i);
+	}
+
+exit:
+	/* Resorte current DMA mode */
+	host_transfer_init(card->host, card->inf_trans_enable, FALSE);
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return ret;
+}
+
+bool card_output_tuning(sd_card_t *card, u64 tuning_address)
+{
+	sd_host_t *host = card->host;
+	int ii, jj, pattern_i, first_0, dll_i_mod;
+	int dat_cmp, dll_result[16];
+	byte test_patern[6] = { 0x55, 0xaa, 0x00, 0xff, 0xf0, 0x0f };
+	u32 dll_i, window_pass_number[16],
+	    window_start_adr[16], window_pass_number_max, dll_mod;
+	u32 ret = FALSE;
+	bool result = FALSE;
+	sd_command_t sd_cmd;
+	u32 cmdflag;
+	u8 phase_count = 11;
+
+	byte *test_buf = kcalloc(512, sizeof(unsigned char), GFP_KERNEL);
+	byte *test_buf_read = kcalloc(512, sizeof(unsigned char), GFP_KERNEL);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (test_buf == NULL || test_buf_read == NULL) {
+		DbgErr("kcalloc buffer failed\n");
+		if (test_buf != NULL)
+			kfree(test_buf);
+		if (test_buf_read != NULL)
+			kfree(test_buf_read);
+		return FALSE;
+	}
+
+	host->output_tuning.start_block = (u32) tuning_address;
+	host->output_tuning.auto_phase_flag = FALSE;
+
+	/* Save Current DMA mode */
+	if (card->host->chip_type == CHIP_GG8
+	    && card->info.sw_cur_setting.sd_access_mode != SD_FNC_AM_DDR200)
+		host_transfer_init(host, FALSE, TRUE);
+	else
+		host_transfer_init(host, TRUE, FALSE);
+
+	if (host->chip_type == CHIP_GG8 || host->chip_type == CHIP_ALBATROSS) {
+		if (card->info.sw_cur_setting.sd_access_mode ==
+		    SD_FNC_AM_DDR200)
+			ret = ddr200_output_tuning(card, (u32) tuning_address);
+		else
+			ret =
+			    sdr104_sdr50_output_tuning(card,
+						       (u32) tuning_address);
+
+		if (ret == 0)
+			result = TRUE;
+	} else {
+		cmdflag = CMD_FLG_RESCHK | CMD_FLG_R1 | CMD_FLG_ADMA_SDMA;
+		window_pass_number_max = 0;
+		for (dll_i = 0; dll_i < phase_count; dll_i++)
+			dll_result[dll_i] = TRUE;
+
+		for (dll_i = 0; dll_i < 512; dll_i++)
+			test_buf[dll_i] = test_patern[dll_i % 6];
+
+		host_cmddat_line_reset(host);
+
+		if (host->chip_type != CHIP_GG8
+		    || host->chip_type == CHIP_ALBATROSS) {
+			if (card_check_rw_ready(card, &sd_cmd, 600) != TRUE) {
+				DbgErr
+				    ("Error when output_tuning,  card_check_rw_ready fail\n");
+				goto exit;
+			}
+		}
+
+		for (dll_i = 0; dll_i < phase_count; dll_i++) {
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, " - DLL Adjust Test %d\n", dll_i);
+
+			if (card->card_present == FALSE) {
+				DbgErr
+				    ("Error when output_tuning,  card is removed\n");
+				goto exit;
+			}
+			host_cmddat_line_reset(host);
+			host_set_output_tuning_phase(host, dll_i);
+
+			if (card->info.sw_cur_setting.sd_access_mode ==
+			    SD_FNC_AM_SDR104
+			    || card->info.sw_cur_setting.sd_access_mode ==
+			    SD_FNC_AM_SDR50
+			    || card->info.sw_cur_setting.sd_access_mode ==
+			    SD_FNC_AM_DDR200) {
+
+				ret = sd_tuning(card, &sd_cmd, 150);
+				if (ret == FALSE) {
+					DbgErr("Error when output_tuning, sd_tuning fail at phase %d\n", dll_i);
+					dll_result[dll_i] = FALSE;
+					continue;
+				}
+			}
+
+			for (pattern_i = 0; pattern_i < 1; pattern_i++) {
+
+				ret = card_send_sdcmd_timeout(card, &sd_cmd,
+							    SD_CMD24,
+							    host->output_tuning.start_block,
+							    (cmdflag),
+							    DATA_DIR_OUT,
+							    test_buf, 512, 500);
+				if (ret == FALSE) {
+					DbgErr("Write data FAILED when output_tuning\n");
+					dll_result[dll_i] = FALSE;
+					host_cmddat_line_reset(host);
+					card_send_command12(card, &sd_cmd);
+					if (card_check_rw_ready
+					    (card, &sd_cmd, 600) != TRUE) {
+						DbgErr("Error when output_tuning write CMD, card_check_rw_ready fail\n");
+						goto exit;
+					}
+					break;
+				}
+
+				ret = card_send_sdcmd_timeout(card, &sd_cmd,
+							    SD_CMD17,
+							    host->output_tuning.start_block,
+							    (cmdflag),
+							    DATA_DIR_IN,
+							    test_buf_read, 512,
+							    500);
+				if (ret == FALSE) {
+					DbgErr("Read data FAILED when output_tuning\n");
+					dll_result[dll_i] = FALSE;
+					host_cmddat_line_reset(host);
+					card_send_command12(card, &sd_cmd);
+					if (card_check_rw_ready(card, &sd_cmd, 600) != TRUE) {
+						DbgErr("Error when output_tuning read CMD, card_check_rw_ready fail\n");
+						goto exit;
+					}
+					break;
+				}
+
+				dat_cmp = TRUE;
+				for (ii = 0; ii < (1 * 512); ii++) {
+					if (*(test_buf + ii) !=
+					    *(test_buf_read + ii)) {
+						dat_cmp = FALSE;
+						dll_result[dll_i] = FALSE;
+						break;
+					}
+				}
+				if (dat_cmp == FALSE)
+					DbgErr("Compare data FAILED at index %d!!!\n", ii);
+
+			}
+		}
+
+		for (ii = 0; ii < 16; ii++) {
+			window_pass_number[ii] = 0;
+			window_start_adr[ii] = 0;
+		}
+
+		first_0 = 0;
+		for (dll_i = 0; dll_i < phase_count; dll_i++) {
+			if (dll_result[dll_i] != TRUE) {
+				first_0 = dll_i;
+				break;
+			}
+		}
+
+		jj = 0;
+		for (dll_i = 0; dll_i < phase_count; dll_i++) {
+			dll_i_mod = (first_0 + dll_i) % phase_count;
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, "DLL phase [%x] result %d.\n",
+				dll_i_mod, dll_result[dll_i_mod]);
+			if (dll_result[dll_i_mod] == TRUE)
+				window_pass_number[jj]++;
+			else {
+				if (window_pass_number[jj] > 0)
+					jj++;
+			}
+			if (window_pass_number[jj] == 1)
+				window_start_adr[jj] = dll_i_mod;
+		}
+
+		for (ii = 0; ii < phase_count; ii++) {
+			if (window_pass_number_max < window_pass_number[ii]) {
+				window_pass_number_max = window_pass_number[ii];
+				jj = ii;
+			}
+		}
+
+		if (window_pass_number_max == 0)
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM,
+				"DLL test result: All DLL test FAIL\n");
+		else {
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM,
+				"DLL test result: Total	%d DLL test PASS\n",
+				window_pass_number_max);
+			window_pass_number_max = window_pass_number_max >> 1;
+			dll_mod = window_start_adr[jj] + window_pass_number_max;
+			dll_mod = dll_mod % phase_count;
+
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, "select DLL phase Number %d\n",
+				dll_mod);
+			host->output_tuning.auto_phase = dll_mod;
+			host->output_tuning.auto_phase_flag = TRUE;
+			result = TRUE;
+			host_set_output_tuning_phase(host,
+				host->output_tuning.auto_phase);
+			if (card->info.sw_cur_setting.sd_access_mode ==
+			    SD_FNC_AM_SDR104
+			    || card->info.sw_cur_setting.sd_access_mode ==
+			    SD_FNC_AM_SDR50
+			    || card->info.sw_cur_setting.sd_access_mode ==
+			    SD_FNC_AM_DDR200) {
+				ret = sd_tuning(card, &sd_cmd, 150);
+				if (ret == FALSE) {
+					DbgErr
+					    ("Error when output_tuning,  sd_tuning fail\n");
+					result = FALSE;
+					goto exit;
+				}
+			}
+
+		}
+
+	}
+exit:
+
+	/* Resorte current DMA mode */
+	host_transfer_init(host, card->inf_trans_enable, FALSE);
+	if (result == FALSE)
+		hostven_set_output_tuning_phase(host, 0, TRUE);
+	host_cmddat_line_reset(host);
+	host->output_tuning.auto_flag = FALSE;
+
+	kfree(test_buf);
+	kfree(test_buf_read);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s result is %d\n", __func__, result);
+
+	return result;
+}
+
+static bool legacy_error_recovery(sd_card_t *card, sd_command_t *pcmd)
+{
+	bool ret;
+	sd_command_t sd_cmd;
+	card_info_t *card_info = &(card->info);
+	sd_host_t *host = card->host;
+	bht_dev_ext_t *pdx = host->pdx;
+	cfg_output_tuning_item_t *cfg =
+	    &pdx->cfg->feature_item.output_tuning_item;
+
+	DbgInfo(MODULE_LEGACY_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s\n", __func__);
+
+	/* Follow SD Host Spec V4.10 Section 3.10.1 Error Interrupt Recovery flow (Page 179) */
+	card_send_command12(card, &sd_cmd);
+
+	/* Call host api to do host related recovery stage2 */
+	ret =
+	    host_error_int_recovery_stage2(card->host,
+					   sd_cmd.err.legacy_err_reg);
+
+	if (ret == FALSE)
+		goto exit;
+
+	ret = card_check_rw_ready(card, &sd_cmd, 150);
+
+	if (ret == FALSE) {
+		DbgErr("Card status is not ready after error recovery");
+		goto exit;
+	}
+
+	if (pcmd != NULL) {
+		/* Crc error */
+		if (pcmd->err.legacy_err_reg & (BIT1 | BIT5)) {
+			if (host->cfg->feature_item.output_tuning_item.enable_dll
+				== 0) {
+				if (card->card_type == CARD_SD)
+					ret = sd_tuning(card, &sd_cmd, 0);
+				else if (card->card_type == CARD_EMMC)
+					ret = emmc_tuning(card, &sd_cmd);
+			} else {
+
+				if (card->card_type == CARD_SD &&
+				    pcmd->data &&
+				    pcmd->data->dir == DATA_DIR_OUT &&
+				    ((cfg->enable_dll == 1)
+				     && (cfg->enable_dll_divider == 1))
+				    && (card_info->sw_cur_setting.sd_access_mode ==
+					SD_FNC_AM_DDR50)) {
+					ret = sd_dll_divider(card, pcmd);
+					if (ret)
+						goto exit;
+				} else if (pcmd->data
+					   && pcmd->data->dir == DATA_DIR_OUT) {
+					if (card->card_type == CARD_SD
+					    || card->card_type == CARD_EMMC) {
+						if (hostven_fix_output_tuning(card->host,
+							card_info->sw_cur_setting.sd_access_mode)
+						    == FALSE) {
+							ret = card_output_tuning(card,
+								pcmd->argument);
+							if (ret)
+								goto exit;
+						}
+					}
+				} else if (pcmd->data
+					   && pcmd->data->dir == DATA_DIR_IN) {
+					if (card->card_type == CARD_SD) {
+						ret =
+						    sd_tuning(card, &sd_cmd, 0);
+					} else if (card->card_type == CARD_EMMC) {
+						ret =
+						    emmc_tuning(card, &sd_cmd);
+					}
+				}
+			}
+		}
+
+	}
+
+exit:
+	DbgInfo(MODULE_LEGACY_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s\n", __func__);
+	return ret;
+}
+
+/*
+ * Function Name: card_degrade_policy
+ *
+ * Abstract: This Function is used set card degrade flag
+ *           if blightway is set, this function can also do card operation which don't need reinit
+ *
+ * Input:
+ *
+ * sd_card_t *card : The Command will send to which  Card
+ * sd_command_t *sd_cmd: if the init occurred at init stage this parameter will be null
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: card_init
+ *
+ */
+
+void card_degrade_policy(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s\n", __func__);
+	switch (card->card_type) {
+	case CARD_SD:
+		sd_degrade_policy(card);
+		break;
+	case CARD_UHS2:
+		uhs2_degrade_policy(card, sd_cmd);
+		break;
+	case CARD_EMMC:
+	case CARD_MMC:
+		mmc_degrade_policy(card);
+		break;
+	default:
+		break;
+
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+}
+
+/*
+ * Function Name: card_rw_recovery
+ *
+ * Abstract: This Function is used to do card rw error recovery
+ *
+ * Input:
+ *
+ * sd_card_t *card : The Command will send to which  Card
+ * sd_command_t *sd_cmd: if the init occurred at init stage this parameter will be null
+ *
+ * Output: None
+ *
+ * Return value: If the routine succeeds, it must return TRUE,
+ *               and fill trans_reg_t  part. otherwize reutrn FALSE
+ *
+ * Notes:
+ *
+ * Caller: card_recovery_flow
+ *
+ */
+
+static bool card_rw_recovery(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	if (sd_cmd == NULL)
+		return FALSE;
+
+	switch (card->card_type) {
+	case CARD_EMMC:
+	case CARD_MMC:
+	case CARD_SD:
+		return legacy_error_recovery(card, sd_cmd);
+	case CARD_UHS2:
+		return uhs2_sd_error_recovery(card, sd_cmd);
+	default:
+		DbgErr("Error Card no RW error recovery\n");
+		break;
+
+	}
+
+	return FALSE;
+}
+
+/*
+ * Function Name: card_init_infinite
+ *
+ * Abstract: This Function is used to determine whehter use infinte or not according to card type
+ *
+ * Input:
+ *
+ * sd_card_t *card : The Command will send to which  Card
+ * sd_host_t *host: Pointer to the host structure
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: card_init
+ *
+ */
+
+static void card_init_transfer(sd_card_t *card, sd_host_t *host)
+{
+	bool autocmd23 = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	card->has_built_inf = FALSE;
+	card->last_dir = DATA_DIR_NONE;
+	card->last_sect = 0;
+
+	if (host->cfg->host_item.test_infinite_transfer_mode.enable_inf ==
+	    FALSE) {
+		card->inf_trans_enable = FALSE;
+		goto next;
+	}
+
+	switch (card->card_type) {
+	case CARD_UHS2:
+		card->inf_trans_enable =
+		    (byte) host->cfg->host_item.test_infinite_transfer_mode.enable_sd40_inf;
+		break;
+	case CARD_SD:
+		card->inf_trans_enable =
+		    (byte) host->cfg->host_item.test_infinite_transfer_mode.enable_legacy_inf;
+		break;
+	case CARD_MMC:
+		card->inf_trans_enable =
+		    (byte) host->cfg->host_item.test_infinite_transfer_mode.enable_mmc_inf;
+		break;
+	case CARD_EMMC:
+		card->inf_trans_enable =
+		    (byte) host->cfg->host_item.test_infinite_transfer_mode.enable_emmc_inf;
+		break;
+	default:
+		card->inf_trans_enable = FALSE;
+		break;
+	}
+
+next:
+	if ((card->card_type == CARD_SD) && (card->info.scr.cmd_support & 0x2))
+		autocmd23 = TRUE;
+
+	host_transfer_init(host, card->inf_trans_enable, FALSE);
+	host_enable_cmd23(host, autocmd23);
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+}
+
+/*
+ * Function Name: card_switch2_adma
+ *
+ * Abstract: call this function to switch to adma2 mode, caller must restore.
+ *
+ * Input:
+ *
+ * sd_card_t *card : The Command will send to which  Card
+ * sd_command_t *sd_cmd: if the init occurred at init stage this parameter will be null
+ *
+ * Output: None
+ *
+ * Return value: If the routine succeeds, it must return TRUE, otherwize reutrn FALSE
+ *
+ * Notes:
+ *
+ * Caller:
+ *
+ */
+
+bool card_switch2_adma(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER | FEATURE_IOCTL_TRACE,
+		NOT_TO_RAM, "Enter %s\n", __func__);
+	/* stop inf */
+	if (card->has_built_inf) {
+		/* need stop first */
+		ret = card_stop_infinite(card, FALSE, sd_cmd);
+		if (ret == FALSE) {
+			DbgErr("Stop Inf error for swithc2_adma\n");
+			goto exit;
+		}
+	}
+
+	host_transfer_init(card->host, FALSE, TRUE);
+	ret = TRUE;
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER | FEATURE_IOCTL_TRACE,
+		NOT_TO_RAM, "Enter %s ret=%d\n", __func__, ret);
+	return ret;
+}
+
+/*
+ * Function Name: card_degrade_info_init
+ *
+ * Abstract: init card degrade info
+ *
+ * Input:
+ *
+ * sd_card_t *card : The Command will send to which  Card
+ * sd_host_t *host: Pointer to the host structure
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: card_stuct_init
+ *
+ */
+
+static void card_degrade_info_init(sd_card_t *card, sd_host_t *host)
+{
+	/* 1. Init the target access mode (Legacy mode) to the maximum access mode. */
+	card->sw_target_setting.sd_access_mode =
+	    (byte) host->cfg->card_item.test_max_access_mode.value;
+
+	/* 2. Init the target drive strength */
+	card->sw_target_setting.sd_drv_type =
+	    (byte) host->cfg->card_item.test_driver_strength_sel.value;
+
+	/* 3. Init the target power limit */
+	card->sw_target_setting.sd_power_limit =
+	    (byte) host->cfg->card_item.test_max_power_limit.value;
+
+	card->degrade_uhs2_range = 0;
+	card->degrade_uhs2_half = 0;
+	card->degrade_uhs2_legacy = 0;
+	card->degrade_final = 0;
+	card->degrade_freq_level = 0;
+
+	/* below item is used for thremal control */
+	card->thermal_enable = 0;
+	card->thermal_uhs2_range = 0;
+	card->thermal_uhs2_half_dis = 0;
+	card->thermal_uhs2_lpm = 0;
+	card->thermal_access_mode = 0;
+	card->thermal_power_limit = 0;
+
+	card->continue_init_fail_cnt = 0;
+	card->continue_rw_err_cnt = 0;
+	card->adma_err_cnt = 0;
+
+}
+
+/*
+ * Function Name: card_stuct_init
+ *
+ * Abstract:
+ *
+ *          1. init card control info, such as degrade info
+ *          2. bind card to host and memset function
+ *
+ * Input:
+ *
+ * bht_dev_ext_t*	pdev_ext: Pointer to the device structure
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: req_global_init
+ *
+ */
+
+void card_stuct_init(bht_dev_ext_t *pdev_ext)
+{
+	sd_card_t *card;
+	sd_host_t *host;
+
+	/* Support 1 virtual card so far. */
+	card = &(pdev_ext->card);
+
+	/* 1. Zero the card structure */
+	os_memset(card, 0, sizeof(sd_card_t));
+
+	/* 2. set the host point of card */
+	card->host = &(pdev_ext->host);
+	host = card->host;
+
+	/* 3. Error Count clear */
+	card->adma_err_cnt = 0;
+	card->continue_init_fail_cnt = 0;
+	card->continue_rw_err_cnt = 0;
+	card->restore_tuning_content_fail = 0;
+	card->read_signal_block_flag = 0;
+
+	card_degrade_info_init(card, host);
+	card->host->output_tuning.auto_phase_flag = FALSE;
+	card->retry_output_fail_phase = 0xFF;
+}
+
+/*
+ * Function Name: card_stuct_uinit
+ *
+ * Abstract:
+ *
+ *          1. this function is called by card remvoe and enter pm
+ *          2. this function will only clear software  flag
+ *
+ * Input:
+ *
+ * sd_card_t *card : Pointer to the card structure
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: remove_card_handle
+ *
+ */
+
+void card_stuct_uinit(sd_card_t *card)
+{
+	card->initialized_once = FALSE;
+	card->card_type = CARD_NONE;
+	os_memset(&card->info, 0, sizeof(card->info));
+	card->has_built_inf = FALSE;
+	card->inf_trans_enable = FALSE;
+	card->last_dir = DATA_DIR_NONE;
+	card->last_sect = 0;
+	os_memset(&card->mmc, 0, sizeof(card->mmc));
+	os_memset(&card->uhs2_info, 0, sizeof(card->uhs2_info));
+	card->quirk = 0;
+	card->quick_init = 0;
+
+	card->adma_err_cnt = 0;
+	card->continue_init_fail_cnt = 0;
+	card->continue_rw_err_cnt = 0;
+	card->restore_tuning_content_fail = 0;
+	card->read_signal_block_flag = 0;
+
+	card->state = CARD_STATE_POWEROFF;
+	card->write_protected = FALSE;
+	card_degrade_info_init(card, card->host);
+	card->host->output_tuning.auto_phase_flag = FALSE;
+	card->thread_init_card_flag = 0;
+	card->retry_output_fail_phase = 0xFF;
+}
+
+static inline bool uhs2_support(sd_host_t *host)
+{
+	bool ret = TRUE;
+	/* 1. Host do not support UHSII */
+	if (!host->uhs2_supp)
+		ret = FALSE;
+
+	/* 1 TODO. correct the check condition */
+	/* 2. Configuration settings to disable UHSII function */
+	if (host->cfg->card_item.sd_card_mode_dis.dis_sd40_card)
+		ret = FALSE;
+	return ret;
+
+}
+
+static inline bool emmc_enabled(sd_host_t *host)
+{
+	/* 1. Configuration settings to disable eMMC function */
+	bool ret = FALSE;
+
+	if (host->cfg->card_item.emmc_mode.emmc_enable)
+		ret = TRUE;
+
+	return ret;
+}
+
+inline bool mmc_disabled(sd_host_t *host)
+{
+	/* 1. Configuration settings to disable eMMC function */
+	bool ret = FALSE;
+
+	if (host->cfg->card_item.mmc_mode_dis.dis_mmc_func)
+		ret = TRUE;
+	return ret;
+}
+
+static void card_variable_init(sd_card_t *card)
+{
+	card->info.card_ccs = 0;
+	card->info.card_s18a = 0;
+	card->info.rca = 0;
+	card->info.ddr_flag = 0;
+	card->info.io_signal_vol = 0;
+	os_memset(&card->info.sw_cur_setting, 0, sizeof(sd_sw_func_t));
+
+	card->uhs2_info.dev_id = 0;
+	os_memset(&card->uhs2_info.uhs2_setting, 0, sizeof(uhs2_info_t));
+	card->mmc.cur_buswidth = EMMC_1Bit_BUSWIDTH;
+	card->mmc.cur_hs_type = 0;
+}
+
+/*
+ * Related register setting and Driver behavior description
+ * 1). SD7.0 Card capacibility detection register
+ * 0x1e0[29:28] = 2’b11: Enable hardware capability detection interrupt;
+ * 0x1e0[25:24] = 2’b11: enable hardware capability detection interrupt status.
+ * 0x1e0[17:16]: write 1 to this bit to clear interrupt status.
+ *
+ */
+static bool check_express_card_clkreqn_status(sd_card_t *card)
+{
+	u32 delay_us = 1;
+	u32 delay_ms;
+	loop_wait_t wait;
+	u32 regval;
+	bool ret = FALSE;
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	switch (host->cfg->card_item.sd7_sdmode_switch_control.switch_method_ctrl) {
+	case HW_DETEC_HW_SWITCH:
+		/* hardware interrupt control */
+		DbgInfo(MODULE_SD_HOST, FEATURE_INTR_TRACE, NOT_TO_RAM,
+			"before clkreqn_status : %d\n", host->clkreqn_status);
+		while (1) {
+			if (os_atomic_read(&host->clkreqn_status) == 1) {
+				ret = TRUE;
+				DbgInfo(MODULE_SD_HOST, FEATURE_INTR_TRACE,
+					NOT_TO_RAM,
+					"Wait express clkreqn complete status ok\n");
+				break;
+			} else if (os_atomic_read(&host->clkreqn_status) == 2) {
+				ret = FALSE;
+				DbgInfo(MODULE_SD_HOST, FEATURE_INTR_TRACE,
+					NOT_TO_RAM,
+					"Wait express clkreqn timeout\n");
+				break;
+			}
+
+			if (card->card_present == FALSE) {
+				ret = FALSE;
+				DbgErr("card is removed\n");
+				break;
+			}
+		}
+		DbgInfo(MODULE_SD_HOST, FEATURE_INTR_TRACE, NOT_TO_RAM,
+			"after clkreqn_status : %d\n", host->clkreqn_status);
+		break;
+
+	case SW_POLL_SW_SWITCH:
+	case SW_POLL_SWCTRL_SWITCH:
+		/* software control */
+
+		/* set polling tmie fix value 30ms */
+		delay_ms = 30;
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"software control\n");
+
+		util_init_waitloop(host->pdx, delay_ms, delay_us, &wait);
+		while (!util_is_timeout(&wait)) {
+			if (host_check_lost(host)) {
+				ret = TRUE;
+				break;
+			}
+
+			if (((sdhci_readl(host, 0x1e0) & (0x1)) == 0)) {
+				ret = TRUE;
+				break;
+			}
+
+			if (card->card_present == FALSE) {
+				ret = FALSE;
+				DbgErr("card is removed\n");
+				break;
+			}
+		}
+
+		break;
+
+	case SW_POLL_INTER_SW_SWITCH:
+	case SW_POLL_INTER_SWCRTL_SWITCH:
+		/* hardware polling control */
+		DbgInfo(MODULE_SD_HOST, FEATURE_INTR_TRACE, NOT_TO_RAM,
+			"software polling control\n");
+		while (1) {
+			if (host_check_lost(host)) {
+				ret = TRUE;
+				DbgErr("chip lost, already switch to sd7.0\n");
+				break;
+			}
+
+			regval = sdhci_readl(host, 0x1e0);
+			if (regval & (1 << 16)) {
+
+				DbgInfo(MODULE_SD_HOST, FEATURE_INTR_TRACE,
+					NOT_TO_RAM,
+					"Wait express clkreqn complete status ok\n");
+				ret = TRUE;
+				sdhci_or16(host, 0x1e2, 0x01);
+				break;
+			} else if (regval & (1 << 17)) {
+				DbgInfo(MODULE_SD_HOST, FEATURE_INTR_TRACE,
+					NOT_TO_RAM,
+					"Wait express clkreqn timeout\n");
+				ret = FALSE;
+				sdhci_or16(host, 0x1e2, 0x02);
+				break;
+			}
+
+			if (card->card_present == FALSE) {
+				ret = FALSE;
+				break;
+				DbgErr("card is removed\n");
+			}
+		}
+		break;
+
+	default:
+		DbgErr("no such value!\n");
+		break;
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s (%d)\n", __func__, ret);
+
+	return ret;
+}
+
+static bool Turn_on_vdd2_or_vdd3(sd_card_t *card, bool flag)
+{
+	sd_host_t *host = card->host;
+	u32 regval;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	regval = sdhci_readl(host, 0x1e0);
+	switch (host->cfg->card_item.sd7_sdmode_switch_control.switch_method_ctrl) {
+	case HW_DETEC_HW_SWITCH:
+		/* set 0x1e0[29:28] = 2’b11, set 0x1e0[25:24] = 2’b11 */
+		regval |= (0x33 << 24);
+		break;
+
+	case SW_POLL_SW_SWITCH:
+	case SW_POLL_SWCTRL_SWITCH:
+		/* set 0x1e0[29:28] = 2’b00, set 0x1e0[25:24] = 2’b00 */
+		regval &= 0xccffffff;
+		break;
+
+	case SW_POLL_INTER_SW_SWITCH:
+	case SW_POLL_INTER_SWCRTL_SWITCH:
+		/* set 0x1e0[29:28] = 2’b00, set 0x1e0[25:24] = 2’b11 */
+		regval |= (0x3 << 24);
+		break;
+
+	default:
+		DbgErr("Error:no such value in registry sd7_sdmode_switch_control, use default value\n");
+		regval |= (0x33 << 24);
+		break;
+	}
+	sdhci_writel(host, 0x1e0, regval);
+
+	/* 1:VDD3 0:VDD2 */
+	if ((flag)
+	    && (host->cfg->card_item.sd7_sdmode_switch_control.vdd3_control)) {
+
+		/* Turn on vdd3 */
+		os_atomic_set(&host->clkreqn_status, 0);
+		host_set_vddx_power(host, VDD3, POWER_ON);
+		ret = check_express_card_clkreqn_status(card);
+		if (!ret) {
+			DbgErr("check clkreq failed fater turn on vdd3\n");
+			/* Turn off vdd3 */
+			host_set_vddx_power(host, VDD3, POWER_OFF);
+
+			/* Turn on vdd2 */
+			os_atomic_set(&host->clkreqn_status, 0);
+			host_set_vddx_power(host, VDD2, POWER_ON);
+			ret = check_express_card_clkreqn_status(card);
+			if (!ret) {
+				DbgErr("check clkreq failed fater turn on vdd2\n");
+				host_set_vddx_power(host, VDD2, POWER_OFF);
+			}
+		}
+	} else {
+		/* Turn on vdd2 */
+		os_atomic_set(&host->clkreqn_status, 0);
+		host_set_vddx_power(host, VDD2, POWER_ON);
+
+		ret = check_express_card_clkreqn_status(card);
+		if (!ret) {
+			DbgErr("check clkreq failed fater turn on vdd2 derectily\n");
+			host_set_vddx_power(host, VDD2, POWER_OFF);
+		}
+	}
+	return ret;
+}
+
+bool pcie_mode_init(sd_card_t *card, bool code_flag)
+{
+	sd_host_t *host = card->host;
+	u32 regval;
+	bool ret;
+	bool host_support_vdd3;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* set flag that driver in sd_express mode */
+	host->sd_express_flag = TRUE;
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Set sd_express_flag\n");
+
+	regval = sdhci_readl(host, 0x44);
+	if (!(regval & (1 << 29)))
+		host_support_vdd3 = FALSE;
+	else
+		host_support_vdd3 = TRUE;
+
+	/* flag 1:for sd cmd code */
+	if (code_flag) {
+
+		host_enable_clock(host, FALSE);
+
+		/* stop clk */
+		if (shift_bit_func_enable(host)) {
+			set_pattern_value(host, 0x34);
+			return TRUE;
+		}
+
+		if (card->card_support_vdd3 && host_support_vdd3)
+			ret = Turn_on_vdd2_or_vdd3(card, TRUE);
+		else
+			ret = Turn_on_vdd2_or_vdd3(card, FALSE);
+
+	} else {
+		/* flag 0 :for trail run code */
+		if (shift_bit_func_enable(host)) {
+			set_pattern_value(host, 0x34);
+			return TRUE;
+		}
+		ret = Turn_on_vdd2_or_vdd3(card, host_support_vdd3);
+	}
+
+	if (ret) {
+		/*
+		 * Software: if pcr 0x444[9]=1,
+		 * set sd host register 054h[8]=1 to assert express_card_mode
+		 */
+		regval = pci_readl(host, 0x444);
+		if (regval & (1 << 9)) {
+			regval = sdhci_readl(host, 0x54);
+			regval |= (1 << 8);
+			sdhci_writel(host, 0x54, regval);
+		}
+		return TRUE;
+
+	}
+
+	DbgErr("Exit pcie mode init with FALSE\n");
+	host->sd_express_flag = FALSE;
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Clear sd_express_flag\n");
+	return FALSE;
+}
+
+bool gg8_get_card_capability_flag(sd_card_t *card, bool check_uhs2_flag)
+{
+	bool ret;
+	bool flag_f8 = FALSE;
+	sd_command_t sd_cmd;
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (check_uhs2_flag) {
+		host_init(host);
+		card_variable_init(card);
+		host_init_400k_clock(host);
+		host_internal_clk_setup(host, TRUE);
+
+		/* 1. Power on card */
+		if (host_get_vdd1_state(host) == FALSE) {
+			os_mdelay(10);
+			/* host_set_vdd1_power(host, TRUE, SDHCI_POWER_VDD1_330); */
+			if (shift_bit_func_enable(host))
+				set_pattern_value(host, 0x11);
+
+			host_set_vddx_power(host, VDD1, POWER_ON);
+		}
+	}
+	/* 1 SD CLK Start */
+	host_enable_clock(host, TRUE);
+
+	/* 2 CMD0 */
+	ret = card_reset_card(card, &sd_cmd);
+	if (!ret) {
+		/* Go Idle State command failed. exit directly. */
+		DbgErr("Reset Card (CMD0) Failed.\n");
+		return FALSE;
+
+	}
+	/* 3. Issue send IF condition command (CMD8) */
+	if (check_uhs2_flag)
+		ret = sd_send_if_cond(card, &sd_cmd, 0x000001AA);
+	else
+		ret = sd_send_if_cond(card, &sd_cmd, 0x000031AA);
+
+
+	if (!ret) {
+		/* 3.1 Error response */
+		if (sd_cmd.err.error_code == ERR_CODE_RESP_ERR ||
+		    sd_cmd.err.error_code == ERR_CODE_NO_CARD) {
+			DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"CMD8 Response Error or no card.\n");
+		} else {
+			/* 5.2 No Response  (Standard Capacity Card) */
+			DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"CMD8 No Responser.\n");
+		}
+
+		return FALSE;
+
+	} else {
+		/* 5.3 Good Response  (High Capacity card) */
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"CMD8 Good Responser\n");
+		flag_f8 = TRUE;
+	}
+
+	/* 5.4.1 read R7 */
+
+	/* sd_send_if_cond argument = 0x000031AA check card support pcie */
+	if (check_uhs2_flag == FALSE) {
+		/* host ask card's PCIe availability */
+		if (!(sd_cmd.response[0] & 0x1000))
+			card->card_support_pcie = FALSE;
+		else
+			card->card_support_pcie = TRUE;
+
+		if (sd_cmd.response[0] & 0x2000) {
+			/* host ask whether card support VDD3 */
+			card->card_support_vdd3 = TRUE;
+		} else
+			card->card_support_vdd3 = FALSE;
+
+	}
+
+	/* if check_uhs2_flag == true, send ACMD41 to check response bit 29  */
+	if (check_uhs2_flag) {
+		ret = card_init_ready(card, &sd_cmd, flag_f8);
+
+		if (!ret) {
+			DbgErr("Wait for card ready (ACMD41) Failed.\n");
+			return FALSE;
+		}
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return TRUE;
+}
+
+bool gg8_sd70_card_init(sd_card_t *card)
+{
+	bool ret;
+	u32 regval;
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	card->pcie_init_flag = TRUE;
+
+	/* update card status */
+	card->card_present = hostven_chk_card_present(host);
+
+	/* check card exist? */
+	if (card->card_present == FALSE || card->card_chg)
+		return FALSE;
+
+
+	if (INIT_DELAY & INIT_DELAY_EN_MASK) {
+		os_mdelay(INIT_DELAY & INIT_DELAY_CFG_MASK);
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"%s init delay %d ms\n", __func__,
+			(INIT_DELAY & INIT_DELAY_CFG_MASK));
+	} else {
+		os_mdelay(200);
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"%s init delay %d ms\n", __func__, 200);
+	}
+
+	/* 0 host side init */
+	host_init(host);
+	card_variable_init(card);
+	host_init_400k_clock(host);
+	host_internal_clk_setup(host, TRUE);
+
+	/* 1. Power on card */
+	if (shift_bit_func_enable(host) &&
+		(host->cfg->card_item.sd7_sdmode_switch_control.card_init_flow_select)) {
+		os_mdelay(10);
+
+		if (shift_bit_func_enable(host))
+			set_pattern_value(host, 0x10);
+
+		host_set_vddx_power(host, VDD1, POWER_ON);
+	} else {
+		if (host_get_vdd1_state(host) == FALSE) {
+			os_mdelay(10);
+
+			if (shift_bit_func_enable(host))
+				set_pattern_value(host, 0x10);
+
+			host_set_vddx_power(host, VDD1, POWER_ON);
+		}
+	}
+
+	regval = pci_readl(host, 0x444);
+	if (!(regval & (0x1 << 11))) {
+		/* CMD8 */
+
+		/* FALSE no need to send ACMD41 */
+		ret = gg8_get_card_capability_flag(card, FALSE);
+		if (!ret) {
+			DbgErr
+			    ("gg8_get_card_capability_flag exit with faile\n");
+		}
+
+		regval = pci_readl(host, 0x444);
+		if (!(regval & (0x7 << 8))) {
+			DbgErr("host not support to switch to sd7.0\n");
+			card->pcie_init_flag = FALSE;
+			return FALSE;
+		}
+
+		if (card->card_support_pcie) {
+			ret = pcie_mode_init(card, TRUE);
+			if (!ret) {
+				DbgErr("pci cmd mode init failed\n");
+				card->pcie_init_flag = FALSE;
+			} else {
+				card->pcie_init_flag = TRUE;
+			}
+		} else {
+			DbgErr("card not support pcie\n");
+			card->pcie_init_flag = FALSE;
+			return FALSE;
+		}
+	} else {
+
+		/* trail run */
+		ret = pcie_mode_init(card, FALSE);
+		if (!ret) {
+			DbgErr("pci trail run mode init failed\n");
+			card->pcie_init_flag = FALSE;
+		} else {
+			card->pcie_init_flag = TRUE;
+		}
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	/* Thomas test: call remove here. */
+	if (card->pcie_init_flag == TRUE) {
+		bht_sd_remove(host->pci_dev.pci_dev);
+
+		return TRUE;
+	}
+
+	if (ret) {
+		card_init_transfer(card, host);
+		card->initialized_once = TRUE;
+		card->state = CARD_STATE_WORKING;
+		card->continue_init_fail_cnt = 0;
+		if (host_wr_protect_pin(host) || card_wr_protect(card))
+			card->write_protected = TRUE;
+		else
+			card->write_protected = FALSE;
+
+		return TRUE;
+	} else {
+		return FALSE;
+	}
+}
+
+/*
+ * Function Name: card_pcie_support
+ *
+ * Abstract: check whether the card supports SD7.0 mode
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output: None
+ *
+ * Return value: return TRUE if the card supports SD7.0 mode, otherwise return FALSE
+ *
+ * Notes:
+ *
+ * Caller: card_init
+ *
+ */
+
+bool card_pcie_support(sd_card_t *card)
+{
+	bool ret = FALSE;
+	u32 regval = 0;
+	bool host_support_sd70 = FALSE;
+	bool sd_cmd_low = FALSE;
+	bool registry_support_sd70 = TRUE;
+	bool any_switch_case_enable = FALSE;
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if ((sdhci_readl(host, 0x40) & (1 << 20)))
+		host_support_sd70 = TRUE;
+
+	if ((pci_readl(host, 0x444) & 0x700))
+		any_switch_case_enable = TRUE;
+
+	/* polling PCR 0x448[31]  */
+	if ((pci_readl(host, 0x448) & (1 << 31))) {
+		regval = pci_readl(host, 0x448);
+		regval |= (1 << 31);
+		pci_writel(host, 0x448, regval);
+		card->cmd_low_reset_flag = TRUE;
+	} else {
+		sd_cmd_low = TRUE;
+	}
+
+	if (host->cfg->card_item.sd_card_mode_dis.dis_sd70_card)
+		registry_support_sd70 = FALSE;
+
+	if (host_support_sd70 && sd_cmd_low && registry_support_sd70
+	    && any_switch_case_enable && (card->cmd_low_reset_flag == FALSE)) {
+		if ((pci_readl(host, 0x444) & (1 << 10))) {
+			if ((pci_readl(host, 0x444) & (1 << 15))) {
+				if ((pci_readl(host, 0x50c) & (1 << 6)))
+					ret = FALSE;
+				else
+					ret = TRUE;
+			} else {
+				if ((pci_readl(host, 0x50c) & (1 << 6)))
+					ret = TRUE;
+				else
+					ret = FALSE;
+			}
+		} else {
+			ret = TRUE;
+		}
+	} else {
+		ret = FALSE;
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s with(%d)\n", __func__, ret);
+	return ret;
+}
+
+/*
+ * Function Name: card_init
+ *
+ * Abstract: Main card initialize entry.
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * int retry_num [in]: Retry number if card init failed.
+ * bool bfullreset: full reset flag
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: thread_init_card
+ *
+ */
+
+bool card_init(sd_card_t *card, int retry_num, bool bfullreset)
+{
+	bool ret = FALSE;
+	bool stbl = FALSE;
+	sd_host_t *host = card->host;
+	bool first_init = TRUE;
+	u32 regval;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (host->pdx == NULL) {
+		DbgErr("host->pdx should not be NULL\n");
+		return FALSE;
+	}
+	if (host_check_lost(host)) {
+		DbgErr("Host lost at card init start\n");
+		return FALSE;
+	}
+
+	if (shift_bit_func_enable(host) &&
+		(host->cfg->card_item.sd7_sdmode_switch_control.card_init_flow_select))
+		goto retry;
+	else
+		goto express_flow;
+
+express_flow:
+	/* SD7.0 card mode init flow */
+	if (host->chip_type == CHIP_GG8) {
+		if (card_pcie_support(card)) {
+			ret = gg8_sd70_card_init(card);
+
+			if (!ret) {
+				regval = pci_readl(host, 0x444);
+				regval &= (~(1 << 11));
+				pci_writel(host, 0x444, regval);
+			}
+
+			if (card->pcie_init_flag == FALSE) {
+				if (card->card_present == TRUE) {
+					if (shift_bit_func_enable(host)
+					    && (host->cfg->card_item.sd7_sdmode_switch_control.card_init_flow_select))
+						goto legacy;
+					else
+						goto retry;
+				} else
+					return FALSE;
+			} else {
+				card->card_type = CARD_SD70;
+				card->card_present = FALSE;
+				return ret;
+			}
+		} else if (card->card_present == TRUE) {
+			if (shift_bit_func_enable(host)
+			    && (host->cfg->card_item.sd7_sdmode_switch_control.card_init_flow_select))
+				goto legacy;
+			else
+				goto retry;
+		} else {
+			return FALSE;
+		}
+	}
+
+retry:
+
+	/* update card status */
+	card->card_present = hostven_chk_card_present(host);
+	if (first_init == TRUE) {
+		first_init = FALSE;
+	} else {
+
+		/* check card exist? */
+		if (card->card_present == FALSE || card->card_chg) {
+			ret = FALSE;
+			goto end;
+		}
+
+		if (INIT_DELAY & INIT_DELAY_EN_MASK) {
+			os_mdelay(INIT_DELAY & INIT_DELAY_CFG_MASK);
+			DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"%s init delay %d ms\n", __func__,
+				(INIT_DELAY & INIT_DELAY_CFG_MASK));
+		} else {
+			os_mdelay(200);
+			DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"%s init delay %d ms\n", __func__, 200);
+		}
+
+	}
+
+	/* Do some Host side initialization */
+	if (bfullreset == FALSE)
+		host_init(host);
+	card_variable_init(card);
+
+	/* Check eMMC function enabled or not */
+	if (emmc_enabled(host)) {
+		hostven_set_pml0_requrest(host, FALSE);
+		ret = emmc_init(card, TRUE);
+		goto exit;
+	}
+
+	if (card_need_get_info(card) == FALSE) {
+		switch (card->card_type) {
+		case CARD_EMMC:
+		case CARD_MMC:
+			goto mmc;
+		case CARD_SD:
+			goto legacy;
+		default:
+			break;
+		}
+	}
+
+	/* Check host and configuration support UHSII or not */
+	if ((uhs2_support(host))
+	    && (card->degrade_uhs2_legacy == 0)
+	    && (card->card_type != CARD_MMC && card->card_type != CARD_SD)) {
+		u32 clk_value = card_get_uhs2_freq(card);
+
+		DbgErr("host support uhs2\n");
+		DbgErr("uhs2 trail run mode\n");
+
+		hostven_set_pml0_requrest(host, TRUE);
+		host_uhs2_init(host, clk_value, bfullreset);
+		ret = host_uhs2_phychk(host, FALSE, &stbl);
+
+		/* phy init ok */
+		if (ret) {
+			ret = uhs2_card_init(card);
+			if (ret) {
+				if (shift_bit_func_enable(host))
+					set_pattern_value(host, 0x32);
+
+				goto exit;
+			} else if (card->card_type == CARD_SDIO) {
+				ret = FALSE;
+				goto end;
+			}
+		}
+		/* stbl check failed */
+		else if (stbl == FALSE) {
+			if (shift_bit_func_enable(host)
+			    && (host->cfg->card_item.sd7_sdmode_switch_control.card_init_flow_select)) {
+				host_uhs2_clear(host,
+					(bool)host->cfg->card_item.test_uhs2_setting2.enable_power_off_vdd1);
+				regval = pci_readl(host, 0x444);
+				if (regval & (1 << 11)) {
+					regval &= (~(1 << 11));
+					pci_writel(host, 0x444, regval);
+				}
+				card_variable_init(card);
+				hostven_set_pml0_requrest(host, FALSE);
+				goto express_flow;
+			}
+
+			if (card->card_type == CARD_UHS2
+			    && card->degrade_uhs2_legacy) {
+				card->card_type = CARD_NONE;
+				card->quick_init = 0;
+				card->degrade_freq_level = 0;
+
+				/* If card last stb.l is ok we continue try as UHS2 */
+				goto exit;
+			}
+
+			host_uhs2_clear(host,
+				(bool)host->cfg->card_item.test_uhs2_setting2.enable_power_off_vdd1);
+			goto legacy;
+		}
+
+		DbgErr("UHS2 init failed\n");
+		/* UHS2 init failed case, try again */
+		goto exit;
+	}
+
+legacy:
+
+	regval = pci_readl(host, 0x444);
+	if (regval & (1 << 11)) {
+		regval &= (~(1 << 11));
+		pci_writel(host, 0x444, regval);
+	}
+
+	card_variable_init(card);
+	/* Do SD Legacy card initialization */
+	if (card->card_type != CARD_MMC) {
+		hostven_set_pml0_requrest(host, FALSE);
+		ret = sd_legacy_init(card);
+		if (card->card_type == CARD_SDIO) {
+			ret = FALSE;
+			goto end;
+		}
+
+		if ((ret == FALSE)
+		    && (card->sw_ctrl_swicth_to_express == FALSE)) {
+			DbgErr("Legacy SD Init failed\n");
+			goto mmc;
+		} else
+			goto exit;
+	}
+
+mmc:
+	if ((card->card_type != CARD_SD) && (card->card_type != CARD_UHS2)) {
+		if (mmc_disabled(host)) {
+			DbgErr("Registry disable MMC card function!!\n");
+			goto exit;
+		}
+		host_poweroff(host, card->card_type);
+		host_init(host);
+		card_variable_init(card);
+		hostven_set_pml0_requrest(host, FALSE);
+		ret = emmc_init(card, FALSE);
+	}
+
+exit:
+	if (ret == TRUE) {
+		card_init_transfer(card, host);
+		card->initialized_once = TRUE;
+		card->state = CARD_STATE_WORKING;
+		card->continue_init_fail_cnt = 0;
+		if (host_wr_protect_pin(host) || card_wr_protect(card))
+			card->write_protected = TRUE;
+		else
+			card->write_protected = FALSE;
+
+	} else {
+		if (card->sw_ctrl_swicth_to_express == TRUE)
+			goto end;
+
+		card->continue_init_fail_cnt++;
+		retry_num--;
+		if ((retry_num == 0) ||
+		    (card->card_present == FALSE) ||
+		    (card->card_type == CARD_ERROR) || host_check_lost(host)) {
+			goto end;
+		}
+
+		/* Call degarde policy if try_times >= 4 */
+		if (card->continue_init_fail_cnt >= CARD_INIT_DEGARDE_TIME)
+			card_degrade_policy(card, NULL);
+
+		/* Need power cycle for retry, etc. */
+		if (card->card_type == CARD_UHS2) {
+			if (host->cfg->card_item.test_uhs2_setting2.enable_full_reset_reinit) {
+				/* If last time not use fullreset, then use fullreset */
+				bfullreset = bfullreset ? FALSE : TRUE;
+				if (bfullreset) {
+					uhs2_full_reset_card(card);
+					DbgErr
+					    ("Card Init failed do fullreset retry\n");
+					goto retry;
+				}
+			}
+		}
+
+		host_poweroff(host, CARD_NONE);
+		card->state = CARD_STATE_POWEROFF;
+		DbgErr("Card Init failed do poweroff retry\n");
+		goto retry;
+	}
+
+end:
+	if (ret == FALSE) {
+		host_poweroff(host, CARD_NONE);
+		card->state = CARD_STATE_POWEROFF;
+		if ((card->degrade_final) ||
+		    (card->card_type == CARD_NONE
+		     && card->continue_init_fail_cnt >= 5)) {
+			DbgErr("Card finally Init failed\n");
+			card->card_type = CARD_ERROR;
+		}
+		card->quick_init = 0;
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+}
+
+bool card_init_stage2(sd_card_t *card)
+{
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	switch (card->card_type) {
+	case CARD_SD:
+		ret = sd_init_stage2(card);
+		break;
+	case CARD_UHS2:
+		ret = uhs2_init_stage2(card);
+		break;
+	case CARD_MMC:
+	case CARD_EMMC:
+		ret = emmc_init_stage2(card);
+		break;
+	default:
+
+		break;
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+}
+
+/*
+ * Function Name: card_power_off
+ *
+ * Abstract: This function is used to set card to power off status
+ *           1. Resume from Sleep mode if necessary
+ *           2. Stop Infintie transfer if necessary
+ *           3. Poweroff Card
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * bool	directly: If true means do card poweroff directly(often use at error case)
+ *
+ * Output: None
+ *
+ * Return value: None
+ *
+ * Notes:
+ *
+ * Caller: card_enter_sleep
+ *
+ */
+
+void card_power_off(sd_card_t *card, bool directly)
+{
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM,
+		"Enter %s directy=%d\n", __func__, directly);
+
+	if (directly)
+		goto next;
+
+	/* If wake up failed than goto poweroff directly */
+	if (card_resume_sleep(card, FALSE) == FALSE)
+		goto next;
+
+	if (card_stop_infinite(card, FALSE, NULL) == FALSE)
+		goto next;
+	else {
+		/* go dormant for UHSII D3-hot */
+		card_enter_sleep(card, FALSE, TRUE);
+	}
+
+next:
+	if (card->state != CARD_STATE_POWEROFF)
+		host_poweroff(card->host, card->card_type);
+	card->state = CARD_STATE_POWEROFF;
+	card->thread_init_card_flag = 0;
+	card->has_built_inf = FALSE;
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+}
+
+/*
+ * Function Name: card_thermal_control
+ *
+ * Abstract: This Function is used to do card thremal control, only for SD
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output: None
+ *
+ * Return value: TRUE means ok, others means error, caller need do error recovery
+ *
+ * Notes: run in thread context
+ *
+ * Caller: func_thermal_control
+ *
+ */
+
+bool card_thermal_control(sd_card_t *card)
+{
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_FUNC_THERMAL, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->card_present == FALSE)
+		goto exit;
+
+	if (card->card_type == CARD_SD)
+		ret = sd_thermal_control(card);
+
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_FUNC_THERMAL, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return ret;
+}
+
+bool card_stop_infinite(sd_card_t *card, bool recover, sd_command_t *pcmd)
+{
+	bool ret = TRUE;
+	sd_command_t sd_cmd;
+	sd_command_t *cmd = (pcmd == NULL) ? &sd_cmd : pcmd;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->card_present == FALSE || card->has_built_inf == FALSE)
+		goto exit;
+
+	ret = card_send_command12(card, cmd);
+	if (ret == FALSE && recover) {
+		DbgErr("Stop Inf failed for cmd12\n");
+		ret = card_rw_recovery(card, cmd);
+		if (ret == FALSE)
+			goto exit;
+	}
+
+	if (ret == TRUE)
+		ret = card_check_rw_ready(card, cmd, 150);
+
+exit:
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+
+}
+
+bool card_enter_sleep(sd_card_t *card, bool recover, bool deepslp)
+{
+	bool ret = TRUE;
+	sd_command_t sd_cmd;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->card_type == CARD_UHS2) {
+		if (deepslp && card->uhs2_info.uhs2_cap.hibernate == 0)
+			deepslp = FALSE;
+		ret = card_stop_infinite(card, recover, &sd_cmd);
+		if (ret == FALSE)
+			goto exit;
+
+		ret = uhs2_enter_dmt(card, &sd_cmd, card->host, deepslp);
+
+		if (ret == TRUE) {
+			card->state =
+			    deepslp ? CARD_STATE_DEEP_SLEEP : CARD_STATE_SLEEP;
+		}
+	}
+
+exit:
+	if (ret == FALSE) {
+		DbgErr("enter sleep failed\n");
+		card_power_off(card, TRUE);
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+
+}
+
+bool card_resume_sleep(sd_card_t *card, bool recover)
+{
+	bool ret = TRUE;
+	bool deepslp = FALSE;
+	sd_command_t sd_cmd;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->state != CARD_STATE_DEEP_SLEEP
+	    && card->state != CARD_STATE_SLEEP)
+		goto exit;
+
+	if (card->card_type == CARD_UHS2) {
+		deepslp = (card->state == CARD_STATE_DEEP_SLEEP) ? TRUE : FALSE;
+		ret = uhs2_resume_dmt(card, &sd_cmd, card->host, deepslp);
+
+		if (ret == TRUE)
+			card->state = CARD_STATE_WORKING;
+	}
+
+exit:
+	if (ret == FALSE) {
+		DbgErr("resume sleep failed\n");
+		if (recover)
+			card_power_off(card, TRUE);
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_OPS, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+}
+
+bool card_piorw_data(sd_card_t *card, u32 sec_addr, u32 sec_cnt,
+		     e_data_dir dir, byte *data)
+{
+	bool ret = FALSE;
+
+	sd_command_t sd_cmd;
+	sd_host_t *host = card->host;
+	u8 cmd_index = 0;
+	u32 cmd_flag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	cfg_item_t *cfg = NULL;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_RW_TRACE, NOT_TO_RAM,
+		"Enter %s dir=%d seccnt=0x%08X secaddr=0x%08X\n", __func__,
+		dir, sec_cnt, sec_addr);
+
+	X_ASSERT(host != NULL);
+
+	cfg = host->cfg;
+	X_ASSERT(cfg != NULL);
+
+	if (data == NULL)
+		goto exit;
+
+	if (sec_cnt > 1)
+		cmd_flag |= CMD_FLG_MULDATA;
+
+	if (cmd_flag & CMD_FLG_MULDATA) {
+		if (dir == DATA_DIR_OUT)
+			cmd_index = SD_CMD25;
+		else
+			cmd_index = SD_CMD18;
+	} else {
+		if (dir == DATA_DIR_OUT)
+			cmd_index = SD_CMD24;
+		else
+			cmd_index = SD_CMD17;
+	}
+
+	cmd_set_auto_cmd_flag(card, &cmd_flag);
+	ret =
+	    card_send_sdcmd(card, &sd_cmd, cmd_index, sec_addr, cmd_flag, dir,
+			    data, sec_cnt * 512);
+	/* todo error recovery and cmd13 */
+
+exit:
+	if (ret == FALSE)
+		DbgErr("Card Pio dir=%d seccnt=0x%08X secaddr=0x%08X failed\n",
+		       dir, sec_cnt, sec_addr);
+	DbgInfo(MODULE_ALL_CARD, FEATURE_RW_TRACE, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+}
+
+static void card_cmd_copy(sd_command_t *dst, sd_command_t *src)
+{
+	sd_data_t *data = dst->data;
+
+	os_memcpy(dst, src, sizeof(sd_command_t));
+	dst->data = data;
+
+	if (data && src->data)
+		os_memcpy(dst->data, src->data, sizeof(sd_data_t));
+	else
+		src->data = NULL;
+}
+
+bool card_dma_rw_data(sd_card_t *card, u32 dma_mode, u32 sec_addr, u32 sec_cnt,
+		      e_data_dir dir, byte *data, sg_list_t *sglist,
+		      u32 sg_len, sd_command_t *cmd_err)
+{
+	bool ret = FALSE;
+
+	sd_command_t sd_cmd;
+	sd_data_t sd_data;
+	sd_host_t *host = card->host;
+	u8 cmd_index = 0;
+	u32 cmd_flag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	cfg_item_t *cfg = NULL;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_RW_TRACE, NOT_TO_RAM,
+		"Enter %s dir=%d seccnt=0x%08X secaddr=0x%08X\n", __func__,
+		dir, sec_cnt, sec_addr);
+
+	cfg = host->cfg;
+
+	if (data == NULL && dma_mode != CFG_TRANS_MODE_ADMA2) {
+		DbgErr("%s argument wrong\n", __func__);
+		goto end;
+	}
+
+	if (sec_cnt > 1)
+		cmd_flag |= CMD_FLG_MULDATA;
+
+	if (cmd_flag & CMD_FLG_MULDATA) {
+		if (dir == DATA_DIR_OUT)
+			cmd_index = SD_CMD25;
+		else
+			cmd_index = SD_CMD18;
+	} else {
+		if (dir == DATA_DIR_OUT)
+			cmd_index = SD_CMD24;
+		else
+			cmd_index = SD_CMD17;
+	}
+
+	cmd_set_auto_cmd_flag(card, &cmd_flag);
+	/* set dma mode */
+	if (dma_mode == CFG_TRANS_MODE_SDMA) {
+		/* host_dma_select(card->host, TRANS_SDMA); */
+		cmd_flag |= CMD_FLG_SDMA;
+		if ((card->card_type != CARD_UHS2) &&
+		    (cmd_flag & CMD_FLG_AUTO23)) {
+			/* SDMA don't use auto CMD23 */
+			cmd_flag &= ~CMD_FLG_AUTO23;
+			cmd_flag |= CMD_FLG_AUTO12;
+		}
+	} else if (dma_mode == CFG_TRANS_MODE_ADMA2) {
+		cmd_flag |= CMD_FLG_ADMA2;
+	} else {
+		/* host_dma_select(card->host, TRANS_ADMA2); */
+		cmd_flag |= CMD_FLG_ADMA_SDMA;
+	}
+
+	os_memset(&sd_data, 0, sizeof(sd_data_t));
+	ret =
+	    build_dma_ctx(card->host->pdx, &sd_data, cmd_flag, dir, data,
+			  sec_cnt * 512, sglist, sg_len);
+	if (ret == FALSE) {
+		DbgErr("build dma ctx failed\n");
+		goto end;
+	}
+
+	ret =
+	    card_send_sdcmd_dma_timeout(card, &sd_cmd, &sd_data, cmd_index,
+					sec_addr, cmd_flag, dir, data,
+					sec_cnt * 512, 0);
+
+	if (ret == FALSE && cmd_err != NULL)
+		card_cmd_copy(cmd_err, &sd_cmd);
+
+end:
+	if (ret == FALSE) {
+		DbgErr("Card dma dir=%d seccnt=0x%08X secaddr=0x%08X failed\n",
+		       dir, sec_cnt, sec_addr);
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_RW_TRACE, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+}
+
+/*
+ * Currently this function is used for dump mode only,
+ * todo to let it support normal case(Add node2 init code for normal case)
+ */
+bool card_adma2_rw_inf(sd_card_t *card, u32 sec_addr, u32 sec_cnt,
+		       e_data_dir dir, sg_list_t *sglist, u32 sg_len,
+		       sd_command_t *cmd_err)
+{
+	u32 flg = 0;
+	bool ret = FALSE;
+	sd_command_t sd_cmd;
+	dma_desc_buf_t *pdma = 0;
+	bht_dev_ext_t *pdx = card->host->pdx;
+	node_t *node = NULL;
+	sd_data_t sd_data;
+	bool data_26bit_len =
+		pdx->cfg->host_item.test_dma_mode_setting.enable_dma_26bit_len ?
+		TRUE : FALSE;
+	DbgInfo(MODULE_ALL_CARD, FEATURE_RW_TRACE, NOT_TO_RAM,
+		"Enter %s dir=%d seccnt=0x%08X secaddr=0x%08X\n", __func__,
+		dir, sec_cnt, sec_addr);
+
+	/* Step1 Check can use Infinte or not */
+	flg = cmd_can_use_inf(card, dir, sec_addr, sec_cnt);
+
+	/* not continue case stop infinite first */
+	if (card->has_built_inf && (flg != CMD_FLG_INF_CON)) {
+		ret = card_stop_infinite(card, FALSE, &sd_cmd);
+		if (ret == FALSE) {
+			DbgErr("%s stop infinite failed\n", __func__);
+			goto exit;
+		}
+	}
+
+	/* Non Infinte Case */
+	if (flg == 0) {
+		ret =
+		    card_dma_rw_data(card, CFG_TRANS_MODE_ADMA2, sec_addr,
+				     sec_cnt, dir, NULL, sglist, sg_len,
+				     cmd_err);
+		goto end;
+	}
+
+	/* Step2 Build Infinte sd_cmd */
+	node =
+	    (pdx->dma_api.cur_node !=
+	    &pdx->dma_api.dma_node) ? &pdx->dma_api.dma_node :
+		&pdx->dma_api.dma_node2;
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+	pdx->dma_api.cur_node = node;
+	if (dir == DATA_DIR_IN)
+		sd_cmd.cmd_index = SD_CMD18;
+	else
+		sd_cmd.cmd_index = SD_CMD25;
+
+	sd_cmd.argument = sec_addr;
+	sd_cmd.cmd_flag |=
+	    CMD_FLG_R1 | CMD_FLG_RESCHK | CMD_FLG_MULDATA | CMD_FLG_ADMA2 | flg;
+	sd_cmd.sd_cmd = 1;
+
+	/* Step3 alloc dma desc buf */
+	pdma = node_get_desc_res(node, MAX_ADMA2_TABLE_LEN);
+	if (pdma == NULL) {
+		DbgErr("%s get desc res failed\n", __func__);
+		ret = FALSE;
+		goto exit;
+	}
+
+	node->phy_node_buffer.head = *pdma;
+	node->phy_node_buffer.end =
+	    build_adma2_desc(sglist, sg_len, (byte *) pdma->va, pdma->len,
+			     card->host->bit64_enable, data_26bit_len);
+
+	if (node->phy_node_buffer.end.va == NULL) {
+		DbgErr("%s prepare dma buffer failed\n", __func__);
+		ret = FALSE;
+		goto exit;
+	}
+
+	if (flg & CMD_FLG_INF_CON)
+		update_adma2_inf_tb(node->phy_node_buffer.end.va,
+				    &(pdx->dma_api.adma2_inf_link_addr),
+				    &node->phy_node_buffer.head.pa,
+				    card->host->bit64_enable);
+	else
+		update_adma2_inf_tb(node->phy_node_buffer.end.va,
+				    &(pdx->dma_api.adma2_inf_link_addr), NULL,
+				    card->host->bit64_enable);
+
+	/* Step4 Send Command12 */
+	sd_cmd.data = &sd_data;
+	sd_cmd.data->data_mng.driver_buff = NULL;
+	sd_cmd.data->data_mng.offset = sd_cmd.data->data_mng.srb_cnt = 0;
+	sd_cmd.data->dir = dir;
+	sd_cmd.data->data_mng.total_bytess = sec_cnt * SD_BLOCK_LEN;
+	sd_cmd.data->data_mng.sys_addr = node->general_desc_tbl.pa;
+
+	cmd_generate_reg(card, &sd_cmd);
+	/* 4.issue cmd */
+	ret = cmd_execute_sync(card, &sd_cmd, NULL);
+
+exit:
+	if (ret == FALSE && cmd_err != NULL)
+		card_cmd_copy(cmd_err, &sd_cmd);
+
+end:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_RW_TRACE, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+
+}
+
+/*
+ * Function Name: card_recovery_flow
+ *
+ * Abstract: This Function is used to do card rw error recovery flow
+ *
+ * Input:
+ *
+ * sd_card_t *card: The Command will send to which Card
+ * sd_command_t *sd_cmd: if the init occurred at init stage this parameter will be null
+ *
+ * Output: None
+ *
+ * Return value:
+ *              REQ_RESULT_NO_CARD: card not exist or not card
+ *              REQ_RESULT_ACCESS_ERR: card rw recovery failed
+ *              REQ_RESULT_OK: no error
+ *
+ * Notes: This function is called in thread context to do RW Error Recovery
+ *
+ * Caller: tag_queue_rw_data_issue_stage
+ *
+ */
+
+e_req_result card_recovery_flow(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	e_req_result result = REQ_RESULT_ACCESS_ERR;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s\n", __func__);
+
+	os_mdelay(50);
+	if (card->card_present == FALSE || card->card_chg
+	    || host_check_lost(card->host) || card->sw_ctrl_swicth_to_express) {
+		DbgErr("Error Recover for no card\n");
+		result = REQ_RESULT_NO_CARD;
+		goto exit;
+	}
+
+	card->continue_rw_err_cnt++;
+
+	/* If Adma Error */
+	if (cmd_is_adma_error(sd_cmd)) {
+		DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"Adma error\n", __func__);
+		card->adma_err_cnt++;
+		if (card->adma_err_cnt >= 3) {
+			DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, "continue adma err>=3\n",
+				__func__);
+			card_degrade_policy(card, sd_cmd);
+			card->continue_rw_err_cnt = 0;
+			card->adma_err_cnt = 0;
+			/* card->thread_init_card_flag = 0; */
+			card_power_off(card, TRUE);
+			if (card_init(card, 1, FALSE) == FALSE) {
+				if (card->card_type == CARD_ERROR) {
+					DbgErr("Adma error recover fatal\n");
+					result = REQ_RESULT_NO_CARD;
+				} else {
+					DbgErr("Adma error recover failed\n");
+					result = REQ_RESULT_ACCESS_ERR;
+				}
+			} else
+				result = REQ_RESULT_OK;
+			goto exit;
+		}
+	}
+
+	if (card_rw_recovery(card, sd_cmd) == FALSE) {
+		card->continue_rw_err_cnt++;
+		if (card->continue_rw_err_cnt >= 3) {
+			DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, "continue rw err>=3\n",
+				__func__);
+			card_degrade_policy(card, sd_cmd);
+			card->continue_rw_err_cnt = 0;
+			card->adma_err_cnt = 0;
+		}
+
+		card_power_off(card, TRUE);
+		if (card_init(card, 1, FALSE) == FALSE) {
+			if (card->card_type == CARD_ERROR) {
+				DbgErr(" error recover fatal\n");
+				result = REQ_RESULT_NO_CARD;
+			} else {
+				DbgErr("error recover failed\n");
+				result = REQ_RESULT_ACCESS_ERR;
+			}
+		} else
+			result = REQ_RESULT_OK;
+	} else
+		result = REQ_RESULT_OK;
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "EXIT %s\n",
+		__func__);
+	return result;
+}
+
+bool card_set_blkcnt(sd_card_t *card, sd_command_t *sd_cmd, u32 blkcnt)
+{
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_LEGACY_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s blkcnt=%d\n", __func__, blkcnt);
+	ret =
+	    card_send_sdcmd(card, sd_cmd, SD_CMD23, blkcnt,
+			    CMD_FLG_R1 | CMD_FLG_RESCHK, DATA_DIR_NONE, NULL,
+			    0);
+	if (ret == FALSE)
+		DbgErr("issue cmd23 failed\n");
+
+	DbgInfo(MODULE_LEGACY_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+
+	return ret;
+}
+
+/*
+ * Function Name: card_is_poweroff
+ *
+ * Abstract: This Function is used to get card power state
+ *
+ * Input:
+ *
+ * sd_card_t *card : The target Card
+ *
+ * Output: None
+ *
+ * Return value:
+ *              TRUE: card poweroff
+ *              FALSE: card doesn't poweroff
+ *
+ * Notes:
+ *
+ * Caller: tag_queue_rw_data_issue_stage
+ *
+ */
+
+bool card_is_poweroff(sd_card_t *card)
+{
+	if (card->state == CARD_STATE_POWEROFF)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+/*
+ * Function Name: card_read_csd
+ *
+ * Abstract: De-select the card and send CMD9, and then select the card.
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *
+ * byte *data: used for storing CSD data
+ *
+ * Return value:
+ *              TRUE: read CSD successfully
+ *              FALSE: occur error when read CSD
+ *
+ * Notes:
+ *
+ * Caller: thread_gen_io
+ *
+ */
+
+bool card_read_csd(sd_card_t *card, byte *data)
+{
+
+	sd_command_t sd_cmd;
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+
+	return sd_read_csd(card, &sd_cmd, data);
+
+}
+
+/*
+ * Function Name: card_program_csd
+ *
+ * Abstract: Program CSD by CMD27
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *
+ * byte *data: used for storing CSD data
+ *
+ * Return value: return TRUE if program CSD successfully, else return FALSE
+ *
+ * Notes:
+ *
+ * Caller: thread_gen_io
+ *
+ */
+
+bool card_program_csd(sd_card_t *card, byte *data)
+{
+
+	sd_command_t sd_cmd;
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+	return sd_program_csd(card, &sd_cmd, data);
+
+}
diff --git a/drivers/scsi/bht/card/mmc.c b/drivers/scsi/bht/card/mmc.c
new file mode 100644
index 000000000000..449307972400
--- /dev/null
+++ b/drivers/scsi/bht/card/mmc.c
@@ -0,0 +1,1666 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: mmc.c
+ *
+ * Abstract: mmc/emmc card initialization
+ *
+ * Version: 1.00
+ *
+ * Author: Amma.Li
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 9/23/2014   Creation    Amma.Li
+ */
+#include "../include/basic.h"
+#include "../include/cardapi.h"
+#include "../include/hostapi.h"
+#include "../host/hostven.h"
+#include "../host/hostreg.h"
+#include "cardcommon.h"
+#include "../include/cmdhandler.h"
+#include "../include/debug.h"
+#include "../include/util.h"
+#define  MMC_SPEC_VERS	0x04U
+/* ------------------emmc setting-------------------- */
+/* ext_csd[196]: card type */
+#define	MMC_CARD_TYPE_H200		  0x30U
+#define	MMC_CARD_TYPE_H400		  0xC0U
+#define	MMC_CARD_TYPE_HS		  0x0FU
+#define	MMC_CARD_DDR_SUPP		  0x0CU
+#define   MMC_CARD_TYPE_HS_DDR_12   0x8
+#define   MMC_CARD_TYPE_HS_DDR_18   0x4
+#define   MMC_CARD_TYPE_HS_52M      0x2
+#define   MMC_CARD_TYPE_HS_26M      0x1
+/* ext_csd[183]: Bus Width */
+#define   MMC_EXTCSD_BUS_WIDTH     (0x00B70000)
+#define   MMC_BUSW_1BIT                0
+#define   MMC_BUSW_SDR_4BIT           (1 << 8)
+#define   MMC_BUSW_SDR_8BIT           (2 << 8)
+#define   MMC_BUSW_DDR_4BIT           (5 << 8)
+#define   MMC_BUSW_DDR_8BIT           (6 << 8)
+/* ext_csd[185]: HS_TIMING */
+#define  MMC_EXTCSD_HS_TIMING       (0x00B90000)
+#define  MMC_TIMING_BACKWARDS       0
+#define  MMC_TIMING_HIGH_SPEED      (1 << 8)
+#define  MMC_TIMING_HS200           (2 << 8)
+#define  MMC_TIMING_HS400           (3 << 8)
+#define  MMC_DRIVER_TYPE            0
+/* emmc CMD6 setting */
+#define   MMC_EXTCSD_WRITE           (3 << 24)
+#define   MMC_EXTCSD_SET             (1 << 24)
+#define   MMC_EXTCSD_CLEAN           (2 < 24)
+/* emmc/mmc RCA */
+#define   MMC_RCA                    (1 << 16)
+/* -------------emmc setting end------------------ */
+static void emmc_get_ext_csd_info(sd_card_t *card);
+static bool emmc_switch_buswidth(sd_card_t *card, sd_command_t *sd_cmd);
+static void emmc_set_freq(sd_card_t *card, u32 clock_freq, bool bddr50);
+
+/* -------------emmc / mmc card CMD setting------------- */
+
+/*
+ * Function Name: emmc_card_init_ready
+ *
+ * Abstract:
+ *           1. Issue CMD1 to Get OCR
+ *           2. Set the card ocr variable
+ *           3. Wait for card ready
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if card ready, else return FALSE
+ *
+ * Notes:
+ *
+ * Caller: emmc_init
+ *
+ */
+
+static bool emmc_card_init_ready(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	byte cmd_index = SD_CMD1;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R3;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	bool ret = FALSE;
+	loop_wait_t wait;
+	u32 delay_us = 20;
+
+	sd_host_t *host = card->host;
+	card_info_t *card_info = &(card->info);
+	cfg_emmc_mode_t *emmc_mode = &(host->cfg->card_item.emmc_mode);
+
+	if (emmc_mode->enable_18_vcc)
+		argument |= EMMC_OCR_LOW;
+	else
+		argument |= EMMC_OCR_HI;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s arg 0x%08x\n", __func__, argument);
+
+	/* Wait for card ready */
+	util_init_waitloop(card->host->pdx,
+			   host->cfg->timeout_item.test_card_init_timeout.value,
+			   delay_us, &wait);
+
+	do {
+		ret =
+		    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag,
+				    dir, data, datalen);
+		if (ret == FALSE) {
+			DbgErr("Issue CMD1 to get eMMC card OCR Fail.\n");
+			break;
+		}
+
+		/* Check Busy status. 0b: On initialization; 1b: Initialization Complete. */
+		if ((sd_cmd->response[0] & 0x80000000) == 0) {
+			os_udelay(delay_us);
+			continue;
+		} else {
+			break;
+		}
+	} while (!util_is_timeout(&wait));
+
+	/* If card ready, set related software flags */
+	if (ret) {
+		/* check card ready or not */
+		if (sd_cmd->response[0] & 0x80000000) {
+			if (sd_cmd->response[0] & 0x40000000)
+				/* the capability > 2GB */
+				card_info->card_ccs = 1;
+			else
+				/* the capability < 2GB */
+				card_info->card_ccs = 0;
+		} else
+			ret = FALSE;
+	}
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ * Function Name: emmc_set_rca
+ *
+ * Abstract: Set a new relative address RCA for MMC/eMMC card(CMD3)
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if issue CMD3 successfully, else return FALSE
+ *
+ * Notes:
+ *
+ * Caller: emmc_init
+ *
+ */
+
+bool emmc_set_rca(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool ret = FALSE;
+	byte cmd_index = SD_CMD3;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	card_info_t *card_info = &(card->info);
+
+	argument = MMC_RCA;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s arg 0x%08x\n", __func__, argument);
+
+	/* Issue CMD3 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		/* Update the card RCA */
+		card_info->rca = (argument & 0xffff0000) >> 16;
+	}
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ * Function Name: emmc_get_ext_csd
+ *
+ * Abstract: Read the MMC/EMMC card Ext_Csd Data
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if issue eMMC CMD8 successfully, else return FALSE
+ *
+ * Notes:
+ *
+ * Caller: emmc_init
+ *
+ */
+
+static bool emmc_get_ext_csd(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	byte cmd_index = SD_CMD8;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[512];
+	u32 datalen = 512;
+
+	bool ret = FALSE;
+	mmc_card_info_t *mmc_info = &(card->mmc);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue eMMC CMD8 to get Ext_Csd */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		/* Get the Ext_Csd */
+		os_memcpy(&(mmc_info->raw_extcsd[0]), data, 512);
+		emmc_get_ext_csd_info(card);
+	}
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ * Function Name: emmc_send_cmd6
+ *
+ * Abstract:
+ *           1. Issue CMD6 to switch mode to modify the Ext_Csd register
+ *           2. Set the emmc card hs_timing & bus width
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ * argument: [31:26] set to 0
+ *           [25:24]: Access    1: set     2: clean     3: write
+ *           [23:16]: Index    the ext_csd index
+ *           [15:8]: value
+ *           [7:3]: set to 0
+ *           [2:0]: cmd set
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if issue CMD6 successfully, else return FALSE
+ *
+ * Notes:
+ *
+ * Caller: emmc_switch_buswidth
+ *
+ */
+
+static bool emmc_send_cmd6(sd_card_t *card,
+			   sd_command_t *sd_cmd, u32 argument)
+{
+	bool result = FALSE;
+	byte cmd_index = SD_CMD6;
+	u32 cmdflag = CMD_FLG_R1B;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s arg = 0x%08x\n", __func__, argument);
+	result =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_bustest_r
+ *
+ * Abstract:
+ *			1. MMC/eMMC card bus width test read (CMD14)
+ *          2. A host reads the reversed bus testing data pattern from a Device.
+ *          3. Used after CMD19 (bus width test write CMD),
+ *				need to check the cmd and data transfer error
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ * u8 *buf : read data pattern buffer
+ * u32 data_len : read data length
+ *
+ * Output: None
+ *
+ * Return value: Return TRUE if issue CMD14 successfully, else return FALSE
+ *
+ * Notes:
+ *
+ * Caller: emmc_bus_width_test
+ */
+static bool emmc_bustest_r(sd_card_t *card,
+			   sd_command_t *sd_cmd, u8 *buf, u32 data_len)
+{
+	bool result = FALSE;
+	byte cmd_index = SD_CMD14;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	byte *data = buf;
+	u32 datalen = data_len;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	result =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_bustest_w
+ *
+ * Abstract:
+ *
+ * 1. MMC/eMMC card bus width test write (CMD19)
+ * 2. A host send the reversed bus testing data pattern from a Device.
+ * 3. Do not need to check the cmd and data transfer error
+ *
+ * Input:
+ *
+ * sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ * sd_command_t *sd_cmd: Pointer to sd command structure
+ * u8 *buf : write data pattern buffer
+ * u32 data_len : write data length
+ *
+ * Output:
+ * None
+ *
+ * Return value:
+ *
+ * Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ * Caller: card_init
+ */
+static bool emmc_bustest_w(sd_card_t *card,
+			   sd_command_t *sd_cmd, u8 *buf, u32 data_len)
+{
+	bool result = FALSE;
+	byte cmd_index = SD_CMD19;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK | CMD_FLG_NO_TRANS;
+	e_data_dir dir = DATA_DIR_OUT;
+	byte *data = buf;
+	u32 datalen = data_len;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	result =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_tuning_hw
+ *
+ * Abstract:
+ *
+ *			1.  Hardware Tuning Procedure (CMD21)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *			sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_tuning
+ */
+
+static bool emmc_tuning_hw(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	byte cmd_index = SD_CMD21;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_TUNE;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	sd_host_t *host = card->host;
+	u32 datalen = 0x40;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* set hardware tuning */
+	host_set_tuning_mode(host, TRUE);
+
+	if ((host->chip_type == CHIP_SDS0) ||
+	    (host->chip_type == CHIP_SDS1) || (host->chip_type == CHIP_FUJIN2)
+	    ) {
+		/* add 200us delay before CMD19 to fix FJ2 ASIC issue 14# */
+		os_udelay(200);
+	}
+
+	/* send emmc tuning CMD21 */
+	result =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (result == FALSE) {
+		DbgErr("eMMC card send hardware tuning CMD failed!!\n");
+		goto exit;
+	}
+
+	/* check tuning success or not */
+	result = host_chk_tuning_comp(host, TRUE);
+	if (!result)
+		DbgErr("Check eMMC tuning failed!\n");
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: sd_tuning_sw
+ *
+ * Abstract:
+ *
+ *			1.  Software Tuning Procedure (CMD21)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *			sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_tuning
+ */
+static bool emmc_tuning_sw(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	byte cmd_index = SD_CMD21;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_TUNE;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u16 i = 0;
+	sd_host_t *host = card->host;
+	u32 datalen = 0x40;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	for (i = 0; i < 100; i++) {
+		/* set software tuning */
+		host_set_tuning_mode(host, FALSE);
+
+		if ((host->chip_type == CHIP_SDS0) ||
+		    (host->chip_type == CHIP_SDS1) ||
+		    (host->chip_type == CHIP_FUJIN2)
+		    ) {
+			/* add 200us delay before CMD19 to fix FJ2 ASIC issue 14# */
+			os_udelay(200);
+		}
+
+		/* send emmc tuning CMD21 */
+		result =
+		    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag,
+				    dir, data, datalen);
+		if (result == FALSE) {
+			DbgErr("eMMC card hardware tuning failed!!\n");
+			goto exit;
+		}
+
+		/* check tuning success or not */
+		result = host_chk_tuning_comp(host, FALSE);
+		if (result)
+			break;
+	}
+
+exit:
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_tuning
+ *
+ * Abstract:
+ *
+ *			 1. Send Hw tuning or Sw tuning by the registry setting
+ *             2. tuning mode: 1 = CFG_TUNING_MODE_HW     0 = CFG_TUNING_MODE_SW
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+bool emmc_tuning(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->mmc.cur_hs_type != EMMC_MODE_HS200
+	    && card->mmc.cur_hs_type != EMMC_MODE_HS400) {
+		result = TRUE;
+		goto exit;
+	}
+
+	if (TUNING_MODE)
+		result = emmc_tuning_hw(card, sd_cmd);
+	else
+		result = emmc_tuning_sw(card, sd_cmd);
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_bus_width_test
+ *
+ * Abstract:
+ *			 1. MMC/eMMC card bus width test by CMD14 (read) and CMD19(write)
+ *            2. The data pattern decided by the bus width (8-bit\4-bit)
+ *            3. Do not need to check the CMD19 any cmd and data transfer error
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *           u32 data_len : data pattern length
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+static bool emmc_bus_width_test(sd_card_t *card,
+				sd_command_t *sd_cmd, u32 data_len)
+{
+	bool result = FALSE;
+	u8 buf[8] = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa };
+	u8 patten[8] = { 0 };
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s datlen %d\n", __func__, data_len);
+
+	if (card->card_present == FALSE)
+		goto exit;
+
+	if (data_len == 4) {
+		os_memset(buf, 0, 8);
+		os_memset(buf, 0x5a, 4);
+
+	}
+
+	/* send CMD19 (eMMC bus write) */
+	result = emmc_bustest_w(card, sd_cmd, buf, data_len);
+
+	/* delay NCR clock */
+	os_udelay(20);
+
+	/* send CMD14 (eMMC bus read) */
+	result = emmc_bustest_r(card, sd_cmd, patten, data_len);
+	if (!result) {
+		DbgErr("eMMC card CMD14 Receive bus width data Failed.\n");
+	} else {
+		result = FALSE;
+
+		/* check patten */
+		if (data_len == 8) {
+			if ((patten[0] == 0xaa) || (patten[1] == 0x55)) {
+				result = TRUE;
+				DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT,
+					NOT_TO_RAM,
+					"8-bit bus width test OK!!\n");
+			}
+		} else if (data_len == 4) {
+			if (patten[0] == 0xa5) {
+				result = TRUE;
+				DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT,
+					NOT_TO_RAM,
+					"4-bit bus width test OK!!\n");
+			}
+		}
+	}
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_get_ext_csd_info
+ *
+ * Abstract:
+ *
+ *			 1. Get the Ext_Csd structure
+ *				(card_type, power class for 52M 26M 1.8V 3.3V voltage)
+ *				from the Ext_Csd raw
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *
+ *			None
+ *
+ * Notes:
+ *
+ *           Caller: emmc_get_ext_csd
+ */
+static void emmc_get_ext_csd_info(sd_card_t *card)
+{
+	mmc_card_info_t *mmc_info = &(card->mmc);
+	extcsd_t *ext_csd = &(mmc_info->ext_csd);
+	u8 *raw_ext_csd = &(mmc_info->raw_extcsd[0]);
+
+	ext_csd->card_type = *(raw_ext_csd + 196);
+	ext_csd->driver_strength_type = *(raw_ext_csd + 197);
+	ext_csd->pwr_cl_52_195 = *(raw_ext_csd + 200);
+	ext_csd->pwr_cl_26_195 = *(raw_ext_csd + 201);
+	ext_csd->pwr_cl_52_360 = *(raw_ext_csd + 202);
+	ext_csd->pwr_cl_26_360 = *(raw_ext_csd + 203);
+	ext_csd->pwr_cl_ddr_52_195 = *(raw_ext_csd + 238);
+	ext_csd->pwr_cl_ddr_52_360 = *(raw_ext_csd + 239);
+	ext_csd->sec_cnt =
+	    (*(raw_ext_csd + 215) << 24) + (*(raw_ext_csd + 214) << 16) +
+	    (*(raw_ext_csd + 213) << 8) + *(raw_ext_csd + 212);
+}
+
+/*
+ *
+ * Function Name: emmc_switch_hs400
+ *
+ * Abstract:
+ *			 1. eMMC card switch HS400 mode
+ *
+ * Input:
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *           Caller: emmc_init_stage2
+ */
+static bool emmc_switch_hs400(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 argument = 0;
+	sd_host_t *host = card->host;
+
+	mmc_card_info_t *mmc_info = &(card->mmc);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+#if (0)
+	/* 1. Check card support hs400 */
+	if ((mmc_info->ext_csd.card_type & MMC_CARD_TYPE_H400) == 0) {
+		DbgErr("eMMC card don't support HS400 mode!!\n");
+		goto exit;
+	}
+
+	/* 2. check card support 8-bit bus width */
+	if ((mmc_info->cur_buswidth != EMMC_8Bit_BUSWIDTH) ||
+	    (host->bus_8bit_supp == FALSE)
+	    ) {
+		DbgErr("The card or host don't support 8bit bus width!!\n");
+		goto exit;
+	}
+#endif
+
+	/* 3. clear UHSI mode select */
+	host_set_uhs_mode(host, 0);
+
+	/* 4.set card mode to DDR50 mode (eMMC: CMD6) */
+	argument =
+	    (MMC_EXTCSD_WRITE | MMC_EXTCSD_HS_TIMING | MMC_TIMING_HIGH_SPEED |
+	     (mmc_info->drv_strength << 12));
+	result = emmc_send_cmd6(card, sd_cmd, argument);
+	if (!result) {
+		DbgErr("Switch DDR50 mode Failed.\n");
+		goto exit;
+	}
+
+	/* 5. change clock to 50M Hz for DDR50 mode */
+	emmc_set_freq(card, SD_CLK_50M, TRUE);
+
+	/* 6.change to 8-bit DDR mode (eMMC: CMD6) */
+	argument =
+	    (MMC_EXTCSD_WRITE | MMC_EXTCSD_BUS_WIDTH | MMC_BUSW_DDR_8BIT);
+	result = emmc_send_cmd6(card, sd_cmd, argument);
+	if (!result) {
+		DbgErr("Change to 8-bit DDR mode Failed.\n");
+		goto exit;
+	}
+
+	/* 7.switch to hs400 */
+	argument =
+	    (MMC_EXTCSD_WRITE | MMC_EXTCSD_HS_TIMING | MMC_TIMING_HS400 |
+	     (mmc_info->drv_strength << 12));
+	result = emmc_send_cmd6(card, sd_cmd, argument);
+	if (!result) {
+		DbgErr("Switch hs400 mode Failed.\n");
+		goto exit;
+	}
+
+	/* 8.if switch hs400 ok, set PCI Register */
+	host_emmc_hs400_set(host, TRUE);
+
+	/* 9.change SDCLK frequency to 200M Hz */
+	emmc_set_freq(card, SD_CLK_BASE, FALSE);
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_switch_hs200
+ *
+ * Abstract:
+ *			 1. eMMC card switch HS200 mode
+ *
+ * Input:
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *           Caller: emmc_init_stage2
+ */
+static bool emmc_switch_hs200(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 argument = 0;
+	u32 card_status = 0;
+	sd_host_t *host = card->host;
+	mmc_card_info_t *mmc_info = &(card->mmc);
+	cfg_emmc_mode_t *emmc_mode = &(host->cfg->card_item.emmc_mode);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* 1. switch signal Data Rate mode bus width (4-bit or 8-bit: eMMC CMD6) */
+	mmc_info->cur_hs_type = EMMC_MODE_HS200;
+	result = emmc_switch_buswidth(card, sd_cmd);
+	if (!result) {
+		DbgErr("Set signal Data Rate 8/4-bit Bus Width Failed.\n");
+		goto exit;
+	}
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Card support driver type %x\n",
+		mmc_info->ext_csd.driver_strength_type);
+	if ((2 << (emmc_mode->drv_strength)) &
+	    (mmc_info->ext_csd.driver_strength_type)
+	    )
+		mmc_info->drv_strength = (byte) emmc_mode->drv_strength;
+	else
+		mmc_info->drv_strength = 0;
+	/* 2.switch card support driver type & hs200 mode (eMMC: CMD6) */
+	argument =
+	    (MMC_EXTCSD_WRITE | MMC_EXTCSD_HS_TIMING | MMC_TIMING_HS200 |
+	     (mmc_info->drv_strength << 12));
+	result = emmc_send_cmd6(card, sd_cmd, argument);
+	if (!result) {
+		DbgErr("Switch HS200 mode Failed.\n");
+		goto exit;
+	}
+
+	/* 3.check card status (Issue CMD13) */
+	result = card_get_card_status(card, sd_cmd, &card_status);
+	if ((result == FALSE) || (card_status & 0x80)
+	    ) {
+		DbgErr("Card Status failed.\n");
+		goto exit;
+	}
+
+	/* 4.change clock to 200M Hz */
+	emmc_set_freq(card, SD_CLK_BASE, FALSE);
+
+	/* 5.switch mode (hs200 == SDR104) */
+	host_set_uhs_mode(host, SDHCI_CTRL_UHS_HS200);
+
+	if (((host->chip_type < CHIP_SEAEAGLE2) || (host->chip_type == CHIP_GG8)
+	     || (host->chip_type == CHIP_ALBATROSS))
+	    && (mmc_info->cur_buswidth == EMMC_8Bit_BUSWIDTH)) {
+		host_set_buswidth(host, BUS_WIDTH4);
+	}
+
+	result = emmc_tuning(card, sd_cmd);
+	if (!result)
+		goto exit;
+
+	if (mmc_info->cur_buswidth == EMMC_8Bit_BUSWIDTH)
+		host_set_buswidth(host, BUS_WIDTH8);
+
+	/* 7.if tuning ok, set PCI & Host Register */
+	host_emmc_hs400_set(host, FALSE);
+
+exit:
+	if (result == FALSE)
+		mmc_info->cur_hs_type = 0;
+	else
+		emmc_mode->enable_ddr_mode = 0;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_switch_hs
+ *
+ * Abstract:
+ *			 1. eMMC card switch High Speed mode
+ *
+ * Input:
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *           Caller: emmc_init_stage2
+ */
+static bool emmc_switch_hs(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 argument = 0;
+	u32 clk = 0;
+	bool bddr50 = FALSE;
+	sd_host_t *host = card->host;
+	u32 b_dis_hs = host->cfg->card_item.emmc_mode.dis_hs;
+	u8 device_type = card->mmc.ext_csd.card_type;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/*
+	 * if registry set disable hs mode or host don't support high speed,
+	 * check card type, and set the clk
+	 */
+	if (b_dis_hs || (host->hs_supp == 0)) {
+		DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"User disable high speed, select 25M timing!!\n");
+		if (device_type & MMC_CARD_TYPE_HS_26M) {
+			DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"select 25M timing!!\n");
+			clk = SD_CLK_25M;
+		}
+	} else {
+		if (device_type &
+		    (MMC_CARD_TYPE_HS_52M | MMC_CARD_TYPE_HS_DDR_12 |
+		     MMC_CARD_TYPE_HS_DDR_18)) {
+			DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"select 52M timing!!\n");
+			clk = SD_CLK_50M;
+			if ((host->cfg->card_item.emmc_mode.enable_ddr_mode) &&
+			    (device_type & MMC_CARD_DDR_SUPP)
+			    ) {
+				bddr50 = TRUE;
+			}
+		} else if (device_type & MMC_CARD_TYPE_HS_26M) {
+			DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"select 25M timing!!\n");
+			clk = SD_CLK_25M;
+		}
+	}
+
+	/* dump power size */
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"PMclass- 52M, DDR, 3.3v: 0x%xh 1.8v: 0x%xh\n",
+		card->mmc.ext_csd.pwr_cl_ddr_52_360,
+		card->mmc.ext_csd.pwr_cl_ddr_52_195);
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"PMclass- 26M, SDR, 3.3v: 0x%xh 1.8v: 0x%xh\n",
+		card->mmc.ext_csd.pwr_cl_26_360,
+		card->mmc.ext_csd.pwr_cl_26_195);
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"PMclass- 52M, SDR, 1.8v: 0x%xh 3.3v: 0x%xh\n",
+		card->mmc.ext_csd.pwr_cl_52_195,
+		card->mmc.ext_csd.pwr_cl_52_360);
+
+	/* if host & card all support high speed, then set the hs_timing */
+	if (clk) {
+		argument =
+		    (MMC_EXTCSD_WRITE | MMC_EXTCSD_HS_TIMING |
+		     MMC_TIMING_HIGH_SPEED);
+		result = emmc_send_cmd6(card, sd_cmd, argument);
+		if (!result) {
+			DbgErr("Switch High Speed mode Failed.\n");
+			goto exit;
+		}
+	}
+
+	/* change clock */
+	if (clk)
+		emmc_set_freq(card, clk, bddr50);
+
+	/* if clock > 50M hz, set 0x28[2]: high speed enable */
+	if (clk == SD_CLK_50M)
+		host_set_highspeed(host, TRUE);
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_ddr_mode_set
+ *
+ * Abstract:
+ *			 1. set eMMC card DDR50 mode
+ *
+ * Input:
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *           Caller: emmc_init_stage2
+ */
+static void emmc_ddr_mode_set(sd_card_t *card)
+{
+	sd_host_t *host = card->host;
+	u32 b_dis_hs = host->cfg->card_item.emmc_mode.dis_hs;
+	u8 device_type = card->mmc.ext_csd.card_type;
+	u32 enable_ddr = host->cfg->card_item.emmc_mode.enable_ddr_mode;
+
+	if ((b_dis_hs == FALSE) &&
+	    (enable_ddr) && (device_type & MMC_CARD_DDR_SUPP)
+	    ) {
+		DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Set host DDR50 mode!!\n");
+		host_set_uhs_mode(host, SDHCI_CTRL_UHS_DDR50);
+		host_emmc_ddr_set(host, TRUE);
+	} else {
+		host->cfg->card_item.emmc_mode.enable_ddr_mode = 0;
+		host_emmc_ddr_set(host, FALSE);
+	}
+
+}
+
+/*
+ *
+ * Function Name: emmc_switch_buswidth
+ *
+ * Abstract:
+ *			 1. set eMMC card bus width
+ *
+ * Input:
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *           Caller: emmc_init_stage2
+ */
+static bool emmc_switch_buswidth(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 argument = 0;
+	u32 data_len = 0;
+	sd_host_t *host = card->host;
+	mmc_card_info_t *mmc_info = &(card->mmc);
+	u32 dis_8_bit = host->cfg->card_item.emmc_mode.dis_8bit_bus_width;
+	u32 dis_4_bit = host->cfg->card_item.emmc_mode.dis_4bit_bus_width;
+	u32 enable_ddr = host->cfg->card_item.emmc_mode.enable_ddr_mode;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->card_present == FALSE)
+		goto exit;
+
+	/* check host & user support 8-bit bus width */
+	if ((dis_8_bit == 0) && (host->bus_8bit_supp)
+	    ) {
+		mmc_info->cur_buswidth = EMMC_8Bit_BUSWIDTH;
+		data_len = 8;
+
+		/* host set 8-bit bus width */
+		host_set_buswidth(host, BUS_WIDTH8);
+
+		/* delay 100us */
+		os_udelay(100);
+
+		result = emmc_bus_width_test(card, sd_cmd, data_len);
+		if (result == TRUE) {
+			if (enable_ddr &&
+			    (card->mmc.ext_csd.card_type & MMC_CARD_DDR_SUPP) &&
+			    (mmc_info->cur_hs_type != EMMC_MODE_HS200)
+			    ) {
+				argument =
+				    (MMC_EXTCSD_WRITE | MMC_EXTCSD_BUS_WIDTH |
+				     MMC_BUSW_DDR_8BIT);
+			} else {
+				argument =
+				    (MMC_EXTCSD_WRITE | MMC_EXTCSD_BUS_WIDTH |
+				     MMC_BUSW_SDR_8BIT);
+			}
+			result = emmc_send_cmd6(card, sd_cmd, argument);
+			if (!result)
+				DbgErr("Set 8-bit bus width Failed.\n");
+			else
+				goto exit;
+		}
+		DbgErr("Set 8-bit bus width Failed.\n");
+
+	}
+
+	/* check user support 4-bit bus width */
+	if (dis_4_bit == FALSE) {
+		mmc_info->cur_buswidth = EMMC_4Bit_BUSWIDTH;
+		/* host set 4-bit bus width */
+		host_set_buswidth(host, BUS_WIDTH4);
+		data_len = 4;
+
+		/* Test 4-bit patten, set block size to 4 bytes */
+		result = emmc_bus_width_test(card, sd_cmd, data_len);
+		if (!result)
+			goto exit;
+
+		if (enable_ddr &&
+		    (card->mmc.ext_csd.card_type & MMC_CARD_DDR_SUPP) &&
+		    (mmc_info->cur_hs_type != EMMC_MODE_HS200)
+		    ) {
+			argument =
+			    (MMC_EXTCSD_WRITE | MMC_EXTCSD_BUS_WIDTH |
+			     MMC_BUSW_DDR_4BIT);
+		} else {
+			argument =
+			    (MMC_EXTCSD_WRITE | MMC_EXTCSD_BUS_WIDTH |
+			     MMC_BUSW_SDR_4BIT);
+		}
+
+		result = emmc_send_cmd6(card, sd_cmd, argument);
+		if (!result)
+			DbgErr("Set 4-bit bus width Failed.\n");
+		else
+			goto exit;
+
+		DbgErr("Set 4-bit bus width Failed.\n");
+
+	}
+
+	/* default 1-bit bus width */
+	mmc_info->cur_buswidth = EMMC_1Bit_BUSWIDTH;
+	host_set_buswidth(host, BUS_WIDTH1);
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_set_trans_clk
+ *
+ * Abstract:
+ *			 1. set MMC/eMMC card(Not support HS) transfer clock
+ *
+ * Input:
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *           Caller: emmc_init_stage2
+ */
+static bool emmc_set_trans_clk(sd_card_t *card)
+{
+	bool result = FALSE;
+	u32 freq_unit = 0;
+	u32 multip_factor = 0;
+	u32 trans_clk;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	/* get the frequency unit    0: 1KHz     1: 10KHz     2: 100KHz       3: 1000KHZ */
+	switch ((card_info->csd.tran_speed) & 0x7) {
+	case 0:
+		freq_unit = 1;
+		break;
+	case 1:
+		freq_unit = 10;
+		break;
+	case 2:
+		freq_unit = 100;
+		break;
+	case 3:
+		freq_unit = 1000;
+		break;
+	default:
+		return result;
+	}
+
+	switch (((card_info->csd.tran_speed) & 0x78) >> 3) {
+	case 1:
+		multip_factor = 100;
+		break;
+	case 2:
+		multip_factor = 120;
+		break;
+	case 3:
+		multip_factor = 130;
+		break;
+	case 4:
+		multip_factor = 150;
+		break;
+	case 5:
+		multip_factor = 200;
+		break;
+	case 6:
+		multip_factor = 260;
+		break;
+	case 7:
+		multip_factor = 300;
+		break;
+	case 8:
+		multip_factor = 350;
+		break;
+	case 9:
+		multip_factor = 400;
+		break;
+	case 10:
+		multip_factor = 450;
+		break;
+	case 11:
+		multip_factor = 520;
+		break;
+	case 12:
+		multip_factor = 550;
+		break;
+	case 13:
+		multip_factor = 600;
+		break;
+	case 14:
+		multip_factor = 700;
+		break;
+	case 15:
+		multip_factor = 800;
+		break;
+	default:
+		goto exit;
+	}
+
+	trans_clk = freq_unit * multip_factor;
+	if (trans_clk >= SD_CLK_BASE) {
+		/* 200M Hz */
+		trans_clk = SD_CLK_BASE;
+	}
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"MMC support trans clk=%d\n", trans_clk);
+	/* change transfer clock */
+	emmc_set_freq(card, trans_clk, FALSE);
+	result = TRUE;
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+static u64 get_emmc_sec_count(sd_card_t *card)
+{
+	u64 capability = 0;
+
+	card_info_t *card_info = &(card->info);
+	mmc_card_info_t *mmc_info = &(card->mmc);
+
+	/* <2G capability / SD_BLOCK_LEN */
+	if (card_info->card_ccs == 0)
+		capability = card->sec_count;
+	else {
+		/* > 2G sector count */
+		capability = mmc_info->ext_csd.sec_cnt;
+	}
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"MMC * EMMC sector count = 0x%x!!\n", capability);
+	return capability;
+}
+
+/*
+ *
+ * Function Name: set_emmc_block_len
+ *
+ * Abstract:
+ *			 1. set MMC/eMMC card block length
+ *
+ * Input:
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *            bool b_hs400: if DDR mode, can't set CMD16 to set block length
+ *
+ * Output:
+ *			None
+ *
+ * Return value:
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *           Caller: emmc_init_stage2
+ */
+static bool set_emmc_block_len(sd_card_t *card, bool b_hs400)
+{
+	bool result = FALSE;
+	u32 block_len = 0;
+	card_info_t *card_info = &(card->info);
+	sd_host_t *host = card->host;
+	cfg_emmc_mode_t *cfg_emmc_mode = &(host->cfg->card_item.emmc_mode);
+	sd_command_t sd_cmd;
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+
+	block_len = (2 << (card_info->csd.read_bl_len));
+
+	if (block_len > host->max_block_len) {
+		DbgWarn(MODULE_MMC_CARD, NOT_TO_RAM,
+			"Device block length > HW Init max block length!!\n");
+	}
+
+	if ((cfg_emmc_mode->enable_ddr_mode) || b_hs400) {
+		/* todo: if DDR mode, */
+		result = TRUE;
+	} else {
+		result = card_set_block_len(card, &sd_cmd, SD_BLOCK_LEN);
+	}
+
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_init_stage2
+ *
+ * Abstract:
+ *			 1. emmc card initialize main function.
+ *            2. Fill virtual card structure, like cid, csd, ext_csd etc.
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init_stage2
+ */
+bool emmc_init_stage2(sd_card_t *card)
+{
+	bool result = FALSE;
+	sd_host_t *host = card->host;
+	mmc_card_info_t *mmc_info = &card->mmc;
+	cfg_emmc_mode_t *cfg_emmc_mode = &(host->cfg->card_item.emmc_mode);
+	sd_command_t sd_cmd;
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* set card work clock to 25M */
+	if (mmc_info->ext_csd.card_type) {
+		emmc_set_freq(card, SD_CLK_25M, FALSE);
+		DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Set eMMC Card Host Clock to 25MHz.\n");
+	}
+
+	/* check emmc card HS200 mode */
+	if ((mmc_info->ext_csd.card_type & MMC_CARD_TYPE_H200) &&
+	    (cfg_emmc_mode->enable_force_hs != 1)
+	    ) {
+		result = emmc_switch_hs200(card, &sd_cmd);
+		if (result == FALSE) {
+			DbgErr("Switch hs200 mode failed!!\n");
+			goto exit;
+		}
+
+		if ((cfg_emmc_mode->enable_force_hs200) ||
+		    (mmc_info->cur_buswidth != EMMC_8Bit_BUSWIDTH) ||
+		    (host->bus_8bit_supp == FALSE)
+		    )
+			goto exit;
+
+		/* check emmc card HS400 mode */
+		if ((host->chip_type == CHIP_SEAEAGLE2
+		     || cfg_emmc_mode->enable_force_hs400
+		     || host->chip_type == CHIP_GG8
+		     || host->chip_type == CHIP_ALBATROSS)
+		    && (mmc_info->ext_csd.card_type & MMC_CARD_TYPE_H400)
+		    ) {
+			/* choose the eMMC hs400 mode */
+			result = emmc_switch_hs400(card, &sd_cmd);
+			if (result == FALSE)
+				DbgErr("Switch hs400 mode failed!!\n");
+			else
+				mmc_info->cur_hs_type = EMMC_MODE_HS400;
+		}
+
+		goto exit;
+	}
+
+	/* check emmc card HS mode */
+	if ((mmc_info->ext_csd.card_type) & MMC_CARD_TYPE_HS) {
+		result = emmc_switch_hs(card, &sd_cmd);
+		if (result == FALSE)
+			DbgErr("Switch hs mode failed!!\n");
+
+	} else {
+		/* set transfer clock */
+		result = emmc_set_trans_clk(card);
+		if (!result) {
+			DbgErr("Set Basic transfer clock failed.\n");
+			goto exit;
+		}
+	}
+
+	/* set MMC/eMMC card bus width & DDR mode */
+	if (emmc_switch_buswidth(card, &sd_cmd) == TRUE) {
+		/* DDR mode not support 1-bit */
+		emmc_ddr_mode_set(card);
+	}
+
+exit:
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: emmc_init
+ *
+ * Abstract:
+ *			 1. emmc card initialize main function.
+ *            2. Fill virtual card structure, like cid, csd, ext_csd etc.
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+bool emmc_init(sd_card_t *card, bool bemmc)
+{
+	bool result = FALSE;
+	sd_host_t *host = card->host;
+	card_info_t *card_info = &(card->info);
+	sd_command_t sd_cmd;
+	cfg_emmc_mode_t *cfg_emmc_mode = &(host->cfg->card_item.emmc_mode);
+	mmc_card_info_t *mmc_info = &(card->mmc);
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s bemmc = %d\n", __func__, bemmc);
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+	os_memset(mmc_info, 0, sizeof(mmc_card_info_t));
+
+	/* 1. emmc host init */
+	result = host_emmc_init(host, cfg_emmc_mode);
+	if (result == FALSE) {
+		DbgErr("Emmc Host Init Failed.\n");
+		goto exit;
+	}
+
+	/* 2. Issue reset command (CMD0) */
+	result = card_reset_card(card, &sd_cmd);
+	result = card_reset_card(card, &sd_cmd);
+	if (!result) {
+		/* Go Idle State command failed. exit directly. */
+		DbgErr("Reset Card (CMD0) Failed.\n");
+		goto exit;
+	}
+
+	/* 2. Wait for card ready (CMD01) */
+	result = emmc_card_init_ready(card, &sd_cmd);
+	if (!result) {
+		DbgErr("Wait for card ready CMD1 Failed.\n");
+		goto exit;
+	}
+
+	if (bemmc)
+		card->card_type = CARD_EMMC;
+	else
+		card->card_type = CARD_MMC;
+
+	/* Get card CID(CMD2) */
+	result = card_all_send_cid(card, &sd_cmd);
+	if (!result) {
+		DbgErr("Get card CID(CMD2) failed.\n");
+		goto exit;
+	}
+
+	/* 4. Set card relative address (CMD3) */
+	result = emmc_set_rca(card, &sd_cmd);
+	if (!result) {
+		DbgErr
+		    ("MMC/eMMC card set card relative address (CMD3) failed.\n");
+		goto exit;
+	}
+
+	/* 5. Get CSD (CMD9) */
+	result = card_get_csd(card, &sd_cmd);
+	if (!result) {
+		DbgErr("Get CSD (CMD9) failed.\n");
+		goto exit;
+	}
+
+	/* 6. Select the card (CMD7) */
+	result = card_select_card(card, &sd_cmd);
+	if (!result) {
+		DbgErr("Select card (CMD7) failed.\n");
+		goto exit;
+	}
+
+	/* 7. Check card lock */
+	if (card->locked == TRUE) {
+		DbgErr("Card is locked!!\n");
+		goto exit;
+	}
+
+	/* 8. Check card SPEC version */
+	if (card_info->csd.mmc_spec_vers < MMC_SPEC_VERS) {
+		DbgWarn(MODULE_MMC_CARD, NOT_TO_RAM,
+			"Spec version < 4: it's old MMC Device!!\n");
+		/* set transfer clock */
+		result = emmc_set_trans_clk(card);
+		if (!result) {
+			DbgErr("Set Basic transfer clock failed.\n");
+			goto exit;
+		}
+		goto exit;
+	}
+
+	/* 9. Get Ext_Csd */
+	result = emmc_get_ext_csd(card, &sd_cmd);
+	if (!result) {
+		DbgErr("Get mmc Ext_Csd failed.\n");
+		goto exit;
+	}
+
+	/* 10. Switch Card mode */
+	result = card_init_stage2(card);
+
+exit:
+	if (result) {
+		/* max LBA */
+		card->sec_count = get_emmc_sec_count(card);
+		result =
+		    set_emmc_block_len(card,
+				       (mmc_info->cur_hs_type ==
+					EMMC_MODE_HS400) ? TRUE : FALSE);
+		if (!result)
+			DbgErr("Set block length failed.\n");
+	}
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ * Function Name: mmc_degrade_policy
+ * Abstract: This Function is used set sd degrade flag
+ *
+ * Input:
+ * sd_card_t *card : The Command will send to which  Card
+ *
+ * Return value:
+ *
+ */
+void mmc_degrade_policy(sd_card_t *card)
+{
+
+	/* check if at hs200 or hs400 then can degrade freq */
+	/* else set degrade_all flag */
+
+	cfg_emmc_mode_t *cfg_emmc_mode =
+	    &(card->host->cfg->card_item.emmc_mode);
+
+	if (cfg_emmc_mode->enable_force_hs400
+	    || cfg_emmc_mode->enable_force_hs200
+	    || (card->mmc.ext_csd.card_type & MMC_CARD_TYPE_H400)
+	    || (card->mmc.ext_csd.card_type & MMC_CARD_TYPE_H200)) {
+		if (card->degrade_freq_level < CARD_DEGRADE_FREQ_TIMES)
+			card->degrade_freq_level++;
+		else
+			card->degrade_final = 1;
+	} else
+		card->degrade_final = 1;
+
+	DbgErr("EMMC degrade final=%d freq_level=%d\n", card->degrade_final,
+	       card->degrade_freq_level);
+
+}
+
+static void emmc_set_freq(sd_card_t *card, u32 clock_freq, bool bddr50)
+{
+	sd_host_t *host = card->host;
+	u32 value = 0;
+	u16 index = card->degrade_freq_level;
+
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, clk_freq_khz=%dkhz, ddr50_mode=%d\n", __func__,
+		clock_freq, bddr50);
+	switch (clock_freq) {
+	case SD_CLK_ID_400K:
+		value = host->cfg->dmdn_tbl[FREQ_EMMC_400K_START_INDEX];
+		break;
+	case SD_CLK_50M:
+		if (bddr50)
+			value =
+			    host->cfg->dmdn_tbl[FREQ_EMMC_DDR50M_START_INDEX];
+		else
+			value = host->cfg->dmdn_tbl[FREQ_EMMC_50M_START_INDEX];
+		break;
+	case SD_CLK_200M:
+		value = host->cfg->dmdn_tbl[FREQ_EMMC_200M_START_INDEX + index];
+		break;
+	default:
+		value = host->cfg->dmdn_tbl[FREQ_EMMC_25M_START_INDEX];
+		break;
+	}
+	host_change_clock(host, value);
+	DbgInfo(MODULE_MMC_CARD, FEATURE_CARD_INIT, TO_RAM,
+		"Enter %s, clk_freq_khz=%dkhz, ddr50_mode=%d\n", __func__,
+		clock_freq, bddr50);
+}
diff --git a/drivers/scsi/bht/card/output_tuning.c b/drivers/scsi/bht/card/output_tuning.c
new file mode 100644
index 000000000000..de1ae5e4f388
--- /dev/null
+++ b/drivers/scsi/bht/card/output_tuning.c
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 BHT Inc.
+ *
+ * File Name: output_tuning.c
+ *
+ * Abstract:
+ *      1. Card tuning main entry
+ *      2. Interface for card tuning
+ *
+ * Version: 1.00
+ *
+ * Author: Chevron
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 3/8/2022		Creation	Chevron
+ */
+
+#include "../include/basic.h"
+#include "../include/card.h"
+#include "../include/cardapi.h"
+#include "cardcommon.h"
+#include "../include/hostapi.h"
+#include "../include/transhapi.h"
+#include "../include/hostvenapi.h"
+#include "../include/util.h"
+#include "../include/debug.h"
+#include "../include/cmdhandler.h"
+#include "../host/hostven.h"
+#include  "../include/card.h"
+#include "../host/hostreg.h"
+
+/* None Device error */
+#define		SD_SUCCESS				0x00000000
+/* Device error */
+#define		SD_ERR_DEVICE			0x00000001
+/*mmio value set timeout */
+#define		SD_ERR_MMIO_SET_TIMEOUT	0x00000002
+#define		SD_ERR_ALL_PHASE_PASS	0x00000003
+#define		SD_ERR_FATAL			0x00000004
+/* Device error need degrade */
+#define		SD_ERR_DEVICE_DEGRADE	0x00000005
+/* Device error need retry */
+#define		SD_ERR_DEVICE_RETRY		0x00000006
+/* Device error need increase drive strength */
+#define		SD_ERR_DEVICE_DS_INS	0x00000007
+/* Retry Over */
+#define    SD_ERR_RETRY_OVER        0x80000000
+/* CRC Error */
+#define    SD_ERR_CRC_MISSMACH      0x40000000
+/* No Response */
+#define    SD_ERR_NO_RESPONSE       0x20000000
+/* No Response */
+#define    SD_ERR_NO_RESPONSE       0x20000000
+
+u16 tuning_phase_result(sd_card_t *card)
+{
+	u16 result[4] = { 0 };
+	u8 phase_count = 11;
+	u16 phase_mask = 0x7FF;
+	/* u32 device_status; */
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	/* Only GG8 support 14 phase tuning */
+	if (card->host->chip_type == CHIP_GG8
+	    || card->host->chip_type == CHIP_ALBATROSS) {
+		phase_count = 14;
+		phase_mask = 0x3FFF;
+	}
+
+	/* get tuning result of 3 cycle */
+	result[0] =
+	    sdhci_readl(card->host, SDHCI_SAMPLE_CLK_RESULT_LOW) & phase_mask;
+	result[1] =
+	    (sdhci_readl(card->host, SDHCI_SAMPLE_CLK_RESULT_LOW) >>
+	     phase_count) & phase_mask;
+
+	/* Low bits result */
+	result[2] =
+	    ((sdhci_readl(card->host, SDHCI_SAMPLE_CLK_RESULT_LOW) >>
+	      (phase_count << 1) & phase_mask));
+
+	/* Result of full bits */
+	if (card->host->chip_type == CHIP_GG8
+	    || card->host->chip_type == CHIP_ALBATROSS)
+		result[2] |=
+		    (sdhci_readl(card->host, SDHCI_SAMPLE_CLK_RESULT_UP) &
+		     0x3FF) << 4;
+	else
+		result[2] |=
+		    (sdhci_readl(card->host, SDHCI_SAMPLE_CLK_RESULT_UP) &
+		     0x3FF) << 1;
+
+	result[3] = result[0] & result[1] & result[2];
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s, result 0x%x, phase count %d\n", __func__,
+		result[3], phase_count);
+	return result[3];
+}
+
+u8 select_tuning_phase(u16 tuning_phase, u8 phase_cnt)
+{
+	u8 temp[14] = { 0 };
+	u8 cnt[14] = { 0 };
+	u8 sel_phase, val, pos, start_phase;
+	u8 i, j;
+
+	i = j = val = pos = sel_phase = 0;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	for (i = 0; i < phase_cnt; i++)
+		temp[i] = (tuning_phase >> i) & 0x01;
+
+	for (i = 0; i < phase_cnt; i++) {
+		for (j = 0; j < phase_cnt; j++) {
+			if (temp[(i + j) % phase_cnt])
+				cnt[i]++;
+			else
+				break;
+		}
+	}
+
+	val = cnt[0];
+	for (i = 0; i < phase_cnt - 1; i++) {
+		if (cnt[i + 1] > val) {
+			val = cnt[i + 1];
+			pos = i + 1;
+		}
+	}
+
+	start_phase = (phase_cnt == 14 ? 9 : 8);
+	sel_phase = ((start_phase + pos + cnt[pos] / 2) % phase_cnt);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s select phase %d\n", __func__, sel_phase);
+	return sel_phase;
+}
+
+void set_input_tuning_phase(sd_card_t *card, u8 sel_phase)
+{
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	host_enable_clock(card->host, FALSE);
+
+	/* Clear origin phase */
+	sdhci_and32(card->host, SDHCI_DLL_PHASE_CFG, ~0x1F000000);
+	/* select the 1B0h[27:24] to config the phase selection */
+	sdhci_or32(card->host, SDHCI_DLL_PHASE_CFG, BIT28);
+	/* set new phase */
+	sdhci_or32(card->host, SDHCI_DLL_PHASE_CFG, sel_phase << 24);
+
+	host_enable_clock(card->host, TRUE);
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s select phase %d\n", __func__, sel_phase);
+}
+
+void generate_traverse_range(sd_card_t *card, u8 center_point, u8 offset,
+			     u8 *start_point, u8 *end_point)
+{
+	u16 phase_mask_all_pass = 0;
+	u8 phase_cnt = 11;
+
+	if (card->host->chip_type == CHIP_GG8
+	    || card->host->chip_type == CHIP_ALBATROSS)
+		phase_cnt = 14;
+
+	if (phase_cnt == 14)
+		phase_mask_all_pass = 0x3FFF;
+	else
+		phase_mask_all_pass = 0x7FF;
+
+	if (center_point < offset) {
+		*start_point = phase_cnt + center_point - offset;
+		*end_point = phase_cnt + center_point + offset;
+	} else {
+		*start_point = center_point - offset;
+		*end_point = center_point + offset;
+	}
+}
+
+u8 get_output_fix_phase(sd_card_t *card)
+{
+	cfg_output_tuning_item_t *output_tuning =
+	    &card->host->cfg->feature_item.output_tuning_item;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_DDR200) {
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"output_tuning_item DDR200\n");
+		return (u8) output_tuning->fixed_value_ddr200;
+	} else if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR104) {
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"output_tuning_item SDR104\n");
+		return (u8) output_tuning->fixed_value_sdr104;
+	} else if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR50) {
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"output_tuning_item SDR50\n");
+		return (u8) output_tuning->fixed_value_sdr50;
+	} else {
+		/* Not support this mode at Bayhub Driver */
+		DbgErr("sd_access_mode %d isn't supported !!!",
+		       card->info.sw_cur_setting.sd_access_mode);
+		return 0;
+	}
+
+}
+
+/* Use to find a output phase in which input tuning result is not all pass */
+u32 find_input_phase_fail_point(sd_card_t *card, u8 *output_phase,
+				u16 *input_tuning_result)
+{
+	u32 result = 0;
+	u8 start_phase, end_phase, index_phase;
+	u8 output_fix_phase = 0;
+	u8 i = 0;
+	u16 phase_mask_all_pass = 0;
+	int ret = 0;
+	sd_command_t sd_cmd;
+	u8 phase_cnt = 11;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	if (card->host->chip_type == CHIP_GG8
+	    || card->host->chip_type == CHIP_ALBATROSS)
+		phase_cnt = 14;
+
+	output_fix_phase = get_output_fix_phase(card);
+
+	if (phase_cnt == 14)
+		phase_mask_all_pass = 0x3FFF;
+	else
+		phase_mask_all_pass = 0x7FF;
+	generate_traverse_range(card, output_fix_phase, 3, &start_phase,
+				&end_phase);
+
+	for (i = start_phase; i <= end_phase; i++) {
+		index_phase = i % phase_cnt;
+
+		host_set_output_tuning_phase(card->host, index_phase);
+
+		ret = sd_tuning(card, &sd_cmd, 150);
+		if (!ret && sd_cmd.err.error_code) {
+			DbgErr("Uncorrect fix output phase!!!\n");
+			result = SD_ERR_FATAL;
+			break;
+		} else if (!ret) {
+			result = SD_ERR_DEVICE_DEGRADE;
+			break;
+		}
+
+		*input_tuning_result = tuning_phase_result(card);
+
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"output phase is %d, input result is 0x%x\n",
+			index_phase, *input_tuning_result);
+		if (*input_tuning_result == phase_mask_all_pass) {
+			result = SD_ERR_ALL_PHASE_PASS;
+			continue;
+		} else {
+			*output_phase = index_phase;
+			result = SD_SUCCESS;
+			break;
+		}
+	}
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return result;
+}
+
+u32 generate_output_input_phase_pair(sd_card_t *card, u8 input_fix_phase,
+				     u8 ddr200)
+{
+	u32 result = 0;
+	u8 output_phase = 0;
+	u8 input_phase = 0;
+	u16 input_tuning_result = 0;
+	u8 output_fix_phase = 0;
+	u8 start_phase, end_phase, index_phase, offset;
+	u8 i = 0;
+	u8 phase_cnt = 11;
+	u16 phase_mask_all_pass = 0x7FF;
+	sd_command_t sd_cmd;
+	int ret = 0;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	if (card->host->chip_type == CHIP_GG8
+	    || card->host->chip_type == CHIP_ALBATROSS) {
+		phase_cnt = 14;
+		phase_mask_all_pass = 0x3FFF;
+	}
+	if (ddr200) {
+		output_fix_phase =
+		(u8) card->host->cfg->feature_item.output_tuning_item.fixed_value_sdr104;
+		offset = 2;
+	} else {
+		output_fix_phase = get_output_fix_phase(card);
+		offset = 3;
+	}
+	generate_traverse_range(card, output_fix_phase, offset, &start_phase,
+				&end_phase);
+
+	for (i = start_phase; i <= end_phase; i++) {
+		index_phase = i % phase_cnt;
+
+		host_set_output_tuning_phase(card->host, index_phase);
+
+		ret = sd_tuning(card, &sd_cmd, 150);
+		if (!ret && sd_cmd.err.error_code) {
+			DbgErr("Uncorrect fix output phase!!!\n");
+			result = SD_ERR_FATAL;
+			break;
+		} else if (!ret) {
+			result = SD_ERR_DEVICE_DEGRADE;
+			break;
+		}
+
+		input_tuning_result = tuning_phase_result(card);
+
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"output phase is %d, input result is 0x%x\n",
+			index_phase, input_tuning_result);
+		if (ddr200) {
+			card->output_input_phase_pair[index_phase] =
+			    select_tuning_phase(input_tuning_result,
+						phase_cnt);
+			continue;
+		}
+
+		if (input_tuning_result == phase_mask_all_pass) {
+			result = SD_ERR_ALL_PHASE_PASS;
+			continue;
+		} else {
+			output_phase = index_phase;
+			result = SD_SUCCESS;
+			break;
+		}
+	}
+
+	/* result = find_input_phase_fail_point(card, &output_phase, &input_tuning_result); */
+	if (ret && ddr200) {
+		u8 temp_phase_pair[14] = { 0 };
+		u8 j;
+
+		/* add all input phase */
+		for (i = start_phase; i <= end_phase; i++) {
+
+			input_phase =
+			    card->output_input_phase_pair[i % phase_cnt];
+			/* caclute the <output,input> phase pair */
+			for (j = i; j < (i + phase_cnt); j++) {
+				index_phase = j % phase_cnt;
+				temp_phase_pair[index_phase] += input_phase;
+				DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+					NOT_TO_RAM,
+					"caclute ddr output-input pair:0x%x-0x%x\n",
+					index_phase, input_phase);
+				input_phase = (input_phase + 1) % phase_cnt;
+			}
+		}
+
+		/* caclute the avargae value for other <output,input> phase pair */
+		for (i = end_phase + 1; i < (start_phase + phase_cnt); i++) {
+			index_phase = i % phase_cnt;
+			card->output_input_phase_pair[index_phase] =
+			    temp_phase_pair[index_phase] / (1 + (offset << 1));
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM,
+				"###caclute ddr output-input pair:0x%x-0x%x\n",
+				index_phase,
+				card->output_input_phase_pair[index_phase]);
+		}
+
+	} else if ((result == SD_SUCCESS) || (result == SD_ERR_ALL_PHASE_PASS)) {
+		if (result == SD_SUCCESS) {
+			start_phase = output_phase;
+			end_phase = output_phase + phase_cnt;
+			input_phase =
+			    select_tuning_phase(input_tuning_result, phase_cnt);
+		} else {
+			start_phase = output_fix_phase;
+			end_phase = output_fix_phase + phase_cnt;
+			input_phase = input_fix_phase;
+			card->input_phase_all_pass = 1;
+			result = SD_SUCCESS;
+		}
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"output-input result:0x%x-0x%x\n", output_phase,
+			input_tuning_result);
+
+		for (i = start_phase; i < end_phase; i++) {
+			index_phase = i % phase_cnt;
+			card->output_input_phase_pair[index_phase] =
+			    input_phase;
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, "output-input pair:0x%x-0x%x\n",
+				index_phase, input_phase);
+			input_phase = (input_phase + 1) % phase_cnt;
+		}
+	}
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return result;
+}
+
+int output_tuning(sd_card_t *card, u32 address, bool ddr200)
+{
+	int ret = 0;
+	u8 test_patern[6] = { 0x55, 0xaa, 0x00, 0xff, 0xf0, 0x0f };
+	u8 input_tuning_pattern[64] = {
+		0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xcc,
+		0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+		0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0xff, 0xee,
+		0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+		0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff,
+		0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+		0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 0x77, 0x77,
+		0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff
+	};
+	int j, k, pattern_i;
+	u32 result = 0;
+	sd_command_t sd_cmd;
+	u32 cmdflag;
+
+	u8 *test_buf = kcalloc(512, sizeof(unsigned char), GFP_KERNEL);
+	u8 *test_buf_read = kcalloc(512, sizeof(unsigned char), GFP_KERNEL);
+
+	if (test_buf == NULL || test_buf_read == NULL) {
+		DbgErr("kcalloc buffer failed\n");
+		if (test_buf != NULL)
+			kfree(test_buf);
+		if (test_buf_read != NULL)
+			kfree(test_buf_read);
+		return SD_ERR_FATAL;
+	}
+
+	if (ddr200)
+		cmdflag =
+		    CMD_FLG_RESCHK | CMD_FLG_R1 | CMD_FLG_ADMA_SDMA |
+		    CMD_FLG_DDR200_WORK_AROUND | CMD_FLG_INF_BUILD;
+	else
+		cmdflag = CMD_FLG_RESCHK | CMD_FLG_R1 | CMD_FLG_ADMA_SDMA;
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* the output tuning pattern make up by four part */
+	for (pattern_i = 0; pattern_i < 4; pattern_i++) {
+		if (pattern_i < 3) {
+			for (k = 0; k < 512; k++) {
+				test_buf[k] =
+				    test_patern[(k % 2) + 2 * pattern_i];
+			}
+		} else {
+			for (j = 0; j < 8; j++) {
+				for (k = 0; k < 64; k++) {
+					if (j % 2) {
+						test_buf[k + 64 * j] =
+						    input_tuning_pattern[k];
+					} else {
+						test_buf[k + 64 * j] =
+						    input_tuning_pattern[(k +
+									  63) %
+									 64];
+					}
+				}
+			}
+		}
+
+		ret =
+		    card_send_sdcmd_timeout(card, &sd_cmd,
+					    ddr200 ? SD_CMD25 : SD_CMD24,
+					    address, cmdflag, DATA_DIR_OUT,
+					    test_buf, 512, 500);
+		if (ret == FALSE) {
+			if (card->input_phase_all_pass) {
+				if (sd_cmd.err.legacy_err_reg & 0x0E) {
+					DbgErr
+					    ("Uncorrect fix input phase!!!\n");
+					result = SD_ERR_FATAL;
+					goto end;
+				}
+			}
+
+			if ((sd_cmd.err.legacy_err_reg & 0x80F)
+			    && (card->info.sw_cur_setting.sd_access_mode ==
+				SD_FNC_AM_DDR200)) {
+				DbgErr("Uncorrect fix output phase!!!\n");
+				result = SD_ERR_FATAL;
+				goto end;
+			}
+
+			if (card->info.sw_cur_setting.sd_access_mode !=
+			    SD_FNC_AM_DDR200) {
+				DbgErr
+				    ("Recovery fail at tuning stage, need re-init!!!\n");
+				result = SD_ERR_DEVICE_RETRY;
+			} else {
+				host_cmddat_line_reset(card->host);
+				card_send_command12(card, &sd_cmd);
+				if (card_check_rw_ready(card, &sd_cmd, 600) !=
+				    TRUE) {
+					DbgErr
+					    ("Uncorrect fix output phase for DDR200!!!\n");
+					result = SD_ERR_FATAL;
+				} else
+					result = SD_ERR_CRC_MISSMACH;
+			}
+			goto end;
+		}
+
+		ret =
+		    card_send_sdcmd_timeout(card, &sd_cmd,
+					    ddr200 ? SD_CMD18 : SD_CMD17,
+					    address, (cmdflag), DATA_DIR_IN,
+					    test_buf_read, 512, 500);
+		if (ret == FALSE) {
+			if (card->input_phase_all_pass) {
+				if (sd_cmd.err.legacy_err_reg & 0x6E) {
+					DbgErr
+					    ("Uncorrect fix input phase!!!\n");
+					result = SD_ERR_FATAL;
+					goto end;
+				}
+			}
+
+			if ((sd_cmd.err.legacy_err_reg & 0x80F)
+			    && (card->info.sw_cur_setting.sd_access_mode ==
+				SD_FNC_AM_DDR200)) {
+				DbgErr("Uncorrect fix output phase!!!\n");
+				result = SD_ERR_FATAL;
+				goto end;
+			}
+
+			if (card->info.sw_cur_setting.sd_access_mode !=
+			    SD_FNC_AM_DDR200) {
+				DbgErr
+				    ("Recovery fail at tuning stage, need re-init!!!\n");
+				result = SD_ERR_DEVICE_RETRY;
+			} else {
+				host_cmddat_line_reset(card->host);
+				card_send_command12(card, &sd_cmd);
+				if (card_check_rw_ready(card, &sd_cmd, 600) !=
+				    TRUE) {
+					DbgErr
+					    ("Uncorrect fix output phase for DDR200!!!\n");
+					result = SD_ERR_FATAL;
+				} else
+					result = SD_ERR_CRC_MISSMACH;
+			}
+			goto end;
+		}
+
+		for (j = 0; j < (1 * 512); j++) {
+			if (*(test_buf + j) != *(test_buf_read + j)) {
+				result = SD_ERR_CRC_MISSMACH;
+				DbgErr("Compare failed!!!\n");
+				goto end;
+			}
+		}
+	}
+	result = SD_SUCCESS;
+end:
+
+	kfree(test_buf);
+	kfree(test_buf_read);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s(%d)\n", __func__, result);
+	return result;
+}
+
+u32 sdr104_sdr50_output_tuning(sd_card_t *card, u32 address)
+{
+	u8 start_phase, end_phase, index_phase;
+	u8 best_output_phase = 0, best_input_phase = 0;
+	u8 i = 0;
+	u8 output_fix_phase = 0;
+	u8 input_fix_phase = 0;
+	u8 output_fail_phase = 0x0;
+	u32 result = 0;
+	u8 phase_cnt = 11;
+	sd_command_t sd_cmd;
+
+	output_fix_phase = get_output_fix_phase(card);
+
+	if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR104)
+		input_fix_phase =
+		    (u8) card->host->cfg->feature_item.output_tuning_item.sdr104_input_fix_phase_value;
+	else
+		input_fix_phase =
+		    (u8) card->host->cfg->feature_item.output_tuning_item.sdr50_input_fix_phase_value;
+
+	if (card->host->chip_type == CHIP_GG8
+	    || card->host->chip_type == CHIP_ALBATROSS)
+		phase_cnt = 14;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s, retry_output_fail_phase is 0x%x\n", __func__,
+		card->retry_output_fail_phase);
+
+	if (card->retry_output_fail_phase != 0xFF) {
+		best_output_phase =
+		    (card->retry_output_fail_phase +
+		     (phase_cnt >> 1)) % (phase_cnt);
+		best_input_phase =
+		    card->output_input_phase_pair[best_output_phase];
+		goto phase_set;
+	}
+
+	result = generate_output_input_phase_pair(card, input_fix_phase, 0);
+	if (result == SD_ERR_DEVICE_DEGRADE || result == SD_ERR_FATAL)
+		goto exit;
+	else if (result == SD_SUCCESS) {
+		start_phase = output_fix_phase + 4;
+		end_phase = start_phase + phase_cnt;
+		for (i = start_phase; i < end_phase; i++) {
+			index_phase = i % phase_cnt;
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM,
+				"output phase is %d, input phase is %d\n",
+				index_phase,
+				card->output_input_phase_pair[index_phase]);
+
+			host_set_output_tuning_phase(card->host, index_phase);
+			set_input_tuning_phase(card,
+					       card->output_input_phase_pair
+					       [index_phase]);
+			result = output_tuning(card, address, 0);
+			if (result == SD_SUCCESS)
+				continue;
+			else if (result == SD_ERR_FATAL)
+				goto exit;
+			else {
+				card->retry_output_fail_phase = index_phase;
+				goto exit;
+			}
+		}
+
+		if (i == end_phase)
+			best_output_phase = output_fix_phase;
+		else
+			best_output_phase =
+			    (output_fail_phase + (phase_cnt >> 1)) % phase_cnt;
+
+		best_input_phase =
+		    card->output_input_phase_pair[best_output_phase];
+	}
+
+phase_set:
+	host_set_output_tuning_phase(card->host, best_output_phase);
+
+	if (sd_tuning(card, &sd_cmd, 150) == FALSE)
+		result = SD_ERR_FATAL;
+	else
+		result = SD_SUCCESS;
+
+exit:
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s result %d,best_output_phase 0x%x, best_input_phase  0x%x\n",
+		__func__, result, best_output_phase, best_input_phase);
+
+	return result;
+}
+
+u32 ddr200_output_tuning(sd_card_t *card, u32 address)
+{
+	u32 result = 0;
+	u8 start_phase, end_phase, index_phase;
+	u8 best_output_phase = 0;
+	u8 output_fix_phase = 0;
+	u8 i = 0;
+	u8 cnt = 0;
+	int pos = -1;
+	u8 phase_cnt = 11;
+	sd_host_t *host = card->host;
+	u16 output_tuning_result = 0;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	if (card->host->chip_type == CHIP_GG8
+	    || card->host->chip_type == CHIP_ALBATROSS)
+		phase_cnt = 14;
+
+	/* get output-input pair at DDR200 mode for DDR200_workaround */
+	result =
+	    generate_output_input_phase_pair(card,
+					     (u8) card->host->cfg->feature_item.output_tuning_item.sdr104_input_fix_phase_value,
+					     1);
+	if (result == SD_ERR_DEVICE_DEGRADE || result == SD_ERR_FATAL)
+		goto exit;
+
+	output_fix_phase = get_output_fix_phase(card);
+
+	generate_traverse_range(card, output_fix_phase, 4, &start_phase,
+				&end_phase);
+
+	for (i = start_phase; i <= end_phase; i++) {
+		index_phase = i % phase_cnt;
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"output phase is %d\n", index_phase);
+
+		/* Used to update input/output phase before write command */
+		host->cur_output_phase = index_phase;
+		result = output_tuning(card, address, 1);
+
+		if (result == SD_SUCCESS) {
+			output_tuning_result |= 1 << index_phase;
+			if (pos == -1)
+				pos = index_phase;
+			cnt++;
+		} else if (result == SD_ERR_FATAL)
+			goto exit;
+		else {
+			/* Find the bad phase after good phase */
+			if (pos != -1) {
+				DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+					NOT_TO_RAM,
+					"break output phase is %d\n",
+					index_phase);
+				break;
+			}
+		}
+	}
+
+	if (!cnt) {
+		DbgErr("All phase failed when output_tuning!!!\n");
+		result = SD_ERR_DEVICE_DEGRADE;
+	} else {
+		best_output_phase = (pos + (cnt >> 1)) % phase_cnt;
+		host->cur_output_phase = best_output_phase;
+		host_set_output_tuning_phase(card->host, best_output_phase);
+		set_input_tuning_phase(card,
+				       card->output_input_phase_pair
+				       [best_output_phase]);
+
+		result = SD_SUCCESS;
+	}
+
+exit:
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"best_output_phase 0x%x, output_tuning_result  0x%x\n",
+		best_output_phase, output_tuning_result);
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s, result %d\n", __func__, result);
+	return result;
+}
diff --git a/drivers/scsi/bht/card/sd.c b/drivers/scsi/bht/card/sd.c
new file mode 100644
index 000000000000..6a21d76945a7
--- /dev/null
+++ b/drivers/scsi/bht/card/sd.c
@@ -0,0 +1,3029 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: sd.c
+ *
+ * Abstract: SD Legacy card initialization
+ *
+ * Version: 1.00
+ *
+ * Author: Samuel
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 9/2/2014   Creation    Samuel
+ */
+#include "../include/basic.h"
+#include "../include/cardapi.h"
+#include "../include/hostapi.h"
+#include "cardcommon.h"
+#include "../include/debug.h"
+#include "../include/cmdhandler.h"
+#include "../include/host.h"
+#include "../include/util.h"
+#include "../include/hostvenapi.h"
+#include "../host/hostven.h"
+#include "card_ddr200_support.h"
+#include "../include/funcapi.h"
+/* 0: card not support ddr200 mode, 1: support  */
+u32 sd_card_ddr200_flag;
+extern bool card_output_tuning(sd_card_t *card, u64 tuning_address);
+extern bool store_tuning_address_content(sd_card_t *card, u64 tuning_address);
+extern bool restore_tuning_address_content(sd_card_t *card,
+					   u64 tuning_address);
+extern u32 generate_output_input_phase_pair(sd_card_t *card,
+					    u8 input_fix_phase, u8 ddr200);
+
+inline bool uhs1_support(sd_host_t *host)
+{
+	bool ret = TRUE;
+
+	/* 2. Configuration settings to disable UHSI function */
+	if (host->cfg->card_item.sd_card_mode_dis.dis_sd30_card)
+		ret = FALSE;
+
+	return ret;
+
+}
+
+static inline bool need_switch_sig_voltage(sd_card_t *card)
+{
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	if (card->card_type == CARD_UHS2)
+		goto exit;
+
+	/* 1. Check configuration settings
+	 * BH722SE2LN-A UHS1 issue#3  Sharkbay QS ULT #6 platform, BH driver 10024,
+	 * set card mode to be SDR25 or SDR12 by registry, but the card is SD2.0 mode.
+	 * Change to switch voltage when s18a is true.
+	 */
+
+	if (card_info->card_s18a)
+		ret = TRUE;
+
+exit:
+	return ret;
+}
+
+static inline bool card_support_cmd6(sd_card_t *card)
+{
+	bool ret = TRUE;
+	card_info_t *card_info = &(card->info);
+	/* 1. SD Memory Card - Spec. Version 1.0 and 1.01 do not support CMD6 */
+	if (card_info->scr.sd_spec < SCR_SPEC_VER_1)
+		ret = FALSE;
+
+	return ret;
+}
+
+#define  SDHCI_POWER_VDD1_330	0x0E00
+#define POWER_ON     TRUE
+#define POWER_OFF    FALSE
+
+bool sd_send_if_cond(sd_card_t *card, sd_command_t *sd_cmd, u32 argument)
+{
+	byte cmd_index = SD_CMD8;
+	/* u32 argument = 0x000001AA;   *  VHS set.  2.7-3.6V Check Pattern : 0xAA */
+	u32 cmdflag = CMD_FLG_R7 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	if (ret) {
+		/* Pattern Check */
+		if ((sd_cmd->response[0] & 0xFF) != 0xAA) {
+			sd_cmd->err.error_code = ERR_CODE_RESP_ERR;
+			ret = FALSE;
+			DbgErr("CMD8 response pattern check failed.");
+		}
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *	static bool sdio_check(sd_card_t *card, sd_command_t *sd_cmd)
+ *	{
+ *		byte cmd_index = SD_CMD5;
+ *		u32 argument = 0;
+ *		u32 cmdflag = CMD_FLG_R4 | CMD_FLG_RESCHK;
+ *		e_data_dir dir = DATA_DIR_NONE;
+ *		byte *data = NULL;
+ *		u32 datalen = 0;
+ *		bool ret = FALSE;
+ *
+ *		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+ *			__func__);
+ *
+ *		ret =
+ *			card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+ *			data, datalen);
+ *
+ *		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+ *			ret, __func__);
+ *		return ret;
+ *	}
+ */
+
+/*
+ *
+ * Function Name: card_init_ready
+ *
+ * Abstract:
+ *
+ *			 1. Issue ACMD41 to Get OCR
+ *            2. Set the card ocr variable
+ *            3. Wait for card ready.
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *           bool flag_f8: Command 8 is executed correctly.
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+bool card_init_ready(sd_card_t *card, sd_command_t *sd_cmd, bool flag_f8)
+{
+	byte cmd_index = SD_CMD41 | SD_APPCMD;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R3;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	bool ret = FALSE;
+	loop_wait_t wait;
+	u32 delay_us = 20;
+
+	sd_host_t *host = card->host;
+	card_info_t *card_info = &(card->info);
+
+	/* default is 0 */
+	card->uhs2_card = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, flag_f8=%d\n", __func__, flag_f8);
+
+	if (flag_f8)
+		os_udelay(20);
+
+	/* 3. Start the card initialization */
+	/* 3.1 Set argument according to the flag F8 (command 8 executed correctly) */
+	argument = (1 << fls32(host->ocr_avail));
+
+	if (card->card_type != CARD_UHS2) {
+		if (flag_f8) {
+			if (uhs1_support(host)) {
+				/*
+				 * BH722SE2LN-A UHS1 issue#3  Sharkbay QS ULT #6 platform,
+				 * BH driver 10024,
+				 * set card mode to be SDR25 or SDR12 by registry,
+				 * but the card is SD2.0 mode.
+				 * Change to send s18R for SDR12/SDR25/SDR50/SDR104.
+				 */
+
+				/* Try to set the HCS/XPC/S18R */
+				argument |= 0x51000000;
+			} else {
+				/* Try to set the HCS */
+				argument |= 0x40000000;
+
+				/* Set XPC */
+				argument |= BIT28;
+			}
+		}
+	} else {
+		/* UHS2 case */
+		/* Set HCS  bit only */
+		argument |= BIT30;
+
+		/* Set XPC */
+		argument |= BIT28;
+	}
+
+	/* 3.2 Wait for card ready */
+	util_init_waitloop(card->host->pdx,
+			   host->cfg->timeout_item.test_card_init_timeout.value,
+			   delay_us, &wait);
+
+	do {
+		ret =
+		    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag,
+				    dir, data, datalen);
+		if (!ret)
+			break;
+
+		if (flag_f8)
+			os_udelay(delay_us);
+
+		/* Check Busy status. 0b: On initialization; 1b: Initialization Complete. */
+		if ((sd_cmd->response[0] & 0x80000000) == 0) {
+			ret = FALSE;
+			continue;
+		} else {
+			/* card is ready */
+			ret = TRUE;
+			/* check uhs2 or not */
+			if ((sd_cmd->response[0] & (1 << 29)) != 0)
+				card->uhs2_card = TRUE;
+			break;
+		}
+	} while (!util_is_timeout(&wait));
+
+	/* 3.3 If card ready, set related software flags */
+	if (ret) {
+		/* 3.3.1. Set sd_virt_card OCR */
+		card_info->card_ccs = (sd_cmd->response[0] & BIT30) >> 30;
+		if (uhs1_support(host))
+			card_info->card_s18a =
+			    (sd_cmd->response[0] & BIT24) >> 24;
+		else
+			card_info->card_s18a = 0;
+
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: signal_voltage_switch
+ *
+ * Abstract:
+ *
+ *			 1.  Do Signal Voltage Switch Procedure (UHSI, CMD11)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+static bool signal_voltage_switch(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	byte cmd_index = SD_CMD11;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	bool ret = FALSE;
+	sd_host_t *host = card->host;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/*
+	 * 1. If S18A of ACMD41 is se to 0, do not need to switch signal voltage,
+	 * Exit from this procedure
+	 */
+	if (card_info->card_s18a == 0) {
+		ret = TRUE;
+		DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Do not need to switch signal voltage.\n");
+
+		goto EXIT;
+	}
+
+	/* 2. Issue CMD11 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (!ret) {
+		DbgErr("Issue CMD11 failed.\n");
+		goto EXIT;
+	}
+
+	ret = host_enable_sd_signal18v(host);
+
+	/* 3.3V->1.8V OK */
+	if (ret == FALSE)
+		goto ERROR;
+	goto EXIT;
+
+ERROR:
+
+	/* return to previous status */
+
+	host_1_8v_sig_set(host, FALSE);
+
+EXIT:
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+
+}
+
+/*
+ *
+ * Function Name: sd_get_sdstatus
+ *
+ * Abstract:
+ *
+ *			 1.  Read the SD Status Register (SSR) (ACMD13)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+static bool sd_get_sdstatus(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD13 | SD_APPCMD;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	u32 datalen = 64;
+
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue ACMD13 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    &(card_info->raw_ssr[0]), datalen);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_send_cmd35
+ *
+ * Abstract:
+ *
+ *			 1.  Read the SD Status Register (SSR) (CMD13)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+static bool sd_send_cmd35(sd_card_t *card)
+{
+
+	byte cmd_index = SD_CMD35;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_OUT;
+	sd_command_t sd_cmd;
+	byte buffer[512] = {
+		0x10, 0x03,
+		0x27, 0x86, 0x45, 0xA5, 0x19, 0x40, 0xF2, 0x25,
+		0x20, 0x47, 0xDF, 0x94, 0xB8, 0x16, 0x13, 0x00,
+		0x11, 0xF2, 0x1B, 0x4F, 0x23, 0x08, 0x2B, 0x33,
+		0x21, 0x8C, 0x16, 0x52, 0x6A, 0x1D, 0x89, 0xE3,
+		0x14, 0x09, 0x53, 0x84, 0x09, 0x47, 0x59, 0x50,
+		0x57, 0xBB, 0x71, 0x3C, 0x47, 0xA7, 0x2A, 0x46,
+		0xE2, 0xAF, 0x43, 0x10, 0x44, 0x05, 0x53, 0x7A,
+		0x79, 0xC3, 0x29, 0xF3, 0x83, 0x45, 0x22, 0x1B,
+	};
+	u32 datalen = 512;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue CMD35 */
+	ret =
+	    card_send_sdcmd(card, &sd_cmd, cmd_index, argument, cmdflag, dir,
+			    buffer, datalen);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_send_cmd34
+ *
+ * Abstract:
+ *
+ *			 1.  Read the SD Status Register (SSR) (CMD13)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+static bool sd_send_cmd34(sd_card_t *card)
+{
+
+	byte cmd_index = SD_CMD34;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	sd_command_t sd_cmd;
+	byte buffer[512] = { 0x00, 0x00, };
+	u32 datalen = 512;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue CMD34 */
+	ret =
+	    card_send_sdcmd(card, &sd_cmd, cmd_index, argument, cmdflag, dir,
+			    buffer, datalen);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_set_bus_width
+ *
+ * Abstract:
+ *
+ *			 1.  Set Bus Width to 4bit (ACMD6)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+static bool sd_set_bus_width(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD6 | SD_APPCMD;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	argument = BUS_WIDTH_4BIT;
+
+	/* Issue ACMD6 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_get_cid
+ *
+ * Abstract:
+ *
+ *			1.  Addressed card sends its card identification data (CID)
+ *			on the CMD line (CMD10)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *			sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *			Caller: card_init
+ */
+
+static bool sd_get_cid(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD10;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R2;
+	e_data_dir dir = DATA_DIR_NONE;
+	byte *data = NULL;
+	u32 datalen = 0;
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	argument = card_info->rca << 16;
+
+	/* Issue CMD10 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		/* Set the card CID info */
+		os_memcpy(&(card_info->raw_cid[0]), &(sd_cmd->response[0]), 16);
+		/* Parse the CID info */
+		card_info->cid.manfid = card_info->raw_cid[0];
+		card_info->cid.oemid =
+		    card_info->raw_cid[1] | (card_info->raw_cid[2] << 8);
+		os_memcpy(card_info->cid.prod_name, &(card_info->raw_cid[3]),
+			  5);
+		card_info->cid.prv = card_info->raw_cid[8];
+		card_info->cid.serial =
+		    card_info->raw_cid[9] | (card_info->raw_cid[10] << 8) |
+		    (card_info->raw_cid[11] << 16) | (card_info->raw_cid[12] << 24);
+	}
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_get_scr
+ *
+ * Abstract:
+ *
+ *			 1.  Read the SD Configuration Register (SCR) (ACMD51)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+static bool sd_get_scr(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD51 | SD_APPCMD;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	u32 datalen = 8;
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue ACMD51 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    &(card_info->raw_scr[0]), datalen);
+	if (ret) {
+		/* Parse the CSD info */
+		card_info->scr.sd_spec = card_info->raw_scr[0] & 0xF;
+		card_info->scr.cmd_support = card_info->raw_scr[3] & 0xF;
+		card_info->scr.sd_spec3 = card_info->raw_scr[2] & 0x80;
+		card_info->scr.sd_specx =
+		    (card_info->raw_scr[2] & 0x3) << 2 |
+			(card_info->raw_scr[3] & 0xc0) >> 6;
+		card_info->scr.reserved_B0 = card_info->raw_scr[7] & 0xFF;
+		card_info->scr.reserved_B1 = card_info->raw_scr[6] & 0xFF;
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_get_scr
+ *
+ * Abstract:
+ *
+ *			 1.  Read the SD Configuration Register (SCR) (ACMD51)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+/*
+ *	static bool sd_clear_card_detect(sd_card_t *card)
+ *	{
+ *
+ *		sd_command_t sd_cmd;
+ *		byte cmd_index = SD_CMD42 | SD_APPCMD;
+ *		u32 argument = 0;
+ *		u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+ *		e_data_dir dir = DATA_DIR_NONE;
+ *		bool ret = FALSE;
+ *
+ *		DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+ *			__func__);
+ *
+ *		ret =
+ *			card_send_sdcmd(card, &sd_cmd, cmd_index, argument, cmdflag, dir,
+ *			NULL, 0);
+ *		DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+ *			ret, __func__);
+ *		return ret;
+ *	}
+ */
+
+/*
+ *
+ * Function Name: sd_switch_function_set_am
+ *
+ * Abstract:
+ *
+ *			 1.  Set SD switch function status (Access Mode) (CMD6)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *           byte access_mode: access mode which want be set.
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_switch_function_set
+ */
+
+bool sd_switch_function_set_am(sd_card_t *card,
+			       sd_command_t *sd_cmd, byte access_mode)
+{
+
+	byte cmd_index = SD_CMD6;
+	u32 argument = SD_FNC_SW | SD_FNC_G1_INFL;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u32 datalen = 64;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, access_mode=0x%x\n", __func__, access_mode);
+
+	if (access_mode == SD_FNC_AM_DDR200)
+		argument = 0x80FFFFEF;
+	else
+		argument |= access_mode;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Set AM to %x, argument=%08X\n", access_mode, argument);
+
+	/* Issue CMD6 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_switch_function_set_ds
+ *
+ * Abstract:
+ *
+ *			 1.  Set SD switch function status (Driver Strength) (CMD6)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *           byte driver_strength: driver strength which want be set.
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_switch_function_set
+ */
+
+bool sd_switch_function_set_ds(sd_card_t *card,
+			       sd_command_t *sd_cmd, byte driver_strength)
+{
+
+	byte cmd_index = SD_CMD6;
+	u32 argument = SD_FNC_SW | SD_FNC_G3_INFL;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u32 datalen = 64;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, driver_strength=0x%x\n", __func__,
+		driver_strength);
+
+	argument |= driver_strength << 8;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Set Driver Strength to %x, argument=%08X\n", driver_strength,
+		argument);
+
+	/* Issue CMD6 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+static byte card_get_max_am_cap(sd_card_t *card)
+{
+	byte max_am_cap = 0;
+
+	if (sd_ddr_support(card))
+		max_am_cap = SD_FNC_AM_DDR200;
+	else if (card->info.sw_func_cap.sd_access_mode & (1 << SD_FNC_AM_SDR104))
+		max_am_cap = SD_FNC_AM_SDR104;
+	else if (card->info.sw_func_cap.sd_access_mode & (1 << SD_FNC_AM_SDR50))
+		max_am_cap = SD_FNC_AM_SDR50;
+	else if (card->info.sw_func_cap.sd_access_mode & (1 << SD_FNC_AM_DDR50))
+		max_am_cap = SD_FNC_AM_DDR50;
+	else if (card->info.sw_func_cap.sd_access_mode & (1 << SD_FNC_AM_HS))
+		max_am_cap = SD_FNC_AM_HS;
+	else if (card->info.sw_func_cap.sd_access_mode & (1 << SD_FNC_AM_DS))
+		max_am_cap = SD_FNC_AM_DS;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "(%x) %s\n",
+		max_am_cap, __func__);
+	return max_am_cap;
+}
+
+static byte card_get_min_am(byte am1, byte am2)
+{
+	byte am = 0;
+
+	switch (am1) {
+	case SD_FNC_AM_DDR200:
+		am = am2;
+		break;
+	case SD_FNC_AM_SDR104:
+		if (am2 == SD_FNC_AM_DDR200)
+			am = am1;
+		else
+			am = am2;
+		break;
+	case SD_FNC_AM_SDR50:
+		if (am2 == SD_FNC_AM_SDR104 || am2 == SD_FNC_AM_DDR200)
+			am = am1;
+		else
+			am = am2;
+		break;
+	case SD_FNC_AM_DDR50:
+		if (am2 == SD_FNC_AM_SDR50 || am2 == SD_FNC_AM_SDR104
+		    || am2 == SD_FNC_AM_DDR200) {
+			am = am1;
+		} else {
+			am = am2;
+		}
+		break;
+	case SD_FNC_AM_HS:
+		if (am2 == SD_FNC_AM_DS)
+			am = am2;
+		else
+			am = am1;
+		break;
+	case SD_FNC_AM_DS:
+		am = am1;
+		break;
+	default:
+		break;
+	}
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "(%x) %s\n", am,
+		__func__);
+	return am;
+}
+
+static byte card_power_limit_to_index(u8 pmlimit)
+{
+	byte i = 0;
+	byte power_limit[5] = {
+		SD_FNC_PL_072W,
+		SD_FNC_PL_144W,
+		SD_FNC_PL_180W,
+		SD_FNC_PL_216W,
+		SD_FNC_PL_288W
+	};
+
+	for (i = 0; i < 5; i++)
+		if (power_limit[i] == pmlimit)
+			return i;
+
+	return 0;
+}
+
+bool sd_switch_power_limit(sd_card_t *card, sd_command_t *sd_cmd, bool *bchg)
+{
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+	bool high_to_low = TRUE;
+	byte start;
+
+	byte power_limit[5] = {
+		SD_FNC_PL_072W,
+		SD_FNC_PL_144W,
+		SD_FNC_PL_180W,
+		SD_FNC_PL_216W,
+		SD_FNC_PL_288W
+	};
+	int i;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, *bchg= %d\n", __func__, *bchg);
+
+	/*
+	 * 3.1 Get Max Power Limit, default: 2.88W
+	 * 3.2 check the Max power limit that card support
+	 * Check order: 2.88W -> 2.16W -> 1.8W -> 1.44W -> 0,72W
+	 */
+
+	start =
+	    card_power_limit_to_index(card->sw_target_setting.sd_power_limit);
+	if (start > 4) {
+		DbgErr("Power Limit settings invalid!");
+		start = 4;
+	}
+
+	/* start  = i; */
+	if (card->thermal_enable)
+		if (card->thermal_heat == 0)
+			high_to_low = FALSE;
+
+	if (high_to_low) {
+		for (i = start; i >= 0; i--) {
+			if (card_info->sw_cur_setting.sd_power_limit ==
+			    power_limit[i] && *bchg == FALSE) {
+				ret = TRUE;
+				*bchg = FALSE;
+				break;
+			}
+			/* Check card support or not */
+			if (card_info->sw_func_cap.sd_power_limit &
+				(1 << (power_limit[i]))) {
+				ret =
+				    sd_switch_function_set_pl(card, sd_cmd,
+							      power_limit[i]);
+				if (!ret) {
+					DbgErr
+					    ("Set Power Limit to %X Failed.\n",
+					     power_limit[i]);
+					goto exit;
+				}
+				/* Update the current settings */
+				card_info->sw_cur_setting.sd_power_limit =
+				    power_limit[i];
+				DbgInfo(MODULE_ALL_CARD,
+					FEATURE_FUNC_THERMAL |
+					FEATURE_CARD_INIT, NOT_TO_RAM,
+					"Powerlimit1 index=%d\n", i);
+				*bchg = TRUE;
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i <= start; i++) {
+			if (card_info->sw_cur_setting.sd_power_limit ==
+			    power_limit[i] && *bchg == FALSE) {
+				ret = TRUE;
+				*bchg = FALSE;
+				break;
+			}
+			/* Check card support or not */
+			if (card_info->sw_func_cap.sd_power_limit &
+				(1 << (power_limit[i]))) {
+				ret =
+				    sd_switch_function_set_pl(card, sd_cmd,
+							      power_limit[i]);
+				if (!ret) {
+					DbgErr
+					    ("Set Power Limit to %X Failed.\n",
+					     power_limit[i]);
+					goto exit;
+				}
+				/* Update the current settings */
+				card_info->sw_cur_setting.sd_power_limit =
+				    power_limit[i];
+				DbgInfo(MODULE_ALL_CARD,
+					FEATURE_FUNC_THERMAL |
+					FEATURE_CARD_INIT, NOT_TO_RAM,
+					"Powerlimit2 index=%d\n", i);
+				*bchg = TRUE;
+				break;
+			}
+		}
+	}
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+bool sd_switch_access_mode(sd_card_t *card, sd_command_t *sd_cmd, bool *bchg)
+{
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+	byte i;
+	u32 clock_freq;
+	u32 regval;
+
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, *bchg= %d\n", __func__, *bchg);
+
+	/* 4.1 Get Max Access Mode of UHSI */
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"card->sw_target_setting.sd_access_mode %d\n",
+		card->sw_target_setting.sd_access_mode);
+	card->sw_target_setting.sd_access_mode =
+	    card_get_min_am(card->sw_target_setting.sd_access_mode,
+			    (byte) card_get_max_am_cap(card));
+	i = card->sw_target_setting.sd_access_mode;
+
+	while (i >= 0) {
+		/* Check card support or not */
+		if (i == SD_FNC_AM_DDR200) {
+			ret = sd_switch_function_set_am(card, sd_cmd, i);
+			if (!ret) {
+				DbgErr("Set Access Mode to %X Failed.\n", i);
+				i = SD_FNC_AM_SDR104;
+				continue;
+			}
+
+			/* Update the current settings */
+			card_info->sw_cur_setting.sd_access_mode = i;
+			DbgInfo(MODULE_ALL_CARD,
+				FEATURE_FUNC_THERMAL | FEATURE_CARD_INIT,
+				NOT_TO_RAM, "Access Mode=%d\n", i);
+			*bchg = TRUE;
+			break;
+		}
+
+		if (card_info->sw_func_cap.sd_access_mode & (1 << i)) {
+			if (card_info->sw_cur_setting.sd_access_mode == i
+			    && *bchg == FALSE) {
+				ret = TRUE;
+				*bchg = FALSE;
+				goto exit;
+			}
+			ret = sd_switch_function_set_am(card, sd_cmd, i);
+			if (!ret) {
+				DbgErr("Set Access Mode to %X Failed.\n", i);
+				goto exit;
+			}
+			/* Update the current settings */
+			card_info->sw_cur_setting.sd_access_mode = i;
+			DbgInfo(MODULE_ALL_CARD,
+				FEATURE_FUNC_THERMAL | FEATURE_CARD_INIT,
+				NOT_TO_RAM, "Access Mode=%d\n", i);
+			*bchg = TRUE;
+			break;
+		}
+
+		/* If DDR50 is the target access mode,
+		 * then the next access mode should be High Speed (1),
+		 * instead of SDR104 (3)
+		 */
+		if (i == SD_FNC_AM_DDR50) {
+			i = SD_FNC_AM_HS;
+			continue;
+		}
+
+		i--;
+	}
+
+	/* 5 Set timing accrodingly */
+	switch (card_info->sw_cur_setting.sd_access_mode) {
+	case SD_FNC_AM_DDR200:
+		{
+			if (card->ddr225_card_flag)
+				clock_freq = SD_CLK_225M;
+			else
+				clock_freq = SD_CLK_200M;
+
+			break;
+		}
+	case SD_FNC_AM_SDR104:
+		{
+			clock_freq = SD_CLK_200M;
+			break;
+		}
+	case SD_FNC_AM_SDR50:
+		{
+			clock_freq = SD_CLK_100M;
+			break;
+		}
+	case SD_FNC_AM_SDR25:
+		{
+			clock_freq = SD_CLK_50M;
+			break;
+		}
+	case SD_FNC_AM_SDR12:
+		{
+			clock_freq = SD_CLK_25M;
+			break;
+		}
+	case SD_FNC_AM_DDR50:
+		{
+			clock_freq = SD_CLK_50M;
+			break;
+		}
+	default:
+		{
+			clock_freq = SD_CLK_25M;
+			break;
+		}
+	}
+
+	if (card_info->sw_cur_setting.sd_access_mode == SD_FNC_AM_DDR50
+	    || card_info->sw_cur_setting.sd_access_mode == SD_FNC_AM_DDR200) {
+		card_legacy_change_clock(card, clock_freq, TRUE);
+	} else {
+		card_legacy_change_clock(card, clock_freq, FALSE);
+	}
+
+	/*
+	 * if the switch is successful,set host mode to DDR200
+	 * host 0x110[17]=1
+	 */
+	if (card_info->sw_cur_setting.sd_access_mode == SD_FNC_AM_DDR200) {
+		regval = sdhci_readl(host, 0x110);
+		regval |= (1 << 17);
+		sdhci_writel(host, 0x110, regval);
+	}
+
+	host_set_uhs_mode(host, card_info->sw_cur_setting.sd_access_mode);
+
+exit:
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+
+}
+
+/*
+ *
+ * Function Name: sd_switch_function_set
+ *
+ * Abstract:
+ *
+ *			 1.  Set SD switch function status
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+bool sd_switch_function_set(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	bool ret = FALSE;
+	sd_host_t *host = card->host;
+	card_info_t *card_info = &(card->info);
+	bool bchg = TRUE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* 1. Check the function card supported */
+
+	/*
+	 * 2. Set Driver Strength
+	 * As default, driver do not set driver strength
+	 * Only set it when configure driver_strength enabled
+	 */
+
+	if (host->cfg->card_item.test_driver_strength_sel.enable_set) {
+		byte driver_strength = card->sw_target_setting.sd_drv_type;
+		/* Do function switch when card support this function */
+		if ((1 << driver_strength) &
+		    (card_info->sw_func_cap.sd_drv_type)) {
+			ret =
+			    sd_switch_function_set_ds(card, sd_cmd,
+						      driver_strength);
+			if (!ret) {
+				DbgErr("Set driver strength to %X Failed.\n",
+				       driver_strength);
+				goto exit;
+			}
+			/* Update the current settings */
+			card_info->sw_cur_setting.sd_drv_type = driver_strength;
+		}
+	} else if ((card_info->cid.manfid == 0x1b) && sd_ddr_support(card)) {
+		/* Driver strength select 3h: Type D */
+		byte driver_strength = 0x3;
+
+		PrintMsg("Samsung DDR200 card need switch DS to type D\n");
+
+		ret = sd_switch_function_set_ds(card, sd_cmd, driver_strength);
+		if (!ret) {
+			DbgErr("Set driver strength to %X Failed.\n",
+			       driver_strength);
+			goto exit;
+		}
+		/* Update the current settings */
+		card_info->sw_cur_setting.sd_drv_type = driver_strength;
+	} else {
+		/* do nothing */
+	}
+
+	/* 3. Set Power Limit. */
+	/* Init case we always do pm setting */
+	bchg = TRUE;
+	ret = sd_switch_power_limit(card, sd_cmd, &bchg);
+	if (!ret) {
+		DbgErr("Set Power Limit Failed.\n");
+		goto exit;
+	}
+
+	/* 4. Set Access mode */
+	/* Init case we always do am setting */
+	bchg = TRUE;
+	ret = sd_switch_access_mode(card, sd_cmd, &bchg);
+	if (!ret) {
+		DbgErr("Set Access Mode Failed.\n");
+		goto exit;
+	}
+exit:
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_tuning_hw
+ *
+ * Abstract:
+ *
+ *			 1.  Hardware Tuning Procedure (CMD19)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_tuning
+ */
+
+bool sd_tuning_hw(sd_card_t *card, sd_command_t *sd_cmd, u32 timeout)
+{
+
+	byte cmd_index = SD_CMD19;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_TUNE;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u32 datalen = 64;
+
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* 1. Set driver HW mode here */
+	host_set_tuning_mode(card->host, TRUE);
+	/* add 200us delay before CMD19 to fix FJ2 ASIC issue 14 */
+	if (card->host->chip_type == CHIP_FUJIN2)
+		os_udelay(200);
+
+	/* 2. Tuning now */
+	ret =
+	    card_send_sdcmd_timeout(card, sd_cmd, cmd_index, argument, cmdflag,
+				    dir, data, datalen, timeout);
+	if (!ret)
+		DbgErr(" - SendCommand19 failed during tuning!\n");
+	else
+		ret = host_chk_tuning_comp(card->host, TRUE);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_tuning_sw
+ *
+ * Abstract:
+ *
+ *			 1.  Software Tuning Procedure (CMD19)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_tuning
+ */
+
+bool sd_tuning_sw(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	byte cmd_index = SD_CMD19;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_TUNE;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u32 datalen = 64;
+	u16 i;
+
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Try 100 SW tuning */
+	for (i = 0; i < 100; i++) {
+		/* 1. Set driver SW mode here */
+		host_set_tuning_mode(card->host, FALSE);
+		/* add 200us delay before CMD19 to fix FJ2 ASIC issue 14 */
+		if (card->host->chip_type == CHIP_FUJIN2)
+			os_udelay(200);
+
+		/* 2. Tuning now */
+		ret =
+		    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag,
+				    dir, data, datalen);
+		if (!ret) {
+			DbgErr("SendCommand19 failed during tuning!\n");
+			break;
+		}
+
+		ret = host_chk_tuning_comp(card->host, TRUE);
+		if (ret)
+			break;
+
+	}
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_tuning
+ *
+ * Abstract:
+ *
+ *			 1.  Tuning Procedure (CMD19)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+bool sd_tuning(sd_card_t *card, sd_command_t *sd_cmd, u32 timeout)
+{
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card_info->sw_cur_setting.sd_access_mode < SD_FNC_AM_SDR50) {
+		/* Only do tuning procedure for DDR50, SDR104, SDR50,DDR200 */
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"No need to do tuning for access mode %d\n",
+			card_info->sw_cur_setting.sd_access_mode);
+		ret = TRUE;
+	} else {
+		if (TUNING_MODE) {
+			/* HW tuning */
+			ret = sd_tuning_hw(card, sd_cmd, timeout);
+		} else {
+			ret = sd_tuning_sw(card, sd_cmd);
+		}
+
+	}
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_switch_function_check
+ *
+ * Abstract:
+ *
+ *			 1.  Get SD switch function status (CMD6)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+bool sd_switch_function_check(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD6;
+	u32 argument = SD_FNC_NOINFL;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u32 datalen = 64;
+	bool ret = FALSE;
+	card_info_t *card_info = &(card->info);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Issue CMD6 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret) {
+		/* Set the card swich function status info */
+		card_info->sw_func_cap.sd_access_mode = data[13];
+		card_info->sw_func_cap.sd_command_system = data[10];
+		card_info->sw_func_cap.sd_drv_type = data[9];
+		card_info->sw_func_cap.sd_power_limit = data[7];
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Card Sup AM:%X\n",
+			card_info->sw_func_cap.sd_access_mode);
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Card Sup CS:%X\n",
+			card_info->sw_func_cap.sd_command_system);
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Card Sup DS:%X\n", card_info->sw_func_cap.sd_drv_type);
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Card Sup PL:%X\n",
+			card_info->sw_func_cap.sd_power_limit);
+	}
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_switch_function_set_pl
+ *
+ * Abstract:
+ *
+ *			 1.  Set SD switch function status (Power Limit) (CMD6)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *           byte driver_strength: driver strength which want be set.
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_switch_function_set
+ */
+
+bool sd_switch_function_set_pl(sd_card_t *card,
+			       sd_command_t *sd_cmd, byte power_limit)
+{
+
+	byte cmd_index = SD_CMD6;
+	u32 argument = SD_FNC_SW | SD_FNC_G4_INFL;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u32 datalen = 64;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Enter %s, power_limit=%d\n", __func__, power_limit);
+
+	argument |= (power_limit) << 12;
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Set Power Limit to %x, argument=%08X\n", power_limit,
+		argument);
+
+	/* Issue CMD6 */
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_switch_function_set_pl
+ *
+ * Abstract:
+ *
+ *			 1.  Set SD switch function status (Power Limit) (CMD6)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *           sd_command_t *sd_cmd: Pointer to sd command structure
+ *           byte driver_strength: driver strength which want be set.
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_switch_function_set
+ */
+
+bool sd_lightning_mode_sw(sd_card_t *card, sd_command_t *sd_cmd)
+{
+
+	byte cmd_index = SD_CMD6;
+	u32 argument = SD_FNC_SW | SD_FNC_G4_INFL;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_IN;
+	byte data[64];
+	u32 datalen = 64;
+	u32 card_status = 0;
+	bool ret = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* 1. Check if lightning mode is enabled or not */
+	/* Host was set to do not support lightning mode */
+	goto EXIT;
+
+	if (card->info.cid.manfid != MID_SANDISK) {
+		/* Card is not SanDisk Card */
+		goto EXIT;
+	}
+
+	/* 2. Set card to vendor specific mode */
+	{
+		cmd_index = SD_CMD6;
+		argument = SD_FNC_SW | SD_FNC_G2_VEN;
+		cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+		dir = DATA_DIR_IN;
+		datalen = 64;
+		/* Issue CMD6 */
+		ret =
+		    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag,
+				    dir, data, datalen);
+		if (ret == FALSE) {
+			DbgErr(("Set Vendor Specific mode failed!\n"));
+
+			goto EXIT;
+		}
+	}
+
+	/* 3. Send CMD13 */
+	ret = card_get_card_status(card, sd_cmd, &card_status);
+	if (ret == FALSE) {
+		DbgErr(("Send Status error(CMD13)\n"));
+
+		goto EXIT;
+	}
+
+	/* 4. Send CMD35 */
+	ret = sd_send_cmd35(card);
+	if (ret == FALSE) {
+		DbgErr(("Send Status error(CMD13)\n"));
+
+		goto EXIT;
+	}
+
+	/* Send CMD34 */
+	ret = sd_send_cmd34(card);
+	if (ret == FALSE) {
+		DbgErr(("Send Status error(CMD13)\n"));
+
+		goto EXIT;
+	}
+
+	/* Delay */
+	os_mdelay(1);
+
+EXIT:
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		ret, __func__);
+	return ret;
+}
+
+/*
+ *
+ * Function Name: sd_card_identify
+ *
+ * Abstract:
+ *
+ *			 1. Issue reset command (CMD0)
+ *            2. Issue send IF condition command (CMD8)
+ *            3. SDIO swithch function supportted?
+ *            4. Wait for card ready (ACMD41)
+ *            5. Signal voltage switch prucedure (CMD11)
+ *            6. Get card CID(CMD2)
+ *            7. Get card relative address (CMD3)
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_legacy_init, ush2_card_init
+ */
+
+bool sd_card_identify(sd_card_t *card)
+{
+	bool result = FALSE;
+	bool flag_f8 = FALSE;
+	sd_command_t sd_cmd;
+	u32 argument = 0x000001AA;
+
+	card->uhs2_card = FALSE;
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+
+	if (card->card_type != CARD_UHS2)
+		os_udelay(200);
+
+	/* 1. Issue reset command (CMD0) */
+
+	result = card_reset_card(card, &sd_cmd);
+	if (!result) {
+		/* Go Idle State command failed. exit directly. */
+		DbgErr("Reset Card (CMD0) Failed.\n");
+		goto exit;
+	}
+
+	/* 2. Issue send IF condition command (CMD8) */
+	result = sd_send_if_cond(card, &sd_cmd, argument);
+	if (!result) {
+
+		/* 2.1 Error response */
+		if (sd_cmd.err.error_code == ERR_CODE_RESP_ERR ||
+		    sd_cmd.err.error_code == ERR_CODE_NO_CARD) {
+			DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"CMD8 Response Error or no card.\n");
+			goto exit;
+		}
+
+		/* 2.2 No Response  (Standard Capacity Card) */
+		{
+			DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"CMD8 No Responser.\n");
+
+			/* 2.2.1 Set flag F8 = 0 */
+			flag_f8 = FALSE;
+#if (0)
+			card->card_cap_type = CARD_SDSC_V1;
+#endif
+			/* 2.2.2 Reset card (CMD0) again. */
+			result = card_reset_card(card, &sd_cmd);
+			if (!result) {
+				/* Go Idle State command failed. exit directly. */
+				DbgErr("Reset Card Again (CMD0) Failed.\n");
+				goto exit;
+			}
+		}
+	} else {
+		/* 2.3 Good Response  (High Capacity card) */
+		/* 2.3.1 Set flag F8 = 1 */
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"CMD8 Good Responser (High Capacity Card).\n");
+
+		flag_f8 = TRUE;
+	}
+
+	/* 3. SDIO swithch function supportted? */
+#if (0)
+	/* RTU_OK */
+	if ((card->card_type != CARD_SD) && (card->card_type != CARD_UHS2)) {
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"SDIO swithch function supportted.\n");
+
+		/* 3.1 issue CMD5 to check card is SDIO card or not */
+		result = sdio_check(card, &sd_cmd);
+		if (result == TRUE) {
+			/* 3.1.1 set card type to SDIO_CARD */
+			card->card_type = CARD_SDIO;
+			DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"SDIO card.\n");
+			/* 3.1.3 Return failed */
+			result = FALSE;
+			goto exit;
+		}
+	}
+#endif
+
+	/* 4. Wait for card ready (ACMD41) */
+	result = card_init_ready(card, &sd_cmd, flag_f8);
+	if (!result) {
+		/*
+		 * 4.1 Return failed for following cases:
+		 * - OCR check fail,
+		 * - or command timeout,
+		 * - or command55 fail,
+		 * - or ACMD41 response error
+		 */
+		DbgErr("Wait for card ready (ACMD41) Failed.\n");
+		goto exit;
+	}
+
+	/* Try to init as SD Legacy card */
+	if (card->card_type != CARD_UHS2)
+		card->card_type = CARD_SD;
+
+	/* 5. Signal voltage switch prucedure (CMD11) */
+	if (need_switch_sig_voltage(card)) {
+		DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Need to do signal voltage switch.\n");
+
+		result = signal_voltage_switch(card, &sd_cmd);
+		if (!result) {
+			/*
+			 * 5.1 If signal voltage switch failed,
+			 * need return failed for power cycle.
+			 */
+			DbgErr("Signal voltage switch failed.\n");
+			goto exit;
+		}
+	}
+
+	/* 6. Get card CID(CMD2) */
+	result = card_all_send_cid(card, &sd_cmd);
+	if (!result) {
+		/* 6.1 If failed, need return failed for power cycle. */
+		DbgErr("Get card CID(CMD2) failed.\n");
+		goto exit;
+	}
+
+	/* 7. Get card relative address (CMD3) */
+	result = card_get_rca(card, &sd_cmd);
+	if (!result) {
+		/* 7.1 If failed, need return failed for power cycle. */
+		DbgErr("Get card relative address (CMD3) failed.\n");
+		goto exit;
+	}
+
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: sd_card_select
+ *
+ * Abstract:
+ *
+ *           1. Get CID (CMD10)
+ *           2. Get CSD (CMD9)
+ *           3. Select the card (CMD7)
+ *           4. Get Lock/Unlock status, CMD7 Response [25].
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: sd_legacy_init, ush2_card_init
+ */
+
+bool sd_card_select(sd_card_t *card)
+{
+	bool result = FALSE;
+	sd_command_t sd_cmd;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+
+	if (card_need_get_info(card)) {
+		/* 1.1 Get CID (CMD10) */
+		result = sd_get_cid(card, &sd_cmd);
+		if (!result) {
+			DbgErr("Get CID (CMD10) failed.\n");
+			goto exit;
+		}
+
+		/* 1.2 Get CSD (CMD9) */
+		result = card_get_csd(card, &sd_cmd);
+		if (!result) {
+			DbgErr("Get CSD (CMD9) failed.\n");
+			goto exit;
+		}
+	} else {
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Already get card info, skip getting CID,CSD.\n");
+	}
+
+	/* 2. Select the card (CMD7) */
+	result = card_select_card(card, &sd_cmd);
+	if (!result) {
+		/* 2.1 If failed, need return failed for power cycle. */
+		DbgErr("Select card (CMD7) failed.\n");
+		goto exit;
+	}
+
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+
+}
+
+bool sd_init_get_info(sd_card_t *card)
+{
+	bool result = TRUE;
+	sd_command_t sd_cmd;
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+
+	/* 11. Set bus width */
+	/* uhs2 card don't need this flow */
+	if (card->card_type == CARD_SD) {
+		/* 11.1 Set card bus width (ACMD6) */
+		result = sd_set_bus_width(card, &sd_cmd);
+		if (!result) {
+			/* 11.1 If failed, need return failed for power cycle. */
+			DbgErr("Set card bus width (ACMD6) failed.\n");
+			goto exit;
+		}
+
+		/* 11.2 Set Host bus width */
+		host_set_buswidth(host, BUS_WIDTH4);
+
+		/* 12. Set block length (CMD16) */
+		result = card_set_block_len(card, &sd_cmd, SD_BLOCK_LEN);
+		if (!result) {
+			/* 12.1 If failed, need return failed for power cycle. */
+			DbgErr("Set block length (CMD16) failed.\n");
+			goto exit;
+		}
+	}
+
+	/* 13. Get card related info, like CID,CSD, SCR, SD_Status */
+	if (card_need_get_info(card)) {
+		/* 13.3 Get SCR (ACMD51) */
+		result = sd_get_scr(card, &sd_cmd);
+		if (!result) {
+			DbgErr("Get SCR (ACMD51) failed.\n");
+			goto exit;
+		}
+		/* 13.4 Get SD Status (ACMD13) */
+		result = sd_get_sdstatus(card, &sd_cmd);
+		if (!result) {
+			DbgErr("Get SD Status (ACMD13) failed.\n");
+			goto exit;
+		}
+	} else {
+		DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Already get card info, skip getting SCR, SD_Status.\n");
+	}
+
+exit:
+	DbgInfo(MODULE_ALL_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+bool sd_init_stage2(sd_card_t *card)
+{
+	bool result = FALSE;
+	sd_host_t *host = card->host;
+	cfg_item_t *cfg_item = card->host->cfg;
+	card_info_t *card_info = &(card->info);
+	sd_command_t sd_cmd;
+	u8 tuning_type = 0;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+
+	if (host->chip_type != CHIP_GG8) {
+		/* 1. Set SD Host Clock to 25MHz */
+		card_legacy_change_clock(card, SD_CLK_25M, FALSE);
+		DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Set SD Host Clock to 25MHz.\n");
+	} else
+		os_mdelay(15);
+
+	result = sd_init_get_info(card);
+	if (!result) {
+		DbgErr("SD Card get info failed\n");
+		goto exit;
+	}
+#if (0)
+	/* Turns Off the Pull-up resistor of the SD Card */
+	result = sd_clear_card_detect(card);
+	if (!result) {
+		DbgErr
+		    ("Turns Off the Pull-up resistor of the SD Card failed\n");
+		goto exit;
+	}
+#endif
+
+	if (card->restore_tuning_content_fail) {
+		result =
+		    restore_tuning_address_content(card,
+						   card->sec_count -
+						   TUNING_ADDRESS_OFFSET);
+		if (!result) {
+			DbgErr("restore_tuning_address_content failed\n");
+			card->restore_tuning_content_fail = 1;
+			goto exit;
+		}
+	}
+
+	/* 2. Need to clear High Speed Enable */
+	host_set_highspeed(host, FALSE);
+
+	/* 3. Swich function check/set */
+	if (card_info->scr.sd_spec < SCR_SPEC_VER_1) {
+		result = TRUE;
+		card->sw_target_setting.sd_access_mode = SD_FNC_AM_DS;
+		if (host->chip_type == CHIP_GG8) {
+			/* 1. Set SD Host Clock to 25MHz */
+			card_legacy_change_clock(card, SD_CLK_25M, FALSE);
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"Set SD Host Clock to 25MHz.\n");
+		}
+		goto exit;
+	} else if (!(card_info->card_s18a)) {
+		card->sw_target_setting.sd_access_mode =
+		    os_min(card->sw_target_setting.sd_access_mode,
+			   SD_FNC_AM_HS);
+		if (card_need_get_info(card)) {
+			/* 3.1. Check if card support Hight Speed. */
+			result = sd_switch_function_check(card, &sd_cmd);
+			if (!result) {
+				DbgErr("Swich function check (CMD6) failed.\n");
+				goto exit;
+			}
+		} else {
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"Card function check skipped.\n");
+		}
+
+		DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Card support High Speed.\n");
+
+		if ((card->info.sw_func_cap.sd_access_mode & (1 << SD_FNC_AM_HS))
+		    && (card->sw_target_setting.sd_access_mode >= SD_FNC_AM_HS)) {
+			result =
+			    sd_switch_function_set_am(card, &sd_cmd,
+						      SD_FNC_AM_HS);
+			if (!result) {
+				DbgErr
+				    ("Set Access Mode to High Speed Failed.\n");
+				goto exit;
+			}
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"Switch to High Speed OK.\n");
+			if (host->chip_type == CHIP_GG8) {
+				/* 1. Set SD Host Clock to 25MHz */
+				card_legacy_change_clock(card, SD_CLK_25M,
+							 FALSE);
+				DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT,
+					NOT_TO_RAM,
+					"Set SD Host Clock to 25MHz.\n");
+			}
+
+			/* 3.2. Update the current settings */
+			card_info->sw_cur_setting.sd_access_mode = SD_FNC_AM_HS;
+			/* 3.3. Need to set High Speed Enable */
+			host_set_highspeed(host, TRUE);
+
+			/* 4. Check Lighting card support */
+			result = sd_lightning_mode_sw(card, &sd_cmd);
+			if (result == TRUE) {
+				DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT,
+					NOT_TO_RAM,
+					"Card support Lighting mode, change clock to 75MHz.\n");
+				/* 4.1. Change the clock to 75MHz */
+				card_legacy_change_clock(card, SD_CLK_75M,
+							 FALSE);
+			} else {
+				DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT,
+					NOT_TO_RAM, "Change clock to 50MHz.\n");
+				/* 4.2. Change the clock to 50MHz */
+				card_legacy_change_clock(card, SD_CLK_50M,
+							 FALSE);
+			}
+			result = TRUE;
+		} else {
+			/*
+			 * Degrade access mode to Default Speed case.
+			 * Need to switch access mode to Default Speed
+			 * as card default AM is High Speed.
+			 */
+			result =
+			    sd_switch_function_set_am(card, &sd_cmd,
+						      SD_FNC_AM_DS);
+			if (!result) {
+				DbgErr
+				    ("Set Access Mode to Default Speed Failed.\n");
+				goto exit;
+			}
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"Switch to Default Speed OK.\n");
+
+		}
+
+	} else {
+
+		if (card_need_get_info(card)) {
+
+			/* 5.1 Swich function check first to get card function capabilities */
+			result = sd_switch_function_check(card, &sd_cmd);
+			if (!result) {
+				DbgErr("Swich function check (CMD6) failed.\n");
+				goto exit;
+			}
+		} else {
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"Card function check skipped.\n");
+		}
+
+		if ((card_get_max_am_cap(card) >= SD_FNC_AM_SDR50)
+		    && (cfg_item->card_item.test_max_access_mode.value >= 0x2))
+			result =
+			    store_tuning_address_content(card,
+							 card->sec_count -
+							 TUNING_ADDRESS_OFFSET);
+		else
+			/* SD2.0 card shall not store tuning  */
+			result = FALSE;
+
+		if (!result) {
+			DbgErr("store_tuning_address_contento failed\n");
+			/* goto exit; */
+		}
+
+		/*
+		 * 5.2 Swich function check set.
+		 * - Driver Strength,
+		 * - Access Mode,
+		 * - Power Limit
+		 * - Change clock freq
+		 */
+
+		result = sd_switch_function_set(card, &sd_cmd);
+		if (!result) {
+			DbgErr("Swich function set (CMD6) failed.\n");
+			goto exit;
+		}
+
+		tuning_type =
+		    hostven_tuning_type_selection(host,
+						  card_info->sw_cur_setting.sd_access_mode);
+
+		/* 5.3 Tuning Procedure (for DDR200, SDR104 and SDR50 Only) */
+		if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR104
+		    || card->info.sw_cur_setting.sd_access_mode ==
+		    SD_FNC_AM_SDR50
+		    || card->info.sw_cur_setting.sd_access_mode ==
+		    SD_FNC_AM_DDR200) {
+			switch (tuning_type) {
+			case 0:
+				hostven_fix_output_tuning(host,
+							  card_info->sw_cur_setting.sd_access_mode);
+				break;
+			case 1:
+				hostven_fix_output_tuning(host,
+							  card_info->sw_cur_setting.sd_access_mode);
+				result = sd_tuning(card, &sd_cmd, 0);
+				if (!result) {
+					DbgErr("Tuning (CMD19) failed.\n");
+					goto exit;
+				}
+				break;
+			case 2:
+				result =
+				    card_output_tuning(card,
+						       card->sec_count -
+						       TUNING_ADDRESS_OFFSET);
+				if (!result) {
+					DbgErr("card_output_tuning failed.\n");
+					card->restore_tuning_content_fail = 1;
+					goto exit;
+				}
+
+				if (card->read_signal_block_flag) {
+					result =
+					    restore_tuning_address_content(card,
+									   card->sec_count
+									   -
+									   TUNING_ADDRESS_OFFSET);
+					if (!result) {
+						DbgErr
+						    ("restore_tuning_address_content failed\n");
+						card->restore_tuning_content_fail
+						    = 1;
+						goto exit;
+					}
+				} else {
+					erase_rw_blk_start_set(card, &sd_cmd,
+							       (u32)
+							       (card->sec_count)
+							       -
+							       TUNING_ADDRESS_OFFSET);
+					erase_rw_blk_end_set(card, &sd_cmd,
+							     ((u32)
+							      (card->sec_count)
+							      -
+							      TUNING_ADDRESS_OFFSET)
+							     + 1);
+					func_erase(card, &sd_cmd);
+				}
+
+				break;
+			default:
+				break;
+			}
+
+			DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+				"Tuning Procedure Done. Access Mode=%d.\n",
+				card_info->sw_cur_setting.sd_access_mode);
+		}
+
+	}
+exit:
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(%d) %s\n",
+		result, __func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: sd_legacy_init
+ *
+ * Abstract:
+ *
+ *			 1. sd legacy card (uhs1, legacy) initialize main function.
+ *            2. Fill virtual card structure, like cid, csd, etc.
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *           Caller: card_init
+ */
+
+bool sd_legacy_init(sd_card_t *card)
+{
+	bool result = FALSE;
+	sd_host_t *host = card->host;
+
+	card->uhs2_card = FALSE;
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (shift_bit_func_enable(host))
+		set_pattern_value(host, 0x10);
+
+	host_sd_init(host);
+
+	/* SD Card Identification */
+	result = sd_card_identify(card);
+	if (!result) {
+		DbgErr("SD Card Identification Stage failed.\n");
+		goto error_exit;
+	}
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Card Identification Stage OK.\n");
+
+	/* SD Card Select and lock/unlock check */
+	result = sd_card_select(card);
+	if (!result) {
+		DbgErr("SD Card Select failed.\n");
+		goto error_exit;
+	}
+
+	if (card->locked == TRUE) {
+		DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+			"Card is Locked.\n");
+		goto next;
+	}
+
+	result = card_init_stage2(card);
+	if (!result) {
+		DbgErr("SD init stage 2 failed.\n");
+		goto error_exit;
+	}
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Card Init Stage 2 OK.\n");
+
+next:
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit(OK) %s\n",
+		__func__);
+	return result;
+
+error_exit:
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit(FAIL) %s\n", __func__);
+	return result;
+}
+
+static byte sd_get_lower_am(sd_card_t *card, byte access_mode)
+{
+	cfg_item_t *cfg = card->host->cfg;
+	byte lower_am = 0;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT | FEATURE_ERROR_RECOVER,
+		NOT_TO_RAM, "Enter %s, access_mode=%d\n", __func__,
+		access_mode);
+
+	/* Degrade access mode according to current access mode. */
+	switch (access_mode) {
+	case SD_FNC_AM_DDR200:
+		lower_am =
+		    card_get_min_am((byte) cfg->card_item.test_max_access_mode.value,
+				    (byte) card_get_max_am_cap(card));
+		break;
+	case SD_FNC_AM_SDR104:
+		/* Degrade to SDR50 directly */
+		lower_am = SD_FNC_AM_SDR50;
+		break;
+	case SD_FNC_AM_SDR50:
+		if ((cfg->card_item.test_max_access_mode.value == SD_FNC_AM_DDR50)
+		    && (card->info.sw_func_cap.sd_access_mode &
+			(1 << SD_FNC_AM_DDR50))) {
+			/*
+			 * Max Access mode is DDR50 and card support DD50,
+			 * then can be degrade to DDR50
+			 */
+			lower_am = SD_FNC_AM_DDR50;
+		} else {
+			/* Degrade to High Speed */
+			lower_am = SD_FNC_AM_HS;
+		}
+		break;
+	case SD_FNC_AM_DDR50:
+		/* Degrade to High Speed directly */
+		lower_am = SD_FNC_AM_HS;
+		break;
+	case SD_FNC_AM_HS:
+		/* Degrade to Default Speed directly */
+		lower_am = SD_FNC_AM_DS;
+		break;
+	default:
+		lower_am = SD_FNC_AM_DS;
+		break;
+	}
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT | FEATURE_ERROR_RECOVER,
+		NOT_TO_RAM, "Exit(%d) %s\n", lower_am, __func__);
+	return lower_am;
+}
+
+static byte sd_get_higher_am(sd_card_t *card, byte access_mode)
+{
+	cfg_item_t *cfg = card->host->cfg;
+	byte higher_am = 0;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT | FEATURE_ERROR_RECOVER,
+		NOT_TO_RAM, "Enter %s, access_mode=%d\n", __func__,
+		access_mode);
+
+	/* get higher access mode. */
+	switch (access_mode) {
+	case SD_FNC_AM_DDR200:
+		higher_am = SD_FNC_AM_DDR200;
+		break;
+	case SD_FNC_AM_SDR104:
+		/* Keep SDR104 */
+		if (sd_ddr_support(card)
+		    && (cfg->card_item.test_max_access_mode.value ==
+			SD_FNC_AM_SDR104))
+			higher_am = SD_FNC_AM_DDR200;
+		else
+			higher_am = SD_FNC_AM_SDR104;
+
+		break;
+	case SD_FNC_AM_SDR50:
+		if ((cfg->card_item.test_max_access_mode.value ==
+		     SD_FNC_AM_SDR104)
+		    && card->info.sw_func_cap.sd_access_mode &
+			(1 << SD_FNC_AM_SDR104)) {
+			/* SDR104 */
+			higher_am = SD_FNC_AM_SDR104;
+		} else {
+			/* SDR50 */
+			higher_am = SD_FNC_AM_SDR50;
+		}
+		break;
+	case SD_FNC_AM_DDR50:
+		/* Degrade to High Speed directly */
+		if ((cfg->card_item.test_max_access_mode.value ==
+		     SD_FNC_AM_SDR50)
+		    && card->info.sw_func_cap.sd_access_mode &
+			(1 << SD_FNC_AM_SDR50)) {
+			/* SDR50 is higher level access mode of DDR50 */
+			higher_am = SD_FNC_AM_SDR50;
+		} else {
+			/* No change */
+			higher_am = SD_FNC_AM_DDR50;
+		}
+		break;
+	case SD_FNC_AM_HS:
+		/* Degrade to Default Speed directly */
+		if ((cfg->card_item.test_max_access_mode.value ==
+		     SD_FNC_AM_DDR50)
+		    && card->info.sw_func_cap.sd_access_mode &
+			(1 << SD_FNC_AM_DDR50)) {
+			/* DDR50 supported, then it is higher level access mode of High Speed. */
+			higher_am = SD_FNC_AM_DDR50;
+		} else if ((cfg->card_item.test_max_access_mode.value ==
+			 SD_FNC_AM_SDR50)
+			&& card->info.sw_func_cap.sd_access_mode &
+			(1 << SD_FNC_AM_SDR50)) {
+			/*
+			 * DDR50 do not supported,
+			 * then SDR50 is the higher level access mode of High Speed.
+			 */
+			higher_am = SD_FNC_AM_SDR50;
+		} else {
+			/* No change */
+			higher_am = SD_FNC_AM_HS;
+		}
+		break;
+	case SD_FNC_AM_DS:
+		if ((cfg->card_item.test_max_access_mode.value == SD_FNC_AM_HS)
+		    && card->info.sw_func_cap.sd_access_mode &
+			(1 << SD_FNC_AM_HS)) {
+			/* High Speed is the higher level access mode of Default Speed. */
+			higher_am = SD_FNC_AM_HS;
+		} else {
+			/* No change */
+			higher_am = SD_FNC_AM_DS;
+		}
+		break;
+	default:
+		break;
+	}
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_CARD_INIT | FEATURE_ERROR_RECOVER,
+		NOT_TO_RAM, "Exit(%d) %s\n", higher_am, __func__);
+	return higher_am;
+}
+
+/*
+ * Function Name: sd_degrade_policy
+ *
+ * Abstract: This Function is used set sd degrade flag
+ *
+ * Input:
+ * sd_card_t *card : The Command will send to which  Card
+
+ * Return value:
+ */
+void sd_degrade_policy(sd_card_t *card)
+{
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR50 ||
+	    card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR104 ||
+	    card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_DDR200) {
+		/* If Access Mode >= SDR50, then try to degrade freq first */
+		if (card->degrade_freq_level < CARD_DEGRADE_FREQ_TIMES) {
+			/* Degrade freq less than 3 times, continue to degrade freq */
+			card->degrade_freq_level++;
+		} else {
+			/* As degrade mode is needed, clear the degrade freq level. */
+			card->degrade_freq_level = 0;
+
+			/* Degrade freq larger than 3 times, then degrade accessmode */
+			card->sw_target_setting.sd_access_mode =
+			    sd_get_lower_am(card,
+					    card->sw_target_setting.sd_access_mode);
+			/* If Degrade to Default Speed already. Mark as degrade final */
+			if (card->sw_target_setting.sd_access_mode ==
+			    SD_FNC_AM_DS) {
+				card->degrade_final = 1;
+			}
+		}
+	} else {
+		/* As degrade mode is needed, clear the degrade freq level. */
+		card->degrade_freq_level = 0;
+
+		/* If Access Mode < SDR50, then degrade access mode directly */
+		card->sw_target_setting.sd_access_mode =
+		    sd_get_lower_am(card,
+				    card->sw_target_setting.sd_access_mode);
+		/* If Degrade to Default Speed already. Mark as degrade final */
+		if (card->sw_target_setting.sd_access_mode == SD_FNC_AM_DS)
+			card->degrade_final = 1;
+
+	}
+
+	DbgErr("Legacy SD degrade target=%d freq_level=%d final=%d\n",
+	       card->sw_target_setting.sd_access_mode, card->degrade_freq_level,
+	       card->degrade_final);
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+}
+
+/*
+ * Function Name: uhs2_thermal_control
+ * Abstract: This Function is used to do card thremal control, only for SD and UHS2 card
+ *
+ * Input:
+ *			sd_card_t *card
+ *
+ * Return value:
+ *			TRUE: means ok
+ *			others means error occur, caller need do error recovery
+ *
+ * Notes:
+ *			run in thread context
+ */
+
+bool sd_thermal_control(sd_card_t *card)
+{
+	bool bheat = (bool)card->thermal_heat;
+	sd_command_t sd_cmd;
+	bool result = TRUE;
+	bool change_am = FALSE;
+	byte am = 0;
+	bool bchg = FALSE;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_FUNC_THERMAL, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* 2.0 Card don't do thermal control */
+	if (card->info.card_s18a == 0
+	    || card->host->cfg->card_item.sd_card_mode_dis.dis_sd30_card)
+		goto exit;
+
+	if (bheat) {
+		am = sd_get_higher_am(card,
+				      card->info.sw_cur_setting.sd_access_mode);
+	} else {
+		am = sd_get_lower_am(card,
+				     card->info.sw_cur_setting.sd_access_mode);
+	}
+
+	/* If one access mode need tuning and another don't need we can't change */
+	if (am == card->info.sw_cur_setting.sd_access_mode) {
+		change_am = FALSE;
+	} else if (am == SD_FNC_AM_SDR50 || am == SD_FNC_AM_SDR104
+		   || am == SD_FNC_AM_DDR200) {
+		if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR50
+		    || card->info.sw_cur_setting.sd_access_mode ==
+		    SD_FNC_AM_DDR200
+		    || card->info.sw_cur_setting.sd_access_mode ==
+		    SD_FNC_AM_SDR104)
+			change_am = TRUE;
+		else if (am != SD_FNC_AM_SDR50 && am != SD_FNC_AM_SDR104
+			 && am != SD_FNC_AM_DDR200)
+			if (card->info.sw_cur_setting.sd_access_mode !=
+			    SD_FNC_AM_SDR50
+			    && card->info.sw_cur_setting.sd_access_mode !=
+			    SD_FNC_AM_SDR104
+			    && card->info.sw_cur_setting.sd_access_mode !=
+			    SD_FNC_AM_DDR200)
+				change_am = TRUE;
+	}
+/* next: */
+	if (change_am) {
+		card->thermal_access_mode = am;
+		DbgInfo(MODULE_SD_CARD, FEATURE_FUNC_THERMAL, NOT_TO_RAM,
+			"thermal switch  am = %d\n", am);
+		result = card_stop_infinite(card, TRUE, NULL);
+		if (result == FALSE) {
+			DbgErr("uhs2 Thermal Stop Infinite failed1\n");
+			goto exit;
+		}
+
+		result = sd_switch_access_mode(card, &sd_cmd, &bchg);
+		if (result == FALSE)
+			goto exit;
+
+		if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR104
+		    || card->info.sw_cur_setting.sd_access_mode ==
+		    SD_FNC_AM_SDR50
+		    || card->info.sw_cur_setting.sd_access_mode ==
+		    SD_FNC_AM_DDR200) {
+
+			if (bchg)
+				result = sd_tuning(card, &sd_cmd, 0);
+			if (!result) {
+				DbgErr("Tuning failed for thermal control.\n");
+				goto exit;
+			}
+		}
+	}
+
+	if (bchg == FALSE) {
+		DbgInfo(MODULE_SD_CARD, FEATURE_FUNC_THERMAL, NOT_TO_RAM,
+			"thermal switch pm heatup = %d\n", card->thermal_heat);
+		result = card_stop_infinite(card, TRUE, NULL);
+		if (result == FALSE) {
+			DbgErr("uhs2 Thermal Stop Infinite failed1\n");
+			goto exit;
+		}
+		result = sd_switch_power_limit(card, &sd_cmd, &bchg);
+	}
+
+	if (result == TRUE && bchg)
+		host_cmddat_line_reset(card->host);
+
+exit:
+	DbgInfo(MODULE_SD_CARD, FEATURE_FUNC_THERMAL, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return result;
+
+}
+
+static u8 sd_adjust_tuning(sd_card_t *card, u32 input_n1, u32 output_n1)
+{
+	u8 result = TRUE;
+	sd_command_t sd_cmd;
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	hostven_set_tuning_phase(host, input_n1, output_n1, FALSE);
+
+	if (card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR104 ||
+	    card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_SDR50 ||
+	    card->info.sw_cur_setting.sd_access_mode == SD_FNC_AM_DDR200) {
+
+		result = sd_tuning(card, &sd_cmd, 150);
+		if (result == FALSE) {
+			DbgErr("sd adjust tuning: sd_tuning fail\n");
+			result = FALSE;
+			goto exit;
+		}
+	}
+
+exit:
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return result;
+}
+
+static void sd_calc_max_passrange(u8 *pdata, u32 *ret, u32 *sum)
+{
+	u32 window_pass_number[22], window_start_adr[22],
+	    window_pass_number_max;
+	int ii, jj, first_0, dll_i_mod, dll_i, dll_mod;
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	for (ii = 0; ii < 22; ii++) {
+		window_pass_number[ii] = 0;
+		window_start_adr[ii] = 0;
+	}
+
+	first_0 = 0;
+	window_pass_number_max = 0;
+	for (dll_i = 0; dll_i < 22; dll_i++) {
+		if (pdata[dll_i] == 0) {
+			first_0 = dll_i;
+			break;
+		}
+	}
+	jj = 0;
+	for (dll_i = 0; dll_i < 22; dll_i++) {
+		dll_i_mod = (first_0 + dll_i) % 22;
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"DLL phase [%x] result %d.\n", dll_i_mod,
+			pdata[dll_i_mod]);
+		if (pdata[dll_i_mod] != 0)
+			window_pass_number[jj]++;
+		else {
+			if (window_pass_number[jj] > 0)
+				jj++;
+
+		}
+		if ((window_pass_number[jj] == 1) && (jj > 0)) {
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, "Error! there are %d DLL window\n",
+				(jj + 1));
+		}
+		if (window_pass_number[jj] == 1)
+			window_start_adr[jj] = dll_i_mod;
+	}
+
+	for (ii = 0; ii < 22; ii++) {
+		if (window_pass_number_max < window_pass_number[ii]) {
+			window_pass_number_max = window_pass_number[ii];
+			jj = ii;
+		}
+	}
+	if (window_pass_number_max == 0)
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"DLL test result: All DLL test FAIL\n");
+	else {
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"DLL test result: Total  %d DLL test PASS\n",
+			window_pass_number_max);
+		window_pass_number_max = window_pass_number_max >> 1;
+		dll_mod = window_start_adr[jj] + window_pass_number_max;
+		dll_mod = dll_mod % 22;
+
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			"select DLL phase Number %d\n", dll_mod);
+	}
+	*ret = dll_mod;
+	*sum = window_pass_number_max;
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+}
+
+/* The caller check */
+u8 testbuf_write[512];
+u8 testbuf_read[512];
+
+bool sd_dll_divider(sd_card_t *card, sd_command_t *pcmd)
+{
+
+	u32 ii, jj, pattern_i;
+	bool ret = FALSE, result = FALSE, datcmp;
+
+	u32 window_pass_sum, dll_i, input_n1, output_n1, input_n, output_n,
+	    DLL_input_Phase = 0, DLL_output_Phase = 0;
+	sd_command_t sd_cmd;
+	byte test_patern[6] = { 0x55, 0xaa, 0x00, 0xff, 0xf0, 0x0f };
+	u32 cmdflag;
+	sd_host_t *host = card->host;
+	u8 phasecheck[22][22], phasepass[22];
+
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	host->output_tuning.start_block = pcmd->argument;
+
+	/* If use read write, Save Current DMA mode */
+	host_transfer_init(host, FALSE, TRUE);
+	cmdflag = CMD_FLG_RESCHK | CMD_FLG_R1 | CMD_FLG_ADMA_SDMA;
+	jj = 0;
+	host_cmddat_line_reset(host);
+	for (dll_i = 0; dll_i < 512; dll_i++)
+		testbuf_write[dll_i] = test_patern[dll_i % 6];
+	if (card_check_rw_ready(card, &sd_cmd, 600) != TRUE) {
+		DbgErr
+		    ("Error when sd dll divider,  card_check_rw_ready fail\n");
+		result = FALSE;
+		goto exit;
+	}
+
+	if (hostven_dll_input_tuning_init(host) == FALSE) {
+		DbgErr
+		    ("Error when sd dll divider,  hostven_dll_input_tuning_init  fail\n");
+		result = FALSE;
+		goto exit;
+	}
+
+	for (output_n1 = 0; output_n1 < 22; output_n1++)
+		for (input_n1 = 0; input_n1 < 22; input_n1++) {
+
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM,
+				" - DLL input tuning  Test %d , %d\n", input_n1,
+				output_n1);
+			phasecheck[output_n1][input_n1] = 0;
+			phasepass[output_n1] = 0;
+			host_cmddat_line_reset(host);
+
+			if (sd_adjust_tuning(card, input_n1, output_n1) ==
+			    FALSE) {
+				DbgErr
+				    (" -adjust Output Tuning phase FAILED!!!\n");
+
+				continue;
+			}
+			for (pattern_i = 0; pattern_i < 1; pattern_i++) {
+				for (ii = 0; ii < (1 * 512); ii++)
+					(*(testbuf_read + ii)) = 0x96;
+
+				ret =
+				    card_send_sdcmd_timeout(card, &sd_cmd,
+							    SD_CMD24,
+							    host->output_tuning.start_block,
+							    (cmdflag),
+							    DATA_DIR_OUT,
+							    testbuf_write, 512,
+							    50);
+				if (ret == FALSE)
+					break;
+				ret =
+				    card_send_sdcmd_timeout(card, &sd_cmd,
+							    SD_CMD17,
+							    host->output_tuning.start_block,
+							    (cmdflag),
+							    DATA_DIR_IN,
+							    testbuf_read, 512,
+							    50);
+				if (ret == FALSE) {
+					DbgErr
+					    ("Read data FAILED when output_tuning\n");
+
+					break;
+				}
+
+				datcmp = TRUE;
+				for (ii = 0; ii < (1 * 512); ii++) {
+					if (*(testbuf_write + ii) !=
+					    *(testbuf_read + ii)) {
+						datcmp = FALSE;
+						phasecheck[output_n1][input_n1]
+						    = 0;
+						break;
+					}
+				}
+				if (datcmp == FALSE) {
+					DbgInfo(MODULE_SD_CARD,
+						FEATURE_ERROR_RECOVER,
+						NOT_TO_RAM,
+						"Compare data FAILED at index %d!!!\n",
+						ii);
+				} else {
+					DbgInfo(MODULE_SD_CARD,
+						FEATURE_ERROR_RECOVER,
+						NOT_TO_RAM,
+						"Compare data OK.\n");
+					phasecheck[output_n1][input_n1] = 1;
+				}
+			}
+		}
+
+	for (output_n = 0; output_n < 22; output_n++) {
+		DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+			" ## The output tuning %d:  ", output_n);
+		for (input_n = 0; input_n < 22; input_n++)
+			DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER,
+				NOT_TO_RAM, "  %d:   %d   ", input_n,
+				phasecheck[output_n][input_n]);
+	}
+
+	for (output_n = 0; output_n < 22; output_n++) {
+		for (input_n = 0; input_n < 22; input_n++)
+			phasepass[output_n] += phasecheck[output_n][input_n];
+	}
+
+	/* check for the max pass range */
+	sd_calc_max_passrange(phasepass, &DLL_output_Phase, &window_pass_sum);
+	sd_calc_max_passrange(phasecheck[DLL_output_Phase], &DLL_input_Phase,
+			      &window_pass_sum);
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"The best input tuning phase is %d\n", DLL_input_Phase);
+	/* Get the optimized clock phase to do read/write test */
+	hostven_set_tuning_phase(host, DLL_input_Phase, DLL_output_Phase,
+				 FALSE);
+	result = TRUE;
+
+exit:
+	/* Resorte current DMA mode */
+	host_transfer_init(host, card->inf_trans_enable, FALSE);
+	if (result == FALSE)
+		hostven_set_tuning_phase(host, 0, 0, TRUE);
+	host_cmddat_line_reset(host);
+	DbgInfo(MODULE_SD_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return result;
+}
+
+/*
+ *
+ * Function Name: sd_read_csd
+ *
+ * Abstract:
+ *
+ *			 1.  De-select the card and send CMD9, and then select the card.
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *			sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *			Caller:
+ */
+bool sd_read_csd(sd_card_t *card, sd_command_t *sd_cmd, byte *data)
+{
+	card_info_t *card_info = &(card->info);
+	bool ret = FALSE, ret1 = FALSE, ret2 = FALSE;
+
+	ret = card_deselect_card(card, sd_cmd);
+	if (!ret)
+		goto exit_select_card;
+
+	ret1 = card_get_csd(card, sd_cmd);
+
+exit_select_card:
+	ret2 = card_select_card(card, sd_cmd);
+
+	if ((ret == FALSE) || (ret1 == FALSE) || (ret2 == FALSE))
+		return FALSE;
+	else {
+		os_memcpy(data, &(card_info->raw_csd[0]), 0x10);
+		return TRUE;
+	}
+}
+
+/*
+ *
+ * Function Name: sd_program_csd
+ *
+ * Abstract:
+ *
+ *			 1.  Program CSD by CMD27.
+ *
+ * Input:
+ *
+ *			sd_card_t *card [in] [out]: Pointer to the virtual card structure
+ *			sd_command_t *sd_cmd: Pointer to sd command structure
+ *
+ * Output:
+ *
+ *			None
+ *
+ * Return value:
+ *
+ *			Return TRUE if card init successfully, else return FALSE.
+ *
+ * Notes:
+ *
+ *			Caller:
+ */
+bool sd_program_csd(sd_card_t *card, sd_command_t *sd_cmd, byte *data)
+{
+
+	byte cmd_index = SD_CMD27;
+	u32 argument = 0;
+	u32 cmdflag = CMD_FLG_R1 | CMD_FLG_RESCHK;
+	e_data_dir dir = DATA_DIR_OUT;
+	u32 datalen = 0x10;
+	sd_host_t *host = card->host;
+	bool ret = FALSE;
+
+	ret =
+	    card_send_sdcmd(card, sd_cmd, cmd_index, argument, cmdflag, dir,
+			    data, datalen);
+	if (ret == FALSE)
+		DbgErr("CMD27 failed\n");
+
+	host_cmddat_line_reset(host);
+
+	DbgInfo(MODULE_ALL_CARD, FEATURE_RW_TRACE, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, ret);
+	return ret;
+
+}
diff --git a/drivers/scsi/bht/card/thermal.c b/drivers/scsi/bht/card/thermal.c
new file mode 100644
index 000000000000..bda251476944
--- /dev/null
+++ b/drivers/scsi/bht/card/thermal.c
@@ -0,0 +1,348 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: thermal.c
+ *
+ * Abstract: This File is used to handle thread event
+ *
+ * Version: 1.00
+ *
+ * Author: Peter.Guo
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 11/05/2014		Creation	Peter.Guo
+ */
+
+#include "../include/basic.h"
+#include "../include/card.h"
+#include "../include/function.h"
+#include "../include/cardapi.h"
+#include "cardcommon.h"
+#include "../include/hostapi.h"
+#include "../include/util.h"
+#include "../include/debug.h"
+
+/*
+ * Function Name: thermal_gpio_sensor
+ * Abstract: This Function is used to do get sensor result for thermal control
+ *
+ * Input:
+ *			sd_host_t *host
+ *
+ * Return value:
+ *			NORMAL
+ *			COOL
+ *			HOT
+ *
+ * Notes:
+ *			run in thread context
+ */
+
+static e_thermal_val thermal_gpio_sensor(sd_host_t *host)
+{
+	e_thermal_val result = THERMAL_NORMAL;
+	u32 value = 0;
+
+	DbgInfo(MODULE_THERMAL, FEATURE_FUNC_THERMAL, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	switch (host->chip_type) {
+	case CHIP_SEAEAGLE:
+		ven_and32(host, 0x22c, ~0x7);
+		ven_or32(host, 0x22c, 0x13);
+		value = ven_readl(host, 0x22c);
+		value = (value & 0x40) >> 6;
+		break;
+	case CHIP_SEAEAGLE2:
+	case CHIP_GG8:
+	case CHIP_ALBATROSS:
+		ven_and32(host, 0x50c, ~0x7);
+		ven_or32(host, 0x50c, 0x13);
+		value = ven_readl(host, 0x50c);
+		value = (value & 0x40) >> 6;
+		break;
+	default:
+		value = pci_readl(host, 0xD4);
+		value = (value & 0x80) >> 7;
+		break;
+	}
+
+	result = (e_thermal_val) value;
+
+	DbgInfo(MODULE_THERMAL, FEATURE_FUNC_THERMAL, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, value);
+	return result;
+
+}
+
+/*
+ * Function Name: thermal_i2c_sensor
+ * Abstract: This Function is used to do get sensor result for thermal control
+ *
+ * Input:
+ *			sd_host_t *host
+ *
+ * Return value:
+ *			NORMAL
+ *			COOL
+ *			HOT
+ *
+ * Notes:
+ *			run in thread context
+ */
+
+static e_thermal_val thermal_i2c_sensor(sd_host_t *host)
+{
+	u32 temp_val = 0, count = 0;
+	u32 upper_limit = 0, lower_limit = 0;
+	e_thermal_val result = THERMAL_NORMAL;
+
+	DbgInfo(MODULE_THERMAL, FEATURE_FUNC_THERMAL, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Enable I2C I/F */
+	ven_and32(host, 0x228, ~0x7);
+	ven_or32(host, 0x228, 0x1);
+	ven_and32(host, 0x230, ~0x7);
+	ven_or32(host, 0x230, 0x1);
+	os_mdelay(1);
+
+	/* Reset I2C function */
+	ven_writel(host, 0x220, 0x80000000);
+
+	os_mdelay(1);
+
+	/* Set FLTR and One short bit */
+	ven_writel(host, 0x220, 0x440000);
+	ven_writel(host, 0x220, 0x20009401);
+
+	while ((ven_readl(host, 0x220) & 0x20000000)) {
+		/* Timeout 5ms */
+		if (count == 5) {
+			DbgErr(" - Wait I2C write operation timeout!\n");
+			break;
+		}
+		/* else if (device_status == DEVICE_STATUS_CHIPLOST) */
+		else if (ven_readl(host, 0x220) == 0xffffffff) {
+			DbgErr("break loop because chip lost!\n");
+			break;
+		}
+
+		os_mdelay(1);
+		count += 1;
+	}
+
+	/* Read the temperature value */
+	ven_writel(host, 0x220, 0x50009400);
+
+	while ((ven_readl(host, 0x220) & 0x10000000)) {
+		/* Timeout 5ms */
+		if (count == 5) {
+			DbgErr(" - Wait I2C read operation timeout!\n");
+			break;
+		}
+		/* else if (device_status == DEVICE_STATUS_CHIPLOST) */
+		else if (ven_readl(host, 0x220) == 0xffffffff) {
+			DbgErr("break loop because chip lost!!\n");
+			break;
+		}
+		os_mdelay(1);
+		count += 1;
+	}
+
+	temp_val = (ven_readl(host, 0x224) & 0xffff) >> 6;
+	/* upper_limit = (tmp_high & 0xffff0000) >> 16; */
+	/* lower_limit = tmp_low & 0xffff; */
+
+	if ((temp_val & 0x200) && (upper_limit & 0x8000)) {
+		if ((temp_val & 0x1ff) < ((upper_limit & 0x1ff) << 2)) {
+			result = THERMAL_HOT;
+			goto exit;
+		}
+	}
+
+	if ((0 == (temp_val & 0x200)) && (upper_limit & 0x8000)) {
+		result = THERMAL_HOT;
+		goto exit;
+	}
+
+	if ((0 == (temp_val & 0x200)) && (0 == (upper_limit & 0x8000))) {
+		if ((temp_val & 0x1ff) > ((upper_limit & 0x1ff) << 2)) {
+			result = THERMAL_HOT;
+			goto exit;
+		}
+	}
+
+	if ((temp_val & 0x200) && (lower_limit & 0x8000)) {
+		if ((temp_val & 0x1ff) > ((lower_limit & 0x1ff) << 2)) {
+			result = THERMAL_COOL;
+			goto exit;
+		}
+	}
+
+	if ((temp_val & 0x200) && (0 == (lower_limit & 0x8000))) {
+		result = THERMAL_COOL;
+		goto exit;
+	}
+
+	if ((0 == (temp_val & 0x200)) && (0 == (lower_limit & 0x8000))) {
+		if ((temp_val & 0x1ff) < ((lower_limit & 0x1ff) << 2)) {
+			result = THERMAL_COOL;
+			goto exit;
+		}
+	}
+
+exit:
+	DbgInfo(MODULE_THERMAL, FEATURE_FUNC_THERMAL, NOT_TO_RAM,
+		"Exit %s result=%d\n", __func__, result);
+	return result;
+
+}
+
+/*
+ * Function Name: func_thermal_control
+ * Abstract: This Function is used to do thremal control
+ *			  This function should be called before send card Read Write
+ *
+ * Input:
+ *			sd_card_t *card
+ *
+ * Return value:
+ *			TRUE: means ok
+ *			others means error occur, caller need do error recovery
+ *
+ * Notes:
+ *			run in thread context
+ */
+
+bool func_thermal_control(sd_card_t *card)
+{
+	sd_host_t *host = card->host;
+	bht_dev_ext_t *pdx = host->pdx;
+	bool result = TRUE;
+	e_thermal_val thermal = THERMAL_NORMAL;
+
+	DbgInfo(MODULE_THERMAL, FEATURE_FUNC_THERMAL, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* If Thermal Control is disabled then do nothing */
+	if (pdx->thermal.enable == 0)
+		goto exit;
+
+	/* If Thermal timeout is not occur then do nothing */
+	if (pdx->thermal.enable_timer_chk == 1 && pdx->thermal.timeout == 0)
+		goto exit;
+
+	pdx->thermal.timeout = 0;
+	pdx->thermal.last_check_ms = os_get_cur_tick();
+
+	/* If card not working do nothing */
+	if (card->state != CARD_STATE_WORKING || card->card_present == FALSE)
+		goto exit;
+
+	if (card->initialized_once == FALSE)
+		goto exit;
+
+	/* Currently only uhs2 and SD support thermal control */
+	switch (card->card_type) {
+	case CARD_SD:
+	case CARD_UHS2:
+		break;
+	default:
+		goto exit;
+	}
+
+	if (pdx->thermal.use_i2c)
+		thermal = thermal_i2c_sensor(host);
+	else
+		thermal = thermal_gpio_sensor(host);
+
+	DbgInfo(MODULE_THERMAL, FEATURE_FUNC_THERMAL, NOT_TO_RAM,
+		"Start do Thermal control sensor=%d\n", thermal);
+
+	if (thermal == THERMAL_NORMAL) {
+		/* nothing to do for no thermal change */
+		goto exit;
+	} else if (thermal == THERMAL_COOL) {
+		/* NEED change to higher mode */
+		pdx->card.thermal_enable = 1;
+		pdx->card.thermal_heat = 1;
+		result = card_thermal_control(card);
+	} else {
+		/* change to lower mode */
+		pdx->card.thermal_enable = 1;
+		pdx->card.thermal_heat = 0;
+		result = card_thermal_control(card);
+	}
+
+	pdx->card.thermal_enable = 0;
+
+exit:
+	DbgInfo(MODULE_THERMAL, FEATURE_FUNC_THERMAL, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: func_thermal_control
+ * Abstract: This Function is used to update thermal control time
+ *			  This function should be called before send card Read Write
+ *
+ * Input:
+ *			sd_card_t *card
+ *
+ * Return value:
+ *			TRUE: means ok
+ *			others means error occur, caller need do error recovery
+ *
+ * Notes:
+ */
+
+void func_thermal_update_time(bht_dev_ext_t *pdx)
+{
+	/* If time check for thermal contorl is not enable do nothing */
+	if (pdx->thermal.enable == 0 || pdx->thermal.enable_timer_chk == 0)
+		return;
+
+	if (pdx->card.state != CARD_STATE_WORKING
+	    || pdx->card.card_present == FALSE)
+		return;
+
+	if (pdx->card.initialized_once == FALSE)
+		return;
+
+	if (pdx->thermal.timeout == 0) {
+		pdx->thermal.timeout =
+		    (os_get_cur_tick() >
+		     (pdx->thermal.last_check_ms +
+		      pdx->thermal.check_period_ms)) ? 1 : 0;
+	}
+
+}
+
+void thermal_init(bht_dev_ext_t *pdx)
+{
+	pdx->thermal.enable = 0;
+	if (pdx->thermal.enable == 0)
+		return;
+	pdx->thermal.use_i2c = 0;
+	pdx->thermal.last_check_ms = os_get_cur_tick();
+	pdx->thermal.enable_timer_chk = 0;
+	pdx->thermal.check_period_ms = 0;
+	DbgInfo(MODULE_THERMAL, FEATURE_DRIVER_INIT, NOT_TO_RAM,
+		"thermal enable=%d i2c=%d timechk=%dms chkperiod=%dms\n",
+		pdx->thermal.enable, pdx->thermal.use_i2c,
+		pdx->thermal.enable_timer_chk, pdx->thermal.check_period_ms);
+
+}
+
+void thermal_uninit(bht_dev_ext_t *pdx)
+{
+	if (pdx->thermal.enable == 0)
+		return;
+	pdx->thermal.last_check_ms = os_get_cur_tick();
+}
diff --git a/drivers/scsi/bht/card/uhs2.c b/drivers/scsi/bht/card/uhs2.c
new file mode 100644
index 000000000000..6f9511b5d33d
--- /dev/null
+++ b/drivers/scsi/bht/card/uhs2.c
@@ -0,0 +1,1228 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 BHT Inc.
+ *
+ * File Name: uhs2.c
+ *
+ * Abstract: SD UHS2 card initialization
+ *
+ * Version: 1.00
+ *
+ * Author: peter.guo
+ *
+ * Environment:	OS Independent
+ *
+ * History:
+ *
+ * 10/10/2014		Creation	Peter.Guo
+ */
+
+#include "../include/basic.h"
+#include "../include/cmdhandler.h"
+#include "../include/cardapi.h"
+#include "../include/hostapi.h"
+#include "cardcommon.h"
+#include "../include/util.h"
+#include "../include/debug.h"
+
+#define UHS2_DEVINIT_CF			0x00000800
+#define UHS2_DEVINIT_GAP		0x0000000F
+#define UHS2_ENUM_PLD			0x00000000
+#define UHS2_GODRM_HBNEN		0x00000080
+#define UHS2_ENMR_IDF			0x000000F0
+#define UHS2_ENMR_IDL			0x0000000F
+
+#define	UHS2_LANES_2L_HD	0x00
+#define	UHS2_LANES_2D1UFD	0x02
+#define	UHS2_LANES_1D2UFD	0x03
+#define	UHS2_LANES_2D2UFD	0x04
+
+#define UHS2_UNRECOVER_ERROR	(BIT0 | BIT2 | BIT7)
+
+static inline bool uhs2_is_uncoverable(sd_command_t *sd_cmd)
+{
+	if ((sd_cmd->err.error_code == ERR_CODE_TIMEOUT) ||
+	    (sd_cmd->err.uhs2_err_reg & UHS2_UNRECOVER_ERROR))
+		return TRUE;
+	else
+		return FALSE;
+}
+
+/*
+ * Function Name: uhs2_access_reg
+ *
+ * Abstract: This Function is used to send uhs2 ccmd
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *	sd_command_t *sd_cmd: This parameter will contail card command info
+ *	byte ioaddr: ioaddr for uhs2 ccmd
+ *	bool broadcast: use broadcast or not
+ *	bool rwcmd: Set RW flag in uhs2 header or not
+ *	byte payload_num: payload count
+ *
+ * Input & Output:
+ *			u32 *payload: contain the register want to setting,
+ *			and store return  regs value
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *			otherwize reutrn FALSE
+ *
+ * Notes:
+ *  so giving the routine another name requires you to modify the build tools.
+ */
+
+static bool uhs2_native_ccmd_internal(sd_card_t *card, sd_command_t *sd_cmd,
+				      u16 ioaddr, bool broadcast, bool rwcmd,
+				      byte payload_num, u32 *payload)
+{
+	bool result = FALSE;
+	u32 headarg = UHS2_CMD_HEADER_NP;
+	int i;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Enter %s ioaddr=0x%04X\n", __func__, ioaddr);
+
+	/* step1 prepare header for uhs2 ccmd       */
+	headarg |= UHS2_NATIVE_CCMD_IOADDR(ioaddr);
+
+	if (broadcast == FALSE)
+		headarg |= UHS2_HEADER_DID(card->uhs2_info.dev_id);
+
+	if (rwcmd)
+		headarg |= UHS2_NATIVE_HEADER_RW;
+
+	switch (payload_num) {
+	case 0:
+		break;
+	case 1:
+		headarg |= UHS2_NATIVE_CCMD_PLEN4;
+		break;
+	case 2:
+		headarg |= UHS2_NATIVE_CCMD_PLEN8;
+		break;
+	case 4:
+		headarg |= UHS2_NATIVE_CCMD_PLEN16;
+		break;
+	default:
+		DbgErr("uhs2 ccmd payload number is wrong\n");
+		goto exit;
+	}
+
+	sd_cmd->uhs2_header = headarg;
+	if (rwcmd)
+		sd_cmd->uhs2_set_pld = 1;
+
+	/* step 2 set payload       */
+	sd_cmd->payload_cnt = payload_num;
+	for (i = 1; i <= payload_num; i++)
+		sd_cmd->trans_reg[0].payload[i] = payload[i - 1];
+
+	result = cmd_generate_reg(card, sd_cmd);
+	if (result == FALSE)
+		goto exit;
+
+	result = cmd_execute_sync(card, sd_cmd, NULL);
+exit:
+	if (result == FALSE)
+		DbgErr("UHS2 Native cmd failed ioaddr=0x%02X errcode=0x%08X\n",
+		       UHS2_GET_NATIVE_IOADDR(sd_cmd->uhs2_header),
+		       sd_cmd->err.error_code);
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Exit %s result=%d\n", __func__, result);
+	return result;
+}
+
+bool uhs2_native_ccmd(sd_card_t *card, sd_command_t *sd_cmd,
+		      u16 ioaddr, bool broadcast, bool rwcmd, byte payload_num,
+		      u32 *payload)
+{
+	os_memset(sd_cmd, 0, sizeof(sd_command_t));
+	return uhs2_native_ccmd_internal(card, sd_cmd, ioaddr, broadcast, rwcmd,
+					 payload_num, payload);
+}
+
+/*
+ * Function Name: uhs2_access_reg
+ *
+ * Abstract: This Function is used to read or inquiry or set uhs2 card registers
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *			sd_command_t *sd_cmd: This parameter will contail card command info
+ *			byte ioaddr: reg addr
+ *	bool broadcast: use broadcast or not
+ *	bool setcfg: set reg or read reg
+ *	byte payload_num: reg count
+ *
+ * Input & Output:
+ *	u32 *payload: contain the register want to setting, and store return  regs value
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ *
+ * Notes:
+ *  so giving the routine another name requires you to modify the build tools.
+ */
+static bool uhs2_access_reg(sd_card_t *card, sd_command_t *sd_cmd,
+			    u16 ioaddr, bool broadcast, bool setcfg,
+			    byte payload_num, u32 *payload)
+{
+	u32 i;
+	bool result = FALSE;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Enter %s ioaddr=0x%04X\n", __func__, ioaddr);
+	os_memset(sd_cmd, 0, sizeof(sd_command_t));
+	if (payload_num > 4) {
+		DbgErr("payload_num is large than 4\n");
+		goto exit;
+	}
+
+	/* set reg case and broadcast inquiry need input value */
+	if (setcfg || broadcast) {
+		for (i = 0; i < payload_num; i++)
+			payload[i] = swapu32(payload[i]);
+		sd_cmd->uhs2_set_pld = 1;
+	} else {
+		for (i = 0; i < payload_num; i++)
+			payload[i] = 0;
+	}
+
+	result =
+	    uhs2_native_ccmd_internal(card, sd_cmd, ioaddr, broadcast, setcfg,
+				      payload_num, payload);
+	if (result == FALSE) {
+		DbgErr
+		    ("uhs2 access reg failed ioaddr=0x%02X broadcast=%d setcfg=%d\n",
+		     ioaddr, broadcast, setcfg);
+		goto exit;
+	}
+
+	/* set reg case don't need get register value */
+	if (setcfg == 0) {
+		for (i = 0; i < payload_num; i++)
+			payload[i] = swapu32(sd_cmd->response[i]);
+	}
+
+exit:
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARDCMD_TRACE, NOT_TO_RAM,
+		"Exit %s result=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_send_fullreset
+ *
+ * Abstract: This Function is used init Send UHS2 full reset ccmd
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *	sd_command_t *sd_cmd,
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *			otherwize reutrn FALSE
+ */
+bool uhs2_send_fullreset(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 payload = 0;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s\n", __func__);
+
+	result =
+	    uhs2_native_ccmd(card, sd_cmd, UHS2_IOADDR_FULLRESET, TRUE, TRUE, 0,
+			     &payload);
+
+	if (result == FALSE)
+		DbgErr("uhs2 fullreset failed\n");
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s\n", __func__);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_trans_abort
+ *
+ * Abstract: This Function is used init Send UHS2 transfer abort command
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *	sd_command_t *sd_cmd,
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+bool uhs2_trans_abort(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 payload = 0;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s\n", __func__);
+
+	result =
+	    uhs2_native_ccmd(card, sd_cmd, UHS2_IOADDR_ABORT, FALSE, TRUE, 0,
+			     &payload);
+
+	if (result == FALSE)
+		DbgErr("uhs2 trans_abort failed\n");
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_full_reset_card
+ *
+ * Abstract: This Function is used to send full reset command, if failed do host reset for all
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+
+bool uhs2_full_reset_card(sd_card_t *card)
+{
+	sd_command_t sd_cmd;
+	bool result = FALSE;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER | FEATURE_CARD_OPS,
+		NOT_TO_RAM, "Enter %s\n", __func__);
+
+	result = uhs2_send_fullreset(card, &sd_cmd);
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER | FEATURE_CARD_OPS,
+		NOT_TO_RAM, "uhs2 full rest ret=%d\n", result);
+	if (result) {
+		os_udelay(200);
+		host_uhs2_reset(card->host, TRUE);
+	} else {
+		/* failed do reset for all */
+		host_uhs2_clear(card->host, TRUE);
+	}
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER | FEATURE_CARD_OPS,
+		NOT_TO_RAM, "Exit %s ret=%d\n", __func__, result);
+
+	return result;
+}
+
+/*
+ * Function Name: uhs2_send_devinit
+ *
+ * Abstract: This Function is used init send uhs2 dev_enum ccmd and get card deviceid
+ *
+ * Input:
+ *			sd_card_t *card : The Command will send to which  Card
+ *			sd_command_t *sd_cmd,
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+
+bool uhs2_dev_enumeration(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 payload = 0;
+	u8 firstid, lastid;
+	u32 resp;
+	u8 devcnt = 0;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	firstid = lastid = 0;
+	payload = UHS2_ENUM_PLD;
+
+	result =
+	    uhs2_native_ccmd(card, sd_cmd, UHS2_IOADDR_ENUM, TRUE, TRUE, 1,
+			     &payload);
+	if (result == FALSE)
+		goto exit;
+
+	resp = sd_cmd->response[0];
+	firstid = (u8) ((resp & UHS2_ENMR_IDF) >> 4);
+	lastid = (u8) (resp & UHS2_ENMR_IDL);
+
+	if (firstid > lastid)
+		devcnt = (lastid + 0x10) - firstid;
+	else
+		devcnt = lastid - firstid + 1;
+
+	card->uhs2_info.dev_id = firstid;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, TO_RAM,
+		"firstid=0x%02X lastid=0x%02X\n", firstid, lastid);
+
+exit:
+	if (result == FALSE)
+		DbgErr("uhs2 enumeration failed\n");
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+
+}
+
+/*
+ * Function Name: uhs2_send_devinit
+ *
+ * Abstract: This Function is used init send uhs2 dev_init cmd
+ *
+ * Input:
+ *			sd_card_t *card : The Command will send to which  Card
+ *			sd_command_t *sd_cmd,
+ *			u8 gap,
+ *			u8 dap,
+ *
+ * Iput & Output:
+ *			u8 *gd,
+ *			u8 *cf
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+
+static bool uhs2_send_devinit(sd_card_t *card, sd_command_t *sd_cmd, u8 *gd,
+			      u8 gap, u8 dap, u8 *cf)
+{
+	bool result = FALSE;
+	u32 payload;
+	u32 resp;
+
+	payload =
+	    UHS2_DEVINIT_CF | (((*gd) & 0xf) << 4) | (gap & 0xf) | ((dap & 0xf)
+								    << 12);
+	result =
+	    uhs2_native_ccmd(card, sd_cmd, UHS2_IOADDR_DEVINIT, TRUE, TRUE, 1,
+			     &payload);
+	if (result == FALSE)
+		goto exit;
+
+	resp = sd_cmd->response[0];
+	if (resp & UHS2_DEVINIT_CF)
+		*cf = 1;
+	else
+		*cf = 0;
+
+	if (gap == (resp & UHS2_DEVINIT_GAP))
+		(*gd)++;
+
+exit:
+	return result;
+}
+
+/*
+ * Function Name: uhs2_devinit_flow
+ *
+ * Abstract: This Function is used do device_init flow
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *			sd_command_t *sd_cmd,
+ *	sd_host_t *host
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+static bool uhs2_devinit_flow(sd_card_t *card, sd_command_t *sd_cmd,
+			      sd_host_t *host)
+{
+	bool result = FALSE;
+	u8 gd, dap, gap, cf;
+
+	/* max 1200ms delay */
+	u32 timeout = 1200;
+	loop_wait_t wait;
+	u32 delay_us = 20;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	cf = 0;
+	gd = 0;
+	dap = host->uhs2_cap.dap;
+	gap = host->uhs2_cap.gap;
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"devinit dap=0x%02X gap=0x%02X\n", dap, gap);
+
+	util_init_waitloop(card->host->pdx, timeout, delay_us, &wait);
+
+	do {
+		result = uhs2_send_devinit(card, sd_cmd, &gd, gap, dap, &cf);
+		os_udelay(delay_us);
+
+		if (result == FALSE) {
+			DbgErr("Device Init cmd error\n");
+			goto exit;
+		}
+	} while ((util_is_timeout(&wait) == FALSE) && (cf == 0));
+
+	if (cf == 0)
+		result = FALSE;
+
+exit:
+	if (result == FALSE)
+		DbgErr("host:%p devinit failed cf=%d\n", host, cf);
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Exit %s\n",
+		__func__);
+	return result;
+
+}
+
+/*
+ * Function Name: uhs2_send_devinit
+ *
+ * Abstract: This Function is used init send uhs2 dev_enum ccmd and get card deviceid
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *	sd_command_t *sd_cmd,
+ *
+ * Return value:
+ *			If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+
+static bool uhs2_card_get_caps(sd_card_t *card, sd_command_t *sd_cmd,
+			       sd_host_t *host)
+{
+	u32 payload[2];
+	bool result = FALSE;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/*
+	 * Get  phy capbality for both host and card support
+	 * 1. Hibernate;  2. Lss_Dir; 3. Lss_Syn
+	 */
+	os_memset(payload, 0, sizeof(payload));
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_PHY_CAPL, FALSE, FALSE, 2,
+			    payload);
+	if (result == FALSE) {
+		DbgErr("Inquiry card phy cap failed\n");
+		goto exit;
+	}
+
+	card->uhs2_info.uhs2_cap.hibernate = (payload[0] & BIT15) ? 1 : 0;
+	card->uhs2_info.uhs2_cap.n_lss_dir = ((payload[1] & 0xF0) >> 4);
+	card->uhs2_info.uhs2_cap.n_lss_syn = ((payload[1] & 0x0F));
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"card hbr=%d lssdir=%d lsssyn=%d\n",
+		card->uhs2_info.uhs2_cap.hibernate,
+		card->uhs2_info.uhs2_cap.n_lss_dir,
+		card->uhs2_info.uhs2_cap.n_lss_syn);
+
+	/*
+	 * Get  Link/Tran capbality for both host and card support
+	 * 1. nfcu;  2. datagap; 3. max block length
+	 */
+	os_memset(payload, 0, sizeof(payload));
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_LINKT_CAPL, FALSE, FALSE,
+			    2, payload);
+	if (result == FALSE) {
+		DbgErr("Inquiry card link cap failed\n");
+		goto exit;
+	}
+
+	card->uhs2_info.uhs2_cap.n_fcu = ((payload[0] & 0xFF00) >> 8);
+	card->uhs2_info.uhs2_cap.n_data_gap = ((payload[1] & 0x00FF));
+	card->uhs2_info.uhs2_cap.max_blk_len =
+	    ((payload[0] & 0xFFF00000) >> 20);
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"card nfcu=%d datagap=%d blklen=%d\n",
+		card->uhs2_info.uhs2_cap.n_fcu,
+		card->uhs2_info.uhs2_cap.n_data_gap,
+		card->uhs2_info.uhs2_cap.max_blk_len);
+
+	/* Below capabliies only decide host */
+	card->uhs2_info.uhs2_cap.speed_range = host->uhs2_cap.speed_range;
+	/* default we use Fast Mode */
+
+	/* card support low power mode */
+	card->uhs2_info.uhs2_cap.pwr_mode = 1;
+	card->uhs2_info.uhs2_cap.retry_cnt = host->uhs2_cap.retry_cnt;
+
+	os_memset(payload, 0, sizeof(payload));
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_GEN_CAPL, FALSE, FALSE, 1,
+			    payload);
+	if (result == FALSE) {
+		DbgErr("Inquiry card gen cap failed\n");
+		goto exit;
+	}
+
+	card->uhs2_info.uhs2_cap.half_supp = (payload[0] & BIT8) ? TRUE : FALSE;
+	card->uhs2_info.uhs2_cap.lanes = ((payload[0] & 0x0E00) >> 8);
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"card halfsupp=%d lanes=%d\n",
+		card->uhs2_info.uhs2_cap.half_supp,
+		card->uhs2_info.uhs2_cap.lanes);
+
+exit:
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s result=%d\n", __func__, result);
+	return result;
+
+}
+
+static byte uhs2_get_large_lss(u32 val1, u32 val2)
+{
+	u32 v1, v2;
+	u32 v = 0;
+
+	v1 = val1;
+	v2 = val2;
+
+	if (v1 == 0)
+		v1 = 16;
+	if (v2 == 0)
+		v2 = 16;
+
+	v = os_max(v1, v2);
+	if (v == 16)
+		v = 0;
+
+	return (byte) v;
+}
+
+/*
+ * Function Name: uhs2_get_card_setting_host
+ *
+ * Abstract: This Function is used generate uhs2 card setting by card caps and host caps
+ *
+ * Input:
+ *	sd_card_t *card :
+ *			sd_host_t *host
+ *
+ */
+static void uhs2_get_card_setting_host(sd_card_t *card, sd_host_t *host)
+{
+	u16 nfcu1, nfcu2;
+	byte lanes;
+
+	card->uhs2_info.uhs2_setting.hibernate =
+	    card->uhs2_info.uhs2_cap.hibernate;
+	card->uhs2_info.uhs2_setting.n_lss_dir =
+	    uhs2_get_large_lss(card->uhs2_info.uhs2_cap.n_lss_dir,
+			       host->uhs2_cap.n_lss_dir);
+	card->uhs2_info.uhs2_setting.n_lss_syn =
+	    uhs2_get_large_lss(card->uhs2_info.uhs2_cap.n_lss_syn,
+			       host->uhs2_cap.n_lss_syn);
+
+	card->uhs2_info.uhs2_setting.n_data_gap =
+	    os_max(card->uhs2_info.uhs2_cap.n_data_gap,
+		   host->uhs2_cap.n_data_gap);
+	card->uhs2_info.uhs2_setting.max_blk_len = 0x200;
+
+	nfcu1 = card->uhs2_info.uhs2_cap.n_fcu;
+	nfcu2 = host->uhs2_cap.n_fcu;
+	if (nfcu1 == 0)
+		nfcu1 = 256;
+	if (nfcu2 == 0)
+		nfcu2 = 256;
+	card->uhs2_info.uhs2_setting.n_fcu =
+	    (nfcu1 >
+	     nfcu2) ? host->uhs2_cap.n_fcu : card->uhs2_info.uhs2_cap.n_fcu;
+
+	card->uhs2_info.uhs2_setting.speed_range =
+	    card->uhs2_info.uhs2_cap.speed_range;
+	card->uhs2_info.uhs2_setting.pwr_mode = 0;
+	card->uhs2_info.uhs2_setting.retry_cnt = host->uhs2_cap.retry_cnt;
+
+	card->uhs2_info.uhs2_setting.half_supp =
+	    os_min(card->uhs2_info.uhs2_cap.half_supp,
+		   (host->uhs2_cap.num_of_lane & 0x1));
+	card->uhs2_info.uhs2_setting.lanes =
+	    card->uhs2_info.uhs2_cap.lanes & host->uhs2_cap.num_of_lane;
+
+	lanes = card->uhs2_info.uhs2_setting.lanes;
+
+	if (lanes & UHS2_LANES_2D2UFD)
+		lanes = UHS2_LANES_2D2UFD;
+	else if (lanes & UHS2_LANES_1D2UFD)
+		lanes = UHS2_LANES_1D2UFD;
+	else if (lanes & UHS2_LANES_2D1UFD)
+		lanes = UHS2_LANES_2D1UFD;
+	else
+		lanes = UHS2_LANES_2L_HD;
+	card->uhs2_info.uhs2_setting.lanes = lanes;
+}
+
+/*
+ * Function Name: uhs2_get_card_setting_host
+ *
+ * Abstract: This Function is used generate uhs2 card setting by vendor setting
+ *
+ * Input:
+ *			sd_card_t *card :
+ *	sd_host_t *host
+ *
+ */
+static void uhs2_update_card_setting_vendor(sd_card_t *card, sd_host_t *host)
+{
+	u16 nfcu1, nfcu2;
+	cfg_uhs2_setting_t *cfg = &host->cfg->card_item.uhs2_setting;
+
+	card->uhs2_info.uhs2_setting.n_lss_dir =
+	    uhs2_get_large_lss(card->uhs2_info.uhs2_setting.n_lss_dir,
+			       cfg->min_lss_dir);
+	card->uhs2_info.uhs2_setting.n_lss_syn =
+	    uhs2_get_large_lss(card->uhs2_info.uhs2_setting.n_lss_syn,
+			       cfg->min_lss_syn);
+
+	card->uhs2_info.uhs2_setting.n_data_gap =
+	    os_max(card->uhs2_info.uhs2_setting.n_data_gap,
+		   cfg->min_data_gap_sel);
+
+	nfcu1 = (u16) card->uhs2_info.uhs2_setting.n_fcu;
+	nfcu2 = (u16) cfg->max_nfcn_sel;
+	if (nfcu1 == 0)
+		nfcu1 = 256;
+	if (nfcu2 == 0)
+		nfcu2 = 256;
+	card->uhs2_info.uhs2_setting.n_fcu =
+	    (nfcu1 >
+	     nfcu2) ? cfg->max_nfcn_sel : card->uhs2_info.uhs2_setting.n_fcu;
+
+	card->uhs2_info.uhs2_setting.speed_range =
+	    os_min(card->uhs2_info.uhs2_setting.speed_range,
+		   cfg->max_speed_range_sel);
+	card->uhs2_info.uhs2_setting.pwr_mode = (byte) cfg->fast_low_pwr_sel;
+
+	card->uhs2_info.uhs2_setting.half_supp =
+	    os_min(card->uhs2_info.uhs2_cap.half_supp, cfg->half_full_sel);
+
+}
+
+/*
+ * Function Name: uhs2_update_card_setting_degrade
+ *
+ * Abstract: This Function is used generate uhs2 card setting by degrade info
+ *
+ * Input:
+ *			sd_card_t *card :
+ *			sd_host_t *host
+ *
+ */
+static void uhs2_update_card_setting_degrade(sd_card_t *card)
+{
+	if (card->degrade_uhs2_range)
+		card->uhs2_info.uhs2_setting.speed_range = 0;
+}
+
+/*
+ * Function Name: uhs2_update_card_setting_thermal
+ *
+ * Abstract: This Function is used generate uhs2 card setting by degrade info
+ *
+ * Input:
+ *			sd_card_t *card :
+ *			sd_host_t *host
+ *
+ */
+static void uhs2_update_card_setting_thermal(sd_card_t *card)
+{
+
+	if (card->thermal_enable == 0)
+		return;
+}
+
+/*
+ * Function Name: uhs2_cfg_set_card
+ *
+ * Abstract: This Function is used to set card's configuration
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *			sd_command_t *sd_cmd,
+ *
+ * Return value:
+ *			If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *			otherwize reutrn FALSE
+ */
+static bool uhs2_cfg_set_card(sd_card_t *card, sd_command_t *sd_cmd,
+			      sd_host_t *host)
+{
+	u32 payload[2];
+	bool result = FALSE;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Set device Phy Setting register */
+	os_memset(payload, 0, sizeof(payload));
+	payload[0] = (card->uhs2_info.uhs2_setting.speed_range << 6);
+	payload[1] = (card->uhs2_info.uhs2_setting.n_lss_syn) |
+	    (card->uhs2_info.uhs2_setting.n_lss_dir << 4);
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_PHY_SETL, FALSE, TRUE, 2,
+			    payload);
+	if (result == FALSE) {
+		DbgErr("set uhs2 cfg phy setting failed ret\n");
+		goto exit;
+	}
+
+	/* Set device Link and trans registers */
+	os_memset(payload, 0, sizeof(payload));
+	payload[0] = (card->uhs2_info.uhs2_setting.n_fcu << 8) |
+	    (card->uhs2_info.uhs2_setting.retry_cnt << 16) |
+	    (card->uhs2_info.uhs2_setting.max_blk_len << 20);
+	payload[1] = (card->uhs2_info.uhs2_setting.n_data_gap);
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_LINKT_SETL, FALSE, TRUE,
+			    2, payload);
+	if (result == FALSE) {
+		DbgErr("set uhs2 cfg linktran setting failed\n");
+		goto exit;
+	}
+
+	/* Set device general setting registers */
+	os_memset(payload, 0, sizeof(payload));
+	payload[0] = (card->uhs2_info.uhs2_setting.pwr_mode) |
+	    (card->uhs2_info.uhs2_setting.lanes << 8);
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_GEN_SETL, FALSE, TRUE, 1,
+			    payload);
+	if (result == FALSE) {
+		DbgErr("set uhs2 cfg gen setting failed ret\n");
+		goto exit;
+	}
+
+	/* Set device to active status */
+	os_memset(payload, 0, sizeof(payload));
+	/* Set config complete      */
+	payload[0] = BIT31;
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_GEN_SETH, FALSE, TRUE, 1,
+			    payload);
+	if (result == FALSE) {
+		DbgErr("set uhs2 cfg set active failed\n");
+		return result;
+	}
+
+exit:
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_enter_dmt
+ *
+ * Abstract: This Function is used to
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *			otherwize reutrn FALSE
+ */
+bool uhs2_enter_dmt(sd_card_t *card, sd_command_t *sd_cmd, sd_host_t *host,
+		    bool hbr)
+{
+	bool result = FALSE;
+	u32 payload = hbr ? UHS2_GODRM_HBNEN : 0;
+	byte retry_cnt = 2;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT | FEATURE_CARD_OPS,
+		NOT_TO_RAM, "Enter %s\n", __func__);
+retry:
+	retry_cnt--;
+	result =
+	    uhs2_native_ccmd(card, sd_cmd, UHS2_IOADDR_GODMT, FALSE, TRUE, 1,
+			     &payload);
+	if (result == FALSE) {
+		if (retry_cnt > 0) {
+			if (uhs2_is_uncoverable(sd_cmd))
+				goto exit;
+
+			result = uhs2_trans_abort(card, sd_cmd);
+			if (result == FALSE)
+				goto exit;
+			goto retry;
+		}
+		goto exit;
+	}
+	result = host_uhs2_go_dmt(host, hbr);
+
+exit:
+	if (result == FALSE)
+		DbgErr("UHS2 go dmt failed hbr=%d\n", hbr);
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT | FEATURE_CARD_OPS,
+		NOT_TO_RAM, "Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_resume_dmt
+ * Abstract: This Function is used to
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *
+ * Return value:
+ *			If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+bool uhs2_resume_dmt(sd_card_t *card, sd_command_t *sd_cmd, sd_host_t *host,
+		     bool hbr)
+{
+	return host_uhs2_resume_dmt(host, hbr);
+}
+
+/*
+ * Function Name: uhs2_card_configuration
+ *
+ * Abstract: This Function is used to
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+bool uhs2_card_configuration(sd_card_t *card, sd_command_t *sd_cmd,
+			     sd_host_t *host)
+{
+	bool result = FALSE;
+	uhs2_info_t info;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	result = uhs2_cfg_set_card(card, sd_cmd, host);
+	if (result == FALSE)
+		goto exit;
+
+	os_memcpy(&info, &card->uhs2_info.uhs2_setting, sizeof(uhs2_info_t));
+	info.speed_range = 0;
+	info.lanes = 0;
+
+	host_uhs2_cfg_set(host, &info, FALSE);
+
+	if (card->uhs2_info.uhs2_setting.lanes == 0
+	    && card->uhs2_info.uhs2_setting.speed_range == 0)
+		goto exit;
+
+	result = uhs2_enter_dmt(card, sd_cmd, host, FALSE);
+	if (result == FALSE)
+		goto exit;
+
+	info.speed_range = card->uhs2_info.uhs2_setting.speed_range;
+	info.lanes = card->uhs2_info.uhs2_setting.lanes;
+	host_uhs2_cfg_set(host, &info, TRUE);
+
+	result = uhs2_resume_dmt(card, sd_cmd, host, FALSE);
+	if (result == FALSE)
+		goto exit;
+
+exit:
+	if (result == FALSE)
+		DbgErr("UHS2 card configuration failed\n");
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+bool uhs2_init_stage2(sd_card_t *card)
+{
+
+	bool result = FALSE;
+	sd_command_t sd_cmd;
+
+	/* Init stage always do pm setting */
+	bool bchg = TRUE;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+	os_memset(&sd_cmd, 0, sizeof(sd_command_t));
+
+	result = sd_init_get_info(card);
+	if (result == FALSE) {
+		DbgErr("SD Card get info failed\n");
+		goto exit;
+	}
+
+	if (card_need_get_info(card)) {
+		result = sd_switch_function_check(card, &sd_cmd);
+		if (!result) {
+			DbgErr("uhs2 swich function check failed.\n");
+			goto exit;
+		}
+	}
+
+	/* 14. Swich function check/set */
+
+	{
+		/*
+		 * 14.2 Swich function check set.
+		 * - Driver Strength,
+		 * - Access Mode,
+		 * - Power Limit
+		 * - Change clock freq
+		 */
+		result = sd_switch_power_limit(card, &sd_cmd, &bchg);
+		if (result == FALSE) {
+			DbgErr("uhs2 switch power limit failed\n");
+			goto exit;
+		}
+
+	}
+exit:
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_card_init
+ *
+ * Abstract: This Function is used init uhs2 card
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *			otherwize reutrn FALSE
+ */
+bool uhs2_card_init(sd_card_t *card)
+{
+	bool result = FALSE;
+	sd_command_t sd_cmd;
+	sd_host_t *host = card->host;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM, "Enter %s\n",
+		__func__);
+
+	/* Try to init as UHS2 card */
+	card->card_type = CARD_UHS2;
+	result = uhs2_devinit_flow(card, &sd_cmd, host);
+	if (result == FALSE)
+		goto exit;
+
+	/* do enumeration */
+	result = uhs2_dev_enumeration(card, &sd_cmd);
+	if (result == FALSE)
+		goto exit;
+
+	if (card_need_get_info(card)) {
+		/* Get card capabilities */
+		result = uhs2_card_get_caps(card, &sd_cmd, host);
+		if (result == FALSE)
+			goto exit;
+
+	}
+
+	uhs2_get_card_setting_host(card, host);
+	uhs2_update_card_setting_vendor(card, host);
+	uhs2_update_card_setting_degrade(card);
+	uhs2_update_card_setting_thermal(card);
+
+	result = uhs2_card_configuration(card, &sd_cmd, host);
+	if (result == FALSE)
+		goto exit;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, TO_RAM,
+		"uhs2 setting n_fcu=%d lss_dir=%d lss_syn=%d datagap=%d\n",
+		card->uhs2_info.uhs2_setting.n_fcu,
+		card->uhs2_info.uhs2_setting.n_lss_dir,
+		card->uhs2_info.uhs2_setting.n_lss_syn,
+		card->uhs2_info.uhs2_setting.n_data_gap);
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, TO_RAM,
+		"uhs2 Setting range=%d half=%d lpm=%d\n",
+		card->uhs2_info.uhs2_setting.speed_range,
+		card->uhs2_info.uhs2_setting.half_supp,
+		card->uhs2_info.uhs2_setting.pwr_mode);
+
+	result = sd_card_identify(card);
+	if (result == FALSE)
+		goto exit;
+
+	result = sd_card_select(card);
+	if (result == FALSE)
+		goto exit;
+
+	if (card->locked == TRUE) {
+		DbgWarn(MODULE_UHS2_CARD, NOT_TO_RAM, "uhs2 card is locked\n");
+		goto exit;
+	}
+
+	result = card_init_stage2(card);
+	if (result == FALSE) {
+		DbgErr("SD init stage 2 failed.\n");
+		goto exit;
+	}
+
+exit:
+	if (result == FALSE)
+		DbgErr("UHS2 card init failed\n");
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_degrade_policy
+ *
+ * Abstract: This Function is used set uhs2 degrade flag
+ *
+ * Input:
+ *	sd_card_t *card : The Command will send to which  Card
+ *  sd_command_t *sd_cmd
+ *
+ * Return value:
+ *  If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *			otherwize reutrn FALSE
+ */
+void uhs2_degrade_policy(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	if (card->degrade_freq_level < CARD_DEGRADE_FREQ_TIMES) {
+		card->degrade_freq_level++;
+		goto exit;
+	}
+
+	if (sd_cmd != NULL && card->uhs2_info.uhs2_setting.half_supp
+	    && (card->degrade_uhs2_half == 0)) {
+		card->degrade_uhs2_half = 1;
+		goto exit;
+	}
+
+	if (card->degrade_uhs2_range == 0
+	    && card->uhs2_info.uhs2_setting.speed_range) {
+		card->degrade_uhs2_range = 1;
+		goto exit;
+	}
+
+	card->degrade_uhs2_legacy = 1;
+	card->quick_init = 0;
+	card->card_type = CARD_NONE;
+	card->degrade_freq_level = 0;
+
+exit:
+	DbgErr("UHS2 degrade range=%d freq_level=%d half=%d legacy=%d\n",
+	       card->degrade_uhs2_range, card->degrade_freq_level,
+	       card->degrade_uhs2_half, card->degrade_uhs2_legacy);
+}
+
+static bool uhs2_read_status_reg(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	u32 payload = 0;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s\n", __func__);
+
+	result =
+	    uhs2_access_reg(card, sd_cmd, UHS2_IOADDR_ST_REG, FALSE, FALSE, 1,
+			    &payload);
+
+	if (result == FALSE)
+		DbgErr("uhs2 read status reg failed\n");
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+/*
+ * Function Name: uhs2_sd_error_recovery
+ *
+ * Abstract: This Function is used do error recovery for uhs2
+ *
+ * Input:
+ *			sd_card_t *card : The Command will send to which  Card
+ *  sd_command_t *sd_cmd
+ *
+ * Return value:
+ *	If the routine succeeds, it must return TRUE, and fill trans_reg_t  part.
+ *	otherwize reutrn FALSE
+ */
+
+bool uhs2_sd_error_recovery(sd_card_t *card, sd_command_t *sd_cmd)
+{
+	bool result = FALSE;
+	sd_command_t recover_cmd;
+
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Enter %s\n", __func__);
+
+	if (sd_cmd == NULL)
+		goto exit;
+
+	/* If uncoverable do fullreset recover directly */
+	if (uhs2_is_uncoverable(sd_cmd))
+		goto full_reset;
+
+	host_uhs2_reset(card->host, FALSE);
+
+	/* do sd-tran */
+	result = uhs2_trans_abort(card, &recover_cmd);
+	if (result == FALSE)
+		goto full_reset;
+
+	result = uhs2_read_status_reg(card, &recover_cmd);
+	if (result == FALSE)
+		goto full_reset;
+
+	/* send cmd12 and check whether */
+	card_send_command12(card, &recover_cmd);
+	if (recover_cmd.uhs2_nack != 0)
+		goto full_reset;
+
+	result = card_check_rw_ready(card, &recover_cmd, 150);
+	if (result == FALSE)
+		goto full_reset;
+
+	goto exit;
+
+full_reset:
+	DbgErr("Do Full reset uhs2 recovery\n");
+	host_uhs2_reset(card->host, FALSE);
+	result = uhs2_full_reset_card(card);
+	if (result)
+		result = card_init(card, 1, TRUE);
+
+exit:
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_ERROR_RECOVER, NOT_TO_RAM,
+		"Exit %s ret=%d\n", __func__, result);
+	return result;
+}
+
+u32 card_get_uhs2_freq(sd_card_t *card)
+{
+	sd_host_t *host = card->host;
+	/* cfg_max_freq_item_t  *freq = &(host->cfg->host_item.max_freq_item); */
+	u16 index = 0;
+	u32 value;
+
+	if (host->cfg == NULL || host->cfg->dmdn_tbl == NULL) {
+		DbgErr("host cfg is null\n");
+		return 0;
+	}
+
+	index = (u16) FREQ_UHS2M_START_INDEX + card->degrade_freq_level;
+	if (index > (u16) FREQ_UHS2M_DEGRE_INDEX)
+		index = (u16) FREQ_UHS2M_DEGRE_INDEX;
+	value = host->cfg->dmdn_tbl[index];
+	DbgInfo(MODULE_UHS2_CARD, FEATURE_CARD_INIT, NOT_TO_RAM,
+		"Get Uhs2 Dmdn=0x%08X\n", value);
+
+	return value;
+}
-- 
2.34.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ