// ---------------------------------------------------------------------------- // Copyright (c) 1992 Olivetti // // File: eisapod.c // // Description: // ---------------------------------------------------------------------------- // #include "fwp.h" #include "oli2msft.h" #include "arceisa.h" #include "inc.h" #include "string.h" #include "debug.h" #include "eisastr.h" extern EISA_BUS_INFO EisaBusInfo[]; // ---------------------------------------------------------------------------- // Define Function Prototypes // ---------------------------------------------------------------------------- BOOLEAN EisaBusPod ( IN ULONG BusNumber ); BOOLEAN EisaIntPod ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ); VOID EisaPicIni ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ); BOOLEAN EisaPicRegTest ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ); BOOLEAN EisaClearPendingInts ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ); BOOLEAN EisaDmaPod ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ); BOOLEAN EisaDmaMaskTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ); BOOLEAN EisaDmaPageTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ); BOOLEAN EisaDmaAddressTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ); BOOLEAN EisaDmaCountTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ); BOOLEAN EisaDmaStopTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ); VOID EisaDmaIni ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ); BOOLEAN EisaOtherPod ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ); BOOLEAN EisaNmiTest ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ); BOOLEAN EisaNmiHandlerTest ( IN ULONG Couse ); BOOLEAN EisaNmiHandler ( IN ULONG Couse ); VOID EisaParityError ( IN PUCHAR EisaIoStart ); VOID EisaIoChkError ( IN PUCHAR EisaIoStart, IN ULONG Slots ); VOID EisaBusTimeoutError ( IN PUCHAR EisaIoStart, IN ULONG Slots ); VOID EisaSlaveTimeoutError ( IN PUCHAR EisaIoStart, IN ULONG Slots ); BOOLEAN EisaRefreshTest ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ); BOOLEAN EisaPort61Test ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ); BOOLEAN EisaTimer1Test ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ); BOOLEAN EisaTimer2Test ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ); // ---------------------------------------------------------------------------- // Define EISA Function Prototypes // ---------------------------------------------------------------------------- VOID EisaClearPendingInt ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo, IN USHORT Irq ); UCHAR EisaAckInt ( IN PEISA_INT_INFO pIntInfo ); VOID EisaSendSpecificEoi ( IN PUCHAR EisaIoStart, IN USHORT Irq ); VOID EisaDisableParityIoCheck ( IN PUCHAR EisaIoStart ); VOID EisaEnableParityIoCheck ( IN PUCHAR EisaIoStart ); VOID EisaDisableInt ( VOID ); VOID EisaDisableNmi ( IN PUCHAR EisaIoStart ); VOID EisaEnableNmi ( IN PUCHAR EisaIoStart ); BOOLEAN EisaCheckReg ( IN PUCHAR Port, IN UCHAR DataMask ); BOOLEAN EisaCheckDeepReg ( IN PUCHAR Port ); UCHAR EisaReadRtc ( IN PUCHAR EisaIoStart, IN ULONG RtcIndex ); VOID EisaOutUchar ( IN PUCHAR Addr, IN UCHAR Value ); UCHAR EisaInUchar ( IN PUCHAR Addr ); // ---------------------------------------------------------------------------- // Define Global Variables // ---------------------------------------------------------------------------- EISA_DMA_REGS_TEST EisaDmaRegsTest[ EISA_DMAS ] = { { DMA_ADDR_0, DMA_PAGE_0, DMA_HPAGE_0, DMA_COUNT_0, DMA_HCOUNT_0, DMA_STOP_0 }, { DMA_ADDR_1, DMA_PAGE_1, DMA_HPAGE_1, DMA_COUNT_1, DMA_HCOUNT_1, DMA_STOP_1 }, { DMA_ADDR_2, DMA_PAGE_2, DMA_HPAGE_2, DMA_COUNT_2, DMA_HCOUNT_2, DMA_STOP_2 }, { DMA_ADDR_3, DMA_PAGE_3, DMA_HPAGE_3, DMA_COUNT_3, DMA_HCOUNT_3, DMA_STOP_3 }, { DMA_ADDR_4, DMA_PAGE_RFR, 0, DMA_COUNT_4, 0, 0 }, { DMA_ADDR_5, DMA_PAGE_5, DMA_HPAGE_5, DMA_COUNT_5, DMA_HCOUNT_5, DMA_STOP_5 }, { DMA_ADDR_6, DMA_PAGE_6, DMA_HPAGE_6, DMA_COUNT_6, DMA_HCOUNT_6, DMA_STOP_6 }, { DMA_ADDR_7, DMA_PAGE_7, DMA_HPAGE_7, DMA_COUNT_7, DMA_HCOUNT_7, DMA_STOP_7 } }; EISA_DMA_CTRL_TEST EisaDmaCtrlTest[ 2 ] = { {DMA_MASK_CLR03, DMA_MASKS03, DMA_1MASK03, DMA_MASK_STAT03, DMA_CHAIN03}, {DMA_MASK_CLR47, DMA_MASKS47, DMA_1MASK47, DMA_MASK_STAT47, DMA_CHAIN47} }; BOOLEAN EisaNmiFlag; // for NMI testing // ---------------------------------------------------------------------------- // PROCEDURE: EisaBusPod: // // DESCRIPTION: This function initializes the hardware of the // specified EISA bus. // // ARGUMENTS: BusNumber EISA bus number // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaBusPod ( IN ULONG BusNumber ) { // // define local variables // BOOLEAN IniOk = TRUE; // initialization status PEISA_DMA_INFO pDmaInfo; // DMA info pointer PEISA_INT_INFO pIntInfo; // INT info pointer PEISA_PORT_INFO pPortInfo; // PORT info pointer PUCHAR EisaIoStart; // EISA I/O virtual address PRINTDBG("EisaBusPod\n\r"); // DEBUG SUPPORT // // initialize variables // pDmaInfo = EisaBusInfo[ BusNumber ].DmaInfo; pIntInfo = EisaBusInfo[ BusNumber ].IntInfo; pPortInfo = EisaBusInfo[ BusNumber ].PortInfo; // EisaIoStart = EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr; EisaIoStart = EISA_IO_VIRTUAL_BASE; // TEMPTEMP // // perform any PIC testing and initialization // if ( !EisaIntPod( EisaIoStart, pIntInfo ) ) { IniOk = FALSE; } // // perform any DMA testing and initialization // if ( !EisaDmaPod( EisaIoStart, pDmaInfo ) ) { IniOk = FALSE; } // // perform any other port testing and initialization // if ( !EisaOtherPod( EisaIoStart, pPortInfo ) ) { IniOk = FALSE; } // // return status // return IniOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaIntPod: // // DESCRIPTION: This function tests and initializes the PIC for the // specified EISA bus. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pIntInfo Interrupt info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaIntPod ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ) { PRINTDBG("EisaIntPod\n\r"); // DEBUG SUPPORT // // if ini already done, return status // if ( pIntInfo->Flags.IniDone ) { return (BOOLEAN)(pIntInfo->Flags.Error); } pIntInfo->Flags.Error = 1; // be pessimistic // // first part of checkpoint // EisaCheckpointFirstFase( EisaPic ); // // disable EISA PICs interrupt chain // EisaDisableInt(); do { // // initialize PICs // EisaPicIni( EisaIoStart, pIntInfo ); // // test registers // if ( !EisaPicRegTest( EisaIoStart, pIntInfo )); // // clear any pending interrupt // else if ( !EisaClearPendingInts( EisaIoStart, pIntInfo )); // // all done // else { pIntInfo->IrqPresent = 0; pIntInfo->IrqShareable = 0; pIntInfo->IrqLevel = 0; pIntInfo->Flags.Error = 0; } } while ( EisaCheckpointFinalFase( EisaPic, pIntInfo->Flags.Error ? FALSE : TRUE )); // // return to caller // pIntInfo->Flags.IniDone = 1; return !(BOOLEAN)(pIntInfo->Flags.Error); } // ---------------------------------------------------------------------------- // PROCEDURE: EisaPicIni: // // DESCRIPTION: This function initializes the PICs of the specified // EISA bus. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pIntInfo Interrupt info pointer // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaPicIni ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ) { PUCHAR Pic1Port1, Pic1Port2, Pic2Port1, Pic2Port2; PRINTDBG("EisaPicIni\n\r"); // DEBUG SUPPORT // // initialize variables // Pic1Port1 = EisaIoStart + PIC1; Pic1Port2 = EisaIoStart + PIC1 + 1; Pic2Port1 = EisaIoStart + PIC2; Pic2Port2 = EisaIoStart + PIC2 + 1; // // Initialize the EISA interrupt controller. There are two cascaded // interrupt controllers, each of which must initialized with 4 initialize // control words. // EisaOutUchar( Pic1Port1, 0x11 ); EisaOutUchar( Pic2Port1, 0x11 ); // // The second intitialization control word sets the iterrupt vector to // 0-15. // EisaOutUchar( Pic1Port2, 0x00 ); EisaOutUchar( Pic2Port2, 0x08 ); // // The thrid initialization control word set the controls for slave mode. // The master ICW3 uses bit position and the slave ICW3 uses a numberic. // EisaOutUchar( Pic1Port2, 0x04 ); EisaOutUchar( Pic2Port2, 0x02 ); // // The fourth initialization control word is used to specify normal // end-of-interrupt mode and not special-fully-nested mode. // EisaOutUchar( Pic1Port2, 0x01 ); EisaOutUchar( Pic2Port2, 0x01 ); // // Mask all the interrupts. // EisaOutUchar( Pic1Port2, 0xFF ); EisaOutUchar( Pic2Port2, 0xFF ); // // set all interrupts to edge sensitive // EisaOutUchar( EisaIoStart + PIC1_ELCR, 0 ); EisaOutUchar( EisaIoStart + PIC2_ELCR, 0 ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaPicRegTest: // // DESCRIPTION: This function performs a test on the PIC registers. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pIntInfo Interrupt info pointer // // RETURN: TRUE all correct // FALSE error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaPicRegTest ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ) { // // initialize variables // BOOLEAN RegOk = FALSE; // be pessimistic PRINTDBG("EisaPicRegTest\n\r"); // DEBUG SUPPORT // // check mask of 1st PIC // if ( !EisaCheckReg( EisaIoStart + PIC1_MASK, 0xFF )); // // check mask of 2nd PIC // else if ( !EisaCheckReg( EisaIoStart + PIC2_MASK, 0xFF )); // // check ELCR 1, but skip bits 0, 1 and 2 (they are reserved) // else if ( !EisaCheckReg( EisaIoStart + PIC1_ELCR, 0xF8 )); // // check ELCR 2, but skip bits 0 and 5 (they are reserved) // else if ( !EisaCheckReg( EisaIoStart + PIC2_ELCR, 0xDE )); // // if we got here, everything is fine // else { EisaOutUchar( EisaIoStart + PIC1_MASK, 0xFF ); EisaOutUchar( EisaIoStart + PIC2_MASK, 0xFF ); EisaOutUchar( EisaIoStart + PIC1_ELCR, 0 ); EisaOutUchar( EisaIoStart + PIC2_ELCR, 0 ); RegOk = TRUE; } return RegOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaClearPendingInts: // // DESCRIPTION: This function cleares any pending interrupt at // the CPU level. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pIntInfo Interrupt info pointer // // RETURN: TRUE all correct // FALSE error // // ASSUMPTIONS: interrupts disabled, PIC lines masked and // all the IRQ lines are edge triggered. // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaClearPendingInts ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo ) { // // initialize variables // UCHAR Irr; // interrupt request register UCHAR Isr; // interrupt service register USHORT Irq; // interrupt level PUCHAR PicPort; // I/O address PRINTDBG("EisaClearPendingInts\n\r"); // DEBUG SUPPORT //-------------------------------------------------- // send a specific EOI for each in service interrupt //-------------------------------------------------- // // read ISR PIC1 // PicPort = EisaIoStart + PIC1; EisaOutUchar( PicPort, OCW3_ISR ); Isr = EisaInUchar( PicPort ); // // send SEOI for each interrupt that was in service // for ( Irq=IRQ0; Isr; Irq++, Isr >>= 1 ) { // // check if this IRQ was in service // if ( !(Isr & 0x1) ) { continue; } // // send a specific and of interrupt // EisaSendSpecificEoi( EisaIoStart, Irq ); } // // read ISR PIC2 // PicPort = EisaIoStart + PIC2; EisaOutUchar( PicPort, OCW3_ISR ); Isr = EisaInUchar( PicPort ); // // send SEOI for each interrupt that was in service // for ( Irq=IRQ8; Isr; Irq++, Isr >>= 1 ) { // // check if this IRQ was in service // if ( !(Isr & 0x1) ) { continue; } // // send a specific and of interrupt // EisaSendSpecificEoi( EisaIoStart, Irq ); } //-------------------------------------------------- // reset all the pending interrupt in the EISA bus //-------------------------------------------------- // // read IRR PIC1 // PicPort = EisaIoStart + PIC1; EisaOutUchar( PicPort, OCW3_IRR ); // don't play with IRQ 0, 1 and 2 Irr = EisaInUchar( PicPort ) & 0xF8; // // clear any PIC1 pending interrupt // for ( Irq=IRQ0; Irr; Irq++, Irr >>= 1 ) { // // check if this IRQ was pending // if ( !(Irr & 0x1) ) { continue; } // // reset the specified IRQ // EisaClearPendingInt( EisaIoStart, pIntInfo, Irq ); } // // read IRR PIC2 // PicPort = EisaIoStart + PIC2; EisaOutUchar( PicPort, OCW3_IRR ); // don't play with IRQ 8 Irr = EisaInUchar( PicPort ) & 0xFE; // // clear any PIC1 pending interrupt // for ( Irq=IRQ8; Irr; Irq++, Irr >>= 1 ) { // // check if this IRQ was pending // if ( !(Irr & 0x1) ) { continue; } // // reset the specifed IRQ // EisaClearPendingInt( EisaIoStart, pIntInfo, Irq ); } //---------------------------------------------------- // error if it is possible to acknowledge an interrupt //---------------------------------------------------- EisaAckInt( pIntInfo ); // // read the ISR // PicPort = EisaIoStart + PIC1; EisaOutUchar( PicPort, OCW3_ISR ); return EisaInUchar( PicPort ) ? FALSE : TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDmaPod: // // DESCRIPTION: This function tests and initializes the DMA for the // specified EISA bus. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaDmaPod ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ) { PRINTDBG("EisaDmaPod\n\r"); // DEBUG SUPPORT // // if ini already done, return status // if ( pDmaInfo->Flags.IniDone ) { return (BOOLEAN)(pDmaInfo->Flags.Error); } pDmaInfo->Flags.Error = 1; // be pessimistic do { // // first part of checkpoint // EisaCheckpointFirstFase( EisaDma ); // // Clear the DMA controllers and disable all the channels. // EisaOutUchar( EisaIoStart + DMA_MASTER_CLR03, 0); EisaOutUchar( EisaIoStart + DMA_COMMAND03, 4); // Set channel 0-3 disable EisaOutUchar( EisaIoStart + DMA_MASTER_CLR47, 0); EisaOutUchar( EisaIoStart + DMA_COMMAND47, 4); // Set channel 4-7 disable // // check mask register // if ( !EisaDmaMaskTest( EisaIoStart, pDmaInfo )); // // check the low and high page // else if ( !EisaDmaPageTest( EisaIoStart, pDmaInfo )); // // check the base/current address register // else if ( !EisaDmaAddressTest( EisaIoStart, pDmaInfo )); // // check the count register // else if ( !EisaDmaCountTest( EisaIoStart, pDmaInfo )); // // check stop register // else if ( !EisaDmaStopTest( EisaIoStart, pDmaInfo )); // // if we got here everything is fine // else { EisaDmaIni( EisaIoStart, pDmaInfo ); pDmaInfo->Flags.Error = 0; } } while ( EisaCheckpointFinalFase( EisaDma, pDmaInfo->Flags.Error ? FALSE : TRUE )); // // return to caller // pDmaInfo->Flags.IniDone = 1; return !(BOOLEAN)(pDmaInfo->Flags.Error); } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDmaMaskTest: // // DESCRIPTION: This function tests the mask register. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: if any error, all DMA channels will be masked. // if no error, all DMA channels will be masked except // for channel 4 which is used to cascade the two DMA // controllers. // // ---------------------------------------------------------------------------- // BOOLEAN EisaDmaMaskTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ) { // // define local variables // UCHAR DmaIndex; // DMA channel within controller ULONG DmaCtrl = 0; // DMA controller PUCHAR Clear, MaskAll, Mask, MaskStatus; // port address BOOLEAN CheckOk = TRUE; // check status PRINTDBG("EisaDmaMaskTest\n\r"); // DEBUG SUPPORT // // one loop per DMA controller // do { // // initialize port values // Clear = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].Clear; MaskAll = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].MaskAll; Mask = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].Mask; MaskStatus = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].MaskStatus; // // test mask clear register // EisaOutUchar( Clear, 0x00 ); if ( EisaInUchar( MaskStatus ) & 0xF ) { CheckOk = FALSE; break; } // // now set all the mask bits // EisaOutUchar( MaskAll, 0x0F ); if ( (EisaInUchar( MaskStatus ) & 0x0F) != 0x0F ) { CheckOk = FALSE; break; } // // now test each single mask bit // for ( DmaIndex=0; DmaIndex < 4; DmaIndex++ ) { // // clear single bit // EisaOutUchar( Mask, DmaIndex ); if ( EisaInUchar( MaskStatus ) & (1 << DmaIndex)) { CheckOk = FALSE; break; } // // set single bit // EisaOutUchar( Mask, 0x04 | DmaIndex ); if ( !(EisaInUchar( MaskStatus ) & (1 << DmaIndex))) { CheckOk = FALSE; break; } } } while( CheckOk && !DmaCtrl++ ); // // return check status // EisaOutUchar( EisaIoStart + DMA_MASKS03, 0x0F ); EisaOutUchar( EisaIoStart + DMA_MASKS47, CheckOk ? 0x0E : 0x0F ); return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDmaPageTest: // // DESCRIPTION: This function tests the low and high pages. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: The low and high page registers will be left in // the power-on state of 0x00. // // ---------------------------------------------------------------------------- // BOOLEAN EisaDmaPageTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ) { // // define local variables // ULONG DmaChannel; // # of DMA channel PUCHAR Port1, Port2; // general I/O ports BOOLEAN CheckOk = TRUE; // check status PRINTDBG("EisaDmaPageTest\n\r"); // DEBUG SUPPORT // // one loop per DMA channel // for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ ) { Port1 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].LowPage; Port2 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].HighPage; // // check high page address // if ( DmaChannel != 4 ) { EisaOutUchar( Port2, 0xFF ); if ( !EisaCheckReg( Port2, 0xFF ) ) { // // error // CheckOk = FALSE; break; } } // // check low page register // EisaOutUchar( Port1, 0x00 ); if ( !EisaCheckReg( Port1, 0xFF ) ) { // // error // CheckOk = FALSE; break; } // // check if high reg has been cleared writing to low reg // if ( DmaChannel != 4 && EisaInUchar( Port2 ) != 0 ) { // // error // CheckOk = FALSE; break; } } // // return check status // return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDmaAddressTest: // // DESCRIPTION: This function tests the address register. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: The address registers will be left in the power-on // state of 0x0000. // // ---------------------------------------------------------------------------- // BOOLEAN EisaDmaAddressTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ) { // // define local variables // ULONG DmaChannel; // # of DMA channel PUCHAR Port1, Port2; // general I/O ports BOOLEAN CheckOk = TRUE; // check status PRINTDBG("EisaDmaAddressTest\n\r"); // DEBUG SUPPORT // // reset the internal DMA pointers // EisaOutUchar( EisaIoStart + DMA_FF_CLR03, 0x00 ); EisaOutUchar( EisaIoStart + DMA_FF_CLR47, 0x00 ); // // one loop per DMA channel // for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ ) { // // load high and address register addresses // Port1 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].Address; Port2 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].HighPage; // // write a value different from zero in high page // if ( DmaChannel != 4 ) { EisaOutUchar( Port2, 0xFF ); } // // check word register using one 8 bit port // if ( !EisaCheckDeepReg( Port1 ) ) { // // error // CheckOk = FALSE; break; } // // initialize register // EisaOutUchar( Port1, 0x00 ); EisaOutUchar( Port1, 0x00 ); // // check if high reg has been cleared writing to low reg // if ( DmaChannel != 4 && EisaInUchar( Port2 ) != 0 ) { // // error // CheckOk = FALSE; break; } } // // return check status // return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDmaCountTest: // // DESCRIPTION: This function tests the count register. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: The count registers will be left in the power-on // state of 0x00 (high) and 0xFFFF (low). // // ---------------------------------------------------------------------------- // BOOLEAN EisaDmaCountTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ) { // // define local variables // ULONG DmaChannel; // # of DMA channel PUCHAR Port1, Port2; // general I/O ports BOOLEAN CheckOk = TRUE; // check status PRINTDBG("EisaDmaCountTest\n\r"); // DEBUG SUPPORT // // reset the internal DMA pointers // EisaOutUchar( EisaIoStart + DMA_FF_CLR03, 0x00 ); EisaOutUchar( EisaIoStart + DMA_FF_CLR47, 0x00 ); // // one loop per DMA channel // for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ ) { // // load high and address register addresses // Port1 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].LowCount; Port2 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].HighCount; // // check high count register // if ( DmaChannel != 4 ) { EisaOutUchar( Port2, 0xFF ); if ( !EisaCheckReg( Port2, 0xFF ) ) { // // error // CheckOk = FALSE; break; } } // // check word register using one 8 bit port // if ( !EisaCheckDeepReg( Port1 ) ) { // // error // CheckOk = FALSE; break; } // // initialize register // EisaOutUchar( Port1, 0xFF ); EisaOutUchar( Port1, 0xFF ); // // check if high reg has been cleared writing to low reg // if ( DmaChannel != 4 && EisaInUchar( Port2 ) != 0 ) { // // error // CheckOk = FALSE; break; } } // // return check status // return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDmaStopTest: // // DESCRIPTION: This function tests the stop register. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: The count registers will be left in the power-on // state of 0xFFFFFC. // // ---------------------------------------------------------------------------- // BOOLEAN EisaDmaStopTest ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ) { // // define local variables // ULONG DmaChannel; // # of DMA channel PUCHAR Stop; // general I/O ports BOOLEAN CheckOk = TRUE; // check status PRINTDBG("EisaDmaStopTest\n\r"); // DEBUG SUPPORT // // one loop per DMA channel // for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ ) { Stop = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].Stop; // // check high page address // if ( DmaChannel != 4 ) { // // initialize stop registers and test them // EisaOutUchar( Stop, 0x00 ); EisaOutUchar( Stop+1, 0x00 ); EisaOutUchar( Stop+2, 0x00 ); if ( !EisaCheckReg( Stop, 0xFC ) || !EisaCheckReg( Stop+1, 0xFF ) || !EisaCheckReg( Stop+2, 0xFF ) ) { // // error // CheckOk = FALSE; break; } } } // // return check status // return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDmaIni: // // DESCRIPTION: This function initializes the DMA controllers of // the specified EISA bus. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaDmaIni ( IN PUCHAR EisaIoStart, IN PEISA_DMA_INFO pDmaInfo ) { // // define local variables // ULONG Index; // general index ULONG DmaCtrl = 0; // DMA controller UCHAR Reg = 0; // DMA command Register PUCHAR Port; // general port PRINTDBG("EisaDmaIni\n\r"); // DEBUG SUPPORT //----------------------------------------------------------------- // // set command registers for fixed priotiry, DREQ active high, // DACK# active low and channels enabled // EisaOutUchar( EisaIoStart + DMA_COMMAND03, Reg ); EisaOutUchar( EisaIoStart + DMA_COMMAND47, Reg ); //----------------------------------------------------------------- // // initialize mode register for channel 4. The other channels will // be initializated during the EisaRequestDmaTransfer functions. // EisaOutUchar( EisaIoStart + DMA_MODE47, 0xC0 ); //----------------------------------------------------------------- // // disable the chaining mode // do { // // load the controller port address // Port = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].Chain; // // disable chaining mode // for ( Index = 0; Index < 4 ; Index++ ) { EisaOutUchar( Port, 0x00 ); } } while( !DmaCtrl++ ); //----------------------------------------------------------------- // // initialize DMA structures // for ( Index = 0; Index < EISA_DMAS; Index++ ) { pDmaInfo->DmaFlags[ Index ].Busy = 0; pDmaInfo->DmaFlags[ Index ].Tc = 0; // stop enabled, T-C output, ISA compatible, // 8 bit I/O byte count and DMA channel // (see DMA configuration). pDmaInfo->DmaExtReg[ Index ] = Index < 4 ? Index : Index - 4; } // // all done // return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaOtherPod: // // DESCRIPTION: This function tests and initializes all the general // ports of the EISA bus. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pPortInfo port info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaOtherPod ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ) { // // define local variables // BOOLEAN ChkOk; PRINTDBG("EisaOtherPod\n\r"); // DEBUG SUPPORT // // if ini already done, return status // if ( pPortInfo->Flags.IniDone ) { return (BOOLEAN)(pPortInfo->Flags.Error); } pPortInfo->Flags.Error = 0; // // check and initialize NMI // do { EisaCheckpointFirstFase( EisaNmi ); if ( !( ChkOk = EisaNmiTest( EisaIoStart, pPortInfo ))) { pPortInfo->Flags.Error = 1; } } while ( EisaCheckpointFinalFase( EisaNmi, ChkOk )); // // check and initialize refresh // do { EisaCheckpointFirstFase( EisaRefresh ); if ( !( ChkOk = EisaRefreshTest( EisaIoStart, pPortInfo ))) { pPortInfo->Flags.Error = 1; } } while ( EisaCheckpointFinalFase( EisaRefresh, ChkOk )); // // check and initialize port 61 // do { EisaCheckpointFirstFase( EisaPort61 ); if ( !( ChkOk = EisaPort61Test( EisaIoStart, pPortInfo ))) { pPortInfo->Flags.Error = 1; } } while ( EisaCheckpointFinalFase( EisaPort61, ChkOk )); // // check and initialize timer1 // do { EisaCheckpointFirstFase( EisaTimer1 ); if ( !( ChkOk = EisaTimer1Test( EisaIoStart, pPortInfo ))) { pPortInfo->Flags.Error = 1; } } while ( EisaCheckpointFinalFase( EisaTimer1, ChkOk )); // // check and initialize timer2 // do { EisaCheckpointFirstFase( EisaTimer2 ); if ( !( ChkOk = EisaTimer2Test( EisaIoStart, pPortInfo ))) { pPortInfo->Flags.Error = 1; } } while ( EisaCheckpointFinalFase( EisaTimer2, ChkOk )); // // return check status // pPortInfo->Flags.IniDone = 1; return !(BOOLEAN)(pPortInfo->Flags.Error); } // ---------------------------------------------------------------------------- // PROCEDURE: EisaNmiTest: // // DESCRIPTION: This function tests and initializes the EISA NMI. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pPortInfo port info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: EisaNmiFlag // // NOTES: if any error, the NMI will be disabled (real-time clock) // if no error, the NMI will be left enabled but with all // the NMI sources disabled. // // ---------------------------------------------------------------------------- // BOOLEAN EisaNmiTest ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ) { PRINTDBG("EisaNmiTest\n\r"); // DEBUG SUPPORT // NOTE: NMI test is disabled for JAZZ. #if 0 // // install an NMI interrupt handler // EisaNmiFlag = FALSE; FwInstallIntVector( EISA_NMI_VECTOR, EisaNmiHandlerTest ); //---------------------------------------------------------------- // // disable all the NMI sources // (using the extended NMI status and contrl port and system control port B) // EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, 0x00 ); // // note that the following operation clears any pending parity or I/O check // errors. // EisaDisableParityIoCheck( EisaIoStart ); EisaEnableNmi( EisaIoStart ); // // ... wait. // ArcEisaStallProcessor( EISA_WAIT_NMI_TEST ); EisaDisableNmi( EisaIoStart ); // // return error if an hot EISA NMI // if ( EisaNmiFlag ) { return FALSE; } //---------------------------------------------------------------- // // enable all the NMI sources used by the fw // EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, EISA_ENABLE_NMI_32 ); EisaEnableParityIoCheck( EisaIoStart ); EisaEnableNmi( EisaIoStart ); // // ... wait // ArcEisaStallProcessor( EISA_WAIT_NMI_TEST ); EisaDisableNmi( EisaIoStart ); // // return error if an hot EISA NMI // if ( EisaNmiFlag ) { return FALSE; } //---------------------------------------------------------------- // // enable NMI I/O port and NMI; and force one to come // EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, EISA_ENABLE_NMI_IO ); EisaEnableNmi( EisaIoStart ); EisaOutUchar( EisaIoStart + EISA_SW_NMI_PORT, 0x00 ); // // ... wait // ArcEisaStallProcessor( EISA_WAIT_NMI_TEST ); EisaDisableNmi( EisaIoStart ); // // return an error if not NMI // if ( !EisaNmiFlag ) { return FALSE; } // // enable the NMI and all the NMI sources used by fw // ( the software NMI will be disabled ) // FwInstallIntVector( EISA_NMI_VECTOR, EisaNmiHandler ); EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, EISA_ENABLE_NMI_32 ); EisaEnableNmi( EisaIoStart ); // // return // #endif // 0 return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaNmiHandlerTest: // // DESCRIPTION: This function is the NMI handler during the NMI test. // // ARGUMENTS: Cause R4000 cause register // // RETURN: TRUE interrupt recognized // // ASSUMPTIONS: // // CALLS: // // GLOBALS: EisaNmi // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaNmiHandlerTest ( IN ULONG Couse ) { PRINTDBG("EisaNmiHandlerTest\n\r"); // DEBUG SUPPORT StatusReg( ~STATUS_EISA_NMI, (ULONG)0 ); EisaNmiFlag = TRUE; return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaNmiHandler: // // DESCRIPTION: This function handles the EISA NMI. // An NMI can be caused by : // // 1) System/Adapter board memory parity error // ( port 61h bit 7 set ) // 2) Adapter I/O channel check error // ( port 61h bit 6 set ) // 3) Fail-Safe Timer (channle 2 or the interval Timer 2) // ( port 461h bit 7 set ) - NOT CHECKED * // 4) DMA bus timeout error // ( port 461h bit 6 set ) // 5) Write to NMI port 462h // ( port 461h bit 5 set ) - NOT CHECKED * // 6) Coprocessor exception interrupt - NOT CHECKED * // // An error message will be displayed indicating the // cause of the error and the system will halt. // The only allowed operation after an NMI is to reset // the machine. // // * The firmware doesn't enable these NMI sources. // // ARGUMENTS: Cause R4000 cause register // // RETURN: TRUE interrupt recognized // // ASSUMPTIONS: // // CALLS: // // GLOBALS: EisaBusInfo // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaNmiHandler ( IN ULONG Couse ) { // // define local variables // PUCHAR EisaIoStart; // eisa I/O virtual address UCHAR NmiData, ExtNmiData; // NMI status ULONG BusNumber = 0; // eisa bus number ULONG Slots; // # slots BOOLEAN NmiPresent; // NMI source status PRINTDBG("EisaNmiHandler\n\r"); // DEBUG SUPPORT // // disable NMI at CPU level // StatusReg( ~STATUS_EISA_NMI, (ULONG)0 ); // // clear screen and display message // FwClearScreen(); FwPrint(EISA_HOT_NMI_MSG); EisaCheckpointFirstFase( EisaHotNmi ); do { // // print eisa bus number // FwPrint( EISA_BUS_NUMBER_MSG , BusNumber ); // // initialize variables // EisaIoStart = EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr; Slots = EisaBusInfo[ BusNumber ].SlotsInfo->PhysSlots; NmiPresent = FALSE; // // read NMI status // NmiData = EisaInUchar( EisaIoStart + EISA_SYS_CTRL_PORTB ); ExtNmiData = EisaInUchar( EisaIoStart + EISA_SYS_EXT_NMI ); // // check if there is a parity error // if ( NmiData & EISA_PARITY_STATUS ) { EisaParityError( EisaIoStart ); NmiPresent = TRUE; } // // check if there is a I/O channel check // if ( NmiData & EISA_IOCHK_STATUS ) { EisaIoChkError( EisaIoStart, Slots ); NmiPresent = TRUE; } // // check if there is a DMA or bus master timeout error // if ( ExtNmiData & EISA_NMI_32_STATUS ) { if ( ExtNmiData & EISA_NMI_32_CAUSE ) { EisaBusTimeoutError( EisaIoStart, Slots ); } else { EisaSlaveTimeoutError( EisaIoStart, Slots ); } NmiPresent = TRUE; } // // if no NMI for this bus, display "no problem" // if ( !NmiPresent ) { FwPrint(EISA_NMI_NOT_FOUND_MSG); } } while( ++BusNumber < EISA_BUSES ); // // print final message and hang // EisaCheckpointFinalFase( EisaHotNmi, FALSE ); while(1); // just to be sure } // ---------------------------------------------------------------------------- // PROCEDURE: EisaParityError: // // DESCRIPTION: This function displays the error message and // returns to the caller without do any other thing. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaParityError ( IN PUCHAR EisaIoStart ) { PRINTDBG("EisaParityError\n\r"); // DEBUG SUPPORT FwPrint(EISA_PARITY_ERROR_MSG , ASCII_CSI ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaIoChkError: // // DESCRIPTION: This function tries to find the slot in error. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // Slots # slots // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaIoChkError ( IN PUCHAR EisaIoStart, IN ULONG Slots ) { // // define local variabls // ULONG AdapId; // adapter ID PUCHAR ExpCtrl; // expansion board ctrl addr UCHAR CtrlBits; // port value PRINTDBG("EisaIoChkError\n\r"); // DEBUG SUPPORT // // display first message // FwPrint(EISA_IO_CHECK_ERROR_MSG , ASCII_CSI); // // check all slots starting from the last one // while( --Slots ) { // // check if there is an adapter with a readable ID // if ( !EisaReadReadyId( EisaIoStart, Slots, &AdapId ) || AdapId == NO_ADAP_ID ) { continue; } ExpCtrl = EisaIoStart + 0x1000 * Slots + EXPANSION_BOARD_CTRL_BITS; // // test the IOCHKERR bit of the Expansion Board Contrl Bits. // the IOCHKERR bit can be read to determine if an expansion // board has a pending error. The expansion board indicates a // pending error by setting IOCHKERR, clearing the ENABLE bit // and entering the disabled state. // // note: because the EISA expansion boards are not required to // support this port, we need the following simple // assumption: this I/O port is not supported if the value // read from it is 0xFF. // if ((CtrlBits = EisaInUchar( ExpCtrl )) != 0xFF ) { if ( CtrlBits & EISA_IOCHKERR ) { break; } } } // // print final message // if ( !Slots ) { FwPrint( EISA_IO_CHECK_NOT_SUP_MSG ); // slot not found } else { FwPrint(EISA_IN_SLOT_MSG , Slots ); // slot in error } // // all done, exit // return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaBusTimeoutError: // // DESCRIPTION: This function displays the bus master number in error. // If a 32-bit bus master tries to hold the bus beyond // the BUS limit (8 usec if BCLK = 8 MHz), the ISP will // assert the NMI and RSTDRV signals togheter. // The RSTDRV signal will remain aserted until the NMI has // been reset by plsing bit 3 of I/O port 461h. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // Slots # slots // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaBusTimeoutError ( IN PUCHAR EisaIoStart, IN ULONG Slots ) { // // define local variables // UCHAR Status; // 32-bit bus master status ULONG BusMaster = 0; // bus master number in error PUCHAR ExtNmi; // extended NMI control PRINTDBG("EisaBusTimeoutError\n\r"); // DEBUG SUPPORT // // find the bus master group in error // if ( ~(Status = EisaInUchar(EisaIoStart+EISA_BUSMASTER_LSTATUS)) & 0xFF ) { BusMaster = 1; } else if ( ~(Status = (EisaInUchar(EisaIoStart+EISA_BUSMASTER_HSTATUS) | 0x80)) & 0xFF ) { BusMaster = 9; } // // find the bus master number in error and display it // FwPrint( EISA_BUS_MASTER_MSG, ASCII_CSI ); if ( BusMaster ) { for (; Status & 1; Status >>= 1, BusMaster++ ); FwPrint(EISA_TIMEOUT_MSG , BusMaster ); } else { FwPrint(EISA_TIMEOUT2_MSG ); // bus master not found } // // reset NMI // ExtNmi = EisaIoStart + EISA_SYS_EXT_NMI; EisaOutUchar( ExtNmi, EisaInUchar( ExtNmi ) & ~EISA_ENABLE_NMI_32 ); // // all done // return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaSlaveTimeoutError: // // DESCRIPTION: This function displays an error message. // If a memory slave extends a cycle long enough that // CMD# is active for more than 256 BCLKs (32usec if // BCLK = 8MHz), the ISP will assert the NMI and RSTDRV // signals togheter. // The RSTDRV signal will remain aserted until the NMI has // been reset by plsing bit 3 of I/O port 461h. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // Slots # slots // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaSlaveTimeoutError ( IN PUCHAR EisaIoStart, IN ULONG Slots ) { // // define local variables // PUCHAR ExtNmi; // extended NMI control PRINTDBG("EisaSlaveTimeoutError\n\r"); // DEBUG SUPPORT // // display the error message // FwPrint(EISA_SLAVE_TIMEOUT_MSG , ASCII_CSI ); // // reset NMI // ExtNmi = EisaIoStart + EISA_SYS_EXT_NMI; EisaOutUchar( ExtNmi, EisaInUchar( ExtNmi ) & ~EISA_ENABLE_NMI_32 ); // // all done // return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaRefreshTest: // // DESCRIPTION: This function tests and initializes the EISA refresh. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pPortInfo port info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: the refresh will be left enabled. // // ---------------------------------------------------------------------------- // BOOLEAN EisaRefreshTest ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ) { // // define local variables // BOOLEAN CheckOk = FALSE; // checking status ULONG Retry; // # retry PUCHAR Port; // general I/O port PRINTDBG("EisaRefreshTest\n\r"); // DEBUG SUPPORT // // clear refresh pages // EisaOutUchar( EisaIoStart + DMA_PAGE_RFR, 0x00 ); EisaOutUchar( EisaIoStart + DMA_HPAGE_RFR, 0x00 ); // // start timer 1, counter 1 // EisaOutUchar( EisaIoStart + EISA_TIMER1_CTRL, 0x54 ); EisaOutUchar( EisaIoStart + EISA_TIMER1_COUNTER1, EISA_RFR_COUNT ); // // check if refresh bit in the system control port B is toggling // Port = EisaIoStart + EISA_SYS_CTRL_PORTB; for ( CheckOk = FALSE, Retry = EISA_RFR_RETRY; Retry; Retry-- ) { // // check if refresh bit is set // if ( READ_REGISTER_UCHAR( Port ) & EISA_REFRESH ) { // // yes, exit loop // CheckOk = TRUE; break; } } // // if time-out, exit with error // if ( !Retry ) { return FALSE; } // // check if refresh bit in the system control port B is toggling // for ( CheckOk = FALSE, Retry = EISA_RFR_RETRY; Retry; Retry-- ) { // // check if refresh bit is cleared // if ( !(READ_REGISTER_UCHAR( Port ) & EISA_REFRESH) ) { // // yes, exit loop // CheckOk = TRUE; break; } } // // return check status // return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaPort61Test: // // DESCRIPTION: This function tests and initializes the system // control port B. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pPortInfo port info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: NMI has already been tested. // // CALLS: // // GLOBALS: // // NOTES: The parity and the I/O channel check, The speaker gate // and speaker timer will be left disabled. // // ---------------------------------------------------------------------------- // BOOLEAN EisaPort61Test ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ) { // // define local variables // PUCHAR Port; // genearl I/O port BOOLEAN CheckOk = TRUE; // check status PRINTDBG("EisaPort61Test\n\r"); // DEBUG SUPPORT Port = EisaIoStart + EISA_SYS_CTRL_PORTB; // // gate signal for speaker timer // EisaOutUchar( Port, EISA_SPEAKER_GATE ); if ( (EisaInUchar( Port ) & 0x0F) != EISA_SPEAKER_GATE ) { CheckOk = FALSE; } // // speaker timer contrl // if ( CheckOk ) { EisaOutUchar( Port, EISA_SPEAKER_TIMER); if ( (EisaInUchar( Port ) & 0x0F) != EISA_SPEAKER_TIMER ) { CheckOk = FALSE; } } // // parity bit // if ( CheckOk ) { EisaOutUchar( Port, EISA_PARITY_OFF); if ( (EisaInUchar( Port ) & 0x0F) != EISA_PARITY_OFF ) { CheckOk = FALSE; } } // // I/O channel check // if ( CheckOk ) { EisaOutUchar( Port, EISA_IOCHK_OFF ); if ( (EisaInUchar( Port ) & 0x0F) != EISA_IOCHK_OFF ) { CheckOk = FALSE; } } // // initialize port 61h. // EisaOutUchar( Port, 0x00 ); // // return check status // return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaTimer1Test: // // DESCRIPTION: This function tests only the counter 2 of // timer 1 (speaker). // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pPortInfo port info pointer // // RETURN: TRUE All done // FALSE Error // // ASSUMPTIONS: NMI has already been tested. // // CALLS: // // GLOBALS: // // NOTES: The functions stops timer1 counter0, turns off the // timer1 counter2 gate and disable the speaker output. // // ---------------------------------------------------------------------------- // BOOLEAN EisaTimer1Test ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ) { // // define local variables // BOOLEAN CheckOk = FALSE; // check status PUCHAR Ctrl, Port, Port61; // genearl I/O ports PRINTDBG("EisaTimer1Test\n\r"); // DEBUG SUPPORT // // initialize variables // Ctrl = EisaIoStart + EISA_TIMER1_CTRL; Port = EisaIoStart + EISA_TIMER1_COUNTER2; Port61 = EisaIoStart + EISA_SYS_CTRL_PORTB; // // disable timer1 counter2 gate, speaker output // EisaOutUchar( Port61, 0x00 ); // // program timer 1, counter 2 (speaker) in 16-bit count, mode 0 // EisaOutUchar( Ctrl, 0xB0 ); EisaOutUchar( Port, 0x00 ); EisaOutUchar( Port, 0x80 ); // // check register // if ( !(EisaCheckDeepReg( Port ))); // // check speaker output. It must be low otherwise there is an error // else if ( EisaInUchar( Port61 ) & EISA_SPEAKER_OUT ); // // enable speaker gate to enable the counter, wait for some time and // check if speaker output is high, if not error out // else { // // enable speaker gate // EisaOutUchar( Port61, EISA_SPEAKER_GATE ); // // wait 40msec = ~ ( 0x8000 / 1.193 Mhz ) + something // // NOTE: Wait longer for JAZZ. // ArcEisaStallProcessor( 40 * 1000 ); ArcEisaStallProcessor( 160 * 1000 ); // // check speaker output // if ( EisaInUchar( Port61 ) & EISA_SPEAKER_OUT ) { // // initialize timer1 counter2 in 16-bit , mode 3 // // EisaOutUchar( Ctrl, 0xB6 ); // EisaOutUchar( Port, // (UCHAR)( EISA_SPEAKER_CLOCK/EISA_SPEAKER_FREQ )); // EisaOutUchar( Port, // (UCHAR)( (EISA_SPEAKER_CLOCK/EISA_SPEAKER_FREQ) >> 8 )); // // all done // CheckOk = TRUE; } } // // disable speaker gate, speaker output // EisaOutUchar( Port61, 0x00 ); // // stop timer1 counter0 sending the control word without the count value // EisaOutUchar( Ctrl, 0x30 ); // // all done, exit // return CheckOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaTimer2Test: // // DESCRIPTION: This function stops the timer2 counter0 (Fail-safe). // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pPortInfo port info pointer // // RETURN: TRUE All done // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaTimer2Test ( IN PUCHAR EisaIoStart, IN PEISA_PORT_INFO pPortInfo ) { PRINTDBG("EisaTimer2Test\n\r"); // DEBUG SUPPORT // // stop timer2 counter0 sending the control word without the count value // EisaOutUchar( EisaIoStart + EISA_TIMER2_CTRL, 0x30 ); // // all done, exit // return TRUE; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaClearPendingInt: // // DESCRIPTION: This function cleares the specified pending interrupt. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pIntInfo interrupt info pointer // Irq IRQ to reset // // RETURN: none // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaClearPendingInt ( IN PUCHAR EisaIoStart, IN PEISA_INT_INFO pIntInfo, IN USHORT Irq ) { // // define local variables // PUCHAR PicMask1, PicMask2; // I/O port address PRINTDBG("EisaClearPendingInt\n\r"); // DEBUG SUPPORT // // initialize variables // PicMask1 = EisaIoStart + PIC1_MASK; PicMask2 = EisaIoStart + PIC2_MASK; // // unmask the specified IRQ // if ( Irq > IRQ7 ) { EisaOutUchar( PicMask1, (UCHAR)(~(1 << IRQ2))); EisaOutUchar( PicMask2, (UCHAR)(~(1 << (Irq % 8)))); } else { EisaOutUchar( PicMask1, (UCHAR)(~(1 << Irq ))); } // // acknowledge the interrupt // EisaAckInt( pIntInfo ); // // mask off all the IRQ lines // EisaOutUchar( PicMask1, 0xFF ); EisaOutUchar( PicMask2, 0xFF ); // // and send a specific EOF // EisaSendSpecificEoi( EisaIoStart, Irq ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaIntAck: // // DESCRIPTION: This function acknowledges the highest priority // interrupt. // // ARGUMENTS: pIntInfo interrupt info pointer (not used) // // RETURN: Int interrupt acknowledged. // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // UCHAR EisaAckInt ( IN PEISA_INT_INFO pIntInfo ) { UCHAR Int; PRINTDBG("EisaAckInt\n\r"); // DEBUG SUPPORT Int = READ_REGISTER_UCHAR( EISA_INT_ACK_ADDR ); EISA_IO_DELAY; return Int; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaSendSpecificEoi: // // DESCRIPTION: This function sends a specific EOI to the spcified // IRQ line. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // Irq IRQ to reset // // RETURN: none // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaSendSpecificEoi ( IN PUCHAR EisaIoStart, IN USHORT Irq ) { // // define local variables // PUCHAR PicPort1, PicPort2; PRINTDBG("EisaSendSpecificEoi\n\r"); // DEBUG SUPPORT // // initialize local variables // PicPort1 = EisaIoStart + PIC1; PicPort2 = EisaIoStart + PIC2; // // send a specific EOI // if ( Irq > IRQ7 ) { EisaOutUchar( PicPort2, OCW2_SEOI | ( Irq % 8 )); EisaOutUchar( PicPort1, OCW2_SEOI | IRQ2 ); } else { EisaOutUchar( PicPort1, OCW2_SEOI | Irq ); } return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDisableParityIoCheck: // // DESCRIPTION: This function disables the partiy and I/O check NMIs. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // // RETURN: none // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaDisableParityIoCheck ( IN PUCHAR EisaIoStart ) { PRINTDBG("EisaDisableParityIoCheck\n\r"); // DEBUG SUPPORT EisaOutUchar( EisaIoStart + EISA_SYS_CTRL_PORTB, ( EisaInUchar( EisaIoStart + EISA_SYS_CTRL_PORTB ) | EISA_PARITY_OFF | EISA_IOCHK_OFF ) & 0x0F ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaEnableParityIoCheck: // // DESCRIPTION: This function enables the partiy and I/O check NMIs. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // // RETURN: none // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaEnableParityIoCheck ( IN PUCHAR EisaIoStart ) { PRINTDBG("EisaEnableParityIoCheck\n\r"); // DEBUG SUPPORT EisaOutUchar( EisaIoStart + EISA_SYS_CTRL_PORTB, ( EisaInUchar( EisaIoStart + EISA_SYS_CTRL_PORTB ) & ~(EISA_PARITY_OFF | EISA_IOCHK_OFF)) & 0x0F ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDisableInt: // // DESCRIPTION: The function disables the EISA interrupts at CPU // level. // // ARGUMENTS: none // // RETURN: none // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaDisableInt ( VOID ) { PRINTDBG("EisaDisableInt\n\r"); // DEBUG SUPPORT StatusReg( ~STATUS_EISA, (ULONG)0 ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaDisableNmi: // // DESCRIPTION: The function disables the NMI using the real-time // clock port. // // ARGUMENTS: none // // RETURN: none // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaDisableNmi ( IN PUCHAR EisaIoStart ) { PRINTDBG("EisaDisableNmi\n\r"); // DEBUG SUPPORT // // at real-time clock address port // EisaOutUchar(EisaIoStart+EISA_RTC_CTRL, EISA_DISABLE_NMI+RTC_C_REG); READ_REGISTER_UCHAR( RTC_VIRTUAL_BASE ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaEnableNmi: // // DESCRIPTION: The function enables the NMI line. // The following ports are used : // // . real-time clock ctrl port // . CPU status register port // // ARGUMENTS: none // // RETURN: none // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaEnableNmi ( IN PUCHAR EisaIoStart ) { PRINTDBG("EisaEnableNmi\n\r"); // DEBUG SUPPORT // // at real-time clock address port // EisaReadRtc( EisaIoStart, RTC_C_REG ); // NOTE: this code has been removed because of a R4000 CPU bug. // // // // // at interrupt enable register // // // // EisaBeginCriticalSection(); // WRITE_REGISTER_UCHAR(INT_ENABLE_ADDR, READ_REGISTER_UCHAR(INT_ENABLE_ADDR) | 0x08); // EisaEndCriticalSection(); // // // at CPU level // StatusReg( (ULONG)-1, STATUS_EISA_NMI + STATUS_IE ); return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaCheckReg: // // DESCRIPTION: This function performs read/write test on an 8 bit // I/O port using the following patterns: FFh, AAh, 55h // and 00h. The original part value is restored before // returning. // // ARGUMENTS: Port port address // DataMask mask for test pattern to compare with // data // // RETURN: TRUE test completed successfully // FALSE error // // ASSUMPTIONS: none // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaCheckReg ( IN PUCHAR Port, IN UCHAR DataMask ) { // // define local variables // BOOLEAN CompOk = TRUE; UCHAR Save, Program; PRINTDBG("EisaCheckReg\n\r"); // DEBUG SUPPORT // // save original value // Save = EisaInUchar( Port ); // // one loop per each value // for ( Program = 0; ; Program += 0x55 ) { // // write port, read it back and compare values // EisaOutUchar( Port, Program ); if ((EisaInUchar( Port ) & DataMask) != (Program & DataMask)) { // // error, value are not the same // CompOk = FALSE; break; } // // exit loop if last value // if ( Program == 0xFF ) { break; } } // // restore original value before returning // EisaOutUchar( Port, Save ); return CompOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaCheckDeepReg: // // DESCRIPTION: This function checks the 2x8bit registers. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // pDmaInfo DMA info pointer // // RETURN: TRUE check completed successfully // FALSE error // // ASSUMPTIONS: The internal pointer has already been resetted. // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // BOOLEAN EisaCheckDeepReg ( IN PUCHAR Port ) { // // define local variables // UCHAR LSave, HSave, Program, LCheck, HCheck; BOOLEAN CompOk = TRUE; PRINTDBG("EisaCheckDeepReg\n\r"); // DEBUG SUPPORT // // save original value // LSave = EisaInUchar( Port ); HSave = EisaInUchar( Port ); // // one loop per each value // for ( Program = 0; ; Program += 0x55 ) { // // write port and read it back // EisaOutUchar( Port, Program ); EisaOutUchar( Port, Program ); EISA_IO_DELAY; // EISA_IO_DELAY; // for the timer chip EISA_IO_DELAY; // LCheck = EisaInUchar( Port ); HCheck = EisaInUchar( Port ); // // check the read values // if ( LCheck != Program || HCheck != Program ) { // // error, value are not the same // CompOk = FALSE; break; } // // exit loop if last value // if ( Program == 0xFF ) { break; } } // // restore the original value // EisaOutUchar( Port, LSave ); EisaOutUchar( Port, HSave ); return CompOk; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaReadRtc: // // DESCRIPTION: This function returns the value of the specified // real-time clock internal address. // // ARGUMENTS: EisaIoStart EISA I/O virtual address // RtcIndex index within the RTC // // RETURN: Value register value // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // UCHAR EisaReadRtc ( IN PUCHAR EisaIoStart, IN ULONG RtcIndex ) { UCHAR Value; PRINTDBG("EisaReadRtc\n\r"); // DEBUG SUPPORT // NOTE: CriticalSection is not supported on JAZZ. // EisaBeginCriticalSection(); EisaOutUchar( EisaIoStart + EISA_RTC_CTRL, RtcIndex ); Value = READ_REGISTER_UCHAR( RTC_VIRTUAL_BASE ); // EisaEndCriticalSection(); return Value; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaOutUchar: // // DESCRIPTION: This function writes an uchar within the EISA I/O // space and delays before returning. // // ARGUMENTS: Addr Address where the value has to be // write to. // Value Value to write // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // VOID EisaOutUchar ( IN PUCHAR Addr, IN UCHAR Value ) { // PRINTDBG("EisaOutUchar\n\r"); // DEBUG SUPPORT WRITE_REGISTER_UCHAR( Addr, Value ); EISA_IO_DELAY; return; } // ---------------------------------------------------------------------------- // PROCEDURE: EisaInUchar: // // DESCRIPTION: This function reads an uchar from the EISA I/O // space and delays before returning. // // ARGUMENTS: Addr Address where the value has to be // read from. // // RETURN: none // // ASSUMPTIONS: // // CALLS: // // GLOBALS: // // NOTES: // // ---------------------------------------------------------------------------- // UCHAR EisaInUchar ( IN PUCHAR Addr ) { UCHAR Value; // PRINTDBG("EisaInUchar\n\r"); // DEBUG SUPPORT Value = READ_REGISTER_UCHAR( Addr ); EISA_IO_DELAY; return Value; }