#include #include #include #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;imfr_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;iops->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;iops = (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