Logo Search packages:      
Sourcecode: linux version File versions  Download package

s_4bri.c

/*
 *
  Copyright (c) Eicon Networks, 2002.
 *
  This source file is supplied for the use with
  Eicon Networks range of DIVA Server Adapters.
 *
  Eicon File Revision :    2.1
 *
  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2, or (at your option)
  any later version.
 *
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  See the GNU General Public License for more details.
 *
  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
#include "platform.h"
#include "di_defs.h"
#include "pc.h"
#include "pr_pc.h"
#include "di.h"
#include "mi_pc.h"
#include "pc_maint.h"
#include "divasync.h"
#include "pc_init.h"
#include "io.h"
#include "helpers.h"
#include "dsrv4bri.h"
#include "dsp_defs.h"
#include "sdp_hdr.h"

/*****************************************************************************/
#define     MAX_XLOG_SIZE     (64 * 1024)

/* --------------------------------------------------------------------------
            Recovery XLOG from QBRI Card
       -------------------------------------------------------------------------- */
static void qBri_cpu_trapped (PISDN_ADAPTER IoAdapter) {
      byte  __iomem *base ;
      word *Xlog ;
      dword   regs[4], TrapID, offset, size ;
      Xdesc   xlogDesc ;
      int factor = (IoAdapter->tasks == 1) ? 1 : 2;

/*
 *    check for trapped MIPS 46xx CPU, dump exception frame
 */

      base = DIVA_OS_MEM_ATTACH_CONTROL(IoAdapter);
      offset = IoAdapter->ControllerNumber * (IoAdapter->MemorySize >> factor) ;

      TrapID = READ_DWORD(&base[0x80]) ;

      if ( (TrapID == 0x99999999) || (TrapID == 0x99999901) )
      {
            dump_trap_frame (IoAdapter, &base[0x90]) ;
            IoAdapter->trapped = 1 ;
      }

      regs[0] = READ_DWORD((base + offset) + 0x70);
      regs[1] = READ_DWORD((base + offset) + 0x74);
      regs[2] = READ_DWORD((base + offset) + 0x78);
      regs[3] = READ_DWORD((base + offset) + 0x7c);
      regs[0] &= IoAdapter->MemorySize - 1 ;

      if ( (regs[0] >= offset)
        && (regs[0] < offset + (IoAdapter->MemorySize >> factor) - 1) )
      {
            if ( !(Xlog = (word *)diva_os_malloc (0, MAX_XLOG_SIZE)) ) {
                  DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
                  return ;
            }

            size = offset + (IoAdapter->MemorySize >> factor) - regs[0] ;
            if ( size > MAX_XLOG_SIZE )
                  size = MAX_XLOG_SIZE ;
            memcpy_fromio (Xlog, &base[regs[0]], size) ;
            xlogDesc.buf = Xlog ;
            xlogDesc.cnt = READ_WORD(&base[regs[1] & (IoAdapter->MemorySize - 1)]) ;
            xlogDesc.out = READ_WORD(&base[regs[2] & (IoAdapter->MemorySize - 1)]) ;
            dump_xlog_buffer (IoAdapter, &xlogDesc) ;
            diva_os_free (0, Xlog) ;
            IoAdapter->trapped = 2 ;
      }
      DIVA_OS_MEM_DETACH_CONTROL(IoAdapter, base);
}

/* --------------------------------------------------------------------------
            Reset QBRI Hardware
       -------------------------------------------------------------------------- */
static void reset_qBri_hardware (PISDN_ADAPTER IoAdapter) {
      word volatile __iomem *qBriReset ;
      byte  volatile __iomem *qBriCntrl ;
      byte  volatile __iomem *p ;

      qBriReset = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
      WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_SOFT_RESET) ;
      diva_os_wait (1) ;
      WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_SOFT_RESET) ;
      diva_os_wait (1);
      WRITE_WORD(qBriReset, READ_WORD(qBriReset) | PLX9054_RELOAD_EEPROM) ;
      diva_os_wait (1) ;
      WRITE_WORD(qBriReset, READ_WORD(qBriReset) & ~PLX9054_RELOAD_EEPROM) ;
      diva_os_wait (1);
      DIVA_OS_MEM_DETACH_PROM(IoAdapter, qBriReset);

      qBriCntrl = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
      p = &qBriCntrl[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
      WRITE_DWORD(p, 0) ;
      DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, qBriCntrl);

      DBG_TRC(("resetted board @ reset addr 0x%08lx", qBriReset))
      DBG_TRC(("resetted board @ cntrl addr 0x%08lx", p))
}

/* --------------------------------------------------------------------------
            Start Card CPU
       -------------------------------------------------------------------------- */
