]>
Commit | Line | Data |
---|---|---|
cd9d2305 AV |
1 | /* |
2 | * FSL UPM NAND driver | |
3 | * | |
4 | * Copyright (C) 2007 MontaVista Software, Inc. | |
5 | * Anton Vorontsov <avorontsov@ru.mvista.com> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation; either version 2 of | |
10 | * the License, or (at your option) any later version. | |
11 | */ | |
12 | ||
13 | #include <config.h> | |
14 | ||
15 | #if defined(CONFIG_CMD_NAND) && defined(CONFIG_NAND_FSL_UPM) | |
16 | #include <common.h> | |
17 | #include <asm/io.h> | |
18 | #include <asm/errno.h> | |
19 | #include <linux/mtd/mtd.h> | |
20 | #include <linux/mtd/fsl_upm.h> | |
21 | #include <nand.h> | |
22 | ||
23 | #define FSL_UPM_MxMR_OP_NO (0 << 28) /* normal operation */ | |
24 | #define FSL_UPM_MxMR_OP_WA (1 << 28) /* write array */ | |
25 | #define FSL_UPM_MxMR_OP_RA (2 << 28) /* read array */ | |
26 | #define FSL_UPM_MxMR_OP_RP (3 << 28) /* run pattern */ | |
27 | ||
28 | static void fsl_upm_start_pattern(struct fsl_upm *upm, u32 pat_offset) | |
29 | { | |
30 | out_be32(upm->mxmr, FSL_UPM_MxMR_OP_RP | pat_offset); | |
31 | } | |
32 | ||
33 | static void fsl_upm_end_pattern(struct fsl_upm *upm) | |
34 | { | |
35 | out_be32(upm->mxmr, FSL_UPM_MxMR_OP_NO); | |
36 | while (in_be32(upm->mxmr) != FSL_UPM_MxMR_OP_NO) | |
37 | eieio(); | |
38 | } | |
39 | ||
40 | static void fsl_upm_run_pattern(struct fsl_upm *upm, int width, u32 cmd) | |
41 | { | |
42 | out_be32(upm->mar, cmd << (32 - width * 8)); | |
43 | out_8(upm->io_addr, 0x0); | |
44 | } | |
45 | ||
46 | static void fsl_upm_setup(struct fsl_upm *upm) | |
47 | { | |
48 | int i; | |
49 | ||
50 | /* write upm array */ | |
51 | out_be32(upm->mxmr, FSL_UPM_MxMR_OP_WA); | |
52 | ||
53 | for (i = 0; i < 64; i++) { | |
54 | out_be32(upm->mdr, upm->array[i]); | |
55 | out_8(upm->io_addr, 0x0); | |
56 | } | |
57 | ||
58 | /* normal operation */ | |
59 | out_be32(upm->mxmr, FSL_UPM_MxMR_OP_NO); | |
60 | while (in_be32(upm->mxmr) != FSL_UPM_MxMR_OP_NO) | |
61 | eieio(); | |
62 | } | |
63 | ||
64 | static void fun_cmdfunc(struct mtd_info *mtd, unsigned command, int column, | |
65 | int page_addr) | |
66 | { | |
67 | struct nand_chip *chip = mtd->priv; | |
68 | struct fsl_upm_nand *fun = chip->priv; | |
69 | ||
70 | fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); | |
71 | ||
72 | if (command == NAND_CMD_SEQIN) { | |
73 | int readcmd; | |
74 | ||
75 | if (column >= mtd->oobblock) { | |
76 | /* OOB area */ | |
77 | column -= mtd->oobblock; | |
78 | readcmd = NAND_CMD_READOOB; | |
79 | } else if (column < 256) { | |
80 | /* First 256 bytes --> READ0 */ | |
81 | readcmd = NAND_CMD_READ0; | |
82 | } else { | |
83 | column -= 256; | |
84 | readcmd = NAND_CMD_READ1; | |
85 | } | |
86 | fsl_upm_run_pattern(&fun->upm, fun->width, readcmd); | |
87 | } | |
88 | ||
89 | fsl_upm_run_pattern(&fun->upm, fun->width, command); | |
90 | ||
91 | fsl_upm_end_pattern(&fun->upm); | |
92 | ||
93 | fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); | |
94 | ||
95 | if (column != -1) | |
96 | fsl_upm_run_pattern(&fun->upm, fun->width, column); | |
97 | ||
98 | if (page_addr != -1) { | |
99 | fsl_upm_run_pattern(&fun->upm, fun->width, page_addr); | |
100 | fsl_upm_run_pattern(&fun->upm, fun->width, | |
101 | (page_addr >> 8) & 0xFF); | |
102 | if (chip->chipsize > (32 << 20)) { | |
103 | fsl_upm_run_pattern(&fun->upm, fun->width, | |
104 | (page_addr >> 16) & 0x0f); | |
105 | } | |
106 | } | |
107 | ||
108 | fsl_upm_end_pattern(&fun->upm); | |
109 | ||
110 | if (fun->wait_pattern) { | |
111 | /* | |
112 | * Some boards/chips needs this. At least on MPC8360E-RDK we | |
113 | * need it. Probably weird chip, because I don't see any need | |
114 | * for this on MPC8555E + Samsung K9F1G08U0A. Usually here are | |
115 | * 0-2 unexpected busy states per block read. | |
116 | */ | |
117 | while (!fun->dev_ready()) | |
118 | debug("unexpected busy state\n"); | |
119 | } | |
120 | } | |
121 | ||
122 | static void nand_write_byte(struct mtd_info *mtd, u_char byte) | |
123 | { | |
124 | struct nand_chip *chip = mtd->priv; | |
125 | ||
126 | out_8(chip->IO_ADDR_W, byte); | |
127 | } | |
128 | ||
129 | static u8 nand_read_byte(struct mtd_info *mtd) | |
130 | { | |
131 | struct nand_chip *chip = mtd->priv; | |
132 | ||
133 | return in_8(chip->IO_ADDR_R); | |
134 | } | |
135 | ||
136 | static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) | |
137 | { | |
138 | int i; | |
139 | struct nand_chip *chip = mtd->priv; | |
140 | ||
141 | for (i = 0; i < len; i++) | |
142 | out_8(chip->IO_ADDR_W, buf[i]); | |
143 | } | |
144 | ||
145 | static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) | |
146 | { | |
147 | int i; | |
148 | struct nand_chip *chip = mtd->priv; | |
149 | ||
150 | for (i = 0; i < len; i++) | |
151 | buf[i] = in_8(chip->IO_ADDR_R); | |
152 | } | |
153 | ||
154 | static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) | |
155 | { | |
156 | int i; | |
157 | struct nand_chip *chip = mtd->priv; | |
158 | ||
159 | for (i = 0; i < len; i++) { | |
160 | if (buf[i] != in_8(chip->IO_ADDR_R)) | |
161 | return -EFAULT; | |
162 | } | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
167 | static void nand_hwcontrol(struct mtd_info *mtd, int cmd) | |
168 | { | |
169 | } | |
170 | ||
171 | static int nand_dev_ready(struct mtd_info *mtd) | |
172 | { | |
173 | struct nand_chip *chip = mtd->priv; | |
174 | struct fsl_upm_nand *fun = chip->priv; | |
175 | ||
176 | return fun->dev_ready(); | |
177 | } | |
178 | ||
179 | int fsl_upm_nand_init(struct nand_chip *chip, struct fsl_upm_nand *fun) | |
180 | { | |
181 | /* yet only 8 bit accessors implemented */ | |
182 | if (fun->width != 1) | |
183 | return -ENOSYS; | |
184 | ||
185 | fsl_upm_setup(&fun->upm); | |
186 | ||
187 | chip->priv = fun; | |
188 | chip->chip_delay = fun->chip_delay; | |
189 | chip->eccmode = NAND_ECC_SOFT; | |
190 | chip->cmdfunc = fun_cmdfunc; | |
191 | chip->hwcontrol = nand_hwcontrol; | |
192 | chip->read_byte = nand_read_byte; | |
193 | chip->read_buf = nand_read_buf; | |
194 | chip->write_byte = nand_write_byte; | |
195 | chip->write_buf = nand_write_buf; | |
196 | chip->verify_buf = nand_verify_buf; | |
197 | chip->dev_ready = nand_dev_ready; | |
198 | ||
199 | return 0; | |
200 | } | |
201 | #endif /* CONFIG_CMD_NAND */ |