summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/ep1a/console/rsPMCQ1.c
blob: c8f9b1c48d1456a2bff5e14c2a050ff75ba5d3db (plain) (tree)




























                                                                           
                                                                  












                                

                          




































                                                
                  
 
               


                                  

                                                    


                                    

                                                


                                    

                                                 


                      


                                                     

 





























                                                                                                                      
 











                                                                                
                         
                                 

                       
                                  

                                



                                                                   

                                                                                        




                                                                    



                                                                               




                                                                          
 


                                                                    
                                                                     
                                           
                                                                     




                                                                               


     

                                  
                                

                                                                    

                                                                                
                   
 
                                  
















                                                                                

                                                                           


                            

                                          







                                                                           








                                                                     































                                                                                
                                                                                             


















                                                                                




                                                                            











































                                                                                
                                                                                                

















                                                                                
                              


             

                          



                           
                
                                  
                                         


                         
                                                 
                            

    






                                                                                                
                                                                                          


                                                            
                                                                      
            
                                                                             


                           
                                                                  







                                  
                                                                   







                                                                           
                                                                         


                                                         
                                                                               


                                                               
                                                                


                                            
                                                                               


































                                                                                    
                                                                    




                                                
                                                                        
     
                                                                                   











                                       
 






                                                              
                                                             
      













                                                                                          






                                                        
                                                                 
            

                                                                  






















                                                                                
                              

                    

                  













                                                                             
                                                   
            
                                                                                               










































                                                                    

                          
 


                                           
                
                                                 





                                                                   




                                           
                
                                                  


      
/* rsPMCQ1.c - Radstone PMCQ1 Common Initialisation Code
 *
 * Copyright 2000 Radstone Technology 
 *
 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
 *
 * You are hereby granted permission to use, copy, modify, and distribute
 * this file, provided that this notice, plus the above copyright notice
 * and disclaimer, appears in all copies. Radstone Technology will provide
 * no support for this code.
 *
 *  COPYRIGHT (c) 2005.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 */

/*
DESCRIPTION
These functions are responsible for scanning for PMCQ1's and setting up
the Motorola MC68360's if present.

USAGE
call rsPMCQ1Init() to perform basic initialisation of the PMCQ1's.
*/

/* includes */
#include <libcpu/io.h>
#include <bsp/irq.h>
#include <stdlib.h>
#include <rtems/bspIo.h>        
#include <bsp/pci.h>
#include <bsp.h>
#include "rsPMCQ1.h"
#include "m68360.h"

/* defines */
#if 0 
#define DEBUG_360     TRUE
#endif

/* Local data */
PPMCQ1BoardData		pmcq1BoardData = NULL;

static unsigned char rsPMCQ1Initialized = FALSE;

/* forward declarations */

/* local Qspan II serial eeprom table */
static unsigned char rsPMCQ1eeprom[] =
    {
    0x00,	/* Byte 0 - PCI_SID */
    0x00,	/* Byte 1 - PCI_SID */
    0x00,	/* Byte 2 - PCI_SID */
    0x00,	/* Byte 3 - PCI_SID */
    0x00,	/* Byte 4 - PBROM_CTL */
    0x00,	/* Byte 5 - PBROM_CTL */
    0x00,	/* Byte 6 - PBROM_CTL */
    0x2C,	/* Byte 7 - PBTI0_CTL */
    0xB0,	/* Byte 8 - PBTI1_CTL */
    0x00,	/* Byte 9 - QBSI0_AT */
    0x00,	/* Byte 10 - QBSI0_AT */
    0x02,	/* Byte 11 - QBSI0_AT */
    0x00,	/* Byte 12 - PCI_ID */
    0x07,	/* Byte 13 - PCI_ID */
    0x11,	/* Byte 14 - PCI_ID */
    0xB5,	/* Byte 15 - PCI_ID */
    0x06,	/* Byte 16 - PCI_CLASS */
    0x80,	/* Byte 17 - PCI_CLASS */
    0x00,	/* Byte 18 - PCI_CLASS */
    0x00,	/* Byte 19 - PCI_MISC1 */
    0x00,	/* Byte 20 - PCI_MISC1 */
    0xC0,	/* Byte 21 - PCI_PMC */
    0x00	/* Byte 22 - PCI_BST */
};

