diff options
Diffstat (limited to 'cpu/mpc824x/drivers/i2o')
-rw-r--r-- | cpu/mpc824x/drivers/i2o/Makefile | 84 | ||||
-rw-r--r-- | cpu/mpc824x/drivers/i2o/Makefile_pc | 90 | ||||
-rw-r--r-- | cpu/mpc824x/drivers/i2o/i2o.h | 345 | ||||
-rw-r--r-- | cpu/mpc824x/drivers/i2o/i2o1.c | 890 | ||||
-rw-r--r-- | cpu/mpc824x/drivers/i2o/i2o2.S | 48 |
5 files changed, 1457 insertions, 0 deletions
diff --git a/cpu/mpc824x/drivers/i2o/Makefile b/cpu/mpc824x/drivers/i2o/Makefile new file mode 100644 index 0000000..3f5ca26 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/Makefile @@ -0,0 +1,84 @@ +########################################################################## +# +# Copyright Motorola, Inc. 1997 +# ALL RIGHTS RESERVED +# +# You are hereby granted a copyright license to use, modify, and +# distribute the SOFTWARE so long as this entire notice is retained +# without alteration in any modified and/or redistributed versions, +# and that such modified versions are clearly identified as such. +# No licenses are granted by implication, estoppel or otherwise under +# any patents or trademarks of Motorola, Inc. +# +# The SOFTWARE is provided on an "AS IS" basis and without warranty. +# To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +# ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +# WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +# PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +# REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +# THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +# To the maximum extent permitted by applicable law, IN NO EVENT SHALL +# MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +# (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +# BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +# INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +# INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libi2o.a + +#DEBUG = -g +DEBUG = +LST = -Hanno -S +OPTIM = +CC = /risc/tools/pkgs/metaware/bin/hcppc +CFLAGS = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT = -big_si -c +ASDEBUG = -l -fm +AS = /risc/tools/pkgs/metaware/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT = -Bbase=0 -Qn -q -r +LKCMD = +LINK = /risc/tools/pkgs/metaware/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL = rm +COPY = cp +LIST = ls + +OBJECTS = i2o1.o i2o2.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(LINK) $(OBJECTS) -o $@ + +objects: i2o1.o + +clean: + $(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: + $(DEL) -f $*.i + $(PREP) -Hasmcpp $< + $(AS) $(ASOPT) $*.i +# $(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: + $(CCobj) $< + +.c.s: + $(CCobj) $(LST) $< + +i2o1.o: i2o.h i2o1.c + +i2o2.o: i2o.h i2o2.s diff --git a/cpu/mpc824x/drivers/i2o/Makefile_pc b/cpu/mpc824x/drivers/i2o/Makefile_pc new file mode 100644 index 0000000..6867f58 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/Makefile_pc @@ -0,0 +1,90 @@ +########################################################################## +# +# makefile_pc for use with PC mksnt tools dink32/drivers/i2o +# +# Copyright Motorola, Inc. 1997 +# ALL RIGHTS RESERVED +# +# You are hereby granted a copyright license to use, modify, and +# distribute the SOFTWARE so long as this entire notice is retained +# without alteration in any modified and/or redistributed versions, +# and that such modified versions are clearly identified as such. +# No licenses are granted by implication, estoppel or otherwise under +# any patents or trademarks of Motorola, Inc. +# +# The SOFTWARE is provided on an "AS IS" basis and without warranty. +# To the maximum extent permitted by applicable law, MOTOROLA DISCLAIMS +# ALL WARRANTIES WHETHER EXPRESS OR IMPLIED, INCLUDING IMPLIED +# WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR +# PURPOSE AND ANY WARRANTY AGAINST INFRINGEMENT WITH +# REGARD TO THE SOFTWARE (INCLUDING ANY MODIFIED VERSIONS +# THEREOF) AND ANY ACCOMPANYING WRITTEN MATERIALS. +# +# To the maximum extent permitted by applicable law, IN NO EVENT SHALL +# MOTOROLA BE LIABLE FOR ANY DAMAGES WHATSOEVER +# (INCLUDING WITHOUT LIMITATION, DAMAGES FOR LOSS OF +# BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS +# INFORMATION, OR OTHER PECUNIARY LOSS) ARISING OF THE USE OR +# INABILITY TO USE THE SOFTWARE. +# +############################################################################ +TARGET = libi2o.a + +#DEBUG = -g +DEBUG = +LST = -Hanno -S +OPTIM = +CC = m:/old_tools/tools/hcppc/bin/hcppc +CFLAGS = -Hnocopyr -c -Hsds -Hon=Char_default_unsigned -Hon=Char_is_rep -I../inc -I/risc/tools/pkgs/metaware/inc +CCobj = $(CC) $(CFLAGS) $(DEBUG) $(OPTIM) +PREP = $(CC) $(CFLAGS) -P + +# Assembler used to build the .s files (for the board version) + +ASOPT = -big_si -c +ASDEBUG = -l -fm +AS = m:/old_tools/tools/hcppc/bin/asppc + +# Linker to bring .o files together into an executable. + +LKOPT = -Bbase=0 -Qn -q -r +LKCMD = +LINK = m:/old_tools/tools/hcppc/bin/ldppc $(LKCMD) $(LKOPT) + +# DOS Utilities + +DEL = rm +COPY = cp +LIST = ls + +OBJECTS = i2o1.o i2o2.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(LINK) $(OBJECTS) -o $@ + +objects: i2o1.o + +clean: + $(DEL) -f *.o *.i *.map *.lst $(TARGET) $(OBJECTS) + +.s.o: + $(DEL) -f $*.i + $(PREP) -Hasmcpp $< + $(AS) $(ASOPT) $*.i +# $(AS) $(ASOPT) $(ASDEBUG) $*.i > $*.lst + +.c.o: + $(CCobj) $< + +.c.s: + $(CCobj) $(LST) $< + +i2o1.o: i2o.h i2o1.c + $(CCobj) $< + +i2o2.o: i2o.h i2o2.s + $(DEL) -f $*.i + $(PREP) -Hasmcpp $< + $(AS) $(ASOPT) $*.i diff --git a/cpu/mpc824x/drivers/i2o/i2o.h b/cpu/mpc824x/drivers/i2o/i2o.h new file mode 100644 index 0000000..26f7c5c --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/i2o.h @@ -0,0 +1,345 @@ +#ifndef I2O_H +#define I2O_H +/********************************************************* + * + * copyright @ Motorola, 1999 + * + *********************************************************/ + +#define I2O_REG_OFFSET 0x0004 + +#define PCI_CFG_CLA 0x0B +#define PCI_CFG_SCL 0x0A +#define PCI_CFG_PIC 0x09 + +#define I2O_IMR0 0x0050 +#define I2O_IMR1 0x0054 +#define I2O_OMR0 0x0058 +#define I2O_OMR1 0x005C + +#define I2O_ODBR 0x0060 +#define I2O_IDBR 0x0068 + +#define I2O_OMISR 0x0030 +#define I2O_OMIMR 0x0034 +#define I2O_IMISR 0x0100 +#define I2O_IMIMR 0x0104 + +/* accessable to PCI master but local processor */ +#define I2O_IFQPR 0x0040 +#define I2O_OFQPR 0x0044 + +/* accessable to local processor */ +#define I2O_IFHPR 0x0120 +#define I2O_IFTPR 0x0128 +#define I2O_IPHPR 0x0130 +#define I2O_IPTPR 0x0138 +#define I2O_OFHPR 0x0140 +#define I2O_OFTPR 0x0148 +#define I2O_OPHPR 0x0150 +#define I2O_OPTPR 0x0158 +#define I2O_MUCR 0x0164 +#define I2O_QBAR 0x0170 + +#define I2O_NUM_MSG 2 + +typedef enum _i2o_status +{ + I2OSUCCESS = 0, + I2OINVALID, + I2OMSGINVALID, + I2ODBINVALID, + I2OQUEINVALID, + I2OQUEEMPTY, + I2OQUEFULL, + I2ONOEVENT, +} I2OSTATUS; + +typedef enum _queue_size +{ + QSIZE_4K = 0x02, + QSIZE_8K = 0x04, + QSIZE_16K = 0x08, + QSIZE_32K = 0x10, + QSIZe_64K = 0x20, +} QUEUE_SIZE; + +typedef enum _location +{ + LOCAL = 0, /* used by local processor to access its own on board device, + local processor's eumbbar is required */ + REMOTE, /* used by PCI master to access the devices on its PCI device, + device's pcsrbar is required */ +} LOCATION; + +/* door bell */ +typedef enum _i2o_in_db +{ + IN_DB = 1, + MC, /* machine check */ +} I2O_IN_DB; + +/* I2O PCI configuration identification */ +typedef struct _i2o_iop +{ + unsigned int base_class : 8; + unsigned int sub_class : 8; + unsigned int prg_code : 8; +} I2OIOP; + +/* I2O Outbound Message Interrupt Status Register */ +typedef struct _i2o_om_stat +{ + unsigned int rsvd0 : 26; + unsigned int opqi : 1; + unsigned int rsvd1 : 1; + unsigned int odi : 1; + unsigned int rsvd2 : 1; + unsigned int om1i : 1; + unsigned int om0i : 1; +} I2OOMSTAT; + +/* I2O inbound Message Interrupt Status Register */ +typedef struct _i2o_im_stat +{ + unsigned int rsvd0 : 23; + unsigned int ofoi : 1; + unsigned int ipoi : 1; + unsigned int rsvd1 : 1; + unsigned int ipqi : 1; + unsigned int mci : 1; + unsigned int idi : 1; + unsigned int rsvd2 : 1; + unsigned int im1i : 1; + unsigned int im0i : 1; +} I2OIMSTAT; + +/** + Enable the interrupt associated with in/out bound msg + + Inbound message interrupt generated by PCI master and serviced by local processor + local processor needs to enable its inbound interrupts it wants to handle (LOCAL) + + Outbound message interrupt generated by local processor and serviced by PCI master + PCI master needs to enable the devices' outbound interrupts it wants to handle (REMOTE) + **/ +extern I2OSTATUS I2OMsgEnable( LOCATION, /* REMOTE/LOCAL */ + unsigned int base, /* pcsrbar/eumbbar */ + unsigned char n ); /* b'1' - msg 0 + * b'10'- msg 1 + * b'11'- both + */ + +/** + Disable the interrupt associated with in/out bound msg + + 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) + **/ +extern I2OSTATUS I2OMsgDisable( LOCATION, /* REMOTE/LOCAL */ + unsigned int base, /* pcsrbar/eumbbar */ + unsigned char n ); /* b'1' - msg 0 + * b'10'- msg 1 + * b'11'- both + */ + +/** + Read the msg register either from local inbound msg 0/1, + or an outbound msg 0/1 of devices. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, outbound msg of the device is read. + Otherwise local inbound msg is read. + **/ +extern I2OSTATUS I2OMsgGet ( LOCATION, /* REMOTE/LOCAL */ + unsigned int base, /*pcsrbar/eumbbar */ + unsigned int n, /* 0 or 1 */ + unsigned int *msg ); + +/** + Write to nth Msg register either on local outbound msg 0/1, + or aninbound msg 0/1 of devices + + 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. + **/ +extern I2OSTATUS I2OMsgPost( LOCATION, /* REMOTE/LOCAL */ + unsigned int base, /*pcsrbar/eumbbar */ + unsigned int n, /* 0 or 1 */ + unsigned int msg ); + +/** + Enable the In/Out DoorBell Interrupt + + InDoorBell interrupt is generated by PCI master and serviced by local processor + local processor needs to enable its inbound doorbell interrupts it wants to handle + + OutDoorbell interrupt is generated by local processor and serviced by PCI master + PCI master needs to enable outbound doorbell interrupts of the devices it wants to handle + **/ +extern I2OSTATUS I2ODBEnable( LOCATION, /* REMOTE/LOCAL */ + unsigned int base, /* pcsrbar/eumbbar */ + unsigned int in_db );/* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ + +/** + Disable the In/Out DoorBell Interrupt + + local processor needs to disable its inbound doorbell interrupts it is not interested + + PCI master needs to disable outbound doorbell interrupts of devices it is not interested + + **/ +extern I2OSTATUS I2ODBDisable( LOCATION, /* REMOTE/LOCAL */ + unsigned int base, /* pcsrbar/eumbbar */ + unsigned int in_db ); /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ + +/** + Read a local indoorbell register, or an outdoorbell of devices. + Reading a doorbell register, the register will be cleared. + + If it is not local, pcsrbar must be passed to the function. + Otherwise eumbbar is passed. + + If it is remote, outdoorbell register on the device is read. + Otherwise local in doorbell is read + **/ +extern unsigned int I2ODBGet( LOCATION, /* REMOTE/LOCAL */ + unsigned int base); /* pcsrbar/eumbbar */ + +/** + Write to a local outdoorbell register, or an indoorbell register of devices. + + 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 + **/ +extern void I2ODBPost( LOCATION, /* REMOTE/LOCAL */ + unsigned int base, /* pcsrbar/eumbbar */ + unsigned int msg ); /* in / out */ + +/** + Read the outbound msg unit interrupt status of devices. Reading an interrupt status register, + the register will be cleared. + + The outbound interrupt status is AND with the outbound + interrupt mask. The result is returned. + + PCI master must pass the pcsrbar to the function. + **/ +extern I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT * ); + +/** + Read the inbound msg unit interrupt status. Reading an interrupt status register, + the register will be cleared. + + The inbound interrupt status is AND with the inbound + interrupt mask. The result is returned. + + Local process must pass its eumbbar to the function. +**/ +extern I2OSTATUS I2OInMsgStatGet( unsigned int eumbbar, I2OIMSTAT * ); + +/** + Configure the I2O FIFO, including QBAR, IFHPR/IFTPR,IPHPR/IPTPR,OFHPR/OFTPR, OPHPR/OPTPR, + MUCR. + **/ +extern I2OSTATUS I2OFIFOInit( unsigned int eumbbar, + QUEUE_SIZE, + unsigned int qba);/* queue base address that must be aligned at 1M */ +/** + Enable the circular queue + **/ +extern I2OSTATUS I2OFIFOEnable( unsigned int eumbbar ); + +/** + Disable the circular queue + **/ +extern void I2OFIFODisable( unsigned int eumbbar ); + +/** + Enable the circular queue interrupt + PCI master enables outbound FIFO interrupt of device + Device enables its inbound FIFO interrupt + **/ +extern void I2OFIFOIntEnable( LOCATION, unsigned int base ); + +/** + Disable the circular queue interrupt + PCI master disables outbound FIFO interrupt of device + Device disables its inbound FIFO interrupt + **/ +extern void I2OFIFOIntDisable( LOCATION, unsigned int base ); + +/** + Enable the circular queue overflow interrupt + **/ +extern void I2OFIFOOverflowIntEnable( unsigned int eumbbar ); + +/** + Disable the circular queue overflow interrupt + **/ +extern void I2OFIFOOverflowIntDisable( unsigned int eumbbar ); + +/** + Allocate a free msg frame from free FIFO. + + PCI Master allocates a free msg frame through inbound queue port of device(IFQPR) + while local processor allocates a free msg frame from outbound free queue(OFTPR) + + Unless both free queues are initialized, allocating a free MF will return 0xffffffff + **/ +extern I2OSTATUS I2OFIFOAlloc( LOCATION, + unsigned int base, + void **pMsg); +/** + Free a used msg frame back to free queue + PCI Master frees a MFA through outbound queue port of device(OFQPR) + while local processor frees a MFA into its inbound free queue(IFHPR) + + Used msg frame does not need to be recycled in the order they + read + + This function has to be called by PCI master to initialize Inbound free queue + and by device to initialize Outbound free queue before I2OFIFOAlloc can be used. + **/ +extern I2OSTATUS I2OFIFOFree( LOCATION, + unsigned int base, + void *pMsg ); + +/** + Post a msg into FIFO + PCI Master posts a msg through inbound queue port of device(IFQPR) + while local processor post a msg into its outbound post queue(OPHPR) + + The total number of msg must be less than the max size of the queue + Otherwise queue overflow interrupt will assert. + **/ +extern I2OSTATUS I2OFIFOPost( LOCATION, + unsigned int base, + void *pMsg ); + +/** + Read a msg from FIFO + PCI Master reads a msg through outbound queue port of device(OFQPR) + while local processor reads a msg from its inbound post queue(IPTPR) + **/ +extern I2OSTATUS I2OFIFOGet( LOCATION, + unsigned int base, + void **pMsg ); + +/** + Get the I2O PCI configuration identification register + **/ +extern I2OSTATUS I2OPCIConfigGet( LOCATION, + unsigned int base, + I2OIOP *); + +#endif diff --git a/cpu/mpc824x/drivers/i2o/i2o1.c b/cpu/mpc824x/drivers/i2o/i2o1.c new file mode 100644 index 0000000..d840af0 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/i2o1.c @@ -0,0 +1,890 @@ +/********************************************************* + * $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 ); +} diff --git a/cpu/mpc824x/drivers/i2o/i2o2.S b/cpu/mpc824x/drivers/i2o/i2o2.S new file mode 100644 index 0000000..1033979 --- /dev/null +++ b/cpu/mpc824x/drivers/i2o/i2o2.S @@ -0,0 +1,48 @@ +/************************************** + * + * copyright @ Motorola, 1999 + * + **************************************/ + +/********************************************************** + * function: load_runtime_reg + * + * input: r3 - value of eumbbar + * r4 - register offset in embedded utility space + * + * output: r3 - register content + **********************************************************/ + .text + .align 2 + .global load_runtime_reg + +load_runtime_reg: + + xor r5,r5,r5 + or r5,r5,r3 /* save eumbbar */ + + lwbrx r3,r4,r5 + sync + + bclr 20, 0 + +/**************************************************************** + * function: store_runtime_reg + * + * input: r3 - value of eumbbar + * r4 - register offset in embedded utility space + * r5 - new value to be stored + * + ****************************************************************/ + .text + .align 2 + .global store_runtime_reg +store_runtime_reg: + + xor r0,r0,r0 + + stwbrx r5, r4, r3 + sync + + bclr 20,0 + |