/* . Function: smc_reset( void ) . Purpose: . This sets the SMC91111 chip to its normal state, hopefully from whatever . mess that any other DOS driver has put it in. . . Maybe I should reset more registers to defaults in here? SOFTRST should . do that for me. . . Method: . 1. send a SOFT RESET . 2. wait for it to finish . 3. enable autorelease mode . 4. reset the memory management unit . 5. clear all interrupts . */ static void smc_reset (struct eth_device *dev) { PRINTK2 ("%s: smc_reset\n", SMC_DEV_NAME); /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ SMC_SELECT_BANK (dev, 0); SMC_outw (dev, RCR_SOFTRST, RCR_REG); /* Setup the Configuration Register */ /* This is necessary because the CONFIG_REG is not affected */ /* by a soft reset */ SMC_SELECT_BANK (dev, 1); #if defined(CONFIG_SMC91111_EXT_PHY) SMC_outw (dev, CONFIG_DEFAULT | CONFIG_EXT_PHY, CONFIG_REG); #else SMC_outw (dev, CONFIG_DEFAULT, CONFIG_REG); #endif /* Release from possible power-down state */ /* Configuration register is not affected by Soft Reset */ SMC_outw (dev, SMC_inw (dev, CONFIG_REG) | CONFIG_EPH_POWER_EN, CONFIG_REG); SMC_SELECT_BANK (dev, 0); /* this should pause enough for the chip to be happy */ udelay (10); /* Disable transmit and receive functionality */ SMC_outw (dev, RCR_CLEAR, RCR_REG); SMC_outw (dev, TCR_CLEAR, TCR_REG); /* set the control register */ SMC_SELECT_BANK (dev, 1); SMC_outw (dev, CTL_DEFAULT, CTL_REG); /* Reset the MMU */ SMC_SELECT_BANK (dev, 2); smc_wait_mmu_release_complete (dev); SMC_outw (dev, MC_RESET, MMU_CMD_REG); while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) udelay (1); /* Wait until not busy */ /* Note: It doesn't seem that waiting for the MMU busy is needed here, but this is a place where future chipsets _COULD_ break. Be wary of issuing another MMU command right after this */ /* Disable all interrupts */ SMC_outb (dev, 0, IM_REG); }
/*********************************************** * Show available memory * ***********************************************/ void dump_memory_info(void) { word mem_info; word old_bank; old_bank = SMC_inw(BANK_SELECT)&0xF; SMC_SELECT_BANK(0); mem_info = SMC_inw( MIR_REG ); PRINTK2("Memory: %4d available\n", (mem_info >> 8)*2048); SMC_SELECT_BANK(old_bank); }
static inline byte SMC_inb(struct eth_device *dev, dword offset) { word _w; _w = SMC_inw(dev, offset & ~((dword)1)); return (offset & 1) ? (byte)(_w >> 8) : (byte)(_w); }
static inline byte SMC_inb(dword offset) { word _w; _w = SMC_inw(offset & ~((dword)1)); return (offset & 1) ? (byte)(_w >> 8) : (byte)(_w); }
static inline void SMC_insw(dword offset, volatile uchar* buf, dword len) { volatile word *p = (volatile word *)buf; while (len-- > 0) { *p++ = SMC_inw(offset); barrier(); *((volatile u32*)(0xc0000000)); } }
static inline void SMC_outb(byte value, dword offset) { word _w; _w = SMC_inw(offset & ~((dword)1)); if (offset & 1) *((volatile word*)(SMC_BASE_ADDRESS+(offset & ~((dword)1)))) = (value<<8) | (_w & 0x00ff); else *((volatile word*)(SMC_BASE_ADDRESS+offset)) = value | (_w & 0xff00); }
static int write_eeprom_reg(struct eth_device *dev, u16 value, u16 reg) { int timeout; SMC_SELECT_BANK(dev, 2); SMC_outw(dev, reg, PTR_REG); SMC_SELECT_BANK(dev, 1); SMC_outw(dev, value, GP_REG); SMC_outw(dev, SMC_inw (dev, CTL_REG) | CTL_EEPROM_SELECT | CTL_STORE, CTL_REG); timeout = 100; while ((SMC_inw(dev, CTL_REG) & CTL_STORE) && --timeout) udelay (100); if (timeout == 0) { printf("Timeout Writing EEPROM register %02x\n", reg); return 0; } return 1; }
static u16 read_eeprom_reg(struct eth_device *dev, u16 reg) { int timeout; SMC_SELECT_BANK(dev, 2); SMC_outw(dev, reg, PTR_REG); SMC_SELECT_BANK(dev, 1); SMC_outw(dev, SMC_inw (dev, CTL_REG) | CTL_EEPROM_SELECT | CTL_RELOAD, CTL_REG); timeout = 100; while((SMC_inw (dev, CTL_REG) & CTL_RELOAD) && --timeout) udelay(100); if (timeout == 0) { printf("Timeout Reading EEPROM register %02x\n", reg); return 0; } return SMC_inw (dev, GP_REG); }
/* Only one release command at a time, please */ static inline void smc_wait_mmu_release_complete (struct eth_device *dev) { int count = 0; /* assume bank 2 selected */ while (SMC_inw (dev, MMU_CMD_REG) & MC_BUSY) { udelay (1); /* Wait until not busy */ if (++count > 200) break; } }
static inline void SMC_outb(struct eth_device *dev, byte value, dword offset) { word _w; _w = SMC_inw(dev, offset & ~((dword)1)); if (offset & 1) *((volatile word*)(dev->iobase + (offset & ~((dword)1)))) = (value<<8) | (_w & 0x00ff); else *((volatile word*)(dev->iobase + offset)) = value | (_w & 0xff00); }
static int poll4int (struct eth_device *dev, byte mask, int timeout) { int tmo = get_timer (0) + timeout * CONFIG_SYS_HZ; int is_timeout = 0; word old_bank = SMC_inw (dev, BSR_REG); PRINTK2 ("Polling...\n"); SMC_SELECT_BANK (dev, 2); while ((SMC_inw (dev, SMC91111_INT_REG) & mask) == 0) { if (get_timer (0) >= tmo) { is_timeout = 1; break; } } /* restore old bank selection */ SMC_SELECT_BANK (dev, old_bank); if (is_timeout) return 1; else return 0; }
static int poll4int (byte mask, int timeout) { int tmo = get_timer (0) + timeout * CFG_HZ; int is_timeout = 0; word old_bank = SMC_inw (BSR_REG); PRINTK2 ("Polling...\n"); SMC_SELECT_BANK (2); while ((SMC_inw (SMC91111_INT_REG) & mask) == 0) { if (get_timer (0) >= tmo) { is_timeout = 1; break; } } /* restore old bank selection */ SMC_SELECT_BANK (old_bank); if (is_timeout) return 1; else return 0; }
int eeprom(int argc, char *argv[]) { int i, len, ret; unsigned char buf[58], *p; struct eth_device dev = { .iobase = CONFIG_SMC91111_BASE }; app_startup(argv); if (get_version() != XF_VERSION) { printf("Wrong XF_VERSION.\n"); printf("Application expects ABI version %d\n", XF_VERSION); printf("Actual U-Boot ABI version %d\n", (int)get_version()); return 1; } return crcek(); if ((SMC_inw (&dev, BANK_SELECT) & 0xFF00) != 0x3300) { printf("SMSC91111 not found.\n"); return 2; } /* Called without parameters - print MAC address */ if (argc < 2) { verify_macaddr(&dev, NULL); return 0; } /* Print help message */ if (argv[1][1] == 'h') { printf("VoiceBlue EEPROM writer\n"); printf("Built: %s at %s\n", U_BOOT_DATE, U_BOOT_TIME); printf("Usage:\n\t<mac_address> [<element_1>] [<...>]\n"); return 0; } /* Try to parse information elements */ len = sizeof(buf); p = buf; for (i = 2; i < argc; i++) { ret = parse_element(argv[i], p, len); switch (ret) { case -1: printf("Element %d: malformed\n", i - 1); return 3; case -2: printf("Element %d: odd character count\n", i - 1); return 3; case -3: printf("Out of EEPROM memory\n"); return 3; default: p += ret; len -= ret; } } /* First argument (MAC) is mandatory */ set_mac(&dev, argv[1]); if (verify_macaddr(&dev, argv[1])) { printf("*** MAC address does not match! ***\n"); return 4; } while (len--) *p++ = 0; write_data(&dev, (u16 *)buf, sizeof(buf) >> 1); return 0; }
/* . Function: smc_send(struct net_device * ) . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a saved_skb is available. . ( this should NOT be called if there is no 'saved_skb' . Now, find the packet number that the chip allocated . Point the data pointers at it in memory . Set the length word in the chip's memory . Dump the packet to chip memory . Check if a last byte is needed ( odd length packet ) . if so, set the control flag right . Tell the card to send it . Enable the transmit interrupt, so I know if it failed . Free the kernel data if I actually sent it. */ static int smc_send(struct eth_device *dev, void *packet, int packet_length) { byte packet_no; byte *buf; int length; int numPages; int try = 0; int time_out; byte status; byte saved_pnr; word saved_ptr; /* save PTR and PNR registers before manipulation */ SMC_SELECT_BANK (dev, 2); saved_pnr = SMC_inb( dev, PN_REG ); saved_ptr = SMC_inw( dev, PTR_REG ); PRINTK3 ("%s: smc_hardware_send_packet\n", SMC_DEV_NAME); length = ETH_ZLEN < packet_length ? packet_length : ETH_ZLEN; /* allocate memory ** The MMU wants the number of pages to be the number of 256 bytes ** 'pages', minus 1 ( since a packet can't ever have 0 pages :) ) ** ** The 91C111 ignores the size bits, but the code is left intact ** for backwards and future compatibility. ** ** Pkt size for allocating is data length +6 (for additional status ** words, length and ctl!) ** ** If odd size then last byte is included in this header. */ numPages = ((length & 0xfffe) + 6); numPages >>= 8; /* Divide by 256 */ if (numPages > 7) { printf ("%s: Far too big packet error. \n", SMC_DEV_NAME); return 0; } /* now, try to allocate the memory */ SMC_SELECT_BANK (dev, 2); SMC_outw (dev, MC_ALLOC | numPages, MMU_CMD_REG); /* FIXME: the ALLOC_INT bit never gets set * * so the following will always give a * * memory allocation error. * * same code works in armboot though * * -ro */ again: try++; time_out = MEMORY_WAIT_TIME; do { status = SMC_inb (dev, SMC91111_INT_REG); if (status & IM_ALLOC_INT) { /* acknowledge the interrupt */ SMC_outb (dev, IM_ALLOC_INT, SMC91111_INT_REG); break; } } while (--time_out); if (!time_out) { PRINTK2 ("%s: memory allocation, try %d failed ...\n", SMC_DEV_NAME, try); if (try < SMC_ALLOC_MAX_TRY) goto again; else return 0; }
int eeprom(int argc, char * const argv[]) { int i, len, ret; unsigned char buf[58], *p; app_startup(argv); i = get_version(); if (i != XF_VERSION) { printf("Using ABI version %d, but U-Boot provides %d\n", XF_VERSION, i); return 1; } if ((SMC_inw(&dev, BANK_SELECT) & 0xFF00) != 0x3300) { puts("SMSC91111 not found\n"); return 2; } /* Called without parameters - print MAC address */ if (argc < 2) { verify_macaddr(NULL); return 0; } /* Print help message */ if (argv[1][1] == 'h') { puts("NetStar EEPROM writer\n" "Built: " U_BOOT_DATE " at " U_BOOT_TIME "\n" "Usage:\n\t<mac_address> [<element_1>] [<...>]\n"); return 0; } /* Try to parse information elements */ len = sizeof(buf); p = buf; for (i = 2; i < argc; i++) { ret = parse_element(argv[i], p, len); switch (ret) { case -1: printf("Element %d: malformed\n", i - 1); return 3; case -2: printf("Element %d: odd character count\n", i - 1); return 3; case -3: puts("Out of EEPROM memory\n"); return 3; default: p += ret; len -= ret; } } /* First argument (MAC) is mandatory */ set_mac(argv[1]); if (verify_macaddr(argv[1])) { puts("*** HWaddr does not match! ***\n"); return 4; } while (len--) *p++ = 0; write_data((u16 *)buf, sizeof(buf) >> 1); return 0; }