upstream u-boot with additional patches for our devices/boards:
https://lists.denx.de/pipermail/u-boot/2017-March/282789.html (AXP crashes) ;
Gbit ethernet patch for some LIME2 revisions ;
with SPI flash support
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
890 lines
26 KiB
890 lines
26 KiB
/*********************************************************
|
|
* $Id
|
|
*
|
|
* copyright @ Motorola, 1999
|
|
*********************************************************/
|
|
#include "i2o.h"
|
|
|
|
extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg );
|
|
#pragma Alias( load_runtime_reg, "load_runtime_reg" );
|
|
|
|
extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val );
|
|
#pragma Alias( store_runtime_reg, "store_runtime_reg" );
|
|
|
|
typedef struct _fifo_stat
|
|
{
|
|
QUEUE_SIZE qsz;
|
|
unsigned int qba;
|
|
} FIFOSTAT;
|
|
|
|
FIFOSTAT fifo_stat = { QSIZE_4K, 0xffffffff };
|
|
|
|
/**********************************************************************************
|
|
* function: I2OMsgEnable
|
|
*
|
|
* description: Enable the interrupt associated with in/out bound msg
|
|
* return I2OSUCCESS if no error, otherwise return I2OMSGINVALID.
|
|
*
|
|
* All previously enabled interrupts are preserved.
|
|
* note:
|
|
* Inbound message interrupt generated by PCI master and serviced by local processor
|
|
* Outbound message interrupt generated by local processor and serviced by PCI master
|
|
*
|
|
* local processor needs to enable its inbound interrupts it wants to handle(LOCAL)
|
|
* PCI master needs to enable the outbound interrupts of devices it wants to handle(REMOTE)
|
|
************************************************************************************/
|
|
I2OSTATUS I2OMsgEnable ( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base, /* pcsrbar/eumbbar */
|
|
unsigned char n ) /* b'1' - msg 0
|
|
* b'10'- msg 1
|
|
* b'11'- both
|
|
*/
|
|
{
|
|
unsigned int reg, val;
|
|
if ( ( n & 0x3 ) == 0 )
|
|
{
|
|
/* neither msg 0, nor msg 1 */
|
|
return I2OMSGINVALID;
|
|
}
|
|
|
|
n = (~n) & 0x3;
|
|
/* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base
|
|
* LOCAL : enable local inbound message, eumbbar as base
|
|
*/
|
|
reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR );
|
|
val = load_runtime_reg( base, reg );
|
|
|
|
val &= 0xfffffffc; /* masked out the msg interrupt bits */
|
|
val |= n; /* LSB are the one we want */
|
|
store_runtime_reg( base, reg, val );
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/*********************************************************************************
|
|
* function: I2OMsgDisable
|
|
*
|
|
* description: Disable the interrupt associated with in/out bound msg
|
|
* Other previously enabled interrupts are preserved.
|
|
* return I2OSUCCESS if no error otherwise return I2OMSGINVALID
|
|
*
|
|
* note:
|
|
* local processor needs to disable its inbound interrupts it is not interested(LOCAL)
|
|
* PCI master needs to disable outbound interrupts of devices it is not interested(REMOTE)
|
|
*********************************************************************************/
|
|
I2OSTATUS I2OMsgDisable( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base, /* pcsrbar/eumbbar */
|
|
unsigned char n ) /* b'1' - msg 0
|
|
* b'10'- msg 1
|
|
* b'11'- both
|
|
*/
|
|
{
|
|
unsigned int reg, val;
|
|
|
|
if ( ( n & 0x3 ) == 0 )
|
|
{
|
|
/* neither msg 0, nor msg 1 */
|
|
return I2OMSGINVALID;
|
|
}
|
|
|
|
/* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base
|
|
* LOCAL : disable local inbound message interrupt, eumbbar as base
|
|
*/
|
|
reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR );
|
|
val = load_runtime_reg( base, reg );
|
|
|
|
val &= 0xfffffffc; /* masked out the msg interrupt bits */
|
|
val |= ( n & 0x3 );
|
|
store_runtime_reg( base, reg, val );
|
|
|
|
return I2OSUCCESS;
|
|
|
|
}
|
|
|
|
/**************************************************************************
|
|
* function: I2OMsgGet
|
|
*
|
|
* description: Local processor reads the nth Msg register from its inbound msg,
|
|
* or a PCI Master reads nth outbound msg from device
|
|
*
|
|
* return I2OSUCCESS if no error, otherwise return I2OMSGINVALID.
|
|
*
|
|
* note:
|
|
* If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed.
|
|
* If it is remote, outbound msg on the device is read; otherwise local inbound msg is read
|
|
*************************************************************************/
|
|
I2OSTATUS I2OMsgGet ( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base, /*pcsrbar/eumbbar */
|
|
unsigned int n, /* 0 or 1 */
|
|
unsigned int *msg )
|
|
{
|
|
if ( n >= I2O_NUM_MSG || msg == 0 )
|
|
{
|
|
return I2OMSGINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* read the outbound msg of the device, pcsrbar as base */
|
|
*msg = load_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET );
|
|
}
|
|
else
|
|
{
|
|
/* read the inbound msg sent by PCI master, eumbbar as base */
|
|
*msg = load_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET );
|
|
}
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/***************************************************************
|
|
* function: I2OMsgPost
|
|
*
|
|
* description: Kahlua writes to its nth outbound msg register
|
|
* PCI master writes to nth inbound msg register of device
|
|
*
|
|
* return I2OSUCCESS if no error, otherwise return I2OMSGINVALID.
|
|
*
|
|
* note:
|
|
* If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed.
|
|
*
|
|
* If it is remote, inbound msg on the device is written; otherwise local outbound msg is written
|
|
***************************************************************/
|
|
I2OSTATUS I2OMsgPost( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base, /*pcsrbar/eumbbar */
|
|
unsigned int n, /* 0 or 1 */
|
|
unsigned int msg )
|
|
{
|
|
if ( n >= I2O_NUM_MSG )
|
|
{
|
|
return I2OMSGINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* write to the inbound msg register of the device, pcsrbar as base */
|
|
store_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET, msg );
|
|
}
|
|
else
|
|
{
|
|
/* write to the outbound msg register for PCI master to read, eumbbar as base */
|
|
store_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET, msg );
|
|
}
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* function: I2ODBEnable
|
|
*
|
|
* description: Local processor enables it's inbound doorbell interrupt
|
|
* PCI master enables outbound doorbell interrupt of devices
|
|
* Other previously enabled interrupts are preserved.
|
|
* Return I2OSUCCESS if no error otherwise return I2ODBINVALID
|
|
*
|
|
* note:
|
|
* In DoorBell interrupt is generated by PCI master and serviced by local processor
|
|
* Out Doorbell interrupt is generated by local processor and serviced by PCI master
|
|
*
|
|
* Out Doorbell interrupt is generated by local processor and serviced by PCI master
|
|
* PCI master needs to enable the outbound doorbell interrupts of device it wants to handle
|
|
**********************************************************************/
|
|
I2OSTATUS I2ODBEnable( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base, /* pcsrbar/eumbbar */
|
|
unsigned int in_db ) /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */
|
|
{
|
|
|
|
/* LOCATION - REMOTE : PCI master initializes outbound doorbell message of device
|
|
* LOCAL : Kahlua initializes its inbound doorbell message
|
|
*/
|
|
unsigned int val;
|
|
|
|
if ( loc == LOCAL && ( in_db & 0x3 ) == 0 )
|
|
{
|
|
return I2ODBINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* pcsrbar is base */
|
|
val = load_runtime_reg( base, I2O_OMIMR );
|
|
val &= 0xfffffff7;
|
|
store_runtime_reg( base, I2O_OMIMR , val );
|
|
}
|
|
else
|
|
{
|
|
/* eumbbar is base */
|
|
val = load_runtime_reg( base, I2O_IMIMR);
|
|
in_db = ( (~in_db) & 0x3 ) << 3;
|
|
val = ( val & 0xffffffe7) | in_db;
|
|
store_runtime_reg( base, I2O_IMIMR, val );
|
|
}
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/**********************************************************************************
|
|
* function: I2ODBDisable
|
|
*
|
|
* description: local processor disables its inbound DoorBell Interrupt
|
|
* PCI master disables outbound DoorBell interrupt of device
|
|
* Other previously enabled interrupts are preserved.
|
|
* return I2OSUCCESS if no error.Otherwise return I2ODBINVALID
|
|
*
|
|
* note:
|
|
* local processor needs to disable its inbound doorbell interrupts it is not interested
|
|
*
|
|
* PCI master needs to disable outbound doorbell interrupts of device it is not interested
|
|
************************************************************************************/
|
|
I2OSTATUS I2ODBDisable( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base, /* pcsrbar/eumbbar */
|
|
unsigned int in_db ) /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */
|
|
{
|
|
/* LOCATION - REMOTE : handle device's out bound message initialization
|
|
* LOCAL : handle local in bound message initialization
|
|
*/
|
|
unsigned int val;
|
|
|
|
if ( loc == LOCAL && ( in_db & 0x3 ) == 0 )
|
|
{
|
|
return I2ODBINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* pcsrbar is the base */
|
|
val = load_runtime_reg( base, I2O_OMIMR );
|
|
val |= 0x8;
|
|
store_runtime_reg( base, I2O_OMIMR, val );
|
|
}
|
|
else
|
|
{
|
|
val = load_runtime_reg( base, I2O_IMIMR);
|
|
in_db = ( in_db & 0x3 ) << 3;
|
|
val |= in_db;
|
|
store_runtime_reg( base, I2O_IMIMR, val );
|
|
}
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/**********************************************************************************
|
|
* function: I2ODBGet
|
|
*
|
|
* description: Local processor reads its in doorbell register,
|
|
* PCI master reads the outdoorbell register of device.
|
|
* After a doorbell register is read, the whole register will be cleared.
|
|
* Otherwise, HW keeps generating interrupt.
|
|
*
|
|
* note:
|
|
* If it is not local, pcsrbar must be passed to the function.
|
|
* Otherwise eumbbar is passed.
|
|
*
|
|
* If it is remote, out doorbell register on the device is read.
|
|
* Otherwise local in doorbell is read
|
|
*
|
|
* If the register is not cleared by write to it, any remaining bit of b'1's
|
|
* will cause interrupt pending.
|
|
*********************************************************************************/
|
|
unsigned int I2ODBGet( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base) /* pcsrbar/eumbbar */
|
|
{
|
|
unsigned int msg, val;
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* read outbound doorbell register of device, pcsrbar is the base */
|
|
val = load_runtime_reg( base, I2O_ODBR );
|
|
msg = val & 0xe0000000;
|
|
store_runtime_reg( base, I2O_ODBR, val ); /* clear the register */
|
|
}
|
|
else
|
|
{
|
|
/* read the inbound doorbell register, eumbbar is the base */
|
|
val = load_runtime_reg( base, I2O_IDBR );
|
|
store_runtime_reg( base, I2O_IDBR, val ); /* clear the register */
|
|
msg = val;
|
|
}
|
|
|
|
return msg;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* function: I2ODBPost
|
|
*
|
|
* description: local processor writes to a outbound doorbell register,
|
|
* PCI master writes to the inbound doorbell register of device
|
|
*
|
|
* note:
|
|
* If it is not local, pcsrbar must be passed to the function.
|
|
* Otherwise eumbbar is passed.
|
|
*
|
|
* If it is remote, in doorbell register on the device is written.
|
|
* Otherwise local out doorbell is written
|
|
*********************************************************************/
|
|
void I2ODBPost( LOCATION loc, /* REMOTE/LOCAL */
|
|
unsigned int base, /* pcsrbar/eumbbar */
|
|
unsigned int msg ) /* in / out */
|
|
{
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* write to inbound doorbell register of device, pcsrbar is the base */
|
|
store_runtime_reg( base, I2O_IDBR, msg );
|
|
}
|
|
else
|
|
{
|
|
/* write to local outbound doorbell register, eumbbar is the base */
|
|
store_runtime_reg( base, I2O_ODBR, msg & 0x1fffffff );
|
|
}
|
|
|
|
}
|
|
|
|
/********************************************************************
|
|
* function: I2OOutMsgStatGet
|
|
*
|
|
* description: PCI master reads device's outbound msg unit interrupt status.
|
|
* Reading an interrupt status register,
|
|
* the register will be cleared.
|
|
*
|
|
* The value of the status register is AND with the outbound
|
|
* interrupt mask and result is returned.
|
|
*
|
|
* note:
|
|
* pcsrbar must be passed to the function.
|
|
********************************************************************/
|
|
I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT *val )
|
|
{
|
|
unsigned int stat;
|
|
unsigned int mask;
|
|
|
|
if ( val == 0 )
|
|
{
|
|
return I2OINVALID;
|
|
}
|
|
|
|
/* read device's outbound status */
|
|
stat = load_runtime_reg( pcsrbar, I2O_OMISR );
|
|
mask = load_runtime_reg( pcsrbar, I2O_OMIMR );
|
|
store_runtime_reg( pcsrbar, I2O_OMISR, stat & 0xffffffd7);
|
|
|
|
stat &= mask;
|
|
val->rsvd0 = ( stat & 0xffffffc0 ) >> 6;
|
|
val->opqi = ( stat & 0x00000020 ) >> 5;
|
|
val->rsvd1 = ( stat & 0x00000010 ) >> 4;
|
|
val->odi = ( stat & 0x00000008 ) >> 3;
|
|
val->rsvd2 = ( stat & 0x00000004 ) >> 2;
|
|
val->om1i = ( stat & 0x00000002 ) >> 1;
|
|
val->om0i = ( stat & 0x00000001 );
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/********************************************************************
|
|
* function: I2OInMsgStatGet
|
|
*
|
|
* description: Local processor reads its inbound msg unit interrupt status.
|
|
* Reading an interrupt status register,
|
|
* the register will be cleared.
|
|
*
|
|
* The inbound msg interrupt status is AND with the inbound
|
|
* msg interrupt mask and result is returned.
|
|
*
|
|
* note:
|
|
* eumbbar must be passed to the function.
|
|
********************************************************************/
|
|
I2OSTATUS I2OInMsgStatGet(unsigned int eumbbar, I2OIMSTAT *val)
|
|
{
|
|
unsigned int stat;
|
|
unsigned int mask;
|
|
|
|
if ( val == 0 )
|
|
{
|
|
return I2OINVALID;
|
|
}
|
|
|
|
/* read device's outbound status */
|
|
stat = load_runtime_reg( eumbbar, I2O_OMISR );
|
|
mask = load_runtime_reg( eumbbar, I2O_OMIMR );
|
|
store_runtime_reg( eumbbar, I2O_OMISR, stat & 0xffffffe7 );
|
|
|
|
stat &= mask;
|
|
val->rsvd0 = ( stat & 0xfffffe00 ) >> 9;
|
|
val->ofoi = ( stat & 0x00000100 ) >> 8;
|
|
val->ipoi = ( stat & 0x00000080 ) >> 7;
|
|
val->rsvd1 = ( stat & 0x00000040 ) >> 6;
|
|
val->ipqi = ( stat & 0x00000020 ) >> 5;
|
|
val->mci = ( stat & 0x00000010 ) >> 4;
|
|
val->idi = ( stat & 0x00000008 ) >> 3;
|
|
val->rsvd2 = ( stat & 0x00000004 ) >> 2;
|
|
val->im1i = ( stat & 0x00000002 ) >> 1;
|
|
val->im0i = ( stat & 0x00000001 );
|
|
|
|
return I2OSUCCESS;
|
|
|
|
}
|
|
|
|
/***********************************************************
|
|
* function: I2OFIFOInit
|
|
*
|
|
* description: Configure the I2O FIFO, including QBAR,
|
|
* IFHPR/IFTPR, IPHPR/IPTPR, OFHPR/OFTPR,
|
|
* OPHPR/OPTPR, MUCR.
|
|
*
|
|
* return I2OSUCCESS if no error,
|
|
* otherwise return I2OQUEINVALID
|
|
*
|
|
* note: It is NOT this driver's responsibility of initializing
|
|
* MFA blocks, i.e., FIFO queue itself. The MFA blocks
|
|
* must be initialized before I2O unit can be used.
|
|
***********************************************************/
|
|
I2OSTATUS I2OFIFOInit( unsigned int eumbbar,
|
|
QUEUE_SIZE sz, /* value of CQS of MUCR */
|
|
unsigned int qba) /* queue base address that must be aligned at 1M */
|
|
{
|
|
|
|
if ( ( qba & 0xfffff ) != 0 )
|
|
{
|
|
/* QBA must be aligned at 1Mbyte boundary */
|
|
return I2OQUEINVALID;
|
|
}
|
|
|
|
store_runtime_reg( eumbbar, I2O_QBAR, qba );
|
|
store_runtime_reg( eumbbar, I2O_MUCR, (unsigned int)sz );
|
|
store_runtime_reg( eumbbar, I2O_IFHPR, qba );
|
|
store_runtime_reg( eumbbar, I2O_IFTPR, qba );
|
|
store_runtime_reg( eumbbar, I2O_IPHPR, qba + 1 * ( sz << 11 ));
|
|
store_runtime_reg( eumbbar, I2O_IPTPR, qba + 1 * ( sz << 11 ));
|
|
store_runtime_reg( eumbbar, I2O_OFHPR, qba + 2 * ( sz << 11 ));
|
|
store_runtime_reg( eumbbar, I2O_OFTPR, qba + 2 * ( sz << 11 ));
|
|
store_runtime_reg( eumbbar, I2O_OPHPR, qba + 3 * ( sz << 11 ));
|
|
store_runtime_reg( eumbbar, I2O_OPTPR, qba + 3 * ( sz << 11 ));
|
|
|
|
fifo_stat.qsz = sz;
|
|
fifo_stat.qba = qba;
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/**************************************************
|
|
* function: I2OFIFOEnable
|
|
*
|
|
* description: Enable the circular queue
|
|
* return I2OSUCCESS if no error.
|
|
* Otherwise I2OQUEINVALID is returned.
|
|
*
|
|
* note:
|
|
*************************************************/
|
|
I2OSTATUS I2OFIFOEnable( unsigned int eumbbar )
|
|
{
|
|
unsigned int val;
|
|
|
|
if ( fifo_stat.qba == 0xfffffff )
|
|
{
|
|
return I2OQUEINVALID;
|
|
}
|
|
|
|
val = load_runtime_reg( eumbbar, I2O_MUCR );
|
|
store_runtime_reg( eumbbar, I2O_MUCR, val | 0x1 );
|
|
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/**************************************************
|
|
* function: I2OFIFODisable
|
|
*
|
|
* description: Disable the circular queue
|
|
*
|
|
* note:
|
|
*************************************************/
|
|
void I2OFIFODisable( unsigned int eumbbar )
|
|
{
|
|
if ( fifo_stat.qba == 0xffffffff )
|
|
{
|
|
/* not enabled */
|
|
return;
|
|
}
|
|
|
|
unsigned int val = load_runtime_reg( eumbbar, I2O_MUCR );
|
|
store_runtime_reg( eumbbar, I2O_MUCR, val & 0xfffffffe );
|
|
}
|
|
|
|
/****************************************************
|
|
* function: I2OFIFOAlloc
|
|
*
|
|
* description: Allocate a free MFA from free FIFO.
|
|
* return I2OSUCCESS if no error.
|
|
* return I2OQUEEMPTY if no more free MFA.
|
|
* return I2OINVALID on other errors.
|
|
*
|
|
* A free MFA must be allocated before a
|
|
* message can be posted.
|
|
*
|
|
* note:
|
|
* PCI Master allocates a free MFA from inbound queue of device
|
|
* (pcsrbar is the base,) through the inbound queue port of device
|
|
* while local processor allocates a free MFA from its outbound
|
|
* queue (eumbbar is the base.)
|
|
*
|
|
****************************************************/
|
|
I2OSTATUS I2OFIFOAlloc( LOCATION loc,
|
|
unsigned int base,
|
|
void **pMsg )
|
|
{
|
|
I2OSTATUS stat = I2OSUCCESS;
|
|
void *pHdr, *pTil;
|
|
|
|
if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff )
|
|
{
|
|
/* not configured */
|
|
return I2OQUEINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* pcsrbar is the base and read the inbound free tail ptr */
|
|
pTil = (void *)load_runtime_reg( base, I2O_IFQPR );
|
|
if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF )
|
|
{
|
|
stat = I2OQUEEMPTY;
|
|
}
|
|
else
|
|
{
|
|
*pMsg = pTil;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* eumbbar is the base and read the outbound free tail ptr */
|
|
pHdr = (void *)load_runtime_reg( base, I2O_OFHPR ); /* queue head */
|
|
pTil = (void *)load_runtime_reg( base, I2O_OFTPR ); /* queue tail */
|
|
|
|
/* check underflow */
|
|
if ( pHdr == pTil )
|
|
{
|
|
/* hdr and til point to the same fifo item, no free MFA */
|
|
stat = I2OQUEEMPTY;
|
|
}
|
|
else
|
|
{
|
|
/* update OFTPR */
|
|
*pMsg = (void *)(*(unsigned char *)pTil);
|
|
pTil = (void *)((unsigned int)pTil + 4);
|
|
if ( (unsigned int)pTil == fifo_stat.qba + ( 4 * ( fifo_stat.qsz << 11 ) ) )
|
|
{
|
|
/* reach the upper limit */
|
|
pTil = (void *)(fifo_stat.qba + ( 3 * (fifo_stat.qsz << 11) ));
|
|
}
|
|
store_runtime_reg( base, I2O_OFTPR, (unsigned int)pTil );
|
|
}
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
/******************************************************
|
|
* function: I2OFIFOFree
|
|
*
|
|
* description: Free a used MFA back to free queue after
|
|
* use.
|
|
* return I2OSUCCESS if no error.
|
|
* return I2OQUEFULL if inbound free queue
|
|
* overflow
|
|
*
|
|
* note: PCI Master frees a MFA into device's outbound queue
|
|
* (OFQPR) while local processor frees a MFA into its
|
|
* inbound queue (IFHPR).
|
|
*****************************************************/
|
|
I2OSTATUS I2OFIFOFree( LOCATION loc,
|
|
unsigned int base,
|
|
void *pMsg )
|
|
{
|
|
void **pHdr, **pTil;
|
|
I2OSTATUS stat = I2OSUCCESS;
|
|
|
|
if ( fifo_stat.qba == 0xffffffff || pMsg == 0 )
|
|
{
|
|
return I2OQUEINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* pcsrbar is the base */
|
|
store_runtime_reg( base, I2O_OFQPR, (unsigned int)pMsg );
|
|
}
|
|
else
|
|
{
|
|
/* eumbbar is the base */
|
|
pHdr = (void **)load_runtime_reg( base, I2O_IFHPR );
|
|
pTil = (void **)load_runtime_reg( base, I2O_IFTPR );
|
|
|
|
/* store MFA */
|
|
*pHdr = pMsg;
|
|
|
|
/* update IFHPR */
|
|
pHdr += 4;
|
|
|
|
if ( (unsigned int)pHdr == fifo_stat.qba + ( fifo_stat.qsz << 11 ) )
|
|
{
|
|
/* reach the upper limit */
|
|
pHdr = (void **)fifo_stat.qba;
|
|
}
|
|
|
|
/* check inbound free queue overflow */
|
|
if ( pHdr != pTil )
|
|
{
|
|
store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr);
|
|
}
|
|
else
|
|
{
|
|
stat = I2OQUEFULL;
|
|
}
|
|
|
|
}
|
|
|
|
return stat;
|
|
|
|
}
|
|
|
|
/*********************************************
|
|
* function: I2OFIFOPost
|
|
*
|
|
* description: Post a msg into FIFO post queue
|
|
* the value of msg must be the one
|
|
* returned by I2OFIFOAlloc
|
|
*
|
|
* note: PCI Master posts a msg into device's inbound queue
|
|
* (IFQPR) while local processor post a msg into device's
|
|
* outbound queue (OPHPR)
|
|
*********************************************/
|
|
I2OSTATUS I2OFIFOPost( LOCATION loc,
|
|
unsigned int base,
|
|
void *pMsg )
|
|
{
|
|
void **pHdr, **pTil;
|
|
I2OSTATUS stat = I2OSUCCESS;
|
|
|
|
if ( fifo_stat.qba == 0xffffffff || pMsg == 0 )
|
|
{
|
|
return I2OQUEINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* pcsrbar is the base */
|
|
store_runtime_reg( base, I2O_IFQPR, (unsigned int)pMsg );
|
|
}
|
|
else
|
|
{
|
|
/* eumbbar is the base */
|
|
pHdr = (void **)load_runtime_reg( base, I2O_OPHPR );
|
|
pTil = (void **)load_runtime_reg( base, I2O_OPTPR );
|
|
|
|
/* store MFA */
|
|
*pHdr = pMsg;
|
|
|
|
/* update IFHPR */
|
|
pHdr += 4;
|
|
|
|
if ( (unsigned int)pHdr == fifo_stat.qba + 3 * ( fifo_stat.qsz << 11 ) )
|
|
{
|
|
/* reach the upper limit */
|
|
pHdr = (void **)(fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) );
|
|
}
|
|
|
|
/* check post queue overflow */
|
|
if ( pHdr != pTil )
|
|
{
|
|
store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr);
|
|
}
|
|
else
|
|
{
|
|
stat = I2OQUEFULL;
|
|
}
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
/************************************************
|
|
* function: I2OFIFOGet
|
|
*
|
|
* description: Read a msg from FIFO
|
|
* This function should be called
|
|
* only when there is a corresponding
|
|
* msg interrupt.
|
|
*
|
|
* note: PCI Master reads a msg from device's outbound queue
|
|
* (OFQPR) while local processor reads a msg from device's
|
|
* inbound queue (IPTPR)
|
|
************************************************/
|
|
I2OSTATUS I2OFIFOGet( LOCATION loc,
|
|
unsigned int base,
|
|
void **pMsg )
|
|
{
|
|
I2OSTATUS stat = I2OSUCCESS;
|
|
void *pHdr, *pTil;
|
|
|
|
if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff )
|
|
{
|
|
/* not configured */
|
|
return I2OQUEINVALID;
|
|
}
|
|
|
|
if ( loc == REMOTE )
|
|
{
|
|
/* pcsrbar is the base */
|
|
pTil = (void *)load_runtime_reg( base, I2O_OFQPR );
|
|
if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF )
|
|
{
|
|
stat = I2OQUEEMPTY;
|
|
}
|
|
else
|
|
{
|
|
*pMsg = pTil;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* eumbbar is the base and read the outbound free tail ptr */
|
|
pHdr = (void *)load_runtime_reg( base, I2O_IPHPR ); /* queue head */
|
|
pTil = (void *)load_runtime_reg( base, I2O_IPTPR ); /* queue tail */
|
|
|
|
/* check underflow */
|
|
if ( pHdr == pTil )
|
|
{
|
|
/* no free MFA */
|
|
stat = I2OQUEEMPTY;
|
|
}
|
|
else
|
|
{
|
|
/* update OFTPR */
|
|
*pMsg = (void *)(*(unsigned char *)pTil);
|
|
pTil = (void *)((unsigned int)pTil + 4);
|
|
if ( (unsigned int)pTil == fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) )
|
|
{
|
|
/* reach the upper limit */
|
|
pTil = (void *)(fifo_stat.qba + 1 * (fifo_stat.qsz << 11) );
|
|
}
|
|
|
|
store_runtime_reg( base, I2O_IPTPR, (unsigned int)pTil );
|
|
}
|
|
}
|
|
|
|
return stat;
|
|
}
|
|
|
|
/********************************************************
|
|
* function: I2OIOP
|
|
*
|
|
* description: Get the I2O PCI configuration identification
|
|
* register.
|
|
*
|
|
* note: PCI master should pass pcsrbar while local processor
|
|
* should pass eumbbar.
|
|
*********************************************************/
|
|
I2OSTATUS I2OPCIConfigGet( LOCATION loc,
|
|
unsigned int base,
|
|
I2OIOP * val)
|
|
{
|
|
unsigned int tmp;
|
|
if ( val == 0 )
|
|
{
|
|
return I2OINVALID;
|
|
}
|
|
tmp = load_runtime_reg( base, PCI_CFG_CLA );
|
|
val->base_class = ( tmp & 0xFF) << 16;
|
|
tmp = load_runtime_reg( base, PCI_CFG_SCL );
|
|
val->sub_class= ( (tmp & 0xFF) << 8 );
|
|
tmp = load_runtime_reg( base, PCI_CFG_PIC );
|
|
val->prg_code = (tmp & 0xFF);
|
|
return I2OSUCCESS;
|
|
}
|
|
|
|
/*********************************************************
|
|
* function: I2OFIFOIntEnable
|
|
*
|
|
* description: Enable the circular post queue interrupt
|
|
*
|
|
* note:
|
|
* PCI master enables outbound FIFO interrupt of device
|
|
* pscrbar is the base
|
|
* Device enables its inbound FIFO interrupt
|
|
* eumbbar is the base
|
|
*******************************************************/
|
|
void I2OFIFOIntEnable( LOCATION loc, unsigned int base )
|
|
{
|
|
unsigned int reg, val;
|
|
|
|
/* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base
|
|
* LOCAL : enable local inbound message, eumbbar as base
|
|
*/
|
|
reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR );
|
|
val = load_runtime_reg( base, reg );
|
|
|
|
val &= 0xffffffdf; /* clear the msg interrupt bits */
|
|
store_runtime_reg( base, reg, val );
|
|
|
|
}
|
|
|
|
/****************************************************
|
|
* function: I2OFIFOIntDisable
|
|
*
|
|
* description: Disable the circular post queue interrupt
|
|
*
|
|
* note:
|
|
* PCI master disables outbound FIFO interrupt of device
|
|
* (pscrbar is the base)
|
|
* Device disables its inbound FIFO interrupt
|
|
* (eumbbar is the base)
|
|
*****************************************************/
|
|
void I2OFIFOIntDisable( LOCATION loc, unsigned int base )
|
|
{
|
|
|
|
/* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base
|
|
* LOCAL : disable local inbound message interrupt, eumbbar as base
|
|
*/
|
|
unsigned int reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR );
|
|
unsigned int val = load_runtime_reg( base, reg );
|
|
|
|
val |= 0x00000020; /* masked out the msg interrupt bits */
|
|
store_runtime_reg( base, reg, val );
|
|
|
|
}
|
|
|
|
/*********************************************************
|
|
* function: I2OFIFOOverflowIntEnable
|
|
*
|
|
* description: Enable the circular queue overflow interrupt
|
|
*
|
|
* note:
|
|
* Device enables its inbound FIFO post overflow interrupt
|
|
* and outbound free overflow interrupt.
|
|
* eumbbar is the base
|
|
*******************************************************/
|
|
void I2OFIFOOverflowIntEnable( unsigned int eumbbar )
|
|
{
|
|
unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR );
|
|
|
|
val &= 0xfffffe7f; /* clear the two overflow interrupt bits */
|
|
store_runtime_reg( eumbbar, I2O_IMIMR, val );
|
|
|
|
}
|
|
|
|
/****************************************************
|
|
* function: I2OFIFOOverflowIntDisable
|
|
*
|
|
* description: Disable the circular queue overflow interrupt
|
|
*
|
|
* note:
|
|
* Device disables its inbound post FIFO overflow interrupt
|
|
* and outbound free FIFO overflow interrupt
|
|
* (eumbbar is the base)
|
|
*****************************************************/
|
|
void I2OFIFOOverflowIntDisable( unsigned int eumbbar )
|
|
{
|
|
|
|
unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR );
|
|
|
|
val |= 0x00000180; /* masked out the msg overflow interrupt bits */
|
|
store_runtime_reg( eumbbar, I2O_IMIMR, val );
|
|
}
|
|
|