/******************************************************************************/
/*                       Copyright 2001 Broadcom Corporation                  */
/*                                                                            */
/* This material is the confidential trade secret and proprietary information */
/* of Broadcom Corp.  It may not be reproduced, used, sold or transferred to  */
/* any third party without the prior written consent of Broadcom Corp.        */
/* All rights reserved.                                                       */
/******************************************************************************/
/*   FileName        : bcm_hostFunctions.c                                    */
/*   Purpose         : Some common code for all hostFunctions                 */
/*   Limitations     : None                                                   */
/*   Author          : Emmanuel Hanssens                                      */
/*   Creation Date   : 17-Sep-2001                                            */
/*   History         : Compiled by CVS                                        */
/******************************************************************************/
/*   $Id: bcm_hostFunctions.c,v 1.25 2004/10/20 10:11:42 hanssens Exp $  */
/******************************************************************************/

#include <string.h>
#include "bcm_hostFunctions.h"
#include "bcm_bigEndianByteSwap.h"
#ifndef NO_FULL_ERROR_HANDLING
# include "bcm_errorHandler.h"
#endif
#include "bcm_transfer.h"
#ifndef NO_STDOUT_PRINT
# include <stdio.h>
#endif

/* {{{ Global definitions */

/* BCM6410 addresses */
#define FP_PAGING_REG        0x4000
#define FP_ENABLE_REG        0x4008
#define FP_RQST_HOST_INT_REG 0x4018
#define FP_PROM_STATUS_REG   0x42B8
#define FP_CHIP_ID_REG       0x4250
#define FP_SELF_TEST_ADDR    16

#ifndef NO_FULL_ERROR_HANDLING
const char * hostErr[ ] =
{
  "no error",
  "%d is larger than maximum allowed page",                /* EHOSTMAXP */
  "interrupt polling time out",                            /* EHOSTINTO */
  "booter is not ready",                                   /* EHOSTBTRD */
};
#endif

HostDev  hostDevices[NB_BCM_DEV];

/* }}} */
/* {{{ hostDriverInit: reset host structures for all devices */

void hostDriverInit(void)
{
  uint16 i;
  for (i=0; i<NB_BCM_DEV; i++)
    memset(&hostDevices[i],0,sizeof(HostDev));
}

/* }}} */
/* {{{ hostOpen: open the host driver for specified device */

HostDev *hostOpen(uint16 bcm6410Id)
{
  hostDevices[bcm6410Id].devId = bcm6410Id;
  return &hostDevices[bcm6410Id];
}

/* }}} */
/* {{{ hostInit: initializes the host structure for specified device */

void hostInit(HostDev *dev)
{
  /* nothing to initialize */
  BCM_UNUSED_PARAMETER(dev);
}

/* }}} */
/* {{{ hostClose: closes the host driver for specified device */

void hostClose(HostDev *dev)
{
  /* reset the msg structure */
  memset(&hostDevices[dev->devId],0, sizeof(HostDev));
}

/* }}} */
/* {{{ hostResetBCM6410: reset the specified device */

void hostResetBCM6410(HostDev *dev)
{
  transferResetBCM6410(dev->devId);
}

/* }}} */
/* {{{ hostEnableBCM6410: enable core 0 on specified device */

void hostEnableBCM6410(HostDev *dev)
{
  uint8 data = 1;
  transferReq(DEV_ADDRESS(dev->devId), BCM_WRITE, FP_ENABLE_REG, &data, 1);
}

/* }}} */
/* {{{ hostReadInterruptStatus: read interrupt register */

uint8  hostReadInterruptStatus(HostDev *dev)
{
  uint8 data;
  transferReq(DEV_ADDRESS(dev->devId), BCM_READ, FP_RQST_HOST_INT_REG, &data, 1);

  return data;
}

/* }}} */
/* {{{ hostReadPage: get current SMEM page */