void start_qBri_hardware (PISDN_ADAPTER IoAdapter) {
      byte volatile __iomem *qBriReset ;
      byte volatile __iomem *p ;

      p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
      qBriReset = &p[(DIVA_4BRI_REVISION(IoAdapter)) ? (MQ2_BREG_RISC) : (MQ_BREG_RISC)];
      WRITE_DWORD(qBriReset, MQ_RISC_COLD_RESET_MASK) ;
      diva_os_wait (2) ;
      WRITE_DWORD(qBriReset, MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK) ;
      diva_os_wait (10) ;
      DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);

      DBG_TRC(("started processor @ addr 0x%08lx", qBriReset))
}

/* --------------------------------------------------------------------------
            Stop Card CPU
       -------------------------------------------------------------------------- */
static void stop_qBri_hardware (PISDN_ADAPTER IoAdapter) {
      byte volatile __iomem *p ;
      dword volatile __iomem *qBriReset ;
      dword volatile __iomem *qBriIrq ;
      dword volatile __iomem *qBriIsacDspReset ;
      int rev2 = DIVA_4BRI_REVISION(IoAdapter);
      int reset_offset = rev2 ? (MQ2_BREG_RISC)      : (MQ_BREG_RISC);
      int irq_offset   = rev2 ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST);
      int hw_offset    = rev2 ? (MQ2_ISAC_DSP_RESET) : (MQ_ISAC_DSP_RESET);

      if ( IoAdapter->ControllerNumber > 0 )
            return ;
      p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
      qBriReset = (dword volatile __iomem *)&p[reset_offset];
      qBriIsacDspReset = (dword volatile __iomem *)&p[hw_offset];
/*
 *    clear interrupt line (reset Local Interrupt Test Register)
 */
      WRITE_DWORD(qBriReset, 0) ;
      WRITE_DWORD(qBriIsacDspReset, 0) ;
      DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
      
      p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
      WRITE_BYTE(&p[PLX9054_INTCSR], 0x00);     /* disable PCI interrupts */
      DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
      
      p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
      qBriIrq   = (dword volatile __iomem *)&p[irq_offset];
      WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
      DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);

      DBG_TRC(("stopped processor @ addr 0x%08lx", qBriReset))

}

/* --------------------------------------------------------------------------
            FPGA download
       -------------------------------------------------------------------------- */
#define FPGA_NAME_OFFSET         0x10

static byte * qBri_check_FPGAsrc (PISDN_ADAPTER IoAdapter, char *FileName,
                                  dword *Length, dword *code) {
      byte *File ;
      char  *fpgaFile, *fpgaType, *fpgaDate, *fpgaTime ;
      dword  fpgaFlen,  fpgaTlen,  fpgaDlen, cnt, year, i ;

      if (!(File = (byte *)xdiLoadFile (FileName, Length, 0))) {
            return (NULL) ;
      }
/*
 *     scan file until FF and put id string into buffer
 */
      for ( i = 0 ; File[i] != 0xff ; )
      {
            if ( ++i >= *Length )
            {
                  DBG_FTL(("FPGA download: start of data header not found"))
                  xdiFreeFile (File) ;
                  return (NULL) ;
            }
      }
      *code = i++ ;

      if ( (File[i] & 0xF0) != 0x20 )
      {
            DBG_FTL(("FPGA download: data header corrupted"))
            xdiFreeFile (File) ;
            return (NULL) ;
      }
      fpgaFlen = (dword)  File[FPGA_NAME_OFFSET - 1] ;
      if ( fpgaFlen == 0 )
            fpgaFlen = 12 ;
      fpgaFile = (char *)&File[FPGA_NAME_OFFSET] ;
      fpgaTlen = (dword)  fpgaFile[fpgaFlen + 2] ;
      if ( fpgaTlen == 0 )
            fpgaTlen = 10 ;
      fpgaType = (char *)&fpgaFile[fpgaFlen + 3] ;
      fpgaDlen = (dword)  fpgaType[fpgaTlen + 2] ;
      if ( fpgaDlen == 0 )
            fpgaDlen = 11 ;
      fpgaDate = (char *)&fpgaType[fpgaTlen + 3] ;
      fpgaTime = (char *)&fpgaDate[fpgaDlen + 3] ;
      cnt = (dword)(((File[  i  ] & 0x0F) << 20) + (File[i + 1] << 12)
                   + (File[i + 2]         <<  4) + (File[i + 3] >>  4)) ;

      if ( (dword)(i + (cnt / 8)) > *Length )
      {
            DBG_FTL(("FPGA download: '%s' file too small (%ld < %ld)",
                     FileName, *Length, code + ((cnt + 7) / 8) ))
            xdiFreeFile (File) ;
            return (NULL) ;
      }
      i = 0 ;
      do
      {
            while ( (fpgaDate[i] != '\0')
                 && ((fpgaDate[i] < '0') || (fpgaDate[i] > '9')) )
            {
                  i++;
            }
            year = 0 ;
            while ( (fpgaDate[i] >= '0') && (fpgaDate[i] <= '9') )
                  year = year * 10 + (fpgaDate[i++] - '0') ;
      } while ( (year < 2000) && (fpgaDate[i] != '\0') );

      switch (IoAdapter->cardType) {
            case CARDTYPE_DIVASRV_B_2F_PCI:
                  break;

            default:
          if ( year >= 2001 ) {
                        IoAdapter->fpga_features |= PCINIT_FPGA_PLX_ACCESS_SUPPORTED ;
                  }
      }

      DBG_LOG(("FPGA[%s] file %s (%s %s) len %d",
               fpgaType, fpgaFile, fpgaDate, fpgaTime, cnt))
      return (File) ;
}

