/*************************************************************************** * Copyright (c) 2003-2010, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * 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. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * * ***************************************************************************/ #include "bstd.h" #include "bkni.h" #include "bspi_flash.h" #include "bfds.h" #include "bstd.h" #include "bchp_sun_top_ctrl.h" #include "gist.h" #include "ramheader.h" extern int printf(const char *, ...); BDBG_MODULE(fds_spi); /* Register software module with debug interface */ #define BSPI_BASE 0xbfc00000 struct bfds_state { bool initialized; int open_cnt; unsigned int spi_base; bspi_t h_spi; b_mutex_t mutex; bspi_settings_t spi_settings; }; static struct bfds_state spi_if = {false,0,BSPI_BASE,NULL}; /*************************************************************************** Summary: Open block device. ****************************************************************************/ int bfds_open( bfds_handle * handle /* [out] return device handle */ ) { *handle = NULL; if (!spi_if.initialized) { bos_create_mutex(&spi_if.mutex); if (bspi_identify(&(spi_if.spi_settings)) != b_ok) { return BFDS_ERROR; } if (bspi_open(&(spi_if.h_spi),&(spi_if.spi_settings)) != b_ok) { return BFDS_ERROR; } spi_if.initialized = true; #if (BCHP_CHIP!=7552) /* check OTP boot rom bit */ if (!(BREG_Read32(GetREG(), BCHP_SUN_TOP_CTRL_OTP_OPTION_TEST_0) & BCHP_SUN_TOP_CTRL_OTP_OPTION_TEST_0_otp_option_boot_rom_enable_MASK)) { spi_if.spi_base = 0xbfc00000; } /* check strap for boot rom */ else if (0 != (BREG_Read32(GetREG(), BCHP_SUN_TOP_CTRL_STRAP_VALUE_0) & BCHP_SUN_TOP_CTRL_STRAP_VALUE_0_strap_boot_config_MASK)) { /* A0 use SPI flash, A1 use NAND */ spi_if.spi_base = 0xbfc00000; } /* Check for A1 chip revision where it always boots from internal ROM */ if ((BREG_Read32(GetREG(), BCHP_SUN_TOP_CTRL_PROD_REVISION) & 0x1)) { spi_if.spi_base = 0xb8c00000; } if ((BREG_Read32(GetREG(), BCHP_SUN_TOP_CTRL_OTP_OPTION_STATUS_0) & BCHP_SUN_TOP_CTRL_OTP_OPTION_STATUS_0_otp_option_boot_rom_enable_MASK)) { spi_if.spi_base = 0xb8c00000; } #else spi_if.spi_base = FLASH_BASE; #endif } if (bos_acquire_mutex(&spi_if.mutex,BOS_PEND_FOREVER) == b_ok) { *handle = &spi_if; spi_if.open_cnt++; bos_release_mutex(&spi_if.mutex); return BFDS_OK; } return BFDS_ERROR; } /*************************************************************************** Summary: Close block device. ****************************************************************************/ int bfds_close( bfds_handle handle /* [in] device handle */ ) { if (handle->initialized) { return BFDS_ERROR; } if (bos_acquire_mutex(&handle->mutex,BOS_PEND_FOREVER) == b_ok) { if (handle->open_cnt == 0) { bos_release_mutex(&handle->mutex); return BFDS_ERROR; } handle->open_cnt--; if (handle->open_cnt == 0) { bspi_close(handle->h_spi); handle->initialized = false; } bos_release_mutex(&handle->mutex); } return BFDS_OK; } /*************************************************************************** Summary: Read from device at offset. ****************************************************************************/ int bfds_read( bfds_handle handle, /* [in] device handle */ unsigned offset, /* [in] offset in bytes */ void * data, /* [out] buffer to copy data into at offset */ unsigned size /* [in] size of the buffer */ ) { int res; if (bos_acquire_mutex(&handle->mutex,BOS_PEND_FOREVER) != b_ok) return BFDS_ERROR; BKNI_Memcpy(data, (void*)(handle->spi_base + offset), size); res = BFDS_OK; bos_release_mutex(&handle->mutex); return res; } /*************************************************************************** Summary: Erase the sector/block at offset. ****************************************************************************/ int bfds_sector_erase( bfds_handle handle, /* [in] device handle */ unsigned offset /* [in] offset in bytes */ ) { int res; bresult bres; if (bos_acquire_mutex(&handle->mutex,BOS_PEND_FOREVER) != b_ok) return BFDS_ERROR; bres = bspi_sector_erase(handle->h_spi, offset); bspi_flush(); res = (b_ok == bres) ? BFDS_OK : BFDS_ERROR; bos_release_mutex(&handle->mutex); return res; } /*************************************************************************** Summary: Program the sector/block at offset. ****************************************************************************/ int bfds_page_program( bfds_handle handle, /* [in] device handle */ unsigned offset, /* [in] offset in bytes */ void * data, /* [in] buffer to program at offset */ unsigned size /* [in] size of the buffer */ ) { int res; bresult bres; if (bos_acquire_mutex(&handle->mutex,BOS_PEND_FOREVER) != b_ok) return BFDS_ERROR; bres = bspi_page_program(handle->h_spi, offset, data, size); res = (b_ok == bres) ? BFDS_OK : BFDS_ERROR; bos_release_mutex(&handle->mutex); return res; } /*************************************************************************** Summary: Retrieve parameters of flash device. ****************************************************************************/ int bfds_get_properties ( bfds_handle handle, /* [in] device handle */ bfds_properties * properties /* [out] details of flash device */ ) { int res; if(NULL == properties){ res = BFDS_ERROR; goto ExitFunc; } properties->flash_sector_size = handle->spi_settings.sector_size; properties->flash_page_size = handle->spi_settings.page_size; properties->flash_total_size = handle->spi_settings.total_size; res = BFDS_OK; ExitFunc: return res; }