blob: db87d07269b0bbe46911144f03edb101e95aded1 [file] [log] [blame]
Harald Welte06a4fc02007-12-19 15:10:52 +01001/*
2 * (C) Copyright 2006 OpenMoko, Inc.
3 * Author: Harald Welte <laforge@openmoko.org>
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Harald Welte06a4fc02007-12-19 15:10:52 +01006 */
7
8#include <common.h>
9
Harald Welte06a4fc02007-12-19 15:10:52 +010010#include <nand.h>
kevin.morfitt@fearnside-systems.co.uke0d81312009-11-17 18:30:34 +090011#include <asm/arch/s3c24x0_cpu.h>
Scott Wood03f6ec32008-08-13 17:04:30 -050012#include <asm/io.h>
Harald Welte06a4fc02007-12-19 15:10:52 +010013
Harald Welte06a4fc02007-12-19 15:10:52 +010014#define S3C2410_NFCONF_EN (1<<15)
15#define S3C2410_NFCONF_512BYTE (1<<14)
16#define S3C2410_NFCONF_4STEP (1<<13)
17#define S3C2410_NFCONF_INITECC (1<<12)
18#define S3C2410_NFCONF_nFCE (1<<11)
19#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
20#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
21#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
22
Scott Wood03f6ec32008-08-13 17:04:30 -050023#define S3C2410_ADDR_NALE 4
24#define S3C2410_ADDR_NCLE 8
25
Hui.Tanga5176e02009-11-18 16:24:04 +080026#ifdef CONFIG_NAND_SPL
27
28/* in the early stage of NAND flash booting, printf() is not available */
29#define printf(fmt, args...)
30
31static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
32{
33 int i;
34 struct nand_chip *this = mtd->priv;
35
36 for (i = 0; i < len; i++)
37 buf[i] = readb(this->IO_ADDR_R);
38}
39#endif
40
Scott Wood03f6ec32008-08-13 17:04:30 -050041static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
Harald Welte06a4fc02007-12-19 15:10:52 +010042{
43 struct nand_chip *chip = mtd->priv;
kevin.morfitt@fearnside-systems.co.uk0d17ec52009-10-10 13:34:09 +090044 struct s3c2410_nand *nand = s3c2410_get_base_nand();
Harald Welte06a4fc02007-12-19 15:10:52 +010045
Marek Vasut04a7a4e2011-10-24 23:40:04 +000046 debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
Scott Wood03f6ec32008-08-13 17:04:30 -050047
48 if (ctrl & NAND_CTRL_CHANGE) {
kevin.morfitt@fearnside-systems.co.uk0d17ec52009-10-10 13:34:09 +090049 ulong IO_ADDR_W = (ulong)nand;
Harald Welte06a4fc02007-12-19 15:10:52 +010050
Scott Wood03f6ec32008-08-13 17:04:30 -050051 if (!(ctrl & NAND_CLE))
52 IO_ADDR_W |= S3C2410_ADDR_NCLE;
53 if (!(ctrl & NAND_ALE))
54 IO_ADDR_W |= S3C2410_ADDR_NALE;
55
56 chip->IO_ADDR_W = (void *)IO_ADDR_W;
57
58 if (ctrl & NAND_NCE)
C Nauman383c43e2010-10-26 23:04:31 +090059 writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,
60 &nand->nfconf);
Scott Wood03f6ec32008-08-13 17:04:30 -050061 else
C Nauman383c43e2010-10-26 23:04:31 +090062 writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,
63 &nand->nfconf);
Harald Welte06a4fc02007-12-19 15:10:52 +010064 }
Scott Wood03f6ec32008-08-13 17:04:30 -050065
66 if (cmd != NAND_CMD_NONE)
67 writeb(cmd, chip->IO_ADDR_W);
Harald Welte06a4fc02007-12-19 15:10:52 +010068}
69
70static int s3c2410_dev_ready(struct mtd_info *mtd)
71{
kevin.morfitt@fearnside-systems.co.uk0d17ec52009-10-10 13:34:09 +090072 struct s3c2410_nand *nand = s3c2410_get_base_nand();
Marek Vasut04a7a4e2011-10-24 23:40:04 +000073 debug("dev_ready\n");
C Nauman383c43e2010-10-26 23:04:31 +090074 return readl(&nand->nfstat) & 0x01;
Harald Welte06a4fc02007-12-19 15:10:52 +010075}
76
77#ifdef CONFIG_S3C2410_NAND_HWECC
78void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
79{
kevin.morfitt@fearnside-systems.co.uk0d17ec52009-10-10 13:34:09 +090080 struct s3c2410_nand *nand = s3c2410_get_base_nand();
Marek Vasut04a7a4e2011-10-24 23:40:04 +000081 debug("s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
C Nauman383c43e2010-10-26 23:04:31 +090082 writel(readl(&nand->nfconf) | S3C2410_NFCONF_INITECC, &nand->nfconf);
Harald Welte06a4fc02007-12-19 15:10:52 +010083}
84
85static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
86 u_char *ecc_code)
87{
Hui.Tanga5176e02009-11-18 16:24:04 +080088 struct s3c2410_nand *nand = s3c2410_get_base_nand();
C Nauman383c43e2010-10-26 23:04:31 +090089 ecc_code[0] = readb(&nand->nfecc);
90 ecc_code[1] = readb(&nand->nfecc + 1);
91 ecc_code[2] = readb(&nand->nfecc + 2);
Marek Vasut04a7a4e2011-10-24 23:40:04 +000092 debug("s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
kevin.morfitt@fearnside-systems.co.uk0d17ec52009-10-10 13:34:09 +090093 mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
Harald Welte06a4fc02007-12-19 15:10:52 +010094
95 return 0;
96}
97
98static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
99 u_char *read_ecc, u_char *calc_ecc)
100{
101 if (read_ecc[0] == calc_ecc[0] &&
102 read_ecc[1] == calc_ecc[1] &&
103 read_ecc[2] == calc_ecc[2])
104 return 0;
105
106 printf("s3c2410_nand_correct_data: not implemented\n");
107 return -1;
108}
109#endif
110
111int board_nand_init(struct nand_chip *nand)
112{
113 u_int32_t cfg;
114 u_int8_t tacls, twrph0, twrph1;
kevin.morfitt@fearnside-systems.co.uk0d17ec52009-10-10 13:34:09 +0900115 struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
116 struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
Harald Welte06a4fc02007-12-19 15:10:52 +0100117
Marek Vasut04a7a4e2011-10-24 23:40:04 +0000118 debug("board_nand_init()\n");
Harald Welte06a4fc02007-12-19 15:10:52 +0100119
C Nauman383c43e2010-10-26 23:04:31 +0900120 writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);
Harald Welte06a4fc02007-12-19 15:10:52 +0100121
122 /* initialize hardware */
David Müller (ELSOFT AG)e03effe2010-11-29 05:49:19 +0000123#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
124 tacls = CONFIG_S3C24XX_TACLS;
125 twrph0 = CONFIG_S3C24XX_TWRPH0;
126 twrph1 = CONFIG_S3C24XX_TWRPH1;
127#else
128 tacls = 4;
129 twrph0 = 8;
130 twrph1 = 8;
131#endif
Harald Welte06a4fc02007-12-19 15:10:52 +0100132
133 cfg = S3C2410_NFCONF_EN;
134 cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
135 cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
136 cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
C Nauman383c43e2010-10-26 23:04:31 +0900137 writel(cfg, &nand_reg->nfconf);
Harald Welte06a4fc02007-12-19 15:10:52 +0100138
139 /* initialize nand_chip data structure */
C Nauman383c43e2010-10-26 23:04:31 +0900140 nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
141 nand->IO_ADDR_W = (void *)&nand_reg->nfdata;
Harald Welte06a4fc02007-12-19 15:10:52 +0100142
Hui.Tanga5176e02009-11-18 16:24:04 +0800143 nand->select_chip = NULL;
144
Harald Welte06a4fc02007-12-19 15:10:52 +0100145 /* read_buf and write_buf are default */
146 /* read_byte and write_byte are default */
Hui.Tanga5176e02009-11-18 16:24:04 +0800147#ifdef CONFIG_NAND_SPL
148 nand->read_buf = nand_read_buf;
149#endif
Harald Welte06a4fc02007-12-19 15:10:52 +0100150
151 /* hwcontrol always must be implemented */
Scott Wood03f6ec32008-08-13 17:04:30 -0500152 nand->cmd_ctrl = s3c2410_hwcontrol;
Harald Welte06a4fc02007-12-19 15:10:52 +0100153
154 nand->dev_ready = s3c2410_dev_ready;
155
156#ifdef CONFIG_S3C2410_NAND_HWECC
Scott Wood03f6ec32008-08-13 17:04:30 -0500157 nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
158 nand->ecc.calculate = s3c2410_nand_calculate_ecc;
159 nand->ecc.correct = s3c2410_nand_correct_data;
Hui.Tanga5176e02009-11-18 16:24:04 +0800160 nand->ecc.mode = NAND_ECC_HW;
161 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
162 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000163 nand->ecc.strength = 1;
Harald Welte06a4fc02007-12-19 15:10:52 +0100164#else
Scott Wood03f6ec32008-08-13 17:04:30 -0500165 nand->ecc.mode = NAND_ECC_SOFT;
Harald Welte06a4fc02007-12-19 15:10:52 +0100166#endif
167
168#ifdef CONFIG_S3C2410_NAND_BBT
Daniel Schwierzeckf9f6c1f2013-06-08 23:00:15 +0200169 nand->bbt_options |= NAND_BBT_USE_FLASH;
Harald Welte06a4fc02007-12-19 15:10:52 +0100170#endif
171
Marek Vasut04a7a4e2011-10-24 23:40:04 +0000172 debug("end of nand_init\n");
Harald Welte06a4fc02007-12-19 15:10:52 +0100173
174 return 0;
175}