/******************************************************************************/

#define FPGA_PROG   0x0001          /* PROG enable low */
#define FPGA_BUSY   0x0002          /* BUSY high, DONE low */
#define     FPGA_CS     0x000C            /* Enable I/O pins */
#define FPGA_CCLK   0x0100
#define FPGA_DOUT   0x0400
#define FPGA_DIN    FPGA_DOUT   /* bidirectional I/O */

int qBri_FPGA_download (PISDN_ADAPTER IoAdapter) {
      int            bit ;
      byte           *File ;
      dword          code, FileLength ;
      word volatile __iomem *addr = (word volatile __iomem *)DIVA_OS_MEM_ATTACH_PROM(IoAdapter);
      word           val, baseval = FPGA_CS | FPGA_PROG ;



      if (DIVA_4BRI_REVISION(IoAdapter))
      {
            char* name;

            switch (IoAdapter->cardType) {
                  case CARDTYPE_DIVASRV_B_2F_PCI:
                        name = "dsbri2f.bit";
                        break;

                  case CARDTYPE_DIVASRV_B_2M_V2_PCI:
                  case CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI:
                        name = "dsbri2m.bit";
                        break;

                  default:
                        name = "ds4bri2.bit";
            }

            File = qBri_check_FPGAsrc (IoAdapter, name,
                                          &FileLength, &code);
      }
      else
      {
            File = qBri_check_FPGAsrc (IoAdapter, "ds4bri.bit",
                                       &FileLength, &code) ;
      }
      if ( !File ) {
            DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
            return (0) ;
      }
/*
 *    prepare download, pulse PROGRAM pin down.
 */
      WRITE_WORD(addr, baseval & ~FPGA_PROG) ; /* PROGRAM low pulse */
      WRITE_WORD(addr, baseval) ;              /* release */
      diva_os_wait (50) ;  /* wait until FPGA finished internal memory clear */
/*
 *    check done pin, must be low
 */
      if ( READ_WORD(addr) & FPGA_BUSY )
      {
            DBG_FTL(("FPGA download: acknowledge for FPGA memory clear missing"))
            xdiFreeFile (File) ;
            DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);
            return (0) ;
      }
/*
 *    put data onto the FPGA
 */
      while ( code < FileLength )
      {
            val = ((word)File[code++]) << 3 ;

            for ( bit = 8 ; bit-- > 0 ; val <<= 1 ) /* put byte onto FPGA */
            {
                  baseval &= ~FPGA_DOUT ;             /* clr  data bit */
                  baseval |= (val & FPGA_DOUT) ;      /* copy data bit */
                  WRITE_WORD(addr, baseval) ;
                  WRITE_WORD(addr, baseval | FPGA_CCLK) ;     /* set CCLK hi */
                  WRITE_WORD(addr, baseval | FPGA_CCLK) ;     /* set CCLK hi */
                  WRITE_WORD(addr, baseval) ;                 /* set CCLK lo */
            }
      }
      xdiFreeFile (File) ;
      diva_os_wait (100) ;
      val = READ_WORD(addr) ;

      DIVA_OS_MEM_DETACH_PROM(IoAdapter, addr);

      if ( !(val & FPGA_BUSY) )
      {
            DBG_FTL(("FPGA download: chip remains in busy state (0x%04x)", val))
            return (0) ;
      }

      return (1) ;
}

static int load_qBri_hardware (PISDN_ADAPTER IoAdapter) {
      return (0);
}

/* --------------------------------------------------------------------------
            Card ISR
       -------------------------------------------------------------------------- */
static int qBri_ISR (struct _ISDN_ADAPTER* IoAdapter) {
      dword volatile     __iomem *qBriIrq ;

      PADAPTER_LIST_ENTRY QuadroList = IoAdapter->QuadroList ;

      word                    i ;
      int               serviced = 0 ;
      byte __iomem *p;

      p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);

      if ( !(READ_BYTE(&p[PLX9054_INTCSR]) & 0x80) ) {
            DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);
            return (0) ;
      }
      DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);

