FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/pcicx.c
1 /*-
2 * TODO:
3 * [1] integrate into current if_ed.c
4 * [2] parse tuples to find out where to map the shared memory buffer,
5 * and what to write into the configuration register
6 * [3] move pcic-specific code into a separate module.
7 *
8 * Device driver for IBM PCMCIA Credit Card Adapter for Ethernet,
9 * if_ze.c
10 *
11 * Based on the Device driver for National Semiconductor DS8390 ethernet
12 * adapters by David Greenman. Modifications for PCMCIA by Keith Moore.
13 * Adapted for FreeBSD 1.1.5 by Jordan Hubbard.
14 *
15 * Currently supports only the IBM Credit Card Adapter for Ethernet, but
16 * could probably work with other PCMCIA cards also, if it were modified
17 * to get the locations of the PCMCIA configuration option register (COR)
18 * by parsing the configuration tuples, rather than by hard-coding in
19 * the value expected by IBM's card.
20 *
21 * Sources for data on the PCMCIA/IBM CCAE specific portions of the driver:
22 *
23 * [1] _Local Area Network Credit Card Adapters Technical Reference_,
24 * IBM Corp., SC30-3585-00, part # 33G9243.
25 * [2] "pre-alpha" PCMCIA support code for Linux by Barry Jaspan.
26 * [3] Intel 82536SL PC Card Interface Controller Data Sheet, Intel
27 * Order Number 290423-002
28 * [4] National Semiconductor DP83902A ST-NIC (tm) Serial Network
29 * Interface Controller for Twisted Pair data sheet.
30 *
31 *
32 * Copyright (C) 1993, David Greenman. This software may be used, modified,
33 * copied, distributed, and sold, in both source and binary form provided
34 * that the above copyright and these terms are retained. Under no
35 * circumstances is the author responsible for the proper functioning
36 * of this software, nor does the author assume any responsibility
37 * for damages incurred with its use.
38 */
39 #include <sys/param.h>
40 #if defined(__FreeBSD__)
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <machine/clock.h>
44 #endif
45 #include <i386/isa/isa_device.h>
46 #include <i386/isa/pcic.h>
47
48 /*
49 * map a portion of the card's memory space into system memory
50 * space.
51 *
52 * slot = # of the slot the card is plugged into
53 * window = which pcic memory map registers to use (0..4)
54 * sys_addr = base system PHYSICAL memory address where we want it. must
55 * be on an appropriate boundary (lower 12 bits are zero).
56 * card_addr = the base address of the card's memory to correspond
57 * to sys_addr
58 * length = length of the segment to map (may be rounded up as necessary)
59 * type = which card memory space to map (attribute or shared)
60 * width = 1 for byte-wide mapping; 2 for word (16-bit) mapping.
61 */
62
63 void
64 pcic_map_memory (int slot, int window, unsigned long sys_addr,
65 unsigned long card_addr, unsigned long length,
66 enum memtype type, int width)
67 {
68 unsigned short offset;
69 unsigned short mem_start_addr;
70 unsigned short mem_stop_addr;
71
72 sys_addr >>= 12;
73 card_addr >>= 12;
74 length >>= 12;
75 /*
76 * compute an offset for the chip such that
77 * (sys_addr + offset) = card_addr
78 * but the arithmetic is done modulo 2^14
79 */
80 offset = (card_addr - sys_addr) & 0x3FFF;
81 /*
82 * now OR in the bit for "attribute memory" if necessary
83 */
84 if (type == ATTRIBUTE) {
85 offset |= (PCIC_REG << 8);
86 /* REG == "region active" pin on card */
87 }
88 /*
89 * okay, set up the chip memory mapping registers, and turn
90 * on the enable bit for this window.
91 * if we are doing 16-bit wide accesses (width == 2),
92 * turn on the appropriate bit.
93 *
94 * XXX for now, we set all of the wait state bits to zero.
95 * Not really sure how they should be set.
96 */
97 mem_start_addr = sys_addr & 0xFFF;
98 if (width == 2)
99 mem_start_addr |= (PCIC_DATA16 << 8);
100 mem_stop_addr = (sys_addr + length) & 0xFFF;
101
102 pcic_putw (slot, MEM_START_ADDR(window), mem_start_addr);
103 pcic_putw (slot, MEM_STOP_ADDR(window), mem_stop_addr);
104 pcic_putw (slot, MEM_OFFSET(window), offset);
105 /*
106 * Assert the bit (PCIC_MEMCS16) that says to decode all of
107 * the address lines.
108 */
109 pcic_putb (slot, PCIC_ADDRWINE,
110 pcic_getb (slot, PCIC_ADDRWINE) |
111 MEM_ENABLE_BIT(window) | PCIC_MEMCS16);
112 }
113
114 void
115 pcic_unmap_memory (int slot, int window)
116 {
117 /*
118 * seems like we need to turn off the enable bit first, after which
119 * we can clear the registers out just to be sure.
120 */
121 pcic_putb (slot, PCIC_ADDRWINE,
122 pcic_getb (slot, PCIC_ADDRWINE) & ~MEM_ENABLE_BIT(window));
123 pcic_putw (slot, MEM_START_ADDR(window), 0);
124 pcic_putw (slot, MEM_STOP_ADDR(window), 0);
125 pcic_putw (slot, MEM_OFFSET(window), 0);
126 }
127
128 /*
129 * map a range of addresses into system i/o space
130 * (no translation of i/o addresses is possible)
131 *
132 * 'width' is:
133 * + 0 to tell the PCIC to generate the ISA IOCS16* signal from
134 * the PCMCIA IOIS16* signal.
135 * + 1 to select 8-bit width
136 * + 2 to select 16-bit width
137 */
138
139 void
140 pcic_map_io (int slot, int window, unsigned short base, unsigned short length,
141 unsigned short width)
142 {
143 unsigned char x;
144
145 pcic_putw (slot, IO_START_ADDR(window), base);
146 pcic_putw (slot, IO_STOP_ADDR(window), base+length-1);
147 /*
148 * select the bits that determine whether
149 * an i/o operation is 8 or 16 bits wide
150 */
151 x = pcic_getb (slot, PCIC_IOCTL);
152 switch (width) {
153 case 0: /* PCMCIA card decides */
154 if (window)
155 x = (x & 0xf0) | PCIC_IO1_CS16;
156 else
157 x = (x & 0x0f) | PCIC_IO0_CS16;
158 break;
159 case 1: /* 8 bits wide */
160 break;
161 case 2: /* 16 bits wide */
162 if (window)
163 x = (x & 0xf0) | PCIC_IO1_16BIT;
164 else
165 x = (x & 0x0f) | PCIC_IO0_16BIT;
166 break;
167 }
168 pcic_putb (slot, PCIC_IOCTL, x);
169 pcic_putb (slot, PCIC_ADDRWINE,
170 pcic_getb (slot, PCIC_ADDRWINE) | IO_ENABLE_BIT(window));
171 }
172
173 #ifdef TEST
174 void
175 pcic_unmap_io (int slot, int window)
176 {
177 pcic_putb (slot, PCIC_ADDRWINE,
178 pcic_getb (slot, PCIC_ADDRWINE) & ~IO_ENABLE_BIT(window));
179 pcic_putw (slot, IO_START_ADDR(window), 0);
180 pcic_putw (slot, IO_STOP_ADDR(window), 0);
181 }
182 #endif /* TEST */
183
184 /*
185 * tell the PCIC which irq we want to use. only the following are legal:
186 * 3, 4, 5, 7, 9, 10, 11, 12, 14, 15
187 *
188 * NB: 'irq' is an interrupt NUMBER, not a MASK as in struct isa_device.
189 */
190
191 void
192 pcic_map_irq (int slot, int irq)
193 {
194 if (irq < 3 || irq == 6 || irq == 8 || irq == 13 || irq > 15) {
195 printf ("zp: pcic_map_irq (slot %d): illegal irq %d\n", slot, irq);
196 return;
197 }
198 pcic_putb (slot, PCIC_INT_GEN,
199 pcic_getb (slot, PCIC_INT_GEN) | (irq & 0x0F));
200 }
201
202 void
203 pcic_power_on (int slot)
204 {
205 pcic_putb (slot, PCIC_STATUS,
206 pcic_getb (slot, PCIC_STATUS) | PCIC_POW);
207 DELAY (100000);
208 pcic_putb (slot, PCIC_POWER,
209 pcic_getb (slot, PCIC_POWER) | PCIC_DISRST | PCIC_PCPWRE);
210 DELAY (100000);
211 pcic_putb (slot, PCIC_POWER,
212 pcic_getb (slot, PCIC_POWER) | PCIC_OUTENA);
213 }
214
215 void
216 pcic_power_off (int slot)
217 {
218 pcic_putb (slot, PCIC_POWER,
219 pcic_getb (slot, PCIC_POWER) & ~(PCIC_OUTENA|PCIC_PCPWRE));
220 }
221
222 void
223 pcic_reset (int slot)
224 {
225 /* assert RESET (by clearing a bit!), wait a bit, and de-assert it */
226 pcic_putb (slot, PCIC_INT_GEN,
227 pcic_getb (slot, PCIC_INT_GEN) & ~PCIC_CARDRESET);
228 DELAY (100000);
229 pcic_putb (slot, PCIC_INT_GEN,
230 pcic_getb (slot, PCIC_INT_GEN) | PCIC_CARDRESET);
231 }
232
Cache object: b3c05f6b876e5b7c8f178d4557fc98b2
|