KL520_SDK_2.2/platform/dev/flash/kdev_flash_winbond.c
2025-12-17 15:55:25 +08:00

917 lines
32 KiB
C

/* Copyright (c) 2020 Kneron, Inc. All Rights Reserved.
*
* The information contained herein is property of Kneron, Inc.
* Terms and conditions of usage are described in detail in Kneron
* STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information.
* NO WARRANTY of ANY KIND is provided. This heading must NOT be removed
* from the file.
*/
/******************************************************************************
* Filename:
* ---------
* kdev_flash_winbond.c
*
* Project:
* --------
* KL520
*
* Description:
* ------------
* This SPI Flash driver is specific for Winbond SPI Flash Access
* HW: Faraday FTSPI020
*
* Author:
* -------
* Teresa Chen
**
******************************************************************************/
#include "project.h"
#include "kdev_flash_winbond.h"
#include "kdrv_spif.h"
#include "kdev_flash.h"
#include "io.h"
//#define FLASH_WB_DBG
#ifdef FLASH_WB_DBG
#include "kmdw_console.h"
#define flash_msg(fmt, ...) info_msg("[WINBOND_FLASH] " fmt, ##__VA_ARGS__)
#else
#define flash_msg(fmt, ...)
#endif
spi_flash_t flash_info;
kdev_spif_parameter_t st_flash_info;
#if FLASH_4BYTES_CMD_EN
bool kdev_flash_is_4byte_address(uint32_t addr)
{
bool ret = false;
if( addr > FLASH_3BYTE_ADDR_MAX )
ret = true;
return ret;
}
#endif
void kdev_flash_4Bytes_ctrl(uint8_t enable)
{
#if FLASH_4BYTES_CMD_EN
//if (kdev_flash_is_4byte_address())
{
if (enable) {
kdrv_spif_set_commands(SPI020_B7_CMD0, SPI020_B7_CMD1, SPI020_B7_CMD2, SPI020_B7_CMD3);
} else {
kdrv_spif_set_commands(SPI020_E9_CMD0, SPI020_E9_CMD1, SPI020_E9_CMD2, SPI020_E9_CMD3);
}
/* wait for command complete */
kdrv_spif_wait_command_complete();
}
#endif
}
void kdev_flash_write_control(uint8_t enable)
{
/* fill in command 0~3 */
if (enable) {
kdrv_spif_set_commands(SPI020_06_CMD0, SPI020_06_CMD1, SPI020_06_CMD2, SPI020_06_CMD3);
} else {
kdrv_spif_set_commands(SPI020_04_CMD0, SPI020_04_CMD1, SPI020_04_CMD2, SPI020_04_CMD3);
}
/* wait for command complete */
kdrv_spif_wait_command_complete();
}
void kdev_flash_write_control_volatile(uint8_t enable)
{
/* fill in command 0~3 */
if (enable) {
kdrv_spif_set_commands(SPI020_50_CMD0, SPI020_50_CMD1, SPI020_50_CMD2, SPI020_50_CMD3);
} else {
kdrv_spif_set_commands(SPI020_04_CMD0, SPI020_04_CMD1, SPI020_04_CMD2, SPI020_04_CMD3);
}
/* wait for command complete */
kdrv_spif_wait_command_complete();
}
void kdev_flash_64kErase(uint32_t offset)
{
/* The start offset should be in 64K boundary */
/* if(offset % SPI020_64K) return 1; */
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(1);
#endif
kdev_flash_write_control(1);/* send write enabled */
/* fill in command 0~3 */
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_DC_CMD1, SPI020_DC_CMD2, SPI020_DC_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_D8_CMD1, SPI020_D8_CMD2, SPI020_D8_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_D8_CMD1, SPI020_D8_CMD2, SPI020_D8_CMD3);
#endif
/* wait for command complete */
kdrv_spif_check_status_till_ready();
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(0);
#endif
}
void kdev_flash_32kErase(uint32_t offset)
{
/* The start offset should be in 64K boundary */
/* if(offset % SPI020_64K) return 1; */
kdev_flash_write_control(1);/* send write enabled */
/* fill in command 0~3 */
kdrv_spif_set_commands(offset, SPI020_52_CMD1, SPI020_52_CMD2, SPI020_52_CMD3);
/* wait for command complete */
kdrv_spif_check_status_till_ready();
}
void kdev_flash_4kErase(uint32_t offset)
{
/* The start offset should be in 64K boundary */
/* if(offset % SPI020_4K) return 1; */
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(1);
#endif
kdev_flash_write_control(1);/* send write enabled */
/* fill in command 0~3 */
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_21_CMD1, SPI020_21_CMD2, SPI020_21_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_20_CMD1, SPI020_20_CMD2, SPI020_20_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_20_CMD1, SPI020_20_CMD2, SPI020_20_CMD3);
#endif
/* wait for command complete */
kdrv_spif_check_status_till_ready();
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(0);
#endif
}
uint32_t kdev_flash_probe(spi_flash_t *flash)
{
uint32_t chip_id=0;
uint32_t probe_90_instruction=0;
/* fill in command 0~3 */
//Read Manufacturer and Device Identification by JEDEC ID(0x9F)
kdrv_spif_set_commands(SPI020_9F_CMD0, SPI020_9F_CMD1, SPI020_9F_CMD2, SPI020_9F_CMD3);
/* read data */
kdrv_spif_read_data(/*(uint8_t *)*/&chip_id, 0x3);
/* wait for command complete */
kdrv_spif_wait_command_complete();
//flash->manufacturer = (chip_id>>24);
flash->manufacturer = (uint8_t )chip_id;
if (flash->manufacturer == 0x00 || flash->manufacturer == 0xFF) {
/* fill in command 0~3 */
//Read Manufacturer and Device Identification by 0x90
kdrv_spif_set_commands(SPI020_90_CMD0, SPI020_90_CMD1, SPI020_90_CMD2, SPI020_90_CMD3);
/* read data */
kdrv_spif_read_data(/*(uint8_t *)*/&chip_id, 0x02/*0x4*/);
/* wait for command complete */
kdrv_spif_wait_command_complete();
//flash->manufacturer = (chip_id>>24);
flash->manufacturer = (uint8_t )chip_id;
probe_90_instruction=1;
}
flash->flash_id = (chip_id>>8);
return probe_90_instruction;
}
/* ===================================
* Init SPI controller and flash device.
* Init flash information and register functions.
* =================================== */
void kdev_flash_read_flash_id(void)
{
uint32_t probe_90_instruction;
uint32_t sizeId;
probe_90_instruction=kdev_flash_probe(&flash_info);
#ifdef FLASH_WB_DBG
char *flash_manu;
switch (flash_info.manufacturer) {
case FLASH_WB_DEV:
flash_manu = "WINBOND";
break;
case FLASH_MXIC_DEV:
flash_manu = "MXIC";
break;
case FLASH_Micron_DEV:
flash_manu = "Micron";
break;
case FLASH_GD_DEV:
flash_manu = "GigaDevice";
break;
case FLASH_ZBIT_DEV:
flash_manu = "Zbit";
break;
default:
flash_manu = "Unknown";
break;
}
#endif
if(probe_90_instruction)
{
sizeId = flash_info.flash_id & 0x00FF;
if(sizeId >= FLASH_SIZE_1MB_ID)
flash_info.flash_size = 0x400 * (1<<(sizeId-FLASH_SIZE_1MB_ID+1));
}
else
{
sizeId = (flash_info.flash_id & 0xFF00)>>8;
if(sizeId >= FLASH_SIZE_512MB_ID) {
flash_info.flash_size = 0x400 * (1<<(sizeId-FLASH_SIZE_1MB_ID-FLASH_SIZE_SHIFT));
flash_msg("flash_size 0x%2X >= 512MB = %d kbytes\n",sizeId, flash_info.flash_size);
}
else if(sizeId >= FLASH_SIZE_1MB_ID) {
flash_info.flash_size = 0x400 * (1<<(sizeId-FLASH_SIZE_1MB_ID));
flash_msg("flash_size 0x%2X = %d kbytes\n",sizeId, flash_info.flash_size);
}
}
flash_msg("Manufacturer ID = 0x%02X (%s)\n", flash_info.manufacturer,flash_manu);
flash_msg("Device ID = 0x");
if(probe_90_instruction)
flash_msg("%02X\n", flash_info.flash_id);
else
flash_msg("%04X\n", flash_info.flash_id);
flash_msg("Flash Size = ");
if((flash_info.flash_size%1024)==0x00) {
flash_msg("%dkByte(%dMByte)\n", flash_info.flash_size,flash_info.flash_size>>10);
} else {
flash_msg("%dkByte\n", flash_info.flash_size);
}
st_flash_info.ID = flash_info.manufacturer;
st_flash_info.erase_4K_support = 1;
st_flash_info.flash_size_KByte = flash_info.flash_size;
st_flash_info.sector_size_Bytes = SPI020_SECTOR_SIZE;
st_flash_info.total_sector_numbers = (st_flash_info.flash_size_KByte * 1024) / st_flash_info.sector_size_Bytes;
}
/* WB Flash */
void kdev_flash_read_status(void)
{
uint16_t nrx_buff_word_index = 0;
uint32_t RDSR1=0; //05h
uint32_t RDSR2=0; //35h
uint32_t RDSR3=0; //15h
kdrv_spif_set_commands( SPI020_05_CMD0_w , SPI020_05_CMD1_w, SPI020_05_CMD2_w, SPI020_05_CMD3_w );
nrx_buff_word_index = 0;
kdrv_spif_read_Rx_FIFO( &RDSR1, &nrx_buff_word_index, 0x01 );
flash_msg("SPI020_05_CMD RDSR1=0x%2X\n", (uint8_t)RDSR1 );
kdrv_spif_wait_command_complete();
kdrv_spif_set_commands(SPI020_35_CMD0, SPI020_35_CMD1, SPI020_35_CMD2, SPI020_35_CMD3 );
nrx_buff_word_index = 0;
kdrv_spif_read_Rx_FIFO( &RDSR2, &nrx_buff_word_index, 0x01 );
flash_msg("SPI020_35_CMD RDSR2=0x%2X\n", (uint8_t)RDSR2 );
kdrv_spif_wait_command_complete();
kdrv_spif_set_commands(SPI020_15_CMD0, SPI020_15_CMD1, SPI020_15_CMD2, SPI020_15_CMD3 );
nrx_buff_word_index = 0;
kdrv_spif_read_Rx_FIFO( &RDSR3, &nrx_buff_word_index, 0x01 );
flash_msg("SPI020_15_CMD RDSR3=0x%2X\n", (uint8_t)RDSR3 );
kdrv_spif_wait_command_complete();
flash_msg("Manufacturer ID = 0x%02X \n", flash_info.manufacturer);
flash_msg("RDSR1(%4X) RDSR2(%4X) RDSR3(%4X) \n", (uint8_t)RDSR1, (uint8_t)RDSR2, (uint8_t)RDSR3);
RDSR1 &= ~0xFC; /* disable Status Register & Block protect bit7,6,5,4,3,2 */
kdev_flash_write_control_volatile(1);
kdrv_spif_set_commands(SPI020_01_CMD0, SPI020_01_CMD1, 1, SPI020_01_CMD3 );
kdrv_spif_write_data((uint8_t*)&RDSR1, 1);
kdrv_spif_check_status_till_ready();
RDSR2 &= ~BIT6; /* clear CMP */
#if defined(FLASH_QUAD_IO_EN) && (FLASH_QUAD_IO_EN == 1)
flash_msg("Set QE enabled \n");
RDSR2 |= BIT1;
#endif
kdev_flash_write_control_volatile(1);
kdrv_spif_set_commands(SPI020_31_CMD0, SPI020_31_CMD1, SPI020_31_CMD2, SPI020_31_CMD3 );
kdrv_spif_write_data((uint8_t*)(&RDSR2), 1);
kdrv_spif_check_status_till_ready();
#if defined(FLASH_QUAD_IO_EN) && (FLASH_QUAD_IO_EN == 1)
flash_msg("FLASH_WB/GD/ZBIT Set QE OK!! \n");
#endif
RDSR3 &= ~0x06; /* clear WPS & ADP bit */
RDSR3 &= ~0x60; /* driver output strength 00 100% */
flash_msg("need to set driver strength 0x%2X \n", (uint8_t)RDSR3 );
kdev_flash_write_control_volatile(1);
kdrv_spif_set_commands(SPI020_11_CMD0, SPI020_11_CMD1, SPI020_11_CMD2, SPI020_11_CMD3 );
kdrv_spif_write_data((uint8_t*)&RDSR3, 1);
kdrv_spif_check_status_till_ready();
flash_msg("RDSR1(%4X) RDSR2(%4X) RDSR3(%4X) \n", (uint8_t)RDSR1, (uint8_t)RDSR2, (uint8_t)RDSR3);
}
kdev_status_t kdev_flash_read_SFDP(void)
{
#define SPI_Rx_SIZE (5)
uint16_t nrx_buff_word_index = 0;
uint32_t nrx_buff_word[ SPI_Rx_SIZE ];
uint32_t ntemp =0;
kdrv_spif_switch_low_speed();
//check status
nrx_buff_word_index =0;
kdrv_spif_set_commands( 0x00 , SPI020_5A_CMD1, 0x04, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x04 );
kdrv_spif_wait_command_complete();
st_flash_info.signature = nrx_buff_word[nrx_buff_word_index-1];//FLASH_SIGNATURE;
//check
if( nrx_buff_word[nrx_buff_word_index-1] != FLASH_SIGNATURE )
{
st_flash_info.ID = flash_info.manufacturer;
st_flash_info.erase_4K_support = 1;
st_flash_info.flash_size_KByte = flash_info.flash_size;
st_flash_info.sector_size_Bytes = SPI020_SECTOR_SIZE;
st_flash_info.total_sector_numbers = (st_flash_info.flash_size_KByte * 1024) / st_flash_info.sector_size_Bytes;
return KDEV_STATUS_ERROR;
}
//get ptr
nrx_buff_word_index =0;
kdrv_spif_set_commands( 0x0C , SPI020_5A_CMD1, 0x01, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x01 );
kdrv_spif_wait_command_complete();
st_flash_info.PTP = nrx_buff_word[nrx_buff_word_index-1] & 0XFF;
//get ID
nrx_buff_word_index =0;
kdrv_spif_set_commands( 0x10 , SPI020_5A_CMD1, 0x04, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x04 );
kdrv_spif_wait_command_complete();
st_flash_info.ID = nrx_buff_word[nrx_buff_word_index-1] & 0XFFFFFFFF;
if( st_flash_info.ID== 0x00 || st_flash_info.ID==0xFF )
{
nrx_buff_word_index =0;
kdrv_spif_set_commands( SPI020_9F_CMD0 , SPI020_9F_CMD1, SPI020_9F_CMD2, SPI020_9F_CMD3 );
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, SPI020_9F_CMD2 );
kdrv_spif_wait_command_complete();
st_flash_info.ID = nrx_buff_word[nrx_buff_word_index-1] & 0xFF;
}
//get 4K erase support
nrx_buff_word_index =0;
kdrv_spif_set_commands( st_flash_info.PTP + 0, SPI020_5A_CMD1, 0x01, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x01 );
kdrv_spif_wait_command_complete();
st_flash_info.erase_4K_support = nrx_buff_word[nrx_buff_word_index-1] & 0x3;
//get size
nrx_buff_word_index =0;
kdrv_spif_set_commands( st_flash_info.PTP+4 , SPI020_5A_CMD1, 0x04, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x04 );
kdrv_spif_wait_command_complete();
st_flash_info.flash_size_KByte = (nrx_buff_word[nrx_buff_word_index-1]>>10)>>3;
ntemp = nrx_buff_word[nrx_buff_word_index-1]>>3;
//get sector size 0x1C
nrx_buff_word_index =0;
kdrv_spif_set_commands( st_flash_info.PTP+0x1C , SPI020_5A_CMD1, 0x01, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x01 );
kdrv_spif_wait_command_complete();
st_flash_info.sector_size_Bytes = 1<<(nrx_buff_word[ nrx_buff_word_index-1 ]&0xFF);
st_flash_info.total_sector_numbers = (ntemp / st_flash_info.sector_size_Bytes)+1;
//get sector size 0x20
nrx_buff_word_index =0;
kdrv_spif_set_commands( st_flash_info.PTP+0x20 , SPI020_5A_CMD1, 0x01, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x01 );
kdrv_spif_wait_command_complete();
st_flash_info.block_size_Bytes = ( 1<<( nrx_buff_word[ nrx_buff_word_index-1 ] & 0xFF ) )/st_flash_info.sector_size_Bytes ;
//get page size
nrx_buff_word_index =0;
kdrv_spif_set_commands( st_flash_info.PTP+0x28 , SPI020_5A_CMD1, 0x01, SPI020_5A_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x01 );
kdrv_spif_wait_command_complete();
ntemp = nrx_buff_word[nrx_buff_word_index-1]&0xFF;
#if 0
//20191219 add
nrx_buff_word_index =0;
kdrv_spif_set_commands(SPI020_15_CMD0, SPI020_15_CMD1, SPI020_15_CMD2, SPI020_15_CMD3);
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x01 );
kdrv_spif_wait_command_complete();
nrx_buff_word_index =0;
kdrv_spif_set_commands(SPI020_35_CMD0, SPI020_35_CMD1, SPI020_35_CMD2, SPI020_35_CMD3);//bessel:wait interrupt instead of delay
kdrv_spif_read_Rx_FIFO( nrx_buff_word, &nrx_buff_word_index, 0x01 );
kdrv_spif_wait_command_complete();
#endif
kdrv_spif_switch_org();
if( (ntemp>>4) == FLASH_PAGE_SIZE_256_CODE )
{
st_flash_info.page_size_Bytes = 256;
}
else
{
st_flash_info.page_size_Bytes = 0;
return KDEV_STATUS_ERROR;
}
return KDEV_STATUS_OK;
}
kdev_status_t kdev_flash_initialize(void)//ARM_Flash_SignalEvent_t cb_event)
{
#if defined(FLASH_COMM) && (FLASH_COMM == FLASH_COMM_SPEED_100MHZ)
kdrv_spif_initialize(SPI_CLK_DIVIDER_2);//reg |= SPI_CLK_MODE0 | SPI_CLK_DIVIDER_2; // SCPU:200MHz, Flash: 100MHz
#elif defined(FLASH_COMM) && (FLASH_COMM == FLASH_COMM_SPEED_50MHZ)
kdrv_spif_initialize(SPI_CLK_DIVIDER_4);//reg |= SPI_CLK_MODE0 | SPI_CLK_DIVIDER_4; // SCPU:200MHz, Flash: 50MHz
#else
kdrv_spif_initialize(SPI_CLK_DIVIDER_8);//reg |= SPI_CLK_MODE0 | SPI_CLK_DIVIDER_8; // SCPU:200MHz, Flash: 25MHz
#endif
kdev_flash_read_flash_id();
kdev_flash_read_status();
#if FLASH_4BYTES_CMD_EN
//kdev_flash_4Bytes_ctrl(1);
#endif
return KDEV_STATUS_OK;
}
kdev_status_t kdev_flash_uninitialize(void)
{
return KDEV_STATUS_OK;
}
kdev_status_t kdev_flash_power_control(ARM_POWER_STATE state)
{
switch (state) {
case ARM_POWER_OFF:
break;
case ARM_POWER_LOW:
break;
case ARM_POWER_FULL:
break;
default:
return KDEV_STATUS_ERROR;
}
return KDEV_STATUS_OK;
}
uint32_t kdev_flash_read_compare(uint8_t type, uint32_t offset, uint32_t len, void *buf)
{
uint32_t *read_buf;//uint8_t *read_buf;
uint32_t ret=0;
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(1);
#endif
if (type & FLASH_DMA_READ) {
regSPIF_irq->st.dw.kdrv_spif_icr = SPI020_cmd_cmplt_intr_en | SPI020_DMA_EN;/* enable DMA function */
}
/* fill in command 0~3 */
if (type & FLASH_DTR_RW) {
if (type & FLASH_DUAL_READ)
kdrv_spif_set_commands(offset, SPI020_BD_CMD1, len, SPI020_BD_CMD3);
else if(type & FLASH_QUAD_RW)
kdrv_spif_set_commands(offset, SPI020_ED_CMD1, len, SPI020_ED_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_0D_CMD1, len, SPI020_0D_CMD3);
} else if (type & FLASH_DUAL_READ) {
if(type & FLASH_IO_RW) {
//fLib_printf("Daul (0xBB) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_BC_CMD1, len, SPI020_BC_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_BB_CMD1, len, SPI020_BB_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_BB_CMD1, len, SPI020_BB_CMD3);
#endif
} else {
//fLib_printf("Daul (0x3B) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_3C_CMD1, len, SPI020_3C_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_3B_CMD1, len, SPI020_3B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_3B_CMD1, len, SPI020_3B_CMD3);
#endif
}
} else if(type & FLASH_QUAD_RW) {
if(type & FLASH_IO_RW) {
//fLib_printf("Quad (0xEB) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_EC_CMD1, len, SPI020_EC_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_EB_CMD1, len, SPI020_EB_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_EB_CMD1, len, SPI020_EB_CMD3);
#endif
} else {
//fLib_printf("Quad (0x6B) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_6C_CMD1, len, SPI020_6C_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_6B_CMD1, len, SPI020_6B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_6B_CMD1, len, SPI020_6B_CMD3);
#endif
}
} else if(type & FLASH_FAST_READ) {
//fLib_printf("Fast (0x0B) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_0C_CMD1, len, SPI020_0C_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_0B_CMD1, len, SPI020_0B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_0B_CMD1, len, SPI020_0B_CMD3);
#endif
} else {/* normal read */
//fLib_printf("Normal (0x03) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_13_CMD1, len, SPI020_13_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_03_CMD1, len, SPI020_03_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_03_CMD1, len, SPI020_03_CMD3);
#endif
}
if (type & FLASH_DMA_READ) {
return 0;
}
read_buf = (uint32_t *)buf;
ret = kdrv_spif_read_compare(read_buf, len);/* read data */
kdrv_spif_wait_command_complete();/* wait for command complete */
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(0);
#endif
return ret;
}
void kdev_flash_read(uint8_t type, uint32_t offset, uint32_t len, void *buf)
{
uint32_t *read_buf;//uint8_t *read_buf;
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(1);
#endif
if (type & FLASH_DMA_READ) {
regSPIF_irq->st.dw.kdrv_spif_icr = SPI020_cmd_cmplt_intr_en | SPI020_DMA_EN;/* enable DMA function */
}
/* fill in command 0~3 */
if (type & FLASH_DTR_RW) { /* Please check flash datasheet which can support DTR or not */
if (type & FLASH_DUAL_READ)
kdrv_spif_set_commands(offset, SPI020_BD_CMD1, len, SPI020_BD_CMD3);
else if(type & FLASH_QUAD_RW)
kdrv_spif_set_commands(offset, SPI020_ED_CMD1, len, SPI020_ED_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_0D_CMD1, len, SPI020_0D_CMD3);
} else if (type & FLASH_DUAL_READ) {
if(type & FLASH_IO_RW) {
//fLib_printf("Daul (0xBB) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_BC_CMD1, len, SPI020_BC_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_BB_CMD1, len, SPI020_BB_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_BB_CMD1, len, SPI020_BB_CMD3);
#endif
} else {
//fLib_printf("Daul (0x3B) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_3C_CMD1, len, SPI020_3C_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_3B_CMD1, len, SPI020_3B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_3B_CMD1, len, SPI020_3B_CMD3);
#endif
}
} else if(type & FLASH_QUAD_RW) {
if(type & FLASH_IO_RW) {
//fLib_printf("Quad (0xEB) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_EC_CMD1, len, SPI020_EC_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_EB_CMD1, len, SPI020_EB_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_EB_CMD1, len, SPI020_EB_CMD3);
#endif
} else {
//fLib_printf("Quad (0x6B) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_6C_CMD1, len, SPI020_6C_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_6B_CMD1, len, SPI020_6B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_6B_CMD1, len, SPI020_6B_CMD3);
#endif
}
} else if(type & FLASH_FAST_READ) {
//fLib_printf("Fast (0x0B) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_0C_CMD1, len, SPI020_0C_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_0B_CMD1, len, SPI020_0B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_0B_CMD1, len, SPI020_0B_CMD3);
#endif
} else {/* normal read */ /* Please be noted that 03h command only can support max. 50MHz */
//fLib_printf("Normal (0x03) read\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_13_CMD1, len, SPI020_13_CMD3);
else
#if defined(SPI_BUS_SPEED) && (SPI_BUS_SPEED == SPI_BUS_SPEED_100MHZ)
kdrv_spif_set_commands(offset, SPI020_0B_CMD1, len, SPI020_0B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_03_CMD1, len, SPI020_03_CMD3);
#endif
#else
#if defined(SPI_BUS_SPEED) && (SPI_BUS_SPEED == SPI_BUS_SPEED_100MHZ)
kdrv_spif_set_commands(offset, SPI020_0B_CMD1, len, SPI020_0B_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_03_CMD1, len, SPI020_03_CMD3);
#endif
#endif
}
if (type & FLASH_DMA_READ) {
return;
}
read_buf = (uint32_t *)buf;
kdrv_spif_read_data(read_buf, len);/* read data */
kdrv_spif_wait_command_complete();/* wait for command complete */
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(0);
#endif
}
void kdev_flash_dma_read_stop(void)
{
kdrv_spif_wait_command_complete();/* wait for command complete */
regSPIF_irq->st.dw.kdrv_spif_icr = SPI020_cmd_cmplt_intr_en;/* disable DMA function */
}
void kdev_flash_dma_write_stop(void)
{
kdrv_spif_wait_command_complete();/* savecodesize, move into spi020_check_status_til_ready */
regSPIF_irq->st.dw.kdrv_spif_icr = SPI020_cmd_cmplt_intr_en;/* disable DMA function */
kdrv_spif_check_status_till_ready_2();
}
uint8_t kdev_flash_r_state_OpCode_35(void)
{
uint16_t nrx_buff_word_index = 0;
uint32_t RDSR2=0; //35h
/* fill in command 0~3 */
kdrv_spif_set_commands(SPI020_35_CMD0, SPI020_35_CMD1, SPI020_35_CMD2, SPI020_35_CMD3 );
nrx_buff_word_index = 0;
kdrv_spif_read_Rx_FIFO( &RDSR2, &nrx_buff_word_index, 0x01 );
//fLib_printf("SPI020_35_CMD1 buf[0]=0x%2X\n", RDSR2 );
kdrv_spif_wait_command_complete();
return (uint8_t)RDSR2;
}
void kdev_flash_write(uint8_t type, uint32_t offset, uint32_t len, void *buf, uint32_t buf_offset)
{
uint8_t *write_buf;
/* This function does not take care about 4 bytes alignment */
/* if ((uint32_t )(para->buf) % 4) return 1; */
kdrv_spif_switch_org();
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(1);
#endif
//fLib_printf("write: offset:%x\n", offset);
kdev_flash_write_control(1);/* send write enabled */
/* fill in command 0~3 */
if(type & FLASH_QUAD_RW) {
//fLib_printf("Quad (0x32) write\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_34_CMD1, len, SPI020_34_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_32_CMD1, len, SPI020_32_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_32_CMD1, len, SPI020_32_CMD3);
#endif
} else {
//fLib_printf("Normal (0x02) write\n");
#if FLASH_4BYTES_CMD_EN
if (kdev_flash_is_4byte_address(offset))
kdrv_spif_set_commands(offset, SPI020_12_CMD1, len, SPI020_12_CMD3);
else
kdrv_spif_set_commands(offset, SPI020_02_CMD1, len, SPI020_02_CMD3);
#else
kdrv_spif_set_commands(offset, SPI020_02_CMD1, len, SPI020_02_CMD3);
#endif
}
if (type & FLASH_DMA_WRITE) {
regSPIF_irq->st.dw.kdrv_spif_icr = SPI020_cmd_cmplt_intr_en | SPI020_DMA_EN;/* enable DMA function */
return;
}
write_buf = (uint8_t *)buf+buf_offset;
//fLib_printf("write_buf:%x, len=%x\n",write_buf, len);
kdrv_spif_write_data(write_buf, len);
kdrv_spif_check_status_till_ready();
#if FLASH_4BYTES_CMD_EN
if(kdev_flash_is_4byte_address(offset))
kdev_flash_4Bytes_ctrl(0);
#endif
return;
}
kdev_status_t kdev_flash_readdata(uint32_t addr, void *data, uint32_t cnt)
{
uint8_t Option;
Option = FLASH_OP_MODE;
kdev_flash_read(Option, addr , cnt , data);
return KDEV_STATUS_OK;
}
kdev_status_t kdev_flash_programming(uint8_t Option, uint32_t addr, const void *data, uint32_t cnt)
{
uint16_t wloop = 0;
uint16_t i = 0;
uint16_t final = 0;
if (cnt % FLASH_PAGE_SIZE == 0)
wloop = (cnt / FLASH_PAGE_SIZE);
else
wloop = (cnt / FLASH_PAGE_SIZE) + 1;
for(i=0; i<wloop; i++)
{
if(i == (wloop - 1))
{
final = cnt-(i*FLASH_PAGE_SIZE); //should <= 256
kdev_flash_write(Option, (addr+(i*FLASH_PAGE_SIZE)), final, (void *)data, (i*FLASH_PAGE_SIZE));
}
else
{
kdev_flash_write(Option, (addr+(i*FLASH_PAGE_SIZE)), FLASH_PAGE_SIZE, (void *)data, (i*FLASH_PAGE_SIZE));
}
}
return KDEV_STATUS_OK;
}
kdev_status_t kdev_flash_programdata(uint32_t addr, const void *data, uint32_t cnt)
{
kdev_status_t status;
uint8_t Option = FLASH_OP_MODE;
status = kdev_flash_programming(Option, addr, data, cnt);
return status;
}
kdev_status_t kdev_flash_programdata_memxfer(uint32_t addr, const void *data, uint32_t cnt)
{
kdev_status_t status;
uint8_t Option = FLASH_OP_MODE;
flash_msg("kdev_flash_programming addr = %d! cnt = %d!", addr, cnt);
//if((addr % FLASH_MINI_BLOCK_SIZE)||(cnt % FLASH_MINI_BLOCK_SIZE)) //not align to 4K size
if(addr % FLASH_MINI_BLOCK_SIZE) //not align to 4K size
{
flash_msg("LOG_CRITICAL: address and size must align to 4K bytes!!\n");
status = KDEV_STATUS_ERROR;
}
else
{
uint32_t sectors = cnt / FLASH_MINI_BLOCK_SIZE;
if(cnt % FLASH_MINI_BLOCK_SIZE)
sectors++;
for(int i=0; i<sectors; i++)
{
kdev_flash_erase_sector(addr+(i*FLASH_MINI_BLOCK_SIZE));
}
status = kdev_flash_programming(Option, addr, data, cnt);
}
return status;
}
kdev_status_t kdev_flash_erase_sector(uint32_t addr)
{
kdev_flash_4kErase(addr); //for program partial
//kdev_flash_64kErase(addr); //for program all
return KDEV_STATUS_OK;
}
kdev_status_t kdev_flash_erase_multi_sector(uint32_t start_addr, uint32_t end_addr)
{
uint16_t i=0;
uint32_t nstart_index = 0;
uint32_t nend_index = 0;
st_flash_info.sector_size_Bytes = st_flash_info.sector_size_Bytes ? st_flash_info.sector_size_Bytes : SPI020_SECTOR_SIZE;
nstart_index = start_addr / st_flash_info.sector_size_Bytes;
nend_index = end_addr/st_flash_info.sector_size_Bytes;
if( ( end_addr%st_flash_info.sector_size_Bytes) == 0 && nend_index > nstart_index )
{
nend_index --;
}
flash_msg("_flash_erase_multi_sectors start_addr = %X! end_addr = %X!", start_addr, end_addr);
flash_msg("_flash_erase_multi_sectors start_index = %d! end_index = %d!", nstart_index, nend_index);
if( (nstart_index <= nend_index) || (nend_index < st_flash_info.total_sector_numbers) )
{
for(i=nstart_index; i<=nend_index; i++)
{
flash_msg("_flash_erase_multi_sectors addr = %d*%d=0x%X!", i, st_flash_info.sector_size_Bytes, i*st_flash_info.sector_size_Bytes);
kdev_flash_4kErase(i*st_flash_info.sector_size_Bytes);
flash_msg("_flash_erase_multi_sectors addr = %d*%d=0x%X done!", i, st_flash_info.sector_size_Bytes, i*st_flash_info.sector_size_Bytes);
}
return KDEV_STATUS_OK;
}
return KDEV_STATUS_ERROR;
}
kdev_status_t kdev_flash_erase_chip(void)
{
kdev_flash_write_control(1);/* send write enabled */
/* fill in command 0~3 */
kdrv_spif_set_commands(SPI020_C7_CMD0, SPI020_C7_CMD1, SPI020_C7_CMD2, SPI020_C7_CMD3);
/* wait for command complete */
kdrv_spif_check_status_till_ready();
return KDEV_STATUS_OK;
}
kdev_flash_status_t kdev_flash_get_status(void)
{
kdev_flash_status_t status;
uint32_t flash_status;
kdrv_spif_set_commands(SPI020_05_CMD0, SPI020_05_CMD1, SPI020_05_CMD2, SPI020_05_CMD3);
kdrv_spif_wait_command_complete();
/* read data */
flash_status = regSPIF_irq->st.bf.kdrv_spif_spisr.SPI_read_status;
*(uint32_t*)&status = flash_status;
return status;
}
kdev_status_t kdev_flash_get_info(void)
{
kdev_status_t status;
status = kdev_flash_read_SFDP();
flash_msg("Read Flash SFDP %s", (status==KDEV_STATUS_OK ? "PASS" : "FAIL"));
return status;
}