/*************************************************************** ** ** Broadcom Corp. Confidential ** Copyright 1998-2000 Broadcom Corp. All Rights Reserved. ** ** THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED ** SOFTWARE LICENSE AGREEMENT BETWEEN THE USER AND BROADCOM. ** YOU HAVE NO RIGHT TO USE OR EXPLOIT THIS MATERIAL EXCEPT ** SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. ** ** File: fstore.c ** Description: Flash storage manager ** ****************************************************************/ /* include files */ #include "fstore.h" #include "ministd.h" #include "bstd.h" #include "bspi_flash.h" #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) #include "bchp_hif_mspi.h" #include "bcm_mips_defs.h" #endif #include "bchp_sun_top_ctrl.h" BDBG_MODULE(fstore); /* Register software module with debug interface */ unsigned int ReadReg32(unsigned int offset); void WriteReg32(unsigned int offset, unsigned int value); #define FSTORE_VERSION 0xFC1A #define FSTORE_VALID 0xBC07 typedef enum fs_flash_type_t { eFS_SP25_BSPI, /* Spansion serial flash on BSPI bus */ eFS_MX25_BSPI, /* Micronix serial flash on BSPI bus */ eFS_TYPE_MAX }fs_flash_type_t; typedef struct fstore_record_t { unsigned short version; /* Version number of data stored, if it does not match expected value use defaults */ unsigned short valid; /* Pattern indicating data is valid 0xBC07 */ unsigned int length; /* Length in bytes of the record */ unsigned int checksum; /* 32bit checksum */ }fstore_record_t; static bresult fstore_read(void *p_fs, unsigned int offset, unsigned char *data, unsigned int size); //static bresult fstore_read_spi(void *p_fs, unsigned int offset, unsigned char *data, unsigned int size); static bresult fstore_erase_spi(void *p_fs, unsigned int offset, unsigned int size); static bresult fstore_prog_spi(void *p_fs, unsigned int offset,void *buffer, unsigned int size); /* IMPORTANT align app flash sector on sector boundary */ static fstore_t s_fstore[eFS_TYPE_MAX] = { #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) /* read_base,write_base, {boot offset,init offset,app offset},sector_size,block_size,max_size */ /* more room for the binary with whole applicaiton in the flash loader offset */ /* we don't have patch section in flash so set it same as APP_DATA */ {0xBFC00000, 0x00000000, { 0, (2 * 1024 * 1024), (2 * 1024 * 1024)}, (4 * 1024), FLASH_SPI_MAX_PAGE_SIZE, (64 * 1024),fstore_read, fstore_erase_spi,fstore_prog_spi},/* eFS_S25FL129P (Model 00) */ {0xBFC00000, 0x00000000, { 0, (2 * 1024 * 1024), (2 * 1024 * 1024)}, (64 * 1024),FLASH_SPI_MAX_PAGE_SIZE, (64 * 1024),fstore_read, fstore_erase_spi,fstore_prog_spi},/* eFS_MX25_SPI */ #else /* read_base,write_base, {boot offset,init offset,app offset},sector_size,block_size,max_size */ {0xBFC00000,0x00000000, { 0, (640 * 1024), (3456 * 1024)}, (4 * 1024) , 4,(64 * 1024),fstore_read, fstore_erase_spi,fstore_prog_spi},/* eFS_MX25_SPI */ {0xBFC00000,0x00000000, { 0, (640 * 1024), (3456 * 1024)}, (64 * 1024) ,4,(64 * 1024),fstore_read, fstore_erase_spi,fstore_prog_spi},/* eFS_MX25_SPI */ #endif }; #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) /* Summary: get flash read address (taking care of size > 4M */ static unsigned char *fstore_get_read_addr(void *p_v, fstore_data_type_t type, unsigned int size) { fstore_t *p_fs = (fstore_t *)p_v; uint32_t offset = p_fs->offset[type]; /*TODO, handle address cross 4M boundry case */ if (offset < 0x00400000) { if ((offset + size) > 0x00400000) printf("%s: address cross 4M boundry\n", __func__); offset += p_fs->read_base; } else { /* check size to make sure not exceed 16M */ offset = BCM_PHYS_TO_KSEG1(0x20000000 - 16*1024*1024) + (offset - 0x00400000); } return (unsigned char *)offset; } #endif /* Summary: Calculate 32 bit checksum */ static inline unsigned int fstore_checksum(unsigned int *addr, unsigned int len) { unsigned int checksum = 0; unsigned int idx; BDBG_MSG(("Calc checksum for array @ 0x%08x, %d bytes (0x%08x)",addr,len,addr[0] )); for (idx = 0; idx < len/sizeof(unsigned int); ++idx) { checksum += addr[idx]; } BDBG_MSG(("0x%08x\n",checksum )); return checksum; } /* Summary: Read data from flash into the buffer. */ static bresult fstore_read(void *p_v, unsigned int offset, unsigned char *data, unsigned int size) { fstore_t *p_fs = (fstore_t *)p_v; #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) mspi_enable_bspi(); if (offset < 0x00400000) { if ((offset + size) > 0x00400000) { memcpy(data,(unsigned char*)(p_fs->read_base + offset), (0x00400000 - offset)); data += (offset + size) - 0x00400000; size = (offset + size) - 0x00400000; offset = BCM_PHYS_TO_KSEG1(0x20000000 - 16*1024*1024); } else offset += p_fs->read_base; } else { /* check size to make sure not exceed 16M */ offset = BCM_PHYS_TO_KSEG1(0x20000000 - 16*1024*1024) + (offset - 0x00400000); } memcpy(data,(unsigned char*)offset,size); #else /* max 4M */ memcpy(data,(unsigned char*)(p_fs->read_base + offset),size); #endif return b_ok; } /* Summary: Read data from flash into the buffer. */ #if 0 static bresult fstore_read_spi(void *p_v, unsigned int offset, unsigned char *data, unsigned int size) { int i; fstore_t *p_fs = (fstore_t *)p_v; for (i = 0; i < size; ++i) { data[i] = 0; if (bspi_read(0,p_fs->read_base + offset + i,&(data[i])) != b_ok) { BDBG_MSG(("%s:%d(0x%08x,0x%02x,%d)\n",__FUNCTION__,__LINE__,offset+i,data[i],1 )); return berr_not_supported; } } return b_ok; } #endif /* Summary: Calculate 32 bit checksum */ #define TS_READ_32( buf ) ((uint32_t)((buf)[0]<<24|(buf)[1]<<16|(buf)[2]<<8|(buf)[3])) static inline unsigned int fstore_checksum_flash(fstore_t *p_fs, unsigned int offset, unsigned int len) { unsigned int checksum = 0; unsigned int val; unsigned int idx; BDBG_MSG(("Calc checksum for array @ 0x%08x, %d bytes",offset,len )); for (idx = 0; idx < len/sizeof(unsigned int); ++idx) { if (p_fs->read(p_fs, offset + (idx * 4),(unsigned char*) &val, 4) != b_ok) return 0; checksum += val; } BDBG_MSG(("0x%08x\n",checksum )); return checksum; } /* Summary: Erase the flash at the given offset. Offset is in bytes but must be aligned to a word boundary. Size is in bytes but must be sector aligned. It will erase all data in sector even if size is less than a sector in length. */ bresult fstore_erase_spi(void *p_v, unsigned int offset, unsigned int size) { fstore_t *p_fs = (fstore_t *)p_v; int i,scnt; bresult result = b_ok; scnt = size/p_fs->sector_size; if (size % p_fs->sector_size) scnt++; BDBG_MSG(("%s %d sectors\n",__FUNCTION__,scnt )); #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) mspi_disable_bspi(); #endif for (i = 0; i < scnt; ++i) { BDBG_MSG(("%s sector %d of %d\n",__FUNCTION__,i,scnt )); /* Erase the header sector */ result = bspi_sector_erase(0,p_fs->write_base + offset + (i * p_fs->sector_size)); if (b_ok != result) break; } #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) mspi_enable_bspi(); #endif if (b_ok == result) BDBG_MSG(("%s done\n",__FUNCTION__)); else BDBG_ERR(("%s failed\n",__FUNCTION__)); return result; } /* Summary: Program the buffer into flash, flash must have been erased before calling this function. Offset and size are in bytes but must be aligned to word boundries. */ bresult fstore_prog_spi(void *p_v, unsigned int offset,void *buffer, unsigned int size) { int i,towrite,j = 0; unsigned char *data_buf = (unsigned char*)buffer; fstore_t *p_fs = (fstore_t *)p_v; bresult result; BDBG_MSG(("%s(0x%08x,%d)\n",__FUNCTION__, offset,size)); #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) mspi_disable_bspi(); #endif for (i = 0; i < size; i += towrite) { if (i + p_fs->block_size >= size) { towrite = size - i; BDBG_MSG(("%s:%d(%d, %d, %d, %d) \n",__FUNCTION__,__LINE__,i,p_fs->block_size,size,towrite)); } else { towrite = p_fs->block_size; } #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) /* to prevent address cross the page boundary of 256 bytes */ towrite = towrite <= (256 - (i&0xFF)) ? towrite : (256 - (i&0xFF)); #endif if ((result = bspi_page_program(0,p_fs->write_base + offset + i,&data_buf[i],towrite)) != b_ok) { BDBG_ERR(("page program failed at %d \n",i,result)); #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) mspi_enable_bspi(); #endif return result; } #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) if ((i % 4096) == 0) #else if ((i % 512) == 0) #endif { //bos_sleep(1); if (0 == (j++ % 2)) printf(("+\n")); else printf(("-\n")); } } #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) mspi_enable_bspi(); /* just verify first 4M */ if (offset > 0x00400000) return b_ok; if ((offset + size) > 0x00400000) size = (0x00400000 - offset); #endif #ifdef FSTORE_VALIDATE for (i = 0; i < size; ++i) { unsigned char val; val = 0; if (bspi_read(0,p_fs->read_base + offset + i,&val) != b_ok) { BDBG_ERR(("Read check failed at %d \n",i)); break; } if (val != data_buf[i]) { BDBG_ERR(("Write failed at %d (0x%02x(0x%08x) != 0x%02x)...\n",i,val,(p_fs->read_base + offset + i),data_buf[i])); } } BDBG_ERR(("verify - done\n")); #endif return b_ok; } /* Summary: Initialize MSPI */ static void mspi_init() { unsigned int lval; #if (BCHP_CHIP == 3560) lval = ReadReg32( BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5); lval &= ~(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_50_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_51_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_52_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_53_MASK); lval |= (1UL << BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_50_SHIFT) | (1UL << BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_51_SHIFT) | (1UL << BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_52_SHIFT) | (1UL << BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5_gpio_53_SHIFT); WriteReg32(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_5, lval); #elif (BCHP_CHIP == 3543) lval = ReadReg32( BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0); lval &= ~(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_ssb_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_miso_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_mosi_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_sck_MASK); WriteReg32(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0, lval); #elif (BCHP_CHIP == 7002) lval = ReadReg32( BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0); lval &= ~(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_ssb_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_miso_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_mosi_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_m_sck_MASK); WriteReg32(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0, lval); /* clear write protect on 7003 board */ lval = ReadReg32(BCHP_GIO_IODIR_LO); lval &= 0x7fffffff; WriteReg32(BCHP_GIO_IODIR_LO, lval); lval = ReadReg32(BCHP_GIO_DATA_LO); lval |= 0x80000000; WriteReg32(BCHP_GIO_DATA_LO, lval); #elif (BCHP_CHIP == 7550) lval = ReadReg32(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0); lval &= ~(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_s_ssb_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_spi_s_miso_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_sf_sck_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_sf_mosi_MASK | BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0_sf_miso_MASK); WriteReg32(BCHP_SUN_TOP_CTRL_PIN_MUX_CTRL_0, lval); #endif } /* Summary: Detect the flash type and initialze the fstore structure. */ bresult fstore_init(fstore_t *p_fs) { fs_flash_type_t ftype = eFS_SP25_BSPI; /* hard code for 93560 and old Aonvision */ mspi_init(); #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) /* check strap for boot rom */ if (0 == (ReadReg32(BCHP_SUN_TOP_CTRL_STRAP_VALUE_0) & BCHP_SUN_TOP_CTRL_STRAP_VALUE_0_strap_boot_config_MASK)) { /* if 32K security code is the beginning 32 K part of bootloader, if not then it will be 0xb8c08000 */ /*TODO verify */ s_fstore[ftype].read_base = 0xb8c00000; } #endif memcpy(p_fs,&(s_fstore[ftype]), sizeof(fstore_t)); BDBG_ERR(("%s(type = %d)\n",__FUNCTION__,ftype )); bspi_identify(); BDBG_SetModuleLevel("fstore",BDBG_eTrace); // BDBG_SetModuleLevel("fstore",BDBG_eWrn); return b_ok; } /* Summary: Get the pointer to the flash type */ fstore_t *fstore_get_flash_info(void) { fs_flash_type_t ftype = eFS_SP25_BSPI; /* hard code for 93560 and old Aonvision */ return (fstore_t *)&s_fstore[ftype]; } /* Summary: Get the fstore record for type */ static bresult fstore_get_record(fstore_t *p_fs, fstore_data_type_t type, fstore_record_t *p_record) { unsigned int csum; bresult result; if ((result = p_fs->read(p_fs, p_fs->offset[type], (unsigned char*) p_record,sizeof(fstore_record_t))) != b_ok) return result; BDBG_MSG(("p_record->version = 0x%04x",p_record->version )); BDBG_MSG(("p_record->signature = 0x%04x",p_record->valid )); BDBG_MSG(("p_record->length = %d",p_record->length )); BDBG_MSG(("p_record->checksum = 0x%08x",p_record->checksum )); /* validate header */ if ((p_record->version != FSTORE_VERSION) || (p_record->valid != FSTORE_VALID) || (p_record->length == 0) || (p_record->length > p_fs->max_size)) { BDBG_WRN(("Invalid record (0x%04x,0x%04x)\n",p_record->version,p_record->valid )); return berr_not_available; } /* Validate checksum */ if ((csum = fstore_checksum_flash(p_fs, p_fs->offset[type] + sizeof(fstore_record_t), p_record->length)) != p_record->checksum) { BDBG_WRN(("Invalid record checksum (0x%08x != 0x%08x)\n",p_record->checksum,csum )); return berr_not_available; } return b_ok; } /* Summary: Update the contents of flash. Length is in bytes */ bresult fstore_update(fstore_t *p_fs, fstore_data_type_t type, void *data, unsigned int length) { bresult result = berr_not_supported; fstore_record_t record; BDBG_MSG(("fstore_update(%d,%d)\n", type,length)); bos_sleep(100); if (fstore_get_record(p_fs,type,&record) != b_ok) { BDBG_MSG(("Create new record...\n")); record.version = FSTORE_VERSION; record.valid = FSTORE_VALID; } record.length = length; record.checksum = fstore_checksum(data,length); BDBG_MSG(("record %d\n", type)); BDBG_MSG(("record.version 0x%04x\n", record.version)); BDBG_MSG(("record.valid 0x%04x\n", record.valid)); BDBG_MSG(("record.offset 0x%08x\n", p_fs->offset[type])); BDBG_MSG(("record.length %d\n", record.length)); BDBG_MSG(("record.checksum 0x%08x\n", record.checksum)); #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) /* only APP_DATA is used for this function */ if ((eFS_APP_DATA == type) && ((length + sizeof(fstore_record_t) > p_fs->max_size))) #else if ((p_fs->offset[type] + length + sizeof(fstore_record_t)) > p_fs->max_size) #endif { BDBG_ERR(("Invalid record length %d, offset = 0x%08x, maximum = 0x%08x\n",length,p_fs->offset[type],p_fs->max_size)); return result; } if (p_fs->erase(p_fs,p_fs->offset[type],length + sizeof(fstore_record_t)) != b_ok) { BDBG_ERR(("fstore_update erase failed\n")); return result; } bos_sleep(100); if (p_fs->program(p_fs,p_fs->offset[type],&record,sizeof(fstore_record_t)) != b_ok) { BDBG_ERR(("fstore_update program record failed\n")); return result; } bos_sleep(100); if (p_fs->program(p_fs,p_fs->offset[type] + sizeof(fstore_record_t),data,length) != b_ok) { BDBG_ERR(("fstore_update program failed\n")); return result; } bos_sleep(100); result = b_ok; return result; } /* Summary: Get the stored data for type. Returns b_ok on success. */ bresult fstore_get(fstore_t *p_fs, fstore_data_type_t type, void **data, unsigned int *length) { bresult result = berr_not_supported; fstore_record_t record; BDBG_MSG(("fstore_get (%d)\n", type)); *data = NULL; *length = 0; if ((result = fstore_get_record(p_fs,type,&record)) != b_ok) return result; BDBG_MSG(("record %d\n",type)); BDBG_MSG(("record.version 0x%08x\n", record.version)); BDBG_MSG(("record.length %d\n", record.length)); BDBG_MSG(("record.checksum 0x%08x\n", record.checksum)); #ifdef BCM_DEBUG /* TEMPORARY HACK TO TEST MSPI NVM ACCESS UNTIL WE HAVE MEMORY MAPPED BSPI */ if (p_fs->read_base == 0x00000000) { BDBG_MSG(("MEMORY LEAK!!!!! MSPI STORAGE ONLY FOR TESTING NVM %d\n",type)); *data = malloc(record.length); if (*data) { if ((result = p_fs->read(p_fs, p_fs->offset[type] + sizeof(fstore_record_t), *data,record.length)) != b_ok) return result; } } else #endif { #if (BCHP_CHIP==7550) ||(BCHP_CHIP==7552) *data = (void*)fstore_get_read_addr(p_fs, type, sizeof(fstore_record_t)); *data += sizeof(fstore_record_t); #else *data = (void*)(p_fs->read_base + p_fs->offset[type] + sizeof(fstore_record_t)); #endif *length = record.length; } return result; } /* Summary: Perform a test to validate the fstore module. */ #ifdef BCM_FSTORE_TEST void fstore_write_pattern(unsigned int * data_ptr, unsigned int len, unsigned int pattern) { int i; BDBG_MSG(("Write pattern 0x%08x, %d words...\n",pattern,len/sizeof(unsigned int))); for (i = 0; i < len/sizeof(unsigned int); i++) { data_ptr[i] = pattern; } } bresult fstore_test(fstore_t *p_fs,int reserved) { bresult result = berr_not_supported; unsigned int len = sizeof(fstore_record_t); void *data_ptr; unsigned char* get_ptr; unsigned int get_len; BDBG_SetModuleLevel("fstore",BDBG_eTrace); //memcpy(p_fs,&(s_fstore[eFS_SP25_SPI]), sizeof(fstore_t)); //memcpy(p_fs,&(s_fstore[eFS_MX29_EBI]), sizeof(fstore_t)); BDBG_ERR(("Setup for testing flash\n")); BDBG_ERR(("read_base = 0x%08x\n",p_fs->read_base)); /* Read base address of device (read/write base to support BSPI on 3543 */ BDBG_ERR(("write_base = 0x%08x\n",p_fs->write_base)); /* Write base address of device */ BDBG_ERR(("offsets = %d,%d,%d\n",p_fs->offset[0],p_fs->offset[1],p_fs->offset[2])); BDBG_ERR(("sector_size = %d\n", p_fs->sector_size)); /* Sector size in bytes */ BDBG_ERR(("block_size = %d\n", p_fs->block_size)); /* Block size in bytes */ BDBG_ERR(("max_size = %d", p_fs->max_size)); /* Block size in bytes */ BDBG_ERR(("read = 0x%08x\n",p_fs->read)); BDBG_ERR(("erase = 0x%08x\n",p_fs->erase)); BDBG_ERR(("program = 0x%08x\n",p_fs->program)); BDBG_ERR(("Update eFS_APP_DATA...\n")); len = (64 * 1024) - sizeof(fstore_record_t); if ((data_ptr = malloc(len)) == NULL) { BDBG_ERR(("Could not allocate memory for test %d\n",len)); return result; } BDBG_ERR(("Write pattern(0x%08x,%d)\n",data_ptr,len)); fstore_write_pattern(data_ptr,len,0xDEAD0ACE); BDBG_ERR(("Update1 eFS_APP_DATA...\n")); if ((result = fstore_update(p_fs,eFS_APP_DATA, data_ptr,len)) != b_ok) { BDBG_ERR(("Update eFS_APP_DATA failed %d\n",result)); return result; } if ((result = fstore_get(p_fs,eFS_APP_DATA, (void**)&get_ptr,&get_len)) != b_ok) { BDBG_ERR(("Get eFS_APP_DATA failed %d\n",result)); return result; } BDBG_ERR(("Update2 eFS_APP_DATA...\n")); if ((result = fstore_update(p_fs,eFS_APP_DATA, data_ptr,len)) != b_ok) { BDBG_ERR(("Update eFS_APP_DATA failed %d\n",result)); return result; } if ((result = fstore_get(p_fs,eFS_APP_DATA, (void**)&get_ptr,&get_len)) != b_ok) { BDBG_ERR(("Get eFS_APP_DATA 2 failed %d\n",result)); return result; } free(data_ptr); // BDBG_SetModuleLevel("fstore",BDBG_eWrn); return b_ok; } #endif