[ 1901129 ] Detect AMD CFI primary vendor-specific extended query table

git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@1095 b68d4a1b-bc3d-0410-92ed-d4ac073336b7
master
Kolja Waschk 17 years ago
parent 6600fe1f01
commit 8db57a7945

@ -3,6 +3,38 @@
* src/bus/buses.c (bus_drivers): bf548_ezkit_bus.
* src/bus/buses.h: Declare bf548_ezkit_bus.
* include/flash/cfi.h (MAJOR_VERSION_OFFSET): New macro.
(MAJOR_VERSION_OFFSET): New macro.
(MINOR_VERSION_OFFSET): New macro.
(ADDRESS_SENSITIVE_UNLOCK_OFFSET): New macro.
(ERASE_SUSPEND_OFFSET): New macro.
(SECTOR_PROTECT_OFFSET): New macro.
(SECTOR_TEMPORARY_UNPROTECT_OFFSET): New macro.
(SECTOR_PROTECT_SCHEME_OFFSET): New macro.
(SIMULTANEOUS_OPERATION_OFFSET): New macro.
(BURST_MODE_TYPE_OFFSET): New macro.
(PAGE_MODE_TYPE_OFFSET): New macro.
(ACC_MIN_OFFSET): New macro.
(ACC_MAX_OFFSET): New macro.
(TOP_BOTTOM_SECTOR_FLAG_OFFSET): New macro.
(PROGRAM_SUSPEND_OFFSET): New macro.
(UNLOCK_BYPASS_OFFSET): New macro.
(SECSI_SECTOR_SIZE_OFFSET): New macro.
(EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET): New macro.
(NON_EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET): New macro.
(ERASE_SUSPEND_TIMEOUT_MAX_OFFSET): New macro.
(PROGRAM_SUSPEND_TIMEOUT_MAX_OFFSET): New macro.
(BANK_ORGANIZATION_OFFSET): New macro.
(BANK_REGION_INFO_OFFSET): New macro.
(struct amd_pri_extened_query_structure): Define.
(amd_pri_extened_query_structure_t): Typedef.
* src/flash/cfi.c (cfi_array_free): Free primary vendor table.
(cfi_detect): Detect AMD CFI primary vendor-specific extended
query table. Reverse the order of erase block region information
for top boot devices.
* src/flash/detectflash.c (detectflash): Print out information
of AMD CFI primary vendor-specific extended query table.
2008-02-24 Kolja Waschk <kawk>
* include/cable.h, include/usbconn.h, include/usbconn/libusb.h,

@ -35,6 +35,10 @@
* September 1999, Order Number: JESD68
* [2] JEDEC Solid State Technology Association, "Common Flash Interface (CFI) ID Codes",
* September 2001, Order Number: JEP137-A
* [3] AMD, "Common Flash Memory Interface Specification", Release 2.0
* December 1, 2001.
* [4] SPANSION, "Common Flash Interface Version 1.4 Vendor Specific
* Extensions", March 22, 2004.
*
*/
@ -155,4 +159,55 @@ typedef struct cfi_query_structure {
} cfi_query_structure_t;
#endif /* __ASSEMBLY__ */
/* AMD primary vendor-specific extended query structure - see [3] and [4] */
#define MAJOR_VERSION_OFFSET 0x03
#define MINOR_VERSION_OFFSET 0x04
#define ADDRESS_SENSITIVE_UNLOCK_OFFSET 0x05
#define ERASE_SUSPEND_OFFSET 0x06
#define SECTOR_PROTECT_OFFSET 0x07
#define SECTOR_TEMPORARY_UNPROTECT_OFFSET 0x08
#define SECTOR_PROTECT_SCHEME_OFFSET 0x09
#define SIMULTANEOUS_OPERATION_OFFSET 0x0A
#define BURST_MODE_TYPE_OFFSET 0x0B
#define PAGE_MODE_TYPE_OFFSET 0x0C
#define ACC_MIN_OFFSET 0x0D
#define ACC_MAX_OFFSET 0x0E
#define TOP_BOTTOM_SECTOR_FLAG_OFFSET 0x0F
#define PROGRAM_SUSPEND_OFFSET 0x10
#define UNLOCK_BYPASS_OFFSET 0x11
#define SECSI_SECTOR_SIZE_OFFSET 0x12
#define EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET 0x13
#define NON_EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET 0x14
#define ERASE_SUSPEND_TIMEOUT_MAX_OFFSET 0x15
#define PROGRAM_SUSPEND_TIMEOUT_MAX_OFFSET 0x16
#define BANK_ORGANIZATION_OFFSET 0x17
#define BANK_REGION_INFO_OFFSET 0X18
#ifndef __ASSEMBLY__
typedef struct amd_pri_extened_query_structure {
uint8_t major_version;
uint8_t minor_version;
uint8_t address_sensitive_unlock;
uint8_t erase_suspend;
uint8_t sector_protect;
uint8_t sector_temporary_unprotect;
uint8_t sector_protect_scheme;
uint8_t simultaneous_operation;
uint8_t burst_mode_type;
uint8_t page_mode_type;
uint16_t acc_min; /* in mV */
uint16_t acc_max; /* in mV */
uint8_t top_bottom_sector_flag;
uint8_t program_suspend;
uint8_t unlock_bypass;
uint8_t secsi_sector_size;
uint8_t embedded_hwrst_timeout_max;
uint8_t non_embedded_hwrst_timeout_max; /* in ns */
uint8_t erase_suspend_timeout_max; /* in ns */
uint8_t program_suspend_timeout_max; /* in us */
uint8_t bank_organization; /* in us */
uint8_t bank_region_info[0];
} amd_pri_extened_query_structure_t;
#endif /* __ASSEMBLY__ */
#endif /* FLASH_CFI_H */

