2 * (C) Copyright 2006 OpenMoko, Inc.
3 * Author: Harald Welte <laforge@openmoko.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 #include <asm/arch/s3c2410.h>
27 #define S3C2410_NFCONF_EN (1<<15)
28 #define S3C2410_NFCONF_512BYTE (1<<14)
29 #define S3C2410_NFCONF_4STEP (1<<13)
30 #define S3C2410_NFCONF_INITECC (1<<12)
31 #define S3C2410_NFCONF_nFCE (1<<11)
32 #define S3C2410_NFCONF_TACLS(x) ((x)<<8)
33 #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
34 #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
36 #define S3C2410_ADDR_NALE 4
37 #define S3C2410_ADDR_NCLE 8
39 static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
41 struct nand_chip *chip = mtd->priv;
42 struct s3c2410_nand *nand = s3c2410_get_base_nand();
44 debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
46 if (ctrl & NAND_CTRL_CHANGE) {
47 ulong IO_ADDR_W = (ulong)nand;
49 if (!(ctrl & NAND_CLE))
50 IO_ADDR_W |= S3C2410_ADDR_NCLE;
51 if (!(ctrl & NAND_ALE))
52 IO_ADDR_W |= S3C2410_ADDR_NALE;
54 chip->IO_ADDR_W = (void *)IO_ADDR_W;
57 writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE,
60 writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE,
64 if (cmd != NAND_CMD_NONE)
65 writeb(cmd, chip->IO_ADDR_W);
68 static int s3c2410_dev_ready(struct mtd_info *mtd)
70 struct s3c2410_nand *nand = s3c2410_get_base_nand();
71 debugX(1, "dev_ready\n");
72 return readl(&nand->NFSTAT) & 0x01;
75 #ifdef CONFIG_S3C2410_NAND_HWECC
76 void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
78 struct s3c2410_nand *nand = s3c2410_get_base_nand();
79 debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
80 writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF);
83 static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
89 debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
90 mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
95 static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
96 u_char *read_ecc, u_char *calc_ecc)
98 if (read_ecc[0] == calc_ecc[0] &&
99 read_ecc[1] == calc_ecc[1] &&
100 read_ecc[2] == calc_ecc[2])
103 printf("s3c2410_nand_correct_data: not implemented\n");
108 int board_nand_init(struct nand_chip *nand)
111 u_int8_t tacls, twrph0, twrph1;
112 struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
113 struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
115 debugX(1, "board_nand_init()\n");
117 writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
119 /* initialize hardware */
124 cfg = S3C2410_NFCONF_EN;
125 cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
126 cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
127 cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
128 writel(cfg, &nand_reg->NFCONF);
130 /* initialize nand_chip data structure */
131 nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
133 /* read_buf and write_buf are default */
134 /* read_byte and write_byte are default */
136 /* hwcontrol always must be implemented */
137 nand->cmd_ctrl = s3c2410_hwcontrol;
139 nand->dev_ready = s3c2410_dev_ready;
141 #ifdef CONFIG_S3C2410_NAND_HWECC
142 nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
143 nand->ecc.calculate = s3c2410_nand_calculate_ecc;
144 nand->ecc.correct = s3c2410_nand_correct_data;
145 nand->ecc.mode = NAND_ECC_HW3_512;
147 nand->ecc.mode = NAND_ECC_SOFT;
150 #ifdef CONFIG_S3C2410_NAND_BBT
151 nand->options = NAND_USE_FLASH_BBT;
156 debugX(1, "end of nand_init\n");