Files
banban/ql-bootloader/common/src/qspi_core.c
T

546 lines
13 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "common.h"
#include "qspi_dma.h"
#include "qspi_flash.h"
#include "qspi_host.h"
#include "qspi_nor.h"
#include "loadtable.h"
#include "bsp.h"
#define RW_BUF_LEN 2048
struct spi_flash_chip *chip=NULL;
BOOL NorFlashSupportDTR = FALSE ;
//static float rd_speed, wr_speed;
struct qspi_mode qspi_tx_mode[] = {
{SPI_OPM_TX, "write_x1"},
{SPI_OPM_TX_QUAD, "write_x4"},
};
struct qspi_mode qspi_rx_mode[] = {
{SPI_OPM_RX, "read_x1"},
{SPI_OPM_RX_DUAL, "read_x2"},
{SPI_OPM_RX_QUAD, "read_x4"},
};
char *qspi_tx_mode_name(int mode)
{
uint8_t i;
for (i = 0; i < 2; i++) {
if (qspi_tx_mode[i].mode == mode)
return qspi_tx_mode[i].name;
}
return NULL;
}
char *qspi_rx_mode_name(int mode)
{
uint8_t i;
for (i = 0; i < 3; i++) {
if (qspi_rx_mode[i].mode == mode)
return qspi_rx_mode[i].name;
}
return NULL;
}
char log_buf[1024*3+1];
void buf_dump(unsigned char* buf, unsigned int len)
{
unsigned int i;
if(len>1024)
len=1024;
memset(log_buf,0,sizeof(log_buf));
for(i=0;i<len;i++)
{
sprintf(log_buf+3*i,"%02x ",buf[i]);
}
uart_printf("\r\n");
uart_printf(log_buf, i*3);
uart_printf("\r\n");
}
#if 0
#define ASR_PROPERTY_QSPI_FLASH_ID_NAME ( "qspi_flash_id" )
#define ASR_PROPERTY_QSPI_INIT_FLAG_NAME ( "qspi_init_flag" )
void qspi_flash_id_save(void)
{
UINT32 asr_property_data, qspi_id;
qspi_id = (chip->mfr_id<<16)|(chip->dev_id);
CP_LOGI("qspi_flash_id_save: 0x%x\r\n",qspi_id);
transmit_data( ASR_PROPERTY_QSPI_INIT_FLAG_NAME ,0x1 );
asr_property_data = get_transmit_data(ASR_PROPERTY_QSPI_INIT_FLAG_NAME);
if( asr_property_data != 0xFFFFFFFF )
CP_LOGI("%s:0x%x\r\n",ASR_PROPERTY_QSPI_INIT_FLAG_NAME,asr_property_data);
transmit_data( ASR_PROPERTY_QSPI_FLASH_ID_NAME ,qspi_id );
asr_property_data = get_transmit_data(ASR_PROPERTY_QSPI_FLASH_ID_NAME);
if( asr_property_data != 0xFFFFFFFF )
CP_LOGI("%s:0x%x\r\n",ASR_PROPERTY_QSPI_FLASH_ID_NAME,asr_property_data);
}
#endif
//comment to porting LCD
//unsigned char qspi_wr_buf[1024*64];
//unsigned char qspi_rd_buf[1024*64];
int bbu_qspi_init(void)
{
struct qspi_host *host;
int cs = QSPI_CS_A1;
int mhz = 104;
//int mhz = 52; fudan micro
//int nand = 0;
int use_xip = 1;
int rx_mode = SPI_OPM_RX_QUAD;
int tx_mode = SPI_OPM_TX_QUAD;
int qpi = 0;
int XMC_SMPR = 0;
host = qspi_host_init(cs, mhz, use_xip);
chip = spi_nor_init(host, cs, rx_mode, tx_mode, qpi);
if(chip->mfr_id == SPIFLASH_MFR_XM){
XMC_SMPR = 1;
if(chip->dev_id == 0x4117 && NorFlashSupportDTR){
XMC_SMPR = 0;//XM25LU64C no need set SMPR
CP_LOGE("XM25LU64C no need set SMPR\r\n");
}else if(chip->dev_id == 0x5016){
XMC_SMPR = 0;//chip->dev_id=0x5016 is XM25LU32C, no need set SMPR
}
if((CHIP_IS_CRANELR || CHIP_IS_CRANELG || CHIP_IS_CRANELRH) && (chip->dev_id == 0x5015)){
XMC_SMPR = 0;//chip->dev_id=0x5015 is XM25QU16C, only on craneLR no need set SMPR
}
}
if ((XMC_SMPR ||(chip->mfr_id == SPIFLASH_MFR_ZBIT))
&&(mhz == 104))
{
qspi_enter_mode(QSPI_DISABLE_MODE);
*(volatile unsigned int*)(QSPI0_SMPR) = (0x1<<5);
qspi_enter_mode(QSPI_NORMAL_MODE);
}
if (!chip) {
CP_LOGE("SPI Nor/NAND flash init failed\r\n");
}
CP_LOGD("get flash total size[%llu] to set mpu\r\n",chip->size);
set_mpu_reg_flash((size_t)chip->size);
mpu_value_check();
#if 0
qspi_flash_id_save();
#endif
CP_LOGD("bbu qspi_init success\r\n");
return 0;
}
//quectel add
#include "ptable.h"
//判定是否是factory的地址,仅适用于内部nor flash,地址为相对地址
static int quec_judge_is_factory_erea(uint32_t addr)
{
_ptentry* p_zone = ptable_find_entry("factory_a");
if(!p_zone)
{
uart_printf("[QUEC][ERROR] ptable load err\r\n");
return -1;
}
if(addr >= p_zone->start && addr < chip->size)
{
return 0;
}
return -1;
}
int crane_qspi_write_uint(unsigned int addr , unsigned int value){
#if 0 //comment to porting LCD
int block_addr = (addr - FLASH_BASE_ADDR)&(~FLASH_BLOCK_MASK);
int block_offset = (addr - FLASH_BASE_ADDR)&( FLASH_BLOCK_MASK);
int ret;
/*
uart_printf("crane_qspi_write_uint block_addr =[%.08x]\r\n",block_addr);
uart_printf("crane_qspi_write_uint block_offset =[%.08x]\r\n",block_offset);
uart_printf("crane_qspi_write_uint value =[%.08x]\r\n",value);
*/
//read from flash to buffer
ret = chip->ops->read(chip, block_addr, FLASH_BLOCK_SIZE, (uint8_t *)qspi_rd_buf);
//update buffer
memcpy((uint8_t *)qspi_rd_buf + block_offset, &value, sizeof(value));
//erase block and write buffer to flash
//
//TODO: any possiablity after erase succeed ,flash write failed or power shut?
// might seprate loadtable into a RO area and RW area to avoid this happen.
//
ret = chip->ops->erase(chip, block_addr, FLASH_BLOCK_SIZE);
ret = chip->ops->write(chip, block_addr, FLASH_BLOCK_SIZE, (uint8_t *)qspi_rd_buf);
return ret;
#endif
}
int crane_qspi_read_uint(unsigned int addr){
int value = 0;
chip->ops->read(chip, (addr-FLASH_BASE_ADDR), sizeof(value), (uint8_t *)&value);
//uart_printf("crane_qspi_read_uint [%x]=[%x] !\r\n",addr,value);
return value;
}
int crane_qspi_erase(unsigned int addr, unsigned int size)
{
int ret = 0;
//uart_printf("crane_qspi_erase addr[%x],size[%x] !\r\n",addr,size);
//QSPI_MutexLock();
#ifdef SUPPORT_EXTERNAL_NORFLASH
if(addr >= 0x90000000){
addr -= 0x90000000;
ret = crane_ext_spi_erase(addr, size);
return ret;
}else
#endif
#if 1 //quectel add
{
if(addr >= 0x80000000){
addr -= 0x80000000;
}
}
#endif
if(quec_judge_is_factory_erea(addr) == 0)
{
return -1;
}
ret = chip->ops->erase(chip, addr, size);
//QSPI_MutexUnlock();
return ret;
}
int crane_qspi_read(unsigned int addr, unsigned int buf_addr, unsigned int size)
{
int ret = 0;
//uart_printf("crane_qspi_read addr[%x],size[%x] !\r\n",addr,size);
//QSPI_MutexLock();
#ifdef SUPPORT_EXTERNAL_NORFLASH
if(addr >= 0x90000000){
addr -= 0x90000000;
ret = crane_ext_spi_read(addr, buf_addr, size);
return ret;
}else
#endif
#if 1 //quectel add
{
if(addr >= 0x80000000){
addr -= 0x80000000;
}
}
#endif
ret = chip->ops->read(chip, addr, size, (uint8_t *)buf_addr);
//QSPI_MutexUnlock();
return ret;
}
int crane_qspi_write(unsigned int addr, unsigned int buf_addr,unsigned int size)
{
int ret = 0;
//uart_printf("crane_qspi_write addr[%x],size[%x] !\r\n",addr,size);
//QSPI_MutexLock();
#ifdef SUPPORT_EXTERNAL_NORFLASH
if(addr >= 0x90000000){
addr -= 0x90000000;
ret = crane_ext_spi_write(addr, buf_addr, size);
return ret;
}else
#endif
#if 1 //quectel add
{
if(addr >= 0x80000000){
addr -= 0x80000000;
}
}
#endif
if(quec_judge_is_factory_erea(addr) == 0)
{
return -1;
}
ret = chip->ops->write(chip, addr, size, buf_addr);
//QSPI_MutexUnlock();
return ret;
}
int bbu_qspi_test(unsigned int base_addr)
{
#if 0 //comment to porting LCD
unsigned int flash_addr;
unsigned int mem_addr;
unsigned int size;
int ret = 0;
unsigned int i;
flash_addr=base_addr;
mem_addr=(unsigned int)qspi_wr_buf;
size=64*1024;
for(i=0;i<sizeof(qspi_wr_buf);i++)
qspi_wr_buf[i]=i;
//dump original empty read bufer
uart_printf("1st dump\r\n");
buf_dump(qspi_rd_buf,size);
uart_printf("erase\r\n");
//erase and write to target flash
ret = chip->ops->erase(chip, flash_addr, 64*1024);
uart_printf("write\r\n");
ret = chip->ops->write(chip, flash_addr, size, (uint8_t *)mem_addr);
//read out and dump the read buffer for local check
mem_addr=(unsigned int)qspi_rd_buf;
memset(qspi_rd_buf,0,sizeof(qspi_rd_buf));
uart_printf("read\r\n");
ret = chip->ops->read(chip, flash_addr, size, (uint8_t *)mem_addr);
uart_printf("2nd dump\r\n");
buf_dump(qspi_rd_buf,size);
uart_printf("bbu_qspi_test baseaddr=[%x] done\r\n",base_addr);
for (i=0;i<size;i++){
if (qspi_rd_buf[i]!=qspi_wr_buf[i])
uart_printf("qspi wrong @0x%x\r\n", i);
}
uart_printf("qspi good!!\r\n");
return 0;
#endif
}
#ifdef SPINOR_SUPPORT
#include "SPI.h"
static int spinor_reset(struct spinor_chip_info *chip)
{
int ret = 0;
int port = SPINOR_getSSPPort();
SPINOR_SW_Reset(port);
return ret;
}
static int spinor_read_id(struct spinor_chip_info *chip, uint8_t *buf)
{
return 0;
}
static int spinor_read_uid(struct spinor_chip_info *chip, uint8_t *buf)
{
return 0;
}
static int spinor_erase(struct spinor_chip_info *chip, int addr, int len)
{
int ret = 0;
int port = SPINOR_getSSPPort();
ret = SPINOR_EraseByBlock(port, addr, len);
return ret;
}
static int spinor_erase_sector(struct spinor_chip_info *chip, int addr, int len)
{
int ret = 0;
int port = SPINOR_getSSPPort();
ret = SPINOR_EraseBySector(port, addr, len);
return ret;
}
static int spinor_write(struct spinor_chip_info *chip, unsigned int addr, int size, unsigned int wbuf)
{
int ret = 0;
int port = SPINOR_getSSPPort();
ret = SPINOR_Write(port, addr, (unsigned char*)wbuf, size);
return ret;
}
static int spinor_read(struct spinor_chip_info *chip, unsigned int addr, int size, unsigned int rbuf)
{
int ret = 0;
int port = SPINOR_getSSPPort();
ret = SPINOR_Read(port, addr, (unsigned char*)rbuf, size);
return ret;
}
/*
struct spinor_chip_info spinor_chip = {0};
static const struct spinor_ops ext_nor_ops = {
.reset = spinor_reset,
.read_id = NULL,
.read = spinor_read,
.write = spinor_write,
.erase = spinor_erase,
.erase_sector = spinor_erase_sector
};
*/
int external_spi_init(void)
{
int ret = 0;
int port = SPINOR_getSSPPort();
// struct spinor_chip_info *chip = &spinor_chip;
// spichip = chip;
InitializeSPIDevice(port,SSP_CLOCK_26M); //SSP_CLOCK_52M//SSP_CLOCK_26M
/*
chip->ops = (void *)&ext_nor_ops;
if(!chip->ops->reset)
return NULL;
ret = chip->ops->reset(chip);
*/
//spinor_reset(NULL);
return ret;
}
// quectel
int crane_ext_spi_erase(unsigned int addr, unsigned int size)
{
int ret = 0;
unsigned int block_size = 64 * 1024;
//uart_printf("crane_qspi_erase addr[%x],size[%x] !\r\n",addr,size);
//ret = spichip->ops->erase(spichip, addr, size);
if ((size >= block_size) && ((size % block_size) == 0))
{
ret = spinor_erase(NULL, addr, size);
}
else
{
// quectel add dont modify it
ret = spinor_erase_sector(NULL, addr, size);
}
return ret;
}
int crane_ext_spi_erase_4k(unsigned int addr, unsigned int size)
{
int ret = 0;
//uart_printf("crane_qspi_erase addr[%x],size[%x] !\r\n",addr,size);
//ret = spichip->ops->erase(spichip, addr, size);
ret = spinor_erase_sector(NULL, addr, size);
return ret;
}
int crane_ext_spi_read(unsigned int addr, unsigned int buf_addr, unsigned int size)
{
int ret = 0;
//uart_printf("crane_qspi_read addr[%x],size[%x] !\r\n",addr,size);
//ret = spichip->ops->read(spichip, addr, size, (uint8_t *)buf_addr);
ret = spinor_read(NULL, addr, size, buf_addr);
return ret;
}
int crane_ext_spi_write(unsigned int addr, unsigned int buf_addr,unsigned int size)
{
int ret = 0;
//uart_printf("crane_qspi_write addr[%x],size[%x] !\r\n",addr,size);
//ret = spichip->ops->write(spichip, addr, size, buf_addr);
ret = spinor_write(NULL, addr, size, buf_addr);
return ret;
}
#if 1 //to read spi pinmux from flashinfo.bin
#include "flashinfo.h"
unsigned char crane_ext_spi_pinmux_no_get(unsigned char *pinmux_no, unsigned char *spi_port, unsigned char *spi_clk)
{
unsigned char *flashinfo_buf= tiny_malloc(0x1000);
size_t flash_info_size = 0;
unsigned char *data;
struct flash_info *info;
unsigned char find = 0;
unsigned char ret = 1;
memset(flashinfo_buf,0,0x1000);
crane_qspi_read(0x2000, (unsigned int)flashinfo_buf, 0x1000); //flashinfo.bin is fixed in 0x2000~0x3000 for 1606L???
data = flashinfo_buf + 0x80; //remove UBI header
do {
info = (struct flash_info *)data;
if(info->magic != FLASH_INFO_MAGIC) {
uart_printf("no flashinfo found\r\n");
find = 0;
break;
}
size_t len = sizeof(struct flash_info);
len += (info->compatible_device_num - 1) * sizeof(struct compatible_device);
flash_info_size += len;
data = (char *)data + len;
if(flash_info_size > 0x1000) {
uart_printf("no ext spi info found\r\n");
break;
}
if(!strcmp(info->device_type, FLASH_TYPE_SPI_NOR)) {
find = 1;
break;
}
} while(info->chained);
if(find == 1)
{
*pinmux_no = info->ssp_gpio;
*spi_port = info->spi_port -1 ;
*spi_clk = info->ssp_clk;
uart_printf("find ext spi info, pinmux_no=%d, spi_port=%d, spi_clk=%d\r\n",*pinmux_no, *spi_port, *spi_clk);
ret = 0;
}
tiny_free(flashinfo_buf);
return ret;
}
#endif
#endif