390 lines
10 KiB
C
390 lines
10 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:
|
|
* ---------
|
|
* kdrv_spif.c
|
|
*
|
|
* Project:
|
|
* --------
|
|
* KL520
|
|
*
|
|
* Description:
|
|
* ------------
|
|
* This SPI Flash driver is for Generic SPI Flash Access
|
|
* HW: Faraday FTSPI020
|
|
*
|
|
* Author:
|
|
* -------
|
|
* Teresa Chen
|
|
**
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
Head Block of The File
|
|
******************************************************************************/
|
|
|
|
#include "kdrv_SPI020.h"
|
|
#include "kdrv_spif.h"
|
|
#include "io.h"
|
|
|
|
//#define SPIF_DBG
|
|
#ifdef SPIF_DBG
|
|
#include "kmdw_console.h"
|
|
#define spif_msg(fmt, ...) info_msg("[KDRV_SPIF] " fmt, ##__VA_ARGS__)
|
|
#else
|
|
#define spif_msg(fmt, ...)
|
|
#endif
|
|
|
|
#define min_t(x,y) ( x < y ? x: y )
|
|
|
|
typedef volatile union
|
|
{
|
|
struct
|
|
{
|
|
uint32_t PA[6]; //0x100~0x114
|
|
} dw; //double word
|
|
} kdrv_spif_io_reg_t;
|
|
|
|
#define kdrv_spif_io_reg ((kdrv_spif_io_reg_t *)(SCU_EXTREG_PA_BASE + 0x100))
|
|
|
|
void kdrv_spif_initialize(uint32_t clock)
|
|
{
|
|
uint32_t reg;
|
|
#if 1 //default is 12mA
|
|
int mA;
|
|
/*16mA*/
|
|
//mA = 0; //4mA
|
|
//mA = 1; //8mA
|
|
//mA = 2; //12mA
|
|
mA = 3; //16mA
|
|
spif_msg("Set SPI driving = %d mA\n", (mA+1)*4);
|
|
for(int i=0; i<6; i++)
|
|
{
|
|
spif_msg("addr = 0x%2X\n",addr);
|
|
reg = kdrv_spif_io_reg->dw.PA[i]; //SPI IO control
|
|
spif_msg("reg = 0x%2X\n",reg);
|
|
reg &= ~0x000000C0; //clear bit6, bit7
|
|
spif_msg("reg = 0x%2X\n",reg);
|
|
reg |= (mA<<6); //select driving strength
|
|
reg |= (1<<8); //select slew rate slow
|
|
spif_msg("reg = 0x%2X\n",reg);
|
|
kdrv_spif_io_reg->dw.PA[i] = reg;
|
|
}
|
|
#endif
|
|
#if 1
|
|
regSPIF_ctrl->st.bf.kdrv_spif_cr.abort = 1;
|
|
/* Wait reset completion */
|
|
do {
|
|
if(regSPIF_ctrl->st.bf.kdrv_spif_cr.abort == 0)
|
|
break;
|
|
} while(1);
|
|
#endif
|
|
/* Set control register */
|
|
reg = regSPIF_ctrl->st.dw.kdrv_spif_cr; // 0x80
|
|
reg &= ~(SPI020_CLK_MODE | SPI020_CLK_DIVIDER);
|
|
reg |= SPI_CLK_MODE0 | clock; // SCPU:200MHz, Flash: 50MHz
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cr = reg;
|
|
regSPIF_ctrl->st.bf.kdrv_spif_cr.XIP_port_sel = 0; /* make sure it's in Command slave port */
|
|
kdrv_spif_pre_log();
|
|
}
|
|
|
|
void kdrv_spif_memxfer_initialize(uint8_t flash_mode, uint8_t mem_mode)
|
|
{
|
|
uint32_t reg;
|
|
uint32_t ntemp;
|
|
|
|
//set as mode0 for SPI020_IO and driving 12mA
|
|
ntemp = ( 0<<0 | ( 3<<7 ) );
|
|
for(int i=0; i<6; i++)
|
|
kdrv_spif_io_reg->dw.PA[i] = ntemp;
|
|
if (!(flash_mode & MEMXFER_INITED)) {
|
|
regSPIF_ctrl->st.bf.kdrv_spif_cr.abort = 1;
|
|
do
|
|
{
|
|
if(regSPIF_ctrl->st.bf.kdrv_spif_cr.abort == 0)
|
|
break;
|
|
}while(1);
|
|
|
|
/* Set control register */
|
|
reg = regSPIF_ctrl->st.dw.kdrv_spif_cr; // 0x80
|
|
reg &= ~(SPI020_CLK_MODE | SPI020_CLK_DIVIDER);
|
|
#if defined(SPI_BUS_SPEED) && (SPI_BUS_SPEED == SPI_BUS_SPEED_100MHZ)
|
|
reg |= SPI_CLK_MODE0 | SPI_CLK_DIVIDER_2;
|
|
#elif defined(SPI_BUS_SPEED) && (SPI_BUS_SPEED == SPI_BUS_SPEED_50MHZ)
|
|
reg |= SPI_CLK_MODE0 | SPI_CLK_DIVIDER_4;
|
|
#else //SPI_BUS_SPEED == SPI_BUS_SPEED_25MHZ
|
|
reg |= SPI_CLK_MODE0 | SPI_CLK_DIVIDER_8;
|
|
#endif
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cr = reg;
|
|
regSPIF_ctrl->st.bf.kdrv_spif_cr.XIP_port_sel = 0; /* make sure it's in Command slave port */
|
|
}
|
|
kdrv_spif_pre_log();
|
|
}
|
|
|
|
void kdrv_spif_set_commands(uint32_t cmd0, uint32_t cmd1, uint32_t cmd2, uint32_t cmd3)
|
|
{
|
|
//spif_msg("cmd = 0x%4X 0x%4X 0x%4X 0x%4X\n",cmd0,cmd1,cmd2,cmd3);
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cmd0 = cmd0;
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cmd1 = cmd1;
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cmd2 = cmd2;
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cmd3 = cmd3;
|
|
}
|
|
|
|
/* Wait until command complete */
|
|
void kdrv_spif_wait_command_complete(void)
|
|
{
|
|
uint32_t reg;
|
|
|
|
do {
|
|
reg = regSPIF_irq->st.dw.kdrv_spif_isr;
|
|
} while ((reg & SPI020_CMD_CMPLT)==0x0);
|
|
// outw(SPI020REG_INTR_ST, (reg | SPI020_CMD_CMPLT));/* clear command complete status */
|
|
regSPIF_irq->st.bf.kdrv_spif_isr.cmd_cmplt_sts=1;/* clear command complete status */
|
|
}
|
|
|
|
uint32_t gflash_clock_log;
|
|
void kdrv_spif_pre_log( void )
|
|
{
|
|
gflash_clock_log = regSPIF_ctrl->st.dw.kdrv_spif_cr;
|
|
}
|
|
|
|
void kdrv_spif_switch_org( void )
|
|
{
|
|
// Reset SPI IP
|
|
regSPIF_ctrl->st.bf.kdrv_spif_cr.abort=1;
|
|
/* Wait reset completion */
|
|
do {
|
|
if(regSPIF_ctrl->st.bf.kdrv_spif_cr.abort==0)
|
|
break;
|
|
} while(1);
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cr = gflash_clock_log;
|
|
}
|
|
|
|
void kdrv_spif_switch_low_speed( void )
|
|
{
|
|
uint32_t reg ;
|
|
// //Reset SPI IP
|
|
regSPIF_ctrl->st.bf.kdrv_spif_cr.abort=1;
|
|
/* Wait reset completion */
|
|
do {
|
|
if(regSPIF_ctrl->st.bf.kdrv_spif_cr.abort==0)
|
|
break;
|
|
} while(1);
|
|
/* Set control register */
|
|
reg = regSPIF_ctrl->st.dw.kdrv_spif_cr;
|
|
reg &= ~(SPI020_CLK_MODE | SPI020_CLK_DIVIDER);
|
|
reg |= SPI_CLK_MODE0 | SPI_CLK_DIVIDER_4;
|
|
regSPIF_ctrl->st.dw.kdrv_spif_cr = reg;
|
|
}
|
|
|
|
uint8_t kdrv_spif_rx_FIFO_empty_check(void)
|
|
{
|
|
if ( ( regSPIF_ctrl->st.bf.kdrv_spif_sr.RXFIFO_Ready ) != 0)
|
|
{
|
|
return 1; //empty
|
|
}
|
|
return 0;//at leat 1 data
|
|
}
|
|
|
|
|
|
/* Wait until the rx fifo ready */
|
|
void kdrv_spif_wait_rx_full(void)
|
|
{
|
|
while(!regSPIF_ctrl->st.bf.kdrv_spif_sr.RXFIFO_Ready);
|
|
}
|
|
|
|
/* Wait until the tx fifo ready */
|
|
void kdrv_spif_wait_tx_empty(void)
|
|
{
|
|
while(!regSPIF_ctrl->st.bf.kdrv_spif_sr.TXFIFO_Ready);
|
|
}
|
|
|
|
/* Get the rx fifo depth, unit in byte */
|
|
uint32_t kdrv_spif_rxfifo_depth(void)
|
|
{
|
|
return (uint8_t)(regSPIF_info->st.bf.kdrv_spif_feature.RXFIFO_DEPTH << 2);
|
|
}
|
|
|
|
/* Get the tx fifo depth, unit in byte */
|
|
uint32_t kdrv_spif_txfifo_depth(void)
|
|
{
|
|
// unsigned int read;
|
|
return (uint8_t)(regSPIF_info->st.bf.kdrv_spif_feature.TXFIFO_DEPTH << 2);
|
|
}
|
|
|
|
void kdrv_spif_read_Rx_FIFO( uint32_t *buf_word, uint16_t *buf_word_index, uint32_t target_byte )
|
|
{
|
|
while( 1 )
|
|
{
|
|
while( kdrv_spif_rx_FIFO_empty_check() == 1 )
|
|
{
|
|
*( buf_word + *buf_word_index )= regSPIF_data->dw.kdrv_spif_dp;
|
|
*buf_word_index = (*buf_word_index) + 1;
|
|
}
|
|
if( (*buf_word_index*4) >= target_byte )
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32_t kdrv_spif_read_compare(/*uint8_t*/uint32_t *buf, uint32_t length)
|
|
{
|
|
uint32_t access_byte;//, tmp_read;
|
|
uint32_t ret=0;
|
|
|
|
while(length > 0)
|
|
{
|
|
kdrv_spif_wait_rx_full();
|
|
access_byte = min_t(length, kdrv_spif_rxfifo_depth());
|
|
length -= access_byte;
|
|
while(access_byte > 0)
|
|
{
|
|
if(*buf == regSPIF_data->dw.kdrv_spif_dp)
|
|
ret += 4;
|
|
buf ++;
|
|
if(access_byte>=4)
|
|
access_byte -= 4;
|
|
else
|
|
access_byte=0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void kdrv_spif_read_data(uint32_t *buf, uint32_t length)
|
|
{
|
|
uint32_t access_byte;//, tmp_read;
|
|
|
|
while(length > 0)
|
|
{
|
|
kdrv_spif_wait_rx_full();
|
|
access_byte = min_t(length, kdrv_spif_rxfifo_depth());
|
|
length -= access_byte;
|
|
while(access_byte > 0)
|
|
{
|
|
*buf= regSPIF_data->dw.kdrv_spif_dp;
|
|
buf ++;
|
|
if(access_byte>=4)
|
|
access_byte -= 4;
|
|
else
|
|
access_byte=0;
|
|
#if 0
|
|
switch(access_byte)
|
|
{
|
|
case 1:
|
|
tmp_read = inw((int8_t * )SPI020REG_DATAPORT);
|
|
*buf = tmp_read&0xFF;
|
|
access_byte = 0;//break while loop
|
|
break;
|
|
case 2:
|
|
tmp_read = inw((int8_t * )SPI020REG_DATAPORT);
|
|
*buf = tmp_read&0xFF;
|
|
buf++;
|
|
*buf = (tmp_read&0xFF00)>>8;
|
|
access_byte = 0;// break while loop
|
|
break;
|
|
case 3:// read chip id will use this case
|
|
tmp_read = inw((int8_t * )SPI020REG_DATAPORT);
|
|
*buf = tmp_read&0x00FF;
|
|
buf++;
|
|
*buf = (tmp_read&0xFF00)>>8;
|
|
buf++;
|
|
*buf = (tmp_read&0xFF0000)>>16;
|
|
access_byte = 0;// break while loop
|
|
break;
|
|
default:// access_byte>=4
|
|
*(uint32_t *)buf= inw((int8_t * )SPI020REG_DATAPORT);
|
|
buf +=4;
|
|
access_byte -= 4;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void kdrv_spif_check_status_till_ready_2(void)
|
|
{
|
|
#if 1
|
|
uint32_t gSPI_RX_buff[4];
|
|
uint16_t gSPI_RX_buff_index;
|
|
volatile uint32_t countdown = 0;
|
|
|
|
while(1)
|
|
{
|
|
countdown =1000;
|
|
kdrv_spif_set_commands( SPI020_05_CMD0_w, SPI020_05_CMD1_w, SPI020_05_CMD2_w, SPI020_05_CMD3_w);
|
|
gSPI_RX_buff_index = 0;
|
|
kdrv_spif_read_Rx_FIFO( gSPI_RX_buff, &gSPI_RX_buff_index, 1 );
|
|
kdrv_spif_wait_command_complete();
|
|
|
|
if( (gSPI_RX_buff[0] & 0x01) == 0x00)
|
|
{
|
|
break;
|
|
}
|
|
while(countdown--);
|
|
}
|
|
#else
|
|
// main_delay_count(0x5100);
|
|
|
|
/* fill in command 0~3 */
|
|
kdrv_spif_set_commands(SPI020_05_CMD0, SPI020_05_CMD1, SPI020_05_CMD2, SPI020_05_CMD3);
|
|
// main_delay_count(0x80);
|
|
/* wait for command complete */
|
|
kdrv_spif_wait_command_complete();
|
|
#endif
|
|
}
|
|
|
|
void kdrv_spif_check_status_till_ready(void)
|
|
{
|
|
/* savecodesize, move into here */
|
|
kdrv_spif_wait_command_complete();
|
|
|
|
/* read status */
|
|
kdrv_spif_check_status_till_ready_2();
|
|
|
|
}
|
|
|
|
void kdrv_spif_check_quad_status_till_ready(void)
|
|
{
|
|
/* savecodesize, move into here */
|
|
kdrv_spif_wait_command_complete();
|
|
|
|
/* read status */
|
|
/* fill in command 0~3 */
|
|
kdrv_spif_set_commands(SPI020_05_CMD0, SPI020_05_CMD1, SPI020_05_CMD2, SPI020_05_CMD3);
|
|
// main_delay_count(0x80);
|
|
/* wait for command complete */
|
|
kdrv_spif_wait_command_complete();
|
|
|
|
}
|
|
|
|
void kdrv_spif_write_data(uint8_t *buf, uint32_t length)
|
|
{
|
|
int32_t access_byte;
|
|
|
|
/* This function assume length is multiple of 4 */
|
|
while(length > 0) {
|
|
kdrv_spif_wait_tx_empty();
|
|
access_byte = min_t(length, kdrv_spif_txfifo_depth());
|
|
length -= access_byte;
|
|
while(access_byte > 0) {
|
|
regSPIF_data->dw.kdrv_spif_dp = *((uint32_t *)buf);
|
|
buf += 4;
|
|
access_byte -= 4;
|
|
}
|
|
}
|
|
}
|
|
|