292 lines
7.3 KiB
C
292 lines
7.3 KiB
C
/*
|
|
* OPTIVIP.C - OPTi Viper-M PCI chipset routines.
|
|
*
|
|
* Notes:
|
|
* Algorithms from OPTi Viper-M 82C556M/82C557M/82C558M doc,
|
|
* 82C558M spec.
|
|
*
|
|
*/
|
|
|
|
#include "local.h"
|
|
|
|
// IRQ = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
|
const UCHAR rgbIRQToBig[16] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 4, 5, 0, 6, 7 };
|
|
const UCHAR rgbIRQToSmall[16] = { 0, 0, 0, 1, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
const UCHAR rgbBigToIRQ[8] = { 0, 5, 9, 10, 11, 12, 14, 15 };
|
|
const UCHAR rgbSmallToIRQ[8] = { 0, 3, 4, 7 };
|
|
|
|
/****************************************************************************
|
|
*
|
|
* OptiViperSetIRQ - Set a OptiViper PCI link to a specific IRQ
|
|
*
|
|
* Exported.
|
|
*
|
|
* ENTRY: bIRQNumber is the new IRQ to be used.
|
|
*
|
|
* bLink is the Link to be set.
|
|
*
|
|
* EXIT: Standard PCIMP return value.
|
|
*
|
|
***************************************************************************/
|
|
PCIMPRET CDECL
|
|
OptiViperSetIRQ(UCHAR bIRQNumber, UCHAR bLink)
|
|
{
|
|
ULONG ulIRQRegister;
|
|
|
|
//
|
|
// If not an OPTi IRQ, bail.
|
|
//
|
|
if (bIRQNumber && (!rgbIRQToBig[bIRQNumber] &&
|
|
!rgbIRQToSmall[bIRQNumber]))
|
|
{
|
|
return(PCIMP_INVALID_IRQ);
|
|
}
|
|
|
|
//
|
|
// Make link number 0 based, and validate.
|
|
//
|
|
bLink--;
|
|
if (bLink > 3) {
|
|
|
|
return(PCIMP_INVALID_LINK);
|
|
}
|
|
|
|
//
|
|
// Read in the big IRQ Register,
|
|
// clear the old IRQ index for the link,
|
|
// set the new IRQ index,
|
|
// and write it back.
|
|
//
|
|
ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40);
|
|
ulIRQRegister &= ~(0x7 << (3 * bLink));
|
|
ulIRQRegister |= rgbIRQToBig[bIRQNumber] << (3 * bLink);
|
|
WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x40, ulIRQRegister);
|
|
|
|
//
|
|
// Read in the small IRQ register,
|
|
// clear the old IRQ index for the link,
|
|
// set the new IRQ index,
|
|
// and write it back.
|
|
//
|
|
ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50);
|
|
ulIRQRegister &= ~(0x3 << (2 * bLink));
|
|
ulIRQRegister |= rgbIRQToSmall[bIRQNumber] << (2 * bLink);
|
|
WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x50, ulIRQRegister);
|
|
|
|
return(PCIMP_SUCCESS);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* OptiViperGetIRQ - Get the IRQ of a OptiViper PCI link
|
|
*
|
|
* Exported.
|
|
*
|
|
* ENTRY: pbIRQNumber is the buffer to fill.
|
|
*
|
|
* bLink is the Link to be read.
|
|
*
|
|
* EXIT: Standard PCIMP return value.
|
|
*
|
|
***************************************************************************/
|
|
PCIMPRET CDECL
|
|
OptiViperGetIRQ(PUCHAR pbIRQNumber, UCHAR bLink)
|
|
{
|
|
ULONG ulIRQRegister;
|
|
ULONG ulIndex;
|
|
|
|
//
|
|
// Make link number 0 based, and validate.
|
|
//
|
|
bLink--;
|
|
if (bLink > 3) {
|
|
|
|
return(PCIMP_INVALID_LINK);
|
|
}
|
|
|
|
//
|
|
// Read in the big IRQ Register.
|
|
//
|
|
ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40);
|
|
|
|
//
|
|
// If we have a big IRQ, we're done.
|
|
//
|
|
ulIndex = (ulIRQRegister >> (bLink * 3)) & 0x7;
|
|
if ((*pbIRQNumber = rgbBigToIRQ[ulIndex]) != 0)
|
|
{
|
|
return(PCIMP_SUCCESS);
|
|
}
|
|
|
|
//
|
|
// Read in the small IRQ register.
|
|
//
|
|
ulIRQRegister=ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50);
|
|
|
|
//
|
|
// Set the buffer to the small IRQ's value.
|
|
//
|
|
ulIndex = (ulIRQRegister >> (bLink * 2)) & 0x3;
|
|
*pbIRQNumber = rgbSmallToIRQ[ulIndex];
|
|
|
|
return(PCIMP_SUCCESS);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* OptiViperSetTrigger - Set the IRQ triggering values for the OptiViper
|
|
*
|
|
* Exported.
|
|
*
|
|
* ENTRY: ulTrigger has bits set for Level triggered IRQs.
|
|
*
|
|
* EXIT: Standard PCIMP return value.
|
|
*
|
|
***************************************************************************/
|
|
PCIMPRET CDECL
|
|
OptiViperSetTrigger(ULONG ulTrigger)
|
|
{
|
|
ULONG ulBigIRQRegister;
|
|
ULONG ulSmallIRQRegister;
|
|
ULONG i;
|
|
|
|
//
|
|
// Read in the big & small IRQ registers,
|
|
// setting all IRQs to edge.
|
|
//
|
|
ulBigIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40) & ~0x00FE0000;
|
|
ulSmallIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50) & ~0x00000700;
|
|
|
|
//
|
|
// For each IRQ...
|
|
//
|
|
for (i=0; i<16; i++)
|
|
{
|
|
//
|
|
// If we want this to be level triggered...
|
|
//
|
|
if (ulTrigger & (1 << i))
|
|
{
|
|
|
|
if (rgbIRQToBig[i])
|
|
{
|
|
//
|
|
// If it's a big IRQ, set the
|
|
// corresponding bit in the
|
|
// big register.
|
|
//
|
|
ulBigIRQRegister |= 1 << (16 + rgbIRQToBig[i]);
|
|
}
|
|
else if (rgbIRQToSmall[i])
|
|
{
|
|
//
|
|
// If it's a small IRQ, set the
|
|
// corresponding bit in the
|
|
// small register.
|
|
//
|
|
ulSmallIRQRegister |= 1 << (11 - rgbIRQToSmall[i]);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Trying to level set an unsupported IRQ.
|
|
//
|
|
return(PCIMP_INVALID_IRQ);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Write the new IRQ register values.
|
|
//
|
|
WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x40, ulBigIRQRegister);
|
|
WriteConfigUlong(bBusPIC, bDevFuncPIC, 0x50, ulSmallIRQRegister);
|
|
|
|
return(PCIMP_SUCCESS);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* OptiViperGetTrigger - Get the IRQ triggering values for the OptiViper
|
|
*
|
|
* Exported.
|
|
*
|
|
* ENTRY: pulTrigger will have bits set for Level triggered IRQs.
|
|
*
|
|
* EXIT: Standard PCIMP return value.
|
|
*
|
|
***************************************************************************/
|
|
PCIMPRET CDECL
|
|
OptiViperGetTrigger(PULONG pulTrigger)
|
|
{
|
|
ULONG ulBigIRQRegister;
|
|
ULONG ulSmallIRQRegister;
|
|
ULONG i;
|
|
|
|
//
|
|
// Assume all edge.
|
|
//
|
|
*pulTrigger = 0;
|
|
|
|
//
|
|
// Read in the big&small IRQ registers.
|
|
//
|
|
ulBigIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x40);
|
|
ulSmallIRQRegister = ReadConfigUlong(bBusPIC, bDevFuncPIC, 0x50);
|
|
|
|
//
|
|
// For each IRQ...
|
|
//
|
|
for (i=0; i<16; i++)
|
|
{
|
|
//
|
|
// If it's a big IRQ and it's level triggered,
|
|
// or if it's a small IRQ and it's level triggered,
|
|
// set the corresponding bit in pulTrigger.
|
|
//
|
|
if ( ((rgbIRQToBig[i]) &&
|
|
(ulBigIRQRegister & (1 << (16 + rgbIRQToBig[i])))) ||
|
|
((rgbIRQToSmall[i]) &&
|
|
(ulSmallIRQRegister & (1 << (11 - rgbIRQToSmall[i])))))
|
|
{
|
|
*pulTrigger |= 1 << i;
|
|
}
|
|
}
|
|
|
|
return(PCIMP_SUCCESS);
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* OptiViperValidateTable - Validate an IRQ table
|
|
*
|
|
* Exported.
|
|
*
|
|
* ENTRY: piihIRQInfoHeader points to an IRQInfoHeader followed
|
|
* by an IRQ Routing Table.
|
|
*
|
|
* ulFlags are PCIMP_VALIDATE flags.
|
|
*
|
|
* EXIT: Standard PCIMP return value.
|
|
*
|
|
***************************************************************************/
|
|
#ifdef ALLOC_PRAGMA
|
|
PCIMPRET CDECL
|
|
OptiViperValidateTable(PIRQINFOHEADER piihIRQInfoHeader, ULONG ulFlags);
|
|
#pragma alloc_text(PAGE, OptiViperValidateTable)
|
|
#endif //ALLOC_PRAGMA
|
|
|
|
PCIMPRET CDECL
|
|
OptiViperValidateTable(PIRQINFOHEADER piihIRQInfoHeader, ULONG ulFlags)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (GetMaxLink(piihIRQInfoHeader)>0x04) {
|
|
|
|
return(PCIMP_FAILURE);
|
|
}
|
|
|
|
return(PCIMP_SUCCESS);
|
|
}
|