1 /* $Id: gazel.c,v 2.11.6.7 2001/09/23 22:24:47 kai Exp $
3 * low level stuff for Gazel isdn cards
6 * based on source code from Karsten Keil
7 * Copyright by BeWan Systems
9 * This software may be used and distributed according to the terms
10 * of the GNU General Public License, incorporated herein by reference.
14 #include <linux/config.h>
15 #include <linux/init.h>
21 #include <linux/pci.h>
23 extern const char *CardType
[];
24 const char *gazel_revision
= "$Revision: 2.11.6.7 $";
25 static spinlock_t gazel_lock
= SPIN_LOCK_UNLOCKED
;
32 #define PLX_CNTRL 0x50 /* registre de controle PLX */
33 #define RESET_GAZEL 0x4
34 #define RESET_9050 0x40000000
35 #define PLX_INCSR 0x4C /* registre d'IT du 9050 */
36 #define INT_ISAC_EN 0x8 /* 1 = enable IT isac */
37 #define INT_ISAC 0x20 /* 1 = IT isac en cours */
38 #define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */
39 #define INT_HSCX 0x4 /* 1 = IT hscx en cours */
40 #define INT_PCI_EN 0x40 /* 1 = enable IT PCI */
41 #define INT_IPAC_EN 0x3 /* enable IT ipac */
44 #define byteout(addr,val) outb(val,addr)
45 #define bytein(addr) inb(addr)
48 readreg(unsigned int adr
, u_short off
)
50 return bytein(adr
+ off
);
54 writereg(unsigned int adr
, u_short off
, u8 data
)
56 byteout(adr
+ off
, data
);
61 read_fifo(unsigned int adr
, u8
* data
, int size
)
63 insb(adr
, data
, size
);
67 write_fifo(unsigned int adr
, u8
* data
, int size
)
69 outsb(adr
, data
, size
);
73 r685_isac_read(struct IsdnCardState
*cs
, u8 off
)
75 return readreg(cs
->hw
.gazel
.isac
, off
);
79 r647_isac_read(struct IsdnCardState
*cs
, u8 off
)
81 return readreg(cs
->hw
.gazel
.isac
, (off
<< 8 & 0xf000) | (off
& 0xf));
85 r685_isac_write(struct IsdnCardState
*cs
, u8 off
, u8 value
)
87 writereg(cs
->hw
.gazel
.isac
, off
, value
);
91 r647_isac_write(struct IsdnCardState
*cs
, u8 off
, u8 value
)
93 writereg(cs
->hw
.gazel
.isac
, (off
<< 8 & 0xf000) | (off
& 0xf), value
);
97 isac_read_fifo(struct IsdnCardState
*cs
, u8
* data
, int size
)
99 read_fifo(cs
->hw
.gazel
.isacfifo
, data
, size
);
103 isac_write_fifo(struct IsdnCardState
*cs
, u8
* data
, int size
)
105 write_fifo(cs
->hw
.gazel
.isacfifo
, data
, size
);
108 static struct dc_hw_ops r685_isac_ops
= {
109 .read_reg
= r685_isac_read
,
110 .write_reg
= r685_isac_write
,
111 .read_fifo
= isac_read_fifo
,
112 .write_fifo
= isac_write_fifo
,
115 static struct dc_hw_ops r647_isac_ops
= {
116 .read_reg
= r647_isac_read
,
117 .write_reg
= r647_isac_write
,
118 .read_fifo
= isac_read_fifo
,
119 .write_fifo
= isac_write_fifo
,
123 r685_hscx_read(struct IsdnCardState
*cs
, int hscx
, u8 off
)
125 return readreg(cs
->hw
.gazel
.hscx
[hscx
], off
);
129 r647_hscx_read(struct IsdnCardState
*cs
, int hscx
, u8 off
)
131 return readreg(cs
->hw
.gazel
.hscx
[hscx
],
132 (off
<< 8 & 0xf000) | (off
& 0xf));
136 r685_hscx_write(struct IsdnCardState
*cs
, int hscx
, u8 off
, u8 value
)
138 writereg(cs
->hw
.gazel
.hscx
[hscx
], off
, value
);
142 r647_hscx_write(struct IsdnCardState
*cs
, int hscx
, u8 off
, u8 value
)
144 writereg(cs
->hw
.gazel
.hscx
[hscx
],
145 (off
<< 8 & 0xf000) | (off
& 0xf), value
);
149 hscx_read_fifo(struct IsdnCardState
*cs
, int hscx
, u8
* data
, int size
)
151 read_fifo(cs
->hw
.gazel
.hscxfifo
[hscx
], data
, size
);
155 hscx_write_fifo(struct IsdnCardState
*cs
, int hscx
, u8
* data
, int size
)
157 write_fifo(cs
->hw
.gazel
.hscxfifo
[hscx
], data
, size
);
160 static struct bc_hw_ops r685_hscx_ops
= {
161 .read_reg
= r685_hscx_read
,
162 .write_reg
= r685_hscx_write
,
163 .read_fifo
= hscx_read_fifo
,
164 .write_fifo
= hscx_write_fifo
,
167 static struct bc_hw_ops r647_hscx_ops
= {
168 .read_reg
= r647_hscx_read
,
169 .write_reg
= r647_hscx_write
,
170 .read_fifo
= hscx_read_fifo
,
171 .write_fifo
= hscx_write_fifo
,
175 ipac_read(struct IsdnCardState
*cs
, u_short off
)
180 spin_lock_irqsave(&gazel_lock
, flags
);
181 byteout(cs
->hw
.gazel
.ipac
, off
);
182 ret
= bytein(cs
->hw
.gazel
.ipac
+ 4);
183 spin_unlock_irqrestore(&gazel_lock
, flags
);
188 ipac_write(struct IsdnCardState
*cs
, u_short off
, u8 data
)
192 spin_lock_irqsave(&gazel_lock
, flags
);
193 byteout(cs
->hw
.gazel
.ipac
, off
);
194 byteout(cs
->hw
.gazel
.ipac
+ 4, data
);
195 spin_unlock_irqrestore(&gazel_lock
, flags
);
200 ipac_readfifo(struct IsdnCardState
*cs
, u8 off
, u8
* data
, int size
)
202 byteout(cs
->hw
.gazel
.ipac
, off
);
203 insb(cs
->hw
.gazel
.ipac
+ 4, data
, size
);
207 ipac_writefifo(struct IsdnCardState
*cs
, u8 off
, u8
* data
, int size
)
209 byteout(cs
->hw
.gazel
.ipac
, off
);
210 outsb(cs
->hw
.gazel
.ipac
+ 4, data
, size
);
213 /* This will generate ipac_dc_ops and ipac_bc_ops using the functions
216 BUILD_IPAC_OPS(ipac
);
219 r647_reset(struct IsdnCardState
*cs
)
221 writereg(cs
->hw
.gazel
.cfg_reg
, 0, 0);
223 writereg(cs
->hw
.gazel
.cfg_reg
, 0, 1);
229 r685_reset(struct IsdnCardState
*cs
)
231 unsigned long plxcntrl
, addr
= cs
->hw
.gazel
.cfg_reg
;
233 plxcntrl
= inl(addr
+ PLX_CNTRL
);
234 plxcntrl
|= (RESET_9050
+ RESET_GAZEL
);
235 outl(plxcntrl
, addr
+ PLX_CNTRL
);
236 plxcntrl
&= ~(RESET_9050
+ RESET_GAZEL
);
238 outl(plxcntrl
, addr
+ PLX_CNTRL
);
240 outb(INT_ISAC_EN
+ INT_HSCX_EN
+ INT_PCI_EN
, addr
+ PLX_INCSR
);
245 r753_reset(struct IsdnCardState
*cs
)
247 unsigned long plxcntrl
, addr
= cs
->hw
.gazel
.cfg_reg
;
249 if (test_bit(FLG_BUGGY_PLX9050
, &cs
->HW_Flags
))
250 /* we can't read, assume the default */
251 plxcntrl
= 0x18784db6;
253 plxcntrl
= inl(addr
+ PLX_CNTRL
);
254 plxcntrl
|= (RESET_9050
+ RESET_GAZEL
);
255 outl(plxcntrl
, addr
+ PLX_CNTRL
);
256 ipac_write(cs
, IPAC_POTA2
, 0x20);
258 plxcntrl
&= ~(RESET_9050
+ RESET_GAZEL
);
259 outl(plxcntrl
, addr
+ PLX_CNTRL
);
261 ipac_write(cs
, IPAC_POTA2
, 0x00);
262 ipac_write(cs
, IPAC_ACFG
, 0xff);
263 ipac_write(cs
, IPAC_AOE
, 0x0);
264 ipac_write(cs
, IPAC_MASK
, 0xff);
265 ipac_write(cs
, IPAC_CONF
, 0x1);
266 outb(INT_IPAC_EN
+ INT_PCI_EN
, addr
+ PLX_INCSR
);
267 ipac_write(cs
, IPAC_MASK
, 0xc0);
272 r742_reset(struct IsdnCardState
*cs
)
274 ipac_write(cs
, IPAC_POTA2
, 0x20);
276 ipac_write(cs
, IPAC_POTA2
, 0x00);
277 ipac_write(cs
, IPAC_ACFG
, 0xff);
278 ipac_write(cs
, IPAC_AOE
, 0x0);
279 ipac_write(cs
, IPAC_MASK
, 0xff);
280 ipac_write(cs
, IPAC_CONF
, 0x1);
281 ipac_write(cs
, IPAC_MASK
, 0xc0);
286 gazel_init(struct IsdnCardState
*cs
)
290 for (i
= 0; i
< 2; i
++) {
291 cs
->bcs
[i
].hw
.hscx
.tsaxr0
= 0x1f;
292 cs
->bcs
[i
].hw
.hscx
.tsaxr1
= 0x23;
297 static struct card_ops r647_ops
= {
300 .release
= hisax_release_resources
,
301 .irq_func
= hscxisac_irq
,
304 static struct card_ops r685_ops
= {
307 .release
= hisax_release_resources
,
308 .irq_func
= hscxisac_irq
,
311 static struct card_ops r742_ops
= {
314 .release
= hisax_release_resources
,
315 .irq_func
= ipac_irq
,
318 static struct card_ops r753_ops
= {
321 .release
= hisax_release_resources
,
322 .irq_func
= ipac_irq
,
326 gazel647_probe(struct IsdnCardState
*cs
, struct IsdnCard
*card
)
331 cs
->irq
= card
->para
[0];
332 cs
->hw
.gazel
.cfg_reg
= card
->para
[1] + 0xC000;
334 printk(KERN_INFO
"Gazel: Card ISA R647/R648 found\n");
335 cs
->dc
.isac
.adf2
= 0x87;
336 printk(KERN_INFO
"Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
337 cs
->irq
, cs
->hw
.gazel
.isac
, cs
->hw
.gazel
.cfg_reg
);
339 "Gazel: hscx A:0x%X hscx B:0x%X\n",
340 cs
->hw
.gazel
.hscx
[0], cs
->hw
.gazel
.hscx
[1]);
342 cs
->hw
.gazel
.isac
= card
->para
[1] + 0x8000;
343 cs
->hw
.gazel
.hscx
[0] = card
->para
[1];
344 cs
->hw
.gazel
.hscx
[1] = card
->para
[1] + 0x4000;
345 cs
->hw
.gazel
.isacfifo
= cs
->hw
.gazel
.isac
;
346 cs
->hw
.gazel
.hscxfifo
[0] = cs
->hw
.gazel
.hscx
[0];
347 cs
->hw
.gazel
.hscxfifo
[1] = cs
->hw
.gazel
.hscx
[1];
349 base
= cs
->hw
.gazel
.hscx
[0];
350 for (i
= 0; i
< 0xc000; i
+= 0x1000) {
351 if (!request_io(&cs
->rs
, base
+ i
, 16, "gazel"))
354 if (!request_io(&cs
->rs
, 0xc000 + base
, 1, "gazel"))
357 cs
->card_ops
= &r647_ops
;
358 if (hscxisac_setup(cs
, &r647_isac_ops
, &r647_hscx_ops
))
361 cs
->card_ops
->reset(cs
);
364 hisax_release_resources(cs
);
369 gazel742_probe(struct IsdnCardState
*cs
, struct IsdnCard
*card
)
372 cs
->irq
= card
->para
[0];
373 cs
->hw
.gazel
.cfg_reg
= card
->para
[1] + 0xC000;
375 printk(KERN_INFO
"Gazel: Card ISA R742 found\n");
376 printk(KERN_INFO
"Gazel: config irq:%d ipac:0x%X\n",
377 cs
->irq
, cs
->hw
.gazel
.ipac
);
379 if (!request_io(&cs
->rs
, cs
->hw
.gazel
.ipac
, 0x8, "gazel"))
382 cs
->card_ops
= &r742_ops
;
383 if (ipac_setup(cs
, &ipac_dc_ops
, &ipac_bc_ops
))
386 cs
->card_ops
->reset(cs
);
389 hisax_release_resources(cs
);
394 gazel685_probe(struct IsdnCardState
*cs
, struct pci_dev
*pdev
)
396 if (pci_enable_device(pdev
))
401 cs
->irq_flags
|= SA_SHIRQ
;
402 cs
->hw
.gazel
.cfg_reg
= pci_resource_start(pdev
, 1);
403 cs
->hw
.gazel
.isac
= pci_resource_start(pdev
, 2) + 0x80;
404 cs
->hw
.gazel
.hscx
[0] = pci_resource_start(pdev
, 2);
405 cs
->hw
.gazel
.hscx
[1] = pci_resource_start(pdev
, 2) + 0x40;
406 cs
->hw
.gazel
.isacfifo
= cs
->hw
.gazel
.isac
;
407 cs
->hw
.gazel
.hscxfifo
[0] = cs
->hw
.gazel
.hscx
[0];
408 cs
->hw
.gazel
.hscxfifo
[1] = cs
->hw
.gazel
.hscx
[1];
409 cs
->dc
.isac
.adf2
= 0x87;
411 if (!request_io(&cs
->rs
, cs
->hw
.gazel
.hscx
[0], 0x100, "gazel"))
413 if (!request_io(&cs
->rs
, cs
->hw
.gazel
.cfg_reg
, 0x80, "gazel"))
416 printk(KERN_INFO
"Gazel: Card PCI R685 found\n");
417 printk(KERN_INFO
"Gazel: config irq:%d isac:0x%X cfg:0x%X\n",
418 cs
->irq
, cs
->hw
.gazel
.isac
, cs
->hw
.gazel
.cfg_reg
);
419 printk(KERN_INFO
"Gazel: hscx A:0x%X hscx B:0x%X\n",
420 cs
->hw
.gazel
.hscx
[0], cs
->hw
.gazel
.hscx
[1]);
422 cs
->card_ops
= &r685_ops
;
423 if (hscxisac_setup(cs
, &r685_isac_ops
, &r685_hscx_ops
))
426 cs
->card_ops
->reset(cs
);
429 hisax_release_resources(cs
);
434 gazel753_probe(struct IsdnCardState
*cs
, struct pci_dev
*pdev
)
438 if (pci_enable_device(pdev
))
443 cs
->irq_flags
|= SA_SHIRQ
;
444 cs
->hw
.gazel
.cfg_reg
= pci_resource_start(pdev
, 1);
445 cs
->hw
.gazel
.ipac
= pci_resource_start(pdev
, 2);
447 if (!request_io(&cs
->rs
, cs
->hw
.gazel
.ipac
, 0x8, "gazel"))
449 if (!request_io(&cs
->rs
, cs
->hw
.gazel
.cfg_reg
, 0x80, "gazel"))
452 printk(KERN_INFO
"Gazel: Card PCI R753 found\n");
453 printk(KERN_INFO
"Gazel: config irq:%d ipac:0x%X cfg:0x%X\n",
454 cs
->irq
, cs
->hw
.gazel
.ipac
, cs
->hw
.gazel
.cfg_reg
);
456 * Erratum for PLX9050, revision 1:
457 * If bit 7 of BAR 0/1 is set, local config registers
458 * can not be read (write is okay)
460 if (cs
->hw
.gazel
.cfg_reg
& 0x80) {
461 pci_read_config_byte(pdev
, PCI_REVISION_ID
, &pci_rev
);
463 printk(KERN_INFO
"Gazel: PLX9050 rev1 workaround "
465 __set_bit(FLG_BUGGY_PLX9050
, &cs
->HW_Flags
);
468 cs
->card_ops
= &r753_ops
;
469 if (ipac_setup(cs
, &ipac_dc_ops
, &ipac_bc_ops
))
472 cs
->card_ops
->reset(cs
);
475 hisax_release_resources(cs
);
479 static struct pci_dev
*dev_tel __initdata
= NULL
;
480 static u16 __initdata dev_id
= PCI_DEVICE_ID_PLX_R685
;
483 setup_gazel(struct IsdnCard
*card
)
487 strcpy(tmp
, gazel_revision
);
488 printk(KERN_INFO
"Gazel: Driver Revision %s\n", HiSax_getrev(tmp
));
491 printk(KERN_INFO
"Gazel: ISA card automatic recognition\n");
492 // we got an irq parameter, assume it is an ISA card
493 // R742 decodes address even in not started...
494 // R647 returns FF if not present or not started
495 // eventually needs improvment
496 card
->cs
->hw
.gazel
.ipac
= card
->para
[1];
497 if (ipac_read(card
->cs
, IPAC_ID
) == 1) {
498 if (gazel742_probe(card
->cs
, card
))
501 if (gazel647_probe(card
->cs
, card
))
508 dev_tel
= pci_find_device(PCI_VENDOR_ID_PLX
, dev_id
, dev_tel
);
511 case PCI_DEVICE_ID_PLX_R685
:
512 if (gazel685_probe(card
->cs
, dev_tel
))
515 case PCI_DEVICE_ID_PLX_R753
:
516 case PCI_DEVICE_ID_PLX_DJINN_ITOO
:
517 if (gazel753_probe(card
->cs
, dev_tel
))
523 case PCI_DEVICE_ID_PLX_R685
:
524 dev_id
= PCI_DEVICE_ID_PLX_R753
;
525 case PCI_DEVICE_ID_PLX_R753
:
526 dev_id
= PCI_DEVICE_ID_PLX_DJINN_ITOO
;
531 printk(KERN_WARNING
"Gazel: No PCI card found\n");