URL
https://opencores.org/ocsvn/xenie/xenie/trunk
Subversion Repositories xenie
[/] [xenie/] [trunk/] [examples/] [Eth_example/] [mb_fw/] [xenie_eth_test_womtd/] [src/] [spansion_flash.c] - Rev 13
Compare with Previous | Blame | View Log
/****************************************************************************** ** ** (C) Copyright 2017 DFC Design, s.r.o., Brno, Czech Republic ** Author: Marek Kvas (m.kvas@dspfpga.com) ** **************************************************************************** ** ** This file is part of Xenia Ethernet Example project. ** ** Xenia Ethernet Example project is free software: you can ** redistribute it and/or modify it under the terms of ** the GNU Lesser General Public License as published by the Free ** Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** Xenia Ethernet Example project is distributed in the hope that ** it will be useful, but WITHOUT ANY WARRANTY; without even ** the implied warranty of MERCHANTABILITY or FITNESS FOR A ** PARTICULAR PURPOSE. See the GNU Lesser General Public License ** for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with Xenia Ethernet Example project. If not, ** see <http://www.gnu.org/licenses/>. **************************************************************************** */ #include <stdio.h> #include <xspi.h> #include "spansion_flash.h" #include "uprintf.h" #define SPANSION_CFG_REG_QUAD (1<<1) #define SPANSION_CFG_REG_OTP_MASK (0x3c) #define SPANSION_BANK_REG_EXT_ADDR (1<<7) #define SPANSION_CFG_REG_BP_SHIFT 2 #define SPANSION_CFG_REG_BP_MASK (0x7 << SPANSION_CFG_REG_BP_SHIFT) #define SPANSION_STAT_REG_WIP (1<<0) #define SPANSION_CFG_REG_LC_MASK (0xc0) #define SPANSION_CFG_REG_LC_DEFAULT 0 static int spansion_flash_cmd_wen(struct spansion_flash *sf); static int spansion_flash_get_cr1(struct spansion_flash *sf, u8 *cr1); static int spansion_flash_get_sr1(struct spansion_flash *sf, u8 *sr1); int spansion_flash_init (struct spansion_flash *sf, XSpi *spi, int slave_num) { u8 rCfg; sf->spi = spi; sf->slave_select = (1<<slave_num); int ret; ret = XSpi_SetOptions(sf->spi, (XSP_MASTER_OPTION | \ XSP_MANUAL_SSELECT_OPTION | \ XSP_CLK_PHASE_1_OPTION | \ XSP_CLK_ACTIVE_LOW_OPTION)); if(ret) return ret; ret = XSpi_SetSlaveSelect(sf->spi, sf->slave_select); if(ret) return ret; ret = XSpi_Start(sf->spi); if (ret) return ret; /* Put spi to polled mode */ XSpi_IntrGlobalDisable(sf->spi); /* Check latency is as expected */ ret = spansion_flash_get_cr1(sf, &rCfg); if(ret) return ret; if ((rCfg & SPANSION_CFG_REG_LC_MASK) != SPANSION_CFG_REG_LC_DEFAULT) { uprintf("Flash is configured with non-default latency code. Cannot read flash\r\n"); return -1; } return 0; } static int spansion_flash_transfer(struct spansion_flash *sf, uint8_t *wr_buf, uint8_t *rd_buf, int len) { int res; res = XSpi_Transfer(sf->spi, wr_buf, rd_buf, len); if(res) return res; return XST_SUCCESS; } /* * Get status and control register value * and set QSPI mode. It needs to be done * after each configuration flash programming * using Xilinx tools as they erase this flag. * * !!!BEWARE: This is potentially dangerous * operation as if power is lost during write to * status and configuration register, both can be * set to all ones. It may set OTP bits that may render * flash unusable. As quad mode flag is non-volatile * it is necessary to do this once only during board * */ int spansion_flash_quad_mode(struct spansion_flash *sf) { int ret; int tmo_cnt; u8 rCfg; u8 rSt; u8 wCfgBuf[3]; ret = spansion_flash_get_cr1(sf, &rCfg); if(ret) return ret; if (rCfg & SPANSION_CFG_REG_QUAD) { return 0; } ret = spansion_flash_get_sr1(sf, &rSt); if(ret) return ret; ret = spansion_flash_cmd_wen(sf); if(ret) return ret; uprintf("WARNING: Setting flash quad mode in flash configuration\r\n" "registers. If power is lost at that moment flash can be\r\n" "corrupted permanently.\r\n"); wCfgBuf[0] = 0x01; wCfgBuf[1] = rSt; wCfgBuf[2] = rCfg | SPANSION_CFG_REG_QUAD; ret = spansion_flash_transfer(sf, wCfgBuf, wCfgBuf, 3); if(ret) return ret; /* Wait until flash finishes write with timeout */ tmo_cnt = 1000; do { ret = spansion_flash_get_sr1(sf, &rSt); if (ret) return ret; if(tmo_cnt) tmo_cnt--; else return -1; } while (rSt & SPANSION_STAT_REG_WIP); /* Reread CFG reg */ ret = spansion_flash_get_cr1(sf, &rCfg); if (ret) return ret; if (rCfg & SPANSION_CFG_REG_QUAD) { uprintf("Flash quad mode set successfully.\r\n"); return 0; } else { uprintf("Flash quad mode was not set, cannot read flash.\r\n"); return -1; } } /* * Use Quad IO 4 byte address read command to read block of data. * spi - SPI core instance to be used * flash_addr - 32 bit start address in flash * buf - pointer to buffer where data shall be stored; must be 8 byte longer then length of data * rad data are placed at buf+8 address. * len - number of bytes to be read from flash; must be 8 bytes lower than true buf len */ int spansion_flash_quad_io_read(struct spansion_flash *sf, uint32_t flash_addr, uint8_t *buf, int len) { XSpi *spi = sf->spi; u8 *cmdbuf = buf; /* Quad IO read with 32 bit address */ *(cmdbuf++) = 0xec; /* Address MSB first */ *(cmdbuf++) = flash_addr >> 24; *(cmdbuf++) = flash_addr >> 16; *(cmdbuf++) = flash_addr >> 8; *(cmdbuf++) = flash_addr; /* 3 Dummy bytes - 6 cycle for latency code 00b */ *(cmdbuf++) = 0; *(cmdbuf++) = 0; *(cmdbuf++) = 0; return XSpi_Transfer(spi, buf, buf, len + 8); } /* * Read and print flash configuration and status. */ int spansion_flash_print_status(struct spansion_flash *sf) { int ret; u8 rCfgBuf[2]; u8 rStBuf[2]; u8 rRDID[4]; rRDID[0] = 0x9f; ret = spansion_flash_transfer(sf, rRDID, rRDID, 4); if(ret) return ret; uprintf("RDID: 0x%02x 0x%02x 0x%02x\r\n", rRDID[1], rRDID[2], rRDID[3]); rStBuf[0] = 0x05; ret = spansion_flash_transfer(sf, rStBuf, rStBuf, 2); if(ret) return ret; uprintf("Status reg 1: 0x%02x\r\n", rStBuf[1]); rStBuf[0] = 0x07; ret = spansion_flash_transfer(sf, rStBuf, rStBuf, 2); if(ret) return ret; uprintf("Status reg 2: 0x%02x\r\n", rStBuf[1]); rCfgBuf[0] = 0x35; ret = spansion_flash_transfer(sf, rCfgBuf, rCfgBuf, 2); if(ret) return ret; uprintf("Configuration reg: 0x%02x\r\n", rCfgBuf[1]); return 0; } /* Send write enable command - needed for register write */ static int spansion_flash_cmd_wen(struct spansion_flash *sf) { int ret; u8 wEnBuf[1]; wEnBuf[0] = 0x6; ret = spansion_flash_transfer(sf, wEnBuf, wEnBuf, 1); return ret; } /* Send Bulk erase command*/ static int spansion_flash_cmd_be(struct spansion_flash *sf) { int ret; u8 buf[1]; buf[0] = 0x60; ret = spansion_flash_transfer(sf, buf, buf, 1); return ret; } /* Send get status register sr1*/ static int spansion_flash_get_sr1(struct spansion_flash *sf, u8 *sr1) { int ret; u8 rStBuf[2]; rStBuf[0] = 0x05; ret = spansion_flash_transfer(sf, rStBuf, rStBuf, 2); *sr1 = rStBuf[1]; return ret; } /* Send get configuration register */ static int spansion_flash_get_cr1(struct spansion_flash *sf, u8 *cr1) { int ret; u8 rCfgBuf[2]; rCfgBuf[0] = 0x35; ret = spansion_flash_transfer(sf, rCfgBuf, rCfgBuf, 2); *cr1 = rCfgBuf[1]; return ret; } /* * Erase whole device using bulk erase. */ int spansion_flash_bulk_erase(struct spansion_flash *sf) { int ret; u8 sr; int i; ret = spansion_flash_cmd_wen(sf); if(ret) return ret; ret = spansion_flash_cmd_be(sf); if(ret) return ret; i = 0; do { ret = spansion_flash_get_sr1(sf, &sr); i++; } while (sr & SPANSION_STAT_REG_WIP); return ret; }