xref: /OK3568_Linux_fs/u-boot/drivers/mtd/nand/raw/denali_spl.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2014       Panasonic Corporation
3  * Copyright (C) 2014-2015  Masahiro Yamada <yamada.masahiro@socionext.com>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <asm/io.h>
10 #include <asm/unaligned.h>
11 #include <linux/mtd/rawnand.h>
12 #include "denali.h"
13 
14 #define DENALI_MAP01		(1 << 26)	/* read/write pages in PIO */
15 #define DENALI_MAP10		(2 << 26)	/* high-level control plane */
16 
17 #define INDEX_CTRL_REG		0x0
18 #define INDEX_DATA_REG		0x10
19 
20 #define SPARE_ACCESS		0x41
21 #define MAIN_ACCESS		0x42
22 #define PIPELINE_ACCESS		0x2000
23 
24 #define BANK(x) ((x) << 24)
25 
26 static void __iomem *denali_flash_mem =
27 			(void __iomem *)CONFIG_SYS_NAND_DATA_BASE;
28 static void __iomem *denali_flash_reg =
29 			(void __iomem *)CONFIG_SYS_NAND_REGS_BASE;
30 
31 static const int flash_bank;
32 static int page_size, oob_size, pages_per_block;
33 
index_addr(uint32_t address,uint32_t data)34 static void index_addr(uint32_t address, uint32_t data)
35 {
36 	writel(address, denali_flash_mem + INDEX_CTRL_REG);
37 	writel(data, denali_flash_mem + INDEX_DATA_REG);
38 }
39 
wait_for_irq(uint32_t irq_mask)40 static int wait_for_irq(uint32_t irq_mask)
41 {
42 	unsigned long timeout = 1000000;
43 	uint32_t intr_status;
44 
45 	do {
46 		intr_status = readl(denali_flash_reg + INTR_STATUS(flash_bank));
47 
48 		if (intr_status & INTR__ECC_UNCOR_ERR) {
49 			debug("Uncorrected ECC detected\n");
50 			return -EBADMSG;
51 		}
52 
53 		if (intr_status & irq_mask)
54 			break;
55 
56 		udelay(1);
57 		timeout--;
58 	} while (timeout);
59 
60 	if (!timeout) {
61 		debug("Timeout with interrupt status %08x\n", intr_status);
62 		return -EIO;
63 	}
64 
65 	return 0;
66 }
67 
read_data_from_flash_mem(uint8_t * buf,int len)68 static void read_data_from_flash_mem(uint8_t *buf, int len)
69 {
70 	int i;
71 	uint32_t *buf32;
72 
73 	/* transfer the data from the flash */
74 	buf32 = (uint32_t *)buf;
75 
76 	/*
77 	 * Let's take care of unaligned access although it rarely happens.
78 	 * Avoid put_unaligned() for the normal use cases since it leads to
79 	 * a bit performance regression.
80 	 */
81 	if ((unsigned long)buf32 % 4) {
82 		for (i = 0; i < len / 4; i++)
83 			put_unaligned(readl(denali_flash_mem + INDEX_DATA_REG),
84 				      buf32++);
85 	} else {
86 		for (i = 0; i < len / 4; i++)
87 			*buf32++ = readl(denali_flash_mem + INDEX_DATA_REG);
88 	}
89 
90 	if (len % 4) {
91 		u32 tmp;
92 
93 		tmp = cpu_to_le32(readl(denali_flash_mem + INDEX_DATA_REG));
94 		buf = (uint8_t *)buf32;
95 		for (i = 0; i < len % 4; i++) {
96 			*buf++ = tmp;
97 			tmp >>= 8;
98 		}
99 	}
100 }
101 
denali_send_pipeline_cmd(int page,int ecc_en,int access_type)102 int denali_send_pipeline_cmd(int page, int ecc_en, int access_type)
103 {
104 	uint32_t addr, cmd;
105 	static uint32_t page_count = 1;
106 
107 	writel(ecc_en, denali_flash_reg + ECC_ENABLE);
108 
109 	/* clear all bits of intr_status. */
110 	writel(0xffff, denali_flash_reg + INTR_STATUS(flash_bank));
111 
112 	addr = BANK(flash_bank) | page;
113 
114 	/* setup the acccess type */
115 	cmd = DENALI_MAP10 | addr;
116 	index_addr(cmd, access_type);
117 
118 	/* setup the pipeline command */
119 	index_addr(cmd, PIPELINE_ACCESS | page_count);
120 
121 	cmd = DENALI_MAP01 | addr;
122 	writel(cmd, denali_flash_mem + INDEX_CTRL_REG);
123 
124 	return wait_for_irq(INTR__LOAD_COMP);
125 }
126 
nand_read_oob(void * buf,int page)127 static int nand_read_oob(void *buf, int page)
128 {
129 	int ret;
130 
131 	ret = denali_send_pipeline_cmd(page, 0, SPARE_ACCESS);
132 	if (ret < 0)
133 		return ret;
134 
135 	read_data_from_flash_mem(buf, oob_size);
136 
137 	return 0;
138 }
139 
nand_read_page(void * buf,int page)140 static int nand_read_page(void *buf, int page)
141 {
142 	int ret;
143 
144 	ret = denali_send_pipeline_cmd(page, 1, MAIN_ACCESS);
145 	if (ret < 0)
146 		return ret;
147 
148 	read_data_from_flash_mem(buf, page_size);
149 
150 	return 0;
151 }
152 
nand_block_isbad(void * buf,int block)153 static int nand_block_isbad(void *buf, int block)
154 {
155 	int ret;
156 
157 	ret = nand_read_oob(buf, block * pages_per_block);
158 	if (ret < 0)
159 		return ret;
160 
161 	return *((uint8_t *)buf + CONFIG_SYS_NAND_BAD_BLOCK_POS) != 0xff;
162 }
163 
164 /* nand_init() - initialize data to make nand usable by SPL */
nand_init(void)165 void nand_init(void)
166 {
167 	/* access to main area */
168 	writel(0, denali_flash_reg + TRANSFER_SPARE_REG);
169 
170 	/*
171 	 * These registers are expected to be already set by the hardware
172 	 * or earlier boot code.  So we read these values out.
173 	 */
174 	page_size = readl(denali_flash_reg + DEVICE_MAIN_AREA_SIZE);
175 	oob_size = readl(denali_flash_reg + DEVICE_SPARE_AREA_SIZE);
176 	pages_per_block = readl(denali_flash_reg + PAGES_PER_BLOCK);
177 }
178 
nand_spl_load_image(uint32_t offs,unsigned int size,void * dst)179 int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst)
180 {
181 	int block, page, column, readlen;
182 	int ret;
183 	int force_bad_block_check = 1;
184 
185 	page = offs / page_size;
186 	column = offs % page_size;
187 
188 	block = page / pages_per_block;
189 	page = page % pages_per_block;
190 
191 	while (size) {
192 		if (force_bad_block_check || page == 0) {
193 			ret = nand_block_isbad(dst, block);
194 			if (ret < 0)
195 				return ret;
196 
197 			if (ret) {
198 				block++;
199 				continue;
200 			}
201 		}
202 
203 		force_bad_block_check = 0;
204 
205 		ret = nand_read_page(dst, block * pages_per_block + page);
206 		if (ret < 0)
207 			return ret;
208 
209 		readlen = min(page_size - column, (int)size);
210 
211 		if (unlikely(column)) {
212 			/* Partial page read */
213 			memmove(dst, dst + column, readlen);
214 			column = 0;
215 		}
216 
217 		size -= readlen;
218 		dst += readlen;
219 		page++;
220 		if (page == pages_per_block) {
221 			block++;
222 			page = 0;
223 		}
224 	}
225 
226 	return 0;
227 }
228 
nand_deselect(void)229 void nand_deselect(void) {}
230