# 3c90xbc.S86 - Routines for supporting 3C90xB/C cards # # 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: 3c90xbc.S86,v 1.1 2003/03/09 00:43:08 gkminix Exp $ # #==================================================================== # #include "common.i86" #include "flash.i86" .file "3c90xbc.S86" .line 30 # #==================================================================== # # Some definitions which are local to this module # PCI_VENDOR .equ H'10B7 # 3Com PCI vendor ID EEPROM_VENDOR .equ H'6D50 # Manufacturer ID # 3C90xB/C on-chip registers STATUS_REG .equ H'000E # NIC status register CMD_REG .equ H'000E # NIC command register CMD_SELBANK .equ H'0800 # Select register bank command CONFIG_BANK .equ H'0003 # Bank for accessing internal config CONFIG_REG .equ H'0000 # Internal configuration register CONFIG_ROMSIZE .equ H'000000C0 # Rom size value CONFIG_ROMFLG .equ H'02000000 # Rom disable flag ROMSIZE_64 .equ H'00000000 # 64kB ROM size ROMSIZE_128 .equ H'00000040 # 128kB ROM size ROM_BANK .equ H'0000 # Bank for accessing ROM registers ROM_ADDR .equ H'0004 # Address for next access to Flash ROM ROM_DATA .equ H'0008 # Data port for Flash ROM access EEPROM_BANK .equ H'0000 # Bank for accessing EEPROM registers EEPROM_CMD .equ H'000A # EEPROM command register EEPROM_DATA .equ H'000C # EEPROM data register EEPROM_CMDMASK .equ H'00C0 # EEPROM command mask EEPROM_ADRMASK .equ H'0F3F # EEPROM address mask EEPROM_READ .equ H'0080 # EEPROM read command EEPROM_WRITE .equ H'0040 # EEPROM write command EEPROM_ERASE .equ H'00C0 # EEPROM erase command EEPROM_BUSY .equ H'8000 # EEPROM busy bit # 3C90xB/C PCI configuration registers PCI_IOBASE .equ H'0010 # I/O base address register PCI_IOADDRMASK .equ H'FFFFFFF8 # Mask to select I/O base address PCI_IOENABMASK .equ H'00000001 # Mask to select I/O register access PCI_HEADERTYPE .equ H'000E # PCI header type PCI_DEFHEADER .equ H'00 # Default PCI header type # 3C90xB/C serial EEPROM configuration data. Note that the B series NIC # only supports up to 64 EEPROM values, while the C series supports up # to 512 EEPROM values. The first couple of values are the same with all # NICs. EEPROM_ADDR0 .equ H'0000 # Offset to node address (word 0) EEPROM_ADDR1 .equ H'0001 # Offset to node address (word 1) EEPROM_ADDR2 .equ H'0002 # Offset to node address (word 2) EEPROM_DEVICEID .equ H'0003 # Offset to PCI device ID EEPROM_MANDATE .equ H'0004 # Offset to manufacturing date EEPROM_MANDIV .equ H'0005 # Offset to manufacturing division EEPROM_MANPROD .equ H'0006 # Offset to manufacturer product code EEPROM_MANID .equ H'0007 # Offset to manufacturer ID EEPROM_PCIPARM .equ H'0008 # Offset to PCI parameters EEPROM_ROMINFO .equ H'0009 # Offset to ROM info EEPROM_MAX .equ 10 # max. number of EEPROM entries .line 99 # #==================================================================== # # Define some external routines # \(.text) # The 3C90xB/C NICs only support Flash EPROMs which get programmed # using the AMD programming algorithm. .extern amd_readid # read Flash EPROM ID .extern amd_erase # erase area of Flash EPROM .extern amd_doprog # program a byte into Flash EPROM .extern fndpci # find PCI device .extern gen_verify # generic verification routine # #==================================================================== # # Detect Flash EPROM interface # Input: FS:SI - Pointer to bootrom image # Output: EDI - Start offset into Flash EPROM for bootrom image # ECX - Size of Flash EPROM available for bootrom image # EAX - Linear address of Flash EPROM (zero if N/A) # DX - Offset to Flash EPROM info structure # Carry set if interface not found # Changed registers: EAX, EBX, ECX, EDX, EDI # ifdetect: push esi # Try to find the NIC in the system mov bx,offset nic_list mov dx,PCI_VENDOR call fndpci jc detec8 shl ax,1 mov si,ax mov ax,name_list[si] # save pointer to NIC name mov [istruct_3c90xbc + ISTRUCT_ID],ax mov [pcipfn],bx # save card identification number # The chip has to report PCI header type 0, otherwise all PCI register # offsets are wrong. mov ax,0xB108 mov di,PCI_HEADERTYPE int 0x1A # call BIOS to get PCI header type jc detec8 cmp cl,PCI_DEFHEADER # check if default header type jne detec8 # Now read the I/O base address from the PCI configuration space. Note that # we can only access the chip using I/O, not using memory mapping, so we # check for this. mov ax,0xB10A mov bx,[pcipfn] mov di,PCI_IOBASE int 0x1A # call BIOS to get I/O base address jc detec8 or ecx,ecx # ressource has to be assigned by BIOS jz detec8 test ecx,PCI_IOENABMASK # check if registers are I/O based jz detec8 and ecx,PCI_IOADDRMASK test ecx,0xFFFF0000 # I/O address has to be within 64kB jnz detec8 mov [ioaddr],cx # save I/O address # Read the size of the Flash EPROM from the internal configuration register. # We consider this size as a window size, e.g. the size which is addressable # by the CPU. The real size of the Flash EPROM can be larger. call save_bank # save old register bank mov al,CONFIG_BANK call set_bank # set bank for configuration register mov dx,cx .ifne CONFIG_REG add dx,CONFIG_REG .endif in eax,dx # read internal config register test eax,CONFIG_ROMFLG # check if Flash EPROM enabled jnz detec8 and eax,CONFIG_ROMSIZE mov ecx,65536 cmp eax,ROMSIZE_64 # determine size of Flash EPROM je detec4 shl ecx cmp eax,ROMSIZE_128 jne detec8 detec4: mov [winsize],ecx # save Flash EPROM window size # Read the serial EEPROM to get configuration data, and check that we # indeed have a 3Com NIC. .ifne CONFIG_BANK - EEPROM_BANK mov al,EEPROM_BANK call set_bank # set bank for EEPROM command register .endif xor si,si mov di,offset eeprom mov cx,EEPROM_MAX detec5: call read_eeprom # read value from serial EEPROM mov [di],ax # save value into temp storage add di,2 inc si loop detec5 cmp word ptr [eeprom + EEPROM_MANID * 2],EEPROM_VENDOR jne detec8 # We have set all internal variables so far, so we can try finding a supported # Flash EPROM chip. .ifne EEPROM_BANK - ROM_BANK mov al,ROM_BANK # set register bank to access ROM call set_bank .endif mov bx,offset istruct_3c90xbc call amd_readid # read ID from Flash EPROM or si,si jz detec7 mov ecx,[si + FSTRUCT_ROMSIZE] cmp ecx,[winsize] # check that the Flash EPROM size is jb detec8 # within the window size mov [romsize],ecx # save physical size of Flash EPROM mov al,[oldbank] call set_bank # restore old register bank mov ecx,[winsize] # return without error xor edi,edi xor eax,eax mov dx,si jmp detec9 # Return to caller. If we switched register banks before, restore the old # bank before returning. detec7: mov al,[oldbank] # restore old register bank call set_bank detec8: stc # return with error detec9: pop esi ret # #==================================================================== # # Read one byte from Flash EPROM. This routine assumes that the NIC chip # has been set to register window 0 already. # Input: EDI - Offset into Flash EPROM # Output: AL - Byte value # Changed registers: AL # ifread: push dx xor al,al cmp edi,[winsize] # check if valid offset jae read9 mov dx,[ioaddr] add dx,ROM_ADDR xchg eax,edi out dx,eax # write offset into Flash EPROM xchg eax,edi add dx,ROM_DATA - ROM_ADDR in al,dx # read data value read9: pop dx ret # #==================================================================== # # Write one byte into Flash EPROM. This routine assumes that the NIC chip # has been set to register window 0 already. # Input: EDI - Offset into Flash EPROM # AL - Byte value # Output: none # Changed registers: none # ifwrite: push dx cmp edi,[winsize] # check if valid offset jae write9 mov dx,[ioaddr] add dx,ROM_ADDR xchg eax,edi out dx,eax # write offset into Flash EPROM xchg eax,edi add dx,ROM_DATA - ROM_ADDR out dx,al # write data value write9: pop dx ret # #==================================================================== # # Initialize NIC for programming. This just sets the register bank to 0. # Input: none # Output: none # Changed registers: AX # ifinit: call save_bank # save old register bank number mov al,ROM_BANK call set_bank # set new register bank clc ret # #==================================================================== # # Terminate programming. This restores the register bank. Note that this # routine does not enable the Flash EPROM. If its not already enabled, # this task should be done by a NIC configuration program. It requires # manipulating the serial configuration EEPROM. # Input: none # Output: none # Changed registers: AX # ifclean: mov al,[oldbank] call set_bank # set old register bank clc ret # #==================================================================== # # Turn programming voltage VPP on # Input: none # Output: none # Changed registers: none # ifvppon: # fall through # #==================================================================== # # Turn programming voltage VPP off # Input: none # Output: none # Changed registers: none # ifvppoff: stc ret # #==================================================================== # # Erase the Flash EPROM area occupied by the rom image. We simply call # the routine for the Flash EPROM chip. # Input: EDI - Offset to rom image block within EPROM # ECX - Number of bytes to erase # Output: carry flag set if error # Registers changed: EAX # iferase: push bx mov bx,offset istruct_3c90xbc call amd_erase # call chip erasure routine pop bx ret # #==================================================================== # # Program a memory area into the Flash EPROM. # Input: FS:SI - Pointer to memory area with source data # ECX - Number of bytes to program # EDI - Offset to rom image block within EPROM # Output: carry flag set if error # Registers changed: EAX # ifprog: push bx push ecx push edi push si push fs mov bx,offset istruct_3c90xbc prog1: mov al,fs:[si] call amd_doprog # program one byte into Flash EPROM jc prog9 inc si # increment source pointer test si,0x8000 jz prog2 # avoid source pointer overflow mov ax,fs add ax,0x0800 mov fs,ax and si,0x7FFF prog2: inc edi # increment offset into Flash EPROM data32 loop prog1 # continue with next byte clc prog9: pop fs pop si pop edi pop ecx pop bx ret # #==================================================================== # # Verify a memory area against the contents of the Flash EPROM. # Input: FS:SI - Pointer to memory area with source data # ECX - Number of bytes to verify # EDI - Offset to rom image block within EPROM # Output: carry flag set if error # Registers changed: EAX # ifverify: push bx mov bx,offset istruct_3c90xbc call gen_verify # call generic routine pop bx ret # #==================================================================== # # Save current register bank number # Input: none # Output: AL - Old register bank number # Changed registers: AX # save_bank: push dx mov dx,[ioaddr] add dx,STATUS_REG in ax,dx shr ax,13 and ax,0x0007 mov [oldbank],al pop dx ret # #==================================================================== # # Set new register bank # Input: AL - Register bank number # Output: none # Changed registers: AX # set_bank: push dx mov dx,[ioaddr] add dx,CMD_REG xor ah,ah add ax,CMD_SELBANK out dx,ax pop dx ret # #==================================================================== # # Read one word from NIC serial EEPROM. This routine assumes that the # EEPROM register bank has been activated already. # Input: SI - Offset into serial EEPROM # Output: AX - Word read from serial EEPROM # Changed registers: AX # read_eeprom: push bx push dx mov dx,[ioaddr] add dx,EEPROM_CMD reade1: in ax,dx # wait until the EEPROM interface test ax,EEPROM_BUSY # is no longer busy jnz reade1 mov ax,si and ax,0x003F mov bx,si # compute address into serial EEPROM shl bx,2 and bx,0x0F00 or ax,bx and ax,EEPROM_ADRMASK or ax,EEPROM_READ # add read command out dx,ax # send read command jcxz reade2 reade2: jcxz reade3 # wait a little bit reade3: in ax,dx # wait until the EEPROM interface test ax,EEPROM_BUSY # is no longer busy jnz reade3 add dx,EEPROM_DATA - EEPROM_CMD in ax,dx # read data value pop dx pop bx ret # #==================================================================== # # String and constants definitions # \(.data) .global istruct_3c90xbc # List of NICs supported by this module pci_list: .word PCI_VENDOR nic_list: .word 0x9200 .word 0x9805 .word 0x9004 .word 0x9005 .word 0x9006 .word 0x900A .word 0x9055 .word 0x9056 .word 0x9058 .word 0x905A .word 0 # NIC names name_3c905c: .asciz "3Com 3C905C" name_3c980c: .asciz "3Com 3C980C" name_3c900btpo: .asciz "3Com 3C900B TPO" name_3c900bcombo: .asciz "3Com 3C900B Combo" name_3c900btpc: .asciz "3Com 3C900B TPC" name_3c900bfl: .asciz "3Com 3C900B FL" name_3c905btx: .asciz "3Com 3C905B TX" name_3c905bt4: .asciz "3Com 3C905B T4" name_3c905bcombo: .asciz "3Com 3C905B Combo" name_3c905bfx: .asciz "3Com 3C905B FX" name_list: .word name_3c905c .word name_3c980c .word name_3c900btpo .word name_3c900bcombo .word name_3c900btpc .word name_3c900bfl .word name_3c905btx .word name_3c905bt4 .word name_3c905bcombo .word name_3c905bfx # Interface definition istruct_3c90xbc: .word 0 # pointer to interface name .word IDEVTYPE_PCI # interface device type .word pci_list # pointer to PCI ID list .word ifdetect # pointer to detection routine .word ifread # pointer to byte read routine .word ifwrite # pointer to byte write routine .word ifvppon # pointer to VPP-on routine .word ifvppoff # pointer to VPP-off routine .word ifinit # pointer to initialization routine .word ifclean # pointer to cleanup routine .word iferase # pointer to erase routine .word ifprog # pointer to programming routine .word ifverify # pointer to verify routine .word 0 # no loader necessary .word 0 # no further flags necessary # #==================================================================== # # Variable definitions # \(.bss) .lcomm pcipfn,2 # PCI identification number for card .lcomm ioaddr,2 # I/O address for register access .lcomm romsize,4 # size of physical Flash ROM .lcomm winsize,4 # size of Flash ROM window .lcomm oldbank,1 # saved bank number .lcomm eeprom,EEPROM_MAX * 2 # area to save EEPROM values # #==================================================================== # .end