xref: /rk3399_rockchip-uboot/drivers/rkflash/flash.c (revision e5e85009939dc0143d82e6c299db92d23dc67b0d)
1ba0501acSDingqiang Lin /*
2ba0501acSDingqiang Lin  * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd
3ba0501acSDingqiang Lin  *
4ba0501acSDingqiang Lin  * SPDX-License-Identifier:	GPL-2.0
5ba0501acSDingqiang Lin  */
6ba0501acSDingqiang Lin 
7ba0501acSDingqiang Lin #include <common.h>
8ba0501acSDingqiang Lin #include <linux/delay.h>
9ba0501acSDingqiang Lin 
10ba0501acSDingqiang Lin #include "flash.h"
11ba0501acSDingqiang Lin #include "flash_com.h"
12ba0501acSDingqiang Lin #include "nandc.h"
13ba0501acSDingqiang Lin #include "rkflash_debug.h"
14ba0501acSDingqiang Lin 
15ba0501acSDingqiang Lin #define FLASH_STRESS_TEST_EN		0
16ba0501acSDingqiang Lin 
17ba0501acSDingqiang Lin static u8 id_byte[MAX_FLASH_NUM][8];
18ba0501acSDingqiang Lin static u8 die_cs_index[MAX_FLASH_NUM];
19ba0501acSDingqiang Lin static u8 g_nand_max_die;
20ba0501acSDingqiang Lin static u16 g_totle_block;
21ba0501acSDingqiang Lin static u8 g_nand_flash_ecc_bits;
22ba0501acSDingqiang Lin static u8 g_nand_idb_res_blk_num;
236f226dcaSJon Lin static u8 g_nand_ecc_en;
24ba0501acSDingqiang Lin 
25ba0501acSDingqiang Lin static struct NAND_PARA_INFO_T nand_para = {
26ba0501acSDingqiang Lin 	2,
27ba0501acSDingqiang Lin 	{0x98, 0xF1, 0, 0, 0, 0},
28ba0501acSDingqiang Lin 	TOSHIBA,
29ba0501acSDingqiang Lin 	1,
30ba0501acSDingqiang Lin 	4,
31ba0501acSDingqiang Lin 	64,
32ba0501acSDingqiang Lin 	1,
33ba0501acSDingqiang Lin 	1,
34ba0501acSDingqiang Lin 	1024,
35ba0501acSDingqiang Lin 	0x100,
36ba0501acSDingqiang Lin 	LSB_0,
37ba0501acSDingqiang Lin 	RR_NONE,
38ba0501acSDingqiang Lin 	16,
39ba0501acSDingqiang Lin 	40,
40ba0501acSDingqiang Lin 	1,
41ba0501acSDingqiang Lin 	0,
42ba0501acSDingqiang Lin 	BBF_1,
43ba0501acSDingqiang Lin 	MPM_0,
44ba0501acSDingqiang Lin 	{0}
45ba0501acSDingqiang Lin };	/* TC58NVG0S3HTA00 */
46ba0501acSDingqiang Lin 
flash_read_id_raw(u8 cs,u8 * buf)47ba0501acSDingqiang Lin static void flash_read_id_raw(u8 cs, u8 *buf)
48ba0501acSDingqiang Lin {
49ba0501acSDingqiang Lin 	u8 *ptr = (u8 *)buf;
50ba0501acSDingqiang Lin 
51ba0501acSDingqiang Lin 	nandc_flash_reset(cs);
52ba0501acSDingqiang Lin 	nandc_flash_cs(cs);
53ba0501acSDingqiang Lin 	nandc_writel(READ_ID_CMD, NANDC_CHIP_CMD(cs));
54ba0501acSDingqiang Lin 	nandc_writel(0x00, NANDC_CHIP_ADDR(cs));
55ba0501acSDingqiang Lin 	nandc_delayns(200);
56ba0501acSDingqiang Lin 
57ba0501acSDingqiang Lin 	ptr[0] = nandc_readl(NANDC_CHIP_DATA(cs));
58ba0501acSDingqiang Lin 	ptr[1] = nandc_readl(NANDC_CHIP_DATA(cs));
59ba0501acSDingqiang Lin 	ptr[2] = nandc_readl(NANDC_CHIP_DATA(cs));
60ba0501acSDingqiang Lin 	ptr[3] = nandc_readl(NANDC_CHIP_DATA(cs));
61ba0501acSDingqiang Lin 	ptr[4] = nandc_readl(NANDC_CHIP_DATA(cs));
62ba0501acSDingqiang Lin 	ptr[5] = nandc_readl(NANDC_CHIP_DATA(cs));
63ba0501acSDingqiang Lin 	ptr[6] = nandc_readl(NANDC_CHIP_DATA(cs));
64ba0501acSDingqiang Lin 	ptr[7] = nandc_readl(NANDC_CHIP_DATA(cs));
65ba0501acSDingqiang Lin 
66ba0501acSDingqiang Lin 	nandc_flash_de_cs(cs);
67ba0501acSDingqiang Lin 	if (ptr[0] != 0xFF && ptr[0] && ptr[1] != 0xFF)
68c84f0ed8SJon Lin 		rkflash_print_error("No.%d FLASH ID:%x %x %x %x %x %x\n",
69ba0501acSDingqiang Lin 				    cs + 1, ptr[0], ptr[1], ptr[2],
70ba0501acSDingqiang Lin 				    ptr[3], ptr[4], ptr[5]);
71ba0501acSDingqiang Lin }
72ba0501acSDingqiang Lin 
flash_bch_sel(u8 bits)73ba0501acSDingqiang Lin static void flash_bch_sel(u8 bits)
74ba0501acSDingqiang Lin {
75ba0501acSDingqiang Lin 	g_nand_flash_ecc_bits = bits;
76ba0501acSDingqiang Lin 	nandc_bch_sel(bits);
77ba0501acSDingqiang Lin }
78ba0501acSDingqiang Lin 
flash_set_sector(u8 num)7957d18453Sjon.lin static void flash_set_sector(u8 num)
8057d18453Sjon.lin {
8157d18453Sjon.lin 	nand_para.sec_per_page = num;
8257d18453Sjon.lin }
8357d18453Sjon.lin 
flash_timing_cfg(u32 ahb_khz)84ba0501acSDingqiang Lin static __maybe_unused void flash_timing_cfg(u32 ahb_khz)
85ba0501acSDingqiang Lin {
86ba0501acSDingqiang Lin 	nandc_time_cfg(nand_para.access_freq);
87ba0501acSDingqiang Lin }
88ba0501acSDingqiang Lin 
flash_read_cmd(u8 cs,u32 page_addr)89ba0501acSDingqiang Lin static void flash_read_cmd(u8 cs, u32 page_addr)
90ba0501acSDingqiang Lin {
91ba0501acSDingqiang Lin 	nandc_writel(READ_CMD >> 8, NANDC_CHIP_CMD(cs));
92ba0501acSDingqiang Lin 	nandc_writel(0x00, NANDC_CHIP_ADDR(cs));
93ba0501acSDingqiang Lin 	nandc_writel(0x00, NANDC_CHIP_ADDR(cs));
94ba0501acSDingqiang Lin 	nandc_writel(page_addr & 0x00ff, NANDC_CHIP_ADDR(cs));
95ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 8, NANDC_CHIP_ADDR(cs));
96ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 16, NANDC_CHIP_ADDR(cs));
97ba0501acSDingqiang Lin 	nandc_writel(READ_CMD & 0x00ff, NANDC_CHIP_CMD(cs));
98ba0501acSDingqiang Lin }
99ba0501acSDingqiang Lin 
flash_prog_first_cmd(u8 cs,u32 page_addr)100ba0501acSDingqiang Lin static void flash_prog_first_cmd(u8 cs, u32 page_addr)
101ba0501acSDingqiang Lin {
102ba0501acSDingqiang Lin 	nandc_writel(PAGE_PROG_CMD >> 8, NANDC_CHIP_CMD(cs));
103ba0501acSDingqiang Lin 	nandc_writel(0x00, NANDC_CHIP_ADDR(cs));
104ba0501acSDingqiang Lin 	nandc_writel(0x00, NANDC_CHIP_ADDR(cs));
105ba0501acSDingqiang Lin 	nandc_writel(page_addr & 0x00ff, NANDC_CHIP_ADDR(cs));
106ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 8, NANDC_CHIP_ADDR(cs));
107ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 16, NANDC_CHIP_ADDR(cs));
108ba0501acSDingqiang Lin }
109ba0501acSDingqiang Lin 
flash_erase_cmd(u8 cs,u32 page_addr)110ba0501acSDingqiang Lin static void flash_erase_cmd(u8 cs, u32 page_addr)
111ba0501acSDingqiang Lin {
112ba0501acSDingqiang Lin 	nandc_writel(BLOCK_ERASE_CMD >> 8, NANDC_CHIP_CMD(cs));
113ba0501acSDingqiang Lin 	nandc_writel(page_addr & 0x00ff, NANDC_CHIP_ADDR(cs));
114ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 8, NANDC_CHIP_ADDR(cs));
115ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 16, NANDC_CHIP_ADDR(cs));
116ba0501acSDingqiang Lin 	nandc_writel(BLOCK_ERASE_CMD & 0x00ff, NANDC_CHIP_CMD(cs));
117ba0501acSDingqiang Lin }
118ba0501acSDingqiang Lin 
flash_prog_second_cmd(u8 cs,u32 page_addr)119ba0501acSDingqiang Lin static void flash_prog_second_cmd(u8 cs, u32 page_addr)
120ba0501acSDingqiang Lin {
121660ca12eSJon Lin 	udelay(100);
122ba0501acSDingqiang Lin 	nandc_writel(PAGE_PROG_CMD & 0x00ff, NANDC_CHIP_CMD(cs));
123ba0501acSDingqiang Lin }
124ba0501acSDingqiang Lin 
flash_read_status(u8 cs,u32 page_addr)125ba0501acSDingqiang Lin static u32 flash_read_status(u8 cs, u32 page_addr)
126ba0501acSDingqiang Lin {
127ba0501acSDingqiang Lin 	nandc_writel(READ_STATUS_CMD, NANDC_CHIP_CMD(cs));
128ba0501acSDingqiang Lin 	nandc_delayns(80);
129ba0501acSDingqiang Lin 
130ba0501acSDingqiang Lin 	return nandc_readl(NANDC_CHIP_DATA(cs));
131ba0501acSDingqiang Lin }
132ba0501acSDingqiang Lin 
flash_read_random_dataout_cmd(u8 cs,u32 col_addr)133ba0501acSDingqiang Lin static void flash_read_random_dataout_cmd(u8 cs, u32 col_addr)
134ba0501acSDingqiang Lin {
135ba0501acSDingqiang Lin 	nandc_writel(READ_DP_OUT_CMD >> 8, NANDC_CHIP_CMD(cs));
136ba0501acSDingqiang Lin 	nandc_writel(col_addr & 0x00ff, NANDC_CHIP_ADDR(cs));
137ba0501acSDingqiang Lin 	nandc_writel(col_addr >> 8, NANDC_CHIP_ADDR(cs));
138ba0501acSDingqiang Lin 	nandc_writel(READ_DP_OUT_CMD & 0x00ff, NANDC_CHIP_CMD(cs));
139ba0501acSDingqiang Lin }
140ba0501acSDingqiang Lin 
flash_read_ecc(u8 cs)1416f226dcaSJon Lin static u32 flash_read_ecc(u8 cs)
1426f226dcaSJon Lin {
1436f226dcaSJon Lin 	u32 ecc0, ecc1;
1446f226dcaSJon Lin 
1456f226dcaSJon Lin 	nandc_writel(READ_ECC_STATUS_CMD, NANDC_CHIP_CMD(cs));
1466f226dcaSJon Lin 	nandc_delayns(80);
1476f226dcaSJon Lin 	ecc0 = nandc_readl(NANDC_CHIP_DATA(cs)) & 0xF;
1486f226dcaSJon Lin 	ecc1 = nandc_readl(NANDC_CHIP_DATA(cs)) & 0xF;
1496f226dcaSJon Lin 	if (ecc1 > ecc0)
1506f226dcaSJon Lin 		ecc0 = ecc1;
1516f226dcaSJon Lin 	ecc1 = nandc_readl(NANDC_CHIP_DATA(cs)) & 0xF;
1526f226dcaSJon Lin 	if (ecc1 > ecc0)
1536f226dcaSJon Lin 		ecc0 = ecc1;
1546f226dcaSJon Lin 	ecc1 = nandc_readl(NANDC_CHIP_DATA(cs)) & 0xF;
1556f226dcaSJon Lin 	if (ecc1 > ecc0)
1566f226dcaSJon Lin 		ecc0 = ecc1;
1576f226dcaSJon Lin 
1586f226dcaSJon Lin 	return ecc0;
1596f226dcaSJon Lin }
1606f226dcaSJon Lin 
flash_read_page_raw(u8 cs,u32 page_addr,u32 * p_data,u32 * p_spare)161ba0501acSDingqiang Lin static u32 flash_read_page_raw(u8 cs, u32 page_addr, u32 *p_data, u32 *p_spare)
162ba0501acSDingqiang Lin {
163c84f0ed8SJon Lin 	u32 error_ecc_bits, ret;
164ba0501acSDingqiang Lin 	u32 sec_per_page = nand_para.sec_per_page;
165c84f0ed8SJon Lin 	u32 nand_ecc = 0;
166ba0501acSDingqiang Lin 
167ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
168ba0501acSDingqiang Lin 	nandc_flash_cs(cs);
169ba0501acSDingqiang Lin 	flash_read_cmd(cs, page_addr);
170ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
171ba0501acSDingqiang Lin 	flash_read_random_dataout_cmd(cs, 0);
172ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
173ba0501acSDingqiang Lin 
174ba0501acSDingqiang Lin 	error_ecc_bits = nandc_xfer_data(cs, NANDC_READ, sec_per_page,
175ba0501acSDingqiang Lin 					 p_data, p_spare);
176c84f0ed8SJon Lin 
177ba0501acSDingqiang Lin 	nandc_flash_de_cs(cs);
178ba0501acSDingqiang Lin 
179ba0501acSDingqiang Lin 	if (error_ecc_bits != NAND_STS_ECC_ERR) {
1806f226dcaSJon Lin 		if (error_ecc_bits >= (u32)nand_para.ecc_bits - 3) {
181c84f0ed8SJon Lin 			ret = NAND_STS_REFRESH;
1826f226dcaSJon Lin 		} else {
183c84f0ed8SJon Lin 			ret = NAND_STS_OK;
1846f226dcaSJon Lin 			if (g_nand_ecc_en) {
185c84f0ed8SJon Lin 				nand_ecc = flash_read_ecc(cs);
1866f226dcaSJon Lin 
1876f226dcaSJon Lin 				if (nand_ecc >= 6) {
188c84f0ed8SJon Lin 					rkflash_print_error("%s nand ecc %x ecc %d\n",
1896f226dcaSJon Lin 							    __func__, page_addr, nand_ecc);
190c84f0ed8SJon Lin 					ret = NAND_STS_REFRESH;
1916f226dcaSJon Lin 				}
1926f226dcaSJon Lin 			}
1936f226dcaSJon Lin 		}
194c84f0ed8SJon Lin 	} else {
195c84f0ed8SJon Lin 		ret = NAND_STS_ECC_ERR;
196ba0501acSDingqiang Lin 	}
197c84f0ed8SJon Lin 	if (nand_ecc > 4 || error_ecc_bits > 4)
198c84f0ed8SJon Lin 		rkflash_print_info("%s %x %x nandc ecc= %d, internal ecc= %d\n",
199c84f0ed8SJon Lin 				   __func__, cs, page_addr, error_ecc_bits, nand_ecc);
200ba0501acSDingqiang Lin 
201c84f0ed8SJon Lin 	return ret;
202ba0501acSDingqiang Lin }
203ba0501acSDingqiang Lin 
flash_read_page(u8 cs,u32 page_addr,u32 * p_data,u32 * p_spare)204ba0501acSDingqiang Lin static u32 flash_read_page(u8 cs, u32 page_addr, u32 *p_data, u32 *p_spare)
205ba0501acSDingqiang Lin {
206c84f0ed8SJon Lin 	u32 ret, i = 0;
207ba0501acSDingqiang Lin 
208ba0501acSDingqiang Lin 	ret = flash_read_page_raw(cs, page_addr, p_data, p_spare);
2096f226dcaSJon Lin 	if (ret == NAND_STS_ECC_ERR) {
210c84f0ed8SJon Lin 		for (; i < 50; i++) {
211ba0501acSDingqiang Lin 			ret = flash_read_page_raw(cs, page_addr, p_data, p_spare);
2126f226dcaSJon Lin 			if (ret != NAND_STS_ECC_ERR) {
2136f226dcaSJon Lin 				ret = NAND_STS_REFRESH;
2146f226dcaSJon Lin 				break;
2156f226dcaSJon Lin 			}
2166f226dcaSJon Lin 		}
217c84f0ed8SJon Lin 		rkflash_print_error("%s %x err_ecc %d\n",
218c84f0ed8SJon Lin 				    __func__, page_addr, ret);
2196f226dcaSJon Lin 	}
220c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x retry=%x\n",
221c84f0ed8SJon Lin 			  __func__, page_addr, p_data[0], i);
222c84f0ed8SJon Lin 
223ba0501acSDingqiang Lin 	return ret;
224ba0501acSDingqiang Lin }
225ba0501acSDingqiang Lin 
flash_prog_page(u8 cs,u32 page_addr,u32 * p_data,u32 * p_spare)226ba0501acSDingqiang Lin static u32 flash_prog_page(u8 cs, u32 page_addr, u32 *p_data, u32 *p_spare)
227ba0501acSDingqiang Lin {
228ba0501acSDingqiang Lin 	u32 status;
229ba0501acSDingqiang Lin 	u32 sec_per_page = nand_para.sec_per_page;
230ba0501acSDingqiang Lin 
231c84f0ed8SJon Lin 	rkflash_print_dio("%s %x %x\n", __func__, page_addr, p_data[0]);
232ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
233ba0501acSDingqiang Lin 	nandc_flash_cs(cs);
234ba0501acSDingqiang Lin 	flash_prog_first_cmd(cs, page_addr);
235ba0501acSDingqiang Lin 	nandc_xfer_data(cs, NANDC_WRITE, sec_per_page, p_data, p_spare);
236ba0501acSDingqiang Lin 	flash_prog_second_cmd(cs, page_addr);
237ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
238ba0501acSDingqiang Lin 	status = flash_read_status(cs, page_addr);
239ba0501acSDingqiang Lin 	nandc_flash_de_cs(cs);
240ba0501acSDingqiang Lin 	status &= 0x01;
241c84f0ed8SJon Lin 	if (status)
242c84f0ed8SJon Lin 		rkflash_print_info("%s addr=%x status=%x\n",
243ba0501acSDingqiang Lin 				   __func__, page_addr, status);
244c84f0ed8SJon Lin 
245ba0501acSDingqiang Lin 	return status;
246ba0501acSDingqiang Lin }
247ba0501acSDingqiang Lin 
flash_erase_block(u8 cs,u32 page_addr)248ba0501acSDingqiang Lin static u32 flash_erase_block(u8 cs, u32 page_addr)
249ba0501acSDingqiang Lin {
250ba0501acSDingqiang Lin 	u32 status;
251ba0501acSDingqiang Lin 
252c84f0ed8SJon Lin 	rkflash_print_dio("%s %x\n", __func__, page_addr);
253ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
254ba0501acSDingqiang Lin 	nandc_flash_cs(cs);
255ba0501acSDingqiang Lin 	flash_erase_cmd(cs, page_addr);
256ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
257ba0501acSDingqiang Lin 	status = flash_read_status(cs, page_addr);
258ba0501acSDingqiang Lin 	nandc_flash_de_cs(cs);
259ba0501acSDingqiang Lin 	status &= 0x01;
260c84f0ed8SJon Lin 	if (status)
261c84f0ed8SJon Lin 		rkflash_print_info("%s pageadd=%x status=%x\n",
262ba0501acSDingqiang Lin 				   __func__, page_addr, status);
263c84f0ed8SJon Lin 
264ba0501acSDingqiang Lin 	return status;
265ba0501acSDingqiang Lin }
266ba0501acSDingqiang Lin 
flash_read_spare(u8 cs,u32 page_addr,u8 * spare)267ba0501acSDingqiang Lin static void flash_read_spare(u8 cs, u32 page_addr, u8 *spare)
268ba0501acSDingqiang Lin {
269ba0501acSDingqiang Lin 	u32 col = nand_para.sec_per_page << 9;
270ba0501acSDingqiang Lin 
271ba0501acSDingqiang Lin 	nandc_writel(READ_CMD >> 8, NANDC_CHIP_CMD(cs));
272ba0501acSDingqiang Lin 	nandc_writel(col, NANDC_CHIP_ADDR(cs));
273ba0501acSDingqiang Lin 	nandc_writel(col >> 8, NANDC_CHIP_ADDR(cs));
274ba0501acSDingqiang Lin 	nandc_writel(page_addr & 0x00ff, NANDC_CHIP_ADDR(cs));
275ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 8, NANDC_CHIP_ADDR(cs));
276ba0501acSDingqiang Lin 	nandc_writel(page_addr >> 16, NANDC_CHIP_ADDR(cs));
277ba0501acSDingqiang Lin 	nandc_writel(READ_CMD & 0x00ff, NANDC_CHIP_CMD(cs));
278ba0501acSDingqiang Lin 
279ba0501acSDingqiang Lin 	nandc_wait_flash_ready(cs);
280ba0501acSDingqiang Lin 
281ba0501acSDingqiang Lin 	*spare = nandc_readl(NANDC_CHIP_DATA(cs));
282ba0501acSDingqiang Lin }
283ba0501acSDingqiang Lin 
284ba0501acSDingqiang Lin /*
285ba0501acSDingqiang Lin  * Read the 1st page's 1st spare byte of a phy_blk
286ba0501acSDingqiang Lin  * If not FF, it's bad blk
287ba0501acSDingqiang Lin  */
flash_get_bad_blk_list(u16 * table,u32 die)288c84f0ed8SJon Lin static s32 flash_get_bad_blk_list(u16 *table, u32 die)
289ba0501acSDingqiang Lin {
290ba0501acSDingqiang Lin 	u16 blk;
291ba0501acSDingqiang Lin 	u32 bad_cnt, page_addr0, page_addr1, page_addr2;
292ba0501acSDingqiang Lin 	u32 blk_per_die;
293ba0501acSDingqiang Lin 	u8 bad_flag0, bad_flag1, bad_flag2;
294ba0501acSDingqiang Lin 
295ba0501acSDingqiang Lin 	bad_cnt = 0;
296ba0501acSDingqiang Lin 	blk_per_die = nand_para.plane_per_die * nand_para.blk_per_plane;
297ba0501acSDingqiang Lin 	for (blk = 0; blk < blk_per_die; blk++) {
298ba0501acSDingqiang Lin 		bad_flag0 = 0xFF;
299ba0501acSDingqiang Lin 		bad_flag1 = 0xFF;
300ba0501acSDingqiang Lin 		bad_flag2 = 0xFF;
301ba0501acSDingqiang Lin 		page_addr0 = (blk + blk_per_die * die) *
302ba0501acSDingqiang Lin 			nand_para.page_per_blk + 0;
303ba0501acSDingqiang Lin 		page_addr1 = page_addr0 + 1;
304ba0501acSDingqiang Lin 		page_addr2 = page_addr0 + nand_para.page_per_blk - 1;
305ba0501acSDingqiang Lin 		flash_read_spare(die, page_addr0, &bad_flag0);
306ba0501acSDingqiang Lin 		flash_read_spare(die, page_addr1, &bad_flag1);
307ba0501acSDingqiang Lin 		flash_read_spare(die, page_addr2, &bad_flag2);
308ba0501acSDingqiang Lin 		if (bad_flag0 != 0xFF ||
309ba0501acSDingqiang Lin 		    bad_flag1 != 0xFF ||
310ba0501acSDingqiang Lin 		    bad_flag2 != 0xFF) {
311ba0501acSDingqiang Lin 			table[bad_cnt++] = blk;
312c84f0ed8SJon Lin 			rkflash_print_error("die[%d], bad_blk[%d]\n", die, blk);
313ba0501acSDingqiang Lin 		}
314ba0501acSDingqiang Lin 	}
315ba0501acSDingqiang Lin 	return bad_cnt;
316ba0501acSDingqiang Lin }
317ba0501acSDingqiang Lin 
flash_die_info_init(void)318ba0501acSDingqiang Lin static void flash_die_info_init(void)
319ba0501acSDingqiang Lin {
320ba0501acSDingqiang Lin 	u32 cs;
321ba0501acSDingqiang Lin 
322ba0501acSDingqiang Lin 	g_nand_max_die = 0;
323ba0501acSDingqiang Lin 	for (cs = 0; cs < MAX_FLASH_NUM; cs++) {
324ba0501acSDingqiang Lin 		if (nand_para.nand_id[1] == id_byte[cs][1]) {
325ba0501acSDingqiang Lin 			die_cs_index[g_nand_max_die] = cs;
326ba0501acSDingqiang Lin 			g_nand_max_die++;
327ba0501acSDingqiang Lin 		}
328ba0501acSDingqiang Lin 	}
329ba0501acSDingqiang Lin 	g_totle_block = g_nand_max_die *  nand_para.plane_per_die *
330ba0501acSDingqiang Lin 			nand_para.blk_per_plane;
331ba0501acSDingqiang Lin }
332ba0501acSDingqiang Lin 
flash_show_info(void)333c84f0ed8SJon Lin static void flash_show_info(void)
334ba0501acSDingqiang Lin {
335c84f0ed8SJon Lin 	rkflash_print_info("No.0 FLASH ID: %x %x %x %x %x %x\n",
336ba0501acSDingqiang Lin 			   nand_para.nand_id[0],
337ba0501acSDingqiang Lin 			   nand_para.nand_id[1],
338ba0501acSDingqiang Lin 			   nand_para.nand_id[2],
339ba0501acSDingqiang Lin 			   nand_para.nand_id[3],
340ba0501acSDingqiang Lin 			   nand_para.nand_id[4],
341ba0501acSDingqiang Lin 			   nand_para.nand_id[5]);
342c84f0ed8SJon Lin 	rkflash_print_info("die_per_chip: %x\n", nand_para.die_per_chip);
343c84f0ed8SJon Lin 	rkflash_print_info("sec_per_page: %x\n", nand_para.sec_per_page);
344c84f0ed8SJon Lin 	rkflash_print_info("page_per_blk: %x\n", nand_para.page_per_blk);
345c84f0ed8SJon Lin 	rkflash_print_info("cell: %x\n", nand_para.cell);
346c84f0ed8SJon Lin 	rkflash_print_info("plane_per_die: %x\n", nand_para.plane_per_die);
347c84f0ed8SJon Lin 	rkflash_print_info("blk_per_plane: %x\n", nand_para.blk_per_plane);
348c84f0ed8SJon Lin 	rkflash_print_info("TotleBlock: %x\n", g_totle_block);
349c84f0ed8SJon Lin 	rkflash_print_info("die gap: %x\n", nand_para.die_gap);
350c84f0ed8SJon Lin 	rkflash_print_info("lsb_mode: %x\n", nand_para.lsb_mode);
351c84f0ed8SJon Lin 	rkflash_print_info("read_retry_mode: %x\n", nand_para.read_retry_mode);
352c84f0ed8SJon Lin 	rkflash_print_info("ecc_bits: %x\n", nand_para.ecc_bits);
353c84f0ed8SJon Lin 	rkflash_print_info("Use ecc_bits: %x\n", g_nand_flash_ecc_bits);
354c84f0ed8SJon Lin 	rkflash_print_info("access_freq: %x\n", nand_para.access_freq);
355c84f0ed8SJon Lin 	rkflash_print_info("opt_mode: %x\n", nand_para.opt_mode);
356ba0501acSDingqiang Lin 
357c84f0ed8SJon Lin 	rkflash_print_info("Cache read enable: %x\n",
358ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_CACHE_READ_EN ? 1 : 0);
359c84f0ed8SJon Lin 	rkflash_print_info("Cache random read enable: %x\n",
360ba0501acSDingqiang Lin 			   nand_para.operation_opt &
361ba0501acSDingqiang Lin 			   NAND_CACHE_RANDOM_READ_EN ? 1 : 0);
362c84f0ed8SJon Lin 	rkflash_print_info("Cache prog enable: %x\n",
363ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_CACHE_PROG_EN ? 1 : 0);
364c84f0ed8SJon Lin 	rkflash_print_info("multi read enable: %x\n",
365ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_MULTI_READ_EN ? 1 : 0);
366ba0501acSDingqiang Lin 
367c84f0ed8SJon Lin 	rkflash_print_info("multi prog enable: %x\n",
368ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_MULTI_PROG_EN ? 1 : 0);
369c84f0ed8SJon Lin 	rkflash_print_info("interleave enable: %x\n",
370ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_INTERLEAVE_EN ? 1 : 0);
371ba0501acSDingqiang Lin 
372c84f0ed8SJon Lin 	rkflash_print_info("read retry enable: %x\n",
373ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_READ_RETRY_EN ? 1 : 0);
374c84f0ed8SJon Lin 	rkflash_print_info("randomizer enable: %x\n",
375ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_RANDOMIZER_EN ? 1 : 0);
376ba0501acSDingqiang Lin 
377c84f0ed8SJon Lin 	rkflash_print_info("SDR enable: %x\n",
378ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_SDR_EN ? 1 : 0);
379c84f0ed8SJon Lin 	rkflash_print_info("ONFI enable: %x\n",
380ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_ONFI_EN ? 1 : 0);
381c84f0ed8SJon Lin 	rkflash_print_info("TOGGLE enable: %x\n",
382ba0501acSDingqiang Lin 			   nand_para.operation_opt & NAND_TOGGLE_EN ? 1 : 0);
383ba0501acSDingqiang Lin 
384c84f0ed8SJon Lin 	rkflash_print_info("g_nand_idb_res_blk_num: %x\n", g_nand_idb_res_blk_num);
385ba0501acSDingqiang Lin }
386ba0501acSDingqiang Lin 
flash_ftl_ops_init(void)387c84f0ed8SJon Lin static void flash_ftl_ops_init(void)
388ba0501acSDingqiang Lin {
38957d18453Sjon.lin 	u8 nandc_ver = nandc_get_version();
39057d18453Sjon.lin 
391ba0501acSDingqiang Lin 	/* para init */
392ba0501acSDingqiang Lin 	g_nand_phy_info.nand_type	= nand_para.cell;
393ba0501acSDingqiang Lin 	g_nand_phy_info.die_num		= nand_para.die_per_chip;
394ba0501acSDingqiang Lin 	g_nand_phy_info.plane_per_die	= nand_para.plane_per_die;
395ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_plane	= nand_para.blk_per_plane;
396ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_blk	= nand_para.page_per_blk;
397ba0501acSDingqiang Lin 	g_nand_phy_info.page_per_slc_blk	= nand_para.page_per_blk /
398ba0501acSDingqiang Lin 						  nand_para.cell;
399ba0501acSDingqiang Lin 	g_nand_phy_info.byte_per_sec	= 512;
400ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_page	= nand_para.sec_per_page;
401ba0501acSDingqiang Lin 	g_nand_phy_info.sec_per_blk	= nand_para.sec_per_page *
402ba0501acSDingqiang Lin 					  nand_para.page_per_blk;
403ba0501acSDingqiang Lin 	g_nand_phy_info.reserved_blk	= 8;
404ba0501acSDingqiang Lin 	g_nand_phy_info.blk_per_die	= nand_para.plane_per_die *
405ba0501acSDingqiang Lin 					  nand_para.blk_per_plane;
406ba0501acSDingqiang Lin 	g_nand_phy_info.ecc_bits	= nand_para.ecc_bits;
407ba0501acSDingqiang Lin 
408ba0501acSDingqiang Lin 	/* driver register */
409c84f0ed8SJon Lin 	g_nand_ops.get_bad_blk_list	= flash_get_bad_blk_list;
410ba0501acSDingqiang Lin 	g_nand_ops.erase_blk		= flash_erase_block;
411ba0501acSDingqiang Lin 	g_nand_ops.prog_page		= flash_prog_page;
412ba0501acSDingqiang Lin 	g_nand_ops.read_page		= flash_read_page;
41357d18453Sjon.lin 	if (nandc_ver == 9) {
41457d18453Sjon.lin 		g_nand_ops.bch_sel = flash_bch_sel;
41557d18453Sjon.lin 		g_nand_ops.set_sec_num = flash_set_sector;
41657d18453Sjon.lin 	}
417ba0501acSDingqiang Lin }
418ba0501acSDingqiang Lin 
nandc_flash_reset(u8 cs)419c84f0ed8SJon Lin void nandc_flash_reset(u8 cs)
420c84f0ed8SJon Lin {
421c84f0ed8SJon Lin 	nandc_flash_cs(cs);
422c84f0ed8SJon Lin 	nandc_writel(RESET_CMD, NANDC_CHIP_CMD(cs));
423c84f0ed8SJon Lin 	nandc_wait_flash_ready(cs);
424c84f0ed8SJon Lin 	nandc_flash_de_cs(cs);
425c84f0ed8SJon Lin }
426c84f0ed8SJon Lin 
nandc_flash_init(void __iomem * nandc_addr)427ba0501acSDingqiang Lin u32 nandc_flash_init(void __iomem *nandc_addr)
428ba0501acSDingqiang Lin {
429ba0501acSDingqiang Lin 	u32 cs;
430ba0501acSDingqiang Lin 
431c84f0ed8SJon Lin 	rkflash_print_error("...%s enter...\n", __func__);
432ba0501acSDingqiang Lin 	g_nand_idb_res_blk_num = MAX_IDB_RESERVED_BLOCK;
4336f226dcaSJon Lin 	g_nand_ecc_en = 0;
434ba0501acSDingqiang Lin 
435ba0501acSDingqiang Lin 	nandc_init(nandc_addr);
436ba0501acSDingqiang Lin 
437ba0501acSDingqiang Lin 	for (cs = 0; cs < MAX_FLASH_NUM; cs++) {
438ba0501acSDingqiang Lin 		flash_read_id_raw(cs, id_byte[cs]);
439ba0501acSDingqiang Lin 		if (cs == 0) {
440ba0501acSDingqiang Lin 			if (id_byte[0][0] == 0xFF ||
441ba0501acSDingqiang Lin 			    id_byte[0][0] == 0 ||
442ba0501acSDingqiang Lin 			    id_byte[0][1] == 0xFF)
443ba0501acSDingqiang Lin 				return FTL_NO_FLASH;
444ba0501acSDingqiang Lin 			if (id_byte[0][1] != 0xF1 &&
445ba0501acSDingqiang Lin 			    id_byte[0][1] != 0xDA &&
446ba0501acSDingqiang Lin 			    id_byte[0][1] != 0xD1 &&
447ba0501acSDingqiang Lin 			    id_byte[0][1] != 0x95 &&
4486e9d994eSJon Lin 			    id_byte[0][1] != 0xDC &&
449c84f0ed8SJon Lin 			    id_byte[0][1] != 0xD3 &&
450fc8db7dcSJon Lin 			    id_byte[0][1] != 0x48 &&
4514c6453e8SJon Lin 			    id_byte[0][1] != 0xA1 &&
4524c6453e8SJon Lin 			    id_byte[0][1] != 0xAA &&
4534c6453e8SJon Lin 			    id_byte[0][1] != 0xAC &&
4545edd0d92SJon Lin 			    id_byte[0][1] != 0x6A &&
455*e5e85009SJon Lin 			    id_byte[0][1] != 0xD7 &&
456*e5e85009SJon Lin 			    id_byte[0][1] != 0x63) {
4575edd0d92SJon Lin 				pr_err("The device not support yet!\n");
4585edd0d92SJon Lin 
459ba0501acSDingqiang Lin 				return FTL_UNSUPPORTED_FLASH;
460ba0501acSDingqiang Lin 			}
4615edd0d92SJon Lin 
4620603e0bdSJon Lin 			if (id_byte[0][1] == 0xD7 && nandc_get_version() != 9) {
4635edd0d92SJon Lin 				pr_err("This device is not compatible, Insufficient ECC capability\n");
4645edd0d92SJon Lin 
4655edd0d92SJon Lin 				return FTL_UNSUPPORTED_FLASH;
4665edd0d92SJon Lin 			}
4675edd0d92SJon Lin 		}
468ba0501acSDingqiang Lin 	}
4696f226dcaSJon Lin 	if (id_byte[0][0] == 0x98 && (id_byte[0][4] & 0x80))
4706f226dcaSJon Lin 		g_nand_ecc_en = 1;
471ba0501acSDingqiang Lin 	nand_para.nand_id[1] = id_byte[0][1];
4724c6453e8SJon Lin 	if (id_byte[0][1] == 0xDA || id_byte[0][1] == 0xAA || id_byte[0][1] == 0x6A) {
473ba0501acSDingqiang Lin 		nand_para.plane_per_die = 2;
4744c6453e8SJon Lin 		nand_para.nand_id[1] = id_byte[0][1];
4754c6453e8SJon Lin 	} else if (id_byte[0][1] == 0xDC || id_byte[0][1] == 0xAC) {
4764c6453e8SJon Lin 		nand_para.nand_id[1] = id_byte[0][1];
477c84f0ed8SJon Lin 		if ((id_byte[0][0] == 0x2C && id_byte[0][3] == 0xA6) ||
478c84f0ed8SJon Lin 		    (id_byte[0][0] == 0xC2 && id_byte[0][3] == 0xA2)) {
479ba0501acSDingqiang Lin 			nand_para.plane_per_die = 2;
480ba0501acSDingqiang Lin 			nand_para.sec_per_page = 8;
481fc8db7dcSJon Lin 		} else if ((id_byte[0][0] == 0x98 && id_byte[0][3] == 0x26) ||
4820603e0bdSJon Lin 			   (id_byte[0][0] == 0xC8 && id_byte[0][2] == 0x80 && ((id_byte[0][3] & 0x3) == 1)) || /* F59L4G81KA (2R) */
4830603e0bdSJon Lin 			   (id_byte[0][0] == 0xC8 && id_byte[0][2] == 0x90 && ((id_byte[0][3] & 0x3) == 2))) { /* GD9F4GxF2A */
4846e9d994eSJon Lin 			nand_para.blk_per_plane = 1024;
48557d18453Sjon.lin 			nand_para.sec_per_page = 8;
4866f226dcaSJon Lin 			nand_para.plane_per_die = 2;
487ba0501acSDingqiang Lin 		} else {
488ba0501acSDingqiang Lin 			nand_para.plane_per_die = 2;
489ba0501acSDingqiang Lin 			nand_para.blk_per_plane = 2048;
490ba0501acSDingqiang Lin 		}
4916e9d994eSJon Lin 	} else if (id_byte[0][1] == 0x48) {
4926e9d994eSJon Lin 		nand_para.sec_per_page = 8;
4936e9d994eSJon Lin 		nand_para.page_per_blk = 128;
4946e9d994eSJon Lin 		nand_para.plane_per_die = 2;
4956e9d994eSJon Lin 		nand_para.blk_per_plane = 2048;
496c84f0ed8SJon Lin 	} else if (id_byte[0][1] == 0xD3) {
4970603e0bdSJon Lin 		if ((id_byte[0][2] == 0xD1 && id_byte[0][4] == 0x5a) || /* S34ML08G2 */
4980603e0bdSJon Lin 		    (id_byte[0][3] == 0x05 && id_byte[0][4] == 0x04)) { /* S34ML08G3 */
4990603e0bdSJon Lin 			nand_para.sec_per_page = 4;
5000603e0bdSJon Lin 			nand_para.page_per_blk = 64;
5010603e0bdSJon Lin 			nand_para.plane_per_die = 2;
5020603e0bdSJon Lin 			nand_para.blk_per_plane = 4096;
5030603e0bdSJon Lin 		} else {
504c84f0ed8SJon Lin 			nand_para.sec_per_page = 8;
505c84f0ed8SJon Lin 			nand_para.page_per_blk = 64;
506c84f0ed8SJon Lin 			nand_para.plane_per_die = 2;
507c84f0ed8SJon Lin 			nand_para.blk_per_plane = 2048;
5080603e0bdSJon Lin 		}
5090603e0bdSJon Lin 	} else if (id_byte[0][1] == 0xD7 && id_byte[0][3] == 0x32) { /* TC58NVG5H2HTAI0 */
5100603e0bdSJon Lin 		nand_para.ecc_bits = 70;
5115edd0d92SJon Lin 		nand_para.blk_per_plane = 2048;
5125edd0d92SJon Lin 		nand_para.sec_per_page = 16;
5135edd0d92SJon Lin 		nand_para.page_per_blk = 128;
5145edd0d92SJon Lin 		nand_para.plane_per_die = 2;
515*e5e85009SJon Lin 	} else if (id_byte[0][1] == 0x63 && id_byte[0][3] == 0x19) { /* IS34ML08G088 */
516*e5e85009SJon Lin 		nand_para.sec_per_page = 8;
517*e5e85009SJon Lin 		nand_para.page_per_blk = 64;
518*e5e85009SJon Lin 		nand_para.plane_per_die = 2;
519*e5e85009SJon Lin 		nand_para.blk_per_plane = 2048;
520ba0501acSDingqiang Lin 	}
521ba0501acSDingqiang Lin 	flash_die_info_init();
522ba0501acSDingqiang Lin 	flash_bch_sel(nand_para.ecc_bits);
523c84f0ed8SJon Lin 	flash_show_info();
524c84f0ed8SJon Lin 	flash_ftl_ops_init();
525ba0501acSDingqiang Lin 
526ba0501acSDingqiang Lin 	return 0;
527ba0501acSDingqiang Lin }
528ba0501acSDingqiang Lin 
nandc_flash_get_id(u8 cs,void * buf)529ba0501acSDingqiang Lin void nandc_flash_get_id(u8 cs, void *buf)
530ba0501acSDingqiang Lin {
531ba0501acSDingqiang Lin 	memcpy(buf, id_byte[cs], 5);
532ba0501acSDingqiang Lin }
533ba0501acSDingqiang Lin 
nandc_flash_deinit(void)534ba0501acSDingqiang Lin u32 nandc_flash_deinit(void)
535ba0501acSDingqiang Lin {
536ba0501acSDingqiang Lin 	return 0;
537ba0501acSDingqiang Lin }
538