#include <stdio.h>
#include <flash/cfi.h>
#include <flash/intel.h>
+#include <flash/jedec.h>
#include <unistd.h>
#include <flash.h>
static int dbg = 0;
+static int amd_flash_erase_( cfi_array_t *cfi_array, uint32_t adr, int eraseall );
static int amd_flash_erase_all( cfi_array_t *cfi_array );
static int amd_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr );
static int amd_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr );
* that do address alignment themselves, such as the Samsung S3C4510B. The bus
* driver has to deal with this. - kawk 2008-01 */
-static int
+static inline int
amd_flash_address_shift( cfi_array_t *cfi_array )
{
if(cfi_array->bus_width == 4) return 2;
if(cfi_array->bus_width != 1) return 0;
return (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_AMD_SCS);
}
+
+
+#define MANID_DEVID(manid, devid) ((manid) << 16 | ((devid) & 0xff))
+
+static int
+amd_flash_autodetect_am29lv400b( cfi_array_t *cfi_array )
+{
+ uint32_t manid_devid;
+
+ if (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code != CFI_VENDOR_AMD_SCS)
+ return 0;
+
+ manid_devid = cfi_array->cfi_chips[0]->cfi.identification_string._urjtag_manid_devid;
+ return ((manid_devid == MANID_DEVID(MANUFACTURER_AMD, FLASHDEVICE_AM29LV400BT)) ||
+ (manid_devid == MANID_DEVID(MANUFACTURER_AMD, FLASHDEVICE_AM29LV400BB)));
+}
+
+static int
+amd_flash_autodetect_am29lv081b( cfi_array_t *cfi_array )
+{
+ uint32_t manid_devid;
+
+ if (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code != CFI_VENDOR_AMD_SCS ||
+ cfi_array->bus_width != 1) return 0;
+
+ manid_devid = cfi_array->cfi_chips[0]->cfi.identification_string._urjtag_manid_devid;
+ return (manid_devid == MANID_DEVID(MANUFACTURER_AMD, FLASHDEVICE_AM29LV081B));
+}
+
/*
* check device status
* 1/true PASS
}
static int
-amd_flash_erase_all( cfi_array_t *cfi_array )
-{
- printf("Error: not implemented.");
- return FLASH_ERROR_UNKNOWN;
-}
-
-static int
-amd_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr )
+amd_flash_erase_( cfi_array_t *cfi_array, uint32_t adr, int eraseall )
{
bus_t *bus = cfi_array->bus;
int o = amd_flash_address_shift( cfi_array );
- printf("flash_erase_block 0x%08X\n", adr);
-
/* printf("protected: %d\n", amdisprotected(ps, cfi_array, adr)); */
bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29, sector erase */
bus_write( bus, cfi_array->address + (0x0555 << o), 0x00800080 );
bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa );
bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 );
- bus_write( bus, adr, 0x00300030 );
+ if (eraseall) {
+ bus_write( bus, cfi_array->address + (0x0555 << o), 0x00100010 ); /* Chip erase */
+ } else {
+ bus_write( bus, adr, 0x00300030 ); /* Sector erase */
+ }
if (amdstatus( cfi_array, adr, 0xffff )) {
printf( "flash_erase_block 0x%08X DONE\n", adr );
}
static int
+amd_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr )
+{
+ printf("flash_erase_block 0x%08X\n", adr);
+ return amd_flash_erase_( cfi_array, adr, 0 /* false */ );
+}
+
+static int
+amd_flash_erase_all( cfi_array_t *cfi_array )
+{
+ uint32_t adr;
+
+ adr = cfi_array->address;
+ printf("flash_erase_all 0x%08X\n", adr);
+
+ return amd_flash_erase_( cfi_array, adr, 1 /* true */ );
+}
+
+static int
amd_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr )
{
printf( "flash_unlock_block 0x%08X IGNORE\n", adr );
}
static int
+amd_flash_program_unbuffered( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count )
+{
+ cfi_query_structure_t *cfi = &(cfi_array->cfi_chips[0]->cfi);
+ int max_bytes_write = cfi->device_geometry.max_bytes_write;
+
+ if (max_bytes_write > 1) {
+ /* you can get more speed if you write a bufferd driver. */
+ }
+
+ /* unroll buffer to single writes */
+ int idx;
+
+ for (idx = 0; idx < count; idx++) {
+ int status = amd_flash_program_single( cfi_array, adr, buffer[idx] );
+ if (status)
+ return status;
+ adr += cfi_array->bus_width;
+ }
+
+ return 0;
+}
+
+static int
amd_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count )
{
/* Single byte programming is forced for 32 bit (2x16) flash configuration.
amd_flash_program,
amd_flash_read_array,
};
+
+flash_driver_t amd_am29lv400b_flash_driver = {
+ 1, /* or 2. buswidth but no used. */
+ N_("AMD/Fujitsu Standard Command Set"),
+ N_("supported: AMD 29LV400B; 1x8 Bit, 1x16 Bit"),
+ amd_flash_autodetect_am29lv400b,
+ amd_flash_print_info,
+ amd_flash_erase_all,
+ amd_flash_erase_block,
+ amd_flash_unlock_block,
+ amd_flash_program_unbuffered,
+ amd_flash_read_array,
+};
+
+flash_driver_t amd_am29lv081b_flash_driver = {
+ 1, /* buswidth */
+ N_("AMD/Fujitsu Standard Command Set"),
+ N_("supported: AMD 29LV081B; 1x8 Bit"),
+ amd_flash_autodetect_am29lv081b,
+ amd_flash_print_info,
+ amd_flash_erase_all,
+ amd_flash_erase_block,
+ amd_flash_unlock_block,
+ amd_flash_program_unbuffered,
+ amd_flash_read_array,
+};
+
* Documentation:
* [1] Spansion, Am29F040B Data Sheet
* [2] Spansion, Am29LV040B Data Sheet
- * [3] Spansion, Am29LV081B Data Sheet
- * [4] Spansion, Am29LV400D Data Sheet
*/
#include "sysdep.h"
#define AMD_UNDEFINED_MODE
#define FLASH_ERASE_ERROR -5
-#define FLASH_ERASE_SUCCESS 0
+#define ERASE_FLASH_SUCCESS 1
-#define AMD_UNKNOWN_DEVICE 0
-#define AMD_29xx040B 1
-#define AMD_29xx081B (0x38)
-#define AMD_29LV400B_TOP (0xB9)
-#define AMD_29LV400B_BOTTOM (0xBA)
+#define AMD_29xx040B 1
#define AMD_BYPASS_UNLOCK_ALGORITHM 1
#define AMD_STANDARD_WRITE_ALGORITHM 0
unsigned short algorithm;
unsigned short unlock_bypass;
}
- var_forced_detection = { AMD_UNKNOWN_DEVICE, 0, 0};
+var_forced_detection;
int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array );
static int amd_29xx040_autodetect( cfi_array_t *cfi_array );
static int amd_29xx040_status( bus_t *bus, uint32_t adr, unsigned short data );
static void amd_29xx040_print_info( cfi_array_t *cfi_array );
static void amd_29xx040_read_array( cfi_array_t *cfi_array );
-static int _amd_29xx040_erase( cfi_array_t *cfi_array, uint32_t adr, int eraseall );
+static int amd_29xx040_erase_( cfi_array_t *cfi_array, uint32_t adr, int eraseall );
static int amd_29xx040_erase_all( cfi_array_t *cfi_array );
static int amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr );
static int amd_29xx040_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data );
static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t *buffer, int count );
static int amd_29xx040_unlock_block( cfi_array_t *cfi_array, uint32_t adr );
-static void amd_29xx040b_init_cfi( cfi_query_structure_t *cfi )
-{
- cfi_erase_block_region_t *region;
-
- region = malloc( sizeof (cfi_erase_block_region_t) );
- cfi->device_geometry.erase_block_regions = region;
- if (region == NULL) {
- return;
- }
- cfi->device_geometry.number_of_erase_regions = 1;
- region->erase_block_size = 64 * 1024;
- region->number_of_erase_blocks = 8;
-}
-
-static void amd_29xx081b_init_cfi( cfi_query_structure_t *cfi )
-{
- cfi_erase_block_region_t *region;
-
- region = malloc( sizeof (cfi_erase_block_region_t) );
- cfi->device_geometry.erase_block_regions = region;
- if (region == NULL) {
- return;
- }
- cfi->device_geometry.number_of_erase_regions = 1;
- region->erase_block_size = 64 * 1024;
- region->number_of_erase_blocks = 16;
-}
-
-static void amd_29lv400b_top_init_cfi( cfi_query_structure_t *cfi )
-{
- cfi_erase_block_region_t *region;
- const int region_number = 4;
- region = malloc( sizeof (cfi_erase_block_region_t) * region_number);
- cfi->device_geometry.erase_block_regions = region;
- if (region == NULL) {
- return;
- }
- cfi->device_geometry.number_of_erase_regions = region_number;
- region[0].erase_block_size = 64 * 1024;
- region[0].number_of_erase_blocks = 8;
- region[1].erase_block_size = 32 * 1024;
- region[1].number_of_erase_blocks = 1;
- region[2].erase_block_size = 8 * 1024;
- region[2].number_of_erase_blocks = 2;
- region[3].erase_block_size = 16 * 1024;
- region[3].number_of_erase_blocks = 1;
-}
-
-static void amd_29lv400b_bottom_init_cfi( cfi_query_structure_t *cfi )
-{
- cfi_erase_block_region_t *region;
- const int region_number = 4;
- region = malloc( sizeof (cfi_erase_block_region_t) * region_number);
- cfi->device_geometry.erase_block_regions = region;
- if (region == NULL) {
- return;
- }
- cfi->device_geometry.number_of_erase_regions = region_number;
- region[0].erase_block_size = 16 * 1024;
- region[0].number_of_erase_blocks = 1;
- region[1].erase_block_size = 8 * 1024;
- region[1].number_of_erase_blocks = 2;
- region[2].erase_block_size = 32 * 1024;
- region[2].number_of_erase_blocks = 1;
- region[3].erase_block_size = 64 * 1024;
- region[3].number_of_erase_blocks = 8;
-}
-
int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array )
{
int mid;
if (mid != 0x01)
return -1;
- switch(did & 0xff)
+ switch(did)
{
- case 0xB9:
- var_forced_detection.flash = AMD_29LV400B_TOP;
- break;
- case 0xBA:
- var_forced_detection.flash = AMD_29LV400B_BOTTOM;
- break;
case 0xA4:
var_forced_detection.flash = AMD_29xx040B;
break;
var_forced_detection.flash = AMD_29xx040B;
var_forced_detection.algorithm = AMD_BYPASS_UNLOCK_ALGORITHM;
break;
- case 0x38:
- var_forced_detection.flash = AMD_29xx081B;
- break;
default:
break;
}
cfi->device_geometry.device_size = 512*1024;
cfi->device_geometry.device_interface = 0; // x 8
cfi->device_geometry.max_bytes_write = 32; //not used
- switch (var_forced_detection.flash) {
- case AMD_29xx040B:
- amd_29xx040b_init_cfi(cfi);
- break;
- case AMD_29xx081B:
- amd_29xx081b_init_cfi(cfi);
- break;
- case AMD_29LV400B_TOP:
- amd_29lv400b_top_init_cfi(cfi);
- break;
- case AMD_29LV400B_BOTTOM:
- amd_29lv400b_bottom_init_cfi(cfi);
- break;
- }
-
+ cfi->device_geometry.number_of_erase_regions = 1;
+ cfi->device_geometry.erase_block_regions =
+ malloc( cfi->device_geometry.number_of_erase_regions * sizeof (cfi_erase_block_region_t) );
if (!cfi->device_geometry.erase_block_regions)
- return -2; /* out of memory, or unsupported flash. */
+ return -2; /* out of memory */
+ cfi->device_geometry.erase_block_regions[0].erase_block_size = 64 * 1024;
+ cfi->device_geometry.erase_block_regions[0].number_of_erase_blocks = 8;
//Add other details for info
}
return 0;
static int amd_29xx040_autodetect( cfi_array_t *cfi_array )
{
- return (var_forced_detection.flash != AMD_UNKNOWN_DEVICE);
+ return(var_forced_detection.flash == AMD_29xx040B); //Non-CFI Am29xx040B flash
}
static int amd_29xx040_status( bus_t *bus, uint32_t adr, unsigned short data )
dq5mask = (1 << 5);
dq7bit = data & dq7mask;
- for (timeout = 0; timeout < 70000; timeout++) //typical sector erase time = 0.7 sec
+ for (timeout = 0; timeout < 1000; timeout++) //typical sector erase time = 0.7 sec
{
data1 = (unsigned short)(bus_read( bus, adr ) & 0xFF);
if((data1 & dq7mask) == dq7bit)
int mid, did, prot;
bus_t *bus = cfi_array->bus;
+
bus_write( bus, cfi_array->address + 0x0, 0xf0 );
bus_write( bus, cfi_array->address + 0x555, 0xaa );
bus_write( bus, cfi_array->address + 0x2AA, 0x55 );
}
printf( _("\n\tChip: ") );
switch (did) {
- case 0xB9:
- printf( "Am29LV400B\t-\t" );
- printf( _("Top Boot Block\n") );
- break;
- case 0xBA:
- printf( "Am29LV400B\t-\t" );
- printf( _("Bottom Boot Block\n") );
- break;
case 0xA4:
printf( "Am29C040B\t-\t" );
printf( _("5V Flash\n") );
printf( "Am29LV040B\t-\t" );
printf( _("3V Flash\n") );
break;
- case 0x38:
- printf( "Am29LV081B\t-\t" );
- printf( _("3V Flash\n") );
- break;
default:
printf ( _("Unknown (ID 0x%04x)"), did );
break;
-static int _amd_29xx040_erase( cfi_array_t *cfi_array, uint32_t adr, int eraseall )
+static int amd_29xx040_erase_( cfi_array_t *cfi_array, uint32_t adr, int eraseall )
{
bus_t *bus = cfi_array->bus;
+ printf("flash_erase_block 0x%08X\n", adr);
+
/* printf("protected: %d\n", amdisprotected(ps, adr)); */
if(var_forced_detection.unlock_bypass == AMD_BYPASS_UNLOCK_MODE)
bus_write( bus, cfi_array->address + 0x555, 0x80 );
bus_write( bus, cfi_array->address + 0x555, 0xaa );
bus_write( bus, cfi_array->address + 0x2AA, 0x55 );
- if (eraseall) {
+ if ( eraseall ) {
bus_write( bus, cfi_array->address + 0x555, 0x10 ); //Chip Erase
} else {
bus_write( bus, adr, 0x30 ); //Sector erase
if (amd_29xx040_status( bus, adr, 0xff )) {
printf( "flash_erase_block 0x%08X DONE\n", adr );
amd_29xx040_read_array( cfi_array ); /* AMD reset */
- return FLASH_ERASE_SUCCESS;
+ return ERASE_FLASH_SUCCESS;
}
printf( "flash_erase_block 0x%08X FAILED\n", adr );
/* Read Array */
return FLASH_ERASE_ERROR;
}
-static int amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr)
+static int
+amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr )
{
printf("flash_erase_block 0x%08X\n", adr);
- return _amd_29xx040_erase( cfi_array, adr, 0 /* false */ );
+ return amd_29xx040_erase_( cfi_array, adr, 0 /* false */ );
}
-static int amd_29xx040_erase_all( cfi_array_t *cfi_array)
+static int
+amd_29xx040_erase_all( cfi_array_t *cfi_array )
{
uint32_t adr;
+
adr = cfi_array->address;
printf("flash_erase_all 0x%08X\n", adr);
- return _amd_29xx040_erase( cfi_array, adr, 1 /* true */ );
-}
-
+ return amd_29xx040_erase_( cfi_array, adr, 1 /* true */ );
+}
static int amd_29xx040_program_single( cfi_array_t *cfi_array, uint32_t adr, uint32_t data )
{
return 0;
}
+
flash_driver_t amd_29xx040_flash_driver = {
1, /* buswidth */
N_("AMD Standard Command Set"),
- N_("supported: AMD 29LV040B, 29C040B, 29LV081B, 29LV400B 1x8 Bit"),
+ N_("supported: AMD 29LV040B, 29C040B, 1x8 Bit"),
amd_29xx040_autodetect,
amd_29xx040_print_info,
amd_29xx040_erase_all,