1fa590c22SMicky Ching /* Driver for Realtek PCI-Express card reader 2fa590c22SMicky Ching * 3fa590c22SMicky Ching * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. 4fa590c22SMicky Ching * 5fa590c22SMicky Ching * This program is free software; you can redistribute it and/or modify it 6fa590c22SMicky Ching * under the terms of the GNU General Public License as published by the 7fa590c22SMicky Ching * Free Software Foundation; either version 2, or (at your option) any 8fa590c22SMicky Ching * later version. 9fa590c22SMicky Ching * 10fa590c22SMicky Ching * This program is distributed in the hope that it will be useful, but 11fa590c22SMicky Ching * WITHOUT ANY WARRANTY; without even the implied warranty of 12fa590c22SMicky Ching * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13fa590c22SMicky Ching * General Public License for more details. 14fa590c22SMicky Ching * 15fa590c22SMicky Ching * You should have received a copy of the GNU General Public License along 16fa590c22SMicky Ching * with this program; if not, see <http://www.gnu.org/licenses/>. 17fa590c22SMicky Ching * 18fa590c22SMicky Ching * Author: 19fa590c22SMicky Ching * Wei WANG (wei_wang@realsil.com.cn) 20fa590c22SMicky Ching * Micky Ching (micky_ching@realsil.com.cn) 21fa590c22SMicky Ching */ 22fa590c22SMicky Ching 23fa590c22SMicky Ching #include <linux/blkdev.h> 24fa590c22SMicky Ching #include <linux/kthread.h> 25fa590c22SMicky Ching #include <linux/sched.h> 26fa590c22SMicky Ching #include <linux/vmalloc.h> 27fa590c22SMicky Ching 28fa590c22SMicky Ching #include "rtsx.h" 29fa590c22SMicky Ching #include "ms.h" 30fa590c22SMicky Ching 31fa590c22SMicky Ching static inline void ms_set_err_code(struct rtsx_chip *chip, u8 err_code) 32fa590c22SMicky Ching { 33d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 34fa590c22SMicky Ching 35fa590c22SMicky Ching ms_card->err_code = err_code; 36fa590c22SMicky Ching } 37fa590c22SMicky Ching 38fa590c22SMicky Ching static inline int ms_check_err_code(struct rtsx_chip *chip, u8 err_code) 39fa590c22SMicky Ching { 40d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 41fa590c22SMicky Ching 42fa590c22SMicky Ching return (ms_card->err_code == err_code); 43fa590c22SMicky Ching } 44fa590c22SMicky Ching 45fa590c22SMicky Ching static int ms_parse_err_code(struct rtsx_chip *chip) 46fa590c22SMicky Ching { 47031366eaSJoe Perches rtsx_trace(chip); 48031366eaSJoe Perches return STATUS_FAIL; 49fa590c22SMicky Ching } 50fa590c22SMicky Ching 51fa590c22SMicky Ching static int ms_transfer_tpc(struct rtsx_chip *chip, u8 trans_mode, 52fa590c22SMicky Ching u8 tpc, u8 cnt, u8 cfg) 53fa590c22SMicky Ching { 54d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 55fa590c22SMicky Ching int retval; 56fa590c22SMicky Ching u8 *ptr; 57fa590c22SMicky Ching 58bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "%s: tpc = 0x%x\n", __func__, tpc); 59fa590c22SMicky Ching 60fa590c22SMicky Ching rtsx_init_cmd(chip); 61fa590c22SMicky Ching 62fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); 63fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); 64fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); 65fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 66fa590c22SMicky Ching 0x01, PINGPONG_BUFFER); 67fa590c22SMicky Ching 68fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 69fa590c22SMicky Ching 0xFF, MS_TRANSFER_START | trans_mode); 70fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, 71fa590c22SMicky Ching MS_TRANSFER_END, MS_TRANSFER_END); 72fa590c22SMicky Ching 73fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, MS_TRANS_CFG, 0, 0); 74fa590c22SMicky Ching 75fa590c22SMicky Ching retval = rtsx_send_cmd(chip, MS_CARD, 5000); 76fa590c22SMicky Ching if (retval < 0) { 77fa590c22SMicky Ching rtsx_clear_ms_error(chip); 78fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 79031366eaSJoe Perches rtsx_trace(chip); 80031366eaSJoe Perches return ms_parse_err_code(chip); 81fa590c22SMicky Ching } 82fa590c22SMicky Ching 83fa590c22SMicky Ching ptr = rtsx_get_cmd_data(chip) + 1; 84fa590c22SMicky Ching 85fa590c22SMicky Ching if (!(tpc & 0x08)) { /* Read Packet */ 86fa590c22SMicky Ching if (*ptr & MS_CRC16_ERR) { 87fa590c22SMicky Ching ms_set_err_code(chip, MS_CRC16_ERROR); 88031366eaSJoe Perches rtsx_trace(chip); 89031366eaSJoe Perches return ms_parse_err_code(chip); 90fa590c22SMicky Ching } 91fa590c22SMicky Ching } else { /* Write Packet */ 92fa590c22SMicky Ching if (CHK_MSPRO(ms_card) && !(*ptr & 0x80)) { 93fa590c22SMicky Ching if (*ptr & (MS_INT_ERR | MS_INT_CMDNK)) { 94fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 95031366eaSJoe Perches rtsx_trace(chip); 96031366eaSJoe Perches return ms_parse_err_code(chip); 97fa590c22SMicky Ching } 98fa590c22SMicky Ching } 99fa590c22SMicky Ching } 100fa590c22SMicky Ching 101fa590c22SMicky Ching if (*ptr & MS_RDY_TIMEOUT) { 102fa590c22SMicky Ching rtsx_clear_ms_error(chip); 103fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 104031366eaSJoe Perches rtsx_trace(chip); 105031366eaSJoe Perches return ms_parse_err_code(chip); 106fa590c22SMicky Ching } 107fa590c22SMicky Ching 108fa590c22SMicky Ching return STATUS_SUCCESS; 109fa590c22SMicky Ching } 110fa590c22SMicky Ching 111fa590c22SMicky Ching static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode, 11211201769SQuentin Lambert u8 tpc, u16 sec_cnt, u8 cfg, bool mode_2k, 113fa590c22SMicky Ching int use_sg, void *buf, int buf_len) 114fa590c22SMicky Ching { 115fa590c22SMicky Ching int retval; 116fa590c22SMicky Ching u8 val, err_code = 0; 117fa590c22SMicky Ching enum dma_data_direction dir; 118fa590c22SMicky Ching 119031366eaSJoe Perches if (!buf || !buf_len) { 120031366eaSJoe Perches rtsx_trace(chip); 121031366eaSJoe Perches return STATUS_FAIL; 122031366eaSJoe Perches } 123fa590c22SMicky Ching 124fa590c22SMicky Ching if (trans_mode == MS_TM_AUTO_READ) { 125fa590c22SMicky Ching dir = DMA_FROM_DEVICE; 126fa590c22SMicky Ching err_code = MS_FLASH_READ_ERROR; 127fa590c22SMicky Ching } else if (trans_mode == MS_TM_AUTO_WRITE) { 128fa590c22SMicky Ching dir = DMA_TO_DEVICE; 129fa590c22SMicky Ching err_code = MS_FLASH_WRITE_ERROR; 130fa590c22SMicky Ching } else { 131031366eaSJoe Perches rtsx_trace(chip); 132031366eaSJoe Perches return STATUS_FAIL; 133fa590c22SMicky Ching } 134fa590c22SMicky Ching 135fa590c22SMicky Ching rtsx_init_cmd(chip); 136fa590c22SMicky Ching 137fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); 138fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 139fa590c22SMicky Ching MS_SECTOR_CNT_H, 0xFF, (u8)(sec_cnt >> 8)); 140fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_SECTOR_CNT_L, 0xFF, (u8)sec_cnt); 141fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); 142fa590c22SMicky Ching 143fa590c22SMicky Ching if (mode_2k) { 144fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 145fa590c22SMicky Ching MS_CFG, MS_2K_SECTOR_MODE, MS_2K_SECTOR_MODE); 146fa590c22SMicky Ching } else { 147fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_CFG, MS_2K_SECTOR_MODE, 0); 148fa590c22SMicky Ching } 149fa590c22SMicky Ching 150fa590c22SMicky Ching trans_dma_enable(dir, chip, sec_cnt * 512, DMA_512); 151fa590c22SMicky Ching 152fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 153fa590c22SMicky Ching MS_TRANSFER, 0xFF, MS_TRANSFER_START | trans_mode); 154fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, 155fa590c22SMicky Ching MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END); 156fa590c22SMicky Ching 157fa590c22SMicky Ching rtsx_send_cmd_no_wait(chip); 158fa590c22SMicky Ching 159fa590c22SMicky Ching retval = rtsx_transfer_data(chip, MS_CARD, buf, buf_len, 160fa590c22SMicky Ching use_sg, dir, chip->mspro_timeout); 161fa590c22SMicky Ching if (retval < 0) { 162fa590c22SMicky Ching ms_set_err_code(chip, err_code); 163fa590c22SMicky Ching if (retval == -ETIMEDOUT) 164fa590c22SMicky Ching retval = STATUS_TIMEDOUT; 165fa590c22SMicky Ching else 166fa590c22SMicky Ching retval = STATUS_FAIL; 167fa590c22SMicky Ching 168031366eaSJoe Perches rtsx_trace(chip); 169031366eaSJoe Perches return retval; 170fa590c22SMicky Ching } 171fa590c22SMicky Ching 1728ee775f9SJoe Perches retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); 1738ee775f9SJoe Perches if (retval) { 1748ee775f9SJoe Perches rtsx_trace(chip); 1758ee775f9SJoe Perches return retval; 1768ee775f9SJoe Perches } 177031366eaSJoe Perches if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) { 178031366eaSJoe Perches rtsx_trace(chip); 179031366eaSJoe Perches return STATUS_FAIL; 180031366eaSJoe Perches } 181fa590c22SMicky Ching 182fa590c22SMicky Ching return STATUS_SUCCESS; 183fa590c22SMicky Ching } 184fa590c22SMicky Ching 185fa590c22SMicky Ching static int ms_write_bytes(struct rtsx_chip *chip, 186fa590c22SMicky Ching u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len) 187fa590c22SMicky Ching { 188d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 189fa590c22SMicky Ching int retval, i; 190fa590c22SMicky Ching 191031366eaSJoe Perches if (!data || (data_len < cnt)) { 192031366eaSJoe Perches rtsx_trace(chip); 193031366eaSJoe Perches return STATUS_ERROR; 194031366eaSJoe Perches } 195fa590c22SMicky Ching 196fa590c22SMicky Ching rtsx_init_cmd(chip); 197fa590c22SMicky Ching 198fa590c22SMicky Ching for (i = 0; i < cnt; i++) { 199fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 200fa590c22SMicky Ching PPBUF_BASE2 + i, 0xFF, data[i]); 201fa590c22SMicky Ching } 202fa590c22SMicky Ching if (cnt % 2) 203fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF, 0xFF); 204fa590c22SMicky Ching 205fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); 206fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); 207fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); 208fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 209fa590c22SMicky Ching 0x01, PINGPONG_BUFFER); 210fa590c22SMicky Ching 211fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 212fa590c22SMicky Ching MS_TRANSFER, 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES); 213fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, 214fa590c22SMicky Ching MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END); 215fa590c22SMicky Ching 216fa590c22SMicky Ching retval = rtsx_send_cmd(chip, MS_CARD, 5000); 217fa590c22SMicky Ching if (retval < 0) { 218fa590c22SMicky Ching u8 val = 0; 219fa590c22SMicky Ching 220fa590c22SMicky Ching rtsx_read_register(chip, MS_TRANS_CFG, &val); 221bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "MS_TRANS_CFG: 0x%02x\n", val); 222fa590c22SMicky Ching 223fa590c22SMicky Ching rtsx_clear_ms_error(chip); 224fa590c22SMicky Ching 225fa590c22SMicky Ching if (!(tpc & 0x08)) { 226fa590c22SMicky Ching if (val & MS_CRC16_ERR) { 227fa590c22SMicky Ching ms_set_err_code(chip, MS_CRC16_ERROR); 228031366eaSJoe Perches rtsx_trace(chip); 229031366eaSJoe Perches return ms_parse_err_code(chip); 230fa590c22SMicky Ching } 231fa590c22SMicky Ching } else { 232fa590c22SMicky Ching if (CHK_MSPRO(ms_card) && !(val & 0x80)) { 233fa590c22SMicky Ching if (val & (MS_INT_ERR | MS_INT_CMDNK)) { 234fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 235031366eaSJoe Perches rtsx_trace(chip); 236031366eaSJoe Perches return ms_parse_err_code(chip); 237fa590c22SMicky Ching } 238fa590c22SMicky Ching } 239fa590c22SMicky Ching } 240fa590c22SMicky Ching 241fa590c22SMicky Ching if (val & MS_RDY_TIMEOUT) { 242fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 243031366eaSJoe Perches rtsx_trace(chip); 244031366eaSJoe Perches return ms_parse_err_code(chip); 245fa590c22SMicky Ching } 246fa590c22SMicky Ching 247fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 248031366eaSJoe Perches rtsx_trace(chip); 249031366eaSJoe Perches return ms_parse_err_code(chip); 250fa590c22SMicky Ching } 251fa590c22SMicky Ching 252fa590c22SMicky Ching return STATUS_SUCCESS; 253fa590c22SMicky Ching } 254fa590c22SMicky Ching 255fa590c22SMicky Ching static int ms_read_bytes(struct rtsx_chip *chip, 256fa590c22SMicky Ching u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len) 257fa590c22SMicky Ching { 258d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 259fa590c22SMicky Ching int retval, i; 260fa590c22SMicky Ching u8 *ptr; 261fa590c22SMicky Ching 262031366eaSJoe Perches if (!data) { 263031366eaSJoe Perches rtsx_trace(chip); 264031366eaSJoe Perches return STATUS_ERROR; 265031366eaSJoe Perches } 266fa590c22SMicky Ching 267fa590c22SMicky Ching rtsx_init_cmd(chip); 268fa590c22SMicky Ching 269fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); 270fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); 271fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); 272fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 273fa590c22SMicky Ching 0x01, PINGPONG_BUFFER); 274fa590c22SMicky Ching 275fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, 276fa590c22SMicky Ching MS_TRANSFER_START | MS_TM_READ_BYTES); 277fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, 278fa590c22SMicky Ching MS_TRANSFER_END, MS_TRANSFER_END); 279fa590c22SMicky Ching 280fa590c22SMicky Ching for (i = 0; i < data_len - 1; i++) 281fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); 282fa590c22SMicky Ching 283fa590c22SMicky Ching if (data_len % 2) 284fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0); 285fa590c22SMicky Ching else 286fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len - 1, 287fa590c22SMicky Ching 0, 0); 288fa590c22SMicky Ching 289fa590c22SMicky Ching retval = rtsx_send_cmd(chip, MS_CARD, 5000); 290fa590c22SMicky Ching if (retval < 0) { 291fa590c22SMicky Ching u8 val = 0; 292fa590c22SMicky Ching 293fa590c22SMicky Ching rtsx_read_register(chip, MS_TRANS_CFG, &val); 294fa590c22SMicky Ching rtsx_clear_ms_error(chip); 295fa590c22SMicky Ching 296fa590c22SMicky Ching if (!(tpc & 0x08)) { 297fa590c22SMicky Ching if (val & MS_CRC16_ERR) { 298fa590c22SMicky Ching ms_set_err_code(chip, MS_CRC16_ERROR); 299031366eaSJoe Perches rtsx_trace(chip); 300031366eaSJoe Perches return ms_parse_err_code(chip); 301fa590c22SMicky Ching } 302fa590c22SMicky Ching } else { 303fa590c22SMicky Ching if (CHK_MSPRO(ms_card) && !(val & 0x80)) { 304fa590c22SMicky Ching if (val & (MS_INT_ERR | MS_INT_CMDNK)) { 305fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 306031366eaSJoe Perches rtsx_trace(chip); 307031366eaSJoe Perches return ms_parse_err_code(chip); 308fa590c22SMicky Ching } 309fa590c22SMicky Ching } 310fa590c22SMicky Ching } 311fa590c22SMicky Ching 312fa590c22SMicky Ching if (val & MS_RDY_TIMEOUT) { 313fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 314031366eaSJoe Perches rtsx_trace(chip); 315031366eaSJoe Perches return ms_parse_err_code(chip); 316fa590c22SMicky Ching } 317fa590c22SMicky Ching 318fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 319031366eaSJoe Perches rtsx_trace(chip); 320031366eaSJoe Perches return ms_parse_err_code(chip); 321fa590c22SMicky Ching } 322fa590c22SMicky Ching 323fa590c22SMicky Ching ptr = rtsx_get_cmd_data(chip) + 1; 324fa590c22SMicky Ching 325fa590c22SMicky Ching for (i = 0; i < data_len; i++) 326fa590c22SMicky Ching data[i] = ptr[i]; 327fa590c22SMicky Ching 328fa590c22SMicky Ching if ((tpc == PRO_READ_SHORT_DATA) && (data_len == 8)) { 329bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Read format progress:\n"); 33069b8b224SFabio Falzoi print_hex_dump_bytes(KBUILD_MODNAME ": ", DUMP_PREFIX_NONE, ptr, 33169b8b224SFabio Falzoi cnt); 332fa590c22SMicky Ching } 333fa590c22SMicky Ching 334fa590c22SMicky Ching return STATUS_SUCCESS; 335fa590c22SMicky Ching } 336fa590c22SMicky Ching 337fa590c22SMicky Ching static int ms_set_rw_reg_addr(struct rtsx_chip *chip, 338fa590c22SMicky Ching u8 read_start, u8 read_cnt, u8 write_start, u8 write_cnt) 339fa590c22SMicky Ching { 340fa590c22SMicky Ching int retval, i; 341fa590c22SMicky Ching u8 data[4]; 342fa590c22SMicky Ching 343fa590c22SMicky Ching data[0] = read_start; 344fa590c22SMicky Ching data[1] = read_cnt; 345fa590c22SMicky Ching data[2] = write_start; 346fa590c22SMicky Ching data[3] = write_cnt; 347fa590c22SMicky Ching 348fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 349fa590c22SMicky Ching retval = ms_write_bytes(chip, SET_RW_REG_ADRS, 4, 350fa590c22SMicky Ching NO_WAIT_INT, data, 4); 351fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 352fa590c22SMicky Ching return STATUS_SUCCESS; 353fa590c22SMicky Ching rtsx_clear_ms_error(chip); 354fa590c22SMicky Ching } 355fa590c22SMicky Ching 356031366eaSJoe Perches rtsx_trace(chip); 357031366eaSJoe Perches return STATUS_FAIL; 358fa590c22SMicky Ching } 359fa590c22SMicky Ching 360fa590c22SMicky Ching static int ms_send_cmd(struct rtsx_chip *chip, u8 cmd, u8 cfg) 361fa590c22SMicky Ching { 362fa590c22SMicky Ching u8 data[2]; 363fa590c22SMicky Ching 364fa590c22SMicky Ching data[0] = cmd; 365fa590c22SMicky Ching data[1] = 0; 366fa590c22SMicky Ching 367fa590c22SMicky Ching return ms_write_bytes(chip, PRO_SET_CMD, 1, cfg, data, 1); 368fa590c22SMicky Ching } 369fa590c22SMicky Ching 370fa590c22SMicky Ching static int ms_set_init_para(struct rtsx_chip *chip) 371fa590c22SMicky Ching { 372d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 373fa590c22SMicky Ching int retval; 374fa590c22SMicky Ching 375fa590c22SMicky Ching if (CHK_HG8BIT(ms_card)) { 376fa590c22SMicky Ching if (chip->asic_code) 377fa590c22SMicky Ching ms_card->ms_clock = chip->asic_ms_hg_clk; 378fa590c22SMicky Ching else 379fa590c22SMicky Ching ms_card->ms_clock = chip->fpga_ms_hg_clk; 380fa590c22SMicky Ching 381fa590c22SMicky Ching } else if (CHK_MSPRO(ms_card) || CHK_MS4BIT(ms_card)) { 382fa590c22SMicky Ching if (chip->asic_code) 383fa590c22SMicky Ching ms_card->ms_clock = chip->asic_ms_4bit_clk; 384fa590c22SMicky Ching else 385fa590c22SMicky Ching ms_card->ms_clock = chip->fpga_ms_4bit_clk; 386fa590c22SMicky Ching 387fa590c22SMicky Ching } else { 388fa590c22SMicky Ching if (chip->asic_code) 389fa590c22SMicky Ching ms_card->ms_clock = chip->asic_ms_1bit_clk; 390fa590c22SMicky Ching else 391fa590c22SMicky Ching ms_card->ms_clock = chip->fpga_ms_1bit_clk; 392fa590c22SMicky Ching } 393fa590c22SMicky Ching 394fa590c22SMicky Ching retval = switch_clock(chip, ms_card->ms_clock); 395031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 396031366eaSJoe Perches rtsx_trace(chip); 397031366eaSJoe Perches return STATUS_FAIL; 398031366eaSJoe Perches } 399fa590c22SMicky Ching 400fa590c22SMicky Ching retval = select_card(chip, MS_CARD); 401031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 402031366eaSJoe Perches rtsx_trace(chip); 403031366eaSJoe Perches return STATUS_FAIL; 404031366eaSJoe Perches } 405fa590c22SMicky Ching 406fa590c22SMicky Ching return STATUS_SUCCESS; 407fa590c22SMicky Ching } 408fa590c22SMicky Ching 409fa590c22SMicky Ching static int ms_switch_clock(struct rtsx_chip *chip) 410fa590c22SMicky Ching { 411d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 412fa590c22SMicky Ching int retval; 413fa590c22SMicky Ching 414fa590c22SMicky Ching retval = select_card(chip, MS_CARD); 415031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 416031366eaSJoe Perches rtsx_trace(chip); 417031366eaSJoe Perches return STATUS_FAIL; 418031366eaSJoe Perches } 419fa590c22SMicky Ching 420fa590c22SMicky Ching retval = switch_clock(chip, ms_card->ms_clock); 421031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 422031366eaSJoe Perches rtsx_trace(chip); 423031366eaSJoe Perches return STATUS_FAIL; 424031366eaSJoe Perches } 425fa590c22SMicky Ching 426fa590c22SMicky Ching return STATUS_SUCCESS; 427fa590c22SMicky Ching } 428fa590c22SMicky Ching 429fa590c22SMicky Ching static int ms_pull_ctl_disable(struct rtsx_chip *chip) 430fa590c22SMicky Ching { 4318ee775f9SJoe Perches int retval; 4328ee775f9SJoe Perches 433fa590c22SMicky Ching if (CHECK_PID(chip, 0x5208)) { 4348ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF, 435fa590c22SMicky Ching MS_D1_PD | MS_D2_PD | MS_CLK_PD | MS_D6_PD); 4368ee775f9SJoe Perches if (retval) { 4378ee775f9SJoe Perches rtsx_trace(chip); 4388ee775f9SJoe Perches return retval; 4398ee775f9SJoe Perches } 4408ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF, 441fa590c22SMicky Ching MS_D3_PD | MS_D0_PD | MS_BS_PD | XD_D4_PD); 4428ee775f9SJoe Perches if (retval) { 4438ee775f9SJoe Perches rtsx_trace(chip); 4448ee775f9SJoe Perches return retval; 4458ee775f9SJoe Perches } 4468ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF, 447fa590c22SMicky Ching MS_D7_PD | XD_CE_PD | XD_CLE_PD | XD_CD_PU); 4488ee775f9SJoe Perches if (retval) { 4498ee775f9SJoe Perches rtsx_trace(chip); 4508ee775f9SJoe Perches return retval; 4518ee775f9SJoe Perches } 4528ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF, 453fa590c22SMicky Ching XD_RDY_PD | SD_D3_PD | SD_D2_PD | XD_ALE_PD); 4548ee775f9SJoe Perches if (retval) { 4558ee775f9SJoe Perches rtsx_trace(chip); 4568ee775f9SJoe Perches return retval; 4578ee775f9SJoe Perches } 4588ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF, 459fa590c22SMicky Ching MS_INS_PU | SD_WP_PD | SD_CD_PU | SD_CMD_PD); 4608ee775f9SJoe Perches if (retval) { 4618ee775f9SJoe Perches rtsx_trace(chip); 4628ee775f9SJoe Perches return retval; 4638ee775f9SJoe Perches } 4648ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF, 465fa590c22SMicky Ching MS_D5_PD | MS_D4_PD); 4668ee775f9SJoe Perches if (retval) { 4678ee775f9SJoe Perches rtsx_trace(chip); 4688ee775f9SJoe Perches return retval; 4698ee775f9SJoe Perches } 470fa590c22SMicky Ching } else if (CHECK_PID(chip, 0x5288)) { 471fa590c22SMicky Ching if (CHECK_BARO_PKG(chip, QFN)) { 4728ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL1, 4738ee775f9SJoe Perches 0xFF, 0x55); 4748ee775f9SJoe Perches if (retval) { 4758ee775f9SJoe Perches rtsx_trace(chip); 4768ee775f9SJoe Perches return retval; 4778ee775f9SJoe Perches } 4788ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL2, 4798ee775f9SJoe Perches 0xFF, 0x55); 4808ee775f9SJoe Perches if (retval) { 4818ee775f9SJoe Perches rtsx_trace(chip); 4828ee775f9SJoe Perches return retval; 4838ee775f9SJoe Perches } 4848ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL3, 4858ee775f9SJoe Perches 0xFF, 0x4B); 4868ee775f9SJoe Perches if (retval) { 4878ee775f9SJoe Perches rtsx_trace(chip); 4888ee775f9SJoe Perches return retval; 4898ee775f9SJoe Perches } 4908ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_PULL_CTL4, 4918ee775f9SJoe Perches 0xFF, 0x69); 4928ee775f9SJoe Perches if (retval) { 4938ee775f9SJoe Perches rtsx_trace(chip); 4948ee775f9SJoe Perches return retval; 4958ee775f9SJoe Perches } 496fa590c22SMicky Ching } 497fa590c22SMicky Ching } 498fa590c22SMicky Ching 499fa590c22SMicky Ching return STATUS_SUCCESS; 500fa590c22SMicky Ching } 501fa590c22SMicky Ching 502fa590c22SMicky Ching static int ms_pull_ctl_enable(struct rtsx_chip *chip) 503fa590c22SMicky Ching { 504fa590c22SMicky Ching int retval; 505fa590c22SMicky Ching 506fa590c22SMicky Ching rtsx_init_cmd(chip); 507fa590c22SMicky Ching 508fa590c22SMicky Ching if (CHECK_PID(chip, 0x5208)) { 509fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF, 510fa590c22SMicky Ching MS_D1_PD | MS_D2_PD | MS_CLK_NP | MS_D6_PD); 511fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF, 512fa590c22SMicky Ching MS_D3_PD | MS_D0_PD | MS_BS_NP | XD_D4_PD); 513fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF, 514fa590c22SMicky Ching MS_D7_PD | XD_CE_PD | XD_CLE_PD | XD_CD_PU); 515fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF, 516fa590c22SMicky Ching XD_RDY_PD | SD_D3_PD | SD_D2_PD | XD_ALE_PD); 517fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF, 518fa590c22SMicky Ching MS_INS_PU | SD_WP_PD | SD_CD_PU | SD_CMD_PD); 519fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF, 520fa590c22SMicky Ching MS_D5_PD | MS_D4_PD); 521fa590c22SMicky Ching } else if (CHECK_PID(chip, 0x5288)) { 522fa590c22SMicky Ching if (CHECK_BARO_PKG(chip, QFN)) { 523fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 524fa590c22SMicky Ching CARD_PULL_CTL1, 0xFF, 0x55); 525fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 526fa590c22SMicky Ching CARD_PULL_CTL2, 0xFF, 0x45); 527fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 528fa590c22SMicky Ching CARD_PULL_CTL3, 0xFF, 0x4B); 529fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, 530fa590c22SMicky Ching CARD_PULL_CTL4, 0xFF, 0x29); 531fa590c22SMicky Ching } 532fa590c22SMicky Ching } 533fa590c22SMicky Ching 534fa590c22SMicky Ching retval = rtsx_send_cmd(chip, MS_CARD, 100); 535031366eaSJoe Perches if (retval < 0) { 536031366eaSJoe Perches rtsx_trace(chip); 537031366eaSJoe Perches return STATUS_FAIL; 538031366eaSJoe Perches } 539fa590c22SMicky Ching 540fa590c22SMicky Ching return STATUS_SUCCESS; 541fa590c22SMicky Ching } 542fa590c22SMicky Ching 543fa590c22SMicky Ching static int ms_prepare_reset(struct rtsx_chip *chip) 544fa590c22SMicky Ching { 545d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 546fa590c22SMicky Ching int retval; 547fa590c22SMicky Ching u8 oc_mask = 0; 548fa590c22SMicky Ching 549fa590c22SMicky Ching ms_card->ms_type = 0; 550fa590c22SMicky Ching ms_card->check_ms_flow = 0; 551fa590c22SMicky Ching ms_card->switch_8bit_fail = 0; 552fa590c22SMicky Ching ms_card->delay_write.delay_write_flag = 0; 553fa590c22SMicky Ching 554fa590c22SMicky Ching ms_card->pro_under_formatting = 0; 555fa590c22SMicky Ching 556fa590c22SMicky Ching retval = ms_power_off_card3v3(chip); 557031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 558031366eaSJoe Perches rtsx_trace(chip); 559031366eaSJoe Perches return STATUS_FAIL; 560031366eaSJoe Perches } 561fa590c22SMicky Ching 562fa590c22SMicky Ching if (!chip->ft2_fast_mode) 563fa590c22SMicky Ching wait_timeout(250); 564fa590c22SMicky Ching 565fa590c22SMicky Ching retval = enable_card_clock(chip, MS_CARD); 566031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 567031366eaSJoe Perches rtsx_trace(chip); 568031366eaSJoe Perches return STATUS_FAIL; 569031366eaSJoe Perches } 570fa590c22SMicky Ching 571fa590c22SMicky Ching if (chip->asic_code) { 572fa590c22SMicky Ching retval = ms_pull_ctl_enable(chip); 573031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 574031366eaSJoe Perches rtsx_trace(chip); 575031366eaSJoe Perches return STATUS_FAIL; 576031366eaSJoe Perches } 577fa590c22SMicky Ching } else { 5788ee775f9SJoe Perches retval = rtsx_write_register(chip, FPGA_PULL_CTL, 579fa590c22SMicky Ching FPGA_MS_PULL_CTL_BIT | 0x20, 0); 5808ee775f9SJoe Perches if (retval) { 5818ee775f9SJoe Perches rtsx_trace(chip); 5828ee775f9SJoe Perches return retval; 5838ee775f9SJoe Perches } 584fa590c22SMicky Ching } 585fa590c22SMicky Ching 586fa590c22SMicky Ching if (!chip->ft2_fast_mode) { 587fa590c22SMicky Ching retval = card_power_on(chip, MS_CARD); 588031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 589031366eaSJoe Perches rtsx_trace(chip); 590031366eaSJoe Perches return STATUS_FAIL; 591031366eaSJoe Perches } 592fa590c22SMicky Ching 593fa590c22SMicky Ching wait_timeout(150); 594fa590c22SMicky Ching 595fa590c22SMicky Ching #ifdef SUPPORT_OCP 596fa590c22SMicky Ching if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) 597fa590c22SMicky Ching oc_mask = MS_OC_NOW | MS_OC_EVER; 598fa590c22SMicky Ching else 599fa590c22SMicky Ching oc_mask = SD_OC_NOW | SD_OC_EVER; 600fa590c22SMicky Ching 601fa590c22SMicky Ching if (chip->ocp_stat & oc_mask) { 602bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n", 603fa590c22SMicky Ching chip->ocp_stat); 604031366eaSJoe Perches rtsx_trace(chip); 605031366eaSJoe Perches return STATUS_FAIL; 606fa590c22SMicky Ching } 607fa590c22SMicky Ching #endif 608fa590c22SMicky Ching } 609fa590c22SMicky Ching 6108ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 6118ee775f9SJoe Perches MS_OUTPUT_EN); 6128ee775f9SJoe Perches if (retval) { 6138ee775f9SJoe Perches rtsx_trace(chip); 6148ee775f9SJoe Perches return retval; 6158ee775f9SJoe Perches } 616fa590c22SMicky Ching 617fa590c22SMicky Ching if (chip->asic_code) { 6188ee775f9SJoe Perches retval = rtsx_write_register(chip, MS_CFG, 0xFF, 6198ee775f9SJoe Perches SAMPLE_TIME_RISING | PUSH_TIME_DEFAULT | NO_EXTEND_TOGGLE | MS_BUS_WIDTH_1); 6208ee775f9SJoe Perches if (retval) { 6218ee775f9SJoe Perches rtsx_trace(chip); 6228ee775f9SJoe Perches return retval; 623fa590c22SMicky Ching } 6248ee775f9SJoe Perches } else { 6258ee775f9SJoe Perches retval = rtsx_write_register(chip, MS_CFG, 0xFF, 6268ee775f9SJoe Perches SAMPLE_TIME_FALLING | PUSH_TIME_DEFAULT | NO_EXTEND_TOGGLE | MS_BUS_WIDTH_1); 6278ee775f9SJoe Perches if (retval) { 6288ee775f9SJoe Perches rtsx_trace(chip); 6298ee775f9SJoe Perches return retval; 6308ee775f9SJoe Perches } 6318ee775f9SJoe Perches } 6328ee775f9SJoe Perches retval = rtsx_write_register(chip, MS_TRANS_CFG, 0xFF, 6338ee775f9SJoe Perches NO_WAIT_INT | NO_AUTO_READ_INT_REG); 6348ee775f9SJoe Perches if (retval) { 6358ee775f9SJoe Perches rtsx_trace(chip); 6368ee775f9SJoe Perches return retval; 6378ee775f9SJoe Perches } 6388ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR, 6398ee775f9SJoe Perches MS_STOP | MS_CLR_ERR); 6408ee775f9SJoe Perches if (retval) { 6418ee775f9SJoe Perches rtsx_trace(chip); 6428ee775f9SJoe Perches return retval; 6438ee775f9SJoe Perches } 644fa590c22SMicky Ching 645fa590c22SMicky Ching retval = ms_set_init_para(chip); 646031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 647031366eaSJoe Perches rtsx_trace(chip); 648031366eaSJoe Perches return STATUS_FAIL; 649031366eaSJoe Perches } 650fa590c22SMicky Ching 651fa590c22SMicky Ching return STATUS_SUCCESS; 652fa590c22SMicky Ching } 653fa590c22SMicky Ching 654fa590c22SMicky Ching static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus) 655fa590c22SMicky Ching { 656d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 657fa590c22SMicky Ching int retval, i; 658fa590c22SMicky Ching u8 val; 659fa590c22SMicky Ching 660fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, Pro_StatusReg, 6, SystemParm, 1); 661031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 662031366eaSJoe Perches rtsx_trace(chip); 663031366eaSJoe Perches return STATUS_FAIL; 664031366eaSJoe Perches } 665fa590c22SMicky Ching 666fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 667fa590c22SMicky Ching retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG, 668fa590c22SMicky Ching 6, NO_WAIT_INT); 669fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 670fa590c22SMicky Ching break; 671fa590c22SMicky Ching } 672031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 673031366eaSJoe Perches rtsx_trace(chip); 674031366eaSJoe Perches return STATUS_FAIL; 675031366eaSJoe Perches } 676fa590c22SMicky Ching 6778ee775f9SJoe Perches retval = rtsx_read_register(chip, PPBUF_BASE2 + 2, &val); 6788ee775f9SJoe Perches if (retval) { 6798ee775f9SJoe Perches rtsx_trace(chip); 6808ee775f9SJoe Perches return retval; 6818ee775f9SJoe Perches } 682bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Type register: 0x%x\n", val); 683fa590c22SMicky Ching if (val != 0x01) { 684fa590c22SMicky Ching if (val != 0x02) 685fa590c22SMicky Ching ms_card->check_ms_flow = 1; 686fa590c22SMicky Ching 687031366eaSJoe Perches rtsx_trace(chip); 688031366eaSJoe Perches return STATUS_FAIL; 689fa590c22SMicky Ching } 690fa590c22SMicky Ching 6918ee775f9SJoe Perches retval = rtsx_read_register(chip, PPBUF_BASE2 + 4, &val); 6928ee775f9SJoe Perches if (retval) { 6938ee775f9SJoe Perches rtsx_trace(chip); 6948ee775f9SJoe Perches return retval; 6958ee775f9SJoe Perches } 696bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Category register: 0x%x\n", val); 697fa590c22SMicky Ching if (val != 0) { 698fa590c22SMicky Ching ms_card->check_ms_flow = 1; 699031366eaSJoe Perches rtsx_trace(chip); 700031366eaSJoe Perches return STATUS_FAIL; 701fa590c22SMicky Ching } 702fa590c22SMicky Ching 7038ee775f9SJoe Perches retval = rtsx_read_register(chip, PPBUF_BASE2 + 5, &val); 7048ee775f9SJoe Perches if (retval) { 7058ee775f9SJoe Perches rtsx_trace(chip); 7068ee775f9SJoe Perches return retval; 7078ee775f9SJoe Perches } 708bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Class register: 0x%x\n", val); 709fa590c22SMicky Ching if (val == 0) { 7108ee775f9SJoe Perches retval = rtsx_read_register(chip, PPBUF_BASE2, &val); 7118ee775f9SJoe Perches if (retval) { 7128ee775f9SJoe Perches rtsx_trace(chip); 7138ee775f9SJoe Perches return retval; 7148ee775f9SJoe Perches } 715fa590c22SMicky Ching if (val & WRT_PRTCT) 716fa590c22SMicky Ching chip->card_wp |= MS_CARD; 717fa590c22SMicky Ching else 718fa590c22SMicky Ching chip->card_wp &= ~MS_CARD; 719fa590c22SMicky Ching 720fa590c22SMicky Ching } else if ((val == 0x01) || (val == 0x02) || (val == 0x03)) { 721fa590c22SMicky Ching chip->card_wp |= MS_CARD; 722fa590c22SMicky Ching } else { 723fa590c22SMicky Ching ms_card->check_ms_flow = 1; 724031366eaSJoe Perches rtsx_trace(chip); 725031366eaSJoe Perches return STATUS_FAIL; 726fa590c22SMicky Ching } 727fa590c22SMicky Ching 728fa590c22SMicky Ching ms_card->ms_type |= TYPE_MSPRO; 729fa590c22SMicky Ching 7308ee775f9SJoe Perches retval = rtsx_read_register(chip, PPBUF_BASE2 + 3, &val); 7318ee775f9SJoe Perches if (retval) { 7328ee775f9SJoe Perches rtsx_trace(chip); 7338ee775f9SJoe Perches return retval; 7348ee775f9SJoe Perches } 735bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "IF Mode register: 0x%x\n", val); 736fa590c22SMicky Ching if (val == 0) { 737fa590c22SMicky Ching ms_card->ms_type &= 0x0F; 738fa590c22SMicky Ching } else if (val == 7) { 739fa590c22SMicky Ching if (switch_8bit_bus) 740fa590c22SMicky Ching ms_card->ms_type |= MS_HG; 741fa590c22SMicky Ching else 742fa590c22SMicky Ching ms_card->ms_type &= 0x0F; 743fa590c22SMicky Ching 744fa590c22SMicky Ching } else { 745031366eaSJoe Perches rtsx_trace(chip); 746031366eaSJoe Perches return STATUS_FAIL; 747fa590c22SMicky Ching } 748fa590c22SMicky Ching 749fa590c22SMicky Ching return STATUS_SUCCESS; 750fa590c22SMicky Ching } 751fa590c22SMicky Ching 752fa590c22SMicky Ching static int ms_confirm_cpu_startup(struct rtsx_chip *chip) 753fa590c22SMicky Ching { 754fa590c22SMicky Ching int retval, i, k; 755fa590c22SMicky Ching u8 val; 756fa590c22SMicky Ching 757fa590c22SMicky Ching /* Confirm CPU StartUp */ 758fa590c22SMicky Ching k = 0; 759fa590c22SMicky Ching do { 760fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 761fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_CARD); 762031366eaSJoe Perches rtsx_trace(chip); 763031366eaSJoe Perches return STATUS_FAIL; 764fa590c22SMicky Ching } 765fa590c22SMicky Ching 766fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 767fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, 768fa590c22SMicky Ching NO_WAIT_INT, &val, 1); 769fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 770fa590c22SMicky Ching break; 771fa590c22SMicky Ching } 772031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 773031366eaSJoe Perches rtsx_trace(chip); 774031366eaSJoe Perches return STATUS_FAIL; 775031366eaSJoe Perches } 776fa590c22SMicky Ching 777031366eaSJoe Perches if (k > 100) { 778031366eaSJoe Perches rtsx_trace(chip); 779031366eaSJoe Perches return STATUS_FAIL; 780031366eaSJoe Perches } 781fa590c22SMicky Ching 782fa590c22SMicky Ching k++; 783fa590c22SMicky Ching wait_timeout(100); 784fa590c22SMicky Ching } while (!(val & INT_REG_CED)); 785fa590c22SMicky Ching 786fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 787fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 788fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 789fa590c22SMicky Ching break; 790fa590c22SMicky Ching } 791031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 792031366eaSJoe Perches rtsx_trace(chip); 793031366eaSJoe Perches return STATUS_FAIL; 794031366eaSJoe Perches } 795fa590c22SMicky Ching 796fa590c22SMicky Ching if (val & INT_REG_ERR) { 797fa590c22SMicky Ching if (val & INT_REG_CMDNK) 798fa590c22SMicky Ching chip->card_wp |= (MS_CARD); 799031366eaSJoe Perches else { 800031366eaSJoe Perches rtsx_trace(chip); 801031366eaSJoe Perches return STATUS_FAIL; 802031366eaSJoe Perches } 803fa590c22SMicky Ching } 804fa590c22SMicky Ching /* -- end confirm CPU startup */ 805fa590c22SMicky Ching 806fa590c22SMicky Ching return STATUS_SUCCESS; 807fa590c22SMicky Ching } 808fa590c22SMicky Ching 809fa590c22SMicky Ching static int ms_switch_parallel_bus(struct rtsx_chip *chip) 810fa590c22SMicky Ching { 811fa590c22SMicky Ching int retval, i; 812fa590c22SMicky Ching u8 data[2]; 813fa590c22SMicky Ching 814fa590c22SMicky Ching data[0] = PARALLEL_4BIT_IF; 815fa590c22SMicky Ching data[1] = 0; 816fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 817fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 1, NO_WAIT_INT, 818fa590c22SMicky Ching data, 2); 819fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 820fa590c22SMicky Ching break; 821fa590c22SMicky Ching } 822031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 823031366eaSJoe Perches rtsx_trace(chip); 824031366eaSJoe Perches return STATUS_FAIL; 825031366eaSJoe Perches } 826fa590c22SMicky Ching 827fa590c22SMicky Ching return STATUS_SUCCESS; 828fa590c22SMicky Ching } 829fa590c22SMicky Ching 830fa590c22SMicky Ching static int ms_switch_8bit_bus(struct rtsx_chip *chip) 831fa590c22SMicky Ching { 832d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 833fa590c22SMicky Ching int retval, i; 834fa590c22SMicky Ching u8 data[2]; 835fa590c22SMicky Ching 836fa590c22SMicky Ching data[0] = PARALLEL_8BIT_IF; 837fa590c22SMicky Ching data[1] = 0; 838fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 839fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 1, 840fa590c22SMicky Ching NO_WAIT_INT, data, 2); 841fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 842fa590c22SMicky Ching break; 843fa590c22SMicky Ching } 844031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 845031366eaSJoe Perches rtsx_trace(chip); 846031366eaSJoe Perches return STATUS_FAIL; 847031366eaSJoe Perches } 848fa590c22SMicky Ching 8498ee775f9SJoe Perches retval = rtsx_write_register(chip, MS_CFG, 0x98, 850fa590c22SMicky Ching MS_BUS_WIDTH_8 | SAMPLE_TIME_FALLING); 8518ee775f9SJoe Perches if (retval) { 8528ee775f9SJoe Perches rtsx_trace(chip); 8538ee775f9SJoe Perches return retval; 8548ee775f9SJoe Perches } 855fa590c22SMicky Ching ms_card->ms_type |= MS_8BIT; 856fa590c22SMicky Ching retval = ms_set_init_para(chip); 857031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 858031366eaSJoe Perches rtsx_trace(chip); 859031366eaSJoe Perches return STATUS_FAIL; 860031366eaSJoe Perches } 861fa590c22SMicky Ching 862fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 863fa590c22SMicky Ching retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 864fa590c22SMicky Ching 1, NO_WAIT_INT); 865031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 866031366eaSJoe Perches rtsx_trace(chip); 867031366eaSJoe Perches return STATUS_FAIL; 868031366eaSJoe Perches } 869fa590c22SMicky Ching } 870fa590c22SMicky Ching 871fa590c22SMicky Ching return STATUS_SUCCESS; 872fa590c22SMicky Ching } 873fa590c22SMicky Ching 874fa590c22SMicky Ching static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus) 875fa590c22SMicky Ching { 876d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 877fa590c22SMicky Ching int retval, i; 878fa590c22SMicky Ching 879fa590c22SMicky Ching for (i = 0; i < 3; i++) { 880fa590c22SMicky Ching retval = ms_prepare_reset(chip); 881031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 882031366eaSJoe Perches rtsx_trace(chip); 883031366eaSJoe Perches return STATUS_FAIL; 884031366eaSJoe Perches } 885fa590c22SMicky Ching 886fa590c22SMicky Ching retval = ms_identify_media_type(chip, switch_8bit_bus); 887031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 888031366eaSJoe Perches rtsx_trace(chip); 889031366eaSJoe Perches return STATUS_FAIL; 890031366eaSJoe Perches } 891fa590c22SMicky Ching 892fa590c22SMicky Ching retval = ms_confirm_cpu_startup(chip); 893031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 894031366eaSJoe Perches rtsx_trace(chip); 895031366eaSJoe Perches return STATUS_FAIL; 896031366eaSJoe Perches } 897fa590c22SMicky Ching 898fa590c22SMicky Ching retval = ms_switch_parallel_bus(chip); 899fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 900fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 901fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_CARD); 902031366eaSJoe Perches rtsx_trace(chip); 903031366eaSJoe Perches return STATUS_FAIL; 904fa590c22SMicky Ching } 905fa590c22SMicky Ching continue; 906fa590c22SMicky Ching } else { 907fa590c22SMicky Ching break; 908fa590c22SMicky Ching } 909fa590c22SMicky Ching } 910fa590c22SMicky Ching 911031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 912031366eaSJoe Perches rtsx_trace(chip); 913031366eaSJoe Perches return STATUS_FAIL; 914031366eaSJoe Perches } 915fa590c22SMicky Ching 916fa590c22SMicky Ching /* Switch MS-PRO into Parallel mode */ 9178ee775f9SJoe Perches retval = rtsx_write_register(chip, MS_CFG, 0x18, MS_BUS_WIDTH_4); 9188ee775f9SJoe Perches if (retval) { 9198ee775f9SJoe Perches rtsx_trace(chip); 9208ee775f9SJoe Perches return retval; 9218ee775f9SJoe Perches } 9228ee775f9SJoe Perches retval = rtsx_write_register(chip, MS_CFG, PUSH_TIME_ODD, 9238ee775f9SJoe Perches PUSH_TIME_ODD); 9248ee775f9SJoe Perches if (retval) { 9258ee775f9SJoe Perches rtsx_trace(chip); 9268ee775f9SJoe Perches return retval; 9278ee775f9SJoe Perches } 928fa590c22SMicky Ching 929fa590c22SMicky Ching retval = ms_set_init_para(chip); 930031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 931031366eaSJoe Perches rtsx_trace(chip); 932031366eaSJoe Perches return STATUS_FAIL; 933031366eaSJoe Perches } 934fa590c22SMicky Ching 935fa590c22SMicky Ching /* If MSPro HG Card, We shall try to switch to 8-bit bus */ 936fa590c22SMicky Ching if (CHK_MSHG(ms_card) && chip->support_ms_8bit && switch_8bit_bus) { 937fa590c22SMicky Ching retval = ms_switch_8bit_bus(chip); 938fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 939fa590c22SMicky Ching ms_card->switch_8bit_fail = 1; 940031366eaSJoe Perches rtsx_trace(chip); 941031366eaSJoe Perches return STATUS_FAIL; 942fa590c22SMicky Ching } 943fa590c22SMicky Ching } 944fa590c22SMicky Ching 945fa590c22SMicky Ching return STATUS_SUCCESS; 946fa590c22SMicky Ching } 947fa590c22SMicky Ching 948fa590c22SMicky Ching #ifdef XC_POWERCLASS 949fa590c22SMicky Ching static int msxc_change_power(struct rtsx_chip *chip, u8 mode) 950fa590c22SMicky Ching { 951fa590c22SMicky Ching int retval; 952fa590c22SMicky Ching u8 buf[6]; 953fa590c22SMicky Ching 954fa590c22SMicky Ching ms_cleanup_work(chip); 955fa590c22SMicky Ching 956fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6); 957031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 958031366eaSJoe Perches rtsx_trace(chip); 959031366eaSJoe Perches return STATUS_FAIL; 960031366eaSJoe Perches } 961fa590c22SMicky Ching 962fa590c22SMicky Ching buf[0] = 0; 963fa590c22SMicky Ching buf[1] = mode; 964fa590c22SMicky Ching buf[2] = 0; 965fa590c22SMicky Ching buf[3] = 0; 966fa590c22SMicky Ching buf[4] = 0; 967fa590c22SMicky Ching buf[5] = 0; 968fa590c22SMicky Ching 969fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_WRITE_REG, 6, NO_WAIT_INT, buf, 6); 970031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 971031366eaSJoe Perches rtsx_trace(chip); 972031366eaSJoe Perches return STATUS_FAIL; 973031366eaSJoe Perches } 974fa590c22SMicky Ching 975fa590c22SMicky Ching retval = ms_send_cmd(chip, XC_CHG_POWER, WAIT_INT); 976031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 977031366eaSJoe Perches rtsx_trace(chip); 978031366eaSJoe Perches return STATUS_FAIL; 979031366eaSJoe Perches } 980fa590c22SMicky Ching 9818ee775f9SJoe Perches retval = rtsx_read_register(chip, MS_TRANS_CFG, buf); 9828ee775f9SJoe Perches if (retval) { 9838ee775f9SJoe Perches rtsx_trace(chip); 9848ee775f9SJoe Perches return retval; 9858ee775f9SJoe Perches } 986031366eaSJoe Perches if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR)) { 987031366eaSJoe Perches rtsx_trace(chip); 988031366eaSJoe Perches return STATUS_FAIL; 989031366eaSJoe Perches } 990fa590c22SMicky Ching 991fa590c22SMicky Ching return STATUS_SUCCESS; 992fa590c22SMicky Ching } 993fa590c22SMicky Ching #endif 994fa590c22SMicky Ching 995fa590c22SMicky Ching static int ms_read_attribute_info(struct rtsx_chip *chip) 996fa590c22SMicky Ching { 997d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 998fa590c22SMicky Ching int retval, i; 999fa590c22SMicky Ching u8 val, *buf, class_code, device_type, sub_class, data[16]; 1000fa590c22SMicky Ching u16 total_blk = 0, blk_size = 0; 1001fa590c22SMicky Ching #ifdef SUPPORT_MSXC 1002fa590c22SMicky Ching u32 xc_total_blk = 0, xc_blk_size = 0; 1003fa590c22SMicky Ching #endif 1004fa590c22SMicky Ching u32 sys_info_addr = 0, sys_info_size; 1005fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18 1006fa590c22SMicky Ching u32 model_name_addr = 0, model_name_size; 1007fa590c22SMicky Ching int found_sys_info = 0, found_model_name = 0; 1008fa590c22SMicky Ching #endif 1009fa590c22SMicky Ching 1010fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, Pro_IntReg, 2, Pro_SystemParm, 7); 1011031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1012031366eaSJoe Perches rtsx_trace(chip); 1013031366eaSJoe Perches return STATUS_FAIL; 1014031366eaSJoe Perches } 1015fa590c22SMicky Ching 1016fa590c22SMicky Ching if (CHK_MS8BIT(ms_card)) 1017fa590c22SMicky Ching data[0] = PARALLEL_8BIT_IF; 1018fa590c22SMicky Ching else 1019fa590c22SMicky Ching data[0] = PARALLEL_4BIT_IF; 1020fa590c22SMicky Ching 1021fa590c22SMicky Ching data[1] = 0; 1022fa590c22SMicky Ching 1023fa590c22SMicky Ching data[2] = 0x40; 1024fa590c22SMicky Ching data[3] = 0; 1025fa590c22SMicky Ching data[4] = 0; 1026fa590c22SMicky Ching data[5] = 0; 1027fa590c22SMicky Ching data[6] = 0; 1028fa590c22SMicky Ching data[7] = 0; 1029fa590c22SMicky Ching 1030fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 1031fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_WRITE_REG, 7, NO_WAIT_INT, 1032fa590c22SMicky Ching data, 8); 1033fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 1034fa590c22SMicky Ching break; 1035fa590c22SMicky Ching } 1036031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1037031366eaSJoe Perches rtsx_trace(chip); 1038031366eaSJoe Perches return STATUS_FAIL; 1039031366eaSJoe Perches } 1040fa590c22SMicky Ching 1041fa590c22SMicky Ching buf = kmalloc(64 * 512, GFP_KERNEL); 10427586170cSEva Rachel Retuya if (!buf) { 1043031366eaSJoe Perches rtsx_trace(chip); 1044031366eaSJoe Perches return STATUS_ERROR; 1045031366eaSJoe Perches } 1046fa590c22SMicky Ching 1047fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 1048fa590c22SMicky Ching retval = ms_send_cmd(chip, PRO_READ_ATRB, WAIT_INT); 1049fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 1050fa590c22SMicky Ching continue; 1051fa590c22SMicky Ching 1052fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); 1053fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1054fa590c22SMicky Ching kfree(buf); 1055031366eaSJoe Perches rtsx_trace(chip); 1056031366eaSJoe Perches return STATUS_FAIL; 1057fa590c22SMicky Ching } 1058fa590c22SMicky Ching if (!(val & MS_INT_BREQ)) { 1059fa590c22SMicky Ching kfree(buf); 1060031366eaSJoe Perches rtsx_trace(chip); 1061031366eaSJoe Perches return STATUS_FAIL; 1062fa590c22SMicky Ching } 1063fa590c22SMicky Ching retval = ms_transfer_data(chip, MS_TM_AUTO_READ, 1064fa590c22SMicky Ching PRO_READ_LONG_DATA, 0x40, WAIT_INT, 1065fa590c22SMicky Ching 0, 0, buf, 64 * 512); 1066fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 1067fa590c22SMicky Ching break; 1068b037e229SRoxana Blaj 1069fa590c22SMicky Ching rtsx_clear_ms_error(chip); 1070fa590c22SMicky Ching } 1071fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1072fa590c22SMicky Ching kfree(buf); 1073031366eaSJoe Perches rtsx_trace(chip); 1074031366eaSJoe Perches return STATUS_FAIL; 1075fa590c22SMicky Ching } 1076fa590c22SMicky Ching 1077fa590c22SMicky Ching i = 0; 1078fa590c22SMicky Ching do { 1079fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); 1080fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1081fa590c22SMicky Ching kfree(buf); 1082031366eaSJoe Perches rtsx_trace(chip); 1083031366eaSJoe Perches return STATUS_FAIL; 1084fa590c22SMicky Ching } 1085fa590c22SMicky Ching 1086fa590c22SMicky Ching if ((val & MS_INT_CED) || !(val & MS_INT_BREQ)) 1087fa590c22SMicky Ching break; 1088fa590c22SMicky Ching 1089fa590c22SMicky Ching retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, 1090fa590c22SMicky Ching PRO_READ_LONG_DATA, 0, WAIT_INT); 1091fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1092fa590c22SMicky Ching kfree(buf); 1093031366eaSJoe Perches rtsx_trace(chip); 1094031366eaSJoe Perches return STATUS_FAIL; 1095fa590c22SMicky Ching } 1096fa590c22SMicky Ching 1097fa590c22SMicky Ching i++; 1098fa590c22SMicky Ching } while (i < 1024); 1099fa590c22SMicky Ching 1100fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1101fa590c22SMicky Ching kfree(buf); 1102031366eaSJoe Perches rtsx_trace(chip); 1103031366eaSJoe Perches return STATUS_FAIL; 1104fa590c22SMicky Ching } 1105fa590c22SMicky Ching 1106fa590c22SMicky Ching if ((buf[0] != 0xa5) && (buf[1] != 0xc3)) { 1107fa590c22SMicky Ching /* Signature code is wrong */ 1108fa590c22SMicky Ching kfree(buf); 1109031366eaSJoe Perches rtsx_trace(chip); 1110031366eaSJoe Perches return STATUS_FAIL; 1111fa590c22SMicky Ching } 1112fa590c22SMicky Ching 1113fa590c22SMicky Ching if ((buf[4] < 1) || (buf[4] > 12)) { 1114fa590c22SMicky Ching kfree(buf); 1115031366eaSJoe Perches rtsx_trace(chip); 1116031366eaSJoe Perches return STATUS_FAIL; 1117fa590c22SMicky Ching } 1118fa590c22SMicky Ching 1119fa590c22SMicky Ching for (i = 0; i < buf[4]; i++) { 1120fa590c22SMicky Ching int cur_addr_off = 16 + i * 12; 1121fa590c22SMicky Ching 1122fa590c22SMicky Ching #ifdef SUPPORT_MSXC 1123fa590c22SMicky Ching if ((buf[cur_addr_off + 8] == 0x10) || 112466e6d70dSYash Shah (buf[cur_addr_off + 8] == 0x13)) { 1125fa590c22SMicky Ching #else 112666e6d70dSYash Shah if (buf[cur_addr_off + 8] == 0x10) { 1127fa590c22SMicky Ching #endif 1128fa590c22SMicky Ching sys_info_addr = ((u32)buf[cur_addr_off + 0] << 24) | 1129fa590c22SMicky Ching ((u32)buf[cur_addr_off + 1] << 16) | 1130fa590c22SMicky Ching ((u32)buf[cur_addr_off + 2] << 8) | 1131fa590c22SMicky Ching buf[cur_addr_off + 3]; 1132fa590c22SMicky Ching sys_info_size = ((u32)buf[cur_addr_off + 4] << 24) | 1133fa590c22SMicky Ching ((u32)buf[cur_addr_off + 5] << 16) | 1134fa590c22SMicky Ching ((u32)buf[cur_addr_off + 6] << 8) | 1135fa590c22SMicky Ching buf[cur_addr_off + 7]; 1136bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "sys_info_addr = 0x%x, sys_info_size = 0x%x\n", 1137fa590c22SMicky Ching sys_info_addr, sys_info_size); 1138fa590c22SMicky Ching if (sys_info_size != 96) { 1139fa590c22SMicky Ching kfree(buf); 1140031366eaSJoe Perches rtsx_trace(chip); 1141031366eaSJoe Perches return STATUS_FAIL; 1142fa590c22SMicky Ching } 1143fa590c22SMicky Ching if (sys_info_addr < 0x1A0) { 1144fa590c22SMicky Ching kfree(buf); 1145031366eaSJoe Perches rtsx_trace(chip); 1146031366eaSJoe Perches return STATUS_FAIL; 1147fa590c22SMicky Ching } 1148fa590c22SMicky Ching if ((sys_info_size + sys_info_addr) > 0x8000) { 1149fa590c22SMicky Ching kfree(buf); 1150031366eaSJoe Perches rtsx_trace(chip); 1151031366eaSJoe Perches return STATUS_FAIL; 1152fa590c22SMicky Ching } 1153fa590c22SMicky Ching 1154fa590c22SMicky Ching #ifdef SUPPORT_MSXC 1155fa590c22SMicky Ching if (buf[cur_addr_off + 8] == 0x13) 1156fa590c22SMicky Ching ms_card->ms_type |= MS_XC; 1157fa590c22SMicky Ching #endif 1158fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18 1159fa590c22SMicky Ching found_sys_info = 1; 1160fa590c22SMicky Ching #else 1161fa590c22SMicky Ching break; 1162fa590c22SMicky Ching #endif 1163fa590c22SMicky Ching } 1164fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18 1165fa590c22SMicky Ching if (buf[cur_addr_off + 8] == 0x15) { 1166fa590c22SMicky Ching model_name_addr = ((u32)buf[cur_addr_off + 0] << 24) | 1167fa590c22SMicky Ching ((u32)buf[cur_addr_off + 1] << 16) | 1168fa590c22SMicky Ching ((u32)buf[cur_addr_off + 2] << 8) | 1169fa590c22SMicky Ching buf[cur_addr_off + 3]; 1170fa590c22SMicky Ching model_name_size = ((u32)buf[cur_addr_off + 4] << 24) | 1171fa590c22SMicky Ching ((u32)buf[cur_addr_off + 5] << 16) | 1172fa590c22SMicky Ching ((u32)buf[cur_addr_off + 6] << 8) | 1173fa590c22SMicky Ching buf[cur_addr_off + 7]; 1174bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "model_name_addr = 0x%x, model_name_size = 0x%x\n", 1175fa590c22SMicky Ching model_name_addr, model_name_size); 1176fa590c22SMicky Ching if (model_name_size != 48) { 1177fa590c22SMicky Ching kfree(buf); 1178031366eaSJoe Perches rtsx_trace(chip); 1179031366eaSJoe Perches return STATUS_FAIL; 1180fa590c22SMicky Ching } 1181fa590c22SMicky Ching if (model_name_addr < 0x1A0) { 1182fa590c22SMicky Ching kfree(buf); 1183031366eaSJoe Perches rtsx_trace(chip); 1184031366eaSJoe Perches return STATUS_FAIL; 1185fa590c22SMicky Ching } 1186fa590c22SMicky Ching if ((model_name_size + model_name_addr) > 0x8000) { 1187fa590c22SMicky Ching kfree(buf); 1188031366eaSJoe Perches rtsx_trace(chip); 1189031366eaSJoe Perches return STATUS_FAIL; 1190fa590c22SMicky Ching } 1191fa590c22SMicky Ching 1192fa590c22SMicky Ching found_model_name = 1; 1193fa590c22SMicky Ching } 1194fa590c22SMicky Ching 1195fa590c22SMicky Ching if (found_sys_info && found_model_name) 1196fa590c22SMicky Ching break; 1197fa590c22SMicky Ching #endif 1198fa590c22SMicky Ching } 1199fa590c22SMicky Ching 1200fa590c22SMicky Ching if (i == buf[4]) { 1201fa590c22SMicky Ching kfree(buf); 1202031366eaSJoe Perches rtsx_trace(chip); 1203031366eaSJoe Perches return STATUS_FAIL; 1204fa590c22SMicky Ching } 1205fa590c22SMicky Ching 1206fa590c22SMicky Ching class_code = buf[sys_info_addr + 0]; 1207fa590c22SMicky Ching device_type = buf[sys_info_addr + 56]; 1208fa590c22SMicky Ching sub_class = buf[sys_info_addr + 46]; 1209fa590c22SMicky Ching #ifdef SUPPORT_MSXC 1210fa590c22SMicky Ching if (CHK_MSXC(ms_card)) { 1211fa590c22SMicky Ching xc_total_blk = ((u32)buf[sys_info_addr + 6] << 24) | 1212fa590c22SMicky Ching ((u32)buf[sys_info_addr + 7] << 16) | 1213fa590c22SMicky Ching ((u32)buf[sys_info_addr + 8] << 8) | 1214fa590c22SMicky Ching buf[sys_info_addr + 9]; 1215fa590c22SMicky Ching xc_blk_size = ((u32)buf[sys_info_addr + 32] << 24) | 1216fa590c22SMicky Ching ((u32)buf[sys_info_addr + 33] << 16) | 1217fa590c22SMicky Ching ((u32)buf[sys_info_addr + 34] << 8) | 1218fa590c22SMicky Ching buf[sys_info_addr + 35]; 1219bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "xc_total_blk = 0x%x, xc_blk_size = 0x%x\n", 1220fa590c22SMicky Ching xc_total_blk, xc_blk_size); 1221fa590c22SMicky Ching } else { 1222fa590c22SMicky Ching total_blk = ((u16)buf[sys_info_addr + 6] << 8) | 1223fa590c22SMicky Ching buf[sys_info_addr + 7]; 1224fa590c22SMicky Ching blk_size = ((u16)buf[sys_info_addr + 2] << 8) | 1225fa590c22SMicky Ching buf[sys_info_addr + 3]; 1226bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n", 1227fa590c22SMicky Ching total_blk, blk_size); 1228fa590c22SMicky Ching } 1229fa590c22SMicky Ching #else 1230fa590c22SMicky Ching total_blk = ((u16)buf[sys_info_addr + 6] << 8) | buf[sys_info_addr + 7]; 1231fa590c22SMicky Ching blk_size = ((u16)buf[sys_info_addr + 2] << 8) | buf[sys_info_addr + 3]; 1232bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n", 1233bf6c0d11SFabio Falzoi total_blk, blk_size); 1234fa590c22SMicky Ching #endif 1235fa590c22SMicky Ching 1236bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "class_code = 0x%x, device_type = 0x%x, sub_class = 0x%x\n", 1237fa590c22SMicky Ching class_code, device_type, sub_class); 1238fa590c22SMicky Ching 1239fa590c22SMicky Ching memcpy(ms_card->raw_sys_info, buf + sys_info_addr, 96); 1240fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18 1241fa590c22SMicky Ching memcpy(ms_card->raw_model_name, buf + model_name_addr, 48); 1242fa590c22SMicky Ching #endif 1243fa590c22SMicky Ching 1244fa590c22SMicky Ching kfree(buf); 1245fa590c22SMicky Ching 1246fa590c22SMicky Ching #ifdef SUPPORT_MSXC 1247fa590c22SMicky Ching if (CHK_MSXC(ms_card)) { 1248031366eaSJoe Perches if (class_code != 0x03) { 1249031366eaSJoe Perches rtsx_trace(chip); 1250031366eaSJoe Perches return STATUS_FAIL; 1251031366eaSJoe Perches } 1252fa590c22SMicky Ching } else { 1253031366eaSJoe Perches if (class_code != 0x02) { 1254031366eaSJoe Perches rtsx_trace(chip); 1255031366eaSJoe Perches return STATUS_FAIL; 1256031366eaSJoe Perches } 1257fa590c22SMicky Ching } 1258fa590c22SMicky Ching #else 1259031366eaSJoe Perches if (class_code != 0x02) { 1260031366eaSJoe Perches rtsx_trace(chip); 1261031366eaSJoe Perches return STATUS_FAIL; 1262031366eaSJoe Perches } 1263fa590c22SMicky Ching #endif 1264fa590c22SMicky Ching 1265fa590c22SMicky Ching if (device_type != 0x00) { 1266fa590c22SMicky Ching if ((device_type == 0x01) || (device_type == 0x02) || 1267fa590c22SMicky Ching (device_type == 0x03)) { 1268fa590c22SMicky Ching chip->card_wp |= MS_CARD; 1269fa590c22SMicky Ching } else { 1270031366eaSJoe Perches rtsx_trace(chip); 1271031366eaSJoe Perches return STATUS_FAIL; 1272fa590c22SMicky Ching } 1273fa590c22SMicky Ching } 1274fa590c22SMicky Ching 1275031366eaSJoe Perches if (sub_class & 0xC0) { 1276031366eaSJoe Perches rtsx_trace(chip); 1277031366eaSJoe Perches return STATUS_FAIL; 1278031366eaSJoe Perches } 1279fa590c22SMicky Ching 1280bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "class_code: 0x%x, device_type: 0x%x, sub_class: 0x%x\n", 1281fa590c22SMicky Ching class_code, device_type, sub_class); 1282fa590c22SMicky Ching 1283fa590c22SMicky Ching #ifdef SUPPORT_MSXC 1284fa590c22SMicky Ching if (CHK_MSXC(ms_card)) { 1285fa590c22SMicky Ching chip->capacity[chip->card2lun[MS_CARD]] = 1286fa590c22SMicky Ching ms_card->capacity = xc_total_blk * xc_blk_size; 1287fa590c22SMicky Ching } else { 1288fa590c22SMicky Ching chip->capacity[chip->card2lun[MS_CARD]] = 1289fa590c22SMicky Ching ms_card->capacity = total_blk * blk_size; 1290fa590c22SMicky Ching } 1291fa590c22SMicky Ching #else 1292fa590c22SMicky Ching ms_card->capacity = total_blk * blk_size; 1293fa590c22SMicky Ching chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity; 1294fa590c22SMicky Ching #endif 1295fa590c22SMicky Ching 1296fa590c22SMicky Ching return STATUS_SUCCESS; 1297fa590c22SMicky Ching } 1298fa590c22SMicky Ching 1299fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE 1300fa590c22SMicky Ching static int mg_set_tpc_para_sub(struct rtsx_chip *chip, 1301fa590c22SMicky Ching int type, u8 mg_entry_num); 1302fa590c22SMicky Ching #endif 1303fa590c22SMicky Ching 1304fa590c22SMicky Ching static int reset_ms_pro(struct rtsx_chip *chip) 1305fa590c22SMicky Ching { 1306d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 1307fa590c22SMicky Ching int retval; 1308fa590c22SMicky Ching #ifdef XC_POWERCLASS 1309fa590c22SMicky Ching u8 change_power_class; 1310fa590c22SMicky Ching 1311fa590c22SMicky Ching if (chip->ms_power_class_en & 0x02) 1312fa590c22SMicky Ching change_power_class = 2; 1313fa590c22SMicky Ching else if (chip->ms_power_class_en & 0x01) 1314fa590c22SMicky Ching change_power_class = 1; 1315fa590c22SMicky Ching else 1316fa590c22SMicky Ching change_power_class = 0; 1317fa590c22SMicky Ching #endif 1318fa590c22SMicky Ching 1319fa590c22SMicky Ching #ifdef XC_POWERCLASS 1320fa590c22SMicky Ching Retry: 1321fa590c22SMicky Ching #endif 1322fa590c22SMicky Ching retval = ms_pro_reset_flow(chip, 1); 1323fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1324fa590c22SMicky Ching if (ms_card->switch_8bit_fail) { 1325fa590c22SMicky Ching retval = ms_pro_reset_flow(chip, 0); 1326031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1327031366eaSJoe Perches rtsx_trace(chip); 1328031366eaSJoe Perches return STATUS_FAIL; 1329031366eaSJoe Perches } 1330fa590c22SMicky Ching } else { 1331031366eaSJoe Perches rtsx_trace(chip); 1332031366eaSJoe Perches return STATUS_FAIL; 1333fa590c22SMicky Ching } 1334fa590c22SMicky Ching } 1335fa590c22SMicky Ching 1336fa590c22SMicky Ching retval = ms_read_attribute_info(chip); 1337031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1338031366eaSJoe Perches rtsx_trace(chip); 1339031366eaSJoe Perches return STATUS_FAIL; 1340031366eaSJoe Perches } 1341fa590c22SMicky Ching 1342fa590c22SMicky Ching #ifdef XC_POWERCLASS 1343fa590c22SMicky Ching if (CHK_HG8BIT(ms_card)) 1344fa590c22SMicky Ching change_power_class = 0; 1345fa590c22SMicky Ching 1346fa590c22SMicky Ching if (change_power_class && CHK_MSXC(ms_card)) { 1347fa590c22SMicky Ching u8 power_class_en = chip->ms_power_class_en; 1348fa590c22SMicky Ching 1349bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "power_class_en = 0x%x\n", 1350bf6c0d11SFabio Falzoi power_class_en); 1351bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "change_power_class = %d\n", 1352bf6c0d11SFabio Falzoi change_power_class); 1353fa590c22SMicky Ching 1354fa590c22SMicky Ching if (change_power_class) 1355fa590c22SMicky Ching power_class_en &= (1 << (change_power_class - 1)); 1356fa590c22SMicky Ching else 1357fa590c22SMicky Ching power_class_en = 0; 1358fa590c22SMicky Ching 1359fa590c22SMicky Ching if (power_class_en) { 1360fa590c22SMicky Ching u8 power_class_mode = 1361fa590c22SMicky Ching (ms_card->raw_sys_info[46] & 0x18) >> 3; 1362bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "power_class_mode = 0x%x", 1363fa590c22SMicky Ching power_class_mode); 1364fa590c22SMicky Ching if (change_power_class > power_class_mode) 1365fa590c22SMicky Ching change_power_class = power_class_mode; 1366fa590c22SMicky Ching if (change_power_class) { 1367fa590c22SMicky Ching retval = msxc_change_power(chip, 1368fa590c22SMicky Ching change_power_class); 1369fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1370fa590c22SMicky Ching change_power_class--; 1371fa590c22SMicky Ching goto Retry; 1372fa590c22SMicky Ching } 1373fa590c22SMicky Ching } 1374fa590c22SMicky Ching } 1375fa590c22SMicky Ching } 1376fa590c22SMicky Ching #endif 1377fa590c22SMicky Ching 1378fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE 1379fa590c22SMicky Ching retval = mg_set_tpc_para_sub(chip, 0, 0); 1380031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1381031366eaSJoe Perches rtsx_trace(chip); 1382031366eaSJoe Perches return STATUS_FAIL; 1383031366eaSJoe Perches } 1384fa590c22SMicky Ching #endif 1385fa590c22SMicky Ching 1386fa590c22SMicky Ching if (CHK_HG8BIT(ms_card)) 1387fa590c22SMicky Ching chip->card_bus_width[chip->card2lun[MS_CARD]] = 8; 1388fa590c22SMicky Ching else 1389fa590c22SMicky Ching chip->card_bus_width[chip->card2lun[MS_CARD]] = 4; 1390fa590c22SMicky Ching 1391fa590c22SMicky Ching return STATUS_SUCCESS; 1392fa590c22SMicky Ching } 1393fa590c22SMicky Ching 1394fa590c22SMicky Ching static int ms_read_status_reg(struct rtsx_chip *chip) 1395fa590c22SMicky Ching { 1396fa590c22SMicky Ching int retval; 1397fa590c22SMicky Ching u8 val[2]; 1398fa590c22SMicky Ching 1399fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, StatusReg0, 2, 0, 0); 1400031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1401031366eaSJoe Perches rtsx_trace(chip); 1402031366eaSJoe Perches return STATUS_FAIL; 1403031366eaSJoe Perches } 1404fa590c22SMicky Ching 1405fa590c22SMicky Ching retval = ms_read_bytes(chip, READ_REG, 2, NO_WAIT_INT, val, 2); 1406031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1407031366eaSJoe Perches rtsx_trace(chip); 1408031366eaSJoe Perches return STATUS_FAIL; 1409031366eaSJoe Perches } 1410fa590c22SMicky Ching 1411fa590c22SMicky Ching if (val[1] & (STS_UCDT | STS_UCEX | STS_UCFG)) { 1412fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_READ_ERROR); 1413031366eaSJoe Perches rtsx_trace(chip); 1414031366eaSJoe Perches return STATUS_FAIL; 1415fa590c22SMicky Ching } 1416fa590c22SMicky Ching 1417fa590c22SMicky Ching return STATUS_SUCCESS; 1418fa590c22SMicky Ching } 1419fa590c22SMicky Ching 1420fa590c22SMicky Ching static int ms_read_extra_data(struct rtsx_chip *chip, 1421fa590c22SMicky Ching u16 block_addr, u8 page_num, u8 *buf, int buf_len) 1422fa590c22SMicky Ching { 1423d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 1424fa590c22SMicky Ching int retval, i; 1425fa590c22SMicky Ching u8 val, data[10]; 1426fa590c22SMicky Ching 1427fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 1428fa590c22SMicky Ching SystemParm, 6); 1429031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1430031366eaSJoe Perches rtsx_trace(chip); 1431031366eaSJoe Perches return STATUS_FAIL; 1432031366eaSJoe Perches } 1433fa590c22SMicky Ching 1434fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) { 1435fa590c22SMicky Ching /* Parallel interface */ 1436fa590c22SMicky Ching data[0] = 0x88; 1437fa590c22SMicky Ching } else { 1438fa590c22SMicky Ching /* Serial interface */ 1439fa590c22SMicky Ching data[0] = 0x80; 1440fa590c22SMicky Ching } 1441fa590c22SMicky Ching data[1] = 0; 1442fa590c22SMicky Ching data[2] = (u8)(block_addr >> 8); 1443fa590c22SMicky Ching data[3] = (u8)block_addr; 1444fa590c22SMicky Ching data[4] = 0x40; 1445fa590c22SMicky Ching data[5] = page_num; 1446fa590c22SMicky Ching 1447fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 1448fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, 1449fa590c22SMicky Ching data, 6); 1450fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 1451fa590c22SMicky Ching break; 1452fa590c22SMicky Ching } 1453031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 1454031366eaSJoe Perches rtsx_trace(chip); 1455031366eaSJoe Perches return STATUS_FAIL; 1456031366eaSJoe Perches } 1457fa590c22SMicky Ching 1458fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1459fa590c22SMicky Ching 1460fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 1461fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); 1462fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 1463fa590c22SMicky Ching break; 1464fa590c22SMicky Ching } 1465031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 1466031366eaSJoe Perches rtsx_trace(chip); 1467031366eaSJoe Perches return STATUS_FAIL; 1468031366eaSJoe Perches } 1469fa590c22SMicky Ching 1470fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1471fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 1472031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1473031366eaSJoe Perches rtsx_trace(chip); 1474031366eaSJoe Perches return STATUS_FAIL; 1475031366eaSJoe Perches } 1476fa590c22SMicky Ching 1477fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 1478fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 1479031366eaSJoe Perches rtsx_trace(chip); 1480031366eaSJoe Perches return STATUS_FAIL; 1481fa590c22SMicky Ching } 1482fa590c22SMicky Ching if (val & INT_REG_CED) { 1483fa590c22SMicky Ching if (val & INT_REG_ERR) { 1484fa590c22SMicky Ching retval = ms_read_status_reg(chip); 1485031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1486031366eaSJoe Perches rtsx_trace(chip); 1487031366eaSJoe Perches return STATUS_FAIL; 1488031366eaSJoe Perches } 1489fa590c22SMicky Ching 1490fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, 1491fa590c22SMicky Ching MS_EXTRA_SIZE, SystemParm, 6); 1492031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1493031366eaSJoe Perches rtsx_trace(chip); 1494031366eaSJoe Perches return STATUS_FAIL; 1495031366eaSJoe Perches } 1496fa590c22SMicky Ching } 1497fa590c22SMicky Ching } 1498fa590c22SMicky Ching 1499fa590c22SMicky Ching retval = ms_read_bytes(chip, READ_REG, MS_EXTRA_SIZE, NO_WAIT_INT, 1500fa590c22SMicky Ching data, MS_EXTRA_SIZE); 1501031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1502031366eaSJoe Perches rtsx_trace(chip); 1503031366eaSJoe Perches return STATUS_FAIL; 1504031366eaSJoe Perches } 1505fa590c22SMicky Ching 1506fa590c22SMicky Ching if (buf && buf_len) { 1507fa590c22SMicky Ching if (buf_len > MS_EXTRA_SIZE) 1508fa590c22SMicky Ching buf_len = MS_EXTRA_SIZE; 1509fa590c22SMicky Ching memcpy(buf, data, buf_len); 1510fa590c22SMicky Ching } 1511fa590c22SMicky Ching 1512fa590c22SMicky Ching return STATUS_SUCCESS; 1513fa590c22SMicky Ching } 1514fa590c22SMicky Ching 1515fa590c22SMicky Ching static int ms_write_extra_data(struct rtsx_chip *chip, 1516fa590c22SMicky Ching u16 block_addr, u8 page_num, u8 *buf, int buf_len) 1517fa590c22SMicky Ching { 1518d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 1519fa590c22SMicky Ching int retval, i; 1520fa590c22SMicky Ching u8 val, data[16]; 1521fa590c22SMicky Ching 1522031366eaSJoe Perches if (!buf || (buf_len < MS_EXTRA_SIZE)) { 1523031366eaSJoe Perches rtsx_trace(chip); 1524031366eaSJoe Perches return STATUS_FAIL; 1525031366eaSJoe Perches } 1526fa590c22SMicky Ching 1527fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 1528fa590c22SMicky Ching SystemParm, 6 + MS_EXTRA_SIZE); 1529031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1530031366eaSJoe Perches rtsx_trace(chip); 1531031366eaSJoe Perches return STATUS_FAIL; 1532031366eaSJoe Perches } 1533fa590c22SMicky Ching 1534fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 1535fa590c22SMicky Ching data[0] = 0x88; 1536fa590c22SMicky Ching else 1537fa590c22SMicky Ching data[0] = 0x80; 1538fa590c22SMicky Ching 1539fa590c22SMicky Ching data[1] = 0; 1540fa590c22SMicky Ching data[2] = (u8)(block_addr >> 8); 1541fa590c22SMicky Ching data[3] = (u8)block_addr; 1542fa590c22SMicky Ching data[4] = 0x40; 1543fa590c22SMicky Ching data[5] = page_num; 1544fa590c22SMicky Ching 1545fa590c22SMicky Ching for (i = 6; i < MS_EXTRA_SIZE + 6; i++) 1546fa590c22SMicky Ching data[i] = buf[i - 6]; 1547fa590c22SMicky Ching 1548fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE), 1549fa590c22SMicky Ching NO_WAIT_INT, data, 16); 1550031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1551031366eaSJoe Perches rtsx_trace(chip); 1552031366eaSJoe Perches return STATUS_FAIL; 1553031366eaSJoe Perches } 1554fa590c22SMicky Ching 1555fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); 1556031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1557031366eaSJoe Perches rtsx_trace(chip); 1558031366eaSJoe Perches return STATUS_FAIL; 1559031366eaSJoe Perches } 1560fa590c22SMicky Ching 1561fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1562fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 1563031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1564031366eaSJoe Perches rtsx_trace(chip); 1565031366eaSJoe Perches return STATUS_FAIL; 1566031366eaSJoe Perches } 1567fa590c22SMicky Ching 1568fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 1569fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 1570031366eaSJoe Perches rtsx_trace(chip); 1571031366eaSJoe Perches return STATUS_FAIL; 1572fa590c22SMicky Ching } 1573fa590c22SMicky Ching if (val & INT_REG_CED) { 1574fa590c22SMicky Ching if (val & INT_REG_ERR) { 1575fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 1576031366eaSJoe Perches rtsx_trace(chip); 1577031366eaSJoe Perches return STATUS_FAIL; 1578fa590c22SMicky Ching } 1579fa590c22SMicky Ching } 1580fa590c22SMicky Ching 1581fa590c22SMicky Ching return STATUS_SUCCESS; 1582fa590c22SMicky Ching } 1583fa590c22SMicky Ching 1584fa590c22SMicky Ching static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num) 1585fa590c22SMicky Ching { 1586d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 1587fa590c22SMicky Ching int retval; 1588fa590c22SMicky Ching u8 val, data[6]; 1589fa590c22SMicky Ching 1590fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 1591fa590c22SMicky Ching SystemParm, 6); 1592031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1593031366eaSJoe Perches rtsx_trace(chip); 1594031366eaSJoe Perches return STATUS_FAIL; 1595031366eaSJoe Perches } 1596fa590c22SMicky Ching 1597fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 1598fa590c22SMicky Ching data[0] = 0x88; 1599fa590c22SMicky Ching else 1600fa590c22SMicky Ching data[0] = 0x80; 1601fa590c22SMicky Ching 1602fa590c22SMicky Ching data[1] = 0; 1603fa590c22SMicky Ching data[2] = (u8)(block_addr >> 8); 1604fa590c22SMicky Ching data[3] = (u8)block_addr; 1605fa590c22SMicky Ching data[4] = 0x20; 1606fa590c22SMicky Ching data[5] = page_num; 1607fa590c22SMicky Ching 1608fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6); 1609031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1610031366eaSJoe Perches rtsx_trace(chip); 1611031366eaSJoe Perches return STATUS_FAIL; 1612031366eaSJoe Perches } 1613fa590c22SMicky Ching 1614fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); 1615031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1616031366eaSJoe Perches rtsx_trace(chip); 1617031366eaSJoe Perches return STATUS_FAIL; 1618031366eaSJoe Perches } 1619fa590c22SMicky Ching 1620fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1621fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 1622031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1623031366eaSJoe Perches rtsx_trace(chip); 1624031366eaSJoe Perches return STATUS_FAIL; 1625031366eaSJoe Perches } 1626fa590c22SMicky Ching 1627fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 1628fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 1629031366eaSJoe Perches rtsx_trace(chip); 1630031366eaSJoe Perches return STATUS_FAIL; 1631fa590c22SMicky Ching } 1632fa590c22SMicky Ching 1633fa590c22SMicky Ching if (val & INT_REG_CED) { 1634fa590c22SMicky Ching if (val & INT_REG_ERR) { 1635fa590c22SMicky Ching if (!(val & INT_REG_BREQ)) { 1636fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_READ_ERROR); 1637031366eaSJoe Perches rtsx_trace(chip); 1638031366eaSJoe Perches return STATUS_FAIL; 1639fa590c22SMicky Ching } 1640fa590c22SMicky Ching retval = ms_read_status_reg(chip); 1641fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 1642fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 1643fa590c22SMicky Ching 1644fa590c22SMicky Ching } else { 1645fa590c22SMicky Ching if (!(val & INT_REG_BREQ)) { 1646fa590c22SMicky Ching ms_set_err_code(chip, MS_BREQ_ERROR); 1647031366eaSJoe Perches rtsx_trace(chip); 1648031366eaSJoe Perches return STATUS_FAIL; 1649fa590c22SMicky Ching } 1650fa590c22SMicky Ching } 1651fa590c22SMicky Ching } 1652fa590c22SMicky Ching 1653fa590c22SMicky Ching retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA, 1654fa590c22SMicky Ching 0, NO_WAIT_INT); 1655031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1656031366eaSJoe Perches rtsx_trace(chip); 1657031366eaSJoe Perches return STATUS_FAIL; 1658031366eaSJoe Perches } 1659fa590c22SMicky Ching 1660031366eaSJoe Perches if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) { 1661031366eaSJoe Perches rtsx_trace(chip); 1662031366eaSJoe Perches return STATUS_FAIL; 1663031366eaSJoe Perches } 1664fa590c22SMicky Ching 1665fa590c22SMicky Ching return STATUS_SUCCESS; 1666fa590c22SMicky Ching } 1667fa590c22SMicky Ching 1668fa590c22SMicky Ching static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk) 1669fa590c22SMicky Ching { 1670d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 1671fa590c22SMicky Ching int retval; 1672fa590c22SMicky Ching u8 val, data[8], extra[MS_EXTRA_SIZE]; 1673fa590c22SMicky Ching 1674fa590c22SMicky Ching retval = ms_read_extra_data(chip, phy_blk, 0, extra, MS_EXTRA_SIZE); 1675031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1676031366eaSJoe Perches rtsx_trace(chip); 1677031366eaSJoe Perches return STATUS_FAIL; 1678031366eaSJoe Perches } 1679fa590c22SMicky Ching 1680fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 1681fa590c22SMicky Ching SystemParm, 7); 1682031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1683031366eaSJoe Perches rtsx_trace(chip); 1684031366eaSJoe Perches return STATUS_FAIL; 1685031366eaSJoe Perches } 1686fa590c22SMicky Ching 1687fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1688fa590c22SMicky Ching 1689fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 1690fa590c22SMicky Ching data[0] = 0x88; 1691fa590c22SMicky Ching else 1692fa590c22SMicky Ching data[0] = 0x80; 1693fa590c22SMicky Ching 1694fa590c22SMicky Ching data[1] = 0; 1695fa590c22SMicky Ching data[2] = (u8)(phy_blk >> 8); 1696fa590c22SMicky Ching data[3] = (u8)phy_blk; 1697fa590c22SMicky Ching data[4] = 0x80; 1698fa590c22SMicky Ching data[5] = 0; 1699fa590c22SMicky Ching data[6] = extra[0] & 0x7F; 1700fa590c22SMicky Ching data[7] = 0xFF; 1701fa590c22SMicky Ching 1702fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 7); 1703031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1704031366eaSJoe Perches rtsx_trace(chip); 1705031366eaSJoe Perches return STATUS_FAIL; 1706031366eaSJoe Perches } 1707fa590c22SMicky Ching 1708fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); 1709031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1710031366eaSJoe Perches rtsx_trace(chip); 1711031366eaSJoe Perches return STATUS_FAIL; 1712031366eaSJoe Perches } 1713fa590c22SMicky Ching 1714fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1715fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 1716031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1717031366eaSJoe Perches rtsx_trace(chip); 1718031366eaSJoe Perches return STATUS_FAIL; 1719031366eaSJoe Perches } 1720fa590c22SMicky Ching 1721fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 1722fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 1723031366eaSJoe Perches rtsx_trace(chip); 1724031366eaSJoe Perches return STATUS_FAIL; 1725fa590c22SMicky Ching } 1726fa590c22SMicky Ching 1727fa590c22SMicky Ching if (val & INT_REG_CED) { 1728fa590c22SMicky Ching if (val & INT_REG_ERR) { 1729fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 1730031366eaSJoe Perches rtsx_trace(chip); 1731031366eaSJoe Perches return STATUS_FAIL; 1732fa590c22SMicky Ching } 1733fa590c22SMicky Ching } 1734fa590c22SMicky Ching 1735fa590c22SMicky Ching return STATUS_SUCCESS; 1736fa590c22SMicky Ching } 1737fa590c22SMicky Ching 1738fa590c22SMicky Ching static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk) 1739fa590c22SMicky Ching { 1740d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 1741fa590c22SMicky Ching int retval, i = 0; 1742fa590c22SMicky Ching u8 val, data[6]; 1743fa590c22SMicky Ching 1744fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 1745fa590c22SMicky Ching SystemParm, 6); 1746031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1747031366eaSJoe Perches rtsx_trace(chip); 1748031366eaSJoe Perches return STATUS_FAIL; 1749031366eaSJoe Perches } 1750fa590c22SMicky Ching 1751fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1752fa590c22SMicky Ching 1753fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 1754fa590c22SMicky Ching data[0] = 0x88; 1755fa590c22SMicky Ching else 1756fa590c22SMicky Ching data[0] = 0x80; 1757fa590c22SMicky Ching 1758fa590c22SMicky Ching data[1] = 0; 1759fa590c22SMicky Ching data[2] = (u8)(phy_blk >> 8); 1760fa590c22SMicky Ching data[3] = (u8)phy_blk; 1761fa590c22SMicky Ching data[4] = 0; 1762fa590c22SMicky Ching data[5] = 0; 1763fa590c22SMicky Ching 1764fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6); 1765031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1766031366eaSJoe Perches rtsx_trace(chip); 1767031366eaSJoe Perches return STATUS_FAIL; 1768031366eaSJoe Perches } 1769fa590c22SMicky Ching 1770fa590c22SMicky Ching ERASE_RTY: 1771fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_ERASE, WAIT_INT); 1772031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1773031366eaSJoe Perches rtsx_trace(chip); 1774031366eaSJoe Perches return STATUS_FAIL; 1775031366eaSJoe Perches } 1776fa590c22SMicky Ching 1777fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1778fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 1779031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1780031366eaSJoe Perches rtsx_trace(chip); 1781031366eaSJoe Perches return STATUS_FAIL; 1782031366eaSJoe Perches } 1783fa590c22SMicky Ching 1784fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 1785fa590c22SMicky Ching if (i < 3) { 1786fa590c22SMicky Ching i++; 1787fa590c22SMicky Ching goto ERASE_RTY; 1788fa590c22SMicky Ching } 1789fa590c22SMicky Ching 1790fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 1791fa590c22SMicky Ching ms_set_bad_block(chip, phy_blk); 1792031366eaSJoe Perches rtsx_trace(chip); 1793031366eaSJoe Perches return STATUS_FAIL; 1794fa590c22SMicky Ching } 1795fa590c22SMicky Ching 1796fa590c22SMicky Ching if (val & INT_REG_CED) { 1797fa590c22SMicky Ching if (val & INT_REG_ERR) { 1798fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 1799031366eaSJoe Perches rtsx_trace(chip); 1800031366eaSJoe Perches return STATUS_FAIL; 1801fa590c22SMicky Ching } 1802fa590c22SMicky Ching } 1803fa590c22SMicky Ching 1804fa590c22SMicky Ching return STATUS_SUCCESS; 1805fa590c22SMicky Ching } 1806fa590c22SMicky Ching 1807fa590c22SMicky Ching static void ms_set_page_status(u16 log_blk, u8 type, u8 *extra, int extra_len) 1808fa590c22SMicky Ching { 1809fa590c22SMicky Ching if (!extra || (extra_len < MS_EXTRA_SIZE)) 1810fa590c22SMicky Ching return; 1811fa590c22SMicky Ching 1812fa590c22SMicky Ching memset(extra, 0xFF, MS_EXTRA_SIZE); 1813fa590c22SMicky Ching 1814fa590c22SMicky Ching if (type == setPS_NG) { 1815fa590c22SMicky Ching /* set page status as 1:NG,and block status keep 1:OK */ 1816fa590c22SMicky Ching extra[0] = 0xB8; 1817fa590c22SMicky Ching } else { 1818fa590c22SMicky Ching /* set page status as 0:Data Error,and block status keep 1:OK */ 1819fa590c22SMicky Ching extra[0] = 0x98; 1820fa590c22SMicky Ching } 1821fa590c22SMicky Ching 1822fa590c22SMicky Ching extra[2] = (u8)(log_blk >> 8); 1823fa590c22SMicky Ching extra[3] = (u8)log_blk; 1824fa590c22SMicky Ching } 1825fa590c22SMicky Ching 1826fa590c22SMicky Ching static int ms_init_page(struct rtsx_chip *chip, u16 phy_blk, u16 log_blk, 1827fa590c22SMicky Ching u8 start_page, u8 end_page) 1828fa590c22SMicky Ching { 1829fa590c22SMicky Ching int retval; 1830fa590c22SMicky Ching u8 extra[MS_EXTRA_SIZE], i; 1831fa590c22SMicky Ching 1832fa590c22SMicky Ching memset(extra, 0xff, MS_EXTRA_SIZE); 1833fa590c22SMicky Ching 1834fa590c22SMicky Ching extra[0] = 0xf8; /* Block, page OK, data erased */ 1835fa590c22SMicky Ching extra[1] = 0xff; 1836fa590c22SMicky Ching extra[2] = (u8)(log_blk >> 8); 1837fa590c22SMicky Ching extra[3] = (u8)log_blk; 1838fa590c22SMicky Ching 1839fa590c22SMicky Ching for (i = start_page; i < end_page; i++) { 1840fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 1841fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_CARD); 1842031366eaSJoe Perches rtsx_trace(chip); 1843031366eaSJoe Perches return STATUS_FAIL; 1844fa590c22SMicky Ching } 1845fa590c22SMicky Ching 1846fa590c22SMicky Ching retval = ms_write_extra_data(chip, phy_blk, i, 1847fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 1848031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1849031366eaSJoe Perches rtsx_trace(chip); 1850031366eaSJoe Perches return STATUS_FAIL; 1851031366eaSJoe Perches } 1852fa590c22SMicky Ching } 1853fa590c22SMicky Ching 1854fa590c22SMicky Ching return STATUS_SUCCESS; 1855fa590c22SMicky Ching } 1856fa590c22SMicky Ching 1857fa590c22SMicky Ching static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, 1858fa590c22SMicky Ching u16 log_blk, u8 start_page, u8 end_page) 1859fa590c22SMicky Ching { 1860d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 1861de904bf0SQuentin Lambert bool uncorrect_flag = false; 1862de904bf0SQuentin Lambert int retval, rty_cnt; 1863fa590c22SMicky Ching u8 extra[MS_EXTRA_SIZE], val, i, j, data[16]; 1864fa590c22SMicky Ching 1865bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Copy page from 0x%x to 0x%x, logical block is 0x%x\n", 1866fa590c22SMicky Ching old_blk, new_blk, log_blk); 1867bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d\n", 1868bf6c0d11SFabio Falzoi start_page, end_page); 1869fa590c22SMicky Ching 1870fa590c22SMicky Ching retval = ms_read_extra_data(chip, new_blk, 0, extra, MS_EXTRA_SIZE); 1871031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1872031366eaSJoe Perches rtsx_trace(chip); 1873031366eaSJoe Perches return STATUS_FAIL; 1874031366eaSJoe Perches } 1875fa590c22SMicky Ching 1876fa590c22SMicky Ching retval = ms_read_status_reg(chip); 1877031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1878031366eaSJoe Perches rtsx_trace(chip); 1879031366eaSJoe Perches return STATUS_FAIL; 1880031366eaSJoe Perches } 1881fa590c22SMicky Ching 18828ee775f9SJoe Perches retval = rtsx_read_register(chip, PPBUF_BASE2, &val); 18838ee775f9SJoe Perches if (retval) { 18848ee775f9SJoe Perches rtsx_trace(chip); 18858ee775f9SJoe Perches return retval; 18868ee775f9SJoe Perches } 1887fa590c22SMicky Ching 1888fa590c22SMicky Ching if (val & BUF_FULL) { 1889fa590c22SMicky Ching retval = ms_send_cmd(chip, CLEAR_BUF, WAIT_INT); 1890031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1891031366eaSJoe Perches rtsx_trace(chip); 1892031366eaSJoe Perches return STATUS_FAIL; 1893031366eaSJoe Perches } 1894fa590c22SMicky Ching 1895fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 1896031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1897031366eaSJoe Perches rtsx_trace(chip); 1898031366eaSJoe Perches return STATUS_FAIL; 1899031366eaSJoe Perches } 1900fa590c22SMicky Ching 1901fa590c22SMicky Ching if (!(val & INT_REG_CED)) { 1902fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 1903031366eaSJoe Perches rtsx_trace(chip); 1904031366eaSJoe Perches return STATUS_FAIL; 1905fa590c22SMicky Ching } 1906fa590c22SMicky Ching } 1907fa590c22SMicky Ching 1908fa590c22SMicky Ching for (i = start_page; i < end_page; i++) { 1909fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 1910fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_CARD); 1911031366eaSJoe Perches rtsx_trace(chip); 1912031366eaSJoe Perches return STATUS_FAIL; 1913fa590c22SMicky Ching } 1914fa590c22SMicky Ching 1915fa590c22SMicky Ching ms_read_extra_data(chip, old_blk, i, extra, MS_EXTRA_SIZE); 1916fa590c22SMicky Ching 1917fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, 1918fa590c22SMicky Ching MS_EXTRA_SIZE, SystemParm, 6); 1919031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1920031366eaSJoe Perches rtsx_trace(chip); 1921031366eaSJoe Perches return STATUS_FAIL; 1922031366eaSJoe Perches } 1923fa590c22SMicky Ching 1924fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1925fa590c22SMicky Ching 1926fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 1927fa590c22SMicky Ching data[0] = 0x88; 1928fa590c22SMicky Ching else 1929fa590c22SMicky Ching data[0] = 0x80; 1930fa590c22SMicky Ching 1931fa590c22SMicky Ching data[1] = 0; 1932fa590c22SMicky Ching data[2] = (u8)(old_blk >> 8); 1933fa590c22SMicky Ching data[3] = (u8)old_blk; 1934fa590c22SMicky Ching data[4] = 0x20; 1935fa590c22SMicky Ching data[5] = i; 1936fa590c22SMicky Ching 1937fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, 1938fa590c22SMicky Ching data, 6); 1939031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1940031366eaSJoe Perches rtsx_trace(chip); 1941031366eaSJoe Perches return STATUS_FAIL; 1942031366eaSJoe Perches } 1943fa590c22SMicky Ching 1944fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); 1945031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1946031366eaSJoe Perches rtsx_trace(chip); 1947031366eaSJoe Perches return STATUS_FAIL; 1948031366eaSJoe Perches } 1949fa590c22SMicky Ching 1950fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 1951fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 1952031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1953031366eaSJoe Perches rtsx_trace(chip); 1954031366eaSJoe Perches return STATUS_FAIL; 1955031366eaSJoe Perches } 1956fa590c22SMicky Ching 1957fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 1958fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 1959031366eaSJoe Perches rtsx_trace(chip); 1960031366eaSJoe Perches return STATUS_FAIL; 1961fa590c22SMicky Ching } 1962fa590c22SMicky Ching 1963fa590c22SMicky Ching if (val & INT_REG_CED) { 1964fa590c22SMicky Ching if (val & INT_REG_ERR) { 1965fa590c22SMicky Ching retval = ms_read_status_reg(chip); 1966fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 1967de904bf0SQuentin Lambert uncorrect_flag = true; 1968bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Uncorrectable error\n"); 1969fa590c22SMicky Ching } else { 1970de904bf0SQuentin Lambert uncorrect_flag = false; 1971fa590c22SMicky Ching } 1972fa590c22SMicky Ching 1973fa590c22SMicky Ching retval = ms_transfer_tpc(chip, 1974fa590c22SMicky Ching MS_TM_NORMAL_READ, 1975fa590c22SMicky Ching READ_PAGE_DATA, 1976fa590c22SMicky Ching 0, NO_WAIT_INT); 1977031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 1978031366eaSJoe Perches rtsx_trace(chip); 1979031366eaSJoe Perches return STATUS_FAIL; 1980031366eaSJoe Perches } 1981fa590c22SMicky Ching 1982fa590c22SMicky Ching if (uncorrect_flag) { 1983fa590c22SMicky Ching ms_set_page_status(log_blk, setPS_NG, 1984fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 1985fa590c22SMicky Ching if (i == 0) 1986fa590c22SMicky Ching extra[0] &= 0xEF; 1987fa590c22SMicky Ching 1988fa590c22SMicky Ching ms_write_extra_data(chip, old_blk, i, 1989fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 1990bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "page %d : extra[0] = 0x%x\n", 1991bf6c0d11SFabio Falzoi i, extra[0]); 1992fa590c22SMicky Ching MS_SET_BAD_BLOCK_FLG(ms_card); 1993fa590c22SMicky Ching 1994fa590c22SMicky Ching ms_set_page_status(log_blk, setPS_Error, 1995fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 1996fa590c22SMicky Ching ms_write_extra_data(chip, new_blk, i, 1997fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 1998fa590c22SMicky Ching continue; 1999fa590c22SMicky Ching } 2000fa590c22SMicky Ching 2001fa590c22SMicky Ching for (rty_cnt = 0; rty_cnt < MS_MAX_RETRY_COUNT; 2002fa590c22SMicky Ching rty_cnt++) { 2003fa590c22SMicky Ching retval = ms_transfer_tpc( 2004fa590c22SMicky Ching chip, 2005fa590c22SMicky Ching MS_TM_NORMAL_WRITE, 2006fa590c22SMicky Ching WRITE_PAGE_DATA, 2007fa590c22SMicky Ching 0, NO_WAIT_INT); 2008fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 2009fa590c22SMicky Ching break; 2010fa590c22SMicky Ching } 2011031366eaSJoe Perches if (rty_cnt == MS_MAX_RETRY_COUNT) { 2012031366eaSJoe Perches rtsx_trace(chip); 2013031366eaSJoe Perches return STATUS_FAIL; 2014031366eaSJoe Perches } 2015fa590c22SMicky Ching } 2016fa590c22SMicky Ching 2017fa590c22SMicky Ching if (!(val & INT_REG_BREQ)) { 2018fa590c22SMicky Ching ms_set_err_code(chip, MS_BREQ_ERROR); 2019031366eaSJoe Perches rtsx_trace(chip); 2020031366eaSJoe Perches return STATUS_FAIL; 2021fa590c22SMicky Ching } 2022fa590c22SMicky Ching } 2023fa590c22SMicky Ching 2024fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, 2025fa590c22SMicky Ching MS_EXTRA_SIZE, SystemParm, (6 + MS_EXTRA_SIZE)); 2026fa590c22SMicky Ching 2027fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 2028fa590c22SMicky Ching 2029fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 2030fa590c22SMicky Ching data[0] = 0x88; 2031fa590c22SMicky Ching else 2032fa590c22SMicky Ching data[0] = 0x80; 2033fa590c22SMicky Ching 2034fa590c22SMicky Ching data[1] = 0; 2035fa590c22SMicky Ching data[2] = (u8)(new_blk >> 8); 2036fa590c22SMicky Ching data[3] = (u8)new_blk; 2037fa590c22SMicky Ching data[4] = 0x20; 2038fa590c22SMicky Ching data[5] = i; 2039fa590c22SMicky Ching 2040fa590c22SMicky Ching if ((extra[0] & 0x60) != 0x60) 2041fa590c22SMicky Ching data[6] = extra[0]; 2042fa590c22SMicky Ching else 2043fa590c22SMicky Ching data[6] = 0xF8; 2044fa590c22SMicky Ching 2045fa590c22SMicky Ching data[6 + 1] = 0xFF; 2046fa590c22SMicky Ching data[6 + 2] = (u8)(log_blk >> 8); 2047fa590c22SMicky Ching data[6 + 3] = (u8)log_blk; 2048fa590c22SMicky Ching 2049fa590c22SMicky Ching for (j = 4; j <= MS_EXTRA_SIZE; j++) 2050fa590c22SMicky Ching data[6 + j] = 0xFF; 2051fa590c22SMicky Ching 2052fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE), 2053fa590c22SMicky Ching NO_WAIT_INT, data, 16); 2054031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2055031366eaSJoe Perches rtsx_trace(chip); 2056031366eaSJoe Perches return STATUS_FAIL; 2057031366eaSJoe Perches } 2058fa590c22SMicky Ching 2059fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); 2060031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2061031366eaSJoe Perches rtsx_trace(chip); 2062031366eaSJoe Perches return STATUS_FAIL; 2063031366eaSJoe Perches } 2064fa590c22SMicky Ching 2065fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 2066fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 2067031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2068031366eaSJoe Perches rtsx_trace(chip); 2069031366eaSJoe Perches return STATUS_FAIL; 2070031366eaSJoe Perches } 2071fa590c22SMicky Ching 2072fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 2073fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 2074031366eaSJoe Perches rtsx_trace(chip); 2075031366eaSJoe Perches return STATUS_FAIL; 2076fa590c22SMicky Ching } 2077fa590c22SMicky Ching 2078fa590c22SMicky Ching if (val & INT_REG_CED) { 2079fa590c22SMicky Ching if (val & INT_REG_ERR) { 2080fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 2081031366eaSJoe Perches rtsx_trace(chip); 2082031366eaSJoe Perches return STATUS_FAIL; 2083fa590c22SMicky Ching } 2084fa590c22SMicky Ching } 2085fa590c22SMicky Ching 2086fa590c22SMicky Ching if (i == 0) { 2087fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, 2088fa590c22SMicky Ching MS_EXTRA_SIZE, SystemParm, 7); 2089031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2090031366eaSJoe Perches rtsx_trace(chip); 2091031366eaSJoe Perches return STATUS_FAIL; 2092031366eaSJoe Perches } 2093fa590c22SMicky Ching 2094fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 2095fa590c22SMicky Ching 2096fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 2097fa590c22SMicky Ching data[0] = 0x88; 2098fa590c22SMicky Ching else 2099fa590c22SMicky Ching data[0] = 0x80; 2100fa590c22SMicky Ching 2101fa590c22SMicky Ching data[1] = 0; 2102fa590c22SMicky Ching data[2] = (u8)(old_blk >> 8); 2103fa590c22SMicky Ching data[3] = (u8)old_blk; 2104fa590c22SMicky Ching data[4] = 0x80; 2105fa590c22SMicky Ching data[5] = 0; 2106fa590c22SMicky Ching data[6] = 0xEF; 2107fa590c22SMicky Ching data[7] = 0xFF; 2108fa590c22SMicky Ching 2109fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 7, 2110fa590c22SMicky Ching NO_WAIT_INT, data, 8); 2111031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2112031366eaSJoe Perches rtsx_trace(chip); 2113031366eaSJoe Perches return STATUS_FAIL; 2114031366eaSJoe Perches } 2115fa590c22SMicky Ching 2116fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); 2117031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2118031366eaSJoe Perches rtsx_trace(chip); 2119031366eaSJoe Perches return STATUS_FAIL; 2120031366eaSJoe Perches } 2121fa590c22SMicky Ching 2122fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 2123fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, 2124fa590c22SMicky Ching NO_WAIT_INT, &val, 1); 2125031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2126031366eaSJoe Perches rtsx_trace(chip); 2127031366eaSJoe Perches return STATUS_FAIL; 2128031366eaSJoe Perches } 2129fa590c22SMicky Ching 2130fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 2131fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 2132031366eaSJoe Perches rtsx_trace(chip); 2133031366eaSJoe Perches return STATUS_FAIL; 2134fa590c22SMicky Ching } 2135fa590c22SMicky Ching 2136fa590c22SMicky Ching if (val & INT_REG_CED) { 2137fa590c22SMicky Ching if (val & INT_REG_ERR) { 2138fa590c22SMicky Ching ms_set_err_code(chip, 2139fa590c22SMicky Ching MS_FLASH_WRITE_ERROR); 2140031366eaSJoe Perches rtsx_trace(chip); 2141031366eaSJoe Perches return STATUS_FAIL; 2142fa590c22SMicky Ching } 2143fa590c22SMicky Ching } 2144fa590c22SMicky Ching } 2145fa590c22SMicky Ching } 2146fa590c22SMicky Ching 2147fa590c22SMicky Ching return STATUS_SUCCESS; 2148fa590c22SMicky Ching } 2149fa590c22SMicky Ching 2150fa590c22SMicky Ching static int reset_ms(struct rtsx_chip *chip) 2151fa590c22SMicky Ching { 2152d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2153fa590c22SMicky Ching int retval; 2154fa590c22SMicky Ching u16 i, reg_addr, block_size; 2155fa590c22SMicky Ching u8 val, extra[MS_EXTRA_SIZE], j, *ptr; 2156fa590c22SMicky Ching #ifndef SUPPORT_MAGIC_GATE 2157fa590c22SMicky Ching u16 eblock_cnt; 2158fa590c22SMicky Ching #endif 2159fa590c22SMicky Ching 2160fa590c22SMicky Ching retval = ms_prepare_reset(chip); 2161031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2162031366eaSJoe Perches rtsx_trace(chip); 2163031366eaSJoe Perches return STATUS_FAIL; 2164031366eaSJoe Perches } 2165fa590c22SMicky Ching 2166fa590c22SMicky Ching ms_card->ms_type |= TYPE_MS; 2167fa590c22SMicky Ching 2168fa590c22SMicky Ching retval = ms_send_cmd(chip, MS_RESET, NO_WAIT_INT); 2169031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2170031366eaSJoe Perches rtsx_trace(chip); 2171031366eaSJoe Perches return STATUS_FAIL; 2172031366eaSJoe Perches } 2173fa590c22SMicky Ching 2174fa590c22SMicky Ching retval = ms_read_status_reg(chip); 2175031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2176031366eaSJoe Perches rtsx_trace(chip); 2177031366eaSJoe Perches return STATUS_FAIL; 2178031366eaSJoe Perches } 2179fa590c22SMicky Ching 21808ee775f9SJoe Perches retval = rtsx_read_register(chip, PPBUF_BASE2, &val); 21818ee775f9SJoe Perches if (retval) { 21828ee775f9SJoe Perches rtsx_trace(chip); 21838ee775f9SJoe Perches return retval; 21848ee775f9SJoe Perches } 2185fa590c22SMicky Ching if (val & WRT_PRTCT) 2186fa590c22SMicky Ching chip->card_wp |= MS_CARD; 2187fa590c22SMicky Ching else 2188fa590c22SMicky Ching chip->card_wp &= ~MS_CARD; 2189fa590c22SMicky Ching 2190fa590c22SMicky Ching i = 0; 2191fa590c22SMicky Ching 2192fa590c22SMicky Ching RE_SEARCH: 2193fa590c22SMicky Ching /* Search Boot Block */ 2194fa590c22SMicky Ching while (i < (MAX_DEFECTIVE_BLOCK + 2)) { 2195fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 2196fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_CARD); 2197031366eaSJoe Perches rtsx_trace(chip); 2198031366eaSJoe Perches return STATUS_FAIL; 2199fa590c22SMicky Ching } 2200fa590c22SMicky Ching 2201fa590c22SMicky Ching retval = ms_read_extra_data(chip, i, 0, extra, MS_EXTRA_SIZE); 2202fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 2203fa590c22SMicky Ching i++; 2204fa590c22SMicky Ching continue; 2205fa590c22SMicky Ching } 2206fa590c22SMicky Ching 2207fa590c22SMicky Ching if (extra[0] & BLOCK_OK) { 2208fa590c22SMicky Ching if (!(extra[1] & NOT_BOOT_BLOCK)) { 2209fa590c22SMicky Ching ms_card->boot_block = i; 2210fa590c22SMicky Ching break; 2211fa590c22SMicky Ching } 2212fa590c22SMicky Ching } 2213fa590c22SMicky Ching i++; 2214fa590c22SMicky Ching } 2215fa590c22SMicky Ching 2216fa590c22SMicky Ching if (i == (MAX_DEFECTIVE_BLOCK + 2)) { 2217bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "No boot block found!"); 2218031366eaSJoe Perches rtsx_trace(chip); 2219031366eaSJoe Perches return STATUS_FAIL; 2220fa590c22SMicky Ching } 2221fa590c22SMicky Ching 2222fa590c22SMicky Ching for (j = 0; j < 3; j++) { 2223fa590c22SMicky Ching retval = ms_read_page(chip, ms_card->boot_block, j); 2224fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 2225fa590c22SMicky Ching if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) { 2226fa590c22SMicky Ching i = ms_card->boot_block + 1; 2227fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 2228fa590c22SMicky Ching goto RE_SEARCH; 2229fa590c22SMicky Ching } 2230fa590c22SMicky Ching } 2231fa590c22SMicky Ching } 2232fa590c22SMicky Ching 2233fa590c22SMicky Ching retval = ms_read_page(chip, ms_card->boot_block, 0); 2234031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2235031366eaSJoe Perches rtsx_trace(chip); 2236031366eaSJoe Perches return STATUS_FAIL; 2237031366eaSJoe Perches } 2238fa590c22SMicky Ching 2239fa590c22SMicky Ching /* Read MS system information as sys_info */ 2240fa590c22SMicky Ching rtsx_init_cmd(chip); 2241fa590c22SMicky Ching 2242fa590c22SMicky Ching for (i = 0; i < 96; i++) 2243fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 0x1A0 + i, 0, 0); 2244fa590c22SMicky Ching 2245fa590c22SMicky Ching retval = rtsx_send_cmd(chip, MS_CARD, 100); 2246031366eaSJoe Perches if (retval < 0) { 2247031366eaSJoe Perches rtsx_trace(chip); 2248031366eaSJoe Perches return STATUS_FAIL; 2249031366eaSJoe Perches } 2250fa590c22SMicky Ching 2251fa590c22SMicky Ching ptr = rtsx_get_cmd_data(chip); 2252fa590c22SMicky Ching memcpy(ms_card->raw_sys_info, ptr, 96); 2253fa590c22SMicky Ching 2254fa590c22SMicky Ching /* Read useful block contents */ 2255fa590c22SMicky Ching rtsx_init_cmd(chip); 2256fa590c22SMicky Ching 2257fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID0, 0, 0); 2258fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID1, 0, 0); 2259fa590c22SMicky Ching 2260fa590c22SMicky Ching for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3; 2261fa590c22SMicky Ching reg_addr++) 2262fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); 2263fa590c22SMicky Ching 2264fa590c22SMicky Ching for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++) 2265fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); 2266fa590c22SMicky Ching 2267fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, MS_Device_Type, 0, 0); 2268fa590c22SMicky Ching rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_Support, 0, 0); 2269fa590c22SMicky Ching 2270fa590c22SMicky Ching retval = rtsx_send_cmd(chip, MS_CARD, 100); 2271031366eaSJoe Perches if (retval < 0) { 2272031366eaSJoe Perches rtsx_trace(chip); 2273031366eaSJoe Perches return STATUS_FAIL; 2274031366eaSJoe Perches } 2275fa590c22SMicky Ching 2276fa590c22SMicky Ching ptr = rtsx_get_cmd_data(chip); 2277fa590c22SMicky Ching 2278bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Boot block data:\n"); 227969b8b224SFabio Falzoi dev_dbg(rtsx_dev(chip), "%*ph\n", 16, ptr); 2280fa590c22SMicky Ching 2281fa590c22SMicky Ching /* Block ID error 2282fa590c22SMicky Ching * HEADER_ID0, HEADER_ID1 2283fa590c22SMicky Ching */ 2284fa590c22SMicky Ching if (ptr[0] != 0x00 || ptr[1] != 0x01) { 2285fa590c22SMicky Ching i = ms_card->boot_block + 1; 2286fa590c22SMicky Ching goto RE_SEARCH; 2287fa590c22SMicky Ching } 2288fa590c22SMicky Ching 2289fa590c22SMicky Ching /* Page size error 2290fa590c22SMicky Ching * PAGE_SIZE_0, PAGE_SIZE_1 2291fa590c22SMicky Ching */ 2292fa590c22SMicky Ching if (ptr[12] != 0x02 || ptr[13] != 0x00) { 2293fa590c22SMicky Ching i = ms_card->boot_block + 1; 2294fa590c22SMicky Ching goto RE_SEARCH; 2295fa590c22SMicky Ching } 2296fa590c22SMicky Ching 2297fa590c22SMicky Ching if ((ptr[14] == 1) || (ptr[14] == 3)) 2298fa590c22SMicky Ching chip->card_wp |= MS_CARD; 2299fa590c22SMicky Ching 2300fa590c22SMicky Ching /* BLOCK_SIZE_0, BLOCK_SIZE_1 */ 2301fa590c22SMicky Ching block_size = ((u16)ptr[6] << 8) | ptr[7]; 2302fa590c22SMicky Ching if (block_size == 0x0010) { 2303fa590c22SMicky Ching /* Block size 16KB */ 2304fa590c22SMicky Ching ms_card->block_shift = 5; 2305fa590c22SMicky Ching ms_card->page_off = 0x1F; 2306fa590c22SMicky Ching } else if (block_size == 0x0008) { 2307fa590c22SMicky Ching /* Block size 8KB */ 2308fa590c22SMicky Ching ms_card->block_shift = 4; 2309fa590c22SMicky Ching ms_card->page_off = 0x0F; 2310fa590c22SMicky Ching } 2311fa590c22SMicky Ching 2312fa590c22SMicky Ching /* BLOCK_COUNT_0, BLOCK_COUNT_1 */ 2313fa590c22SMicky Ching ms_card->total_block = ((u16)ptr[8] << 8) | ptr[9]; 2314fa590c22SMicky Ching 2315fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE 2316fa590c22SMicky Ching j = ptr[10]; 2317fa590c22SMicky Ching 2318fa590c22SMicky Ching if (ms_card->block_shift == 4) { /* 4MB or 8MB */ 2319fa590c22SMicky Ching if (j < 2) { /* Effective block for 4MB: 0x1F0 */ 2320fa590c22SMicky Ching ms_card->capacity = 0x1EE0; 2321fa590c22SMicky Ching } else { /* Effective block for 8MB: 0x3E0 */ 2322fa590c22SMicky Ching ms_card->capacity = 0x3DE0; 2323fa590c22SMicky Ching } 2324fa590c22SMicky Ching } else { /* 16MB, 32MB, 64MB or 128MB */ 2325fa590c22SMicky Ching if (j < 5) { /* Effective block for 16MB: 0x3E0 */ 2326fa590c22SMicky Ching ms_card->capacity = 0x7BC0; 2327fa590c22SMicky Ching } else if (j < 0xA) { /* Effective block for 32MB: 0x7C0 */ 2328fa590c22SMicky Ching ms_card->capacity = 0xF7C0; 2329fa590c22SMicky Ching } else if (j < 0x11) { /* Effective block for 64MB: 0xF80 */ 2330fa590c22SMicky Ching ms_card->capacity = 0x1EF80; 2331fa590c22SMicky Ching } else { /* Effective block for 128MB: 0x1F00 */ 2332fa590c22SMicky Ching ms_card->capacity = 0x3DF00; 2333fa590c22SMicky Ching } 2334fa590c22SMicky Ching } 2335fa590c22SMicky Ching #else 2336fa590c22SMicky Ching /* EBLOCK_COUNT_0, EBLOCK_COUNT_1 */ 2337fa590c22SMicky Ching eblock_cnt = ((u16)ptr[10] << 8) | ptr[11]; 2338fa590c22SMicky Ching 2339fa590c22SMicky Ching ms_card->capacity = ((u32)eblock_cnt - 2) << ms_card->block_shift; 2340fa590c22SMicky Ching #endif 2341fa590c22SMicky Ching 2342fa590c22SMicky Ching chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity; 2343fa590c22SMicky Ching 2344fa590c22SMicky Ching /* Switch I/F Mode */ 2345fa590c22SMicky Ching if (ptr[15]) { 2346fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, 0, 0, SystemParm, 1); 2347031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2348031366eaSJoe Perches rtsx_trace(chip); 2349031366eaSJoe Perches return STATUS_FAIL; 2350031366eaSJoe Perches } 2351fa590c22SMicky Ching 23528ee775f9SJoe Perches retval = rtsx_write_register(chip, PPBUF_BASE2, 0xFF, 0x88); 23538ee775f9SJoe Perches if (retval) { 23548ee775f9SJoe Perches rtsx_trace(chip); 23558ee775f9SJoe Perches return retval; 23568ee775f9SJoe Perches } 23578ee775f9SJoe Perches retval = rtsx_write_register(chip, PPBUF_BASE2 + 1, 0xFF, 0); 23588ee775f9SJoe Perches if (retval) { 23598ee775f9SJoe Perches rtsx_trace(chip); 23608ee775f9SJoe Perches return retval; 23618ee775f9SJoe Perches } 2362fa590c22SMicky Ching 2363fa590c22SMicky Ching retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG, 1, 2364fa590c22SMicky Ching NO_WAIT_INT); 2365031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2366031366eaSJoe Perches rtsx_trace(chip); 2367031366eaSJoe Perches return STATUS_FAIL; 2368031366eaSJoe Perches } 2369fa590c22SMicky Ching 23708ee775f9SJoe Perches retval = rtsx_write_register(chip, MS_CFG, 23718ee775f9SJoe Perches 0x58 | MS_NO_CHECK_INT, 2372fa590c22SMicky Ching MS_BUS_WIDTH_4 | PUSH_TIME_ODD | MS_NO_CHECK_INT); 23738ee775f9SJoe Perches if (retval) { 23748ee775f9SJoe Perches rtsx_trace(chip); 23758ee775f9SJoe Perches return retval; 23768ee775f9SJoe Perches } 2377fa590c22SMicky Ching 2378fa590c22SMicky Ching ms_card->ms_type |= MS_4BIT; 2379fa590c22SMicky Ching } 2380fa590c22SMicky Ching 2381fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 2382fa590c22SMicky Ching chip->card_bus_width[chip->card2lun[MS_CARD]] = 4; 2383fa590c22SMicky Ching else 2384fa590c22SMicky Ching chip->card_bus_width[chip->card2lun[MS_CARD]] = 1; 2385fa590c22SMicky Ching 2386fa590c22SMicky Ching return STATUS_SUCCESS; 2387fa590c22SMicky Ching } 2388fa590c22SMicky Ching 2389fa590c22SMicky Ching static int ms_init_l2p_tbl(struct rtsx_chip *chip) 2390fa590c22SMicky Ching { 2391d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2392fa590c22SMicky Ching int size, i, seg_no, retval; 2393fa590c22SMicky Ching u16 defect_block, reg_addr; 2394fa590c22SMicky Ching u8 val1, val2; 2395fa590c22SMicky Ching 2396fa590c22SMicky Ching ms_card->segment_cnt = ms_card->total_block >> 9; 2397bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "ms_card->segment_cnt = %d\n", 2398bf6c0d11SFabio Falzoi ms_card->segment_cnt); 2399fa590c22SMicky Ching 2400fa590c22SMicky Ching size = ms_card->segment_cnt * sizeof(struct zone_entry); 2401fa590c22SMicky Ching ms_card->segment = vzalloc(size); 24027586170cSEva Rachel Retuya if (!ms_card->segment) { 2403031366eaSJoe Perches rtsx_trace(chip); 2404031366eaSJoe Perches return STATUS_FAIL; 2405031366eaSJoe Perches } 2406fa590c22SMicky Ching 2407fa590c22SMicky Ching retval = ms_read_page(chip, ms_card->boot_block, 1); 2408031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2409031366eaSJoe Perches rtsx_trace(chip); 2410031366eaSJoe Perches goto INIT_FAIL; 2411031366eaSJoe Perches } 2412fa590c22SMicky Ching 2413fa590c22SMicky Ching reg_addr = PPBUF_BASE2; 2414fa590c22SMicky Ching for (i = 0; i < (((ms_card->total_block >> 9) * 10) + 1); i++) { 24157ef4ec4aSVatika Harlalka int block_no; 24167ef4ec4aSVatika Harlalka 2417fa590c22SMicky Ching retval = rtsx_read_register(chip, reg_addr++, &val1); 2418031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2419031366eaSJoe Perches rtsx_trace(chip); 2420031366eaSJoe Perches goto INIT_FAIL; 2421031366eaSJoe Perches } 2422fa590c22SMicky Ching 2423fa590c22SMicky Ching retval = rtsx_read_register(chip, reg_addr++, &val2); 2424031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2425031366eaSJoe Perches rtsx_trace(chip); 2426031366eaSJoe Perches goto INIT_FAIL; 2427031366eaSJoe Perches } 2428fa590c22SMicky Ching 2429fa590c22SMicky Ching defect_block = ((u16)val1 << 8) | val2; 2430fa590c22SMicky Ching if (defect_block == 0xFFFF) 2431fa590c22SMicky Ching break; 2432fa590c22SMicky Ching 2433fa590c22SMicky Ching seg_no = defect_block / 512; 24347ef4ec4aSVatika Harlalka 24357ef4ec4aSVatika Harlalka block_no = ms_card->segment[seg_no].disable_count++; 24367ef4ec4aSVatika Harlalka ms_card->segment[seg_no].defect_list[block_no] = defect_block; 2437fa590c22SMicky Ching } 2438fa590c22SMicky Ching 2439fa590c22SMicky Ching for (i = 0; i < ms_card->segment_cnt; i++) { 2440fa590c22SMicky Ching ms_card->segment[i].build_flag = 0; 2441fa590c22SMicky Ching ms_card->segment[i].l2p_table = NULL; 2442fa590c22SMicky Ching ms_card->segment[i].free_table = NULL; 2443fa590c22SMicky Ching ms_card->segment[i].get_index = 0; 2444fa590c22SMicky Ching ms_card->segment[i].set_index = 0; 2445fa590c22SMicky Ching ms_card->segment[i].unused_blk_cnt = 0; 2446fa590c22SMicky Ching 2447bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "defective block count of segment %d is %d\n", 2448fa590c22SMicky Ching i, ms_card->segment[i].disable_count); 2449fa590c22SMicky Ching } 2450fa590c22SMicky Ching 2451fa590c22SMicky Ching return STATUS_SUCCESS; 2452fa590c22SMicky Ching 2453fa590c22SMicky Ching INIT_FAIL: 2454fa590c22SMicky Ching vfree(ms_card->segment); 2455fa590c22SMicky Ching ms_card->segment = NULL; 2456fa590c22SMicky Ching 2457fa590c22SMicky Ching return STATUS_FAIL; 2458fa590c22SMicky Ching } 2459fa590c22SMicky Ching 2460fa590c22SMicky Ching static u16 ms_get_l2p_tbl(struct rtsx_chip *chip, int seg_no, u16 log_off) 2461fa590c22SMicky Ching { 2462d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2463fa590c22SMicky Ching struct zone_entry *segment; 2464fa590c22SMicky Ching 2465e6e1d57eSBhaktipriya Shridhar if (!ms_card->segment) 2466fa590c22SMicky Ching return 0xFFFF; 2467fa590c22SMicky Ching 2468fa590c22SMicky Ching segment = &(ms_card->segment[seg_no]); 2469fa590c22SMicky Ching 2470fa590c22SMicky Ching if (segment->l2p_table) 2471fa590c22SMicky Ching return segment->l2p_table[log_off]; 2472fa590c22SMicky Ching 2473fa590c22SMicky Ching return 0xFFFF; 2474fa590c22SMicky Ching } 2475fa590c22SMicky Ching 2476fa590c22SMicky Ching static void ms_set_l2p_tbl(struct rtsx_chip *chip, 2477fa590c22SMicky Ching int seg_no, u16 log_off, u16 phy_blk) 2478fa590c22SMicky Ching { 2479d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2480fa590c22SMicky Ching struct zone_entry *segment; 2481fa590c22SMicky Ching 2482e6e1d57eSBhaktipriya Shridhar if (!ms_card->segment) 2483fa590c22SMicky Ching return; 2484fa590c22SMicky Ching 2485fa590c22SMicky Ching segment = &(ms_card->segment[seg_no]); 2486fa590c22SMicky Ching if (segment->l2p_table) 2487fa590c22SMicky Ching segment->l2p_table[log_off] = phy_blk; 2488fa590c22SMicky Ching } 2489fa590c22SMicky Ching 2490fa590c22SMicky Ching static void ms_set_unused_block(struct rtsx_chip *chip, u16 phy_blk) 2491fa590c22SMicky Ching { 2492d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2493fa590c22SMicky Ching struct zone_entry *segment; 2494fa590c22SMicky Ching int seg_no; 2495fa590c22SMicky Ching 2496fa590c22SMicky Ching seg_no = (int)phy_blk >> 9; 2497fa590c22SMicky Ching segment = &(ms_card->segment[seg_no]); 2498fa590c22SMicky Ching 2499fa590c22SMicky Ching segment->free_table[segment->set_index++] = phy_blk; 2500fa590c22SMicky Ching if (segment->set_index >= MS_FREE_TABLE_CNT) 2501fa590c22SMicky Ching segment->set_index = 0; 2502fa590c22SMicky Ching 2503fa590c22SMicky Ching segment->unused_blk_cnt++; 2504fa590c22SMicky Ching } 2505fa590c22SMicky Ching 2506fa590c22SMicky Ching static u16 ms_get_unused_block(struct rtsx_chip *chip, int seg_no) 2507fa590c22SMicky Ching { 2508d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2509fa590c22SMicky Ching struct zone_entry *segment; 2510fa590c22SMicky Ching u16 phy_blk; 2511fa590c22SMicky Ching 2512fa590c22SMicky Ching segment = &(ms_card->segment[seg_no]); 2513fa590c22SMicky Ching 2514fa590c22SMicky Ching if (segment->unused_blk_cnt <= 0) 2515fa590c22SMicky Ching return 0xFFFF; 2516fa590c22SMicky Ching 2517fa590c22SMicky Ching phy_blk = segment->free_table[segment->get_index]; 2518fa590c22SMicky Ching segment->free_table[segment->get_index++] = 0xFFFF; 2519fa590c22SMicky Ching if (segment->get_index >= MS_FREE_TABLE_CNT) 2520fa590c22SMicky Ching segment->get_index = 0; 2521fa590c22SMicky Ching 2522fa590c22SMicky Ching segment->unused_blk_cnt--; 2523fa590c22SMicky Ching 2524fa590c22SMicky Ching return phy_blk; 2525fa590c22SMicky Ching } 2526fa590c22SMicky Ching 2527fa590c22SMicky Ching static const unsigned short ms_start_idx[] = {0, 494, 990, 1486, 1982, 2478, 2528fa590c22SMicky Ching 2974, 3470, 3966, 4462, 4958, 2529fa590c22SMicky Ching 5454, 5950, 6446, 6942, 7438, 2530fa590c22SMicky Ching 7934}; 2531fa590c22SMicky Ching 2532fa590c22SMicky Ching static int ms_arbitrate_l2p(struct rtsx_chip *chip, u16 phy_blk, 2533fa590c22SMicky Ching u16 log_off, u8 us1, u8 us2) 2534fa590c22SMicky Ching { 2535d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2536fa590c22SMicky Ching struct zone_entry *segment; 2537fa590c22SMicky Ching int seg_no; 2538fa590c22SMicky Ching u16 tmp_blk; 2539fa590c22SMicky Ching 2540fa590c22SMicky Ching seg_no = (int)phy_blk >> 9; 2541fa590c22SMicky Ching segment = &(ms_card->segment[seg_no]); 2542fa590c22SMicky Ching tmp_blk = segment->l2p_table[log_off]; 2543fa590c22SMicky Ching 2544fa590c22SMicky Ching if (us1 != us2) { 2545fa590c22SMicky Ching if (us1 == 0) { 2546fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) 2547fa590c22SMicky Ching ms_erase_block(chip, tmp_blk); 2548fa590c22SMicky Ching 2549fa590c22SMicky Ching ms_set_unused_block(chip, tmp_blk); 2550fa590c22SMicky Ching segment->l2p_table[log_off] = phy_blk; 2551fa590c22SMicky Ching } else { 2552fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) 2553fa590c22SMicky Ching ms_erase_block(chip, phy_blk); 2554fa590c22SMicky Ching 2555fa590c22SMicky Ching ms_set_unused_block(chip, phy_blk); 2556fa590c22SMicky Ching } 2557fa590c22SMicky Ching } else { 2558fa590c22SMicky Ching if (phy_blk < tmp_blk) { 2559fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) 2560fa590c22SMicky Ching ms_erase_block(chip, phy_blk); 2561fa590c22SMicky Ching 2562fa590c22SMicky Ching ms_set_unused_block(chip, phy_blk); 2563fa590c22SMicky Ching } else { 2564fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) 2565fa590c22SMicky Ching ms_erase_block(chip, tmp_blk); 2566fa590c22SMicky Ching 2567fa590c22SMicky Ching ms_set_unused_block(chip, tmp_blk); 2568fa590c22SMicky Ching segment->l2p_table[log_off] = phy_blk; 2569fa590c22SMicky Ching } 2570fa590c22SMicky Ching } 2571fa590c22SMicky Ching 2572fa590c22SMicky Ching return STATUS_SUCCESS; 2573fa590c22SMicky Ching } 2574fa590c22SMicky Ching 2575fa590c22SMicky Ching static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) 2576fa590c22SMicky Ching { 2577d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2578fa590c22SMicky Ching struct zone_entry *segment; 2579de904bf0SQuentin Lambert bool defect_flag; 2580de904bf0SQuentin Lambert int retval, table_size, disable_cnt, i; 2581127883b8SVatika Harlalka u16 start, end, phy_blk, log_blk, tmp_blk, idx; 2582fa590c22SMicky Ching u8 extra[MS_EXTRA_SIZE], us1, us2; 2583fa590c22SMicky Ching 2584bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "ms_build_l2p_tbl: %d\n", seg_no); 2585fa590c22SMicky Ching 2586e6e1d57eSBhaktipriya Shridhar if (!ms_card->segment) { 2587fa590c22SMicky Ching retval = ms_init_l2p_tbl(chip); 2588031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2589031366eaSJoe Perches rtsx_trace(chip); 2590031366eaSJoe Perches return retval; 2591031366eaSJoe Perches } 2592fa590c22SMicky Ching } 2593fa590c22SMicky Ching 2594fa590c22SMicky Ching if (ms_card->segment[seg_no].build_flag) { 2595bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "l2p table of segment %d has been built\n", 2596bf6c0d11SFabio Falzoi seg_no); 2597fa590c22SMicky Ching return STATUS_SUCCESS; 2598fa590c22SMicky Ching } 2599fa590c22SMicky Ching 2600fa590c22SMicky Ching if (seg_no == 0) 2601fa590c22SMicky Ching table_size = 494; 2602fa590c22SMicky Ching else 2603fa590c22SMicky Ching table_size = 496; 2604fa590c22SMicky Ching 2605fa590c22SMicky Ching segment = &(ms_card->segment[seg_no]); 2606fa590c22SMicky Ching 2607e6e1d57eSBhaktipriya Shridhar if (!segment->l2p_table) { 2608fa590c22SMicky Ching segment->l2p_table = vmalloc(table_size * 2); 26097586170cSEva Rachel Retuya if (!segment->l2p_table) { 2610031366eaSJoe Perches rtsx_trace(chip); 2611031366eaSJoe Perches goto BUILD_FAIL; 2612031366eaSJoe Perches } 2613fa590c22SMicky Ching } 2614fa590c22SMicky Ching memset((u8 *)(segment->l2p_table), 0xff, table_size * 2); 2615fa590c22SMicky Ching 2616e6e1d57eSBhaktipriya Shridhar if (!segment->free_table) { 2617fa590c22SMicky Ching segment->free_table = vmalloc(MS_FREE_TABLE_CNT * 2); 26187586170cSEva Rachel Retuya if (!segment->free_table) { 2619031366eaSJoe Perches rtsx_trace(chip); 2620031366eaSJoe Perches goto BUILD_FAIL; 2621031366eaSJoe Perches } 2622fa590c22SMicky Ching } 2623fa590c22SMicky Ching memset((u8 *)(segment->free_table), 0xff, MS_FREE_TABLE_CNT * 2); 2624fa590c22SMicky Ching 2625fa590c22SMicky Ching start = (u16)seg_no << 9; 2626fa590c22SMicky Ching end = (u16)(seg_no + 1) << 9; 2627fa590c22SMicky Ching 2628fa590c22SMicky Ching disable_cnt = segment->disable_count; 2629fa590c22SMicky Ching 2630fa590c22SMicky Ching segment->get_index = segment->set_index = 0; 2631fa590c22SMicky Ching segment->unused_blk_cnt = 0; 2632fa590c22SMicky Ching 2633fa590c22SMicky Ching for (phy_blk = start; phy_blk < end; phy_blk++) { 2634fa590c22SMicky Ching if (disable_cnt) { 2635de904bf0SQuentin Lambert defect_flag = false; 2636fa590c22SMicky Ching for (i = 0; i < segment->disable_count; i++) { 2637fa590c22SMicky Ching if (phy_blk == segment->defect_list[i]) { 2638de904bf0SQuentin Lambert defect_flag = true; 2639fa590c22SMicky Ching break; 2640fa590c22SMicky Ching } 2641fa590c22SMicky Ching } 2642fa590c22SMicky Ching if (defect_flag) { 2643fa590c22SMicky Ching disable_cnt--; 2644fa590c22SMicky Ching continue; 2645fa590c22SMicky Ching } 2646fa590c22SMicky Ching } 2647fa590c22SMicky Ching 2648fa590c22SMicky Ching retval = ms_read_extra_data(chip, phy_blk, 0, 2649fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 2650fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 2651bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "read extra data fail\n"); 2652fa590c22SMicky Ching ms_set_bad_block(chip, phy_blk); 2653fa590c22SMicky Ching continue; 2654fa590c22SMicky Ching } 2655fa590c22SMicky Ching 2656fa590c22SMicky Ching if (seg_no == ms_card->segment_cnt - 1) { 2657fa590c22SMicky Ching if (!(extra[1] & NOT_TRANSLATION_TABLE)) { 2658fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) { 2659fa590c22SMicky Ching retval = ms_erase_block(chip, phy_blk); 2660fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 2661fa590c22SMicky Ching continue; 2662fa590c22SMicky Ching extra[2] = 0xff; 2663fa590c22SMicky Ching extra[3] = 0xff; 2664fa590c22SMicky Ching } 2665fa590c22SMicky Ching } 2666fa590c22SMicky Ching } 2667fa590c22SMicky Ching 2668fa590c22SMicky Ching if (!(extra[0] & BLOCK_OK)) 2669fa590c22SMicky Ching continue; 2670fa590c22SMicky Ching if (!(extra[1] & NOT_BOOT_BLOCK)) 2671fa590c22SMicky Ching continue; 2672fa590c22SMicky Ching if ((extra[0] & PAGE_OK) != PAGE_OK) 2673fa590c22SMicky Ching continue; 2674fa590c22SMicky Ching 2675fa590c22SMicky Ching log_blk = ((u16)extra[2] << 8) | extra[3]; 2676fa590c22SMicky Ching 2677fa590c22SMicky Ching if (log_blk == 0xFFFF) { 2678fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) { 2679fa590c22SMicky Ching retval = ms_erase_block(chip, phy_blk); 2680fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 2681fa590c22SMicky Ching continue; 2682fa590c22SMicky Ching } 2683fa590c22SMicky Ching ms_set_unused_block(chip, phy_blk); 2684fa590c22SMicky Ching continue; 2685fa590c22SMicky Ching } 2686fa590c22SMicky Ching 2687fa590c22SMicky Ching if ((log_blk < ms_start_idx[seg_no]) || 2688fa590c22SMicky Ching (log_blk >= ms_start_idx[seg_no + 1])) { 2689fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) { 2690fa590c22SMicky Ching retval = ms_erase_block(chip, phy_blk); 2691fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 2692fa590c22SMicky Ching continue; 2693fa590c22SMicky Ching } 2694fa590c22SMicky Ching ms_set_unused_block(chip, phy_blk); 2695fa590c22SMicky Ching continue; 2696fa590c22SMicky Ching } 2697fa590c22SMicky Ching 2698127883b8SVatika Harlalka idx = log_blk - ms_start_idx[seg_no]; 2699127883b8SVatika Harlalka 2700127883b8SVatika Harlalka if (segment->l2p_table[idx] == 0xFFFF) { 2701127883b8SVatika Harlalka segment->l2p_table[idx] = phy_blk; 2702fa590c22SMicky Ching continue; 2703fa590c22SMicky Ching } 2704fa590c22SMicky Ching 2705fa590c22SMicky Ching us1 = extra[0] & 0x10; 2706127883b8SVatika Harlalka tmp_blk = segment->l2p_table[idx]; 2707fa590c22SMicky Ching retval = ms_read_extra_data(chip, tmp_blk, 0, 2708fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 2709fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 2710fa590c22SMicky Ching continue; 2711fa590c22SMicky Ching us2 = extra[0] & 0x10; 2712fa590c22SMicky Ching 2713fa590c22SMicky Ching (void)ms_arbitrate_l2p(chip, phy_blk, 2714fa590c22SMicky Ching log_blk-ms_start_idx[seg_no], us1, us2); 2715fa590c22SMicky Ching continue; 2716fa590c22SMicky Ching } 2717fa590c22SMicky Ching 2718fa590c22SMicky Ching segment->build_flag = 1; 2719fa590c22SMicky Ching 2720bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "unused block count: %d\n", 2721bf6c0d11SFabio Falzoi segment->unused_blk_cnt); 2722fa590c22SMicky Ching 2723fa590c22SMicky Ching /* Logical Address Confirmation Process */ 2724fa590c22SMicky Ching if (seg_no == ms_card->segment_cnt - 1) { 2725fa590c22SMicky Ching if (segment->unused_blk_cnt < 2) 2726fa590c22SMicky Ching chip->card_wp |= MS_CARD; 2727fa590c22SMicky Ching } else { 2728fa590c22SMicky Ching if (segment->unused_blk_cnt < 1) 2729fa590c22SMicky Ching chip->card_wp |= MS_CARD; 2730fa590c22SMicky Ching } 2731fa590c22SMicky Ching 2732fa590c22SMicky Ching if (chip->card_wp & MS_CARD) 2733fa590c22SMicky Ching return STATUS_SUCCESS; 2734fa590c22SMicky Ching 2735fa590c22SMicky Ching for (log_blk = ms_start_idx[seg_no]; 2736fa590c22SMicky Ching log_blk < ms_start_idx[seg_no + 1]; log_blk++) { 2737127883b8SVatika Harlalka idx = log_blk - ms_start_idx[seg_no]; 2738127883b8SVatika Harlalka if (segment->l2p_table[idx] == 0xFFFF) { 2739fa590c22SMicky Ching phy_blk = ms_get_unused_block(chip, seg_no); 2740fa590c22SMicky Ching if (phy_blk == 0xFFFF) { 2741fa590c22SMicky Ching chip->card_wp |= MS_CARD; 2742fa590c22SMicky Ching return STATUS_SUCCESS; 2743fa590c22SMicky Ching } 2744fa590c22SMicky Ching retval = ms_init_page(chip, phy_blk, log_blk, 0, 1); 2745031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2746031366eaSJoe Perches rtsx_trace(chip); 2747031366eaSJoe Perches goto BUILD_FAIL; 2748031366eaSJoe Perches } 2749fa590c22SMicky Ching 2750127883b8SVatika Harlalka segment->l2p_table[idx] = phy_blk; 2751fa590c22SMicky Ching if (seg_no == ms_card->segment_cnt - 1) { 2752fa590c22SMicky Ching if (segment->unused_blk_cnt < 2) { 2753fa590c22SMicky Ching chip->card_wp |= MS_CARD; 2754fa590c22SMicky Ching return STATUS_SUCCESS; 2755fa590c22SMicky Ching } 2756fa590c22SMicky Ching } else { 2757fa590c22SMicky Ching if (segment->unused_blk_cnt < 1) { 2758fa590c22SMicky Ching chip->card_wp |= MS_CARD; 2759fa590c22SMicky Ching return STATUS_SUCCESS; 2760fa590c22SMicky Ching } 2761fa590c22SMicky Ching } 2762fa590c22SMicky Ching } 2763fa590c22SMicky Ching } 2764fa590c22SMicky Ching 2765fa590c22SMicky Ching /* Make boot block be the first normal block */ 2766fa590c22SMicky Ching if (seg_no == 0) { 2767fa590c22SMicky Ching for (log_blk = 0; log_blk < 494; log_blk++) { 2768fa590c22SMicky Ching tmp_blk = segment->l2p_table[log_blk]; 2769fa590c22SMicky Ching if (tmp_blk < ms_card->boot_block) { 2770bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "Boot block is not the first normal block.\n"); 2771fa590c22SMicky Ching 2772fa590c22SMicky Ching if (chip->card_wp & MS_CARD) 2773fa590c22SMicky Ching break; 2774fa590c22SMicky Ching 2775fa590c22SMicky Ching phy_blk = ms_get_unused_block(chip, 0); 2776fa590c22SMicky Ching retval = ms_copy_page(chip, tmp_blk, phy_blk, 2777fa590c22SMicky Ching log_blk, 0, ms_card->page_off + 1); 2778031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2779031366eaSJoe Perches rtsx_trace(chip); 2780031366eaSJoe Perches return STATUS_FAIL; 2781031366eaSJoe Perches } 2782fa590c22SMicky Ching 2783fa590c22SMicky Ching segment->l2p_table[log_blk] = phy_blk; 2784fa590c22SMicky Ching 2785fa590c22SMicky Ching retval = ms_set_bad_block(chip, tmp_blk); 2786031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2787031366eaSJoe Perches rtsx_trace(chip); 2788031366eaSJoe Perches return STATUS_FAIL; 2789031366eaSJoe Perches } 2790fa590c22SMicky Ching } 2791fa590c22SMicky Ching } 2792fa590c22SMicky Ching } 2793fa590c22SMicky Ching 2794fa590c22SMicky Ching return STATUS_SUCCESS; 2795fa590c22SMicky Ching 2796fa590c22SMicky Ching BUILD_FAIL: 2797fa590c22SMicky Ching segment->build_flag = 0; 2798fa590c22SMicky Ching vfree(segment->l2p_table); 2799fa590c22SMicky Ching segment->l2p_table = NULL; 2800fa590c22SMicky Ching vfree(segment->free_table); 2801fa590c22SMicky Ching segment->free_table = NULL; 2802fa590c22SMicky Ching 2803fa590c22SMicky Ching return STATUS_FAIL; 2804fa590c22SMicky Ching } 2805fa590c22SMicky Ching 2806fa590c22SMicky Ching int reset_ms_card(struct rtsx_chip *chip) 2807fa590c22SMicky Ching { 2808d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2809fa590c22SMicky Ching int retval; 2810fa590c22SMicky Ching 2811fa590c22SMicky Ching memset(ms_card, 0, sizeof(struct ms_info)); 2812fa590c22SMicky Ching 2813fa590c22SMicky Ching retval = enable_card_clock(chip, MS_CARD); 2814031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2815031366eaSJoe Perches rtsx_trace(chip); 2816031366eaSJoe Perches return STATUS_FAIL; 2817031366eaSJoe Perches } 2818fa590c22SMicky Ching 2819fa590c22SMicky Ching retval = select_card(chip, MS_CARD); 2820031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2821031366eaSJoe Perches rtsx_trace(chip); 2822031366eaSJoe Perches return STATUS_FAIL; 2823031366eaSJoe Perches } 2824fa590c22SMicky Ching 2825fa590c22SMicky Ching ms_card->ms_type = 0; 2826fa590c22SMicky Ching 2827fa590c22SMicky Ching retval = reset_ms_pro(chip); 2828fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 2829fa590c22SMicky Ching if (ms_card->check_ms_flow) { 2830fa590c22SMicky Ching retval = reset_ms(chip); 2831031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2832031366eaSJoe Perches rtsx_trace(chip); 2833031366eaSJoe Perches return STATUS_FAIL; 2834031366eaSJoe Perches } 2835fa590c22SMicky Ching } else { 2836031366eaSJoe Perches rtsx_trace(chip); 2837031366eaSJoe Perches return STATUS_FAIL; 2838fa590c22SMicky Ching } 2839fa590c22SMicky Ching } 2840fa590c22SMicky Ching 2841fa590c22SMicky Ching retval = ms_set_init_para(chip); 2842031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2843031366eaSJoe Perches rtsx_trace(chip); 2844031366eaSJoe Perches return STATUS_FAIL; 2845031366eaSJoe Perches } 2846fa590c22SMicky Ching 2847fa590c22SMicky Ching if (!CHK_MSPRO(ms_card)) { 2848fa590c22SMicky Ching /* Build table for the last segment, 2849fa590c22SMicky Ching * to check if L2P table block exists, erasing it 2850fa590c22SMicky Ching */ 2851fa590c22SMicky Ching retval = ms_build_l2p_tbl(chip, ms_card->total_block / 512 - 1); 2852031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2853031366eaSJoe Perches rtsx_trace(chip); 2854031366eaSJoe Perches return STATUS_FAIL; 2855031366eaSJoe Perches } 2856fa590c22SMicky Ching } 2857fa590c22SMicky Ching 2858bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "ms_card->ms_type = 0x%x\n", ms_card->ms_type); 2859fa590c22SMicky Ching 2860fa590c22SMicky Ching return STATUS_SUCCESS; 2861fa590c22SMicky Ching } 2862fa590c22SMicky Ching 2863fa590c22SMicky Ching static int mspro_set_rw_cmd(struct rtsx_chip *chip, 2864fa590c22SMicky Ching u32 start_sec, u16 sec_cnt, u8 cmd) 2865fa590c22SMicky Ching { 2866fa590c22SMicky Ching int retval, i; 2867fa590c22SMicky Ching u8 data[8]; 2868fa590c22SMicky Ching 2869fa590c22SMicky Ching data[0] = cmd; 2870fa590c22SMicky Ching data[1] = (u8)(sec_cnt >> 8); 2871fa590c22SMicky Ching data[2] = (u8)sec_cnt; 2872fa590c22SMicky Ching data[3] = (u8)(start_sec >> 24); 2873fa590c22SMicky Ching data[4] = (u8)(start_sec >> 16); 2874fa590c22SMicky Ching data[5] = (u8)(start_sec >> 8); 2875fa590c22SMicky Ching data[6] = (u8)start_sec; 2876fa590c22SMicky Ching data[7] = 0; 2877fa590c22SMicky Ching 2878fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 2879fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7, 2880fa590c22SMicky Ching WAIT_INT, data, 8); 2881fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 2882fa590c22SMicky Ching break; 2883fa590c22SMicky Ching } 2884031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 2885031366eaSJoe Perches rtsx_trace(chip); 2886031366eaSJoe Perches return STATUS_FAIL; 2887031366eaSJoe Perches } 2888fa590c22SMicky Ching 2889fa590c22SMicky Ching return STATUS_SUCCESS; 2890fa590c22SMicky Ching } 2891fa590c22SMicky Ching 2892fa590c22SMicky Ching void mspro_stop_seq_mode(struct rtsx_chip *chip) 2893fa590c22SMicky Ching { 2894d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2895fa590c22SMicky Ching int retval; 2896fa590c22SMicky Ching 2897fa590c22SMicky Ching if (ms_card->seq_mode) { 2898fa590c22SMicky Ching retval = ms_switch_clock(chip); 2899fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 2900fa590c22SMicky Ching return; 2901fa590c22SMicky Ching 2902fa590c22SMicky Ching ms_card->seq_mode = 0; 2903fa590c22SMicky Ching ms_card->total_sec_cnt = 0; 2904fa590c22SMicky Ching ms_send_cmd(chip, PRO_STOP, WAIT_INT); 2905fa590c22SMicky Ching 2906fa590c22SMicky Ching rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); 2907fa590c22SMicky Ching } 2908fa590c22SMicky Ching } 2909fa590c22SMicky Ching 2910fa590c22SMicky Ching static inline int ms_auto_tune_clock(struct rtsx_chip *chip) 2911fa590c22SMicky Ching { 2912d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 2913fa590c22SMicky Ching int retval; 2914fa590c22SMicky Ching 2915fa590c22SMicky Ching if (chip->asic_code) { 2916fa590c22SMicky Ching if (ms_card->ms_clock > 30) 2917fa590c22SMicky Ching ms_card->ms_clock -= 20; 2918fa590c22SMicky Ching } else { 2919fa590c22SMicky Ching if (ms_card->ms_clock == CLK_80) 2920fa590c22SMicky Ching ms_card->ms_clock = CLK_60; 2921fa590c22SMicky Ching else if (ms_card->ms_clock == CLK_60) 2922fa590c22SMicky Ching ms_card->ms_clock = CLK_40; 2923fa590c22SMicky Ching } 2924fa590c22SMicky Ching 2925fa590c22SMicky Ching retval = ms_switch_clock(chip); 2926031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2927031366eaSJoe Perches rtsx_trace(chip); 2928031366eaSJoe Perches return STATUS_FAIL; 2929031366eaSJoe Perches } 2930fa590c22SMicky Ching 2931fa590c22SMicky Ching return STATUS_SUCCESS; 2932fa590c22SMicky Ching } 2933fa590c22SMicky Ching 2934fa590c22SMicky Ching static int mspro_rw_multi_sector(struct scsi_cmnd *srb, 2935fa590c22SMicky Ching struct rtsx_chip *chip, u32 start_sector, 2936fa590c22SMicky Ching u16 sector_cnt) 2937fa590c22SMicky Ching { 2938d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 293911201769SQuentin Lambert bool mode_2k = false; 294011201769SQuentin Lambert int retval; 2941fa590c22SMicky Ching u16 count; 2942fa590c22SMicky Ching u8 val, trans_mode, rw_tpc, rw_cmd; 2943fa590c22SMicky Ching 2944fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 2945fa590c22SMicky Ching 2946fa590c22SMicky Ching ms_card->cleanup_counter = 0; 2947fa590c22SMicky Ching 2948fa590c22SMicky Ching if (CHK_MSHG(ms_card)) { 2949fa590c22SMicky Ching if ((start_sector % 4) || (sector_cnt % 4)) { 2950fa590c22SMicky Ching if (srb->sc_data_direction == DMA_FROM_DEVICE) { 2951fa590c22SMicky Ching rw_tpc = PRO_READ_LONG_DATA; 2952fa590c22SMicky Ching rw_cmd = PRO_READ_DATA; 2953fa590c22SMicky Ching } else { 2954fa590c22SMicky Ching rw_tpc = PRO_WRITE_LONG_DATA; 2955fa590c22SMicky Ching rw_cmd = PRO_WRITE_DATA; 2956fa590c22SMicky Ching } 2957fa590c22SMicky Ching } else { 2958fa590c22SMicky Ching if (srb->sc_data_direction == DMA_FROM_DEVICE) { 2959fa590c22SMicky Ching rw_tpc = PRO_READ_QUAD_DATA; 2960fa590c22SMicky Ching rw_cmd = PRO_READ_2K_DATA; 2961fa590c22SMicky Ching } else { 2962fa590c22SMicky Ching rw_tpc = PRO_WRITE_QUAD_DATA; 2963fa590c22SMicky Ching rw_cmd = PRO_WRITE_2K_DATA; 2964fa590c22SMicky Ching } 296511201769SQuentin Lambert mode_2k = true; 2966fa590c22SMicky Ching } 2967fa590c22SMicky Ching } else { 2968fa590c22SMicky Ching if (srb->sc_data_direction == DMA_FROM_DEVICE) { 2969fa590c22SMicky Ching rw_tpc = PRO_READ_LONG_DATA; 2970fa590c22SMicky Ching rw_cmd = PRO_READ_DATA; 2971fa590c22SMicky Ching } else { 2972fa590c22SMicky Ching rw_tpc = PRO_WRITE_LONG_DATA; 2973fa590c22SMicky Ching rw_cmd = PRO_WRITE_DATA; 2974fa590c22SMicky Ching } 2975fa590c22SMicky Ching } 2976fa590c22SMicky Ching 2977fa590c22SMicky Ching retval = ms_switch_clock(chip); 2978031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 2979031366eaSJoe Perches rtsx_trace(chip); 2980031366eaSJoe Perches return STATUS_FAIL; 2981031366eaSJoe Perches } 2982fa590c22SMicky Ching 2983fa590c22SMicky Ching if (srb->sc_data_direction == DMA_FROM_DEVICE) 2984fa590c22SMicky Ching trans_mode = MS_TM_AUTO_READ; 2985fa590c22SMicky Ching else 2986fa590c22SMicky Ching trans_mode = MS_TM_AUTO_WRITE; 2987fa590c22SMicky Ching 29888ee775f9SJoe Perches retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); 29898ee775f9SJoe Perches if (retval) { 29908ee775f9SJoe Perches rtsx_trace(chip); 29918ee775f9SJoe Perches return retval; 29928ee775f9SJoe Perches } 2993fa590c22SMicky Ching 2994fa590c22SMicky Ching if (ms_card->seq_mode) { 2995fa590c22SMicky Ching if ((ms_card->pre_dir != srb->sc_data_direction) 2996fa590c22SMicky Ching || ((ms_card->pre_sec_addr + ms_card->pre_sec_cnt) != start_sector) 2997fa590c22SMicky Ching || (mode_2k && (ms_card->seq_mode & MODE_512_SEQ)) 2998fa590c22SMicky Ching || (!mode_2k && (ms_card->seq_mode & MODE_2K_SEQ)) 2999fa590c22SMicky Ching || !(val & MS_INT_BREQ) 3000fa590c22SMicky Ching || ((ms_card->total_sec_cnt + sector_cnt) > 0xFE00)) { 3001fa590c22SMicky Ching ms_card->seq_mode = 0; 3002fa590c22SMicky Ching ms_card->total_sec_cnt = 0; 3003fa590c22SMicky Ching if (val & MS_INT_BREQ) { 3004fa590c22SMicky Ching retval = ms_send_cmd(chip, PRO_STOP, WAIT_INT); 3005031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3006031366eaSJoe Perches rtsx_trace(chip); 3007031366eaSJoe Perches return STATUS_FAIL; 3008031366eaSJoe Perches } 3009fa590c22SMicky Ching 3010fa590c22SMicky Ching rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); 3011fa590c22SMicky Ching } 3012fa590c22SMicky Ching } 3013fa590c22SMicky Ching } 3014fa590c22SMicky Ching 3015fa590c22SMicky Ching if (!ms_card->seq_mode) { 3016fa590c22SMicky Ching ms_card->total_sec_cnt = 0; 3017fa590c22SMicky Ching if (sector_cnt >= SEQ_START_CRITERIA) { 3018fa590c22SMicky Ching if ((ms_card->capacity - start_sector) > 0xFE00) 3019fa590c22SMicky Ching count = 0xFE00; 3020fa590c22SMicky Ching else 3021fa590c22SMicky Ching count = (u16)(ms_card->capacity - start_sector); 3022fa590c22SMicky Ching 3023fa590c22SMicky Ching if (count > sector_cnt) { 3024fa590c22SMicky Ching if (mode_2k) 3025b0ef3ed4SJiayi Ye ms_card->seq_mode = MODE_2K_SEQ; 3026fa590c22SMicky Ching else 3027b0ef3ed4SJiayi Ye ms_card->seq_mode = MODE_512_SEQ; 3028fa590c22SMicky Ching } 3029fa590c22SMicky Ching } else { 3030fa590c22SMicky Ching count = sector_cnt; 3031fa590c22SMicky Ching } 3032fa590c22SMicky Ching retval = mspro_set_rw_cmd(chip, start_sector, count, rw_cmd); 3033fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3034fa590c22SMicky Ching ms_card->seq_mode = 0; 3035031366eaSJoe Perches rtsx_trace(chip); 3036031366eaSJoe Perches return STATUS_FAIL; 3037fa590c22SMicky Ching } 3038fa590c22SMicky Ching } 3039fa590c22SMicky Ching 3040fa590c22SMicky Ching retval = ms_transfer_data(chip, trans_mode, rw_tpc, sector_cnt, 3041fa590c22SMicky Ching WAIT_INT, mode_2k, scsi_sg_count(srb), 3042fa590c22SMicky Ching scsi_sglist(srb), scsi_bufflen(srb)); 3043fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3044fa590c22SMicky Ching ms_card->seq_mode = 0; 3045fa590c22SMicky Ching rtsx_read_register(chip, MS_TRANS_CFG, &val); 3046fa590c22SMicky Ching rtsx_clear_ms_error(chip); 3047fa590c22SMicky Ching 3048fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 3049fa590c22SMicky Ching chip->rw_need_retry = 0; 3050bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "No card exist, exit mspro_rw_multi_sector\n"); 3051031366eaSJoe Perches rtsx_trace(chip); 3052031366eaSJoe Perches return STATUS_FAIL; 3053fa590c22SMicky Ching } 3054fa590c22SMicky Ching 3055fa590c22SMicky Ching if (val & MS_INT_BREQ) 3056fa590c22SMicky Ching ms_send_cmd(chip, PRO_STOP, WAIT_INT); 3057fa590c22SMicky Ching 3058fa590c22SMicky Ching if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) { 3059bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "MSPro CRC error, tune clock!\n"); 3060fa590c22SMicky Ching chip->rw_need_retry = 1; 3061fa590c22SMicky Ching ms_auto_tune_clock(chip); 3062fa590c22SMicky Ching } 3063fa590c22SMicky Ching 3064031366eaSJoe Perches rtsx_trace(chip); 3065031366eaSJoe Perches return retval; 3066fa590c22SMicky Ching } 3067fa590c22SMicky Ching 3068fa590c22SMicky Ching if (ms_card->seq_mode) { 3069fa590c22SMicky Ching ms_card->pre_sec_addr = start_sector; 3070fa590c22SMicky Ching ms_card->pre_sec_cnt = sector_cnt; 3071fa590c22SMicky Ching ms_card->pre_dir = srb->sc_data_direction; 3072fa590c22SMicky Ching ms_card->total_sec_cnt += sector_cnt; 3073fa590c22SMicky Ching } 3074fa590c22SMicky Ching 3075fa590c22SMicky Ching return STATUS_SUCCESS; 3076fa590c22SMicky Ching } 3077fa590c22SMicky Ching 3078fa590c22SMicky Ching static int mspro_read_format_progress(struct rtsx_chip *chip, 3079fa590c22SMicky Ching const int short_data_len) 3080fa590c22SMicky Ching { 3081d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3082fa590c22SMicky Ching int retval, i; 3083fa590c22SMicky Ching u32 total_progress, cur_progress; 3084fa590c22SMicky Ching u8 cnt, tmp; 3085fa590c22SMicky Ching u8 data[8]; 3086fa590c22SMicky Ching 3087bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "mspro_read_format_progress, short_data_len = %d\n", 3088fa590c22SMicky Ching short_data_len); 3089fa590c22SMicky Ching 3090fa590c22SMicky Ching retval = ms_switch_clock(chip); 3091fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3092fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3093031366eaSJoe Perches rtsx_trace(chip); 3094031366eaSJoe Perches return STATUS_FAIL; 3095fa590c22SMicky Ching } 3096fa590c22SMicky Ching 3097fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp); 3098fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3099fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3100031366eaSJoe Perches rtsx_trace(chip); 3101031366eaSJoe Perches return STATUS_FAIL; 3102fa590c22SMicky Ching } 3103fa590c22SMicky Ching 3104fa590c22SMicky Ching if (!(tmp & MS_INT_BREQ)) { 3105fa590c22SMicky Ching if ((tmp & (MS_INT_CED | MS_INT_BREQ | MS_INT_CMDNK | MS_INT_ERR)) == MS_INT_CED) { 3106fa590c22SMicky Ching ms_card->format_status = FORMAT_SUCCESS; 3107fa590c22SMicky Ching return STATUS_SUCCESS; 3108fa590c22SMicky Ching } 3109fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3110031366eaSJoe Perches rtsx_trace(chip); 3111031366eaSJoe Perches return STATUS_FAIL; 3112fa590c22SMicky Ching } 3113fa590c22SMicky Ching 3114fa590c22SMicky Ching if (short_data_len >= 256) 3115fa590c22SMicky Ching cnt = 0; 3116fa590c22SMicky Ching else 3117fa590c22SMicky Ching cnt = (u8)short_data_len; 3118fa590c22SMicky Ching 3119fa590c22SMicky Ching retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, 3120fa590c22SMicky Ching MS_NO_CHECK_INT); 3121fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3122fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3123031366eaSJoe Perches rtsx_trace(chip); 3124031366eaSJoe Perches return STATUS_FAIL; 3125fa590c22SMicky Ching } 3126fa590c22SMicky Ching 3127fa590c22SMicky Ching retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, cnt, WAIT_INT, 3128fa590c22SMicky Ching data, 8); 3129fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3130fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3131031366eaSJoe Perches rtsx_trace(chip); 3132031366eaSJoe Perches return STATUS_FAIL; 3133fa590c22SMicky Ching } 3134fa590c22SMicky Ching 3135fa590c22SMicky Ching total_progress = (data[0] << 24) | (data[1] << 16) | 3136fa590c22SMicky Ching (data[2] << 8) | data[3]; 3137fa590c22SMicky Ching cur_progress = (data[4] << 24) | (data[5] << 16) | 3138fa590c22SMicky Ching (data[6] << 8) | data[7]; 3139fa590c22SMicky Ching 3140bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "total_progress = %d, cur_progress = %d\n", 3141fa590c22SMicky Ching total_progress, cur_progress); 3142fa590c22SMicky Ching 3143fa590c22SMicky Ching if (total_progress == 0) { 3144fa590c22SMicky Ching ms_card->progress = 0; 3145fa590c22SMicky Ching } else { 3146fa590c22SMicky Ching u64 ulltmp = (u64)cur_progress * (u64)65535; 31473c97fbbeSTapasweni Pathak 3148fa590c22SMicky Ching do_div(ulltmp, total_progress); 3149fa590c22SMicky Ching ms_card->progress = (u16)ulltmp; 3150fa590c22SMicky Ching } 3151bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "progress = %d\n", ms_card->progress); 3152fa590c22SMicky Ching 3153fa590c22SMicky Ching for (i = 0; i < 5000; i++) { 3154fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp); 3155fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3156fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3157031366eaSJoe Perches rtsx_trace(chip); 3158031366eaSJoe Perches return STATUS_FAIL; 3159fa590c22SMicky Ching } 3160fa590c22SMicky Ching if (tmp & (MS_INT_CED | MS_INT_CMDNK | 3161fa590c22SMicky Ching MS_INT_BREQ | MS_INT_ERR)) 3162fa590c22SMicky Ching break; 3163fa590c22SMicky Ching 3164fa590c22SMicky Ching wait_timeout(1); 3165fa590c22SMicky Ching } 3166fa590c22SMicky Ching 3167fa590c22SMicky Ching retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, 0); 3168fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3169fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3170031366eaSJoe Perches rtsx_trace(chip); 3171031366eaSJoe Perches return STATUS_FAIL; 3172fa590c22SMicky Ching } 3173fa590c22SMicky Ching 3174fa590c22SMicky Ching if (i == 5000) { 3175fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3176031366eaSJoe Perches rtsx_trace(chip); 3177031366eaSJoe Perches return STATUS_FAIL; 3178fa590c22SMicky Ching } 3179fa590c22SMicky Ching 3180fa590c22SMicky Ching if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) { 3181fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3182031366eaSJoe Perches rtsx_trace(chip); 3183031366eaSJoe Perches return STATUS_FAIL; 3184fa590c22SMicky Ching } 3185fa590c22SMicky Ching 3186fa590c22SMicky Ching if (tmp & MS_INT_CED) { 3187fa590c22SMicky Ching ms_card->format_status = FORMAT_SUCCESS; 3188fa590c22SMicky Ching ms_card->pro_under_formatting = 0; 3189fa590c22SMicky Ching } else if (tmp & MS_INT_BREQ) { 3190fa590c22SMicky Ching ms_card->format_status = FORMAT_IN_PROGRESS; 3191fa590c22SMicky Ching } else { 3192fa590c22SMicky Ching ms_card->format_status = FORMAT_FAIL; 3193fa590c22SMicky Ching ms_card->pro_under_formatting = 0; 3194031366eaSJoe Perches rtsx_trace(chip); 3195031366eaSJoe Perches return STATUS_FAIL; 3196fa590c22SMicky Ching } 3197fa590c22SMicky Ching 3198fa590c22SMicky Ching return STATUS_SUCCESS; 3199fa590c22SMicky Ching } 3200fa590c22SMicky Ching 3201fa590c22SMicky Ching void mspro_polling_format_status(struct rtsx_chip *chip) 3202fa590c22SMicky Ching { 3203d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3204fa590c22SMicky Ching int i; 3205fa590c22SMicky Ching 3206fa590c22SMicky Ching if (ms_card->pro_under_formatting && 3207fa590c22SMicky Ching (rtsx_get_stat(chip) != RTSX_STAT_SS)) { 3208fa590c22SMicky Ching rtsx_set_stat(chip, RTSX_STAT_RUN); 3209fa590c22SMicky Ching 3210fa590c22SMicky Ching for (i = 0; i < 65535; i++) { 3211fa590c22SMicky Ching mspro_read_format_progress(chip, MS_SHORT_DATA_LEN); 3212fa590c22SMicky Ching if (ms_card->format_status != FORMAT_IN_PROGRESS) 3213fa590c22SMicky Ching break; 3214fa590c22SMicky Ching } 3215fa590c22SMicky Ching } 3216fa590c22SMicky Ching } 3217fa590c22SMicky Ching 3218fa590c22SMicky Ching int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip, 321911201769SQuentin Lambert int short_data_len, bool quick_format) 3220fa590c22SMicky Ching { 3221d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3222fa590c22SMicky Ching int retval, i; 3223fa590c22SMicky Ching u8 buf[8], tmp; 3224fa590c22SMicky Ching u16 para; 3225fa590c22SMicky Ching 3226fa590c22SMicky Ching retval = ms_switch_clock(chip); 3227031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3228031366eaSJoe Perches rtsx_trace(chip); 3229031366eaSJoe Perches return STATUS_FAIL; 3230031366eaSJoe Perches } 3231fa590c22SMicky Ching 3232fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, Pro_TPCParm, 0x01); 3233031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3234031366eaSJoe Perches rtsx_trace(chip); 3235031366eaSJoe Perches return STATUS_FAIL; 3236031366eaSJoe Perches } 3237fa590c22SMicky Ching 3238fa590c22SMicky Ching memset(buf, 0, 2); 3239fa590c22SMicky Ching switch (short_data_len) { 3240fa590c22SMicky Ching case 32: 3241fa590c22SMicky Ching buf[0] = 0; 3242fa590c22SMicky Ching break; 3243fa590c22SMicky Ching case 64: 3244fa590c22SMicky Ching buf[0] = 1; 3245fa590c22SMicky Ching break; 3246fa590c22SMicky Ching case 128: 3247fa590c22SMicky Ching buf[0] = 2; 3248fa590c22SMicky Ching break; 3249fa590c22SMicky Ching case 256: 3250fa590c22SMicky Ching default: 3251fa590c22SMicky Ching buf[0] = 3; 3252fa590c22SMicky Ching break; 3253fa590c22SMicky Ching } 3254fa590c22SMicky Ching 3255fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 3256fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_WRITE_REG, 1, 3257fa590c22SMicky Ching NO_WAIT_INT, buf, 2); 3258fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 3259fa590c22SMicky Ching break; 3260fa590c22SMicky Ching } 3261031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 3262031366eaSJoe Perches rtsx_trace(chip); 3263031366eaSJoe Perches return STATUS_FAIL; 3264031366eaSJoe Perches } 3265fa590c22SMicky Ching 3266fa590c22SMicky Ching if (quick_format) 3267fa590c22SMicky Ching para = 0x0000; 3268fa590c22SMicky Ching else 3269fa590c22SMicky Ching para = 0x0001; 3270fa590c22SMicky Ching 3271fa590c22SMicky Ching retval = mspro_set_rw_cmd(chip, 0, para, PRO_FORMAT); 3272031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3273031366eaSJoe Perches rtsx_trace(chip); 3274031366eaSJoe Perches return STATUS_FAIL; 3275031366eaSJoe Perches } 3276fa590c22SMicky Ching 32778ee775f9SJoe Perches retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp); 32788ee775f9SJoe Perches if (retval) { 32798ee775f9SJoe Perches rtsx_trace(chip); 32808ee775f9SJoe Perches return retval; 32818ee775f9SJoe Perches } 3282fa590c22SMicky Ching 3283031366eaSJoe Perches if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) { 3284031366eaSJoe Perches rtsx_trace(chip); 3285031366eaSJoe Perches return STATUS_FAIL; 3286031366eaSJoe Perches } 3287fa590c22SMicky Ching 3288fa590c22SMicky Ching if ((tmp & (MS_INT_BREQ | MS_INT_CED)) == MS_INT_BREQ) { 3289fa590c22SMicky Ching ms_card->pro_under_formatting = 1; 3290fa590c22SMicky Ching ms_card->progress = 0; 3291fa590c22SMicky Ching ms_card->format_status = FORMAT_IN_PROGRESS; 3292fa590c22SMicky Ching return STATUS_SUCCESS; 3293fa590c22SMicky Ching } 3294fa590c22SMicky Ching 3295fa590c22SMicky Ching if (tmp & MS_INT_CED) { 3296fa590c22SMicky Ching ms_card->pro_under_formatting = 0; 3297fa590c22SMicky Ching ms_card->progress = 0; 3298fa590c22SMicky Ching ms_card->format_status = FORMAT_SUCCESS; 3299fa590c22SMicky Ching set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_NO_SENSE); 3300fa590c22SMicky Ching return STATUS_SUCCESS; 3301fa590c22SMicky Ching } 3302fa590c22SMicky Ching 3303031366eaSJoe Perches rtsx_trace(chip); 3304031366eaSJoe Perches return STATUS_FAIL; 3305fa590c22SMicky Ching } 3306fa590c22SMicky Ching 3307fa590c22SMicky Ching static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, 3308fa590c22SMicky Ching u16 log_blk, u8 start_page, u8 end_page, 3309fa590c22SMicky Ching u8 *buf, unsigned int *index, 3310fa590c22SMicky Ching unsigned int *offset) 3311fa590c22SMicky Ching { 3312d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3313fa590c22SMicky Ching int retval, i; 3314fa590c22SMicky Ching u8 extra[MS_EXTRA_SIZE], page_addr, val, trans_cfg, data[6]; 3315fa590c22SMicky Ching u8 *ptr; 3316fa590c22SMicky Ching 3317fa590c22SMicky Ching retval = ms_read_extra_data(chip, phy_blk, start_page, 3318fa590c22SMicky Ching extra, MS_EXTRA_SIZE); 3319fa590c22SMicky Ching if (retval == STATUS_SUCCESS) { 3320fa590c22SMicky Ching if ((extra[1] & 0x30) != 0x30) { 3321fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_READ_ERROR); 3322031366eaSJoe Perches rtsx_trace(chip); 3323031366eaSJoe Perches return STATUS_FAIL; 3324fa590c22SMicky Ching } 3325fa590c22SMicky Ching } 3326fa590c22SMicky Ching 3327fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 3328fa590c22SMicky Ching SystemParm, 6); 3329031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3330031366eaSJoe Perches rtsx_trace(chip); 3331031366eaSJoe Perches return STATUS_FAIL; 3332031366eaSJoe Perches } 3333fa590c22SMicky Ching 3334fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 3335fa590c22SMicky Ching data[0] = 0x88; 3336fa590c22SMicky Ching else 3337fa590c22SMicky Ching data[0] = 0x80; 3338fa590c22SMicky Ching 3339fa590c22SMicky Ching data[1] = 0; 3340fa590c22SMicky Ching data[2] = (u8)(phy_blk >> 8); 3341fa590c22SMicky Ching data[3] = (u8)phy_blk; 3342fa590c22SMicky Ching data[4] = 0; 3343fa590c22SMicky Ching data[5] = start_page; 3344fa590c22SMicky Ching 3345fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 3346fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, 3347fa590c22SMicky Ching data, 6); 3348fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 3349fa590c22SMicky Ching break; 3350fa590c22SMicky Ching } 3351031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 3352031366eaSJoe Perches rtsx_trace(chip); 3353031366eaSJoe Perches return STATUS_FAIL; 3354031366eaSJoe Perches } 3355fa590c22SMicky Ching 3356fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 3357fa590c22SMicky Ching 3358fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); 3359031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3360031366eaSJoe Perches rtsx_trace(chip); 3361031366eaSJoe Perches return STATUS_FAIL; 3362031366eaSJoe Perches } 3363fa590c22SMicky Ching 3364fa590c22SMicky Ching ptr = buf; 3365fa590c22SMicky Ching 3366fa590c22SMicky Ching for (page_addr = start_page; page_addr < end_page; page_addr++) { 3367fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 3368fa590c22SMicky Ching 3369fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 3370fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_CARD); 3371031366eaSJoe Perches rtsx_trace(chip); 3372031366eaSJoe Perches return STATUS_FAIL; 3373fa590c22SMicky Ching } 3374fa590c22SMicky Ching 3375fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 3376031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3377031366eaSJoe Perches rtsx_trace(chip); 3378031366eaSJoe Perches return STATUS_FAIL; 3379031366eaSJoe Perches } 3380fa590c22SMicky Ching 3381fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 3382fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 3383031366eaSJoe Perches rtsx_trace(chip); 3384031366eaSJoe Perches return STATUS_FAIL; 3385fa590c22SMicky Ching } 3386fa590c22SMicky Ching if (val & INT_REG_ERR) { 3387fa590c22SMicky Ching if (val & INT_REG_BREQ) { 3388fa590c22SMicky Ching retval = ms_read_status_reg(chip); 3389fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3390fa590c22SMicky Ching if (!(chip->card_wp & MS_CARD)) { 3391fa590c22SMicky Ching reset_ms(chip); 3392fa590c22SMicky Ching ms_set_page_status(log_blk, setPS_NG, extra, MS_EXTRA_SIZE); 3393fa590c22SMicky Ching ms_write_extra_data(chip, phy_blk, 3394fa590c22SMicky Ching page_addr, extra, MS_EXTRA_SIZE); 3395fa590c22SMicky Ching } 3396fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_READ_ERROR); 3397031366eaSJoe Perches rtsx_trace(chip); 3398031366eaSJoe Perches return STATUS_FAIL; 3399fa590c22SMicky Ching } 3400fa590c22SMicky Ching } else { 3401fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_READ_ERROR); 3402031366eaSJoe Perches rtsx_trace(chip); 3403031366eaSJoe Perches return STATUS_FAIL; 3404fa590c22SMicky Ching } 3405fa590c22SMicky Ching } else { 3406fa590c22SMicky Ching if (!(val & INT_REG_BREQ)) { 3407fa590c22SMicky Ching ms_set_err_code(chip, MS_BREQ_ERROR); 3408031366eaSJoe Perches rtsx_trace(chip); 3409031366eaSJoe Perches return STATUS_FAIL; 3410fa590c22SMicky Ching } 3411fa590c22SMicky Ching } 3412fa590c22SMicky Ching 3413fa590c22SMicky Ching if (page_addr == (end_page - 1)) { 3414fa590c22SMicky Ching if (!(val & INT_REG_CED)) { 3415fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT); 3416031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3417031366eaSJoe Perches rtsx_trace(chip); 3418031366eaSJoe Perches return STATUS_FAIL; 3419031366eaSJoe Perches } 3420fa590c22SMicky Ching } 3421fa590c22SMicky Ching 3422fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, 3423fa590c22SMicky Ching &val, 1); 3424031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3425031366eaSJoe Perches rtsx_trace(chip); 3426031366eaSJoe Perches return STATUS_FAIL; 3427031366eaSJoe Perches } 3428fa590c22SMicky Ching 3429fa590c22SMicky Ching if (!(val & INT_REG_CED)) { 3430fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_READ_ERROR); 3431031366eaSJoe Perches rtsx_trace(chip); 3432031366eaSJoe Perches return STATUS_FAIL; 3433fa590c22SMicky Ching } 3434fa590c22SMicky Ching 3435fa590c22SMicky Ching trans_cfg = NO_WAIT_INT; 3436fa590c22SMicky Ching } else { 3437fa590c22SMicky Ching trans_cfg = WAIT_INT; 3438fa590c22SMicky Ching } 3439fa590c22SMicky Ching 3440fa590c22SMicky Ching rtsx_init_cmd(chip); 3441fa590c22SMicky Ching 3442fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, READ_PAGE_DATA); 3443fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 3444fa590c22SMicky Ching 0xFF, trans_cfg); 3445fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 3446fa590c22SMicky Ching 0x01, RING_BUFFER); 3447fa590c22SMicky Ching 3448fa590c22SMicky Ching trans_dma_enable(DMA_FROM_DEVICE, chip, 512, DMA_512); 3449fa590c22SMicky Ching 3450fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, 3451fa590c22SMicky Ching MS_TRANSFER_START | MS_TM_NORMAL_READ); 3452fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, 3453fa590c22SMicky Ching MS_TRANSFER_END, MS_TRANSFER_END); 3454fa590c22SMicky Ching 3455fa590c22SMicky Ching rtsx_send_cmd_no_wait(chip); 3456fa590c22SMicky Ching 3457fa590c22SMicky Ching retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr, 3458fa590c22SMicky Ching 512, scsi_sg_count(chip->srb), 3459fa590c22SMicky Ching index, offset, DMA_FROM_DEVICE, 3460fa590c22SMicky Ching chip->ms_timeout); 3461fa590c22SMicky Ching if (retval < 0) { 3462fa590c22SMicky Ching if (retval == -ETIMEDOUT) { 3463fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 3464fa590c22SMicky Ching rtsx_clear_ms_error(chip); 3465031366eaSJoe Perches rtsx_trace(chip); 3466031366eaSJoe Perches return STATUS_TIMEDOUT; 3467fa590c22SMicky Ching } 3468fa590c22SMicky Ching 3469fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); 3470fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3471fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 3472fa590c22SMicky Ching rtsx_clear_ms_error(chip); 3473031366eaSJoe Perches rtsx_trace(chip); 3474031366eaSJoe Perches return STATUS_TIMEDOUT; 3475fa590c22SMicky Ching } 3476fa590c22SMicky Ching if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) { 3477fa590c22SMicky Ching ms_set_err_code(chip, MS_CRC16_ERROR); 3478fa590c22SMicky Ching rtsx_clear_ms_error(chip); 3479031366eaSJoe Perches rtsx_trace(chip); 3480031366eaSJoe Perches return STATUS_FAIL; 3481fa590c22SMicky Ching } 3482fa590c22SMicky Ching } 3483fa590c22SMicky Ching 3484fa590c22SMicky Ching if (scsi_sg_count(chip->srb) == 0) 3485fa590c22SMicky Ching ptr += 512; 3486fa590c22SMicky Ching } 3487fa590c22SMicky Ching 3488fa590c22SMicky Ching return STATUS_SUCCESS; 3489fa590c22SMicky Ching } 3490fa590c22SMicky Ching 3491fa590c22SMicky Ching static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, 3492fa590c22SMicky Ching u16 new_blk, u16 log_blk, u8 start_page, 3493fa590c22SMicky Ching u8 end_page, u8 *buf, unsigned int *index, 3494fa590c22SMicky Ching unsigned int *offset) 3495fa590c22SMicky Ching { 3496d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3497fa590c22SMicky Ching int retval, i; 3498fa590c22SMicky Ching u8 page_addr, val, data[16]; 3499fa590c22SMicky Ching u8 *ptr; 3500fa590c22SMicky Ching 3501fa590c22SMicky Ching if (!start_page) { 3502fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 3503fa590c22SMicky Ching SystemParm, 7); 3504031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3505031366eaSJoe Perches rtsx_trace(chip); 3506031366eaSJoe Perches return STATUS_FAIL; 3507031366eaSJoe Perches } 3508fa590c22SMicky Ching 3509fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 3510fa590c22SMicky Ching data[0] = 0x88; 3511fa590c22SMicky Ching else 3512fa590c22SMicky Ching data[0] = 0x80; 3513fa590c22SMicky Ching 3514fa590c22SMicky Ching data[1] = 0; 3515fa590c22SMicky Ching data[2] = (u8)(old_blk >> 8); 3516fa590c22SMicky Ching data[3] = (u8)old_blk; 3517fa590c22SMicky Ching data[4] = 0x80; 3518fa590c22SMicky Ching data[5] = 0; 3519fa590c22SMicky Ching data[6] = 0xEF; 3520fa590c22SMicky Ching data[7] = 0xFF; 3521fa590c22SMicky Ching 3522fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, 3523fa590c22SMicky Ching data, 8); 3524031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3525031366eaSJoe Perches rtsx_trace(chip); 3526031366eaSJoe Perches return STATUS_FAIL; 3527031366eaSJoe Perches } 3528fa590c22SMicky Ching 3529fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); 3530031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3531031366eaSJoe Perches rtsx_trace(chip); 3532031366eaSJoe Perches return STATUS_FAIL; 3533031366eaSJoe Perches } 3534fa590c22SMicky Ching 3535fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 3536fa590c22SMicky Ching retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1, 3537fa590c22SMicky Ching NO_WAIT_INT); 3538031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3539031366eaSJoe Perches rtsx_trace(chip); 3540031366eaSJoe Perches return STATUS_FAIL; 3541031366eaSJoe Perches } 3542fa590c22SMicky Ching } 3543fa590c22SMicky Ching 3544fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, 3545fa590c22SMicky Ching SystemParm, (6 + MS_EXTRA_SIZE)); 3546031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3547031366eaSJoe Perches rtsx_trace(chip); 3548031366eaSJoe Perches return STATUS_FAIL; 3549031366eaSJoe Perches } 3550fa590c22SMicky Ching 3551fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 3552fa590c22SMicky Ching 3553fa590c22SMicky Ching if (CHK_MS4BIT(ms_card)) 3554fa590c22SMicky Ching data[0] = 0x88; 3555fa590c22SMicky Ching else 3556fa590c22SMicky Ching data[0] = 0x80; 3557fa590c22SMicky Ching 3558fa590c22SMicky Ching data[1] = 0; 3559fa590c22SMicky Ching data[2] = (u8)(new_blk >> 8); 3560fa590c22SMicky Ching data[3] = (u8)new_blk; 3561fa590c22SMicky Ching if ((end_page - start_page) == 1) 3562fa590c22SMicky Ching data[4] = 0x20; 3563fa590c22SMicky Ching else 3564fa590c22SMicky Ching data[4] = 0; 3565fa590c22SMicky Ching 3566fa590c22SMicky Ching data[5] = start_page; 3567fa590c22SMicky Ching data[6] = 0xF8; 3568fa590c22SMicky Ching data[7] = 0xFF; 3569fa590c22SMicky Ching data[8] = (u8)(log_blk >> 8); 3570fa590c22SMicky Ching data[9] = (u8)log_blk; 3571fa590c22SMicky Ching 3572fa590c22SMicky Ching for (i = 0x0A; i < 0x10; i++) 3573fa590c22SMicky Ching data[i] = 0xFF; 3574fa590c22SMicky Ching 3575fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 3576fa590c22SMicky Ching retval = ms_write_bytes(chip, WRITE_REG, 6 + MS_EXTRA_SIZE, 3577fa590c22SMicky Ching NO_WAIT_INT, data, 16); 3578fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 3579fa590c22SMicky Ching break; 3580fa590c22SMicky Ching } 3581031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 3582031366eaSJoe Perches rtsx_trace(chip); 3583031366eaSJoe Perches return STATUS_FAIL; 3584031366eaSJoe Perches } 3585fa590c22SMicky Ching 3586fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 3587fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); 3588fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 3589fa590c22SMicky Ching break; 3590fa590c22SMicky Ching } 3591031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 3592031366eaSJoe Perches rtsx_trace(chip); 3593031366eaSJoe Perches return STATUS_FAIL; 3594031366eaSJoe Perches } 3595fa590c22SMicky Ching 3596fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 3597031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3598031366eaSJoe Perches rtsx_trace(chip); 3599031366eaSJoe Perches return STATUS_FAIL; 3600031366eaSJoe Perches } 3601fa590c22SMicky Ching 3602fa590c22SMicky Ching ptr = buf; 3603fa590c22SMicky Ching for (page_addr = start_page; page_addr < end_page; page_addr++) { 3604fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 3605fa590c22SMicky Ching 3606fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 3607fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_CARD); 3608031366eaSJoe Perches rtsx_trace(chip); 3609031366eaSJoe Perches return STATUS_FAIL; 3610fa590c22SMicky Ching } 3611fa590c22SMicky Ching 3612fa590c22SMicky Ching if (val & INT_REG_CMDNK) { 3613fa590c22SMicky Ching ms_set_err_code(chip, MS_CMD_NK); 3614031366eaSJoe Perches rtsx_trace(chip); 3615031366eaSJoe Perches return STATUS_FAIL; 3616fa590c22SMicky Ching } 3617fa590c22SMicky Ching if (val & INT_REG_ERR) { 3618fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 3619031366eaSJoe Perches rtsx_trace(chip); 3620031366eaSJoe Perches return STATUS_FAIL; 3621fa590c22SMicky Ching } 3622fa590c22SMicky Ching if (!(val & INT_REG_BREQ)) { 3623fa590c22SMicky Ching ms_set_err_code(chip, MS_BREQ_ERROR); 3624031366eaSJoe Perches rtsx_trace(chip); 3625031366eaSJoe Perches return STATUS_FAIL; 3626fa590c22SMicky Ching } 3627fa590c22SMicky Ching 3628fa590c22SMicky Ching udelay(30); 3629fa590c22SMicky Ching 3630fa590c22SMicky Ching rtsx_init_cmd(chip); 3631fa590c22SMicky Ching 3632fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 3633fa590c22SMicky Ching 0xFF, WRITE_PAGE_DATA); 3634fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 3635fa590c22SMicky Ching 0xFF, WAIT_INT); 3636fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 3637fa590c22SMicky Ching 0x01, RING_BUFFER); 3638fa590c22SMicky Ching 3639fa590c22SMicky Ching trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512); 3640fa590c22SMicky Ching 3641fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, 3642fa590c22SMicky Ching MS_TRANSFER_START | MS_TM_NORMAL_WRITE); 3643fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, 3644fa590c22SMicky Ching MS_TRANSFER_END, MS_TRANSFER_END); 3645fa590c22SMicky Ching 3646fa590c22SMicky Ching rtsx_send_cmd_no_wait(chip); 3647fa590c22SMicky Ching 3648fa590c22SMicky Ching retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr, 3649fa590c22SMicky Ching 512, scsi_sg_count(chip->srb), 3650fa590c22SMicky Ching index, offset, DMA_TO_DEVICE, 3651fa590c22SMicky Ching chip->ms_timeout); 3652fa590c22SMicky Ching if (retval < 0) { 3653fa590c22SMicky Ching ms_set_err_code(chip, MS_TO_ERROR); 3654fa590c22SMicky Ching rtsx_clear_ms_error(chip); 3655fa590c22SMicky Ching 3656031366eaSJoe Perches if (retval == -ETIMEDOUT) { 3657031366eaSJoe Perches rtsx_trace(chip); 3658031366eaSJoe Perches return STATUS_TIMEDOUT; 3659031366eaSJoe Perches } 3660031366eaSJoe Perches rtsx_trace(chip); 3661031366eaSJoe Perches return STATUS_FAIL; 3662fa590c22SMicky Ching } 3663fa590c22SMicky Ching 3664fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); 3665031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3666031366eaSJoe Perches rtsx_trace(chip); 3667031366eaSJoe Perches return STATUS_FAIL; 3668031366eaSJoe Perches } 3669fa590c22SMicky Ching 3670fa590c22SMicky Ching if ((end_page - start_page) == 1) { 3671fa590c22SMicky Ching if (!(val & INT_REG_CED)) { 3672fa590c22SMicky Ching ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); 3673031366eaSJoe Perches rtsx_trace(chip); 3674031366eaSJoe Perches return STATUS_FAIL; 3675fa590c22SMicky Ching } 3676fa590c22SMicky Ching } else { 3677fa590c22SMicky Ching if (page_addr == (end_page - 1)) { 3678fa590c22SMicky Ching if (!(val & INT_REG_CED)) { 3679fa590c22SMicky Ching retval = ms_send_cmd(chip, BLOCK_END, 3680fa590c22SMicky Ching WAIT_INT); 3681031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3682031366eaSJoe Perches rtsx_trace(chip); 3683031366eaSJoe Perches return STATUS_FAIL; 3684031366eaSJoe Perches } 3685fa590c22SMicky Ching } 3686fa590c22SMicky Ching 3687fa590c22SMicky Ching retval = ms_read_bytes(chip, GET_INT, 1, 3688fa590c22SMicky Ching NO_WAIT_INT, &val, 1); 3689031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3690031366eaSJoe Perches rtsx_trace(chip); 3691031366eaSJoe Perches return STATUS_FAIL; 3692031366eaSJoe Perches } 3693fa590c22SMicky Ching } 3694fa590c22SMicky Ching 3695fa590c22SMicky Ching if ((page_addr == (end_page - 1)) || 3696fa590c22SMicky Ching (page_addr == ms_card->page_off)) { 3697fa590c22SMicky Ching if (!(val & INT_REG_CED)) { 3698fa590c22SMicky Ching ms_set_err_code(chip, 3699fa590c22SMicky Ching MS_FLASH_WRITE_ERROR); 3700031366eaSJoe Perches rtsx_trace(chip); 3701031366eaSJoe Perches return STATUS_FAIL; 3702fa590c22SMicky Ching } 3703fa590c22SMicky Ching } 3704fa590c22SMicky Ching } 3705fa590c22SMicky Ching 3706fa590c22SMicky Ching if (scsi_sg_count(chip->srb) == 0) 3707fa590c22SMicky Ching ptr += 512; 3708fa590c22SMicky Ching } 3709fa590c22SMicky Ching 3710fa590c22SMicky Ching return STATUS_SUCCESS; 3711fa590c22SMicky Ching } 3712fa590c22SMicky Ching 3713fa590c22SMicky Ching static int ms_finish_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, 3714fa590c22SMicky Ching u16 log_blk, u8 page_off) 3715fa590c22SMicky Ching { 3716d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3717fa590c22SMicky Ching int retval, seg_no; 3718fa590c22SMicky Ching 3719fa590c22SMicky Ching retval = ms_copy_page(chip, old_blk, new_blk, log_blk, 3720fa590c22SMicky Ching page_off, ms_card->page_off + 1); 3721031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3722031366eaSJoe Perches rtsx_trace(chip); 3723031366eaSJoe Perches return STATUS_FAIL; 3724031366eaSJoe Perches } 3725fa590c22SMicky Ching 3726fa590c22SMicky Ching seg_no = old_blk >> 9; 3727fa590c22SMicky Ching 3728fa590c22SMicky Ching if (MS_TST_BAD_BLOCK_FLG(ms_card)) { 3729fa590c22SMicky Ching MS_CLR_BAD_BLOCK_FLG(ms_card); 3730fa590c22SMicky Ching ms_set_bad_block(chip, old_blk); 3731fa590c22SMicky Ching } else { 3732fa590c22SMicky Ching retval = ms_erase_block(chip, old_blk); 3733fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 3734fa590c22SMicky Ching ms_set_unused_block(chip, old_blk); 3735fa590c22SMicky Ching } 3736fa590c22SMicky Ching 3737fa590c22SMicky Ching ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk); 3738fa590c22SMicky Ching 3739fa590c22SMicky Ching return STATUS_SUCCESS; 3740fa590c22SMicky Ching } 3741fa590c22SMicky Ching 3742fa590c22SMicky Ching static int ms_prepare_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, 3743fa590c22SMicky Ching u16 log_blk, u8 start_page) 3744fa590c22SMicky Ching { 3745fa590c22SMicky Ching int retval; 3746fa590c22SMicky Ching 3747fa590c22SMicky Ching if (start_page) { 3748fa590c22SMicky Ching retval = ms_copy_page(chip, old_blk, new_blk, log_blk, 3749fa590c22SMicky Ching 0, start_page); 3750031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3751031366eaSJoe Perches rtsx_trace(chip); 3752031366eaSJoe Perches return STATUS_FAIL; 3753031366eaSJoe Perches } 3754fa590c22SMicky Ching } 3755fa590c22SMicky Ching 3756fa590c22SMicky Ching return STATUS_SUCCESS; 3757fa590c22SMicky Ching } 3758fa590c22SMicky Ching 3759fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 3760fa590c22SMicky Ching int ms_delay_write(struct rtsx_chip *chip) 3761fa590c22SMicky Ching { 3762d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3763fa590c22SMicky Ching struct ms_delay_write_tag *delay_write = &(ms_card->delay_write); 3764fa590c22SMicky Ching int retval; 3765fa590c22SMicky Ching 3766fa590c22SMicky Ching if (delay_write->delay_write_flag) { 3767fa590c22SMicky Ching retval = ms_set_init_para(chip); 3768031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3769031366eaSJoe Perches rtsx_trace(chip); 3770031366eaSJoe Perches return STATUS_FAIL; 3771031366eaSJoe Perches } 3772fa590c22SMicky Ching 3773fa590c22SMicky Ching delay_write->delay_write_flag = 0; 3774fa590c22SMicky Ching retval = ms_finish_write(chip, 3775fa590c22SMicky Ching delay_write->old_phyblock, 3776fa590c22SMicky Ching delay_write->new_phyblock, 3777fa590c22SMicky Ching delay_write->logblock, 3778fa590c22SMicky Ching delay_write->pageoff); 3779031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 3780031366eaSJoe Perches rtsx_trace(chip); 3781031366eaSJoe Perches return STATUS_FAIL; 3782031366eaSJoe Perches } 3783fa590c22SMicky Ching } 3784fa590c22SMicky Ching 3785fa590c22SMicky Ching return STATUS_SUCCESS; 3786fa590c22SMicky Ching } 3787fa590c22SMicky Ching #endif 3788fa590c22SMicky Ching 3789fa590c22SMicky Ching static inline void ms_rw_fail(struct scsi_cmnd *srb, struct rtsx_chip *chip) 3790fa590c22SMicky Ching { 3791fa590c22SMicky Ching if (srb->sc_data_direction == DMA_FROM_DEVICE) 3792fa590c22SMicky Ching set_sense_type(chip, SCSI_LUN(srb), 3793fa590c22SMicky Ching SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); 3794fa590c22SMicky Ching else 3795fa590c22SMicky Ching set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); 3796fa590c22SMicky Ching } 3797fa590c22SMicky Ching 3798fa590c22SMicky Ching static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, 3799fa590c22SMicky Ching u32 start_sector, u16 sector_cnt) 3800fa590c22SMicky Ching { 3801d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 3802fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 3803fa590c22SMicky Ching int retval, seg_no; 3804fa590c22SMicky Ching unsigned int index = 0, offset = 0; 3805fa590c22SMicky Ching u16 old_blk = 0, new_blk = 0, log_blk, total_sec_cnt = sector_cnt; 3806fa590c22SMicky Ching u8 start_page, end_page = 0, page_cnt; 3807fa590c22SMicky Ching u8 *ptr; 3808fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 3809fa590c22SMicky Ching struct ms_delay_write_tag *delay_write = &(ms_card->delay_write); 3810fa590c22SMicky Ching #endif 3811fa590c22SMicky Ching 3812fa590c22SMicky Ching ms_set_err_code(chip, MS_NO_ERROR); 3813fa590c22SMicky Ching 3814fa590c22SMicky Ching ms_card->cleanup_counter = 0; 3815fa590c22SMicky Ching 3816fa590c22SMicky Ching ptr = (u8 *)scsi_sglist(srb); 3817fa590c22SMicky Ching 3818fa590c22SMicky Ching retval = ms_switch_clock(chip); 3819fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3820fa590c22SMicky Ching ms_rw_fail(srb, chip); 3821031366eaSJoe Perches rtsx_trace(chip); 3822031366eaSJoe Perches return STATUS_FAIL; 3823fa590c22SMicky Ching } 3824fa590c22SMicky Ching 3825fa590c22SMicky Ching log_blk = (u16)(start_sector >> ms_card->block_shift); 3826fa590c22SMicky Ching start_page = (u8)(start_sector & ms_card->page_off); 3827fa590c22SMicky Ching 3828fa590c22SMicky Ching for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) { 3829fa590c22SMicky Ching if (log_blk < ms_start_idx[seg_no + 1]) 3830fa590c22SMicky Ching break; 3831fa590c22SMicky Ching } 3832fa590c22SMicky Ching 3833fa590c22SMicky Ching if (ms_card->segment[seg_no].build_flag == 0) { 3834fa590c22SMicky Ching retval = ms_build_l2p_tbl(chip, seg_no); 3835fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3836fa590c22SMicky Ching chip->card_fail |= MS_CARD; 3837fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); 3838031366eaSJoe Perches rtsx_trace(chip); 3839031366eaSJoe Perches return STATUS_FAIL; 3840fa590c22SMicky Ching } 3841fa590c22SMicky Ching } 3842fa590c22SMicky Ching 3843fa590c22SMicky Ching if (srb->sc_data_direction == DMA_TO_DEVICE) { 3844fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 3845fa590c22SMicky Ching if (delay_write->delay_write_flag && 3846fa590c22SMicky Ching (delay_write->logblock == log_blk) && 3847fa590c22SMicky Ching (start_page > delay_write->pageoff)) { 3848fa590c22SMicky Ching delay_write->delay_write_flag = 0; 3849fa590c22SMicky Ching retval = ms_copy_page(chip, 3850fa590c22SMicky Ching delay_write->old_phyblock, 3851fa590c22SMicky Ching delay_write->new_phyblock, log_blk, 3852fa590c22SMicky Ching delay_write->pageoff, start_page); 3853fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3854fa590c22SMicky Ching set_sense_type(chip, lun, 3855fa590c22SMicky Ching SENSE_TYPE_MEDIA_WRITE_ERR); 3856031366eaSJoe Perches rtsx_trace(chip); 3857031366eaSJoe Perches return STATUS_FAIL; 3858fa590c22SMicky Ching } 3859fa590c22SMicky Ching old_blk = delay_write->old_phyblock; 3860fa590c22SMicky Ching new_blk = delay_write->new_phyblock; 3861fa590c22SMicky Ching } else if (delay_write->delay_write_flag && 3862fa590c22SMicky Ching (delay_write->logblock == log_blk) && 3863fa590c22SMicky Ching (start_page == delay_write->pageoff)) { 3864fa590c22SMicky Ching delay_write->delay_write_flag = 0; 3865fa590c22SMicky Ching old_blk = delay_write->old_phyblock; 3866fa590c22SMicky Ching new_blk = delay_write->new_phyblock; 3867fa590c22SMicky Ching } else { 3868fa590c22SMicky Ching retval = ms_delay_write(chip); 3869fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3870fa590c22SMicky Ching set_sense_type(chip, lun, 3871fa590c22SMicky Ching SENSE_TYPE_MEDIA_WRITE_ERR); 3872031366eaSJoe Perches rtsx_trace(chip); 3873031366eaSJoe Perches return STATUS_FAIL; 3874fa590c22SMicky Ching } 3875fa590c22SMicky Ching #endif 3876fa590c22SMicky Ching old_blk = ms_get_l2p_tbl(chip, seg_no, 3877fa590c22SMicky Ching log_blk - ms_start_idx[seg_no]); 3878fa590c22SMicky Ching new_blk = ms_get_unused_block(chip, seg_no); 3879fa590c22SMicky Ching if ((old_blk == 0xFFFF) || (new_blk == 0xFFFF)) { 3880fa590c22SMicky Ching set_sense_type(chip, lun, 3881fa590c22SMicky Ching SENSE_TYPE_MEDIA_WRITE_ERR); 3882031366eaSJoe Perches rtsx_trace(chip); 3883031366eaSJoe Perches return STATUS_FAIL; 3884fa590c22SMicky Ching } 3885fa590c22SMicky Ching 3886fa590c22SMicky Ching retval = ms_prepare_write(chip, old_blk, new_blk, 3887fa590c22SMicky Ching log_blk, start_page); 3888fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3889fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 3890fa590c22SMicky Ching set_sense_type(chip, lun, 3891fa590c22SMicky Ching SENSE_TYPE_MEDIA_NOT_PRESENT); 3892031366eaSJoe Perches rtsx_trace(chip); 3893031366eaSJoe Perches return STATUS_FAIL; 3894fa590c22SMicky Ching } 3895fa590c22SMicky Ching set_sense_type(chip, lun, 3896fa590c22SMicky Ching SENSE_TYPE_MEDIA_WRITE_ERR); 3897031366eaSJoe Perches rtsx_trace(chip); 3898031366eaSJoe Perches return STATUS_FAIL; 3899fa590c22SMicky Ching } 3900fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 3901fa590c22SMicky Ching } 3902fa590c22SMicky Ching #endif 3903fa590c22SMicky Ching } else { 3904fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 3905fa590c22SMicky Ching retval = ms_delay_write(chip); 3906fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3907fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 3908fa590c22SMicky Ching set_sense_type(chip, lun, 3909fa590c22SMicky Ching SENSE_TYPE_MEDIA_NOT_PRESENT); 3910031366eaSJoe Perches rtsx_trace(chip); 3911031366eaSJoe Perches return STATUS_FAIL; 3912fa590c22SMicky Ching } 3913fa590c22SMicky Ching set_sense_type(chip, lun, 3914fa590c22SMicky Ching SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); 3915031366eaSJoe Perches rtsx_trace(chip); 3916031366eaSJoe Perches return STATUS_FAIL; 3917fa590c22SMicky Ching } 3918fa590c22SMicky Ching #endif 3919fa590c22SMicky Ching old_blk = ms_get_l2p_tbl(chip, seg_no, 3920fa590c22SMicky Ching log_blk - ms_start_idx[seg_no]); 3921fa590c22SMicky Ching if (old_blk == 0xFFFF) { 3922fa590c22SMicky Ching set_sense_type(chip, lun, 3923fa590c22SMicky Ching SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); 3924031366eaSJoe Perches rtsx_trace(chip); 3925031366eaSJoe Perches return STATUS_FAIL; 3926fa590c22SMicky Ching } 3927fa590c22SMicky Ching } 3928fa590c22SMicky Ching 3929bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n", 3930fa590c22SMicky Ching seg_no, old_blk, new_blk); 3931fa590c22SMicky Ching 3932fa590c22SMicky Ching while (total_sec_cnt) { 3933fa590c22SMicky Ching if ((start_page + total_sec_cnt) > (ms_card->page_off + 1)) 3934fa590c22SMicky Ching end_page = ms_card->page_off + 1; 3935fa590c22SMicky Ching else 3936fa590c22SMicky Ching end_page = start_page + (u8)total_sec_cnt; 3937fa590c22SMicky Ching 3938fa590c22SMicky Ching page_cnt = end_page - start_page; 3939fa590c22SMicky Ching 3940bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d, page_cnt = %d\n", 3941fa590c22SMicky Ching start_page, end_page, page_cnt); 3942fa590c22SMicky Ching 3943fa590c22SMicky Ching if (srb->sc_data_direction == DMA_FROM_DEVICE) { 3944fa590c22SMicky Ching retval = ms_read_multiple_pages(chip, 3945fa590c22SMicky Ching old_blk, log_blk, start_page, end_page, 3946fa590c22SMicky Ching ptr, &index, &offset); 3947fa590c22SMicky Ching } else { 3948fa590c22SMicky Ching retval = ms_write_multiple_pages(chip, old_blk, 3949fa590c22SMicky Ching new_blk, log_blk, start_page, end_page, 3950fa590c22SMicky Ching ptr, &index, &offset); 3951fa590c22SMicky Ching } 3952fa590c22SMicky Ching 3953fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3954fa590c22SMicky Ching toggle_gpio(chip, 1); 3955fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 3956fa590c22SMicky Ching set_sense_type(chip, lun, 3957fa590c22SMicky Ching SENSE_TYPE_MEDIA_NOT_PRESENT); 3958031366eaSJoe Perches rtsx_trace(chip); 3959031366eaSJoe Perches return STATUS_FAIL; 3960fa590c22SMicky Ching } 3961fa590c22SMicky Ching ms_rw_fail(srb, chip); 3962031366eaSJoe Perches rtsx_trace(chip); 3963031366eaSJoe Perches return STATUS_FAIL; 3964fa590c22SMicky Ching } 3965fa590c22SMicky Ching 3966fa590c22SMicky Ching if (srb->sc_data_direction == DMA_TO_DEVICE) { 3967fa590c22SMicky Ching if (end_page == (ms_card->page_off + 1)) { 3968fa590c22SMicky Ching retval = ms_erase_block(chip, old_blk); 3969fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 3970fa590c22SMicky Ching ms_set_unused_block(chip, old_blk); 3971fa590c22SMicky Ching 3972fa590c22SMicky Ching ms_set_l2p_tbl(chip, seg_no, 3973fa590c22SMicky Ching log_blk - ms_start_idx[seg_no], 3974fa590c22SMicky Ching new_blk); 3975fa590c22SMicky Ching } 3976fa590c22SMicky Ching } 3977fa590c22SMicky Ching 3978fa590c22SMicky Ching total_sec_cnt -= page_cnt; 3979fa590c22SMicky Ching if (scsi_sg_count(srb) == 0) 3980fa590c22SMicky Ching ptr += page_cnt * 512; 3981fa590c22SMicky Ching 3982fa590c22SMicky Ching if (total_sec_cnt == 0) 3983fa590c22SMicky Ching break; 3984fa590c22SMicky Ching 3985fa590c22SMicky Ching log_blk++; 3986fa590c22SMicky Ching 3987fa590c22SMicky Ching for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; 3988fa590c22SMicky Ching seg_no++) { 3989fa590c22SMicky Ching if (log_blk < ms_start_idx[seg_no+1]) 3990fa590c22SMicky Ching break; 3991fa590c22SMicky Ching } 3992fa590c22SMicky Ching 3993fa590c22SMicky Ching if (ms_card->segment[seg_no].build_flag == 0) { 3994fa590c22SMicky Ching retval = ms_build_l2p_tbl(chip, seg_no); 3995fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 3996fa590c22SMicky Ching chip->card_fail |= MS_CARD; 3997fa590c22SMicky Ching set_sense_type(chip, lun, 3998fa590c22SMicky Ching SENSE_TYPE_MEDIA_NOT_PRESENT); 3999031366eaSJoe Perches rtsx_trace(chip); 4000031366eaSJoe Perches return STATUS_FAIL; 4001fa590c22SMicky Ching } 4002fa590c22SMicky Ching } 4003fa590c22SMicky Ching 4004fa590c22SMicky Ching old_blk = ms_get_l2p_tbl(chip, seg_no, 4005fa590c22SMicky Ching log_blk - ms_start_idx[seg_no]); 4006fa590c22SMicky Ching if (old_blk == 0xFFFF) { 4007fa590c22SMicky Ching ms_rw_fail(srb, chip); 4008031366eaSJoe Perches rtsx_trace(chip); 4009031366eaSJoe Perches return STATUS_FAIL; 4010fa590c22SMicky Ching } 4011fa590c22SMicky Ching 4012fa590c22SMicky Ching if (srb->sc_data_direction == DMA_TO_DEVICE) { 4013fa590c22SMicky Ching new_blk = ms_get_unused_block(chip, seg_no); 4014fa590c22SMicky Ching if (new_blk == 0xFFFF) { 4015fa590c22SMicky Ching ms_rw_fail(srb, chip); 4016031366eaSJoe Perches rtsx_trace(chip); 4017031366eaSJoe Perches return STATUS_FAIL; 4018fa590c22SMicky Ching } 4019fa590c22SMicky Ching } 4020fa590c22SMicky Ching 4021bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n", 4022fa590c22SMicky Ching seg_no, old_blk, new_blk); 4023fa590c22SMicky Ching 4024fa590c22SMicky Ching start_page = 0; 4025fa590c22SMicky Ching } 4026fa590c22SMicky Ching 4027fa590c22SMicky Ching if (srb->sc_data_direction == DMA_TO_DEVICE) { 4028fa590c22SMicky Ching if (end_page < (ms_card->page_off + 1)) { 4029fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 4030fa590c22SMicky Ching delay_write->delay_write_flag = 1; 4031fa590c22SMicky Ching delay_write->old_phyblock = old_blk; 4032fa590c22SMicky Ching delay_write->new_phyblock = new_blk; 4033fa590c22SMicky Ching delay_write->logblock = log_blk; 4034fa590c22SMicky Ching delay_write->pageoff = end_page; 4035fa590c22SMicky Ching #else 4036fa590c22SMicky Ching retval = ms_finish_write(chip, old_blk, new_blk, 4037fa590c22SMicky Ching log_blk, end_page); 4038fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4039fa590c22SMicky Ching if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) { 4040fa590c22SMicky Ching set_sense_type(chip, lun, 4041fa590c22SMicky Ching SENSE_TYPE_MEDIA_NOT_PRESENT); 4042031366eaSJoe Perches rtsx_trace(chip); 4043031366eaSJoe Perches return STATUS_FAIL; 4044fa590c22SMicky Ching } 4045fa590c22SMicky Ching 4046fa590c22SMicky Ching ms_rw_fail(srb, chip); 4047031366eaSJoe Perches rtsx_trace(chip); 4048031366eaSJoe Perches return STATUS_FAIL; 4049fa590c22SMicky Ching } 4050fa590c22SMicky Ching #endif 4051fa590c22SMicky Ching } 4052fa590c22SMicky Ching } 4053fa590c22SMicky Ching 4054fa590c22SMicky Ching scsi_set_resid(srb, 0); 4055fa590c22SMicky Ching 4056fa590c22SMicky Ching return STATUS_SUCCESS; 4057fa590c22SMicky Ching } 4058fa590c22SMicky Ching 4059fa590c22SMicky Ching int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, 4060fa590c22SMicky Ching u32 start_sector, u16 sector_cnt) 4061fa590c22SMicky Ching { 4062d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 4063fa590c22SMicky Ching int retval; 4064fa590c22SMicky Ching 4065fa590c22SMicky Ching if (CHK_MSPRO(ms_card)) 4066fa590c22SMicky Ching retval = mspro_rw_multi_sector(srb, chip, start_sector, 4067fa590c22SMicky Ching sector_cnt); 4068fa590c22SMicky Ching else 4069fa590c22SMicky Ching retval = ms_rw_multi_sector(srb, chip, start_sector, 4070fa590c22SMicky Ching sector_cnt); 4071fa590c22SMicky Ching 4072fa590c22SMicky Ching return retval; 4073fa590c22SMicky Ching } 4074fa590c22SMicky Ching 4075fa590c22SMicky Ching void ms_free_l2p_tbl(struct rtsx_chip *chip) 4076fa590c22SMicky Ching { 4077d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 4078fa590c22SMicky Ching int i = 0; 4079fa590c22SMicky Ching 4080fa590c22SMicky Ching if (ms_card->segment != NULL) { 4081fa590c22SMicky Ching for (i = 0; i < ms_card->segment_cnt; i++) { 4082fa590c22SMicky Ching vfree(ms_card->segment[i].l2p_table); 4083fa590c22SMicky Ching ms_card->segment[i].l2p_table = NULL; 4084fa590c22SMicky Ching vfree(ms_card->segment[i].free_table); 4085fa590c22SMicky Ching ms_card->segment[i].free_table = NULL; 4086fa590c22SMicky Ching } 4087fa590c22SMicky Ching vfree(ms_card->segment); 4088fa590c22SMicky Ching ms_card->segment = NULL; 4089fa590c22SMicky Ching } 4090fa590c22SMicky Ching } 4091fa590c22SMicky Ching 4092fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE 4093fa590c22SMicky Ching 4094fa590c22SMicky Ching #ifdef READ_BYTES_WAIT_INT 4095fa590c22SMicky Ching static int ms_poll_int(struct rtsx_chip *chip) 4096fa590c22SMicky Ching { 4097fa590c22SMicky Ching int retval; 4098fa590c22SMicky Ching u8 val; 4099fa590c22SMicky Ching 4100fa590c22SMicky Ching rtsx_init_cmd(chip); 4101fa590c22SMicky Ching 4102fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANS_CFG, MS_INT_CED, MS_INT_CED); 4103fa590c22SMicky Ching 4104fa590c22SMicky Ching retval = rtsx_send_cmd(chip, MS_CARD, 5000); 4105031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4106031366eaSJoe Perches rtsx_trace(chip); 4107031366eaSJoe Perches return STATUS_FAIL; 4108031366eaSJoe Perches } 4109fa590c22SMicky Ching 4110fa590c22SMicky Ching val = *rtsx_get_cmd_data(chip); 4111031366eaSJoe Perches if (val & MS_INT_ERR) { 4112031366eaSJoe Perches rtsx_trace(chip); 4113031366eaSJoe Perches return STATUS_FAIL; 4114031366eaSJoe Perches } 4115fa590c22SMicky Ching 4116fa590c22SMicky Ching return STATUS_SUCCESS; 4117fa590c22SMicky Ching } 4118fa590c22SMicky Ching #endif 4119fa590c22SMicky Ching 4120fa590c22SMicky Ching #ifdef MS_SAMPLE_INT_ERR 4121fa590c22SMicky Ching static int check_ms_err(struct rtsx_chip *chip) 4122fa590c22SMicky Ching { 4123fa590c22SMicky Ching int retval; 4124fa590c22SMicky Ching u8 val; 4125fa590c22SMicky Ching 4126fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANSFER, &val); 4127fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 4128fa590c22SMicky Ching return 1; 4129fa590c22SMicky Ching if (val & MS_TRANSFER_ERR) 4130fa590c22SMicky Ching return 1; 4131fa590c22SMicky Ching 4132fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); 4133fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 4134fa590c22SMicky Ching return 1; 4135fa590c22SMicky Ching 4136fa590c22SMicky Ching if (val & (MS_INT_ERR | MS_INT_CMDNK)) 4137fa590c22SMicky Ching return 1; 4138fa590c22SMicky Ching 4139fa590c22SMicky Ching return 0; 4140fa590c22SMicky Ching } 4141fa590c22SMicky Ching #else 4142fa590c22SMicky Ching static int check_ms_err(struct rtsx_chip *chip) 4143fa590c22SMicky Ching { 4144fa590c22SMicky Ching int retval; 4145fa590c22SMicky Ching u8 val; 4146fa590c22SMicky Ching 4147fa590c22SMicky Ching retval = rtsx_read_register(chip, MS_TRANSFER, &val); 4148fa590c22SMicky Ching if (retval != STATUS_SUCCESS) 4149fa590c22SMicky Ching return 1; 4150fa590c22SMicky Ching if (val & MS_TRANSFER_ERR) 4151fa590c22SMicky Ching return 1; 4152fa590c22SMicky Ching 4153fa590c22SMicky Ching return 0; 4154fa590c22SMicky Ching } 4155fa590c22SMicky Ching #endif 4156fa590c22SMicky Ching 4157fa590c22SMicky Ching static int mg_send_ex_cmd(struct rtsx_chip *chip, u8 cmd, u8 entry_num) 4158fa590c22SMicky Ching { 4159fa590c22SMicky Ching int retval, i; 4160fa590c22SMicky Ching u8 data[8]; 4161fa590c22SMicky Ching 4162fa590c22SMicky Ching data[0] = cmd; 4163fa590c22SMicky Ching data[1] = 0; 4164fa590c22SMicky Ching data[2] = 0; 4165fa590c22SMicky Ching data[3] = 0; 4166fa590c22SMicky Ching data[4] = 0; 4167fa590c22SMicky Ching data[5] = 0; 4168fa590c22SMicky Ching data[6] = entry_num; 4169fa590c22SMicky Ching data[7] = 0; 4170fa590c22SMicky Ching 4171fa590c22SMicky Ching for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { 4172fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7, WAIT_INT, 4173fa590c22SMicky Ching data, 8); 4174fa590c22SMicky Ching if (retval == STATUS_SUCCESS) 4175fa590c22SMicky Ching break; 4176fa590c22SMicky Ching } 4177031366eaSJoe Perches if (i == MS_MAX_RETRY_COUNT) { 4178031366eaSJoe Perches rtsx_trace(chip); 4179031366eaSJoe Perches return STATUS_FAIL; 4180031366eaSJoe Perches } 4181fa590c22SMicky Ching 4182fa590c22SMicky Ching if (check_ms_err(chip)) { 4183fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4184031366eaSJoe Perches rtsx_trace(chip); 4185031366eaSJoe Perches return STATUS_FAIL; 4186fa590c22SMicky Ching } 4187fa590c22SMicky Ching 4188fa590c22SMicky Ching return STATUS_SUCCESS; 4189fa590c22SMicky Ching } 4190fa590c22SMicky Ching 4191fa590c22SMicky Ching static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type, 4192fa590c22SMicky Ching u8 mg_entry_num) 4193fa590c22SMicky Ching { 4194fa590c22SMicky Ching int retval; 4195fa590c22SMicky Ching u8 buf[6]; 4196fa590c22SMicky Ching 4197fa590c22SMicky Ching if (type == 0) 4198fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_TPCParm, 1); 4199fa590c22SMicky Ching else 4200fa590c22SMicky Ching retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6); 4201fa590c22SMicky Ching 4202031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4203031366eaSJoe Perches rtsx_trace(chip); 4204031366eaSJoe Perches return STATUS_FAIL; 4205031366eaSJoe Perches } 4206fa590c22SMicky Ching 4207fa590c22SMicky Ching buf[0] = 0; 4208fa590c22SMicky Ching buf[1] = 0; 4209fa590c22SMicky Ching if (type == 1) { 4210fa590c22SMicky Ching buf[2] = 0; 4211fa590c22SMicky Ching buf[3] = 0; 4212fa590c22SMicky Ching buf[4] = 0; 4213fa590c22SMicky Ching buf[5] = mg_entry_num; 4214fa590c22SMicky Ching } 4215fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6, 4216fa590c22SMicky Ching NO_WAIT_INT, buf, 6); 4217031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4218031366eaSJoe Perches rtsx_trace(chip); 4219031366eaSJoe Perches return STATUS_FAIL; 4220031366eaSJoe Perches } 4221fa590c22SMicky Ching 4222fa590c22SMicky Ching return STATUS_SUCCESS; 4223fa590c22SMicky Ching } 4224fa590c22SMicky Ching 4225fa590c22SMicky Ching int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip) 4226fa590c22SMicky Ching { 4227fa590c22SMicky Ching int retval; 4228fa590c22SMicky Ching int i; 4229fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 4230fa590c22SMicky Ching u8 buf1[32], buf2[12]; 4231fa590c22SMicky Ching 4232fa590c22SMicky Ching if (scsi_bufflen(srb) < 12) { 4233fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); 4234031366eaSJoe Perches rtsx_trace(chip); 4235031366eaSJoe Perches return STATUS_FAIL; 4236fa590c22SMicky Ching } 4237fa590c22SMicky Ching 4238fa590c22SMicky Ching ms_cleanup_work(chip); 4239fa590c22SMicky Ching 4240fa590c22SMicky Ching retval = ms_switch_clock(chip); 4241031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4242031366eaSJoe Perches rtsx_trace(chip); 4243031366eaSJoe Perches return STATUS_FAIL; 4244031366eaSJoe Perches } 4245fa590c22SMicky Ching 4246fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_SET_LID, 0); 4247fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4248fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); 4249031366eaSJoe Perches rtsx_trace(chip); 4250031366eaSJoe Perches return STATUS_FAIL; 4251fa590c22SMicky Ching } 4252fa590c22SMicky Ching 4253fa590c22SMicky Ching memset(buf1, 0, 32); 4254fa590c22SMicky Ching rtsx_stor_get_xfer_buf(buf2, min_t(int, 12, scsi_bufflen(srb)), srb); 4255fa590c22SMicky Ching for (i = 0; i < 8; i++) 4256fa590c22SMicky Ching buf1[8 + i] = buf2[4 + i]; 4257fa590c22SMicky Ching 4258fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, 4259fa590c22SMicky Ching buf1, 32); 4260fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4261fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); 4262031366eaSJoe Perches rtsx_trace(chip); 4263031366eaSJoe Perches return STATUS_FAIL; 4264fa590c22SMicky Ching } 4265fa590c22SMicky Ching if (check_ms_err(chip)) { 4266fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); 4267fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4268031366eaSJoe Perches rtsx_trace(chip); 4269031366eaSJoe Perches return STATUS_FAIL; 4270fa590c22SMicky Ching } 4271fa590c22SMicky Ching 4272fa590c22SMicky Ching return STATUS_SUCCESS; 4273fa590c22SMicky Ching } 4274fa590c22SMicky Ching 4275fa590c22SMicky Ching int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip) 4276fa590c22SMicky Ching { 4277fa590c22SMicky Ching int retval = STATUS_FAIL; 4278fa590c22SMicky Ching int bufflen; 4279fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 4280fa590c22SMicky Ching u8 *buf = NULL; 4281fa590c22SMicky Ching 4282fa590c22SMicky Ching ms_cleanup_work(chip); 4283fa590c22SMicky Ching 4284fa590c22SMicky Ching retval = ms_switch_clock(chip); 4285031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4286031366eaSJoe Perches rtsx_trace(chip); 4287031366eaSJoe Perches return STATUS_FAIL; 4288031366eaSJoe Perches } 4289fa590c22SMicky Ching 4290fa590c22SMicky Ching buf = kmalloc(1540, GFP_KERNEL); 4291031366eaSJoe Perches if (!buf) { 4292031366eaSJoe Perches rtsx_trace(chip); 4293031366eaSJoe Perches return STATUS_ERROR; 4294031366eaSJoe Perches } 4295fa590c22SMicky Ching 4296fa590c22SMicky Ching buf[0] = 0x04; 4297fa590c22SMicky Ching buf[1] = 0x1A; 4298fa590c22SMicky Ching buf[2] = 0x00; 4299fa590c22SMicky Ching buf[3] = 0x00; 4300fa590c22SMicky Ching 4301fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_GET_LEKB, 0); 4302fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4303fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4304031366eaSJoe Perches rtsx_trace(chip); 4305541e4d2dSQuentin Lambert goto free_buffer; 4306fa590c22SMicky Ching } 4307fa590c22SMicky Ching 4308fa590c22SMicky Ching retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA, 4309fa590c22SMicky Ching 3, WAIT_INT, 0, 0, buf + 4, 1536); 4310fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4311fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4312fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4313031366eaSJoe Perches rtsx_trace(chip); 4314541e4d2dSQuentin Lambert goto free_buffer; 4315fa590c22SMicky Ching } 4316fa590c22SMicky Ching if (check_ms_err(chip)) { 4317fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4318fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4319031366eaSJoe Perches rtsx_trace(chip); 4320031366eaSJoe Perches return STATUS_FAIL; 4321fa590c22SMicky Ching } 4322fa590c22SMicky Ching 4323fa590c22SMicky Ching bufflen = min_t(int, 1052, scsi_bufflen(srb)); 4324fa590c22SMicky Ching rtsx_stor_set_xfer_buf(buf, bufflen, srb); 4325fa590c22SMicky Ching 4326541e4d2dSQuentin Lambert free_buffer: 4327fa590c22SMicky Ching kfree(buf); 4328fa590c22SMicky Ching return retval; 4329fa590c22SMicky Ching } 4330fa590c22SMicky Ching 4331fa590c22SMicky Ching int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip) 4332fa590c22SMicky Ching { 4333d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 4334fa590c22SMicky Ching int retval; 4335fa590c22SMicky Ching int bufflen; 4336fa590c22SMicky Ching int i; 4337fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 4338fa590c22SMicky Ching u8 buf[32]; 4339fa590c22SMicky Ching 4340fa590c22SMicky Ching ms_cleanup_work(chip); 4341fa590c22SMicky Ching 4342fa590c22SMicky Ching retval = ms_switch_clock(chip); 4343031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4344031366eaSJoe Perches rtsx_trace(chip); 4345031366eaSJoe Perches return STATUS_FAIL; 4346031366eaSJoe Perches } 4347fa590c22SMicky Ching 4348fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_GET_ID, 0); 4349fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4350fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); 4351031366eaSJoe Perches rtsx_trace(chip); 4352031366eaSJoe Perches return STATUS_FAIL; 4353fa590c22SMicky Ching } 4354fa590c22SMicky Ching 4355fa590c22SMicky Ching retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT, 4356fa590c22SMicky Ching buf, 32); 4357fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4358fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); 4359031366eaSJoe Perches rtsx_trace(chip); 4360031366eaSJoe Perches return STATUS_FAIL; 4361fa590c22SMicky Ching } 4362fa590c22SMicky Ching if (check_ms_err(chip)) { 4363fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); 4364fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4365031366eaSJoe Perches rtsx_trace(chip); 4366031366eaSJoe Perches return STATUS_FAIL; 4367fa590c22SMicky Ching } 4368fa590c22SMicky Ching 4369fa590c22SMicky Ching memcpy(ms_card->magic_gate_id, buf, 16); 4370fa590c22SMicky Ching 4371fa590c22SMicky Ching #ifdef READ_BYTES_WAIT_INT 4372fa590c22SMicky Ching retval = ms_poll_int(chip); 4373fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4374fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); 4375031366eaSJoe Perches rtsx_trace(chip); 4376031366eaSJoe Perches return STATUS_FAIL; 4377fa590c22SMicky Ching } 4378fa590c22SMicky Ching #endif 4379fa590c22SMicky Ching 4380fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_SET_RD, 0); 4381fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4382fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); 4383031366eaSJoe Perches rtsx_trace(chip); 4384031366eaSJoe Perches return STATUS_FAIL; 4385fa590c22SMicky Ching } 4386fa590c22SMicky Ching 4387fa590c22SMicky Ching bufflen = min_t(int, 12, scsi_bufflen(srb)); 4388fa590c22SMicky Ching rtsx_stor_get_xfer_buf(buf, bufflen, srb); 4389fa590c22SMicky Ching 4390fa590c22SMicky Ching for (i = 0; i < 8; i++) 4391fa590c22SMicky Ching buf[i] = buf[4 + i]; 4392fa590c22SMicky Ching 4393fa590c22SMicky Ching for (i = 0; i < 24; i++) 4394fa590c22SMicky Ching buf[8 + i] = 0; 4395fa590c22SMicky Ching 4396fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 4397fa590c22SMicky Ching 32, WAIT_INT, buf, 32); 4398fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4399fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); 4400031366eaSJoe Perches rtsx_trace(chip); 4401031366eaSJoe Perches return STATUS_FAIL; 4402fa590c22SMicky Ching } 4403fa590c22SMicky Ching if (check_ms_err(chip)) { 4404fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM); 4405fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4406031366eaSJoe Perches rtsx_trace(chip); 4407031366eaSJoe Perches return STATUS_FAIL; 4408fa590c22SMicky Ching } 4409fa590c22SMicky Ching 4410fa590c22SMicky Ching ms_card->mg_auth = 0; 4411fa590c22SMicky Ching 4412fa590c22SMicky Ching return STATUS_SUCCESS; 4413fa590c22SMicky Ching } 4414fa590c22SMicky Ching 4415fa590c22SMicky Ching int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip) 4416fa590c22SMicky Ching { 4417d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 4418fa590c22SMicky Ching int retval; 4419fa590c22SMicky Ching int bufflen; 4420fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 4421fa590c22SMicky Ching u8 buf1[32], buf2[36]; 4422fa590c22SMicky Ching 4423fa590c22SMicky Ching ms_cleanup_work(chip); 4424fa590c22SMicky Ching 4425fa590c22SMicky Ching retval = ms_switch_clock(chip); 4426031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4427031366eaSJoe Perches rtsx_trace(chip); 4428031366eaSJoe Perches return STATUS_FAIL; 4429031366eaSJoe Perches } 4430fa590c22SMicky Ching 4431fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0); 4432fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4433fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4434031366eaSJoe Perches rtsx_trace(chip); 4435031366eaSJoe Perches return STATUS_FAIL; 4436fa590c22SMicky Ching } 4437fa590c22SMicky Ching 4438fa590c22SMicky Ching retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT, 4439fa590c22SMicky Ching buf1, 32); 4440fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4441fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4442031366eaSJoe Perches rtsx_trace(chip); 4443031366eaSJoe Perches return STATUS_FAIL; 4444fa590c22SMicky Ching } 4445fa590c22SMicky Ching if (check_ms_err(chip)) { 4446fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4447fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4448031366eaSJoe Perches rtsx_trace(chip); 4449031366eaSJoe Perches return STATUS_FAIL; 4450fa590c22SMicky Ching } 4451fa590c22SMicky Ching 4452fa590c22SMicky Ching buf2[0] = 0x00; 4453fa590c22SMicky Ching buf2[1] = 0x22; 4454fa590c22SMicky Ching buf2[2] = 0x00; 4455fa590c22SMicky Ching buf2[3] = 0x00; 4456fa590c22SMicky Ching 4457fa590c22SMicky Ching memcpy(buf2 + 4, ms_card->magic_gate_id, 16); 4458fa590c22SMicky Ching memcpy(buf2 + 20, buf1, 16); 4459fa590c22SMicky Ching 4460fa590c22SMicky Ching bufflen = min_t(int, 36, scsi_bufflen(srb)); 4461fa590c22SMicky Ching rtsx_stor_set_xfer_buf(buf2, bufflen, srb); 4462fa590c22SMicky Ching 4463fa590c22SMicky Ching #ifdef READ_BYTES_WAIT_INT 4464fa590c22SMicky Ching retval = ms_poll_int(chip); 4465fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4466fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4467031366eaSJoe Perches rtsx_trace(chip); 4468031366eaSJoe Perches return STATUS_FAIL; 4469fa590c22SMicky Ching } 4470fa590c22SMicky Ching #endif 4471fa590c22SMicky Ching 4472fa590c22SMicky Ching return STATUS_SUCCESS; 4473fa590c22SMicky Ching } 4474fa590c22SMicky Ching 4475fa590c22SMicky Ching int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip) 4476fa590c22SMicky Ching { 4477d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 4478fa590c22SMicky Ching int retval; 4479fa590c22SMicky Ching int i; 4480fa590c22SMicky Ching int bufflen; 4481fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 4482fa590c22SMicky Ching u8 buf[32]; 4483fa590c22SMicky Ching 4484fa590c22SMicky Ching ms_cleanup_work(chip); 4485fa590c22SMicky Ching 4486fa590c22SMicky Ching retval = ms_switch_clock(chip); 4487031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4488031366eaSJoe Perches rtsx_trace(chip); 4489031366eaSJoe Perches return STATUS_FAIL; 4490031366eaSJoe Perches } 4491fa590c22SMicky Ching 4492fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0); 4493fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4494fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4495031366eaSJoe Perches rtsx_trace(chip); 4496031366eaSJoe Perches return STATUS_FAIL; 4497fa590c22SMicky Ching } 4498fa590c22SMicky Ching 4499fa590c22SMicky Ching bufflen = min_t(int, 12, scsi_bufflen(srb)); 4500fa590c22SMicky Ching rtsx_stor_get_xfer_buf(buf, bufflen, srb); 4501fa590c22SMicky Ching 4502fa590c22SMicky Ching for (i = 0; i < 8; i++) 4503fa590c22SMicky Ching buf[i] = buf[4 + i]; 4504fa590c22SMicky Ching 4505fa590c22SMicky Ching for (i = 0; i < 24; i++) 4506fa590c22SMicky Ching buf[8 + i] = 0; 4507fa590c22SMicky Ching 4508fa590c22SMicky Ching retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, 4509fa590c22SMicky Ching buf, 32); 4510fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4511fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4512031366eaSJoe Perches rtsx_trace(chip); 4513031366eaSJoe Perches return STATUS_FAIL; 4514fa590c22SMicky Ching } 4515fa590c22SMicky Ching if (check_ms_err(chip)) { 4516fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); 4517fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4518031366eaSJoe Perches rtsx_trace(chip); 4519031366eaSJoe Perches return STATUS_FAIL; 4520fa590c22SMicky Ching } 4521fa590c22SMicky Ching 4522fa590c22SMicky Ching ms_card->mg_auth = 1; 4523fa590c22SMicky Ching 4524fa590c22SMicky Ching return STATUS_SUCCESS; 4525fa590c22SMicky Ching } 4526fa590c22SMicky Ching 4527fa590c22SMicky Ching int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) 4528fa590c22SMicky Ching { 4529d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 4530fa590c22SMicky Ching int retval; 4531fa590c22SMicky Ching int bufflen; 4532fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 4533fa590c22SMicky Ching u8 *buf = NULL; 4534fa590c22SMicky Ching 4535fa590c22SMicky Ching ms_cleanup_work(chip); 4536fa590c22SMicky Ching 4537fa590c22SMicky Ching retval = ms_switch_clock(chip); 4538031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4539031366eaSJoe Perches rtsx_trace(chip); 4540031366eaSJoe Perches return STATUS_FAIL; 4541031366eaSJoe Perches } 4542fa590c22SMicky Ching 4543fa590c22SMicky Ching buf = kmalloc(1028, GFP_KERNEL); 4544031366eaSJoe Perches if (!buf) { 4545031366eaSJoe Perches rtsx_trace(chip); 4546031366eaSJoe Perches return STATUS_ERROR; 4547031366eaSJoe Perches } 4548fa590c22SMicky Ching 4549fa590c22SMicky Ching buf[0] = 0x04; 4550fa590c22SMicky Ching buf[1] = 0x02; 4551fa590c22SMicky Ching buf[2] = 0x00; 4552fa590c22SMicky Ching buf[3] = 0x00; 4553fa590c22SMicky Ching 4554fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_GET_IBD, ms_card->mg_entry_num); 4555fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4556fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); 4557031366eaSJoe Perches rtsx_trace(chip); 4558541e4d2dSQuentin Lambert goto free_buffer; 4559fa590c22SMicky Ching } 4560fa590c22SMicky Ching 4561fa590c22SMicky Ching retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA, 4562fa590c22SMicky Ching 2, WAIT_INT, 0, 0, buf + 4, 1024); 4563fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4564fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); 4565fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4566031366eaSJoe Perches rtsx_trace(chip); 4567541e4d2dSQuentin Lambert goto free_buffer; 4568fa590c22SMicky Ching } 4569fa590c22SMicky Ching if (check_ms_err(chip)) { 4570fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); 4571fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4572031366eaSJoe Perches rtsx_trace(chip); 4573031366eaSJoe Perches return STATUS_FAIL; 4574fa590c22SMicky Ching } 4575fa590c22SMicky Ching 4576fa590c22SMicky Ching bufflen = min_t(int, 1028, scsi_bufflen(srb)); 4577fa590c22SMicky Ching rtsx_stor_set_xfer_buf(buf, bufflen, srb); 4578fa590c22SMicky Ching 4579541e4d2dSQuentin Lambert free_buffer: 4580fa590c22SMicky Ching kfree(buf); 4581fa590c22SMicky Ching return retval; 4582fa590c22SMicky Ching } 4583fa590c22SMicky Ching 4584fa590c22SMicky Ching int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) 4585fa590c22SMicky Ching { 4586d1af6476SDilek Uzulmez struct ms_info *ms_card = &chip->ms_card; 4587fa590c22SMicky Ching int retval; 4588fa590c22SMicky Ching int bufflen; 4589fa590c22SMicky Ching #ifdef MG_SET_ICV_SLOW 4590fa590c22SMicky Ching int i; 4591fa590c22SMicky Ching #endif 4592fa590c22SMicky Ching unsigned int lun = SCSI_LUN(srb); 4593fa590c22SMicky Ching u8 *buf = NULL; 4594fa590c22SMicky Ching 4595fa590c22SMicky Ching ms_cleanup_work(chip); 4596fa590c22SMicky Ching 4597fa590c22SMicky Ching retval = ms_switch_clock(chip); 4598031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4599031366eaSJoe Perches rtsx_trace(chip); 4600031366eaSJoe Perches return STATUS_FAIL; 4601031366eaSJoe Perches } 4602fa590c22SMicky Ching 4603fa590c22SMicky Ching buf = kmalloc(1028, GFP_KERNEL); 4604031366eaSJoe Perches if (!buf) { 4605031366eaSJoe Perches rtsx_trace(chip); 4606031366eaSJoe Perches return STATUS_ERROR; 4607031366eaSJoe Perches } 4608fa590c22SMicky Ching 4609fa590c22SMicky Ching bufflen = min_t(int, 1028, scsi_bufflen(srb)); 4610fa590c22SMicky Ching rtsx_stor_get_xfer_buf(buf, bufflen, srb); 4611fa590c22SMicky Ching 4612fa590c22SMicky Ching retval = mg_send_ex_cmd(chip, MG_SET_IBD, ms_card->mg_entry_num); 4613fa590c22SMicky Ching if (retval != STATUS_SUCCESS) { 4614fa590c22SMicky Ching if (ms_card->mg_auth == 0) { 4615fa590c22SMicky Ching if ((buf[5] & 0xC0) != 0) 4616fa590c22SMicky Ching set_sense_type(chip, lun, 4617fa590c22SMicky Ching SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); 4618fa590c22SMicky Ching else 4619fa590c22SMicky Ching set_sense_type(chip, lun, 4620fa590c22SMicky Ching SENSE_TYPE_MG_WRITE_ERR); 4621fa590c22SMicky Ching } else { 4622fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); 4623fa590c22SMicky Ching } 4624031366eaSJoe Perches rtsx_trace(chip); 4625031366eaSJoe Perches goto SetICVFinish; 4626fa590c22SMicky Ching } 4627fa590c22SMicky Ching 4628fa590c22SMicky Ching #ifdef MG_SET_ICV_SLOW 4629fa590c22SMicky Ching for (i = 0; i < 2; i++) { 4630fa590c22SMicky Ching udelay(50); 4631fa590c22SMicky Ching 4632fa590c22SMicky Ching rtsx_init_cmd(chip); 4633fa590c22SMicky Ching 4634fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 4635fa590c22SMicky Ching 0xFF, PRO_WRITE_LONG_DATA); 4636fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, WAIT_INT); 4637fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 4638fa590c22SMicky Ching 0x01, RING_BUFFER); 4639fa590c22SMicky Ching 4640fa590c22SMicky Ching trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512); 4641fa590c22SMicky Ching 4642fa590c22SMicky Ching rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, 4643fa590c22SMicky Ching MS_TRANSFER_START | MS_TM_NORMAL_WRITE); 4644fa590c22SMicky Ching rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, 4645fa590c22SMicky Ching MS_TRANSFER_END, MS_TRANSFER_END); 4646fa590c22SMicky Ching 4647fa590c22SMicky Ching rtsx_send_cmd_no_wait(chip); 4648fa590c22SMicky Ching 4649fa590c22SMicky Ching retval = rtsx_transfer_data(chip, MS_CARD, buf + 4 + i*512, 4650fa590c22SMicky Ching 512, 0, DMA_TO_DEVICE, 3000); 4651fa590c22SMicky Ching if ((retval < 0) || check_ms_err(chip)) { 4652fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4653fa590c22SMicky Ching if (ms_card->mg_auth == 0) { 4654fa590c22SMicky Ching if ((buf[5] & 0xC0) != 0) 4655fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); 4656fa590c22SMicky Ching else 4657fa590c22SMicky Ching set_sense_type(chip, lun, 4658fa590c22SMicky Ching SENSE_TYPE_MG_WRITE_ERR); 4659fa590c22SMicky Ching } else { 4660fa590c22SMicky Ching set_sense_type(chip, lun, 4661fa590c22SMicky Ching SENSE_TYPE_MG_WRITE_ERR); 4662fa590c22SMicky Ching } 4663fa590c22SMicky Ching retval = STATUS_FAIL; 4664031366eaSJoe Perches rtsx_trace(chip); 4665031366eaSJoe Perches goto SetICVFinish; 4666fa590c22SMicky Ching } 4667fa590c22SMicky Ching } 4668fa590c22SMicky Ching #else 4669fa590c22SMicky Ching retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA, 4670fa590c22SMicky Ching 2, WAIT_INT, 0, 0, buf + 4, 1024); 4671fa590c22SMicky Ching if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) { 4672fa590c22SMicky Ching rtsx_clear_ms_error(chip); 4673fa590c22SMicky Ching if (ms_card->mg_auth == 0) { 4674fa590c22SMicky Ching if ((buf[5] & 0xC0) != 0) 4675fa590c22SMicky Ching set_sense_type(chip, lun, 4676fa590c22SMicky Ching SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); 4677fa590c22SMicky Ching else 4678fa590c22SMicky Ching set_sense_type(chip, lun, 4679fa590c22SMicky Ching SENSE_TYPE_MG_WRITE_ERR); 4680fa590c22SMicky Ching } else { 4681fa590c22SMicky Ching set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); 4682fa590c22SMicky Ching } 4683031366eaSJoe Perches rtsx_trace(chip); 4684031366eaSJoe Perches goto SetICVFinish; 4685fa590c22SMicky Ching } 4686fa590c22SMicky Ching #endif 4687fa590c22SMicky Ching 4688fa590c22SMicky Ching SetICVFinish: 4689fa590c22SMicky Ching kfree(buf); 4690fa590c22SMicky Ching return retval; 4691fa590c22SMicky Ching } 4692fa590c22SMicky Ching 4693fa590c22SMicky Ching #endif /* SUPPORT_MAGIC_GATE */ 4694fa590c22SMicky Ching 4695fa590c22SMicky Ching void ms_cleanup_work(struct rtsx_chip *chip) 4696fa590c22SMicky Ching { 4697fa590c22SMicky Ching struct ms_info *ms_card = &(chip->ms_card); 4698fa590c22SMicky Ching 4699fa590c22SMicky Ching if (CHK_MSPRO(ms_card)) { 4700fa590c22SMicky Ching if (ms_card->seq_mode) { 4701bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "MS Pro: stop transmission\n"); 4702fa590c22SMicky Ching mspro_stop_seq_mode(chip); 4703fa590c22SMicky Ching ms_card->cleanup_counter = 0; 4704fa590c22SMicky Ching } 4705fa590c22SMicky Ching if (CHK_MSHG(ms_card)) { 4706fa590c22SMicky Ching rtsx_write_register(chip, MS_CFG, 4707fa590c22SMicky Ching MS_2K_SECTOR_MODE, 0x00); 4708fa590c22SMicky Ching } 4709fa590c22SMicky Ching } 4710fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 4711fa590c22SMicky Ching else if ((!CHK_MSPRO(ms_card)) && ms_card->delay_write.delay_write_flag) { 4712bf6c0d11SFabio Falzoi dev_dbg(rtsx_dev(chip), "MS: delay write\n"); 4713fa590c22SMicky Ching ms_delay_write(chip); 4714fa590c22SMicky Ching ms_card->cleanup_counter = 0; 4715fa590c22SMicky Ching } 4716fa590c22SMicky Ching #endif 4717fa590c22SMicky Ching } 4718fa590c22SMicky Ching 4719fa590c22SMicky Ching int ms_power_off_card3v3(struct rtsx_chip *chip) 4720fa590c22SMicky Ching { 4721fa590c22SMicky Ching int retval; 4722fa590c22SMicky Ching 4723fa590c22SMicky Ching retval = disable_card_clock(chip, MS_CARD); 4724031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4725031366eaSJoe Perches rtsx_trace(chip); 4726031366eaSJoe Perches return STATUS_FAIL; 4727031366eaSJoe Perches } 4728fa590c22SMicky Ching 4729fa590c22SMicky Ching if (chip->asic_code) { 4730fa590c22SMicky Ching retval = ms_pull_ctl_disable(chip); 4731031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4732031366eaSJoe Perches rtsx_trace(chip); 4733031366eaSJoe Perches return STATUS_FAIL; 4734031366eaSJoe Perches } 4735fa590c22SMicky Ching } else { 47368ee775f9SJoe Perches retval = rtsx_write_register(chip, FPGA_PULL_CTL, 47378ee775f9SJoe Perches FPGA_MS_PULL_CTL_BIT | 0x20, 47388ee775f9SJoe Perches FPGA_MS_PULL_CTL_BIT); 47398ee775f9SJoe Perches if (retval) { 47408ee775f9SJoe Perches rtsx_trace(chip); 47418ee775f9SJoe Perches return retval; 4742fa590c22SMicky Ching } 47438ee775f9SJoe Perches } 47448ee775f9SJoe Perches retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0); 47458ee775f9SJoe Perches if (retval) { 47468ee775f9SJoe Perches rtsx_trace(chip); 47478ee775f9SJoe Perches return retval; 47488ee775f9SJoe Perches } 4749fa590c22SMicky Ching if (!chip->ft2_fast_mode) { 4750fa590c22SMicky Ching retval = card_power_off(chip, MS_CARD); 4751031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4752031366eaSJoe Perches rtsx_trace(chip); 4753031366eaSJoe Perches return STATUS_FAIL; 4754031366eaSJoe Perches } 4755fa590c22SMicky Ching } 4756fa590c22SMicky Ching 4757fa590c22SMicky Ching return STATUS_SUCCESS; 4758fa590c22SMicky Ching } 4759fa590c22SMicky Ching 4760fa590c22SMicky Ching int release_ms_card(struct rtsx_chip *chip) 4761fa590c22SMicky Ching { 4762fa590c22SMicky Ching struct ms_info *ms_card = &(chip->ms_card); 4763fa590c22SMicky Ching int retval; 4764fa590c22SMicky Ching 4765fa590c22SMicky Ching #ifdef MS_DELAY_WRITE 4766fa590c22SMicky Ching ms_card->delay_write.delay_write_flag = 0; 4767fa590c22SMicky Ching #endif 4768fa590c22SMicky Ching ms_card->pro_under_formatting = 0; 4769fa590c22SMicky Ching 4770fa590c22SMicky Ching chip->card_ready &= ~MS_CARD; 4771fa590c22SMicky Ching chip->card_fail &= ~MS_CARD; 4772fa590c22SMicky Ching chip->card_wp &= ~MS_CARD; 4773fa590c22SMicky Ching 4774fa590c22SMicky Ching ms_free_l2p_tbl(chip); 4775fa590c22SMicky Ching 4776fa590c22SMicky Ching memset(ms_card->raw_sys_info, 0, 96); 4777fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18 4778fa590c22SMicky Ching memset(ms_card->raw_model_name, 0, 48); 4779fa590c22SMicky Ching #endif 4780fa590c22SMicky Ching 4781fa590c22SMicky Ching retval = ms_power_off_card3v3(chip); 4782031366eaSJoe Perches if (retval != STATUS_SUCCESS) { 4783031366eaSJoe Perches rtsx_trace(chip); 4784031366eaSJoe Perches return STATUS_FAIL; 4785031366eaSJoe Perches } 4786fa590c22SMicky Ching 4787fa590c22SMicky Ching return STATUS_SUCCESS; 4788fa590c22SMicky Ching } 4789