1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision :    2.1
10 *
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.
15 *
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.
20 *
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.
24 *
25 */
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"
40
41/*****************************************************************************/
42#define	MAX_XLOG_SIZE	(64 * 1024)
43
44/* --------------------------------------------------------------------------
45   Recovery XLOG from QBRI Card
46   -------------------------------------------------------------------------- */
47static 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;
53
54/*
55 *	check for trapped MIPS 46xx CPU, dump exception frame
56 */
57
58	base = DIVA_OS_MEM_ATTACH_CONTROL(IoAdapter);
59	offset = IoAdapter->ControllerNumber * (IoAdapter->MemorySize >> factor);
60
61	TrapID = READ_DWORD(&base[0x80]);
62
63	if ((TrapID == 0x99999999) || (TrapID == 0x99999901))
64	{
65		dump_trap_frame(IoAdapter, &base[0x90]);
66		IoAdapter->trapped = 1;
67	}
68
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;
74
75	if ((regs[0] >= offset)
76	    && (regs[0] < offset + (IoAdapter->MemorySize >> factor) - 1))
77	{
78		if (!(Xlog = (word *)diva_os_malloc(0, MAX_XLOG_SIZE))) {
79			DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
80			return;
81		}
82
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;
93	}
94	DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
95}
96
97/* --------------------------------------------------------------------------
98   Reset QBRI Hardware
99   -------------------------------------------------------------------------- */
100static void reset_qBri_hardware(PISDN_ADAPTER IoAdapter) {
101	word volatile __iomem *qBriReset;
102	byte  volatile __iomem *qBriCntrl;
103	byte  volatile __iomem *p;
104
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);
115
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);
120
121	DBG_TRC(("resetted board @ reset addr 0x%08lx", qBriReset))
122		DBG_TRC(("resetted board @ cntrl addr 0x%08lx", p))
123		}
124
125/* --------------------------------------------------------------------------
126   Start Card CPU
127   -------------------------------------------------------------------------- */
128void start_qBri_hardware(PISDN_ADAPTER IoAdapter) {
129	byte volatile __iomem *qBriReset;
130	byte volatile __iomem *p;
131
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);
139
140	DBG_TRC(("started processor @ addr 0x%08lx", qBriReset))
141		}
142
143/* --------------------------------------------------------------------------
144   Stop Card CPU
145   -------------------------------------------------------------------------- */
146static 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);
155
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];
161/*
162 *	clear interrupt line (reset Local Interrupt Test Register)
163 */
164	WRITE_DWORD(qBriReset, 0);
165	WRITE_DWORD(qBriIsacDspReset, 0);
166	DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
167
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);
171
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);
176
177	DBG_TRC(("stopped processor @ addr 0x%08lx", qBriReset))
178
179		}
180
181/* --------------------------------------------------------------------------
182   FPGA download
183   -------------------------------------------------------------------------- */
184#define FPGA_NAME_OFFSET         0x10
185
186static 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;
191
192	if (!(File = (byte *)xdiLoadFile(FileName, Length, 0))) {
193		return (NULL);
194	}
195/*
196 *	 scan file until FF and put id string into buffer
197 */
198	for (i = 0; File[i] != 0xff;)
199	{
200		if (++i >= *Length)
201		{
202			DBG_FTL(("FPGA download: start of data header not found"))
203				xdiFreeFile(File);
204			return (NULL);
205		}
206	}
207	*code = i++;
208
209	if ((File[i] & 0xF0) != 0x20)
210	{
211		DBG_FTL(("FPGA download: data header corrupted"))
212			xdiFreeFile(File);
213		return (NULL);
214	}
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));
230
231	if ((dword)(i + (cnt / 8)) > *Length)
232	{
233		DBG_FTL(("FPGA download: '%s' file too small (%ld < %ld)",
234			 FileName, *Length, code + ((cnt + 7) / 8)))
235			xdiFreeFile(File);
236		return (NULL);
237	}
238	i = 0;
239	do
240	{
241		while ((fpgaDate[i] != '\0')
242		       && ((fpgaDate[i] < '0') || (fpgaDate[i] > '9')))
243		{
244			i++;
245		}
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'));
250
251	switch (IoAdapter->cardType) {
252	case CARDTYPE_DIVASRV_B_2F_PCI:
253		break;
254
255	default:
256		if (year >= 2001) {
257			IoAdapter->fpga_features |= PCINIT_FPGA_PLX_ACCESS_SUPPORTED;
258		}
259	}
260
261	DBG_LOG(("FPGA[%s] file %s (%s %s) len %d",
262		 fpgaType, fpgaFile, fpgaDate, fpgaTime, cnt))
263		return (File);
264}
265
266/******************************************************************************/
267
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 */
274
275int 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;
281
282
283
284	if (DIVA_4BRI_REVISION(IoAdapter))
285	{
286		char *name;
287
288		switch (IoAdapter->cardType) {
289		case CARDTYPE_DIVASRV_B_2F_PCI:
290			name = "dsbri2f.bit";
291			break;
292
293		case CARDTYPE_DIVASRV_B_2M_V2_PCI:
294		case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
295			name = "dsbri2m.bit";
296			break;
297
298		default:
299			name = "ds4bri2.bit";
300		}
301
302		File = qBri_check_FPGAsrc(IoAdapter, name,
303					  &FileLength, &code);
304	}
305	else
306	{
307		File = qBri_check_FPGAsrc(IoAdapter, "ds4bri.bit",
308					  &FileLength, &code);
309	}
310	if (!File) {
311		DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
312		return (0);
313	}
314/*
315 *	prepare download, pulse PROGRAM pin down.
316 */
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 */
320/*
321 *	check done pin, must be low
322 */
323	if (READ_WORD(addr) & FPGA_BUSY)
324	{
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);
329	}
330/*
331 *	put data onto the FPGA
332 */
333	while (code < FileLength)
334	{
335		val = ((word)File[code++]) << 3;
336
337		for (bit = 8; bit-- > 0; val <<= 1) /* put byte onto FPGA */
338		{
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 */
345		}
346	}
347	xdiFreeFile(File);
348	diva_os_wait(100);
349	val = READ_WORD(addr);
350
351	DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
352
353	if (!(val & FPGA_BUSY))
354	{
355		DBG_FTL(("FPGA download: chip remains in busy state (0x%04x)", val))
356			return (0);
357	}
358
359	return (1);
360}
361
362static int load_qBri_hardware(PISDN_ADAPTER IoAdapter) {
363	return (0);
364}
365
366/* --------------------------------------------------------------------------
367   Card ISR
368   -------------------------------------------------------------------------- */
369static int qBri_ISR(struct _ISDN_ADAPTER *IoAdapter) {
370	dword volatile     __iomem *qBriIrq;
371
372	PADAPTER_LIST_ENTRY QuadroList = IoAdapter->QuadroList;
373
374	word			i;
375	int			serviced = 0;
376	byte __iomem *p;
377
378	p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
379
380	if (!(READ_BYTE(&p[PLX9054_INTCSR]) & 0x80)) {
381		DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
382		return (0);
383	}
384	DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
385
386/*
387 *	clear interrupt line (reset Local Interrupt Test Register)
388 */
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);
393
394	for (i = 0; i < IoAdapter->tasks; ++i)
395	{
396		IoAdapter = QuadroList->QuadroAdapter[i];
397
398		if (IoAdapter && IoAdapter->Initialized
399		    && IoAdapter->tst_irq(&IoAdapter->a))
400		{
401			IoAdapter->IrqCount++;
402			serviced = 1;
403			diva_os_schedule_soft_isr(&IoAdapter->isr_soft_isr);
404		}
405	}
406
407	return (serviced);
408}
409
410/* --------------------------------------------------------------------------
411   Does disable the interrupt on the card
412   -------------------------------------------------------------------------- */
413static void disable_qBri_interrupt(PISDN_ADAPTER IoAdapter) {
414	dword volatile __iomem *qBriIrq;
415	byte __iomem *p;
416
417	if (IoAdapter->ControllerNumber > 0)
418		return;
419/*
420 *	clear interrupt line (reset Local Interrupt Test Register)
421 */
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);
425
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);
430}
431
432/* --------------------------------------------------------------------------
433   Install Adapter Entry Points
434   -------------------------------------------------------------------------- */
435static void set_common_qBri_functions(PISDN_ADAPTER IoAdapter) {
436	ADAPTER *a;
437
438	a = &IoAdapter->a;
439
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;
448
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;
454
455	IoAdapter->load = load_qBri_hardware;
456
457	IoAdapter->disIrq = disable_qBri_interrupt;
458	IoAdapter->rstFnc = reset_qBri_hardware;
459	IoAdapter->stop = stop_qBri_hardware;
460	IoAdapter->trapFnc = qBri_cpu_trapped;
461
462	IoAdapter->diva_isr_handler = qBri_ISR;
463
464	IoAdapter->a.io = (void *)IoAdapter;
465}
466
467static void set_qBri_functions(PISDN_ADAPTER IoAdapter) {
468	if (!IoAdapter->tasks) {
469		IoAdapter->tasks = MQ_INSTANCE_COUNT;
470	}
471	IoAdapter->MemorySize = MQ_MEMORY_SIZE;
472	set_common_qBri_functions(IoAdapter);
473	diva_os_set_qBri_functions(IoAdapter);
474}
475
476static void set_qBri2_functions(PISDN_ADAPTER IoAdapter) {
477	if (!IoAdapter->tasks) {
478		IoAdapter->tasks = MQ_INSTANCE_COUNT;
479	}
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);
483}
484
485/******************************************************************************/
486
487void prepare_qBri_functions(PISDN_ADAPTER IoAdapter) {
488
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]);
493
494}
495
496void prepare_qBri2_functions(PISDN_ADAPTER IoAdapter) {
497	if (!IoAdapter->tasks) {
498		IoAdapter->tasks = MQ_INSTANCE_COUNT;
499	}
500
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]);
506	}
507
508}
509
510/* -------------------------------------------------------------------------- */
511