ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / isdn / hisax / bkm_a8.c
1 /* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $
2  *
3  * low level stuff for Scitel Quadro (4*S0, passive)
4  *
5  * Author       Roland Klabunde
6  * Copyright    by Roland Klabunde   <R.Klabunde@Berkom.de>
7  * 
8  * This software may be used and distributed according to the terms
9  * of the GNU General Public License, incorporated herein by reference.
10  *
11  */
12
13
14 #include <linux/config.h>
15 #include <linux/init.h>
16 #include "hisax.h"
17 #include "isac.h"
18 #include "ipac.h"
19 #include "hscx.h"
20 #include "isdnl1.h"
21 #include <linux/pci.h>
22 #include "bkm_ax.h"
23
24 #if CONFIG_PCI
25
26 #define ATTEMPT_PCI_REMAPPING   /* Required for PLX rev 1 */
27
28 extern const char *CardType[];
29
30 const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
31
32 static const char *sct_quadro_subtypes[] =
33 {
34         "",
35         "#1",
36         "#2",
37         "#3",
38         "#4"
39 };
40
41
42 #define wordout(addr,val) outw(val,addr)
43 #define wordin(addr) inw(addr)
44
45 static inline u_char
46 readreg(unsigned int ale, unsigned int adr, u_char off)
47 {
48         register u_char ret;
49         wordout(ale, off);
50         ret = wordin(adr) & 0xFF;
51         return (ret);
52 }
53
54 static inline void
55 readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
56 {
57         int i;
58         wordout(ale, off);
59         for (i = 0; i < size; i++)
60                 data[i] = wordin(adr) & 0xFF;
61 }
62
63
64 static inline void
65 writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
66 {
67         wordout(ale, off);
68         wordout(adr, data);
69 }
70
71 static inline void
72 writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
73 {
74         int i;
75         wordout(ale, off);
76         for (i = 0; i < size; i++)
77                 wordout(adr, data[i]);
78 }
79
80 /* Interface functions */
81
82 static u_char
83 ReadISAC(struct IsdnCardState *cs, u_char offset)
84 {
85         return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
86 }
87
88 static void
89 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
90 {
91         writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
92 }
93
94 static void
95 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
96 {
97         readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
98 }
99
100 static void
101 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
102 {
103         writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
104 }
105
106
107 static u_char
108 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
109 {
110         return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
111 }
112
113 static void
114 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
115 {
116         writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
117 }
118
119 /* Set the specific ipac to active */
120 static void
121 set_ipac_active(struct IsdnCardState *cs, u_int active)
122 {
123         /* set irq mask */
124         writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
125                 active ? 0xc0 : 0xff);
126 }
127
128 /*
129  * fast interrupt HSCX stuff goes here
130  */
131
132 #define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
133         cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
134 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
135         cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
136 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
137         cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
138 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
139         cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
140
141 #include "hscx_irq.c"
142
143 static irqreturn_t
144 bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
145 {
146         struct IsdnCardState *cs = dev_id;
147         u_char ista, val, icnt = 5;
148         u_long flags;
149
150         spin_lock_irqsave(&cs->lock, flags);
151         ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
152         if (!(ista & 0x3f)) { /* not this IPAC */
153                 spin_unlock_irqrestore(&cs->lock, flags);
154                 return IRQ_NONE;
155         }
156       Start_IPAC:
157         if (cs->debug & L1_DEB_IPAC)
158                 debugl1(cs, "IPAC ISTA %02X", ista);
159         if (ista & 0x0f) {
160                 val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
161                 if (ista & 0x01)
162                         val |= 0x01;
163                 if (ista & 0x04)
164                         val |= 0x02;
165                 if (ista & 0x08)
166                         val |= 0x04;
167                 if (val) {
168                         hscx_int_main(cs, val);
169                 }
170         }
171         if (ista & 0x20) {
172                 val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
173                 if (val) {
174                         isac_interrupt(cs, val);
175                 }
176         }
177         if (ista & 0x10) {
178                 val = 0x01;
179                 isac_interrupt(cs, val);
180         }
181         ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
182         if ((ista & 0x3f) && icnt) {
183                 icnt--;
184                 goto Start_IPAC;
185         }
186         if (!icnt)
187                 printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOP\n",
188                        CardType[cs->typ],
189                        sct_quadro_subtypes[cs->subtyp]);
190         writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
191         writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
192         spin_unlock_irqrestore(&cs->lock, flags);
193         return IRQ_HANDLED;
194 }
195
196 void
197 release_io_sct_quadro(struct IsdnCardState *cs)
198 {
199         release_region(cs->hw.ax.base & 0xffffffc0, 128);
200         if (cs->subtyp == SCT_1)
201                 release_region(cs->hw.ax.plx_adr, 64);
202 }
203
204 static void
205 enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
206 {
207         if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
208                 if (bEnable)
209                         wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
210                 else
211                         wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
212         }
213 }
214
215 static void
216 reset_bkm(struct IsdnCardState *cs)
217 {
218         if (cs->subtyp == SCT_1) {
219                 wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
220                 mdelay(10);
221                 /* Remove the soft reset */
222                 wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
223                 mdelay(10);
224         }
225 }
226
227 static int
228 BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
229 {
230         u_long flags;
231
232         switch (mt) {
233                 case CARD_RESET:
234                         spin_lock_irqsave(&cs->lock, flags);
235                         /* Disable ints */
236                         set_ipac_active(cs, 0);
237                         enable_bkm_int(cs, 0);
238                         reset_bkm(cs);
239                         spin_unlock_irqrestore(&cs->lock, flags);
240                         return (0);
241                 case CARD_RELEASE:
242                         /* Sanity */
243                         spin_lock_irqsave(&cs->lock, flags);
244                         set_ipac_active(cs, 0);
245                         enable_bkm_int(cs, 0);
246                         spin_unlock_irqrestore(&cs->lock, flags);
247                         release_io_sct_quadro(cs);
248                         return (0);
249                 case CARD_INIT:
250                         spin_lock_irqsave(&cs->lock, flags);
251                         cs->debug |= L1_DEB_IPAC;
252                         set_ipac_active(cs, 1);
253                         inithscxisac(cs, 3);
254                         /* Enable ints */
255                         enable_bkm_int(cs, 1);
256                         spin_unlock_irqrestore(&cs->lock, flags);
257                         return (0);
258                 case CARD_TEST:
259                         return (0);
260         }
261         return (0);
262 }
263
264 int __init
265 sct_alloc_io(u_int adr, u_int len)
266 {
267         if (!request_region(adr, len, "scitel")) {
268                 printk(KERN_WARNING
269                         "HiSax: Scitel port %#x-%#x already in use\n",
270                         adr, adr + len);
271                 return (1);
272         }
273         return(0);
274 }
275
276 static struct pci_dev *dev_a8 __initdata = NULL;
277 static u16  sub_vendor_id __initdata = 0;
278 static u16  sub_sys_id __initdata = 0;
279 static u_char pci_bus __initdata = 0;
280 static u_char pci_device_fn __initdata = 0;
281 static u_char pci_irq __initdata = 0;
282
283 #endif /* CONFIG_PCI */
284
285 int __init
286 setup_sct_quadro(struct IsdnCard *card)
287 {
288 #if CONFIG_PCI
289         struct IsdnCardState *cs = card->cs;
290         char tmp[64];
291         u_char pci_rev_id;
292         u_int found = 0;
293         u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
294
295         strcpy(tmp, sct_quadro_revision);
296         printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
297         if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
298                 cs->subtyp = SCT_1;     /* Preset */
299         } else
300                 return (0);
301
302         /* Identify subtype by para[0] */
303         if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
304                 cs->subtyp = card->para[0];
305         else {
306                 printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n",
307                         CardType[card->typ]);
308                 return (0);
309         }
310         if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
311                 (sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
312                 return (0);
313         if (cs->subtyp == SCT_1) {
314                 while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX,
315                         PCI_DEVICE_ID_PLX_9050, dev_a8))) {
316                         
317                         sub_vendor_id = dev_a8->subsystem_vendor;
318                         sub_sys_id = dev_a8->subsystem_device;
319                         if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
320                                 (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
321                                 if (pci_enable_device(dev_a8))
322                                         return(0);
323                                 pci_ioaddr1 = pci_resource_start(dev_a8, 1);
324                                 pci_irq = dev_a8->irq;
325                                 pci_bus = dev_a8->bus->number;
326                                 pci_device_fn = dev_a8->devfn;
327                                 found = 1;
328                                 break;
329                         }
330                 }
331                 if (!found) {
332                         printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
333                                 CardType[card->typ],
334                                 sct_quadro_subtypes[cs->subtyp]);
335                         return (0);
336                 }
337 #ifdef ATTEMPT_PCI_REMAPPING
338 /* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
339                 pci_read_config_byte(dev_a8, PCI_REVISION_ID, &pci_rev_id);
340                 if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
341                         printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
342                                 CardType[card->typ],
343                                 sct_quadro_subtypes[cs->subtyp]);
344                         /* Restart PCI negotiation */
345                         pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int) - 1);
346                         /* Move up by 0x80 byte */
347                         pci_ioaddr1 += 0x80;
348                         pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
349                         pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1);
350                         dev_a8->resource[ 1].start = pci_ioaddr1;
351                 }
352 #endif /* End HACK */
353         }
354         if (!pci_irq) {         /* IRQ range check ?? */
355                 printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n",
356                        CardType[card->typ],
357                        sct_quadro_subtypes[cs->subtyp]);
358                 return (0);
359         }
360         pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
361         pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
362         pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
363         pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
364         pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
365         if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
366                 printk(KERN_WARNING "HiSax: %s (%s): No IO base address(es)\n",
367                        CardType[card->typ],
368                        sct_quadro_subtypes[cs->subtyp]);
369                 return (0);
370         }
371         pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
372         pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
373         pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
374         pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
375         pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
376         /* Take over */
377         cs->irq = pci_irq;
378         cs->irq_flags |= SA_SHIRQ;
379         /* pci_ioaddr1 is unique to all subdevices */
380         /* pci_ioaddr2 is for the fourth subdevice only */
381         /* pci_ioaddr3 is for the third subdevice only */
382         /* pci_ioaddr4 is for the second subdevice only */
383         /* pci_ioaddr5 is for the first subdevice only */
384         cs->hw.ax.plx_adr = pci_ioaddr1;
385         /* Enter all ipac_base addresses */
386         switch(cs->subtyp) {
387                 case 1:
388                         cs->hw.ax.base = pci_ioaddr5 + 0x00;
389                         if (sct_alloc_io(pci_ioaddr1, 128))
390                                 return(0);
391                         if (sct_alloc_io(pci_ioaddr5, 64))
392                                 return(0);
393                         /* disable all IPAC */
394                         writereg(pci_ioaddr5, pci_ioaddr5 + 4,
395                                 IPAC_MASK, 0xFF);
396                         writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
397                                 IPAC_MASK, 0xFF);
398                         writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
399                                 IPAC_MASK, 0xFF);
400                         writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
401                                 IPAC_MASK, 0xFF);
402                         break;
403                 case 2:
404                         cs->hw.ax.base = pci_ioaddr4 + 0x08;
405                         if (sct_alloc_io(pci_ioaddr4, 64))
406                                 return(0);
407                         break;
408                 case 3:
409                         cs->hw.ax.base = pci_ioaddr3 + 0x10;
410                         if (sct_alloc_io(pci_ioaddr3, 64))
411                                 return(0);
412                         break;
413                 case 4:
414                         cs->hw.ax.base = pci_ioaddr2 + 0x20;
415                         if (sct_alloc_io(pci_ioaddr2, 64))
416                                 return(0);
417                         break;
418         }       
419         /* For isac and hscx data path */
420         cs->hw.ax.data_adr = cs->hw.ax.base + 4;
421
422         printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n",
423                CardType[card->typ],
424                sct_quadro_subtypes[cs->subtyp],
425                cs->hw.ax.plx_adr,
426                cs->hw.ax.base,
427                cs->hw.ax.data_adr,
428                cs->irq);
429
430         test_and_set_bit(HW_IPAC, &cs->HW_Flags);
431
432         cs->readisac = &ReadISAC;
433         cs->writeisac = &WriteISAC;
434         cs->readisacfifo = &ReadISACfifo;
435         cs->writeisacfifo = &WriteISACfifo;
436
437         cs->BC_Read_Reg = &ReadHSCX;
438         cs->BC_Write_Reg = &WriteHSCX;
439         cs->BC_Send_Data = &hscx_fill_fifo;
440         cs->cardmsg = &BKM_card_msg;
441         cs->irq_func = &bkm_interrupt_ipac;
442
443         printk(KERN_INFO "HiSax: %s (%s): IPAC Version %d\n",
444                 CardType[card->typ],
445                 sct_quadro_subtypes[cs->subtyp],
446                 readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
447         return (1);
448 #else
449         printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
450 #endif /* CONFIG_PCI */
451 }