@ -51,6 +51,8 @@ cfi_array_free( cfi_array_t *cfi_array )
continue;
free( cfi_array->cfi_chips[i]->cfi.device_geometry.erase_block_regions );
if (cfi_array->cfi_chips[i]->cfi.identification_string.pri_vendor_tbl)
free (cfi_array->cfi_chips[i]->cfi.identification_string.pri_vendor_tbl);
free( cfi_array->cfi_chips[i] );
}
free( cfi_array->cfi_chips );
@ -98,6 +100,7 @@ cfi_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array )
cfi_query_structure_t *cfi;
uint32_t tmp;
int ret = -4; /* CFI not detected (Q) */
uint16_t pri_vendor_tbl_adr;
/* detect CFI capable devices - see Table 1 in [1] */
for (ma = 1; ma <= 4; ma *= 2) {
@ -203,6 +206,106 @@ cfi_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array )
}
}
pri_vendor_tbl_adr = read2(PRI_VENDOR_TABLE_ADR_OFFSET);
/* AMD CFI Primary Vendor-Specific Extended Query Table - see [3] and [4] */
if (cfi->identification_string.pri_id_code == CFI_VENDOR_AMD_SCS
&& pri_vendor_tbl_adr != 0) {
amd_pri_extened_query_structure_t *pri_vendor_tbl;
uint8_t major_version;
uint8_t minor_version;
uint8_t num_of_banks;
int i;
#undef A
#define A(off) (adr + (pri_vendor_tbl_adr + off) * ba * ma)
if (read1 (0) != 'P' || read1 (1) != 'R' || read1 (2) != 'I') {
write1 (0, CFI_CMD_READ_ARRAY1);
return -9; /* CFI primary vendor table not detected */
}
major_version = read1 (MAJOR_VERSION_OFFSET);
minor_version = read1 (MINOR_VERSION_OFFSET);
if (major_version > '1' || (major_version == '1' && minor_version >= '3'))
num_of_banks = read1 (BANK_ORGANIZATION_OFFSET);
else
num_of_banks = 0;
pri_vendor_tbl = (amd_pri_extened_query_structure_t *)
calloc (1, sizeof (amd_pri_extened_query_structure_t)
+ num_of_banks * sizeof (uint8_t));
if (!pri_vendor_tbl) {
write1 (0, CFI_CMD_READ_ARRAY1);
return -2; /* out of memory */
}
if (major_version > '1' || (major_version == '1' && minor_version >= '0')) {
pri_vendor_tbl->major_version = major_version;
pri_vendor_tbl->minor_version = minor_version;
pri_vendor_tbl->address_sensitive_unlock = read1 (ADDRESS_SENSITIVE_UNLOCK_OFFSET);
pri_vendor_tbl->erase_suspend = read1 (ERASE_SUSPEND_OFFSET);
pri_vendor_tbl->sector_protect = read1 (SECTOR_PROTECT_OFFSET);
pri_vendor_tbl->sector_temporary_unprotect = read1 (SECTOR_TEMPORARY_UNPROTECT_OFFSET);
pri_vendor_tbl->sector_protect_scheme = read1 (SECTOR_PROTECT_SCHEME_OFFSET);
pri_vendor_tbl->simultaneous_operation = read1 (SIMULTANEOUS_OPERATION_OFFSET);
pri_vendor_tbl->burst_mode_type = read1 (BURST_MODE_TYPE_OFFSET);
pri_vendor_tbl->page_mode_type = read1 (PAGE_MODE_TYPE_OFFSET);
}
if (major_version > '1' || (major_version == '1' && minor_version >= '1')) {
tmp = read1 (ACC_MIN_OFFSET);
pri_vendor_tbl->acc_min = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
tmp = read1 (ACC_MAX_OFFSET);
pri_vendor_tbl->acc_max = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
pri_vendor_tbl->top_bottom_sector_flag = read1 (TOP_BOTTOM_SECTOR_FLAG_OFFSET);
}
if (major_version > '1' || (major_version == '1' && minor_version >= '2'))
pri_vendor_tbl->program_suspend = read1 (PROGRAM_SUSPEND_OFFSET);
if (major_version > '1' || (major_version == '1' && minor_version >= '3')) {
if (pri_vendor_tbl->simultaneous_operation)
pri_vendor_tbl->bank_organization = read1 (BANK_ORGANIZATION_OFFSET);
else
pri_vendor_tbl->bank_organization = 0;
for (i = 0; i < pri_vendor_tbl->bank_organization; i++)
pri_vendor_tbl->bank_region_info[i] = read1 (BANK_REGION_INFO_OFFSET + i * sizeof (uint8_t));
}
if (major_version > '1' || (major_version == '1' && minor_version >= '4')) {
pri_vendor_tbl->unlock_bypass = read1 (UNLOCK_BYPASS_OFFSET);
tmp = read1 (SECSI_SECTOR_SIZE_OFFSET);
pri_vendor_tbl->secsi_sector_size = tmp ? (1 << tmp) : 0;
tmp = read1 (EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET);
pri_vendor_tbl->embedded_hwrst_timeout_max = tmp ? (1 << tmp) : 0;
tmp = read1 (NON_EMBEDDED_HWRST_TIMEOUT_MAX_OFFSET);
pri_vendor_tbl->non_embedded_hwrst_timeout_max = tmp ? (1 << tmp) : 0;
tmp = read1 (ERASE_SUSPEND_TIMEOUT_MAX_OFFSET);
pri_vendor_tbl->erase_suspend_timeout_max = tmp ? (1 << tmp) : 0;
tmp = read1 (PROGRAM_SUSPEND_TIMEOUT_MAX_OFFSET);
pri_vendor_tbl->program_suspend_timeout_max = tmp ? (1 << tmp) : 0;
}
cfi->identification_string.pri_vendor_tbl = (void *) pri_vendor_tbl;
#undef A
#define A(off) (adr + (off) * ba * ma)
/* Reverse the order of erase block region information for top boot devices. */
if ((major_version > '1' || (major_version == '1' && minor_version >= '1'))
&& pri_vendor_tbl->top_bottom_sector_flag == 0x3)
{
uint32_t y, z;
uint32_t n = cfi->device_geometry.number_of_erase_regions;
for (i = 0; i < n / 2; i++) {
z = cfi->device_geometry.erase_block_regions[i].erase_block_size;
y = cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks;
cfi->device_geometry.erase_block_regions[i].erase_block_size
= cfi->device_geometry.erase_block_regions[n - i - 1].erase_block_size;
cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks
= cfi->device_geometry.erase_block_regions[n - i - 1].number_of_erase_blocks;
cfi->device_geometry.erase_block_regions[n - i - 1].erase_block_size = z;
cfi->device_geometry.erase_block_regions[n - i - 1].number_of_erase_blocks = y;
}
}
}
/* TODO: Intel Primary Algorithm Extended Query Table - see Table 5. in [2] */
/* Read Array */