void MsDelay(void)
{
  printk("..");
}

void write8( int addr, int data ){
  out_8((volatile void *)addr, (unsigned char)data);
  Processor_Synchronize();
}

void write16( int addr, int data ) {
  out_be16((volatile void *)addr, (short)data );
  Processor_Synchronize();
}

void write32( int addr, int data ) {
  out_be32((volatile unsigned int *)addr, data );
  Processor_Synchronize();
}

int read32( int addr){
  int value = in_be32((volatile unsigned int *)addr);
  Processor_Synchronize();
  return value;
}

void rsPMCQ1_scc_On(const struct __rtems_irq_connect_data__ *ptr) 
{

}

void rsPMCQ1_scc_Off(const struct __rtems_irq_connect_data__ *ptr) 
{

}

int rsPMCQ1_scc_except_always_enabled(const struct __rtems_irq_connect_data__ *ptr)
{
  return TRUE;
}


void rsPMCQ1ShowIntrStatus(void )
{
  unsigned long   status;
  unsigned long   mask;
  PPMCQ1BoardData boardData;

  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext)
  {

    status = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_STATUS );
    mask   = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_MASK );
    printk("rsPMCQ1ShowIntrStatus: interrupt status 0x%x) 0x%x with mask: 0x%x\n", boardData->quiccInt, status, mask);
  }
}

  
/*******************************************************************************
* rsPMCQ1Int - handle a PMCQ1 interrupt
*
* This routine gets called when the QUICC or MA causes
* an interrupt.
*
* RETURNS: NONE.
*/

void rsPMCQ1Int( void *ptr )
{
  unsigned long   status;
  static unsigned long   status1;
  unsigned long   mask;
  uint32_t        data;
  PPMCQ1BoardData boardData = ptr;
  volatile unsigned long *hrdwr;
  unsigned long           value;

  status = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_STATUS );
  mask   = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_MASK );


  if (((mask & PMCQ1_INT_MASK_QUICC) == 0) && ((status & PMCQ1_INT_STATUS_QUICC) != 0 ))
  {
    /* If there is a handler call it otherwise mask the interrupt */
    if (boardData->quiccInt) {
      boardData->quiccInt(boardData->quiccArg);
    } else {
      printk("No handler - Masking interrupt\n");
      hrdwr = (volatile unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK);
      value = (*hrdwr) | PMCQ1_INT_MASK_QUICC;
      *hrdwr = value;
    }
  }

  if (((mask & PMCQ1_INT_MASK_MA) == 0) && (status & PMCQ1_INT_STATUS_MA))
  {

    /* If there is a handler call it otherwise mask the interrupt */
    if (boardData->maInt) {
      boardData->maInt(boardData->maArg);
      data = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_STATUS );
      data = data & (~PMCQ1_INT_STATUS_MA);
      PMCQ1_Write_EPLD(boardData->baseaddr, PMCQ1_INT_STATUS, data );
    } else { 
      printk("No handler - Masking interrupt\n");
      hrdwr = (volatile unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK);
      value = (*hrdwr) | PMCQ1_INT_MASK_MA;
      *hrdwr = value;
    }
  }

  RTEMS_COMPILER_MEMORY_BARRIER();

  /* Clear Interrupt on QSPAN */
  hrdwr = (volatile unsigned long *)(boardData->bridgeaddr + 0x600);
  *hrdwr = 0x00001000;

  /* read back the status register to ensure that the pci write has completed */
  status1 = *hrdwr;

  RTEMS_COMPILER_MEMORY_BARRIER();
}


