]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/mtd/nand/spr_nand.c
Merge branch 'master' of git://git.denx.de/u-boot-arm
[karo-tx-uboot.git] / drivers / mtd / nand / spr_nand.c
1 /*
2  * (C) Copyright 2009
3  * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <nand.h>
26 #include <linux/mtd/nand_ecc.h>
27 #include <asm/io.h>
28 #include <asm/arch/hardware.h>
29 #include <asm/arch/spr_nand.h>
30
31 static struct fsmc_regs *const fsmc_regs_p =
32     (struct fsmc_regs *)CONFIG_SPEAR_FSMCBASE;
33
34 static struct nand_ecclayout spear_nand_ecclayout = {
35         .eccbytes = 24,
36         .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52,
37                    66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116},
38         .oobfree = {
39                     {.offset = 8, .length = 8},
40                     {.offset = 24, .length = 8},
41                     {.offset = 40, .length = 8},
42                     {.offset = 56, .length = 8},
43                     {.offset = 72, .length = 8},
44                     {.offset = 88, .length = 8},
45                     {.offset = 104, .length = 8},
46                     {.offset = 120, .length = 8}
47                     }
48 };
49
50 static void spear_nand_hwcontrol(struct mtd_info *mtd, int cmd, uint ctrl)
51 {
52         struct nand_chip *this = mtd->priv;
53         ulong IO_ADDR_W;
54
55         if (ctrl & NAND_CTRL_CHANGE) {
56                 IO_ADDR_W = (ulong)this->IO_ADDR_W;
57
58                 IO_ADDR_W &= ~(CONFIG_SYS_NAND_CLE | CONFIG_SYS_NAND_ALE);
59                 if (ctrl & NAND_CLE)
60                         IO_ADDR_W |= CONFIG_SYS_NAND_CLE;
61                 if (ctrl & NAND_ALE)
62                         IO_ADDR_W |= CONFIG_SYS_NAND_ALE;
63
64                 if (ctrl & NAND_NCE) {
65                         writel(readl(&fsmc_regs_p->genmemctrl_pc) |
66                                FSMC_ENABLE, &fsmc_regs_p->genmemctrl_pc);
67                 } else {
68                         writel(readl(&fsmc_regs_p->genmemctrl_pc) &
69                                ~FSMC_ENABLE, &fsmc_regs_p->genmemctrl_pc);
70                 }
71                 this->IO_ADDR_W = (void *)IO_ADDR_W;
72         }
73
74         if (cmd != NAND_CMD_NONE)
75                 writeb(cmd, this->IO_ADDR_W);
76 }
77
78 static int spear_read_hwecc(struct mtd_info *mtd,
79                             const u_char *data, u_char ecc[3])
80 {
81         u_int ecc_tmp;
82
83         /* read the h/w ECC */
84         ecc_tmp = readl(&fsmc_regs_p->genmemctrl_ecc);
85
86         ecc[0] = (u_char) (ecc_tmp & 0xFF);
87         ecc[1] = (u_char) ((ecc_tmp & 0xFF00) >> 8);
88         ecc[2] = (u_char) ((ecc_tmp & 0xFF0000) >> 16);
89
90         return 0;
91 }
92
93 void spear_enable_hwecc(struct mtd_info *mtd, int mode)
94 {
95         writel(readl(&fsmc_regs_p->genmemctrl_pc) & ~0x80,
96                &fsmc_regs_p->genmemctrl_pc);
97         writel(readl(&fsmc_regs_p->genmemctrl_pc) & ~FSMC_ECCEN,
98                &fsmc_regs_p->genmemctrl_pc);
99         writel(readl(&fsmc_regs_p->genmemctrl_pc) | FSMC_ECCEN,
100                &fsmc_regs_p->genmemctrl_pc);
101 }
102
103 int spear_nand_init(struct nand_chip *nand)
104 {
105         writel(FSMC_DEVWID_8 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON,
106                &fsmc_regs_p->genmemctrl_pc);
107         writel(readl(&fsmc_regs_p->genmemctrl_pc) | FSMC_TCLR_1 | FSMC_TAR_1,
108                &fsmc_regs_p->genmemctrl_pc);
109         writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
110                &fsmc_regs_p->genmemctrl_comm);
111         writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
112                &fsmc_regs_p->genmemctrl_attrib);
113
114         nand->options = 0;
115         nand->ecc.mode = NAND_ECC_HW;
116         nand->ecc.layout = &spear_nand_ecclayout;
117         nand->ecc.size = 512;
118         nand->ecc.bytes = 3;
119         nand->ecc.calculate = spear_read_hwecc;
120         nand->ecc.hwctl = spear_enable_hwecc;
121         nand->ecc.correct = nand_correct_data;
122         nand->cmd_ctrl = spear_nand_hwcontrol;
123         return 0;
124 }