blob: afccaf91e22c96d1138f3a4555e528b878ef4cdf [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
2 * Freescale QuadSPI driver.
3 *
4 * Copyright (C) 2013 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11#include <sdio.h>
12#include <common.h>
13#include <asm/io.h>
14#include "nor.h"
15#include <image.h>
16#include <linux/byteorder/generic.h>
17#include <secure_verify.h>
18#include "config.h"
19#include "flash.h"
20
21
22/* Used when the "_ext_id" is two bytes at most */
23#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
24 .id = { \
25 ((_jedec_id) >> 16) & 0xff, \
26 ((_jedec_id) >> 8) & 0xff, \
27 (_jedec_id) & 0xff, \
28 ((_ext_id) >> 8) & 0xff, \
29 (_ext_id) & 0xff, \
30 }, \
31 .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
32 .sector_size = (_sector_size), \
33 .n_sectors = (_n_sectors), \
34 .page_size = 256, \
35 .flags = (_flags),
36
37
38spinor_cmd_t nor_cmd_table[]=
39{
40 {CMD_RDFT, TX_DMA_DIS, RX_DMA_DIS, ADDR_TX_EN, ADDR_WIDTH_24, DATA_TX_DIS, DATA_RX_EN, DUMY_TX_EN, 1, 0, ADDR_MULTI_LINE_DIS, DATA_MULTI_LINE_DIS, TRANS_MOD_SINGLE, "read fast"},
41 {CMD_RDID, TX_DMA_DIS, RX_DMA_DIS, ADDR_TX_DIS, ADDR_WIDTH_24, DATA_TX_DIS, DATA_RX_EN, DUMY_TX_DIS, 0, 0, ADDR_MULTI_LINE_DIS, DATA_MULTI_LINE_DIS, TRANS_MOD_SINGLE, "read identification"},
42 {NULL}
43};
44
45#ifdef CONFIG_ZX297520V3_UFI_MINI_32K_NOR
46static const struct nor_info spi_nor_ids[] = {
47 /* GigaDevice */
48 { "gd25q128", INFO(0xc86018, 0, 32 * 1024, 512, 0) },
49 /* winbond */
50 { "w25q128fw", INFO(0xef6018, 0, 32 * 1024, 512, 0) },
51 /* dosilicon */
52 { "fm25m4aa", INFO(0xf84218, 0, 32 * 1024, 512, 0) },
53 /* fudanwei */
54 { "fm25w128", INFO(0xA12818, 0, 32 * 1024, 512, 0) },
55 /* XMC */
56 { "XM25QU64C", INFO(0x204117, 0, 32 * 1024, 256, 0) },
57 { "XM25QU128", INFO(0x205018, 0, 32 * 1024, 512, 0) },
58 { "XM25QU128C", INFO(0x204118, 0, 32 * 1024, 512, 0) },
59 /* DQ25Q128AL */
60 { "DQ25Q128AL", INFO(0x546018, 0, 32 * 1024, 512, 0) },
61 /* dosilicon */
62 { "DS25M4AB", INFO(0xE54218, 0, 32 * 1024, 512, 0) },
63 /* esmt(eon) */
64 { "EN25SX128A", INFO(0x1C7818, 0, 32 * 1024, 512, 0) },
65 /* dosilicon */
66 { "FM25M4AA", INFO(0xF84218, 0, 32 * 1024, 512, 0) },
67 { },
68};
69#else
70static const struct nor_info spi_nor_ids[] = {
71 /* GigaDevice */
72 { "gd25q128", INFO(0xc86018, 0, 64 * 1024, 256, 0) },
73 /* winbond */
74 { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, 0) },
75 /* dosilicon */
76 { "fm25m4aa", INFO(0xf84218, 0, 64 * 1024, 256, 0) },
77 /* fudanwei */
78 { "fm25w128", INFO(0xA12818, 0, 64 * 1024, 256, 0) },
79 /* xmc */
80 { "XM25QU128", INFO(0x205018, 0, 64 * 1024, 256, 0) },
81 { "XM25QU128C", INFO(0x204118, 0, 64 * 1024, 256, 0) },
82 /* DQ25Q128AL */
83 { "DQ25Q128AL", INFO(0x546018, 0, 64 * 1024, 256, 0) },
84 /* dosilicon */
85 { "DS25M4AB", INFO(0xE54218, 0, 64 * 1024, 256, 0) },
86 /* esmt(eon) */
87 { "EN25SX128A", INFO(0x1C7818, 0, 64 * 1024, 256, 0) },
88 /* dosilicon */
89 { "FM25M4AA", INFO(0xF84218, 0, 64 * 1024, 256, 0) },
90 { },
91};
92#endif
93
94
95struct nor_info *spi_nor_flash = NULL;
96
97
98 void spifc_enable(void)
99{
100 volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
101
102 if(spifc->SFC_EN & FC_EN_BACK)
103 {
104 printf("spifc en err.\n");
105 return;
106 }
107 spifc->SFC_EN |= (1 << FC_EN);
108 spifc->SFC_CTRL0 |= (1 << FC_SCLK_PAUSE_EN);
109}
110
111 void spifc_disable(void)
112{
113 volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
114
115 if(!(spifc->SFC_EN & FC_EN_BACK))
116 {
117 printf("spifc dis err.\n");
118 return;
119 }
120 spifc->SFC_EN &= (~(1 <<FC_EN));
121}
122
123 void spifc_setup_cmd(spinor_cmd_t *cmd, uint32_t addr, uint32_t len)
124{
125 volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
126
127 /* clear dma config */
128 spifc->SFC_CTRL0 &= ~((1 << FC_RX_DMA_EN)|(1 << FC_TX_DMA_EN));
129 /* clear fifo */
130 spifc->SFC_CTRL0 |= (1 << FC_RXFIFO_CLR)|(1 << FC_TXFIFO_CLR);
131
132 /* clear interrupt register */
133 spifc->SFC_INT_SW_CLR = 0xFF;
134
135 /* dma + fifo config */
136 spifc->SFC_CTRL0 |= ((cmd->tx_dma_en << FC_TX_DMA_EN)
137 | (cmd->rx_dma_en << FC_RX_DMA_EN)
138 | (1 << FC_RXFIFO_THRES)
139 | (1 << FC_TXFIFO_THRES));
140
141 /* addr dumy data code config */
142 spifc->SFC_CTRL1 = 0;
143 spifc->SFC_CTRL1 = ((cmd->addr_tx_en << FC_ADDR_TX_EN)
144 | (cmd->dumy_tx_en << FC_DUMMY_TX_EN)
145 | (cmd->data_rx_en << FC_READ_DAT_EN)
146 | (cmd->data_tx_en << FC_WRITE_DAT_EN));
147
148 spifc->SFC_CTRL2 = 0;
149 spifc->SFC_CTRL2 = ((cmd->dumy_byte_num << FC_DUMMY_BYTE_NUM)
150 | (cmd->dumy_bit_num << FC_DUMMY_BIT_NUM)
151 | (cmd->addr_byte_num << FC_ADDR_BYTE_NUM)
152 | (cmd->addr_multi_line_en << FC_ADDR_MULTI_LINE_EN)
153 | (cmd->data_multi_line_en << FC_DAT_MULTI_LINE_EN)
154 | (cmd->trans_mod << FC_TRANS_MOD));
155
156 if(len)
157 spifc->SFC_BYTE_NUM = len - 1;
158 else
159 spifc->SFC_BYTE_NUM = 0;
160
161 spifc->SFC_ADDR = addr;
162 spifc->SFC_INS = cmd->cmd;
163}
164
165 int spifc_wait_cmd_end(void)
166{
167 volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
168 uint32_t intr_status = 0;
169
170 while(!(spifc->SFC_INT_RAW & FC_INT_RAW_MASK));
171
172 intr_status = spifc->SFC_INT_RAW;
173 spifc->SFC_INT_SW_CLR = intr_status; /* ??? */
174
175 if(intr_status & FC_INT_RAW_CMD_END)
176 {
177 return 0;
178 }
179 else
180 {
181 printf("intr status err.\n");
182 return -1;
183 }
184}
185
186uint32_t spifc_read_fifo(uint8_t *buf, uint32_t len)
187{
188 volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
189 uint32_t *p = (uint32_t *)buf;
190 uint32_t cnt = 0;
191
192 int remainder_cnt = len % 4;
193
194 if(remainder_cnt != 0)
195 {
196 len = len + (4 - remainder_cnt);
197 }
198 else
199 {
200 remainder_cnt = 4;
201 }
202
203 while(cnt < (len>>2))
204 {
205 if(spifc->SFC_SW & (FC_RX_FIFO_CNT_MASK<<FC_RX_FIFO_CNT))//rx fifo not empty
206 {
207 p[cnt++]= spifc->SFC_DATA;
208 }
209 }
210
211 return ((cnt<<2) - (4 - remainder_cnt));
212}
213
214 void spifc_start(void)
215{
216 volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
217
218 spifc->SFC_START |= FC_START;
219}
220
221spinor_cmd_t *cmd_seek(u8 opcode)
222{
223 int i;
224
225 for(i = 0; (&nor_cmd_table[i]) != NULL; i++)
226 {
227 if(opcode == nor_cmd_table[i].cmd)
228 {
229 return (&nor_cmd_table[i]);
230 }
231 }
232
233 return NULL;
234}
235
236int nor_read_reg(u8 opcode, int len, u8 *buf)
237{
238 int ret = 0;
239 spinor_cmd_t *cmd = NULL;
240
241 cmd = cmd_seek(opcode);
242 if(cmd == NULL)
243 {
244 printf("cmd_seek unkown cmd error.\n");
245 return -1;
246 }
247
248 spifc_setup_cmd(cmd, 0x0, len);
249 spifc_start();
250 ret = spifc_wait_cmd_end();
251 if(ret != 0)
252 {
253 printf("spifc_wait_cmd_end error.\n");
254 return ret;
255 }
256
257 ret = spifc_read_fifo(buf, len);
258 if(ret < 0)
259 {
260 printf("spifc_read_fifo error.\n");
261 return ret;
262 }
263
264 return 0;
265}
266
267int nor_read_id(void)
268{
269 int tmp;
270 u8 id[SPI_NOR_MAX_ID_LEN];
271 const struct nor_info *info;
272
273 tmp = nor_read_reg(CMD_RDID, SPI_NOR_MAX_ID_LEN, id);
274 if(tmp < 0)
275 {
276 printf("error reading JEDEC ID\n");
277 return tmp;
278 }
279
280 for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++)
281 {
282 info = &spi_nor_ids[tmp];
283 if(info->id_len)
284 {
285 if(!memcmp(info->id, id, info->id_len))
286 {
287 spi_nor_flash = info;
288 return 0;
289 }
290 }
291 }
292 printf("unrecognized JEDEC id\n");
293 return -1;
294
295}
296
297int spi_nor_read(uint32_t from, size_t len, u_char *buf)
298{
299 int ret;
300 spinor_cmd_t *cmd = NULL;
301
302 cmd = cmd_seek(CMD_RDFT);
303 if(cmd == NULL)
304 {
305 printf("cmd_seek unkown error.\n");
306 return -1;
307 }
308
309 spifc_setup_cmd(cmd, from, len);
310 spifc_start();
311 ret = spifc_read_fifo(buf, len);
312 if(ret < 0)
313 {
314 printf("spifc_read_fifo error.\n");
315 return ret;
316 }
317
318 ret = spifc_wait_cmd_end();
319 if(ret != 0)
320 {
321 printf("spifc_wait_cmd_end error.\n");
322 return ret;
323 }
324
325 return 0;
326}
327
328int nor_read(uint32_t from, uint32_t len, uint32_t to)
329{
330 int ret;
331 u32 page_offset, page_size, i;
332 struct nor_info *info = spi_nor_flash;
333
334 page_offset = from & (info->page_size - 1);
335
336 /* do all the bytes fit onto one page? */
337 if (page_offset + len <= info->page_size) {
338 ret = spi_nor_read(from, len, (uint8_t *)to);
339 } else {
340 /* the size of data remaining on the first page */
341 page_size = info->page_size - page_offset;
342 ret = spi_nor_read(from, page_size, (uint8_t *)to);
343
344 /* read everything in nor->page_size chunks */
345 for (i = page_size; i < len; i += page_size) {
346 page_size = len - i;
347 if (page_size > info->page_size)
348 page_size = info->page_size;
349
350 ret = spi_nor_read(from + i, page_size, ((uint8_t *)to + i));
351 }
352 }
353
354 return ret;
355}
356
357
358
359int nor_init(void)
360{
361 int ret = 0;
362
363 spifc_disable(); //hsy ?
364
365 spifc_enable();
366
367 ret = nor_read_id();
368 if(ret != 0)
369 {
370 return -1;
371 }
372
373 flash.flash_type = NOR_BOOT;
374 flash.page_size = spi_nor_flash->page_size;
375 flash.read = nor_read;
376
377 return 0;
378}
379
380/*
381 **********************************************************************
382 * Function:
383 * Description:
384 * Parameters:
385 * Input:
386 * Output:
387 * Returns:
388 * Others:
389 **********************************************************************
390 */
391int board_flash_init(void)
392{
393 int ret = 0;
394 char boot_mode = 0;
395
396 boot_mode = get_boot_mode();
397 if(boot_mode != NOR_BOOT)
398 {
399 printf("not nor flash.\n");
400 return -1;
401 }
402
403 writel(CFG_START_MODE_NOR, CFG_BOOT_MODE_START_MODE_FOR_UBOOT);
404 ret = nor_init();
405 if(ret != 0)
406 {
407 printf("nor init err.\n");
408 return -1;
409 }
410
411 printf("nor init ok.\n");
412
413 return 0;
414}
415
416
417