# amdchips.S86 - Low level routines for AMD like flash EPROM chip access # # Copyright (C) 2002-2003 Gero Kuhlmann # # 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 # 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., 675 Mass Ave, Cambridge, MA 02139, USA. # # $Id: amdchips.S86,v 1.1 2003/03/09 00:43:08 gkminix Exp $ # #==================================================================== # #include "common.i86" #include "flash.i86" .file "amdchips.S86" .line 30 # #==================================================================== # # Internal additions to the flash EPROM chip definition structure # FSTRUCT_ID .equ FSTRUCT_INT + H'0000 # offset to chip ID FSTRUCT_SNUM .equ FSTRUCT_INT + H'0004 # offset to number of sectors FSTRUCT_SSIZE .equ FSTRUCT_INT + H'0006 # offset to sector size FSTRUCT_FLAGS .equ FSTRUCT_INT + H'0008 # offset to special flags FSTRUCT_ISIZE .equ FSTRUCT_INT + H'000A # total size of structure FFLAG_SNGL_RST .equ H'0001 # flag for single-byte reset # #==================================================================== # # Definitions used for programming AMD Flash EPROM chips # MASK_LARGE .equ H'7FFF # large command address mask MASK_SMALL .equ H'07FF # small command address mask CMDOFS1 .equ H'2AAA # first command address CMDOFS2 .equ H'5555 # second command address CMDOP1 .equ H'55 # first command opcode CMDOP2 .equ H'AA # second command opcode ERASE1_CMD .equ H'80 # first command for erasing full chip ERASE2_CMD .equ H'10 # second command for erasing full chip ERASE3_CMD .equ H'30 # second command for erasing one sector READID_CMD .equ H'90 # command to read chip ID PROG_CMD .equ H'A0 # command to program a byte RESET_CMD .equ H'F0 # command to reset chip state machine .line 68 # #==================================================================== # # Public routines defined in this module # \(.text) .global amd_readid .global amd_erase .global amd_doprog # #==================================================================== # # Read manufacturer ID from Flash-EPROM # Input: BX - Pointer to interface definition structure # Output: SI - Pointer to Flash EPROM info structure, zero if no # Flash EPROM found # Changed registers: AX, SI # amd_readid: push edx push edi # Read the manufacturer and device ID from the chip, if there is a # chip. It is the responsibility of the caller to ensure that this # routine does not write into RAM. Also note that at least AMD has # introduced a 3-byte device ID code. We read the entire code into # EDX, with the highest word being zero if there is only a single- # byte ID. mov dword ptr [addrmask],MASK_LARGE mov word ptr [curchip],0 rdid1: xor edx,edx # clear device ID mov al,READID_CMD call sendop # send READID command xor edi,edi call [bx + ISTRUCT_READ] # read manufacturer ID mov dl,al inc edi call [bx + ISTRUCT_READ] # read device ID mov dh,al cmp al,0x7E # check if three byte ID code jne rdid2 shl edx,16 mov edi,0x000E call [bx + ISTRUCT_READ] # read second byte of device ID mov dl,al inc edi call [bx + ISTRUCT_READ] # read third byte of device ID mov dh,al rol edx,16 # Now find the chip in the list of supported Flash EPROMS. rdid2: mov si,offset cstruct_list rdid3: mov ax,[si + FSTRUCT_INTID] or ax,ax # check if end of list jz rdid4 cmp edx,[si + FSTRUCT_ID] # find chip ID in chip list je rdid5 add si,FSTRUCT_ISIZE jmp rdid3 # If we couldnt find the chip, reset the chip (if that works at # all) and try to read the ID again, this time with the smaller # address mask. rdid4: call reset xor si,si xor dx,dx cmp dword ptr [addrmask],MASK_SMALL je rdid8 mov dword ptr [addrmask],MASK_SMALL jmp rdid1 # We found the chip, so save the pointer to the chip definition # structure and terminate the ID reading mode by resetting the # chip. rdid5: mov [curchip],si call reset rdid8: pop edi pop edx ret # #==================================================================== # # Erase the memory area occupied by the rom image. If the Flash EPROM # is not a uniform sector type, we simply erase the whole chip. # Input: BX - Pointer to interface definition structure # EDI - Offset to rom image block within EPROM # ECX - Number of bytes to erase # Output: carry flag set if error # Registers changed: EAX # amd_erase: push edx push ecx push edi push si mov si,[curchip] mov eax,edi add eax,ecx cmp eax,[si + FSTRUCT_ROMSIZE] jae erase8 # check if EPROM size exceeded mov [imgstart],edi # save values for later reference mov [imgend],eax mov [imglen],ecx # If the chip has a uniform sector layout, we only need to erase the # sectors which get occupied by the new EPROM image. mov dx,[si + FSTRUCT_SNUM] or dx,dx # check if uniform sector layout jz erase3 movzx32 eax,word ptr [si + FSTRUCT_SSIZE] dec eax not eax # compute offset to first sector and edi,eax mov ecx,[imgend] sub ecx,edi mov ax,cx shr ecx,16 # compute number of sectors to erase mov dx,cx div word ptr [si + FSTRUCT_SSIZE] or dx,dx # check if number of bytes is multiple jz erase1 # of sector size inc ax # round up to next sector size erase1: mov cx,ax mov edx,edi erase2: mov al,ERASE1_CMD call sendop # send ERASE1 command mov al,ERASE3_CMD call sendop # send ERASE3 command mov al,0xFF call waitop # wait until operation finished jc erase7 movzx32 eax,word ptr [si + FSTRUCT_SSIZE] add edx,eax # continue with next sector loop erase2 clc jmp erase9 # If the chip has a boot block sector layout, we only need to erase the # sectors which get occupied by the new EPROM image. erase3: mov dx,[si + FSTRUCT_SSIZE] or dx,dx # check if boot sector layout jz erase6 cld mov si,dx lodsw # get number of sectors mov cx,ax erase4: lodsd # get offset to next sector mov edx,eax mov eax,[si] # check if sector is within cmp edx,[imgstart] # programming limits jae eraseA cmp eax,[imgstart] jbe erase5 eraseA: cmp edx,[imgend] jae erase5 mov al,ERASE1_CMD call sendop # send ERASE1 command mov al,ERASE3_CMD call sendop # send ERASE3 command mov al,0xFF call waitop # wait until operation finished jc erase7 erase5: loop erase4 # continue with next sector clc jmp erase9 # The chip doesnt have a sector layout so we erase everything. erase6: mov al,ERASE1_CMD call sendop # send ERASE1 command mov al,ERASE2_CMD call sendop # send ERASE2 command mov al,0xFF xor edi,edi call waitop # wait until operation finished jnc erase9 erase7: call reset # reset chip in case of error erase8: stc erase9: pop si pop edi pop ecx pop edx ret # #==================================================================== # # Program one byte into Flash EPROM chip # Input: BX - Pointer to interface definition structure # AL - Byte value to program # EDI - Offset into Flash EPROM # Output: carry flag set if error # Registers changed: EAX # amd_doprog: cmp edi,[imgstart] jb prog8 # check if address is within limits cmp edi,[imgend] jae prog8 push ax call [bx + ISTRUCT_READ] cmp al,0xFF # the value at the programming pop ax # location has to be erased jne prog8 push ax push edi mov al,PROG_CMD call sendop # send programming command pop edi pop ax call [bx + ISTRUCT_WRITE] # write next byte into EPROM call waitop # wait until programming jnc prog9 # operation is completed prog8: stc prog9: ret # #==================================================================== # # Send reset command to flash EPROM. # Input: BX - Pointer to interface definition structure # Output: None # Registers changed: AX # reset: push si mov si,[curchip] push edi mov al,RESET_CMD or si,si jz reset1 test word ptr [si + FSTRUCT_FLAGS],FFLAG_SNGL_RST jz reset1 xor edi,edi call [bx + ISTRUCT_WRITE] jmp reset9 reset1: call sendop reset9: pop edi pop si ret # #==================================================================== # # Send OP code to Flash-EPROM. This involves writing three bytes into the # flash EPROM at exactly specified locations. See AMD data sheets for # further information. # Input: AL - Command byte # BX - Pointer to interface definition structure # EDX - Sector offset (only for sector erase command) # Output: EDI - Sector offset (only for sector erase command) # Registers changed: AX, EDI # sendop: push ax mov al,CMDOP2 mov edi,CMDOFS2 and edi,[addrmask] call [bx + ISTRUCT_WRITE] mov al,CMDOP1 mov edi,CMDOFS1 and edi,[addrmask] call [bx + ISTRUCT_WRITE] pop ax mov edi,CMDOFS2 and edi,[addrmask] cmp al,ERASE3_CMD jne sndop1 mov edi,edx sndop1: call [bx + ISTRUCT_WRITE] ret # #==================================================================== # # Wait for the chip to process programming/erase. When programming is in # progress, the flash EPROM toggles the highest bit, and converts it back # to its original value when the programming is done. For a further ex- # planation of this algorithm see the data sheets. # Input: AL - Programmed byte # BX - Pointer to interface definition structure # EDI - Offset to programming location # Output: carry flag set if error # Registers changed: AX # waitop: push cx and al,0B10000000 mov cl,al wait1: call [bx + ISTRUCT_READ] mov ch,al and al,0B10000000 cmp cl,al je wait8 test ch,0B00100000 jz wait1 call [bx + ISTRUCT_READ] and al,0B10000000 cmp cl,al je wait8 stc jmp wait9 wait8: clc wait9: pop cx ret # #==================================================================== # # String and constants definitions # \(.data) # Names of Flash EPROM chips which can be used by this program name10: .asciz "AT29C512" name11: .asciz "AT29C010A" name12: .asciz "AT49F512" name13: .asciz "AT49(F)(LV)(BV)001(N)" name14: .asciz "AT49(F)(LV)(BV)001(N)T" name15: .asciz "AT29LV512" name16: .asciz "AT29LV010A" name20: .asciz "SST29EE010" name21: .asciz "SST29LE010" name22: .asciz "SST39SF010" name23: .asciz "SST39VF010" name24: .asciz "SST39VF512" name30: .asciz "AM29LV010" name31: .asciz "AM29F010" name32: .asciz "AM29LV001BB" name33: .asciz "AM29LV001BT" name40: .asciz "STM29F512" name41: .asciz "STM29F010B" name42: .asciz "STM29W512" name43: .asciz "STM29W010B" # List of Flash EPROM definition structures cstruct_list: # Atmel chips .word CHIP_AT29C512 # internal chip ID number .word name10 # offset to chip name .long 65536 # total size in bytes .byte 0x1F, 0x5D, 0x00, 0x00 # chip ID code .word 512 # number of sectors .word 128 # size of each sector in bytes .word 0 # flags .word CHIP_AT29C010 .word name11 .long 131072 .byte 0x1F, 0xD5, 0x00, 0x00 .word 1024 .word 128 .word 0 .word CHIP_AT49F512 .word name12 .long 65536 .byte 0x1F, 0x03, 0x00, 0x00 .word 0 # this chip has no individually .word 0 # erasable sectors .word 0 .word CHIP_AT49F001N .word name13 .long 131072 .byte 0x1F, 0x05, 0x00, 0x00 .word 0 .word sects13 .word 0 .word CHIP_AT49F001T .word name14 .long 131072 .byte 0x1F, 0x04, 0x00, 0x00 .word 0 .word sects14 .word 0 .word CHIP_AT29LV512 .word name15 .long 65536 .byte 0x1F, 0x3D, 0x00, 0x00 .word 512 .word 128 .word 0 .word CHIP_AT29LV010 .word name16 .long 131072 .byte 0x1F, 0x35, 0x00, 0x00 .word 1024 .word 128 .word 0 # SST chips .word CHIP_SST29EE010 .word name20 .long 131072 .byte 0xBF, 0x07, 0x00, 0x00 .word 1024 .word 128 .word 0 .word CHIP_SST29LE010 .word name21 .long 131072 .byte 0xBF, 0x08, 0x00, 0x00 .word 1024 .word 128 .word 0 .word CHIP_SST39SF010 .word name22 .long 131072 .byte 0xBF, 0xB5, 0x00, 0x00 .word 32 .word 4096 .word 0 .word CHIP_SST39VF010 .word name23 .long 131072 .byte 0xBF, 0xD5, 0x00, 0x00 .word 32 .word 4096 .word 0 .word CHIP_SST39VF512 .word name24 .long 65536 .byte 0xBF, 0xD4, 0x00, 0x00 .word 16 .word 4096 .word 0 # AMD chips .word CHIP_AM29LV010 .word name30 .long 131072 .byte 0x01, 0x6B, 0x00, 0x00 .word 8 .word 16384 .word FFLAG_SNGL_RST .word CHIP_AM29F010 .word name31 .long 131072 .byte 0x01, 0x20, 0x00, 0x00 .word 8 .word 16384 .word 0 .word CHIP_AM29LV001B .word name32 .long 131072 .byte 0x01, 0x6D, 0x00, 0x00 .word 0 .word sects32 .word FFLAG_SNGL_RST .word CHIP_AM29LV001T .word name33 .long 131072 .byte 0x01, 0xED, 0x00, 0x00 .word 0 .word sects33 .word FFLAG_SNGL_RST # ST microelectronics chips .word CHIP_STM29F512 .word name40 .long 65536 .byte 0x20, 0x24, 0x00, 0x00 .word 0 # this chip has no individually .word 0 # erasable sectors .word 0 .word CHIP_STM29F010 .word name41 .long 131072 .byte 0x20, 0x20, 0x00, 0x00 .word 8 .word 16384 .word 0 .word CHIP_STM29W512 .word name42 .long 65536 .byte 0x20, 0x27, 0x00, 0x00 .word 0 # this chip has no individually .word 0 # erasable sectors .word 0 .word CHIP_STM29W010 .word name43 .long 131072 .byte 0x20, 0x23, 0x00, 0x00 .word 8 .word 16384 .word 0 .word 0 # end of list # Sector table for AT49F001N sects13: .word 5 # number of sectors .long 0x00000 .long 0x04000 .long 0x06000 .long 0x08000 .long 0x10000 # Sector table for AT49F001T sects14: .word 5 # number of sectors .long 0x00000 .long 0x10000 .long 0x18000 .long 0x1A000 .long 0x1C000 # Sector table for AM29LV001BB sects32: .word 10 # number of sectors .long 0x00000 .long 0x04000 .long 0x08000 .long 0x0C000 .long 0x10000 .long 0x14000 .long 0x18000 .long 0x1C000 .long 0x1D000 .long 0x1E000 # Sector table for AM29LV001BT sects33: .word 10 # number of sectors .long 0x00000 .long 0x02000 .long 0x03000 .long 0x04000 .long 0x08000 .long 0x0C000 .long 0x10000 .long 0x14000 .long 0x18000 .long 0x1C000 # #==================================================================== # # Variable definitions # \(.bss) .lcomm curchip,2 # pointer to current chip structure .lcomm addrmask,4 # command address mask .lcomm imgstart,4 # start offset of rom image .lcomm imgend,4 # end offset of rom image .lcomm imglen,4 # length of rom image # #==================================================================== # .end