uint8 hostReadPage(HostDev *dev)
{
  uint8 page;

  transferReq(DEV_ADDRESS(dev->devId), BCM_READ, FP_PAGING_REG, &page, 1);
  return page;
}

/* }}} */
/* {{{ hostReadChipId: read chip id register */

uint32 hostReadChipId(HostDev *dev)
{
  uint32 data;
  transferReq(DEV_ADDRESS(dev->devId), BCM_READ, FP_CHIP_ID_REG,
              (uint8 *) &data, 4);

  bigEndianByteSwap((uint8 *) &data, uint32Layout);
  return data;
}

/* }}} */
/* {{{ hostSetPage: set SMEM page to specified value */

void hostSetPage(HostDev *dev, uint8 page)
{
#ifndef NO_FULL_ERROR_HANDLING
  if (page > BCM_MAX_PAGE)
    FATAL_ERROR( hostErr[EHOSTMAXP], page );
#endif

  transferReq(DEV_ADDRESS(dev->devId), BCM_WRITE, FP_PAGING_REG, &page, 1);
}

/* }}} */
/* {{{ hostPROMonBoard: tell whether a PROM is connected */

uint8 hostPROMonBoard(HostDev *dev)
{
  uint8 status;

  transferReq(DEV_ADDRESS(dev->devId), BCM_READ, FP_PROM_STATUS_REG, 
              &status, 1);
  return status & 1;            /* bit 0 */
}

/* }}} */
/* {{{ hostIsBCM6410enabled: tell whether both FPs are running */

int hostIsBCM6410enabled(HostDev *dev)
{
  uint8 data;

  transferReq(DEV_ADDRESS(dev->devId), BCM_READ, FP_ENABLE_REG, &data, 1);
  return data == 3;            /* bit 0 */
}

/* }}} */
/* {{{ hostWriteImage: load image into FMEM */

void hostWriteImage(HostDev *dev, 
                    uint8    firstPageIndex, 
                    uint8   *image, 
                    uint32   imageSize)
{
  uint32 transferSize;
  
#ifndef NO_STDOUT_PRINT
  printf("Loading boot image ");
#endif

  while (imageSize > 0)
  {
#ifndef NO_STDOUT_PRINT
    /* show progression: a dot for each page started */
    printf(".");
    fflush(stdout);
#endif

    transferSize = min(imageSize, BCM_PAGE_SIZE);

    /* set the paging register in order to copy the data at the correct place
       in FMEM */
    hostSetPage(dev, firstPageIndex);
    
    /* copy the data at address 0 in the current page */
    transferReq(DEV_ADDRESS(dev->devId), BCM_WRITE, 0, image, transferSize);

    imageSize -= transferSize;
    image     += transferSize;
    firstPageIndex ++; /* increment the page index for next write */
  }

#ifndef NO_STDOUT_PRINT
  printf(" done\n");
#endif
}

/* }}} */
/* {{{ hostGetSelfTest: get Power On Self Test outputs */

void     hostGetSelfTest(HostDev  *dev,
                         SelfTest *selfTest)
{

  transferReq(DEV_ADDRESS(dev->devId), BCM_READ, FP_SELF_TEST_ADDR,
              (uint8 *) selfTest, sizeof(SelfTest));

  bigEndianByteSwap((uint8 *) selfTest, selfTestLayout);
}

/* }}} */
/* {{{ hostDumpMemLong: dump long word (64b) from memory */

int      hostDumpMemLong(HostDev  *dev,
                         uint32    memAddr,
                         uint8    *data)
{
  uint8  pageIndex = memAddr / BCM_PAGE_SIZE;
  uint32 pageAddr  = memAddr % BCM_PAGE_SIZE;
  
  if (pageIndex > BCM_MAX_PAGE)
    return BCM_FAILURE;
  
  /* set the paging register */
  hostSetPage(dev, pageIndex);
    
  transferReq(DEV_ADDRESS(dev->devId), BCM_READ, pageAddr, data, 8);

  return BCM_SUCCESS;
}

/* }}} */
