blob: f2f3e722e5d0cb5431fb13b719bfa267122e32df [file] [log] [blame]
Harald Welte16158772007-12-19 15:10:52 +01001/*
2 * (C) Copyright 2006 OpenMoko, Inc.
3 * Author: Harald Welte <laforge@openmoko.org>
4 *
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.
9 *
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.
14 *
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,
18 * MA 02111-1307 USA
19 */
20
21#include <common.h>
22
Harald Welte16158772007-12-19 15:10:52 +010023#include <nand.h>
24#include <s3c2410.h>
Scott Wood1a23a192008-08-13 17:04:30 -050025#include <asm/io.h>
Harald Welte16158772007-12-19 15:10:52 +010026
Harald Welte16158772007-12-19 15:10:52 +010027#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)
35
Scott Wood1a23a192008-08-13 17:04:30 -050036#define S3C2410_ADDR_NALE 4
37#define S3C2410_ADDR_NCLE 8
38
39static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
Harald Welte16158772007-12-19 15:10:52 +010040{
41 struct nand_chip *chip = mtd->priv;
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090042 struct s3c2410_nand *nand = s3c2410_get_base_nand();
Harald Welte16158772007-12-19 15:10:52 +010043
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090044 debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
Harald Welte16158772007-12-19 15:10:52 +010045
Scott Wood1a23a192008-08-13 17:04:30 -050046 if (ctrl & NAND_CTRL_CHANGE) {
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090047 ulong IO_ADDR_W = (ulong)nand;
Scott Wood1a23a192008-08-13 17:04:30 -050048
49 if (!(ctrl & NAND_CLE))
50 IO_ADDR_W |= S3C2410_ADDR_NCLE;
51 if (!(ctrl & NAND_ALE))
52 IO_ADDR_W |= S3C2410_ADDR_NALE;
53
54 chip->IO_ADDR_W = (void *)IO_ADDR_W;
55
56 if (ctrl & NAND_NCE)
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090057 writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE,
58 &nand->NFCONF);
Scott Wood1a23a192008-08-13 17:04:30 -050059 else
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090060 writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE,
61 &nand->NFCONF);
Harald Welte16158772007-12-19 15:10:52 +010062 }
Scott Wood1a23a192008-08-13 17:04:30 -050063
64 if (cmd != NAND_CMD_NONE)
65 writeb(cmd, chip->IO_ADDR_W);
Harald Welte16158772007-12-19 15:10:52 +010066}
67
68static int s3c2410_dev_ready(struct mtd_info *mtd)
69{
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090070 struct s3c2410_nand *nand = s3c2410_get_base_nand();
71 debugX(1, "dev_ready\n");
72 return readl(&nand->NFSTAT) & 0x01;
Harald Welte16158772007-12-19 15:10:52 +010073}
74
75#ifdef CONFIG_S3C2410_NAND_HWECC
76void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
77{
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090078 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);
Harald Welte16158772007-12-19 15:10:52 +010081}
82
83static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
84 u_char *ecc_code)
85{
86 ecc_code[0] = NFECC0;
87 ecc_code[1] = NFECC1;
88 ecc_code[2] = NFECC2;
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +090089 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]);
Harald Welte16158772007-12-19 15:10:52 +010091
92 return 0;
93}
94
95static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
96 u_char *read_ecc, u_char *calc_ecc)
97{
98 if (read_ecc[0] == calc_ecc[0] &&
99 read_ecc[1] == calc_ecc[1] &&
100 read_ecc[2] == calc_ecc[2])
101 return 0;
102
103 printf("s3c2410_nand_correct_data: not implemented\n");
104 return -1;
105}
106#endif
107
108int board_nand_init(struct nand_chip *nand)
109{
110 u_int32_t cfg;
111 u_int8_t tacls, twrph0, twrph1;
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +0900112 struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
113 struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
Harald Welte16158772007-12-19 15:10:52 +0100114
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +0900115 debugX(1, "board_nand_init()\n");
Harald Welte16158772007-12-19 15:10:52 +0100116
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +0900117 writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON);
Harald Welte16158772007-12-19 15:10:52 +0100118
119 /* initialize hardware */
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +0900120 twrph0 = 3;
121 twrph1 = 0;
122 tacls = 0;
Harald Welte16158772007-12-19 15:10:52 +0100123
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);
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +0900128 writel(cfg, &nand_reg->NFCONF);
Harald Welte16158772007-12-19 15:10:52 +0100129
130 /* initialize nand_chip data structure */
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +0900131 nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA;
Harald Welte16158772007-12-19 15:10:52 +0100132
133 /* read_buf and write_buf are default */
134 /* read_byte and write_byte are default */
135
136 /* hwcontrol always must be implemented */
Scott Wood1a23a192008-08-13 17:04:30 -0500137 nand->cmd_ctrl = s3c2410_hwcontrol;
Harald Welte16158772007-12-19 15:10:52 +0100138
139 nand->dev_ready = s3c2410_dev_ready;
140
141#ifdef CONFIG_S3C2410_NAND_HWECC
Scott Wood1a23a192008-08-13 17:04:30 -0500142 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;
Harald Welte16158772007-12-19 15:10:52 +0100146#else
Scott Wood1a23a192008-08-13 17:04:30 -0500147 nand->ecc.mode = NAND_ECC_SOFT;
Harald Welte16158772007-12-19 15:10:52 +0100148#endif
149
150#ifdef CONFIG_S3C2410_NAND_BBT
151 nand->options = NAND_USE_FLASH_BBT;
152#else
153 nand->options = 0;
154#endif
155
kevin.morfitt@fearnside-systems.co.uk3d1988a2009-10-10 13:34:09 +0900156 debugX(1, "end of nand_init\n");
Harald Welte16158772007-12-19 15:10:52 +0100157
158 return 0;
159}