📄 flash_nor.c
字号:
/********************************************************************** * flash_nor.c * * NOR device level operations * * This file implements wrappers for device specific functions on * NOR flash parts. * * Copyright (C) 2004-2006 Qualcomm, Inc. * **********************************************************************//*=========================================================================== EDIT HISTORY FOR MODULE This section contains comments describing changes made to the module. Notice that changes are listed in reverse chronological order. $Header: //depot/asic/msmshared/drivers/flash/MSM_FLASH.01.04/flash_nor.c#3 $ $DateTime: 2006/05/16 22:40:13 $ $Author: dhamimp $when who what, where, why-------- --- ----------------------------------------------------------2005-12-05 dp NOR Flash Driver Unification2006-01-27 dp Added Intel MLC support2004-10-21 drh Clean up warning message2004-07-20 drh Remove MSM6050 conditional. All MSM platforms support this code now.2004-02-23 drh Support partition tables. Move MSM specific device bases table to flash_msm.c.2004-02-21 drh Came from services/efs/fs_nor_device.c===========================================================================*//**************************************************************** * Include Files ***************************************************************/#include "flash.h"#include "flash_nor.h"#include "err.h"#include "comdef.h"#include "msg.h"#include "rex.h"#include "task.h"#include <string.h>uint16 fs_dev_max_sleep_counter=100;uint16 fs_dev_max_sleep_duration=50;#undef FSND_DEBUG/*lint -e613 -e668 upper layers already check for null pointers *///lint -e526 Don't warn about undefined extern symbols/**************************************************************** * Function Prototypes ***************************************************************/#ifdef FSND_DEBUGextern int printf(const char *fmt,...);#endif/* forward function prototype declarations */int fs_nor_device_bad_block_check(fs_device_t self, block_id block);int fs_nor_device_mark_block_bad(fs_device_t self, block_id block);char * fs_nor_device_name(fs_device_t self);uint32 fs_nor_device_block_count(fs_device_t self);uint32 fs_nor_device_block_size(fs_device_t self);uint32 fs_nor_device_page_size(fs_device_t self);int fs_nor_device_write_page (fs_device_t self, page_id page, void *data);int fs_nor_device_write_partial_page (fs_device_t self, page_id page, void *data, int offset, int length);boolean fsi_ram_probe (void);int fs_nor_device_erase_block (fs_device_t self, block_id block);void *fs_nor_device_read_ptr (fs_device_t self, page_id page);int fs_nor_device_read_page (fs_device_t self, page_id page, void *data);int fs_nor_device_is_page_erased (fs_device_t self, page_id page);int fs_nor_device_start_erase_block (fs_device_t self, block_id block);int fs_nor_device_suspend_erase (fs_device_t self);int fs_nor_device_resume_erase (fs_device_t self);int fs_nor_device_erase_block_status(fs_device_t self);void cache_mmu_disable(void);void cache_mmu_re_enable(void); /**************************************************************** * MACROS ***************************************************************//* On processors with CPU instruction cacheing, we must disable * cacheing during probe. These macros make the code much * cleaner due to the conditional nature of the operation. */#define CACHE_DISABLE() cache_mmu_disable()#define CACHE_REENABLE() cache_mmu_re_enable()/**************************************************************** * Global Data ***************************************************************/static fs_device_write_style_t fs_nor_device_get_write_style (fs_device_t dev);/* Array containing fs_device_data structure definitions for all the * nor devices currently supported */struct fs_device_data nor_devices_array[] = { { fs_nor_device_name, 0, /* Maker ID */ 0, /* Device ID */ fs_nor_device_block_count, fs_nor_device_block_size, fs_nor_device_page_size, 0, /* Total page size */ fs_nor_device_bad_block_check, fs_nor_device_mark_block_bad, fs_nor_device_write_page, fs_nor_device_erase_block, fs_nor_device_read_ptr, fs_nor_device_read_page, fs_nor_device_is_page_erased, fs_nor_device_write_partial_page, fs_nor_device_start_erase_block, fs_nor_device_suspend_erase, fs_nor_device_resume_erase, fs_nor_device_erase_block_status, 0, /* Is block erased */ 0, /* Read spare bytes */ 0, /* Read multiple pages */ 0, /* Copy page */ 0, /* Lock Unlock Locktight */ 0, /* open partition */ 0, /* partition table read */ 0, /* partition table write */ 0, /* set ECC state */ fs_nor_device_get_write_style, }};/* Make sure that if EFS1 is compiled in, we do not duplicate these *//* Device base address. */volatile word *fs_dev_base;/* Which flash component did we detect. */fsi_nor_device *nor_device = NULL;fsi_erase_state_type fsi_erase_state;/* Most components need an address to check status of, or continue an erase. */dword fsi_erase_location;static uint32 nv_byte_offset;static uint32 last_page_id;/**************************************************************** * Functions ***************************************************************//***********************************************************************FUNCTION fs_nor_device_probeDESCRIPTION This functions helps probe and identify the memory device to see if it is one of the known nor devices. For every nor device defnied in the array nor_devices_array the probe_device function is called until the device is successfully identified.DEPENDENCIES NoneRETURN VALUE fs_device_data structure pointer fs_device_t if the nor device was identified successfully else FS_NO_DEVICE **********************************************************************/fs_device_tfs_nor_device_probe (void){ int i = 0; uint32 block_count; uint32 pages_in_block; fs_device_t self; ProbeTbl_t prPtr; nor_device = NULL; last_page_id = 0; /* Cacheing of flash must be disabled during probe * or flash will look like RAM and no flash will * be found. */ CACHE_DISABLE(); /* Probe at each of the possible addresses for flash 0 * using the MSM specific table provided from flash_msm.c */ prPtr = probe_info_data_flash; while ( nor_device == NULL ) { fs_dev_base = prPtr->probe_addr; if (fsi_ram_probe() == FALSE) nor_device = prPtr->probe_fcn(fs_dev_base);#ifdef SHADOW_MODE else { extern const fsi_nor_device RAM_NOR; nor_device = (fsi_nor_device *)&RAM_NOR; }#endif i++; prPtr++; /* Do not go past the end of the array */ if ( i >= probe_info_size ) { break; } } if (nor_device == NULL) { CACHE_REENABLE(); return FS_NO_DEVICE; } /* Call device's configure function. On some flash parts, * this will unlock the sectors for programming, on others * it is merely a stub. */ if ((*nor_device->ops->configure) (nor_device, fs_dev_base) != FLASH_SUCCESS) { CACHE_REENABLE(); return FS_NO_DEVICE; } nv_byte_offset = (uint32)&fs_dev_base[(nor_device->efs_info.efs_boffset >> 1)];#ifdef FSND_DEBUG printf("\tnorprobe: Flash Base address 0x%x\n", FLASH_BASE); printf("\tnorprobe: fs_dev_base 0x%x\n", fs_dev_base); printf("\tnorprobe: NV byte offset 0x%x\n", nor_device->efs_info.efs_boffset); printf("\tnorprobe: NV byte size 0x%x\n", nor_device->efs_info.efs_bsize); printf("\tnorprobe: NV absolute start address 0x%x\n", nv_byte_offset); printf("\tnorprobe: %s device\n", (char *)nor_device->name);#endif self = (fs_device_t)&nor_devices_array[0]; block_count = self->block_count(self); pages_in_block = self->block_size(self); last_page_id = (block_count * pages_in_block) - 1; CACHE_REENABLE(); return self;} /* End of fs_nor_device_probe *//***********************************************************************FUNCTION fs_nor_device_write_pageDESCRIPTION This functions writes a page data into the given page on the deviceDEPENDENCIES NoneRETURN VALUE FS_DEVICE_DONE if write was successful else FS_DEVICE_FAIL**********************************************************************/intfs_nor_device_write_page (fs_device_t self, page_id page, void *data){ int length = self->page_size (self); //lint !e713 no loss of precision.#ifdef FSND_DEBUG printf("\twrite: page 0x%x\n", page);#endif return fs_nor_device_write_partial_page (self, page, data, 0, length);} /* End of fs_nor_device_write_page *//***********************************************************************FUNCTION fs_nor_device_erase_blockiDESCRIPTION This function erases the contents of the given block DEPENDENCIES NoneRETURN VALUE FS_DEVICE_DONE if erase was successful else FS_DEVICE_FAIL**********************************************************************/static intfs_nor_device_erase_blocki (uint32 block_addr){ flash_status status; uint16 sleepcounter=0; rex_timer_type fs_dev_tout_timer; rex_tcb_type * my_tcb; /* Determine if we have to check if an erase has terminated or not. */ switch (fsi_erase_state) { case FSI_READ_MODE: break; /* Easy. */ case FSI_ERASING: /* Must check to see if this erase is still running. */ ERR_FATAL ("not yet written 123", 0, 0, 0); break; case FSI_ERASE_SUSPENDED: MSG_MED ("flash_nor: Attempt to start erase while erase is suspended", 0, 0, 0); return FS_FAIL_S; } /* If we made it here, then the component is now sitting in read mode. Our offset is in bytes from the beginning of EFS, get a pointer to the real data. */ fsi_erase_location = (nor_device->efs_info.efs_boffset >> 1) + (block_addr >> 1); status = (*nor_device->ops->erase_start) (&fs_dev_base[(nor_device->efs_info.efs_boffset >> 1)], (dword)block_addr); if (status != FLASH_SUCCESS) return FS_DEVICE_FAIL; fsi_erase_state = FSI_ERASING; do { sleepcounter++; if(sleepcounter > fs_dev_max_sleep_counter) { my_tcb = rex_self(); rex_def_timer (&fs_dev_tout_timer, my_tcb, FS_OP_COMPLETE_SIG); rex_timed_wait (FS_OP_COMPLETE_SIG, &fs_dev_tout_timer, fs_dev_max_sleep_duration); sleepcounter=0; } status = (*nor_device->ops->erase_status)(&fs_dev_base[fsi_erase_location]); } while (status != FLASH_SUCCESS); fsi_erase_state = FSI_READ_MODE; return FS_DEVICE_DONE;} /* End of fs_nor_device_erase_block *//***********************************************************************FUNCTION fs_nor_device_erase_blockDESCRIPTION This function is a wrapper for the actual erase block and handles the special case of the last block, which is actually several blocks.DEPENDENCIES NoneRETURN VALUE FS_DEVICE_DONE if erase was successful else FS_DEVICE_FAIL**********************************************************************/intfs_nor_device_erase_block (fs_device_t self, block_id block){ int status; uint32 block_address; int block_size_shift; uint16 no_of_shifts = 1; uint32 block_count = self->block_count(self); /*uint32 last_block = block_count - 1; uint32 small_block_count; uint32 small_block_bytes; int i;*/ /* bail out early if block is invalid */ if (block >= block_count) { return FS_DEVICE_FAIL; } block_size_shift = self->block_size (self); while (block_size_shift != 2) { block_size_shift >>= 1; no_of_shifts++; } /* Set the block address */ block_address = block << (FS_NOR_PAGE_ADDR_BITS + no_of_shifts);#ifdef FSND_DEBUG printf("\terase: block address 0x%x\n", block_address); printf("\terase: absolute address 0x%x\n", (block_address + (nv_byte_offset)));#endif status = fs_nor_device_erase_blocki(block_address); if (status != FS_DEVICE_DONE) return FS_DEVICE_FAIL; /* special code for handling of erase of last block presently commented out to improve EFS2 performance */ /* Call the internal function that does erase and wait for each * block as necessary. Account for the fact that the last "block" * is really several blocks masquerading as one block to the * public interface */ /*if (block != last_block) { status = fs_nor_device_erase_blocki(block_address); if (status != FS_DEVICE_DONE) return FS_DEVICE_FAIL; } else { small_block_count = nor_device->info.small_block_count; small_block_bytes = nor_device->info.small_block_bytes; for (i=0; i<small_block_count; i++) { status = fs_nor_device_erase_blocki(block_address); if (status != FS_DEVICE_DONE) return FS_DEVICE_FAIL; block_address += small_block_bytes; } }*/ /* End of special code for handling of last block */ return FS_DEVICE_DONE;} /* End of fs_nor_device_erase_block */ /***********************************************************************FUNCTION fs_nor_device_is_page_erasedDESCRIPTION This function checks if every byte of a given page is erased DEPENDENCIES NoneRETURN VALUE TRUE if page is erased FALSE if page is not erased, or any error occurs during checking**********************************************************************/intfs_nor_device_is_page_erased (fs_device_t self, page_id page){ uint32 page_address; byte *rdptr; uint32 page_size = self->page_size (self); uint32 i; page_address = page << FS_NOR_PAGE_ADDR_BITS; /* Verify that the requested page is in range. */ if ((page_address + page_size) > (nor_device->efs_info.efs_bsize)) { return FALSE; } /* get the address to the beginning of NV into a byte pointer * and the add the page offset to it to come up with the * page address */ rdptr = (byte *) &fs_dev_base[(nor_device->efs_info.efs_boffset >> 1)]; rdptr += page_address;#ifdef FSND_DEBUG printf("\tis_page_erased: absolute address 0x%x\n", rdptr);#endif for (i=0; i<page_size; i++) { if (rdptr[i] != 0xFF) return FALSE; } return TRUE;} /* END fs_nor_device_is_page_erased *//***********************************************************************FUNCTION fs_nor_device_read_ptrDESCRIPTION This function returns an address pointer to a page.DEPENDENCIES NoneRETURN VALUE Pointer to the page beginningSIDE EFFECTS None**********************************************************************/void *fs_nor_device_read_ptr (fs_device_t self, page_id page)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -