xref: /rk3399_rockchip-uboot/drivers/rkflash/nandc.c (revision 98c8a00dcbd893276c6d18a88e8e1ad17b089d59)
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/compat.h>
9ba0501acSDingqiang Lin #include <linux/delay.h>
10ba0501acSDingqiang Lin 
11ba0501acSDingqiang Lin #include "flash.h"
12ba0501acSDingqiang Lin #include "flash_com.h"
13ba0501acSDingqiang Lin #include "nandc.h"
14cd67f373SDingqiang Lin #include "rk_sftl.h"
15ba0501acSDingqiang Lin 
16ba0501acSDingqiang Lin #define     CPU_DELAY_NS(n)	ndelay(n)
17*98c8a00dSJon Lin #define     usleep_range(a, b)	udelay((b))
18ba0501acSDingqiang Lin 
19ba0501acSDingqiang Lin #define	    NANDC_MASTER_EN
20ba0501acSDingqiang Lin 
21ba0501acSDingqiang Lin void __iomem *nandc_base;
2227ffef75SDingqiang Lin static u8 g_nandc_ver;
23ba0501acSDingqiang Lin 
24ba0501acSDingqiang Lin static u32 g_nandc_ecc_bits;
25ba0501acSDingqiang Lin #ifdef NANDC_MASTER_EN
26ba0501acSDingqiang Lin static struct MASTER_INFO_T master;
27ba0501acSDingqiang Lin static u32 *g_master_temp_buf;
28ba0501acSDingqiang Lin #endif
29ba0501acSDingqiang Lin 
nandc_get_version(void)3057d18453Sjon.lin u8 nandc_get_version(void)
3157d18453Sjon.lin {
3257d18453Sjon.lin 	return g_nandc_ver;
3357d18453Sjon.lin }
3457d18453Sjon.lin 
nandc_init(void __iomem * nandc_addr)35ba0501acSDingqiang Lin void nandc_init(void __iomem *nandc_addr)
36ba0501acSDingqiang Lin {
37ba0501acSDingqiang Lin 	union FM_CTL_T ctl_reg;
38ba0501acSDingqiang Lin 
39ba0501acSDingqiang Lin 	nandc_base = nandc_addr;
40ba0501acSDingqiang Lin 
41ba0501acSDingqiang Lin 	ctl_reg.d32 = 0;
4227ffef75SDingqiang Lin 	g_nandc_ver = 6;
4327ffef75SDingqiang Lin 	if (nandc_readl(NANDC_V9_NANDC_VER) == RK3326_NANDC_VER)
4427ffef75SDingqiang Lin 		g_nandc_ver = 9;
4527ffef75SDingqiang Lin 	if (g_nandc_ver == 9) {
4627ffef75SDingqiang Lin 		ctl_reg.V9.wp = 1;
4727ffef75SDingqiang Lin 		ctl_reg.V9.sif_read_delay = 2;
4827ffef75SDingqiang Lin 		nandc_writel(ctl_reg.d32, NANDC_V9_FMCTL);
4927ffef75SDingqiang Lin 		nandc_writel(0, NANDC_V9_RANDMZ_CFG);
5027ffef75SDingqiang Lin 		nandc_writel(0x1041, NANDC_V9_FMWAIT);
5127ffef75SDingqiang Lin 	} else {
52ba0501acSDingqiang Lin 		ctl_reg.V6.wp = 1;
53ba0501acSDingqiang Lin 		nandc_writel(ctl_reg.d32, NANDC_FMCTL);
54ba0501acSDingqiang Lin 		nandc_writel(0, NANDC_RANDMZ_CFG);
5527ffef75SDingqiang Lin 		nandc_writel(0x1061, NANDC_FMWAIT);
5627ffef75SDingqiang Lin 	}
57ba0501acSDingqiang Lin 	nandc_time_cfg(40);
58ba0501acSDingqiang Lin 
59ba0501acSDingqiang Lin #ifdef NANDC_MASTER_EN
60ba0501acSDingqiang Lin 	if (!g_master_temp_buf)
61ba0501acSDingqiang Lin 		g_master_temp_buf = (u32 *)ftl_malloc(MAX_FLASH_PAGE_SIZE +
62ba0501acSDingqiang Lin 					      MAX_FLASH_PAGE_SIZE / 8);
63ba0501acSDingqiang Lin 	master.page_buf = &g_master_temp_buf[0];
64ba0501acSDingqiang Lin 	master.spare_buf = &g_master_temp_buf[MAX_FLASH_PAGE_SIZE / 4];
65ba0501acSDingqiang Lin 	master.mapped = 0;
66ba0501acSDingqiang Lin #endif
67ba0501acSDingqiang Lin }
68ba0501acSDingqiang Lin 
nandc_flash_cs(u8 chip_sel)69ba0501acSDingqiang Lin void nandc_flash_cs(u8 chip_sel)
70ba0501acSDingqiang Lin {
71ba0501acSDingqiang Lin 	union FM_CTL_T tmp;
72ba0501acSDingqiang Lin 
73ba0501acSDingqiang Lin 	tmp.d32 = nandc_readl(NANDC_FMCTL);
74ba0501acSDingqiang Lin 	tmp.V6.cs = 0x01 << chip_sel;
75ba0501acSDingqiang Lin 	nandc_writel(tmp.d32, NANDC_FMCTL);
76ba0501acSDingqiang Lin }
77ba0501acSDingqiang Lin 
nandc_flash_de_cs(u8 chip_sel)78ba0501acSDingqiang Lin void nandc_flash_de_cs(u8 chip_sel)
79ba0501acSDingqiang Lin {
80ba0501acSDingqiang Lin 	union FM_CTL_T tmp;
81ba0501acSDingqiang Lin 
82ba0501acSDingqiang Lin 	tmp.d32 = nandc_readl(NANDC_FMCTL);
83ba0501acSDingqiang Lin 	tmp.V6.cs = 0;
84ba0501acSDingqiang Lin 	tmp.V6.flash_abort_clear = 0;
85ba0501acSDingqiang Lin 	nandc_writel(tmp.d32, NANDC_FMCTL);
86ba0501acSDingqiang Lin }
87ba0501acSDingqiang Lin 
nandc_delayns(u32 count)88ba0501acSDingqiang Lin u32 nandc_delayns(u32 count)
89ba0501acSDingqiang Lin {
90ba0501acSDingqiang Lin 	CPU_DELAY_NS(count);
91ba0501acSDingqiang Lin 	return 0;
92ba0501acSDingqiang Lin }
93ba0501acSDingqiang Lin 
nandc_wait_flash_ready(u8 chip_sel)94ba0501acSDingqiang Lin u32 nandc_wait_flash_ready(u8 chip_sel)
95ba0501acSDingqiang Lin {
96ba0501acSDingqiang Lin 	union FM_CTL_T tmp;
97ba0501acSDingqiang Lin 	u32 status;
98ba0501acSDingqiang Lin 	u32 i;
99ba0501acSDingqiang Lin 
100ba0501acSDingqiang Lin 	status = 0;
101ba0501acSDingqiang Lin 	for (i = 0; i < 100000; i++) {
102ba0501acSDingqiang Lin 		nandc_delayns(100);
103ba0501acSDingqiang Lin 		tmp.d32 = nandc_readl(NANDC_FMCTL);
104ba0501acSDingqiang Lin 		if (tmp.V6.rdy != 0)
105ba0501acSDingqiang Lin 			break;
106ba0501acSDingqiang Lin 	}
107ba0501acSDingqiang Lin 
108ba0501acSDingqiang Lin 	if (i >= 100000)
109ba0501acSDingqiang Lin 		status = -1;
110ba0501acSDingqiang Lin 	return status;
111ba0501acSDingqiang Lin }
112ba0501acSDingqiang Lin 
nandc_randmz_sel(u8 chip_sel,u32 randmz_seed)113ba0501acSDingqiang Lin void nandc_randmz_sel(u8 chip_sel, u32 randmz_seed)
114ba0501acSDingqiang Lin {
115ba0501acSDingqiang Lin 	nandc_writel(randmz_seed, NANDC_RANDMZ_CFG);
116ba0501acSDingqiang Lin }
117ba0501acSDingqiang Lin 
nandc_time_cfg(u32 ns)118ba0501acSDingqiang Lin void nandc_time_cfg(u32 ns)
119ba0501acSDingqiang Lin {
12027ffef75SDingqiang Lin 	if (g_nandc_ver == 9) {
12127ffef75SDingqiang Lin 		if (ns < 36)
12227ffef75SDingqiang Lin 			nandc_writel(0x1041, NANDC_V9_FMWAIT);
12327ffef75SDingqiang Lin 		else if (ns >= 100)
12427ffef75SDingqiang Lin 			nandc_writel(0x2082, NANDC_V9_FMWAIT);
12527ffef75SDingqiang Lin 		else
12627ffef75SDingqiang Lin 			nandc_writel(0x1061, NANDC_V9_FMWAIT);
12727ffef75SDingqiang Lin 	} else {
128ba0501acSDingqiang Lin 		if (ns < 36)
129ba0501acSDingqiang Lin 			nandc_writel(0x1061, NANDC_FMWAIT);
130ba0501acSDingqiang Lin 		else if (ns >= 100)
131ba0501acSDingqiang Lin 			nandc_writel(0x2082, NANDC_FMWAIT);
132ba0501acSDingqiang Lin 		else
133ba0501acSDingqiang Lin 			nandc_writel(0x1081, NANDC_FMWAIT);
134ba0501acSDingqiang Lin 	}
13527ffef75SDingqiang Lin }
136ba0501acSDingqiang Lin 
nandc_bch_sel(u8 bits)137ba0501acSDingqiang Lin void nandc_bch_sel(u8 bits)
138ba0501acSDingqiang Lin {
139ba0501acSDingqiang Lin 	union BCH_CTL_T tmp;
140ba0501acSDingqiang Lin 	union FL_CTL_T fl_reg;
14127ffef75SDingqiang Lin 	u8 bch_config;
142ba0501acSDingqiang Lin 
143ba0501acSDingqiang Lin 	fl_reg.d32 = 0;
144ba0501acSDingqiang Lin 	fl_reg.V6.rst = 1;
145ba0501acSDingqiang Lin 	g_nandc_ecc_bits = bits;
14627ffef75SDingqiang Lin 	if (g_nandc_ver == 9) {
14727ffef75SDingqiang Lin 		nandc_writel(fl_reg.d32, NANDC_V9_FLCTL);
14827ffef75SDingqiang Lin 		if (bits == 70)
14927ffef75SDingqiang Lin 			bch_config = 0;
15027ffef75SDingqiang Lin 		else if (bits == 60)
15127ffef75SDingqiang Lin 			bch_config = 3;
15227ffef75SDingqiang Lin 		else if (bits == 40)
15327ffef75SDingqiang Lin 			bch_config = 2;
15427ffef75SDingqiang Lin 		else
15527ffef75SDingqiang Lin 			bch_config = 1;
15627ffef75SDingqiang Lin 		tmp.d32 = 0;
15727ffef75SDingqiang Lin 		tmp.V9.bchmode = bch_config;
15827ffef75SDingqiang Lin 		tmp.V9.bchrst = 1;
15927ffef75SDingqiang Lin 		nandc_writel(tmp.d32, NANDC_V9_BCHCTL);
16027ffef75SDingqiang Lin 	} else {
16127ffef75SDingqiang Lin 		nandc_writel(fl_reg.d32, NANDC_FLCTL);
162ba0501acSDingqiang Lin 		tmp.d32 = 0;
163ba0501acSDingqiang Lin 		tmp.V6.addr = 0x10;
164ba0501acSDingqiang Lin 		tmp.V6.bch_mode1 = 0;
165ba0501acSDingqiang Lin 		if (bits == 16) {
166ba0501acSDingqiang Lin 			tmp.V6.bch_mode = 0;
167ba0501acSDingqiang Lin 		} else if (bits == 24) {
168ba0501acSDingqiang Lin 			tmp.V6.bch_mode = 1;
169ba0501acSDingqiang Lin 		} else {
170ba0501acSDingqiang Lin 			tmp.V6.bch_mode1 = 1;
171ba0501acSDingqiang Lin 			tmp.V6.bch_mode = 1;
172ba0501acSDingqiang Lin 			if (bits == 40)
173ba0501acSDingqiang Lin 				tmp.V6.bch_mode = 0;
174ba0501acSDingqiang Lin 		}
175ba0501acSDingqiang Lin 		tmp.V6.rst = 1;
176ba0501acSDingqiang Lin 		nandc_writel(tmp.d32, NANDC_BCHCTL);
177ba0501acSDingqiang Lin 	}
17827ffef75SDingqiang Lin }
179ba0501acSDingqiang Lin 
18027ffef75SDingqiang Lin /*
18127ffef75SDingqiang Lin  *Nandc xfer data transmission
18227ffef75SDingqiang Lin  *1. set bch register except nandc version equals 9
18327ffef75SDingqiang Lin  *2. set internal transfer control register
18427ffef75SDingqiang Lin  *3. set bus transfer
18527ffef75SDingqiang Lin  *	a. target memory data address
18627ffef75SDingqiang Lin  *	b. ahb setting
18727ffef75SDingqiang Lin  *4. configure register orderly and start transmission
18827ffef75SDingqiang Lin  */
nandc_xfer_start(u8 dir,u8 n_sec,u32 * data,u32 * spare)18927ffef75SDingqiang Lin static void nandc_xfer_start(u8 dir, u8 n_sec, u32 *data, u32 *spare)
190ba0501acSDingqiang Lin {
191ba0501acSDingqiang Lin 	union BCH_CTL_T bch_reg;
192ba0501acSDingqiang Lin 	union FL_CTL_T fl_reg;
193ba0501acSDingqiang Lin 	u32 i;
194ba0501acSDingqiang Lin 	union MTRANS_CFG_T master_reg;
19527ffef75SDingqiang Lin 	u16 *p_spare_tmp = (u16 *)spare;
19627ffef75SDingqiang Lin 	unsigned long vir_addr;
197ba0501acSDingqiang Lin 
198ba0501acSDingqiang Lin 	fl_reg.d32 = 0;
19927ffef75SDingqiang Lin 	if (g_nandc_ver == 9) {
20027ffef75SDingqiang Lin 		fl_reg.V9.flash_rdn = dir;
20127ffef75SDingqiang Lin 		fl_reg.V9.bypass = 1;
20227ffef75SDingqiang Lin 		fl_reg.V9.tr_count = 1;
20327ffef75SDingqiang Lin 		fl_reg.V9.async_tog_mix = 1;
20427ffef75SDingqiang Lin 		fl_reg.V9.cor_able = 1;
20527ffef75SDingqiang Lin 		fl_reg.V9.st_addr = 0;
20627ffef75SDingqiang Lin 		fl_reg.V9.page_num = (n_sec + 1) / 2;
20727ffef75SDingqiang Lin 		/* dma start transfer data do care flash rdy */
20827ffef75SDingqiang Lin 		fl_reg.V9.flash_st_mod = 1;
20927ffef75SDingqiang Lin 
21027ffef75SDingqiang Lin 		if (dir != 0) {
21127ffef75SDingqiang Lin 			for (i = 0; i < n_sec / 2; i++) {
21227ffef75SDingqiang Lin 				if (spare) {
21327ffef75SDingqiang Lin 					master.spare_buf[i] =
21427ffef75SDingqiang Lin 						(p_spare_tmp[0]) |
21527ffef75SDingqiang Lin 						((u32)p_spare_tmp[1] << 16);
21627ffef75SDingqiang Lin 					p_spare_tmp += 2;
21727ffef75SDingqiang Lin 				} else {
21827ffef75SDingqiang Lin 					master.spare_buf[i] = 0xffffffff;
21927ffef75SDingqiang Lin 				}
22027ffef75SDingqiang Lin 			}
22127ffef75SDingqiang Lin 		} else {
22227ffef75SDingqiang Lin 			master.spare_buf[0] = 1;
22327ffef75SDingqiang Lin 		}
22427ffef75SDingqiang Lin 		master.page_vir = (u32 *)((data == (u32 *)NULL) ?
22527ffef75SDingqiang Lin 					  master.page_buf :
22627ffef75SDingqiang Lin 					  (u32 *)data);
22727ffef75SDingqiang Lin 		master.spare_vir = (u32 *)master.spare_buf;
22827ffef75SDingqiang Lin 
22927ffef75SDingqiang Lin 		master.page_phy = (u32)((unsigned long)master.page_vir);
23027ffef75SDingqiang Lin 		master.spare_phy = (u32)((unsigned long)master.spare_vir);
23127ffef75SDingqiang Lin 		vir_addr = ((unsigned long)master.page_phy);
23227ffef75SDingqiang Lin 		flush_dcache_range(vir_addr & (~0x3FuL),
23327ffef75SDingqiang Lin 				   ((vir_addr + 63) & (~0x3FuL)) +
23427ffef75SDingqiang Lin 					fl_reg.V6.page_num * 1024);
23527ffef75SDingqiang Lin 		vir_addr = ((unsigned long)master.spare_phy);
23627ffef75SDingqiang Lin 		flush_dcache_range(vir_addr & (~0x3FuL),
23727ffef75SDingqiang Lin 				   ((vir_addr + 63) & (~0x3FuL)) +
23827ffef75SDingqiang Lin 					fl_reg.V6.page_num * 128);
23927ffef75SDingqiang Lin 		master.mapped = 1;
24027ffef75SDingqiang Lin 		nandc_writel(master.page_phy, NANDC_V9_MTRANS_SADDR0);
24127ffef75SDingqiang Lin 		nandc_writel(master.spare_phy, NANDC_V9_MTRANS_SADDR1);
24227ffef75SDingqiang Lin 
24327ffef75SDingqiang Lin 		master_reg.d32 =  nandc_readl(NANDC_V9_MTRANS_CFG);
24427ffef75SDingqiang Lin 		master_reg.V9.incr_num = 16;
24527ffef75SDingqiang Lin 		master_reg.V9.burst = 7;
24627ffef75SDingqiang Lin 		master_reg.V9.hsize = 2;
24727ffef75SDingqiang Lin 		master_reg.V9.bus_mode = 1;
24827ffef75SDingqiang Lin 		master_reg.V9.ahb_wr = !dir;
24927ffef75SDingqiang Lin 		master_reg.V9.ahb_wr_st = 1;
25027ffef75SDingqiang Lin 		master_reg.V9.redundance_size = 0;
25127ffef75SDingqiang Lin 
25227ffef75SDingqiang Lin 		nandc_writel(master_reg.d32, NANDC_V9_MTRANS_CFG);
25327ffef75SDingqiang Lin 		nandc_writel(fl_reg.d32, NANDC_V9_FLCTL);
25427ffef75SDingqiang Lin 		fl_reg.V9.flash_st = 1;
25527ffef75SDingqiang Lin 		nandc_writel(fl_reg.d32, NANDC_V9_FLCTL);
25627ffef75SDingqiang Lin 	} else {
257ba0501acSDingqiang Lin 		bch_reg.d32 = nandc_readl(NANDC_BCHCTL);
258ba0501acSDingqiang Lin 		bch_reg.V6.addr = 0x10;
259ba0501acSDingqiang Lin 		bch_reg.V6.power_down = 0;
26027ffef75SDingqiang Lin 		bch_reg.V6.region = 0;
261ba0501acSDingqiang Lin 
262ba0501acSDingqiang Lin 		fl_reg.V6.rdn = dir;
263ba0501acSDingqiang Lin 		fl_reg.V6.dma = 1;
264ba0501acSDingqiang Lin 		fl_reg.V6.tr_count = 1;
265ba0501acSDingqiang Lin 		fl_reg.V6.async_tog_mix = 1;
266ba0501acSDingqiang Lin 		fl_reg.V6.cor_en = 1;
26727ffef75SDingqiang Lin 		fl_reg.V6.st_addr = 0;
268ba0501acSDingqiang Lin 
269ba0501acSDingqiang Lin 		master_reg.d32 = nandc_readl(NANDC_MTRANS_CFG);
270ba0501acSDingqiang Lin 		master_reg.V6.bus_mode = 0;
27127ffef75SDingqiang Lin 		if (dir != 0) {
272ba0501acSDingqiang Lin 			u32 spare_sz = 64;
273ba0501acSDingqiang Lin 
27427ffef75SDingqiang Lin 			for (i = 0; i < n_sec / 2; i++) {
27527ffef75SDingqiang Lin 				if (spare) {
276ba0501acSDingqiang Lin 					master.spare_buf[i * spare_sz / 4] =
27727ffef75SDingqiang Lin 					(p_spare_tmp[0]) |
27827ffef75SDingqiang Lin 					((u32)p_spare_tmp[1] << 16);
279ba0501acSDingqiang Lin 					p_spare_tmp += 2;
280ba0501acSDingqiang Lin 				} else {
281ba0501acSDingqiang Lin 					master.spare_buf[i * spare_sz / 4] =
282ba0501acSDingqiang Lin 					0xffffffff;
283ba0501acSDingqiang Lin 				}
284ba0501acSDingqiang Lin 			}
285ba0501acSDingqiang Lin 		}
28627ffef75SDingqiang Lin 		fl_reg.V6.page_num = (n_sec + 1) / 2;
28727ffef75SDingqiang Lin 		master.page_vir = (u32 *)((data == (u32 *)NULL) ?
288ba0501acSDingqiang Lin 					  master.page_buf :
28927ffef75SDingqiang Lin 					  (u32 *)data);
290ba0501acSDingqiang Lin 		master.spare_vir = (u32 *)master.spare_buf;
291ba0501acSDingqiang Lin 
292ba0501acSDingqiang Lin 		master.page_phy = (u32)((unsigned long)master.page_vir);
293ba0501acSDingqiang Lin 		master.spare_phy = (u32)((unsigned long)master.spare_vir);
294ba0501acSDingqiang Lin 		vir_addr = ((unsigned long)master.page_phy);
295ba0501acSDingqiang Lin 		flush_dcache_range(vir_addr & (~0x3FuL),
296ba0501acSDingqiang Lin 				   ((vir_addr + 63) & (~0x3FuL)) +
297ba0501acSDingqiang Lin 					fl_reg.V6.page_num * 1024);
298ba0501acSDingqiang Lin 		vir_addr = ((unsigned long)master.spare_phy);
299ba0501acSDingqiang Lin 		flush_dcache_range(vir_addr & (~0x3FuL),
300ba0501acSDingqiang Lin 				   ((vir_addr + 63) & (~0x3FuL)) +
301ba0501acSDingqiang Lin 					fl_reg.V6.page_num * 128);
302ba0501acSDingqiang Lin 		master.mapped = 1;
303ba0501acSDingqiang Lin 		nandc_writel(master.page_phy, NANDC_MTRANS_SADDR0);
304ba0501acSDingqiang Lin 		nandc_writel(master.spare_phy, NANDC_MTRANS_SADDR1);
305ba0501acSDingqiang Lin 		master_reg.d32 = 0;
306ba0501acSDingqiang Lin 		master_reg.V6.incr_num = 16;
307ba0501acSDingqiang Lin 		master_reg.V6.burst = 7;
308ba0501acSDingqiang Lin 		master_reg.V6.hsize = 2;
309ba0501acSDingqiang Lin 		master_reg.V6.bus_mode = 1;
310ba0501acSDingqiang Lin 		master_reg.V6.ahb_wr = !dir;
311ba0501acSDingqiang Lin 		master_reg.V6.ahb_wr_st = 1;
312ba0501acSDingqiang Lin 
313ba0501acSDingqiang Lin 		nandc_writel(master_reg.d32, NANDC_MTRANS_CFG);
314ba0501acSDingqiang Lin 		nandc_writel(bch_reg.d32, NANDC_BCHCTL);
315ba0501acSDingqiang Lin 		nandc_writel(fl_reg.d32, NANDC_FLCTL);
316ba0501acSDingqiang Lin 		fl_reg.V6.start = 1;
317ba0501acSDingqiang Lin 		nandc_writel(fl_reg.d32, NANDC_FLCTL);
318ba0501acSDingqiang Lin 	}
31927ffef75SDingqiang Lin }
320ba0501acSDingqiang Lin 
32127ffef75SDingqiang Lin /*
32227ffef75SDingqiang Lin  * Wait for the end of data transmission
32327ffef75SDingqiang Lin  */
nandc_xfer_done(void)32427ffef75SDingqiang Lin static void nandc_xfer_done(void)
325ba0501acSDingqiang Lin {
326ba0501acSDingqiang Lin 	union FL_CTL_T fl_reg;
327ba0501acSDingqiang Lin 	union MTRANS_CFG_T master_reg;
328ba0501acSDingqiang Lin 
32927ffef75SDingqiang Lin 	if (g_nandc_ver == 9) {
33027ffef75SDingqiang Lin 		union MTRANS_STAT_T stat_reg;
33127ffef75SDingqiang Lin 
33227ffef75SDingqiang Lin 		master_reg.d32 = nandc_readl(NANDC_V9_MTRANS_CFG);
33327ffef75SDingqiang Lin 		if (master_reg.V9.ahb_wr != 0) {
33427ffef75SDingqiang Lin 			do {
33527ffef75SDingqiang Lin 				fl_reg.d32 = nandc_readl(NANDC_V9_FLCTL);
33627ffef75SDingqiang Lin 				stat_reg.d32 = nandc_readl(NANDC_V9_MTRANS_STAT);
337*98c8a00dSJon Lin 				usleep_range(20, 30);
33827ffef75SDingqiang Lin 			} while (stat_reg.V9.mtrans_cnt < fl_reg.V9.page_num ||
33927ffef75SDingqiang Lin 				 fl_reg.V9.tr_rdy == 0);
340*98c8a00dSJon Lin 			udelay(5);
34127ffef75SDingqiang Lin 		} else {
34227ffef75SDingqiang Lin 			do {
34327ffef75SDingqiang Lin 				fl_reg.d32 = nandc_readl(NANDC_V9_FLCTL);
344*98c8a00dSJon Lin 				usleep_range(20, 30);
34527ffef75SDingqiang Lin 			} while (fl_reg.V9.tr_rdy == 0);
34627ffef75SDingqiang Lin 		}
34727ffef75SDingqiang Lin 	} else {
348ba0501acSDingqiang Lin 		master_reg.d32 = nandc_readl(NANDC_MTRANS_CFG);
349ba0501acSDingqiang Lin 		if (master_reg.V6.bus_mode != 0) {
350ba0501acSDingqiang Lin 			union MTRANS_STAT_T stat_reg;
351ba0501acSDingqiang Lin 
352ba0501acSDingqiang Lin 		if (master_reg.V6.ahb_wr != 0) {
353ba0501acSDingqiang Lin 			do {
354ba0501acSDingqiang Lin 				fl_reg.d32 = nandc_readl(NANDC_FLCTL);
355ba0501acSDingqiang Lin 				stat_reg.d32 = nandc_readl(NANDC_MTRANS_STAT);
356*98c8a00dSJon Lin 				usleep_range(20, 30);
35727ffef75SDingqiang Lin 			} while (stat_reg.V6.mtrans_cnt < fl_reg.V6.page_num ||
35827ffef75SDingqiang Lin 				 fl_reg.V6.tr_rdy == 0);
359ba0501acSDingqiang Lin 		} else {
360ba0501acSDingqiang Lin 			do {
361ba0501acSDingqiang Lin 				fl_reg.d32 = nandc_readl(NANDC_FLCTL);
362*98c8a00dSJon Lin 				usleep_range(20, 30);
363ba0501acSDingqiang Lin 			} while (fl_reg.V6.tr_rdy == 0);
364ba0501acSDingqiang Lin 			}
365ba0501acSDingqiang Lin 		} else {
366ba0501acSDingqiang Lin 			do {
367ba0501acSDingqiang Lin 				fl_reg.d32 = nandc_readl(NANDC_FLCTL);
368ba0501acSDingqiang Lin 			} while ((fl_reg.V6.tr_rdy == 0));
369ba0501acSDingqiang Lin 		}
370ba0501acSDingqiang Lin 	}
37127ffef75SDingqiang Lin }
372ba0501acSDingqiang Lin 
nandc_xfer_data(u8 chip_sel,u8 dir,u8 n_sec,u32 * p_data,u32 * p_spare)37327ffef75SDingqiang Lin u32 nandc_xfer_data(u8 chip_sel, u8 dir, u8 n_sec,
374ba0501acSDingqiang Lin 		    u32 *p_data, u32 *p_spare)
375ba0501acSDingqiang Lin {
376ba0501acSDingqiang Lin 	u32 status = NAND_STS_OK;
377ba0501acSDingqiang Lin 	u32 i;
378ba0501acSDingqiang Lin 	u32 spare[16];
379ba0501acSDingqiang Lin 	union BCH_ST_T bch_st_reg;
380ba0501acSDingqiang Lin 
381ba0501acSDingqiang Lin 	if (dir == NANDC_WRITE && !p_spare) {
382ba0501acSDingqiang Lin 		p_spare = (u32 *)spare;
383ba0501acSDingqiang Lin 		memset(spare, 0xFF, sizeof(spare));
384ba0501acSDingqiang Lin 	}
38527ffef75SDingqiang Lin 	nandc_xfer_start(dir, n_sec, p_data, p_spare);
38627ffef75SDingqiang Lin 	nandc_xfer_done();
387ba0501acSDingqiang Lin 	if (dir == NANDC_READ) {
38827ffef75SDingqiang Lin 		if (g_nandc_ver == 9) {
38927ffef75SDingqiang Lin 			for (i = 0; i < n_sec / 4; i++) {
39027ffef75SDingqiang Lin 				bch_st_reg.d32 = nandc_readl(NANDC_V9_BCHST(i));
39127ffef75SDingqiang Lin 				if (n_sec > 2) {
39227ffef75SDingqiang Lin 					if (bch_st_reg.V9.fail0 || bch_st_reg.V9.fail1) {
39327ffef75SDingqiang Lin 						status = NAND_STS_ECC_ERR;
39427ffef75SDingqiang Lin 					} else {
39527ffef75SDingqiang Lin 						u32 tmp = max((u32)bch_st_reg.V9.err_bits0,
39627ffef75SDingqiang Lin 							      (u32)bch_st_reg.V9.err_bits1);
39727ffef75SDingqiang Lin 						status = max(tmp, status);
39827ffef75SDingqiang Lin 					}
39927ffef75SDingqiang Lin 				} else {
40027ffef75SDingqiang Lin 					if (bch_st_reg.V9.fail0)
40127ffef75SDingqiang Lin 						status = NAND_STS_ECC_ERR;
40227ffef75SDingqiang Lin 					else
40327ffef75SDingqiang Lin 						status = bch_st_reg.V9.err_bits0;
40427ffef75SDingqiang Lin 				}
40527ffef75SDingqiang Lin 			}
406ba0501acSDingqiang Lin 			if (p_spare) {
40727ffef75SDingqiang Lin 				for (i = 0; i < n_sec / 2; i++)
40827ffef75SDingqiang Lin 					p_spare[i] = master.spare_buf[i];
409ba0501acSDingqiang Lin 			}
41027ffef75SDingqiang Lin 		} else {
41127ffef75SDingqiang Lin 			for (i = 0; i < n_sec / 4 ; i++) {
412ba0501acSDingqiang Lin 				bch_st_reg.d32 = nandc_readl(NANDC_BCHST(i));
413ba0501acSDingqiang Lin 				if (bch_st_reg.V6.fail0 || bch_st_reg.V6.fail1) {
414ba0501acSDingqiang Lin 					status = NAND_STS_ECC_ERR;
415ba0501acSDingqiang Lin 				} else {
416ba0501acSDingqiang Lin 					u32 tmp = 0;
417ba0501acSDingqiang Lin 
418ba0501acSDingqiang Lin 					tmp =
419ba0501acSDingqiang Lin 					max(bch_st_reg.V6.err_bits0 |
420ba0501acSDingqiang Lin 					    ((u32)bch_st_reg.V6.err_bits0_5 << 5),
421ba0501acSDingqiang Lin 					    bch_st_reg.V6.err_bits1 |
422ba0501acSDingqiang Lin 					    ((u32)bch_st_reg.V6.err_bits1_5 << 5));
423ba0501acSDingqiang Lin 					status = max(tmp, status);
424ba0501acSDingqiang Lin 				}
425ba0501acSDingqiang Lin 			}
42627ffef75SDingqiang Lin 			if (p_spare) {
42727ffef75SDingqiang Lin 				u32 spare_sz = 64;
42827ffef75SDingqiang Lin 				u32 temp_data;
42927ffef75SDingqiang Lin 				u8 *p_spare_temp = (u8 *)p_spare;
43027ffef75SDingqiang Lin 
43127ffef75SDingqiang Lin 				for (i = 0; i < n_sec / 2; i++) {
43227ffef75SDingqiang Lin 					temp_data = master.spare_buf[i * spare_sz / 4];
43327ffef75SDingqiang Lin 					*p_spare_temp++ = (u8)temp_data;
43427ffef75SDingqiang Lin 					*p_spare_temp++ = (u8)(temp_data >> 8);
43527ffef75SDingqiang Lin 					*p_spare_temp++ = (u8)(temp_data >> 16);
43627ffef75SDingqiang Lin 					*p_spare_temp++ = (u8)(temp_data >> 24);
43727ffef75SDingqiang Lin 				}
438ba0501acSDingqiang Lin 			}
439ba0501acSDingqiang Lin 			nandc_writel(0, NANDC_MTRANS_CFG);
44027ffef75SDingqiang Lin 		}
44127ffef75SDingqiang Lin 	}
442ba0501acSDingqiang Lin 	return status;
443ba0501acSDingqiang Lin }
444ba0501acSDingqiang Lin 
nandc_clean_irq(void)445ba0501acSDingqiang Lin void nandc_clean_irq(void)
446ba0501acSDingqiang Lin {
447ba0501acSDingqiang Lin }
448