[ 1873220 ] Merge libbrux into src, and inclow into include. Compiles now.
git-svn-id: https://urjtag.svn.sourceforge.net/svnroot/urjtag/trunk@926 b68d4a1b-bc3d-0410-92ed-d4ac073336b7master
parent
a3547df4c0
commit
aae9e008ec
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2003 ETC s.r.o.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by Marcel Telka <marcel@telka.sk>, 2003.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <flash.h>
|
||||
#include <cmd.h>
|
||||
|
||||
static int
|
||||
cmd_detectflash_run( char *params[] )
|
||||
{
|
||||
uint32_t adr;
|
||||
|
||||
if (cmd_params( params ) != 2)
|
||||
return -1;
|
||||
|
||||
if (!bus) {
|
||||
printf( _("Error: Bus driver missing.\n") );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (cmd_get_number( params[1], &adr ))
|
||||
return -1;
|
||||
|
||||
detectflash( bus, adr );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_detectflash_help( void )
|
||||
{
|
||||
printf( _(
|
||||
"Usage: %s ADDRESS\n"
|
||||
"Detect flash memory type connected to a part.\n"
|
||||
"\n"
|
||||
"ADDRESS Base address for memory region\n"
|
||||
), "detectflash" );
|
||||
}
|
||||
|
||||
cmd_t cmd_detectflash = {
|
||||
"detectflash",
|
||||
N_("detect parameters of flash chips attached to a part"),
|
||||
cmd_detectflash_help,
|
||||
cmd_detectflash_run
|
||||
};
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2003 ETC s.r.o.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by Marcel Telka <marcel@telka.sk>, 2003.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <cmd.h>
|
||||
|
||||
static int
|
||||
cmd_help_run( char *params[] )
|
||||
{
|
||||
int i;
|
||||
|
||||
/* short description generation */
|
||||
if (!params[1]) {
|
||||
printf( _("Command list:\n\n") );
|
||||
for (i = 0; cmds[i]; i++)
|
||||
printf( _("%-13s %s\n"), cmds[i]->name, cmds[i]->desc ? _(cmds[i]->desc) : _("(no description available)") );
|
||||
printf( _("\nType \"help COMMAND\" for details about a particular command.\n") );
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (params[2])
|
||||
return -1;
|
||||
|
||||
/* search and print help for a particular command */
|
||||
for (i = 0; cmds[i]; i++)
|
||||
if (strcasecmp( cmds[i]->name, params[1] ) == 0) {
|
||||
if (cmds[i]->help)
|
||||
cmds[i]->help();
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf( _("%s: unknown command\n"), params[1] );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_help_help( void )
|
||||
{
|
||||
printf( _(
|
||||
"Usage: %s [COMMAND]\n"
|
||||
"Print short help for COMMAND, or list of available commands.\n"
|
||||
), "help" );
|
||||
}
|
||||
|
||||
cmd_t cmd_help = {
|
||||
"help",
|
||||
N_("display this help"),
|
||||
cmd_help_help,
|
||||
cmd_help_run
|
||||
};
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2003 ETC s.r.o.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by Marcel Telka <marcel@telka.sk>, 2003.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cmd.h>
|
||||
|
||||
static int
|
||||
cmd_quit_run( char *params[] )
|
||||
{
|
||||
if (params[1])
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_quit_help( void )
|
||||
{
|
||||
printf( _(
|
||||
"Usage: %s\n"
|
||||
"Exit from %s.\n"
|
||||
), "quit", PACKAGE );
|
||||
}
|
||||
|
||||
cmd_t cmd_quit = {
|
||||
"quit",
|
||||
N_("exit and terminate this session"),
|
||||
cmd_quit_help,
|
||||
cmd_quit_run
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
#
|
||||
# $Id: Makefile.am 506 2003-08-13 10:05:15Z telka $
|
||||
#
|
||||
# Copyright (C) 2002 ETC s.r.o.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
#
|
||||
# Written by Marcel Telka <marcel@telka.sk>, 2002.
|
||||
#
|
||||
|
||||
include $(top_srcdir)/Makefile.rules
|
||||
|
||||
noinst_LIBRARIES = libflash.a
|
||||
|
||||
libflash_a_SOURCES = \
|
||||
amd.c \
|
||||
amd_flash.c \
|
||||
cfi.c \
|
||||
detectflash.c \
|
||||
intel.c \
|
||||
jedec.c
|
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Flash driver for AMD Am29LV640D, Am29LV641D, Am29LV642D
|
||||
* Copyright (C) 2003 AH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by August Hörandl <august.hoerandl@gmx.at>
|
||||
* Modified by Marcel Telka <marcel@telka.sk>, 2003.
|
||||
*
|
||||
* Documentation:
|
||||
* [1] Advanced Micro Devices, "Am29LV640D/Am29LV641D",
|
||||
* September 20, 2002 Rev B, 22366b8.pdf
|
||||
* [2] Advanced Micro Devices, "Am29LV642D",
|
||||
* August 14, 2001 Rev A, 25022.pdf
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <flash/cfi.h>
|
||||
#include <flash/intel.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <flash.h>
|
||||
#include <bus.h>
|
||||
|
||||
static int dbg = 0;
|
||||
|
||||
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 );
|
||||
static int amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data );
|
||||
static void amd_flash_read_array( cfi_array_t *cfi_array );
|
||||
|
||||
/* The code below assumes a connection of the flash chip address LSB (A0)
|
||||
* to A0, A1 or A2 of the CPU bus dependent on the bus width, which is the
|
||||
* most common connection pattern:
|
||||
* 8 Bit devices: A0..Ax connected to A0..Ax of CPU bus
|
||||
* 16 Bit devices: A0..Ax connected to A1..Ax+1 of CPU bus
|
||||
* 32 Bit devices: A0..Ax connected to A2..Ax+2 of CPU bus
|
||||
* The offset "o" is used here dependent on the bus width (8, 16 or 32 bit) to
|
||||
* align the patterns emitted on the address lines at either A0, A1 or A2. */
|
||||
|
||||
static int o;
|
||||
|
||||
/* NOTE: It does not work for SoC chips or boards with extra address decoders
|
||||
* that do address alignment themselves, such as the Samsung S3C4510B. The bus
|
||||
* driver has to deal with this. - kawk 2008-01 */
|
||||
|
||||
/* autodetect, we can handle this chip */
|
||||
static int
|
||||
amd_flash_autodetect32( cfi_array_t *cfi_array )
|
||||
{
|
||||
if(cfi_array->bus_width != 4) return 0;
|
||||
o = 2; /* Heuristic */
|
||||
return (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_AMD_SCS);
|
||||
}
|
||||
|
||||
static int
|
||||
amd_flash_autodetect16( cfi_array_t *cfi_array )
|
||||
{
|
||||
if(cfi_array->bus_width != 2) return 0;
|
||||
o = 1; /* Heuristic */
|
||||
return (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_AMD_SCS);
|
||||
}
|
||||
|
||||
static int
|
||||
amd_flash_autodetect8( cfi_array_t *cfi_array )
|
||||
{
|
||||
if(cfi_array->bus_width != 1) return 0;
|
||||
o = 0; /* Heuristic */
|
||||
return (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_AMD_SCS);
|
||||
}
|
||||
/*
|
||||
* check device status
|
||||
* 1/true PASS
|
||||
* 0/false FAIL
|
||||
*/
|
||||
/*
|
||||
* first implementation: see [1], page 29
|
||||
*/
|
||||
#if 0
|
||||
static int
|
||||
amdstatus29( parts *ps, uint32_t adr, uint32_t data )
|
||||
{
|
||||
int timeout;
|
||||
uint32_t dq7mask = ((1 << 7) << 16) + (1 << 7);
|
||||
uint32_t dq5mask = ((1 << 5) << 16) + (1 << 5);
|
||||
uint32_t bit7 = (data & (1 << 7)) != 0;
|
||||
uint32_t data1;
|
||||
|
||||
for (timeout = 0; timeout < 100; timeout++) {
|
||||
data1 = bus_read( ps, adr << o );
|
||||
data1 = bus_read( ps, adr << o );
|
||||
if (dbg)
|
||||
printf( "amdstatus %d: %04X (%04X) = %04X\n", timeout, data1, (data1 & dq7mask), bit7 );
|
||||
if (((data1 & dq7mask) == dq7mask) == bit7) /* FIXME: This looks non-portable */
|
||||
return 1;
|
||||
|
||||
if ((data1 & dq5mask) == dq5mask)
|
||||
break;
|
||||
usleep( 100 );
|
||||
}
|
||||
|
||||
data1 = bus_read( ps, adr << o );
|
||||
if (((data1 & dq7mask) == dq7mask) == bit7) /* FIXME: This looks non-portable */
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
|
||||
#if 1
|
||||
/*
|
||||
* second implementation: see [1], page 30
|
||||
*/
|
||||
static int
|
||||
amdstatus( bus_t *bus, uint32_t adr, int data )
|
||||
{
|
||||
int timeout;
|
||||
uint32_t togglemask = ((1 << 6) << 16) + (1 << 6); /* DQ 6 */
|
||||
/* int dq5mask = ((1 << 5) << 16) + (1 << 5); DQ5 */
|
||||
|
||||
for (timeout = 0; timeout < 100; timeout++) {
|
||||
uint32_t data1 = bus_read( bus, adr );
|
||||
uint32_t data2 = bus_read( bus, adr );
|
||||
|
||||
/*printf("amdstatus %d: %04X/%04X %04X/%04X \n", */
|
||||
/* timeout, data1, data2, (data1 & togglemask), (data2 & togglemask)); */
|
||||
if ( (data1 & togglemask) == (data2 & togglemask))
|
||||
return 1;
|
||||
|
||||
/* if ( (data1 & dq5mask) != 0 ) TODO */
|
||||
/* return 0; */
|
||||
if (dbg)
|
||||
printf( "amdstatus %d: %04X/%04X\n", timeout, data1, data2 );
|
||||
else
|
||||
printf( "." );
|
||||
usleep( 100 );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* 1 */
|
||||
|
||||
/* Note: This implementation of amdstatus() has been added by patch
|
||||
[ 1429825 ] EJTAG driver (some remaining patch lines for flash/amd.c)
|
||||
It's a quirk workaround and seems to break status polling for other chips.
|
||||
Therefore it's deactivated at the moment but kept for reference. */
|
||||
/*
|
||||
* second implementation: see [1], page 30
|
||||
*/
|
||||
static int
|
||||
amdstatus( bus_t *bus, uint32_t adr, int data )
|
||||
{
|
||||
int timeout;
|
||||
uint32_t togglemask = ((1 << 6) << 16) + (1 << 6); /* DQ 6 */
|
||||
/* int dq5mask = ((1 << 5) << 16) + (1 << 5); DQ5 */
|
||||
uint32_t data1, data2;
|
||||
|
||||
data1 = bus_read( bus, adr );
|
||||
for (timeout = 0; timeout < 100; timeout++) {
|
||||
data2 = bus_read( bus, adr );
|
||||
|
||||
|
||||
/*printf("amdstatus %d: %04X/%04X %04X/%04X \n", */
|
||||
/* timeout, data1, data2, (data1 & togglemask), (data2 & togglemask)); */
|
||||
/* Work around an issue with RTL8181: toggle bits don't
|
||||
toggle when reading the same flash address repeatedly
|
||||
without any other memory access in between. Other
|
||||
bits reflect the current status, and data after the
|
||||
operation is complete - only Q6/Q2 bits don't toggle
|
||||
when they should. Looks like the CPU not deasserting
|
||||
CE or OE, so data is output to the bus continuously.
|
||||
So, check for the correct data read twice instead. */
|
||||
/*if ( (data1 & togglemask) == (data2 & togglemask)) */
|
||||
if ( (data1 == data) && (data2 == data) )
|
||||
return 1;
|
||||
|
||||
/* if ( (data1 & dq5mask) != 0 ) TODO */
|
||||
/* return 0; */
|
||||
if (dbg)
|
||||
printf( "amdstatus %d: %04X/%04X\n", timeout, data1, data2 );
|
||||
else
|
||||
printf( "." );
|
||||
usleep( 100 );
|
||||
data1 = data2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* 0 */
|
||||
|
||||
#if 0
|
||||
static int
|
||||
amdisprotected( parts *ps, cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
bus_write( ps, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29, sector erase */
|
||||
bus_write( ps, cfi_array->address + (0x02aa << o), 0x00550055 );
|
||||
bus_write( ps, cfi_array->address + (0x0555 << o), 0x00900090 );
|
||||
|
||||
data = bus_read( ps, adr + (0x0002 << 2) );
|
||||
/* Read Array */
|
||||
amd_flash_read_array( ps ); /* AMD reset */
|
||||
|
||||
return ((data & 0x00ff00ff) != 0);
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
static void
|
||||
amd_flash_print_info( cfi_array_t *cfi_array )
|
||||
{
|
||||
int mid, cid, prot;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29 */
|
||||
bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 );
|
||||
bus_write( bus, cfi_array->address + (0x0555 << o), 0x00900090 );
|
||||
mid = bus_read( bus, cfi_array->address + (0x00 << o) ) & 0xFFFF;
|
||||
cid = bus_read( bus, cfi_array->address + (0x01 << o) ) & 0xFFFF;
|
||||
prot = bus_read( bus, cfi_array->address + (0x02 << o) ) & 0xFF;
|
||||
amd_flash_read_array( cfi_array ); /* AMD reset */
|
||||
printf( _("Chip: AMD Flash\n\tManufacturer: ") );
|
||||
switch (mid) {
|
||||
case 0x0001:
|
||||
printf( _("AMD") );
|
||||
break;
|
||||
case 0x0020:
|
||||
printf( _("ST/Samsung") );
|
||||
break;
|
||||
case 0x002C:
|
||||
printf( _("Macronix") );
|
||||
break;
|
||||
default:
|
||||
printf( _("Unknown manufacturer (ID 0x%04x)"), mid );
|
||||
break;
|
||||
}
|
||||
printf( _("\n\tChip: ") );
|
||||
switch (cid) {
|
||||
case 0x004F:
|
||||
printf( _("Am29LV040B") );
|
||||
break;
|
||||
case 0x22D7:
|
||||
printf( _("Am29LV640D/Am29LV641D/Am29LV642D") );
|
||||
break;
|
||||
case 0x225B:
|
||||
printf( _("Am29LV800B") );
|
||||
break;
|
||||
case 0x2249:
|
||||
printf( _("MX29LV160B") );
|
||||
break;
|
||||
case 0x0049:
|
||||
printf( _("AM29LV160DB") );
|
||||
break;
|
||||
case 0x0093:
|
||||
printf( _("Am29LV065D") );
|
||||
break;
|
||||
case 0x00ca:
|
||||
printf( _("M29W320DT") );
|
||||
break;
|
||||
case 0x00cb:
|
||||
printf( _("M29W320DB") );
|
||||
break;
|
||||
default:
|
||||
printf ( _("Unknown (ID 0x%04x)"), cid );
|
||||
break;
|
||||
}
|
||||
printf( _("\n\tProtected: %04x\n"), prot );
|
||||
|
||||
/* Read Array */
|
||||
bus_write( bus, cfi_array->address + (0x0000 << o), 0x00ff00ff );
|
||||
}
|
||||
|
||||
static int
|
||||
amd_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
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 + (0x02aa << o), 0x00550055 );
|
||||
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 (amdstatus( bus, adr, 0xffff )) {
|
||||
printf( "flash_erase_block 0x%08X DONE\n", adr );
|
||||
amd_flash_read_array( cfi_array ); /* AMD reset */
|
||||
return 0;
|
||||
}
|
||||
printf( "flash_erase_block 0x%08X FAILED\n", adr );
|
||||
/* Read Array */
|
||||
amd_flash_read_array( cfi_array ); /* AMD reset */
|
||||
|
||||
return FLASH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
amd_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
printf( "flash_unlock_block 0x%08X IGNORE\n", adr );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
amd_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data )
|
||||
{
|
||||
int status;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
if (dbg)
|
||||
printf("\nflash_program 0x%08X = 0x%08X\n", adr, data);
|
||||
|
||||
bus_write( bus, cfi_array->address + (0x0555 << o), 0x00aa00aa ); /* autoselect p29, program */
|
||||
bus_write( bus, cfi_array->address + (0x02aa << o), 0x00550055 );
|
||||
bus_write( bus, cfi_array->address + (0x0555 << o), 0x00A000A0 );
|
||||
|
||||
bus_write( bus, adr, data );
|
||||
status = amdstatus( bus, adr, data );
|
||||
/* amd_flash_read_array(ps); */
|
||||
|
||||
return !status;
|
||||
}
|
||||
|
||||
static void
|
||||
amd_flash_read_array( cfi_array_t *cfi_array )
|
||||
{
|
||||
/* Read Array */
|
||||
bus_write( cfi_array->bus, cfi_array->address, 0x00F000F0 ); /* AMD reset */
|
||||
}
|
||||
|
||||
flash_driver_t amd_32_flash_driver = {
|
||||
4, /* buswidth */
|
||||
N_("AMD/Fujitsu Standard Command Set"),
|
||||
N_("supported: AMD 29LV640D, 29LV641D, 29LV642D; 2x16 Bit"),
|
||||
amd_flash_autodetect32,
|
||||
amd_flash_print_info,
|
||||
amd_flash_erase_block,
|
||||
amd_flash_unlock_block,
|
||||
amd_flash_program,
|
||||
amd_flash_read_array,
|
||||
};
|
||||
|
||||
flash_driver_t amd_16_flash_driver = {
|
||||
2, /* buswidth */
|
||||
N_("AMD/Fujitsu Standard Command Set"),
|
||||
N_("supported: AMD 29LV800B; 1x16 Bit"),
|
||||
amd_flash_autodetect16,
|
||||
amd_flash_print_info,
|
||||
amd_flash_erase_block,
|
||||
amd_flash_unlock_block,
|
||||
amd_flash_program,
|
||||
amd_flash_read_array,
|
||||
};
|
||||
|
||||
flash_driver_t amd_8_flash_driver = {
|
||||
1, /* buswidth */
|
||||
N_("AMD/Fujitsu Standard Command Set"),
|
||||
N_("supported: AMD 29LV160, AMD 29LV065D, AMD 29LV040B; 1x8 Bit"),
|
||||
amd_flash_autodetect8,
|
||||
amd_flash_print_info,
|
||||
amd_flash_erase_block,
|
||||
amd_flash_unlock_block,
|
||||
amd_flash_program,
|
||||
amd_flash_read_array,
|
||||
};
|
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* $Id: amd_flash.c,v 1.0 20/09/2006 12:38:01 $
|
||||
*
|
||||
* AMD 8 bit flash driver for AM29F040B & AM29LV040B
|
||||
* Copyright (C) 2006 Kila Medical Systems.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by Ajith Kumar P.C <ajithpc@kila.com>
|
||||
*
|
||||
* Documentation:
|
||||
* [1] Spansion, Am29F040B Data Sheet
|
||||
* [2] Spansion, Am29LV040B Data Sheet
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <flash/cfi.h>
|
||||
#include <flash/intel.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <flash.h>
|
||||
#include <bus.h>
|
||||
|
||||
//write specific
|
||||
#define AMD_SECTOR_PROTECTED
|
||||
|
||||
//Read Specific
|
||||
#define AMD_READ_IN_ERASE_SUSPENDED_SECTOR
|
||||
#define AMD_READ_IN_NON_ERASE_SUSPENDED_SECTOR
|
||||
#define AMD_NORMAL_READ
|
||||
#define AMD_UNKNOWN_READ
|
||||
|
||||
//Mode
|
||||
#define AMD_ERASE_SUSPEND_MODE
|
||||
#define AMD_READING_MODE
|
||||
#define AMD_EMBEDDED_ERASE_ALGORITHM
|
||||
#define AMD_EMBEDDED_PROGRAM_ALGORITHM
|
||||
#define AMD_UNDEFINED_MODE
|
||||
|
||||
#define FLASH_ERASE_ERROR -5
|
||||
#define ERASE_FLASH_SUCCESS 1
|
||||
|
||||
#define AMD_29xx040B 1
|
||||
|
||||
#define AMD_BYPASS_UNLOCK_ALGORITHM 1
|
||||
#define AMD_STANDARD_WRITE_ALGORITHM 0
|
||||
#define AMD_BYPASS_UNLOCK_MODE 1
|
||||
#define AMD_STANDARD_MODE 0
|
||||
|
||||
struct
|
||||
{
|
||||
unsigned long flash;
|
||||
unsigned short algorithm;
|
||||
unsigned short unlock_bypass;
|
||||
}
|
||||
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_block( cfi_array_t *cfi_array, uint32_t adr );
|
||||
static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data );
|
||||
static int amd_29xx040_unlock_block( cfi_array_t *cfi_array, uint32_t adr );
|
||||
|
||||
int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array )
|
||||
{
|
||||
int mid;
|
||||
int did;
|
||||
bus_area_t area;
|
||||
cfi_query_structure_t *cfi ;
|
||||
|
||||
if (!cfi_array || !bus)
|
||||
return -1; /* invalid parameters */
|
||||
|
||||
*cfi_array = calloc( 1, sizeof (cfi_array_t) );
|
||||
if (!*cfi_array)
|
||||
return -2; /* out of memory */
|
||||
|
||||
bus_write( bus, adr+0x0, 0xf0 );
|
||||
bus_write( bus, adr+0x555, 0xaa );
|
||||
bus_write( bus, adr+0x2AA, 0x55 );
|
||||
bus_write( bus, adr+0x555, 0x90 );
|
||||
mid = bus_read( bus, adr+0x0);
|
||||
did = bus_read( bus, adr+0x1);
|
||||
bus_write( bus, adr+0x0, 0xf0 );
|
||||
|
||||
printf( "%s: mid %x, did %x\n", __FUNCTION__, mid, did );
|
||||
if (mid != 0x01)
|
||||
return -1;
|
||||
|
||||
switch(did)
|
||||
{
|
||||
case 0xA4:
|
||||
var_forced_detection.flash = AMD_29xx040B;
|
||||
break;
|
||||
case 0x4F:
|
||||
var_forced_detection.flash = AMD_29xx040B;
|
||||
var_forced_detection.algorithm = AMD_BYPASS_UNLOCK_ALGORITHM;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
(*cfi_array)->bus = bus;
|
||||
(*cfi_array)->address = 0;
|
||||
if (bus_area( bus, adr+0, &area ) != 0)
|
||||
return -8; /* bus width detection failed */
|
||||
unsigned int bw = area.width;
|
||||
int ba,i;
|
||||
if (bw != 8 && bw != 16 && bw != 32)
|
||||
return -3; /* invalid bus width */
|
||||
(*cfi_array)->bus_width = ba = bw / 8;
|
||||
(*cfi_array)->cfi_chips = calloc( ba, sizeof (cfi_chip_t *) );
|
||||
if (!(*cfi_array)->cfi_chips)
|
||||
return -2;
|
||||
for ( i=0; i<ba; i++ )
|
||||
{
|
||||
(*cfi_array)->cfi_chips[i] = calloc( 1, sizeof (cfi_chip_t) );
|
||||
if (!(*cfi_array)->cfi_chips[i])
|
||||
return -2; /* out of memory */
|
||||
(*cfi_array)->cfi_chips[i]->width = 1; //ba;
|
||||
cfi = &(*cfi_array)->cfi_chips[i]->cfi;
|
||||
|
||||
cfi->identification_string.pri_id_code = CFI_VENDOR_NULL;
|
||||
cfi->identification_string.pri_vendor_tbl = NULL;
|
||||
cfi->identification_string.alt_id_code = 0;
|
||||
cfi->identification_string.alt_vendor_tbl = NULL;
|
||||
|
||||
cfi->device_geometry.device_size = 512*1024;
|
||||
cfi->device_geometry.device_interface = 0; // x 8
|
||||
cfi->device_geometry.max_bytes_write = 32; //not used
|
||||
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 */
|
||||
|
||||
cfi->device_geometry.erase_block_regions[i].erase_block_size = 64 * 1024;
|
||||
cfi->device_geometry.erase_block_regions[i].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_29xx040B); //Non-CFI Am29xx040B flash
|
||||
}
|
||||
|
||||
static int amd_29xx040_status( bus_t *bus, uint32_t adr, unsigned short data )
|
||||
{
|
||||
short timeout;
|
||||
unsigned short dq7bit,dq7mask,dq5mask;
|
||||
unsigned short data1;
|
||||
|
||||
dq7mask = (1 << 7);
|
||||
dq5mask = (1 << 5);
|
||||
dq7bit = data & dq7mask;
|
||||
|
||||
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)
|
||||
return 1; //Success
|
||||
|
||||
if((data1 & dq5mask) == dq5mask)
|
||||
{
|
||||
data1 = (unsigned short)(bus_read( bus, adr ) & 0xFF);
|
||||
if((data1 & dq7mask) == dq7bit)
|
||||
{
|
||||
return 1; //Success
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0; //Failure - Needs a reset command to return back to read array data
|
||||
}
|
||||
}
|
||||
usleep (50);
|
||||
}
|
||||
|
||||
return 0; //hardware failure
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void amd_29xx040_print_info( cfi_array_t *cfi_array )
|
||||
{
|
||||
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 );
|
||||
bus_write( bus, cfi_array->address + 0x555, 0x90 );
|
||||
mid = bus_read( bus, cfi_array->address + 0x0);
|
||||
did = bus_read( bus, cfi_array->address + 0x1);
|
||||
prot = bus_read( bus, cfi_array->address + 0x2);
|
||||
bus_write( bus, cfi_array->address + 0x0, 0xf0 );
|
||||
|
||||
printf( "%s: mid %x, did %x\n", __FUNCTION__, mid, did );
|
||||
// amd_29xx040_read_array( cfi_array ); /* AMD reset */
|
||||
|
||||
switch (mid)
|
||||
{
|
||||
case 0x01:
|
||||
printf( _("Chip: AMD Flash\n\tPartNumber: ") );
|
||||
break;
|
||||
default:
|
||||
printf( _("Unknown manufacturer (ID 0x%04x)"), mid );
|
||||
break;
|
||||
}
|
||||
printf( _("\n\tChip: ") );
|
||||
switch (did) {
|
||||
case 0xA4:
|
||||
printf( _("Am29C040B\t-\t") );
|
||||
printf( _("5V Flash\n") );
|
||||
break;
|
||||
case 0x4F:
|
||||
printf( _("Am29LV040B\t-\t") );
|
||||
printf( _("3V Flash\n") );
|
||||
break;
|
||||
default:
|
||||
printf ( _("Unknown (ID 0x%04x)"), did );
|
||||
break;
|
||||
}
|
||||
printf( _("\n\tProtected: %04x\n"), prot );
|
||||
}
|
||||
|
||||
static void amd_29xx040_read_array( cfi_array_t *cfi_array )
|
||||
{
|
||||
/* Read Array */
|
||||
if(var_forced_detection.unlock_bypass == AMD_BYPASS_UNLOCK_MODE)
|
||||
{
|
||||
bus_write( bus, cfi_array->address + 0x555, 0x90 );
|
||||
bus_write( bus, cfi_array->address + 0x2AA, 0x00 );
|
||||
usleep(100);
|
||||
var_forced_detection.unlock_bypass = AMD_STANDARD_MODE;
|
||||
}
|
||||
bus_write( cfi_array->bus, cfi_array->address + 0x0, 0x0F0 ); /* AMD reset */
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int amd_29xx040_erase_block( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
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, 0x90 );
|
||||
bus_write( bus, cfi_array->address + 0x2AA, 0x00 );
|
||||
usleep(100);
|
||||
var_forced_detection.unlock_bypass = AMD_STANDARD_MODE;
|
||||
}
|
||||
|
||||
bus_write( bus, cfi_array->address + 0x0, 0xf0 );
|
||||
bus_write( bus, cfi_array->address + 0x555, 0xaa );
|
||||
bus_write( bus, cfi_array->address + 0x2AA, 0x55 );
|
||||
bus_write( bus, cfi_array->address + 0x555, 0x80 );
|
||||
bus_write( bus, cfi_array->address + 0x555, 0xaa );
|
||||
bus_write( bus, cfi_array->address + 0x2AA, 0x55 );
|
||||
// bus_write( bus, cfi_array->address + 0x555, 0x10 ); //Chip Erase
|
||||
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 ERASE_FLASH_SUCCESS;
|
||||
}
|
||||
printf( "flash_erase_block 0x%08X FAILED\n", adr );
|
||||
/* Read Array */
|
||||
amd_29xx040_read_array( cfi_array ); /* AMD reset */
|
||||
|
||||
return FLASH_ERASE_ERROR;
|
||||
}
|
||||
|
||||
static int amd_29xx040_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data )
|
||||
{
|
||||
int status;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
if (0)
|
||||
printf("\nflash_program 0x%08X = 0x%08X\n", adr, data);
|
||||
if(var_forced_detection.algorithm == AMD_BYPASS_UNLOCK_ALGORITHM)
|
||||
{
|
||||
if(var_forced_detection.unlock_bypass != AMD_BYPASS_UNLOCK_MODE)
|
||||
{
|
||||
bus_write( bus, cfi_array->address + 0x555, 0xaa );
|
||||
bus_write( bus, cfi_array->address + 0x2AA, 0x55 );
|
||||
bus_write( bus, cfi_array->address + 0x555, 0x20 );
|
||||
usleep(1000);
|
||||
var_forced_detection.unlock_bypass = AMD_BYPASS_UNLOCK_MODE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bus_write( bus, cfi_array->address + 0x555, 0xaa );
|
||||
bus_write( bus, cfi_array->address + 0x2AA, 0x55 );
|
||||
}
|
||||
|
||||
bus_write( bus, cfi_array->address + 0x555, 0xA0 );
|
||||
bus_write( bus, adr, data );
|
||||
status = amd_29xx040_status( bus, adr, data );
|
||||
/* amd_29xx040_read_array(cfi_array); */
|
||||
|
||||
return !status;
|
||||
}
|
||||
|
||||
static int amd_29xx040_unlock_block( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
printf( "flash_unlock_block 0x%08X IGNORE\n", adr );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
flash_driver_t amd_29xx040_flash_driver = {
|
||||
1, /* buswidth */
|
||||
N_("AMD Standard Command Set"),
|
||||
N_("supported: AMD 29LV040B, 29C040B, 1x8 Bit"),
|
||||
amd_29xx040_autodetect,
|
||||
amd_29xx040_print_info,
|
||||
amd_29xx040_erase_block,
|
||||
amd_29xx040_unlock_block,
|
||||
amd_29xx040_program,
|
||||
amd_29xx040_read_array,
|
||||
};
|
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002, 2003 ETC s.r.o.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by Marcel Telka <marcel@telka.sk>, 2002, 2003.
|
||||
*
|
||||
* Documentation:
|
||||
* [1] JEDEC Solid State Technology Association, "Common Flash Interface (CFI)",
|
||||
* September 1999, Order Number: JESD68
|
||||
* [2] Intel Corporation, "Common Flash Interface (CFI) and Command Sets
|
||||
* Application Note 646", April 2000, Order Number: 292204-004
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <flash/cfi.h>
|
||||
|
||||
#include <flash.h>
|
||||
#include <bus.h>
|
||||
|
||||
void
|
||||
cfi_array_free( cfi_array_t *cfi_array )
|
||||
{
|
||||
if (!cfi_array)
|
||||
return;
|
||||
|
||||
if (cfi_array->cfi_chips) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cfi_array->bus_width; i++) {
|
||||
if (!cfi_array->cfi_chips[i])
|
||||
continue;
|
||||
|
||||
free( cfi_array->cfi_chips[i]->cfi.device_geometry.erase_block_regions );
|
||||
free( cfi_array->cfi_chips[i] );
|
||||
}
|
||||
free( cfi_array->cfi_chips );
|
||||
}
|
||||
|
||||
free( cfi_array );
|
||||
}
|
||||
|
||||
int
|
||||
cfi_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array )
|
||||
{
|
||||
unsigned int bw; /* bus width */
|
||||
unsigned int d; /* data offset */
|
||||
int ba; /* bus width address multiplier */
|
||||
int ma; /* flash mode address multiplier */
|
||||
bus_area_t area;
|
||||
|
||||
if (!cfi_array || !bus)
|
||||
return -1; /* invalid parameters */
|
||||
|
||||
*cfi_array = calloc( 1, sizeof (cfi_array_t) );
|
||||
if (!*cfi_array)
|
||||
return -2; /* out of memory */
|
||||
|
||||
(*cfi_array)->bus = bus;
|
||||
(*cfi_array)->address = adr;
|
||||
if (bus_area( bus, adr, &area ) != 0)
|
||||
return -8; /* bus width detection failed */
|
||||
bw = area.width;
|
||||
if (bw != 8 && bw != 16 && bw != 32)
|
||||
return -3; /* invalid bus width */
|
||||
(*cfi_array)->bus_width = ba = bw / 8;
|
||||
(*cfi_array)->cfi_chips = calloc( ba, sizeof (cfi_chip_t *) );
|
||||
if (!(*cfi_array)->cfi_chips)
|
||||
return -2; /* out of memory */
|
||||
|
||||
for (d = 0; d < bw; d += 8) {
|
||||
#define A(off) (adr + (off) * ba * ma)
|
||||
#define D(data) ((data) << d)
|
||||
#define gD(data) (((data) >> d) & 0xFF)
|
||||
#define read1(off) gD(bus_read( bus, A(off) ))
|
||||
#define read2(off) (bus_read_start( bus, A(off) ), gD(bus_read_next( bus, A((off) + 1) )) | gD(bus_read_end( bus )) << 8)
|
||||
#define write1(off,data) bus_write( bus, A(off), D(data) )
|
||||
|
||||
cfi_query_structure_t *cfi;
|
||||
uint32_t tmp;
|
||||
int ret = -4; /* CFI not detected (Q) */
|
||||
|
||||
/* detect CFI capable devices - see Table 1 in [1] */
|
||||
for (ma = 1; ma <= 4; ma *= 2) {
|
||||
write1( CFI_CMD_QUERY_OFFSET, CFI_CMD_QUERY );
|
||||
|
||||
if (read1(CFI_QUERY_ID_OFFSET) == 'Q') {
|
||||
ret = -5; /* CFI not detected (R) */
|
||||
if (read1(CFI_QUERY_ID_OFFSET + 1) == 'R')
|
||||
break;
|
||||
}
|
||||
|
||||
write1( 0, CFI_CMD_READ_ARRAY1 );
|
||||
}
|
||||
|
||||
if (ma > 4)
|
||||
return ret; /* CFI not detected (Q or R) */
|
||||
|
||||
if (read1(CFI_QUERY_ID_OFFSET + 2) != 'Y') {
|
||||
write1( 0, CFI_CMD_READ_ARRAY1 );
|
||||
return -6; /* CFI not detected (Y) */
|
||||
}
|
||||
|
||||
(*cfi_array)->cfi_chips[d / 8] = calloc( 1, sizeof (cfi_chip_t) );
|
||||
if (!(*cfi_array)->cfi_chips[d / 8]) {
|
||||
write1( 0, CFI_CMD_READ_ARRAY1 );
|
||||
return -2; /* out of memory */
|
||||
}
|
||||
cfi = &(*cfi_array)->cfi_chips[d / 8]->cfi;
|
||||
|
||||
/* Identification string - see Table 6 in [1] */
|
||||
cfi->identification_string.pri_id_code = read2(PRI_VENDOR_ID_OFFSET);
|
||||
cfi->identification_string.pri_vendor_tbl = NULL;
|
||||
cfi->identification_string.alt_id_code = read2(ALT_VENDOR_ID_OFFSET);
|
||||
cfi->identification_string.alt_vendor_tbl = NULL;
|
||||
|
||||
/* System interface information - see Table 7 in [1] */
|
||||
tmp = read1(VCC_MIN_WEV_OFFSET);
|
||||
cfi->system_interface_info.vcc_min_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
|
||||
tmp = read1(VCC_MAX_WEV_OFFSET);
|
||||
cfi->system_interface_info.vcc_max_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
|
||||
tmp = read1(VPP_MIN_WEV_OFFSET);
|
||||
cfi->system_interface_info.vpp_min_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
|
||||
tmp = read1(VPP_MAX_WEV_OFFSET);
|
||||
cfi->system_interface_info.vpp_max_wev = ((tmp >> 4) & 0xF) * 1000 + (tmp & 0xF) * 100;
|
||||
|
||||
/* TODO: Add out of range checks for timeouts */
|
||||
tmp = read1(TYP_SINGLE_WRITE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.typ_single_write_timeout = tmp ? (1 << tmp) : 0;
|
||||
|
||||
tmp = read1(TYP_BUFFER_WRITE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.typ_buffer_write_timeout = tmp ? (1 << tmp) : 0;
|
||||
|
||||
tmp = read1(TYP_BLOCK_ERASE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.typ_block_erase_timeout = tmp ? (1 << tmp) : 0;
|
||||
|
||||
tmp = read1(TYP_CHIP_ERASE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.typ_chip_erase_timeout = tmp ? (1 << tmp) : 0;
|
||||
|
||||
tmp = read1(MAX_SINGLE_WRITE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.max_single_write_timeout =
|
||||
(tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_single_write_timeout;
|
||||
|
||||
tmp = read1(MAX_BUFFER_WRITE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.max_buffer_write_timeout =
|
||||
(tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_buffer_write_timeout;
|
||||
|
||||
tmp = read1(MAX_BLOCK_ERASE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.max_block_erase_timeout =
|
||||
(tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_block_erase_timeout;
|
||||
|
||||
tmp = read1(MAX_CHIP_ERASE_TIMEOUT_OFFSET);
|
||||
cfi->system_interface_info.max_chip_erase_timeout =
|
||||
(tmp ? (1 << tmp) : 0) * cfi->system_interface_info.typ_chip_erase_timeout;
|
||||
|
||||
/* Device geometry - see Table 8 in [1] */
|
||||
/* TODO: Add out of range check */
|
||||
cfi->device_geometry.device_size = 1 << read1(DEVICE_SIZE_OFFSET);
|
||||
|
||||
cfi->device_geometry.device_interface = read2(FLASH_DEVICE_INTERFACE_OFFSET);
|
||||
|
||||
/* TODO: Add out of range check */
|
||||
cfi->device_geometry.max_bytes_write = 1 << read2(MAX_BYTES_WRITE_OFFSET);
|
||||
|
||||
tmp = cfi->device_geometry.number_of_erase_regions = read1(NUMBER_OF_ERASE_REGIONS_OFFSET);
|
||||
|
||||
cfi->device_geometry.erase_block_regions = malloc( tmp * sizeof (cfi_erase_block_region_t) );
|
||||
if (!cfi->device_geometry.erase_block_regions) {
|
||||
write1( 0, CFI_CMD_READ_ARRAY1 );
|
||||
return -2; /* out of memory */
|
||||
}
|
||||
|
||||
{
|
||||
int a;
|
||||
int i;
|
||||
|
||||
for (i = 0, a = ERASE_BLOCK_REGION_OFFSET; i < tmp; i++, a += 4) {
|
||||
uint32_t y = read2(a);
|
||||
uint32_t z = read2(a + 2) << 8;
|
||||
if (z == 0)
|
||||
z = 128;
|
||||
cfi->device_geometry.erase_block_regions[i].erase_block_size = z;
|
||||
cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks = y + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Intel Primary Algorithm Extended Query Table - see Table 5. in [2] */
|
||||
|
||||
/* Read Array */
|
||||
write1( 0, CFI_CMD_READ_ARRAY1 );
|
||||
|
||||
#undef A
|
||||
#undef D
|
||||
#undef gD
|
||||
#undef read1
|
||||
#undef read2
|
||||
#undef write1
|
||||
|
||||
switch (cfi->device_geometry.device_interface) {
|
||||
case CFI_INTERFACE_X8:
|
||||
if (ma != 1)
|
||||
return -7; /* error in device detection */
|
||||
(*cfi_array)->cfi_chips[d / 8]->width = 1;
|
||||
break;
|
||||
case CFI_INTERFACE_X16:
|
||||
if (ma != 1)
|
||||
return -7; /* error in device detection */
|
||||
(*cfi_array)->cfi_chips[d / 8]->width = 2;
|
||||
d += 8;
|
||||
break;
|
||||
case CFI_INTERFACE_X8_X16:
|
||||
if (ma != 1 && ma != 2)
|
||||
return -7; /* error in device detection */
|
||||
(*cfi_array)->cfi_chips[d / 8]->width = 2 / ma;
|
||||
if (ma == 1)
|
||||
d += 8;
|
||||
break;
|
||||
case CFI_INTERFACE_X32:
|
||||
if (ma != 1)
|
||||
return -7; /* error in device detection */
|
||||
(*cfi_array)->cfi_chips[d / 8]->width = 4;
|
||||
d += 24;
|
||||
break;
|
||||
case CFI_INTERFACE_X16_X32:
|
||||
if (ma != 1 && ma != 2)
|
||||
return -7; /* error in device detection */
|
||||
(*cfi_array)->cfi_chips[d / 8]->width = 4 / ma;
|
||||
if (ma == 1)
|
||||
d += 24;
|
||||
else
|
||||
d += 8;
|
||||
break;
|
||||
default:
|
||||
return -7; /* error in device detection */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 ETC s.r.o.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by Marcel Telka <marcel@telka.sk>, 2002.
|
||||
*
|
||||
* Documentation:
|
||||
* [1] JEDEC Solid State Technology Association, "Common Flash Interface (CFI)",
|
||||
* September 1999, Order Number: JESD68
|
||||
* [2] JEDEC Solid State Technology Association, "Common Flash Interface (CFI) ID Codes",
|
||||
* September 2001, Order Number: JEP137-A
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <flash/cfi.h>
|
||||
#include <flash/intel.h>
|
||||
#include <flash/mic.h>
|
||||
|
||||
#include <flash.h>
|
||||
#include <bus.h>
|
||||
|
||||
cfi_array_t *cfi_array = NULL;
|
||||
|
||||
extern int jedec_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array );
|
||||
|
||||
extern int amd_detect(bus_t *bus, uint32_t adr, cfi_array_t **cfi_array ); //Ajith
|
||||
|
||||
void
|
||||
detectflash( bus_t *bus, uint32_t adr )
|
||||
{
|
||||
cfi_query_structure_t *cfi;
|
||||
const char *s;
|
||||
|
||||
if (!bus) {
|
||||
printf( _("Error: Missing bus driver!\n") );
|
||||
return;
|
||||
}
|
||||
|
||||
cfi_array_free( cfi_array );
|
||||
cfi_array = NULL;
|
||||
|
||||
bus_prepare( bus );
|
||||
|
||||
if (cfi_detect( bus, adr, &cfi_array )) {
|
||||
cfi_array_free( cfi_array );
|
||||
cfi_array = NULL;
|
||||
if (jedec_detect( bus, adr, &cfi_array ) != 0) {
|
||||
cfi_array_free( cfi_array );
|
||||
if(amd_detect(bus, adr, &cfi_array ) != 0)
|
||||
{
|
||||
cfi_array_free( cfi_array );
|
||||
cfi_array->bus_width = 1;
|
||||
cfi_array = NULL;
|
||||
printf( _("Flash not found!\n") );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cfi = &cfi_array->cfi_chips[0]->cfi;
|
||||
|
||||
/* detect CFI capable devices */
|
||||
/* TODO: Low chip only */
|
||||
/* see 4.3.2 in [1] */
|
||||
printf( _("Query identification string:\n") );
|
||||
/* see section 2 in [2] */
|
||||
switch (cfi->identification_string.pri_id_code) {
|
||||
case CFI_VENDOR_NULL:
|
||||
s = N_("null");
|
||||
break;
|
||||
case CFI_VENDOR_INTEL_ECS:
|
||||
s = N_("Intel/Sharp Extended Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_AMD_SCS:
|
||||
s = N_("AMD/Fujitsu Standard Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_INTEL_SCS:
|
||||
s = N_("Intel Standard Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_AMD_ECS:
|
||||
s = N_("AMD/Fujitsu Extended Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_MITSUBISHI_SCS:
|
||||
s = N_("Mitsubishi Standard Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_MITSUBISHI_ECS:
|
||||
s = N_("Mitsubishi Extended Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_SST_PWCS:
|
||||
s = N_("Page Write Command Set");
|
||||
break;
|
||||
default:
|
||||
s = N_("unknown!!!");
|
||||
break;
|
||||
}
|
||||
printf( _("\tPrimary Algorithm Command Set and Control Interface ID Code: 0x%04X (%s)\n"), cfi->identification_string.pri_id_code, _(s) );
|
||||
switch (cfi->identification_string.alt_id_code) {
|
||||
case CFI_VENDOR_NULL:
|
||||
s = N_("null");
|
||||
break;
|
||||
case CFI_VENDOR_INTEL_ECS:
|
||||
s = N_("Intel/Sharp Extended Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_AMD_SCS:
|
||||
s = N_("AMD/Fujitsu Standard Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_INTEL_SCS:
|
||||
s = N_("Intel Standard Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_AMD_ECS:
|
||||
s = N_("AMD/Fujitsu Extended Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_MITSUBISHI_SCS:
|
||||
s = N_("Mitsubishi Standard Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_MITSUBISHI_ECS:
|
||||
s = N_("Mitsubishi Extended Command Set");
|
||||
break;
|
||||
case CFI_VENDOR_SST_PWCS:
|
||||
s = N_("Page Write Command Set");
|
||||
break;
|
||||
default:
|
||||
s = N_("unknown!!!");
|
||||
break;
|
||||
}
|
||||
printf( _("\tAlternate Algorithm Command Set and Control Interface ID Code: 0x%04X (%s)\n"), cfi->identification_string.alt_id_code, _(s) );
|
||||
|
||||
/* see 4.3.3 in [1] */
|
||||
printf( _("Query system interface information:\n") );
|
||||
printf( _("\tVcc Logic Supply Minimum Write/Erase or Write voltage: %d mV\n"), cfi->system_interface_info.vcc_min_wev );
|
||||
printf( _("\tVcc Logic Supply Maximum Write/Erase or Write voltage: %d mV\n"), cfi->system_interface_info.vcc_max_wev );
|
||||
printf( _("\tVpp [Programming] Supply Minimum Write/Erase voltage: %d mV\n"), cfi->system_interface_info.vpp_min_wev );
|
||||
printf( _("\tVpp [Programming] Supply Maximum Write/Erase voltage: %d mV\n"), cfi->system_interface_info.vpp_max_wev );
|
||||
printf( _("\tTypical timeout per single byte/word program: %d us\n"), cfi->system_interface_info.typ_single_write_timeout );
|
||||
printf( _("\tTypical timeout for maximum-size multi-byte program: %d us\n"), cfi->system_interface_info.typ_buffer_write_timeout );
|
||||
printf( _("\tTypical timeout per individual block erase: %d ms\n"), cfi->system_interface_info.typ_block_erase_timeout );
|
||||
printf( _("\tTypical timeout for full chip erase: %d ms\n"), cfi->system_interface_info.typ_chip_erase_timeout );
|
||||
printf( _("\tMaximum timeout for byte/word program: %d us\n"), cfi->system_interface_info.max_single_write_timeout );
|
||||
printf( _("\tMaximum timeout for multi-byte program: %d us\n"), cfi->system_interface_info.max_buffer_write_timeout );
|
||||
printf( _("\tMaximum timeout per individual block erase: %d ms\n"), cfi->system_interface_info.max_block_erase_timeout );
|
||||
printf( _("\tMaximum timeout for chip erase: %d ms\n"), cfi->system_interface_info.max_chip_erase_timeout );
|
||||
|
||||
/* see 4.3.4 in [1] */
|
||||
printf( _("Device geometry definition:\n") );
|
||||
printf( _("\tDevice Size: %d B (%d KiB, %d MiB)\n"),
|
||||
cfi->device_geometry.device_size,
|
||||
cfi->device_geometry.device_size / 1024,
|
||||
cfi->device_geometry.device_size / (1024 * 1024) );
|
||||
/* see section 4 in [2] */
|
||||
switch (cfi->device_geometry.device_interface) {
|
||||
case CFI_INTERFACE_X8:
|
||||
s = N_("x8");
|
||||
break;
|
||||
case CFI_INTERFACE_X16:
|
||||
s = N_("x16");
|
||||
break;
|
||||
case CFI_INTERFACE_X8_X16:
|
||||
s = N_("x8/x16");
|
||||
break;
|
||||
case CFI_INTERFACE_X32:
|
||||
s = N_("x32");
|
||||
break;
|
||||
case CFI_INTERFACE_X16_X32:
|
||||
s = N_("x16/x32");
|
||||
break;
|
||||
default:
|
||||
s = N_("unknown!!!");
|
||||
break;
|
||||
}
|
||||
printf( _("\tFlash Device Interface Code description: 0x%04X (%s)\n"), cfi->device_geometry.device_interface, _(s) );
|
||||
printf( _("\tMaximum number of bytes in multi-byte program: %d\n"), cfi->device_geometry.max_bytes_write );
|
||||
printf( _("\tNumber of Erase Block Regions within device: %d\n"), cfi->device_geometry.number_of_erase_regions );
|
||||
printf( _("\tErase Block Region Information:\n") );
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cfi->device_geometry.number_of_erase_regions; i++) {
|
||||
printf( _("\t\tRegion %d:\n"), i );
|
||||
printf( _("\t\t\tErase Block Size: %d B (%d KiB)\n"),
|
||||
cfi->device_geometry.erase_block_regions[i].erase_block_size,
|
||||
cfi->device_geometry.erase_block_regions[i].erase_block_size / 1024 );
|
||||
printf( _("\t\t\tNumber of Erase Blocks: %d\n"), cfi->device_geometry.erase_block_regions[i].number_of_erase_blocks );
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,380 @@
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 ETC s.r.o.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Written by Marcel Telka <marcel@telka.sk>, 2002.
|
||||
* Changed by August Hörandl, 2003
|
||||
*
|
||||
* Documentation:
|
||||
* [1] Advanced Micro Devices, "Common Flash Memory Interface Specification Release 2.0",
|
||||
* December 1, 2001
|
||||
* [2] Intel Corporation, "Intel PXA250 and PXA210 Application Processors
|
||||
* Developer's Manual", February 2002, Order Number: 278522-001
|
||||
* [3] Intel Corporation, "Common Flash Interface (CFI) and Command Sets
|
||||
* Application Note 646", April 2000, Order Number: 292204-004
|
||||
* [4] Advanced Micro Devices, "Common Flash Memory Interface Publication 100 Vendor & Device
|
||||
* ID Code Assignments", December 1, 2001, Volume Number: 96.1
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysdep.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <flash/cfi.h>
|
||||
#include <flash/intel.h>
|
||||
#include <flash/mic.h>
|
||||
|
||||
#include <flash.h>
|
||||
#include <bus.h>
|
||||
|
||||
static int intel_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr );
|
||||
static int intel_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr );
|
||||
static int intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data );
|
||||
static int intel_flash_erase_block32( cfi_array_t *cfi_array, uint32_t adr );
|
||||
static int intel_flash_unlock_block32( cfi_array_t *cfi_array, uint32_t adr );
|
||||
static int intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t data );
|
||||
|
||||
/* autodetect, we can handle this chip */
|
||||
static int
|
||||
intel_flash_autodetect32( cfi_array_t *cfi_array )
|
||||
{
|
||||
bus_area_t area;
|
||||
|
||||
if (bus_area( cfi_array->bus, cfi_array->address, &area ) != 0)
|
||||
return 0;
|
||||
|
||||
return ((cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS)
|
||||
|| (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_SCS))
|
||||
&& (area.width == 32);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_autodetect( cfi_array_t *cfi_array )
|
||||
{
|
||||
bus_area_t area;
|
||||
|
||||
if (bus_area( cfi_array->bus, cfi_array->address, &area ) != 0)
|
||||
return 0;
|
||||
|
||||
return ((cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS)
|
||||
|| (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_SCS))
|
||||
&& (area.width == 16);
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_autodetect8( cfi_array_t *cfi_array )
|
||||
{
|
||||
bus_area_t area;
|
||||
|
||||
if (bus_area( cfi_array->bus, cfi_array->address, &area ) != 0)
|
||||
return 0;
|
||||
|
||||
return ((cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS)
|
||||
|| (cfi_array->cfi_chips[0]->cfi.identification_string.pri_id_code == CFI_VENDOR_INTEL_SCS))
|
||||
&& (area.width == 8);
|
||||
}
|
||||
|
||||
static void
|
||||
_intel_flash_print_info( cfi_array_t *cfi_array, int o )
|
||||
{
|
||||
uint32_t mid, cid;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
mid = (bus_read( bus, cfi_array->address + (0x00 << o) ) & 0xFF);
|
||||
switch (mid) {
|
||||
case STD_MIC_INTEL:
|
||||
printf( _("Manufacturer: %s\n"), STD_MICN_INTEL );
|
||||
break;
|
||||
default:
|
||||
printf( _("Unknown manufacturer (0x%04X)!\n"), mid);
|
||||
break;
|
||||
}
|
||||
|
||||
printf( _("Chip: ") );
|
||||
cid = (bus_read( bus, cfi_array->address + (0x01 << o) ) & 0xFFFF);
|
||||
switch (cid) {
|
||||
case 0x0016:
|
||||
printf( "28F320J3A\n" );
|
||||
break;
|
||||
case 0x0017:
|
||||
printf( "28F640J3A\n" );
|
||||
break;
|
||||
case 0x0018:
|
||||
printf( "28F128J3A\n" );
|
||||
break;
|
||||
case 0x001D:
|
||||
printf( "28F256J3A\n" );
|
||||
break;
|
||||
case 0x8801:
|
||||
printf( "28F640K3\n" );
|
||||
break;
|
||||
case 0x8802:
|
||||
printf( "28F128K3\n" );
|
||||
break;
|
||||
case 0x8803:
|
||||
printf( "28F256K3\n" );
|
||||
break;
|
||||
case 0x8805:
|
||||
printf( "28F640K18\n" );
|
||||
break;
|
||||
case 0x8806:
|
||||
printf( "28F128K18\n" );
|
||||
break;
|
||||
case 0x8807:
|
||||
printf( "28F256K18\n" );
|
||||
break;
|
||||
case 0x880B:
|
||||
printf( "GE28F640L18T\n" );
|
||||
break;
|
||||
case 0x880C:
|
||||
printf( "GE28F128L18T\n" );
|
||||
break;
|
||||
case 0x880D:
|
||||
printf( "GE28F256L18T\n" );
|
||||
break;
|
||||
case 0x880E:
|
||||
printf( "GE28F640L18B\n" );
|
||||
break;
|
||||
case 0x880F:
|
||||
printf( "GE28F128L18B\n" );
|
||||
break;
|
||||
case 0x8810:
|
||||
printf( "GE28F256L18B\n" );
|
||||
break;
|
||||
default:
|
||||
printf( _("Unknown (0x%02X)!\n"), cid );
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read Array */
|
||||
bus_write( bus, cfi_array->address + (0 << o), 0x00FF00FF );
|
||||
}
|
||||
|
||||
static void
|
||||
intel_flash_print_info( cfi_array_t *cfi_array )
|
||||
{
|
||||
int o = 1;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
/* Intel Primary Algorithm Extended Query Table - see Table 5. in [3] */
|
||||
/* TODO */
|
||||
|
||||
/* Clear Status Register */
|
||||
bus_write( bus, cfi_array->address + (0 << o), 0x0050 );
|
||||
|
||||
/* Read Identifier Command */
|
||||
bus_write( bus, cfi_array->address + (0 << 0), 0x0090 );
|
||||
|
||||
_intel_flash_print_info( cfi_array, o );
|
||||
}
|
||||
|
||||
static void
|
||||
intel_flash_print_info32( cfi_array_t *cfi_array )
|
||||
{
|
||||
int o = 2;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
/* Intel Primary Algorithm Extended Query Table - see Table 5. in [3] */
|
||||
/* TODO */
|
||||
|
||||
/* Clear Status Register */
|
||||
bus_write( bus, cfi_array->address + (0 << o), 0x00500050 );
|
||||
|
||||
/* Read Identifier Command */
|
||||
bus_write( bus, cfi_array->address + (0 << 0), 0x00900090 );
|
||||
|
||||
_intel_flash_print_info( cfi_array, o );
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_erase_block( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
uint16_t sr;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER );
|
||||
bus_write( bus, adr, CFI_INTEL_CMD_BLOCK_ERASE );
|
||||
bus_write( bus, adr, CFI_INTEL_CMD_CONFIRM );
|
||||
|
||||
while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */
|
||||
|
||||
switch (sr & ~CFI_INTEL_SR_READY) {
|
||||
case 0:
|
||||
return 0;
|
||||
case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_PROGRAM_ERROR:
|
||||
printf( _("flash: invalid command seq\n") );
|
||||
return FLASH_ERROR_INVALID_COMMAND_SEQUENCE;
|
||||
case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_VPEN_ERROR:
|
||||
printf( _("flash: low vpen\n") );
|
||||
return FLASH_ERROR_LOW_VPEN;
|
||||
case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_BLOCK_LOCKED:
|
||||
printf( _("flash: block locked\n") );
|
||||
return FLASH_ERROR_BLOCK_LOCKED;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FLASH_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_unlock_block( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
uint16_t sr;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER );
|
||||
bus_write( bus, adr, CFI_INTEL_CMD_LOCK_SETUP );
|
||||
bus_write( bus, adr, CFI_INTEL_CMD_UNLOCK_BLOCK );
|
||||
|
||||
while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */
|
||||
|
||||
if (sr != CFI_INTEL_SR_READY) {
|
||||
printf( _("flash: unknown error while unblocking\n") );
|
||||
return FLASH_ERROR_UNKNOWN;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_program( cfi_array_t *cfi_array, uint32_t adr, uint32_t data )
|
||||
{
|
||||
uint16_t sr;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
bus_write( bus, cfi_array->address, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER );
|
||||
bus_write( bus, adr, CFI_INTEL_CMD_PROGRAM1 );
|
||||
bus_write( bus, adr, data );
|
||||
|
||||
while (!((sr = bus_read( bus, cfi_array->address ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */
|
||||
|
||||
if (sr != CFI_INTEL_SR_READY) {
|
||||
printf( _("flash: unknown error while programming\n") );
|
||||
return FLASH_ERROR_UNKNOWN;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_erase_block32( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
uint32_t sr;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
bus_write( bus, cfi_array->address, (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER << 16) | CFI_INTEL_CMD_CLEAR_STATUS_REGISTER );
|
||||
bus_write( bus, adr, (CFI_INTEL_CMD_BLOCK_ERASE << 16) | CFI_INTEL_CMD_BLOCK_ERASE );
|
||||
bus_write( bus, adr, (CFI_INTEL_CMD_CONFIRM << 16) | CFI_INTEL_CMD_CONFIRM );
|
||||
|
||||
while (((sr = bus_read( bus, cfi_array->address ) & 0x00FE00FE) & ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) ; /* TODO: add timeout */
|
||||
|
||||
if (sr != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) {
|
||||
printf( "\nsr = 0x%08X\n", sr );
|
||||
return FLASH_ERROR_UNKNOWN;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_unlock_block32( cfi_array_t *cfi_array, uint32_t adr )
|
||||
{
|
||||
uint32_t sr;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
bus_write( bus, cfi_array->address, (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER << 16) | CFI_INTEL_CMD_CLEAR_STATUS_REGISTER );
|
||||
bus_write( bus, adr, (CFI_INTEL_CMD_LOCK_SETUP << 16) | CFI_INTEL_CMD_LOCK_SETUP );
|
||||
bus_write( bus, adr, (CFI_INTEL_CMD_UNLOCK_BLOCK << 16) | CFI_INTEL_CMD_UNLOCK_BLOCK );
|
||||
|
||||
while (((sr = bus_read( bus, cfi_array->address ) & 0x00FE00FE) & ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) ; /* TODO: add timeout */
|
||||
|
||||
if (sr != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) {
|
||||
printf( "\nsr = 0x%08X\n", sr );
|
||||
return FLASH_ERROR_UNKNOWN;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
intel_flash_program32( cfi_array_t *cfi_array, uint32_t adr, uint32_t data )
|
||||
{
|
||||
uint32_t sr;
|
||||
bus_t *bus = cfi_array->bus;
|
||||
|
||||
bus_write( bus, cfi_array->address, (CFI_INTEL_CMD_CLEAR_STATUS_REGISTER << 16) | CFI_INTEL_CMD_CLEAR_STATUS_REGISTER );
|
||||
bus_write( bus, adr, (CFI_INTEL_CMD_PROGRAM1 << 16) | CFI_INTEL_CMD_PROGRAM1 );
|
||||
bus_write( bus, adr, data );
|
||||
|
||||
while (((sr = bus_read( bus, cfi_array->address ) & 0x00FE00FE) & ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) ; /* TODO: add timeout */
|
||||
|
||||
if (sr != ((CFI_INTEL_SR_READY << 16) | CFI_INTEL_SR_READY)) {
|
||||
printf( "\nsr = 0x%08X\n", sr );
|
||||
return FLASH_ERROR_UNKNOWN;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
intel_flash_readarray32( cfi_array_t *cfi_array )
|
||||
{
|
||||
/* Read Array */
|
||||
bus_write( cfi_array->bus, cfi_array->address, 0x00FF00FF );
|
||||
}
|
||||
|
||||
static void
|
||||
intel_flash_readarray( cfi_array_t *cfi_array )
|
||||
{
|
||||
/* Read Array */
|
||||
bus_write( cfi_array->bus, cfi_array->address, 0x00FF00FF );
|
||||
}
|
||||
|
||||
flash_driver_t intel_32_flash_driver = {
|
||||
4, /* buswidth */
|
||||
N_("Intel Standard Command Set"),
|
||||
N_("supported: 28Fxxxx, 2 x 16 bit"),
|
||||
intel_flash_autodetect32,
|
||||
intel_flash_print_info32,
|
||||
intel_flash_erase_block32,
|
||||
intel_flash_unlock_block32,
|
||||
intel_flash_program32,
|
||||
intel_flash_readarray32,
|
||||
};
|
||||
|
||||
flash_driver_t intel_16_flash_driver = {
|
||||
2, /* buswidth */
|
||||
N_("Intel Standard Command Set"),
|
||||
N_("supported: 28Fxxxx, 1 x 16 bit"),
|
||||
intel_flash_autodetect,
|
||||
intel_flash_print_info,
|
||||
intel_flash_erase_block,
|
||||
intel_flash_unlock_block,
|
||||
intel_flash_program,
|
||||
intel_flash_readarray,
|
||||
};
|
||||
|
||||
flash_driver_t intel_8_flash_driver = {
|
||||
1, /* buswidth */
|
||||
N_("Intel Standard Command Set"),
|
||||
N_("supported: 28Fxxxx, 1 x 8 bit"),
|
||||
intel_flash_autodetect8,
|
||||
intel_flash_print_info,
|
||||
intel_flash_erase_block,
|
||||
intel_flash_unlock_block,
|
||||
intel_flash_program,
|
||||
intel_flash_readarray,
|
||||
};
|
@ -0,0 +1,490 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <flash/cfi.h>
|
||||
#include <flash/intel.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <flash.h>
|
||||
#include <bus.h>
|
||||
|
||||
/* Manufacturers */
|
||||
#define MANUFACTURER_AMD 0x0001
|
||||
#define MANUFACTURER_ATMEL 0x001F
|
||||
#define MANUFACTURER_FUJITSU 0x0004
|
||||
#define MANUFACTURER_ST 0x0020
|
||||
#define MANUFACTURER_SST 0x00BF
|
||||
#define MANUFACTURER_TOSHIBA 0x0098
|
||||
#define MANUFACTURER_MX 0x00C2
|
||||
|
||||
/* AMD */
|
||||
#define AM29F800BB 0x2258
|
||||
#define AM29F800BT 0x22D6
|
||||
#define AM29LV800BB 0x225B
|
||||
#define AM29LV800BT 0x22DA
|
||||
#define AM29LV160DT 0x22C4
|
||||
#define AM29LV160DB 0x2249
|
||||
#define AM29BDS323D 0x22D1
|
||||
#define AM29BDS643D 0x227E
|
||||
#define AM29LV040B 0x004F
|
||||
|
||||
/* Atmel */
|
||||
#define AT49xV16x 0x00C0
|
||||
#define AT49xV16xT 0x00C2
|
||||
|
||||
/* Fujitsu */
|
||||
#define MBM29LV160TE 0x22C4
|
||||
#define MBM29LV160BE 0x2249
|
||||
#define MBM29LV800BB 0x225B
|
||||
|
||||
/* ST - www.st.com */
|
||||
#define M29W800T 0x00D7
|
||||
#define M29W160DT 0x22C4
|
||||
#define M29W160DB 0x2249
|
||||
|
||||
/* SST */
|
||||
#define SST39LF800 0x2781
|
||||
#define SST39LF160 0x2782
|
||||
|
||||
/* Toshiba */
|
||||
#define TC58FVT160 0x00C2
|
||||
#define TC58FVB160 0x0043
|
||||
|
||||
/* MX */
|
||||
#define MX29LV400T 0x22B9
|
||||
|
||||
/* Autoselect methods */
|
||||
#define AUTOSELECT_M1 0
|
||||
#define AUTOSELECT_M2 1
|
||||
#define AUTOSELECT_NUM 2
|
||||
|
||||
struct mtd_erase_region_info {
|
||||
u_int32_t offset; /* At which this region starts, from the beginning of the MTD */
|
||||
u_int32_t erasesize; /* For this region */
|
||||
u_int32_t numblocks; /* Number of blocks of erasesize in this region */
|
||||
};
|
||||
|
||||
struct amd_flash_info {
|
||||
const int mfr_id;
|
||||
const int dev_id;
|
||||
const char *name;
|
||||
const long size;
|
||||
const u_int8_t interface_width;
|
||||
const int as_method;
|
||||
const int numeraseregions;
|
||||
const struct mtd_erase_region_info regions[4];
|
||||
};
|
||||
|
||||
static const struct amd_flash_info table[] = {
|
||||
{
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29LV160DT,
|
||||
.name = "AMD AM29LV160DT",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
|
||||
{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29LV160DB,
|
||||
.name = "AMD AM29LV160DB",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
{ .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_TOSHIBA,
|
||||
.dev_id = TC58FVT160,
|
||||
.name = "Toshiba TC58FVT160",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
|
||||
{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_FUJITSU,
|
||||
.dev_id = MBM29LV160TE,
|
||||
.name = "Fujitsu MBM29LV160TE",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
|
||||
{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_TOSHIBA,
|
||||
.dev_id = TC58FVB160,
|
||||
.name = "Toshiba TC58FVB160",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
{ .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_FUJITSU,
|
||||
.dev_id = MBM29LV160BE,
|
||||
.name = "Fujitsu MBM29LV160BE",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
{ .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29LV800BB,
|
||||
.name = "AMD AM29LV800BB",
|
||||
.size = 0x00100000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
{ .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29F800BB,
|
||||
.name = "AMD AM29F800BB",
|
||||
.size = 0x00100000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
{ .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29LV800BT,
|
||||
.name = "AMD AM29LV800BT",
|
||||
.size = 0x00100000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
|
||||
{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29F800BT,
|
||||
.name = "AMD AM29F800BT",
|
||||
.size = 0x00100000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
|
||||
{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29LV800BB,
|
||||
.name = "AMD AM29LV800BB",
|
||||
.size = 0x00100000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
|
||||
{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_FUJITSU,
|
||||
.dev_id = MBM29LV800BB,
|
||||
.name = "Fujitsu MBM29LV800BB",
|
||||
.size = 0x00100000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
{ .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_ST,
|
||||
.dev_id = M29W800T,
|
||||
.name = "ST M29W800T",
|
||||
.size = 0x00100000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
|
||||
{ .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_ST,
|
||||
.dev_id = M29W160DT,
|
||||
.name = "ST M29W160DT",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
|
||||
{ .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_ST,
|
||||
.dev_id = M29W160DB,
|
||||
.name = "ST M29W160DB",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
{ .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29BDS323D,
|
||||
.name = "AMD AM29BDS323D",
|
||||
.size = 0x00400000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 3,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
|
||||
{ .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
|
||||
{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29BDS643D,
|
||||
.name = "AMD AM29BDS643D",
|
||||
.size = 0x00800000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 3,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
|
||||
{ .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
|
||||
{ .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 },
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_ATMEL,
|
||||
.dev_id = AT49xV16x,
|
||||
.name = "Atmel AT49xV16x",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 2,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 },
|
||||
{ .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_ATMEL,
|
||||
.dev_id = AT49xV16xT,
|
||||
.name = "Atmel AT49xV16xT",
|
||||
.size = 0x00200000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 2,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
|
||||
{ .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 }
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_MX,
|
||||
.dev_id = MX29LV400T,
|
||||
.name = "MX 29LV400T",
|
||||
.size = 0x0080000,
|
||||
.interface_width = CFI_INTERFACE_X16, /* correct default? */
|
||||
.as_method = AUTOSELECT_M1,
|
||||
.numeraseregions = 4,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 7 },
|
||||
{ .offset = 0x070000, .erasesize = 0x08000, .numblocks = 1 },
|
||||
{ .offset = 0x078000, .erasesize = 0x02000, .numblocks = 2 },
|
||||
{ .offset = 0x07c000, .erasesize = 0x04000, .numblocks = 1 },
|
||||
}
|
||||
}, {
|
||||
.mfr_id = MANUFACTURER_AMD,
|
||||
.dev_id = AM29LV040B,
|
||||
.name = "AMD AM29LV040B",
|
||||
.size = 0x0080000,
|
||||
.interface_width = CFI_INTERFACE_X8, /* checked, ok */
|
||||
.as_method = AUTOSELECT_M2,
|
||||
.numeraseregions = 1,
|
||||
.regions = {
|
||||
{ .offset = 0x000000, .erasesize = 0x10000, .numblocks = 8 },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
jedec_detect( bus_t *bus, uint32_t adr, cfi_array_t **cfi_array )
|
||||
{
|
||||
/* Temporary containers for manufacturer and device id while
|
||||
probing with different Autoselect methods. */
|
||||
int manid_as[AUTOSELECT_NUM], devid_as[AUTOSELECT_NUM];
|
||||
int manid = 0, devid = 0;
|
||||
int ba, bw;
|
||||
int i, j;
|
||||
cfi_query_structure_t *cfi;
|
||||
bus_area_t area;
|
||||
|
||||
*cfi_array = calloc( 1, sizeof (cfi_array_t) );
|
||||
if (!*cfi_array)
|
||||
return -2; /* out of memory */
|
||||
|
||||
(*cfi_array)->bus = bus;
|
||||
(*cfi_array)->address = adr;
|
||||
if (bus_area( bus, adr, &area ) != 0)
|
||||
return -8; /* bus width detection failed */
|
||||
bw = area.width;
|
||||
if (bw != 8 && bw != 16 && bw != 32)
|
||||
return -3; /* invalid bus width */
|
||||
(*cfi_array)->bus_width = ba = bw / 8;
|
||||
|
||||
(*cfi_array)->cfi_chips = calloc( 1, sizeof (cfi_chip_t *) );
|
||||
if (!(*cfi_array)->cfi_chips)
|
||||
return -2; /* out of memory */
|
||||
|
||||
(*cfi_array)->cfi_chips[0] = calloc( 1, sizeof (cfi_chip_t) );
|
||||
if (!(*cfi_array)->cfi_chips[0])
|
||||
return -2; /* out of memory */
|
||||
|
||||
/* probe device with Autoselect method 1 */
|
||||
bus_write(bus, adr, 0xf0);
|
||||
bus_write(bus, adr+0xaaa, 0xaa);
|
||||
bus_write(bus, adr+0x555, 0x55);
|
||||
bus_write(bus, adr+0xaaa, 0x90);
|
||||
|
||||
manid_as[AUTOSELECT_M1] = bus_read(bus, adr+0);
|
||||
devid_as[AUTOSELECT_M1] = bus_read(bus, adr+2);
|
||||
bus_write(bus, adr, 0xf0);
|
||||
|
||||
/* probe device with Autoselect method 2 */
|
||||
bus_write(bus, adr, 0xf0);
|
||||
bus_write(bus, adr+0x555, 0xaa);
|
||||
bus_write(bus, adr+0x2aa, 0x55);
|
||||
bus_write(bus, adr+0x555, 0x90);
|
||||
|
||||
manid_as[AUTOSELECT_M2] = bus_read(bus, adr+0);
|
||||
devid_as[AUTOSELECT_M2] = bus_read(bus, adr+1);
|
||||
bus_write(bus, adr, 0xf0);
|
||||
|
||||
for(i=0 ; i<sizeof(table)/sizeof(struct amd_flash_info) ; i++) {
|
||||
/* compare manufacturer and device id based on the result
|
||||
of the device's Autoselect method */
|
||||
manid = manid_as[table[i].as_method];
|
||||
devid = devid_as[table[i].as_method];
|
||||
if(manid==table[i].mfr_id && devid==table[i].dev_id) break;
|
||||
}
|
||||
fprintf(stderr, "dev ID=%04x man ID=%04x\n", devid, manid);
|
||||
|
||||
if(i==sizeof(table)/sizeof(struct amd_flash_info))
|
||||
return -4;
|
||||
|
||||
cfi = &(*cfi_array)->cfi_chips[0]->cfi;
|
||||
|
||||
cfi->identification_string.pri_id_code = CFI_VENDOR_AMD_SCS;
|
||||
cfi->identification_string.pri_vendor_tbl = NULL;
|
||||
cfi->identification_string.alt_id_code = 0;
|
||||
cfi->identification_string.alt_vendor_tbl = NULL;
|
||||
|
||||
cfi->device_geometry.device_size = table[i].size;
|
||||
/* annotate chip width */
|
||||
cfi->device_geometry.device_interface = table[i].interface_width;
|
||||
switch (table[i].interface_width) {
|
||||
case CFI_INTERFACE_X8:
|
||||
(*cfi_array)->cfi_chips[0]->width = 1;
|
||||
break;
|
||||
case CFI_INTERFACE_X16:
|
||||
(*cfi_array)->cfi_chips[0]->width = 2;
|
||||
break;
|
||||
case CFI_INTERFACE_X8_X16:
|
||||
fprintf(stderr, "Warning: Unsupported interface geometry %s, falling back to %s\n", "CFI_INTERFACE_X8_X16", "CFI_INTERFACE_X16");
|
||||
(*cfi_array)->cfi_chips[0]->width = 2;
|
||||
cfi->device_geometry.device_interface = CFI_INTERFACE_X16;
|
||||
break;
|
||||
case CFI_INTERFACE_X32:
|
||||
(*cfi_array)->cfi_chips[0]->width = 4;
|
||||
break;
|
||||
case CFI_INTERFACE_X16_X32:
|
||||
fprintf(stderr, "Warning: Unsupported interface geometry %s, falling back to %s\n", "CFI_INTERFACE_X16_X32", "CFI_INTERFACE_X32");
|
||||
(*cfi_array)->cfi_chips[0]->width = 4;
|
||||
cfi->device_geometry.device_interface = CFI_INTERFACE_X32;
|
||||
break;
|
||||
default:
|
||||
/* unsupported interface geometry */
|
||||
fprintf(stderr, "Error: Unsupported interface geometry %d, bailing out\n", table[i].interface_width);
|
||||
(*cfi_array)->cfi_chips[0]->width = 1;
|
||||
cfi->device_geometry.device_interface = CFI_INTERFACE_X8;
|
||||
return -5;
|
||||
break;
|
||||
}
|
||||
|
||||
cfi->device_geometry.number_of_erase_regions = table[i].numeraseregions;
|
||||
|
||||
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 */
|
||||
|
||||
for(j=0;j<cfi->device_geometry.number_of_erase_regions; j++) {
|
||||
cfi->device_geometry.erase_block_regions[j].erase_block_size =
|
||||
table[i].regions[j].erasesize;
|
||||
cfi->device_geometry.erase_block_regions[j].number_of_erase_blocks =
|
||||
table[i].regions[j].numblocks;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Found %s flash, size = %li bytes.\n", table[i].name, table[i].size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue