xref: /openbmc/linux/drivers/staging/rts5208/ms.c (revision 5a77b84d)
1bb1e6779SKim Bradley // SPDX-License-Identifier: GPL-2.0+
2bb1e6779SKim Bradley /*
3bb1e6779SKim Bradley  * Driver for Realtek PCI-Express card reader
4fa590c22SMicky Ching  *
5fa590c22SMicky Ching  * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
6fa590c22SMicky Ching  *
7fa590c22SMicky Ching  * Author:
8fa590c22SMicky Ching  *   Wei WANG (wei_wang@realsil.com.cn)
9fa590c22SMicky Ching  *   Micky Ching (micky_ching@realsil.com.cn)
10fa590c22SMicky Ching  */
11fa590c22SMicky Ching 
12fa590c22SMicky Ching #include <linux/blkdev.h>
13fa590c22SMicky Ching #include <linux/kthread.h>
14fa590c22SMicky Ching #include <linux/sched.h>
15fa590c22SMicky Ching #include <linux/vmalloc.h>
16fa590c22SMicky Ching 
17fa590c22SMicky Ching #include "rtsx.h"
18fa590c22SMicky Ching #include "ms.h"
19fa590c22SMicky Ching 
ms_set_err_code(struct rtsx_chip * chip,u8 err_code)20fa590c22SMicky Ching static inline void ms_set_err_code(struct rtsx_chip *chip, u8 err_code)
21fa590c22SMicky Ching {
22d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
23fa590c22SMicky Ching 
24fa590c22SMicky Ching 	ms_card->err_code = err_code;
25fa590c22SMicky Ching }
26fa590c22SMicky Ching 
ms_check_err_code(struct rtsx_chip * chip,u8 err_code)27fa590c22SMicky Ching static inline int ms_check_err_code(struct rtsx_chip *chip, u8 err_code)
28fa590c22SMicky Ching {
29d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
30fa590c22SMicky Ching 
31fa590c22SMicky Ching 	return (ms_card->err_code == err_code);
32fa590c22SMicky Ching }
33fa590c22SMicky Ching 
ms_parse_err_code(struct rtsx_chip * chip)34fa590c22SMicky Ching static int ms_parse_err_code(struct rtsx_chip *chip)
35fa590c22SMicky Ching {
36031366eaSJoe Perches 	return STATUS_FAIL;
37fa590c22SMicky Ching }
38fa590c22SMicky Ching 
ms_transfer_tpc(struct rtsx_chip * chip,u8 trans_mode,u8 tpc,u8 cnt,u8 cfg)39fa590c22SMicky Ching static int ms_transfer_tpc(struct rtsx_chip *chip, u8 trans_mode,
40fa590c22SMicky Ching 			   u8 tpc, u8 cnt, u8 cfg)
41fa590c22SMicky Ching {
42d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
43fa590c22SMicky Ching 	int retval;
44fa590c22SMicky Ching 	u8 *ptr;
45fa590c22SMicky Ching 
46bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "%s: tpc = 0x%x\n", __func__, tpc);
47fa590c22SMicky Ching 
48fa590c22SMicky Ching 	rtsx_init_cmd(chip);
49fa590c22SMicky Ching 
50fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
51fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
52fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
53fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
54fa590c22SMicky Ching 		     0x01, PINGPONG_BUFFER);
55fa590c22SMicky Ching 
56fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER,
57fa590c22SMicky Ching 		     0xFF, MS_TRANSFER_START | trans_mode);
58fa590c22SMicky Ching 	rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
59fa590c22SMicky Ching 		     MS_TRANSFER_END, MS_TRANSFER_END);
60fa590c22SMicky Ching 
61fa590c22SMicky Ching 	rtsx_add_cmd(chip, READ_REG_CMD, MS_TRANS_CFG, 0, 0);
62fa590c22SMicky Ching 
63fa590c22SMicky Ching 	retval = rtsx_send_cmd(chip, MS_CARD, 5000);
64fa590c22SMicky Ching 	if (retval < 0) {
65fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
66fa590c22SMicky Ching 		ms_set_err_code(chip, MS_TO_ERROR);
67031366eaSJoe Perches 		return ms_parse_err_code(chip);
68fa590c22SMicky Ching 	}
69fa590c22SMicky Ching 
70fa590c22SMicky Ching 	ptr = rtsx_get_cmd_data(chip) + 1;
71fa590c22SMicky Ching 
72fa590c22SMicky Ching 	if (!(tpc & 0x08)) {		/* Read Packet */
73fa590c22SMicky Ching 		if (*ptr & MS_CRC16_ERR) {
74fa590c22SMicky Ching 			ms_set_err_code(chip, MS_CRC16_ERROR);
75031366eaSJoe Perches 			return ms_parse_err_code(chip);
76fa590c22SMicky Ching 		}
77fa590c22SMicky Ching 	} else {			/* Write Packet */
78fa590c22SMicky Ching 		if (CHK_MSPRO(ms_card) && !(*ptr & 0x80)) {
79fa590c22SMicky Ching 			if (*ptr & (MS_INT_ERR | MS_INT_CMDNK)) {
80fa590c22SMicky Ching 				ms_set_err_code(chip, MS_CMD_NK);
81031366eaSJoe Perches 				return ms_parse_err_code(chip);
82fa590c22SMicky Ching 			}
83fa590c22SMicky Ching 		}
84fa590c22SMicky Ching 	}
85fa590c22SMicky Ching 
86fa590c22SMicky Ching 	if (*ptr & MS_RDY_TIMEOUT) {
87fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
88fa590c22SMicky Ching 		ms_set_err_code(chip, MS_TO_ERROR);
89031366eaSJoe Perches 		return ms_parse_err_code(chip);
90fa590c22SMicky Ching 	}
91fa590c22SMicky Ching 
92fa590c22SMicky Ching 	return STATUS_SUCCESS;
93fa590c22SMicky Ching }
94fa590c22SMicky Ching 
ms_transfer_data(struct rtsx_chip * chip,u8 trans_mode,u8 tpc,u16 sec_cnt,u8 cfg,bool mode_2k,int use_sg,void * buf,int buf_len)95fa590c22SMicky Ching static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode,
9611201769SQuentin Lambert 			    u8 tpc, u16 sec_cnt, u8 cfg, bool mode_2k,
97fa590c22SMicky Ching 			    int use_sg, void *buf, int buf_len)
98fa590c22SMicky Ching {
99fa590c22SMicky Ching 	int retval;
100fa590c22SMicky Ching 	u8 val, err_code = 0;
101fa590c22SMicky Ching 	enum dma_data_direction dir;
102fa590c22SMicky Ching 
1039f902b49SAymen Qader 	if (!buf || !buf_len)
104031366eaSJoe Perches 		return STATUS_FAIL;
105fa590c22SMicky Ching 
106fa590c22SMicky Ching 	if (trans_mode == MS_TM_AUTO_READ) {
107fa590c22SMicky Ching 		dir = DMA_FROM_DEVICE;
108fa590c22SMicky Ching 		err_code = MS_FLASH_READ_ERROR;
109fa590c22SMicky Ching 	} else if (trans_mode == MS_TM_AUTO_WRITE) {
110fa590c22SMicky Ching 		dir = DMA_TO_DEVICE;
111fa590c22SMicky Ching 		err_code = MS_FLASH_WRITE_ERROR;
112fa590c22SMicky Ching 	} else {
113031366eaSJoe Perches 		return STATUS_FAIL;
114fa590c22SMicky Ching 	}
115fa590c22SMicky Ching 
116fa590c22SMicky Ching 	rtsx_init_cmd(chip);
117fa590c22SMicky Ching 
118fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
119fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD,
120fa590c22SMicky Ching 		     MS_SECTOR_CNT_H, 0xFF, (u8)(sec_cnt >> 8));
121fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_SECTOR_CNT_L, 0xFF, (u8)sec_cnt);
122fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
123fa590c22SMicky Ching 
124fa590c22SMicky Ching 	if (mode_2k) {
125fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD,
126fa590c22SMicky Ching 			     MS_CFG, MS_2K_SECTOR_MODE, MS_2K_SECTOR_MODE);
127fa590c22SMicky Ching 	} else {
128fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_CFG, MS_2K_SECTOR_MODE, 0);
129fa590c22SMicky Ching 	}
130fa590c22SMicky Ching 
131fa590c22SMicky Ching 	trans_dma_enable(dir, chip, sec_cnt * 512, DMA_512);
132fa590c22SMicky Ching 
133fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD,
134fa590c22SMicky Ching 		     MS_TRANSFER, 0xFF, MS_TRANSFER_START | trans_mode);
135fa590c22SMicky Ching 	rtsx_add_cmd(chip, CHECK_REG_CMD,
136fa590c22SMicky Ching 		     MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END);
137fa590c22SMicky Ching 
138fa590c22SMicky Ching 	rtsx_send_cmd_no_wait(chip);
139fa590c22SMicky Ching 
140fa590c22SMicky Ching 	retval = rtsx_transfer_data(chip, MS_CARD, buf, buf_len,
141fa590c22SMicky Ching 				    use_sg, dir, chip->mspro_timeout);
142fa590c22SMicky Ching 	if (retval < 0) {
143fa590c22SMicky Ching 		ms_set_err_code(chip, err_code);
144fa590c22SMicky Ching 		if (retval == -ETIMEDOUT)
145fa590c22SMicky Ching 			retval = STATUS_TIMEDOUT;
146fa590c22SMicky Ching 		else
147fa590c22SMicky Ching 			retval = STATUS_FAIL;
148fa590c22SMicky Ching 
149031366eaSJoe Perches 		return retval;
150fa590c22SMicky Ching 	}
151fa590c22SMicky Ching 
1528ee775f9SJoe Perches 	retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
1539f902b49SAymen Qader 	if (retval)
1548ee775f9SJoe Perches 		return retval;
1559f902b49SAymen Qader 
1569f902b49SAymen Qader 	if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT))
157031366eaSJoe Perches 		return STATUS_FAIL;
158fa590c22SMicky Ching 
159fa590c22SMicky Ching 	return STATUS_SUCCESS;
160fa590c22SMicky Ching }
161fa590c22SMicky Ching 
ms_write_bytes(struct rtsx_chip * chip,u8 tpc,u8 cnt,u8 cfg,u8 * data,int data_len)162fa590c22SMicky Ching static int ms_write_bytes(struct rtsx_chip *chip,
163fa590c22SMicky Ching 			  u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len)
164fa590c22SMicky Ching {
165d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
166fa590c22SMicky Ching 	int retval, i;
167fa590c22SMicky Ching 
1687b228bdfSBenjamin Philip 	if (!data || data_len < cnt)
169031366eaSJoe Perches 		return STATUS_ERROR;
170fa590c22SMicky Ching 
171fa590c22SMicky Ching 	rtsx_init_cmd(chip);
172fa590c22SMicky Ching 
173fa590c22SMicky Ching 	for (i = 0; i < cnt; i++) {
174fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD,
175fa590c22SMicky Ching 			     PPBUF_BASE2 + i, 0xFF, data[i]);
176fa590c22SMicky Ching 	}
177fa590c22SMicky Ching 	if (cnt % 2)
178fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF, 0xFF);
179fa590c22SMicky Ching 
180fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
181fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
182fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
183fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
184fa590c22SMicky Ching 		     0x01, PINGPONG_BUFFER);
185fa590c22SMicky Ching 
186fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD,
187fa590c22SMicky Ching 		     MS_TRANSFER, 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES);
188fa590c22SMicky Ching 	rtsx_add_cmd(chip, CHECK_REG_CMD,
189fa590c22SMicky Ching 		     MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END);
190fa590c22SMicky Ching 
191fa590c22SMicky Ching 	retval = rtsx_send_cmd(chip, MS_CARD, 5000);
192fa590c22SMicky Ching 	if (retval < 0) {
193fa590c22SMicky Ching 		u8 val = 0;
194fa590c22SMicky Ching 
195fa590c22SMicky Ching 		rtsx_read_register(chip, MS_TRANS_CFG, &val);
196bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "MS_TRANS_CFG: 0x%02x\n", val);
197fa590c22SMicky Ching 
198fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
199fa590c22SMicky Ching 
200fa590c22SMicky Ching 		if (!(tpc & 0x08)) {
201fa590c22SMicky Ching 			if (val & MS_CRC16_ERR) {
202fa590c22SMicky Ching 				ms_set_err_code(chip, MS_CRC16_ERROR);
203031366eaSJoe Perches 				return ms_parse_err_code(chip);
204fa590c22SMicky Ching 			}
205fa590c22SMicky Ching 		} else {
206fa590c22SMicky Ching 			if (CHK_MSPRO(ms_card) && !(val & 0x80)) {
207fa590c22SMicky Ching 				if (val & (MS_INT_ERR | MS_INT_CMDNK)) {
208fa590c22SMicky Ching 					ms_set_err_code(chip, MS_CMD_NK);
209031366eaSJoe Perches 					return ms_parse_err_code(chip);
210fa590c22SMicky Ching 				}
211fa590c22SMicky Ching 			}
212fa590c22SMicky Ching 		}
213fa590c22SMicky Ching 
214fa590c22SMicky Ching 		if (val & MS_RDY_TIMEOUT) {
215fa590c22SMicky Ching 			ms_set_err_code(chip, MS_TO_ERROR);
216031366eaSJoe Perches 			return ms_parse_err_code(chip);
217fa590c22SMicky Ching 		}
218fa590c22SMicky Ching 
219fa590c22SMicky Ching 		ms_set_err_code(chip, MS_TO_ERROR);
220031366eaSJoe Perches 		return ms_parse_err_code(chip);
221fa590c22SMicky Ching 	}
222fa590c22SMicky Ching 
223fa590c22SMicky Ching 	return STATUS_SUCCESS;
224fa590c22SMicky Ching }
225fa590c22SMicky Ching 
ms_read_bytes(struct rtsx_chip * chip,u8 tpc,u8 cnt,u8 cfg,u8 * data,int data_len)226fa590c22SMicky Ching static int ms_read_bytes(struct rtsx_chip *chip,
227fa590c22SMicky Ching 			 u8 tpc, u8 cnt, u8 cfg, u8 *data, int data_len)
228fa590c22SMicky Ching {
229d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
230fa590c22SMicky Ching 	int retval, i;
231fa590c22SMicky Ching 	u8 *ptr;
232fa590c22SMicky Ching 
2339f902b49SAymen Qader 	if (!data)
234031366eaSJoe Perches 		return STATUS_ERROR;
235fa590c22SMicky Ching 
236fa590c22SMicky Ching 	rtsx_init_cmd(chip);
237fa590c22SMicky Ching 
238fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc);
239fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt);
240fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg);
241fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
242fa590c22SMicky Ching 		     0x01, PINGPONG_BUFFER);
243fa590c22SMicky Ching 
244fa590c22SMicky Ching 	rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
245fa590c22SMicky Ching 		     MS_TRANSFER_START | MS_TM_READ_BYTES);
246fa590c22SMicky Ching 	rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
247fa590c22SMicky Ching 		     MS_TRANSFER_END, MS_TRANSFER_END);
248fa590c22SMicky Ching 
249fa590c22SMicky Ching 	for (i = 0; i < data_len - 1; i++)
250fa590c22SMicky Ching 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0);
251fa590c22SMicky Ching 
252fa590c22SMicky Ching 	if (data_len % 2)
253fa590c22SMicky Ching 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0);
254fa590c22SMicky Ching 	else
255fa590c22SMicky Ching 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len - 1,
256fa590c22SMicky Ching 			     0, 0);
257fa590c22SMicky Ching 
258fa590c22SMicky Ching 	retval = rtsx_send_cmd(chip, MS_CARD, 5000);
259fa590c22SMicky Ching 	if (retval < 0) {
260fa590c22SMicky Ching 		u8 val = 0;
261fa590c22SMicky Ching 
262fa590c22SMicky Ching 		rtsx_read_register(chip, MS_TRANS_CFG, &val);
263fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
264fa590c22SMicky Ching 
265fa590c22SMicky Ching 		if (!(tpc & 0x08)) {
266fa590c22SMicky Ching 			if (val & MS_CRC16_ERR) {
267fa590c22SMicky Ching 				ms_set_err_code(chip, MS_CRC16_ERROR);
268031366eaSJoe Perches 				return ms_parse_err_code(chip);
269fa590c22SMicky Ching 			}
270fa590c22SMicky Ching 		} else {
271fa590c22SMicky Ching 			if (CHK_MSPRO(ms_card) && !(val & 0x80)) {
272fa590c22SMicky Ching 				if (val & (MS_INT_ERR | MS_INT_CMDNK)) {
273fa590c22SMicky Ching 					ms_set_err_code(chip, MS_CMD_NK);
274031366eaSJoe Perches 					return ms_parse_err_code(chip);
275fa590c22SMicky Ching 				}
276fa590c22SMicky Ching 			}
277fa590c22SMicky Ching 		}
278fa590c22SMicky Ching 
279fa590c22SMicky Ching 		if (val & MS_RDY_TIMEOUT) {
280fa590c22SMicky Ching 			ms_set_err_code(chip, MS_TO_ERROR);
281031366eaSJoe Perches 			return ms_parse_err_code(chip);
282fa590c22SMicky Ching 		}
283fa590c22SMicky Ching 
284fa590c22SMicky Ching 		ms_set_err_code(chip, MS_TO_ERROR);
285031366eaSJoe Perches 		return ms_parse_err_code(chip);
286fa590c22SMicky Ching 	}
287fa590c22SMicky Ching 
288fa590c22SMicky Ching 	ptr = rtsx_get_cmd_data(chip) + 1;
289fa590c22SMicky Ching 
290fa590c22SMicky Ching 	for (i = 0; i < data_len; i++)
291fa590c22SMicky Ching 		data[i] = ptr[i];
292fa590c22SMicky Ching 
2937b228bdfSBenjamin Philip 	if (tpc == PRO_READ_SHORT_DATA && data_len == 8) {
294bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "Read format progress:\n");
29569b8b224SFabio Falzoi 		print_hex_dump_bytes(KBUILD_MODNAME ": ", DUMP_PREFIX_NONE, ptr,
29669b8b224SFabio Falzoi 				     cnt);
297fa590c22SMicky Ching 	}
298fa590c22SMicky Ching 
299fa590c22SMicky Ching 	return STATUS_SUCCESS;
300fa590c22SMicky Ching }
301fa590c22SMicky Ching 
ms_set_rw_reg_addr(struct rtsx_chip * chip,u8 read_start,u8 read_cnt,u8 write_start,u8 write_cnt)302259334edSWayne Porter static int ms_set_rw_reg_addr(struct rtsx_chip *chip, u8 read_start,
303259334edSWayne Porter 			      u8 read_cnt, u8 write_start, u8 write_cnt)
304fa590c22SMicky Ching {
305fa590c22SMicky Ching 	int retval, i;
306fa590c22SMicky Ching 	u8 data[4];
307fa590c22SMicky Ching 
308fa590c22SMicky Ching 	data[0] = read_start;
309fa590c22SMicky Ching 	data[1] = read_cnt;
310fa590c22SMicky Ching 	data[2] = write_start;
311fa590c22SMicky Ching 	data[3] = write_cnt;
312fa590c22SMicky Ching 
313fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
314fa590c22SMicky Ching 		retval = ms_write_bytes(chip, SET_RW_REG_ADRS, 4,
315fa590c22SMicky Ching 					NO_WAIT_INT, data, 4);
316fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
317fa590c22SMicky Ching 			return STATUS_SUCCESS;
318fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
319fa590c22SMicky Ching 	}
320fa590c22SMicky Ching 
321031366eaSJoe Perches 	return STATUS_FAIL;
322fa590c22SMicky Ching }
323fa590c22SMicky Ching 
ms_send_cmd(struct rtsx_chip * chip,u8 cmd,u8 cfg)324fa590c22SMicky Ching static int ms_send_cmd(struct rtsx_chip *chip, u8 cmd, u8 cfg)
325fa590c22SMicky Ching {
326fa590c22SMicky Ching 	u8 data[2];
327fa590c22SMicky Ching 
328fa590c22SMicky Ching 	data[0] = cmd;
329fa590c22SMicky Ching 	data[1] = 0;
330fa590c22SMicky Ching 
331fa590c22SMicky Ching 	return ms_write_bytes(chip, PRO_SET_CMD, 1, cfg, data, 1);
332fa590c22SMicky Ching }
333fa590c22SMicky Ching 
ms_set_init_para(struct rtsx_chip * chip)334fa590c22SMicky Ching static int ms_set_init_para(struct rtsx_chip *chip)
335fa590c22SMicky Ching {
336d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
337fa590c22SMicky Ching 	int retval;
338fa590c22SMicky Ching 
339fa590c22SMicky Ching 	if (CHK_HG8BIT(ms_card)) {
340fa590c22SMicky Ching 		if (chip->asic_code)
341fa590c22SMicky Ching 			ms_card->ms_clock = chip->asic_ms_hg_clk;
342fa590c22SMicky Ching 		else
343fa590c22SMicky Ching 			ms_card->ms_clock = chip->fpga_ms_hg_clk;
344fa590c22SMicky Ching 
345fa590c22SMicky Ching 	} else if (CHK_MSPRO(ms_card) || CHK_MS4BIT(ms_card)) {
346fa590c22SMicky Ching 		if (chip->asic_code)
347fa590c22SMicky Ching 			ms_card->ms_clock = chip->asic_ms_4bit_clk;
348fa590c22SMicky Ching 		else
349fa590c22SMicky Ching 			ms_card->ms_clock = chip->fpga_ms_4bit_clk;
350fa590c22SMicky Ching 
351fa590c22SMicky Ching 	} else {
352fa590c22SMicky Ching 		if (chip->asic_code)
353fa590c22SMicky Ching 			ms_card->ms_clock = chip->asic_ms_1bit_clk;
354fa590c22SMicky Ching 		else
355fa590c22SMicky Ching 			ms_card->ms_clock = chip->fpga_ms_1bit_clk;
356fa590c22SMicky Ching 	}
357fa590c22SMicky Ching 
358fa590c22SMicky Ching 	retval = switch_clock(chip, ms_card->ms_clock);
3599f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
360031366eaSJoe Perches 		return STATUS_FAIL;
361fa590c22SMicky Ching 
362fa590c22SMicky Ching 	retval = select_card(chip, MS_CARD);
3639f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
364031366eaSJoe Perches 		return STATUS_FAIL;
365fa590c22SMicky Ching 
366fa590c22SMicky Ching 	return STATUS_SUCCESS;
367fa590c22SMicky Ching }
368fa590c22SMicky Ching 
ms_switch_clock(struct rtsx_chip * chip)369fa590c22SMicky Ching static int ms_switch_clock(struct rtsx_chip *chip)
370fa590c22SMicky Ching {
371d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
372fa590c22SMicky Ching 	int retval;
373fa590c22SMicky Ching 
374fa590c22SMicky Ching 	retval = select_card(chip, MS_CARD);
3759f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
376031366eaSJoe Perches 		return STATUS_FAIL;
377fa590c22SMicky Ching 
378fa590c22SMicky Ching 	retval = switch_clock(chip, ms_card->ms_clock);
3799f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
380031366eaSJoe Perches 		return STATUS_FAIL;
381fa590c22SMicky Ching 
382fa590c22SMicky Ching 	return STATUS_SUCCESS;
383fa590c22SMicky Ching }
384fa590c22SMicky Ching 
ms_pull_ctl_disable(struct rtsx_chip * chip)385fa590c22SMicky Ching static int ms_pull_ctl_disable(struct rtsx_chip *chip)
386fa590c22SMicky Ching {
3878ee775f9SJoe Perches 	int retval;
3888ee775f9SJoe Perches 
389fa590c22SMicky Ching 	if (CHECK_PID(chip, 0x5208)) {
3908ee775f9SJoe Perches 		retval = rtsx_write_register(chip, CARD_PULL_CTL1, 0xFF,
39125ccf0b0SWayne Porter 					     MS_D1_PD | MS_D2_PD | MS_CLK_PD |
39225ccf0b0SWayne Porter 					     MS_D6_PD);
3939f902b49SAymen Qader 		if (retval)
3948ee775f9SJoe Perches 			return retval;
3959f902b49SAymen Qader 
3968ee775f9SJoe Perches 		retval = rtsx_write_register(chip, CARD_PULL_CTL2, 0xFF,
39725ccf0b0SWayne Porter 					     MS_D3_PD | MS_D0_PD | MS_BS_PD |
39825ccf0b0SWayne Porter 					     XD_D4_PD);
3999f902b49SAymen Qader 		if (retval)
4008ee775f9SJoe Perches 			return retval;
4019f902b49SAymen Qader 
4028ee775f9SJoe Perches 		retval = rtsx_write_register(chip, CARD_PULL_CTL3, 0xFF,
40325ccf0b0SWayne Porter 					     MS_D7_PD | XD_CE_PD | XD_CLE_PD |
40425ccf0b0SWayne Porter 					     XD_CD_PU);
4059f902b49SAymen Qader 		if (retval)
4068ee775f9SJoe Perches 			return retval;
4079f902b49SAymen Qader 
4088ee775f9SJoe Perches 		retval = rtsx_write_register(chip, CARD_PULL_CTL4, 0xFF,
40925ccf0b0SWayne Porter 					     XD_RDY_PD | SD_D3_PD | SD_D2_PD |
41025ccf0b0SWayne Porter 					     XD_ALE_PD);
4119f902b49SAymen Qader 		if (retval)
4128ee775f9SJoe Perches 			return retval;
4139f902b49SAymen Qader 
4148ee775f9SJoe Perches 		retval = rtsx_write_register(chip, CARD_PULL_CTL5, 0xFF,
41525ccf0b0SWayne Porter 					     MS_INS_PU | SD_WP_PD | SD_CD_PU |
41625ccf0b0SWayne Porter 					     SD_CMD_PD);
4179f902b49SAymen Qader 		if (retval)
4188ee775f9SJoe Perches 			return retval;
4199f902b49SAymen Qader 
4208ee775f9SJoe Perches 		retval = rtsx_write_register(chip, CARD_PULL_CTL6, 0xFF,
421fa590c22SMicky Ching 					     MS_D5_PD | MS_D4_PD);
4229f902b49SAymen Qader 		if (retval)
4238ee775f9SJoe Perches 			return retval;
4249f902b49SAymen Qader 
425fa590c22SMicky Ching 	} else if (CHECK_PID(chip, 0x5288)) {
426fa590c22SMicky Ching 		if (CHECK_BARO_PKG(chip, QFN)) {
4278ee775f9SJoe Perches 			retval = rtsx_write_register(chip, CARD_PULL_CTL1,
4288ee775f9SJoe Perches 						     0xFF, 0x55);
4299f902b49SAymen Qader 			if (retval)
4308ee775f9SJoe Perches 				return retval;
4319f902b49SAymen Qader 
4328ee775f9SJoe Perches 			retval = rtsx_write_register(chip, CARD_PULL_CTL2,
4338ee775f9SJoe Perches 						     0xFF, 0x55);
4349f902b49SAymen Qader 			if (retval)
4358ee775f9SJoe Perches 				return retval;
4369f902b49SAymen Qader 
4378ee775f9SJoe Perches 			retval = rtsx_write_register(chip, CARD_PULL_CTL3,
4388ee775f9SJoe Perches 						     0xFF, 0x4B);
4399f902b49SAymen Qader 			if (retval)
4408ee775f9SJoe Perches 				return retval;
4419f902b49SAymen Qader 
4428ee775f9SJoe Perches 			retval = rtsx_write_register(chip, CARD_PULL_CTL4,
4438ee775f9SJoe Perches 						     0xFF, 0x69);
4449f902b49SAymen Qader 			if (retval)
4458ee775f9SJoe Perches 				return retval;
4468ee775f9SJoe Perches 		}
447fa590c22SMicky Ching 	}
448fa590c22SMicky Ching 
449fa590c22SMicky Ching 	return STATUS_SUCCESS;
450fa590c22SMicky Ching }
451fa590c22SMicky Ching 
ms_pull_ctl_enable(struct rtsx_chip * chip)452fa590c22SMicky Ching static int ms_pull_ctl_enable(struct rtsx_chip *chip)
453fa590c22SMicky Ching {
454fa590c22SMicky Ching 	int retval;
455fa590c22SMicky Ching 
456fa590c22SMicky Ching 	rtsx_init_cmd(chip);
457fa590c22SMicky Ching 
458fa590c22SMicky Ching 	if (CHECK_PID(chip, 0x5208)) {
459fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL1, 0xFF,
460fa590c22SMicky Ching 			     MS_D1_PD | MS_D2_PD | MS_CLK_NP | MS_D6_PD);
461fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL2, 0xFF,
462fa590c22SMicky Ching 			     MS_D3_PD | MS_D0_PD | MS_BS_NP | XD_D4_PD);
463fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL3, 0xFF,
464fa590c22SMicky Ching 			     MS_D7_PD | XD_CE_PD | XD_CLE_PD | XD_CD_PU);
465fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL4, 0xFF,
466fa590c22SMicky Ching 			     XD_RDY_PD | SD_D3_PD | SD_D2_PD | XD_ALE_PD);
467fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL5, 0xFF,
468fa590c22SMicky Ching 			     MS_INS_PU | SD_WP_PD | SD_CD_PU | SD_CMD_PD);
469fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PULL_CTL6, 0xFF,
470fa590c22SMicky Ching 			     MS_D5_PD | MS_D4_PD);
471fa590c22SMicky Ching 	} else if (CHECK_PID(chip, 0x5288)) {
472fa590c22SMicky Ching 		if (CHECK_BARO_PKG(chip, QFN)) {
473fa590c22SMicky Ching 			rtsx_add_cmd(chip, WRITE_REG_CMD,
474fa590c22SMicky Ching 				     CARD_PULL_CTL1, 0xFF, 0x55);
475fa590c22SMicky Ching 			rtsx_add_cmd(chip, WRITE_REG_CMD,
476fa590c22SMicky Ching 				     CARD_PULL_CTL2, 0xFF, 0x45);
477fa590c22SMicky Ching 			rtsx_add_cmd(chip, WRITE_REG_CMD,
478fa590c22SMicky Ching 				     CARD_PULL_CTL3, 0xFF, 0x4B);
479fa590c22SMicky Ching 			rtsx_add_cmd(chip, WRITE_REG_CMD,
480fa590c22SMicky Ching 				     CARD_PULL_CTL4, 0xFF, 0x29);
481fa590c22SMicky Ching 		}
482fa590c22SMicky Ching 	}
483fa590c22SMicky Ching 
484fa590c22SMicky Ching 	retval = rtsx_send_cmd(chip, MS_CARD, 100);
4859f902b49SAymen Qader 	if (retval < 0)
486031366eaSJoe Perches 		return STATUS_FAIL;
487fa590c22SMicky Ching 
488fa590c22SMicky Ching 	return STATUS_SUCCESS;
489fa590c22SMicky Ching }
490fa590c22SMicky Ching 
ms_prepare_reset(struct rtsx_chip * chip)491fa590c22SMicky Ching static int ms_prepare_reset(struct rtsx_chip *chip)
492fa590c22SMicky Ching {
493d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
494fa590c22SMicky Ching 	int retval;
495fa590c22SMicky Ching 	u8 oc_mask = 0;
496fa590c22SMicky Ching 
497fa590c22SMicky Ching 	ms_card->ms_type = 0;
498fa590c22SMicky Ching 	ms_card->check_ms_flow = 0;
499fa590c22SMicky Ching 	ms_card->switch_8bit_fail = 0;
500fa590c22SMicky Ching 	ms_card->delay_write.delay_write_flag = 0;
501fa590c22SMicky Ching 
502fa590c22SMicky Ching 	ms_card->pro_under_formatting = 0;
503fa590c22SMicky Ching 
504fa590c22SMicky Ching 	retval = ms_power_off_card3v3(chip);
5059f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
506031366eaSJoe Perches 		return STATUS_FAIL;
507fa590c22SMicky Ching 
508fa590c22SMicky Ching 	if (!chip->ft2_fast_mode)
509fa590c22SMicky Ching 		wait_timeout(250);
510fa590c22SMicky Ching 
511fa590c22SMicky Ching 	retval = enable_card_clock(chip, MS_CARD);
5129f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
513031366eaSJoe Perches 		return STATUS_FAIL;
514fa590c22SMicky Ching 
515fa590c22SMicky Ching 	if (chip->asic_code) {
516fa590c22SMicky Ching 		retval = ms_pull_ctl_enable(chip);
5179f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
518031366eaSJoe Perches 			return STATUS_FAIL;
519fa590c22SMicky Ching 	} else {
5208ee775f9SJoe Perches 		retval = rtsx_write_register(chip, FPGA_PULL_CTL,
521fa590c22SMicky Ching 					     FPGA_MS_PULL_CTL_BIT | 0x20, 0);
5229f902b49SAymen Qader 		if (retval)
5238ee775f9SJoe Perches 			return retval;
5248ee775f9SJoe Perches 	}
525fa590c22SMicky Ching 
526fa590c22SMicky Ching 	if (!chip->ft2_fast_mode) {
527fa590c22SMicky Ching 		retval = card_power_on(chip, MS_CARD);
5289f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
529031366eaSJoe Perches 			return STATUS_FAIL;
530fa590c22SMicky Ching 
531fa590c22SMicky Ching 		wait_timeout(150);
532fa590c22SMicky Ching 
533fa590c22SMicky Ching #ifdef SUPPORT_OCP
534fa590c22SMicky Ching 		if (CHECK_LUN_MODE(chip, SD_MS_2LUN))
535fa590c22SMicky Ching 			oc_mask = MS_OC_NOW | MS_OC_EVER;
536fa590c22SMicky Ching 		else
537fa590c22SMicky Ching 			oc_mask = SD_OC_NOW | SD_OC_EVER;
538fa590c22SMicky Ching 
539fa590c22SMicky Ching 		if (chip->ocp_stat & oc_mask) {
540bf6c0d11SFabio Falzoi 			dev_dbg(rtsx_dev(chip), "Over current, OCPSTAT is 0x%x\n",
541fa590c22SMicky Ching 				chip->ocp_stat);
542031366eaSJoe Perches 			return STATUS_FAIL;
543fa590c22SMicky Ching 		}
544fa590c22SMicky Ching #endif
545fa590c22SMicky Ching 	}
546fa590c22SMicky Ching 
5478ee775f9SJoe Perches 	retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN,
5488ee775f9SJoe Perches 				     MS_OUTPUT_EN);
5499f902b49SAymen Qader 	if (retval)
5508ee775f9SJoe Perches 		return retval;
551fa590c22SMicky Ching 
552fa590c22SMicky Ching 	if (chip->asic_code) {
5538ee775f9SJoe Perches 		retval = rtsx_write_register(chip, MS_CFG, 0xFF,
55425ccf0b0SWayne Porter 					     SAMPLE_TIME_RISING |
55525ccf0b0SWayne Porter 					     PUSH_TIME_DEFAULT |
55625ccf0b0SWayne Porter 					     NO_EXTEND_TOGGLE |
55725ccf0b0SWayne Porter 					     MS_BUS_WIDTH_1);
5589f902b49SAymen Qader 		if (retval)
5598ee775f9SJoe Perches 			return retval;
5609f902b49SAymen Qader 
5618ee775f9SJoe Perches 	} else {
5628ee775f9SJoe Perches 		retval = rtsx_write_register(chip, MS_CFG, 0xFF,
56325ccf0b0SWayne Porter 					     SAMPLE_TIME_FALLING |
56425ccf0b0SWayne Porter 					     PUSH_TIME_DEFAULT |
56525ccf0b0SWayne Porter 					     NO_EXTEND_TOGGLE |
56625ccf0b0SWayne Porter 					     MS_BUS_WIDTH_1);
5679f902b49SAymen Qader 		if (retval)
5688ee775f9SJoe Perches 			return retval;
5698ee775f9SJoe Perches 	}
5708ee775f9SJoe Perches 	retval = rtsx_write_register(chip, MS_TRANS_CFG, 0xFF,
5718ee775f9SJoe Perches 				     NO_WAIT_INT | NO_AUTO_READ_INT_REG);
5729f902b49SAymen Qader 	if (retval)
5738ee775f9SJoe Perches 		return retval;
5749f902b49SAymen Qader 
5758ee775f9SJoe Perches 	retval = rtsx_write_register(chip, CARD_STOP, MS_STOP | MS_CLR_ERR,
5768ee775f9SJoe Perches 				     MS_STOP | MS_CLR_ERR);
5779f902b49SAymen Qader 	if (retval)
5788ee775f9SJoe Perches 		return retval;
579fa590c22SMicky Ching 
580fa590c22SMicky Ching 	retval = ms_set_init_para(chip);
5819f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
582031366eaSJoe Perches 		return STATUS_FAIL;
583fa590c22SMicky Ching 
584fa590c22SMicky Ching 	return STATUS_SUCCESS;
585fa590c22SMicky Ching }
586fa590c22SMicky Ching 
ms_identify_media_type(struct rtsx_chip * chip,int switch_8bit_bus)587fa590c22SMicky Ching static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus)
588fa590c22SMicky Ching {
589d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
590fa590c22SMicky Ching 	int retval, i;
591fa590c22SMicky Ching 	u8 val;
592fa590c22SMicky Ching 
5936e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, PRO_STATUS_REG, 6, SYSTEM_PARAM, 1);
5949f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
595031366eaSJoe Perches 		return STATUS_FAIL;
596fa590c22SMicky Ching 
597fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
598fa590c22SMicky Ching 		retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG,
599fa590c22SMicky Ching 					 6, NO_WAIT_INT);
600fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
601fa590c22SMicky Ching 			break;
602fa590c22SMicky Ching 	}
6039f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
604031366eaSJoe Perches 		return STATUS_FAIL;
605fa590c22SMicky Ching 
6068ee775f9SJoe Perches 	retval = rtsx_read_register(chip, PPBUF_BASE2 + 2, &val);
6079f902b49SAymen Qader 	if (retval)
6088ee775f9SJoe Perches 		return retval;
6099f902b49SAymen Qader 
610bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "Type register: 0x%x\n", val);
611fa590c22SMicky Ching 	if (val != 0x01) {
612fa590c22SMicky Ching 		if (val != 0x02)
613fa590c22SMicky Ching 			ms_card->check_ms_flow = 1;
614fa590c22SMicky Ching 
615031366eaSJoe Perches 		return STATUS_FAIL;
616fa590c22SMicky Ching 	}
617fa590c22SMicky Ching 
6188ee775f9SJoe Perches 	retval = rtsx_read_register(chip, PPBUF_BASE2 + 4, &val);
6199f902b49SAymen Qader 	if (retval)
6208ee775f9SJoe Perches 		return retval;
6219f902b49SAymen Qader 
622bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "Category register: 0x%x\n", val);
623fa590c22SMicky Ching 	if (val != 0) {
624fa590c22SMicky Ching 		ms_card->check_ms_flow = 1;
625031366eaSJoe Perches 		return STATUS_FAIL;
626fa590c22SMicky Ching 	}
627fa590c22SMicky Ching 
6288ee775f9SJoe Perches 	retval = rtsx_read_register(chip, PPBUF_BASE2 + 5, &val);
6299f902b49SAymen Qader 	if (retval)
6308ee775f9SJoe Perches 		return retval;
6319f902b49SAymen Qader 
632bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "Class register: 0x%x\n", val);
633fa590c22SMicky Ching 	if (val == 0) {
6348ee775f9SJoe Perches 		retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
6359f902b49SAymen Qader 		if (retval)
6368ee775f9SJoe Perches 			return retval;
6379f902b49SAymen Qader 
638fa590c22SMicky Ching 		if (val & WRT_PRTCT)
639fa590c22SMicky Ching 			chip->card_wp |= MS_CARD;
640fa590c22SMicky Ching 		else
641fa590c22SMicky Ching 			chip->card_wp &= ~MS_CARD;
642fa590c22SMicky Ching 
643fa590c22SMicky Ching 	} else if ((val == 0x01) || (val == 0x02) || (val == 0x03)) {
644fa590c22SMicky Ching 		chip->card_wp |= MS_CARD;
645fa590c22SMicky Ching 	} else {
646fa590c22SMicky Ching 		ms_card->check_ms_flow = 1;
647031366eaSJoe Perches 		return STATUS_FAIL;
648fa590c22SMicky Ching 	}
649fa590c22SMicky Ching 
650fa590c22SMicky Ching 	ms_card->ms_type |= TYPE_MSPRO;
651fa590c22SMicky Ching 
6528ee775f9SJoe Perches 	retval = rtsx_read_register(chip, PPBUF_BASE2 + 3, &val);
6539f902b49SAymen Qader 	if (retval)
6548ee775f9SJoe Perches 		return retval;
6559f902b49SAymen Qader 
656bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "IF Mode register: 0x%x\n", val);
657fa590c22SMicky Ching 	if (val == 0) {
658fa590c22SMicky Ching 		ms_card->ms_type &= 0x0F;
659fa590c22SMicky Ching 	} else if (val == 7) {
660fa590c22SMicky Ching 		if (switch_8bit_bus)
661fa590c22SMicky Ching 			ms_card->ms_type |= MS_HG;
662fa590c22SMicky Ching 		else
663fa590c22SMicky Ching 			ms_card->ms_type &= 0x0F;
664fa590c22SMicky Ching 
665fa590c22SMicky Ching 	} else {
666031366eaSJoe Perches 		return STATUS_FAIL;
667fa590c22SMicky Ching 	}
668fa590c22SMicky Ching 
669fa590c22SMicky Ching 	return STATUS_SUCCESS;
670fa590c22SMicky Ching }
671fa590c22SMicky Ching 
ms_confirm_cpu_startup(struct rtsx_chip * chip)672fa590c22SMicky Ching static int ms_confirm_cpu_startup(struct rtsx_chip *chip)
673fa590c22SMicky Ching {
674fa590c22SMicky Ching 	int retval, i, k;
675fa590c22SMicky Ching 	u8 val;
676fa590c22SMicky Ching 
677fa590c22SMicky Ching 	/* Confirm CPU StartUp */
678fa590c22SMicky Ching 	k = 0;
679fa590c22SMicky Ching 	do {
680fa590c22SMicky Ching 		if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
681fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_CARD);
682031366eaSJoe Perches 			return STATUS_FAIL;
683fa590c22SMicky Ching 		}
684fa590c22SMicky Ching 
685fa590c22SMicky Ching 		for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
686fa590c22SMicky Ching 			retval = ms_read_bytes(chip, GET_INT, 1,
687fa590c22SMicky Ching 					       NO_WAIT_INT, &val, 1);
688fa590c22SMicky Ching 			if (retval == STATUS_SUCCESS)
689fa590c22SMicky Ching 				break;
690fa590c22SMicky Ching 		}
6919f902b49SAymen Qader 		if (i == MS_MAX_RETRY_COUNT)
692031366eaSJoe Perches 			return STATUS_FAIL;
693fa590c22SMicky Ching 
6949f902b49SAymen Qader 		if (k > 100)
695031366eaSJoe Perches 			return STATUS_FAIL;
696fa590c22SMicky Ching 
697fa590c22SMicky Ching 		k++;
698fa590c22SMicky Ching 		wait_timeout(100);
699fa590c22SMicky Ching 	} while (!(val & INT_REG_CED));
700fa590c22SMicky Ching 
701fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
702fa590c22SMicky Ching 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
703fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
704fa590c22SMicky Ching 			break;
705fa590c22SMicky Ching 	}
7069f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
707031366eaSJoe Perches 		return STATUS_FAIL;
708fa590c22SMicky Ching 
709fa590c22SMicky Ching 	if (val & INT_REG_ERR) {
7109f902b49SAymen Qader 		if (val & INT_REG_CMDNK)
711fa590c22SMicky Ching 			chip->card_wp |= (MS_CARD);
7129f902b49SAymen Qader 		else
713031366eaSJoe Perches 			return STATUS_FAIL;
714031366eaSJoe Perches 	}
715fa590c22SMicky Ching 	/* --  end confirm CPU startup */
716fa590c22SMicky Ching 
717fa590c22SMicky Ching 	return STATUS_SUCCESS;
718fa590c22SMicky Ching }
719fa590c22SMicky Ching 
ms_switch_parallel_bus(struct rtsx_chip * chip)720fa590c22SMicky Ching static int ms_switch_parallel_bus(struct rtsx_chip *chip)
721fa590c22SMicky Ching {
722fa590c22SMicky Ching 	int retval, i;
723fa590c22SMicky Ching 	u8 data[2];
724fa590c22SMicky Ching 
725fa590c22SMicky Ching 	data[0] = PARALLEL_4BIT_IF;
726fa590c22SMicky Ching 	data[1] = 0;
727fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
728fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, 1, NO_WAIT_INT,
729fa590c22SMicky Ching 					data, 2);
730fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
731fa590c22SMicky Ching 			break;
732fa590c22SMicky Ching 	}
7339f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
734031366eaSJoe Perches 		return STATUS_FAIL;
735fa590c22SMicky Ching 
736fa590c22SMicky Ching 	return STATUS_SUCCESS;
737fa590c22SMicky Ching }
738fa590c22SMicky Ching 
ms_switch_8bit_bus(struct rtsx_chip * chip)739fa590c22SMicky Ching static int ms_switch_8bit_bus(struct rtsx_chip *chip)
740fa590c22SMicky Ching {
741d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
742fa590c22SMicky Ching 	int retval, i;
743fa590c22SMicky Ching 	u8 data[2];
744fa590c22SMicky Ching 
745fa590c22SMicky Ching 	data[0] = PARALLEL_8BIT_IF;
746fa590c22SMicky Ching 	data[1] = 0;
747fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
748fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, 1,
749fa590c22SMicky Ching 					NO_WAIT_INT, data, 2);
750fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
751fa590c22SMicky Ching 			break;
752fa590c22SMicky Ching 	}
7539f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
754031366eaSJoe Perches 		return STATUS_FAIL;
755fa590c22SMicky Ching 
7568ee775f9SJoe Perches 	retval = rtsx_write_register(chip, MS_CFG, 0x98,
757fa590c22SMicky Ching 				     MS_BUS_WIDTH_8 | SAMPLE_TIME_FALLING);
7589f902b49SAymen Qader 	if (retval)
7598ee775f9SJoe Perches 		return retval;
7609f902b49SAymen Qader 
761fa590c22SMicky Ching 	ms_card->ms_type |= MS_8BIT;
762fa590c22SMicky Ching 	retval = ms_set_init_para(chip);
7639f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
764031366eaSJoe Perches 		return STATUS_FAIL;
765fa590c22SMicky Ching 
766fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
767fa590c22SMicky Ching 		retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT,
768fa590c22SMicky Ching 					 1, NO_WAIT_INT);
7699f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
770031366eaSJoe Perches 			return STATUS_FAIL;
771031366eaSJoe Perches 	}
772fa590c22SMicky Ching 
773fa590c22SMicky Ching 	return STATUS_SUCCESS;
774fa590c22SMicky Ching }
775fa590c22SMicky Ching 
ms_pro_reset_flow(struct rtsx_chip * chip,int switch_8bit_bus)776fa590c22SMicky Ching static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus)
777fa590c22SMicky Ching {
778d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
779fa590c22SMicky Ching 	int retval, i;
780fa590c22SMicky Ching 
781fa590c22SMicky Ching 	for (i = 0; i < 3; i++) {
782fa590c22SMicky Ching 		retval = ms_prepare_reset(chip);
7839f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
784031366eaSJoe Perches 			return STATUS_FAIL;
785fa590c22SMicky Ching 
786fa590c22SMicky Ching 		retval = ms_identify_media_type(chip, switch_8bit_bus);
7879f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
788031366eaSJoe Perches 			return STATUS_FAIL;
789fa590c22SMicky Ching 
790fa590c22SMicky Ching 		retval = ms_confirm_cpu_startup(chip);
7919f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
792031366eaSJoe Perches 			return STATUS_FAIL;
793fa590c22SMicky Ching 
794fa590c22SMicky Ching 		retval = ms_switch_parallel_bus(chip);
795fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
796fa590c22SMicky Ching 			if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
797fa590c22SMicky Ching 				ms_set_err_code(chip, MS_NO_CARD);
798031366eaSJoe Perches 				return STATUS_FAIL;
799fa590c22SMicky Ching 			}
800fa590c22SMicky Ching 			continue;
801fa590c22SMicky Ching 		} else {
802fa590c22SMicky Ching 			break;
803fa590c22SMicky Ching 		}
804fa590c22SMicky Ching 	}
805fa590c22SMicky Ching 
8069f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
807031366eaSJoe Perches 		return STATUS_FAIL;
808fa590c22SMicky Ching 
809fa590c22SMicky Ching 	/* Switch MS-PRO into Parallel mode */
8108ee775f9SJoe Perches 	retval = rtsx_write_register(chip, MS_CFG, 0x18, MS_BUS_WIDTH_4);
8119f902b49SAymen Qader 	if (retval)
8128ee775f9SJoe Perches 		return retval;
8139f902b49SAymen Qader 
8148ee775f9SJoe Perches 	retval = rtsx_write_register(chip, MS_CFG, PUSH_TIME_ODD,
8158ee775f9SJoe Perches 				     PUSH_TIME_ODD);
8169f902b49SAymen Qader 	if (retval)
8178ee775f9SJoe Perches 		return retval;
818fa590c22SMicky Ching 
819fa590c22SMicky Ching 	retval = ms_set_init_para(chip);
8209f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
821031366eaSJoe Perches 		return STATUS_FAIL;
822fa590c22SMicky Ching 
823fa590c22SMicky Ching 	/* If MSPro HG Card, We shall try to switch to 8-bit bus */
824fa590c22SMicky Ching 	if (CHK_MSHG(ms_card) && chip->support_ms_8bit && switch_8bit_bus) {
825fa590c22SMicky Ching 		retval = ms_switch_8bit_bus(chip);
826fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
827fa590c22SMicky Ching 			ms_card->switch_8bit_fail = 1;
828031366eaSJoe Perches 			return STATUS_FAIL;
829fa590c22SMicky Ching 		}
830fa590c22SMicky Ching 	}
831fa590c22SMicky Ching 
832fa590c22SMicky Ching 	return STATUS_SUCCESS;
833fa590c22SMicky Ching }
834fa590c22SMicky Ching 
835fa590c22SMicky Ching #ifdef XC_POWERCLASS
msxc_change_power(struct rtsx_chip * chip,u8 mode)836fa590c22SMicky Ching static int msxc_change_power(struct rtsx_chip *chip, u8 mode)
837fa590c22SMicky Ching {
838fa590c22SMicky Ching 	int retval;
839fa590c22SMicky Ching 	u8 buf[6];
840fa590c22SMicky Ching 
841fa590c22SMicky Ching 	ms_cleanup_work(chip);
842fa590c22SMicky Ching 
8436e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_DATA_COUNT1, 6);
8449f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
845031366eaSJoe Perches 		return STATUS_FAIL;
846fa590c22SMicky Ching 
847fa590c22SMicky Ching 	buf[0] = 0;
848fa590c22SMicky Ching 	buf[1] = mode;
849fa590c22SMicky Ching 	buf[2] = 0;
850fa590c22SMicky Ching 	buf[3] = 0;
851fa590c22SMicky Ching 	buf[4] = 0;
852fa590c22SMicky Ching 	buf[5] = 0;
853fa590c22SMicky Ching 
854fa590c22SMicky Ching 	retval = ms_write_bytes(chip, PRO_WRITE_REG, 6, NO_WAIT_INT, buf, 6);
8559f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
856031366eaSJoe Perches 		return STATUS_FAIL;
857fa590c22SMicky Ching 
858fa590c22SMicky Ching 	retval = ms_send_cmd(chip, XC_CHG_POWER, WAIT_INT);
8599f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
860031366eaSJoe Perches 		return STATUS_FAIL;
861fa590c22SMicky Ching 
8628ee775f9SJoe Perches 	retval = rtsx_read_register(chip, MS_TRANS_CFG, buf);
8639f902b49SAymen Qader 	if (retval)
8648ee775f9SJoe Perches 		return retval;
8659f902b49SAymen Qader 
8669f902b49SAymen Qader 	if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR))
867031366eaSJoe Perches 		return STATUS_FAIL;
868fa590c22SMicky Ching 
869fa590c22SMicky Ching 	return STATUS_SUCCESS;
870fa590c22SMicky Ching }
871fa590c22SMicky Ching #endif
872fa590c22SMicky Ching 
ms_read_attribute_info(struct rtsx_chip * chip)873fa590c22SMicky Ching static int ms_read_attribute_info(struct rtsx_chip *chip)
874fa590c22SMicky Ching {
875d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
876fa590c22SMicky Ching 	int retval, i;
877fa590c22SMicky Ching 	u8 val, *buf, class_code, device_type, sub_class, data[16];
878fa590c22SMicky Ching 	u16 total_blk = 0, blk_size = 0;
879fa590c22SMicky Ching #ifdef SUPPORT_MSXC
880fa590c22SMicky Ching 	u32 xc_total_blk = 0, xc_blk_size = 0;
881fa590c22SMicky Ching #endif
882fa590c22SMicky Ching 	u32 sys_info_addr = 0, sys_info_size;
883fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18
884fa590c22SMicky Ching 	u32 model_name_addr = 0, model_name_size;
885fa590c22SMicky Ching 	int found_sys_info = 0, found_model_name = 0;
886fa590c22SMicky Ching #endif
887fa590c22SMicky Ching 
8886e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, PRO_INT_REG, 2, PRO_SYSTEM_PARAM, 7);
8899f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
890031366eaSJoe Perches 		return STATUS_FAIL;
891fa590c22SMicky Ching 
892fa590c22SMicky Ching 	if (CHK_MS8BIT(ms_card))
893fa590c22SMicky Ching 		data[0] = PARALLEL_8BIT_IF;
894fa590c22SMicky Ching 	else
895fa590c22SMicky Ching 		data[0] = PARALLEL_4BIT_IF;
896fa590c22SMicky Ching 
897fa590c22SMicky Ching 	data[1] = 0;
898fa590c22SMicky Ching 
899fa590c22SMicky Ching 	data[2] = 0x40;
900fa590c22SMicky Ching 	data[3] = 0;
901fa590c22SMicky Ching 	data[4] = 0;
902fa590c22SMicky Ching 	data[5] = 0;
903fa590c22SMicky Ching 	data[6] = 0;
904fa590c22SMicky Ching 	data[7] = 0;
905fa590c22SMicky Ching 
906fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
907fa590c22SMicky Ching 		retval = ms_write_bytes(chip, PRO_WRITE_REG, 7, NO_WAIT_INT,
908fa590c22SMicky Ching 					data, 8);
909fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
910fa590c22SMicky Ching 			break;
911fa590c22SMicky Ching 	}
9129f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
913031366eaSJoe Perches 		return STATUS_FAIL;
914fa590c22SMicky Ching 
915fa590c22SMicky Ching 	buf = kmalloc(64 * 512, GFP_KERNEL);
9169f902b49SAymen Qader 	if (!buf)
917031366eaSJoe Perches 		return STATUS_ERROR;
918fa590c22SMicky Ching 
919fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
920fa590c22SMicky Ching 		retval = ms_send_cmd(chip, PRO_READ_ATRB, WAIT_INT);
921fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS)
922fa590c22SMicky Ching 			continue;
923fa590c22SMicky Ching 
924fa590c22SMicky Ching 		retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
925fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
926fa590c22SMicky Ching 			kfree(buf);
927031366eaSJoe Perches 			return STATUS_FAIL;
928fa590c22SMicky Ching 		}
929fa590c22SMicky Ching 		if (!(val & MS_INT_BREQ)) {
930fa590c22SMicky Ching 			kfree(buf);
931031366eaSJoe Perches 			return STATUS_FAIL;
932fa590c22SMicky Ching 		}
933fa590c22SMicky Ching 		retval = ms_transfer_data(chip, MS_TM_AUTO_READ,
934fa590c22SMicky Ching 					  PRO_READ_LONG_DATA, 0x40, WAIT_INT,
935fa590c22SMicky Ching 					  0, 0, buf, 64 * 512);
936fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
937fa590c22SMicky Ching 			break;
938b037e229SRoxana Blaj 
939fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
940fa590c22SMicky Ching 	}
941fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
942fa590c22SMicky Ching 		kfree(buf);
943031366eaSJoe Perches 		return STATUS_FAIL;
944fa590c22SMicky Ching 	}
945fa590c22SMicky Ching 
946fa590c22SMicky Ching 	i = 0;
947fa590c22SMicky Ching 	do {
948fa590c22SMicky Ching 		retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
949fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
950fa590c22SMicky Ching 			kfree(buf);
951031366eaSJoe Perches 			return STATUS_FAIL;
952fa590c22SMicky Ching 		}
953fa590c22SMicky Ching 
954fa590c22SMicky Ching 		if ((val & MS_INT_CED) || !(val & MS_INT_BREQ))
955fa590c22SMicky Ching 			break;
956fa590c22SMicky Ching 
957fa590c22SMicky Ching 		retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ,
958fa590c22SMicky Ching 					 PRO_READ_LONG_DATA, 0, WAIT_INT);
959fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
960fa590c22SMicky Ching 			kfree(buf);
961031366eaSJoe Perches 			return STATUS_FAIL;
962fa590c22SMicky Ching 		}
963fa590c22SMicky Ching 
964fa590c22SMicky Ching 		i++;
965fa590c22SMicky Ching 	} while (i < 1024);
966fa590c22SMicky Ching 
9677b228bdfSBenjamin Philip 	if (buf[0] != 0xa5 && buf[1] != 0xc3) {
968fa590c22SMicky Ching 		/* Signature code is wrong */
969fa590c22SMicky Ching 		kfree(buf);
970031366eaSJoe Perches 		return STATUS_FAIL;
971fa590c22SMicky Ching 	}
972fa590c22SMicky Ching 
9737b228bdfSBenjamin Philip 	if (buf[4] < 1 || buf[4] > 12) {
974fa590c22SMicky Ching 		kfree(buf);
975031366eaSJoe Perches 		return STATUS_FAIL;
976fa590c22SMicky Ching 	}
977fa590c22SMicky Ching 
978fa590c22SMicky Ching 	for (i = 0; i < buf[4]; i++) {
979fa590c22SMicky Ching 		int cur_addr_off = 16 + i * 12;
980fa590c22SMicky Ching 
981fa590c22SMicky Ching #ifdef SUPPORT_MSXC
9827b228bdfSBenjamin Philip 		if (buf[cur_addr_off + 8] == 0x10 ||
9837b228bdfSBenjamin Philip 		    buf[cur_addr_off + 8] == 0x13) {
984fa590c22SMicky Ching #else
98566e6d70dSYash Shah 		if (buf[cur_addr_off + 8] == 0x10) {
986fa590c22SMicky Ching #endif
987fa590c22SMicky Ching 			sys_info_addr = ((u32)buf[cur_addr_off + 0] << 24) |
988fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 1] << 16) |
989fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 2] << 8) |
990fa590c22SMicky Ching 				buf[cur_addr_off + 3];
991fa590c22SMicky Ching 			sys_info_size = ((u32)buf[cur_addr_off + 4] << 24) |
992fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 5] << 16) |
993fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 6] << 8) |
994fa590c22SMicky Ching 				buf[cur_addr_off + 7];
995bf6c0d11SFabio Falzoi 			dev_dbg(rtsx_dev(chip), "sys_info_addr = 0x%x, sys_info_size = 0x%x\n",
996fa590c22SMicky Ching 				sys_info_addr, sys_info_size);
997fa590c22SMicky Ching 			if (sys_info_size != 96)  {
998fa590c22SMicky Ching 				kfree(buf);
999031366eaSJoe Perches 				return STATUS_FAIL;
1000fa590c22SMicky Ching 			}
1001fa590c22SMicky Ching 			if (sys_info_addr < 0x1A0) {
1002fa590c22SMicky Ching 				kfree(buf);
1003031366eaSJoe Perches 				return STATUS_FAIL;
1004fa590c22SMicky Ching 			}
1005fa590c22SMicky Ching 			if ((sys_info_size + sys_info_addr) > 0x8000) {
1006fa590c22SMicky Ching 				kfree(buf);
1007031366eaSJoe Perches 				return STATUS_FAIL;
1008fa590c22SMicky Ching 			}
1009fa590c22SMicky Ching 
1010fa590c22SMicky Ching #ifdef SUPPORT_MSXC
1011fa590c22SMicky Ching 			if (buf[cur_addr_off + 8] == 0x13)
1012fa590c22SMicky Ching 				ms_card->ms_type |= MS_XC;
1013fa590c22SMicky Ching #endif
1014fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18
1015fa590c22SMicky Ching 			found_sys_info = 1;
1016fa590c22SMicky Ching #else
1017fa590c22SMicky Ching 			break;
1018fa590c22SMicky Ching #endif
1019fa590c22SMicky Ching 		}
1020fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18
1021fa590c22SMicky Ching 		if (buf[cur_addr_off + 8] == 0x15) {
1022fa590c22SMicky Ching 			model_name_addr = ((u32)buf[cur_addr_off + 0] << 24) |
1023fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 1] << 16) |
1024fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 2] << 8) |
1025fa590c22SMicky Ching 				buf[cur_addr_off + 3];
1026fa590c22SMicky Ching 			model_name_size = ((u32)buf[cur_addr_off + 4] << 24) |
1027fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 5] << 16) |
1028fa590c22SMicky Ching 				((u32)buf[cur_addr_off + 6] << 8) |
1029fa590c22SMicky Ching 				buf[cur_addr_off + 7];
1030bf6c0d11SFabio Falzoi 			dev_dbg(rtsx_dev(chip), "model_name_addr = 0x%x, model_name_size = 0x%x\n",
1031fa590c22SMicky Ching 				model_name_addr, model_name_size);
1032fa590c22SMicky Ching 			if (model_name_size != 48)  {
1033fa590c22SMicky Ching 				kfree(buf);
1034031366eaSJoe Perches 				return STATUS_FAIL;
1035fa590c22SMicky Ching 			}
1036fa590c22SMicky Ching 			if (model_name_addr < 0x1A0) {
1037fa590c22SMicky Ching 				kfree(buf);
1038031366eaSJoe Perches 				return STATUS_FAIL;
1039fa590c22SMicky Ching 			}
1040fa590c22SMicky Ching 			if ((model_name_size + model_name_addr) > 0x8000) {
1041fa590c22SMicky Ching 				kfree(buf);
1042031366eaSJoe Perches 				return STATUS_FAIL;
1043fa590c22SMicky Ching 			}
1044fa590c22SMicky Ching 
1045fa590c22SMicky Ching 			found_model_name = 1;
1046fa590c22SMicky Ching 		}
1047fa590c22SMicky Ching 
1048fa590c22SMicky Ching 		if (found_sys_info && found_model_name)
1049fa590c22SMicky Ching 			break;
1050fa590c22SMicky Ching #endif
1051fa590c22SMicky Ching 	}
1052fa590c22SMicky Ching 
1053fa590c22SMicky Ching 	if (i == buf[4]) {
1054fa590c22SMicky Ching 		kfree(buf);
1055031366eaSJoe Perches 		return STATUS_FAIL;
1056fa590c22SMicky Ching 	}
1057fa590c22SMicky Ching 
1058fa590c22SMicky Ching 	class_code =  buf[sys_info_addr + 0];
1059fa590c22SMicky Ching 	device_type = buf[sys_info_addr + 56];
1060fa590c22SMicky Ching 	sub_class = buf[sys_info_addr + 46];
1061fa590c22SMicky Ching #ifdef SUPPORT_MSXC
1062fa590c22SMicky Ching 	if (CHK_MSXC(ms_card)) {
1063fa590c22SMicky Ching 		xc_total_blk = ((u32)buf[sys_info_addr + 6] << 24) |
1064fa590c22SMicky Ching 				((u32)buf[sys_info_addr + 7] << 16) |
1065fa590c22SMicky Ching 				((u32)buf[sys_info_addr + 8] << 8) |
1066fa590c22SMicky Ching 				buf[sys_info_addr + 9];
1067fa590c22SMicky Ching 		xc_blk_size = ((u32)buf[sys_info_addr + 32] << 24) |
1068fa590c22SMicky Ching 				((u32)buf[sys_info_addr + 33] << 16) |
1069fa590c22SMicky Ching 				((u32)buf[sys_info_addr + 34] << 8) |
1070fa590c22SMicky Ching 				buf[sys_info_addr + 35];
1071bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "xc_total_blk = 0x%x, xc_blk_size = 0x%x\n",
1072fa590c22SMicky Ching 			xc_total_blk, xc_blk_size);
1073fa590c22SMicky Ching 	} else {
1074fa590c22SMicky Ching 		total_blk = ((u16)buf[sys_info_addr + 6] << 8) |
1075fa590c22SMicky Ching 			buf[sys_info_addr + 7];
1076fa590c22SMicky Ching 		blk_size = ((u16)buf[sys_info_addr + 2] << 8) |
1077fa590c22SMicky Ching 			buf[sys_info_addr + 3];
1078bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n",
1079fa590c22SMicky Ching 			total_blk, blk_size);
1080fa590c22SMicky Ching 	}
1081fa590c22SMicky Ching #else
1082fa590c22SMicky Ching 	total_blk = ((u16)buf[sys_info_addr + 6] << 8) | buf[sys_info_addr + 7];
1083fa590c22SMicky Ching 	blk_size = ((u16)buf[sys_info_addr + 2] << 8) | buf[sys_info_addr + 3];
1084bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "total_blk = 0x%x, blk_size = 0x%x\n",
1085bf6c0d11SFabio Falzoi 		total_blk, blk_size);
1086fa590c22SMicky Ching #endif
1087fa590c22SMicky Ching 
1088bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "class_code = 0x%x, device_type = 0x%x, sub_class = 0x%x\n",
1089fa590c22SMicky Ching 		class_code, device_type, sub_class);
1090fa590c22SMicky Ching 
1091fa590c22SMicky Ching 	memcpy(ms_card->raw_sys_info, buf + sys_info_addr, 96);
1092fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18
1093fa590c22SMicky Ching 	memcpy(ms_card->raw_model_name, buf + model_name_addr, 48);
1094fa590c22SMicky Ching #endif
1095fa590c22SMicky Ching 
1096fa590c22SMicky Ching 	kfree(buf);
1097fa590c22SMicky Ching 
1098fa590c22SMicky Ching #ifdef SUPPORT_MSXC
1099fa590c22SMicky Ching 	if (CHK_MSXC(ms_card)) {
11009f902b49SAymen Qader 		if (class_code != 0x03)
1101031366eaSJoe Perches 			return STATUS_FAIL;
1102fa590c22SMicky Ching 	} else {
11039f902b49SAymen Qader 		if (class_code != 0x02)
1104031366eaSJoe Perches 			return STATUS_FAIL;
1105031366eaSJoe Perches 	}
1106fa590c22SMicky Ching #else
11079f902b49SAymen Qader 	if (class_code != 0x02)
1108031366eaSJoe Perches 		return STATUS_FAIL;
1109fa590c22SMicky Ching #endif
1110fa590c22SMicky Ching 
1111fa590c22SMicky Ching 	if (device_type != 0x00) {
11127b228bdfSBenjamin Philip 		if (device_type == 0x01 || device_type == 0x02 ||
11137b228bdfSBenjamin Philip 		    device_type == 0x03) {
1114fa590c22SMicky Ching 			chip->card_wp |= MS_CARD;
1115fa590c22SMicky Ching 		} else {
1116031366eaSJoe Perches 			return STATUS_FAIL;
1117fa590c22SMicky Ching 		}
1118fa590c22SMicky Ching 	}
1119fa590c22SMicky Ching 
11209f902b49SAymen Qader 	if (sub_class & 0xC0)
1121031366eaSJoe Perches 		return STATUS_FAIL;
1122fa590c22SMicky Ching 
1123bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "class_code: 0x%x, device_type: 0x%x, sub_class: 0x%x\n",
1124fa590c22SMicky Ching 		class_code, device_type, sub_class);
1125fa590c22SMicky Ching 
1126fa590c22SMicky Ching #ifdef SUPPORT_MSXC
1127fa590c22SMicky Ching 	if (CHK_MSXC(ms_card)) {
1128fa590c22SMicky Ching 		chip->capacity[chip->card2lun[MS_CARD]] =
1129fa590c22SMicky Ching 			ms_card->capacity = xc_total_blk * xc_blk_size;
1130fa590c22SMicky Ching 	} else {
1131fa590c22SMicky Ching 		chip->capacity[chip->card2lun[MS_CARD]] =
1132fa590c22SMicky Ching 			ms_card->capacity = total_blk * blk_size;
1133fa590c22SMicky Ching 	}
1134fa590c22SMicky Ching #else
1135fa590c22SMicky Ching 	ms_card->capacity = total_blk * blk_size;
1136fa590c22SMicky Ching 	chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity;
1137fa590c22SMicky Ching #endif
1138fa590c22SMicky Ching 
1139fa590c22SMicky Ching 	return STATUS_SUCCESS;
1140fa590c22SMicky Ching }
1141fa590c22SMicky Ching 
1142fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE
1143fa590c22SMicky Ching static int mg_set_tpc_para_sub(struct rtsx_chip *chip,
1144fa590c22SMicky Ching 			       int type, u8 mg_entry_num);
1145fa590c22SMicky Ching #endif
1146fa590c22SMicky Ching 
1147fa590c22SMicky Ching static int reset_ms_pro(struct rtsx_chip *chip)
1148fa590c22SMicky Ching {
1149d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1150fa590c22SMicky Ching 	int retval;
1151fa590c22SMicky Ching #ifdef XC_POWERCLASS
1152fa590c22SMicky Ching 	u8 change_power_class;
1153fa590c22SMicky Ching 
1154fa590c22SMicky Ching 	if (chip->ms_power_class_en & 0x02)
1155fa590c22SMicky Ching 		change_power_class = 2;
1156fa590c22SMicky Ching 	else if (chip->ms_power_class_en & 0x01)
1157fa590c22SMicky Ching 		change_power_class = 1;
1158fa590c22SMicky Ching 	else
1159fa590c22SMicky Ching 		change_power_class = 0;
1160fa590c22SMicky Ching #endif
1161fa590c22SMicky Ching 
1162fa590c22SMicky Ching #ifdef XC_POWERCLASS
1163d264ceb7SWayne Porter retry:
1164fa590c22SMicky Ching #endif
1165fa590c22SMicky Ching 	retval = ms_pro_reset_flow(chip, 1);
1166fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
1167fa590c22SMicky Ching 		if (ms_card->switch_8bit_fail) {
1168fa590c22SMicky Ching 			retval = ms_pro_reset_flow(chip, 0);
11699f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
1170031366eaSJoe Perches 				return STATUS_FAIL;
1171fa590c22SMicky Ching 		} else {
1172031366eaSJoe Perches 			return STATUS_FAIL;
1173fa590c22SMicky Ching 		}
1174fa590c22SMicky Ching 	}
1175fa590c22SMicky Ching 
1176fa590c22SMicky Ching 	retval = ms_read_attribute_info(chip);
11779f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1178031366eaSJoe Perches 		return STATUS_FAIL;
1179fa590c22SMicky Ching 
1180fa590c22SMicky Ching #ifdef XC_POWERCLASS
1181fa590c22SMicky Ching 	if (CHK_HG8BIT(ms_card))
1182fa590c22SMicky Ching 		change_power_class = 0;
1183fa590c22SMicky Ching 
1184fa590c22SMicky Ching 	if (change_power_class && CHK_MSXC(ms_card)) {
1185fa590c22SMicky Ching 		u8 power_class_en = chip->ms_power_class_en;
1186fa590c22SMicky Ching 
1187bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "power_class_en = 0x%x\n",
1188bf6c0d11SFabio Falzoi 			power_class_en);
1189bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "change_power_class = %d\n",
1190bf6c0d11SFabio Falzoi 			change_power_class);
1191fa590c22SMicky Ching 
1192fa590c22SMicky Ching 		if (change_power_class)
1193fa590c22SMicky Ching 			power_class_en &= (1 << (change_power_class - 1));
1194fa590c22SMicky Ching 		else
1195fa590c22SMicky Ching 			power_class_en = 0;
1196fa590c22SMicky Ching 
1197fa590c22SMicky Ching 		if (power_class_en) {
1198fa590c22SMicky Ching 			u8 power_class_mode =
1199fa590c22SMicky Ching 				(ms_card->raw_sys_info[46] & 0x18) >> 3;
1200bf6c0d11SFabio Falzoi 			dev_dbg(rtsx_dev(chip), "power_class_mode = 0x%x",
1201fa590c22SMicky Ching 				power_class_mode);
1202fa590c22SMicky Ching 			if (change_power_class > power_class_mode)
1203fa590c22SMicky Ching 				change_power_class = power_class_mode;
1204fa590c22SMicky Ching 			if (change_power_class) {
1205fa590c22SMicky Ching 				retval = msxc_change_power(chip,
1206fa590c22SMicky Ching 							   change_power_class);
1207fa590c22SMicky Ching 				if (retval != STATUS_SUCCESS) {
1208fa590c22SMicky Ching 					change_power_class--;
1209d264ceb7SWayne Porter 					goto retry;
1210fa590c22SMicky Ching 				}
1211fa590c22SMicky Ching 			}
1212fa590c22SMicky Ching 		}
1213fa590c22SMicky Ching 	}
1214fa590c22SMicky Ching #endif
1215fa590c22SMicky Ching 
1216fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE
1217fa590c22SMicky Ching 	retval = mg_set_tpc_para_sub(chip, 0, 0);
12189f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1219031366eaSJoe Perches 		return STATUS_FAIL;
1220fa590c22SMicky Ching #endif
1221fa590c22SMicky Ching 
1222fa590c22SMicky Ching 	if (CHK_HG8BIT(ms_card))
1223fa590c22SMicky Ching 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 8;
1224fa590c22SMicky Ching 	else
1225fa590c22SMicky Ching 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 4;
1226fa590c22SMicky Ching 
1227fa590c22SMicky Ching 	return STATUS_SUCCESS;
1228fa590c22SMicky Ching }
1229fa590c22SMicky Ching 
1230fa590c22SMicky Ching static int ms_read_status_reg(struct rtsx_chip *chip)
1231fa590c22SMicky Ching {
1232fa590c22SMicky Ching 	int retval;
1233fa590c22SMicky Ching 	u8 val[2];
1234fa590c22SMicky Ching 
12356e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, STATUS_REG0, 2, 0, 0);
12369f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1237031366eaSJoe Perches 		return STATUS_FAIL;
1238fa590c22SMicky Ching 
1239fa590c22SMicky Ching 	retval = ms_read_bytes(chip, READ_REG, 2, NO_WAIT_INT, val, 2);
12409f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1241031366eaSJoe Perches 		return STATUS_FAIL;
1242fa590c22SMicky Ching 
1243fa590c22SMicky Ching 	if (val[1] & (STS_UCDT | STS_UCEX | STS_UCFG)) {
1244fa590c22SMicky Ching 		ms_set_err_code(chip, MS_FLASH_READ_ERROR);
1245031366eaSJoe Perches 		return STATUS_FAIL;
1246fa590c22SMicky Ching 	}
1247fa590c22SMicky Ching 
1248fa590c22SMicky Ching 	return STATUS_SUCCESS;
1249fa590c22SMicky Ching }
1250fa590c22SMicky Ching 
1251fa590c22SMicky Ching static int ms_read_extra_data(struct rtsx_chip *chip,
1252fa590c22SMicky Ching 			      u16 block_addr, u8 page_num, u8 *buf, int buf_len)
1253fa590c22SMicky Ching {
1254d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1255fa590c22SMicky Ching 	int retval, i;
1256fa590c22SMicky Ching 	u8 val, data[10];
1257fa590c22SMicky Ching 
12586e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
12596e653e9cSGabriela Bittencourt 				    SYSTEM_PARAM, 6);
12609f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1261031366eaSJoe Perches 		return STATUS_FAIL;
1262fa590c22SMicky Ching 
1263fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card)) {
1264fa590c22SMicky Ching 		/* Parallel interface */
1265fa590c22SMicky Ching 		data[0] = 0x88;
1266fa590c22SMicky Ching 	} else {
1267fa590c22SMicky Ching 		/* Serial interface */
1268fa590c22SMicky Ching 		data[0] = 0x80;
1269fa590c22SMicky Ching 	}
1270fa590c22SMicky Ching 	data[1] = 0;
1271fa590c22SMicky Ching 	data[2] = (u8)(block_addr >> 8);
1272fa590c22SMicky Ching 	data[3] = (u8)block_addr;
1273fa590c22SMicky Ching 	data[4] = 0x40;
1274fa590c22SMicky Ching 	data[5] = page_num;
1275fa590c22SMicky Ching 
1276fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
1277fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
1278fa590c22SMicky Ching 					data, 6);
1279fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
1280fa590c22SMicky Ching 			break;
1281fa590c22SMicky Ching 	}
12829f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
1283031366eaSJoe Perches 		return STATUS_FAIL;
1284fa590c22SMicky Ching 
1285fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1286fa590c22SMicky Ching 
1287fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
1288fa590c22SMicky Ching 		retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
1289fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
1290fa590c22SMicky Ching 			break;
1291fa590c22SMicky Ching 	}
12929f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
1293031366eaSJoe Perches 		return STATUS_FAIL;
1294fa590c22SMicky Ching 
1295fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1296fa590c22SMicky Ching 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
12979f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1298031366eaSJoe Perches 		return STATUS_FAIL;
1299fa590c22SMicky Ching 
1300fa590c22SMicky Ching 	if (val & INT_REG_CMDNK) {
1301fa590c22SMicky Ching 		ms_set_err_code(chip, MS_CMD_NK);
1302031366eaSJoe Perches 		return STATUS_FAIL;
1303fa590c22SMicky Ching 	}
1304fa590c22SMicky Ching 	if (val & INT_REG_CED) {
1305fa590c22SMicky Ching 		if (val & INT_REG_ERR) {
1306fa590c22SMicky Ching 			retval = ms_read_status_reg(chip);
13079f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
1308031366eaSJoe Perches 				return STATUS_FAIL;
1309fa590c22SMicky Ching 
13106e653e9cSGabriela Bittencourt 			retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG,
13116e653e9cSGabriela Bittencourt 						    MS_EXTRA_SIZE, SYSTEM_PARAM,
13129c378f14SWayne Porter 						    6);
13139f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
1314031366eaSJoe Perches 				return STATUS_FAIL;
1315031366eaSJoe Perches 		}
1316fa590c22SMicky Ching 	}
1317fa590c22SMicky Ching 
1318fa590c22SMicky Ching 	retval = ms_read_bytes(chip, READ_REG, MS_EXTRA_SIZE, NO_WAIT_INT,
1319fa590c22SMicky Ching 			       data, MS_EXTRA_SIZE);
13209f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1321031366eaSJoe Perches 		return STATUS_FAIL;
1322fa590c22SMicky Ching 
1323fa590c22SMicky Ching 	if (buf && buf_len) {
1324fa590c22SMicky Ching 		if (buf_len > MS_EXTRA_SIZE)
1325fa590c22SMicky Ching 			buf_len = MS_EXTRA_SIZE;
1326fa590c22SMicky Ching 		memcpy(buf, data, buf_len);
1327fa590c22SMicky Ching 	}
1328fa590c22SMicky Ching 
1329fa590c22SMicky Ching 	return STATUS_SUCCESS;
1330fa590c22SMicky Ching }
1331fa590c22SMicky Ching 
13329c378f14SWayne Porter static int ms_write_extra_data(struct rtsx_chip *chip, u16 block_addr,
13339c378f14SWayne Porter 			       u8 page_num, u8 *buf, int buf_len)
1334fa590c22SMicky Ching {
1335d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1336fa590c22SMicky Ching 	int retval, i;
1337fa590c22SMicky Ching 	u8 val, data[16];
1338fa590c22SMicky Ching 
13397b228bdfSBenjamin Philip 	if (!buf || buf_len < MS_EXTRA_SIZE)
1340031366eaSJoe Perches 		return STATUS_FAIL;
1341fa590c22SMicky Ching 
13426e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
13436e653e9cSGabriela Bittencourt 				    SYSTEM_PARAM, 6 + MS_EXTRA_SIZE);
13449f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1345031366eaSJoe Perches 		return STATUS_FAIL;
1346fa590c22SMicky Ching 
1347fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card))
1348fa590c22SMicky Ching 		data[0] = 0x88;
1349fa590c22SMicky Ching 	else
1350fa590c22SMicky Ching 		data[0] = 0x80;
1351fa590c22SMicky Ching 
1352fa590c22SMicky Ching 	data[1] = 0;
1353fa590c22SMicky Ching 	data[2] = (u8)(block_addr >> 8);
1354fa590c22SMicky Ching 	data[3] = (u8)block_addr;
1355fa590c22SMicky Ching 	data[4] = 0x40;
1356fa590c22SMicky Ching 	data[5] = page_num;
1357fa590c22SMicky Ching 
1358fa590c22SMicky Ching 	for (i = 6; i < MS_EXTRA_SIZE + 6; i++)
1359fa590c22SMicky Ching 		data[i] = buf[i - 6];
1360fa590c22SMicky Ching 
1361fa590c22SMicky Ching 	retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
1362fa590c22SMicky Ching 				NO_WAIT_INT, data, 16);
13639f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1364031366eaSJoe Perches 		return STATUS_FAIL;
1365fa590c22SMicky Ching 
1366fa590c22SMicky Ching 	retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
13679f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1368031366eaSJoe Perches 		return STATUS_FAIL;
1369fa590c22SMicky Ching 
1370fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1371fa590c22SMicky Ching 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
13729f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1373031366eaSJoe Perches 		return STATUS_FAIL;
1374fa590c22SMicky Ching 
1375fa590c22SMicky Ching 	if (val & INT_REG_CMDNK) {
1376fa590c22SMicky Ching 		ms_set_err_code(chip, MS_CMD_NK);
1377031366eaSJoe Perches 		return STATUS_FAIL;
1378fa590c22SMicky Ching 	}
1379fa590c22SMicky Ching 	if (val & INT_REG_CED) {
1380fa590c22SMicky Ching 		if (val & INT_REG_ERR) {
1381fa590c22SMicky Ching 			ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
1382031366eaSJoe Perches 			return STATUS_FAIL;
1383fa590c22SMicky Ching 		}
1384fa590c22SMicky Ching 	}
1385fa590c22SMicky Ching 
1386fa590c22SMicky Ching 	return STATUS_SUCCESS;
1387fa590c22SMicky Ching }
1388fa590c22SMicky Ching 
1389fa590c22SMicky Ching static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num)
1390fa590c22SMicky Ching {
1391d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1392fa590c22SMicky Ching 	int retval;
1393fa590c22SMicky Ching 	u8 val, data[6];
1394fa590c22SMicky Ching 
13956e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
13966e653e9cSGabriela Bittencourt 				    SYSTEM_PARAM, 6);
13979f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1398031366eaSJoe Perches 		return STATUS_FAIL;
1399fa590c22SMicky Ching 
1400fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card))
1401fa590c22SMicky Ching 		data[0] = 0x88;
1402fa590c22SMicky Ching 	else
1403fa590c22SMicky Ching 		data[0] = 0x80;
1404fa590c22SMicky Ching 
1405fa590c22SMicky Ching 	data[1] = 0;
1406fa590c22SMicky Ching 	data[2] = (u8)(block_addr >> 8);
1407fa590c22SMicky Ching 	data[3] = (u8)block_addr;
1408fa590c22SMicky Ching 	data[4] = 0x20;
1409fa590c22SMicky Ching 	data[5] = page_num;
1410fa590c22SMicky Ching 
1411fa590c22SMicky Ching 	retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
14129f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1413031366eaSJoe Perches 		return STATUS_FAIL;
1414fa590c22SMicky Ching 
1415fa590c22SMicky Ching 	retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
14169f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1417031366eaSJoe Perches 		return STATUS_FAIL;
1418fa590c22SMicky Ching 
1419fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1420fa590c22SMicky Ching 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
14219f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1422031366eaSJoe Perches 		return STATUS_FAIL;
1423fa590c22SMicky Ching 
1424fa590c22SMicky Ching 	if (val & INT_REG_CMDNK) {
1425fa590c22SMicky Ching 		ms_set_err_code(chip, MS_CMD_NK);
1426031366eaSJoe Perches 		return STATUS_FAIL;
1427fa590c22SMicky Ching 	}
1428fa590c22SMicky Ching 
1429fa590c22SMicky Ching 	if (val & INT_REG_CED) {
1430fa590c22SMicky Ching 		if (val & INT_REG_ERR) {
1431fa590c22SMicky Ching 			if (!(val & INT_REG_BREQ)) {
1432fa590c22SMicky Ching 				ms_set_err_code(chip,  MS_FLASH_READ_ERROR);
1433031366eaSJoe Perches 				return STATUS_FAIL;
1434fa590c22SMicky Ching 			}
1435fa590c22SMicky Ching 			retval = ms_read_status_reg(chip);
1436fa590c22SMicky Ching 			if (retval != STATUS_SUCCESS)
1437fa590c22SMicky Ching 				ms_set_err_code(chip,  MS_FLASH_WRITE_ERROR);
1438fa590c22SMicky Ching 
1439fa590c22SMicky Ching 		} else {
1440fa590c22SMicky Ching 			if (!(val & INT_REG_BREQ)) {
1441fa590c22SMicky Ching 				ms_set_err_code(chip, MS_BREQ_ERROR);
1442031366eaSJoe Perches 				return STATUS_FAIL;
1443fa590c22SMicky Ching 			}
1444fa590c22SMicky Ching 		}
1445fa590c22SMicky Ching 	}
1446fa590c22SMicky Ching 
1447fa590c22SMicky Ching 	retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA,
1448fa590c22SMicky Ching 				 0, NO_WAIT_INT);
14499f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1450031366eaSJoe Perches 		return STATUS_FAIL;
1451fa590c22SMicky Ching 
14529f902b49SAymen Qader 	if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR))
1453031366eaSJoe Perches 		return STATUS_FAIL;
1454fa590c22SMicky Ching 
1455fa590c22SMicky Ching 	return STATUS_SUCCESS;
1456fa590c22SMicky Ching }
1457fa590c22SMicky Ching 
1458fa590c22SMicky Ching static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk)
1459fa590c22SMicky Ching {
1460d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1461fa590c22SMicky Ching 	int retval;
1462fa590c22SMicky Ching 	u8 val, data[8], extra[MS_EXTRA_SIZE];
1463fa590c22SMicky Ching 
1464fa590c22SMicky Ching 	retval = ms_read_extra_data(chip, phy_blk, 0, extra, MS_EXTRA_SIZE);
14659f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1466031366eaSJoe Perches 		return STATUS_FAIL;
1467fa590c22SMicky Ching 
14686e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
14696e653e9cSGabriela Bittencourt 				    SYSTEM_PARAM, 7);
14709f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1471031366eaSJoe Perches 		return STATUS_FAIL;
1472fa590c22SMicky Ching 
1473fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1474fa590c22SMicky Ching 
1475fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card))
1476fa590c22SMicky Ching 		data[0] = 0x88;
1477fa590c22SMicky Ching 	else
1478fa590c22SMicky Ching 		data[0] = 0x80;
1479fa590c22SMicky Ching 
1480fa590c22SMicky Ching 	data[1] = 0;
1481fa590c22SMicky Ching 	data[2] = (u8)(phy_blk >> 8);
1482fa590c22SMicky Ching 	data[3] = (u8)phy_blk;
1483fa590c22SMicky Ching 	data[4] = 0x80;
1484fa590c22SMicky Ching 	data[5] = 0;
1485fa590c22SMicky Ching 	data[6] = extra[0] & 0x7F;
1486fa590c22SMicky Ching 	data[7] = 0xFF;
1487fa590c22SMicky Ching 
1488fa590c22SMicky Ching 	retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 7);
14899f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1490031366eaSJoe Perches 		return STATUS_FAIL;
1491fa590c22SMicky Ching 
1492fa590c22SMicky Ching 	retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
14939f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1494031366eaSJoe Perches 		return STATUS_FAIL;
1495fa590c22SMicky Ching 
1496fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1497fa590c22SMicky Ching 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
14989f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1499031366eaSJoe Perches 		return STATUS_FAIL;
1500fa590c22SMicky Ching 
1501fa590c22SMicky Ching 	if (val & INT_REG_CMDNK) {
1502fa590c22SMicky Ching 		ms_set_err_code(chip, MS_CMD_NK);
1503031366eaSJoe Perches 		return STATUS_FAIL;
1504fa590c22SMicky Ching 	}
1505fa590c22SMicky Ching 
1506fa590c22SMicky Ching 	if (val & INT_REG_CED) {
1507fa590c22SMicky Ching 		if (val & INT_REG_ERR) {
1508fa590c22SMicky Ching 			ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
1509031366eaSJoe Perches 			return STATUS_FAIL;
1510fa590c22SMicky Ching 		}
1511fa590c22SMicky Ching 	}
1512fa590c22SMicky Ching 
1513fa590c22SMicky Ching 	return STATUS_SUCCESS;
1514fa590c22SMicky Ching }
1515fa590c22SMicky Ching 
1516fa590c22SMicky Ching static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk)
1517fa590c22SMicky Ching {
1518d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1519fa590c22SMicky Ching 	int retval, i = 0;
1520fa590c22SMicky Ching 	u8 val, data[6];
1521fa590c22SMicky Ching 
15226e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
15236e653e9cSGabriela Bittencourt 				    SYSTEM_PARAM, 6);
15249f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1525031366eaSJoe Perches 		return STATUS_FAIL;
1526fa590c22SMicky Ching 
1527fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1528fa590c22SMicky Ching 
1529fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card))
1530fa590c22SMicky Ching 		data[0] = 0x88;
1531fa590c22SMicky Ching 	else
1532fa590c22SMicky Ching 		data[0] = 0x80;
1533fa590c22SMicky Ching 
1534fa590c22SMicky Ching 	data[1] = 0;
1535fa590c22SMicky Ching 	data[2] = (u8)(phy_blk >> 8);
1536fa590c22SMicky Ching 	data[3] = (u8)phy_blk;
1537fa590c22SMicky Ching 	data[4] = 0;
1538fa590c22SMicky Ching 	data[5] = 0;
1539fa590c22SMicky Ching 
1540fa590c22SMicky Ching 	retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
15419f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1542031366eaSJoe Perches 		return STATUS_FAIL;
1543fa590c22SMicky Ching 
1544fa590c22SMicky Ching ERASE_RTY:
1545fa590c22SMicky Ching 	retval = ms_send_cmd(chip, BLOCK_ERASE, WAIT_INT);
15469f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1547031366eaSJoe Perches 		return STATUS_FAIL;
1548fa590c22SMicky Ching 
1549fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
1550fa590c22SMicky Ching 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
15519f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1552031366eaSJoe Perches 		return STATUS_FAIL;
1553fa590c22SMicky Ching 
1554fa590c22SMicky Ching 	if (val & INT_REG_CMDNK) {
1555fa590c22SMicky Ching 		if (i < 3) {
1556fa590c22SMicky Ching 			i++;
1557fa590c22SMicky Ching 			goto ERASE_RTY;
1558fa590c22SMicky Ching 		}
1559fa590c22SMicky Ching 
1560fa590c22SMicky Ching 		ms_set_err_code(chip, MS_CMD_NK);
1561fa590c22SMicky Ching 		ms_set_bad_block(chip, phy_blk);
1562031366eaSJoe Perches 		return STATUS_FAIL;
1563fa590c22SMicky Ching 	}
1564fa590c22SMicky Ching 
1565fa590c22SMicky Ching 	if (val & INT_REG_CED) {
1566fa590c22SMicky Ching 		if (val & INT_REG_ERR) {
1567fa590c22SMicky Ching 			ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
1568031366eaSJoe Perches 			return STATUS_FAIL;
1569fa590c22SMicky Ching 		}
1570fa590c22SMicky Ching 	}
1571fa590c22SMicky Ching 
1572fa590c22SMicky Ching 	return STATUS_SUCCESS;
1573fa590c22SMicky Ching }
1574fa590c22SMicky Ching 
1575fa590c22SMicky Ching static void ms_set_page_status(u16 log_blk, u8 type, u8 *extra, int extra_len)
1576fa590c22SMicky Ching {
15777b228bdfSBenjamin Philip 	if (!extra || extra_len < MS_EXTRA_SIZE)
1578fa590c22SMicky Ching 		return;
1579fa590c22SMicky Ching 
1580fa590c22SMicky Ching 	memset(extra, 0xFF, MS_EXTRA_SIZE);
1581fa590c22SMicky Ching 
15826e653e9cSGabriela Bittencourt 	if (type == set_PS_NG) {
1583fa590c22SMicky Ching 		/* set page status as 1:NG,and block status keep 1:OK */
1584fa590c22SMicky Ching 		extra[0] = 0xB8;
1585fa590c22SMicky Ching 	} else {
1586fa590c22SMicky Ching 		/* set page status as 0:Data Error,and block status keep 1:OK */
1587fa590c22SMicky Ching 		extra[0] = 0x98;
1588fa590c22SMicky Ching 	}
1589fa590c22SMicky Ching 
1590fa590c22SMicky Ching 	extra[2] = (u8)(log_blk >> 8);
1591fa590c22SMicky Ching 	extra[3] = (u8)log_blk;
1592fa590c22SMicky Ching }
1593fa590c22SMicky Ching 
1594fa590c22SMicky Ching static int ms_init_page(struct rtsx_chip *chip, u16 phy_blk, u16 log_blk,
1595fa590c22SMicky Ching 			u8 start_page, u8 end_page)
1596fa590c22SMicky Ching {
1597fa590c22SMicky Ching 	int retval;
1598fa590c22SMicky Ching 	u8 extra[MS_EXTRA_SIZE], i;
1599fa590c22SMicky Ching 
1600fa590c22SMicky Ching 	memset(extra, 0xff, MS_EXTRA_SIZE);
1601fa590c22SMicky Ching 
1602fa590c22SMicky Ching 	extra[0] = 0xf8;	/* Block, page OK, data erased */
1603fa590c22SMicky Ching 	extra[1] = 0xff;
1604fa590c22SMicky Ching 	extra[2] = (u8)(log_blk >> 8);
1605fa590c22SMicky Ching 	extra[3] = (u8)log_blk;
1606fa590c22SMicky Ching 
1607fa590c22SMicky Ching 	for (i = start_page; i < end_page; i++) {
1608fa590c22SMicky Ching 		if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
1609fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_CARD);
1610031366eaSJoe Perches 			return STATUS_FAIL;
1611fa590c22SMicky Ching 		}
1612fa590c22SMicky Ching 
1613fa590c22SMicky Ching 		retval = ms_write_extra_data(chip, phy_blk, i,
1614fa590c22SMicky Ching 					     extra, MS_EXTRA_SIZE);
16159f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1616031366eaSJoe Perches 			return STATUS_FAIL;
1617031366eaSJoe Perches 	}
1618fa590c22SMicky Ching 
1619fa590c22SMicky Ching 	return STATUS_SUCCESS;
1620fa590c22SMicky Ching }
1621fa590c22SMicky Ching 
1622fa590c22SMicky Ching static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
1623fa590c22SMicky Ching 			u16 log_blk, u8 start_page, u8 end_page)
1624fa590c22SMicky Ching {
1625d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1626de904bf0SQuentin Lambert 	bool uncorrect_flag = false;
1627de904bf0SQuentin Lambert 	int retval, rty_cnt;
1628fa590c22SMicky Ching 	u8 extra[MS_EXTRA_SIZE], val, i, j, data[16];
1629fa590c22SMicky Ching 
1630bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "Copy page from 0x%x to 0x%x, logical block is 0x%x\n",
1631fa590c22SMicky Ching 		old_blk, new_blk, log_blk);
1632bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d\n",
1633bf6c0d11SFabio Falzoi 		start_page, end_page);
1634fa590c22SMicky Ching 
1635fa590c22SMicky Ching 	retval = ms_read_extra_data(chip, new_blk, 0, extra, MS_EXTRA_SIZE);
16369f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1637031366eaSJoe Perches 		return STATUS_FAIL;
1638fa590c22SMicky Ching 
1639fa590c22SMicky Ching 	retval = ms_read_status_reg(chip);
16409f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1641031366eaSJoe Perches 		return STATUS_FAIL;
1642fa590c22SMicky Ching 
16438ee775f9SJoe Perches 	retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
16449f902b49SAymen Qader 	if (retval)
16458ee775f9SJoe Perches 		return retval;
1646fa590c22SMicky Ching 
1647fa590c22SMicky Ching 	if (val & BUF_FULL) {
1648fa590c22SMicky Ching 		retval = ms_send_cmd(chip, CLEAR_BUF, WAIT_INT);
16499f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1650031366eaSJoe Perches 			return STATUS_FAIL;
1651fa590c22SMicky Ching 
1652fa590c22SMicky Ching 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
16539f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1654031366eaSJoe Perches 			return STATUS_FAIL;
1655fa590c22SMicky Ching 
1656fa590c22SMicky Ching 		if (!(val & INT_REG_CED)) {
1657fa590c22SMicky Ching 			ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
1658031366eaSJoe Perches 			return STATUS_FAIL;
1659fa590c22SMicky Ching 		}
1660fa590c22SMicky Ching 	}
1661fa590c22SMicky Ching 
1662fa590c22SMicky Ching 	for (i = start_page; i < end_page; i++) {
1663fa590c22SMicky Ching 		if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
1664fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_CARD);
1665031366eaSJoe Perches 			return STATUS_FAIL;
1666fa590c22SMicky Ching 		}
1667fa590c22SMicky Ching 
166873b69c01SAditya Pakki 		retval = ms_read_extra_data(chip, old_blk, i, extra,
166973b69c01SAditya Pakki 					    MS_EXTRA_SIZE);
167073b69c01SAditya Pakki 		if (retval != STATUS_SUCCESS)
167173b69c01SAditya Pakki 			return STATUS_FAIL;
1672fa590c22SMicky Ching 
16736e653e9cSGabriela Bittencourt 		retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG,
16746e653e9cSGabriela Bittencourt 					    MS_EXTRA_SIZE, SYSTEM_PARAM, 6);
16759f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1676031366eaSJoe Perches 			return STATUS_FAIL;
1677fa590c22SMicky Ching 
1678fa590c22SMicky Ching 		ms_set_err_code(chip, MS_NO_ERROR);
1679fa590c22SMicky Ching 
1680fa590c22SMicky Ching 		if (CHK_MS4BIT(ms_card))
1681fa590c22SMicky Ching 			data[0] = 0x88;
1682fa590c22SMicky Ching 		else
1683fa590c22SMicky Ching 			data[0] = 0x80;
1684fa590c22SMicky Ching 
1685fa590c22SMicky Ching 		data[1] = 0;
1686fa590c22SMicky Ching 		data[2] = (u8)(old_blk >> 8);
1687fa590c22SMicky Ching 		data[3] = (u8)old_blk;
1688fa590c22SMicky Ching 		data[4] = 0x20;
1689fa590c22SMicky Ching 		data[5] = i;
1690fa590c22SMicky Ching 
1691fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
1692fa590c22SMicky Ching 					data, 6);
16939f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1694031366eaSJoe Perches 			return STATUS_FAIL;
1695fa590c22SMicky Ching 
1696fa590c22SMicky Ching 		retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
16979f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1698031366eaSJoe Perches 			return STATUS_FAIL;
1699fa590c22SMicky Ching 
1700fa590c22SMicky Ching 		ms_set_err_code(chip, MS_NO_ERROR);
1701fa590c22SMicky Ching 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
17029f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1703031366eaSJoe Perches 			return STATUS_FAIL;
1704fa590c22SMicky Ching 
1705fa590c22SMicky Ching 		if (val & INT_REG_CMDNK) {
1706fa590c22SMicky Ching 			ms_set_err_code(chip, MS_CMD_NK);
1707031366eaSJoe Perches 			return STATUS_FAIL;
1708fa590c22SMicky Ching 		}
1709fa590c22SMicky Ching 
1710fa590c22SMicky Ching 		if (val & INT_REG_CED) {
1711fa590c22SMicky Ching 			if (val & INT_REG_ERR) {
1712fa590c22SMicky Ching 				retval = ms_read_status_reg(chip);
1713fa590c22SMicky Ching 				if (retval != STATUS_SUCCESS) {
1714de904bf0SQuentin Lambert 					uncorrect_flag = true;
1715bf6c0d11SFabio Falzoi 					dev_dbg(rtsx_dev(chip), "Uncorrectable error\n");
1716fa590c22SMicky Ching 				} else {
1717de904bf0SQuentin Lambert 					uncorrect_flag = false;
1718fa590c22SMicky Ching 				}
1719fa590c22SMicky Ching 
1720fa590c22SMicky Ching 				retval = ms_transfer_tpc(chip,
1721fa590c22SMicky Ching 							 MS_TM_NORMAL_READ,
1722fa590c22SMicky Ching 							 READ_PAGE_DATA,
1723fa590c22SMicky Ching 							 0, NO_WAIT_INT);
17249f902b49SAymen Qader 				if (retval != STATUS_SUCCESS)
1725031366eaSJoe Perches 					return STATUS_FAIL;
1726fa590c22SMicky Ching 
1727fa590c22SMicky Ching 				if (uncorrect_flag) {
17286e653e9cSGabriela Bittencourt 					ms_set_page_status(log_blk, set_PS_NG,
17299c378f14SWayne Porter 							   extra,
17309c378f14SWayne Porter 							   MS_EXTRA_SIZE);
1731fa590c22SMicky Ching 					if (i == 0)
1732fa590c22SMicky Ching 						extra[0] &= 0xEF;
1733fa590c22SMicky Ching 
1734fa590c22SMicky Ching 					ms_write_extra_data(chip, old_blk, i,
17359c378f14SWayne Porter 							    extra,
17369c378f14SWayne Porter 							    MS_EXTRA_SIZE);
1737bf6c0d11SFabio Falzoi 					dev_dbg(rtsx_dev(chip), "page %d : extra[0] = 0x%x\n",
1738bf6c0d11SFabio Falzoi 						i, extra[0]);
1739fa590c22SMicky Ching 					MS_SET_BAD_BLOCK_FLG(ms_card);
1740fa590c22SMicky Ching 
17416e653e9cSGabriela Bittencourt 					ms_set_page_status(log_blk,
17426e653e9cSGabriela Bittencourt 							   set_PS_error, extra,
17439c378f14SWayne Porter 							   MS_EXTRA_SIZE);
1744fa590c22SMicky Ching 					ms_write_extra_data(chip, new_blk, i,
17459c378f14SWayne Porter 							    extra,
17469c378f14SWayne Porter 							    MS_EXTRA_SIZE);
1747fa590c22SMicky Ching 					continue;
1748fa590c22SMicky Ching 				}
1749fa590c22SMicky Ching 
1750fa590c22SMicky Ching 				for (rty_cnt = 0; rty_cnt < MS_MAX_RETRY_COUNT;
1751fa590c22SMicky Ching 				     rty_cnt++) {
1752b25c7dc1SSamuel Sjöberg 					retval = ms_transfer_tpc(chip,
1753fa590c22SMicky Ching 								 MS_TM_NORMAL_WRITE,
1754fa590c22SMicky Ching 								 WRITE_PAGE_DATA,
1755fa590c22SMicky Ching 								 0, NO_WAIT_INT);
1756fa590c22SMicky Ching 					if (retval == STATUS_SUCCESS)
1757fa590c22SMicky Ching 						break;
1758fa590c22SMicky Ching 				}
17599f902b49SAymen Qader 				if (rty_cnt == MS_MAX_RETRY_COUNT)
1760031366eaSJoe Perches 					return STATUS_FAIL;
1761031366eaSJoe Perches 			}
1762fa590c22SMicky Ching 
1763fa590c22SMicky Ching 			if (!(val & INT_REG_BREQ)) {
1764fa590c22SMicky Ching 				ms_set_err_code(chip, MS_BREQ_ERROR);
1765031366eaSJoe Perches 				return STATUS_FAIL;
1766fa590c22SMicky Ching 			}
1767fa590c22SMicky Ching 		}
1768fa590c22SMicky Ching 
17696e653e9cSGabriela Bittencourt 		retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
17706e653e9cSGabriela Bittencourt 					    SYSTEM_PARAM, (6 + MS_EXTRA_SIZE));
1771*5a77b84dSDenis Arefev 		if (retval != STATUS_SUCCESS)
1772*5a77b84dSDenis Arefev 			return STATUS_FAIL;
1773fa590c22SMicky Ching 
1774fa590c22SMicky Ching 		ms_set_err_code(chip, MS_NO_ERROR);
1775fa590c22SMicky Ching 
1776fa590c22SMicky Ching 		if (CHK_MS4BIT(ms_card))
1777fa590c22SMicky Ching 			data[0] = 0x88;
1778fa590c22SMicky Ching 		else
1779fa590c22SMicky Ching 			data[0] = 0x80;
1780fa590c22SMicky Ching 
1781fa590c22SMicky Ching 		data[1] = 0;
1782fa590c22SMicky Ching 		data[2] = (u8)(new_blk >> 8);
1783fa590c22SMicky Ching 		data[3] = (u8)new_blk;
1784fa590c22SMicky Ching 		data[4] = 0x20;
1785fa590c22SMicky Ching 		data[5] = i;
1786fa590c22SMicky Ching 
1787fa590c22SMicky Ching 		if ((extra[0] & 0x60) != 0x60)
1788fa590c22SMicky Ching 			data[6] = extra[0];
1789fa590c22SMicky Ching 		else
1790fa590c22SMicky Ching 			data[6] = 0xF8;
1791fa590c22SMicky Ching 
1792fa590c22SMicky Ching 		data[6 + 1] = 0xFF;
1793fa590c22SMicky Ching 		data[6 + 2] = (u8)(log_blk >> 8);
1794fa590c22SMicky Ching 		data[6 + 3] = (u8)log_blk;
1795fa590c22SMicky Ching 
1796fa590c22SMicky Ching 		for (j = 4; j <= MS_EXTRA_SIZE; j++)
1797fa590c22SMicky Ching 			data[6 + j] = 0xFF;
1798fa590c22SMicky Ching 
1799fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
1800fa590c22SMicky Ching 					NO_WAIT_INT, data, 16);
18019f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1802031366eaSJoe Perches 			return STATUS_FAIL;
1803fa590c22SMicky Ching 
1804fa590c22SMicky Ching 		retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
18059f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1806031366eaSJoe Perches 			return STATUS_FAIL;
1807fa590c22SMicky Ching 
1808fa590c22SMicky Ching 		ms_set_err_code(chip, MS_NO_ERROR);
1809fa590c22SMicky Ching 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
18109f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
1811031366eaSJoe Perches 			return STATUS_FAIL;
1812fa590c22SMicky Ching 
1813fa590c22SMicky Ching 		if (val & INT_REG_CMDNK) {
1814fa590c22SMicky Ching 			ms_set_err_code(chip, MS_CMD_NK);
1815031366eaSJoe Perches 			return STATUS_FAIL;
1816fa590c22SMicky Ching 		}
1817fa590c22SMicky Ching 
1818fa590c22SMicky Ching 		if (val & INT_REG_CED) {
1819fa590c22SMicky Ching 			if (val & INT_REG_ERR) {
1820fa590c22SMicky Ching 				ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
1821031366eaSJoe Perches 				return STATUS_FAIL;
1822fa590c22SMicky Ching 			}
1823fa590c22SMicky Ching 		}
1824fa590c22SMicky Ching 
1825fa590c22SMicky Ching 		if (i == 0) {
18266e653e9cSGabriela Bittencourt 			retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG,
18276e653e9cSGabriela Bittencourt 						    MS_EXTRA_SIZE, SYSTEM_PARAM,
18289c378f14SWayne Porter 						    7);
18299f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
1830031366eaSJoe Perches 				return STATUS_FAIL;
1831fa590c22SMicky Ching 
1832fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_ERROR);
1833fa590c22SMicky Ching 
1834fa590c22SMicky Ching 			if (CHK_MS4BIT(ms_card))
1835fa590c22SMicky Ching 				data[0] = 0x88;
1836fa590c22SMicky Ching 			else
1837fa590c22SMicky Ching 				data[0] = 0x80;
1838fa590c22SMicky Ching 
1839fa590c22SMicky Ching 			data[1] = 0;
1840fa590c22SMicky Ching 			data[2] = (u8)(old_blk >> 8);
1841fa590c22SMicky Ching 			data[3] = (u8)old_blk;
1842fa590c22SMicky Ching 			data[4] = 0x80;
1843fa590c22SMicky Ching 			data[5] = 0;
1844fa590c22SMicky Ching 			data[6] = 0xEF;
1845fa590c22SMicky Ching 			data[7] = 0xFF;
1846fa590c22SMicky Ching 
1847fa590c22SMicky Ching 			retval = ms_write_bytes(chip, WRITE_REG, 7,
1848fa590c22SMicky Ching 						NO_WAIT_INT, data, 8);
18499f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
1850031366eaSJoe Perches 				return STATUS_FAIL;
1851fa590c22SMicky Ching 
1852fa590c22SMicky Ching 			retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
18539f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
1854031366eaSJoe Perches 				return STATUS_FAIL;
1855fa590c22SMicky Ching 
1856fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_ERROR);
1857fa590c22SMicky Ching 			retval = ms_read_bytes(chip, GET_INT, 1,
1858fa590c22SMicky Ching 					       NO_WAIT_INT, &val, 1);
18599f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
1860031366eaSJoe Perches 				return STATUS_FAIL;
1861fa590c22SMicky Ching 
1862fa590c22SMicky Ching 			if (val & INT_REG_CMDNK) {
1863fa590c22SMicky Ching 				ms_set_err_code(chip, MS_CMD_NK);
1864031366eaSJoe Perches 				return STATUS_FAIL;
1865fa590c22SMicky Ching 			}
1866fa590c22SMicky Ching 
1867fa590c22SMicky Ching 			if (val & INT_REG_CED) {
1868fa590c22SMicky Ching 				if (val & INT_REG_ERR) {
1869fa590c22SMicky Ching 					ms_set_err_code(chip,
1870fa590c22SMicky Ching 							MS_FLASH_WRITE_ERROR);
1871031366eaSJoe Perches 					return STATUS_FAIL;
1872fa590c22SMicky Ching 				}
1873fa590c22SMicky Ching 			}
1874fa590c22SMicky Ching 		}
1875fa590c22SMicky Ching 	}
1876fa590c22SMicky Ching 
1877fa590c22SMicky Ching 	return STATUS_SUCCESS;
1878fa590c22SMicky Ching }
1879fa590c22SMicky Ching 
1880fa590c22SMicky Ching static int reset_ms(struct rtsx_chip *chip)
1881fa590c22SMicky Ching {
1882d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
1883fa590c22SMicky Ching 	int retval;
1884fa590c22SMicky Ching 	u16 i, reg_addr, block_size;
1885fa590c22SMicky Ching 	u8 val, extra[MS_EXTRA_SIZE], j, *ptr;
1886fa590c22SMicky Ching #ifndef SUPPORT_MAGIC_GATE
1887fa590c22SMicky Ching 	u16 eblock_cnt;
1888fa590c22SMicky Ching #endif
1889fa590c22SMicky Ching 
1890fa590c22SMicky Ching 	retval = ms_prepare_reset(chip);
18919f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1892031366eaSJoe Perches 		return STATUS_FAIL;
1893fa590c22SMicky Ching 
1894fa590c22SMicky Ching 	ms_card->ms_type |= TYPE_MS;
1895fa590c22SMicky Ching 
1896fa590c22SMicky Ching 	retval = ms_send_cmd(chip, MS_RESET, NO_WAIT_INT);
18979f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1898031366eaSJoe Perches 		return STATUS_FAIL;
1899fa590c22SMicky Ching 
1900fa590c22SMicky Ching 	retval = ms_read_status_reg(chip);
19019f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1902031366eaSJoe Perches 		return STATUS_FAIL;
1903fa590c22SMicky Ching 
19048ee775f9SJoe Perches 	retval = rtsx_read_register(chip, PPBUF_BASE2, &val);
19059f902b49SAymen Qader 	if (retval)
19068ee775f9SJoe Perches 		return retval;
19079f902b49SAymen Qader 
1908fa590c22SMicky Ching 	if (val & WRT_PRTCT)
1909fa590c22SMicky Ching 		chip->card_wp |= MS_CARD;
1910fa590c22SMicky Ching 	else
1911fa590c22SMicky Ching 		chip->card_wp &= ~MS_CARD;
1912fa590c22SMicky Ching 
1913fa590c22SMicky Ching 	i = 0;
1914fa590c22SMicky Ching 
1915fa590c22SMicky Ching RE_SEARCH:
1916fa590c22SMicky Ching 	/* Search Boot Block */
1917fa590c22SMicky Ching 	while (i < (MAX_DEFECTIVE_BLOCK + 2)) {
1918fa590c22SMicky Ching 		if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
1919fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_CARD);
1920031366eaSJoe Perches 			return STATUS_FAIL;
1921fa590c22SMicky Ching 		}
1922fa590c22SMicky Ching 
1923fa590c22SMicky Ching 		retval = ms_read_extra_data(chip, i, 0, extra, MS_EXTRA_SIZE);
1924fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
1925fa590c22SMicky Ching 			i++;
1926fa590c22SMicky Ching 			continue;
1927fa590c22SMicky Ching 		}
1928fa590c22SMicky Ching 
1929fa590c22SMicky Ching 		if (extra[0] & BLOCK_OK) {
1930fa590c22SMicky Ching 			if (!(extra[1] & NOT_BOOT_BLOCK)) {
1931fa590c22SMicky Ching 				ms_card->boot_block = i;
1932fa590c22SMicky Ching 				break;
1933fa590c22SMicky Ching 			}
1934fa590c22SMicky Ching 		}
1935fa590c22SMicky Ching 		i++;
1936fa590c22SMicky Ching 	}
1937fa590c22SMicky Ching 
1938fa590c22SMicky Ching 	if (i == (MAX_DEFECTIVE_BLOCK + 2)) {
1939bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "No boot block found!");
1940031366eaSJoe Perches 		return STATUS_FAIL;
1941fa590c22SMicky Ching 	}
1942fa590c22SMicky Ching 
1943fa590c22SMicky Ching 	for (j = 0; j < 3; j++) {
1944fa590c22SMicky Ching 		retval = ms_read_page(chip, ms_card->boot_block, j);
1945fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
1946fa590c22SMicky Ching 			if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) {
1947fa590c22SMicky Ching 				i = ms_card->boot_block + 1;
1948fa590c22SMicky Ching 				ms_set_err_code(chip, MS_NO_ERROR);
1949fa590c22SMicky Ching 				goto RE_SEARCH;
1950fa590c22SMicky Ching 			}
1951fa590c22SMicky Ching 		}
1952fa590c22SMicky Ching 	}
1953fa590c22SMicky Ching 
1954fa590c22SMicky Ching 	retval = ms_read_page(chip, ms_card->boot_block, 0);
19559f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
1956031366eaSJoe Perches 		return STATUS_FAIL;
1957fa590c22SMicky Ching 
1958fa590c22SMicky Ching 	/* Read MS system information as sys_info */
1959fa590c22SMicky Ching 	rtsx_init_cmd(chip);
1960fa590c22SMicky Ching 
1961fa590c22SMicky Ching 	for (i = 0; i < 96; i++)
1962fa590c22SMicky Ching 		rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 0x1A0 + i, 0, 0);
1963fa590c22SMicky Ching 
1964fa590c22SMicky Ching 	retval = rtsx_send_cmd(chip, MS_CARD, 100);
19659f902b49SAymen Qader 	if (retval < 0)
1966031366eaSJoe Perches 		return STATUS_FAIL;
1967fa590c22SMicky Ching 
1968fa590c22SMicky Ching 	ptr = rtsx_get_cmd_data(chip);
1969fa590c22SMicky Ching 	memcpy(ms_card->raw_sys_info, ptr, 96);
1970fa590c22SMicky Ching 
1971fa590c22SMicky Ching 	/* Read useful block contents */
1972fa590c22SMicky Ching 	rtsx_init_cmd(chip);
1973fa590c22SMicky Ching 
1974fa590c22SMicky Ching 	rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID0, 0, 0);
1975fa590c22SMicky Ching 	rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID1, 0, 0);
1976fa590c22SMicky Ching 
1977fa590c22SMicky Ching 	for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3;
1978fa590c22SMicky Ching 	     reg_addr++)
1979fa590c22SMicky Ching 		rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
1980fa590c22SMicky Ching 
1981fa590c22SMicky Ching 	for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++)
1982fa590c22SMicky Ching 		rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0);
1983fa590c22SMicky Ching 
19846e653e9cSGabriela Bittencourt 	rtsx_add_cmd(chip, READ_REG_CMD, MS_device_type, 0, 0);
19856e653e9cSGabriela Bittencourt 	rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_support, 0, 0);
1986fa590c22SMicky Ching 
1987fa590c22SMicky Ching 	retval = rtsx_send_cmd(chip, MS_CARD, 100);
19889f902b49SAymen Qader 	if (retval < 0)
1989031366eaSJoe Perches 		return STATUS_FAIL;
1990fa590c22SMicky Ching 
1991fa590c22SMicky Ching 	ptr = rtsx_get_cmd_data(chip);
1992fa590c22SMicky Ching 
1993bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "Boot block data:\n");
199469b8b224SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "%*ph\n", 16, ptr);
1995fa590c22SMicky Ching 
1996fa590c22SMicky Ching 	/* Block ID error
1997fa590c22SMicky Ching 	 * HEADER_ID0, HEADER_ID1
1998fa590c22SMicky Ching 	 */
1999fa590c22SMicky Ching 	if (ptr[0] != 0x00 || ptr[1] != 0x01) {
2000fa590c22SMicky Ching 		i = ms_card->boot_block + 1;
2001fa590c22SMicky Ching 		goto RE_SEARCH;
2002fa590c22SMicky Ching 	}
2003fa590c22SMicky Ching 
2004fa590c22SMicky Ching 	/* Page size error
2005fa590c22SMicky Ching 	 * PAGE_SIZE_0, PAGE_SIZE_1
2006fa590c22SMicky Ching 	 */
2007fa590c22SMicky Ching 	if (ptr[12] != 0x02 || ptr[13] != 0x00) {
2008fa590c22SMicky Ching 		i = ms_card->boot_block + 1;
2009fa590c22SMicky Ching 		goto RE_SEARCH;
2010fa590c22SMicky Ching 	}
2011fa590c22SMicky Ching 
20127b228bdfSBenjamin Philip 	if (ptr[14] == 1 || ptr[14] == 3)
2013fa590c22SMicky Ching 		chip->card_wp |= MS_CARD;
2014fa590c22SMicky Ching 
2015fa590c22SMicky Ching 	/* BLOCK_SIZE_0, BLOCK_SIZE_1 */
2016fa590c22SMicky Ching 	block_size = ((u16)ptr[6] << 8) | ptr[7];
2017fa590c22SMicky Ching 	if (block_size == 0x0010) {
2018fa590c22SMicky Ching 		/* Block size 16KB */
2019fa590c22SMicky Ching 		ms_card->block_shift = 5;
2020fa590c22SMicky Ching 		ms_card->page_off = 0x1F;
2021fa590c22SMicky Ching 	} else if (block_size == 0x0008) {
2022fa590c22SMicky Ching 		/* Block size 8KB */
2023fa590c22SMicky Ching 		ms_card->block_shift = 4;
2024fa590c22SMicky Ching 		ms_card->page_off = 0x0F;
2025fa590c22SMicky Ching 	}
2026fa590c22SMicky Ching 
2027fa590c22SMicky Ching 	/* BLOCK_COUNT_0, BLOCK_COUNT_1 */
2028fa590c22SMicky Ching 	ms_card->total_block = ((u16)ptr[8] << 8) | ptr[9];
2029fa590c22SMicky Ching 
2030fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE
2031fa590c22SMicky Ching 	j = ptr[10];
2032fa590c22SMicky Ching 
2033fa590c22SMicky Ching 	if (ms_card->block_shift == 4)  { /* 4MB or 8MB */
2034fa590c22SMicky Ching 		if (j < 2)  { /* Effective block for 4MB: 0x1F0 */
2035fa590c22SMicky Ching 			ms_card->capacity = 0x1EE0;
2036fa590c22SMicky Ching 		} else { /* Effective block for 8MB: 0x3E0 */
2037fa590c22SMicky Ching 			ms_card->capacity = 0x3DE0;
2038fa590c22SMicky Ching 		}
2039fa590c22SMicky Ching 	} else  { /* 16MB, 32MB, 64MB or 128MB */
2040fa590c22SMicky Ching 		if (j < 5)  { /* Effective block for 16MB: 0x3E0 */
2041fa590c22SMicky Ching 			ms_card->capacity = 0x7BC0;
2042fa590c22SMicky Ching 		} else if (j < 0xA) { /* Effective block for 32MB: 0x7C0 */
2043fa590c22SMicky Ching 			ms_card->capacity = 0xF7C0;
2044fa590c22SMicky Ching 		} else if (j < 0x11) { /* Effective block for 64MB: 0xF80 */
2045fa590c22SMicky Ching 			ms_card->capacity = 0x1EF80;
2046fa590c22SMicky Ching 		} else { /* Effective block for 128MB: 0x1F00 */
2047fa590c22SMicky Ching 			ms_card->capacity = 0x3DF00;
2048fa590c22SMicky Ching 		}
2049fa590c22SMicky Ching 	}
2050fa590c22SMicky Ching #else
2051fa590c22SMicky Ching 	/* EBLOCK_COUNT_0, EBLOCK_COUNT_1 */
2052fa590c22SMicky Ching 	eblock_cnt = ((u16)ptr[10] << 8) | ptr[11];
2053fa590c22SMicky Ching 
2054fa590c22SMicky Ching 	ms_card->capacity = ((u32)eblock_cnt - 2) << ms_card->block_shift;
2055fa590c22SMicky Ching #endif
2056fa590c22SMicky Ching 
2057fa590c22SMicky Ching 	chip->capacity[chip->card2lun[MS_CARD]] = ms_card->capacity;
2058fa590c22SMicky Ching 
2059fa590c22SMicky Ching 	/* Switch I/F Mode */
2060fa590c22SMicky Ching 	if (ptr[15]) {
20616e653e9cSGabriela Bittencourt 		retval = ms_set_rw_reg_addr(chip, 0, 0, SYSTEM_PARAM, 1);
20629f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
2063031366eaSJoe Perches 			return STATUS_FAIL;
2064fa590c22SMicky Ching 
20658ee775f9SJoe Perches 		retval = rtsx_write_register(chip, PPBUF_BASE2, 0xFF, 0x88);
20669f902b49SAymen Qader 		if (retval)
20678ee775f9SJoe Perches 			return retval;
20689f902b49SAymen Qader 
20698ee775f9SJoe Perches 		retval = rtsx_write_register(chip, PPBUF_BASE2 + 1, 0xFF, 0);
20709f902b49SAymen Qader 		if (retval)
20718ee775f9SJoe Perches 			return retval;
2072fa590c22SMicky Ching 
2073fa590c22SMicky Ching 		retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG, 1,
2074fa590c22SMicky Ching 					 NO_WAIT_INT);
20759f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
2076031366eaSJoe Perches 			return STATUS_FAIL;
2077fa590c22SMicky Ching 
20788ee775f9SJoe Perches 		retval = rtsx_write_register(chip, MS_CFG,
20798ee775f9SJoe Perches 					     0x58 | MS_NO_CHECK_INT,
208025ccf0b0SWayne Porter 					     MS_BUS_WIDTH_4 |
208125ccf0b0SWayne Porter 					     PUSH_TIME_ODD |
208225ccf0b0SWayne Porter 					     MS_NO_CHECK_INT);
20839f902b49SAymen Qader 		if (retval)
20848ee775f9SJoe Perches 			return retval;
2085fa590c22SMicky Ching 
2086fa590c22SMicky Ching 		ms_card->ms_type |= MS_4BIT;
2087fa590c22SMicky Ching 	}
2088fa590c22SMicky Ching 
2089fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card))
2090fa590c22SMicky Ching 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 4;
2091fa590c22SMicky Ching 	else
2092fa590c22SMicky Ching 		chip->card_bus_width[chip->card2lun[MS_CARD]] = 1;
2093fa590c22SMicky Ching 
2094fa590c22SMicky Ching 	return STATUS_SUCCESS;
2095fa590c22SMicky Ching }
2096fa590c22SMicky Ching 
2097fa590c22SMicky Ching static int ms_init_l2p_tbl(struct rtsx_chip *chip)
2098fa590c22SMicky Ching {
2099d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2100fa590c22SMicky Ching 	int size, i, seg_no, retval;
2101fa590c22SMicky Ching 	u16 defect_block, reg_addr;
2102fa590c22SMicky Ching 	u8 val1, val2;
2103fa590c22SMicky Ching 
2104fa590c22SMicky Ching 	ms_card->segment_cnt = ms_card->total_block >> 9;
2105bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "ms_card->segment_cnt = %d\n",
2106bf6c0d11SFabio Falzoi 		ms_card->segment_cnt);
2107fa590c22SMicky Ching 
2108fa590c22SMicky Ching 	size = ms_card->segment_cnt * sizeof(struct zone_entry);
2109fa590c22SMicky Ching 	ms_card->segment = vzalloc(size);
21109f902b49SAymen Qader 	if (!ms_card->segment)
2111031366eaSJoe Perches 		return STATUS_FAIL;
2112fa590c22SMicky Ching 
2113fa590c22SMicky Ching 	retval = ms_read_page(chip, ms_card->boot_block, 1);
21149f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2115031366eaSJoe Perches 		goto INIT_FAIL;
2116fa590c22SMicky Ching 
2117fa590c22SMicky Ching 	reg_addr = PPBUF_BASE2;
2118fa590c22SMicky Ching 	for (i = 0; i < (((ms_card->total_block >> 9) * 10) + 1); i++) {
21197ef4ec4aSVatika Harlalka 		int block_no;
21207ef4ec4aSVatika Harlalka 
2121fa590c22SMicky Ching 		retval = rtsx_read_register(chip, reg_addr++, &val1);
21229f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
2123031366eaSJoe Perches 			goto INIT_FAIL;
2124fa590c22SMicky Ching 
2125fa590c22SMicky Ching 		retval = rtsx_read_register(chip, reg_addr++, &val2);
21269f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
2127031366eaSJoe Perches 			goto INIT_FAIL;
2128fa590c22SMicky Ching 
2129fa590c22SMicky Ching 		defect_block = ((u16)val1 << 8) | val2;
2130fa590c22SMicky Ching 		if (defect_block == 0xFFFF)
2131fa590c22SMicky Ching 			break;
2132fa590c22SMicky Ching 
2133fa590c22SMicky Ching 		seg_no = defect_block / 512;
21347ef4ec4aSVatika Harlalka 
21357ef4ec4aSVatika Harlalka 		block_no = ms_card->segment[seg_no].disable_count++;
21367ef4ec4aSVatika Harlalka 		ms_card->segment[seg_no].defect_list[block_no] = defect_block;
2137fa590c22SMicky Ching 	}
2138fa590c22SMicky Ching 
2139fa590c22SMicky Ching 	for (i = 0; i < ms_card->segment_cnt; i++) {
2140fa590c22SMicky Ching 		ms_card->segment[i].build_flag = 0;
2141fa590c22SMicky Ching 		ms_card->segment[i].l2p_table = NULL;
2142fa590c22SMicky Ching 		ms_card->segment[i].free_table = NULL;
2143fa590c22SMicky Ching 		ms_card->segment[i].get_index = 0;
2144fa590c22SMicky Ching 		ms_card->segment[i].set_index = 0;
2145fa590c22SMicky Ching 		ms_card->segment[i].unused_blk_cnt = 0;
2146fa590c22SMicky Ching 
2147bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "defective block count of segment %d is %d\n",
2148fa590c22SMicky Ching 			i, ms_card->segment[i].disable_count);
2149fa590c22SMicky Ching 	}
2150fa590c22SMicky Ching 
2151fa590c22SMicky Ching 	return STATUS_SUCCESS;
2152fa590c22SMicky Ching 
2153fa590c22SMicky Ching INIT_FAIL:
2154fa590c22SMicky Ching 	vfree(ms_card->segment);
2155fa590c22SMicky Ching 	ms_card->segment = NULL;
2156fa590c22SMicky Ching 
2157fa590c22SMicky Ching 	return STATUS_FAIL;
2158fa590c22SMicky Ching }
2159fa590c22SMicky Ching 
2160fa590c22SMicky Ching static u16 ms_get_l2p_tbl(struct rtsx_chip *chip, int seg_no, u16 log_off)
2161fa590c22SMicky Ching {
2162d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2163fa590c22SMicky Ching 	struct zone_entry *segment;
2164fa590c22SMicky Ching 
2165e6e1d57eSBhaktipriya Shridhar 	if (!ms_card->segment)
2166fa590c22SMicky Ching 		return 0xFFFF;
2167fa590c22SMicky Ching 
2168c86bdd47SRehas Sachdeva 	segment = &ms_card->segment[seg_no];
2169fa590c22SMicky Ching 
2170fa590c22SMicky Ching 	if (segment->l2p_table)
2171fa590c22SMicky Ching 		return segment->l2p_table[log_off];
2172fa590c22SMicky Ching 
2173fa590c22SMicky Ching 	return 0xFFFF;
2174fa590c22SMicky Ching }
2175fa590c22SMicky Ching 
2176fa590c22SMicky Ching static void ms_set_l2p_tbl(struct rtsx_chip *chip,
2177fa590c22SMicky Ching 			   int seg_no, u16 log_off, u16 phy_blk)
2178fa590c22SMicky Ching {
2179d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2180fa590c22SMicky Ching 	struct zone_entry *segment;
2181fa590c22SMicky Ching 
2182e6e1d57eSBhaktipriya Shridhar 	if (!ms_card->segment)
2183fa590c22SMicky Ching 		return;
2184fa590c22SMicky Ching 
2185c86bdd47SRehas Sachdeva 	segment = &ms_card->segment[seg_no];
2186fa590c22SMicky Ching 	if (segment->l2p_table)
2187fa590c22SMicky Ching 		segment->l2p_table[log_off] = phy_blk;
2188fa590c22SMicky Ching }
2189fa590c22SMicky Ching 
2190fa590c22SMicky Ching static void ms_set_unused_block(struct rtsx_chip *chip, u16 phy_blk)
2191fa590c22SMicky Ching {
2192d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2193fa590c22SMicky Ching 	struct zone_entry *segment;
2194fa590c22SMicky Ching 	int seg_no;
2195fa590c22SMicky Ching 
2196fa590c22SMicky Ching 	seg_no = (int)phy_blk >> 9;
2197c86bdd47SRehas Sachdeva 	segment = &ms_card->segment[seg_no];
2198fa590c22SMicky Ching 
2199fa590c22SMicky Ching 	segment->free_table[segment->set_index++] = phy_blk;
2200fa590c22SMicky Ching 	if (segment->set_index >= MS_FREE_TABLE_CNT)
2201fa590c22SMicky Ching 		segment->set_index = 0;
2202fa590c22SMicky Ching 
2203fa590c22SMicky Ching 	segment->unused_blk_cnt++;
2204fa590c22SMicky Ching }
2205fa590c22SMicky Ching 
2206fa590c22SMicky Ching static u16 ms_get_unused_block(struct rtsx_chip *chip, int seg_no)
2207fa590c22SMicky Ching {
2208d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2209fa590c22SMicky Ching 	struct zone_entry *segment;
2210fa590c22SMicky Ching 	u16 phy_blk;
2211fa590c22SMicky Ching 
2212c86bdd47SRehas Sachdeva 	segment = &ms_card->segment[seg_no];
2213fa590c22SMicky Ching 
2214fa590c22SMicky Ching 	if (segment->unused_blk_cnt <= 0)
2215fa590c22SMicky Ching 		return 0xFFFF;
2216fa590c22SMicky Ching 
2217fa590c22SMicky Ching 	phy_blk = segment->free_table[segment->get_index];
2218fa590c22SMicky Ching 	segment->free_table[segment->get_index++] = 0xFFFF;
2219fa590c22SMicky Ching 	if (segment->get_index >= MS_FREE_TABLE_CNT)
2220fa590c22SMicky Ching 		segment->get_index = 0;
2221fa590c22SMicky Ching 
2222fa590c22SMicky Ching 	segment->unused_blk_cnt--;
2223fa590c22SMicky Ching 
2224fa590c22SMicky Ching 	return phy_blk;
2225fa590c22SMicky Ching }
2226fa590c22SMicky Ching 
2227fa590c22SMicky Ching static const unsigned short ms_start_idx[] = {0, 494, 990, 1486, 1982, 2478,
2228fa590c22SMicky Ching 					      2974, 3470, 3966, 4462, 4958,
2229fa590c22SMicky Ching 					      5454, 5950, 6446, 6942, 7438,
2230fa590c22SMicky Ching 					      7934};
2231fa590c22SMicky Ching 
2232fa590c22SMicky Ching static int ms_arbitrate_l2p(struct rtsx_chip *chip, u16 phy_blk,
2233fa590c22SMicky Ching 			    u16 log_off, u8 us1, u8 us2)
2234fa590c22SMicky Ching {
2235d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2236fa590c22SMicky Ching 	struct zone_entry *segment;
2237fa590c22SMicky Ching 	int seg_no;
2238fa590c22SMicky Ching 	u16 tmp_blk;
2239fa590c22SMicky Ching 
2240fa590c22SMicky Ching 	seg_no = (int)phy_blk >> 9;
2241c86bdd47SRehas Sachdeva 	segment = &ms_card->segment[seg_no];
2242fa590c22SMicky Ching 	tmp_blk = segment->l2p_table[log_off];
2243fa590c22SMicky Ching 
2244fa590c22SMicky Ching 	if (us1 != us2) {
2245fa590c22SMicky Ching 		if (us1 == 0) {
2246fa590c22SMicky Ching 			if (!(chip->card_wp & MS_CARD))
2247fa590c22SMicky Ching 				ms_erase_block(chip, tmp_blk);
2248fa590c22SMicky Ching 
2249fa590c22SMicky Ching 			ms_set_unused_block(chip, tmp_blk);
2250fa590c22SMicky Ching 			segment->l2p_table[log_off] = phy_blk;
2251fa590c22SMicky Ching 		} else {
2252fa590c22SMicky Ching 			if (!(chip->card_wp & MS_CARD))
2253fa590c22SMicky Ching 				ms_erase_block(chip, phy_blk);
2254fa590c22SMicky Ching 
2255fa590c22SMicky Ching 			ms_set_unused_block(chip, phy_blk);
2256fa590c22SMicky Ching 		}
2257fa590c22SMicky Ching 	} else {
2258fa590c22SMicky Ching 		if (phy_blk < tmp_blk) {
2259fa590c22SMicky Ching 			if (!(chip->card_wp & MS_CARD))
2260fa590c22SMicky Ching 				ms_erase_block(chip, phy_blk);
2261fa590c22SMicky Ching 
2262fa590c22SMicky Ching 			ms_set_unused_block(chip, phy_blk);
2263fa590c22SMicky Ching 		} else {
2264fa590c22SMicky Ching 			if (!(chip->card_wp & MS_CARD))
2265fa590c22SMicky Ching 				ms_erase_block(chip, tmp_blk);
2266fa590c22SMicky Ching 
2267fa590c22SMicky Ching 			ms_set_unused_block(chip, tmp_blk);
2268fa590c22SMicky Ching 			segment->l2p_table[log_off] = phy_blk;
2269fa590c22SMicky Ching 		}
2270fa590c22SMicky Ching 	}
2271fa590c22SMicky Ching 
2272fa590c22SMicky Ching 	return STATUS_SUCCESS;
2273fa590c22SMicky Ching }
2274fa590c22SMicky Ching 
2275fa590c22SMicky Ching static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no)
2276fa590c22SMicky Ching {
2277d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2278fa590c22SMicky Ching 	struct zone_entry *segment;
2279de904bf0SQuentin Lambert 	bool defect_flag;
2280de904bf0SQuentin Lambert 	int retval, table_size, disable_cnt, i;
2281127883b8SVatika Harlalka 	u16 start, end, phy_blk, log_blk, tmp_blk, idx;
2282fa590c22SMicky Ching 	u8 extra[MS_EXTRA_SIZE], us1, us2;
2283fa590c22SMicky Ching 
22841bb90b68SAndrea della Porta 	dev_dbg(rtsx_dev(chip), "%s: %d\n", __func__, seg_no);
2285fa590c22SMicky Ching 
2286e6e1d57eSBhaktipriya Shridhar 	if (!ms_card->segment) {
2287fa590c22SMicky Ching 		retval = ms_init_l2p_tbl(chip);
22889f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
2289031366eaSJoe Perches 			return retval;
2290031366eaSJoe Perches 	}
2291fa590c22SMicky Ching 
2292fa590c22SMicky Ching 	if (ms_card->segment[seg_no].build_flag) {
2293bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "l2p table of segment %d has been built\n",
2294bf6c0d11SFabio Falzoi 			seg_no);
2295fa590c22SMicky Ching 		return STATUS_SUCCESS;
2296fa590c22SMicky Ching 	}
2297fa590c22SMicky Ching 
2298fa590c22SMicky Ching 	if (seg_no == 0)
2299fa590c22SMicky Ching 		table_size = 494;
2300fa590c22SMicky Ching 	else
2301fa590c22SMicky Ching 		table_size = 496;
2302fa590c22SMicky Ching 
2303c86bdd47SRehas Sachdeva 	segment = &ms_card->segment[seg_no];
2304fa590c22SMicky Ching 
2305e6e1d57eSBhaktipriya Shridhar 	if (!segment->l2p_table) {
230642bc47b3SKees Cook 		segment->l2p_table = vmalloc(array_size(table_size, 2));
23079f902b49SAymen Qader 		if (!segment->l2p_table)
2308031366eaSJoe Perches 			goto BUILD_FAIL;
2309031366eaSJoe Perches 	}
23109e43eed4SGustavo A. R. Silva 	memset((u8 *)(segment->l2p_table), 0xff, array_size(table_size, 2));
2311fa590c22SMicky Ching 
2312e6e1d57eSBhaktipriya Shridhar 	if (!segment->free_table) {
23139e43eed4SGustavo A. R. Silva 		segment->free_table = vmalloc(array_size(MS_FREE_TABLE_CNT, 2));
23149f902b49SAymen Qader 		if (!segment->free_table)
2315031366eaSJoe Perches 			goto BUILD_FAIL;
2316031366eaSJoe Perches 	}
23179e43eed4SGustavo A. R. Silva 	memset((u8 *)(segment->free_table), 0xff, array_size(MS_FREE_TABLE_CNT, 2));
2318fa590c22SMicky Ching 
2319fa590c22SMicky Ching 	start = (u16)seg_no << 9;
2320fa590c22SMicky Ching 	end = (u16)(seg_no + 1) << 9;
2321fa590c22SMicky Ching 
2322fa590c22SMicky Ching 	disable_cnt = segment->disable_count;
2323fa590c22SMicky Ching 
232436e32ee5SWayne Porter 	segment->get_index = 0;
232536e32ee5SWayne Porter 	segment->set_index = 0;
2326fa590c22SMicky Ching 	segment->unused_blk_cnt = 0;
2327fa590c22SMicky Ching 
2328fa590c22SMicky Ching 	for (phy_blk = start; phy_blk < end; phy_blk++) {
2329fa590c22SMicky Ching 		if (disable_cnt) {
2330de904bf0SQuentin Lambert 			defect_flag = false;
2331fa590c22SMicky Ching 			for (i = 0; i < segment->disable_count; i++) {
2332fa590c22SMicky Ching 				if (phy_blk == segment->defect_list[i]) {
2333de904bf0SQuentin Lambert 					defect_flag = true;
2334fa590c22SMicky Ching 					break;
2335fa590c22SMicky Ching 				}
2336fa590c22SMicky Ching 			}
2337fa590c22SMicky Ching 			if (defect_flag) {
2338fa590c22SMicky Ching 				disable_cnt--;
2339fa590c22SMicky Ching 				continue;
2340fa590c22SMicky Ching 			}
2341fa590c22SMicky Ching 		}
2342fa590c22SMicky Ching 
2343fa590c22SMicky Ching 		retval = ms_read_extra_data(chip, phy_blk, 0,
2344fa590c22SMicky Ching 					    extra, MS_EXTRA_SIZE);
2345fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
2346bf6c0d11SFabio Falzoi 			dev_dbg(rtsx_dev(chip), "read extra data fail\n");
2347fa590c22SMicky Ching 			ms_set_bad_block(chip, phy_blk);
2348fa590c22SMicky Ching 			continue;
2349fa590c22SMicky Ching 		}
2350fa590c22SMicky Ching 
2351fa590c22SMicky Ching 		if (seg_no == ms_card->segment_cnt - 1) {
2352fa590c22SMicky Ching 			if (!(extra[1] & NOT_TRANSLATION_TABLE)) {
2353fa590c22SMicky Ching 				if (!(chip->card_wp & MS_CARD)) {
2354fa590c22SMicky Ching 					retval = ms_erase_block(chip, phy_blk);
2355fa590c22SMicky Ching 					if (retval != STATUS_SUCCESS)
2356fa590c22SMicky Ching 						continue;
2357fa590c22SMicky Ching 					extra[2] = 0xff;
2358fa590c22SMicky Ching 					extra[3] = 0xff;
2359fa590c22SMicky Ching 				}
2360fa590c22SMicky Ching 			}
2361fa590c22SMicky Ching 		}
2362fa590c22SMicky Ching 
2363fa590c22SMicky Ching 		if (!(extra[0] & BLOCK_OK))
2364fa590c22SMicky Ching 			continue;
2365fa590c22SMicky Ching 		if (!(extra[1] & NOT_BOOT_BLOCK))
2366fa590c22SMicky Ching 			continue;
2367fa590c22SMicky Ching 		if ((extra[0] & PAGE_OK) != PAGE_OK)
2368fa590c22SMicky Ching 			continue;
2369fa590c22SMicky Ching 
2370fa590c22SMicky Ching 		log_blk = ((u16)extra[2] << 8) | extra[3];
2371fa590c22SMicky Ching 
2372fa590c22SMicky Ching 		if (log_blk == 0xFFFF) {
2373fa590c22SMicky Ching 			if (!(chip->card_wp & MS_CARD)) {
2374fa590c22SMicky Ching 				retval = ms_erase_block(chip, phy_blk);
2375fa590c22SMicky Ching 				if (retval != STATUS_SUCCESS)
2376fa590c22SMicky Ching 					continue;
2377fa590c22SMicky Ching 			}
2378fa590c22SMicky Ching 			ms_set_unused_block(chip, phy_blk);
2379fa590c22SMicky Ching 			continue;
2380fa590c22SMicky Ching 		}
2381fa590c22SMicky Ching 
23827b228bdfSBenjamin Philip 		if (log_blk < ms_start_idx[seg_no] ||
23837b228bdfSBenjamin Philip 		    log_blk >= ms_start_idx[seg_no + 1]) {
2384fa590c22SMicky Ching 			if (!(chip->card_wp & MS_CARD)) {
2385fa590c22SMicky Ching 				retval = ms_erase_block(chip, phy_blk);
2386fa590c22SMicky Ching 				if (retval != STATUS_SUCCESS)
2387fa590c22SMicky Ching 					continue;
2388fa590c22SMicky Ching 			}
2389fa590c22SMicky Ching 			ms_set_unused_block(chip, phy_blk);
2390fa590c22SMicky Ching 			continue;
2391fa590c22SMicky Ching 		}
2392fa590c22SMicky Ching 
2393127883b8SVatika Harlalka 		idx = log_blk - ms_start_idx[seg_no];
2394127883b8SVatika Harlalka 
2395127883b8SVatika Harlalka 		if (segment->l2p_table[idx] == 0xFFFF) {
2396127883b8SVatika Harlalka 			segment->l2p_table[idx] = phy_blk;
2397fa590c22SMicky Ching 			continue;
2398fa590c22SMicky Ching 		}
2399fa590c22SMicky Ching 
2400fa590c22SMicky Ching 		us1 = extra[0] & 0x10;
2401127883b8SVatika Harlalka 		tmp_blk = segment->l2p_table[idx];
2402fa590c22SMicky Ching 		retval = ms_read_extra_data(chip, tmp_blk, 0,
2403fa590c22SMicky Ching 					    extra, MS_EXTRA_SIZE);
2404fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS)
2405fa590c22SMicky Ching 			continue;
2406fa590c22SMicky Ching 		us2 = extra[0] & 0x10;
2407fa590c22SMicky Ching 
2408fa590c22SMicky Ching 		(void)ms_arbitrate_l2p(chip, phy_blk,
2409fa590c22SMicky Ching 				log_blk - ms_start_idx[seg_no], us1, us2);
2410fa590c22SMicky Ching 	}
2411fa590c22SMicky Ching 
2412fa590c22SMicky Ching 	segment->build_flag = 1;
2413fa590c22SMicky Ching 
2414bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "unused block count: %d\n",
2415bf6c0d11SFabio Falzoi 		segment->unused_blk_cnt);
2416fa590c22SMicky Ching 
2417fa590c22SMicky Ching 	/* Logical Address Confirmation Process */
2418fa590c22SMicky Ching 	if (seg_no == ms_card->segment_cnt - 1) {
2419fa590c22SMicky Ching 		if (segment->unused_blk_cnt < 2)
2420fa590c22SMicky Ching 			chip->card_wp |= MS_CARD;
2421fa590c22SMicky Ching 	} else {
2422fa590c22SMicky Ching 		if (segment->unused_blk_cnt < 1)
2423fa590c22SMicky Ching 			chip->card_wp |= MS_CARD;
2424fa590c22SMicky Ching 	}
2425fa590c22SMicky Ching 
2426fa590c22SMicky Ching 	if (chip->card_wp & MS_CARD)
2427fa590c22SMicky Ching 		return STATUS_SUCCESS;
2428fa590c22SMicky Ching 
2429fa590c22SMicky Ching 	for (log_blk = ms_start_idx[seg_no];
2430fa590c22SMicky Ching 	     log_blk < ms_start_idx[seg_no + 1]; log_blk++) {
2431127883b8SVatika Harlalka 		idx = log_blk - ms_start_idx[seg_no];
2432127883b8SVatika Harlalka 		if (segment->l2p_table[idx] == 0xFFFF) {
2433fa590c22SMicky Ching 			phy_blk = ms_get_unused_block(chip, seg_no);
2434fa590c22SMicky Ching 			if (phy_blk == 0xFFFF) {
2435fa590c22SMicky Ching 				chip->card_wp |= MS_CARD;
2436fa590c22SMicky Ching 				return STATUS_SUCCESS;
2437fa590c22SMicky Ching 			}
2438fa590c22SMicky Ching 			retval = ms_init_page(chip, phy_blk, log_blk, 0, 1);
24399f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
2440031366eaSJoe Perches 				goto BUILD_FAIL;
2441fa590c22SMicky Ching 
2442127883b8SVatika Harlalka 			segment->l2p_table[idx] = phy_blk;
2443fa590c22SMicky Ching 			if (seg_no == ms_card->segment_cnt - 1) {
2444fa590c22SMicky Ching 				if (segment->unused_blk_cnt < 2) {
2445fa590c22SMicky Ching 					chip->card_wp |= MS_CARD;
2446fa590c22SMicky Ching 					return STATUS_SUCCESS;
2447fa590c22SMicky Ching 				}
2448fa590c22SMicky Ching 			} else {
2449fa590c22SMicky Ching 				if (segment->unused_blk_cnt < 1) {
2450fa590c22SMicky Ching 					chip->card_wp |= MS_CARD;
2451fa590c22SMicky Ching 					return STATUS_SUCCESS;
2452fa590c22SMicky Ching 				}
2453fa590c22SMicky Ching 			}
2454fa590c22SMicky Ching 		}
2455fa590c22SMicky Ching 	}
2456fa590c22SMicky Ching 
2457fa590c22SMicky Ching 	/* Make boot block be the first normal block */
2458fa590c22SMicky Ching 	if (seg_no == 0) {
2459fa590c22SMicky Ching 		for (log_blk = 0; log_blk < 494; log_blk++) {
2460fa590c22SMicky Ching 			tmp_blk = segment->l2p_table[log_blk];
2461fa590c22SMicky Ching 			if (tmp_blk < ms_card->boot_block) {
2462bf6c0d11SFabio Falzoi 				dev_dbg(rtsx_dev(chip), "Boot block is not the first normal block.\n");
2463fa590c22SMicky Ching 
2464fa590c22SMicky Ching 				if (chip->card_wp & MS_CARD)
2465fa590c22SMicky Ching 					break;
2466fa590c22SMicky Ching 
2467fa590c22SMicky Ching 				phy_blk = ms_get_unused_block(chip, 0);
2468fa590c22SMicky Ching 				retval = ms_copy_page(chip, tmp_blk, phy_blk,
24699c378f14SWayne Porter 						      log_blk, 0,
24709c378f14SWayne Porter 						      ms_card->page_off + 1);
24719f902b49SAymen Qader 				if (retval != STATUS_SUCCESS)
2472031366eaSJoe Perches 					return STATUS_FAIL;
2473fa590c22SMicky Ching 
2474fa590c22SMicky Ching 				segment->l2p_table[log_blk] = phy_blk;
2475fa590c22SMicky Ching 
2476fa590c22SMicky Ching 				retval = ms_set_bad_block(chip, tmp_blk);
24779f902b49SAymen Qader 				if (retval != STATUS_SUCCESS)
2478031366eaSJoe Perches 					return STATUS_FAIL;
2479031366eaSJoe Perches 			}
2480fa590c22SMicky Ching 		}
2481fa590c22SMicky Ching 	}
2482fa590c22SMicky Ching 
2483fa590c22SMicky Ching 	return STATUS_SUCCESS;
2484fa590c22SMicky Ching 
2485fa590c22SMicky Ching BUILD_FAIL:
2486fa590c22SMicky Ching 	segment->build_flag = 0;
2487fa590c22SMicky Ching 	vfree(segment->l2p_table);
2488fa590c22SMicky Ching 	segment->l2p_table = NULL;
2489fa590c22SMicky Ching 	vfree(segment->free_table);
2490fa590c22SMicky Ching 	segment->free_table = NULL;
2491fa590c22SMicky Ching 
2492fa590c22SMicky Ching 	return STATUS_FAIL;
2493fa590c22SMicky Ching }
2494fa590c22SMicky Ching 
2495fa590c22SMicky Ching int reset_ms_card(struct rtsx_chip *chip)
2496fa590c22SMicky Ching {
2497d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
24987f7aeea7SDan Carpenter 	int seg_no = ms_card->total_block / 512 - 1;
2499fa590c22SMicky Ching 	int retval;
2500fa590c22SMicky Ching 
2501fa590c22SMicky Ching 	memset(ms_card, 0, sizeof(struct ms_info));
2502fa590c22SMicky Ching 
2503fa590c22SMicky Ching 	retval = enable_card_clock(chip, MS_CARD);
25049f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2505031366eaSJoe Perches 		return STATUS_FAIL;
2506fa590c22SMicky Ching 
2507fa590c22SMicky Ching 	retval = select_card(chip, MS_CARD);
25089f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2509031366eaSJoe Perches 		return STATUS_FAIL;
2510fa590c22SMicky Ching 
2511fa590c22SMicky Ching 	ms_card->ms_type = 0;
2512fa590c22SMicky Ching 
2513fa590c22SMicky Ching 	retval = reset_ms_pro(chip);
2514fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
2515fa590c22SMicky Ching 		if (ms_card->check_ms_flow) {
2516fa590c22SMicky Ching 			retval = reset_ms(chip);
25179f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
2518031366eaSJoe Perches 				return STATUS_FAIL;
2519fa590c22SMicky Ching 		} else {
2520031366eaSJoe Perches 			return STATUS_FAIL;
2521fa590c22SMicky Ching 		}
2522fa590c22SMicky Ching 	}
2523fa590c22SMicky Ching 
2524fa590c22SMicky Ching 	retval = ms_set_init_para(chip);
25259f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2526031366eaSJoe Perches 		return STATUS_FAIL;
2527fa590c22SMicky Ching 
2528fa590c22SMicky Ching 	if (!CHK_MSPRO(ms_card)) {
2529fa590c22SMicky Ching 		/* Build table for the last segment,
2530fa590c22SMicky Ching 		 * to check if L2P table block exists, erasing it
2531fa590c22SMicky Ching 		 */
25327f7aeea7SDan Carpenter 		retval = ms_build_l2p_tbl(chip, seg_no);
25339f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
2534031366eaSJoe Perches 			return STATUS_FAIL;
2535031366eaSJoe Perches 	}
2536fa590c22SMicky Ching 
2537bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "ms_card->ms_type = 0x%x\n", ms_card->ms_type);
2538fa590c22SMicky Ching 
2539fa590c22SMicky Ching 	return STATUS_SUCCESS;
2540fa590c22SMicky Ching }
2541fa590c22SMicky Ching 
2542fa590c22SMicky Ching static int mspro_set_rw_cmd(struct rtsx_chip *chip,
2543fa590c22SMicky Ching 			    u32 start_sec, u16 sec_cnt, u8 cmd)
2544fa590c22SMicky Ching {
2545fa590c22SMicky Ching 	int retval, i;
2546fa590c22SMicky Ching 	u8 data[8];
2547fa590c22SMicky Ching 
2548fa590c22SMicky Ching 	data[0] = cmd;
2549fa590c22SMicky Ching 	data[1] = (u8)(sec_cnt >> 8);
2550fa590c22SMicky Ching 	data[2] = (u8)sec_cnt;
2551fa590c22SMicky Ching 	data[3] = (u8)(start_sec >> 24);
2552fa590c22SMicky Ching 	data[4] = (u8)(start_sec >> 16);
2553fa590c22SMicky Ching 	data[5] = (u8)(start_sec >> 8);
2554fa590c22SMicky Ching 	data[6] = (u8)start_sec;
2555fa590c22SMicky Ching 	data[7] = 0;
2556fa590c22SMicky Ching 
2557fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
2558fa590c22SMicky Ching 		retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7,
2559fa590c22SMicky Ching 					WAIT_INT, data, 8);
2560fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
2561fa590c22SMicky Ching 			break;
2562fa590c22SMicky Ching 	}
25639f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
2564031366eaSJoe Perches 		return STATUS_FAIL;
2565fa590c22SMicky Ching 
2566fa590c22SMicky Ching 	return STATUS_SUCCESS;
2567fa590c22SMicky Ching }
2568fa590c22SMicky Ching 
2569fa590c22SMicky Ching void mspro_stop_seq_mode(struct rtsx_chip *chip)
2570fa590c22SMicky Ching {
2571d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2572fa590c22SMicky Ching 	int retval;
2573fa590c22SMicky Ching 
2574fa590c22SMicky Ching 	if (ms_card->seq_mode) {
2575fa590c22SMicky Ching 		retval = ms_switch_clock(chip);
2576fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS)
2577fa590c22SMicky Ching 			return;
2578fa590c22SMicky Ching 
2579fa590c22SMicky Ching 		ms_card->seq_mode = 0;
2580fa590c22SMicky Ching 		ms_card->total_sec_cnt = 0;
2581fa590c22SMicky Ching 		ms_send_cmd(chip, PRO_STOP, WAIT_INT);
2582fa590c22SMicky Ching 
2583fa590c22SMicky Ching 		rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH);
2584fa590c22SMicky Ching 	}
2585fa590c22SMicky Ching }
2586fa590c22SMicky Ching 
2587fa590c22SMicky Ching static inline int ms_auto_tune_clock(struct rtsx_chip *chip)
2588fa590c22SMicky Ching {
2589d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2590fa590c22SMicky Ching 	int retval;
2591fa590c22SMicky Ching 
2592fa590c22SMicky Ching 	if (chip->asic_code) {
2593fa590c22SMicky Ching 		if (ms_card->ms_clock > 30)
2594fa590c22SMicky Ching 			ms_card->ms_clock -= 20;
2595fa590c22SMicky Ching 	} else {
2596fa590c22SMicky Ching 		if (ms_card->ms_clock == CLK_80)
2597fa590c22SMicky Ching 			ms_card->ms_clock = CLK_60;
2598fa590c22SMicky Ching 		else if (ms_card->ms_clock == CLK_60)
2599fa590c22SMicky Ching 			ms_card->ms_clock = CLK_40;
2600fa590c22SMicky Ching 	}
2601fa590c22SMicky Ching 
2602fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
26039f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2604031366eaSJoe Perches 		return STATUS_FAIL;
2605fa590c22SMicky Ching 
2606fa590c22SMicky Ching 	return STATUS_SUCCESS;
2607fa590c22SMicky Ching }
2608fa590c22SMicky Ching 
2609fa590c22SMicky Ching static int mspro_rw_multi_sector(struct scsi_cmnd *srb,
2610fa590c22SMicky Ching 				 struct rtsx_chip *chip, u32 start_sector,
2611fa590c22SMicky Ching 				 u16 sector_cnt)
2612fa590c22SMicky Ching {
2613d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
261411201769SQuentin Lambert 	bool mode_2k = false;
261511201769SQuentin Lambert 	int retval;
2616fa590c22SMicky Ching 	u16 count;
2617fa590c22SMicky Ching 	u8 val, trans_mode, rw_tpc, rw_cmd;
2618fa590c22SMicky Ching 
2619fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
2620fa590c22SMicky Ching 
2621fa590c22SMicky Ching 	ms_card->cleanup_counter = 0;
2622fa590c22SMicky Ching 
2623fa590c22SMicky Ching 	if (CHK_MSHG(ms_card)) {
2624fa590c22SMicky Ching 		if ((start_sector % 4) || (sector_cnt % 4)) {
2625fa590c22SMicky Ching 			if (srb->sc_data_direction == DMA_FROM_DEVICE) {
2626fa590c22SMicky Ching 				rw_tpc = PRO_READ_LONG_DATA;
2627fa590c22SMicky Ching 				rw_cmd = PRO_READ_DATA;
2628fa590c22SMicky Ching 			} else {
2629fa590c22SMicky Ching 				rw_tpc = PRO_WRITE_LONG_DATA;
2630fa590c22SMicky Ching 				rw_cmd = PRO_WRITE_DATA;
2631fa590c22SMicky Ching 			}
2632fa590c22SMicky Ching 		} else {
2633fa590c22SMicky Ching 			if (srb->sc_data_direction == DMA_FROM_DEVICE) {
2634fa590c22SMicky Ching 				rw_tpc = PRO_READ_QUAD_DATA;
2635fa590c22SMicky Ching 				rw_cmd = PRO_READ_2K_DATA;
2636fa590c22SMicky Ching 			} else {
2637fa590c22SMicky Ching 				rw_tpc = PRO_WRITE_QUAD_DATA;
2638fa590c22SMicky Ching 				rw_cmd = PRO_WRITE_2K_DATA;
2639fa590c22SMicky Ching 			}
264011201769SQuentin Lambert 			mode_2k = true;
2641fa590c22SMicky Ching 		}
2642fa590c22SMicky Ching 	} else {
2643fa590c22SMicky Ching 		if (srb->sc_data_direction == DMA_FROM_DEVICE) {
2644fa590c22SMicky Ching 			rw_tpc = PRO_READ_LONG_DATA;
2645fa590c22SMicky Ching 			rw_cmd = PRO_READ_DATA;
2646fa590c22SMicky Ching 		} else {
2647fa590c22SMicky Ching 			rw_tpc = PRO_WRITE_LONG_DATA;
2648fa590c22SMicky Ching 			rw_cmd = PRO_WRITE_DATA;
2649fa590c22SMicky Ching 		}
2650fa590c22SMicky Ching 	}
2651fa590c22SMicky Ching 
2652fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
26539f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2654031366eaSJoe Perches 		return STATUS_FAIL;
2655fa590c22SMicky Ching 
2656fa590c22SMicky Ching 	if (srb->sc_data_direction == DMA_FROM_DEVICE)
2657fa590c22SMicky Ching 		trans_mode = MS_TM_AUTO_READ;
2658fa590c22SMicky Ching 	else
2659fa590c22SMicky Ching 		trans_mode = MS_TM_AUTO_WRITE;
2660fa590c22SMicky Ching 
26618ee775f9SJoe Perches 	retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
26629f902b49SAymen Qader 	if (retval)
26638ee775f9SJoe Perches 		return retval;
2664fa590c22SMicky Ching 
2665fa590c22SMicky Ching 	if (ms_card->seq_mode) {
26667b228bdfSBenjamin Philip 		if (ms_card->pre_dir != srb->sc_data_direction ||
266725ccf0b0SWayne Porter 		    ((ms_card->pre_sec_addr + ms_card->pre_sec_cnt) !=
266825ccf0b0SWayne Porter 		     start_sector) ||
266925ccf0b0SWayne Porter 		    (mode_2k && (ms_card->seq_mode & MODE_512_SEQ)) ||
267025ccf0b0SWayne Porter 		    (!mode_2k && (ms_card->seq_mode & MODE_2K_SEQ)) ||
267125ccf0b0SWayne Porter 		    !(val & MS_INT_BREQ) ||
267225ccf0b0SWayne Porter 		    ((ms_card->total_sec_cnt + sector_cnt) > 0xFE00)) {
2673fa590c22SMicky Ching 			ms_card->seq_mode = 0;
2674fa590c22SMicky Ching 			ms_card->total_sec_cnt = 0;
2675fa590c22SMicky Ching 			if (val & MS_INT_BREQ) {
2676fa590c22SMicky Ching 				retval = ms_send_cmd(chip, PRO_STOP, WAIT_INT);
26779f902b49SAymen Qader 				if (retval != STATUS_SUCCESS)
2678031366eaSJoe Perches 					return STATUS_FAIL;
2679fa590c22SMicky Ching 
268025ccf0b0SWayne Porter 				rtsx_write_register(chip, RBCTL, RB_FLUSH,
268125ccf0b0SWayne Porter 						    RB_FLUSH);
2682fa590c22SMicky Ching 			}
2683fa590c22SMicky Ching 		}
2684fa590c22SMicky Ching 	}
2685fa590c22SMicky Ching 
2686fa590c22SMicky Ching 	if (!ms_card->seq_mode) {
2687fa590c22SMicky Ching 		ms_card->total_sec_cnt = 0;
2688fa590c22SMicky Ching 		if (sector_cnt >= SEQ_START_CRITERIA) {
2689fa590c22SMicky Ching 			if ((ms_card->capacity - start_sector) > 0xFE00)
2690fa590c22SMicky Ching 				count = 0xFE00;
2691fa590c22SMicky Ching 			else
2692fa590c22SMicky Ching 				count = (u16)(ms_card->capacity - start_sector);
2693fa590c22SMicky Ching 
2694fa590c22SMicky Ching 			if (count > sector_cnt) {
2695fa590c22SMicky Ching 				if (mode_2k)
2696b0ef3ed4SJiayi Ye 					ms_card->seq_mode = MODE_2K_SEQ;
2697fa590c22SMicky Ching 				else
2698b0ef3ed4SJiayi Ye 					ms_card->seq_mode = MODE_512_SEQ;
2699fa590c22SMicky Ching 			}
2700fa590c22SMicky Ching 		} else {
2701fa590c22SMicky Ching 			count = sector_cnt;
2702fa590c22SMicky Ching 		}
2703fa590c22SMicky Ching 		retval = mspro_set_rw_cmd(chip, start_sector, count, rw_cmd);
2704fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
2705fa590c22SMicky Ching 			ms_card->seq_mode = 0;
2706031366eaSJoe Perches 			return STATUS_FAIL;
2707fa590c22SMicky Ching 		}
2708fa590c22SMicky Ching 	}
2709fa590c22SMicky Ching 
2710fa590c22SMicky Ching 	retval = ms_transfer_data(chip, trans_mode, rw_tpc, sector_cnt,
2711fa590c22SMicky Ching 				  WAIT_INT, mode_2k, scsi_sg_count(srb),
2712fa590c22SMicky Ching 				  scsi_sglist(srb), scsi_bufflen(srb));
2713fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
2714fa590c22SMicky Ching 		ms_card->seq_mode = 0;
2715fa590c22SMicky Ching 		rtsx_read_register(chip, MS_TRANS_CFG, &val);
2716fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
2717fa590c22SMicky Ching 
2718fa590c22SMicky Ching 		if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
2719fa590c22SMicky Ching 			chip->rw_need_retry = 0;
27202d772591SGaurav Pathak 			dev_dbg(rtsx_dev(chip), "No card exist, exit %s\n",
27212d772591SGaurav Pathak 				__func__);
2722031366eaSJoe Perches 			return STATUS_FAIL;
2723fa590c22SMicky Ching 		}
2724fa590c22SMicky Ching 
2725fa590c22SMicky Ching 		if (val & MS_INT_BREQ)
2726fa590c22SMicky Ching 			ms_send_cmd(chip, PRO_STOP, WAIT_INT);
2727fa590c22SMicky Ching 
2728fa590c22SMicky Ching 		if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
2729bf6c0d11SFabio Falzoi 			dev_dbg(rtsx_dev(chip), "MSPro CRC error, tune clock!\n");
2730fa590c22SMicky Ching 			chip->rw_need_retry = 1;
2731fa590c22SMicky Ching 			ms_auto_tune_clock(chip);
2732fa590c22SMicky Ching 		}
2733fa590c22SMicky Ching 
2734031366eaSJoe Perches 		return retval;
2735fa590c22SMicky Ching 	}
2736fa590c22SMicky Ching 
2737fa590c22SMicky Ching 	if (ms_card->seq_mode) {
2738fa590c22SMicky Ching 		ms_card->pre_sec_addr = start_sector;
2739fa590c22SMicky Ching 		ms_card->pre_sec_cnt = sector_cnt;
2740fa590c22SMicky Ching 		ms_card->pre_dir = srb->sc_data_direction;
2741fa590c22SMicky Ching 		ms_card->total_sec_cnt += sector_cnt;
2742fa590c22SMicky Ching 	}
2743fa590c22SMicky Ching 
2744fa590c22SMicky Ching 	return STATUS_SUCCESS;
2745fa590c22SMicky Ching }
2746fa590c22SMicky Ching 
2747fa590c22SMicky Ching static int mspro_read_format_progress(struct rtsx_chip *chip,
2748fa590c22SMicky Ching 				      const int short_data_len)
2749fa590c22SMicky Ching {
2750d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2751fa590c22SMicky Ching 	int retval, i;
2752fa590c22SMicky Ching 	u32 total_progress, cur_progress;
2753fa590c22SMicky Ching 	u8 cnt, tmp;
2754fa590c22SMicky Ching 	u8 data[8];
2755fa590c22SMicky Ching 
27562d772591SGaurav Pathak 	dev_dbg(rtsx_dev(chip), "%s, short_data_len = %d\n", __func__,
2757fa590c22SMicky Ching 		short_data_len);
2758fa590c22SMicky Ching 
2759fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
2760fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
2761fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2762031366eaSJoe Perches 		return STATUS_FAIL;
2763fa590c22SMicky Ching 	}
2764fa590c22SMicky Ching 
2765fa590c22SMicky Ching 	retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp);
2766fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
2767fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2768031366eaSJoe Perches 		return STATUS_FAIL;
2769fa590c22SMicky Ching 	}
2770fa590c22SMicky Ching 
2771fa590c22SMicky Ching 	if (!(tmp & MS_INT_BREQ)) {
277225ccf0b0SWayne Porter 		if ((tmp & (MS_INT_CED | MS_INT_BREQ | MS_INT_CMDNK |
277325ccf0b0SWayne Porter 			    MS_INT_ERR)) == MS_INT_CED) {
2774fa590c22SMicky Ching 			ms_card->format_status = FORMAT_SUCCESS;
2775fa590c22SMicky Ching 			return STATUS_SUCCESS;
2776fa590c22SMicky Ching 		}
2777fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2778031366eaSJoe Perches 		return STATUS_FAIL;
2779fa590c22SMicky Ching 	}
2780fa590c22SMicky Ching 
2781fa590c22SMicky Ching 	if (short_data_len >= 256)
2782fa590c22SMicky Ching 		cnt = 0;
2783fa590c22SMicky Ching 	else
2784fa590c22SMicky Ching 		cnt = (u8)short_data_len;
2785fa590c22SMicky Ching 
2786fa590c22SMicky Ching 	retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT,
2787fa590c22SMicky Ching 				     MS_NO_CHECK_INT);
2788fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
2789fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2790031366eaSJoe Perches 		return STATUS_FAIL;
2791fa590c22SMicky Ching 	}
2792fa590c22SMicky Ching 
2793fa590c22SMicky Ching 	retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, cnt, WAIT_INT,
2794fa590c22SMicky Ching 			       data, 8);
2795fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
2796fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2797031366eaSJoe Perches 		return STATUS_FAIL;
2798fa590c22SMicky Ching 	}
2799fa590c22SMicky Ching 
2800fa590c22SMicky Ching 	total_progress = (data[0] << 24) | (data[1] << 16) |
2801fa590c22SMicky Ching 		(data[2] << 8) | data[3];
2802fa590c22SMicky Ching 	cur_progress = (data[4] << 24) | (data[5] << 16) |
2803fa590c22SMicky Ching 		(data[6] << 8) | data[7];
2804fa590c22SMicky Ching 
2805bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "total_progress = %d, cur_progress = %d\n",
2806fa590c22SMicky Ching 		total_progress, cur_progress);
2807fa590c22SMicky Ching 
2808fa590c22SMicky Ching 	if (total_progress == 0) {
2809fa590c22SMicky Ching 		ms_card->progress = 0;
2810fa590c22SMicky Ching 	} else {
2811fa590c22SMicky Ching 		u64 ulltmp = (u64)cur_progress * (u64)65535;
28123c97fbbeSTapasweni Pathak 
2813fa590c22SMicky Ching 		do_div(ulltmp, total_progress);
2814fa590c22SMicky Ching 		ms_card->progress = (u16)ulltmp;
2815fa590c22SMicky Ching 	}
2816bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "progress = %d\n", ms_card->progress);
2817fa590c22SMicky Ching 
2818fa590c22SMicky Ching 	for (i = 0; i < 5000; i++) {
2819fa590c22SMicky Ching 		retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp);
2820fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
2821fa590c22SMicky Ching 			ms_card->format_status = FORMAT_FAIL;
2822031366eaSJoe Perches 			return STATUS_FAIL;
2823fa590c22SMicky Ching 		}
2824fa590c22SMicky Ching 		if (tmp & (MS_INT_CED | MS_INT_CMDNK |
2825fa590c22SMicky Ching 				MS_INT_BREQ | MS_INT_ERR))
2826fa590c22SMicky Ching 			break;
2827fa590c22SMicky Ching 
2828fa590c22SMicky Ching 		wait_timeout(1);
2829fa590c22SMicky Ching 	}
2830fa590c22SMicky Ching 
2831fa590c22SMicky Ching 	retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, 0);
2832fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
2833fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2834031366eaSJoe Perches 		return STATUS_FAIL;
2835fa590c22SMicky Ching 	}
2836fa590c22SMicky Ching 
2837fa590c22SMicky Ching 	if (i == 5000) {
2838fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2839031366eaSJoe Perches 		return STATUS_FAIL;
2840fa590c22SMicky Ching 	}
2841fa590c22SMicky Ching 
2842fa590c22SMicky Ching 	if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) {
2843fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2844031366eaSJoe Perches 		return STATUS_FAIL;
2845fa590c22SMicky Ching 	}
2846fa590c22SMicky Ching 
2847fa590c22SMicky Ching 	if (tmp & MS_INT_CED) {
2848fa590c22SMicky Ching 		ms_card->format_status = FORMAT_SUCCESS;
2849fa590c22SMicky Ching 		ms_card->pro_under_formatting = 0;
2850fa590c22SMicky Ching 	} else if (tmp & MS_INT_BREQ) {
2851fa590c22SMicky Ching 		ms_card->format_status = FORMAT_IN_PROGRESS;
2852fa590c22SMicky Ching 	} else {
2853fa590c22SMicky Ching 		ms_card->format_status = FORMAT_FAIL;
2854fa590c22SMicky Ching 		ms_card->pro_under_formatting = 0;
2855031366eaSJoe Perches 		return STATUS_FAIL;
2856fa590c22SMicky Ching 	}
2857fa590c22SMicky Ching 
2858fa590c22SMicky Ching 	return STATUS_SUCCESS;
2859fa590c22SMicky Ching }
2860fa590c22SMicky Ching 
2861fa590c22SMicky Ching void mspro_polling_format_status(struct rtsx_chip *chip)
2862fa590c22SMicky Ching {
2863d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2864fa590c22SMicky Ching 	int i;
2865fa590c22SMicky Ching 
2866fa590c22SMicky Ching 	if (ms_card->pro_under_formatting &&
2867fa590c22SMicky Ching 	    (rtsx_get_stat(chip) != RTSX_STAT_SS)) {
2868fa590c22SMicky Ching 		rtsx_set_stat(chip, RTSX_STAT_RUN);
2869fa590c22SMicky Ching 
2870fa590c22SMicky Ching 		for (i = 0; i < 65535; i++) {
2871fa590c22SMicky Ching 			mspro_read_format_progress(chip, MS_SHORT_DATA_LEN);
2872fa590c22SMicky Ching 			if (ms_card->format_status != FORMAT_IN_PROGRESS)
2873fa590c22SMicky Ching 				break;
2874fa590c22SMicky Ching 		}
2875fa590c22SMicky Ching 	}
2876fa590c22SMicky Ching }
2877fa590c22SMicky Ching 
2878fa590c22SMicky Ching int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip,
287911201769SQuentin Lambert 		 int short_data_len, bool quick_format)
2880fa590c22SMicky Ching {
2881d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2882fa590c22SMicky Ching 	int retval, i;
2883fa590c22SMicky Ching 	u8 buf[8], tmp;
2884fa590c22SMicky Ching 	u16 para;
2885fa590c22SMicky Ching 
2886fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
28879f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2888031366eaSJoe Perches 		return STATUS_FAIL;
2889fa590c22SMicky Ching 
28906e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, PRO_TPC_PARM, 0x01);
28919f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2892031366eaSJoe Perches 		return STATUS_FAIL;
2893fa590c22SMicky Ching 
2894fa590c22SMicky Ching 	memset(buf, 0, 2);
2895fa590c22SMicky Ching 	switch (short_data_len) {
2896fa590c22SMicky Ching 	case 32:
2897fa590c22SMicky Ching 		buf[0] = 0;
2898fa590c22SMicky Ching 		break;
2899fa590c22SMicky Ching 	case 64:
2900fa590c22SMicky Ching 		buf[0] = 1;
2901fa590c22SMicky Ching 		break;
2902fa590c22SMicky Ching 	case 128:
2903fa590c22SMicky Ching 		buf[0] = 2;
2904fa590c22SMicky Ching 		break;
2905fa590c22SMicky Ching 	case 256:
2906fa590c22SMicky Ching 	default:
2907fa590c22SMicky Ching 		buf[0] = 3;
2908fa590c22SMicky Ching 		break;
2909fa590c22SMicky Ching 	}
2910fa590c22SMicky Ching 
2911fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
2912fa590c22SMicky Ching 		retval = ms_write_bytes(chip, PRO_WRITE_REG, 1,
2913fa590c22SMicky Ching 					NO_WAIT_INT, buf, 2);
2914fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
2915fa590c22SMicky Ching 			break;
2916fa590c22SMicky Ching 	}
29179f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
2918031366eaSJoe Perches 		return STATUS_FAIL;
2919fa590c22SMicky Ching 
2920fa590c22SMicky Ching 	if (quick_format)
2921fa590c22SMicky Ching 		para = 0x0000;
2922fa590c22SMicky Ching 	else
2923fa590c22SMicky Ching 		para = 0x0001;
2924fa590c22SMicky Ching 
2925fa590c22SMicky Ching 	retval = mspro_set_rw_cmd(chip, 0, para, PRO_FORMAT);
29269f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2927031366eaSJoe Perches 		return STATUS_FAIL;
2928fa590c22SMicky Ching 
29298ee775f9SJoe Perches 	retval = rtsx_read_register(chip, MS_TRANS_CFG, &tmp);
29309f902b49SAymen Qader 	if (retval)
29318ee775f9SJoe Perches 		return retval;
2932fa590c22SMicky Ching 
29339f902b49SAymen Qader 	if (tmp & (MS_INT_CMDNK | MS_INT_ERR))
2934031366eaSJoe Perches 		return STATUS_FAIL;
2935fa590c22SMicky Ching 
2936fa590c22SMicky Ching 	if ((tmp & (MS_INT_BREQ | MS_INT_CED)) == MS_INT_BREQ) {
2937fa590c22SMicky Ching 		ms_card->pro_under_formatting = 1;
2938fa590c22SMicky Ching 		ms_card->progress = 0;
2939fa590c22SMicky Ching 		ms_card->format_status = FORMAT_IN_PROGRESS;
2940fa590c22SMicky Ching 		return STATUS_SUCCESS;
2941fa590c22SMicky Ching 	}
2942fa590c22SMicky Ching 
2943fa590c22SMicky Ching 	if (tmp & MS_INT_CED) {
2944fa590c22SMicky Ching 		ms_card->pro_under_formatting = 0;
2945fa590c22SMicky Ching 		ms_card->progress = 0;
2946fa590c22SMicky Ching 		ms_card->format_status = FORMAT_SUCCESS;
2947fa590c22SMicky Ching 		set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_NO_SENSE);
2948fa590c22SMicky Ching 		return STATUS_SUCCESS;
2949fa590c22SMicky Ching 	}
2950fa590c22SMicky Ching 
2951031366eaSJoe Perches 	return STATUS_FAIL;
2952fa590c22SMicky Ching }
2953fa590c22SMicky Ching 
2954fa590c22SMicky Ching static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk,
2955fa590c22SMicky Ching 				  u16 log_blk, u8 start_page, u8 end_page,
2956fa590c22SMicky Ching 				  u8 *buf, unsigned int *index,
2957fa590c22SMicky Ching 				  unsigned int *offset)
2958fa590c22SMicky Ching {
2959d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
2960fa590c22SMicky Ching 	int retval, i;
2961fa590c22SMicky Ching 	u8 extra[MS_EXTRA_SIZE], page_addr, val, trans_cfg, data[6];
2962fa590c22SMicky Ching 	u8 *ptr;
2963fa590c22SMicky Ching 
2964fa590c22SMicky Ching 	retval = ms_read_extra_data(chip, phy_blk, start_page,
2965fa590c22SMicky Ching 				    extra, MS_EXTRA_SIZE);
2966fa590c22SMicky Ching 	if (retval == STATUS_SUCCESS) {
2967fa590c22SMicky Ching 		if ((extra[1] & 0x30) != 0x30) {
2968fa590c22SMicky Ching 			ms_set_err_code(chip, MS_FLASH_READ_ERROR);
2969031366eaSJoe Perches 			return STATUS_FAIL;
2970fa590c22SMicky Ching 		}
2971fa590c22SMicky Ching 	}
2972fa590c22SMicky Ching 
29736e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
29746e653e9cSGabriela Bittencourt 				    SYSTEM_PARAM, 6);
29759f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
2976031366eaSJoe Perches 		return STATUS_FAIL;
2977fa590c22SMicky Ching 
2978fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card))
2979fa590c22SMicky Ching 		data[0] = 0x88;
2980fa590c22SMicky Ching 	else
2981fa590c22SMicky Ching 		data[0] = 0x80;
2982fa590c22SMicky Ching 
2983fa590c22SMicky Ching 	data[1] = 0;
2984fa590c22SMicky Ching 	data[2] = (u8)(phy_blk >> 8);
2985fa590c22SMicky Ching 	data[3] = (u8)phy_blk;
2986fa590c22SMicky Ching 	data[4] = 0;
2987fa590c22SMicky Ching 	data[5] = start_page;
2988fa590c22SMicky Ching 
2989fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
2990fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
2991fa590c22SMicky Ching 					data, 6);
2992fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
2993fa590c22SMicky Ching 			break;
2994fa590c22SMicky Ching 	}
29959f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
2996031366eaSJoe Perches 		return STATUS_FAIL;
2997fa590c22SMicky Ching 
2998fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
2999fa590c22SMicky Ching 
3000fa590c22SMicky Ching 	retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT);
30019f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3002031366eaSJoe Perches 		return STATUS_FAIL;
3003fa590c22SMicky Ching 
3004fa590c22SMicky Ching 	ptr = buf;
3005fa590c22SMicky Ching 
3006fa590c22SMicky Ching 	for (page_addr = start_page; page_addr < end_page; page_addr++) {
3007fa590c22SMicky Ching 		ms_set_err_code(chip, MS_NO_ERROR);
3008fa590c22SMicky Ching 
3009fa590c22SMicky Ching 		if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
3010fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_CARD);
3011031366eaSJoe Perches 			return STATUS_FAIL;
3012fa590c22SMicky Ching 		}
3013fa590c22SMicky Ching 
3014fa590c22SMicky Ching 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
30159f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3016031366eaSJoe Perches 			return STATUS_FAIL;
3017fa590c22SMicky Ching 
3018fa590c22SMicky Ching 		if (val & INT_REG_CMDNK) {
3019fa590c22SMicky Ching 			ms_set_err_code(chip, MS_CMD_NK);
3020031366eaSJoe Perches 			return STATUS_FAIL;
3021fa590c22SMicky Ching 		}
3022fa590c22SMicky Ching 		if (val & INT_REG_ERR) {
3023fa590c22SMicky Ching 			if (val & INT_REG_BREQ) {
3024fa590c22SMicky Ching 				retval = ms_read_status_reg(chip);
3025fa590c22SMicky Ching 				if (retval != STATUS_SUCCESS) {
3026fa590c22SMicky Ching 					if (!(chip->card_wp & MS_CARD)) {
3027fa590c22SMicky Ching 						reset_ms(chip);
302825ccf0b0SWayne Porter 						ms_set_page_status
30296e653e9cSGabriela Bittencourt 							(log_blk, set_PS_NG,
303025ccf0b0SWayne Porter 							 extra,
303125ccf0b0SWayne Porter 							 MS_EXTRA_SIZE);
303225ccf0b0SWayne Porter 						ms_write_extra_data
303325ccf0b0SWayne Porter 							(chip, phy_blk,
303425ccf0b0SWayne Porter 							 page_addr, extra,
303525ccf0b0SWayne Porter 							 MS_EXTRA_SIZE);
3036fa590c22SMicky Ching 					}
303725ccf0b0SWayne Porter 					ms_set_err_code(chip,
303825ccf0b0SWayne Porter 							MS_FLASH_READ_ERROR);
3039031366eaSJoe Perches 					return STATUS_FAIL;
3040fa590c22SMicky Ching 				}
3041fa590c22SMicky Ching 			} else {
3042fa590c22SMicky Ching 				ms_set_err_code(chip, MS_FLASH_READ_ERROR);
3043031366eaSJoe Perches 				return STATUS_FAIL;
3044fa590c22SMicky Ching 			}
3045fa590c22SMicky Ching 		} else {
3046fa590c22SMicky Ching 			if (!(val & INT_REG_BREQ)) {
3047fa590c22SMicky Ching 				ms_set_err_code(chip, MS_BREQ_ERROR);
3048031366eaSJoe Perches 				return STATUS_FAIL;
3049fa590c22SMicky Ching 			}
3050fa590c22SMicky Ching 		}
3051fa590c22SMicky Ching 
3052fa590c22SMicky Ching 		if (page_addr == (end_page - 1)) {
3053fa590c22SMicky Ching 			if (!(val & INT_REG_CED)) {
3054fa590c22SMicky Ching 				retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT);
30559f902b49SAymen Qader 				if (retval != STATUS_SUCCESS)
3056031366eaSJoe Perches 					return STATUS_FAIL;
3057031366eaSJoe Perches 			}
3058fa590c22SMicky Ching 
3059fa590c22SMicky Ching 			retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT,
3060fa590c22SMicky Ching 					       &val, 1);
30619f902b49SAymen Qader 			if (retval != STATUS_SUCCESS)
3062031366eaSJoe Perches 				return STATUS_FAIL;
3063fa590c22SMicky Ching 
3064fa590c22SMicky Ching 			if (!(val & INT_REG_CED)) {
3065fa590c22SMicky Ching 				ms_set_err_code(chip, MS_FLASH_READ_ERROR);
3066031366eaSJoe Perches 				return STATUS_FAIL;
3067fa590c22SMicky Ching 			}
3068fa590c22SMicky Ching 
3069fa590c22SMicky Ching 			trans_cfg = NO_WAIT_INT;
3070fa590c22SMicky Ching 		} else {
3071fa590c22SMicky Ching 			trans_cfg = WAIT_INT;
3072fa590c22SMicky Ching 		}
3073fa590c22SMicky Ching 
3074fa590c22SMicky Ching 		rtsx_init_cmd(chip);
3075fa590c22SMicky Ching 
3076fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, READ_PAGE_DATA);
3077fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG,
3078fa590c22SMicky Ching 			     0xFF, trans_cfg);
3079fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
3080fa590c22SMicky Ching 			     0x01, RING_BUFFER);
3081fa590c22SMicky Ching 
3082fa590c22SMicky Ching 		trans_dma_enable(DMA_FROM_DEVICE, chip, 512, DMA_512);
3083fa590c22SMicky Ching 
3084fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
3085fa590c22SMicky Ching 			     MS_TRANSFER_START |  MS_TM_NORMAL_READ);
3086fa590c22SMicky Ching 		rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
3087fa590c22SMicky Ching 			     MS_TRANSFER_END, MS_TRANSFER_END);
3088fa590c22SMicky Ching 
3089fa590c22SMicky Ching 		rtsx_send_cmd_no_wait(chip);
3090fa590c22SMicky Ching 
30919c378f14SWayne Porter 		retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr, 512,
30929c378f14SWayne Porter 						    scsi_sg_count(chip->srb),
30939c378f14SWayne Porter 						    index, offset,
30949c378f14SWayne Porter 						    DMA_FROM_DEVICE,
3095fa590c22SMicky Ching 						    chip->ms_timeout);
3096fa590c22SMicky Ching 		if (retval < 0) {
3097fa590c22SMicky Ching 			if (retval == -ETIMEDOUT) {
3098fa590c22SMicky Ching 				ms_set_err_code(chip, MS_TO_ERROR);
3099fa590c22SMicky Ching 				rtsx_clear_ms_error(chip);
3100031366eaSJoe Perches 				return STATUS_TIMEDOUT;
3101fa590c22SMicky Ching 			}
3102fa590c22SMicky Ching 
3103fa590c22SMicky Ching 			retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
3104fa590c22SMicky Ching 			if (retval != STATUS_SUCCESS) {
3105fa590c22SMicky Ching 				ms_set_err_code(chip, MS_TO_ERROR);
3106fa590c22SMicky Ching 				rtsx_clear_ms_error(chip);
3107031366eaSJoe Perches 				return STATUS_TIMEDOUT;
3108fa590c22SMicky Ching 			}
3109fa590c22SMicky Ching 			if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) {
3110fa590c22SMicky Ching 				ms_set_err_code(chip, MS_CRC16_ERROR);
3111fa590c22SMicky Ching 				rtsx_clear_ms_error(chip);
3112031366eaSJoe Perches 				return STATUS_FAIL;
3113fa590c22SMicky Ching 			}
3114fa590c22SMicky Ching 		}
3115fa590c22SMicky Ching 
3116fa590c22SMicky Ching 		if (scsi_sg_count(chip->srb) == 0)
3117fa590c22SMicky Ching 			ptr += 512;
3118fa590c22SMicky Ching 	}
3119fa590c22SMicky Ching 
3120fa590c22SMicky Ching 	return STATUS_SUCCESS;
3121fa590c22SMicky Ching }
3122fa590c22SMicky Ching 
3123fa590c22SMicky Ching static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk,
3124fa590c22SMicky Ching 				   u16 new_blk, u16 log_blk, u8 start_page,
3125fa590c22SMicky Ching 				u8 end_page, u8 *buf, unsigned int *index,
3126fa590c22SMicky Ching 				unsigned int *offset)
3127fa590c22SMicky Ching {
3128d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3129fa590c22SMicky Ching 	int retval, i;
3130fa590c22SMicky Ching 	u8 page_addr, val, data[16];
3131fa590c22SMicky Ching 	u8 *ptr;
3132fa590c22SMicky Ching 
3133fa590c22SMicky Ching 	if (!start_page) {
31346e653e9cSGabriela Bittencourt 		retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
31356e653e9cSGabriela Bittencourt 					    SYSTEM_PARAM, 7);
31369f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3137031366eaSJoe Perches 			return STATUS_FAIL;
3138fa590c22SMicky Ching 
3139fa590c22SMicky Ching 		if (CHK_MS4BIT(ms_card))
3140fa590c22SMicky Ching 			data[0] = 0x88;
3141fa590c22SMicky Ching 		else
3142fa590c22SMicky Ching 			data[0] = 0x80;
3143fa590c22SMicky Ching 
3144fa590c22SMicky Ching 		data[1] = 0;
3145fa590c22SMicky Ching 		data[2] = (u8)(old_blk >> 8);
3146fa590c22SMicky Ching 		data[3] = (u8)old_blk;
3147fa590c22SMicky Ching 		data[4] = 0x80;
3148fa590c22SMicky Ching 		data[5] = 0;
3149fa590c22SMicky Ching 		data[6] = 0xEF;
3150fa590c22SMicky Ching 		data[7] = 0xFF;
3151fa590c22SMicky Ching 
3152fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT,
3153fa590c22SMicky Ching 					data, 8);
31549f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3155031366eaSJoe Perches 			return STATUS_FAIL;
3156fa590c22SMicky Ching 
3157fa590c22SMicky Ching 		retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
31589f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3159031366eaSJoe Perches 			return STATUS_FAIL;
3160fa590c22SMicky Ching 
3161fa590c22SMicky Ching 		ms_set_err_code(chip, MS_NO_ERROR);
3162fa590c22SMicky Ching 		retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1,
3163fa590c22SMicky Ching 					 NO_WAIT_INT);
31649f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3165031366eaSJoe Perches 			return STATUS_FAIL;
3166031366eaSJoe Perches 	}
3167fa590c22SMicky Ching 
31686e653e9cSGabriela Bittencourt 	retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE,
31696e653e9cSGabriela Bittencourt 				    SYSTEM_PARAM, (6 + MS_EXTRA_SIZE));
31709f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3171031366eaSJoe Perches 		return STATUS_FAIL;
3172fa590c22SMicky Ching 
3173fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
3174fa590c22SMicky Ching 
3175fa590c22SMicky Ching 	if (CHK_MS4BIT(ms_card))
3176fa590c22SMicky Ching 		data[0] = 0x88;
3177fa590c22SMicky Ching 	else
3178fa590c22SMicky Ching 		data[0] = 0x80;
3179fa590c22SMicky Ching 
3180fa590c22SMicky Ching 	data[1] = 0;
3181fa590c22SMicky Ching 	data[2] = (u8)(new_blk >> 8);
3182fa590c22SMicky Ching 	data[3] = (u8)new_blk;
3183fa590c22SMicky Ching 	if ((end_page - start_page) == 1)
3184fa590c22SMicky Ching 		data[4] = 0x20;
3185fa590c22SMicky Ching 	else
3186fa590c22SMicky Ching 		data[4] = 0;
3187fa590c22SMicky Ching 
3188fa590c22SMicky Ching 	data[5] = start_page;
3189fa590c22SMicky Ching 	data[6] = 0xF8;
3190fa590c22SMicky Ching 	data[7] = 0xFF;
3191fa590c22SMicky Ching 	data[8] = (u8)(log_blk >> 8);
3192fa590c22SMicky Ching 	data[9] = (u8)log_blk;
3193fa590c22SMicky Ching 
3194fa590c22SMicky Ching 	for (i = 0x0A; i < 0x10; i++)
3195fa590c22SMicky Ching 		data[i] = 0xFF;
3196fa590c22SMicky Ching 
3197fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
3198fa590c22SMicky Ching 		retval = ms_write_bytes(chip, WRITE_REG, 6 + MS_EXTRA_SIZE,
3199fa590c22SMicky Ching 					NO_WAIT_INT, data, 16);
3200fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
3201fa590c22SMicky Ching 			break;
3202fa590c22SMicky Ching 	}
32039f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
3204031366eaSJoe Perches 		return STATUS_FAIL;
3205fa590c22SMicky Ching 
3206fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
3207fa590c22SMicky Ching 		retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT);
3208fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
3209fa590c22SMicky Ching 			break;
3210fa590c22SMicky Ching 	}
32119f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
3212031366eaSJoe Perches 		return STATUS_FAIL;
3213fa590c22SMicky Ching 
3214fa590c22SMicky Ching 	retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
32159f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3216031366eaSJoe Perches 		return STATUS_FAIL;
3217fa590c22SMicky Ching 
3218fa590c22SMicky Ching 	ptr = buf;
3219fa590c22SMicky Ching 	for (page_addr = start_page; page_addr < end_page; page_addr++) {
3220fa590c22SMicky Ching 		ms_set_err_code(chip, MS_NO_ERROR);
3221fa590c22SMicky Ching 
3222fa590c22SMicky Ching 		if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
3223fa590c22SMicky Ching 			ms_set_err_code(chip, MS_NO_CARD);
3224031366eaSJoe Perches 			return STATUS_FAIL;
3225fa590c22SMicky Ching 		}
3226fa590c22SMicky Ching 
3227fa590c22SMicky Ching 		if (val & INT_REG_CMDNK) {
3228fa590c22SMicky Ching 			ms_set_err_code(chip, MS_CMD_NK);
3229031366eaSJoe Perches 			return STATUS_FAIL;
3230fa590c22SMicky Ching 		}
3231fa590c22SMicky Ching 		if (val & INT_REG_ERR) {
3232fa590c22SMicky Ching 			ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
3233031366eaSJoe Perches 			return STATUS_FAIL;
3234fa590c22SMicky Ching 		}
3235fa590c22SMicky Ching 		if (!(val & INT_REG_BREQ)) {
3236fa590c22SMicky Ching 			ms_set_err_code(chip, MS_BREQ_ERROR);
3237031366eaSJoe Perches 			return STATUS_FAIL;
3238fa590c22SMicky Ching 		}
3239fa590c22SMicky Ching 
3240fa590c22SMicky Ching 		udelay(30);
3241fa590c22SMicky Ching 
3242fa590c22SMicky Ching 		rtsx_init_cmd(chip);
3243fa590c22SMicky Ching 
3244fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC,
3245fa590c22SMicky Ching 			     0xFF, WRITE_PAGE_DATA);
3246fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG,
3247fa590c22SMicky Ching 			     0xFF, WAIT_INT);
3248fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
3249fa590c22SMicky Ching 			     0x01, RING_BUFFER);
3250fa590c22SMicky Ching 
3251fa590c22SMicky Ching 		trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512);
3252fa590c22SMicky Ching 
3253fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
3254fa590c22SMicky Ching 			     MS_TRANSFER_START |  MS_TM_NORMAL_WRITE);
3255fa590c22SMicky Ching 		rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
3256fa590c22SMicky Ching 			     MS_TRANSFER_END, MS_TRANSFER_END);
3257fa590c22SMicky Ching 
3258fa590c22SMicky Ching 		rtsx_send_cmd_no_wait(chip);
3259fa590c22SMicky Ching 
32609c378f14SWayne Porter 		retval = rtsx_transfer_data_partial(chip, MS_CARD, ptr,	512,
32619c378f14SWayne Porter 						    scsi_sg_count(chip->srb),
32629c378f14SWayne Porter 						    index, offset,
32639c378f14SWayne Porter 						    DMA_TO_DEVICE,
3264fa590c22SMicky Ching 						    chip->ms_timeout);
3265fa590c22SMicky Ching 		if (retval < 0) {
3266fa590c22SMicky Ching 			ms_set_err_code(chip, MS_TO_ERROR);
3267fa590c22SMicky Ching 			rtsx_clear_ms_error(chip);
3268fa590c22SMicky Ching 
32699f902b49SAymen Qader 			if (retval == -ETIMEDOUT)
3270031366eaSJoe Perches 				return STATUS_TIMEDOUT;
3271031366eaSJoe Perches 			return STATUS_FAIL;
3272fa590c22SMicky Ching 		}
3273fa590c22SMicky Ching 
3274fa590c22SMicky Ching 		retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1);
32759f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3276031366eaSJoe Perches 			return STATUS_FAIL;
3277fa590c22SMicky Ching 
3278fa590c22SMicky Ching 		if ((end_page - start_page) == 1) {
3279fa590c22SMicky Ching 			if (!(val & INT_REG_CED)) {
3280fa590c22SMicky Ching 				ms_set_err_code(chip, MS_FLASH_WRITE_ERROR);
3281031366eaSJoe Perches 				return STATUS_FAIL;
3282fa590c22SMicky Ching 			}
3283fa590c22SMicky Ching 		} else {
3284fa590c22SMicky Ching 			if (page_addr == (end_page - 1)) {
3285fa590c22SMicky Ching 				if (!(val & INT_REG_CED)) {
3286fa590c22SMicky Ching 					retval = ms_send_cmd(chip, BLOCK_END,
3287fa590c22SMicky Ching 							     WAIT_INT);
32889f902b49SAymen Qader 					if (retval != STATUS_SUCCESS)
3289031366eaSJoe Perches 						return STATUS_FAIL;
3290031366eaSJoe Perches 				}
3291fa590c22SMicky Ching 
3292fa590c22SMicky Ching 				retval = ms_read_bytes(chip, GET_INT, 1,
3293fa590c22SMicky Ching 						       NO_WAIT_INT, &val, 1);
32949f902b49SAymen Qader 				if (retval != STATUS_SUCCESS)
3295031366eaSJoe Perches 					return STATUS_FAIL;
3296031366eaSJoe Perches 			}
3297fa590c22SMicky Ching 
32987b228bdfSBenjamin Philip 			if (page_addr == (end_page - 1) ||
32997b228bdfSBenjamin Philip 			    page_addr == ms_card->page_off) {
3300fa590c22SMicky Ching 				if (!(val & INT_REG_CED)) {
3301fa590c22SMicky Ching 					ms_set_err_code(chip,
3302fa590c22SMicky Ching 							MS_FLASH_WRITE_ERROR);
3303031366eaSJoe Perches 					return STATUS_FAIL;
3304fa590c22SMicky Ching 				}
3305fa590c22SMicky Ching 			}
3306fa590c22SMicky Ching 		}
3307fa590c22SMicky Ching 
3308fa590c22SMicky Ching 		if (scsi_sg_count(chip->srb) == 0)
3309fa590c22SMicky Ching 			ptr += 512;
3310fa590c22SMicky Ching 	}
3311fa590c22SMicky Ching 
3312fa590c22SMicky Ching 	return STATUS_SUCCESS;
3313fa590c22SMicky Ching }
3314fa590c22SMicky Ching 
3315fa590c22SMicky Ching static int ms_finish_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
3316fa590c22SMicky Ching 			   u16 log_blk, u8 page_off)
3317fa590c22SMicky Ching {
3318d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3319fa590c22SMicky Ching 	int retval, seg_no;
3320fa590c22SMicky Ching 
3321fa590c22SMicky Ching 	retval = ms_copy_page(chip, old_blk, new_blk, log_blk,
3322fa590c22SMicky Ching 			      page_off, ms_card->page_off + 1);
33239f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3324031366eaSJoe Perches 		return STATUS_FAIL;
3325fa590c22SMicky Ching 
3326fa590c22SMicky Ching 	seg_no = old_blk >> 9;
3327fa590c22SMicky Ching 
3328fa590c22SMicky Ching 	if (MS_TST_BAD_BLOCK_FLG(ms_card)) {
3329fa590c22SMicky Ching 		MS_CLR_BAD_BLOCK_FLG(ms_card);
3330fa590c22SMicky Ching 		ms_set_bad_block(chip, old_blk);
3331fa590c22SMicky Ching 	} else {
3332fa590c22SMicky Ching 		retval = ms_erase_block(chip, old_blk);
3333fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
3334fa590c22SMicky Ching 			ms_set_unused_block(chip, old_blk);
3335fa590c22SMicky Ching 	}
3336fa590c22SMicky Ching 
3337fa590c22SMicky Ching 	ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk);
3338fa590c22SMicky Ching 
3339fa590c22SMicky Ching 	return STATUS_SUCCESS;
3340fa590c22SMicky Ching }
3341fa590c22SMicky Ching 
3342fa590c22SMicky Ching static int ms_prepare_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
3343fa590c22SMicky Ching 			    u16 log_blk, u8 start_page)
3344fa590c22SMicky Ching {
3345fa590c22SMicky Ching 	int retval;
3346fa590c22SMicky Ching 
3347fa590c22SMicky Ching 	if (start_page) {
3348fa590c22SMicky Ching 		retval = ms_copy_page(chip, old_blk, new_blk, log_blk,
3349fa590c22SMicky Ching 				      0, start_page);
33509f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3351031366eaSJoe Perches 			return STATUS_FAIL;
3352031366eaSJoe Perches 	}
3353fa590c22SMicky Ching 
3354fa590c22SMicky Ching 	return STATUS_SUCCESS;
3355fa590c22SMicky Ching }
3356fa590c22SMicky Ching 
3357fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
3358fa590c22SMicky Ching int ms_delay_write(struct rtsx_chip *chip)
3359fa590c22SMicky Ching {
3360d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3361c86bdd47SRehas Sachdeva 	struct ms_delay_write_tag *delay_write = &ms_card->delay_write;
3362fa590c22SMicky Ching 	int retval;
3363fa590c22SMicky Ching 
3364fa590c22SMicky Ching 	if (delay_write->delay_write_flag) {
3365fa590c22SMicky Ching 		retval = ms_set_init_para(chip);
33669f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3367031366eaSJoe Perches 			return STATUS_FAIL;
3368fa590c22SMicky Ching 
3369fa590c22SMicky Ching 		delay_write->delay_write_flag = 0;
3370fa590c22SMicky Ching 		retval = ms_finish_write(chip,
3371fa590c22SMicky Ching 					 delay_write->old_phyblock,
3372fa590c22SMicky Ching 					delay_write->new_phyblock,
3373fa590c22SMicky Ching 					delay_write->logblock,
3374fa590c22SMicky Ching 					delay_write->pageoff);
33759f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
3376031366eaSJoe Perches 			return STATUS_FAIL;
3377031366eaSJoe Perches 	}
3378fa590c22SMicky Ching 
3379fa590c22SMicky Ching 	return STATUS_SUCCESS;
3380fa590c22SMicky Ching }
3381fa590c22SMicky Ching #endif
3382fa590c22SMicky Ching 
3383fa590c22SMicky Ching static inline void ms_rw_fail(struct scsi_cmnd *srb, struct rtsx_chip *chip)
3384fa590c22SMicky Ching {
3385fa590c22SMicky Ching 	if (srb->sc_data_direction == DMA_FROM_DEVICE)
3386fa590c22SMicky Ching 		set_sense_type(chip, SCSI_LUN(srb),
3387fa590c22SMicky Ching 			       SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
3388fa590c22SMicky Ching 	else
3389fa590c22SMicky Ching 		set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR);
3390fa590c22SMicky Ching }
3391fa590c22SMicky Ching 
3392fa590c22SMicky Ching static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip,
3393fa590c22SMicky Ching 			      u32 start_sector, u16 sector_cnt)
3394fa590c22SMicky Ching {
3395d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3396fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
3397fa590c22SMicky Ching 	int retval, seg_no;
3398fa590c22SMicky Ching 	unsigned int index = 0, offset = 0;
3399fa590c22SMicky Ching 	u16 old_blk = 0, new_blk = 0, log_blk, total_sec_cnt = sector_cnt;
3400fa590c22SMicky Ching 	u8 start_page, end_page = 0, page_cnt;
3401fa590c22SMicky Ching 	u8 *ptr;
3402fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
3403c86bdd47SRehas Sachdeva 	struct ms_delay_write_tag *delay_write = &ms_card->delay_write;
3404fa590c22SMicky Ching #endif
3405fa590c22SMicky Ching 
3406fa590c22SMicky Ching 	ms_set_err_code(chip, MS_NO_ERROR);
3407fa590c22SMicky Ching 
3408fa590c22SMicky Ching 	ms_card->cleanup_counter = 0;
3409fa590c22SMicky Ching 
3410fa590c22SMicky Ching 	ptr = (u8 *)scsi_sglist(srb);
3411fa590c22SMicky Ching 
3412fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
3413fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3414fa590c22SMicky Ching 		ms_rw_fail(srb, chip);
3415031366eaSJoe Perches 		return STATUS_FAIL;
3416fa590c22SMicky Ching 	}
3417fa590c22SMicky Ching 
3418fa590c22SMicky Ching 	log_blk = (u16)(start_sector >> ms_card->block_shift);
3419fa590c22SMicky Ching 	start_page = (u8)(start_sector & ms_card->page_off);
3420fa590c22SMicky Ching 
3421fa590c22SMicky Ching 	for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) {
3422fa590c22SMicky Ching 		if (log_blk < ms_start_idx[seg_no + 1])
3423fa590c22SMicky Ching 			break;
3424fa590c22SMicky Ching 	}
3425fa590c22SMicky Ching 
3426fa590c22SMicky Ching 	if (ms_card->segment[seg_no].build_flag == 0) {
3427fa590c22SMicky Ching 		retval = ms_build_l2p_tbl(chip, seg_no);
3428fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
3429fa590c22SMicky Ching 			chip->card_fail |= MS_CARD;
3430fa590c22SMicky Ching 			set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
3431031366eaSJoe Perches 			return STATUS_FAIL;
3432fa590c22SMicky Ching 		}
3433fa590c22SMicky Ching 	}
3434fa590c22SMicky Ching 
3435fa590c22SMicky Ching 	if (srb->sc_data_direction == DMA_TO_DEVICE) {
3436fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
3437fa590c22SMicky Ching 		if (delay_write->delay_write_flag &&
34387b228bdfSBenjamin Philip 		    delay_write->logblock == log_blk &&
34397b228bdfSBenjamin Philip 		    start_page > delay_write->pageoff) {
3440fa590c22SMicky Ching 			delay_write->delay_write_flag = 0;
3441fa590c22SMicky Ching 			retval = ms_copy_page(chip,
3442fa590c22SMicky Ching 					      delay_write->old_phyblock,
34439c378f14SWayne Porter 					      delay_write->new_phyblock,
34449c378f14SWayne Porter 					      log_blk,
3445fa590c22SMicky Ching 					      delay_write->pageoff, start_page);
3446fa590c22SMicky Ching 			if (retval != STATUS_SUCCESS) {
3447fa590c22SMicky Ching 				set_sense_type(chip, lun,
3448fa590c22SMicky Ching 					       SENSE_TYPE_MEDIA_WRITE_ERR);
3449031366eaSJoe Perches 				return STATUS_FAIL;
3450fa590c22SMicky Ching 			}
3451fa590c22SMicky Ching 			old_blk = delay_write->old_phyblock;
3452fa590c22SMicky Ching 			new_blk = delay_write->new_phyblock;
3453fa590c22SMicky Ching 		} else if (delay_write->delay_write_flag &&
3454fa590c22SMicky Ching 				(delay_write->logblock == log_blk) &&
3455fa590c22SMicky Ching 				(start_page == delay_write->pageoff)) {
3456fa590c22SMicky Ching 			delay_write->delay_write_flag = 0;
3457fa590c22SMicky Ching 			old_blk = delay_write->old_phyblock;
3458fa590c22SMicky Ching 			new_blk = delay_write->new_phyblock;
3459fa590c22SMicky Ching 		} else {
3460fa590c22SMicky Ching 			retval = ms_delay_write(chip);
3461fa590c22SMicky Ching 			if (retval != STATUS_SUCCESS) {
3462fa590c22SMicky Ching 				set_sense_type(chip, lun,
3463fa590c22SMicky Ching 					       SENSE_TYPE_MEDIA_WRITE_ERR);
3464031366eaSJoe Perches 				return STATUS_FAIL;
3465fa590c22SMicky Ching 			}
3466fa590c22SMicky Ching #endif
346725ccf0b0SWayne Porter 			old_blk = ms_get_l2p_tbl
346825ccf0b0SWayne Porter 					(chip, seg_no,
3469fa590c22SMicky Ching 					 log_blk - ms_start_idx[seg_no]);
3470fa590c22SMicky Ching 			new_blk  = ms_get_unused_block(chip, seg_no);
34717b228bdfSBenjamin Philip 			if (old_blk == 0xFFFF || new_blk == 0xFFFF) {
3472fa590c22SMicky Ching 				set_sense_type(chip, lun,
3473fa590c22SMicky Ching 					       SENSE_TYPE_MEDIA_WRITE_ERR);
3474031366eaSJoe Perches 				return STATUS_FAIL;
3475fa590c22SMicky Ching 			}
3476fa590c22SMicky Ching 
3477fa590c22SMicky Ching 			retval = ms_prepare_write(chip, old_blk, new_blk,
3478fa590c22SMicky Ching 						  log_blk, start_page);
3479fa590c22SMicky Ching 			if (retval != STATUS_SUCCESS) {
348025ccf0b0SWayne Porter 				if (detect_card_cd(chip, MS_CARD) !=
348125ccf0b0SWayne Porter 				    STATUS_SUCCESS) {
348225ccf0b0SWayne Porter 					set_sense_type
348325ccf0b0SWayne Porter 						(chip, lun,
3484fa590c22SMicky Ching 						SENSE_TYPE_MEDIA_NOT_PRESENT);
3485031366eaSJoe Perches 					return STATUS_FAIL;
3486fa590c22SMicky Ching 				}
3487fa590c22SMicky Ching 				set_sense_type(chip, lun,
3488fa590c22SMicky Ching 					       SENSE_TYPE_MEDIA_WRITE_ERR);
3489031366eaSJoe Perches 				return STATUS_FAIL;
3490fa590c22SMicky Ching 			}
3491fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
3492fa590c22SMicky Ching 		}
3493fa590c22SMicky Ching #endif
3494fa590c22SMicky Ching 	} else {
3495fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
3496fa590c22SMicky Ching 		retval = ms_delay_write(chip);
3497fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
3498fa590c22SMicky Ching 			if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
3499fa590c22SMicky Ching 				set_sense_type(chip, lun,
3500fa590c22SMicky Ching 					       SENSE_TYPE_MEDIA_NOT_PRESENT);
3501031366eaSJoe Perches 				return STATUS_FAIL;
3502fa590c22SMicky Ching 			}
3503fa590c22SMicky Ching 			set_sense_type(chip, lun,
3504fa590c22SMicky Ching 				       SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
3505031366eaSJoe Perches 			return STATUS_FAIL;
3506fa590c22SMicky Ching 		}
3507fa590c22SMicky Ching #endif
3508fa590c22SMicky Ching 		old_blk = ms_get_l2p_tbl(chip, seg_no,
3509fa590c22SMicky Ching 					 log_blk - ms_start_idx[seg_no]);
3510fa590c22SMicky Ching 		if (old_blk == 0xFFFF) {
3511fa590c22SMicky Ching 			set_sense_type(chip, lun,
3512fa590c22SMicky Ching 				       SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
3513031366eaSJoe Perches 			return STATUS_FAIL;
3514fa590c22SMicky Ching 		}
3515fa590c22SMicky Ching 	}
3516fa590c22SMicky Ching 
3517bf6c0d11SFabio Falzoi 	dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n",
3518fa590c22SMicky Ching 		seg_no, old_blk, new_blk);
3519fa590c22SMicky Ching 
3520fa590c22SMicky Ching 	while (total_sec_cnt) {
3521fa590c22SMicky Ching 		if ((start_page + total_sec_cnt) > (ms_card->page_off + 1))
3522fa590c22SMicky Ching 			end_page = ms_card->page_off + 1;
3523fa590c22SMicky Ching 		else
3524fa590c22SMicky Ching 			end_page = start_page + (u8)total_sec_cnt;
3525fa590c22SMicky Ching 
3526fa590c22SMicky Ching 		page_cnt = end_page - start_page;
3527fa590c22SMicky Ching 
3528bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "start_page = %d, end_page = %d, page_cnt = %d\n",
3529fa590c22SMicky Ching 			start_page, end_page, page_cnt);
3530fa590c22SMicky Ching 
3531fa590c22SMicky Ching 		if (srb->sc_data_direction == DMA_FROM_DEVICE) {
3532fa590c22SMicky Ching 			retval = ms_read_multiple_pages(chip,
35339c378f14SWayne Porter 							old_blk, log_blk,
35349c378f14SWayne Porter 							start_page, end_page,
3535fa590c22SMicky Ching 							ptr, &index, &offset);
3536fa590c22SMicky Ching 		} else {
35379c378f14SWayne Porter 			retval = ms_write_multiple_pages(chip, old_blk, new_blk,
35389c378f14SWayne Porter 							 log_blk, start_page,
35399c378f14SWayne Porter 							 end_page, ptr, &index,
35409c378f14SWayne Porter 							 &offset);
3541fa590c22SMicky Ching 		}
3542fa590c22SMicky Ching 
3543fa590c22SMicky Ching 		if (retval != STATUS_SUCCESS) {
3544fa590c22SMicky Ching 			toggle_gpio(chip, 1);
3545fa590c22SMicky Ching 			if (detect_card_cd(chip, MS_CARD) != STATUS_SUCCESS) {
3546fa590c22SMicky Ching 				set_sense_type(chip, lun,
3547fa590c22SMicky Ching 					       SENSE_TYPE_MEDIA_NOT_PRESENT);
3548031366eaSJoe Perches 				return STATUS_FAIL;
3549fa590c22SMicky Ching 			}
3550fa590c22SMicky Ching 			ms_rw_fail(srb, chip);
3551031366eaSJoe Perches 			return STATUS_FAIL;
3552fa590c22SMicky Ching 		}
3553fa590c22SMicky Ching 
3554fa590c22SMicky Ching 		if (srb->sc_data_direction == DMA_TO_DEVICE) {
3555fa590c22SMicky Ching 			if (end_page == (ms_card->page_off + 1)) {
3556fa590c22SMicky Ching 				retval = ms_erase_block(chip, old_blk);
3557fa590c22SMicky Ching 				if (retval == STATUS_SUCCESS)
3558fa590c22SMicky Ching 					ms_set_unused_block(chip, old_blk);
3559fa590c22SMicky Ching 
3560fa590c22SMicky Ching 				ms_set_l2p_tbl(chip, seg_no,
3561fa590c22SMicky Ching 					       log_blk - ms_start_idx[seg_no],
3562fa590c22SMicky Ching 					       new_blk);
3563fa590c22SMicky Ching 			}
3564fa590c22SMicky Ching 		}
3565fa590c22SMicky Ching 
3566fa590c22SMicky Ching 		total_sec_cnt -= page_cnt;
3567fa590c22SMicky Ching 		if (scsi_sg_count(srb) == 0)
3568fa590c22SMicky Ching 			ptr += page_cnt * 512;
3569fa590c22SMicky Ching 
3570fa590c22SMicky Ching 		if (total_sec_cnt == 0)
3571fa590c22SMicky Ching 			break;
3572fa590c22SMicky Ching 
3573fa590c22SMicky Ching 		log_blk++;
3574fa590c22SMicky Ching 
3575fa590c22SMicky Ching 		for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1;
3576fa590c22SMicky Ching 				seg_no++) {
3577fa590c22SMicky Ching 			if (log_blk < ms_start_idx[seg_no + 1])
3578fa590c22SMicky Ching 				break;
3579fa590c22SMicky Ching 		}
3580fa590c22SMicky Ching 
3581fa590c22SMicky Ching 		if (ms_card->segment[seg_no].build_flag == 0) {
3582fa590c22SMicky Ching 			retval = ms_build_l2p_tbl(chip, seg_no);
3583fa590c22SMicky Ching 			if (retval != STATUS_SUCCESS) {
3584fa590c22SMicky Ching 				chip->card_fail |= MS_CARD;
3585fa590c22SMicky Ching 				set_sense_type(chip, lun,
3586fa590c22SMicky Ching 					       SENSE_TYPE_MEDIA_NOT_PRESENT);
3587031366eaSJoe Perches 				return STATUS_FAIL;
3588fa590c22SMicky Ching 			}
3589fa590c22SMicky Ching 		}
3590fa590c22SMicky Ching 
3591fa590c22SMicky Ching 		old_blk = ms_get_l2p_tbl(chip, seg_no,
3592fa590c22SMicky Ching 					 log_blk - ms_start_idx[seg_no]);
3593fa590c22SMicky Ching 		if (old_blk == 0xFFFF) {
3594fa590c22SMicky Ching 			ms_rw_fail(srb, chip);
3595031366eaSJoe Perches 			return STATUS_FAIL;
3596fa590c22SMicky Ching 		}
3597fa590c22SMicky Ching 
3598fa590c22SMicky Ching 		if (srb->sc_data_direction == DMA_TO_DEVICE) {
3599fa590c22SMicky Ching 			new_blk = ms_get_unused_block(chip, seg_no);
3600fa590c22SMicky Ching 			if (new_blk == 0xFFFF) {
3601fa590c22SMicky Ching 				ms_rw_fail(srb, chip);
3602031366eaSJoe Perches 				return STATUS_FAIL;
3603fa590c22SMicky Ching 			}
3604fa590c22SMicky Ching 		}
3605fa590c22SMicky Ching 
3606bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n",
3607fa590c22SMicky Ching 			seg_no, old_blk, new_blk);
3608fa590c22SMicky Ching 
3609fa590c22SMicky Ching 		start_page = 0;
3610fa590c22SMicky Ching 	}
3611fa590c22SMicky Ching 
3612fa590c22SMicky Ching 	if (srb->sc_data_direction == DMA_TO_DEVICE) {
3613fa590c22SMicky Ching 		if (end_page < (ms_card->page_off + 1)) {
3614fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
3615fa590c22SMicky Ching 			delay_write->delay_write_flag = 1;
3616fa590c22SMicky Ching 			delay_write->old_phyblock = old_blk;
3617fa590c22SMicky Ching 			delay_write->new_phyblock = new_blk;
3618fa590c22SMicky Ching 			delay_write->logblock = log_blk;
3619fa590c22SMicky Ching 			delay_write->pageoff = end_page;
3620fa590c22SMicky Ching #else
3621fa590c22SMicky Ching 			retval = ms_finish_write(chip, old_blk, new_blk,
3622fa590c22SMicky Ching 						 log_blk, end_page);
3623fa590c22SMicky Ching 			if (retval != STATUS_SUCCESS) {
362425ccf0b0SWayne Porter 				if (detect_card_cd(chip, MS_CARD) !=
362525ccf0b0SWayne Porter 				    STATUS_SUCCESS) {
362625ccf0b0SWayne Porter 					set_sense_type
362725ccf0b0SWayne Porter 						(chip, lun,
3628fa590c22SMicky Ching 						SENSE_TYPE_MEDIA_NOT_PRESENT);
3629031366eaSJoe Perches 					return STATUS_FAIL;
3630fa590c22SMicky Ching 				}
3631fa590c22SMicky Ching 
3632fa590c22SMicky Ching 				ms_rw_fail(srb, chip);
3633031366eaSJoe Perches 				return STATUS_FAIL;
3634fa590c22SMicky Ching 			}
3635fa590c22SMicky Ching #endif
3636fa590c22SMicky Ching 		}
3637fa590c22SMicky Ching 	}
3638fa590c22SMicky Ching 
3639fa590c22SMicky Ching 	scsi_set_resid(srb, 0);
3640fa590c22SMicky Ching 
3641fa590c22SMicky Ching 	return STATUS_SUCCESS;
3642fa590c22SMicky Ching }
3643fa590c22SMicky Ching 
3644fa590c22SMicky Ching int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip,
3645fa590c22SMicky Ching 	  u32 start_sector, u16 sector_cnt)
3646fa590c22SMicky Ching {
3647d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3648fa590c22SMicky Ching 	int retval;
3649fa590c22SMicky Ching 
3650fa590c22SMicky Ching 	if (CHK_MSPRO(ms_card))
3651fa590c22SMicky Ching 		retval = mspro_rw_multi_sector(srb, chip, start_sector,
3652fa590c22SMicky Ching 					       sector_cnt);
3653fa590c22SMicky Ching 	else
3654fa590c22SMicky Ching 		retval = ms_rw_multi_sector(srb, chip, start_sector,
3655fa590c22SMicky Ching 					    sector_cnt);
3656fa590c22SMicky Ching 
3657fa590c22SMicky Ching 	return retval;
3658fa590c22SMicky Ching }
3659fa590c22SMicky Ching 
3660fa590c22SMicky Ching void ms_free_l2p_tbl(struct rtsx_chip *chip)
3661fa590c22SMicky Ching {
3662d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3663fa590c22SMicky Ching 	int i = 0;
3664fa590c22SMicky Ching 
3665f432bc81SSandhya Bankar 	if (ms_card->segment) {
3666fa590c22SMicky Ching 		for (i = 0; i < ms_card->segment_cnt; i++) {
3667fa590c22SMicky Ching 			vfree(ms_card->segment[i].l2p_table);
3668fa590c22SMicky Ching 			ms_card->segment[i].l2p_table = NULL;
3669fa590c22SMicky Ching 			vfree(ms_card->segment[i].free_table);
3670fa590c22SMicky Ching 			ms_card->segment[i].free_table = NULL;
3671fa590c22SMicky Ching 		}
3672fa590c22SMicky Ching 		vfree(ms_card->segment);
3673fa590c22SMicky Ching 		ms_card->segment = NULL;
3674fa590c22SMicky Ching 	}
3675fa590c22SMicky Ching }
3676fa590c22SMicky Ching 
3677fa590c22SMicky Ching #ifdef SUPPORT_MAGIC_GATE
3678fa590c22SMicky Ching 
3679fa590c22SMicky Ching #ifdef READ_BYTES_WAIT_INT
3680fa590c22SMicky Ching static int ms_poll_int(struct rtsx_chip *chip)
3681fa590c22SMicky Ching {
3682fa590c22SMicky Ching 	int retval;
3683fa590c22SMicky Ching 	u8 val;
3684fa590c22SMicky Ching 
3685fa590c22SMicky Ching 	rtsx_init_cmd(chip);
3686fa590c22SMicky Ching 
3687fa590c22SMicky Ching 	rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANS_CFG, MS_INT_CED, MS_INT_CED);
3688fa590c22SMicky Ching 
3689fa590c22SMicky Ching 	retval = rtsx_send_cmd(chip, MS_CARD, 5000);
36909f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3691031366eaSJoe Perches 		return STATUS_FAIL;
3692fa590c22SMicky Ching 
3693fa590c22SMicky Ching 	val = *rtsx_get_cmd_data(chip);
36949f902b49SAymen Qader 	if (val & MS_INT_ERR)
3695031366eaSJoe Perches 		return STATUS_FAIL;
3696fa590c22SMicky Ching 
3697fa590c22SMicky Ching 	return STATUS_SUCCESS;
3698fa590c22SMicky Ching }
3699fa590c22SMicky Ching #endif
3700fa590c22SMicky Ching 
3701fa590c22SMicky Ching #ifdef MS_SAMPLE_INT_ERR
3702fa590c22SMicky Ching static int check_ms_err(struct rtsx_chip *chip)
3703fa590c22SMicky Ching {
3704fa590c22SMicky Ching 	int retval;
3705fa590c22SMicky Ching 	u8 val;
3706fa590c22SMicky Ching 
3707fa590c22SMicky Ching 	retval = rtsx_read_register(chip, MS_TRANSFER, &val);
3708fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS)
3709fa590c22SMicky Ching 		return 1;
3710fa590c22SMicky Ching 	if (val & MS_TRANSFER_ERR)
3711fa590c22SMicky Ching 		return 1;
3712fa590c22SMicky Ching 
3713fa590c22SMicky Ching 	retval = rtsx_read_register(chip, MS_TRANS_CFG, &val);
3714fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS)
3715fa590c22SMicky Ching 		return 1;
3716fa590c22SMicky Ching 
3717fa590c22SMicky Ching 	if (val & (MS_INT_ERR | MS_INT_CMDNK))
3718fa590c22SMicky Ching 		return 1;
3719fa590c22SMicky Ching 
3720fa590c22SMicky Ching 	return 0;
3721fa590c22SMicky Ching }
3722fa590c22SMicky Ching #else
3723fa590c22SMicky Ching static int check_ms_err(struct rtsx_chip *chip)
3724fa590c22SMicky Ching {
3725fa590c22SMicky Ching 	int retval;
3726fa590c22SMicky Ching 	u8 val;
3727fa590c22SMicky Ching 
3728fa590c22SMicky Ching 	retval = rtsx_read_register(chip, MS_TRANSFER, &val);
3729fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS)
3730fa590c22SMicky Ching 		return 1;
3731fa590c22SMicky Ching 	if (val & MS_TRANSFER_ERR)
3732fa590c22SMicky Ching 		return 1;
3733fa590c22SMicky Ching 
3734fa590c22SMicky Ching 	return 0;
3735fa590c22SMicky Ching }
3736fa590c22SMicky Ching #endif
3737fa590c22SMicky Ching 
3738fa590c22SMicky Ching static int mg_send_ex_cmd(struct rtsx_chip *chip, u8 cmd, u8 entry_num)
3739fa590c22SMicky Ching {
3740fa590c22SMicky Ching 	int retval, i;
3741fa590c22SMicky Ching 	u8 data[8];
3742fa590c22SMicky Ching 
3743fa590c22SMicky Ching 	data[0] = cmd;
3744fa590c22SMicky Ching 	data[1] = 0;
3745fa590c22SMicky Ching 	data[2] = 0;
3746fa590c22SMicky Ching 	data[3] = 0;
3747fa590c22SMicky Ching 	data[4] = 0;
3748fa590c22SMicky Ching 	data[5] = 0;
3749fa590c22SMicky Ching 	data[6] = entry_num;
3750fa590c22SMicky Ching 	data[7] = 0;
3751fa590c22SMicky Ching 
3752fa590c22SMicky Ching 	for (i = 0; i < MS_MAX_RETRY_COUNT; i++) {
3753fa590c22SMicky Ching 		retval = ms_write_bytes(chip, PRO_EX_SET_CMD, 7, WAIT_INT,
3754fa590c22SMicky Ching 					data, 8);
3755fa590c22SMicky Ching 		if (retval == STATUS_SUCCESS)
3756fa590c22SMicky Ching 			break;
3757fa590c22SMicky Ching 	}
37589f902b49SAymen Qader 	if (i == MS_MAX_RETRY_COUNT)
3759031366eaSJoe Perches 		return STATUS_FAIL;
3760fa590c22SMicky Ching 
3761fa590c22SMicky Ching 	if (check_ms_err(chip)) {
3762fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
3763031366eaSJoe Perches 		return STATUS_FAIL;
3764fa590c22SMicky Ching 	}
3765fa590c22SMicky Ching 
3766fa590c22SMicky Ching 	return STATUS_SUCCESS;
3767fa590c22SMicky Ching }
3768fa590c22SMicky Ching 
3769fa590c22SMicky Ching static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type,
3770fa590c22SMicky Ching 			       u8 mg_entry_num)
3771fa590c22SMicky Ching {
3772fa590c22SMicky Ching 	int retval;
3773fa590c22SMicky Ching 	u8 buf[6];
3774fa590c22SMicky Ching 
3775fa590c22SMicky Ching 	if (type == 0)
37766e653e9cSGabriela Bittencourt 		retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_TPC_PARM, 1);
3777fa590c22SMicky Ching 	else
37786e653e9cSGabriela Bittencourt 		retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_DATA_COUNT1, 6);
3779fa590c22SMicky Ching 
37809f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3781031366eaSJoe Perches 		return STATUS_FAIL;
3782fa590c22SMicky Ching 
3783fa590c22SMicky Ching 	buf[0] = 0;
3784fa590c22SMicky Ching 	buf[1] = 0;
3785fa590c22SMicky Ching 	if (type == 1) {
3786fa590c22SMicky Ching 		buf[2] = 0;
3787fa590c22SMicky Ching 		buf[3] = 0;
3788fa590c22SMicky Ching 		buf[4] = 0;
3789fa590c22SMicky Ching 		buf[5] = mg_entry_num;
3790fa590c22SMicky Ching 	}
3791fa590c22SMicky Ching 	retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6,
3792fa590c22SMicky Ching 				NO_WAIT_INT, buf, 6);
37939f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3794031366eaSJoe Perches 		return STATUS_FAIL;
3795fa590c22SMicky Ching 
3796fa590c22SMicky Ching 	return STATUS_SUCCESS;
3797fa590c22SMicky Ching }
3798fa590c22SMicky Ching 
3799fa590c22SMicky Ching int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip)
3800fa590c22SMicky Ching {
3801fa590c22SMicky Ching 	int retval;
3802fa590c22SMicky Ching 	int i;
3803fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
3804fa590c22SMicky Ching 	u8 buf1[32], buf2[12];
3805fa590c22SMicky Ching 
3806fa590c22SMicky Ching 	if (scsi_bufflen(srb) < 12) {
3807fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD);
3808031366eaSJoe Perches 		return STATUS_FAIL;
3809fa590c22SMicky Ching 	}
3810fa590c22SMicky Ching 
3811fa590c22SMicky Ching 	ms_cleanup_work(chip);
3812fa590c22SMicky Ching 
3813fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
38149f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3815031366eaSJoe Perches 		return STATUS_FAIL;
3816fa590c22SMicky Ching 
3817fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_SET_LID, 0);
3818fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3819fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
3820031366eaSJoe Perches 		return STATUS_FAIL;
3821fa590c22SMicky Ching 	}
3822fa590c22SMicky Ching 
3823fa590c22SMicky Ching 	memset(buf1, 0, 32);
3824fa590c22SMicky Ching 	rtsx_stor_get_xfer_buf(buf2, min_t(int, 12, scsi_bufflen(srb)), srb);
3825fa590c22SMicky Ching 	for (i = 0; i < 8; i++)
3826fa590c22SMicky Ching 		buf1[8 + i] = buf2[4 + i];
3827fa590c22SMicky Ching 
3828fa590c22SMicky Ching 	retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT,
3829fa590c22SMicky Ching 				buf1, 32);
3830fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3831fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
3832031366eaSJoe Perches 		return STATUS_FAIL;
3833fa590c22SMicky Ching 	}
3834fa590c22SMicky Ching 	if (check_ms_err(chip)) {
3835fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
3836fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
3837031366eaSJoe Perches 		return STATUS_FAIL;
3838fa590c22SMicky Ching 	}
3839fa590c22SMicky Ching 
3840fa590c22SMicky Ching 	return STATUS_SUCCESS;
3841fa590c22SMicky Ching }
3842fa590c22SMicky Ching 
3843fa590c22SMicky Ching int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip)
3844fa590c22SMicky Ching {
38458467c3b4SColin Ian King 	int retval;
3846fa590c22SMicky Ching 	int bufflen;
3847fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
3848fa590c22SMicky Ching 	u8 *buf = NULL;
3849fa590c22SMicky Ching 
3850fa590c22SMicky Ching 	ms_cleanup_work(chip);
3851fa590c22SMicky Ching 
3852fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
38539f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3854031366eaSJoe Perches 		return STATUS_FAIL;
3855fa590c22SMicky Ching 
3856fa590c22SMicky Ching 	buf = kmalloc(1540, GFP_KERNEL);
38579f902b49SAymen Qader 	if (!buf)
3858031366eaSJoe Perches 		return STATUS_ERROR;
3859fa590c22SMicky Ching 
3860fa590c22SMicky Ching 	buf[0] = 0x04;
3861fa590c22SMicky Ching 	buf[1] = 0x1A;
3862fa590c22SMicky Ching 	buf[2] = 0x00;
3863fa590c22SMicky Ching 	buf[3] = 0x00;
3864fa590c22SMicky Ching 
3865fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_GET_LEKB, 0);
3866fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3867fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
3868541e4d2dSQuentin Lambert 		goto free_buffer;
3869fa590c22SMicky Ching 	}
3870fa590c22SMicky Ching 
3871fa590c22SMicky Ching 	retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA,
3872fa590c22SMicky Ching 				  3, WAIT_INT, 0, 0, buf + 4, 1536);
3873fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3874fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
3875fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
3876541e4d2dSQuentin Lambert 		goto free_buffer;
3877fa590c22SMicky Ching 	}
3878fa590c22SMicky Ching 	if (check_ms_err(chip)) {
3879fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
3880fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
38810b25e9faSQuentin Lambert 		retval = STATUS_FAIL;
38820b25e9faSQuentin Lambert 		goto free_buffer;
3883fa590c22SMicky Ching 	}
3884fa590c22SMicky Ching 
3885fa590c22SMicky Ching 	bufflen = min_t(int, 1052, scsi_bufflen(srb));
3886fa590c22SMicky Ching 	rtsx_stor_set_xfer_buf(buf, bufflen, srb);
3887fa590c22SMicky Ching 
3888541e4d2dSQuentin Lambert free_buffer:
3889fa590c22SMicky Ching 	kfree(buf);
3890fa590c22SMicky Ching 	return retval;
3891fa590c22SMicky Ching }
3892fa590c22SMicky Ching 
3893fa590c22SMicky Ching int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip)
3894fa590c22SMicky Ching {
3895d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3896fa590c22SMicky Ching 	int retval;
3897fa590c22SMicky Ching 	int bufflen;
3898fa590c22SMicky Ching 	int i;
3899fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
3900fa590c22SMicky Ching 	u8 buf[32];
3901fa590c22SMicky Ching 
3902fa590c22SMicky Ching 	ms_cleanup_work(chip);
3903fa590c22SMicky Ching 
3904fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
39059f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3906031366eaSJoe Perches 		return STATUS_FAIL;
3907fa590c22SMicky Ching 
3908fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_GET_ID, 0);
3909fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3910fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
3911031366eaSJoe Perches 		return STATUS_FAIL;
3912fa590c22SMicky Ching 	}
3913fa590c22SMicky Ching 
3914fa590c22SMicky Ching 	retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT,
3915fa590c22SMicky Ching 			       buf, 32);
3916fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3917fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
3918031366eaSJoe Perches 		return STATUS_FAIL;
3919fa590c22SMicky Ching 	}
3920fa590c22SMicky Ching 	if (check_ms_err(chip)) {
3921fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
3922fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
3923031366eaSJoe Perches 		return STATUS_FAIL;
3924fa590c22SMicky Ching 	}
3925fa590c22SMicky Ching 
3926fa590c22SMicky Ching 	memcpy(ms_card->magic_gate_id, buf, 16);
3927fa590c22SMicky Ching 
3928fa590c22SMicky Ching #ifdef READ_BYTES_WAIT_INT
3929fa590c22SMicky Ching 	retval = ms_poll_int(chip);
3930fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3931fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
3932031366eaSJoe Perches 		return STATUS_FAIL;
3933fa590c22SMicky Ching 	}
3934fa590c22SMicky Ching #endif
3935fa590c22SMicky Ching 
3936fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_SET_RD, 0);
3937fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3938fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
3939031366eaSJoe Perches 		return STATUS_FAIL;
3940fa590c22SMicky Ching 	}
3941fa590c22SMicky Ching 
3942fa590c22SMicky Ching 	bufflen = min_t(int, 12, scsi_bufflen(srb));
3943fa590c22SMicky Ching 	rtsx_stor_get_xfer_buf(buf, bufflen, srb);
3944fa590c22SMicky Ching 
3945fa590c22SMicky Ching 	for (i = 0; i < 8; i++)
3946fa590c22SMicky Ching 		buf[i] = buf[4 + i];
3947fa590c22SMicky Ching 
3948fa590c22SMicky Ching 	for (i = 0; i < 24; i++)
3949fa590c22SMicky Ching 		buf[8 + i] = 0;
3950fa590c22SMicky Ching 
3951fa590c22SMicky Ching 	retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA,
3952fa590c22SMicky Ching 				32, WAIT_INT, buf, 32);
3953fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3954fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
3955031366eaSJoe Perches 		return STATUS_FAIL;
3956fa590c22SMicky Ching 	}
3957fa590c22SMicky Ching 	if (check_ms_err(chip)) {
3958fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_INCOMPATIBLE_MEDIUM);
3959fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
3960031366eaSJoe Perches 		return STATUS_FAIL;
3961fa590c22SMicky Ching 	}
3962fa590c22SMicky Ching 
3963fa590c22SMicky Ching 	ms_card->mg_auth = 0;
3964fa590c22SMicky Ching 
3965fa590c22SMicky Ching 	return STATUS_SUCCESS;
3966fa590c22SMicky Ching }
3967fa590c22SMicky Ching 
3968fa590c22SMicky Ching int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip)
3969fa590c22SMicky Ching {
3970d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
3971fa590c22SMicky Ching 	int retval;
3972fa590c22SMicky Ching 	int bufflen;
3973fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
3974fa590c22SMicky Ching 	u8 buf1[32], buf2[36];
3975fa590c22SMicky Ching 
3976fa590c22SMicky Ching 	ms_cleanup_work(chip);
3977fa590c22SMicky Ching 
3978fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
39799f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
3980031366eaSJoe Perches 		return STATUS_FAIL;
3981fa590c22SMicky Ching 
3982fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0);
3983fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3984fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
3985031366eaSJoe Perches 		return STATUS_FAIL;
3986fa590c22SMicky Ching 	}
3987fa590c22SMicky Ching 
3988fa590c22SMicky Ching 	retval = ms_read_bytes(chip, PRO_READ_SHORT_DATA, 32, WAIT_INT,
3989fa590c22SMicky Ching 			       buf1, 32);
3990fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
3991fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
3992031366eaSJoe Perches 		return STATUS_FAIL;
3993fa590c22SMicky Ching 	}
3994fa590c22SMicky Ching 	if (check_ms_err(chip)) {
3995fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
3996fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
3997031366eaSJoe Perches 		return STATUS_FAIL;
3998fa590c22SMicky Ching 	}
3999fa590c22SMicky Ching 
4000fa590c22SMicky Ching 	buf2[0] = 0x00;
4001fa590c22SMicky Ching 	buf2[1] = 0x22;
4002fa590c22SMicky Ching 	buf2[2] = 0x00;
4003fa590c22SMicky Ching 	buf2[3] = 0x00;
4004fa590c22SMicky Ching 
4005fa590c22SMicky Ching 	memcpy(buf2 + 4, ms_card->magic_gate_id, 16);
4006fa590c22SMicky Ching 	memcpy(buf2 + 20, buf1, 16);
4007fa590c22SMicky Ching 
4008fa590c22SMicky Ching 	bufflen = min_t(int, 36, scsi_bufflen(srb));
4009fa590c22SMicky Ching 	rtsx_stor_set_xfer_buf(buf2, bufflen, srb);
4010fa590c22SMicky Ching 
4011fa590c22SMicky Ching #ifdef READ_BYTES_WAIT_INT
4012fa590c22SMicky Ching 	retval = ms_poll_int(chip);
4013fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
4014fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
4015031366eaSJoe Perches 		return STATUS_FAIL;
4016fa590c22SMicky Ching 	}
4017fa590c22SMicky Ching #endif
4018fa590c22SMicky Ching 
4019fa590c22SMicky Ching 	return STATUS_SUCCESS;
4020fa590c22SMicky Ching }
4021fa590c22SMicky Ching 
4022fa590c22SMicky Ching int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip)
4023fa590c22SMicky Ching {
4024d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
4025fa590c22SMicky Ching 	int retval;
4026fa590c22SMicky Ching 	int i;
4027fa590c22SMicky Ching 	int bufflen;
4028fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
4029fa590c22SMicky Ching 	u8 buf[32];
4030fa590c22SMicky Ching 
4031fa590c22SMicky Ching 	ms_cleanup_work(chip);
4032fa590c22SMicky Ching 
4033fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
40349f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
4035031366eaSJoe Perches 		return STATUS_FAIL;
4036fa590c22SMicky Ching 
4037fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0);
4038fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
4039fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
4040031366eaSJoe Perches 		return STATUS_FAIL;
4041fa590c22SMicky Ching 	}
4042fa590c22SMicky Ching 
4043fa590c22SMicky Ching 	bufflen = min_t(int, 12, scsi_bufflen(srb));
4044fa590c22SMicky Ching 	rtsx_stor_get_xfer_buf(buf, bufflen, srb);
4045fa590c22SMicky Ching 
4046fa590c22SMicky Ching 	for (i = 0; i < 8; i++)
4047fa590c22SMicky Ching 		buf[i] = buf[4 + i];
4048fa590c22SMicky Ching 
4049fa590c22SMicky Ching 	for (i = 0; i < 24; i++)
4050fa590c22SMicky Ching 		buf[8 + i] = 0;
4051fa590c22SMicky Ching 
4052fa590c22SMicky Ching 	retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT,
4053fa590c22SMicky Ching 				buf, 32);
4054fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
4055fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
4056031366eaSJoe Perches 		return STATUS_FAIL;
4057fa590c22SMicky Ching 	}
4058fa590c22SMicky Ching 	if (check_ms_err(chip)) {
4059fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN);
4060fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
4061031366eaSJoe Perches 		return STATUS_FAIL;
4062fa590c22SMicky Ching 	}
4063fa590c22SMicky Ching 
4064fa590c22SMicky Ching 	ms_card->mg_auth = 1;
4065fa590c22SMicky Ching 
4066fa590c22SMicky Ching 	return STATUS_SUCCESS;
4067fa590c22SMicky Ching }
4068fa590c22SMicky Ching 
4069fa590c22SMicky Ching int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
4070fa590c22SMicky Ching {
4071d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
4072fa590c22SMicky Ching 	int retval;
4073fa590c22SMicky Ching 	int bufflen;
4074fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
4075fa590c22SMicky Ching 	u8 *buf = NULL;
4076fa590c22SMicky Ching 
4077fa590c22SMicky Ching 	ms_cleanup_work(chip);
4078fa590c22SMicky Ching 
4079fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
40809f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
4081031366eaSJoe Perches 		return STATUS_FAIL;
4082fa590c22SMicky Ching 
4083fa590c22SMicky Ching 	buf = kmalloc(1028, GFP_KERNEL);
40849f902b49SAymen Qader 	if (!buf)
4085031366eaSJoe Perches 		return STATUS_ERROR;
4086fa590c22SMicky Ching 
4087fa590c22SMicky Ching 	buf[0] = 0x04;
4088fa590c22SMicky Ching 	buf[1] = 0x02;
4089fa590c22SMicky Ching 	buf[2] = 0x00;
4090fa590c22SMicky Ching 	buf[3] = 0x00;
4091fa590c22SMicky Ching 
4092fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_GET_IBD, ms_card->mg_entry_num);
4093fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
4094fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
4095541e4d2dSQuentin Lambert 		goto free_buffer;
4096fa590c22SMicky Ching 	}
4097fa590c22SMicky Ching 
4098fa590c22SMicky Ching 	retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA,
4099fa590c22SMicky Ching 				  2, WAIT_INT, 0, 0, buf + 4, 1024);
4100fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
4101fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
4102fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
4103541e4d2dSQuentin Lambert 		goto free_buffer;
4104fa590c22SMicky Ching 	}
4105fa590c22SMicky Ching 	if (check_ms_err(chip)) {
4106fa590c22SMicky Ching 		set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
4107fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
41080b25e9faSQuentin Lambert 		retval = STATUS_FAIL;
41090b25e9faSQuentin Lambert 		goto free_buffer;
4110fa590c22SMicky Ching 	}
4111fa590c22SMicky Ching 
4112fa590c22SMicky Ching 	bufflen = min_t(int, 1028, scsi_bufflen(srb));
4113fa590c22SMicky Ching 	rtsx_stor_set_xfer_buf(buf, bufflen, srb);
4114fa590c22SMicky Ching 
4115541e4d2dSQuentin Lambert free_buffer:
4116fa590c22SMicky Ching 	kfree(buf);
4117fa590c22SMicky Ching 	return retval;
4118fa590c22SMicky Ching }
4119fa590c22SMicky Ching 
4120fa590c22SMicky Ching int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
4121fa590c22SMicky Ching {
4122d1af6476SDilek Uzulmez 	struct ms_info *ms_card = &chip->ms_card;
4123fa590c22SMicky Ching 	int retval;
4124fa590c22SMicky Ching 	int bufflen;
4125fa590c22SMicky Ching #ifdef MG_SET_ICV_SLOW
4126fa590c22SMicky Ching 	int i;
4127fa590c22SMicky Ching #endif
4128fa590c22SMicky Ching 	unsigned int lun = SCSI_LUN(srb);
4129fa590c22SMicky Ching 	u8 *buf = NULL;
4130fa590c22SMicky Ching 
4131fa590c22SMicky Ching 	ms_cleanup_work(chip);
4132fa590c22SMicky Ching 
4133fa590c22SMicky Ching 	retval = ms_switch_clock(chip);
41349f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
4135031366eaSJoe Perches 		return STATUS_FAIL;
4136fa590c22SMicky Ching 
4137fa590c22SMicky Ching 	buf = kmalloc(1028, GFP_KERNEL);
41389f902b49SAymen Qader 	if (!buf)
4139031366eaSJoe Perches 		return STATUS_ERROR;
4140fa590c22SMicky Ching 
4141fa590c22SMicky Ching 	bufflen = min_t(int, 1028, scsi_bufflen(srb));
4142fa590c22SMicky Ching 	rtsx_stor_get_xfer_buf(buf, bufflen, srb);
4143fa590c22SMicky Ching 
4144fa590c22SMicky Ching 	retval = mg_send_ex_cmd(chip, MG_SET_IBD, ms_card->mg_entry_num);
4145fa590c22SMicky Ching 	if (retval != STATUS_SUCCESS) {
4146fa590c22SMicky Ching 		if (ms_card->mg_auth == 0) {
4147fa590c22SMicky Ching 			if ((buf[5] & 0xC0) != 0)
414825ccf0b0SWayne Porter 				set_sense_type
414925ccf0b0SWayne Porter 					(chip, lun,
4150fa590c22SMicky Ching 					SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
4151fa590c22SMicky Ching 			else
4152fa590c22SMicky Ching 				set_sense_type(chip, lun,
4153fa590c22SMicky Ching 					       SENSE_TYPE_MG_WRITE_ERR);
4154fa590c22SMicky Ching 		} else {
4155fa590c22SMicky Ching 			set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
4156fa590c22SMicky Ching 		}
41576e653e9cSGabriela Bittencourt 		goto set_ICV_finish;
4158fa590c22SMicky Ching 	}
4159fa590c22SMicky Ching 
4160fa590c22SMicky Ching #ifdef MG_SET_ICV_SLOW
4161fa590c22SMicky Ching 	for (i = 0; i < 2; i++) {
4162fa590c22SMicky Ching 		udelay(50);
4163fa590c22SMicky Ching 
4164fa590c22SMicky Ching 		rtsx_init_cmd(chip);
4165fa590c22SMicky Ching 
4166fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC,
4167fa590c22SMicky Ching 			     0xFF, PRO_WRITE_LONG_DATA);
4168fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, WAIT_INT);
4169fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE,
4170fa590c22SMicky Ching 			     0x01, RING_BUFFER);
4171fa590c22SMicky Ching 
4172fa590c22SMicky Ching 		trans_dma_enable(DMA_TO_DEVICE, chip, 512, DMA_512);
4173fa590c22SMicky Ching 
4174fa590c22SMicky Ching 		rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF,
4175fa590c22SMicky Ching 			     MS_TRANSFER_START |  MS_TM_NORMAL_WRITE);
4176fa590c22SMicky Ching 		rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER,
4177fa590c22SMicky Ching 			     MS_TRANSFER_END, MS_TRANSFER_END);
4178fa590c22SMicky Ching 
4179fa590c22SMicky Ching 		rtsx_send_cmd_no_wait(chip);
4180fa590c22SMicky Ching 
4181fa590c22SMicky Ching 		retval = rtsx_transfer_data(chip, MS_CARD, buf + 4 + i * 512,
4182fa590c22SMicky Ching 					    512, 0, DMA_TO_DEVICE, 3000);
41837b228bdfSBenjamin Philip 		if (retval < 0 || check_ms_err(chip)) {
4184fa590c22SMicky Ching 			rtsx_clear_ms_error(chip);
4185fa590c22SMicky Ching 			if (ms_card->mg_auth == 0) {
4186fa590c22SMicky Ching 				if ((buf[5] & 0xC0) != 0)
418725ccf0b0SWayne Porter 					set_sense_type
418825ccf0b0SWayne Porter 					    (chip, lun,
418925ccf0b0SWayne Porter 					     SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
4190fa590c22SMicky Ching 				else
4191fa590c22SMicky Ching 					set_sense_type(chip, lun,
4192fa590c22SMicky Ching 						       SENSE_TYPE_MG_WRITE_ERR);
4193fa590c22SMicky Ching 			} else {
4194fa590c22SMicky Ching 				set_sense_type(chip, lun,
4195fa590c22SMicky Ching 					       SENSE_TYPE_MG_WRITE_ERR);
4196fa590c22SMicky Ching 			}
4197fa590c22SMicky Ching 			retval = STATUS_FAIL;
41986e653e9cSGabriela Bittencourt 			goto set_ICV_finish;
4199fa590c22SMicky Ching 		}
4200fa590c22SMicky Ching 	}
4201fa590c22SMicky Ching #else
4202fa590c22SMicky Ching 	retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA,
4203fa590c22SMicky Ching 				  2, WAIT_INT, 0, 0, buf + 4, 1024);
42047b228bdfSBenjamin Philip 	if (retval != STATUS_SUCCESS || check_ms_err(chip)) {
4205fa590c22SMicky Ching 		rtsx_clear_ms_error(chip);
4206fa590c22SMicky Ching 		if (ms_card->mg_auth == 0) {
4207fa590c22SMicky Ching 			if ((buf[5] & 0xC0) != 0)
420825ccf0b0SWayne Porter 				set_sense_type
420925ccf0b0SWayne Porter 				    (chip, lun,
4210fa590c22SMicky Ching 				     SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB);
4211fa590c22SMicky Ching 			else
4212fa590c22SMicky Ching 				set_sense_type(chip, lun,
4213fa590c22SMicky Ching 					       SENSE_TYPE_MG_WRITE_ERR);
4214fa590c22SMicky Ching 		} else {
4215fa590c22SMicky Ching 			set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR);
4216fa590c22SMicky Ching 		}
42176e653e9cSGabriela Bittencourt 		goto set_ICV_finish;
4218fa590c22SMicky Ching 	}
4219fa590c22SMicky Ching #endif
4220fa590c22SMicky Ching 
42216e653e9cSGabriela Bittencourt set_ICV_finish:
4222fa590c22SMicky Ching 	kfree(buf);
4223fa590c22SMicky Ching 	return retval;
4224fa590c22SMicky Ching }
4225fa590c22SMicky Ching 
4226fa590c22SMicky Ching #endif /* SUPPORT_MAGIC_GATE */
4227fa590c22SMicky Ching 
4228fa590c22SMicky Ching void ms_cleanup_work(struct rtsx_chip *chip)
4229fa590c22SMicky Ching {
4230c86bdd47SRehas Sachdeva 	struct ms_info *ms_card = &chip->ms_card;
4231fa590c22SMicky Ching 
4232fa590c22SMicky Ching 	if (CHK_MSPRO(ms_card)) {
4233fa590c22SMicky Ching 		if (ms_card->seq_mode) {
4234bf6c0d11SFabio Falzoi 			dev_dbg(rtsx_dev(chip), "MS Pro: stop transmission\n");
4235fa590c22SMicky Ching 			mspro_stop_seq_mode(chip);
4236fa590c22SMicky Ching 			ms_card->cleanup_counter = 0;
4237fa590c22SMicky Ching 		}
4238fa590c22SMicky Ching 		if (CHK_MSHG(ms_card)) {
4239fa590c22SMicky Ching 			rtsx_write_register(chip, MS_CFG,
4240fa590c22SMicky Ching 					    MS_2K_SECTOR_MODE, 0x00);
4241fa590c22SMicky Ching 		}
4242fa590c22SMicky Ching 	}
4243fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
424425ccf0b0SWayne Porter 	else if ((!CHK_MSPRO(ms_card)) &&
424525ccf0b0SWayne Porter 		 ms_card->delay_write.delay_write_flag) {
4246bf6c0d11SFabio Falzoi 		dev_dbg(rtsx_dev(chip), "MS: delay write\n");
4247fa590c22SMicky Ching 		ms_delay_write(chip);
4248fa590c22SMicky Ching 		ms_card->cleanup_counter = 0;
4249fa590c22SMicky Ching 	}
4250fa590c22SMicky Ching #endif
4251fa590c22SMicky Ching }
4252fa590c22SMicky Ching 
4253fa590c22SMicky Ching int ms_power_off_card3v3(struct rtsx_chip *chip)
4254fa590c22SMicky Ching {
4255fa590c22SMicky Ching 	int retval;
4256fa590c22SMicky Ching 
4257fa590c22SMicky Ching 	retval = disable_card_clock(chip, MS_CARD);
42589f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
4259031366eaSJoe Perches 		return STATUS_FAIL;
4260fa590c22SMicky Ching 
4261fa590c22SMicky Ching 	if (chip->asic_code) {
4262fa590c22SMicky Ching 		retval = ms_pull_ctl_disable(chip);
42639f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
4264031366eaSJoe Perches 			return STATUS_FAIL;
4265fa590c22SMicky Ching 	} else {
42668ee775f9SJoe Perches 		retval = rtsx_write_register(chip, FPGA_PULL_CTL,
42678ee775f9SJoe Perches 					     FPGA_MS_PULL_CTL_BIT | 0x20,
42688ee775f9SJoe Perches 					     FPGA_MS_PULL_CTL_BIT);
42699f902b49SAymen Qader 		if (retval)
42708ee775f9SJoe Perches 			return retval;
4271fa590c22SMicky Ching 	}
42728ee775f9SJoe Perches 	retval = rtsx_write_register(chip, CARD_OE, MS_OUTPUT_EN, 0);
42739f902b49SAymen Qader 	if (retval)
42748ee775f9SJoe Perches 		return retval;
42759f902b49SAymen Qader 
4276fa590c22SMicky Ching 	if (!chip->ft2_fast_mode) {
4277fa590c22SMicky Ching 		retval = card_power_off(chip, MS_CARD);
42789f902b49SAymen Qader 		if (retval != STATUS_SUCCESS)
4279031366eaSJoe Perches 			return STATUS_FAIL;
4280031366eaSJoe Perches 	}
4281fa590c22SMicky Ching 
4282fa590c22SMicky Ching 	return STATUS_SUCCESS;
4283fa590c22SMicky Ching }
4284fa590c22SMicky Ching 
4285fa590c22SMicky Ching int release_ms_card(struct rtsx_chip *chip)
4286fa590c22SMicky Ching {
4287c86bdd47SRehas Sachdeva 	struct ms_info *ms_card = &chip->ms_card;
4288fa590c22SMicky Ching 	int retval;
4289fa590c22SMicky Ching 
4290fa590c22SMicky Ching #ifdef MS_DELAY_WRITE
4291fa590c22SMicky Ching 	ms_card->delay_write.delay_write_flag = 0;
4292fa590c22SMicky Ching #endif
4293fa590c22SMicky Ching 	ms_card->pro_under_formatting = 0;
4294fa590c22SMicky Ching 
4295fa590c22SMicky Ching 	chip->card_ready &= ~MS_CARD;
4296fa590c22SMicky Ching 	chip->card_fail &= ~MS_CARD;
4297fa590c22SMicky Ching 	chip->card_wp &= ~MS_CARD;
4298fa590c22SMicky Ching 
4299fa590c22SMicky Ching 	ms_free_l2p_tbl(chip);
4300fa590c22SMicky Ching 
4301fa590c22SMicky Ching 	memset(ms_card->raw_sys_info, 0, 96);
4302fa590c22SMicky Ching #ifdef SUPPORT_PCGL_1P18
4303fa590c22SMicky Ching 	memset(ms_card->raw_model_name, 0, 48);
4304fa590c22SMicky Ching #endif
4305fa590c22SMicky Ching 
4306fa590c22SMicky Ching 	retval = ms_power_off_card3v3(chip);
43079f902b49SAymen Qader 	if (retval != STATUS_SUCCESS)
4308031366eaSJoe Perches 		return STATUS_FAIL;
4309fa590c22SMicky Ching 
4310fa590c22SMicky Ching 	return STATUS_SUCCESS;
4311fa590c22SMicky Ching }
4312