/* a tiny device driver to fill the eeprom on * the NetWinder yellowfin board */ #include #ifdef MODULE #ifdef MODVERSIONS #include #endif #include #include #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE < 0x10338 #ifdef MODULE #if !defined(CONFIG_MODVERSIONS) && !defined(__NO_VERSION__) char kernel_version[] = UTS_RELEASE; #endif #else #undef MOD_INC_USE_COUNT #define MOD_INC_USE_COUNT #undef MOD_DEC_USE_COUNT #define MOD_DEC_USE_COUNT #endif #endif /* 1.3.38 */ #if (LINUX_VERSION_CODE >= 0x10344) #define NEW_MULTICAST #include #endif #define BASE_ADDR 0x500 /* Offsets to the hardware */ enum yellowfin_offsets { TxCtrl=0x00, TxStatus=0x04, TxPtr=0x0C, TxIntrSel=0x10, TxBranchSel=0x14, TxWaitSel=0x18, RxCtrl=0x40, RxStatus=0x44, RxPtr=0x4C, RxIntrSel=0x50, RxBranchSel=0x54, RxWaitSel=0x58, EventStatus=0x80, IntrEnb=0x82, IntrClear=0x84, IntrStatus=0x86, ChipRev=0x8C, DMACtrl=0x90, GPio=0x9e, GPioCtrl=0x9f, Cnfg=0xA0, FrameGap0=0xA2, FrameGap1=0xA4, MII_Cmd=0xA6, MII_Addr=0xA8, MII_Wr_Data=0xAA, MII_Rd_Data=0xAC, MII_Status=0xAE, RxDepth=0xB8, FlowCtrl=0xBC, AddrMode=0xD0, StnAddr=0xD2, HashTbl=0xD8, FIFOcfg=0xF8, EEStatus=0xF0, EECtrl=0xF1, EEAddr=0xF2, EERead=0xF3, EEWrite=0xF4, EEFeature=0xF5, }; extern unsigned int board_id; extern unsigned int serial_num; int force = 0; void delay_wait(int ticks) { /* wait ticks*10 ms */ current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + ticks; schedule(); } void delay20ms(void) { //wait good 20 ms delay_wait(3); } static int read_eeprom(long ioaddr, int location) { int bogus_cnt = 100000; volatile int c; outb((0xFF & location), ioaddr + EEAddr); /* issue a read command */ outb((0x30 | ((location >> 8) & 7)), ioaddr + EECtrl); while (((c = inb(ioaddr + EEStatus)) & 0x80) && (bogus_cnt > 0)) { bogus_cnt--; } if (!bogus_cnt || c) { printk("8xc885 eeprom read error: status 0x%02X.\n",c); return(-1); } else return(inb(ioaddr + EERead) & 0xFF); } static int write_eeprom(int ioaddr, int location, int value) { int bogus_cnt = 100000; volatile int c; outb(1, ioaddr + EEFeature); //enable writing outb((location & 0xFF), ioaddr + EEAddr); outb((value & 0xFF), ioaddr + EEWrite); /* issue a write command */ outb(0x20 | ((location >> 8) & 7), ioaddr + EECtrl); while (((c = inb(ioaddr + EEStatus)) & 0x80) && (bogus_cnt > 0)) { bogus_cnt--; } if (!bogus_cnt || c) { printk("8xc885 eeprom write error: status 0x%02X.\n",c); return(-1); } // poll for ready #if 0 do { outb(0x10, ioaddr + EECtrl); //sequential read while (((c = inb(ioaddr + EEStatus)) & 0x80) && (bogus_cnt > 0)) { bogus_cnt--; } } while ((c & 0x01) && (bogus_cnt > 0)); if (!bogus_cnt || c) { printk("8xc885 eeprom write timeout: status 0x%02X.\n",c); return(-1); } #endif return (0); } /* the yellowfin chip only needs a simple add */ static unsigned char calc_checksum(unsigned char *eeprom) { int crc = 0x55; /* NB really 32 bits, int32 or __s32. */ int i; for (i = 0; i < 10; i++) /* Note: loc. 63 is the CRC. */ crc += eeprom[i]; return (unsigned char) (-(signed char)(crc & 0xff)); } int init_module(void) { int i; unsigned short sum = 0; int ioaddr; int retry; unsigned char vnc_eeprom[16] = /* Serial EEPROM contents. */ { 0x4E,0x57, /* sub vendor ID 'NW' */ 0x59,0x46, /* subsystem ID 'YF'*/ 0,0,0,0,0,0,0,0,0,0,0,0 /* 12 reserved */ }; unsigned char vnc_verify[16]; ioaddr = BASE_ADDR; // io mapped PCI memory address 0x500 if (inw(ioaddr + ChipRev) != 0x701) { printk("The YellowFin (83c885) device does not seem to be installed.\n" "No upgrade done\n"); return 0; } // set the two eeprom control bits to outputs //outb(inb(ioaddr + GPioCtrl) & 0xFC, ioaddr + GPioCtrl); #if 0 i = (read_eeprom(ioaddr, 5) << 8) + read_eeprom(ioaddr, 6); if (i==0x1057 && force==0) { printk("This YellowFin (8xc885) board has already been initialized.\n" "To force a new config, uninstall this module and reinstall with\n" " insmod yellow_upgd.o force=1\n"); return 0; } #endif printk("Upgrading board rev. %X serial #: %d (0x%x)...\n",board_id, serial_num,serial_num); vnc_eeprom[4] = 0; vnc_eeprom[5] = 0x10; vnc_eeprom[6] = 0x57; vnc_eeprom[7] = 0xC0; vnc_eeprom[8] = serial_num >> 8; vnc_eeprom[9] = serial_num; i = calc_checksum(vnc_eeprom); vnc_eeprom[10] = i & 0xFF; for (i = 0; i < 11; i++) { vnc_verify[i] = ~vnc_eeprom[i]; retry = 100; while (retry & vnc_verify[i] != vnc_eeprom[i]) { write_eeprom(ioaddr, i, vnc_eeprom[i]); delay20ms(); vnc_verify[i] = read_eeprom(ioaddr, i); } if (!retry) { printk("Verify error!\n"); return(i+1); } } // now program the same stuff directly in the StationAddress regs // that way we do not need to wait till reset for chip to read it in for (i = 0; i < 6; i++) { outb(vnc_eeprom[4+i], ioaddr + StnAddr + i); } printk("Done OK..\n"); return(0); } void cleanup_module(void) { }