/* 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; #if 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); } #endif int gp_ack(GPctrl, GPreg, ioaddr) { volatile int ack; //8 bits clocked - read acknowledge // make GP0 input, GP1 still output (clock) outb(GPctrl | 1, ioaddr + GPioCtrl); outb(GPreg , ioaddr + GPio); //data lo, clock lo udelay(1); outb(GPreg | 2, ioaddr + GPio); //data lo, clock hi udelay(1); ack = inb(ioaddr + GPio); outb(GPreg , ioaddr + GPio); //data lo, clock lo // make GP0 and 1 outputs outb(GPctrl , ioaddr + GPioCtrl); if (ack & 0x01) { printk("Ack error!\n"); return(1); } return(0); } void gp_write_byte(data, GPreg, ioaddr) { int i; for (i = 7; i>=0; i--) { udelay(1); if (data & (1<=0; i--) { udelay(1); outb(GPreg | 2, ioaddr + GPio); //data lo, clock hi ack = inb(ioaddr + GPio); ack &= 0x01; ack <<= i; data |= ack; udelay(1); outb(GPreg , ioaddr + GPio); //data lo, clock lo udelay(2); } // make GP0 and 1 outputs outb(GPctrl , ioaddr + GPioCtrl); //================================================================= // generate stop condition udelay(2); outb(GPreg | 2, ioaddr + GPio); //data lo, clock hi udelay(2); outb(GPreg | 3, ioaddr + GPio); //data hi, clock hi outb(GPctrl | 3, ioaddr + GPioCtrl); return(data); } static int read_eeprom(long ioaddr, int location) { int bogus_cnt = 100000; volatile unsigned char status; volatile unsigned char data; outb(location, ioaddr + EEAddr); /* issue a read command */ outb(0x30 | ((location >> 8) & 7), ioaddr + EECtrl); while (((status=inb(ioaddr + EEStatus)) & 0x80) && --bogus_cnt > 0) ; data = inb(ioaddr + EERead); if (status) printk ("Suspect read problem: address 0x%02X, data 0x%02X, status 0x%02X.\n", location, data, status); return data; } static void write_eeprom(int ioaddr, int location, int value) { int bogus_cnt = 100000; outb(1, ioaddr + EEFeature); outb(location, ioaddr + EEAddr); outb(value, ioaddr + EEWrite); /* issue a write command */ outb(0x20 | ((location >> 8) & 7), ioaddr + EECtrl); while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0) ; // poll for ready do { outb(0x10, ioaddr + EECtrl); while ((inb(ioaddr + EEStatus) & 0x80) && --bogus_cnt > 0); } while ((inb(ioaddr + EEStatus) & 0x81) && bogus_cnt > 0); return; } /* 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[128] = /* 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[12]; ioaddr = BASE_ADDR; // io mapped PCI memory address 0x500 if (inw(ioaddr + ChipRev) != 0x701) { printk(KERN_INFO "The YellowFin (83c885) device does not seem to be installed.\n" KERN_INFO "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(KERN_INFO "This YellowFin (8xc885) board has already been initialized.\n" KERN_INFO "To force a new config, uninstall this module and reinstall with\n" KERN_INFO " 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; retry = 10; write_loop: #if 0 printk("write_eeprom: "); for (i = 0; i < 11; i++) { printk("%02X ",vnc_eeprom[i]); write_eeprom(ioaddr, i, vnc_eeprom[i]); } printk("\n"); #endif printk("ws_read_eeprom: "); for (i = 0; i < 11; i++) { vnc_verify[i] = ws_read_eeprom(ioaddr, i); printk("%02X ",vnc_verify[i]); // delay20ms(); } printk("\n"); #if 1 printk(" read_eeprom: "); for (i = 0; i < 11; i++) { vnc_verify[i] = read_eeprom(ioaddr, i); printk("%02X ",vnc_verify[i]); // delay20ms(); } printk("\n"); #endif #if 0 for (i = 0; i < 11; i++) { if ((vnc_verify[i] != vnc_eeprom[i]) && retry) { retry--; goto write_loop; } } #endif printk("Done..\n"); return (-EBUSY); } void cleanup_module(void) { }