@ -213,4 +213,144 @@ detectflash( bus_t *bus, uint32_t adr )
printf( _("\t\t\tNumber of Erase Blocks: %d\n"), cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks );
}
}
if (cfi->identification_string.pri_id_code == CFI_VENDOR_AMD_SCS
&& cfi->identification_string.pri_vendor_tbl != NULL)
{
amd_pri_extened_query_structure_t *pri_vendor_tbl;
uint8_t major_version;
uint8_t minor_version;
int i;
const char *required_or_not[2] = {
N_("Required"), N_("Not required")
};
const char *supported_or_not[2] = {
N_("Supported"), N_("Not supported")
};
const char *process_technology[6] = {
N_("170-nm Floating Gate technology"), N_("230-nm MirrorBit(tm) technology"),
N_("130-nm Floating Gate technology"), N_("110-nm MirrorBit(tm) technology"),
N_("90-nm Floating Gate technology"), N_("90-nm MirrorBit(tm) technology")
};
const char *process_technology_13[3] = {
N_("CS49"), N_("CS59"), N_("CS99")
};
const char *erase_suspend[3] = {
N_("Not supported"), N_("Read only"), N_("Read/write")
};
const char *sector_protect_scheme[8] = {
N_("29F040 mode"), N_("29F016 mode"), N_("29F400 mode"),
N_("29LV800 mode"), N_("29BDS640 mode (Software Command Locking)"),
N_("29BDD160 mode (New Sector Protect)"),
N_("29PDL128 mode (New Sector Protect + 29LV800)"),
N_("Advanced Sector Protect")
};
const char *page_mode_type[4] = {
N_("Not supported"), N_("4 word Page"), N_("8 word Page"), N_("16 word Page")
};
const char *top_bottom[6] = {
N_("No boot"), N_("8x8kb sectors at top and bottom with WP control"),
N_("Bottom boot device"), N_("Top boot device"),
N_("Uniform bottom boot device"), N_("Uniform top boot device")
};
const char *bad_value = N_("Bad value");
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
pri_vendor_tbl = cfi->identification_string.pri_vendor_tbl;
major_version = pri_vendor_tbl->major_version;
minor_version = pri_vendor_tbl->minor_version;
printf (_("Primary Vendor-Specific Extended Query:\n"));
printf (_("\tMajor version number: %c\n"), pri_vendor_tbl->major_version);
printf (_("\tMinor version number: %c\n"), pri_vendor_tbl->minor_version);
if (major_version > '1' || (major_version == '1' && minor_version >= '0'))
{
if ((pri_vendor_tbl->address_sensitive_unlock & 0x3) < ARRAY_SIZE (required_or_not))
printf (_("\tAddress Sensitive Unlock: %s\n"),
required_or_not[pri_vendor_tbl->address_sensitive_unlock & 0x3]);
else
printf (_("\tAddress Sensitive Unlock: %s\n"), bad_value);
if (major_version > '1' || (major_version == '1' && minor_version >= '4'))
{
if ((pri_vendor_tbl->address_sensitive_unlock >> 2) < ARRAY_SIZE (process_technology))
printf (_("\tProcess Technology: %s\n"),
process_technology[pri_vendor_tbl->address_sensitive_unlock >> 2]);
else
printf (_("\tProcess Technology: %s\n"), bad_value);
}
else if (major_version == '1' && minor_version == '3')
{
if ((pri_vendor_tbl->address_sensitive_unlock >> 2) < ARRAY_SIZE (process_technology_13))
printf (_("\tProcess Technology: %s\n"),
process_technology_13[pri_vendor_tbl->address_sensitive_unlock >> 2]);
else
printf (_("\tProcess Technology: %s\n"), bad_value);
}
if (pri_vendor_tbl->erase_suspend < ARRAY_SIZE (erase_suspend))
printf (_("\tErase Suspend: %s\n"), erase_suspend[pri_vendor_tbl->erase_suspend]);
if (pri_vendor_tbl->sector_protect == 0)
printf (_("\tSector Protect: Not supported\n"));
else
printf (_("\tSector Protect: %d sectors per group\n"), pri_vendor_tbl->sector_protect);
if (pri_vendor_tbl->sector_temporary_unprotect < ARRAY_SIZE (supported_or_not))
printf (_("\tSector Temporary Unprotect: %s\n"), supported_or_not[pri_vendor_tbl->sector_temporary_unprotect]);
else
printf (_("\tSector Temporary Unprotect: %s\n"), bad_value);
if (pri_vendor_tbl->sector_protect_scheme < ARRAY_SIZE (sector_protect_scheme))
printf (_("\tSector Protect/Unprotect Scheme: %s\n"),
sector_protect_scheme[pri_vendor_tbl->sector_protect_scheme]);
else
printf (_("\tSector Protect/Unprotect Scheme: %s\n"), bad_value);
if (pri_vendor_tbl->simultaneous_operation == 0)
printf (_("\tSimultaneous Operation: Not supported\n"));
else
printf (_("\tSimultaneous Operation: %d sectors\n"), pri_vendor_tbl->simultaneous_operation);
if (pri_vendor_tbl->burst_mode_type < ARRAY_SIZE (supported_or_not))
printf (_("\tBurst Mode Type: %s\n"), supported_or_not[pri_vendor_tbl->burst_mode_type]);
else
printf (_("\tBurst Mode Type: %s\n"), bad_value);
if (pri_vendor_tbl->page_mode_type < ARRAY_SIZE (page_mode_type))
printf (_("\tPage Mode Type: %s\n"), page_mode_type[pri_vendor_tbl->page_mode_type]);
else
printf (_("\tPage Mode Type: %s\n"), bad_value);
}
if (major_version > '1' || (major_version == '1' && minor_version >= '1'))
{
printf (_("\tACC (Acceleration) Supply Minimum: %d mV\n"), pri_vendor_tbl->acc_min);
printf (_("\tACC (Acceleration) Supply Maximum: %d mV\n"), pri_vendor_tbl->acc_max);
if (pri_vendor_tbl->top_bottom_sector_flag < ARRAY_SIZE (top_bottom))
printf (_("\tTop/Bottom Sector Flag: %s\n"), top_bottom[pri_vendor_tbl->top_bottom_sector_flag]);
else
printf (_("\tTop/Bottom Sector Flag: %s\n"), bad_value);
}
if (major_version > '1' || (major_version == '1' && minor_version >= '2'))
{
if (pri_vendor_tbl->program_suspend < ARRAY_SIZE (supported_or_not))
printf (_("\tProgram Suspend: %s\n"), supported_or_not[pri_vendor_tbl->program_suspend]);
else
printf (_("\tProgram Suspend: %s\n"), bad_value);
}
if (major_version > '1' || (major_version == '1' && minor_version >= '4'))
{
if (pri_vendor_tbl->unlock_bypass < ARRAY_SIZE (supported_or_not))
printf (_("\tUnlock Bypass: %s\n"), supported_or_not[pri_vendor_tbl->unlock_bypass]);
else
printf (_("\tUnlock Bypass: %s\n"), bad_value);
printf (_("\tSecSi Sector (Customer OTP Area) Size: %d bytes\n"), pri_vendor_tbl->secsi_sector_size);
printf (_("\tEmbedded Hardware Reset Timeout Maximum: %d ns\n"), pri_vendor_tbl->embedded_hwrst_timeout_max);
printf (_("\tNon-Embedded Hardware Reset Timeout Maximum: %d ns\n"), pri_vendor_tbl->non_embedded_hwrst_timeout_max);
printf (_("\tErase Suspend Timeout Maximum: %d us\n"), pri_vendor_tbl->erase_suspend_timeout_max);
printf (_("\tProgram Suspend Timeout Maximum: %d us\n"), pri_vendor_tbl->program_suspend_timeout_max);
}
if ((major_version > '1' || (major_version == '1' && minor_version >= '3'))
&& pri_vendor_tbl->bank_organization)
{
printf (_("\tBank Organization:\n"));
for (i = 0; i < pri_vendor_tbl->bank_organization; i++)
printf (_("\t\tBank%d: %d sectors\n"), i + 1, pri_vendor_tbl->bank_region_info[i]);
}
}
}

Loading…
Cancel
Save