mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
![Colin Ian King](/assets/img/avatar_default.png)
The retval status checks in the proceeding do loop return out of function ms_read_attritbute_info if there is an error condition, thus we never reach the end of the loop with retval failed status. Therefore, the retval status check at end of the do loop is redundant and can be removed. Detected with CoverityScan, CID#143000 ("Logically dead code") Signed-off-by: Colin Ian King <colin.king@canonical.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
4829 lines
108 KiB
C
4829 lines
108 KiB
C
/* Driver for Realtek PCI-Express card reader
|
|
*
|
|
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author:
|
|
* Wei WANG (wei_wang@realsil.com.cn)
|
|
* Micky Ching (micky_ching@realsil.com.cn)
|
|
*/
|
|
|
|
#include <linux/blkdev.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include "rtsx.h"
|
|
#include "ms.h"
|
|
|
|
static inline void ms_set_err_code(struct rtsx_chip *chip, u8 err_code)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
|
|
ms_card->err_code = err_code;
|
|
}
|
|
|
|
static inline int ms_check_err_code(struct rtsx_chip *chip, u8 err_code)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
|
|
return (ms_card->err_code == err_code);
|
|
}
|
|
|
|
static int ms_parse_err_code(struct rtsx_chip *chip)
|
|
{
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
static int ms_transfer_tpc(struct rtsx_chip *chip, u8 trans_mode,
|
|
u8 tpc, u8 cnt, u8 cfg)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
u8 *ptr;
|
|
|
|
dev_dbg(rtsx_dev(chip), "%s: tpc = 0x%x\n", __func__, tpc);
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
|
0x01, PINGPONG_BUFFER);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER,
|
|
0xFF, MS_TRANSFER_START | trans_mode);
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
|
|
MS_TRANSFER_END, MS_TRANSFER_END);
|
|
|
|
rtsx_add_cmd(chip, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
|
|
|
|
retval = rtsx_send_cmd(chip, MS_CARD, 5000);
|
|
if (retval < 0) {
|
|
rtsx_clear_ms_error(chip);
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
|
|
ptr = rtsx_get_cmd_data(chip) + 1;
|
|
|
|
if (!(tpc & 0x08)) { /* Read Packet */
|
|
if (*ptr & MS_CRC16_ERR) {
|
|
ms_set_err_code(chip, MS_CRC16_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
} else { /* Write Packet */
|
|
if (CHK_MSPRO(ms_card) && !(*ptr & 0x80)) {
|
|
if (*ptr & (MS_INT_ERR | MS_INT_CMDNK)) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (*ptr & MS_RDY_TIMEOUT) {
|
|
rtsx_clear_ms_error(chip);
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode,
|
|
u8 tpc, u16 sec_cnt, u8 cfg, bool mode_2k,
|
|
int use_sg, void *buf, int buf_len)
|
|
{
|
|
int retval;
|
|
u8 val, err_code = 0;
|
|
enum dma_data_direction dir;
|
|
|
|
if (!buf || !buf_len) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (trans_mode == MS_TM_AUTO_READ) {
|
|
dir = DMA_FROM_DEVICE;
|
|
err_code = MS_FLASH_READ_ERROR;
|
|
} else if (trans_mode == MS_TM_AUTO_WRITE) {
|
|
dir = DMA_TO_DEVICE;
|
|
err_code = MS_FLASH_WRITE_ERROR;
|
|
} else {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
MS_SECTOR_CNT_H, 0xFF, (u8)(sec_cnt >> 8));
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_SECTOR_CNT_L, 0xFF, (u8)sec_cnt);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
|
|
|
|
if (mode_2k) {
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
MS_CFG, MS_2K_SECTOR_MODE, MS_2K_SECTOR_MODE);
|
|
} else {
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_CFG, MS_2K_SECTOR_MODE, 0);
|
|
}
|
|
|
|
trans_dma_enable(dir, chip, sec_cnt * 512, DMA_512);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
MS_TRANSFER, 0xFF, MS_TRANSFER_START | trans_mode);
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD,
|
|
MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END);
|
|
|
|
rtsx_send_cmd_no_wait(chip);
|
|
|
|
retval = rtsx_transfer_data(chip, MS_CARD, buf, buf_len,
|
|
use_sg, dir, chip->mspro_timeout);
|
|
if (retval < 0) {
|
|
ms_set_err_code(chip, err_code);
|
|
if (retval == -ETIMEDOUT)
|
|
retval = STATUS_TIMEDOUT;
|
|
else
|
|
retval = STATUS_FAIL;
|
|
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_write_bytes(struct rtsx_chip *chip,
|
|
u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
|
|
if (!data || (data_len < cnt)) {
|
|
rtsx_trace(chip);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
PPBUF_BASE2 + i, 0xFF, data[i]);
|
|
}
|
|
if (cnt % 2)
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF, 0xFF);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
|
0x01, PINGPONG_BUFFER);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
MS_TRANSFER, 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES);
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD,
|
|
MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END);
|
|
|
|
retval = rtsx_send_cmd(chip, MS_CARD, 5000);
|
|
if (retval < 0) {
|
|
u8 val = 0;
|
|
|
|
rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
dev_dbg(rtsx_dev(chip), "MS_TRANS_CFG: 0x%02x\n", val);
|
|
|
|
rtsx_clear_ms_error(chip);
|
|
|
|
if (!(tpc & 0x08)) {
|
|
if (val & MS_CRC16_ERR) {
|
|
ms_set_err_code(chip, MS_CRC16_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
} else {
|
|
if (CHK_MSPRO(ms_card) && !(val & 0x80)) {
|
|
if (val & (MS_INT_ERR | MS_INT_CMDNK)) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (val & MS_RDY_TIMEOUT) {
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_read_bytes(struct rtsx_chip *chip,
|
|
u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 *ptr;
|
|
|
|
if (!data) {
|
|
rtsx_trace(chip);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
|
0x01, PINGPONG_BUFFER);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
|
|
MS_TRANSFER_START | MS_TM_READ_BYTES);
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
|
|
MS_TRANSFER_END, MS_TRANSFER_END);
|
|
|
|
for (i = 0; i < data_len - 1; i++)
|
|
rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
|
|
|
|
if (data_len % 2)
|
|
rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0);
|
|
else
|
|
rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len - 1,
|
|
0, 0);
|
|
|
|
retval = rtsx_send_cmd(chip, MS_CARD, 5000);
|
|
if (retval < 0) {
|
|
u8 val = 0;
|
|
|
|
rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
rtsx_clear_ms_error(chip);
|
|
|
|
if (!(tpc & 0x08)) {
|
|
if (val & MS_CRC16_ERR) {
|
|
ms_set_err_code(chip, MS_CRC16_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
} else {
|
|
if (CHK_MSPRO(ms_card) && !(val & 0x80)) {
|
|
if (val & (MS_INT_ERR | MS_INT_CMDNK)) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (val & MS_RDY_TIMEOUT) {
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_trace(chip);
|
|
return ms_parse_err_code(chip);
|
|
}
|
|
|
|
ptr = rtsx_get_cmd_data(chip) + 1;
|
|
|
|
for (i = 0; i < data_len; i++)
|
|
data[i] = ptr[i];
|
|
|
|
if ((tpc == PRO_READ_SHORT_DATA) && (data_len == 8)) {
|
|
dev_dbg(rtsx_dev(chip), "Read format progress:\n");
|
|
print_hex_dump_bytes(KBUILD_MODNAME ": ", DUMP_PREFIX_NONE, ptr,
|
|
cnt);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_set_rw_reg_addr(struct rtsx_chip *chip, u8 read_start,
|
|
u8 read_cnt, u8 write_start, u8 write_cnt)
|
|
{
|
|
int retval, i;
|
|
u8 data[4];
|
|
|
|
data[0] = read_start;
|
|
data[1] = read_cnt;
|
|
data[2] = write_start;
|
|
data[3] = write_cnt;
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, SET_RW_REG_ADRS, 4,
|
|
NO_WAIT_INT, data, 4);
|
|
if (retval == STATUS_SUCCESS)
|
|
return STATUS_SUCCESS;
|
|
rtsx_clear_ms_error(chip);
|
|
}
|
|
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
static int ms_send_cmd(struct rtsx_chip *chip, u8 cmd, u8 cfg)
|
|
{
|
|
u8 data[2];
|
|
|
|
data[0] = cmd;
|
|
data[1] = 0;
|
|
|
|
return ms_write_bytes(chip, PRO_SET_CMD, 1, cfg, data, 1);
|
|
}
|
|
|
|
static int ms_set_init_para(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
|
|
if (CHK_HG8BIT(ms_card)) {
|
|
if (chip->asic_code)
|
|
ms_card->ms_clock = chip->asic_ms_hg_clk;
|
|
else
|
|
ms_card->ms_clock = chip->fpga_ms_hg_clk;
|
|
|
|
} else if (CHK_MSPRO(ms_card) || CHK_MS4BIT(ms_card)) {
|
|
if (chip->asic_code)
|
|
ms_card->ms_clock = chip->asic_ms_4bit_clk;
|
|
else
|
|
ms_card->ms_clock = chip->fpga_ms_4bit_clk;
|
|
|
|
} else {
|
|
if (chip->asic_code)
|
|
ms_card->ms_clock = chip->asic_ms_1bit_clk;
|
|
else
|
|
ms_card->ms_clock = chip->fpga_ms_1bit_clk;
|
|
}
|
|
|
|
retval = switch_clock(chip, ms_card->ms_clock);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = select_card(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_switch_clock(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
|
|
retval = select_card(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = switch_clock(chip, ms_card->ms_clock);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_pull_ctl_disable(struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
|
|
if (CHECK_PID(chip, 0x5208)) {
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF,
|
|
MS_D1_PD | MS_D2_PD | MS_CLK_PD |
|
|
MS_D6_PD);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF,
|
|
MS_D3_PD | MS_D0_PD | MS_BS_PD |
|
|
XD_D4_PD);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF,
|
|
MS_D7_PD | XD_CE_PD | XD_CLE_PD |
|
|
XD_CD_PU);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF,
|
|
XD_RDY_PD | SD_D3_PD | SD_D2_PD |
|
|
XD_ALE_PD);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF,
|
|
MS_INS_PU | SD_WP_PD | SD_CD_PU |
|
|
SD_CMD_PD);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF,
|
|
MS_D5_PD | MS_D4_PD);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
} else if (CHECK_PID(chip, 0x5288)) {
|
|
if (CHECK_BARO_PKG(chip, QFN)) {
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL1,
|
|
0xFF, 0x55);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL2,
|
|
0xFF, 0x55);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL3,
|
|
0xFF, 0x4B);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_PULL_CTL4,
|
|
0xFF, 0x69);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_pull_ctl_enable(struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
if (CHECK_PID(chip, 0x5208)) {
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF,
|
|
MS_D1_PD | MS_D2_PD | MS_CLK_NP | MS_D6_PD);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF,
|
|
MS_D3_PD | MS_D0_PD | MS_BS_NP | XD_D4_PD);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF,
|
|
MS_D7_PD | XD_CE_PD | XD_CLE_PD | XD_CD_PU);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF,
|
|
XD_RDY_PD | SD_D3_PD | SD_D2_PD | XD_ALE_PD);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF,
|
|
MS_INS_PU | SD_WP_PD | SD_CD_PU | SD_CMD_PD);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF,
|
|
MS_D5_PD | MS_D4_PD);
|
|
} else if (CHECK_PID(chip, 0x5288)) {
|
|
if (CHECK_BARO_PKG(chip, QFN)) {
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
CARD_PULL_CTL1, 0xFF, 0x55);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
CARD_PULL_CTL2, 0xFF, 0x45);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
CARD_PULL_CTL3, 0xFF, 0x4B);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD,
|
|
CARD_PULL_CTL4, 0xFF, 0x29);
|
|
}
|
|
}
|
|
|
|
retval = rtsx_send_cmd(chip, MS_CARD, 100);
|
|
if (retval < 0) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_prepare_reset(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
u8 oc_mask = 0;
|
|
|
|
ms_card->ms_type = 0;
|
|
ms_card->check_ms_flow = 0;
|
|
ms_card->switch_8bit_fail = 0;
|
|
ms_card->delay_write.delay_write_flag = 0;
|
|
|
|
ms_card->pro_under_formatting = 0;
|
|
|
|
retval = ms_power_off_card3v3(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (!chip->ft2_fast_mode)
|
|
wait_timeout(250);
|
|
|
|
retval = enable_card_clock(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (chip->asic_code) {
|
|
retval = ms_pull_ctl_enable(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
|
|
FPGA_MS_PULL_CTL_BIT | 0x20, 0);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
if (!chip->ft2_fast_mode) {
|
|
retval = card_power_on(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
wait_timeout(150);
|
|
|
|
#ifdef SUPPORT_OCP
|
|
if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
|
|
oc_mask = MS_OC_NOW | MS_OC_EVER;
|
|
else
|
|
oc_mask = SD_OC_NOW | SD_OC_EVER;
|
|
|
|
if (chip->ocp_stat & oc_mask) {
|
|
dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n",
|
|
chip->ocp_stat);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN,
|
|
MS_OUTPUT_EN);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
if (chip->asic_code) {
|
|
retval = rtsx_write_register(chip, MS_CFG, 0xFF,
|
|
SAMPLE_TIME_RISING |
|
|
PUSH_TIME_DEFAULT |
|
|
NO_EXTEND_TOGGLE |
|
|
MS_BUS_WIDTH_1);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
} else {
|
|
retval = rtsx_write_register(chip, MS_CFG, 0xFF,
|
|
SAMPLE_TIME_FALLING |
|
|
PUSH_TIME_DEFAULT |
|
|
NO_EXTEND_TOGGLE |
|
|
MS_BUS_WIDTH_1);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
}
|
|
retval = rtsx_write_register(chip, MS_TRANS_CFG, 0xFF,
|
|
NO_WAIT_INT | NO_AUTO_READ_INT_REG);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR,
|
|
MS_STOP | MS_CLR_ERR);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
retval = ms_set_init_para(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 val;
|
|
|
|
retval = ms_set_rw_reg_addr(chip, Pro_StatusReg, 6, SystemParm, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG,
|
|
6, NO_WAIT_INT);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, PPBUF_BASE2 + 2, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
dev_dbg(rtsx_dev(chip), "Type register: 0x%x\n", val);
|
|
if (val != 0x01) {
|
|
if (val != 0x02)
|
|
ms_card->check_ms_flow = 1;
|
|
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, PPBUF_BASE2 + 4, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
dev_dbg(rtsx_dev(chip), "Category register: 0x%x\n", val);
|
|
if (val != 0) {
|
|
ms_card->check_ms_flow = 1;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, PPBUF_BASE2 + 5, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
dev_dbg(rtsx_dev(chip), "Class register: 0x%x\n", val);
|
|
if (val == 0) {
|
|
retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
if (val & WRT_PRTCT)
|
|
chip->card_wp |= MS_CARD;
|
|
else
|
|
chip->card_wp &= ~MS_CARD;
|
|
|
|
} else if ((val == 0x01) || (val == 0x02) || (val == 0x03)) {
|
|
chip->card_wp |= MS_CARD;
|
|
} else {
|
|
ms_card->check_ms_flow = 1;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_card->ms_type |= TYPE_MSPRO;
|
|
|
|
retval = rtsx_read_register(chip, PPBUF_BASE2 + 3, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
dev_dbg(rtsx_dev(chip), "IF Mode register: 0x%x\n", val);
|
|
if (val == 0) {
|
|
ms_card->ms_type &= 0x0F;
|
|
} else if (val == 7) {
|
|
if (switch_8bit_bus)
|
|
ms_card->ms_type |= MS_HG;
|
|
else
|
|
ms_card->ms_type &= 0x0F;
|
|
|
|
} else {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_confirm_cpu_startup(struct rtsx_chip *chip)
|
|
{
|
|
int retval, i, k;
|
|
u8 val;
|
|
|
|
/* Confirm CPU StartUp */
|
|
k = 0;
|
|
do {
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_NO_CARD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_read_bytes(chip, GET_INT, 1,
|
|
NO_WAIT_INT, &val, 1);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (k > 100) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
k++;
|
|
wait_timeout(100);
|
|
} while (!(val & INT_REG_CED));
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_ERR) {
|
|
if (val & INT_REG_CMDNK) {
|
|
chip->card_wp |= (MS_CARD);
|
|
} else {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
/* -- end confirm CPU startup */
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_switch_parallel_bus(struct rtsx_chip *chip)
|
|
{
|
|
int retval, i;
|
|
u8 data[2];
|
|
|
|
data[0] = PARALLEL_4BIT_IF;
|
|
data[1] = 0;
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, WRITE_REG, 1, NO_WAIT_INT,
|
|
data, 2);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_switch_8bit_bus(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 data[2];
|
|
|
|
data[0] = PARALLEL_8BIT_IF;
|
|
data[1] = 0;
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, WRITE_REG, 1,
|
|
NO_WAIT_INT, data, 2);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_write_register(chip, MS_CFG, 0x98,
|
|
MS_BUS_WIDTH_8 | SAMPLE_TIME_FALLING);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
ms_card->ms_type |= MS_8BIT;
|
|
retval = ms_set_init_para(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT,
|
|
1, NO_WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
|
|
for (i = 0; i < 3; i++) {
|
|
retval = ms_prepare_reset(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_identify_media_type(chip, switch_8bit_bus);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_confirm_cpu_startup(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_switch_parallel_bus(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_NO_CARD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
/* Switch MS-PRO into Parallel mode */
|
|
retval = rtsx_write_register(chip, MS_CFG, 0x18, MS_BUS_WIDTH_4);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, MS_CFG, PUSH_TIME_ODD,
|
|
PUSH_TIME_ODD);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
retval = ms_set_init_para(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
/* If MSPro HG Card, We shall try to switch to 8-bit bus */
|
|
if (CHK_MSHG(ms_card) && chip->support_ms_8bit && switch_8bit_bus) {
|
|
retval = ms_switch_8bit_bus(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->switch_8bit_fail = 1;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#ifdef XC_POWERCLASS
|
|
static int msxc_change_power(struct rtsx_chip *chip, u8 mode)
|
|
{
|
|
int retval;
|
|
u8 buf[6];
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
buf[0] = 0;
|
|
buf[1] = mode;
|
|
buf[2] = 0;
|
|
buf[3] = 0;
|
|
buf[4] = 0;
|
|
buf[5] = 0;
|
|
|
|
retval = ms_write_bytes(chip, PRO_WRITE_REG, 6, NO_WAIT_INT, buf, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, XC_CHG_POWER, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, buf);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR)) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
static int ms_read_attribute_info(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 val, *buf, class_code, device_type, sub_class, data[16];
|
|
u16 total_blk = 0, blk_size = 0;
|
|
#ifdef SUPPORT_MSXC
|
|
u32 xc_total_blk = 0, xc_blk_size = 0;
|
|
#endif
|
|
u32 sys_info_addr = 0, sys_info_size;
|
|
#ifdef SUPPORT_PCGL_1P18
|
|
u32 model_name_addr = 0, model_name_size;
|
|
int found_sys_info = 0, found_model_name = 0;
|
|
#endif
|
|
|
|
retval = ms_set_rw_reg_addr(chip, Pro_IntReg, 2, Pro_SystemParm, 7);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (CHK_MS8BIT(ms_card))
|
|
data[0] = PARALLEL_8BIT_IF;
|
|
else
|
|
data[0] = PARALLEL_4BIT_IF;
|
|
|
|
data[1] = 0;
|
|
|
|
data[2] = 0x40;
|
|
data[3] = 0;
|
|
data[4] = 0;
|
|
data[5] = 0;
|
|
data[6] = 0;
|
|
data[7] = 0;
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, PRO_WRITE_REG, 7, NO_WAIT_INT,
|
|
data, 8);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
buf = kmalloc(64 * 512, GFP_KERNEL);
|
|
if (!buf) {
|
|
rtsx_trace(chip);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_send_cmd(chip, PRO_READ_ATRB, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS)
|
|
continue;
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
if (retval != STATUS_SUCCESS) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (!(val & MS_INT_BREQ)) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
retval = ms_transfer_data(chip, MS_TM_AUTO_READ,
|
|
PRO_READ_LONG_DATA, 0x40, WAIT_INT,
|
|
0, 0, buf, 64 * 512);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
|
|
rtsx_clear_ms_error(chip);
|
|
}
|
|
if (retval != STATUS_SUCCESS) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
i = 0;
|
|
do {
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
if (retval != STATUS_SUCCESS) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if ((val & MS_INT_CED) || !(val & MS_INT_BREQ))
|
|
break;
|
|
|
|
retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ,
|
|
PRO_READ_LONG_DATA, 0, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
i++;
|
|
} while (i < 1024);
|
|
|
|
if ((buf[0] != 0xa5) && (buf[1] != 0xc3)) {
|
|
/* Signature code is wrong */
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if ((buf[4] < 1) || (buf[4] > 12)) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
for (i = 0; i < buf[4]; i++) {
|
|
int cur_addr_off = 16 + i * 12;
|
|
|
|
#ifdef SUPPORT_MSXC
|
|
if ((buf[cur_addr_off + 8] == 0x10) ||
|
|
(buf[cur_addr_off + 8] == 0x13)) {
|
|
#else
|
|
if (buf[cur_addr_off + 8] == 0x10) {
|
|
#endif
|
|
sys_info_addr = ((u32)buf[cur_addr_off + 0] << 24) |
|
|
((u32)buf[cur_addr_off + 1] << 16) |
|
|
((u32)buf[cur_addr_off + 2] << 8) |
|
|
buf[cur_addr_off + 3];
|
|
sys_info_size = ((u32)buf[cur_addr_off + 4] << 24) |
|
|
((u32)buf[cur_addr_off + 5] << 16) |
|
|
((u32)buf[cur_addr_off + 6] << 8) |
|
|
buf[cur_addr_off + 7];
|
|
dev_dbg(rtsx_dev(chip), "sys_info_addr = 0x%x, sys_info_size = 0x%x\n",
|
|
sys_info_addr, sys_info_size);
|
|
if (sys_info_size != 96) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (sys_info_addr < 0x1A0) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if ((sys_info_size + sys_info_addr) > 0x8000) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
#ifdef SUPPORT_MSXC
|
|
if (buf[cur_addr_off + 8] == 0x13)
|
|
ms_card->ms_type |= MS_XC;
|
|
#endif
|
|
#ifdef SUPPORT_PCGL_1P18
|
|
found_sys_info = 1;
|
|
#else
|
|
break;
|
|
#endif
|
|
}
|
|
#ifdef SUPPORT_PCGL_1P18
|
|
if (buf[cur_addr_off + 8] == 0x15) {
|
|
model_name_addr = ((u32)buf[cur_addr_off + 0] << 24) |
|
|
((u32)buf[cur_addr_off + 1] << 16) |
|
|
((u32)buf[cur_addr_off + 2] << 8) |
|
|
buf[cur_addr_off + 3];
|
|
model_name_size = ((u32)buf[cur_addr_off + 4] << 24) |
|
|
((u32)buf[cur_addr_off + 5] << 16) |
|
|
((u32)buf[cur_addr_off + 6] << 8) |
|
|
buf[cur_addr_off + 7];
|
|
dev_dbg(rtsx_dev(chip), "model_name_addr = 0x%x, model_name_size = 0x%x\n",
|
|
model_name_addr, model_name_size);
|
|
if (model_name_size != 48) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (model_name_addr < 0x1A0) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if ((model_name_size + model_name_addr) > 0x8000) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
found_model_name = 1;
|
|
}
|
|
|
|
if (found_sys_info && found_model_name)
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
if (i == buf[4]) {
|
|
kfree(buf);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
class_code = buf[sys_info_addr + 0];
|
|
device_type = buf[sys_info_addr + 56];
|
|
sub_class = buf[sys_info_addr + 46];
|
|
#ifdef SUPPORT_MSXC
|
|
if (CHK_MSXC(ms_card)) {
|
|
xc_total_blk = ((u32)buf[sys_info_addr + 6] << 24) |
|
|
((u32)buf[sys_info_addr + 7] << 16) |
|
|
((u32)buf[sys_info_addr + 8] << 8) |
|
|
buf[sys_info_addr + 9];
|
|
xc_blk_size = ((u32)buf[sys_info_addr + 32] << 24) |
|
|
((u32)buf[sys_info_addr + 33] << 16) |
|
|
((u32)buf[sys_info_addr + 34] << 8) |
|
|
buf[sys_info_addr + 35];
|
|
dev_dbg(rtsx_dev(chip), "xc_total_blk = 0x%x, xc_blk_size = 0x%x\n",
|
|
xc_total_blk, xc_blk_size);
|
|
} else {
|
|
total_blk = ((u16)buf[sys_info_addr + 6] << 8) |
|
|
buf[sys_info_addr + 7];
|
|
blk_size = ((u16)buf[sys_info_addr + 2] << 8) |
|
|
buf[sys_info_addr + 3];
|
|
dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n",
|
|
total_blk, blk_size);
|
|
}
|
|
#else
|
|
total_blk = ((u16)buf[sys_info_addr + 6] << 8) | buf[sys_info_addr + 7];
|
|
blk_size = ((u16)buf[sys_info_addr + 2] << 8) | buf[sys_info_addr + 3];
|
|
dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n",
|
|
total_blk, blk_size);
|
|
#endif
|
|
|
|
dev_dbg(rtsx_dev(chip), "class_code = 0x%x, device_type = 0x%x, sub_class = 0x%x\n",
|
|
class_code, device_type, sub_class);
|
|
|
|
memcpy(ms_card->raw_sys_info, buf + sys_info_addr, 96);
|
|
#ifdef SUPPORT_PCGL_1P18
|
|
memcpy(ms_card->raw_model_name, buf + model_name_addr, 48);
|
|
#endif
|
|
|
|
kfree(buf);
|
|
|
|
#ifdef SUPPORT_MSXC
|
|
if (CHK_MSXC(ms_card)) {
|
|
if (class_code != 0x03) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
if (class_code != 0x02) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
#else
|
|
if (class_code != 0x02) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
|
|
if (device_type != 0x00) {
|
|
if ((device_type == 0x01) || (device_type == 0x02) ||
|
|
(device_type == 0x03)) {
|
|
chip->card_wp |= MS_CARD;
|
|
} else {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
if (sub_class & 0xC0) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
dev_dbg(rtsx_dev(chip), "class_code: 0x%x, device_type: 0x%x, sub_class: 0x%x\n",
|
|
class_code, device_type, sub_class);
|
|
|
|
#ifdef SUPPORT_MSXC
|
|
if (CHK_MSXC(ms_card)) {
|
|
chip->capacity[chip->card2lun[MS_CARD]] =
|
|
ms_card->capacity = xc_total_blk * xc_blk_size;
|
|
} else {
|
|
chip->capacity[chip->card2lun[MS_CARD]] =
|
|
ms_card->capacity = total_blk * blk_size;
|
|
}
|
|
#else
|
|
ms_card->capacity = total_blk * blk_size;
|
|
chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity;
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#ifdef SUPPORT_MAGIC_GATE
|
|
static int mg_set_tpc_para_sub(struct rtsx_chip *chip,
|
|
int type, u8 mg_entry_num);
|
|
#endif
|
|
|
|
static int reset_ms_pro(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
#ifdef XC_POWERCLASS
|
|
u8 change_power_class;
|
|
|
|
if (chip->ms_power_class_en & 0x02)
|
|
change_power_class = 2;
|
|
else if (chip->ms_power_class_en & 0x01)
|
|
change_power_class = 1;
|
|
else
|
|
change_power_class = 0;
|
|
#endif
|
|
|
|
#ifdef XC_POWERCLASS
|
|
retry:
|
|
#endif
|
|
retval = ms_pro_reset_flow(chip, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (ms_card->switch_8bit_fail) {
|
|
retval = ms_pro_reset_flow(chip, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_read_attribute_info(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
#ifdef XC_POWERCLASS
|
|
if (CHK_HG8BIT(ms_card))
|
|
change_power_class = 0;
|
|
|
|
if (change_power_class && CHK_MSXC(ms_card)) {
|
|
u8 power_class_en = chip->ms_power_class_en;
|
|
|
|
dev_dbg(rtsx_dev(chip), "power_class_en = 0x%x\n",
|
|
power_class_en);
|
|
dev_dbg(rtsx_dev(chip), "change_power_class = %d\n",
|
|
change_power_class);
|
|
|
|
if (change_power_class)
|
|
power_class_en &= (1 << (change_power_class - 1));
|
|
else
|
|
power_class_en = 0;
|
|
|
|
if (power_class_en) {
|
|
u8 power_class_mode =
|
|
(ms_card->raw_sys_info[46] & 0x18) >> 3;
|
|
dev_dbg(rtsx_dev(chip), "power_class_mode = 0x%x",
|
|
power_class_mode);
|
|
if (change_power_class > power_class_mode)
|
|
change_power_class = power_class_mode;
|
|
if (change_power_class) {
|
|
retval = msxc_change_power(chip,
|
|
change_power_class);
|
|
if (retval != STATUS_SUCCESS) {
|
|
change_power_class--;
|
|
goto retry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef SUPPORT_MAGIC_GATE
|
|
retval = mg_set_tpc_para_sub(chip, 0, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
|
|
if (CHK_HG8BIT(ms_card))
|
|
chip->card_bus_width[chip->card2lun[MS_CARD]] = 8;
|
|
else
|
|
chip->card_bus_width[chip->card2lun[MS_CARD]] = 4;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_read_status_reg(struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
u8 val[2];
|
|
|
|
retval = ms_set_rw_reg_addr(chip, StatusReg0, 2, 0, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, READ_REG, 2, NO_WAIT_INT, val, 2);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val[1] & (STS_UCDT | STS_UCEX | STS_UCFG)) {
|
|
ms_set_err_code(chip, MS_FLASH_READ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_read_extra_data(struct rtsx_chip *chip,
|
|
u16 block_addr, u8 page_num, u8 *buf, int buf_len)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 val, data[10];
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (CHK_MS4BIT(ms_card)) {
|
|
/* Parallel interface */
|
|
data[0] = 0x88;
|
|
} else {
|
|
/* Serial interface */
|
|
data[0] = 0x80;
|
|
}
|
|
data[1] = 0;
|
|
data[2] = (u8)(block_addr >> 8);
|
|
data[3] = (u8)block_addr;
|
|
data[4] = 0x40;
|
|
data[5] = page_num;
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
|
|
data, 6);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
retval = ms_read_status_reg(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
|
|
MS_EXTRA_SIZE, SystemParm,
|
|
6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, READ_REG, MS_EXTRA_SIZE, NO_WAIT_INT,
|
|
data, MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (buf && buf_len) {
|
|
if (buf_len > MS_EXTRA_SIZE)
|
|
buf_len = MS_EXTRA_SIZE;
|
|
memcpy(buf, data, buf_len);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_write_extra_data(struct rtsx_chip *chip, u16 block_addr,
|
|
u8 page_num, u8 *buf, int buf_len)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 val, data[16];
|
|
|
|
if (!buf || (buf_len < MS_EXTRA_SIZE)) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, 6 + MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(block_addr >> 8);
|
|
data[3] = (u8)block_addr;
|
|
data[4] = 0x40;
|
|
data[5] = page_num;
|
|
|
|
for (i = 6; i < MS_EXTRA_SIZE + 6; i++)
|
|
data[i] = buf[i - 6];
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
|
|
NO_WAIT_INT, data, 16);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
u8 val, data[6];
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(block_addr >> 8);
|
|
data[3] = (u8)block_addr;
|
|
data[4] = 0x20;
|
|
data[5] = page_num;
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
if (!(val & INT_REG_BREQ)) {
|
|
ms_set_err_code(chip, MS_FLASH_READ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
retval = ms_read_status_reg(chip);
|
|
if (retval != STATUS_SUCCESS)
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
|
|
} else {
|
|
if (!(val & INT_REG_BREQ)) {
|
|
ms_set_err_code(chip, MS_BREQ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA,
|
|
0, NO_WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
u8 val, data[8], extra[MS_EXTRA_SIZE];
|
|
|
|
retval = ms_read_extra_data(chip, phy_blk, 0, extra, MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, 7);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(phy_blk >> 8);
|
|
data[3] = (u8)phy_blk;
|
|
data[4] = 0x80;
|
|
data[5] = 0;
|
|
data[6] = extra[0] & 0x7F;
|
|
data[7] = 0xFF;
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 7);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i = 0;
|
|
u8 val, data[6];
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(phy_blk >> 8);
|
|
data[3] = (u8)phy_blk;
|
|
data[4] = 0;
|
|
data[5] = 0;
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ERASE_RTY:
|
|
retval = ms_send_cmd(chip, BLOCK_ERASE, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
if (i < 3) {
|
|
i++;
|
|
goto ERASE_RTY;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
ms_set_bad_block(chip, phy_blk);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static void ms_set_page_status(u16 log_blk, u8 type, u8 *extra, int extra_len)
|
|
{
|
|
if (!extra || (extra_len < MS_EXTRA_SIZE))
|
|
return;
|
|
|
|
memset(extra, 0xFF, MS_EXTRA_SIZE);
|
|
|
|
if (type == setPS_NG) {
|
|
/* set page status as 1:NG,and block status keep 1:OK */
|
|
extra[0] = 0xB8;
|
|
} else {
|
|
/* set page status as 0:Data Error,and block status keep 1:OK */
|
|
extra[0] = 0x98;
|
|
}
|
|
|
|
extra[2] = (u8)(log_blk >> 8);
|
|
extra[3] = (u8)log_blk;
|
|
}
|
|
|
|
static int ms_init_page(struct rtsx_chip *chip, u16 phy_blk, u16 log_blk,
|
|
u8 start_page, u8 end_page)
|
|
{
|
|
int retval;
|
|
u8 extra[MS_EXTRA_SIZE], i;
|
|
|
|
memset(extra, 0xff, MS_EXTRA_SIZE);
|
|
|
|
extra[0] = 0xf8; /* Block, page OK, data erased */
|
|
extra[1] = 0xff;
|
|
extra[2] = (u8)(log_blk >> 8);
|
|
extra[3] = (u8)log_blk;
|
|
|
|
for (i = start_page; i < end_page; i++) {
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_NO_CARD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_write_extra_data(chip, phy_blk, i,
|
|
extra, MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
|
|
u16 log_blk, u8 start_page, u8 end_page)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
bool uncorrect_flag = false;
|
|
int retval, rty_cnt;
|
|
u8 extra[MS_EXTRA_SIZE], val, i, j, data[16];
|
|
|
|
dev_dbg(rtsx_dev(chip), "Copy page from 0x%x to 0x%x, logical block is 0x%x\n",
|
|
old_blk, new_blk, log_blk);
|
|
dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d\n",
|
|
start_page, end_page);
|
|
|
|
retval = ms_read_extra_data(chip, new_blk, 0, extra, MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_status_reg(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
if (val & BUF_FULL) {
|
|
retval = ms_send_cmd(chip, CLEAR_BUF, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (!(val & INT_REG_CED)) {
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
for (i = start_page; i < end_page; i++) {
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_NO_CARD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_read_extra_data(chip, old_blk, i, extra, MS_EXTRA_SIZE);
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
|
|
MS_EXTRA_SIZE, SystemParm, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(old_blk >> 8);
|
|
data[3] = (u8)old_blk;
|
|
data[4] = 0x20;
|
|
data[5] = i;
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
|
|
data, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
retval = ms_read_status_reg(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
uncorrect_flag = true;
|
|
dev_dbg(rtsx_dev(chip), "Uncorrectable error\n");
|
|
} else {
|
|
uncorrect_flag = false;
|
|
}
|
|
|
|
retval = ms_transfer_tpc(chip,
|
|
MS_TM_NORMAL_READ,
|
|
READ_PAGE_DATA,
|
|
0, NO_WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (uncorrect_flag) {
|
|
ms_set_page_status(log_blk, setPS_NG,
|
|
extra,
|
|
MS_EXTRA_SIZE);
|
|
if (i == 0)
|
|
extra[0] &= 0xEF;
|
|
|
|
ms_write_extra_data(chip, old_blk, i,
|
|
extra,
|
|
MS_EXTRA_SIZE);
|
|
dev_dbg(rtsx_dev(chip), "page %d : extra[0] = 0x%x\n",
|
|
i, extra[0]);
|
|
MS_SET_BAD_BLOCK_FLG(ms_card);
|
|
|
|
ms_set_page_status(log_blk, setPS_Error,
|
|
extra,
|
|
MS_EXTRA_SIZE);
|
|
ms_write_extra_data(chip, new_blk, i,
|
|
extra,
|
|
MS_EXTRA_SIZE);
|
|
continue;
|
|
}
|
|
|
|
for (rty_cnt = 0; rty_cnt < MS_MAX_RETRY_COUNT;
|
|
rty_cnt++) {
|
|
retval = ms_transfer_tpc(
|
|
chip,
|
|
MS_TM_NORMAL_WRITE,
|
|
WRITE_PAGE_DATA,
|
|
0, NO_WAIT_INT);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (rty_cnt == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
if (!(val & INT_REG_BREQ)) {
|
|
ms_set_err_code(chip, MS_BREQ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, (6 + MS_EXTRA_SIZE));
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(new_blk >> 8);
|
|
data[3] = (u8)new_blk;
|
|
data[4] = 0x20;
|
|
data[5] = i;
|
|
|
|
if ((extra[0] & 0x60) != 0x60)
|
|
data[6] = extra[0];
|
|
else
|
|
data[6] = 0xF8;
|
|
|
|
data[6 + 1] = 0xFF;
|
|
data[6 + 2] = (u8)(log_blk >> 8);
|
|
data[6 + 3] = (u8)log_blk;
|
|
|
|
for (j = 4; j <= MS_EXTRA_SIZE; j++)
|
|
data[6 + j] = 0xFF;
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
|
|
NO_WAIT_INT, data, 16);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
if (i == 0) {
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
|
|
MS_EXTRA_SIZE, SystemParm,
|
|
7);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(old_blk >> 8);
|
|
data[3] = (u8)old_blk;
|
|
data[4] = 0x80;
|
|
data[5] = 0;
|
|
data[6] = 0xEF;
|
|
data[7] = 0xFF;
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, 7,
|
|
NO_WAIT_INT, data, 8);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_read_bytes(chip, GET_INT, 1,
|
|
NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CED) {
|
|
if (val & INT_REG_ERR) {
|
|
ms_set_err_code(chip,
|
|
MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int reset_ms(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
u16 i, reg_addr, block_size;
|
|
u8 val, extra[MS_EXTRA_SIZE], j, *ptr;
|
|
#ifndef SUPPORT_MAGIC_GATE
|
|
u16 eblock_cnt;
|
|
#endif
|
|
|
|
retval = ms_prepare_reset(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_card->ms_type |= TYPE_MS;
|
|
|
|
retval = ms_send_cmd(chip, MS_RESET, NO_WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_status_reg(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
if (val & WRT_PRTCT)
|
|
chip->card_wp |= MS_CARD;
|
|
else
|
|
chip->card_wp &= ~MS_CARD;
|
|
|
|
i = 0;
|
|
|
|
RE_SEARCH:
|
|
/* Search Boot Block */
|
|
while (i < (MAX_DEFECTIVE_BLOCK + 2)) {
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_NO_CARD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_extra_data(chip, i, 0, extra, MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS) {
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if (extra[0] & BLOCK_OK) {
|
|
if (!(extra[1] & NOT_BOOT_BLOCK)) {
|
|
ms_card->boot_block = i;
|
|
break;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (i == (MAX_DEFECTIVE_BLOCK + 2)) {
|
|
dev_dbg(rtsx_dev(chip), "No boot block found!");
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
retval = ms_read_page(chip, ms_card->boot_block, j);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) {
|
|
i = ms_card->boot_block + 1;
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
goto RE_SEARCH;
|
|
}
|
|
}
|
|
}
|
|
|
|
retval = ms_read_page(chip, ms_card->boot_block, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
/* Read MS system information as sys_info */
|
|
rtsx_init_cmd(chip);
|
|
|
|
for (i = 0; i < 96; i++)
|
|
rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 0x1A0 + i, 0, 0);
|
|
|
|
retval = rtsx_send_cmd(chip, MS_CARD, 100);
|
|
if (retval < 0) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ptr = rtsx_get_cmd_data(chip);
|
|
memcpy(ms_card->raw_sys_info, ptr, 96);
|
|
|
|
/* Read useful block contents */
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID0, 0, 0);
|
|
rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID1, 0, 0);
|
|
|
|
for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3;
|
|
reg_addr++)
|
|
rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
|
|
|
|
for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++)
|
|
rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
|
|
|
|
rtsx_add_cmd(chip, READ_REG_CMD, MS_Device_Type, 0, 0);
|
|
rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_Support, 0, 0);
|
|
|
|
retval = rtsx_send_cmd(chip, MS_CARD, 100);
|
|
if (retval < 0) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ptr = rtsx_get_cmd_data(chip);
|
|
|
|
dev_dbg(rtsx_dev(chip), "Boot block data:\n");
|
|
dev_dbg(rtsx_dev(chip), "%*ph\n", 16, ptr);
|
|
|
|
/* Block ID error
|
|
* HEADER_ID0, HEADER_ID1
|
|
*/
|
|
if (ptr[0] != 0x00 || ptr[1] != 0x01) {
|
|
i = ms_card->boot_block + 1;
|
|
goto RE_SEARCH;
|
|
}
|
|
|
|
/* Page size error
|
|
* PAGE_SIZE_0, PAGE_SIZE_1
|
|
*/
|
|
if (ptr[12] != 0x02 || ptr[13] != 0x00) {
|
|
i = ms_card->boot_block + 1;
|
|
goto RE_SEARCH;
|
|
}
|
|
|
|
if ((ptr[14] == 1) || (ptr[14] == 3))
|
|
chip->card_wp |= MS_CARD;
|
|
|
|
/* BLOCK_SIZE_0, BLOCK_SIZE_1 */
|
|
block_size = ((u16)ptr[6] << 8) | ptr[7];
|
|
if (block_size == 0x0010) {
|
|
/* Block size 16KB */
|
|
ms_card->block_shift = 5;
|
|
ms_card->page_off = 0x1F;
|
|
} else if (block_size == 0x0008) {
|
|
/* Block size 8KB */
|
|
ms_card->block_shift = 4;
|
|
ms_card->page_off = 0x0F;
|
|
}
|
|
|
|
/* BLOCK_COUNT_0, BLOCK_COUNT_1 */
|
|
ms_card->total_block = ((u16)ptr[8] << 8) | ptr[9];
|
|
|
|
#ifdef SUPPORT_MAGIC_GATE
|
|
j = ptr[10];
|
|
|
|
if (ms_card->block_shift == 4) { /* 4MB or 8MB */
|
|
if (j < 2) { /* Effective block for 4MB: 0x1F0 */
|
|
ms_card->capacity = 0x1EE0;
|
|
} else { /* Effective block for 8MB: 0x3E0 */
|
|
ms_card->capacity = 0x3DE0;
|
|
}
|
|
} else { /* 16MB, 32MB, 64MB or 128MB */
|
|
if (j < 5) { /* Effective block for 16MB: 0x3E0 */
|
|
ms_card->capacity = 0x7BC0;
|
|
} else if (j < 0xA) { /* Effective block for 32MB: 0x7C0 */
|
|
ms_card->capacity = 0xF7C0;
|
|
} else if (j < 0x11) { /* Effective block for 64MB: 0xF80 */
|
|
ms_card->capacity = 0x1EF80;
|
|
} else { /* Effective block for 128MB: 0x1F00 */
|
|
ms_card->capacity = 0x3DF00;
|
|
}
|
|
}
|
|
#else
|
|
/* EBLOCK_COUNT_0, EBLOCK_COUNT_1 */
|
|
eblock_cnt = ((u16)ptr[10] << 8) | ptr[11];
|
|
|
|
ms_card->capacity = ((u32)eblock_cnt - 2) << ms_card->block_shift;
|
|
#endif
|
|
|
|
chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity;
|
|
|
|
/* Switch I/F Mode */
|
|
if (ptr[15]) {
|
|
retval = ms_set_rw_reg_addr(chip, 0, 0, SystemParm, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_write_register(chip, PPBUF_BASE2, 0xFF, 0x88);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
retval = rtsx_write_register(chip, PPBUF_BASE2 + 1, 0xFF, 0);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG, 1,
|
|
NO_WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_write_register(chip, MS_CFG,
|
|
0x58 | MS_NO_CHECK_INT,
|
|
MS_BUS_WIDTH_4 |
|
|
PUSH_TIME_ODD |
|
|
MS_NO_CHECK_INT);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
ms_card->ms_type |= MS_4BIT;
|
|
}
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
chip->card_bus_width[chip->card2lun[MS_CARD]] = 4;
|
|
else
|
|
chip->card_bus_width[chip->card2lun[MS_CARD]] = 1;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_init_l2p_tbl(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int size, i, seg_no, retval;
|
|
u16 defect_block, reg_addr;
|
|
u8 val1, val2;
|
|
|
|
ms_card->segment_cnt = ms_card->total_block >> 9;
|
|
dev_dbg(rtsx_dev(chip), "ms_card->segment_cnt = %d\n",
|
|
ms_card->segment_cnt);
|
|
|
|
size = ms_card->segment_cnt * sizeof(struct zone_entry);
|
|
ms_card->segment = vzalloc(size);
|
|
if (!ms_card->segment) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_page(chip, ms_card->boot_block, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
goto INIT_FAIL;
|
|
}
|
|
|
|
reg_addr = PPBUF_BASE2;
|
|
for (i = 0; i < (((ms_card->total_block >> 9) * 10) + 1); i++) {
|
|
int block_no;
|
|
|
|
retval = rtsx_read_register(chip, reg_addr++, &val1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
goto INIT_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, reg_addr++, &val2);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
goto INIT_FAIL;
|
|
}
|
|
|
|
defect_block = ((u16)val1 << 8) | val2;
|
|
if (defect_block == 0xFFFF)
|
|
break;
|
|
|
|
seg_no = defect_block / 512;
|
|
|
|
block_no = ms_card->segment[seg_no].disable_count++;
|
|
ms_card->segment[seg_no].defect_list[block_no] = defect_block;
|
|
}
|
|
|
|
for (i = 0; i < ms_card->segment_cnt; i++) {
|
|
ms_card->segment[i].build_flag = 0;
|
|
ms_card->segment[i].l2p_table = NULL;
|
|
ms_card->segment[i].free_table = NULL;
|
|
ms_card->segment[i].get_index = 0;
|
|
ms_card->segment[i].set_index = 0;
|
|
ms_card->segment[i].unused_blk_cnt = 0;
|
|
|
|
dev_dbg(rtsx_dev(chip), "defective block count of segment %d is %d\n",
|
|
i, ms_card->segment[i].disable_count);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
INIT_FAIL:
|
|
vfree(ms_card->segment);
|
|
ms_card->segment = NULL;
|
|
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
static u16 ms_get_l2p_tbl(struct rtsx_chip *chip, int seg_no, u16 log_off)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
struct zone_entry *segment;
|
|
|
|
if (!ms_card->segment)
|
|
return 0xFFFF;
|
|
|
|
segment = &ms_card->segment[seg_no];
|
|
|
|
if (segment->l2p_table)
|
|
return segment->l2p_table[log_off];
|
|
|
|
return 0xFFFF;
|
|
}
|
|
|
|
static void ms_set_l2p_tbl(struct rtsx_chip *chip,
|
|
int seg_no, u16 log_off, u16 phy_blk)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
struct zone_entry *segment;
|
|
|
|
if (!ms_card->segment)
|
|
return;
|
|
|
|
segment = &ms_card->segment[seg_no];
|
|
if (segment->l2p_table)
|
|
segment->l2p_table[log_off] = phy_blk;
|
|
}
|
|
|
|
static void ms_set_unused_block(struct rtsx_chip *chip, u16 phy_blk)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
struct zone_entry *segment;
|
|
int seg_no;
|
|
|
|
seg_no = (int)phy_blk >> 9;
|
|
segment = &ms_card->segment[seg_no];
|
|
|
|
segment->free_table[segment->set_index++] = phy_blk;
|
|
if (segment->set_index >= MS_FREE_TABLE_CNT)
|
|
segment->set_index = 0;
|
|
|
|
segment->unused_blk_cnt++;
|
|
}
|
|
|
|
static u16 ms_get_unused_block(struct rtsx_chip *chip, int seg_no)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
struct zone_entry *segment;
|
|
u16 phy_blk;
|
|
|
|
segment = &ms_card->segment[seg_no];
|
|
|
|
if (segment->unused_blk_cnt <= 0)
|
|
return 0xFFFF;
|
|
|
|
phy_blk = segment->free_table[segment->get_index];
|
|
segment->free_table[segment->get_index++] = 0xFFFF;
|
|
if (segment->get_index >= MS_FREE_TABLE_CNT)
|
|
segment->get_index = 0;
|
|
|
|
segment->unused_blk_cnt--;
|
|
|
|
return phy_blk;
|
|
}
|
|
|
|
static const unsigned short ms_start_idx[] = {0, 494, 990, 1486, 1982, 2478,
|
|
2974, 3470, 3966, 4462, 4958,
|
|
5454, 5950, 6446, 6942, 7438,
|
|
7934};
|
|
|
|
static int ms_arbitrate_l2p(struct rtsx_chip *chip, u16 phy_blk,
|
|
u16 log_off, u8 us1, u8 us2)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
struct zone_entry *segment;
|
|
int seg_no;
|
|
u16 tmp_blk;
|
|
|
|
seg_no = (int)phy_blk >> 9;
|
|
segment = &ms_card->segment[seg_no];
|
|
tmp_blk = segment->l2p_table[log_off];
|
|
|
|
if (us1 != us2) {
|
|
if (us1 == 0) {
|
|
if (!(chip->card_wp & MS_CARD))
|
|
ms_erase_block(chip, tmp_blk);
|
|
|
|
ms_set_unused_block(chip, tmp_blk);
|
|
segment->l2p_table[log_off] = phy_blk;
|
|
} else {
|
|
if (!(chip->card_wp & MS_CARD))
|
|
ms_erase_block(chip, phy_blk);
|
|
|
|
ms_set_unused_block(chip, phy_blk);
|
|
}
|
|
} else {
|
|
if (phy_blk < tmp_blk) {
|
|
if (!(chip->card_wp & MS_CARD))
|
|
ms_erase_block(chip, phy_blk);
|
|
|
|
ms_set_unused_block(chip, phy_blk);
|
|
} else {
|
|
if (!(chip->card_wp & MS_CARD))
|
|
ms_erase_block(chip, tmp_blk);
|
|
|
|
ms_set_unused_block(chip, tmp_blk);
|
|
segment->l2p_table[log_off] = phy_blk;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
struct zone_entry *segment;
|
|
bool defect_flag;
|
|
int retval, table_size, disable_cnt, i;
|
|
u16 start, end, phy_blk, log_blk, tmp_blk, idx;
|
|
u8 extra[MS_EXTRA_SIZE], us1, us2;
|
|
|
|
dev_dbg(rtsx_dev(chip), "ms_build_l2p_tbl: %d\n", seg_no);
|
|
|
|
if (!ms_card->segment) {
|
|
retval = ms_init_l2p_tbl(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
if (ms_card->segment[seg_no].build_flag) {
|
|
dev_dbg(rtsx_dev(chip), "l2p table of segment %d has been built\n",
|
|
seg_no);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (seg_no == 0)
|
|
table_size = 494;
|
|
else
|
|
table_size = 496;
|
|
|
|
segment = &ms_card->segment[seg_no];
|
|
|
|
if (!segment->l2p_table) {
|
|
segment->l2p_table = vmalloc(table_size * 2);
|
|
if (!segment->l2p_table) {
|
|
rtsx_trace(chip);
|
|
goto BUILD_FAIL;
|
|
}
|
|
}
|
|
memset((u8 *)(segment->l2p_table), 0xff, table_size * 2);
|
|
|
|
if (!segment->free_table) {
|
|
segment->free_table = vmalloc(MS_FREE_TABLE_CNT * 2);
|
|
if (!segment->free_table) {
|
|
rtsx_trace(chip);
|
|
goto BUILD_FAIL;
|
|
}
|
|
}
|
|
memset((u8 *)(segment->free_table), 0xff, MS_FREE_TABLE_CNT * 2);
|
|
|
|
start = (u16)seg_no << 9;
|
|
end = (u16)(seg_no + 1) << 9;
|
|
|
|
disable_cnt = segment->disable_count;
|
|
|
|
segment->get_index = 0;
|
|
segment->set_index = 0;
|
|
segment->unused_blk_cnt = 0;
|
|
|
|
for (phy_blk = start; phy_blk < end; phy_blk++) {
|
|
if (disable_cnt) {
|
|
defect_flag = false;
|
|
for (i = 0; i < segment->disable_count; i++) {
|
|
if (phy_blk == segment->defect_list[i]) {
|
|
defect_flag = true;
|
|
break;
|
|
}
|
|
}
|
|
if (defect_flag) {
|
|
disable_cnt--;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
retval = ms_read_extra_data(chip, phy_blk, 0,
|
|
extra, MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS) {
|
|
dev_dbg(rtsx_dev(chip), "read extra data fail\n");
|
|
ms_set_bad_block(chip, phy_blk);
|
|
continue;
|
|
}
|
|
|
|
if (seg_no == ms_card->segment_cnt - 1) {
|
|
if (!(extra[1] & NOT_TRANSLATION_TABLE)) {
|
|
if (!(chip->card_wp & MS_CARD)) {
|
|
retval = ms_erase_block(chip, phy_blk);
|
|
if (retval != STATUS_SUCCESS)
|
|
continue;
|
|
extra[2] = 0xff;
|
|
extra[3] = 0xff;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!(extra[0] & BLOCK_OK))
|
|
continue;
|
|
if (!(extra[1] & NOT_BOOT_BLOCK))
|
|
continue;
|
|
if ((extra[0] & PAGE_OK) != PAGE_OK)
|
|
continue;
|
|
|
|
log_blk = ((u16)extra[2] << 8) | extra[3];
|
|
|
|
if (log_blk == 0xFFFF) {
|
|
if (!(chip->card_wp & MS_CARD)) {
|
|
retval = ms_erase_block(chip, phy_blk);
|
|
if (retval != STATUS_SUCCESS)
|
|
continue;
|
|
}
|
|
ms_set_unused_block(chip, phy_blk);
|
|
continue;
|
|
}
|
|
|
|
if ((log_blk < ms_start_idx[seg_no]) ||
|
|
(log_blk >= ms_start_idx[seg_no + 1])) {
|
|
if (!(chip->card_wp & MS_CARD)) {
|
|
retval = ms_erase_block(chip, phy_blk);
|
|
if (retval != STATUS_SUCCESS)
|
|
continue;
|
|
}
|
|
ms_set_unused_block(chip, phy_blk);
|
|
continue;
|
|
}
|
|
|
|
idx = log_blk - ms_start_idx[seg_no];
|
|
|
|
if (segment->l2p_table[idx] == 0xFFFF) {
|
|
segment->l2p_table[idx] = phy_blk;
|
|
continue;
|
|
}
|
|
|
|
us1 = extra[0] & 0x10;
|
|
tmp_blk = segment->l2p_table[idx];
|
|
retval = ms_read_extra_data(chip, tmp_blk, 0,
|
|
extra, MS_EXTRA_SIZE);
|
|
if (retval != STATUS_SUCCESS)
|
|
continue;
|
|
us2 = extra[0] & 0x10;
|
|
|
|
(void)ms_arbitrate_l2p(chip, phy_blk,
|
|
log_blk - ms_start_idx[seg_no], us1, us2);
|
|
continue;
|
|
}
|
|
|
|
segment->build_flag = 1;
|
|
|
|
dev_dbg(rtsx_dev(chip), "unused block count: %d\n",
|
|
segment->unused_blk_cnt);
|
|
|
|
/* Logical Address Confirmation Process */
|
|
if (seg_no == ms_card->segment_cnt - 1) {
|
|
if (segment->unused_blk_cnt < 2)
|
|
chip->card_wp |= MS_CARD;
|
|
} else {
|
|
if (segment->unused_blk_cnt < 1)
|
|
chip->card_wp |= MS_CARD;
|
|
}
|
|
|
|
if (chip->card_wp & MS_CARD)
|
|
return STATUS_SUCCESS;
|
|
|
|
for (log_blk = ms_start_idx[seg_no];
|
|
log_blk < ms_start_idx[seg_no + 1]; log_blk++) {
|
|
idx = log_blk - ms_start_idx[seg_no];
|
|
if (segment->l2p_table[idx] == 0xFFFF) {
|
|
phy_blk = ms_get_unused_block(chip, seg_no);
|
|
if (phy_blk == 0xFFFF) {
|
|
chip->card_wp |= MS_CARD;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
retval = ms_init_page(chip, phy_blk, log_blk, 0, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
goto BUILD_FAIL;
|
|
}
|
|
|
|
segment->l2p_table[idx] = phy_blk;
|
|
if (seg_no == ms_card->segment_cnt - 1) {
|
|
if (segment->unused_blk_cnt < 2) {
|
|
chip->card_wp |= MS_CARD;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
if (segment->unused_blk_cnt < 1) {
|
|
chip->card_wp |= MS_CARD;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Make boot block be the first normal block */
|
|
if (seg_no == 0) {
|
|
for (log_blk = 0; log_blk < 494; log_blk++) {
|
|
tmp_blk = segment->l2p_table[log_blk];
|
|
if (tmp_blk < ms_card->boot_block) {
|
|
dev_dbg(rtsx_dev(chip), "Boot block is not the first normal block.\n");
|
|
|
|
if (chip->card_wp & MS_CARD)
|
|
break;
|
|
|
|
phy_blk = ms_get_unused_block(chip, 0);
|
|
retval = ms_copy_page(chip, tmp_blk, phy_blk,
|
|
log_blk, 0,
|
|
ms_card->page_off + 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
segment->l2p_table[log_blk] = phy_blk;
|
|
|
|
retval = ms_set_bad_block(chip, tmp_blk);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
BUILD_FAIL:
|
|
segment->build_flag = 0;
|
|
vfree(segment->l2p_table);
|
|
segment->l2p_table = NULL;
|
|
vfree(segment->free_table);
|
|
segment->free_table = NULL;
|
|
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
int reset_ms_card(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
|
|
memset(ms_card, 0, sizeof(struct ms_info));
|
|
|
|
retval = enable_card_clock(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = select_card(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_card->ms_type = 0;
|
|
|
|
retval = reset_ms_pro(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (ms_card->check_ms_flow) {
|
|
retval = reset_ms(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_set_init_para(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (!CHK_MSPRO(ms_card)) {
|
|
/* Build table for the last segment,
|
|
* to check if L2P table block exists, erasing it
|
|
*/
|
|
retval = ms_build_l2p_tbl(chip, ms_card->total_block / 512 - 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
dev_dbg(rtsx_dev(chip), "ms_card->ms_type = 0x%x\n", ms_card->ms_type);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int mspro_set_rw_cmd(struct rtsx_chip *chip,
|
|
u32 start_sec, u16 sec_cnt, u8 cmd)
|
|
{
|
|
int retval, i;
|
|
u8 data[8];
|
|
|
|
data[0] = cmd;
|
|
data[1] = (u8)(sec_cnt >> 8);
|
|
data[2] = (u8)sec_cnt;
|
|
data[3] = (u8)(start_sec >> 24);
|
|
data[4] = (u8)(start_sec >> 16);
|
|
data[5] = (u8)(start_sec >> 8);
|
|
data[6] = (u8)start_sec;
|
|
data[7] = 0;
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7,
|
|
WAIT_INT, data, 8);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
void mspro_stop_seq_mode(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
|
|
if (ms_card->seq_mode) {
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS)
|
|
return;
|
|
|
|
ms_card->seq_mode = 0;
|
|
ms_card->total_sec_cnt = 0;
|
|
ms_send_cmd(chip, PRO_STOP, WAIT_INT);
|
|
|
|
rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH);
|
|
}
|
|
}
|
|
|
|
static inline int ms_auto_tune_clock(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
|
|
if (chip->asic_code) {
|
|
if (ms_card->ms_clock > 30)
|
|
ms_card->ms_clock -= 20;
|
|
} else {
|
|
if (ms_card->ms_clock == CLK_80)
|
|
ms_card->ms_clock = CLK_60;
|
|
else if (ms_card->ms_clock == CLK_60)
|
|
ms_card->ms_clock = CLK_40;
|
|
}
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int mspro_rw_multi_sector(struct scsi_cmnd *srb,
|
|
struct rtsx_chip *chip, u32 start_sector,
|
|
u16 sector_cnt)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
bool mode_2k = false;
|
|
int retval;
|
|
u16 count;
|
|
u8 val, trans_mode, rw_tpc, rw_cmd;
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
ms_card->cleanup_counter = 0;
|
|
|
|
if (CHK_MSHG(ms_card)) {
|
|
if ((start_sector % 4) || (sector_cnt % 4)) {
|
|
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
|
|
rw_tpc = PRO_READ_LONG_DATA;
|
|
rw_cmd = PRO_READ_DATA;
|
|
} else {
|
|
rw_tpc = PRO_WRITE_LONG_DATA;
|
|
rw_cmd = PRO_WRITE_DATA;
|
|
}
|
|
} else {
|
|
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
|
|
rw_tpc = PRO_READ_QUAD_DATA;
|
|
rw_cmd = PRO_READ_2K_DATA;
|
|
} else {
|
|
rw_tpc = PRO_WRITE_QUAD_DATA;
|
|
rw_cmd = PRO_WRITE_2K_DATA;
|
|
}
|
|
mode_2k = true;
|
|
}
|
|
} else {
|
|
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
|
|
rw_tpc = PRO_READ_LONG_DATA;
|
|
rw_cmd = PRO_READ_DATA;
|
|
} else {
|
|
rw_tpc = PRO_WRITE_LONG_DATA;
|
|
rw_cmd = PRO_WRITE_DATA;
|
|
}
|
|
}
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (srb->sc_data_direction == DMA_FROM_DEVICE)
|
|
trans_mode = MS_TM_AUTO_READ;
|
|
else
|
|
trans_mode = MS_TM_AUTO_WRITE;
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
if (ms_card->seq_mode) {
|
|
if ((ms_card->pre_dir != srb->sc_data_direction) ||
|
|
((ms_card->pre_sec_addr + ms_card->pre_sec_cnt) !=
|
|
start_sector) ||
|
|
(mode_2k && (ms_card->seq_mode & MODE_512_SEQ)) ||
|
|
(!mode_2k && (ms_card->seq_mode & MODE_2K_SEQ)) ||
|
|
!(val & MS_INT_BREQ) ||
|
|
((ms_card->total_sec_cnt + sector_cnt) > 0xFE00)) {
|
|
ms_card->seq_mode = 0;
|
|
ms_card->total_sec_cnt = 0;
|
|
if (val & MS_INT_BREQ) {
|
|
retval = ms_send_cmd(chip, PRO_STOP, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
rtsx_write_register(chip, RBCTL, RB_FLUSH,
|
|
RB_FLUSH);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ms_card->seq_mode) {
|
|
ms_card->total_sec_cnt = 0;
|
|
if (sector_cnt >= SEQ_START_CRITERIA) {
|
|
if ((ms_card->capacity - start_sector) > 0xFE00)
|
|
count = 0xFE00;
|
|
else
|
|
count = (u16)(ms_card->capacity - start_sector);
|
|
|
|
if (count > sector_cnt) {
|
|
if (mode_2k)
|
|
ms_card->seq_mode = MODE_2K_SEQ;
|
|
else
|
|
ms_card->seq_mode = MODE_512_SEQ;
|
|
}
|
|
} else {
|
|
count = sector_cnt;
|
|
}
|
|
retval = mspro_set_rw_cmd(chip, start_sector, count, rw_cmd);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->seq_mode = 0;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_transfer_data(chip, trans_mode, rw_tpc, sector_cnt,
|
|
WAIT_INT, mode_2k, scsi_sg_count(srb),
|
|
scsi_sglist(srb), scsi_bufflen(srb));
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->seq_mode = 0;
|
|
rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
rtsx_clear_ms_error(chip);
|
|
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
chip->rw_need_retry = 0;
|
|
dev_dbg(rtsx_dev(chip), "No card exist, exit mspro_rw_multi_sector\n");
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & MS_INT_BREQ)
|
|
ms_send_cmd(chip, PRO_STOP, WAIT_INT);
|
|
|
|
if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
|
|
dev_dbg(rtsx_dev(chip), "MSPro CRC error, tune clock!\n");
|
|
chip->rw_need_retry = 1;
|
|
ms_auto_tune_clock(chip);
|
|
}
|
|
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
if (ms_card->seq_mode) {
|
|
ms_card->pre_sec_addr = start_sector;
|
|
ms_card->pre_sec_cnt = sector_cnt;
|
|
ms_card->pre_dir = srb->sc_data_direction;
|
|
ms_card->total_sec_cnt += sector_cnt;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int mspro_read_format_progress(struct rtsx_chip *chip,
|
|
const int short_data_len)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u32 total_progress, cur_progress;
|
|
u8 cnt, tmp;
|
|
u8 data[8];
|
|
|
|
dev_dbg(rtsx_dev(chip), "mspro_read_format_progress, short_data_len = %d\n",
|
|
short_data_len);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (!(tmp & MS_INT_BREQ)) {
|
|
if ((tmp & (MS_INT_CED | MS_INT_BREQ | MS_INT_CMDNK |
|
|
MS_INT_ERR)) == MS_INT_CED) {
|
|
ms_card->format_status = FORMAT_SUCCESS;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (short_data_len >= 256)
|
|
cnt = 0;
|
|
else
|
|
cnt = (u8)short_data_len;
|
|
|
|
retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT,
|
|
MS_NO_CHECK_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, cnt, WAIT_INT,
|
|
data, 8);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
total_progress = (data[0] << 24) | (data[1] << 16) |
|
|
(data[2] << 8) | data[3];
|
|
cur_progress = (data[4] << 24) | (data[5] << 16) |
|
|
(data[6] << 8) | data[7];
|
|
|
|
dev_dbg(rtsx_dev(chip), "total_progress = %d, cur_progress = %d\n",
|
|
total_progress, cur_progress);
|
|
|
|
if (total_progress == 0) {
|
|
ms_card->progress = 0;
|
|
} else {
|
|
u64 ulltmp = (u64)cur_progress * (u64)65535;
|
|
|
|
do_div(ulltmp, total_progress);
|
|
ms_card->progress = (u16)ulltmp;
|
|
}
|
|
dev_dbg(rtsx_dev(chip), "progress = %d\n", ms_card->progress);
|
|
|
|
for (i = 0; i < 5000; i++) {
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (tmp & (MS_INT_CED | MS_INT_CMDNK |
|
|
MS_INT_BREQ | MS_INT_ERR))
|
|
break;
|
|
|
|
wait_timeout(1);
|
|
}
|
|
|
|
retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (i == 5000) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (tmp & MS_INT_CED) {
|
|
ms_card->format_status = FORMAT_SUCCESS;
|
|
ms_card->pro_under_formatting = 0;
|
|
} else if (tmp & MS_INT_BREQ) {
|
|
ms_card->format_status = FORMAT_IN_PROGRESS;
|
|
} else {
|
|
ms_card->format_status = FORMAT_FAIL;
|
|
ms_card->pro_under_formatting = 0;
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
void mspro_polling_format_status(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int i;
|
|
|
|
if (ms_card->pro_under_formatting &&
|
|
(rtsx_get_stat(chip) != RTSX_STAT_SS)) {
|
|
rtsx_set_stat(chip, RTSX_STAT_RUN);
|
|
|
|
for (i = 0; i < 65535; i++) {
|
|
mspro_read_format_progress(chip, MS_SHORT_DATA_LEN);
|
|
if (ms_card->format_status != FORMAT_IN_PROGRESS)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
|
int short_data_len, bool quick_format)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 buf[8], tmp;
|
|
u16 para;
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, Pro_TPCParm, 0x01);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
memset(buf, 0, 2);
|
|
switch (short_data_len) {
|
|
case 32:
|
|
buf[0] = 0;
|
|
break;
|
|
case 64:
|
|
buf[0] = 1;
|
|
break;
|
|
case 128:
|
|
buf[0] = 2;
|
|
break;
|
|
case 256:
|
|
default:
|
|
buf[0] = 3;
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, PRO_WRITE_REG, 1,
|
|
NO_WAIT_INT, buf, 2);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (quick_format)
|
|
para = 0x0000;
|
|
else
|
|
para = 0x0001;
|
|
|
|
retval = mspro_set_rw_cmd(chip, 0, para, PRO_FORMAT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
|
|
if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if ((tmp & (MS_INT_BREQ | MS_INT_CED)) == MS_INT_BREQ) {
|
|
ms_card->pro_under_formatting = 1;
|
|
ms_card->progress = 0;
|
|
ms_card->format_status = FORMAT_IN_PROGRESS;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (tmp & MS_INT_CED) {
|
|
ms_card->pro_under_formatting = 0;
|
|
ms_card->progress = 0;
|
|
ms_card->format_status = FORMAT_SUCCESS;
|
|
set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_NO_SENSE);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk,
|
|
u16 log_blk, u8 start_page, u8 end_page,
|
|
u8 *buf, unsigned int *index,
|
|
unsigned int *offset)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 extra[MS_EXTRA_SIZE], page_addr, val, trans_cfg, data[6];
|
|
u8 *ptr;
|
|
|
|
retval = ms_read_extra_data(chip, phy_blk, start_page,
|
|
extra, MS_EXTRA_SIZE);
|
|
if (retval == STATUS_SUCCESS) {
|
|
if ((extra[1] & 0x30) != 0x30) {
|
|
ms_set_err_code(chip, MS_FLASH_READ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(phy_blk >> 8);
|
|
data[3] = (u8)phy_blk;
|
|
data[4] = 0;
|
|
data[5] = start_page;
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
|
|
data, 6);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ptr = buf;
|
|
|
|
for (page_addr = start_page; page_addr < end_page; page_addr++) {
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_NO_CARD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (val & INT_REG_ERR) {
|
|
if (val & INT_REG_BREQ) {
|
|
retval = ms_read_status_reg(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (!(chip->card_wp & MS_CARD)) {
|
|
reset_ms(chip);
|
|
ms_set_page_status
|
|
(log_blk, setPS_NG,
|
|
extra,
|
|
MS_EXTRA_SIZE);
|
|
ms_write_extra_data
|
|
(chip, phy_blk,
|
|
page_addr, extra,
|
|
MS_EXTRA_SIZE);
|
|
}
|
|
ms_set_err_code(chip,
|
|
MS_FLASH_READ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
ms_set_err_code(chip, MS_FLASH_READ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
if (!(val & INT_REG_BREQ)) {
|
|
ms_set_err_code(chip, MS_BREQ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
if (page_addr == (end_page - 1)) {
|
|
if (!(val & INT_REG_CED)) {
|
|
retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT,
|
|
&val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (!(val & INT_REG_CED)) {
|
|
ms_set_err_code(chip, MS_FLASH_READ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
trans_cfg = NO_WAIT_INT;
|
|
} else {
|
|
trans_cfg = WAIT_INT;
|
|
}
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, READ_PAGE_DATA);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG,
|
|
0xFF, trans_cfg);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
|
0x01, RING_BUFFER);
|
|
|
|
trans_dma_enable(DMA_FROM_DEVICE, chip, 512, DMA_512);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
|
|
MS_TRANSFER_START | MS_TM_NORMAL_READ);
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
|
|
MS_TRANSFER_END, MS_TRANSFER_END);
|
|
|
|
rtsx_send_cmd_no_wait(chip);
|
|
|
|
retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr, 512,
|
|
scsi_sg_count(chip->srb),
|
|
index, offset,
|
|
DMA_FROM_DEVICE,
|
|
chip->ms_timeout);
|
|
if (retval < 0) {
|
|
if (retval == -ETIMEDOUT) {
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_TIMEDOUT;
|
|
}
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_TIMEDOUT;
|
|
}
|
|
if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
|
|
ms_set_err_code(chip, MS_CRC16_ERROR);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
if (scsi_sg_count(chip->srb) == 0)
|
|
ptr += 512;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk,
|
|
u16 new_blk, u16 log_blk, u8 start_page,
|
|
u8 end_page, u8 *buf, unsigned int *index,
|
|
unsigned int *offset)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, i;
|
|
u8 page_addr, val, data[16];
|
|
u8 *ptr;
|
|
|
|
if (!start_page) {
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, 7);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(old_blk >> 8);
|
|
data[3] = (u8)old_blk;
|
|
data[4] = 0x80;
|
|
data[5] = 0;
|
|
data[6] = 0xEF;
|
|
data[7] = 0xFF;
|
|
|
|
retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT,
|
|
data, 8);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1,
|
|
NO_WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE,
|
|
SystemParm, (6 + MS_EXTRA_SIZE));
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (CHK_MS4BIT(ms_card))
|
|
data[0] = 0x88;
|
|
else
|
|
data[0] = 0x80;
|
|
|
|
data[1] = 0;
|
|
data[2] = (u8)(new_blk >> 8);
|
|
data[3] = (u8)new_blk;
|
|
if ((end_page - start_page) == 1)
|
|
data[4] = 0x20;
|
|
else
|
|
data[4] = 0;
|
|
|
|
data[5] = start_page;
|
|
data[6] = 0xF8;
|
|
data[7] = 0xFF;
|
|
data[8] = (u8)(log_blk >> 8);
|
|
data[9] = (u8)log_blk;
|
|
|
|
for (i = 0x0A; i < 0x10; i++)
|
|
data[i] = 0xFF;
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, WRITE_REG, 6 + MS_EXTRA_SIZE,
|
|
NO_WAIT_INT, data, 16);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ptr = buf;
|
|
for (page_addr = start_page; page_addr < end_page; page_addr++) {
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
ms_set_err_code(chip, MS_NO_CARD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (val & INT_REG_CMDNK) {
|
|
ms_set_err_code(chip, MS_CMD_NK);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (val & INT_REG_ERR) {
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (!(val & INT_REG_BREQ)) {
|
|
ms_set_err_code(chip, MS_BREQ_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
udelay(30);
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC,
|
|
0xFF, WRITE_PAGE_DATA);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG,
|
|
0xFF, WAIT_INT);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
|
0x01, RING_BUFFER);
|
|
|
|
trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
|
|
MS_TRANSFER_START | MS_TM_NORMAL_WRITE);
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
|
|
MS_TRANSFER_END, MS_TRANSFER_END);
|
|
|
|
rtsx_send_cmd_no_wait(chip);
|
|
|
|
retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr, 512,
|
|
scsi_sg_count(chip->srb),
|
|
index, offset,
|
|
DMA_TO_DEVICE,
|
|
chip->ms_timeout);
|
|
if (retval < 0) {
|
|
ms_set_err_code(chip, MS_TO_ERROR);
|
|
rtsx_clear_ms_error(chip);
|
|
|
|
if (retval == -ETIMEDOUT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_TIMEDOUT;
|
|
}
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if ((end_page - start_page) == 1) {
|
|
if (!(val & INT_REG_CED)) {
|
|
ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
if (page_addr == (end_page - 1)) {
|
|
if (!(val & INT_REG_CED)) {
|
|
retval = ms_send_cmd(chip, BLOCK_END,
|
|
WAIT_INT);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, GET_INT, 1,
|
|
NO_WAIT_INT, &val, 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
if ((page_addr == (end_page - 1)) ||
|
|
(page_addr == ms_card->page_off)) {
|
|
if (!(val & INT_REG_CED)) {
|
|
ms_set_err_code(chip,
|
|
MS_FLASH_WRITE_ERROR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (scsi_sg_count(chip->srb) == 0)
|
|
ptr += 512;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_finish_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
|
|
u16 log_blk, u8 page_off)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval, seg_no;
|
|
|
|
retval = ms_copy_page(chip, old_blk, new_blk, log_blk,
|
|
page_off, ms_card->page_off + 1);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
seg_no = old_blk >> 9;
|
|
|
|
if (MS_TST_BAD_BLOCK_FLG(ms_card)) {
|
|
MS_CLR_BAD_BLOCK_FLG(ms_card);
|
|
ms_set_bad_block(chip, old_blk);
|
|
} else {
|
|
retval = ms_erase_block(chip, old_blk);
|
|
if (retval == STATUS_SUCCESS)
|
|
ms_set_unused_block(chip, old_blk);
|
|
}
|
|
|
|
ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int ms_prepare_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
|
|
u16 log_blk, u8 start_page)
|
|
{
|
|
int retval;
|
|
|
|
if (start_page) {
|
|
retval = ms_copy_page(chip, old_blk, new_blk, log_blk,
|
|
0, start_page);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
#ifdef MS_DELAY_WRITE
|
|
int ms_delay_write(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
struct ms_delay_write_tag *delay_write = &ms_card->delay_write;
|
|
int retval;
|
|
|
|
if (delay_write->delay_write_flag) {
|
|
retval = ms_set_init_para(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
delay_write->delay_write_flag = 0;
|
|
retval = ms_finish_write(chip,
|
|
delay_write->old_phyblock,
|
|
delay_write->new_phyblock,
|
|
delay_write->logblock,
|
|
delay_write->pageoff);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
static inline void ms_rw_fail(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
if (srb->sc_data_direction == DMA_FROM_DEVICE)
|
|
set_sense_type(chip, SCSI_LUN(srb),
|
|
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
|
|
else
|
|
set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR);
|
|
}
|
|
|
|
static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
|
u32 start_sector, u16 sector_cnt)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
int retval, seg_no;
|
|
unsigned int index = 0, offset = 0;
|
|
u16 old_blk = 0, new_blk = 0, log_blk, total_sec_cnt = sector_cnt;
|
|
u8 start_page, end_page = 0, page_cnt;
|
|
u8 *ptr;
|
|
#ifdef MS_DELAY_WRITE
|
|
struct ms_delay_write_tag *delay_write = &ms_card->delay_write;
|
|
#endif
|
|
|
|
ms_set_err_code(chip, MS_NO_ERROR);
|
|
|
|
ms_card->cleanup_counter = 0;
|
|
|
|
ptr = (u8 *)scsi_sglist(srb);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
ms_rw_fail(srb, chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
log_blk = (u16)(start_sector >> ms_card->block_shift);
|
|
start_page = (u8)(start_sector & ms_card->page_off);
|
|
|
|
for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) {
|
|
if (log_blk < ms_start_idx[seg_no + 1])
|
|
break;
|
|
}
|
|
|
|
if (ms_card->segment[seg_no].build_flag == 0) {
|
|
retval = ms_build_l2p_tbl(chip, seg_no);
|
|
if (retval != STATUS_SUCCESS) {
|
|
chip->card_fail |= MS_CARD;
|
|
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
if (srb->sc_data_direction == DMA_TO_DEVICE) {
|
|
#ifdef MS_DELAY_WRITE
|
|
if (delay_write->delay_write_flag &&
|
|
(delay_write->logblock == log_blk) &&
|
|
(start_page > delay_write->pageoff)) {
|
|
delay_write->delay_write_flag = 0;
|
|
retval = ms_copy_page(chip,
|
|
delay_write->old_phyblock,
|
|
delay_write->new_phyblock,
|
|
log_blk,
|
|
delay_write->pageoff, start_page);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_WRITE_ERR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
old_blk = delay_write->old_phyblock;
|
|
new_blk = delay_write->new_phyblock;
|
|
} else if (delay_write->delay_write_flag &&
|
|
(delay_write->logblock == log_blk) &&
|
|
(start_page == delay_write->pageoff)) {
|
|
delay_write->delay_write_flag = 0;
|
|
old_blk = delay_write->old_phyblock;
|
|
new_blk = delay_write->new_phyblock;
|
|
} else {
|
|
retval = ms_delay_write(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_WRITE_ERR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
old_blk = ms_get_l2p_tbl
|
|
(chip, seg_no,
|
|
log_blk - ms_start_idx[seg_no]);
|
|
new_blk = ms_get_unused_block(chip, seg_no);
|
|
if ((old_blk == 0xFFFF) || (new_blk == 0xFFFF)) {
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_WRITE_ERR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_prepare_write(chip, old_blk, new_blk,
|
|
log_blk, start_page);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (detect_card_cd(chip, MS_CARD) !=
|
|
STATUS_SUCCESS) {
|
|
set_sense_type
|
|
(chip, lun,
|
|
SENSE_TYPE_MEDIA_NOT_PRESENT);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_WRITE_ERR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#ifdef MS_DELAY_WRITE
|
|
}
|
|
#endif
|
|
} else {
|
|
#ifdef MS_DELAY_WRITE
|
|
retval = ms_delay_write(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_NOT_PRESENT);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
old_blk = ms_get_l2p_tbl(chip, seg_no,
|
|
log_blk - ms_start_idx[seg_no]);
|
|
if (old_blk == 0xFFFF) {
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n",
|
|
seg_no, old_blk, new_blk);
|
|
|
|
while (total_sec_cnt) {
|
|
if ((start_page + total_sec_cnt) > (ms_card->page_off + 1))
|
|
end_page = ms_card->page_off + 1;
|
|
else
|
|
end_page = start_page + (u8)total_sec_cnt;
|
|
|
|
page_cnt = end_page - start_page;
|
|
|
|
dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d, page_cnt = %d\n",
|
|
start_page, end_page, page_cnt);
|
|
|
|
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
|
|
retval = ms_read_multiple_pages(chip,
|
|
old_blk, log_blk,
|
|
start_page, end_page,
|
|
ptr, &index, &offset);
|
|
} else {
|
|
retval = ms_write_multiple_pages(chip, old_blk, new_blk,
|
|
log_blk, start_page,
|
|
end_page, ptr, &index,
|
|
&offset);
|
|
}
|
|
|
|
if (retval != STATUS_SUCCESS) {
|
|
toggle_gpio(chip, 1);
|
|
if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_NOT_PRESENT);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
ms_rw_fail(srb, chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (srb->sc_data_direction == DMA_TO_DEVICE) {
|
|
if (end_page == (ms_card->page_off + 1)) {
|
|
retval = ms_erase_block(chip, old_blk);
|
|
if (retval == STATUS_SUCCESS)
|
|
ms_set_unused_block(chip, old_blk);
|
|
|
|
ms_set_l2p_tbl(chip, seg_no,
|
|
log_blk - ms_start_idx[seg_no],
|
|
new_blk);
|
|
}
|
|
}
|
|
|
|
total_sec_cnt -= page_cnt;
|
|
if (scsi_sg_count(srb) == 0)
|
|
ptr += page_cnt * 512;
|
|
|
|
if (total_sec_cnt == 0)
|
|
break;
|
|
|
|
log_blk++;
|
|
|
|
for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1;
|
|
seg_no++) {
|
|
if (log_blk < ms_start_idx[seg_no + 1])
|
|
break;
|
|
}
|
|
|
|
if (ms_card->segment[seg_no].build_flag == 0) {
|
|
retval = ms_build_l2p_tbl(chip, seg_no);
|
|
if (retval != STATUS_SUCCESS) {
|
|
chip->card_fail |= MS_CARD;
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MEDIA_NOT_PRESENT);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
old_blk = ms_get_l2p_tbl(chip, seg_no,
|
|
log_blk - ms_start_idx[seg_no]);
|
|
if (old_blk == 0xFFFF) {
|
|
ms_rw_fail(srb, chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (srb->sc_data_direction == DMA_TO_DEVICE) {
|
|
new_blk = ms_get_unused_block(chip, seg_no);
|
|
if (new_blk == 0xFFFF) {
|
|
ms_rw_fail(srb, chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n",
|
|
seg_no, old_blk, new_blk);
|
|
|
|
start_page = 0;
|
|
}
|
|
|
|
if (srb->sc_data_direction == DMA_TO_DEVICE) {
|
|
if (end_page < (ms_card->page_off + 1)) {
|
|
#ifdef MS_DELAY_WRITE
|
|
delay_write->delay_write_flag = 1;
|
|
delay_write->old_phyblock = old_blk;
|
|
delay_write->new_phyblock = new_blk;
|
|
delay_write->logblock = log_blk;
|
|
delay_write->pageoff = end_page;
|
|
#else
|
|
retval = ms_finish_write(chip, old_blk, new_blk,
|
|
log_blk, end_page);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (detect_card_cd(chip, MS_CARD) !=
|
|
STATUS_SUCCESS) {
|
|
set_sense_type
|
|
(chip, lun,
|
|
SENSE_TYPE_MEDIA_NOT_PRESENT);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_rw_fail(srb, chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
scsi_set_resid(srb, 0);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
|
|
u32 start_sector, u16 sector_cnt)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
|
|
if (CHK_MSPRO(ms_card))
|
|
retval = mspro_rw_multi_sector(srb, chip, start_sector,
|
|
sector_cnt);
|
|
else
|
|
retval = ms_rw_multi_sector(srb, chip, start_sector,
|
|
sector_cnt);
|
|
|
|
return retval;
|
|
}
|
|
|
|
void ms_free_l2p_tbl(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int i = 0;
|
|
|
|
if (ms_card->segment) {
|
|
for (i = 0; i < ms_card->segment_cnt; i++) {
|
|
vfree(ms_card->segment[i].l2p_table);
|
|
ms_card->segment[i].l2p_table = NULL;
|
|
vfree(ms_card->segment[i].free_table);
|
|
ms_card->segment[i].free_table = NULL;
|
|
}
|
|
vfree(ms_card->segment);
|
|
ms_card->segment = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef SUPPORT_MAGIC_GATE
|
|
|
|
#ifdef READ_BYTES_WAIT_INT
|
|
static int ms_poll_int(struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
u8 val;
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANS_CFG, MS_INT_CED, MS_INT_CED);
|
|
|
|
retval = rtsx_send_cmd(chip, MS_CARD, 5000);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
val = *rtsx_get_cmd_data(chip);
|
|
if (val & MS_INT_ERR) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MS_SAMPLE_INT_ERR
|
|
static int check_ms_err(struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
u8 val;
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANSFER, &val);
|
|
if (retval != STATUS_SUCCESS)
|
|
return 1;
|
|
if (val & MS_TRANSFER_ERR)
|
|
return 1;
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
|
|
if (retval != STATUS_SUCCESS)
|
|
return 1;
|
|
|
|
if (val & (MS_INT_ERR | MS_INT_CMDNK))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
#else
|
|
static int check_ms_err(struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
u8 val;
|
|
|
|
retval = rtsx_read_register(chip, MS_TRANSFER, &val);
|
|
if (retval != STATUS_SUCCESS)
|
|
return 1;
|
|
if (val & MS_TRANSFER_ERR)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int mg_send_ex_cmd(struct rtsx_chip *chip, u8 cmd, u8 entry_num)
|
|
{
|
|
int retval, i;
|
|
u8 data[8];
|
|
|
|
data[0] = cmd;
|
|
data[1] = 0;
|
|
data[2] = 0;
|
|
data[3] = 0;
|
|
data[4] = 0;
|
|
data[5] = 0;
|
|
data[6] = entry_num;
|
|
data[7] = 0;
|
|
|
|
for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
|
|
retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7, WAIT_INT,
|
|
data, 8);
|
|
if (retval == STATUS_SUCCESS)
|
|
break;
|
|
}
|
|
if (i == MS_MAX_RETRY_COUNT) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (check_ms_err(chip)) {
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type,
|
|
u8 mg_entry_num)
|
|
{
|
|
int retval;
|
|
u8 buf[6];
|
|
|
|
if (type == 0)
|
|
retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_TPCParm, 1);
|
|
else
|
|
retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6);
|
|
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
buf[0] = 0;
|
|
buf[1] = 0;
|
|
if (type == 1) {
|
|
buf[2] = 0;
|
|
buf[3] = 0;
|
|
buf[4] = 0;
|
|
buf[5] = mg_entry_num;
|
|
}
|
|
retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6,
|
|
NO_WAIT_INT, buf, 6);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
int i;
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
u8 buf1[32], buf2[12];
|
|
|
|
if (scsi_bufflen(srb) < 12) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_SET_LID, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
memset(buf1, 0, 32);
|
|
rtsx_stor_get_xfer_buf(buf2, min_t(int, 12, scsi_bufflen(srb)), srb);
|
|
for (i = 0; i < 8; i++)
|
|
buf1[8 + i] = buf2[4 + i];
|
|
|
|
retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT,
|
|
buf1, 32);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (check_ms_err(chip)) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
int retval = STATUS_FAIL;
|
|
int bufflen;
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
u8 *buf = NULL;
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
buf = kmalloc(1540, GFP_KERNEL);
|
|
if (!buf) {
|
|
rtsx_trace(chip);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
buf[0] = 0x04;
|
|
buf[1] = 0x1A;
|
|
buf[2] = 0x00;
|
|
buf[3] = 0x00;
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_GET_LEKB, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_trace(chip);
|
|
goto free_buffer;
|
|
}
|
|
|
|
retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA,
|
|
3, WAIT_INT, 0, 0, buf + 4, 1536);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
goto free_buffer;
|
|
}
|
|
if (check_ms_err(chip)) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
retval = STATUS_FAIL;
|
|
goto free_buffer;
|
|
}
|
|
|
|
bufflen = min_t(int, 1052, scsi_bufflen(srb));
|
|
rtsx_stor_set_xfer_buf(buf, bufflen, srb);
|
|
|
|
free_buffer:
|
|
kfree(buf);
|
|
return retval;
|
|
}
|
|
|
|
int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
int bufflen;
|
|
int i;
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
u8 buf[32];
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_GET_ID, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT,
|
|
buf, 32);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (check_ms_err(chip)) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
memcpy(ms_card->magic_gate_id, buf, 16);
|
|
|
|
#ifdef READ_BYTES_WAIT_INT
|
|
retval = ms_poll_int(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_SET_RD, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
bufflen = min_t(int, 12, scsi_bufflen(srb));
|
|
rtsx_stor_get_xfer_buf(buf, bufflen, srb);
|
|
|
|
for (i = 0; i < 8; i++)
|
|
buf[i] = buf[4 + i];
|
|
|
|
for (i = 0; i < 24; i++)
|
|
buf[8 + i] = 0;
|
|
|
|
retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA,
|
|
32, WAIT_INT, buf, 32);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (check_ms_err(chip)) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_card->mg_auth = 0;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
int bufflen;
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
u8 buf1[32], buf2[36];
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT,
|
|
buf1, 32);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (check_ms_err(chip)) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
buf2[0] = 0x00;
|
|
buf2[1] = 0x22;
|
|
buf2[2] = 0x00;
|
|
buf2[3] = 0x00;
|
|
|
|
memcpy(buf2 + 4, ms_card->magic_gate_id, 16);
|
|
memcpy(buf2 + 20, buf1, 16);
|
|
|
|
bufflen = min_t(int, 36, scsi_bufflen(srb));
|
|
rtsx_stor_set_xfer_buf(buf2, bufflen, srb);
|
|
|
|
#ifdef READ_BYTES_WAIT_INT
|
|
retval = ms_poll_int(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
int i;
|
|
int bufflen;
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
u8 buf[32];
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
bufflen = min_t(int, 12, scsi_bufflen(srb));
|
|
rtsx_stor_get_xfer_buf(buf, bufflen, srb);
|
|
|
|
for (i = 0; i < 8; i++)
|
|
buf[i] = buf[4 + i];
|
|
|
|
for (i = 0; i < 24; i++)
|
|
buf[8 + i] = 0;
|
|
|
|
retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT,
|
|
buf, 32);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
if (check_ms_err(chip)) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
ms_card->mg_auth = 1;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
int bufflen;
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
u8 *buf = NULL;
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
buf = kmalloc(1028, GFP_KERNEL);
|
|
if (!buf) {
|
|
rtsx_trace(chip);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
buf[0] = 0x04;
|
|
buf[1] = 0x02;
|
|
buf[2] = 0x00;
|
|
buf[3] = 0x00;
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_GET_IBD, ms_card->mg_entry_num);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
|
|
rtsx_trace(chip);
|
|
goto free_buffer;
|
|
}
|
|
|
|
retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA,
|
|
2, WAIT_INT, 0, 0, buf + 4, 1024);
|
|
if (retval != STATUS_SUCCESS) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
goto free_buffer;
|
|
}
|
|
if (check_ms_err(chip)) {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
|
|
rtsx_clear_ms_error(chip);
|
|
rtsx_trace(chip);
|
|
retval = STATUS_FAIL;
|
|
goto free_buffer;
|
|
}
|
|
|
|
bufflen = min_t(int, 1028, scsi_bufflen(srb));
|
|
rtsx_stor_set_xfer_buf(buf, bufflen, srb);
|
|
|
|
free_buffer:
|
|
kfree(buf);
|
|
return retval;
|
|
}
|
|
|
|
int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
int bufflen;
|
|
#ifdef MG_SET_ICV_SLOW
|
|
int i;
|
|
#endif
|
|
unsigned int lun = SCSI_LUN(srb);
|
|
u8 *buf = NULL;
|
|
|
|
ms_cleanup_work(chip);
|
|
|
|
retval = ms_switch_clock(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
buf = kmalloc(1028, GFP_KERNEL);
|
|
if (!buf) {
|
|
rtsx_trace(chip);
|
|
return STATUS_ERROR;
|
|
}
|
|
|
|
bufflen = min_t(int, 1028, scsi_bufflen(srb));
|
|
rtsx_stor_get_xfer_buf(buf, bufflen, srb);
|
|
|
|
retval = mg_send_ex_cmd(chip, MG_SET_IBD, ms_card->mg_entry_num);
|
|
if (retval != STATUS_SUCCESS) {
|
|
if (ms_card->mg_auth == 0) {
|
|
if ((buf[5] & 0xC0) != 0)
|
|
set_sense_type
|
|
(chip, lun,
|
|
SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
|
|
else
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MG_WRITE_ERR);
|
|
} else {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
|
|
}
|
|
rtsx_trace(chip);
|
|
goto SetICVFinish;
|
|
}
|
|
|
|
#ifdef MG_SET_ICV_SLOW
|
|
for (i = 0; i < 2; i++) {
|
|
udelay(50);
|
|
|
|
rtsx_init_cmd(chip);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC,
|
|
0xFF, PRO_WRITE_LONG_DATA);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, WAIT_INT);
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
|
|
0x01, RING_BUFFER);
|
|
|
|
trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512);
|
|
|
|
rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
|
|
MS_TRANSFER_START | MS_TM_NORMAL_WRITE);
|
|
rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
|
|
MS_TRANSFER_END, MS_TRANSFER_END);
|
|
|
|
rtsx_send_cmd_no_wait(chip);
|
|
|
|
retval = rtsx_transfer_data(chip, MS_CARD, buf + 4 + i * 512,
|
|
512, 0, DMA_TO_DEVICE, 3000);
|
|
if ((retval < 0) || check_ms_err(chip)) {
|
|
rtsx_clear_ms_error(chip);
|
|
if (ms_card->mg_auth == 0) {
|
|
if ((buf[5] & 0xC0) != 0)
|
|
set_sense_type
|
|
(chip, lun,
|
|
SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
|
|
else
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MG_WRITE_ERR);
|
|
} else {
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MG_WRITE_ERR);
|
|
}
|
|
retval = STATUS_FAIL;
|
|
rtsx_trace(chip);
|
|
goto SetICVFinish;
|
|
}
|
|
}
|
|
#else
|
|
retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA,
|
|
2, WAIT_INT, 0, 0, buf + 4, 1024);
|
|
if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) {
|
|
rtsx_clear_ms_error(chip);
|
|
if (ms_card->mg_auth == 0) {
|
|
if ((buf[5] & 0xC0) != 0)
|
|
set_sense_type
|
|
(chip, lun,
|
|
SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
|
|
else
|
|
set_sense_type(chip, lun,
|
|
SENSE_TYPE_MG_WRITE_ERR);
|
|
} else {
|
|
set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
|
|
}
|
|
rtsx_trace(chip);
|
|
goto SetICVFinish;
|
|
}
|
|
#endif
|
|
|
|
SetICVFinish:
|
|
kfree(buf);
|
|
return retval;
|
|
}
|
|
|
|
#endif /* SUPPORT_MAGIC_GATE */
|
|
|
|
void ms_cleanup_work(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
|
|
if (CHK_MSPRO(ms_card)) {
|
|
if (ms_card->seq_mode) {
|
|
dev_dbg(rtsx_dev(chip), "MS Pro: stop transmission\n");
|
|
mspro_stop_seq_mode(chip);
|
|
ms_card->cleanup_counter = 0;
|
|
}
|
|
if (CHK_MSHG(ms_card)) {
|
|
rtsx_write_register(chip, MS_CFG,
|
|
MS_2K_SECTOR_MODE, 0x00);
|
|
}
|
|
}
|
|
#ifdef MS_DELAY_WRITE
|
|
else if ((!CHK_MSPRO(ms_card)) &&
|
|
ms_card->delay_write.delay_write_flag) {
|
|
dev_dbg(rtsx_dev(chip), "MS: delay write\n");
|
|
ms_delay_write(chip);
|
|
ms_card->cleanup_counter = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int ms_power_off_card3v3(struct rtsx_chip *chip)
|
|
{
|
|
int retval;
|
|
|
|
retval = disable_card_clock(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
if (chip->asic_code) {
|
|
retval = ms_pull_ctl_disable(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
} else {
|
|
retval = rtsx_write_register(chip, FPGA_PULL_CTL,
|
|
FPGA_MS_PULL_CTL_BIT | 0x20,
|
|
FPGA_MS_PULL_CTL_BIT);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
}
|
|
retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0);
|
|
if (retval) {
|
|
rtsx_trace(chip);
|
|
return retval;
|
|
}
|
|
if (!chip->ft2_fast_mode) {
|
|
retval = card_power_off(chip, MS_CARD);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int release_ms_card(struct rtsx_chip *chip)
|
|
{
|
|
struct ms_info *ms_card = &chip->ms_card;
|
|
int retval;
|
|
|
|
#ifdef MS_DELAY_WRITE
|
|
ms_card->delay_write.delay_write_flag = 0;
|
|
#endif
|
|
ms_card->pro_under_formatting = 0;
|
|
|
|
chip->card_ready &= ~MS_CARD;
|
|
chip->card_fail &= ~MS_CARD;
|
|
chip->card_wp &= ~MS_CARD;
|
|
|
|
ms_free_l2p_tbl(chip);
|
|
|
|
memset(ms_card->raw_sys_info, 0, 96);
|
|
#ifdef SUPPORT_PCGL_1P18
|
|
memset(ms_card->raw_model_name, 0, 48);
|
|
#endif
|
|
|
|
retval = ms_power_off_card3v3(chip);
|
|
if (retval != STATUS_SUCCESS) {
|
|
rtsx_trace(chip);
|
|
return STATUS_FAIL;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|