summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/sparc/leon2/cchip/cchip.c
blob: 09d8a4cfd8a1bac23edb521a43e5fe371e6d1be3 (plain) (tree)
1
2
3
4
5
6
7
8
9

        
  
                 

                                                  

   
  

                        


                                                           
                                         
   



































                                                                 





                           



                                       




                              
 
                             
 
                                      



                                      











                               


                  

                          
 


                       
 


                                  
 



                            
 




                    




                          
 







                                                                          
 
                                                 
 




                                                           
 
            


                                                 

      



                                
                 
                                                               

      



                                                                         
 



                                  
 




                                                   
 

                                      
            


                                                                      
      















                                                                       


                                                    

                                                    




                    
 
           




                              
                            































                                                        
                 
                                                                               
      
           


                          
 


















































                                                                                





                                                                    

                                                





                                    
                                                     

                                                             
 
                                             




                            
 
                                              
 

                              
 

                                                                      


                                                         

                                        
            

                                                           
      
                                                              
 

                                                                    



                                                    
 
                  
                     
                                                          
      


                          


                                                










                                                                
 
                         
 
                                       
 
/** 
 * @file
 *
 * @ingroup cchip
 *
 * @brief GR-701 (Companion Chip) PCI board driver
 */

/*
 *  COPYRIGHT (c) 2007.
 *  Aeroflex Gaisler AB.
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#include <bsp.h>
#include <rtems/bspIo.h>
#include <rtems.h>
#include <string.h>

#include <rtems.h>
#include <leon.h>
#include <ambapp.h>
#include <pci.h>

#include <b1553brm_pci.h>
#include <occan_pci.h>
#include <grspw_pci.h>
#include <apbuart_pci.h>

#include <cchip.h>

/*
#define DEBUG
#define DEBUG_IRQS
*/
#define BOARD_INFO
/*#define PRINT_SPURIOUS*/

/* AT697 Register MAP */
static LEON_Register_Map *regs = (LEON_Register_Map *)0x80000000;

/* initializes interrupt management for companionship board */
void cchip1_irq_init(void);

/* register interrupt handler (called from drivers) */
void cchip1_set_isr(void *handler, int irqno, void *arg);

#define READ_REG(address) _READ_REG((unsigned int)address)
static __inline__ unsigned int _READ_REG(unsigned int addr) {
  unsigned int tmp;
  __asm__ ("lda [%1]1, %0 "
    : "=r"(tmp)
    : "r"(addr)
  );
  return tmp;
}

/* PCI bride reg layout on AMBA side */
typedef struct {
  unsigned int bar0;
  unsigned int bar1;
  unsigned int bar2;
  unsigned int bar3;
  unsigned int bar4;/* 0x10 */

  unsigned int unused[4*3-1];

  unsigned int ambabars[1]; /* 0x40 */
} amba_bridge_regs;

/* PCI bride reg layout on PCI side */
typedef struct {
  unsigned int bar0;
  unsigned int bar1;
  unsigned int bar2;
  unsigned int bar3;
  unsigned int bar4; /* 0x10 */

  unsigned int ilevel;
  unsigned int ipend;
  unsigned int iforce;
  unsigned int istatus;
  unsigned int iclear;
  unsigned int imask;
} pci_bridge_regs;

typedef struct {
  pci_bridge_regs  *pcib;
  amba_bridge_regs *ambab;

  /* AT697 PCI */
  unsigned int bars[5];
  int bus, dev, fun;

  /* AMBA bus */
  struct ambapp_bus amba_bus;
  struct ambapp_mmap amba_maps[2];

  /* FT AHB SRAM */
  int ftsram_size; /* kb */
  unsigned int ftsram_start;
  unsigned int ftsram_end;

} cchip1;

cchip1 cc1;

