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