📄 flash_nor_spansion.c
字号:
/* Sometimes, the parts don't return status correctly the first time. A normally completed erase should read with the value of 0xFFFF. If this isn't what we got, try to read the status register again. */ if (tmp != 0xFFFF) { retry_count++; if (retry_count < 5) goto retry; /* The device is not giving us meaningful status. This seems to * happen (rarely) once in a while. About the only thing to do * here, is start the erase back up again, and wait for it to * finish. */ *eraseaddr = 0x30; /* The bit toggling seems to break until the erase itself finish * The only way that gives us to determine when the erase is don * is that the value 0xFFFF will appear. This comes in about 5m * after the erase itself finishes. If something is really wron * and the erase doesn't ever finish, the dog will eventually ha * to kick in. */ do { tmp = FSI_AMD_PEEK (eraseaddr); } while (tmp != 0xFFFF); result = FLASH_SUCCESS; done = 1; break; } *eraseaddr = 0xF0; result = FLASH_SUCCESS; done = 1; break; } } return result;}/*===========================================================================FUNCTION FSI_SPANSION_RESUMEDESCRIPTION Resume a suspended erase.DEPENDENCIES The fsi_spansion_suspend must have sucessfully suspended the device.RETURN VALUE FLASH_SUCCESS - The erase has been resumed.SIDE EFFECTS None===========================================================================*/LOCAL flash_statusfsi_spansion_resume (flash_ptr_type eraseaddr){ /* Issue the resume command. */#ifdef FEATURE_EFS_AMD_SUSPEND_FETCH_BUG INTLOCK (); FSI_AMD_POKE (eraseaddr, 0x30); INTFREE ();#else *eraseaddr = 0x30;#endif clk_busy_wait(4); return FLASH_SUCCESS;}/* fsi_and_resume *//*===========================================================================FUNCTION FSI_SPANSION_CONFIGUREDESCRIPTION Do any necessary initializtion.DEPENDENCIES Must be done before any operations are carried out on the flash hardware.RETURN VALUE FLASH_SUCCESS - SuccessSIDE EFFECTS None===========================================================================*/LOCAL flash_statusfsi_spansion_configure (fsi_nor_device * nor_device, flash_ptr_type baseaddr){ word i; flash_status status; status = flash_geometry_init(nor_device, baseaddr); /* Initialize the erased value array for quick erase compares. */ for (i = 0; i < ERASE_VERIFY_BLK; i++) { erase_verify_buf[i] = (uint8)0xFF; } /* just a stub for devices that need no configuration */ return status;}/*===========================================================================FUNCTION FSI_SPANSION_WRITEDESCRIPTION Write a block of byte to Spansion flash part.DEPENDENCIES The device must not be in erasing state.RETURN VALUE FLASH_SUCCESS - If write completed normally FLASH_FAILURE - If write operation failed FLASH_TIMEOUT - If write operation timed out SIDE EFFECTS None===========================================================================*/LOCAL flash_statusfsi_spansion_write (byte *buffer, flash_ptr_type baseaddr, dword offset, dword count){ flash_status status = FLASH_SUCCESS; dword inbuff_offset=0; word num_to_copy, num_written = 0;#ifdef FLASH_CHECK dword size = count; byte *source = buffer;#endif /*----------------------------------------------------------------*/ /* Use the byte write */ if(count < SPANSION_BUFFER_WRITE_SIZE) { status = fsi_spansion_byte_write( buffer,baseaddr,offset,count); return status; } KICK_DOG_AND_CHECK_DATA(); /* Check for the offset is not at the buffer boundary */ inbuff_offset = offset % SPANSION_BUFFER_WRITE_SIZE; if(inbuff_offset) { status =fsi_spansion_byte_write( buffer,baseaddr,offset, (SPANSION_BUFFER_WRITE_SIZE -inbuff_offset)); num_written += (SPANSION_BUFFER_WRITE_SIZE -inbuff_offset); KICK_DOG_AND_CHECK_DATA(); } if(status == FLASH_SUCCESS) { while(num_written < count) { num_to_copy = MIN(count-num_written, SPANSION_BUFFER_WRITE_SIZE); if(num_to_copy < SPANSION_BUFFER_WRITE_SIZE) { status = fsi_spansion_byte_write( buffer+num_written,baseaddr,offset+ num_written,num_to_copy); } else { KICK_DOG_AND_CHECK_DATA(); status =fsi_spansion_buffer_write(buffer+num_written,baseaddr,offset+ num_written,num_to_copy); } num_written += num_to_copy; if(status != FLASH_SUCCESS) { return status; } } }#ifdef FLASH_CHECK { dword i; volatile byte *part_base = ((volatile byte *) baseaddr + offset); for (i = 0; i < size; i++) { if(part_base[i] != source[i]) ERR_FATAL("Write verify failed",0,0,0); if ((i % 16)==0) KICK_DOG_AND_CHECK_DATA(); } }#endif return status;}/* fsi_spansion_write *//*===========================================================================FUNCTION FSI_SPANSION_BUFFER_WRITEDESCRIPTION Write a block of bytes to an SPANSION part.DEPENDENCIES The device must not be in erasing state.RETURN VALUE FLASH_SUCCESS - If write completed normally FLASH_TIMEOUT - If write operation timed outSIDE EFFECTS None===========================================================================*/LOCAL flash_statusfsi_spansion_buffer_write (byte *buffer, flash_ptr_type baseaddr, dword offset, dword count){ flash_status status = FLASH_SUCCESS; dword word_addr; byte *buf_ptr = buffer; dword wcount,word_val=0,i; volatile byte *part_base; volatile word *wptr,*current_wptr=0; byte timeout_cnt=0; volatile word tmp; /*----------------------------------------------------------------*/ KICK_DOG_AND_CHECK_DATA(); if(!count){ return FLASH_SUCCESS; } if(offset) { word_addr = offset/2; } else { word_addr = offset; } part_base = ((volatile byte *) baseaddr + offset); /* Do word operations. */ wptr = (volatile word *) part_base; /*======================================================== * * Write buffer programming command sequences * * * 1. Issue the unlock command 1 Addr: 0x555 Data: 0x00AA * * 2. Issue the unlock command 2 Addr: 0x2AA Data: 0x0055 * * 3. Write the buffer load * Addr: starting address Data: 0x0025 * * 4. Specify the number of program Location * Addr: Starting addresss Data: word len * * 5. Load 1st data word * Addr: Starting Address Data: program data * * 6. Load next data word * Addr: Write buffer location Data: program data * * 7. ...... * * 8. Load last data word * Addr: Write buffer location Data: program data * * 9. Write buffer program confirm. This command must follow the last * write buffer location loaded, or the operation will ABORT. * Addr: Sector Address Data: 0x0029 * *==================================================================*/ /* Commands to unlock the device */ *(baseaddr + 0x0555L) = 0x00AA; *(baseaddr + 0x02AAL) = 0x0055; /* Command to do the buffer write */ *(baseaddr + word_addr) = 0x0025; /* Load the len of the buffer to the starting address */ wcount = (count/2) -1; *(baseaddr + word_addr) = wcount; /* Write to the buffer */ for(i=0;i<(count/2);i++) { /* Put together the next word to write to Flash. */ word_val = (buf_ptr[1] << 8) | buf_ptr[0]; *wptr = word_val; //lint !e734 will never exceed 2 bytes current_wptr = wptr; wptr++; buf_ptr+=2; } /* Write buffer program confirm */ *current_wptr = 0x29; //lint !e794 this pointer will have ptr assigned clk_busy_wait(4); /* Wait for the write. */ while (1) //lint !e716 while(1) has break and return.. { tmp = *current_wptr; //lint !e794 current_wptr will have ptr assigned /* Exit when finished. */ if ((tmp & FS_AMD_DQ7) != (word_val & FS_AMD_DQ7)) { if ((tmp & FS_AMD_DQ5) != 0) { timeout_cnt++; if(timeout_cnt >= SPANSION_MAX_TIMEOUT_CNT) { *(baseaddr + 0x555) = 0xAA; *(baseaddr + 0x2AA) = 0x55; *(baseaddr + 0x555) = 0xF0; return FLASH_TIMEOUT; } } } else { break; } }/* while */ KICK_DOG_AND_CHECK_DATA(); return status;}/*===========================================================================FUNCTION FSI_SPANSION_BYTE_WRITEDESCRIPTION Write a block of bytes to an SPANSION part.DEPENDENCIES The fs_dev_init must have been called. The device must not be in erasing state.RETURN VALUE FLASH_SUCCESS - If write completed normally FLASH_TIMEOUT - If write operation timed outSIDE EFFECTS None===========================================================================*/LOCAL flash_statusfsi_spansion_byte_write (byte *buffer, flash_ptr_type baseaddr, dword offset, dword count){ volatile byte *part_base, *bptr; volatile word *wptr, *check_ptr; word value; word tmp; byte timeout_cnt=0; /*---------------------------------------------------------------*/ KICK_DOG_AND_CHECK_DATA(); /* Base address of operation. */ part_base = ((volatile byte *) baseaddr + offset); check_ptr = (volatile word *) ((dword) part_base & ~1); (void)check_ptr; // is this pointer and assignment above really needed...??!! /* Determine if the block is aligned or not. */ if (((dword) buffer & 1) == 0 && (offset & 1) == 0 && (count & 1) == 0) { /* Do word operations. */ wptr = (volatile word *) part_base; /* Since we're already aligned, we could compare with 0, but the 1 will be needed for future optimizations. */ while (count > 1) { value = *((word *) buffer); *(baseaddr + 0x555) = 0xAA; *(baseaddr + 0x2AA) = 0x55; *(baseaddr + 0x555) = 0xA0; *wptr = value; /* Wait 4 micro second before check for status. Per Spansion recommendation */ clk_busy_wait(4); /* Wait for the write. */ while (1) //lint !e716 while(1) has break and return.. { tmp = *wptr; /* Exit when finished. */ if ((tmp & FS_AMD_DQ7) != (value & FS_AMD_DQ7)) { if ((tmp & FS_AMD_DQ5) != 0) { timeout_cnt++; if(timeout_cnt >= SPANSION_MAX_TIMEOUT_CNT) { *wptr = 0xF0; return FLASH_TIMEOUT; } } } else { break; } } buffer += 2; wptr += 1; count -= 2; } } else { /* Do byte operations. */ bptr = part_base; while (count > 0) { value = *buffer; /* The command accesses need to be word oriented or the data will be placed on the wrong data lines. Compute a word pointer from the byte pointer that is always at an even address. */ wptr = ((volatile word *) ((dword) bptr & ~1)); /* Get old value. */ tmp = *wptr; *(baseaddr + 0x555) = 0xAA; *(baseaddr + 0x2AA) = 0x55; *(baseaddr + 0x555) = 0xA0; /* Assumes little endian. */ if (((dword) bptr & 1) == 0) value = tmp & (value | 0xFF00); else value = tmp & ((value << 8) | 0x00FF); *wptr = value; /* Wait 4 micro second before check for status. Per Spansion recommendation */ clk_busy_wait(4); /* Wait for the write. */ while (1) //lint !e716 while(1) has break and return.. { tmp = *wptr; /* Exit when finished. */ if ((tmp & FS_AMD_DQ7) != (value & FS_AMD_DQ7)) { if ((tmp & FS_AMD_DQ5) != 0) { timeout_cnt++; if(timeout_cnt >= SPANSION_MAX_TIMEOUT_CNT) { *(baseaddr + 0x0) = 0xF0; return FLASH_TIMEOUT; } } } else { break; } } buffer += 1; bptr += 1; count -= 1; } } KICK_DOG_AND_CHECK_DATA(); return FLASH_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -