xref: /arm-trusted-firmware/drivers/mtd/nand/raw_nand.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <stddef.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <common/debug.h>
12*91f16700Schasinglulu #include <drivers/delay_timer.h>
13*91f16700Schasinglulu #include <drivers/raw_nand.h>
14*91f16700Schasinglulu #include <lib/utils.h>
15*91f16700Schasinglulu 
16*91f16700Schasinglulu #include <platform_def.h>
17*91f16700Schasinglulu 
18*91f16700Schasinglulu #define ONFI_SIGNATURE_ADDR	0x20U
19*91f16700Schasinglulu 
20*91f16700Schasinglulu /* CRC calculation */
21*91f16700Schasinglulu #define CRC_POLYNOM		0x8005U
22*91f16700Schasinglulu #define CRC_INIT_VALUE		0x4F4EU
23*91f16700Schasinglulu 
24*91f16700Schasinglulu /* Status register */
25*91f16700Schasinglulu #define NAND_STATUS_READY	BIT(6)
26*91f16700Schasinglulu 
27*91f16700Schasinglulu static struct rawnand_device rawnand_dev;
28*91f16700Schasinglulu 
29*91f16700Schasinglulu #pragma weak plat_get_raw_nand_data
30*91f16700Schasinglulu int plat_get_raw_nand_data(struct rawnand_device *device)
31*91f16700Schasinglulu {
32*91f16700Schasinglulu 	return 0;
33*91f16700Schasinglulu }
34*91f16700Schasinglulu 
35*91f16700Schasinglulu static int nand_send_cmd(uint8_t cmd, unsigned int tim)
36*91f16700Schasinglulu {
37*91f16700Schasinglulu 	struct nand_req req;
38*91f16700Schasinglulu 
39*91f16700Schasinglulu 	zeromem(&req, sizeof(struct nand_req));
40*91f16700Schasinglulu 	req.nand = rawnand_dev.nand_dev;
41*91f16700Schasinglulu 	req.type = NAND_REQ_CMD | cmd;
42*91f16700Schasinglulu 	req.inst_delay = tim;
43*91f16700Schasinglulu 
44*91f16700Schasinglulu 	return rawnand_dev.ops->exec(&req);
45*91f16700Schasinglulu }
46*91f16700Schasinglulu 
47*91f16700Schasinglulu static int nand_send_addr(uint8_t addr, unsigned int tim)
48*91f16700Schasinglulu {
49*91f16700Schasinglulu 	struct nand_req req;
50*91f16700Schasinglulu 
51*91f16700Schasinglulu 	zeromem(&req, sizeof(struct nand_req));
52*91f16700Schasinglulu 	req.nand = rawnand_dev.nand_dev;
53*91f16700Schasinglulu 	req.type = NAND_REQ_ADDR;
54*91f16700Schasinglulu 	req.addr = &addr;
55*91f16700Schasinglulu 	req.inst_delay = tim;
56*91f16700Schasinglulu 
57*91f16700Schasinglulu 	return rawnand_dev.ops->exec(&req);
58*91f16700Schasinglulu }
59*91f16700Schasinglulu 
60*91f16700Schasinglulu static int nand_send_wait(unsigned int delay, unsigned int tim)
61*91f16700Schasinglulu {
62*91f16700Schasinglulu 	struct nand_req req;
63*91f16700Schasinglulu 
64*91f16700Schasinglulu 	zeromem(&req, sizeof(struct nand_req));
65*91f16700Schasinglulu 	req.nand = rawnand_dev.nand_dev;
66*91f16700Schasinglulu 	req.type = NAND_REQ_WAIT;
67*91f16700Schasinglulu 	req.inst_delay = tim;
68*91f16700Schasinglulu 	req.delay_ms = delay;
69*91f16700Schasinglulu 
70*91f16700Schasinglulu 	return rawnand_dev.ops->exec(&req);
71*91f16700Schasinglulu }
72*91f16700Schasinglulu 
73*91f16700Schasinglulu 
74*91f16700Schasinglulu static int nand_read_data(uint8_t *data, unsigned int length, bool use_8bit)
75*91f16700Schasinglulu {
76*91f16700Schasinglulu 	struct nand_req req;
77*91f16700Schasinglulu 
78*91f16700Schasinglulu 	zeromem(&req, sizeof(struct nand_req));
79*91f16700Schasinglulu 	req.nand = rawnand_dev.nand_dev;
80*91f16700Schasinglulu 	req.type = NAND_REQ_DATAIN | (use_8bit ? NAND_REQ_BUS_WIDTH_8 : 0U);
81*91f16700Schasinglulu 	req.addr = data;
82*91f16700Schasinglulu 	req.length = length;
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	return rawnand_dev.ops->exec(&req);
85*91f16700Schasinglulu }
86*91f16700Schasinglulu 
87*91f16700Schasinglulu int nand_change_read_column_cmd(unsigned int offset, uintptr_t buffer,
88*91f16700Schasinglulu 				unsigned int len)
89*91f16700Schasinglulu {
90*91f16700Schasinglulu 	int ret;
91*91f16700Schasinglulu 	uint8_t addr[2];
92*91f16700Schasinglulu 	unsigned int i;
93*91f16700Schasinglulu 
94*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_CHANGE_1ST, 0U);
95*91f16700Schasinglulu 	if (ret !=  0) {
96*91f16700Schasinglulu 		return ret;
97*91f16700Schasinglulu 	}
98*91f16700Schasinglulu 
99*91f16700Schasinglulu 	if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
100*91f16700Schasinglulu 		offset /= 2U;
101*91f16700Schasinglulu 	}
102*91f16700Schasinglulu 
103*91f16700Schasinglulu 	addr[0] = offset;
104*91f16700Schasinglulu 	addr[1] = offset >> 8;
105*91f16700Schasinglulu 
106*91f16700Schasinglulu 	for (i = 0; i < 2U; i++) {
107*91f16700Schasinglulu 		ret = nand_send_addr(addr[i], 0U);
108*91f16700Schasinglulu 		if (ret !=  0) {
109*91f16700Schasinglulu 			return ret;
110*91f16700Schasinglulu 		}
111*91f16700Schasinglulu 	}
112*91f16700Schasinglulu 
113*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_CHANGE_2ND, NAND_TCCS_MIN);
114*91f16700Schasinglulu 	if (ret !=  0) {
115*91f16700Schasinglulu 		return ret;
116*91f16700Schasinglulu 	}
117*91f16700Schasinglulu 
118*91f16700Schasinglulu 	return nand_read_data((uint8_t *)buffer, len, false);
119*91f16700Schasinglulu }
120*91f16700Schasinglulu 
121*91f16700Schasinglulu int nand_read_page_cmd(unsigned int page, unsigned int offset,
122*91f16700Schasinglulu 		       uintptr_t buffer, unsigned int len)
123*91f16700Schasinglulu {
124*91f16700Schasinglulu 	uint8_t addr[5];
125*91f16700Schasinglulu 	uint8_t i = 0U;
126*91f16700Schasinglulu 	uint8_t j;
127*91f16700Schasinglulu 	int ret;
128*91f16700Schasinglulu 
129*91f16700Schasinglulu 	VERBOSE(">%s page %u offset %u buffer 0x%lx\n", __func__, page, offset,
130*91f16700Schasinglulu 		buffer);
131*91f16700Schasinglulu 
132*91f16700Schasinglulu 	if (rawnand_dev.nand_dev->buswidth == NAND_BUS_WIDTH_16) {
133*91f16700Schasinglulu 		offset /= 2U;
134*91f16700Schasinglulu 	}
135*91f16700Schasinglulu 
136*91f16700Schasinglulu 	addr[i++] = offset;
137*91f16700Schasinglulu 	addr[i++] = offset >> 8;
138*91f16700Schasinglulu 
139*91f16700Schasinglulu 	addr[i++] = page;
140*91f16700Schasinglulu 	addr[i++] = page >> 8;
141*91f16700Schasinglulu 	if (rawnand_dev.nand_dev->size > SZ_128M) {
142*91f16700Schasinglulu 		addr[i++] = page >> 16;
143*91f16700Schasinglulu 	}
144*91f16700Schasinglulu 
145*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_READ_1ST, 0U);
146*91f16700Schasinglulu 	if (ret != 0) {
147*91f16700Schasinglulu 		return ret;
148*91f16700Schasinglulu 	}
149*91f16700Schasinglulu 
150*91f16700Schasinglulu 	for (j = 0U; j < i; j++) {
151*91f16700Schasinglulu 		ret = nand_send_addr(addr[j], 0U);
152*91f16700Schasinglulu 		if (ret != 0) {
153*91f16700Schasinglulu 			return ret;
154*91f16700Schasinglulu 		}
155*91f16700Schasinglulu 	}
156*91f16700Schasinglulu 
157*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_READ_2ND, NAND_TWB_MAX);
158*91f16700Schasinglulu 	if (ret != 0) {
159*91f16700Schasinglulu 		return ret;
160*91f16700Schasinglulu 	}
161*91f16700Schasinglulu 
162*91f16700Schasinglulu 	ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
163*91f16700Schasinglulu 	if (ret != 0) {
164*91f16700Schasinglulu 		return ret;
165*91f16700Schasinglulu 	}
166*91f16700Schasinglulu 
167*91f16700Schasinglulu 	if (buffer != 0U) {
168*91f16700Schasinglulu 		ret = nand_read_data((uint8_t *)buffer, len, false);
169*91f16700Schasinglulu 	}
170*91f16700Schasinglulu 
171*91f16700Schasinglulu 	return ret;
172*91f16700Schasinglulu }
173*91f16700Schasinglulu 
174*91f16700Schasinglulu static int nand_status(uint8_t *status)
175*91f16700Schasinglulu {
176*91f16700Schasinglulu 	int ret;
177*91f16700Schasinglulu 
178*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_STATUS, NAND_TWHR_MIN);
179*91f16700Schasinglulu 	if (ret != 0) {
180*91f16700Schasinglulu 		return ret;
181*91f16700Schasinglulu 	}
182*91f16700Schasinglulu 
183*91f16700Schasinglulu 	if (status != NULL) {
184*91f16700Schasinglulu 		ret = nand_read_data(status, 1U, true);
185*91f16700Schasinglulu 	}
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	return ret;
188*91f16700Schasinglulu }
189*91f16700Schasinglulu 
190*91f16700Schasinglulu int nand_wait_ready(unsigned int delay_ms)
191*91f16700Schasinglulu {
192*91f16700Schasinglulu 	uint8_t status;
193*91f16700Schasinglulu 	int ret;
194*91f16700Schasinglulu 	uint64_t timeout;
195*91f16700Schasinglulu 
196*91f16700Schasinglulu 	/* Wait before reading status */
197*91f16700Schasinglulu 	udelay(1);
198*91f16700Schasinglulu 
199*91f16700Schasinglulu 	ret = nand_status(NULL);
200*91f16700Schasinglulu 	if (ret != 0) {
201*91f16700Schasinglulu 		return ret;
202*91f16700Schasinglulu 	}
203*91f16700Schasinglulu 
204*91f16700Schasinglulu 	timeout = timeout_init_us(delay_ms * 1000U);
205*91f16700Schasinglulu 	while (!timeout_elapsed(timeout)) {
206*91f16700Schasinglulu 		ret = nand_read_data(&status, 1U, true);
207*91f16700Schasinglulu 		if (ret != 0) {
208*91f16700Schasinglulu 			return ret;
209*91f16700Schasinglulu 		}
210*91f16700Schasinglulu 
211*91f16700Schasinglulu 		if ((status & NAND_STATUS_READY) != 0U) {
212*91f16700Schasinglulu 			return nand_send_cmd(NAND_CMD_READ_1ST, 0U);
213*91f16700Schasinglulu 		}
214*91f16700Schasinglulu 
215*91f16700Schasinglulu 		udelay(10);
216*91f16700Schasinglulu 	}
217*91f16700Schasinglulu 
218*91f16700Schasinglulu 	return -ETIMEDOUT;
219*91f16700Schasinglulu }
220*91f16700Schasinglulu 
221*91f16700Schasinglulu static int nand_reset(void)
222*91f16700Schasinglulu {
223*91f16700Schasinglulu 	int ret;
224*91f16700Schasinglulu 
225*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_RESET, NAND_TWB_MAX);
226*91f16700Schasinglulu 	if (ret != 0) {
227*91f16700Schasinglulu 		return ret;
228*91f16700Schasinglulu 	}
229*91f16700Schasinglulu 
230*91f16700Schasinglulu 	return nand_send_wait(PSEC_TO_MSEC(NAND_TRST_MAX), 0U);
231*91f16700Schasinglulu }
232*91f16700Schasinglulu 
233*91f16700Schasinglulu #if NAND_ONFI_DETECT
234*91f16700Schasinglulu static uint16_t nand_check_crc(uint16_t crc, uint8_t *data_in,
235*91f16700Schasinglulu 			       unsigned int data_len)
236*91f16700Schasinglulu {
237*91f16700Schasinglulu 	uint32_t i;
238*91f16700Schasinglulu 	uint32_t j;
239*91f16700Schasinglulu 	uint32_t bit;
240*91f16700Schasinglulu 
241*91f16700Schasinglulu 	for (i = 0U; i < data_len; i++) {
242*91f16700Schasinglulu 		uint8_t cur_param = *data_in++;
243*91f16700Schasinglulu 
244*91f16700Schasinglulu 		for (j = BIT(7); j != 0U; j >>= 1) {
245*91f16700Schasinglulu 			bit = crc & BIT(15);
246*91f16700Schasinglulu 			crc <<= 1;
247*91f16700Schasinglulu 
248*91f16700Schasinglulu 			if ((cur_param & j) != 0U) {
249*91f16700Schasinglulu 				bit ^= BIT(15);
250*91f16700Schasinglulu 			}
251*91f16700Schasinglulu 
252*91f16700Schasinglulu 			if (bit != 0U) {
253*91f16700Schasinglulu 				crc ^= CRC_POLYNOM;
254*91f16700Schasinglulu 			}
255*91f16700Schasinglulu 		}
256*91f16700Schasinglulu 
257*91f16700Schasinglulu 		crc &= GENMASK(15, 0);
258*91f16700Schasinglulu 	}
259*91f16700Schasinglulu 
260*91f16700Schasinglulu 	return crc;
261*91f16700Schasinglulu }
262*91f16700Schasinglulu 
263*91f16700Schasinglulu static int nand_read_id(uint8_t addr, uint8_t *id, unsigned int size)
264*91f16700Schasinglulu {
265*91f16700Schasinglulu 	int ret;
266*91f16700Schasinglulu 
267*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_READID, 0U);
268*91f16700Schasinglulu 	if (ret !=  0) {
269*91f16700Schasinglulu 		return ret;
270*91f16700Schasinglulu 	}
271*91f16700Schasinglulu 
272*91f16700Schasinglulu 	ret = nand_send_addr(addr, NAND_TWHR_MIN);
273*91f16700Schasinglulu 	if (ret !=  0) {
274*91f16700Schasinglulu 		return ret;
275*91f16700Schasinglulu 	}
276*91f16700Schasinglulu 
277*91f16700Schasinglulu 	return nand_read_data(id, size, true);
278*91f16700Schasinglulu }
279*91f16700Schasinglulu 
280*91f16700Schasinglulu static int nand_read_param_page(void)
281*91f16700Schasinglulu {
282*91f16700Schasinglulu 	struct nand_param_page page;
283*91f16700Schasinglulu 	uint8_t addr = 0U;
284*91f16700Schasinglulu 	int ret;
285*91f16700Schasinglulu 
286*91f16700Schasinglulu 	ret = nand_send_cmd(NAND_CMD_READ_PARAM_PAGE, 0U);
287*91f16700Schasinglulu 	if (ret != 0) {
288*91f16700Schasinglulu 		return ret;
289*91f16700Schasinglulu 	}
290*91f16700Schasinglulu 
291*91f16700Schasinglulu 	ret = nand_send_addr(addr, NAND_TWB_MAX);
292*91f16700Schasinglulu 	if (ret != 0) {
293*91f16700Schasinglulu 		return ret;
294*91f16700Schasinglulu 	}
295*91f16700Schasinglulu 
296*91f16700Schasinglulu 	ret = nand_send_wait(PSEC_TO_MSEC(NAND_TR_MAX), NAND_TRR_MIN);
297*91f16700Schasinglulu 	if (ret != 0) {
298*91f16700Schasinglulu 		return ret;
299*91f16700Schasinglulu 	}
300*91f16700Schasinglulu 
301*91f16700Schasinglulu 	ret = nand_read_data((uint8_t *)&page, sizeof(page), true);
302*91f16700Schasinglulu 	if (ret != 0) {
303*91f16700Schasinglulu 		return ret;
304*91f16700Schasinglulu 	}
305*91f16700Schasinglulu 
306*91f16700Schasinglulu 	if (strncmp((char *)&page.page_sig, "ONFI", 4) != 0) {
307*91f16700Schasinglulu 		WARN("Error ONFI detection\n");
308*91f16700Schasinglulu 		return -EINVAL;
309*91f16700Schasinglulu 	}
310*91f16700Schasinglulu 
311*91f16700Schasinglulu 	if (nand_check_crc(CRC_INIT_VALUE, (uint8_t *)&page, 254U) !=
312*91f16700Schasinglulu 	    page.crc16) {
313*91f16700Schasinglulu 		WARN("Error reading param\n");
314*91f16700Schasinglulu 		return -EINVAL;
315*91f16700Schasinglulu 	}
316*91f16700Schasinglulu 
317*91f16700Schasinglulu 	if ((page.features & ONFI_FEAT_BUS_WIDTH_16) != 0U) {
318*91f16700Schasinglulu 		rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_16;
319*91f16700Schasinglulu 	} else {
320*91f16700Schasinglulu 		rawnand_dev.nand_dev->buswidth = NAND_BUS_WIDTH_8;
321*91f16700Schasinglulu 	}
322*91f16700Schasinglulu 
323*91f16700Schasinglulu 	rawnand_dev.nand_dev->block_size = page.num_pages_per_blk *
324*91f16700Schasinglulu 					   page.bytes_per_page;
325*91f16700Schasinglulu 	rawnand_dev.nand_dev->page_size = page.bytes_per_page;
326*91f16700Schasinglulu 	rawnand_dev.nand_dev->size = page.num_pages_per_blk *
327*91f16700Schasinglulu 				     page.bytes_per_page *
328*91f16700Schasinglulu 				     page.num_blk_in_lun * page.num_lun;
329*91f16700Schasinglulu 
330*91f16700Schasinglulu 	if (page.nb_ecc_bits != GENMASK_32(7, 0)) {
331*91f16700Schasinglulu 		rawnand_dev.nand_dev->ecc.max_bit_corr = page.nb_ecc_bits;
332*91f16700Schasinglulu 		rawnand_dev.nand_dev->ecc.size = SZ_512;
333*91f16700Schasinglulu 	}
334*91f16700Schasinglulu 
335*91f16700Schasinglulu 	VERBOSE("Page size %u, block_size %u, Size %llu, ecc %u, buswidth %u\n",
336*91f16700Schasinglulu 		rawnand_dev.nand_dev->page_size,
337*91f16700Schasinglulu 		rawnand_dev.nand_dev->block_size, rawnand_dev.nand_dev->size,
338*91f16700Schasinglulu 		rawnand_dev.nand_dev->ecc.max_bit_corr,
339*91f16700Schasinglulu 		rawnand_dev.nand_dev->buswidth);
340*91f16700Schasinglulu 
341*91f16700Schasinglulu 	return 0;
342*91f16700Schasinglulu }
343*91f16700Schasinglulu 
344*91f16700Schasinglulu static int detect_onfi(void)
345*91f16700Schasinglulu {
346*91f16700Schasinglulu 	int ret;
347*91f16700Schasinglulu 	char id[4];
348*91f16700Schasinglulu 
349*91f16700Schasinglulu 	ret = nand_read_id(ONFI_SIGNATURE_ADDR, (uint8_t *)id, sizeof(id));
350*91f16700Schasinglulu 	if (ret != 0) {
351*91f16700Schasinglulu 		return ret;
352*91f16700Schasinglulu 	}
353*91f16700Schasinglulu 
354*91f16700Schasinglulu 	if (strncmp(id, "ONFI", sizeof(id)) != 0) {
355*91f16700Schasinglulu 		WARN("NAND Non ONFI detected\n");
356*91f16700Schasinglulu 		return -ENODEV;
357*91f16700Schasinglulu 	}
358*91f16700Schasinglulu 
359*91f16700Schasinglulu 	return nand_read_param_page();
360*91f16700Schasinglulu }
361*91f16700Schasinglulu #endif
362*91f16700Schasinglulu 
363*91f16700Schasinglulu static int nand_mtd_block_is_bad(unsigned int block)
364*91f16700Schasinglulu {
365*91f16700Schasinglulu 	unsigned int nbpages_per_block = rawnand_dev.nand_dev->block_size /
366*91f16700Schasinglulu 					 rawnand_dev.nand_dev->page_size;
367*91f16700Schasinglulu 	uint8_t bbm_marker[2];
368*91f16700Schasinglulu 	uint8_t page;
369*91f16700Schasinglulu 	int ret;
370*91f16700Schasinglulu 
371*91f16700Schasinglulu 	for (page = 0U; page < 2U; page++) {
372*91f16700Schasinglulu 		ret = nand_read_page_cmd(block * nbpages_per_block,
373*91f16700Schasinglulu 					 rawnand_dev.nand_dev->page_size,
374*91f16700Schasinglulu 					 (uintptr_t)bbm_marker,
375*91f16700Schasinglulu 					 sizeof(bbm_marker));
376*91f16700Schasinglulu 		if (ret != 0) {
377*91f16700Schasinglulu 			return ret;
378*91f16700Schasinglulu 		}
379*91f16700Schasinglulu 
380*91f16700Schasinglulu 		if ((bbm_marker[0] != GENMASK_32(7, 0)) ||
381*91f16700Schasinglulu 		    (bbm_marker[1] != GENMASK_32(7, 0))) {
382*91f16700Schasinglulu 			WARN("Block %u is bad\n", block);
383*91f16700Schasinglulu 			return 1;
384*91f16700Schasinglulu 		}
385*91f16700Schasinglulu 	}
386*91f16700Schasinglulu 
387*91f16700Schasinglulu 	return 0;
388*91f16700Schasinglulu }
389*91f16700Schasinglulu 
390*91f16700Schasinglulu static int nand_mtd_read_page_raw(struct nand_device *nand, unsigned int page,
391*91f16700Schasinglulu 				  uintptr_t buffer)
392*91f16700Schasinglulu {
393*91f16700Schasinglulu 	return nand_read_page_cmd(page, 0U, buffer,
394*91f16700Schasinglulu 				  rawnand_dev.nand_dev->page_size);
395*91f16700Schasinglulu }
396*91f16700Schasinglulu 
397*91f16700Schasinglulu void nand_raw_ctrl_init(const struct nand_ctrl_ops *ops)
398*91f16700Schasinglulu {
399*91f16700Schasinglulu 	rawnand_dev.ops = ops;
400*91f16700Schasinglulu }
401*91f16700Schasinglulu 
402*91f16700Schasinglulu int nand_raw_init(unsigned long long *size, unsigned int *erase_size)
403*91f16700Schasinglulu {
404*91f16700Schasinglulu 	int ret;
405*91f16700Schasinglulu 
406*91f16700Schasinglulu 	rawnand_dev.nand_dev = get_nand_device();
407*91f16700Schasinglulu 	if (rawnand_dev.nand_dev == NULL) {
408*91f16700Schasinglulu 		return -EINVAL;
409*91f16700Schasinglulu 	}
410*91f16700Schasinglulu 
411*91f16700Schasinglulu 	rawnand_dev.nand_dev->mtd_block_is_bad = nand_mtd_block_is_bad;
412*91f16700Schasinglulu 	rawnand_dev.nand_dev->mtd_read_page = nand_mtd_read_page_raw;
413*91f16700Schasinglulu 	rawnand_dev.nand_dev->ecc.mode = NAND_ECC_NONE;
414*91f16700Schasinglulu 
415*91f16700Schasinglulu 	if ((rawnand_dev.ops->setup == NULL) ||
416*91f16700Schasinglulu 	    (rawnand_dev.ops->exec == NULL)) {
417*91f16700Schasinglulu 		return -ENODEV;
418*91f16700Schasinglulu 	}
419*91f16700Schasinglulu 
420*91f16700Schasinglulu 	ret = nand_reset();
421*91f16700Schasinglulu 	if (ret != 0) {
422*91f16700Schasinglulu 		return ret;
423*91f16700Schasinglulu 	}
424*91f16700Schasinglulu 
425*91f16700Schasinglulu #if NAND_ONFI_DETECT
426*91f16700Schasinglulu 	if (detect_onfi() != 0) {
427*91f16700Schasinglulu 		WARN("Detect ONFI failed\n");
428*91f16700Schasinglulu 	}
429*91f16700Schasinglulu #endif
430*91f16700Schasinglulu 
431*91f16700Schasinglulu 	if (plat_get_raw_nand_data(&rawnand_dev) != 0) {
432*91f16700Schasinglulu 		return -EINVAL;
433*91f16700Schasinglulu 	}
434*91f16700Schasinglulu 
435*91f16700Schasinglulu 	assert((rawnand_dev.nand_dev->page_size != 0U) &&
436*91f16700Schasinglulu 	       (rawnand_dev.nand_dev->block_size != 0U) &&
437*91f16700Schasinglulu 	       (rawnand_dev.nand_dev->size != 0U));
438*91f16700Schasinglulu 
439*91f16700Schasinglulu 	*size = rawnand_dev.nand_dev->size;
440*91f16700Schasinglulu 	*erase_size = rawnand_dev.nand_dev->block_size;
441*91f16700Schasinglulu 
442*91f16700Schasinglulu 	rawnand_dev.ops->setup(rawnand_dev.nand_dev);
443*91f16700Schasinglulu 
444*91f16700Schasinglulu 	return 0;
445*91f16700Schasinglulu }
446