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