1 // 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 
15 static struct mt7621_nfc nfc_dev;
16 static u8 *buffer;
17 static int nand_valid;
18 
nand_command_lp(struct mtd_info * mtd,unsigned int command,int column,int page_addr)19 static 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 
nfc_read_page_hwecc(struct mtd_info * mtd,void * buf,unsigned int page)74 static 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 
nfc_read_oob_hwecc(struct mtd_info * mtd,void * buf,u32 len,unsigned int page)89 static 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 
nfc_check_bad_block(struct mtd_info * mtd,unsigned int page)109 static 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 
nand_spl_load_image(uint32_t offs,unsigned int size,void * dest)139 int 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 
nand_default_bbt(struct mtd_info * mtd)189 int nand_default_bbt(struct mtd_info *mtd)
190 {
191 	return 0;
192 }
193 
nand_size(void)194 unsigned 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 
nand_deselect(void)206 void nand_deselect(void)
207 {
208 }
209 
nand_init(void)210 void 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 }
238