diff --git a/libbrux/.cvsignore b/libbrux/.cvsignore new file mode 100644 index 00000000..ac2c8950 --- /dev/null +++ b/libbrux/.cvsignore @@ -0,0 +1,8 @@ +.deps +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.log +config.status +configure diff --git a/libbrux/AUTHORS b/libbrux/AUTHORS new file mode 100644 index 00000000..5caef8db --- /dev/null +++ b/libbrux/AUTHORS @@ -0,0 +1 @@ +Marcel Telka diff --git a/libbrux/ChangeLog b/libbrux/ChangeLog new file mode 100644 index 00000000..46907847 --- /dev/null +++ b/libbrux/ChangeLog @@ -0,0 +1,10 @@ +2003-06-02 Marcel Telka + + * flash/cfi.c: New file. Moved from jtag module (src/flash/cfi.c). + * flash/amd.c: New file. Moved from jtag module (src/flash/amd.c). + * flash/intel.c: New file. Moved from jtag module (src/flash/intel.c). + + * autogen.sh: New file. + * configure.ac: Ditto. + * Makefile.am: Ditto. + diff --git a/libbrux/Makefile.am b/libbrux/Makefile.am new file mode 100644 index 00000000..9f2a7ead --- /dev/null +++ b/libbrux/Makefile.am @@ -0,0 +1,31 @@ +# +# $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 , 2003. +# + +include $(top_srcdir)/../Makefile.rules + +noinst_LIBRARIES = libbrux.a + +libbrux_a_SOURCES = \ + flash/cfi.c \ + flash/amd.c \ + flash/intel.c diff --git a/libbrux/NEWS b/libbrux/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/libbrux/README b/libbrux/README new file mode 100644 index 00000000..e69de29b diff --git a/libbrux/autogen.sh b/libbrux/autogen.sh new file mode 100755 index 00000000..dc57579d --- /dev/null +++ b/libbrux/autogen.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# +# $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 , 2002, 2003. +# + +if autoreconf -i -s -v -f ; then + echo + echo "autoreconf done." + echo +else + echo + echo "autoreconf failed." + echo + exit 1 +fi + +./configure --enable-maintainer-mode diff --git a/libbrux/configure.ac b/libbrux/configure.ac new file mode 100644 index 00000000..68533343 --- /dev/null +++ b/libbrux/configure.ac @@ -0,0 +1,64 @@ +# +# $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 , 2002, 2003. +# + +AC_INIT(libbrux,0.1) + +AC_PREREQ(2.54) + +AC_CONFIG_AUX_DIR(../tools) + +AM_INIT_AUTOMAKE + +AC_CONFIG_FILES( + Makefile +) + +AM_MAINTAINER_MODE + +AC_GNU_SOURCE + +AC_PROG_CC +AC_PROG_RANLIB + +AC_ARG_WITH(include, + AC_HELP_STRING([--with-include=PATH], [Path to the openwince includes]), + openwince_inc="$withval") + +AC_CACHE_CHECK([for the openwince includes], openwince_includes_path, [ + openwince_includes_path="no" + for openwince_include in $openwince_inc /usr/include/openwince /usr/local/include/openwince; do + if test -f "$openwince_include/common.h"; then + openwince_includes_path="$openwince_include" + break + fi + done +]) +if test "$openwince_includes_path" = "no"; then + AC_MSG_ERROR([The openwince include package not found.]) +fi +CPPFLAGS="$CPPFLAGS -I$openwince_includes_path -I$openwince_includes_path/device -I$openwince_includes_path/arm" + +CFLAGS="$CFLAGS -Wall" +CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/.. -I\$(top_srcdir)/../include" + +AC_OUTPUT diff --git a/libbrux/flash/amd.c b/libbrux/flash/amd.c new file mode 100644 index 00000000..8763e613 --- /dev/null +++ b/libbrux/flash/amd.c @@ -0,0 +1,253 @@ +/* + * $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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include "flash.h" +#include "bus.h" + +static int dbg = 0; + +static int amd_flash_erase_block( bus_t *bus, uint32_t adr ); +static int amd_flash_unlock_block( bus_t *bus, uint32_t adr ); +static int amd_flash_program( bus_t *bus, uint32_t adr, uint32_t data ); +static void amd_flash_read_array( bus_t *bus ); + +/* autodetect, we can handle this chip */ +static int +amd_flash_autodetect( bus_t *bus, cfi_query_structure_t *cfi ) +{ + return (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 o = 2; + 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 */ + +/* + * 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)) /* no toggle */ + 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; +} + +#if 0 +static int +amdisprotected( parts *ps, uint32_t adr ) +{ + uint32_t data; + int o = 2; + + bus_write( ps, 0x0555 << o, 0x00aa00aa ); /* autoselect p29, sector erase */ + bus_write( ps, 0x02aa << o, 0x00550055 ); + bus_write( ps, 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( bus_t *bus ) +{ + int o = 2; + int mid, cid, prot; + + bus_write( bus, 0x0555 << o, 0x00aa00aa ); /* autoselect p29 */ + bus_write( bus, 0x02aa << o, 0x00550055 ); + bus_write( bus, 0x0555 << o, 0x00900090 ); + mid = bus_read( bus, 0x00 << o ) & 0xFFFF; + cid = bus_read( bus, 0x01 << o ) & 0xFFFF; + prot = bus_read( bus, 0x02 << o ) & 0xFF; + amd_flash_read_array( bus ); /* AMD reset */ + printf( _("Chip: AMD Flash\n\tManufacturer: ") ); + switch (mid) { + case 0x0001: + printf( _("AMD") ); + break; + default: + printf( _("Unknown manufacturer (ID 0x%04x)"), mid ); + break; + } + printf( _("\n\tChip: ") ); + switch (cid) { + case 0x22D7: + printf( _("Am29LV640D/Am29LV641D/Am29LV642D") ); + break; + default: + printf ( _("Unknown (ID 0x%04x)"), cid ); + break; + } + printf( _("\n\tProtected: %04x\n"), prot ); +} + +static int +amd_flash_erase_block( bus_t *bus, uint32_t adr ) +{ + int o = 2; + + printf("flash_erase_block 0x%08X\n", adr); + + /* printf("protected: %d\n", amdisprotected(ps, adr)); */ + + bus_write( bus, 0x0555 << o, 0x00aa00aa ); /* autoselect p29, sector erase */ + bus_write( bus, 0x02aa << o, 0x00550055 ); + bus_write( bus, 0x0555 << o, 0x00800080 ); + bus_write( bus, 0x0555 << o, 0x00aa00aa ); + bus_write( bus, 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( bus ); /* AMD reset */ + return 0; + } + printf( "flash_erase_block 0x%08X FAILED\n", adr ); + /* Read Array */ + amd_flash_read_array( bus ); /* AMD reset */ + + return CFI_INTEL_ERROR_UNKNOWN; +} + +static int +amd_flash_unlock_block( bus_t *bus, uint32_t adr ) +{ + printf( "flash_unlock_block 0x%08X IGNORE\n", adr ); + return 0; +} + +static int +amd_flash_program( bus_t *bus, uint32_t adr, uint32_t data ) +{ + int o = 2; + int status; + + if (dbg) + printf("\nflash_program 0x%08X = 0x%08X\n", adr, data); + + bus_write( bus, 0x0555 << o, 0x00aa00aa ); /* autoselect p29, program */ + bus_write( bus, 0x02aa << o, 0x00550055 ); + bus_write( bus, 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( bus_t *bus ) +{ + /* Read Array */ + bus_write( bus, 0x0, 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_autodetect, + amd_flash_print_info, + amd_flash_erase_block, + amd_flash_unlock_block, + amd_flash_program, + amd_flash_read_array, +}; diff --git a/libbrux/flash/cfi.c b/libbrux/flash/cfi.c new file mode 100644 index 00000000..d07a3202 --- /dev/null +++ b/libbrux/flash/cfi.c @@ -0,0 +1,253 @@ +/* + * $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 , 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 +#include +#include + +#include "cfi.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 ) +{ + int bw; /* bus width */ + int d; /* data offset */ + int ba; /* bus width address multiplier */ + int ma; /* flash mode address multiplier */ + + 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; + bw = bus_width( bus, adr ); + 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; + ma = 1; + + /* detect CFI capable devices - see Table 1 in [1] */ + write1( CFI_CMD_QUERY_OFFSET, CFI_CMD_QUERY ); + + if (read1(CFI_QUERY_ID_OFFSET) != 'Q') { + write1( 0, CFI_CMD_READ_ARRAY1 ); + return -4; /* CFI not detected (Q) */ + } + + for (; ma <= 4; ma *= 2) + if (read1(CFI_QUERY_ID_OFFSET + 1) == 'R') + break; + if (ma > 4) { + write1( 0, CFI_CMD_READ_ARRAY1 ); + return -5; /* CFI not detected (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; +} diff --git a/libbrux/flash/intel.c b/libbrux/flash/intel.c new file mode 100644 index 00000000..5f6a569e --- /dev/null +++ b/libbrux/flash/intel.c @@ -0,0 +1,310 @@ +/* + * $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 , 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 + +#include +#include +#include +#include +#include +#include + +#include "flash.h" +#include "bus.h" + +static int intel_flash_erase_block( bus_t *bus, uint32_t adr ); +static int intel_flash_unlock_block( bus_t *bus, uint32_t adr ); +static int intel_flash_program( bus_t *bus, uint32_t adr, uint32_t data ); +static int intel_flash_erase_block32( bus_t *bus, uint32_t adr ); +static int intel_flash_unlock_block32( bus_t *bus, uint32_t adr ); +static int intel_flash_program32( bus_t *bus, uint32_t adr, uint32_t data ); + +/* autodetect, we can handle this chip */ +static int +intel_flash_autodetect32( bus_t *bus, cfi_query_structure_t *cfi ) +{ + return (cfi->identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS) && (bus_width( bus, 0 ) == 32); +} + +static int +intel_flash_autodetect( bus_t *bus, cfi_query_structure_t *cfi ) +{ + return (cfi->identification_string.pri_id_code == CFI_VENDOR_INTEL_ECS) && (bus_width( bus, 0 ) == 16); +} + +static void +_intel_flash_print_info( bus_t *bus, int o ) +{ + uint32_t mid, cid; + + mid = (bus_read( bus, 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, 0x01 << o ) & 0xFFFF); + switch (cid) { + case 0x0016: + printf( "28F320J3A\n" ); + break; + case 0x0017: + printf( "28F640J3A\n" ); + break; + case 0x0018: + printf( "28F128J3A\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; + default: + printf( _("Unknown (0x%02X)!\n"), cid ); + break; + } + + /* Read Array */ + bus_write( bus, 0 << o, 0x00FF00FF ); +} + +static void +intel_flash_print_info( bus_t *bus ) +{ + int o = 1; + /* Intel Primary Algorithm Extended Query Table - see Table 5. in [3] */ + /* TODO */ + + /* Clear Status Register */ + bus_write( bus, 0 << o, 0x0050 ); + + /* Read Identifier Command */ + bus_write( bus, 0 << 0, 0x0090 ); + + _intel_flash_print_info( bus, o ); +} + +static void +intel_flash_print_info32( bus_t *bus ) +{ + int o = 2; + /* Intel Primary Algorithm Extended Query Table - see Table 5. in [3] */ + /* TODO */ + + /* Clear Status Register */ + bus_write( bus, 0 << o, 0x00500050 ); + + /* Read Identifier Command */ + bus_write( bus, 0 << 0, 0x00900090 ); + + _intel_flash_print_info( bus, o ); +} + +static int +intel_flash_erase_block( bus_t *bus, uint32_t adr ) +{ + uint16_t sr; + + bus_write( bus, 0, 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, 0 ) & 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 CFI_INTEL_ERROR_INVALID_COMMAND_SEQUENCE; + case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_VPEN_ERROR: + printf( _("flash: low vpen\n") ); + return CFI_INTEL_ERROR_LOW_VPEN; + case CFI_INTEL_SR_ERASE_ERROR | CFI_INTEL_SR_BLOCK_LOCKED: + printf( _("flash: block locked\n") ); + return CFI_INTEL_ERROR_BLOCK_LOCKED; + default: + break; + } + + return CFI_INTEL_ERROR_UNKNOWN; +} + +static int +intel_flash_unlock_block( bus_t *bus, uint32_t adr ) +{ + uint16_t sr; + + bus_write( bus, 0, 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, 0 ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + if (sr != CFI_INTEL_SR_READY) { + printf( _("flash: unknown error while unblocking\n") ); + return CFI_INTEL_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_program( bus_t *bus, uint32_t adr, uint32_t data ) +{ + uint16_t sr; + + bus_write( bus, 0, CFI_INTEL_CMD_CLEAR_STATUS_REGISTER ); + bus_write( bus, adr, CFI_INTEL_CMD_PROGRAM1 ); + bus_write( bus, adr, data ); + + while (!((sr = bus_read( bus, 0 ) & 0xFE) & CFI_INTEL_SR_READY)) ; /* TODO: add timeout */ + + if (sr != CFI_INTEL_SR_READY) { + printf( _("flash: unknown error while programming\n") ); + return CFI_INTEL_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_erase_block32( bus_t *bus, uint32_t adr ) +{ + uint32_t sr; + + bus_write( bus, 0, (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, 0 ) & 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 CFI_INTEL_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_unlock_block32( bus_t *bus, uint32_t adr ) +{ + uint32_t sr; + + bus_write( bus, 0, (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, 0 ) & 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 CFI_INTEL_ERROR_UNKNOWN; + } else + return 0; +} + +static int +intel_flash_program32( bus_t *bus, uint32_t adr, uint32_t data ) +{ + uint32_t sr; + + bus_write( bus, 0, (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, 0 ) & 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 CFI_INTEL_ERROR_UNKNOWN; + } else + return 0; +} + +static void +intel_flash_readarray32( bus_t *bus ) +{ + /* Read Array */ + bus_write( bus, 0, 0x00FF00FF ); +} + +static void +intel_flash_readarray( bus_t *bus ) +{ + /* Read Array */ + bus_write( bus, 0, 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, +};