int init_pcif(void){
  unsigned int com1;
  int i,bus,dev,fun;
  pci_bridge_regs *pcib;
  amba_bridge_regs *ambab;
  struct ambapp_bus *abus;

  if ( BSP_pciFindDevice(0x1AC8, 0x0701, 0, &bus, &dev, &fun) == 0 ) {
    ;
  }else if (BSP_pciFindDevice(0x16E3, 0x0210, 0, &bus, &dev, &fun) == 0) {
    ;
  } else {
    /* didn't find any Companionship board on the PCI bus. */
    return -1;
  }

  /* found Companionship PCI board, Set it up: */

  pci_read_config_dword(bus, dev, fun, 0x10, &cc1.bars[0]);
  pci_read_config_dword(bus, dev, fun, 0x14, &cc1.bars[1]);
  pci_read_config_dword(bus, dev, fun, 0x18, &cc1.bars[2]);
  pci_read_config_dword(bus, dev, fun, 0x1c, &cc1.bars[3]);
  pci_read_config_dword(bus, dev, fun, 0x20, &cc1.bars[4]);

#ifdef DEBUG
  for(i=0; i<5; i++){
    printk("PCI: BAR%d: 0x%x\n\r",i,cc1.bars[i]);
  }
#endif

  /* Set up PCI ==> AMBA */
  pcib = (void *)cc1.bars[0];
  pcib->bar0 = 0xfc000000;
  /*  pcib->bar1 = 0xff000000;*/
#ifdef BOARD_INFO
  printk("Found CCHIP1 Board at 0x%lx\n\r",(unsigned int)pcib);
#endif

  /* AMBA MAP cc1.bars[1] (in CPU) ==> 0xf0000000(remote amba address) */
  cc1.amba_maps[0].size = 0x04000000;
  cc1.amba_maps[0].local_adr = cc1.bars[1];
  cc1.amba_maps[0].remote_adr = 0xfc000000;

  /* Mark end of table */
  cc1.amba_maps[1].size=0;
  cc1.amba_maps[1].local_adr = 0;
  cc1.amba_maps[1].remote_adr = 0;

  /* Enable I/O and Mem accesses */
  pci_read_config_dword(bus, dev, fun, 0x4, &com1);
  com1 |= 0x3;
  pci_write_config_dword(bus, dev, fun, 0x4, com1);
  pci_read_config_dword(bus, dev, fun, 0x4, &com1);

  /* Set up AMBA Masters ==> PCI */
  ambab = (void *)(cc1.bars[1]+0x400);
#ifdef DEBUG
  printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",0,ambab->bar0,pcib->bar0);
  printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",1,ambab->bar1,pcib->bar1);
  printk("AMBA: PCIBAR[%d]: 0x%x, 0x%x\n\r",2,ambab->bar2,pcib->bar2);
#endif
  /* 0xe0000000(AMBA) ==> 0x40000000(PCI) ==> 0x40000000(AT697 AMBA) */
  ambab->ambabars[0] = 0x40000000;

  /* Scan bus for AMBA devices */
  abus = &cc1.amba_bus;
  memset(abus,0,sizeof(*abus));
  ambapp_scan(abus, cc1.bars[1]+0x3f00000, NULL, &cc1.amba_maps[0]);

  /* Init all msters, max 16 */
  for(i=1; i<16; i++) {
    ambab->ambabars[i] = 0x40000000;
    if (READ_REG(&ambab->ambabars[i]) != 0x40000000)
      break;
  }

  /* Enable PCI Master */
   pci_read_config_dword(bus, dev, fun, 0x4, &com1);
   com1 |= 0x4;
   pci_write_config_dword(bus, dev, fun, 0x4, com1);
   pci_read_config_dword(bus, dev, fun, 0x4, &com1);

  cc1.pcib  = pcib;
  cc1.ambab = ambab;
  cc1.bus = bus;
  cc1.dev = dev;
  cc1.fun = fun;

  return 0;
}

#ifndef GAISLER_FTAHBRAM
 #define GAISLER_FTAHBRAM 0x50
#endif
int init_onboard_sram(void){
  struct ambapp_ahb_info ahb;
  struct ambapp_apb_info apb;
  unsigned int conf, size;

  /* Find SRAM controller
   * 1. AHB slave interface
   * 2. APB slave interface
   */
  if ( ambapp_find_apbslv(&cc1.amba_bus, VENDOR_GAISLER,
      GAISLER_FTAHBRAM, &apb) != 1 ){
    printk("On Board FT SRAM not found (APB)\n");
    return -1;
  }

  if ( ambapp_find_ahbslv(&cc1.amba_bus, VENDOR_GAISLER,
      GAISLER_FTAHBRAM, &ahb) != 1 ){
    printk("On Board FT SRAM not found (AHB)\n");
    return -1;
  }

  /* We have found the controller.
   * Get it going.
   *
   * Get size of SRAM
   */
  conf = *(unsigned int *)apb.start;
  size = (conf >>10) & 0x7;

  /* 2^x kb */
  cc1.ftsram_size = 1<<size;
  cc1.ftsram_start = ahb.start[0];
  cc1.ftsram_end = size*1024 + cc1.ftsram_start;
#ifdef BOARD_INFO
  printk("Found FT AHB SRAM %dkb at 0x%lx\n",cc1.ftsram_size,cc1.ftsram_start);
#endif
  return 0;
}

