linux/drivers/isdn/hardware/eicon/s_4bri.c
<<
>>
Prefs
   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