OpenCores
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;
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.