/*******************************************************************************
*
* rsPMCQ1MaIntConnect - connect a MiniAce interrupt routine
*
* This routine is called to connect a MiniAce interrupt handler
* upto a PMCQ1.
*
* RETURNS: OK if PMCQ1 found, ERROR if not.
*/

unsigned int rsPMCQ1MaIntConnect (
    unsigned long	busNo,	/* Pci Bus number of PMCQ1 */
    unsigned long	slotNo,	/* Pci Slot number of PMCQ1 */
    unsigned long	funcNo,	/* Pci Function number of PMCQ1 */
    PMCQ1_FUNCTION_PTR	routine,/* interrupt routine */
    void * 	        arg	/* argument to pass to interrupt routine */
)
{
  PPMCQ1BoardData boardData;
  uint32_t        data;
  unsigned int    status = RTEMS_IO_ERROR;

  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext)
  {
    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
        (boardData->funcNo == funcNo))
    {
      boardData->maInt = routine;
      boardData->maArg = arg;

      data  = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_MASK );
      data &= (~PMCQ1_INT_MASK_MA);
      PMCQ1_Write_EPLD(boardData->baseaddr, PMCQ1_INT_MASK, data );

      data = PMCQ1_Read_EPLD(boardData->baseaddr, PMCQ1_INT_STATUS );
      data &= (~PMCQ1_INT_STATUS_MA);
      PMCQ1_Write_EPLD(boardData->baseaddr, PMCQ1_INT_STATUS, data );

      status = RTEMS_SUCCESSFUL;
      break;
    }
  }

  return (status);
}
    
/*******************************************************************************
*
* rsPMCQ1MaIntDisconnect - disconnect a MiniAce interrupt routine
*
* This routine is called to disconnect a MiniAce interrupt handler
* from a PMCQ1. It also masks the interrupt source on the PMCQ1.
*
* RETURNS: OK if PMCQ1 found, ERROR if not.
*/

unsigned int rsPMCQ1MaIntDisconnect(
    unsigned long	busNo,	/* Pci Bus number of PMCQ1 */
    unsigned long	slotNo,	/* Pci Slot number of PMCQ1 */
    unsigned long	funcNo	/* Pci Function number of PMCQ1 */
)
{
  PPMCQ1BoardData boardData;
  unsigned int status = RTEMS_IO_ERROR;

  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext) {
    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
        (boardData->funcNo == funcNo))
    {
      boardData->maInt = NULL;
      *(volatile unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK) |= PMCQ1_INT_MASK_MA;
      status = RTEMS_SUCCESSFUL;
      break;
    }
  }

  return (status);
}
    
/*******************************************************************************
*
* rsPMCQ1QuiccIntConnect - connect a Quicc interrupt routine
*
* This routine is called to connect a Quicc interrupt handler
* upto a PMCQ1.
*
* RETURNS: OK if PMCQ1 found, ERROR if not.
*/

unsigned int rsPMCQ1QuiccIntConnect(
  unsigned long         busNo,	 /* Pci Bus number of PMCQ1 */ 
  unsigned long         slotNo,  /* Pci Slot number of PMCQ1 */
  unsigned long         funcNo,  /* Pci Function number of PMCQ1 */
  PMCQ1_FUNCTION_PTR    routine, /* interrupt routine */
  void *                arg      /* argument to pass to interrupt routine */
)
{
  PPMCQ1BoardData boardData;
  unsigned int status = RTEMS_IO_ERROR;

  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext)
  {
    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
        (boardData->funcNo == funcNo)) 
    {
      boardData->quiccInt = routine;
      boardData->quiccArg = arg;
      status = RTEMS_SUCCESSFUL;
      break;
    }
  }
  return (status);
}
    
/*******************************************************************************
*
* rsPMCQ1QuiccIntDisconnect - disconnect a Quicc interrupt routine
*
* This routine is called to disconnect a Quicc interrupt handler
* from a PMCQ1. It also masks the interrupt source on the PMCQ1.
*
* RETURNS: OK if PMCQ1 found, ERROR if not.
*/

