Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[linux/fpc-iii.git] / drivers / isdn / hardware / eicon / s_4bri.c
blobec12165fbf62850de5381d67f6044ba6d4f96754
2 /*
4 Copyright (c) Eicon Networks, 2002.
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
9 Eicon File Revision : 2.1
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "platform.h"
27 #include "di_defs.h"
28 #include "pc.h"
29 #include "pr_pc.h"
30 #include "di.h"
31 #include "mi_pc.h"
32 #include "pc_maint.h"
33 #include "divasync.h"
34 #include "pc_init.h"
35 #include "io.h"
36 #include "helpers.h"
37 #include "dsrv4bri.h"
38 #include "dsp_defs.h"
39 #include "sdp_hdr.h"
41 /*****************************************************************************/
42 #define MAX_XLOG_SIZE (64 * 1024)
44 /* --------------------------------------------------------------------------
45 Recovery XLOG from QBRI Card
46 -------------------------------------------------------------------------- */
47 static void qBri_cpu_trapped(PISDN_ADAPTER IoAdapter) {
48 byte __iomem *base;
49 word *Xlog;
50 dword regs[4], TrapID, offset, size;
51 Xdesc xlogDesc;
52 int factor = (IoAdapter->tasks == 1) ? 1 : 2;
55 * check for trapped MIPS 46xx CPU, dump exception frame
58 base = DIVA_OS_MEM_ATTACH_CONTROL(IoAdapter);
59 offset = IoAdapter->ControllerNumber * (IoAdapter->MemorySize >> factor);
61 TrapID = READ_DWORD(&base[0x80]);
63 if ((TrapID == 0x99999999) || (TrapID == 0x99999901))
65 dump_trap_frame(IoAdapter, &base[0x90]);
66 IoAdapter->trapped = 1;
69 regs[0] = READ_DWORD((base + offset) + 0x70);
70 regs[1] = READ_DWORD((base + offset) + 0x74);
71 regs[2] = READ_DWORD((base + offset) + 0x78);
72 regs[3] = READ_DWORD((base + offset) + 0x7c);
73 regs[0] &= IoAdapter->MemorySize - 1;
75 if ((regs[0] >= offset)
76 && (regs[0] < offset + (IoAdapter->MemorySize >> factor) - 1))
78 if (!(Xlog = (word *)diva_os_malloc(0, MAX_XLOG_SIZE))) {
79 DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
80 return;
83 size = offset + (IoAdapter->MemorySize >> factor) - regs[0];
84 if (size > MAX_XLOG_SIZE)
85 size = MAX_XLOG_SIZE;
86 memcpy_fromio(Xlog, &base[regs[0]], size);
87 xlogDesc.buf = Xlog;
88 xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]);
89 xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]);
90 dump_xlog_buffer(IoAdapter, &xlogDesc);
91 diva_os_free(0, Xlog);
92 IoAdapter->trapped = 2;
94 DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
97 /* --------------------------------------------------------------------------
98 Reset QBRI Hardware
99 -------------------------------------------------------------------------- */
100 static void reset_qBri_hardware(PISDN_ADAPTER IoAdapter) {
101 word volatile __iomem *qBriReset;
102 byte volatile __iomem *qBriCntrl;
103 byte volatile __iomem *p;
105 qBriReset = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
106 WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_SOFT_RESET);
107 diva_os_wait(1);
108 WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_SOFT_RESET);
109 diva_os_wait(1);
110 WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_RELOAD_EEPROM);
111 diva_os_wait(1);
112 WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_RELOAD_EEPROM);
113 diva_os_wait(1);
114 DIVA_OS_MEM_DETACH_PROM(IoAdapter, qBriReset);
116 qBriCntrl = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
117 p = &qBriCntrl[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
118 WRITE_DWORD(p, 0);
119 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, qBriCntrl);
121 DBG_TRC(("resetted board @ reset addr 0x%08lx", qBriReset))
122 DBG_TRC(("resetted board @ cntrl addr 0x%08lx", p))
125 /* --------------------------------------------------------------------------
126 Start Card CPU
127 -------------------------------------------------------------------------- */
128 void start_qBri_hardware(PISDN_ADAPTER IoAdapter) {
129 byte volatile __iomem *qBriReset;
130 byte volatile __iomem *p;
132 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
133 qBriReset = &p[(DIVA_4BRI_REVISION(IoAdapter)) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
134 WRITE_DWORD(qBriReset, MQ_RISC_COLD_RESET_MASK);
135 diva_os_wait(2);
136 WRITE_DWORD(qBriReset, MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK);
137 diva_os_wait(10);
138 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
140 DBG_TRC(("started processor @ addr 0x%08lx", qBriReset))
143 /* --------------------------------------------------------------------------
144 Stop Card CPU
145 -------------------------------------------------------------------------- */
146 static void stop_qBri_hardware(PISDN_ADAPTER IoAdapter) {
147 byte volatile __iomem *p;
148 dword volatile __iomem *qBriReset;
149 dword volatile __iomem *qBriIrq;
150 dword volatile __iomem *qBriIsacDspReset;
151 int rev2 = DIVA_4BRI_REVISION(IoAdapter);
152 int reset_offset = rev2 ? (MQ2_BREG_RISC) : (MQ_BREG_RISC);
153 int irq_offset = rev2 ? (MQ2_BREG_IRQ_TEST) : (MQ_BREG_IRQ_TEST);
154 int hw_offset = rev2 ? (MQ2_ISAC_DSP_RESET) : (MQ_ISAC_DSP_RESET);
156 if (IoAdapter->ControllerNumber > 0)
157 return;
158 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
159 qBriReset = (dword volatile __iomem *)&p[reset_offset];
160 qBriIsacDspReset = (dword volatile __iomem *)&p[hw_offset];
162 * clear interrupt line (reset Local Interrupt Test Register)
164 WRITE_DWORD(qBriReset, 0);
165 WRITE_DWORD(qBriIsacDspReset, 0);
166 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
168 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
169 WRITE_BYTE(&p[PLX9054_INTCSR], 0x00); /* disable PCI interrupts */
170 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
172 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
173 qBriIrq = (dword volatile __iomem *)&p[irq_offset];
174 WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF);
175 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
177 DBG_TRC(("stopped processor @ addr 0x%08lx", qBriReset))
181 /* --------------------------------------------------------------------------
182 FPGA download
183 -------------------------------------------------------------------------- */
184 #define FPGA_NAME_OFFSET 0x10
186 static byte *qBri_check_FPGAsrc(PISDN_ADAPTER IoAdapter, char *FileName,
187 dword *Length, dword *code) {
188 byte *File;
189 char *fpgaFile, *fpgaType, *fpgaDate, *fpgaTime;
190 dword fpgaFlen, fpgaTlen, fpgaDlen, cnt, year, i;
192 if (!(File = (byte *)xdiLoadFile(FileName, Length, 0))) {
193 return (NULL);
196 * scan file until FF and put id string into buffer
198 for (i = 0; File[i] != 0xff;)
200 if (++i >= *Length)
202 DBG_FTL(("FPGA download: start of data header not found"))
203 xdiFreeFile(File);
204 return (NULL);
207 *code = i++;
209 if ((File[i] & 0xF0) != 0x20)
211 DBG_FTL(("FPGA download: data header corrupted"))
212 xdiFreeFile(File);
213 return (NULL);
215 fpgaFlen = (dword)File[FPGA_NAME_OFFSET - 1];
216 if (fpgaFlen == 0)
217 fpgaFlen = 12;
218 fpgaFile = (char *)&File[FPGA_NAME_OFFSET];
219 fpgaTlen = (dword)fpgaFile[fpgaFlen + 2];
220 if (fpgaTlen == 0)
221 fpgaTlen = 10;
222 fpgaType = (char *)&fpgaFile[fpgaFlen + 3];
223 fpgaDlen = (dword) fpgaType[fpgaTlen + 2];
224 if (fpgaDlen == 0)
225 fpgaDlen = 11;
226 fpgaDate = (char *)&fpgaType[fpgaTlen + 3];
227 fpgaTime = (char *)&fpgaDate[fpgaDlen + 3];
228 cnt = (dword)(((File[i] & 0x0F) << 20) + (File[i + 1] << 12)
229 + (File[i + 2] << 4) + (File[i + 3] >> 4));
231 if ((dword)(i + (cnt / 8)) > *Length)
233 DBG_FTL(("FPGA download: '%s' file too small (%ld < %ld)",
234 FileName, *Length, code + ((cnt + 7) / 8)))
235 xdiFreeFile(File);
236 return (NULL);
238 i = 0;
241 while ((fpgaDate[i] != '\0')
242 && ((fpgaDate[i] < '0') || (fpgaDate[i] > '9')))
244 i++;
246 year = 0;
247 while ((fpgaDate[i] >= '0') && (fpgaDate[i] <= '9'))
248 year = year * 10 + (fpgaDate[i++] - '0');
249 } while ((year < 2000) && (fpgaDate[i] != '\0'));
251 switch (IoAdapter->cardType) {
252 case CARDTYPE_DIVASRV_B_2F_PCI:
253 break;
255 default:
256 if (year >= 2001) {
257 IoAdapter->fpga_features |= PCINIT_FPGA_PLX_ACCESS_SUPPORTED;
261 DBG_LOG(("FPGA[%s] file %s (%s %s) len %d",
262 fpgaType, fpgaFile, fpgaDate, fpgaTime, cnt))
263 return (File);
266 /******************************************************************************/
268 #define FPGA_PROG 0x0001 /* PROG enable low */
269 #define FPGA_BUSY 0x0002 /* BUSY high, DONE low */
270 #define FPGA_CS 0x000C /* Enable I/O pins */
271 #define FPGA_CCLK 0x0100
272 #define FPGA_DOUT 0x0400
273 #define FPGA_DIN FPGA_DOUT /* bidirectional I/O */
275 int qBri_FPGA_download(PISDN_ADAPTER IoAdapter) {
276 int bit;
277 byte *File;
278 dword code, FileLength;
279 word volatile __iomem *addr = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
280 word val, baseval = FPGA_CS | FPGA_PROG;
284 if (DIVA_4BRI_REVISION(IoAdapter))
286 char *name;
288 switch (IoAdapter->cardType) {
289 case CARDTYPE_DIVASRV_B_2F_PCI:
290 name = "dsbri2f.bit";
291 break;
293 case CARDTYPE_DIVASRV_B_2M_V2_PCI:
294 case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
295 name = "dsbri2m.bit";
296 break;
298 default:
299 name = "ds4bri2.bit";
302 File = qBri_check_FPGAsrc(IoAdapter, name,
303 &FileLength, &code);
305 else
307 File = qBri_check_FPGAsrc(IoAdapter, "ds4bri.bit",
308 &FileLength, &code);
310 if (!File) {
311 DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
312 return (0);
315 * prepare download, pulse PROGRAM pin down.
317 WRITE_WORD(addr, baseval & ~FPGA_PROG); /* PROGRAM low pulse */
318 WRITE_WORD(addr, baseval); /* release */
319 diva_os_wait(50); /* wait until FPGA finished internal memory clear */
321 * check done pin, must be low
323 if (READ_WORD(addr) & FPGA_BUSY)
325 DBG_FTL(("FPGA download: acknowledge for FPGA memory clear missing"))
326 xdiFreeFile(File);
327 DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
328 return (0);
331 * put data onto the FPGA
333 while (code < FileLength)
335 val = ((word)File[code++]) << 3;
337 for (bit = 8; bit-- > 0; val <<= 1) /* put byte onto FPGA */
339 baseval &= ~FPGA_DOUT; /* clr data bit */
340 baseval |= (val & FPGA_DOUT); /* copy data bit */
341 WRITE_WORD(addr, baseval);
342 WRITE_WORD(addr, baseval | FPGA_CCLK); /* set CCLK hi */
343 WRITE_WORD(addr, baseval | FPGA_CCLK); /* set CCLK hi */
344 WRITE_WORD(addr, baseval); /* set CCLK lo */
347 xdiFreeFile(File);
348 diva_os_wait(100);
349 val = READ_WORD(addr);
351 DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
353 if (!(val & FPGA_BUSY))
355 DBG_FTL(("FPGA download: chip remains in busy state (0x%04x)", val))
356 return (0);
359 return (1);
362 static int load_qBri_hardware(PISDN_ADAPTER IoAdapter) {
363 return (0);
366 /* --------------------------------------------------------------------------
367 Card ISR
368 -------------------------------------------------------------------------- */
369 static int qBri_ISR(struct _ISDN_ADAPTER *IoAdapter) {
370 dword volatile __iomem *qBriIrq;
372 PADAPTER_LIST_ENTRY QuadroList = IoAdapter->QuadroList;
374 word i;
375 int serviced = 0;
376 byte __iomem *p;
378 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
380 if (!(READ_BYTE(&p[PLX9054_INTCSR]) & 0x80)) {
381 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
382 return (0);
384 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
387 * clear interrupt line (reset Local Interrupt Test Register)
389 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
390 qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST) : (MQ_BREG_IRQ_TEST)]);
391 WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF);
392 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
394 for (i = 0; i < IoAdapter->tasks; ++i)
396 IoAdapter = QuadroList->QuadroAdapter[i];
398 if (IoAdapter && IoAdapter->Initialized
399 && IoAdapter->tst_irq(&IoAdapter->a))
401 IoAdapter->IrqCount++;
402 serviced = 1;
403 diva_os_schedule_soft_isr(&IoAdapter->isr_soft_isr);
407 return (serviced);
410 /* --------------------------------------------------------------------------
411 Does disable the interrupt on the card
412 -------------------------------------------------------------------------- */
413 static void disable_qBri_interrupt(PISDN_ADAPTER IoAdapter) {
414 dword volatile __iomem *qBriIrq;
415 byte __iomem *p;
417 if (IoAdapter->ControllerNumber > 0)
418 return;
420 * clear interrupt line (reset Local Interrupt Test Register)
422 p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
423 WRITE_BYTE(&p[PLX9054_INTCSR], 0x00); /* disable PCI interrupts */
424 DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
426 p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
427 qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST) : (MQ_BREG_IRQ_TEST)]);
428 WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF);
429 DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
432 /* --------------------------------------------------------------------------
433 Install Adapter Entry Points
434 -------------------------------------------------------------------------- */
435 static void set_common_qBri_functions(PISDN_ADAPTER IoAdapter) {
436 ADAPTER *a;
438 a = &IoAdapter->a;
440 a->ram_in = mem_in;
441 a->ram_inw = mem_inw;
442 a->ram_in_buffer = mem_in_buffer;
443 a->ram_look_ahead = mem_look_ahead;
444 a->ram_out = mem_out;
445 a->ram_outw = mem_outw;
446 a->ram_out_buffer = mem_out_buffer;
447 a->ram_inc = mem_inc;
449 IoAdapter->out = pr_out;
450 IoAdapter->dpc = pr_dpc;
451 IoAdapter->tst_irq = scom_test_int;
452 IoAdapter->clr_irq = scom_clear_int;
453 IoAdapter->pcm = (struct pc_maint *)MIPS_MAINT_OFFS;
455 IoAdapter->load = load_qBri_hardware;
457 IoAdapter->disIrq = disable_qBri_interrupt;
458 IoAdapter->rstFnc = reset_qBri_hardware;
459 IoAdapter->stop = stop_qBri_hardware;
460 IoAdapter->trapFnc = qBri_cpu_trapped;
462 IoAdapter->diva_isr_handler = qBri_ISR;
464 IoAdapter->a.io = (void *)IoAdapter;
467 static void set_qBri_functions(PISDN_ADAPTER IoAdapter) {
468 if (!IoAdapter->tasks) {
469 IoAdapter->tasks = MQ_INSTANCE_COUNT;
471 IoAdapter->MemorySize = MQ_MEMORY_SIZE;
472 set_common_qBri_functions(IoAdapter);
473 diva_os_set_qBri_functions(IoAdapter);
476 static void set_qBri2_functions(PISDN_ADAPTER IoAdapter) {
477 if (!IoAdapter->tasks) {
478 IoAdapter->tasks = MQ_INSTANCE_COUNT;
480 IoAdapter->MemorySize = (IoAdapter->tasks == 1) ? BRI2_MEMORY_SIZE : MQ2_MEMORY_SIZE;
481 set_common_qBri_functions(IoAdapter);
482 diva_os_set_qBri2_functions(IoAdapter);
485 /******************************************************************************/
487 void prepare_qBri_functions(PISDN_ADAPTER IoAdapter) {
489 set_qBri_functions(IoAdapter->QuadroList->QuadroAdapter[0]);
490 set_qBri_functions(IoAdapter->QuadroList->QuadroAdapter[1]);
491 set_qBri_functions(IoAdapter->QuadroList->QuadroAdapter[2]);
492 set_qBri_functions(IoAdapter->QuadroList->QuadroAdapter[3]);
496 void prepare_qBri2_functions(PISDN_ADAPTER IoAdapter) {
497 if (!IoAdapter->tasks) {
498 IoAdapter->tasks = MQ_INSTANCE_COUNT;
501 set_qBri2_functions(IoAdapter->QuadroList->QuadroAdapter[0]);
502 if (IoAdapter->tasks > 1) {
503 set_qBri2_functions(IoAdapter->QuadroList->QuadroAdapter[1]);
504 set_qBri2_functions(IoAdapter->QuadroList->QuadroAdapter[2]);
505 set_qBri2_functions(IoAdapter->QuadroList->QuadroAdapter[3]);
510 /* -------------------------------------------------------------------------- */