blob: 114fc8b7ceaca78e6c72fd4c65cdd241a66b0649 [file] [log] [blame]
developer10a61df2022-05-20 11:23:47 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2022 MediaTek Inc. All rights reserved.
4 *
5 * Author: Weijie Gao <weijie.gao@mediatek.com>
6 */
7
8#include <image.h>
9#include <malloc.h>
10#include <linux/sizes.h>
11#include <linux/delay.h>
12#include <linux/mtd/rawnand.h>
13#include "mt7621_nand.h"
14
15static struct mt7621_nfc nfc_dev;
16static u8 *buffer;
17static int nand_valid;
18
19static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
20 int column, int page_addr)
21{
22 register struct nand_chip *chip = mtd_to_nand(mtd);
23
24 /* Command latch cycle */
25 chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
26
27 if (column != -1 || page_addr != -1) {
28 int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE;
29
30 /* Serially input address */
31 if (column != -1) {
32 chip->cmd_ctrl(mtd, column, ctrl);
33 ctrl &= ~NAND_CTRL_CHANGE;
34 if (command != NAND_CMD_READID)
35 chip->cmd_ctrl(mtd, column >> 8, ctrl);
36 }
37 if (page_addr != -1) {
38 chip->cmd_ctrl(mtd, page_addr, ctrl);
39 chip->cmd_ctrl(mtd, page_addr >> 8,
40 NAND_NCE | NAND_ALE);
41 if (chip->options & NAND_ROW_ADDR_3)
42 chip->cmd_ctrl(mtd, page_addr >> 16,
43 NAND_NCE | NAND_ALE);
44 }
45 }
46 chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
47
48 /*
49 * Program and erase have their own busy handlers status, sequential
50 * in and status need no delay.
51 */
52 switch (command) {
53 case NAND_CMD_STATUS:
54 case NAND_CMD_READID:
55 case NAND_CMD_SET_FEATURES:
56 return;
57
58 case NAND_CMD_READ0:
59 chip->cmd_ctrl(mtd, NAND_CMD_READSTART,
60 NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
61 chip->cmd_ctrl(mtd, NAND_CMD_NONE,
62 NAND_NCE | NAND_CTRL_CHANGE);
63 }
64
65 /*
66 * Apply this short delay always to ensure that we do wait tWB in
67 * any case on any machine.
68 */
69 ndelay(100);
70
71 nand_wait_ready(mtd);
72}
73
74static int nfc_read_page_hwecc(struct mtd_info *mtd, void *buf,
75 unsigned int page)
76{
77 struct nand_chip *chip = mtd_to_nand(mtd);
78 int ret;
79
80 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page);
81
82 ret = chip->ecc.read_page(mtd, chip, buf, 1, page);
83 if (ret < 0 || ret > chip->ecc.strength)
84 return -1;
85
86 return 0;
87}
88
89static int nfc_read_oob_hwecc(struct mtd_info *mtd, void *buf, u32 len,
90 unsigned int page)
91{
92 struct nand_chip *chip = mtd_to_nand(mtd);
93 int ret;
94
95 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, page);
96
97 ret = chip->ecc.read_page(mtd, chip, NULL, 1, page);
98 if (ret < 0)
99 return -1;
100
101 if (len > mtd->oobsize)
102 len = mtd->oobsize;
103
104 memcpy(buf, chip->oob_poi, len);
105
106 return 0;
107}
108
109static int nfc_check_bad_block(struct mtd_info *mtd, unsigned int page)
110{
111 struct nand_chip *chip = mtd_to_nand(mtd);
112 u32 pages_per_block, i = 0;
113 int ret;
114 u8 bad;
115
116 pages_per_block = 1 << (mtd->erasesize_shift - mtd->writesize_shift);
117
118 /* Read from first/last page(s) if necessary */
119 if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) {
120 page += pages_per_block - 1;
121 if (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)
122 page--;
123 }
124
125 do {
126 ret = nfc_read_oob_hwecc(mtd, &bad, 1, page);
127 if (ret)
128 return ret;
129
130 ret = bad != 0xFF;
131
132 i++;
133 page++;
134 } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
135
136 return ret;
137}
138
139int nand_spl_load_image(uint32_t offs, unsigned int size, void *dest)
140{
141 struct mt7621_nfc *nfc = &nfc_dev;
142 struct nand_chip *chip = &nfc->nand;
143 struct mtd_info *mtd = &chip->mtd;
144 u32 addr, col, page, chksz;
145 bool check_bad = true;
146
147 if (!nand_valid)
148 return -ENODEV;
149
150 while (size) {
151 if (check_bad || !(offs & mtd->erasesize_mask)) {
152 addr = offs & (~mtd->erasesize_mask);
153 page = addr >> mtd->writesize_shift;
154 if (nfc_check_bad_block(mtd, page)) {
155 /* Skip bad block */
156 if (addr >= mtd->size - mtd->erasesize)
157 return -1;
158
159 offs += mtd->erasesize;
160 continue;
161 }
162
163 check_bad = false;
164 }
165
166 col = offs & mtd->writesize_mask;
167 page = offs >> mtd->writesize_shift;
168 chksz = min(mtd->writesize - col, (uint32_t)size);
169
170 if (unlikely(chksz < mtd->writesize)) {
171 /* Not reading a full page */
172 if (nfc_read_page_hwecc(mtd, buffer, page))
173 return -1;
174
175 memcpy(dest, buffer + col, chksz);
176 } else {
177 if (nfc_read_page_hwecc(mtd, dest, page))
178 return -1;
179 }
180
181 dest += chksz;
182 offs += chksz;
183 size -= chksz;
184 }
185
186 return 0;
187}
188
189int nand_default_bbt(struct mtd_info *mtd)
190{
191 return 0;
192}
193
194unsigned long nand_size(void)
195{
196 if (!nand_valid)
197 return 0;
198
199 /* Unlikely that NAND size > 2GBytes */
200 if (nfc_dev.nand.chipsize <= SZ_2G)
201 return nfc_dev.nand.chipsize;
202
203 return SZ_2G;
204}
205
206void nand_deselect(void)
207{
208}
209
210void nand_init(void)
211{
212 struct mtd_info *mtd;
213 struct nand_chip *chip;
214
215 if (nand_valid)
216 return;
217
218 mt7621_nfc_spl_init(&nfc_dev);
219
220 chip = &nfc_dev.nand;
221 mtd = &chip->mtd;
222 chip->cmdfunc = nand_command_lp;
223
224 if (mt7621_nfc_spl_post_init(&nfc_dev))
225 return;
226
227 mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
228 mtd->writesize_shift = ffs(mtd->writesize) - 1;
229 mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
230 mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
231
232 buffer = malloc(mtd->writesize);
233 if (!buffer)
234 return;
235
236 nand_valid = 1;
237}