unsigned int rsPMCQ1QuiccIntDisconnect(
    unsigned long	busNo,	/* Pci Bus number of PMCQ1 */
    unsigned long	slotNo,	/* Pci Slot number of PMCQ1 */
    unsigned long	funcNo	/* Pci Function number of PMCQ1 */
)
{
  PPMCQ1BoardData boardData;
  unsigned int status = RTEMS_IO_ERROR;

  for (boardData = pmcq1BoardData; boardData; boardData = boardData->pNext) 
  {
    if ((boardData->busNo == busNo) && (boardData->slotNo == slotNo) && 
        (boardData->funcNo == funcNo))
    {
      boardData->quiccInt = NULL;
      *(volatile unsigned long *)(boardData->baseaddr + PMCQ1_INT_MASK) |= PMCQ1_INT_MASK_QUICC;
      status = RTEMS_SUCCESSFUL;
      break;
    }
  }

  return (status);
}
 
   
/*******************************************************************************
*
* rsPMCQ1Init - initialize the PMCQ1's
*
* This routine is called to initialize the PCI card to a quiescent state.
*
* RETURNS: OK if PMCQ1 found, ERROR if not.
*/

unsigned int rsPMCQ1Init(void)
{
  int busNo;
  int slotNo;
  uint32_t baseaddr = 0;
  uint32_t bridgeaddr = 0;
  unsigned long pbti0_ctl;
  int i;
  unsigned char int_vector;
  int fun;
  uint32_t temp;
  PPMCQ1BoardData       boardData;
  rtems_irq_connect_data *IrqData = NULL;

  if (rsPMCQ1Initialized)
  {
    printk("rsPMCQ1Init: Already Initialized\n");
    return RTEMS_SUCCESSFUL;
  } 

  for (i=0;;i++){
    if ( pci_find_device(PCI_VEN_ID_RADSTONE, PCI_DEV_ID_PMCQ1, i, &busNo, &slotNo, &fun) != 0 )
      break;

    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_2, &baseaddr);
    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_0, &bridgeaddr);
#ifdef DEBUG_360
  printk("rsPMCQ1Init: PMCQ1 baseaddr 0x%08x bridgeaddr 0x%08x\n", baseaddr, bridgeaddr );
