162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* Linux header file for the ATP pocket ethernet adapter. */ 362306a36Sopenharmony_ci/* v1.09 8/9/2000 becker@scyld.com. */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/if_ether.h> 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* The header prepended to received packets. */ 962306a36Sopenharmony_cistruct rx_header { 1062306a36Sopenharmony_ci ushort pad; /* Pad. */ 1162306a36Sopenharmony_ci ushort rx_count; 1262306a36Sopenharmony_ci ushort rx_status; /* Unknown bit assignments :-<. */ 1362306a36Sopenharmony_ci ushort cur_addr; /* Apparently the current buffer address(?) */ 1462306a36Sopenharmony_ci}; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define PAR_DATA 0 1762306a36Sopenharmony_ci#define PAR_STATUS 1 1862306a36Sopenharmony_ci#define PAR_CONTROL 2 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define Ctrl_LNibRead 0x08 /* LP_PSELECP */ 2162306a36Sopenharmony_ci#define Ctrl_HNibRead 0 2262306a36Sopenharmony_ci#define Ctrl_LNibWrite 0x08 /* LP_PSELECP */ 2362306a36Sopenharmony_ci#define Ctrl_HNibWrite 0 2462306a36Sopenharmony_ci#define Ctrl_SelData 0x04 /* LP_PINITP */ 2562306a36Sopenharmony_ci#define Ctrl_IRQEN 0x10 /* LP_PINTEN */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define EOW 0xE0 2862306a36Sopenharmony_ci#define EOC 0xE0 2962306a36Sopenharmony_ci#define WrAddr 0x40 /* Set address of EPLC read, write register. */ 3062306a36Sopenharmony_ci#define RdAddr 0xC0 3162306a36Sopenharmony_ci#define HNib 0x10 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cienum page0_regs { 3462306a36Sopenharmony_ci /* The first six registers hold 3562306a36Sopenharmony_ci * the ethernet physical station address. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, 3862306a36Sopenharmony_ci TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ 3962306a36Sopenharmony_ci TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ 4062306a36Sopenharmony_ci ISR = 10, IMR = 11, /* Interrupt status and mask. */ 4162306a36Sopenharmony_ci CMR1 = 12, /* Command register 1. */ 4262306a36Sopenharmony_ci CMR2 = 13, /* Command register 2. */ 4362306a36Sopenharmony_ci MODSEL = 14, /* Mode select register. */ 4462306a36Sopenharmony_ci MAR = 14, /* Memory address register (?). */ 4562306a36Sopenharmony_ci CMR2_h = 0x1d, 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cienum eepage_regs { 4962306a36Sopenharmony_ci PROM_CMD = 6, 5062306a36Sopenharmony_ci PROM_DATA = 7 /* Note that PROM_CMD is in the "high" bits. */ 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define ISR_TxOK 0x01 5462306a36Sopenharmony_ci#define ISR_RxOK 0x04 5562306a36Sopenharmony_ci#define ISR_TxErr 0x02 5662306a36Sopenharmony_ci#define ISRh_RxErr 0x11 /* ISR, high nibble */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define CMR1h_MUX 0x08 /* Select printer multiplexor on 8012. */ 5962306a36Sopenharmony_ci#define CMR1h_RESET 0x04 /* Reset. */ 6062306a36Sopenharmony_ci#define CMR1h_RxENABLE 0x02 /* Rx unit enable. */ 6162306a36Sopenharmony_ci#define CMR1h_TxENABLE 0x01 /* Tx unit enable. */ 6262306a36Sopenharmony_ci#define CMR1h_TxRxOFF 0x00 6362306a36Sopenharmony_ci#define CMR1_ReXmit 0x08 /* Trigger a retransmit. */ 6462306a36Sopenharmony_ci#define CMR1_Xmit 0x04 /* Trigger a transmit. */ 6562306a36Sopenharmony_ci#define CMR1_IRQ 0x02 /* Interrupt active. */ 6662306a36Sopenharmony_ci#define CMR1_BufEnb 0x01 /* Enable the buffer(?). */ 6762306a36Sopenharmony_ci#define CMR1_NextPkt 0x01 /* Enable the buffer(?). */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define CMR2_NULL 8 7062306a36Sopenharmony_ci#define CMR2_IRQOUT 9 7162306a36Sopenharmony_ci#define CMR2_RAMTEST 10 7262306a36Sopenharmony_ci#define CMR2_EEPROM 12 /* Set to page 1, for reading the EEPROM. */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define CMR2h_OFF 0 /* No accept mode. */ 7562306a36Sopenharmony_ci#define CMR2h_Physical 1 /* Accept a physical address match only. */ 7662306a36Sopenharmony_ci#define CMR2h_Normal 2 /* Accept physical and broadcast address. */ 7762306a36Sopenharmony_ci#define CMR2h_PROMISC 3 /* Promiscuous mode. */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* An inline function used below: it differs from inb() by explicitly 8062306a36Sopenharmony_ci * return an unsigned char, saving a truncation. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic inline unsigned char inbyte(unsigned short port) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci unsigned char _v; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci __asm__ __volatile__ ("inb %w1,%b0" : "=a" (_v) : "d" (port)); 8762306a36Sopenharmony_ci return _v; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* Read register OFFSET. 9162306a36Sopenharmony_ci * This command should always be terminated with read_end(). 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic inline unsigned char read_nibble(short port, unsigned char offset) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci unsigned char retval; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci outb(EOC+offset, port + PAR_DATA); 9862306a36Sopenharmony_ci outb(RdAddr+offset, port + PAR_DATA); 9962306a36Sopenharmony_ci inbyte(port + PAR_STATUS); /* Settling time delay */ 10062306a36Sopenharmony_ci retval = inbyte(port + PAR_STATUS); 10162306a36Sopenharmony_ci outb(EOC+offset, port + PAR_DATA); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return retval; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci/* Functions for bulk data read. The interrupt line is always disabled. */ 10762306a36Sopenharmony_ci/* Get a byte using read mode 0, reading data from the control lines. */ 10862306a36Sopenharmony_cistatic inline unsigned char read_byte_mode0(short ioaddr) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci unsigned char low_nib; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); 11362306a36Sopenharmony_ci inbyte(ioaddr + PAR_STATUS); 11462306a36Sopenharmony_ci low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; 11562306a36Sopenharmony_ci outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); 11662306a36Sopenharmony_ci inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ 11762306a36Sopenharmony_ci inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ 11862306a36Sopenharmony_ci return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* The same as read_byte_mode0(), but does multiple inb()s for stability. */ 12262306a36Sopenharmony_cistatic inline unsigned char read_byte_mode2(short ioaddr) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci unsigned char low_nib; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); 12762306a36Sopenharmony_ci inbyte(ioaddr + PAR_STATUS); 12862306a36Sopenharmony_ci low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; 12962306a36Sopenharmony_ci outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); 13062306a36Sopenharmony_ci inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ 13162306a36Sopenharmony_ci return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* Read a byte through the data register. */ 13562306a36Sopenharmony_cistatic inline unsigned char read_byte_mode4(short ioaddr) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci unsigned char low_nib; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci outb(RdAddr | MAR, ioaddr + PAR_DATA); 14062306a36Sopenharmony_ci low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; 14162306a36Sopenharmony_ci outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); 14262306a36Sopenharmony_ci return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* Read a byte through the data register, double reading to allow settling. */ 14662306a36Sopenharmony_cistatic inline unsigned char read_byte_mode6(short ioaddr) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci unsigned char low_nib; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci outb(RdAddr | MAR, ioaddr + PAR_DATA); 15162306a36Sopenharmony_ci inbyte(ioaddr + PAR_STATUS); 15262306a36Sopenharmony_ci low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; 15362306a36Sopenharmony_ci outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); 15462306a36Sopenharmony_ci inbyte(ioaddr + PAR_STATUS); 15562306a36Sopenharmony_ci return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic inline void 15962306a36Sopenharmony_ciwrite_reg(short port, unsigned char reg, unsigned char value) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci unsigned char outval; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci outb(EOC | reg, port + PAR_DATA); 16462306a36Sopenharmony_ci outval = WrAddr | reg; 16562306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 16662306a36Sopenharmony_ci outb(outval, port + PAR_DATA); /* Double write for PS/2. */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci outval &= 0xf0; 16962306a36Sopenharmony_ci outval |= value; 17062306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 17162306a36Sopenharmony_ci outval &= 0x1f; 17262306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 17362306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci outb(EOC | outval, port + PAR_DATA); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic inline void 17962306a36Sopenharmony_ciwrite_reg_high(short port, unsigned char reg, unsigned char value) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci unsigned char outval = EOC | HNib | reg; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 18462306a36Sopenharmony_ci outval &= WrAddr | HNib | 0x0f; 18562306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 18662306a36Sopenharmony_ci outb(outval, port + PAR_DATA); /* Double write for PS/2. */ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci outval = WrAddr | HNib | value; 18962306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 19062306a36Sopenharmony_ci outval &= HNib | 0x0f; /* HNib | value */ 19162306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 19262306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci outb(EOC | HNib | outval, port + PAR_DATA); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* Write a byte out using nibble mode. The low nibble is written first. */ 19862306a36Sopenharmony_cistatic inline void 19962306a36Sopenharmony_ciwrite_reg_byte(short port, unsigned char reg, unsigned char value) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci unsigned char outval; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */ 20462306a36Sopenharmony_ci outval = WrAddr | reg; 20562306a36Sopenharmony_ci outb(outval, port + PAR_DATA); 20662306a36Sopenharmony_ci outb(outval, port + PAR_DATA); /* Double write for PS/2. */ 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA); 20962306a36Sopenharmony_ci outb(value & 0x0f, port + PAR_DATA); 21062306a36Sopenharmony_ci value >>= 4; 21162306a36Sopenharmony_ci outb(value, port + PAR_DATA); 21262306a36Sopenharmony_ci outb(0x10 | value, port + PAR_DATA); 21362306a36Sopenharmony_ci outb(0x10 | value, port + PAR_DATA); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci outb(EOC | value, port + PAR_DATA); /* Reset the address register. */ 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* Bulk data writes to the packet buffer. The interrupt line remains enabled. 21962306a36Sopenharmony_ci * The first, faster method uses only the dataport (data modes 0, 2 & 4). 22062306a36Sopenharmony_ci * The second (backup) method uses data and control regs (modes 1, 3 & 5). 22162306a36Sopenharmony_ci * It should only be needed when there is skew between the individual data 22262306a36Sopenharmony_ci * lines. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic inline void write_byte_mode0(short ioaddr, unsigned char value) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci outb(value & 0x0f, ioaddr + PAR_DATA); 22762306a36Sopenharmony_ci outb((value>>4) | 0x10, ioaddr + PAR_DATA); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic inline void write_byte_mode1(short ioaddr, unsigned char value) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci outb(value & 0x0f, ioaddr + PAR_DATA); 23362306a36Sopenharmony_ci outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL); 23462306a36Sopenharmony_ci outb((value>>4) | 0x10, ioaddr + PAR_DATA); 23562306a36Sopenharmony_ci outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* Write 16bit VALUE to the packet buffer: the same as above just doubled. */ 23962306a36Sopenharmony_cistatic inline void write_word_mode0(short ioaddr, unsigned short value) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci outb(value & 0x0f, ioaddr + PAR_DATA); 24262306a36Sopenharmony_ci value >>= 4; 24362306a36Sopenharmony_ci outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); 24462306a36Sopenharmony_ci value >>= 4; 24562306a36Sopenharmony_ci outb(value & 0x0f, ioaddr + PAR_DATA); 24662306a36Sopenharmony_ci value >>= 4; 24762306a36Sopenharmony_ci outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* EEPROM_Ctrl bits. */ 25162306a36Sopenharmony_ci#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ 25262306a36Sopenharmony_ci#define EE_CS 0x02 /* EEPROM chip select. */ 25362306a36Sopenharmony_ci#define EE_CLK_HIGH 0x12 25462306a36Sopenharmony_ci#define EE_CLK_LOW 0x16 25562306a36Sopenharmony_ci#define EE_DATA_WRITE 0x01 /* EEPROM chip data in. */ 25662306a36Sopenharmony_ci#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* The EEPROM commands include the alway-set leading bit. */ 25962306a36Sopenharmony_ci#define EE_WRITE_CMD(offset) (((5 << 6) + (offset)) << 17) 26062306a36Sopenharmony_ci#define EE_READ(offset) (((6 << 6) + (offset)) << 17) 26162306a36Sopenharmony_ci#define EE_ERASE(offset) (((7 << 6) + (offset)) << 17) 26262306a36Sopenharmony_ci#define EE_CMD_SIZE 27 /* The command+address+data size. */ 263