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