int cchip1_register(void){

  /* Init AT697 PCI Controller */
  init_pci();

  /* Find & init CChip board .
   * Also scan AMBA Plug&Play info for us.
   */
  if ( init_pcif() ){
    printk("Failed to initialize CCHIP board\n\r");
    return -1;
  }

  /* Set interrupt common board stuff */
  cchip1_irq_init();

  /* Find on board SRAM */
  if ( init_onboard_sram() ){
    printk("Failed to register On Board SRAM. It is needed by b1553BRM\n");
    return -1;
  }

  /* Register interrupt install functions */
  b1553brm_pci_int_reg = cchip1_set_isr;
  occan_pci_int_reg = cchip1_set_isr;
  grspw_pci_int_reg = cchip1_set_isr;
  apbuart_pci_int_reg = cchip1_set_isr;

  /* register the BRM PCI driver, use 16k FTSRAM... */
  if ( b1553brm_pci_register(&cc1.amba_bus,0,0,3,cc1.ftsram_start,0xffa00000) ){
    printk("Failed to register BRM PCI driver\n");
    return -1;
  }

  /* register the BRM PCI driver, no DMA memory... */
  if ( occan_pci_register(&cc1.amba_bus) ){
    printk("Failed to register OC_CAN PCI driver\n");
    return -1;
  }

  /* register the GRSPW PCI driver, use malloc... */
  if ( grspw_pci_register(&cc1.amba_bus,0,0xe0000000) ){
    printk("Failed to register GRSPW PCI driver\n");
    return -1;
  }

  /* register the APBUART PCI driver, no DMA memory */
  if ( apbuart_pci_register(&cc1.amba_bus) ){
    printk("Failed to register APBUART PCI driver\n");
    return -1;
  }

  return 0;
}

static rtems_isr cchip1_interrupt_dispatcher(rtems_vector_number v);
static unsigned int cchip1_spurious_cnt;

typedef struct {
  unsigned int (*handler)(int irqno, void *arg);
  void *arg;
} int_handler;

static int_handler int_handlers[16];

void cchip1_irq_init(void){

  /* Configure AT697 ioport bit 7 to input pci irq */
  regs->PIO_Direction &= ~(1<<7);
  regs->PIO_Interrupt  = 0x87;          /* level sensitive */

  /* Set up irq controller (mask all IRQs) */
  cc1.pcib->imask = 0x0000;
  cc1.pcib->ipend = 0;
  cc1.pcib->iclear = 0xffff;
  cc1.pcib->iforce = 0;
  cc1.pcib->ilevel = 0x0;

  memset(int_handlers,0,sizeof(int_handlers));

  /* Reset spurious counter */
  cchip1_spurious_cnt = 0;

  /* Register interrupt handler */
  set_vector(cchip1_interrupt_dispatcher,LEON_TRAP_TYPE(CCHIP_IRQ),1);
}

void cchip1_set_isr(void *handler, int irqno, void *arg){
  int_handlers[irqno].handler = handler;
  int_handlers[irqno].arg = arg;
#ifdef DEBUG
  printk("Registering IRQ %d to 0x%lx(%d,0x%lx)\n\r",
      irqno,(unsigned int)handler,irqno,(unsigned int)arg);
#endif
  cc1.pcib->imask |= 1<<irqno; /* Enable the registered IRQ */
}

static rtems_isr cchip1_interrupt_dispatcher(rtems_vector_number v){
  unsigned int pending = READ_REG(&cc1.pcib->ipend);
  unsigned int (*handler)(int irqno, void *arg);
  unsigned int clr = pending;
  int irq=1;

  if ( !pending ){
#ifdef PRINT_SPURIOUS
    printk("Spurious IRQ %d: %d\n",v,cchip1_spurious_cnt);
#endif
    cchip1_spurious_cnt++;
    return;
  }
#ifdef DEBUG_IRQS
  printk("CCIRQ: 0x%x\n",(unsigned int)pending);
#endif
  /* IRQ 0 doesn't exist */
  irq=1;
  pending = pending>>1;

  while ( pending ){
    if ( (pending & 1) && (handler=int_handlers[irq].handler) ){
      handler(irq,int_handlers[irq].arg);
    }
    irq++;
    pending = pending>>1;
  }

  cc1.pcib->iclear = clr;

  /*LEON_Clear_interrupt( brd->irq );*/
}