#endif

    /* Set function code to normal mode and enable window */
    pbti0_ctl = (*(unsigned long *)(bridgeaddr + 0x100)) & 0xff0fffff;
    eieio();
    *(volatile unsigned long *)(bridgeaddr + 0x100) = pbti0_ctl | 0x00500080;
    eieio();

    /* Assert QBUS reset */
    *(volatile unsigned long *)(bridgeaddr + 0x800) |= 0x00000080;
    eieio();

    /*
     * Hold QBus in reset for 1ms 
     */
    MsDelay();

    /* Take QBUS out of reset */
    *(volatile unsigned long *)(bridgeaddr + 0x800) &= ~0x00000080;
    eieio();

    MsDelay();

    /* If a QUICC is fitted initialise it */
    if (PMCQ1_Read_EPLD(baseaddr, PMCQ1_BUILD_OPTION) & PMCQ1_QUICC_FITTED)
    {
#ifdef DEBUG_360 
  printk("rsPMCQ1Init: Found QUICC busNo %d slotNo %d\n", busNo, slotNo);
#endif

      /* Initialise MBAR (must use function code of 7) */
      *(volatile unsigned long *)(bridgeaddr + 0x100) = pbti0_ctl | 0x00700080;
      eieio();

      /* place internal 8K SRAM and registers at address 0x0 */
      *(volatile unsigned long *)(baseaddr + Q1_360_MBAR) = 0x1;
      eieio();

      /* Set function code to normal mode */
      *(volatile unsigned long *)(bridgeaddr + 0x100) = pbti0_ctl | 0x00500080;
      eieio();

      /* Disable the SWT and perform basic initialisation */
      write8(baseaddr+Q1_360_SIM_SYPCR,0);		
      eieio();

      write32(baseaddr+Q1_360_SIM_MCR,0xa0001029);
      write16(baseaddr+Q1_360_SIM_PICR,0);
      write16(baseaddr+Q1_360_SIM_PITR,0);

      write16(baseaddr+Q1_360_CPM_ICCR,0x770);
      write16(baseaddr+Q1_360_CPM_SDCR,0x770);
      write32(baseaddr+Q1_360_CPM_CICR,0x00e49f00);
      write16(baseaddr+Q1_360_SIM_PEPAR,0x2080);
      eieio();

      /* Enable SRAM */
      write32(baseaddr+Q1_360_SIM_GMR,0x00001000);  /* external master wait state */
      eieio();
      write32(baseaddr+Q1_360_SIM_OR0,0x1ff00000);  /*| MEMC_OR_FC*/
      eieio();
      write32(baseaddr+Q1_360_SIM_BR0,0);  
      eieio();
      write32(baseaddr+Q1_360_SIM_OR1,(0x5ff00000 | 0x00000780));  /*| MEMC_OR_FC*/
      eieio();
      write32(baseaddr+Q1_360_SIM_BR1,(0x00000040 | 0x00000001 | 0x00200280) );  
      eieio();
    }

    /*
     * If a second PCI window is present then make it opposite
     * endian to simplify 1553 integration.
     */
    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_3, &temp);
    if (temp) {
      *(volatile unsigned long *)(bridgeaddr + 0x110) |= 0x00500880;
    }

    /*
     * Create descriptor structure for this card
     */
    if ((boardData = calloc(1, sizeof(struct _PMCQ1BoardData))) == NULL)
    {
      printk("rsPMCQ1Init: Error Unable to allocate memory for _PMCQ1BoardData\n");
      return(RTEMS_IO_ERROR);
    }

    boardData->pNext = pmcq1BoardData;
    boardData->busNo = busNo;
    boardData->slotNo = slotNo;
    boardData->funcNo = 0;
    boardData->baseaddr = baseaddr;
    boardData->bridgeaddr = bridgeaddr;
    boardData->quiccInt = NULL;
    boardData->maInt = NULL;
    pmcq1BoardData = boardData;

    mc68360_scc_create_chip( boardData, int_vector );

    /*
     * Connect PMCQ1 interrupt handler.
     */
    pci_read_config_byte(busNo, slotNo, 0, 0x3c, &int_vector);
#ifdef DEBUG_360
    printk("rsPMCQ1Init: PMCQ1 int_vector %d\n", int_vector);
#endif

    if ((IrqData = calloc( 1, sizeof(rtems_irq_connect_data) )) == NULL )
    {
      printk("rsPMCQ1Init: Error Unable to allocate memory for rtems_irq_connect_data\n");
      return(RTEMS_IO_ERROR);
    }
    IrqData->name   = ((unsigned int)BSP_PCI_IRQ0 + int_vector);
    IrqData->hdl    = rsPMCQ1Int;
    IrqData->handle = boardData;
    IrqData->on     = rsPMCQ1_scc_On;
    IrqData->off    = rsPMCQ1_scc_Off;
    IrqData->isOn   = rsPMCQ1_scc_except_always_enabled;

    if (!BSP_install_rtems_shared_irq_handler (IrqData)) {
        printk("Error installing interrupt handler!\n");
        rtems_fatal_error_occurred(1);
    }

    /*
     * Enable PMCQ1 Interrupts from QSPAN-II
     */
    *(volatile unsigned long *)(bridgeaddr + 0x600) = 0x00001000;
    eieio();
    Processor_Synchronize();
    *(volatile unsigned long *)(bridgeaddr + 0x604) |= 0x00001000;
    eieio();
  }

  if (i > 0)
  {
    rsPMCQ1Initialized = TRUE;
  }
  return((i > 0) ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR);
}

