/*- * TODO: * [1] integrate into current if_ed.c * [2] parse tuples to find out where to map the shared memory buffer, * and what to write into the configuration register * [3] move pcic-specific code into a separate module. * * Device driver for IBM PCMCIA Credit Card Adapter for Ethernet, * if_ze.c * * Based on the Device driver for National Semiconductor DS8390 ethernet * adapters by David Greenman. Modifications for PCMCIA by Keith Moore. * Adapted for FreeBSD 1.1.5 by Jordan Hubbard. * * Currently supports only the IBM Credit Card Adapter for Ethernet, but * could probably work with other PCMCIA cards also, if it were modified * to get the locations of the PCMCIA configuration option register (COR) * by parsing the configuration tuples, rather than by hard-coding in * the value expected by IBM's card. * * Sources for data on the PCMCIA/IBM CCAE specific portions of the driver: * * [1] _Local Area Network Credit Card Adapters Technical Reference_, * IBM Corp., SC30-3585-00, part # 33G9243. * [2] "pre-alpha" PCMCIA support code for Linux by Barry Jaspan. * [3] Intel 82536SL PC Card Interface Controller Data Sheet, Intel * Order Number 290423-002 * [4] National Semiconductor DP83902A ST-NIC (tm) Serial Network * Interface Controller for Twisted Pair data sheet. * * * Copyright (C) 1993, David Greenman. This software may be used, modified, * copied, distributed, and sold, in both source and binary form provided * that the above copyright and these terms are retained. Under no * circumstances is the author responsible for the proper functioning * of this software, nor does the author assume any responsibility * for damages incurred with its use. */ #include #if defined(__FreeBSD__) #include #include #include #endif #include #include /* * map a portion of the card's memory space into system memory * space. * * slot = # of the slot the card is plugged into * window = which pcic memory map registers to use (0..4) * sys_addr = base system PHYSICAL memory address where we want it. must * be on an appropriate boundary (lower 12 bits are zero). * card_addr = the base address of the card's memory to correspond * to sys_addr * length = length of the segment to map (may be rounded up as necessary) * type = which card memory space to map (attribute or shared) * width = 1 for byte-wide mapping; 2 for word (16-bit) mapping. */ void pcic_map_memory (int slot, int window, unsigned long sys_addr, unsigned long card_addr, unsigned long length, enum memtype type, int width) { unsigned short offset; unsigned short mem_start_addr; unsigned short mem_stop_addr; sys_addr >>= 12; card_addr >>= 12; length >>= 12; /* * compute an offset for the chip such that * (sys_addr + offset) = card_addr * but the arithmetic is done modulo 2^14 */ offset = (card_addr - sys_addr) & 0x3FFF; /* * now OR in the bit for "attribute memory" if necessary */ if (type == ATTRIBUTE) { offset |= (PCIC_REG << 8); /* REG == "region active" pin on card */ } /* * okay, set up the chip memory mapping registers, and turn * on the enable bit for this window. * if we are doing 16-bit wide accesses (width == 2), * turn on the appropriate bit. * * XXX for now, we set all of the wait state bits to zero. * Not really sure how they should be set. */ mem_start_addr = sys_addr & 0xFFF; if (width == 2) mem_start_addr |= (PCIC_DATA16 << 8); mem_stop_addr = (sys_addr + length) & 0xFFF; pcic_putw (slot, MEM_START_ADDR(window), mem_start_addr); pcic_putw (slot, MEM_STOP_ADDR(window), mem_stop_addr); pcic_putw (slot, MEM_OFFSET(window), offset); /* * Assert the bit (PCIC_MEMCS16) that says to decode all of * the address lines. */ pcic_putb (slot, PCIC_ADDRWINE, pcic_getb (slot, PCIC_ADDRWINE) | MEM_ENABLE_BIT(window) | PCIC_MEMCS16); } void pcic_unmap_memory (int slot, int window) { /* * seems like we need to turn off the enable bit first, after which * we can clear the registers out just to be sure. */ pcic_putb (slot, PCIC_ADDRWINE, pcic_getb (slot, PCIC_ADDRWINE) & ~MEM_ENABLE_BIT(window)); pcic_putw (slot, MEM_START_ADDR(window), 0); pcic_putw (slot, MEM_STOP_ADDR(window), 0); pcic_putw (slot, MEM_OFFSET(window), 0); } /* * map a range of addresses into system i/o space * (no translation of i/o addresses is possible) * * 'width' is: * + 0 to tell the PCIC to generate the ISA IOCS16* signal from * the PCMCIA IOIS16* signal. * + 1 to select 8-bit width * + 2 to select 16-bit width */ void pcic_map_io (int slot, int window, unsigned short base, unsigned short length, unsigned short width) { unsigned char x; pcic_putw (slot, IO_START_ADDR(window), base); pcic_putw (slot, IO_STOP_ADDR(window), base+length-1); /* * select the bits that determine whether * an i/o operation is 8 or 16 bits wide */ x = pcic_getb (slot, PCIC_IOCTL); switch (width) { case 0: /* PCMCIA card decides */ if (window) x = (x & 0xf0) | PCIC_IO1_CS16; else x = (x & 0x0f) | PCIC_IO0_CS16; break; case 1: /* 8 bits wide */ break; case 2: /* 16 bits wide */ if (window) x = (x & 0xf0) | PCIC_IO1_16BIT; else x = (x & 0x0f) | PCIC_IO0_16BIT; break; } pcic_putb (slot, PCIC_IOCTL, x); pcic_putb (slot, PCIC_ADDRWINE, pcic_getb (slot, PCIC_ADDRWINE) | IO_ENABLE_BIT(window)); } #ifdef TEST void pcic_unmap_io (int slot, int window) { pcic_putb (slot, PCIC_ADDRWINE, pcic_getb (slot, PCIC_ADDRWINE) & ~IO_ENABLE_BIT(window)); pcic_putw (slot, IO_START_ADDR(window), 0); pcic_putw (slot, IO_STOP_ADDR(window), 0); } #endif /* TEST */ /* * tell the PCIC which irq we want to use. only the following are legal: * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 * * NB: 'irq' is an interrupt NUMBER, not a MASK as in struct isa_device. */ void pcic_map_irq (int slot, int irq) { if (irq < 3 || irq == 6 || irq == 8 || irq == 13 || irq > 15) { printf ("zp: pcic_map_irq (slot %d): illegal irq %d\n", slot, irq); return; } pcic_putb (slot, PCIC_INT_GEN, pcic_getb (slot, PCIC_INT_GEN) | (irq & 0x0F)); } void pcic_power_on (int slot) { pcic_putb (slot, PCIC_STATUS, pcic_getb (slot, PCIC_STATUS) | PCIC_POW); DELAY (100000); pcic_putb (slot, PCIC_POWER, pcic_getb (slot, PCIC_POWER) | PCIC_DISRST | PCIC_PCPWRE); DELAY (100000); pcic_putb (slot, PCIC_POWER, pcic_getb (slot, PCIC_POWER) | PCIC_OUTENA); } void pcic_power_off (int slot) { pcic_putb (slot, PCIC_POWER, pcic_getb (slot, PCIC_POWER) & ~(PCIC_OUTENA|PCIC_PCPWRE)); } void pcic_reset (int slot) { /* assert RESET (by clearing a bit!), wait a bit, and de-assert it */ pcic_putb (slot, PCIC_INT_GEN, pcic_getb (slot, PCIC_INT_GEN) & ~PCIC_CARDRESET); DELAY (100000); pcic_putb (slot, PCIC_INT_GEN, pcic_getb (slot, PCIC_INT_GEN) | PCIC_CARDRESET); }