/*
 *    clear interrupt line (reset Local Interrupt Test Register)
 */
      p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
      qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
      WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
      DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);

      for ( i = 0 ; i < IoAdapter->tasks; ++i )
      {
            IoAdapter = QuadroList->QuadroAdapter[i] ;

            if ( IoAdapter && IoAdapter->Initialized
              && IoAdapter->tst_irq (&IoAdapter->a) )
            {
                  IoAdapter->IrqCount++ ;
                  serviced = 1 ;
                  diva_os_schedule_soft_isr (&IoAdapter->isr_soft_isr);
            }
      }

      return (serviced) ;
}

/* --------------------------------------------------------------------------
            Does disable the interrupt on the card
       -------------------------------------------------------------------------- */
static void disable_qBri_interrupt (PISDN_ADAPTER IoAdapter) {
      dword volatile __iomem *qBriIrq ;
      byte __iomem *p;

      if ( IoAdapter->ControllerNumber > 0 )
            return ;
/*
 *    clear interrupt line (reset Local Interrupt Test Register)
 */
      p = DIVA_OS_MEM_ATTACH_RESET(IoAdapter);
      WRITE_BYTE(&p[PLX9054_INTCSR], 0x00);     /* disable PCI interrupts */
      DIVA_OS_MEM_DETACH_RESET(IoAdapter, p);

      p = DIVA_OS_MEM_ATTACH_CTLREG(IoAdapter);
      qBriIrq = (dword volatile __iomem *)(&p[DIVA_4BRI_REVISION(IoAdapter) ? (MQ2_BREG_IRQ_TEST)  : (MQ_BREG_IRQ_TEST)]);
      WRITE_DWORD(qBriIrq, MQ_IRQ_REQ_OFF) ;
      DIVA_OS_MEM_DETACH_CTLREG(IoAdapter, p);
}

/* --------------------------------------------------------------------------
            Install Adapter Entry Points
       -------------------------------------------------------------------------- */
static void set_common_qBri_functions (PISDN_ADAPTER IoAdapter) {
      ADAPTER *a;

      a = &IoAdapter->a ;

      a->ram_in           = mem_in ;
      a->ram_inw          = mem_inw ;
      a->ram_in_buffer    = mem_in_buffer ;
      a->ram_look_ahead   = mem_look_ahead ;
      a->ram_out          = mem_out ;
      a->ram_outw         = mem_outw ;
      a->ram_out_buffer   = mem_out_buffer ;
      a->ram_inc          = mem_inc ;

      IoAdapter->out      = pr_out ;
      IoAdapter->dpc      = pr_dpc ;
      IoAdapter->tst_irq  = scom_test_int ;
      IoAdapter->clr_irq  = scom_clear_int ;
      IoAdapter->pcm      = (struct pc_maint *)MIPS_MAINT_OFFS ;

      IoAdapter->load     = load_qBri_hardware ;

      IoAdapter->disIrq   = disable_qBri_interrupt ;
      IoAdapter->rstFnc   = reset_qBri_hardware ;
      IoAdapter->stop     = stop_qBri_hardware ;
      IoAdapter->trapFnc  = qBri_cpu_trapped ;

      IoAdapter->diva_isr_handler = qBri_ISR;

      IoAdapter->a.io       = (void*)IoAdapter ;
}

static void set_qBri_functions (PISDN_ADAPTER IoAdapter) {
      if (!IoAdapter->tasks) {
            IoAdapter->tasks = MQ_INSTANCE_COUNT;
      }
      IoAdapter->MemorySize = MQ_MEMORY_SIZE ;
      set_common_qBri_functions (IoAdapter) ;
      diva_os_set_qBri_functions (IoAdapter) ;
}

static void set_qBri2_functions (PISDN_ADAPTER IoAdapter) {
      if (!IoAdapter->tasks) {
            IoAdapter->tasks = MQ_INSTANCE_COUNT;
      }
      IoAdapter->MemorySize = (IoAdapter->tasks == 1) ? BRI2_MEMORY_SIZE : MQ2_MEMORY_SIZE;
      set_common_qBri_functions (IoAdapter) ;
      diva_os_set_qBri2_functions (IoAdapter) ;
}

/******************************************************************************/

void prepare_qBri_functions (PISDN_ADAPTER IoAdapter) {

      set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
      set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
      set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
      set_qBri_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;

}

void prepare_qBri2_functions (PISDN_ADAPTER IoAdapter) {
      if (!IoAdapter->tasks) {
            IoAdapter->tasks = MQ_INSTANCE_COUNT;
      }

      set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[0]) ;
      if (IoAdapter->tasks > 1) {
            set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[1]) ;
            set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[2]) ;
            set_qBri2_functions (IoAdapter->QuadroList->QuadroAdapter[3]) ;
      }

}

/* -------------------------------------------------------------------------- */

Generated by  Doxygen 1.6.0   Back to index