[PATCH 3/9] scsi: bht: card: Add the source files related to card initialization
From: liuchang_125125
Date: Fri Oct 13 2023 - 04:34:00 EST
From: Charl Liu <liuchang_125125@xxxxxxx>
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@xxxxxxx>
---
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