[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/boot/common/src/loader/drivers/nor.c b/boot/common/src/loader/drivers/nor.c
new file mode 100755
index 0000000..afccaf9
--- /dev/null
+++ b/boot/common/src/loader/drivers/nor.c
@@ -0,0 +1,417 @@
+/*
+ * Freescale QuadSPI driver.
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <sdio.h>
+#include <common.h>
+#include <asm/io.h>
+#include "nor.h"
+#include <image.h>
+#include <linux/byteorder/generic.h>
+#include <secure_verify.h>
+#include "config.h"
+#include "flash.h"
+
+
+/* Used when the "_ext_id" is two bytes at most */
+#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
+ .id = { \
+ ((_jedec_id) >> 16) & 0xff, \
+ ((_jedec_id) >> 8) & 0xff, \
+ (_jedec_id) & 0xff, \
+ ((_ext_id) >> 8) & 0xff, \
+ (_ext_id) & 0xff, \
+ }, \
+ .id_len = (!(_jedec_id) ? 0 : (3 + ((_ext_id) ? 2 : 0))), \
+ .sector_size = (_sector_size), \
+ .n_sectors = (_n_sectors), \
+ .page_size = 256, \
+ .flags = (_flags),
+
+
+spinor_cmd_t nor_cmd_table[]=
+{
+ {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"},
+ {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"},
+ {NULL}
+};
+
+#ifdef CONFIG_ZX297520V3_UFI_MINI_32K_NOR
+static const struct nor_info spi_nor_ids[] = {
+ /* GigaDevice */
+ { "gd25q128", INFO(0xc86018, 0, 32 * 1024, 512, 0) },
+ /* winbond */
+ { "w25q128fw", INFO(0xef6018, 0, 32 * 1024, 512, 0) },
+ /* dosilicon */
+ { "fm25m4aa", INFO(0xf84218, 0, 32 * 1024, 512, 0) },
+ /* fudanwei */
+ { "fm25w128", INFO(0xA12818, 0, 32 * 1024, 512, 0) },
+ /* XMC */
+ { "XM25QU64C", INFO(0x204117, 0, 32 * 1024, 256, 0) },
+ { "XM25QU128", INFO(0x205018, 0, 32 * 1024, 512, 0) },
+ { "XM25QU128C", INFO(0x204118, 0, 32 * 1024, 512, 0) },
+ /* DQ25Q128AL */
+ { "DQ25Q128AL", INFO(0x546018, 0, 32 * 1024, 512, 0) },
+ /* dosilicon */
+ { "DS25M4AB", INFO(0xE54218, 0, 32 * 1024, 512, 0) },
+ /* esmt(eon) */
+ { "EN25SX128A", INFO(0x1C7818, 0, 32 * 1024, 512, 0) },
+ /* dosilicon */
+ { "FM25M4AA", INFO(0xF84218, 0, 32 * 1024, 512, 0) },
+ { },
+};
+#else
+static const struct nor_info spi_nor_ids[] = {
+ /* GigaDevice */
+ { "gd25q128", INFO(0xc86018, 0, 64 * 1024, 256, 0) },
+ /* winbond */
+ { "w25q128fw", INFO(0xef6018, 0, 64 * 1024, 256, 0) },
+ /* dosilicon */
+ { "fm25m4aa", INFO(0xf84218, 0, 64 * 1024, 256, 0) },
+ /* fudanwei */
+ { "fm25w128", INFO(0xA12818, 0, 64 * 1024, 256, 0) },
+ /* xmc */
+ { "XM25QU128", INFO(0x205018, 0, 64 * 1024, 256, 0) },
+ { "XM25QU128C", INFO(0x204118, 0, 64 * 1024, 256, 0) },
+ /* DQ25Q128AL */
+ { "DQ25Q128AL", INFO(0x546018, 0, 64 * 1024, 256, 0) },
+ /* dosilicon */
+ { "DS25M4AB", INFO(0xE54218, 0, 64 * 1024, 256, 0) },
+ /* esmt(eon) */
+ { "EN25SX128A", INFO(0x1C7818, 0, 64 * 1024, 256, 0) },
+ /* dosilicon */
+ { "FM25M4AA", INFO(0xF84218, 0, 64 * 1024, 256, 0) },
+ { },
+};
+#endif
+
+
+struct nor_info *spi_nor_flash = NULL;
+
+
+ void spifc_enable(void)
+{
+ volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
+
+ if(spifc->SFC_EN & FC_EN_BACK)
+ {
+ printf("spifc en err.\n");
+ return;
+ }
+ spifc->SFC_EN |= (1 << FC_EN);
+ spifc->SFC_CTRL0 |= (1 << FC_SCLK_PAUSE_EN);
+}
+
+ void spifc_disable(void)
+{
+ volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
+
+ if(!(spifc->SFC_EN & FC_EN_BACK))
+ {
+ printf("spifc dis err.\n");
+ return;
+ }
+ spifc->SFC_EN &= (~(1 <<FC_EN));
+}
+
+ void spifc_setup_cmd(spinor_cmd_t *cmd, uint32_t addr, uint32_t len)
+{
+ volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
+
+ /* clear dma config */
+ spifc->SFC_CTRL0 &= ~((1 << FC_RX_DMA_EN)|(1 << FC_TX_DMA_EN));
+ /* clear fifo */
+ spifc->SFC_CTRL0 |= (1 << FC_RXFIFO_CLR)|(1 << FC_TXFIFO_CLR);
+
+ /* clear interrupt register */
+ spifc->SFC_INT_SW_CLR = 0xFF;
+
+ /* dma + fifo config */
+ spifc->SFC_CTRL0 |= ((cmd->tx_dma_en << FC_TX_DMA_EN)
+ | (cmd->rx_dma_en << FC_RX_DMA_EN)
+ | (1 << FC_RXFIFO_THRES)
+ | (1 << FC_TXFIFO_THRES));
+
+ /* addr dumy data code config */
+ spifc->SFC_CTRL1 = 0;
+ spifc->SFC_CTRL1 = ((cmd->addr_tx_en << FC_ADDR_TX_EN)
+ | (cmd->dumy_tx_en << FC_DUMMY_TX_EN)
+ | (cmd->data_rx_en << FC_READ_DAT_EN)
+ | (cmd->data_tx_en << FC_WRITE_DAT_EN));
+
+ spifc->SFC_CTRL2 = 0;
+ spifc->SFC_CTRL2 = ((cmd->dumy_byte_num << FC_DUMMY_BYTE_NUM)
+ | (cmd->dumy_bit_num << FC_DUMMY_BIT_NUM)
+ | (cmd->addr_byte_num << FC_ADDR_BYTE_NUM)
+ | (cmd->addr_multi_line_en << FC_ADDR_MULTI_LINE_EN)
+ | (cmd->data_multi_line_en << FC_DAT_MULTI_LINE_EN)
+ | (cmd->trans_mod << FC_TRANS_MOD));
+
+ if(len)
+ spifc->SFC_BYTE_NUM = len - 1;
+ else
+ spifc->SFC_BYTE_NUM = 0;
+
+ spifc->SFC_ADDR = addr;
+ spifc->SFC_INS = cmd->cmd;
+}
+
+ int spifc_wait_cmd_end(void)
+{
+ volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
+ uint32_t intr_status = 0;
+
+ while(!(spifc->SFC_INT_RAW & FC_INT_RAW_MASK));
+
+ intr_status = spifc->SFC_INT_RAW;
+ spifc->SFC_INT_SW_CLR = intr_status; /* ??? */
+
+ if(intr_status & FC_INT_RAW_CMD_END)
+ {
+ return 0;
+ }
+ else
+ {
+ printf("intr status err.\n");
+ return -1;
+ }
+}
+
+uint32_t spifc_read_fifo(uint8_t *buf, uint32_t len)
+{
+ volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
+ uint32_t *p = (uint32_t *)buf;
+ uint32_t cnt = 0;
+
+ int remainder_cnt = len % 4;
+
+ if(remainder_cnt != 0)
+ {
+ len = len + (4 - remainder_cnt);
+ }
+ else
+ {
+ remainder_cnt = 4;
+ }
+
+ while(cnt < (len>>2))
+ {
+ if(spifc->SFC_SW & (FC_RX_FIFO_CNT_MASK<<FC_RX_FIFO_CNT))//rx fifo not empty
+ {
+ p[cnt++]= spifc->SFC_DATA;
+ }
+ }
+
+ return ((cnt<<2) - (4 - remainder_cnt));
+}
+
+ void spifc_start(void)
+{
+ volatile struct spifc_nor_reg_t* spifc = (struct spifc_nor_reg_t*)SYS_SPI_NAND_BASE;
+
+ spifc->SFC_START |= FC_START;
+}
+
+spinor_cmd_t *cmd_seek(u8 opcode)
+{
+ int i;
+
+ for(i = 0; (&nor_cmd_table[i]) != NULL; i++)
+ {
+ if(opcode == nor_cmd_table[i].cmd)
+ {
+ return (&nor_cmd_table[i]);
+ }
+ }
+
+ return NULL;
+}
+
+int nor_read_reg(u8 opcode, int len, u8 *buf)
+{
+ int ret = 0;
+ spinor_cmd_t *cmd = NULL;
+
+ cmd = cmd_seek(opcode);
+ if(cmd == NULL)
+ {
+ printf("cmd_seek unkown cmd error.\n");
+ return -1;
+ }
+
+ spifc_setup_cmd(cmd, 0x0, len);
+ spifc_start();
+ ret = spifc_wait_cmd_end();
+ if(ret != 0)
+ {
+ printf("spifc_wait_cmd_end error.\n");
+ return ret;
+ }
+
+ ret = spifc_read_fifo(buf, len);
+ if(ret < 0)
+ {
+ printf("spifc_read_fifo error.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int nor_read_id(void)
+{
+ int tmp;
+ u8 id[SPI_NOR_MAX_ID_LEN];
+ const struct nor_info *info;
+
+ tmp = nor_read_reg(CMD_RDID, SPI_NOR_MAX_ID_LEN, id);
+ if(tmp < 0)
+ {
+ printf("error reading JEDEC ID\n");
+ return tmp;
+ }
+
+ for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++)
+ {
+ info = &spi_nor_ids[tmp];
+ if(info->id_len)
+ {
+ if(!memcmp(info->id, id, info->id_len))
+ {
+ spi_nor_flash = info;
+ return 0;
+ }
+ }
+ }
+ printf("unrecognized JEDEC id\n");
+ return -1;
+
+}
+
+int spi_nor_read(uint32_t from, size_t len, u_char *buf)
+{
+ int ret;
+ spinor_cmd_t *cmd = NULL;
+
+ cmd = cmd_seek(CMD_RDFT);
+ if(cmd == NULL)
+ {
+ printf("cmd_seek unkown error.\n");
+ return -1;
+ }
+
+ spifc_setup_cmd(cmd, from, len);
+ spifc_start();
+ ret = spifc_read_fifo(buf, len);
+ if(ret < 0)
+ {
+ printf("spifc_read_fifo error.\n");
+ return ret;
+ }
+
+ ret = spifc_wait_cmd_end();
+ if(ret != 0)
+ {
+ printf("spifc_wait_cmd_end error.\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int nor_read(uint32_t from, uint32_t len, uint32_t to)
+{
+ int ret;
+ u32 page_offset, page_size, i;
+ struct nor_info *info = spi_nor_flash;
+
+ page_offset = from & (info->page_size - 1);
+
+ /* do all the bytes fit onto one page? */
+ if (page_offset + len <= info->page_size) {
+ ret = spi_nor_read(from, len, (uint8_t *)to);
+ } else {
+ /* the size of data remaining on the first page */
+ page_size = info->page_size - page_offset;
+ ret = spi_nor_read(from, page_size, (uint8_t *)to);
+
+ /* read everything in nor->page_size chunks */
+ for (i = page_size; i < len; i += page_size) {
+ page_size = len - i;
+ if (page_size > info->page_size)
+ page_size = info->page_size;
+
+ ret = spi_nor_read(from + i, page_size, ((uint8_t *)to + i));
+ }
+ }
+
+ return ret;
+}
+
+
+
+int nor_init(void)
+{
+ int ret = 0;
+
+ spifc_disable(); //hsy ?
+
+ spifc_enable();
+
+ ret = nor_read_id();
+ if(ret != 0)
+ {
+ return -1;
+ }
+
+ flash.flash_type = NOR_BOOT;
+ flash.page_size = spi_nor_flash->page_size;
+ flash.read = nor_read;
+
+ return 0;
+}
+
+/*
+ **********************************************************************
+ * Function:
+ * Description:
+ * Parameters:
+ * Input:
+ * Output:
+ * Returns:
+ * Others:
+ **********************************************************************
+ */
+int board_flash_init(void)
+{
+ int ret = 0;
+ char boot_mode = 0;
+
+ boot_mode = get_boot_mode();
+ if(boot_mode != NOR_BOOT)
+ {
+ printf("not nor flash.\n");
+ return -1;
+ }
+
+ writel(CFG_START_MODE_NOR, CFG_BOOT_MODE_START_MODE_FOR_UBOOT);
+ ret = nor_init();
+ if(ret != 0)
+ {
+ printf("nor init err.\n");
+ return -1;
+ }
+
+ printf("nor init ok.\n");
+
+ return 0;
+}
+
+
+