xref: /rk3399_ARM-atf/drivers/mtd/nand/spi_nand.c (revision 6e86b462490429fee6db877338a649b0e199b0ec)
1c3e57739SLionel Debieve /*
2*6e86b462SYann Gautier  * Copyright (c) 2019-2022,  STMicroelectronics - All Rights Reserved
3c3e57739SLionel Debieve  *
4c3e57739SLionel Debieve  * SPDX-License-Identifier: BSD-3-Clause
5c3e57739SLionel Debieve  */
6c3e57739SLionel Debieve 
7c3e57739SLionel Debieve #include <assert.h>
8c3e57739SLionel Debieve #include <errno.h>
9c3e57739SLionel Debieve #include <stddef.h>
10c3e57739SLionel Debieve 
11c3e57739SLionel Debieve #include <common/debug.h>
12c3e57739SLionel Debieve #include <drivers/delay_timer.h>
13c3e57739SLionel Debieve #include <drivers/spi_nand.h>
14c3e57739SLionel Debieve #include <lib/utils.h>
15c3e57739SLionel Debieve 
16*6e86b462SYann Gautier #include <platform_def.h>
17*6e86b462SYann Gautier 
18c3e57739SLionel Debieve #define SPI_NAND_MAX_ID_LEN		4U
19c3e57739SLionel Debieve #define DELAY_US_400MS			400000U
20c3e57739SLionel Debieve #define MACRONIX_ID			0xC2U
21c3e57739SLionel Debieve 
22c3e57739SLionel Debieve static struct spinand_device spinand_dev;
23c3e57739SLionel Debieve 
24c3e57739SLionel Debieve #pragma weak plat_get_spi_nand_data
25c3e57739SLionel Debieve int plat_get_spi_nand_data(struct spinand_device *device)
26c3e57739SLionel Debieve {
27c3e57739SLionel Debieve 	return 0;
28c3e57739SLionel Debieve }
29c3e57739SLionel Debieve 
30c3e57739SLionel Debieve static int spi_nand_reg(bool read_reg, uint8_t reg, uint8_t *val,
31c3e57739SLionel Debieve 			enum spi_mem_data_dir dir)
32c3e57739SLionel Debieve {
33c3e57739SLionel Debieve 	struct spi_mem_op op;
34c3e57739SLionel Debieve 
35c3e57739SLionel Debieve 	zeromem(&op, sizeof(struct spi_mem_op));
36c3e57739SLionel Debieve 	if (read_reg) {
37c3e57739SLionel Debieve 		op.cmd.opcode = SPI_NAND_OP_GET_FEATURE;
38c3e57739SLionel Debieve 	} else {
39c3e57739SLionel Debieve 		op.cmd.opcode = SPI_NAND_OP_SET_FEATURE;
40c3e57739SLionel Debieve 	}
41c3e57739SLionel Debieve 
42c3e57739SLionel Debieve 	op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
43c3e57739SLionel Debieve 	op.addr.val = reg;
44c3e57739SLionel Debieve 	op.addr.nbytes = 1U;
45c3e57739SLionel Debieve 	op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
46c3e57739SLionel Debieve 	op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
47c3e57739SLionel Debieve 	op.data.dir = dir;
48c3e57739SLionel Debieve 	op.data.nbytes = 1U;
49c3e57739SLionel Debieve 	op.data.buf = val;
50c3e57739SLionel Debieve 
51c3e57739SLionel Debieve 	return spi_mem_exec_op(&op);
52c3e57739SLionel Debieve }
53c3e57739SLionel Debieve 
54c3e57739SLionel Debieve static int spi_nand_read_reg(uint8_t reg, uint8_t *val)
55c3e57739SLionel Debieve {
56c3e57739SLionel Debieve 	return spi_nand_reg(true, reg, val, SPI_MEM_DATA_IN);
57c3e57739SLionel Debieve }
58c3e57739SLionel Debieve 
59c3e57739SLionel Debieve static int spi_nand_write_reg(uint8_t reg, uint8_t val)
60c3e57739SLionel Debieve {
61c3e57739SLionel Debieve 	return spi_nand_reg(false, reg, &val, SPI_MEM_DATA_OUT);
62c3e57739SLionel Debieve }
63c3e57739SLionel Debieve 
64c3e57739SLionel Debieve static int spi_nand_update_cfg(uint8_t mask, uint8_t val)
65c3e57739SLionel Debieve {
66c3e57739SLionel Debieve 	int ret;
67c3e57739SLionel Debieve 	uint8_t cfg = spinand_dev.cfg_cache;
68c3e57739SLionel Debieve 
69c3e57739SLionel Debieve 	cfg &= ~mask;
70c3e57739SLionel Debieve 	cfg |= val;
71c3e57739SLionel Debieve 
72c3e57739SLionel Debieve 	if (cfg == spinand_dev.cfg_cache) {
73c3e57739SLionel Debieve 		return 0;
74c3e57739SLionel Debieve 	}
75c3e57739SLionel Debieve 
76c3e57739SLionel Debieve 	ret = spi_nand_write_reg(SPI_NAND_REG_CFG, cfg);
77c3e57739SLionel Debieve 	if (ret == 0) {
78c3e57739SLionel Debieve 		spinand_dev.cfg_cache = cfg;
79c3e57739SLionel Debieve 	}
80c3e57739SLionel Debieve 
81c3e57739SLionel Debieve 	return ret;
82c3e57739SLionel Debieve }
83c3e57739SLionel Debieve 
84c3e57739SLionel Debieve static int spi_nand_ecc_enable(bool enable)
85c3e57739SLionel Debieve {
86c3e57739SLionel Debieve 	return spi_nand_update_cfg(SPI_NAND_CFG_ECC_EN,
87c3e57739SLionel Debieve 				   enable ? SPI_NAND_CFG_ECC_EN : 0U);
88c3e57739SLionel Debieve }
89c3e57739SLionel Debieve 
90c3e57739SLionel Debieve static int spi_nand_quad_enable(uint8_t manufacturer_id)
91c3e57739SLionel Debieve {
92c3e57739SLionel Debieve 	bool enable = false;
93c3e57739SLionel Debieve 
94c3e57739SLionel Debieve 	if (manufacturer_id != MACRONIX_ID) {
95c3e57739SLionel Debieve 		return 0;
96c3e57739SLionel Debieve 	}
97c3e57739SLionel Debieve 
98c3e57739SLionel Debieve 	if (spinand_dev.spi_read_cache_op.data.buswidth ==
99c3e57739SLionel Debieve 	    SPI_MEM_BUSWIDTH_4_LINE) {
100c3e57739SLionel Debieve 		enable = true;
101c3e57739SLionel Debieve 	}
102c3e57739SLionel Debieve 
103c3e57739SLionel Debieve 	return spi_nand_update_cfg(SPI_NAND_CFG_QE,
104c3e57739SLionel Debieve 				   enable ? SPI_NAND_CFG_QE : 0U);
105c3e57739SLionel Debieve }
106c3e57739SLionel Debieve 
107c3e57739SLionel Debieve static int spi_nand_wait_ready(uint8_t *status)
108c3e57739SLionel Debieve {
109c3e57739SLionel Debieve 	int ret;
110c3e57739SLionel Debieve 	uint64_t timeout = timeout_init_us(DELAY_US_400MS);
111c3e57739SLionel Debieve 
112c3e57739SLionel Debieve 	while (!timeout_elapsed(timeout)) {
113c3e57739SLionel Debieve 		ret = spi_nand_read_reg(SPI_NAND_REG_STATUS, status);
114c3e57739SLionel Debieve 		if (ret != 0) {
115c3e57739SLionel Debieve 			return ret;
116c3e57739SLionel Debieve 		}
117c3e57739SLionel Debieve 
118c3e57739SLionel Debieve 		VERBOSE("%s Status %x\n", __func__, *status);
119c3e57739SLionel Debieve 		if ((*status & SPI_NAND_STATUS_BUSY) == 0U) {
120c3e57739SLionel Debieve 			return 0;
121c3e57739SLionel Debieve 		}
122c3e57739SLionel Debieve 	}
123c3e57739SLionel Debieve 
124c3e57739SLionel Debieve 	return -ETIMEDOUT;
125c3e57739SLionel Debieve }
126c3e57739SLionel Debieve 
127c3e57739SLionel Debieve static int spi_nand_reset(void)
128c3e57739SLionel Debieve {
129c3e57739SLionel Debieve 	struct spi_mem_op op;
130c3e57739SLionel Debieve 	uint8_t status;
131c3e57739SLionel Debieve 	int ret;
132c3e57739SLionel Debieve 
133c3e57739SLionel Debieve 	zeromem(&op, sizeof(struct spi_mem_op));
134c3e57739SLionel Debieve 	op.cmd.opcode = SPI_NAND_OP_RESET;
135c3e57739SLionel Debieve 	op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
136c3e57739SLionel Debieve 
137c3e57739SLionel Debieve 	ret = spi_mem_exec_op(&op);
138c3e57739SLionel Debieve 	if (ret != 0) {
139c3e57739SLionel Debieve 		return ret;
140c3e57739SLionel Debieve 	}
141c3e57739SLionel Debieve 
142c3e57739SLionel Debieve 	return spi_nand_wait_ready(&status);
143c3e57739SLionel Debieve }
144c3e57739SLionel Debieve 
145c3e57739SLionel Debieve static int spi_nand_read_id(uint8_t *id)
146c3e57739SLionel Debieve {
147c3e57739SLionel Debieve 	struct spi_mem_op op;
148c3e57739SLionel Debieve 
149c3e57739SLionel Debieve 	zeromem(&op, sizeof(struct spi_mem_op));
150c3e57739SLionel Debieve 	op.cmd.opcode = SPI_NAND_OP_READ_ID;
151c3e57739SLionel Debieve 	op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
152c3e57739SLionel Debieve 	op.data.dir = SPI_MEM_DATA_IN;
153c3e57739SLionel Debieve 	op.data.nbytes = SPI_NAND_MAX_ID_LEN;
154c3e57739SLionel Debieve 	op.data.buf = id;
155c3e57739SLionel Debieve 	op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
156c3e57739SLionel Debieve 
157c3e57739SLionel Debieve 	return spi_mem_exec_op(&op);
158c3e57739SLionel Debieve }
159c3e57739SLionel Debieve 
160c3e57739SLionel Debieve static int spi_nand_load_page(unsigned int page)
161c3e57739SLionel Debieve {
162c3e57739SLionel Debieve 	struct spi_mem_op op;
163c3e57739SLionel Debieve 	uint32_t block_nb = page / spinand_dev.nand_dev->block_size;
164c3e57739SLionel Debieve 	uint32_t page_nb = page - (block_nb * spinand_dev.nand_dev->page_size);
165c3e57739SLionel Debieve 	uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
166c3e57739SLionel Debieve 				     spinand_dev.nand_dev->page_size;
167c3e57739SLionel Debieve 	uint32_t block_sh = __builtin_ctz(nbpages_per_block) + 1U;
168c3e57739SLionel Debieve 
169c3e57739SLionel Debieve 	zeromem(&op, sizeof(struct spi_mem_op));
170c3e57739SLionel Debieve 	op.cmd.opcode = SPI_NAND_OP_LOAD_PAGE;
171c3e57739SLionel Debieve 	op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
172c3e57739SLionel Debieve 	op.addr.val = (block_nb << block_sh) | page_nb;
173c3e57739SLionel Debieve 	op.addr.nbytes = 3U;
174c3e57739SLionel Debieve 	op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
175c3e57739SLionel Debieve 
176c3e57739SLionel Debieve 	return spi_mem_exec_op(&op);
177c3e57739SLionel Debieve }
178c3e57739SLionel Debieve 
179c3e57739SLionel Debieve static int spi_nand_read_from_cache(unsigned int page, unsigned int offset,
180c3e57739SLionel Debieve 				    uint8_t *buffer, unsigned int len)
181c3e57739SLionel Debieve {
182c3e57739SLionel Debieve 	uint32_t nbpages_per_block = spinand_dev.nand_dev->block_size /
183c3e57739SLionel Debieve 				     spinand_dev.nand_dev->page_size;
184c3e57739SLionel Debieve 	uint32_t block_nb = page / nbpages_per_block;
185c3e57739SLionel Debieve 	uint32_t page_sh = __builtin_ctz(spinand_dev.nand_dev->page_size) + 1U;
186c3e57739SLionel Debieve 
187c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.addr.val = offset;
188c3e57739SLionel Debieve 
189c3e57739SLionel Debieve 	if ((spinand_dev.nand_dev->nb_planes > 1U) && ((block_nb % 2U) == 1U)) {
190c3e57739SLionel Debieve 		spinand_dev.spi_read_cache_op.addr.val |= 1U << page_sh;
191c3e57739SLionel Debieve 	}
192c3e57739SLionel Debieve 
193c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.data.buf = buffer;
194c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.data.nbytes = len;
195c3e57739SLionel Debieve 
196c3e57739SLionel Debieve 	return spi_mem_exec_op(&spinand_dev.spi_read_cache_op);
197c3e57739SLionel Debieve }
198c3e57739SLionel Debieve 
199c3e57739SLionel Debieve static int spi_nand_read_page(unsigned int page, unsigned int offset,
200c3e57739SLionel Debieve 			      uint8_t *buffer, unsigned int len,
201c3e57739SLionel Debieve 			      bool ecc_enabled)
202c3e57739SLionel Debieve {
203c3e57739SLionel Debieve 	uint8_t status;
204c3e57739SLionel Debieve 	int ret;
205c3e57739SLionel Debieve 
206c3e57739SLionel Debieve 	ret = spi_nand_ecc_enable(ecc_enabled);
207c3e57739SLionel Debieve 	if (ret != 0) {
208c3e57739SLionel Debieve 		return ret;
209c3e57739SLionel Debieve 	}
210c3e57739SLionel Debieve 
211c3e57739SLionel Debieve 	ret = spi_nand_load_page(page);
212c3e57739SLionel Debieve 	if (ret != 0) {
213c3e57739SLionel Debieve 		return ret;
214c3e57739SLionel Debieve 	}
215c3e57739SLionel Debieve 
216c3e57739SLionel Debieve 	ret = spi_nand_wait_ready(&status);
217c3e57739SLionel Debieve 	if (ret != 0) {
218c3e57739SLionel Debieve 		return ret;
219c3e57739SLionel Debieve 	}
220c3e57739SLionel Debieve 
221c3e57739SLionel Debieve 	ret = spi_nand_read_from_cache(page, offset, buffer, len);
222c3e57739SLionel Debieve 	if (ret != 0) {
223c3e57739SLionel Debieve 		return ret;
224c3e57739SLionel Debieve 	}
225c3e57739SLionel Debieve 
226c3e57739SLionel Debieve 	if (ecc_enabled && ((status & SPI_NAND_STATUS_ECC_UNCOR) != 0U)) {
227c3e57739SLionel Debieve 		return -EBADMSG;
228c3e57739SLionel Debieve 	}
229c3e57739SLionel Debieve 
230c3e57739SLionel Debieve 	return 0;
231c3e57739SLionel Debieve }
232c3e57739SLionel Debieve 
233c3e57739SLionel Debieve static int spi_nand_mtd_block_is_bad(unsigned int block)
234c3e57739SLionel Debieve {
235c3e57739SLionel Debieve 	unsigned int nbpages_per_block = spinand_dev.nand_dev->block_size /
236c3e57739SLionel Debieve 					 spinand_dev.nand_dev->page_size;
237c3e57739SLionel Debieve 	uint8_t bbm_marker[2];
238c3e57739SLionel Debieve 	int ret;
239c3e57739SLionel Debieve 
240c3e57739SLionel Debieve 	ret = spi_nand_read_page(block * nbpages_per_block,
241c3e57739SLionel Debieve 				 spinand_dev.nand_dev->page_size,
242c3e57739SLionel Debieve 				 bbm_marker, sizeof(bbm_marker), false);
243c3e57739SLionel Debieve 	if (ret != 0) {
244c3e57739SLionel Debieve 		return ret;
245c3e57739SLionel Debieve 	}
246c3e57739SLionel Debieve 
247c3e57739SLionel Debieve 	if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
248c3e57739SLionel Debieve 	    (bbm_marker[1] != GENMASK_32(7, 0))) {
249*6e86b462SYann Gautier 		WARN("Block %u is bad\n", block);
250c3e57739SLionel Debieve 		return 1;
251c3e57739SLionel Debieve 	}
252c3e57739SLionel Debieve 
253c3e57739SLionel Debieve 	return 0;
254c3e57739SLionel Debieve }
255c3e57739SLionel Debieve 
256c3e57739SLionel Debieve static int spi_nand_mtd_read_page(struct nand_device *nand, unsigned int page,
257c3e57739SLionel Debieve 				  uintptr_t buffer)
258c3e57739SLionel Debieve {
259c3e57739SLionel Debieve 	return spi_nand_read_page(page, 0, (uint8_t *)buffer,
260c3e57739SLionel Debieve 				  spinand_dev.nand_dev->page_size, true);
261c3e57739SLionel Debieve }
262c3e57739SLionel Debieve 
263c3e57739SLionel Debieve int spi_nand_init(unsigned long long *size, unsigned int *erase_size)
264c3e57739SLionel Debieve {
265c3e57739SLionel Debieve 	uint8_t id[SPI_NAND_MAX_ID_LEN];
266c3e57739SLionel Debieve 	int ret;
267c3e57739SLionel Debieve 
268c3e57739SLionel Debieve 	spinand_dev.nand_dev = get_nand_device();
269c3e57739SLionel Debieve 	if (spinand_dev.nand_dev == NULL) {
270c3e57739SLionel Debieve 		return -EINVAL;
271c3e57739SLionel Debieve 	}
272c3e57739SLionel Debieve 
273c3e57739SLionel Debieve 	spinand_dev.nand_dev->mtd_block_is_bad = spi_nand_mtd_block_is_bad;
274c3e57739SLionel Debieve 	spinand_dev.nand_dev->mtd_read_page = spi_nand_mtd_read_page;
275c3e57739SLionel Debieve 	spinand_dev.nand_dev->nb_planes = 1;
276c3e57739SLionel Debieve 
277c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.cmd.opcode = SPI_NAND_OP_READ_FROM_CACHE;
278c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.cmd.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
279c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.addr.nbytes = 2U;
280c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.addr.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
281c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.dummy.nbytes = 1U;
282c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.dummy.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
283c3e57739SLionel Debieve 	spinand_dev.spi_read_cache_op.data.buswidth = SPI_MEM_BUSWIDTH_1_LINE;
284c3e57739SLionel Debieve 
285c3e57739SLionel Debieve 	if (plat_get_spi_nand_data(&spinand_dev) != 0) {
286c3e57739SLionel Debieve 		return -EINVAL;
287c3e57739SLionel Debieve 	}
288c3e57739SLionel Debieve 
289bc453ab1SChristophe Kerello 	assert((spinand_dev.nand_dev->page_size != 0U) &&
290bc453ab1SChristophe Kerello 	       (spinand_dev.nand_dev->block_size != 0U) &&
291bc453ab1SChristophe Kerello 	       (spinand_dev.nand_dev->size != 0U));
292bc453ab1SChristophe Kerello 
293c3e57739SLionel Debieve 	ret = spi_nand_reset();
294c3e57739SLionel Debieve 	if (ret != 0) {
295c3e57739SLionel Debieve 		return ret;
296c3e57739SLionel Debieve 	}
297c3e57739SLionel Debieve 
298c3e57739SLionel Debieve 	ret = spi_nand_read_id(id);
299c3e57739SLionel Debieve 	if (ret != 0) {
300c3e57739SLionel Debieve 		return ret;
301c3e57739SLionel Debieve 	}
302c3e57739SLionel Debieve 
303c3e57739SLionel Debieve 	ret = spi_nand_read_reg(SPI_NAND_REG_CFG, &spinand_dev.cfg_cache);
304c3e57739SLionel Debieve 	if (ret != 0) {
305c3e57739SLionel Debieve 		return ret;
306c3e57739SLionel Debieve 	}
307c3e57739SLionel Debieve 
3084490b796SChristophe Kerello 	ret = spi_nand_quad_enable(id[1]);
309c3e57739SLionel Debieve 	if (ret != 0) {
310c3e57739SLionel Debieve 		return ret;
311c3e57739SLionel Debieve 	}
312c3e57739SLionel Debieve 
3134490b796SChristophe Kerello 	VERBOSE("SPI_NAND Detected ID 0x%x\n", id[1]);
314c3e57739SLionel Debieve 
315*6e86b462SYann Gautier 	VERBOSE("Page size %u, Block size %u, size %llu\n",
316c3e57739SLionel Debieve 		spinand_dev.nand_dev->page_size,
317c3e57739SLionel Debieve 		spinand_dev.nand_dev->block_size,
318c3e57739SLionel Debieve 		spinand_dev.nand_dev->size);
319c3e57739SLionel Debieve 
320c3e57739SLionel Debieve 	*size = spinand_dev.nand_dev->size;
321c3e57739SLionel Debieve 	*erase_size = spinand_dev.nand_dev->block_size;
322c3e57739SLionel Debieve 
323c3e57739SLionel Debieve 	return 0;
324c3e57739SLionel Debieve }
325