/*******************************************************************************
*
* rsPMCQ1Commission - initialize the serial EEPROM on the QSPAN
*
* This routine is called to initialize the EEPROM attached to the QSPAN
* on the PMCQ1 module. It will load standard settings into any QSPAN's
* found with apparently uninitialised EEPROM's or PMCQ1's (to allow
* EEPROM modifications to be performed).
*/

unsigned int rsPMCQ1Commission( unsigned long busNo, unsigned long slotNo )
{
  unsigned int status = RTEMS_IO_ERROR;
  uint32_t     bridgeaddr = 0;
  unsigned long val;
  int i;
  uint32_t venId1;
  uint32_t venId2;

  pci_read_config_dword(busNo, slotNo, 0, PCI_VENDOR_ID, &venId1);
  pci_read_config_dword(busNo, slotNo, 0, PCI_VENDOR_ID, &venId2);
  if ((venId1 == 0x086210e3) ||
      (venId2 == PCI_ID(PCI_VEN_ID_RADSTONE, PCI_DEV_ID_PMCQ1)))
  {
    pci_read_config_dword(busNo, slotNo, 0, PCI_BASE_ADDRESS_0, &bridgeaddr);
    status = RTEMS_SUCCESSFUL;

    /*
     * The On board PMCQ1 on an EP1A has a subVendor ID of 0.
     * A real PMCQ1 also has the sub vendor ID set up.
     */
    if ((busNo == 0) && (slotNo == 1)) {
      *(volatile unsigned long *)rsPMCQ1eeprom = 0;
    } else {
      *(volatile unsigned long *)rsPMCQ1eeprom = PCI_ID(PCI_VEN_ID_RADSTONE, PCI_DEV_ID_PMCQ1);
    }

    for (i = 0; i < 23; i++) {
      /* Wait until interface not active */
      while(read32(bridgeaddr + 0x804) & 0x80000000) {
        rtems_bsp_delay(1);
      }

      /* Write value */
      write32(bridgeaddr + 0x804, (rsPMCQ1eeprom[i] << 8) | i);

      /* delay for > 31 usec to allow active bit to become set */
      rtems_bsp_delay(100);

      /* Wait until interface not active */
      while(read32(bridgeaddr + 0x804) & 0x80000000) {
        rtems_bsp_delay(1);
      }

      /* Re-read value */
      write32(bridgeaddr + 0x804, 0x40000000 | i);

      /* delay for > 31 usec to allow active bit to become set */
      rtems_bsp_delay(100);

      /* Wait until interface not active */
      while((val = read32(bridgeaddr + 0x804)) & 0x80000000) {
        rtems_bsp_delay(1);
      }

      if (((val >> 8) & 0xff) != rsPMCQ1eeprom[i]) {
        printk("Error writing byte %d expected 0x%02x got 0x%02x\n",
               i, rsPMCQ1eeprom[i], (unsigned char)(val >> 8));
        status = RTEMS_IO_ERROR;
        break;	
      }
    }
  }
  return(status);
}

uint32_t PMCQ1_Read_EPLD( uint32_t base, uint32_t reg )
{
  uint32_t           data;
  volatile uint32_t *ptr;

  Processor_Synchronize();
  ptr =  (volatile uint32_t *)(base + reg);
  data =  *ptr ;
#ifdef DEBUG_360
  printk("EPLD Read 0x%x: 0x%08x\n", ptr, data );
#endif
  return data;
}

void PMCQ1_Write_EPLD( uint32_t base, uint32_t reg, uint32_t data )
{
  volatile uint32_t *ptr;

  ptr = (volatile uint32_t *) (base + reg);
  *ptr = data;
  Processor_Synchronize();
#ifdef DEBUG_360
  printk("EPLD Write 0x%x: 0x%08x\n", ptr, data );
#endif
}