From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/halfire/ppc/ctrlops.c | 471 +++++ private/ntos/nthals/halfire/ppc/fp82091.c | 120 ++ private/ntos/nthals/halfire/ppc/fp82091.h | 426 ++++ private/ntos/nthals/halfire/ppc/fparch.h | 46 + private/ntos/nthals/halfire/ppc/fpbat.c | 346 ++++ private/ntos/nthals/halfire/ppc/fpbat.h | 20 + private/ntos/nthals/halfire/ppc/fpbt445.c | 413 ++++ private/ntos/nthals/halfire/ppc/fpbt445.h | 180 ++ private/ntos/nthals/halfire/ppc/fpcpu.h | 179 ++ private/ntos/nthals/halfire/ppc/fpcpu.s | 387 ++++ private/ntos/nthals/halfire/ppc/fpdcc.c | 226 +++ private/ntos/nthals/halfire/ppc/fpdcc.h | 142 ++ private/ntos/nthals/halfire/ppc/fpdebug.h | 171 ++ private/ntos/nthals/halfire/ppc/fpds1385.c | 372 ++++ private/ntos/nthals/halfire/ppc/fpds1385.h | 213 ++ private/ntos/nthals/halfire/ppc/fpi2c.c | 1016 ++++++++++ private/ntos/nthals/halfire/ppc/fpi2c.h | 39 + private/ntos/nthals/halfire/ppc/fpi2csup.h | 232 +++ private/ntos/nthals/halfire/ppc/fpints.c | 292 +++ private/ntos/nthals/halfire/ppc/fpio.h | 230 +++ private/ntos/nthals/halfire/ppc/fplibc.c | 114 ++ private/ntos/nthals/halfire/ppc/fpnvram.h | 105 + private/ntos/nthals/halfire/ppc/fppci.h | 189 ++ private/ntos/nthals/halfire/ppc/fppcisup.c | 1101 +++++++++++ private/ntos/nthals/halfire/ppc/fppcisup.h | 142 ++ private/ntos/nthals/halfire/ppc/fpproto.h | 17 + private/ntos/nthals/halfire/ppc/fpreg.h | 422 ++++ private/ntos/nthals/halfire/ppc/fprgstry.c | 871 +++++++++ private/ntos/nthals/halfire/ppc/halp.h | 267 +++ private/ntos/nthals/halfire/ppc/pcibios.c | 1084 +++++++++++ private/ntos/nthals/halfire/ppc/pcibios.h | 58 + private/ntos/nthals/halfire/ppc/pcip.h | 249 +++ private/ntos/nthals/halfire/ppc/phcalls.c | 120 ++ private/ntos/nthals/halfire/ppc/phprods.c | 794 ++++++++ private/ntos/nthals/halfire/ppc/phsystem.h | 270 +++ private/ntos/nthals/halfire/ppc/phsystem.s | 487 +++++ private/ntos/nthals/halfire/ppc/phvrsion.c | 433 +++++ private/ntos/nthals/halfire/ppc/pxbeep.c | 144 ++ private/ntos/nthals/halfire/ppc/pxbusdat.c | 207 ++ private/ntos/nthals/halfire/ppc/pxcache.s | 1105 +++++++++++ private/ntos/nthals/halfire/ppc/pxcalstl.c | 150 ++ private/ntos/nthals/halfire/ppc/pxcirrus.h | 234 +++ private/ntos/nthals/halfire/ppc/pxclksup.s | 163 ++ private/ntos/nthals/halfire/ppc/pxclock.c | 287 +++ private/ntos/nthals/halfire/ppc/pxdat.c | 113 ++ private/ntos/nthals/halfire/ppc/pxdisp.c | 2907 ++++++++++++++++++++++++++++ private/ntos/nthals/halfire/ppc/pxenviro.c | 729 +++++++ private/ntos/nthals/halfire/ppc/pxflshbf.s | 159 ++ private/ntos/nthals/halfire/ppc/pxflshio.c | 195 ++ private/ntos/nthals/halfire/ppc/pxhalp.h | 291 +++ private/ntos/nthals/halfire/ppc/pxhwsup.c | 2212 +++++++++++++++++++++ private/ntos/nthals/halfire/ppc/pxidaho.h | 149 ++ private/ntos/nthals/halfire/ppc/pxidle.c | 77 + private/ntos/nthals/halfire/ppc/pxinithl.c | 1114 +++++++++++ private/ntos/nthals/halfire/ppc/pxintsup.s | 121 ++ private/ntos/nthals/halfire/ppc/pxirql.c | 182 ++ private/ntos/nthals/halfire/ppc/pxisabus.c | 576 ++++++ private/ntos/nthals/halfire/ppc/pxmapio.c | 134 ++ private/ntos/nthals/halfire/ppc/pxmemctl.c | 243 +++ private/ntos/nthals/halfire/ppc/pxmemctl.h | 68 + private/ntos/nthals/halfire/ppc/pxmisc.s | 282 +++ private/ntos/nthals/halfire/ppc/pxnatsup.c | 90 + private/ntos/nthals/halfire/ppc/pxnatsup.h | 67 + private/ntos/nthals/halfire/ppc/pxnvrsup.h | 35 + private/ntos/nthals/halfire/ppc/pxpcibus.c | 2327 ++++++++++++++++++++++ private/ntos/nthals/halfire/ppc/pxpciint.c | 398 ++++ private/ntos/nthals/halfire/ppc/pxpcisup.c | 267 +++ private/ntos/nthals/halfire/ppc/pxpcisup.h | 66 + private/ntos/nthals/halfire/ppc/pxport.c | 855 ++++++++ private/ntos/nthals/halfire/ppc/pxproc.c | 250 +++ private/ntos/nthals/halfire/ppc/pxprof.c | 277 +++ private/ntos/nthals/halfire/ppc/pxreturn.c | 223 +++ private/ntos/nthals/halfire/ppc/pxrtcsup.h | 37 + private/ntos/nthals/halfire/ppc/pxs3.h | 770 ++++++++ private/ntos/nthals/halfire/ppc/pxsiosup.c | 1866 ++++++++++++++++++ private/ntos/nthals/halfire/ppc/pxsiosup.h | 231 +++ private/ntos/nthals/halfire/ppc/pxstall.s | 390 ++++ private/ntos/nthals/halfire/ppc/pxsysbus.c | 298 +++ private/ntos/nthals/halfire/ppc/pxsysint.c | 243 +++ private/ntos/nthals/halfire/ppc/pxtime.c | 340 ++++ private/ntos/nthals/halfire/ppc/pxusage.c | 512 +++++ private/ntos/nthals/halfire/ppc/sysbios.c | 73 + private/ntos/nthals/halfire/ppc/sysbios.h | 31 + private/ntos/nthals/halfire/ppc/txtpalet.h | 107 + private/ntos/nthals/halfire/ppc/x86bios.c | 1201 ++++++++++++ private/ntos/nthals/halfire/ppc/x86bios.h | 24 + 86 files changed, 35064 insertions(+) create mode 100644 private/ntos/nthals/halfire/ppc/ctrlops.c create mode 100644 private/ntos/nthals/halfire/ppc/fp82091.c create mode 100644 private/ntos/nthals/halfire/ppc/fp82091.h create mode 100644 private/ntos/nthals/halfire/ppc/fparch.h create mode 100644 private/ntos/nthals/halfire/ppc/fpbat.c create mode 100644 private/ntos/nthals/halfire/ppc/fpbat.h create mode 100644 private/ntos/nthals/halfire/ppc/fpbt445.c create mode 100644 private/ntos/nthals/halfire/ppc/fpbt445.h create mode 100644 private/ntos/nthals/halfire/ppc/fpcpu.h create mode 100644 private/ntos/nthals/halfire/ppc/fpcpu.s create mode 100644 private/ntos/nthals/halfire/ppc/fpdcc.c create mode 100644 private/ntos/nthals/halfire/ppc/fpdcc.h create mode 100644 private/ntos/nthals/halfire/ppc/fpdebug.h create mode 100644 private/ntos/nthals/halfire/ppc/fpds1385.c create mode 100644 private/ntos/nthals/halfire/ppc/fpds1385.h create mode 100644 private/ntos/nthals/halfire/ppc/fpi2c.c create mode 100644 private/ntos/nthals/halfire/ppc/fpi2c.h create mode 100644 private/ntos/nthals/halfire/ppc/fpi2csup.h create mode 100644 private/ntos/nthals/halfire/ppc/fpints.c create mode 100644 private/ntos/nthals/halfire/ppc/fpio.h create mode 100644 private/ntos/nthals/halfire/ppc/fplibc.c create mode 100644 private/ntos/nthals/halfire/ppc/fpnvram.h create mode 100644 private/ntos/nthals/halfire/ppc/fppci.h create mode 100644 private/ntos/nthals/halfire/ppc/fppcisup.c create mode 100644 private/ntos/nthals/halfire/ppc/fppcisup.h create mode 100644 private/ntos/nthals/halfire/ppc/fpproto.h create mode 100644 private/ntos/nthals/halfire/ppc/fpreg.h create mode 100644 private/ntos/nthals/halfire/ppc/fprgstry.c create mode 100644 private/ntos/nthals/halfire/ppc/halp.h create mode 100644 private/ntos/nthals/halfire/ppc/pcibios.c create mode 100644 private/ntos/nthals/halfire/ppc/pcibios.h create mode 100644 private/ntos/nthals/halfire/ppc/pcip.h create mode 100644 private/ntos/nthals/halfire/ppc/phcalls.c create mode 100644 private/ntos/nthals/halfire/ppc/phprods.c create mode 100644 private/ntos/nthals/halfire/ppc/phsystem.h create mode 100644 private/ntos/nthals/halfire/ppc/phsystem.s create mode 100644 private/ntos/nthals/halfire/ppc/phvrsion.c create mode 100644 private/ntos/nthals/halfire/ppc/pxbeep.c create mode 100644 private/ntos/nthals/halfire/ppc/pxbusdat.c create mode 100644 private/ntos/nthals/halfire/ppc/pxcache.s create mode 100644 private/ntos/nthals/halfire/ppc/pxcalstl.c create mode 100644 private/ntos/nthals/halfire/ppc/pxcirrus.h create mode 100644 private/ntos/nthals/halfire/ppc/pxclksup.s create mode 100644 private/ntos/nthals/halfire/ppc/pxclock.c create mode 100644 private/ntos/nthals/halfire/ppc/pxdat.c create mode 100644 private/ntos/nthals/halfire/ppc/pxdisp.c create mode 100644 private/ntos/nthals/halfire/ppc/pxenviro.c create mode 100644 private/ntos/nthals/halfire/ppc/pxflshbf.s create mode 100644 private/ntos/nthals/halfire/ppc/pxflshio.c create mode 100644 private/ntos/nthals/halfire/ppc/pxhalp.h create mode 100644 private/ntos/nthals/halfire/ppc/pxhwsup.c create mode 100644 private/ntos/nthals/halfire/ppc/pxidaho.h create mode 100644 private/ntos/nthals/halfire/ppc/pxidle.c create mode 100644 private/ntos/nthals/halfire/ppc/pxinithl.c create mode 100644 private/ntos/nthals/halfire/ppc/pxintsup.s create mode 100644 private/ntos/nthals/halfire/ppc/pxirql.c create mode 100644 private/ntos/nthals/halfire/ppc/pxisabus.c create mode 100644 private/ntos/nthals/halfire/ppc/pxmapio.c create mode 100644 private/ntos/nthals/halfire/ppc/pxmemctl.c create mode 100644 private/ntos/nthals/halfire/ppc/pxmemctl.h create mode 100644 private/ntos/nthals/halfire/ppc/pxmisc.s create mode 100644 private/ntos/nthals/halfire/ppc/pxnatsup.c create mode 100644 private/ntos/nthals/halfire/ppc/pxnatsup.h create mode 100644 private/ntos/nthals/halfire/ppc/pxnvrsup.h create mode 100644 private/ntos/nthals/halfire/ppc/pxpcibus.c create mode 100644 private/ntos/nthals/halfire/ppc/pxpciint.c create mode 100644 private/ntos/nthals/halfire/ppc/pxpcisup.c create mode 100644 private/ntos/nthals/halfire/ppc/pxpcisup.h create mode 100644 private/ntos/nthals/halfire/ppc/pxport.c create mode 100644 private/ntos/nthals/halfire/ppc/pxproc.c create mode 100644 private/ntos/nthals/halfire/ppc/pxprof.c create mode 100644 private/ntos/nthals/halfire/ppc/pxreturn.c create mode 100644 private/ntos/nthals/halfire/ppc/pxrtcsup.h create mode 100644 private/ntos/nthals/halfire/ppc/pxs3.h create mode 100644 private/ntos/nthals/halfire/ppc/pxsiosup.c create mode 100644 private/ntos/nthals/halfire/ppc/pxsiosup.h create mode 100644 private/ntos/nthals/halfire/ppc/pxstall.s create mode 100644 private/ntos/nthals/halfire/ppc/pxsysbus.c create mode 100644 private/ntos/nthals/halfire/ppc/pxsysint.c create mode 100644 private/ntos/nthals/halfire/ppc/pxtime.c create mode 100644 private/ntos/nthals/halfire/ppc/pxusage.c create mode 100644 private/ntos/nthals/halfire/ppc/sysbios.c create mode 100644 private/ntos/nthals/halfire/ppc/sysbios.h create mode 100644 private/ntos/nthals/halfire/ppc/txtpalet.h create mode 100644 private/ntos/nthals/halfire/ppc/x86bios.c create mode 100644 private/ntos/nthals/halfire/ppc/x86bios.h (limited to 'private/ntos/nthals/halfire/ppc') diff --git a/private/ntos/nthals/halfire/ppc/ctrlops.c b/private/ntos/nthals/halfire/ppc/ctrlops.c new file mode 100644 index 000000000..f921d2ed6 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/ctrlops.c @@ -0,0 +1,471 @@ +/*++ + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + ctrlops.c + +Abstract: + + This module implements the code to emulate call, retunr, and various + control operations. + +Author: + + David N. Cutler (davec) 10-Nov-1994 + + +Environment: + + Kernel mode only. + +Revision History: + + Scott Geranen 5-Mar-1996 Added hooks for System BIOS emulation + +--*/ + +#include "nthal.h" +#include "emulate.h" +#include "sysbios.h" + +VOID +XmCallOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a call opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Target; + ULONG Source; + + // + // Save the target address, push the current segment, if required, and + // push the current IP, set the destination segment, if required, and + // set the new IP. + // + + Target = P->DstValue.Long; + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + if ((P->CurrentOpcode == 0x9a) || (P->FunctionIndex != X86_CALL_OP)) { + XmPushStack(P, P->SegmentRegister[CS]); + XmPushStack(P, P->Eip); + P->SegmentRegister[CS] = P->DstSegment; + + } else { + XmPushStack(P, P->Eip); + } + + P->Eip = Target; + XmTraceJumps(P); + return; +} + +VOID +XmEnterOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates an enter opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Allocate; + ULONG Frame; + ULONG Number; + + // + // set the number of bytes to allocate on the stack and the number + // of nesting levels. + // + + Allocate = P->SrcValue.Long; + Number = P->DstValue.Long; + + // + // Set the data type and save the frame pointer on the stack. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + XmPushStack(P, P->Gpr[EBP].Exx); + Frame = P->Gpr[ESP].Exx; + + } else { + P->DataType = WORD_DATA; + XmPushStack(P, P->Gpr[BP].Xx); + Frame = P->Gpr[SP].Xx; + } + + // + // Save the current stack pointer and push parameters on the stack. + // + + if (Number != 0) { + + // + // If the level number is not one, then raise an exception. + // + // N.B. Level numbers greater than one are not supported. + // + + if (Number != 1) { + longjmp(&P->JumpBuffer[0], XM_ILLEGAL_LEVEL_NUMBER); + } + + XmPushStack(P, Frame); + } + + // + // Allocate local storage on stack. + // + + if (P->OpsizePrefixActive != FALSE) { + P->Gpr[EBP].Exx = Frame; + P->Gpr[ESP].Exx = P->Gpr[ESP].Exx - Allocate; + + } else { + P->Gpr[BP].Xx = (USHORT)Frame; + P->Gpr[SP].Xx = (USHORT)(P->Gpr[SP].Xx - Allocate); + } + + return; +} + +VOID +XmHltOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a hlt opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + // + // Halt instructions are not supported by the emulator. + // + + longjmp(&P->JumpBuffer[0], XM_HALT_INSTRUCTION); + return; +} + +VOID +XmIntOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates an int opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Number; + PULONG Vector; + + // + // If the int instruction is an int 3, then set the interrupt vector + // to 3. Otherwise, if the int instruction is an into, then set the + // vector to 4 if OF is set. use the source interrupt vector. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + if (P->CurrentOpcode == 0xcc) { + Number = 3; + + } else if (P->CurrentOpcode == 0xce) { + if (P->Eflags.OF == 0) { + return; + } + + Number = 4; + + } else { + Number = P->SrcValue.Byte; + } + + // + // If the vector number is 0x42, then nop the interrupt. This is the + // standard EGA video driver entry point in a PC's motherboard BIOS + // for which there is no code. + // + +#if !defined(_PURE_EMULATION_) + + if (Number == 0x42) { + return; + } + +#endif + + // + // Try to emulate a system BIOS call first. + // + if (!HalpEmulateSystemBios(P, Number)) { + + // + // Either it isn't a BIOS call or it isn't supported. + // Emulate the x86 stream instead. Note that this + // doesn't support chained handlers. + + // + // Push the current flags, code segment, and EIP on the stack. + // + + XmPushStack(P, P->AllFlags); + XmPushStack(P, P->SegmentRegister[CS]); + XmPushStack(P, P->Eip); + + // + // Set the new coded segment and IP from the specified interrupt + // vector. + // + + Vector = (PULONG)(P->TranslateAddress)(0, 0); + P->SegmentRegister[CS] = (USHORT)(Vector[Number] >> 16); + P->Eip = (USHORT)(Vector[Number] & 0xffff); + XmTraceJumps(P); + } + + return; +} + +VOID +XmIretOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates an iret opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the data type and restore the return address, code segment, + // and flags. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + P->Eip = XmPopStack(P); + P->SegmentRegister[CS] = (USHORT)XmPopStack(P); + P->AllFlags = XmPopStack(P); + XmTraceJumps(P); + + // + // Check for emulator exit conditions. + // + + if ((P->Eip == 0xffff) && (P->SegmentRegister[CS] == 0xffff)) { + longjmp(&P->JumpBuffer[0], XM_SUCCESS); + } + + return; +} + +VOID +XmLeaveOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a leave opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + // + // Set the data type, restore the stack pointer, and restore the frame + // pointer. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + P->Gpr[ESP].Exx = P->Gpr[EBP].Exx; + P->Gpr[EBP].Exx = XmPopStack(P); + + } else { + P->DataType = WORD_DATA; + P->Gpr[SP].Xx = P->Gpr[BP].Xx; + P->Gpr[BP].Xx = (USHORT)XmPopStack(P); + } + + return; +} + +VOID +XmRetOp ( + PRXM_CONTEXT P + ) + +/*++ + +Routine Description: + + This function emulates a ret opcode. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + None. + +--*/ + +{ + + ULONG Adjust; + + // + // Compute the number of bytes that are to be removed from the stack + // after having removed the return address and optionally the new CS + // segment value. + // + + if ((P->CurrentOpcode & 0x1) == 0) { + Adjust = XmGetWordImmediate(P); + + } else { + Adjust = 0; + } + + // + // Remove the return address from the stack and set the new IP. + // + + if (P->OpsizePrefixActive != FALSE) { + P->DataType = LONG_DATA; + + } else { + P->DataType = WORD_DATA; + } + + P->Eip = XmPopStack(P); + + // + // If the current opcode is a far return, then remove the new CS segment + // value from the stack. + // + + if ((P->CurrentOpcode & 0x8) != 0) { + P->SegmentRegister[CS] = (USHORT)XmPopStack(P); + } + + // + // Remove the specified number of bytes from the stack. + // + + P->Gpr[ESP].Exx += Adjust; + XmTraceJumps(P); + + // + // Check for emulator exit conditions. + // + + if ((P->Eip == 0xffff) && (P->SegmentRegister[CS] == 0xffff)) { + longjmp(&P->JumpBuffer[0], XM_SUCCESS); + } + + return; +} diff --git a/private/ntos/nthals/halfire/ppc/fp82091.c b/private/ntos/nthals/halfire/ppc/fp82091.c new file mode 100644 index 000000000..b9b353158 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fp82091.c @@ -0,0 +1,120 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1994 FirePower Systems, Inc. + +Module Name: + + fp82091.c + +Abstract: + + The module provides the Intel AIP (82091AA) support for Power PC. + +Author: + + +Revision History: + + + +--*/ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fp82091.c $ + * $Revision: 1.5 $ + * $Date: 1996/01/16 20:45:10 $ + * $Locker: $ + */ + +#include "halp.h" +#include "fpreg.h" +#include "fpio.h" +#include "fp82091.h" + + + +BOOLEAN +HalpInitIntelAIP ( + VOID + ) + + +{ + + // + // AIP configuration + // + + rIndexAIP1 = AIPCFG1; + rTargetAIP1 = CLOCK_POWERED_ON | + PRIMARY_ADDRESS_CONFIG | + SOFTWARE_MOTHERBOARD; + FireSyncRegister(); + + rIndexAIP1 = AIPCFG2; + // + // Active High Mode is ISA-Compatible + // + rTargetAIP1 = IRQ3_ACTIVE_HIGH | + IRQ4_ACTIVE_HIGH | + IRQ5_ACTIVE_HIGH | + IRQ6_ACTIVE_HIGH | + IRQ7_ACTIVE_HIGH; + FireSyncRegister(); + + rIndexAIP1 = FCFG1; + rTargetAIP1 = FDC_ENABLE | + PRIMARY_FDC_ADDRESS | + TWO_DISK_DRIVES; + FireSyncRegister(); + + rIndexAIP1 = FCFG2; + rTargetAIP1 = 0x00; // No Powerdown control, + // no reset + FireSyncRegister(); + + + rIndexAIP1 = PCFG1; + rTargetAIP1 = PP_ENABLE | + PP_ADDRESS_SELECT_2 | // Parallel Port1 (3BC-3BE) + PP_IRQ7 | + PP_FIFO_THRSEL_8; + FireSyncRegister(); + + rIndexAIP1 = PCFG2; + rTargetAIP1 = 0x00; // No Powerdown control, + // no reset + FireSyncRegister(); + + rIndexAIP1 = SACFG1; + rTargetAIP1 = PORTA_ENABLE | + PORTA_ADDRESS_SELECT_0 | // Serial Port1 (3F8-3FF + PORTA_IRQ4; + FireSyncRegister(); + + rIndexAIP1 = SACFG2; + rTargetAIP1 = 0x00; // No Powerdown control, + // no reset, no test mode + FireSyncRegister(); + + rIndexAIP1 = SBCFG1; + rTargetAIP1 = PORTB_ENABLE | + PORTB_ADDRESS_SELECT_1 | // Serial Port2 (2F8-2FF) + PORTB_IRQ3; + FireSyncRegister(); + + rIndexAIP1 = SACFG2; + rTargetAIP1 = 0x00; // No Powerdown control, + // no reset, no test mode + FireSyncRegister(); + + rIndexAIP1 = IDECFG; + rTargetAIP1 = IDE_INTERFACE_ENABLE; // IDE interface enable + FireSyncRegister(); + + return TRUE; + +} diff --git a/private/ntos/nthals/halfire/ppc/fp82091.h b/private/ntos/nthals/halfire/ppc/fp82091.h new file mode 100644 index 000000000..5fed59a86 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fp82091.h @@ -0,0 +1,426 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation +Copyright (c) 1994 FirePower Systems, Inc. + +Module Name: + + pxaipsup.h + +Abstract: + + The module defines the structures, and defines for the + AIP (Intel 82091AA) Advanced Integrated Peripheral chip. + +Author: + + +Revision History: + + +--*/ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fp82091.h $ + * $Revision: 1.5 $ + * $Date: 1996/05/14 02:32:08 $ + * $Locker: $ + */ + +// AIP configuration registers + + +// +// Index register select +// + +#define AIPID 0x00 // Product Identification +#define AIPREV 0x01 // Revision Identification +#define AIPCFG1 0x02 // AIP Configuration 1 +#define AIPCFG2 0x03 // AIP Configuration 2 +#define FCFG1 0x10 // FDC Configuration +#define FCFG2 0x11 // FDC Power Management and + /* Status */ +#define PCFG1 0x20 // Parallel Port Configuration +#define PCFG2 0x21 // Parallel Port Power Management + /* and Status */ +#define SACFG1 0x30 // Serial Port A Configuration +#define SACFG2 0x31 // Serail Port A Power Management + /* and Status */ +#define SBCFG1 0x40 // Serial Port B Configuration +#define SBCFG2 0x41 // Serial Port B Power Management + /* and Status */ +#define IDECFG 0x50 // IDE Configuration + +/*+++ + + AIPID: RO + 7-0 Product Identification Number + + + AIPREV: RO + 7-4 Step Number + 3-0 Dash Number + + AIPCFG1: R/W + 7 Not Used + 6 Supply Voltage (RO) + 0: 5.0V + 1: 3.3V + 4-5 Configuration Mode Select (R/W) + 0x00 Software Motherboard + 0x01 Software Add-in + 0x10 Extended Hardware + 0x11 Basic Hardware + 3 Configuration Address Select (RO) + 0: Secondary Address + 1: Primary Address + 2-1 Reserved + 0 Clock Off (R/W) + 0: AIP powered on + 1: AIP powered off + + AIPCFG2: R/W + 7 IRQ7 Mode Select (R/W) + 0: Active High + 1: Active Low + 6 IRQ6 Mode Select (R/W) + 0: Active High + 1: Active Low + 5 IRQ5 Mode Select (R/W) + 0: Active High + 1: Active Low + 4 IRQ4 Mode Select (R/W) + 0: Active High + 1: Active Low + 3 IRQ3 Mode Select (R/W) + 0: Active High + 1: Active Low + 2-0 Reserved + + FCFG1: R/W + 7 Floppy Disk Drive Quantity (R/W) + 0: Two + 1: Four + 6-2 Reserved + 1 FDC Address Select (R/W) + 0: Primary (3F0-3F7) + 1: Secondary (370-377) + 0 FDC Enable (R/W) + 0: Disable + 1: Enable + + FCFG2: R/W + 7-4 Reserved + 3 FDC Auto Powerdown Enable (R/W) + 0: Disable + 1: Enable, 0: Disable + 2 FDC Reset (R/W) + 0: No FDC Module Reset + 1: Reset FDC Module, 0: No FDC Module Reset + 1 FDC Idle Status (RO) + 0: Active + 1: Idle, 0: Active + 0 FDC Direct Powerdown Control (R/W) + 0: Not in Direct Powerdown + 1: Powerdown, 0: Not in Direct Powerdown + + PCFG1: R/W + 7 PP FIFO Threshold Select (R/W) + 0: 8 (forward and reverse) + 1: 1 (forward), 15(reverse) + 6-5 PP Hardware Mode Select (R/W) + 00: ISA-Compatible (read), ISA-Compatible (write) + 01: PS/2-Compatible (read), PS/2-Compatible (write) + 10: EPP (read) , EPP (write) + 11: ECP (read), Reserved (do not write) + 4 Reserved + 3 PP Interrupt Select (R/W) + 0: IRQ5 + 1: IRQ7 + 2-1 PP Address Select (R/W) + 00: 378-37F + 01: 278-27F + 10: 3BC-3BE + 11: Reserved + 0 PP Enable (R/W) + 0: Disable + 1: Enable + PCFG2: R/W + 7-6 Reserved + 5 PP FIFO Error Status (RO) + 0: No Underrun or Overrun + 1: Underrun or Overrun + 4 Reserved + 3 PP Auto Powerdown Enable (R/W) + 0: Disable + 1: Enable + 2 PP Reset (R/W) + 0: Inactive + 1: Active + 1 PP Idle Status (RO) + 0: Avtive + 1: Idle + 0 PP Port Direct Powerdown (R/W) + 0: Disabled + 1: Enabled + + SACFG1: R/W + 7 MIDI Clock Enable for Serial Port A (R/W) + 0: 1.8642 MHz Clock + 1: 2MHz Clock + 6-5 Reserved + 4 Serial Port A IRQ Select (R/W) + 0: IRQ3 + 1: IRQ4 + 3-1 Serial Port A Address Select (R/W) + 000: 3F8-3FF + 001: 2F8-2FF + 010: 220-227 + 011: 228-22F + 100: 238-23F + 101: 2E8-2EF + 110: 338-33F + 111: 3E8-3EF + 0 Serial Port A Enable (R/W) + 0: Disable + 1: Enable + + SACFG2: R/W + 0: to Disable + 1: to Enable + ------------------------------------------------------------- + 7-5 Reserved + 4 Serial Port A Test Mode (R/W) + 3 Serial Port A Auto Powerdown Enable (R/W) + 2 Serial Port A Reset (R/W) + 1 Serial Port A Idle Status (RO) + 0 Serial Port A Direct Powerdown Control (R/W) + + + SBCFG1: R/W + ------------------------------------------------------------- + 7 MIDI Clock Enable for Serial Port B (R/W) + 0: 1.8642 MHz Clock + 1: 2MHz Clock + 6-5 Reserved + 4 Serial Port B IRQ Select (R/W) + 0: IRQ3 + 1: IRQ4 + 3-1 Serial Port B Address Select (R/W) + 000: 3F8-3FF + 001: 2F8-2FF + 010: 220-227 + 011: 228-22F + 100: 238-23F + 101: 2E8-2EF + 110: 338-33F + 111: 3E8-3EF + 0 Serial Port B Enable (R/W) + 0: Disable + 1: Enable + + SBCFG2: R/W + ------------------------------------------------------------- + 7-5 Reserved + 4 Serial Port B Test Mode (R/W) + 0: Disable + 1: Enable + 3 Serial Port B Auto Powerdown Enable (R/W) + 0: Disable + 1: Enable + 2 Serial Port B Reset (R/W) + 0: Reset Inactive + 1: Reset Active + 1 Serial Port B Idle Status (RO) + 0: Active + 1: Idle + 0 Serial Port B Direct Powerdown Control (R/W) + 0: Disable + 1: Enable + + IDECFG: R/W + 7-3 Reserved + 2 IDE Dual Interface Select (R/W) + 1: Primary and Secondary Address Selected + 0: Dual Interface Disabled + 1 IDE Address Select (R/W) + 0: Primary (1F0-1F7,3F6,3F7) + 1: Secondary (170-17F,376,377) + 0 IDE Interface Enable (R/W) + 0: Disable + 1: Enable, 0: Disable + +---*/ + + +// +// Data register values +// + +// +// AIPCFG1 +// + +#define CLOCK_POWERED_ON 0x00 +#define CLOCK_POWERED_OFF 0x01 +#define PRIMARY_ADDRESS_CONFIG 0x00 +#define SECONDARY_ADDRESS_CONFIG 0x08 +#define SOFTWARE_MOTHERBOARD 0x00 +#define SOFTWARE_ADDIN 0x10 +#define EXTENDED_HARDWARE 0x20 +#define BASIC_HARDWARE 0x30 +#define SUPPLY_VOLTAGE_33V 0x40 + +// +// AIPCFG2 +// + +#define IRQ3_ACTIVE_LOW 0x08 +#define IRQ3_ACTIVE_HIGH 0x00 +#define IRQ4_ACTIVE_LOW 0x10 +#define IRQ4_ACTIVE_HIGH 0x00 +#define IRQ5_ACTIVE_LOW 0x20 +#define IRQ5_ACTIVE_HIGH 0x00 +#define IRQ6_ACTIVE_LOW 0x40 +#define IRQ6_ACTIVE_HIGH 0x00 +#define IRQ7_ACTIVE_LOW 0x80 +#define IRQ7_ACTIVE_HIGH 0x00 +#define AIPCFG2_MASK 0xF8 + +// +// FCFG1 +// + +#define FDC_ENABLE 0x01 +#define PRIMARY_FDC_ADDRESS 0x00 +#define SECONDARY_FDC_ADDRESS 0x02 +#define TWO_DISK_DRIVES 0x00 +#define FOUR_DISK_DRIVES 0x80 +#define FCFG1_MASK 0x83 + +// +// FCFG2 +// + +#define FDC_DIRECT_POWERDOWN 0x01 +#define FDC_IDLE 0x02 /* read-only */ +#define RESET_FDC_MODULE 0x04 +#define FDC_AUTO_POWERDOWN_ENABLE 0x08 +#define FCFG2_MASK 0x0F + +// +// PCFG1 +// + +#define PP_ENABLE 0x01 +#define PP_ADDRESS_SELECT_0 0x00 /* 378-37F */ +#define PP_ADDRESS_SELECT_1 0x02 /* 278-27F */ +#define PP_ADDRESS_SELECT_2 0x04 /* 3BC-3BE */ +#define PP_IRQ7 0x08 +#define PP_IRQ5 0x00 +#define PP_HWMODE_ISA_COMPAT 0x00 +#define PP_HWMODE_PS2_COMPAT 0x20 +#define PP_HWMODE_EPP 0x40 +#define PP_HWMODE_ECP 0x60 /* read-only */ +#define PP_FIFO_THRSEL_1 0x80 +#define PP_FIFO_THRSEL_8 0x00 +#define PCFG1_MASK 0xEF + + +// +// PCFG2 +// + +#define PP_DIRECT_POWERDOWN 0x01 +#define PP_IDLE 0x02 /* read-only */ +#define PP_RESET 0x04 +#define PP_AUTO_POWERDOWN_ENABLE 0x08 +#define PP_FIFO_UNDERRUN_OR_OVERRUN 0x20 +#define PCFG2_MASK 0x2F + +// +// SACFG1 +// + +#define PORTA_ENABLE 0x01 +#define PORTA_ADDRESS_SELECT_0 0x00 /* 3F8-3FF */ +#define PORTA_ADDRESS_SELECT_1 0x02 /* 2F8-2FF */ +#define PORTA_ADDRESS_SELECT_2 0x04 /* 220-227 */ +#define PORTA_ADDRESS_SELECT_3 0x06 /* 228-22F */ +#define PORTA_ADDRESS_SELECT_4 0x08 /* 238-23F */ +#define PORTA_ADDRESS_SELECT_5 0x0A /* 2E8-2EF */ +#define PORTA_ADDRESS_SELECT_6 0x0C /* 338-33F */ +#define PORTA_ADDRESS_SELECT_7 0x0D /* 3E8-3EF */ +#define PORTA_IRQ4 0x10 +#define PORTA_IRQ3 0x00 +#define PORTA_MIDI_CLOCK_2000KHZ 0x80 +#define PORTA_MIDI_CLOCK_1846KHZ 0x00 +#define SACFG1_MASK 0x9F + + +// +// SACFG2 +// + +#define PORTA_DIRECT_POWERDOWN 0x01 +#define PORTA_IDLE 0x02 /* read-only */ +#define PORTA_RESET 0x04 +#define PORTA_AUTO_POWERDOWN_ENABLE 0x08 +#define PORTA_TEST_MODE_ENABLE 0x10 +#define SACFG2_MASK 0x1F + +// +// SBCFG1 +// + +#define PORTB_ENABLE 0x01 +#define PORTB_ADDRESS_SELECT_0 0x00 /* 3F8-3FF */ +#define PORTB_ADDRESS_SELECT_1 0x02 /* 2F8-2FF */ +#define PORTB_ADDRESS_SELECT_2 0x04 /* 220-227 */ +#define PORTB_ADDRESS_SELECT_3 0x06 /* 228-22F */ +#define PORTB_ADDRESS_SELECT_4 0x08 /* 238-23F */ +#define PORTB_ADDRESS_SELECT_5 0x0A /* 2E8-2EF */ +#define PORTB_ADDRESS_SELECT_6 0x0C /* 338-33F */ +#define PORTB_ADDRESS_SELECT_7 0x0D /* 3E8-3EF */ +#define PORTB_IRQ4 0x10 +#define PORTB_IRQ3 0x00 +#define PORTB_MIDI_CLOCK_2000KHZ 0x80 +#define PORTB_MIDI_CLOCK_1846KHZ 0x00 +#define SBCFG1_MASK 0x9F + + +// +// SBCFG2 +// + +#define PORTB_DIRECT_POWERDOWN 0x01 +#define PORTB_IDLE 0x02 /* read-only */ +#define PORTB_RESET 0x04 +#define PORTB_AUTO_POWERDOWN_ENABLE 0x08 +#define PORTB_TEST_MODE_ENABLE 0x10 +#define SBCFG2_MASK 0x1F + +// +// IDECFG +// + +#define IDE_INTERFACE_ENABLE 0x01 +#define PRIMARY_IDE_ADDRESS 0x00 +#define SECONDARY_IDE_ADDRESS 0x02 +#define IDE_DUAL_INTERFACE 0x04 +#define IDECFG_MASK 0x07 + + +typedef struct _INTEL_AIP_CONTROL { + UCHAR Reserved1[0x22]; + UCHAR AIPConfigIndexRegister; // Offset 0x22 + UCHAR AIPConfigTargetRegister; // Offset 0x23 +// UCHAR Reserved1[0x26E]; +// UCHAR AIPConfigIndexRegister; // Offset 0x26E +// UCHAR AIPConfigTargetRegister; // Offset 0x26F +} INTEL_AIP_CONTROL, *PINTEL_AIP_CONTROL; + diff --git a/private/ntos/nthals/halfire/ppc/fparch.h b/private/ntos/nthals/halfire/ppc/fparch.h new file mode 100644 index 000000000..99c9685fd --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fparch.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1995. FirePower Systems, Inc. + * (Do Not Distribute without permission) + * + * $RCSfile: fparch.h $ + * $Revision: 1.4 $ + * $Date: 1996/01/11 07:05:05 $ + * $Locker: $ + * + */ + +#ifndef _FPARCH_H +#define _FPARCH_H +// +// These names are not sacrosanct, and should be revised upon input from Susan, +// Jim, and anyone else interested. +// +enum scope_use { + ENG, + MFG, + TEST, + CUST + }; + +enum rel_state { + GENERAL, + OFFICIAL, + TESTING, + CONTROLLED, + LAB + }; + + +typedef struct _TheBigRev { + CHAR Org[80]; // originating organization, ( i.e. + // who built it ) + enum scope_use Scope; // release status from the releasing org + CHAR BuildDate[16]; // time of year, date, day, hour, min, + CHAR BuildTime[16]; // time of year, date, day, hour, min, + // sec it was built + UCHAR Major; // the Major revision of this item + UCHAR Minor; // Minor rev of this item: + enum rel_state State; // the release status of this item +} RelInfo; + +#endif // _FPARCH_H diff --git a/private/ntos/nthals/halfire/ppc/fpbat.c b/private/ntos/nthals/halfire/ppc/fpbat.c new file mode 100644 index 000000000..cdebbf049 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpbat.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpbat.c $ + * $Revision: 1.7 $ + * $Date: 1996/05/14 02:32:13 $ + * $Locker: $ + */ + +/*++ + +Module Name: + +fpbat.c + +Abstract: + + This module implements the HAL display initialization and output routines + for a Sandalfoot PowerPC system using either an S3 or Weitek P9000 + video adapter. + +Author: + + Roger Lanser February 1995 + Bill Rees May 1995 + +Environment: + + Kernel mode + +Revision History: + + Roger Lanser 02-23-95: Added FirePower Video and INT10, nuc'd others + +--*/ + +#include "halp.h" +#include "string.h" +#include "fpbat.h" +#include "arccodes.h" +#include "phsystem.h" +#include "pxmemctl.h" +#include "fpdcc.h" +#include "fpcpu.h" +#include "fpdebug.h" +#include "phsystem.h" +#include "x86bios.h" +#include "pxpcisup.h" + +#define MAX_DBATS 4 + + + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(INIT, HalpInitializeVRAM) +#if DBG +#pragma alloc_text(INIT, HalpDisplayBatForVRAM) +#endif +#endif + +extern ULONG TmpVramBase; +extern ULONG TmpDbatNum; +extern ULONG TmpDbatVal; +extern BOOLEAN HalpDisplayOwnedByHal; // make sure is false: [breeze:1/27/95] + + +extern PUCHAR HalpVideoMemoryBase; +extern ULONG HalpVideoMemorySize; +extern BOOLEAN HalpDisplayTypeUnknown; + +#define MEM1MB 0x00100000 +#define MEM2MB 0x00200000 +#define MEM4MB 0x00400000 + +// +// Define OEM font variables. +// + + + +/*++ + +Routine Description: PVOID HalpMarkDbatForVRAM () + + This function Marks the VRAM DBAT cacheable and if it's on an + mp system marks the DBAT with the memory coherence attribute + according to the architecture manual. + +Arguments: + + VramBase - The base of VRAM to map. + + VramSize - The size of VRAM to map (output). + +Return Value: + + Mapped virtual address. + +--*/ + +VOID +HalpMarkDbatForVRAM ( + IN PVOID /* PHYSICAL_ADDRESS */ VramBase, + IN OUT PULONG VramSize + ) +{ + ULONG i, low, hi; + // + // find the bat register used for the display memory and make + // it cacheable + // + for (i = 0; i < MAX_DBATS; i++) { + low = HalpGetLowerDBAT(i); + if ((low & 0xfffe0000) == (ULONG) VramBase) { + // + // Turn cache bit on. + // + hi = HalpGetUpperDBAT(i); + hi &= 0xfffe0000; // Clear BL, Vs, Vp bit + low &= 0xffffff87; // Clear W, I, M, & G bits - + // assuming PP is set to 10 + switch (*VramSize) { + case MEM1MB: + hi |= 0x1f; // Set 1MB block size with Vs & Vp bits on + break; + case MEM2MB: + hi |= 0x3f; // Set 2MB block size with Vs & Vp bits on + break; + case MEM4MB: + default: + hi |= 0x7f; // Set 4MB block size with Vs & Vp bits on + break; + } + + // + // Gives us a flag to turn off cached VRAM during debug + // sessions. Makes the display more trust worthy. + // + HDBG(DBG_DISPNOCACHE, low |= CACHE_INHIBIT;); + + // + // Flag to turn on MEMORY COHERENCE, i.e. make it a global + // attribute so the processor will through the proper signals + // onto the bus to allow other cpus to snoop and act on it. + // + HDBG(DBG_DISPMEMCOHERE, low |= MEMORY_COHRNCY;); + HalpSetUpperDBAT(i, hi); + if ((SystemType == SYS_POWERTOP) || (SystemType == SYS_POWERSLICE) + || (SystemType == SYS_POWERSERVE)) { + low |= MEMORY_COHRNCY; + } + HalpSetLowerDBAT(i, low); + break; + } + } + +} +/*++ + +Routine Description: PVOID HalpInitializeVRAM () + + This function maps the VRAM DBAT and marks it cacheable. + +Arguments: + + VramBase - The base of VRAM to map. + + VramSize - The size of VRAM to map (output). + +Return Value: + + Mapped virtual address. + +--*/ + +PVOID +HalpInitializeVRAM ( + IN PVOID /* PHYSICAL_ADDRESS */ VramBase, + IN OUT PULONG VramSize, + OUT PULONG VramWidth + ) +{ + PVOID va = NULL; + ULONG hi, low, detect_reg; + LONG i; + + switch (SystemType) { + case SYS_POWERPRO: + /* + * Read VRAM presence detect register SIMM01 + */ + detect_reg = READ_REGISTER_UCHAR(((PUCHAR)HalpIoControlBase)+0x0890); + if ((detect_reg & 0xf0) == 0xf0 ) { + *VramSize = MEM1MB; + *VramWidth = VRAM_32BIT; + } else { + *VramSize = MEM2MB; + *VramWidth = VRAM_64BIT; + } + break; + case SYS_POWERTOP: + /* + * Read VRAM presence detect register SIMM23 + */ + detect_reg = READ_REGISTER_UCHAR(((PUCHAR)HalpIoControlBase)+0x08C0); + // + // if either of the vram simms in slot 2 or 3 appears missing ( i.e. + // reports it's nibble is an 'f' ), set the vram size to 2 meg. + // + if (((detect_reg & 0xf0) == 0xf0) || ((detect_reg & 0x0f) == 0x0f)) { + *VramSize = MEM2MB; + *VramWidth = VRAM_64BIT; + } else { + *VramSize = MEM4MB; + *VramWidth = VRAM_128BIT; + } + break; + case SYS_POWERSERVE: + case SYS_UNKNOWN: + default: + KeBugCheck(HAL_INITIALIZATION_FAILED); + break; + } + + // + // Map a BAT. + // + + va = KePhase0MapIo(VramBase, *VramSize); + + if (!va) { + // + // Bad news, the map failed. Look for the DBAT that has the + // memory space mapping and use it. + // + for (i = 0; i < MAX_DBATS; i++) { + low = HalpGetLowerDBAT(i); + if (IO_MEMORY_PHYSICAL_BASE == (low &= 0xfffe0000)) { + low |= IO_MEMORY_PHYSICAL_BASE; + HalpSetLowerDBAT(i, low); + hi = HalpGetUpperDBAT(i); + va = (PVOID)(hi & 0xfffe0000); // Get va + break; + } + } + // + // Give up... + // + if (!va) { + return va; + } + } + + // + // find the bat register used for the display memory and make + // it cacheable + // + for (i = 0; i < MAX_DBATS; i++) { + low = HalpGetLowerDBAT(i); + if ((low & 0xfffe0000) == (ULONG) VramBase) { + // + // Turn cache bit on. + // + hi = HalpGetUpperDBAT(i); + hi &= 0xfffe0000; // Clear BL, Vs, Vp bit + low &= 0xffffff87; // Clear W, I, M, & G bits - + // assuming PP is set to 10 + switch (*VramSize) { + case MEM1MB: + hi |= 0x1f; // Set 1MB block size with Vs & Vp bits on + break; + case MEM2MB: + hi |= 0x3f; // Set 2MB block size with Vs & Vp bits on + break; + case MEM4MB: + default: + hi |= 0x7f; // Set 4MB block size with Vs & Vp bits on + break; + } + + // + // Gives us a flag to turn off cached VRAM during debug + // sessions. Makes the display more trust worthy. + // + // HDBG(DBG_DISPNOCACHE, low |= CACHE_INHIBIT;); + + // + // Flag to turn on MEMORY COHERENCE, i.e. make it a global + // attribute so the processor will through the proper signals + // onto the bus to allow other cpus to snoop and act on it. + // + // HDBG(DBG_DISPMEMCOHERE, low |= MEMORY_COHRNCY;); + HalpSetUpperDBAT(i, hi); + if ( SystemDescription[SystemType].Flags & SYS_MPFOREAL) { + low |= MEMORY_COHRNCY; + } + HalpSetLowerDBAT(i, low); + break; + } + } + return va; +} + +#if DBG +/*++ + + Routine Description: VOID HalpDisplayBatForVRAM () + + This function displays the VRAM BAT. + +Arguments: + + +Return Value: + + none + +--*/ + +VOID +HalpDisplayBatForVRAM ( + void + ) +{ + ULONG hi, low; + LONG i; + + // + // Look for the DBAT mapped to the VRAM + // + for (i = 0; i < 4; i++) { + low = HalpGetLowerDBAT(i); + if ((low & 0xfffe0000) == (ULONG)DISPLAY_MEMORY_BASE) { + hi = HalpGetUpperDBAT(i); + HalpDebugPrint("HalpDisplayBatForVRAM: (%d): U(0x%08x) L(0x%08x)\n", i, hi, low); + break; + } + } +} +#endif // DBG diff --git a/private/ntos/nthals/halfire/ppc/fpbat.h b/private/ntos/nthals/halfire/ppc/fpbat.h new file mode 100644 index 000000000..bb9266092 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpbat.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpbat.h $ + * $Revision: 1.2 $ + * $Date: 1996/01/11 07:05:18 $ + * $Locker: $ + */ + +#ifndef _FPBAT_H +#define _FPBAT_H + +PVOID HalpInitializeVRAM ( PVOID , PULONG, PULONG ); + +#if DBG +VOID HalpDisplayBatForVRAM ( void ); +#endif + +#endif // _FPBAT_H diff --git a/private/ntos/nthals/halfire/ppc/fpbt445.c b/private/ntos/nthals/halfire/ppc/fpbt445.c new file mode 100644 index 000000000..514a81778 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpbt445.c @@ -0,0 +1,413 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpbt445.c $ + * $Revision: 1.9 $ + * $Date: 1996/05/14 02:32:18 $ + * $Locker: $ + * + * This file contains references to registers in the display controller chip + * known as the DCC. This chip control's vram setup and works in conjunction + * with the ram dac which, in this case is a Brooktree Bt485. + * + */ + +#include "halp.h" +#include "phsystem.h" +#include "fpio.h" +#include "fpDcc.h" +#include "fpBt445.h" + +VOID +HalpSetupBt445( + ULONG Mode, + ULONG VramWidth + ) +/*++ + +Routine Description: + + This routine initializes the display hardware for 640x480 in preparation + for HalDisplayString(). This means that either we are booting up or + dealing with the blue screen of death. We should really change this to + a higher resolution ASAP. [ged] + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + ULONG i; + ULONG modeIndex; + + + // + // BT445 Mask value + // + // The order of entries must match btTab + // + UCHAR btMask[30][3] = { + {6,0x05,0x3f}, + {6,0x06,0xcf}, + {6,0x07,0x00}, + {2,0x06,0x7f}, + {6,0x0a,0xbb}, + {6,0x0d,0x00}, + {5,0x00,0x00}, + {5,0x08,0x00}, + {5,0x10,0x00}, + {6,0x09,0x00}, + {6,0x01,0xdf}, + {6,0x02,0xbf}, + {5,0x1a,0x0f}, + {5,0x22,0x03}, + {6,0x0f,0x00}, + {6,0x03,0x3f}, + {6,0x0b,0x3f}, + {5,0x01,0x00}, + {5,0x09,0x00}, + {5,0x11,0x00}, + {2,0x05,0x00}, + {2,0x04,0x00}, + {5,0x18,0x00}, + {5,0x19,0x00}, + {5,0x1b,0x0f}, + {5,0x20,0x00}, + {5,0x21,0x00}, + {5,0x23,0x03}, + {6,0x0e,0x00}, + {6,0x08,0x1c} + }; + + // BT445 Address register + // address (index) + // register + // 2 = BT445 Group 0 Register + // 5 = BT445 Config Register + // 6 = BT445 Group 1 Register + // value + typedef struct { + UCHAR reg; + UCHAR addr; + UCHAR value; + } BTTAB; // [rdl:01.03.95] + + // [rdl:01.03.95] + BTTAB btTab[3 /* 32/64/128 bit vram */][2 /* mode 0 or 15 */][30] = { + // 32 bit VRAM width + { + // Mode 0 - 640X480 8 bit 72Hz + { + {6,0x05,0x2c}, + {6,0x06,0x84}, + {6,0x07,0x84}, + {2,0x06,0x00}, + {6,0x0a,0x00}, + {6,0x0d,0x08}, + {5,0x00,0x07}, + {5,0x08,0x07}, + {5,0x10,0x07}, + {6,0x09,0x40}, + {6,0x01,0x40}, + {6,0x02,0x00}, + {5,0x1a,0x00}, + {5,0x22,0x00}, + {6,0x0f,0x01}, + {6,0x03,0x03}, + {6,0x0b,0x03}, + {5,0x01,0x08}, + {5,0x09,0x08}, + {5,0x11,0x08}, + {2,0x05,0x00}, + {2,0x04,0xff}, + {5,0x18,0x00}, + {5,0x19,0x01}, + {5,0x1b,0x00}, + {5,0x20,0x00}, + {5,0x21,0x01}, + {5,0x23,0x00}, + {6,0x0e,0x00}, + {6,0x08,0x04} + }, + + // Mode 15 - 1024X768 8 bit 60Hz + { + {6,0x05,0x37}, + {6,0x06,0x45}, + {6,0x07,0x84}, + {2,0x06,0x00}, + {6,0x0a,0x00}, + {6,0x0d,0x08}, + {5,0x00,0x07}, + {5,0x08,0x07}, + {5,0x10,0x07}, + {6,0x09,0x40}, + {6,0x01,0x40}, + {6,0x02,0x00}, + {5,0x1a,0x00}, + {5,0x22,0x00}, + {6,0x0f,0x01}, + {6,0x03,0x03}, + {6,0x0b,0x03}, + {5,0x01,0x08}, + {5,0x09,0x08}, + {5,0x11,0x08}, + {2,0x05,0x00}, + {2,0x04,0xff}, + {5,0x18,0x00}, + {5,0x19,0x01}, + {5,0x1b,0x00}, + {5,0x20,0x00}, + {5,0x21,0x01}, + {5,0x23,0x00}, + {6,0x0e,0x00}, + {6,0x08,0x04} + } + }, + // 64 bit VRAM width + { + // Mode 0 - 640X480 8 bit 72Hz + { + {6,0x05,0x2c}, + {6,0x06,0x84}, + {6,0x07,0x84}, + {2,0x06,0x00}, + {6,0x0a,0x80}, + {6,0x0d,0x08}, + {5,0x00,0x07}, + {5,0x08,0x07}, + {5,0x10,0x07}, + {6,0x09,0x00}, + {6,0x01,0x40}, + {6,0x02,0x00}, + {5,0x1a,0x00}, + {5,0x22,0x00}, + {6,0x0f,0x01}, + {6,0x03,0x07}, + {6,0x0b,0x07}, + {5,0x01,0x08}, + {5,0x09,0x08}, + {5,0x11,0x08}, + {2,0x05,0x00}, + {2,0x04,0xff}, + {5,0x18,0x00}, + {5,0x19,0x01}, + {5,0x1b,0x00}, + {5,0x20,0x00}, + {5,0x21,0x01}, + {5,0x23,0x00}, + {6,0x0e,0x00}, + {6,0x08,0x04} + }, + + // Mode 15 - 1024X768 8 bit 60Hz + { + {6,0x05,0x37}, + {6,0x06,0x45}, + {6,0x07,0x84}, + {2,0x06,0x00}, + {6,0x0a,0x80}, + {6,0x0d,0x08}, + {5,0x00,0x07}, + {5,0x08,0x07}, + {5,0x10,0x07}, + {6,0x09,0x00}, + {6,0x01,0x40}, + {6,0x02,0x00}, + {5,0x1a,0x00}, + {5,0x22,0x00}, + {6,0x0f,0x01}, + {6,0x03,0x07}, + {6,0x0b,0x07}, + {5,0x01,0x08}, + {5,0x09,0x08}, + {5,0x11,0x08}, + {2,0x05,0x00}, + {2,0x04,0xff}, + {5,0x18,0x00}, + {5,0x19,0x01}, + {5,0x1b,0x00}, + {5,0x20,0x00}, + {5,0x21,0x01}, + {5,0x23,0x00}, + {6,0x0e,0x00}, + {6,0x08,0x04} + } + }, + // 128 bit VRAM width + { + // Mode 0 - 640X480 8 bit 72Hz + { + {6,0x05,0x2c}, + {6,0x06,0x84}, + {6,0x07,0x84}, + {2,0x06,0x00}, + {6,0x0a,0x80}, + {6,0x0d,0x08}, + {5,0x00,0x07}, + {5,0x08,0x07}, + {5,0x10,0x07}, + {6,0x09,0x00}, + {6,0x01,0x40}, + {6,0x02,0x00}, + {5,0x1a,0x00}, + {5,0x22,0x00}, + {6,0x0f,0x01}, + {6,0x03,0x07}, + {6,0x0b,0x07}, + {5,0x01,0x08}, + {5,0x09,0x08}, + {5,0x11,0x08}, + {2,0x05,0x00}, + {2,0x04,0xff}, + {5,0x18,0x00}, + {5,0x19,0x01}, + {5,0x1b,0x00}, + {5,0x20,0x00}, + {5,0x21,0x01}, + {5,0x23,0x00}, + {6,0x0e,0x00}, + {6,0x08,0x04} + }, + + // Mode 15 - 1024X768 8 bit 60Hz + { + {6,0x05,0x37}, + {6,0x06,0x45}, + {6,0x07,0x84}, + {2,0x06,0x00}, + {6,0x0a,0x80}, + {6,0x0d,0x08}, + {5,0x00,0x07}, + {5,0x08,0x07}, + {5,0x10,0x07}, + {6,0x09,0x00}, + {6,0x01,0x40}, + {6,0x02,0x00}, + {5,0x1a,0x00}, + {5,0x22,0x00}, + {6,0x0f,0x01}, + {6,0x03,0x07}, + {6,0x0b,0x07}, + {5,0x01,0x08}, + {5,0x09,0x08}, + {5,0x11,0x08}, + {2,0x05,0x00}, + {2,0x04,0xff}, + {5,0x18,0x00}, + {5,0x19,0x01}, + {5,0x1b,0x00}, + {5,0x20,0x00}, + {5,0x21,0x01}, + {5,0x23,0x00}, + {6,0x0e,0x00}, + {6,0x08,0x04} + } + } + }; + + + + // + // Setup the RAMDAC (Bt445) + // + // go table driven [rdl:01.03.95] + // + modeIndex = (Mode) ? 1 : 0; // if not mode 0, then make it mode 15. + for (i = 0; i < sizeof(btTab[0][0])/sizeof(BTTAB); i++) { + BTTAB tab = btTab[VramWidth][modeIndex][i]; + UCHAR value = tab.value; + + WRITE_REGISTER_UCHAR((PUCHAR)HalpIoControlBase + BT445_ADDRESS, tab.addr); + FireSyncRegister(); + + if (tab.reg == btMask[i][0] && tab.addr == btMask[i][1]) { + if (btMask[i][2]) { + value = READ_REGISTER_UCHAR((PUCHAR)HalpIoControlBase + BT445_ADDRESS + tab.reg); + value &= ~btMask[i][2]; + value |= btMask[i][2] & tab.value; + } + } else { + // + // btMask is out of order with respect to btTab + // + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + + WRITE_REGISTER_UCHAR((PUCHAR)HalpIoControlBase + BT445_ADDRESS + tab.reg, value); + FireSyncRegister(); + } + + // + // ...and program the color lookup table with "NT" colors + // starting pixel address for loading RGB values: + // + rRamDacAddr = 0; + FireSyncRegister(); + + // + // load the red, green, and blue data for pixel 0: + // + rDacPrimeLut = 0x00; + FireSyncRegister(); + rDacPrimeLut = 0x00; + FireSyncRegister(); + rDacPrimeLut = 0x00; + FireSyncRegister(); + + // + // load the red, green, and blue data for pixel 1: ( this gives NT + // the characteristice BLUE screen for booting ) + // + rDacPrimeLut = 0x00; + FireSyncRegister(); + rDacPrimeLut = 0x00; + FireSyncRegister(); + rDacPrimeLut = 0xff; + FireSyncRegister(); + + for (i=2; i<=0xff; i++) { + /* A grey ramp with entry 255 white */ + rDacPrimeLut = (UCHAR) i; + rDacPrimeLut = (UCHAR) i; + rDacPrimeLut = (UCHAR) i; + FireSyncRegister(); + } + + return; +} // Init Vram + +ULONG +HalpSetPixelColorMap( ULONG Color, ULONG Pixel ) +{ + UCHAR Red, Green, Blue, Control; + // + // set the display to red while in phase 0: + // + rRamDacAddr = (UCHAR) ( Pixel & 0x000000ff); + FireSyncRegister(); + + Control = (UCHAR) ( ( Color >> 24 ) & 0x000000ff ); + Red = (UCHAR) ( ( Color >> 16 ) & 0x000000ff ); + Green = (UCHAR) ( ( Color >> 8 ) & 0x000000ff ); + Blue = (UCHAR) ( Color & 0x000000ff ); + // + // load the red, green, and blue data for pixel 1: + // ( this is the normal NT BLUE boot screen ) + // + rDacPrimeLut = Red; // set this pixel to no red ... + FireSyncRegister(); + rDacPrimeLut = Green; // set this pixel to no green ... + FireSyncRegister(); + rDacPrimeLut = Blue; // set this pixel to max blue. + FireSyncRegister(); + return(0); +} + diff --git a/private/ntos/nthals/halfire/ppc/fpbt445.h b/private/ntos/nthals/halfire/ppc/fpbt445.h new file mode 100644 index 000000000..3b2d721f6 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpbt445.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpbt445.h $ + * $Revision: 1.7 $ + * $Date: 1996/01/11 07:05:32 $ + * $Locker: $ + * + * This file contains references to registers in the BrookTree Bt445 RamDac. + * + */ + +#ifndef FPBT445_H +#define FPBT445_H +/* +** The Bt445 organizes it's registers into a complex index based arrangement. +** The final data registers are actually accessed via some control bits which +** show up memory mapped. However, since each control address can access +** several registers, the register desired must be specified through the Bt445 +** index register. For example, if you want to read the ID value of the chip, +** you must write the id register value ( 0x00 ) to the Bt445 address ( index ). +** Then you must read the address that corresponds to control register 2. +** +*/ + +// +// defines for access to control register 0 ( c bits = 000 ) +// Use rRamDacAddr to access the Bt445 address register +// +#define BT_Address 0x00 // index register into the Bt445. + +// +// defines for access to control register 1 ( c bits = 001 ) +// Use rDacPrimeLut to access the primary color palette register +// NOTE: This register requires MODULO 3 loading and reading +// + + +// +// defines for access to control register 2 ( c bits = 010 ) +// use rRamDacCntl to access +// +#define DAC_ID_REG 0x00 // +#define DAC_REVISION_REG 0x01 +#define DAC_READ_ENABLE 0x04 +#define DAC_BLINK_ENABLE 0x05 +#define DAC_COMMAND_REG0 0x06 +#define DAC_TEST_REG0 0x07 + +// +// defines for access to control register 3 ( c bits = 011 ) +// use rDacOvlayLut to access the overlay color palette +// NOTE: This register requires MODULO 3 loading and reading +// + + +// +// defines for access to control register 5 ( c bits = 101 ) +// use rDacPixelBit to access the rgb pixel layout register +// +#define RED_MSB_POSITION 0x00 +#define RED_WIDTH_CNTL 0x01 +#define RED_DISPLAY_ENBL 0x02 +#define RED_BLINK_ENBL 0x03 + +#define GREEN_MSB_POSITION 0x08 +#define GREEN_WIDTH_CNTL 0x09 +#define GREEN_DISPLAY_ENBL 0x0A +#define GREEN_BLINK_ENBL 0x0B + +#define BLUE_MSB_POSITION 0x10 +#define BLUE_WIDTH_CNTL 0x11 +#define BLUE_DISPLAY_ENBL 0x12 +#define BLUE_BLINK_ENBL 0x13 + +#define OVRLY_MSB_POSITION 0x18 +#define OVRLY_WIDTH_CNTL 0x19 +#define OVRLY_DISPLAY_ENBL 0x1A +#define OVRLY_BLINK_ENBL 0x1B + +#define CURSOR_MSB_POSITION 0x20 +#define CURSOR_WIDTH_CNTL 0x21 +#define CURSOR_DISPLAY_ENBL 0x22 +#define CURSOR_BLINK_ENBL 0x23 + + + +// +// defines for access to control register 6 ( c bits = 110 ) +// use rDacPixelClks to access +// +#define TEST_REG1 0x00 +#define COMMAND_REG1 0x01 +#define DIGI_OUT_CNTL 0x02 +#define VIDCLK_CYCLE 0x03 +#define PIXEL_PLL_RATE0 0x05 +#define PIXEL_PLL_RATE1 0x06 +#define PLL_CONTROL 0x07 +#define PIXEL_LOAD_CNTL 0x08 +#define PIXEL_PORT_START 0x09 +#define PIXEL_FORMAT_CNTL 0x0A +#define MPX_RATE_REG 0x0B +#define SIG_ANLYS_REG 0x0C +#define PIXEL_DEPTH_CNTL 0x0D +#define PALETTE_BYPASS_POS 0x0E +#define PALETTE_BYPASS_WIDTH 0x0F + +// +// defines for access to control register 7 ( c bits = 111 ) +// use rRamDacCursor to access the cursor color register +// NOTE: This register requires MODULO 3 loading and reading +// +#define CURSOR_CLR0 0x00 +#define CURSOR_CLR1 0x01 +#define CURSOR_CLR2 0x02 +#define CURSOR_CLR3 0x03 + +/* +** +**.................... Bit Field Definitions........................ +** +*/ + +// +// Command Register 0 bit masks: +// +#define USE_PALETTE 0x40 // use color palette not overlay color 0 +// +// These defines cover TWO bits: bit positions 4 and 5 +// +#define BLINK_16ON_48OFF 0x00 +#define BLINK_16ON_16OFF 0x10 +#define BLINK_32ON_32OFF 0x20 +#define BLINK_64ON_64OFF 0x30 +#define ENBL_OVRLY0_BLINK 0x04 +#define ENBL_OVRLY1_BLINK 0x08 +#define ENBL_OVRLY0_DSPLY 0x02 +#define ENBL_OVRLY1_DSPLY 0x01 + +// +// COMMAND_REG1: Bit fields +// +#define ENABLE_GREEN_SYNC 0x80 // generate sync on the IOG output +#define IRE75_PEDESTAL 0x40 // generate a blank pedestal of 7.5 IRE +#define NORMAL_POWER_OP 0x00 // normal operations ( i.e. no pwr dwn ) +#define PWR_OFF_DACS 0x08 // Turn off DACs. functionally still ops +#define DAC_RAM_OFF 0x10 // Dac and Ram off: no functions out +#define DAC_RAM_CLKS_OFF 0x18 // turn off clocks too +#define RIGHT_JSTFY_PIXBITS 0x04 // right justify pixels and zero extend +#define ENABLE_SIG_ANLYS 0x02 // turn on SAR +#define RESET_PIPE_DEPTH 0x01 + +// Pixel Timing Register: Field definitions: +// + +/* +** Pixel Format Control Fields ( PIXEL_FORMAT_CNTL register ) +** +*/ +#define UNPACK_LSB_FIRST 0x80 +#define ENABLE_CURSOR 0x20 +#define ENABLE_CURSOR_COLOR0 0x10 +#define ENABLE_OVERLAY 0x08 +#define USE_COLOR_PALETTE 0x00 +#define BYPASS_COLOR_PALETTE 0x01 +#define USE_INPUT_PIXEL_FIELD 0x02 + +/* +** Pixel PLL Rate Register 0 +*/ + +// +// Prototype Declarations +// + +VOID HalpSetupBt445( ULONG, ULONG ); +ULONG HalpSetPixelColorMap( ULONG Color, ULONG Pixel ); + +#endif diff --git a/private/ntos/nthals/halfire/ppc/fpcpu.h b/private/ntos/nthals/halfire/ppc/fpcpu.h new file mode 100644 index 000000000..9a18fbdaa --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpcpu.h @@ -0,0 +1,179 @@ + +/* + * Copyright (c) 1995. FirePower Systems, Inc. + * (Do Not Distribute without permission) + * + * $RCSfile: fpcpu.h $ + * $Revision: 1.8 $ + * $Date: 1996/05/14 02:32:23 $ + * $Locker: $ + * + */ + +#ifndef FPCPU_h +#define FPCPU_h + +// +// These defines setup access to the power pc chip itself. Reliance upon the +// defines will isolate code from power pc chip variations and ease migration +// to new cpus +// + + + +// +// Since the documentation refers to the bit positions of the cpu fields in +// IBM relative format, handle the conversion of IBM bit position to shift +// arguments +// +#define WORD(x) (( 1 ) << ( 31 - x )) + + +/* +************************************************************************ +** +** Machine State Register +** +************************************************************************ +*/ +// +// pull a bit out of the MSR: this is based on IBM bit ordering as shown in +// the powerpc books ( 0 == MSB ) +// + +// #define MSR(x) ( ( HalpReadMsr() >> ( 31 - x ) ) & 0x01 ) +#define MSR(x) ( ( __builtin_get_msr() >> ( 31 - x ) ) & 0x01 ) + +#define POW 13 // Power Management Enable +#define TGPR 14 // Temporary GPR remapping +#define ILE 15 // Exception Little-endian mode +#define EE 16 // External interrupt enable +#define PR 17 // Privilege Level +#define FP 18 // Floating Point Enable +#define ME 19 // Machine Check Enable +#define FE0 20 // Floating Point Exception mode 0 +#define SE 21 // single step trace enable +#define BE 22 // Branch Trace Enable +#define FE1 23 // floating point exception mode 1 +#define IP 25 // Exception Prefix ( exception vector is 0xff... ? +#define IR 26 // Instruction Address Translation +#define DR 27 // Data Address Translation +#define RI 30 // Recoverable Exception +#define LE 31 // Endian bit (little or big ) + +// +// setup Flags to go along with the MSR bits +// +#define ENABLE_PWR_MGMT WORD( POW ) +#define ENABLE_GPR_REMAP WORD( TGPR ) +#define EXCEPTION_LE WORD( ILE ) +#define ENABLE_EXTERNAL_INTS WORD( EE ) +#define EXEC_AT_USER_LEVEL WORD( PR ) +#define FLOAT_PT_AVAIL WORD( FP ) +#define ENABLE_MACHINE_CHK WORD( ME ) +#define FLOAT_EXCPT_MODE0 WORD( FE0 ) +#define ENABLE_SGL_STP_TRCE WORD( SE ) +#define ENABLE_BRNCH_TRCE WORD( BE ) +#define FLOAT_EXCPT_MODE1 WORD( FE1 ) +#define EXCPT_PREFX_0xFFF WORD( IP ) +#define ENABLE_INSTR_TRANS WORD( IR ) +#define ENABLE_DATA_TRANS WORD( DR ) +#define EXCPTION_IS_RECOVBL WORD( RI ) +#define RUN_LITTLE_ENDIAN WORD( LE ) + + +/* +************************************************************************ +** +** Processor Version Register +** +************************************************************************ +*/ +#define CPU_VERSION ( ( ( HalpReadProcessorRev ) & 0xffff0000 ) >> 16 ) +#define CPU_REVISION ( ( ( HalpReadProcessorRev ) & 0x0000ffff ) ) + + +/* +************************************************************************ +** +** Block Address Translation registers +** +************************************************************************ +*/ +// +// Here are defines for the UPPER 32 bit bat register: +// +#define PAGE_INDEX_BITS 0xfffe0000 +#define BLK_EFF_PI(x) ( x & PAGE_INDEX_BITS ) + +#define A_128K_BLOCK_SIZE 0x00000000 +#define A_256K_BLOCK_SIZE 0x00000004 +#define A_512K_BLOCK_SIZE 0x0000000c +#define A_1MEG_BLOCK_SIZE 0x0000001c +#define A_2MEG_BLOCK_SIZE 0x0000003c +#define A_4MEG_BLOCK_SIZE 0x0000007c +#define A_8MEG_BLOCK_SIZE 0x000000fc +#define A_16MB_BLOCK_SIZE 0x000001fc +#define A_32MB_BLOCK_SIZE 0x000003fc +#define A_64MB_BLOCK_SIZE 0x000007fc +#define A_128M_BLOCK_SIZE 0x00000ffc +#define A_256M_BLOCK_SIZE 0x00001ffc + +#define SUPERVISOR_ONLY 0x00000002 +#define USER_ACCESS_VALID 0x00000001 + +// +// The Lower BAT Register +// +#define BLOCK_REAL_PAGE_NUMBER(x) ( (x >> 8) & REAL_BITS) + +// +// WIMG: VIMVENDERS BITS: +// +#define WRITE_THROUGH 0x00000040 +#define CACHE_INHIBIT 0x00000020 +#define MEMORY_COHRNCY 0x00000010 +#define GUARDED_BLOCK 0x00000008 // for IBAT use only.... + +#define PAGE_RW_ACCESS 0x00000002 +#define PAGE_RO_ACCESS 0x00000001 +#define PAGE_UNAVAILBL 0x00000000 + + +/* +************************************************************************ +** +** Hardware Implementation Register 0 ( HID0 ) +** +************************************************************************ +*/ + +#define EMCP 0 // Enable Machine Check Pin +#define EBA 2 // Enable Bus Address Parity Checking +#define EBD 3 // Enable Bus Data Parity Checking +#define SBCLK 4 // selct bus clock for test clock pin +#define EICE 5 // Enable ISE outputs: pipeline tracking support +#define ECLK 6 // Enable external test clock pin +#define PAR 7 // Disable precharge of ARTRY_L and shared signals +#define DOZE 8 // Doze mode: pll, time base, and snooping active +#define NAP 9 // Nap Mode: pll and time base active +#define SLEEP 10 // Sleep mode: no external clock required +#define DPM 11 // Enable Dynamic power management +#define RISEG 12 // Reserved for test +#define ICE 16 // Instruction cache enable +#define DCE 17 // Data cache enable +#define ILOCK 18 // lock instruction cache +#define DLOCK 19 // lock data cache +#define ICFI 20 // instruction cache flash invalidate +#define DCI 21 // Data cache flash invalidate +#define FBIOB 27 // Force branch indirect on bus +#define NOOPTI 31 // No-op touch instructions + +#define ENABLE_ICACHE WORD( ICE ) +#define ENABLE_DCACHE WORD( DCE ) +#define LOCK_ICACHE WORD( ILOCK ) +#define LOCK_DCACHE WORD( DLOCK ) +#define INVLIDAT_ICACHE WORD( ICFI ) +#define INVLIDAT_DCACHE WORD( DCI ) + +#endif diff --git a/private/ntos/nthals/halfire/ppc/fpcpu.s b/private/ntos/nthals/halfire/ppc/fpcpu.s new file mode 100644 index 000000000..c052c9787 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpcpu.s @@ -0,0 +1,387 @@ +//++ +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxsystem.s +// +// Abstract: +// +// This module implements the routines to handle system functions: +// Provides system specific info. +// Currently provides processor version type +// +// Author: +// breeze@firepower.com +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpcpu.s $ + * $Revision: 1.12 $ + * $Date: 1996/01/11 07:05:51 $ + * $Locker: $ + */ + +#include "kxppc.h" +#include "fpcpu.h" + + .set BatValue, r.3 +//++ +// +// Routine Description: +// +// +// Arguments: +// None +// +// +// Return Value: +// Processor Version register value +// +// +//-- + + + LEAF_ENTRY(HalpReadProcessorRev) + mfpvr r.3 // get processor version + LEAF_EXIT(HalpReadProcessorRev) + + + +//++ +// +// Routine Description: +// +// +// Arguments: +// None +// +// +// Return Value: +// Machine State register value +// +// +//-- + + + LEAF_ENTRY(HalpGetStack) + or r3, r1, r1 // get stack value + LEAF_EXIT(HalpGetStack) + + +//++ +// +// Routine Description: +// +// +// Arguments: +// None +// +// +// Return Value: +// Machine State register value +// +// +//-- + + + LEAF_ENTRY(HalpReadMSR) + mfmsr r.3 // get processor version + LEAF_EXIT(HalpReadMSR) + +/***************************************************************************** + Synopsis: + ULONG HalpReadIbatUpper(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit upper instruction BAT value + for a given . + + Returns: + Returns the 32-bit upper BAT value. +*****************************************************************************/ + + .set BatNumber, r.3 + + LEAF_ENTRY(HalpReadIbatUpper) + + cmpli 0,0,BatNumber,0 + bne NotUI0 + mfibatu BatNumber,0 + b ExitUI +NotUI0: + cmpli 0,0,BatNumber,1 + bne NotUI1 + mfibatu BatNumber,1 + b ExitUI +NotUI1: + cmpli 0,0,BatNumber,2 + bne NotUI2 + mfibatu BatNumber,2 + b ExitUI +NotUI2: + mfibatu BatNumber,3 // OK, it's three by default + +ExitUI: + + LEAF_EXIT(HalpReadIbatUpper) + +/***************************************************************************** + Synopsis: + ULONG HalpReadIbatLower(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit lower instruction BAT value for given . + + Returns: + Returns the 32-bit lower BAT value. +*****************************************************************************/ + + LEAF_ENTRY(HalpReadIbatLower) + + cmpli 0,0,BatNumber,0 + bne NotLI0 + mfibatl BatNumber,0 + b ExitLI +NotLI0: + cmpli 0,0,BatNumber,1 + bne NotLI1 + mfibatl BatNumber,1 + b ExitLI +NotLI1: + cmpli 0,0,BatNumber,2 + bne NotLI2 + mfibatl BatNumber,2 + b ExitLI +NotLI2: + mfibatl BatNumber,3 // OK, it's three by default + +ExitLI: + + LEAF_EXIT(HalpReadIbatLower) + +/***************************************************************************** + Synopsis: + ULONG HalpReadDbatUpper(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit upper data BAT value for a given . + + Returns: + Returns the 32-bit upper BAT value. +*****************************************************************************/ + + LEAF_ENTRY(HalpReadDbatUpper) + + cmpli 0,0,BatNumber,0 + bne NotUD0 + mfdbatu BatNumber,0 + b ExitUD +NotUD0: + cmpli 0,0,BatNumber,1 + bne NotUD1 + mfdbatu BatNumber,1 + b ExitUD +NotUD1: + cmpli 0,0,BatNumber,2 + bne NotUD2 + mfdbatu BatNumber,2 + b ExitUD +NotUD2: + mfdbatu BatNumber,3 // OK, it's three by default + +ExitUD: + + LEAF_EXIT(HalpReadDbatUpper) + +/***************************************************************************** + Synopsis: + ULONG HalpReadDbatLower(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit lower data BAT value for a given . + + Returns: + Returns the 32-bit lower BAT value. +*****************************************************************************/ + + LEAF_ENTRY(HalpReadDbatLower) + + cmpli 0,0,BatNumber,0 + bne NotLD0 + mfdbatl BatNumber,0 + b ExitLD +NotLD0: + cmpli 0,0,BatNumber,1 + bne NotLD1 + mfdbatl BatNumber,1 + b ExitLD +NotLD1: + cmpli 0,0,BatNumber,2 + bne NotLD2 + mfdbatl BatNumber,2 + b ExitLD +NotLD2: + mfdbatl BatNumber,3 // OK, it's three by default + +ExitLD: + + LEAF_EXIT(HalpReadDbatLower) + +/***************************************************************************** + Synopsis: + VOID HalpSetDbat3Lower(ULONG BatValue) [ged] + + Purpose: + Writes the 32-bit lower data BAT value to DBAT3. + + Returns: + Nothing +*****************************************************************************/ + + + LEAF_ENTRY(HalpSetDbat3Lower) + + mtdbatl 3,BatValue + + LEAF_EXIT(HalpSetDbat3Lower) + +/***************************************************************************** + Synopsis: + VOID HalpSetDbat3Lower(ULONG BatValue) [ged] + + Purpose: + Writes the 32-bit lower data BAT value to DBAT1. + + Returns: + Nothing +*****************************************************************************/ + + LEAF_ENTRY(HalpSetDbat2Lower) + + mtdbatl 2,BatValue + + LEAF_EXIT(HalpSetDbat2Lower) + +/***************************************************************************** + Synopsis: + VOID HalpSetDbat3Lower(ULONG BatValue) [ged] + + Purpose: + Writes the 32-bit lower data BAT value to DBAT1. + + Returns: + Nothing +*****************************************************************************/ + + LEAF_ENTRY(HalpSetDbat1Lower) + + mtdbatl 1,BatValue + + LEAF_EXIT(HalpSetDbat1Lower) + +/***************************************************************************** + Synopsis: + VOID HalpSetDbat3Lower(ULONG BatValue) [ged] + + Purpose: + Writes the 32-bit lower data BAT value to DBAT1. + + Returns: + Nothing +*****************************************************************************/ + + LEAF_ENTRY(HalpSetDbat0Lower) + + mtdbatl 0,BatValue + + LEAF_EXIT(HalpSetDbat0Lower) + + +/***************************************************************************** + Synopsis: + VOID HalpGetInstructionTimes() + + Purpose: + run a 1024 instructions measure how long the cpu needs to + execute them ( measured by time base value which is 1/4 bus speed ) + + Algorithm: + string together 8 instructions so that they are dependent on their + preceding neighbor and loop through this set of 8 instructions 128 + times. Compare the lower time base register's value before and after + this instruction run. + + To guarentee correct timing, this routine waits for the lower time base + register to 'flip' to the new value and then start running the test + instructions. The run is done three times to make sure the entire + sequence is in L1 cache. + + The Time Base runs at 1/4 bus speed so the number of instructions + that the cpu executes for a given amount of time is measured as + the amount of time required to run 1024 instructions. If the time + base changes by 256 'ticks' then the cpu is running at bus speed. + + Returns: the incremental change in the time base lower register + +*****************************************************************************/ + + //.set LOOPCOUNT, 0x400 // 8 * real loop count (8 * 0x80 ). + .set LOOPCOUNT, 0x780 // 8 * real loop count (8 * 0x80 ). + LEAF_ENTRY(HalpGetInstructionTimes) + + sync + andi. r10,r9,0 // zero r10: holds the current loop count + andi. r8,r9,0 // zero r8: holds the do again flag. + andi. r7,r9,0 // zero r7: execution time within each loop through + andi. r3,r9,0 // zero r3: maintain summation of execution times + andi. r9,r9,0 // zero r9: holds the current loop count + sync +START: mftb r6 // save off the starting value of lower time + // base register +CHECK: mftb r5 // check the time base again and see if it's just + // changed.... + cmp 0,0,r5,r6 + beq CHECK // wait for a new time period to start... + + // + // Run through some single cycle instructions. In order to defeat + // the double issue pipes of the ppc, create a dependency between + // an instruction and the preceding instruction. This will more + // accurately reflect the amount of time the cpu uses to execute + // an instruction in a stream relative to the bus frequency. + // +TIMES: addi r9,r9,1 + addi r9,r9,1 + addi r9,r9,1 + addi r9,r9,1 + addi r9,r9,1 + addi r9,r9,1 + addi r9,r9,1 + addi r9,r9,1 + + cmpi 0,0,r9,LOOPCOUNT + bne TIMES // bc 4,2,TIMES + mftb r6 // save off ending value of lower time base register + sync + andi. r9,r9,0 // zero r9: in preparation for another pass + addi r8,r8,1 // increment the flag + cmpli 0,0,r8,2 // compare the flag to '2'. Ensure the last pass + // through is fully out of L1 cache. + blt START // to make sure we're in cache, branch back. + subf r3,r5,r6 // subtract r5 from r6 and store in r3 and return. + + LEAF_EXIT(HalpGetInstructionTimes) diff --git a/private/ntos/nthals/halfire/ppc/fpdcc.c b/private/ntos/nthals/halfire/ppc/fpdcc.c new file mode 100644 index 000000000..33b5a175b --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpdcc.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpdcc.c $ + * $Revision: 1.12 $ + * $Date: 1996/01/11 07:06:05 $ + * $Locker: $ + * + * This file contains references to registers in the display controller chip + * known as the DCC. This chip control's vram setup and works in conjunction + * with the ram dac which, in this case is a Brooktree Bt485. + * + */ + +#include "halp.h" +#include "phsystem.h" +#include "fpio.h" +#include "fpDcc.h" +#include "fpbt445.h" + +VOID +HalpSetupDCC( + ULONG Mode, + ULONG VramWidth + ); +/*++ + +Routine Description: VOID HalpSetupDCC() + + This routine initializes the display hardware for 640x480 in preparation + for HalDisplayString(). This means that either we are booting up or + dealing with the blue screen of death. We should really change this to + a higher resolution ASAP. [ged] + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +VOID +HalpSetupDCC( + ULONG Mode, + ULONG VramWidth + ) +{ + LONG modeIndex; + LONG i; + + // + // DCC Config A + // + UCHAR configA[NUMBER_OF_VRAM_WIDTH_TYPES] = { + A_1to1_64BitDac | HSYNC_ENABLE | VSYNC_ENABLE | CSYNC_ENABLE, + A_1to1_64BitDac | HSYNC_ENABLE | VSYNC_ENABLE | CSYNC_ENABLE, + A_2to1_64BitDac | HSYNC_ENABLE | VSYNC_ENABLE | CSYNC_ENABLE + }; + + // [rdl:01.03.95] + typedef struct { + UCHAR reg; + UCHAR value; + } DCCTAB; + + // [rdl:01.03.95] + DCCTAB DCCtab[3 /* 32/64/128 bit vram */][2 /* mode 0 or 15 */][13] = { + // 32 bit VRAM width + { + // [0] Mode 0 - 640X480 8 bit 72Hz + { + {HZNTL_COUNT_L,0xcf}, + {HZNTL_COUNT_H,0x00}, + {VERT_COUNT_L,0x07}, + {VERT_COUNT_H,0x02}, + {HZNTL_SYNC_STOP,0x09}, + {HZNTL_BLK_STP_L,0x29}, + {HZNTL_BLK_STP_H,0x00}, + {HZNTL_DTA_STP_L,0xc9}, + {HZNTL_DTA_STP_H,0x00}, + {VERT_SYNC_STOP,0x02}, + {VERT_BLK_STOP,0x1e}, + {VERT_DTA_STP_L,0xfe}, + {VERT_DTA_STP_H,0x01} + }, + // [1] Mode 15 - 1024X768 8 bit 60Hz + { + {HZNTL_COUNT_L,0x4f}, + {HZNTL_COUNT_H,0x01}, + {VERT_COUNT_L,0x25}, + {VERT_COUNT_H,0x03}, + {HZNTL_SYNC_STOP,0x21}, + {HZNTL_BLK_STP_L,0x49}, + {HZNTL_BLK_STP_H,0x00}, + {HZNTL_DTA_STP_L,0x49}, + {HZNTL_DTA_STP_H,0x01}, + {VERT_SYNC_STOP,0x05}, + {VERT_BLK_STOP,0x22}, + {VERT_DTA_STP_L,0x22}, + {VERT_DTA_STP_H,0x03}, + } + }, + // 64 bit VRAM width + { + // [0] Mode 0 - 640X480 8 bit 72Hz + { + {HZNTL_COUNT_L,0x67}, + {HZNTL_COUNT_H,0x00}, + {VERT_COUNT_L,0x07}, + {VERT_COUNT_H,0x02}, + {HZNTL_SYNC_STOP,0x04}, + {HZNTL_BLK_STP_L,0x14}, + {HZNTL_BLK_STP_H,0x00}, + {HZNTL_DTA_STP_L,0x64}, + {HZNTL_DTA_STP_H,0x00}, + {VERT_SYNC_STOP,0x02}, + {VERT_BLK_STOP,0x1e}, + {VERT_DTA_STP_L,0xfe}, + {VERT_DTA_STP_H,0x01} + }, + // [1] Mode 15 - 1024X768 8 bit 60Hz + { + {HZNTL_COUNT_L,0xa7}, + {HZNTL_COUNT_H,0x00}, + {VERT_COUNT_L,0x25}, + {VERT_COUNT_H,0x03}, + {HZNTL_SYNC_STOP,0x10}, + {HZNTL_BLK_STP_L,0x24}, + {HZNTL_BLK_STP_H,0x00}, + {HZNTL_DTA_STP_L,0xa4}, + {HZNTL_DTA_STP_H,0x00}, + {VERT_SYNC_STOP,0x05}, + {VERT_BLK_STOP,0x22}, + {VERT_DTA_STP_L,0x22}, + {VERT_DTA_STP_H,0x03}, + } + }, + // 128 bit VRAM width + { + // [0] Mode 0 - 640X480 8 bit 72Hz + { + {HZNTL_COUNT_L,0x67}, + {HZNTL_COUNT_H,0x00}, + {VERT_COUNT_L,0x07}, + {VERT_COUNT_H,0x02}, + {HZNTL_SYNC_STOP,0x04}, + {HZNTL_BLK_STP_L,0x14}, + {HZNTL_BLK_STP_H,0x00}, + {HZNTL_DTA_STP_L,0x64}, + {HZNTL_DTA_STP_H,0x00}, + {VERT_SYNC_STOP,0x02}, + {VERT_BLK_STOP,0x1e}, + {VERT_DTA_STP_L,0xfe}, + {VERT_DTA_STP_H,0x01} + }, + // [1] Mode 15 - 1024X768 8 bit 60Hz + { + {HZNTL_COUNT_L,0xa7}, + {HZNTL_COUNT_H,0x00}, + {VERT_COUNT_L,0x25}, + {VERT_COUNT_H,0x03}, + {HZNTL_SYNC_STOP,0x10}, + {HZNTL_BLK_STP_L,0x24}, + {HZNTL_BLK_STP_H,0x00}, + {HZNTL_DTA_STP_L,0xa4}, + {HZNTL_DTA_STP_H,0x00}, + {VERT_SYNC_STOP,0x05}, + {VERT_BLK_STOP,0x22}, + {VERT_DTA_STP_L,0x22}, + {VERT_DTA_STP_H,0x03}, + } + } + }; + + + // + // Disable all counters and state machines before we go messing around. + // + rDccIndex = dccConfigB; + FireSyncRegister(); + rDccData = DCC_HALT_CLK; + FireSyncRegister(); + + HalpSetupBt445(Mode, VramWidth); + + // + // Setup the DCC + // + rDccIndex = dccIntReg; + FireSyncRegister(); + rDccData = 0x00; // Clear the interrupt bit ( bit 0 ) + FireSyncRegister(); + + rDccIndex = dccTimingA; + FireSyncRegister(); + rDccData = 0x07; // delay syncs by 7 DispClk cycles + FireSyncRegister(); + + rDccIndex = dccConfigA; + FireSyncRegister(); + rDccData = configA[VramWidth]; + FireSyncRegister(); + +#define DCC_STORE(reg,val) { \ + WRITE_REGISTER_UCHAR((PUCHAR)HalpIoControlBase + DCC_INDEX, reg); \ + WRITE_REGISTER_UCHAR((PUCHAR)HalpIoControlBase + DCC_DATA, val); \ +} + + // go table driven [rdl:01.03.95] + modeIndex = (Mode) ? 1 : 0; // if not mode 0, then make it mode 15. + for (i = 0; i < sizeof(DCCtab[0][0])/sizeof(DCCTAB); i++) { + DCCTAB tab = DCCtab[VramWidth][modeIndex][i]; + DCC_STORE(tab.reg, tab.value); + } + + rDccIndex = dccConfigB; // Turn on counters, *DO LAST* + FireSyncRegister(); + rDccData = 0x00; + FireSyncRegister(); + + return; +} // HalpSetupDCC diff --git a/private/ntos/nthals/halfire/ppc/fpdcc.h b/private/ntos/nthals/halfire/ppc/fpdcc.h new file mode 100644 index 000000000..09a27bc11 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpdcc.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * (Do Not Distribute without permission) + * + * $RCSfile: fpdcc.h $ + * $Revision: 1.11 $ + * $Date: 1996/01/11 07:06:16 $ + * $Locker: $ + * + * This file contains references to registers in the display controller chip + * known as the DCC. This chip control's vram setup and works in conjunction + * with the ram dac which, in this case is a Brooktree Bt445. + * + */ + +#ifndef FPDCC_H +#define FPDCC_H + +// +// Prototype declarations for routines in fpDcc.c + + +// The dcc registers are not memory mapped but are indexed map through the +// dcc Index register. To access any dcc specific register, write the register +// value to the index register and either read or write data through the data +// register. See fpio.h for the macros to write to these registers +// +// register and address offset +//----------------------------- +// +#define dccIndex DCC_INDEX + +#define dccID 0x00 // ID register +#define dccMonId 0x01 // Monitor and Panel ID +#define dccGpioA 0x02 // General Purpose I/O register A +#define dccIntReg 0x03 // Interrupt Status +#define dccPLL 0x04 // PLL Interface Register +#define dccTimingA 0x05 // Timing Register A +#define dccConfigA 0x06 // Configuration Register A +#define dccConfigB 0x07 // Configuration Register B +#define dccHCntLow 0x08 // Hoizontal Count Low +#define dccHCntHigh 0x09 // Hoizontal Count High +#define dccVCntLow 0x0A // Vertical Count Low +#define dccVCntHigh 0x0B // Vertical Count High +#define dccHSyncStop 0x0C // Hoizontal Sync Stop +#define dccHBlankStopLow 0x0D // Horizontal Blank Stop low +#define dccHBlankStopHigh 0x0E // Horizontal Blank Stop High +#define dccHDataStopLow 0x0F // Horizontal Data Stop Low +#define dccHDataStopHigh 0x10 // Horizontal Data Stop High +#define dccVSyncStop 0x11 // Vertical Sync Stop +#define dccVBlankStop 0x12 // Vertical Blank Stop +#define dccVDataStopLow 0x13 // Vertical Data Stop Low +#define dccVDataStopHigh 0x14 // Vertical Data Stop High +#define dccCSynicStartLow 0x15 // Composite Sync Start Low +#define dccCSyncStartHigh 0x16 // Composite Sync Start High +#define dccLineStart 0x17 // Line Start +#define dccLineStop 0x18 // Line Stop +#define dccFrameStart 0x19 // Frame Start +#define dccFrameStop 0x1a // Frame Stop +#define dccIntTriggerLow 0x1B // Interrupt Trigger Low +#define dccIntTriggerHigh 0x1C // Interrupt Trigger High +#define dccTimingB 0x1D // Timing Register B +#define dccGpioB 0x1E // General Purpose I/O register B + +// +// 0x1E - 0x3F reserved; +// + +// +// Inidividual bit mappings for register use: + +#define INT_BIT 0x01 // LSB of Interrupt Register: dccIntReg + +#define PLL_CLK 0x01 // PLL clock bit in Pll Interface: dccPLL +#define PLL_DATA 0x02 // Data Bit for the PLL port. +#define PLL_WnotR 0x04 // this bit activates the Pll data driver. + +#define HV_SYNC_DELAY 0x0f +#define CSYNC_DELAY 0xf0 + +// +// Configuration Register A +// +#define HSYNC_ENABLE 0x01 // enable Horizontal Sync pulse +#define VSYNC_ENABLE 0x02 // enable Vertical Sync pulse +#define CSYNC_ENABLE 0x04 // enable Composite Sync pulse +#define FRAME_ENABLE 0x08 // enable Frame pulse +#define LINE_ENABLE 0x10 // enable Line pulse + +#define A_1to1_32BitDac 0x00 // 1:1 mux mode, frequency = DispClk +#define AB_2to1_32BitDac 0x20 // 2:1 mux mode, frequency = 1/2DispClk +#define A_1to1_64BitDac 0x80 // 1:1 mux, 64 bit Data width, f=DispClk +#define A_2to1_32BitDac 0xA0 // 2:1 mux, 32 bit width, f=1/2(DispClk) +#define A_2to1_64BitDac 0xC0 // 2:1 mux, 64 bit width, f=1/2(DispClk) +#define A_4to1_32BitDac 0xE0 // 4:1 mux, 32 bit width, f=1/4(DispClk) + +// +// Configuration Register B +// +#define HSYNC_ACTV_HIGH 0x01 // Active High state for Horizontal Sync +#define VSYNC_ACTV_HIGH 0x02 // Active High state for Vertical Sync +#define CSYNC_ACTV_HIGH 0x04 // Active High state for Composite Sync +#define FRAME_ACTV_HIGH 0x08 // Active High state for Frame Pulse +#define LINE_ACTV_HIGH 0x10 // Active High state for Line Pulse +#define BLANK_ACTV_HIGH 0x20 // Active High state for Blanking Pulse +#define DCC_HALT_CLK 0x80 // Disables and Resets all counters and state + // machines. Xbus interface is still active. + +// DCC Definitions +#define INT_STATUS 0x03 +#define PLL_INTERFACE 0x04 +#define TIMING_A 0x05 +#define CONFIG_A 0x06 +#define CONFIG_B 0x07 +#define HZNTL_COUNT_L 0x08 +#define HZNTL_COUNT_H 0x09 +#define VERT_COUNT_L 0x0a +#define VERT_COUNT_H 0x0b +#define HZNTL_SYNC_STOP 0x0c +#define HZNTL_BLK_STP_L 0x0d +#define HZNTL_BLK_STP_H 0x0e +#define HZNTL_DTA_STP_L 0x0f +#define HZNTL_DTA_STP_H 0x10 +#define VERT_SYNC_STOP 0x11 +#define VERT_BLK_STOP 0x12 +#define VERT_DTA_STP_L 0x13 +#define VERT_DTA_STP_H 0x14 +#define GPIO_B 0x1e + + +// +// VRAM width list. +// + +typedef enum _DCC_VRAM_WIDTH { + VRAM_32BIT = 0, + VRAM_64BIT, + VRAM_128BIT, + NUMBER_OF_VRAM_WIDTH_TYPES +} DCC_VRAM_WIDTH; + +#endif diff --git a/private/ntos/nthals/halfire/ppc/fpdebug.h b/private/ntos/nthals/halfire/ppc/fpdebug.h new file mode 100644 index 000000000..b39899b86 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpdebug.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpdebug.h $ + * $Revision: 1.30 $ + * $Date: 1996/01/11 07:06:23 $ + * $Locker: $ + */ + +#ifndef _FPDEBUG_H +#define _FPDEBUG_H + +#include "fpdcc.h" // to cover the led writing macro..... + +// +// This file provides an interface that allows individual debug printfs +// to be turned on and off in the HAL based on an environment variable. +// It also provides a means for turning on/off debug functionality +// (like auto stopping at a break point). +// + +// +// Externs for global variables stuffed at run-time +// Default values are provided in sources files +// +#if defined(HALDEBUG_ON) +extern int HalpDebugValue; +#endif + +// +// Macros used in C code to access the debug funcationality +// + +// +// Since DBG is always defined ( at least as of 2/6/95 ), must change the test +// to look at the value of DBG +// +// #if !defined(DBG) +// #if DBG != 1 +#if !defined(HALDEBUG_ON) +#define HDBG(_value, _str) +#define RDBG(_value, _str) +#else +#define DBGSET(_value) ((_value)&(HalpDebugValue)) + +#define HDBG(_value, _str) \ + { \ + if (DBGSET(_value)) { \ + _str; \ + } \ + } + +#endif + +// +// Defines used in the C code for each of the values, +// so someone can tell what bits to turn on. +// +// Note: behavioral changes are at the top portion of the word and +// simple informational ones are at the bottom portion of the word. +// +#define DBG_GENERAL 0x00000001 +#define DBG_EXTERNAL 0x00000002 +#define DBG_INTERNAL 0x00000004 +#define DBG_INTERRUPTS 0x00000008 +#define DBG_DUMPTREE 0x00000010 +#define DBG_IPI 0x00000020 +#define DBG_DBAT 0x00000040 +#define DBG_REGISTRY 0x00000080 +#define DBG_DMA 0x00000100 +#define DBG_ISA 0x00000200 +#define DBG_MPINTS 0x00000400 +#define DBG_PCI 0x00000800 +#define DBG_DISPLAY 0x00001000 +#define DBG_I2C 0x00002000 +#define DBG_TIME 0x00004000 + +#define DBG_BUS 0x04000000 +#define DBG_DISPMEMCOHERE 0x08000000 +#define DBG_DISPNOCACHE 0x10000000 +#define DBG_COLORS 0x20000000 +#define DBG_BREAK 0x40000000 +#define DBG_PROC1DBG 0x80000000 + +#define PRNTGENRL(_str) HDBG(DBG_GENERAL, _str) +#define PRNTINTR(_str) HDBG(DBG_INTERRUPTS, _str) +#define PRNTPCI(_str) HDBG(DBG_PCI, _str) +#define PRNTREE(_str) HDBG(DBG_DUMPTREE, _str) +#define PRNTDISP(_str) HDBG(DBG_DISPLAY, _str) +#define PRNTI2C(_str) HDBG(DBG_I2C, _str) +#define PRNTTIME(_str) HDBG(DBG_TIME, _str) + + +// +// Assert macro definitions for the HAL - Checked/Debug Builds only +// +#if defined(HALDEBUG_ON) +#define _assert_begin(_exp) \ + ULONG holdit,ee,CpuId; \ + ee = MSR(EE); \ + HalpDisableInterrupts(); \ + rScratchPad2 = 0xdeadbeef; \ + FireSyncRegister(); \ + CpuId = GetCpuId(); \ + holdit = RInterruptMask(CpuId); \ + RInterruptMask(CpuId) = 0x0; \ + WaitForRInterruptMask(CpuId); \ + HalpDebugPrint("HAssertion Failure at line %d in file %s\n", \ + __LINE__, __FILE__); \ + HalpDebugPrint("HAssertion: " #_exp "\n"); + + +#define _assert_end \ + HalpDebugPrint("Calling Debugger\n"); \ + DbgBreakPoint(); \ + RInterruptMask(CpuId) = holdit; \ + if (ee) { \ + HalpEnableInterrupts(); \ + } \ + +#define HASSERT(_exp) \ + if (!(_exp)) { \ + _assert_begin(_exp); \ + _assert_end; \ + } + + +#define HASSERTMSG(_exp, _msg) \ + if (!(_exp)) { \ + _assert_begin(_exp); \ + HalpDebugPrint("HAssertion Message: %s\n", _msg); \ + _assert_end; \ + } + +#define HASSERTEXEC(_exp, _exec) \ + if (!(_exp)) { \ + _assert_begin(_exp); \ + { \ + _exec; \ + } \ + _assert_end; \ + } + + +#define SET_LEDS(DATA) \ + rDccIndex = dccGpioA; \ + FireSyncRegister(); \ + rDccData = DATA; \ + FireSyncRegister(); + +#define GET_LEDS(DATA) \ + rDccIndex = dccGpioA; \ + FireSyncRegister(); \ + DATA = rDccData; + +#define TURN_ON(x,y) \ + GET_LEDS(x); \ + SET_LEDS((x | 0xf0 ) & ~(x)); + +#else // Free/Non-Debug Builds + +#define HASSERT(_exp) +#define HASSERTEXEC(_exp, _msg) +#define HASSERTMSG(_exp, _exec) +#define SET_LEDS(DATA) +#define GET_LEDS(DATA) +#define TURN_ON(x,y) +#endif // HALDEBUG_ON + +#endif // _FPDEBUG_H diff --git a/private/ntos/nthals/halfire/ppc/fpds1385.c b/private/ntos/nthals/halfire/ppc/fpds1385.c new file mode 100644 index 000000000..06cac0749 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpds1385.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpds1385.c $ + * $Revision: 1.14 $ + * $Date: 1996/05/20 22:35:57 $ + * $Locker: $ + * + * fpds1385.c: set of routines to init, and maintain the DS1385 + * + */ + +#include "fpdebug.h" +#include "halp.h" +#include "phsystem.h" +#include "fpreg.h" +#include "fpio.h" // pick up the io space register access macros +#include "fpds1385.h" // defines specific to the dallas 1385 + +#define DS1385_BAILOUT_COUNT 10 + +UCHAR OriginalA; // storage location for rtc data in control reg a +UCHAR OriginalB; // storage location for rtc data in control reg b +BOOLEAN RtcBinaryMode = FALSE; + // Flag to indicate if RTC is programmed in BINHEX or + // BCD format + +BOOLEAN RtcFailure = FALSE; + // Flag to indicate if the RTC was read correctly +BOOLEAN NvramFailure = FALSE; + // Flag to indicate if the NVRAM was read correctly +ULONG TotalDs1385Failures = 0; + // Keep track of failures to read the DS1385 +/* + * HalpInitFireRTC: + * + * Make sure the dallas 1385 chip is correctly setup. This means that + * all the configuration bits are in place. If the chip is not correctly + * setup, save the time off, fix the bits, recalculate the time if needed, + * and restore the time. Particularly, if the "DataMode" or "24/12 hour" + * bits are changed the time will need to be recalculated. + */ +BOOLEAN +HalpInitFirePowerRTC( VOID ) +{ + TIME_FIELDS TimeFields; + UCHAR tval; + BOOLEAN Status = FALSE; + UCHAR ds1385Data; + + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpInitFirePowerRTC: begin \n");); + if ( !(HalQueryRealTimeClock( &TimeFields )) ) { + HalDisplayString("Not sure RTC is initted \n"); + } + + // + // Make sure the time is valid before worrying about any of the bits. + // + ds1385Data = HalpDS1385ReadReg(RTC_CONTROL_REGISTERD); + if ( ds1385Data & RTC_VRT ) { + + // + // Verify that the DataMode is BCD + // the time style is 24 hour, + // that Daylight Savings is NOT enabled, + // that the square wave output is enabled. + // + tval = HalpDS1385ReadReg(RTC_CONTROL_REGISTERB); + OriginalB = tval; + HDBG(DBG_GENERAL, + HalpDebugPrint("HalpInitFirePowerRTC: register b is %x \n", + OriginalB);); + + HalpDS1385WriteReg(RTC_CONTROL_REGISTERB, + RTC_24_HR | + // + // for consistency with firmware, setup the RTC + // to maintain the time in BCD format rather + // than binary + // + // RTC_BIN_MODE | + RTC_SQWE| + RTC_UIE | + RTC_PIE); + + RtcBinaryMode = FALSE; + tval = HalpDS1385ReadReg(RTC_CONTROL_REGISTERA); + OriginalA = tval; + HDBG(DBG_GENERAL, + HalpDebugPrint("HalpInitFirePowerRTC: register a is %x\n", + OriginalA);); + + // + // Ensure the Oscillator is running and updating, not either + // stopped or counting but not updating. + // + if ((tval & ( RTC_DV1 | RTC_DV2 | RTC_DV0 )) != RTC_DV1 ) { + tval = RTC_DV1; + } + HalpDS1385WriteReg(RTC_CONTROL_REGISTERA, (UCHAR)(tval | RTC_4096_HZ)); + + // + // Clear the interrupt flag bits + // + tval = HalpDS1385ReadReg(RTC_CONTROL_REGISTERC); + + // + // Finally, restore the time: HalSetRealTimeClock will take + // care of any BCD=BIN conversion necessary. + // + if ( HalSetRealTimeClock ( &TimeFields)) { + Status=TRUE; + } + + } else { + + HalDisplayString("RTC Time is invalid: battery is dead?\n"); + } + HDBG(DBG_INTERNAL, + HalpDebugPrint("HalpInitFirePowerRTC: end \n");); + return(Status); +} + + +// +// write a byte to the specified DS1385 register. +// First acquire the spin lock to make sure something else is not +// trying to access the DS1385 (RTC or NVRAM). Then do the write +// Finally, release the spinlock. +// +VOID +HalpDS1385WriteReg(UCHAR reg, UCHAR value) +{ + KIRQL OldIrql; + UCHAR data0, data1, data2; + ULONG failureCount = 0; + + KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql); + + // We have a problem accessing the DS1385 correctly. To get around this, + // we use the Dave Stewart method; after writing the DS1385 regiser, we + // read it back 3 times - if + // one of the three values compares with the value written, we are + // done. If we do not get a comparison, throw all three values away and + // try the write + // again. If, after 10 interations we cannot read a consistent pair, + // we assert a failure flag; the routine calling us must decide what + // to do with the flag. + while (failureCount < DS1385_BAILOUT_COUNT) { + // Write the register + rIndexRTC = reg; + FireSyncRegister(); + rDataRTC = value; + // make sure access to the chip is complete before releasing + // the spin lock + FireSyncRegister(); + + // Read it three times + rIndexRTC = reg; + FireSyncRegister(); + data0 = rDataRTC; + + rIndexRTC = reg; + FireSyncRegister(); + data1 = rDataRTC; + + rIndexRTC = reg; + FireSyncRegister(); + data2 = rDataRTC; + + if ((data0 == value) || (data1 == value) || (data2 == value)) { + break; + } + failureCount++; + } + + if (failureCount == DS1385_BAILOUT_COUNT) { + RtcFailure = TRUE; + } + + TotalDs1385Failures += failureCount; + KeReleaseSpinLock(&HalpDS1385Lock, OldIrql); +} + +// +// read a byte from the specified DS1385 register. +// First acquire the spin lock to make sure something else is not +// trying to access the DS1385 (RTC or NVRAM). Then do the read +// Finally, release the spinlock. +// +UCHAR +HalpDS1385ReadReg(UCHAR reg) +{ + KIRQL OldIrql; + UCHAR result = 0xff; + UCHAR data0, data1, data2; + ULONG failureCount = 0; + + KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql); + + // We have a problem accessing the DS1385 correctly. To get around this, + // we use the Dave Stewart method; read the DS1385 register 3 times - if + // one of the three values compares with either of the other two, return + // it. If we do not get a comparison, throw all three values away and try + // again. If, after 10 interations we cannot read a consistent pair, + // we assert a failure flag; the routine calling us must decide what + // to do with the flag. + while (failureCount < DS1385_BAILOUT_COUNT) { + rIndexRTC = reg; + FireSyncRegister(); + data0 = rDataRTC; + + rIndexRTC = reg; + FireSyncRegister(); + data1 = rDataRTC; + + rIndexRTC = reg; + FireSyncRegister(); + data2 = rDataRTC; + + if ((data0 == data1) || (data0 == data2)) { + result = data0; + break; + } + if (data1 == data2) { + result = data1; + break; + } + failureCount++; + } + + if (failureCount == DS1385_BAILOUT_COUNT) { + RtcFailure = TRUE; + } + + TotalDs1385Failures += failureCount; + KeReleaseSpinLock(&HalpDS1385Lock, OldIrql); + return result; +} + +// +// write a byte to the specified address in the DS1385 NVRAM. +// First acquire the spin lock to make sure something else is not +// trying to access the DS1385 (RTC or NVRAM). Then do the write +// Finally, release the spinlock. +// +VOID +HalpDS1385WriteNVRAM(USHORT addr, UCHAR value) +{ + KIRQL OldIrql; + UCHAR data0, data1, data2; + ULONG failureCount = 0; + + KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql); + + // We have a problem accessing the DS1385 correctly. To get around this, + // we use the Dave Stewart method; after writing the DS1385 regiser, we + // read it back 3 times - if + // one of the three values compares with the value written, we are + // done. If we do not get a comparison, throw all three values away and + // try the write + // again. If, after 10 interations we cannot read a consistent pair, + // we assert a failure flag; the routine calling us must decide what + // to do with the flag. + while (failureCount < DS1385_BAILOUT_COUNT) { + // Write the register + rNvramAddr0 = addr & 0xff; + FireSyncRegister(); + rNvramAddr1 = addr >> 8; + FireSyncRegister(); + rNvramData = value; + // make sure access to the chip is complete before releasing + // the spin lock + FireSyncRegister(); + + // Read the register three times + rNvramAddr0 = addr & 0xff; + FireSyncRegister(); + rNvramAddr1 = addr >> 8; + FireSyncRegister(); + data0 = rNvramData; + + rNvramAddr0 = addr & 0xff; + FireSyncRegister(); + rNvramAddr1 = addr >> 8; + FireSyncRegister(); + data1 = rNvramData; + + rNvramAddr0 = addr & 0xff; + FireSyncRegister(); + rNvramAddr1 = addr >> 8; + FireSyncRegister(); + data2 = rNvramData; + + if ((data0 == value) || (data1 == value) || (data2 == value)) { + break; + } + failureCount++; + } + + if (failureCount == DS1385_BAILOUT_COUNT) { + NvramFailure = TRUE; + } + + TotalDs1385Failures += failureCount; + KeReleaseSpinLock(&HalpDS1385Lock, OldIrql); +} + + +// +// read a byte from the specified address in the DS1385 NVRAM. +// First acquire the spin lock to make sure something else is not +// trying to access the DS1385 (RTC or NVRAM). Then do the read +// Finally, release the spinlock. +// +UCHAR +HalpDS1385ReadNVRAM(USHORT addr) +{ + KIRQL OldIrql; + UCHAR data0, data1, data2; + UCHAR result = 0xff; + ULONG failureCount = 0; + + KeAcquireSpinLock(&HalpDS1385Lock, &OldIrql); + + // We have a problem accessing the DS1385 correctly. To get around this, + // we use the Dave Stewart method; read the DS1385 register 3 times - if + // one of the three values compares with either of the other two, return + // it. If we do not get a comparison, throw all three values away and try + // again. If, after 10 interations we cannot read a consistent pair, + // we assert a failure flag; the routine calling us must decide what + // to do with the flag. + while (failureCount < DS1385_BAILOUT_COUNT) { + rNvramAddr0 = addr & 0xff; + FireSyncRegister(); + rNvramAddr1 = addr >> 8; + FireSyncRegister(); + data0 = rNvramData; + + rNvramAddr0 = addr & 0xff; + FireSyncRegister(); + rNvramAddr1 = addr >> 8; + FireSyncRegister(); + data1 = rNvramData; + + rNvramAddr0 = addr & 0xff; + FireSyncRegister(); + rNvramAddr1 = addr >> 8; + FireSyncRegister(); + data2 = rNvramData; + + if ((data0 == data1) || (data0 == data2)) { + result = data0; + break; + } + if (data1 == data2) { + result = data1; + break; + } + failureCount++; + } + + if (failureCount == DS1385_BAILOUT_COUNT) { + NvramFailure = TRUE; + } + + TotalDs1385Failures += failureCount; + KeReleaseSpinLock(&HalpDS1385Lock, OldIrql); + return result; +} + diff --git a/private/ntos/nthals/halfire/ppc/fpds1385.h b/private/ntos/nthals/halfire/ppc/fpds1385.h new file mode 100644 index 000000000..6c41e0e63 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpds1385.h @@ -0,0 +1,213 @@ +/* +** fpds1385.h header file definitions for the dallas 1385 chip. +** This chip is functionally equivalent to the 1387. +** +** +** 1385 features: +** counts seconds, miniutes, hours, days, day of the week, date, month +** and year with leap year compensation +** +** Binary or BCD representation of time, calendar, and alarm +** +** 12 or 24 hour clock with AM and PM in 12 hour mode +** +** daylight savings time op[tino +** +** selectable between motorola and intel bus timing +** +** programmable square wave output +** +** bus compatible interrupt signals ( ~IRQ ) +** +** three interrupts are separately software maskable and testable: +** time of day alarm ( once/second to once/day ) +** periodic rates from 122 uA to 500 ms +** end of clock update cycle +** +** 4k X 8 NVRAM ( nonvolatile over 10 years ). +** +** +** note: this file created with tab stops of 8 spaces +** c.f. Dallas data book for 1992-1993, pp 6-129, 6-147 +*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpds1385.h $ + * $Revision: 1.8 $ + * $Date: 1996/05/14 02:32:34 $ + * $Locker: $ + */ + + +#ifndef FPDS1385 +#define FPDS1385 + +typedef struct _RTC_CONTROL { + UCHAR Reserved0[0x71]; + UCHAR RtcData; // Offset 0x71 +} RTC_CONTROL, *PRTC_CONTROL; + +typedef struct _NVRAM_CONTROL { + UCHAR Reserved0[0x72]; + UCHAR NvramIndexLo; // Offset 0x72 + UCHAR Reserved1[2]; + UCHAR NvramIndexHi; // Offset 0x75 + UCHAR Reserved2[1]; + UCHAR NvramData; // Offset 0x77 +} NVRAM_CONTROL, *PNVRAM_CONTROL; +// +// Define Realtime Clock register numbers. +// + +#define RTC_SECOND 0 // second of minute [0..59] +#define RTC_SECOND_ALARM 1 // seconds to alarm +#define RTC_MINUTE 2 // minute of hour [0..59] +#define RTC_MINUTE_ALARM 3 // minutes to alarm +#define RTC_HOUR 4 // hour of day [0..23] +#define RTC_HOUR_ALARM 5 // hours to alarm +#define RTC_DAY_OF_WEEK 6 // day of week [1..7] +#define RTC_DAY_OF_MONTH 7 // day of month [1..31] +#define RTC_MONTH 8 // month of year [1..12] +#define RTC_YEAR 9 // year [00..99] +#define RTC_CONTROL_REGISTERA 10 // control register A +#define RTC_CONTROL_REGISTERB 11 // control register B +#define RTC_CONTROL_REGISTERC 12 // control register C +#define RTC_CONTROL_REGISTERD 13 // control register D +#define RTC_BATTERY_BACKED_UP_RAM 14 // battery backed up RAM [0..49] + + +/* + *********************************************************************** +** +** The registers used for the indexing: +** +*/ + +// +// time.... +// +#define SECONDS 0x00 +#define MINUTES 0x02 +#define HOURS 0x04 + +// +// calendar.... +// +#define DAY_O_WEEK 0x06 +#define DAY_O_MONTH 0x07 +#define MONTH 0x08 +#define YEAR 0x09 + +// +// and the alarm bits +// +#define ALARM_secs 0x01 +#define ALARM_mins 0x03 +#define ALARM_hrs 0x05 + +// +// registers +// +#define RegA 0x0A +#define RegB 0x0B +#define RegC 0x0C +#define RegD 0x0D + +/* + *********************************************************************** +** +** Register BIT definitions +** +*/ + +// +// Register A +// +#define RTC_UIP 0x80 +#define RTC_DV2 0x40 +#define RTC_DV1 0x20 +#define RTC_DV0 0x10 + +// +// these defines spec a set of 4 bits at a time. Each set defines an output +// frequency +// +// Period in ms Frequency in hz +#define RTC_DC__ 0x00 // no output wave +#define A_0256_HZ 0x01 // 3.90625 256 dup +#define A_0128_HZ 0x02 // 7.8125 128 dup +#define RTC_8192_HZ 0x03 // .122070 8192 +#define RTC_4096_HZ 0x04 // .244141 4096 +#define RTC_2048_HZ 0x05 // .488281 2048 +#define RTC_1024_HZ 0x06 // .9765625 1024 +#define RTC_0512_HZ 0x07 // 1.953125 512 +#define RTC_0256_HZ 0x08 // 3.90625 256 +#define RTC_0128_HZ 0x09 // 7.8125 128 +#define RTC_0064_HZ 0x0A // 15.625 64 +#define RTC_0032_HZ 0x0B // 31.25 32 +#define RTC_0016_HZ 0x0C // 62.5 16 +#define RTC_0008_HZ 0x0D // 125 8 +#define RTC_0004_HZ 0x0E // 250 4 +#define RTC_0002_HZ 0x0F // 500 2 + + +// +// Register B +// +#define RTC_SET 0x80 // set bit: 0=> allow update, 1=> block update +#define RTC_PIE 0x40 // periodic interrupt enable +#define RTC_AIE 0x20 // alarm interrupt enable +#define RTC_UIE 0x10 // update ended interrupt enable +#define RTC_SQWE 0x08 // sqaure wave enable +#define RTC_BIN_MODE 0x04 // data mode set to Binary ( Not Coded Decimal ) +#define RTC_24_HR 0x02 // 24 or 12 hour mode +#define RTC_DSE 0x01 // daylight savings enable + +// +// Register C ( bits [3:0] are reserved by dallas, read as 0 ) +// + +#define RTC_IRQF 0x80 // interrupt request flag +#define RTC_PF 0x40 // periodic interrupt flag +#define RTC_AF 0x20 // alarm interrupt flag +#define RTC_UF 0x10 // update endend interrupt flag + + +// +// Register D: ( only bit 7 is defined at present ) +// + +#define RTC_VRT 0x80 // valid ram and time + + +// +// the ds1385 chip requires multiple accesses to read or write +// information. To make sure tose accesses are done atomically, +// the following spinlock must be held. It is initialized in +// pxinithl.c +extern KSPIN_LOCK HalpDS1385Lock; +// +// Reading and Writing the time to the RTC takes several accesses +// to the chip to synchronize those actions, the following spin +// lock must be held. Using the chip's spin lock above is not +// necessary because accesses to the chip's registers can be +// intermixed with the chip's nvram. This lock is initialized in +// pxinithl.c +extern KSPIN_LOCK HalpRTCLock; +/* +** +** PROTOTYPE declarations for the c-code +** +*/ + +BOOLEAN HalpInitFirePowerRTC( VOID ); + +VOID HalpDS1385WriteReg(UCHAR reg, UCHAR value); +UCHAR HalpDS1385ReadReg(UCHAR reg); +VOID HalpDS1385WriteNVRAM(USHORT addr, UCHAR value); +UCHAR HalpDS1385ReadNVRAM(USHORT addr); + +#endif diff --git a/private/ntos/nthals/halfire/ppc/fpi2c.c b/private/ntos/nthals/halfire/ppc/fpi2c.c new file mode 100644 index 000000000..d352d93f0 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpi2c.c @@ -0,0 +1,1016 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpi2c.c $ + * $Revision: 1.21 $ + * $Date: 1996/03/05 02:15:54 $ + * $Locker: $ + */ +/* fpi2c.c - FirePower I2C (I squared C) */ +#include "halp.h" +#include "phsystem.h" +#include "pxmemctl.h" +#include "fpdebug.h" +#include "fpio.h" +#include "phsystem.h" +#include "fpi2csup.h" +#include "pxpcisup.h" +#include "fpcpu.h" + +extern VOID +HalpSetValueKeyString(HANDLE key, PCHAR nameBuffer, PCHAR dataBuffer); + +/* defines */ + +#define I2CBUS_TIMEOUT 1000 +#define I2CBUS_MAXROMSIZE 0x80 +#define I2CBUS_CONTROLLER 0x8E0 +#define I2C8584S0 0x8E0 +#define I2C8584S1 0x8E1 +#define rI2C8584S0 _IOREG( I2CBUS_CONTROLLER ) +#define rI2C8584S1 _IOREG( I2CBUS_CONTROLLER + 1) + +#define SLAVE_ADDRESS_WRITE(address) (UCHAR)(0xa0|(address << 1)) +#define SLAVE_ADDRESS_READ(address) (UCHAR)(0xa1|(address << 1)) + +/* control register S1 */ +#define S1_PIN 0x80 +#define S1_ES0 0x40 +#define S1_ES1 0x20 +#define S1_ES2 0x10 +#define S1_ENI 0x08 +#define S1_STA 0x04 +#define S1_STO 0x02 +#define S1_ACK 0x01 + +/* status register S1 */ +#define S1_STS 0x20 +#define S1_BER 0x10 +#define S1_LRB 0x08 +#define S1_AAS 0x04 +#define S1_LAB 0x02 +#define S1_BB 0x01 + +// Interrupt Info from the IIC +struct PAIRS IntPairTable[MAXIMUM_PCI_SLOTS]; +extern UCHAR PciDevicePrimaryInts[]; + +extern ULONG CpuClockMultiplier; +extern ULONG ProcessorBusFrequency; + +/* prototypes */ +static VOID Write8584S0(UCHAR byte); +static VOID Write8584S1(UCHAR byte); + +static UCHAR Read8584S0(VOID); +static UCHAR Read8583S1(VOID); + +/* HAL does not initialize I2C. Firmware does it +BOOLEAN +HalpInitializeI2C() +{ +} +*/ + +static VOID i2c_delay(VOID) +{ + UCHAR byte; +// KeStallExecutionProcessor(1000); /* 1000 us */ + // Chip Select Signal must be changed. + byte = 0x00; + WRITE_REGISTER_UCHAR(((PUCHAR)HalpIoControlBase) + 0x80, byte); +} + +static VOID Write8584S0(UCHAR byte) +{ + WRITE_REGISTER_UCHAR(((PUCHAR)HalpIoControlBase) + I2C8584S0, byte); + i2c_delay(); +} + +static VOID Write8584S1(UCHAR byte) +{ + WRITE_REGISTER_UCHAR(((PUCHAR)HalpIoControlBase) + I2C8584S1, byte); + i2c_delay(); +} + +static UCHAR Read8584S0(VOID) +{ + UCHAR byte; + byte = READ_REGISTER_UCHAR(((PUCHAR)HalpIoControlBase) + I2C8584S0); + i2c_delay(); + return byte; +} + +static UCHAR Read8584S1(VOID) +{ + UCHAR byte; + byte = READ_REGISTER_UCHAR(((PUCHAR)HalpIoControlBase) + I2C8584S1); + i2c_delay(); + return byte; +} + +BOOLEAN I2CWaitForPin(VOID) +{ + UCHAR byte; + int timeout = I2CBUS_TIMEOUT; + + //PRNTI2C(HalpDebugPrint("I2CWaitForPin starts...\n")); + + while (timeout-- > 0) { + if (((byte = Read8584S1()) & S1_PIN) == 0x00) { + return TRUE; + } + } + return FALSE; +} + +BOOLEAN I2CWaitForAck(VOID) +{ + UCHAR byte; + int timeout = I2CBUS_TIMEOUT; + + //PRNTI2C(HalpDebugPrint("I2CWaitForAck starts...\n")); + while (timeout-- > 0) { + if (((byte = Read8584S1()) & S1_PIN) == 0x00) { + break; + } + } + if (timeout <= 0) return FALSE; + if (byte & S1_LRB) return FALSE; + else return TRUE; +} + +BOOLEAN I2CWaitWhileBusBusy(VOID) +{ + int timeout = I2CBUS_TIMEOUT; + UCHAR byte; + + //PRNTI2C(HalpDebugPrint("I2CWaitWhileBusBusy starts...\n")); + while (timeout-- > 0) { + if (((byte = Read8584S1()) & S1_BB) != 0x00) + break; + } + if (timeout <= 0) return FALSE; + return TRUE; +} + +VOID I2CStart(VOID) +{ + Write8584S1(0xc5); +} + +VOID I2CRestart(VOID) +{ + Write8584S1(0x45); +} + +VOID I2CPutByte(UCHAR byte) +{ + Write8584S0(byte); +} + +VOID I2CDummyRead(VOID) +{ + UCHAR dummy; + dummy = Read8584S0(); +} + +UCHAR I2CGetByte(VOID) +{ + return Read8584S0(); +} + +VOID I2CStop(VOID) +{ + Write8584S1(0xc3); +} + +VOID I2CNotAck(VOID) +{ + Write8584S1(0x40); +} + +BOOLEAN HalpI2CPutByte(UCHAR address, UCHAR index, UCHAR byte) +{ + BOOLEAN bResult; + + bResult = I2CWaitWhileBusBusy(); + if (bResult == FALSE) return FALSE; + + I2CPutByte(SLAVE_ADDRESS_WRITE(address)); // to write slave address and index + I2CStart(); + if (I2CWaitForAck() == FALSE) { + I2CStop(); + //KeStallExecutionProcessor(10000); /* 10 ms */ + return FALSE; + } + + I2CPutByte(index); + if (I2CWaitForAck() == FALSE) { + I2CStop(); + //KeStallExecutionProcessor(10000); /* 10 ms */ + return FALSE; + } + I2CPutByte(byte); + I2CWaitForPin(); + I2CStop(); + KeStallExecutionProcessor(10000); /* 10 ms */ + return TRUE; +} + +BOOLEAN HalpI2CGetByte(UCHAR address, UCHAR index, PUCHAR buf) +{ + BOOLEAN bResult; + + bResult = I2CWaitWhileBusBusy(); + if (bResult == FALSE) return FALSE; + + I2CPutByte(SLAVE_ADDRESS_WRITE(address)); // to write slave address and index + I2CStart(); + if (I2CWaitForAck() == FALSE) { + I2CStop(); + I2CDummyRead(); + return FALSE; + } + + I2CPutByte(index); + if (I2CWaitForAck() == FALSE) { + I2CStop(); + I2CDummyRead(); + return FALSE; + } + + I2CRestart(); + I2CPutByte(SLAVE_ADDRESS_READ(address)); // to read + if (I2CWaitForAck() == FALSE) { + I2CStop(); + I2CDummyRead(); + return FALSE; + } + + I2CDummyRead(); + I2CWaitForPin(); + I2CNotAck(); + *buf = I2CGetByte(); + I2CWaitForPin(); + I2CStop(); + I2CDummyRead(); + return TRUE; +} + +VOID +HalpDumpI2CEEPROM(VOID) +{ + UCHAR address = 0; + UCHAR i; + static UCHAR uc; + BOOLEAN bResult; + + PRNTI2C(DbgPrint("HalpDumpI2CEEPROM starts...&I2C8584S0=0x%x &I2C8584S1=0x%x\n", + ((PUCHAR)HalpIoControlBase) + I2C8584S0, + ((PUCHAR)HalpIoControlBase) + I2C8584S1)); + PRNTI2C(DbgPrint("--- I2C address 0 -----------------------------\n")); + PRNTI2C(DbgPrint("00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n")); + PRNTI2C(DbgPrint("-----------------------------------------------\n")); + + for (i = 0; i < 128; i++) { + bResult = HalpI2CGetByte(address, i, &uc); + if (bResult == FALSE) { + PRNTI2C(DbgPrint("HalpI2CGetByte(%d) failed.\n", i)); + } else { + PRNTI2C(DbgPrint("%02x", uc)); + } + if ((i%16) == 15) { + PRNTI2C(DbgPrint("\n")); + } else { + PRNTI2C(DbgPrint(" ")); + } + } + + PRNTI2C(DbgPrint("--- I2C address 1 -----------------------------\n")); + PRNTI2C(DbgPrint("00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n")); + PRNTI2C(DbgPrint("-----------------------------------------------\n")); + + address = 1; + for (i = 0; i < 128; i++) { + bResult = HalpI2CGetByte(address, i, &uc); + if (bResult == FALSE) { + PRNTI2C(DbgPrint("HalpI2CGetByte(%d) failed.\n", i)); + } else { + PRNTI2C(DbgPrint("%02x", uc)); + } + if ((i%16) == 15) { + PRNTI2C(DbgPrint("\n")); + } else { + PRNTI2C(DbgPrint(" ")); + } + } +} + +BOOLEAN HalpGetI2CSignature(PULONG pSignature) +{ + ULONG ul; + PUCHAR p = (PUCHAR)&ul; + UCHAR address = 0; + UCHAR index = 0; + + HalpI2CGetByte(address, index++, p++); + HalpI2CGetByte(address, index++, p++); + HalpI2CGetByte(address, index++, p++); + HalpI2CGetByte(address, index, p); + + *pSignature = ul; + return TRUE; +} + +BOOLEAN HalpGetI2CItemDescriptor(PUCHAR p) +{ + UCHAR address = 0; + UCHAR index = sizeof(META); + + PRNTI2C(HalpDebugPrint("index=%d 0x%x ", index, index)); + + HalpI2CGetByte(address, index++, p++); + HalpI2CGetByte(address, index++, p++); + *p = 0x00; + + return TRUE; +} + +BOOLEAN HalpGetI2CBoardRev(PUCHAR p) +{ + UCHAR address = 0; + UCHAR index = sizeof(META) + 2*sizeof(UCHAR); + + + PRNTI2C(HalpDebugPrint("index=%d 0x%x ", index, index)); + + HalpI2CGetByte(address, index++, p++); + HalpI2CGetByte(address, index++, p++); + *p = 0x00; + + return TRUE; +} + +BOOLEAN HalpI2CGetUshort(UCHAR address, UCHAR index, PUSHORT pus) +{ + BOOLEAN bResult = FALSE; + PUCHAR p = (PUCHAR)pus; + + bResult = HalpI2CGetByte(address, index++, p++); + if (bResult == FALSE) return FALSE; + bResult = HalpI2CGetByte(address, index++, p++); + if (bResult == FALSE) return FALSE; + + return TRUE; +} + +BOOLEAN HalpI2CGetUlong(UCHAR address, UCHAR index, PULONG pul) +{ + BOOLEAN bResult = FALSE; + PUCHAR p = (PUCHAR)pul; + + bResult = HalpI2CGetByte(address, index++, p++); + if (bResult == FALSE) return FALSE; + bResult = HalpI2CGetByte(address, index++, p++); + if (bResult == FALSE) return FALSE; + bResult = HalpI2CGetByte(address, index++, p++); + if (bResult == FALSE) return FALSE; + bResult = HalpI2CGetByte(address, index, p); + if (bResult == FALSE) return FALSE; + return TRUE; +} + +// OR together the sturcture types for this IIC address and return it as a +// flag. NOTA BENA: we intercept known non-IIC platforms and return a special +// cased result. +ULONG FindDataTypes(UCHAR address, SYSTEM_TYPE System) +{ + int index = 0; + ULONG datatype; + ULONG FoundTypes = 0; + UCHAR offset; + BOOLEAN bResult = FALSE; + + // The ES and MX (non-IIC) platforms are special cased + if ((System == SYS_POWERTOP) || (System == SYS_POWERPRO)) { + if (address == 0) { + FoundTypes = SYS_DATA; + } + return FoundTypes; + } + + while (index < I2CBUS_MAXROMSIZE) { + bResult = HalpI2CGetUlong(address, (UCHAR)index, &datatype); + if ((bResult == FALSE) || (datatype == EMPTY_DATA)) { + break; + } + FoundTypes |= datatype; + HalpI2CGetByte(address, (UCHAR)(index+sizeof(ULONG)), &offset); + if (offset == 0) { + break; + } + index += offset; + } + + return FoundTypes; +} + +UCHAR I2CFindIndexOf(UCHAR address, ULONG datatype_wanted) +{ + int index = 0; + ULONG datatype; + UCHAR offset; + BOOLEAN bResult = FALSE; + + while (index < I2CBUS_MAXROMSIZE) { + bResult = HalpI2CGetUlong(address, (UCHAR)index, &datatype); + if (bResult == FALSE) { + //DbgPrint("FindIndexOf failed\n"); + return 0; + } + //DbgPrint("I2CFindIndexOf: address=%d datatype_wanted=0x%08x index=0x%02x datatype=0x%08x\n", address, datatype_wanted, index, datatype); + if (datatype == datatype_wanted) return index; + if (datatype == EMPTY_DATA) return 0; + + HalpI2CGetByte(address, (UCHAR)(index+sizeof(ULONG)), &offset); + if (offset == 0) return 0; + index += offset; + } + //DbgPrint("FindIndexOf could not find key (0x%08x).\n", datatype_wanted); + return 0; +} + +BOOLEAN HalpDoesI2CExist(UCHAR address) +{ + ULONG ul; + UCHAR index = 5; + BOOLEAN bResult = FALSE; + +#if DBG +{ + static BOOLEAN firsttime = TRUE; + if (firsttime) { + HalpDumpI2CEEPROM(); + firsttime = FALSE; + } +} +#endif + bResult = HalpI2CGetUlong(address, index, &ul); + if (bResult == FALSE) return FALSE; + + if (ul == CURRENT_SIGNATURE) return TRUE; + return FALSE; +} + +BOOLEAN HalpI2CGetSystem(SYSTEM_TYPE *psystemtype) +{ + UCHAR address = 0; + UCHAR index; + UCHAR system; + + PRNTI2C(DbgPrint("HalpI2CGetSystem starts...\n")); + if (HalpDoesI2CExist(address) == FALSE) { + PRNTI2C(DbgPrint("HalpDoesI2CExist returned FALSE.\n")); + *psystemtype = SYS_UNKNOWN; + return FALSE; + } + if ((index = I2CFindIndexOf(address, SYS_DATA)) == 0) { + *psystemtype = SYS_UNKNOWN; + return FALSE; + } + index += sizeof(ULONG) + sizeof(UCHAR); + HalpI2CGetByte(address, index, &system); + if (system == LX_SYSTEM) { + *psystemtype = SYS_POWERSLICE; + return TRUE; + } + if (system == MX_SYSTEM) { + *psystemtype = SYS_POWERTOP; + return TRUE; + } + if (system == TX_SYSTEM) { + *psystemtype = SYS_POWERSERVE; + return TRUE; + } + if (system == TX_PROTO) { + *psystemtype = SYS_POWERSERVE; + return TRUE; + } + + // We found a system type so we need to return TRUE; since we do not + // recognize it, make it unknown. + *psystemtype = SYS_UNKNOWN; + return TRUE; +} + +BOOLEAN HalpI2CGetBoard(UCHAR address, BOARD *pb) +{ + UCHAR index; + UCHAR uc; + USHORT us; + ULONG ul; + + if ((index = I2CFindIndexOf(address, BOARD_DATA)) == 0) { + return FALSE; + } + index += 5; + + HalpI2CGetByte(address, index, &uc); + pb->PartType[0] = uc; + index++; + + HalpI2CGetByte(address, index, &uc); + pb->PartType[1] = uc; + index++; + + HalpI2CGetByte(address, index, &uc); + pb->PartRev[0] = uc; + index++; + + HalpI2CGetByte(address, index, &uc); + pb->PartRev[1] = uc; + index++; + + HalpI2CGetUlong(address, index, &ul); + pb->BoardNumber = ul; + index += 4; + + HalpI2CGetUshort(address, index, &us); + pb->Version = us; + index += 2; + + { + int i; + for (i = 0; i < 8; i++) { + HalpI2CGetByte(address, index, &uc); + pb->SerialNumber[i] = uc; + index++; + } + } + + return TRUE; +} + +BOOLEAN HalpI2CGetProcessor(UCHAR address, PROCESSOR *p) +{ + UCHAR index; + UCHAR uc; + + if ((index = I2CFindIndexOf(address, CPU_DATA)) == 0) { + return FALSE; + } + index += 5; + + HalpI2CGetByte(address, index, &uc); + p->Total = uc; + index++; + + HalpI2CGetByte(address, index, &uc); + p->BusFrequency = uc; + index++; + + HalpI2CGetByte(address, index, &uc); + p->TenXFactor = uc; + index++; + + return TRUE; +} + +BOOLEAN HalpI2CGetCache(UCHAR address, CACHE *p) +{ + UCHAR index; + UCHAR uc; + USHORT us; + ULONG ul; + + if ((index = I2CFindIndexOf(address, CACHE_DATA)) == 0) { + return FALSE; + } + index += 5; + + HalpI2CGetByte(address, index, &uc); + p->MaxSets = uc; + index++; + + HalpI2CGetByte(address, index, &uc); + p->Bytes2Line = uc; + index++; + + HalpI2CGetUshort(address, index, &us); + p->Lines2Set = us; + index += 2; + + HalpI2CGetByte(address, index, &uc); + p->SramBanks = uc; + index++; + + HalpI2CGetUlong(address, index, &ul); + p->Performance = ul; + index += 4; + + HalpI2CGetUlong(address, index, &ul); + p->MaxSize = ul; + index += 4; + + HalpI2CGetUlong(address, index, &ul); + p->Properties = ul; + index += 4; + + return TRUE; +} + +BOOLEAN HalpI2CGetDRAM(UCHAR address, MEMORY *p) +{ + UCHAR index; + UCHAR uc; + USHORT us; + ULONG ul; + + if ((index = I2CFindIndexOf(address, DRAM_DATA)) == 0) { + return FALSE; + } + index += 5; + + HalpI2CGetUlong(address, index, &ul); + p->BaseAddress = ul; + index += 4; + + HalpI2CGetUshort(address, index, &us); + p->MaxBankSize = us; + index += 2; + + HalpI2CGetByte(address, index, &uc); + p->MaxNumBanks = uc; + index ++; + + return TRUE; +} + +BOOLEAN HalpI2CGetBus(UCHAR address, BUS *p) +{ + UCHAR index; + UCHAR uc; + ULONG ul; + + if ((index = I2CFindIndexOf(address, BUS_DATA)) == 0) { + return FALSE; + } + index += 5; + + HalpI2CGetByte(address, index, &uc); + p->NumIoBus = uc; + index++; + + HalpI2CGetUlong(address, index, &ul); + p->ConfigAddr = ul; + index += 4; + + return TRUE; +} + +BOOLEAN HalpI2CGetIntsTotal(UCHAR address, UCHAR *p) +{ + UCHAR index; + UCHAR uc; + + if ((index = I2CFindIndexOf(address, INT_DATA)) == 0) { + return FALSE; + } + index += 5; + + HalpI2CGetByte(address, index, &uc); + *p = uc; + + return TRUE; +} + +BOOLEAN HalpI2CGetIntsAPair(UCHAR address, UCHAR i, struct PAIRS *p) +{ + UCHAR index; + UCHAR uc; + + if ((index = I2CFindIndexOf(address, INT_DATA)) == 0) { + return FALSE; + } + index += 5; + + index += sizeof(UCHAR) + i * (sizeof(UCHAR)*2); + + HalpI2CGetByte(address, index, &uc); + p->Int = uc; + index++; + + HalpI2CGetByte(address, index, &uc); + p->SlotNumber = uc; + index++; + + return TRUE; +} + +BOOLEAN HalpI2CGetInterrupt() +{ + UCHAR address = 0; // Id of the MLB I2c + UCHAR size; + UCHAR entry; + struct PAIRS *IntPairs = &IntPairTable[0]; + UCHAR slot; + + // Does the MLB I2C exist? + if (HalpDoesI2CExist(address) == FALSE) { + return FALSE; + } + + // Is there an interrupt structure on the MLB? + if (HalpI2CGetIntsTotal(address, &size) == FALSE) { + return FALSE; + } + + // Initialize the interrupt pairs table + for (entry = 0; entry < MAXIMUM_PCI_SLOTS; entry++) { + IntPairTable[entry].Int = INVALID_INT; + IntPairTable[entry].SlotNumber = INVALID_SLOTNUMBER; + } + + // Now fill up the IntPair table from the IIC upto MaxSize entries; + // should size > MaxSize be an error? + if (size > MAXIMUM_PCI_SLOTS) size = MAXIMUM_PCI_SLOTS; + if (size == 0) return FALSE; + + for (entry = 0; entry < size; entry++) { + if (HalpI2CGetIntsAPair(address, entry, IntPairs) == FALSE) { + return FALSE; + } + IntPairs++; + } + + for (entry = 0; entry < size; entry++) { + slot = IntPairTable[entry].SlotNumber; + if (slot < MAXIMUM_PCI_SLOTS) { + PciDevicePrimaryInts[slot] = IntPairTable[entry].Int; + } + } + + return TRUE; +} + +// Fill in the registry info for the IIC at the passed in address. +// NOTE BENA: we intercept non-IIC platforms and special case the data. +BOOLEAN HalpFillUpRegistryForIIC(HANDLE key, UCHAR address, SYSTEM_TYPE System) +{ + BOOLEAN bStatus; + BOARD board; + PROCESSOR cpu; + MEMORY memory; + BUS bus; + UCHAR numInts; + struct PAIRS DefaultPair[4]; + BOOLEAN NonIIC = FALSE; + CCHAR buffer[64]; + + // Set up default values for all of the structures to assist in filling + // out the registry for non-IIC platforms + board.PartType[0] = 'N'; + board.PartType[1] = 'A'; + board.PartRev[0] = 'N'; + board.PartRev[1] = 'A'; + board.BoardNumber = 0; + board.Version = 0; + board.SerialNumber[0] = '-'; + board.SerialNumber[1] = '-'; + board.SerialNumber[2] = ' '; + board.SerialNumber[3] = 'N'; + board.SerialNumber[4] = 'A'; + board.SerialNumber[5] = ' '; + board.SerialNumber[6] = '-'; + board.SerialNumber[7] = '-'; + + cpu.Total = (UCHAR)HalpProcessorCount(); + cpu.TenXFactor = (UCHAR)CpuClockMultiplier; + cpu.BusFrequency = (UCHAR)(ProcessorBusFrequency/1000000); + + memory.BaseAddress = 0x0; + memory.MaxBankSize = 0x40; + memory.MaxNumBanks = (System == SYS_POWERPRO)?2:4; + + bus.NumIoBus = 1; + bus.ConfigAddr = 0x80800800; + + numInts = 4; + + DefaultPair[0].Int = 25; + DefaultPair[0].SlotNumber = 1; + DefaultPair[1].Int = 22; + DefaultPair[1].SlotNumber = 2; + DefaultPair[2].Int = 23; + DefaultPair[2].SlotNumber = 3; + DefaultPair[3].Int = 26; + DefaultPair[3].SlotNumber = 4; + + // The ES and MX (non-IIC) platforms are special cased + if ((System == SYS_POWERTOP) || (System == SYS_POWERPRO)) { + NonIIC = TRUE; + } + + if ((NonIIC == TRUE) || (HalpI2CGetBoard(address, &board) == TRUE)) { + sprintf(buffer, "%c%c", board.PartType[0], board.PartType[1]); + HalpSetValueKeyString(key, "Board - Part Type", buffer); + sprintf(buffer, "%c%c", board.PartRev[0], board.PartRev[1]); + HalpSetValueKeyString(key, "Board - Part Rev", buffer); + sprintf(buffer, "%x", board.BoardNumber); + HalpSetValueKeyString(key, "Board - Number", buffer); + sprintf(buffer, "%x", board.Version); + HalpSetValueKeyString(key, "Board - Version", buffer); + sprintf(buffer, "%c%c%c%c%c%c%c%c", + board.SerialNumber[0], board.SerialNumber[1], + board.SerialNumber[2], board.SerialNumber[3], + board.SerialNumber[4], board.SerialNumber[5], + board.SerialNumber[6], board.SerialNumber[7]); + HalpSetValueKeyString(key, "Board - Serial Number", buffer); + } + + if ((NonIIC == TRUE) || (HalpI2CGetProcessor(address, &cpu) == TRUE)) { + sprintf(buffer, "%d", cpu.Total); + HalpSetValueKeyString(key, "CPU - Total Number of CPUs", buffer); + sprintf(buffer, "%d", cpu.BusFrequency); + if ((cpu.BusFrequency == 66) || (cpu.BusFrequency == 33)) { + sprintf(buffer, "%d.%d", cpu.BusFrequency, cpu.BusFrequency); + } + else { + sprintf(buffer, "%d", cpu.BusFrequency); + } + HalpSetValueKeyString(key, "CPU - Bus Frequency", buffer); + sprintf(buffer, "%d", cpu.TenXFactor); + HalpSetValueKeyString(key, "CPU - 10 Times Factor", buffer); + } + + if ((NonIIC == TRUE) || (HalpI2CGetDRAM(address, &memory) == TRUE)) { + sprintf(buffer, "0x%08x", memory.BaseAddress); + HalpSetValueKeyString(key, "Memory - Base Address", buffer); + sprintf(buffer, "0x%08x", memory.MaxBankSize); + HalpSetValueKeyString(key, "Memory - Max Bank Size", buffer); + sprintf(buffer, "%d", memory.MaxNumBanks); + HalpSetValueKeyString(key, "Memory - Max # of Banks", buffer); + } + + if ((NonIIC == TRUE) || (HalpI2CGetBus(address, &bus) == TRUE)) { + sprintf(buffer, "%d", bus.NumIoBus); + HalpSetValueKeyString(key, "Bus - Number of Buses", buffer); + sprintf(buffer, "0x%08x", bus.ConfigAddr); + HalpSetValueKeyString(key, "Bus - Configration Address", buffer); + } + + if ((NonIIC == TRUE) || (HalpI2CGetIntsTotal(address, &numInts) == TRUE)) { + char keyName[32]; + UCHAR i = 0; + struct PAIRS *pair; + + sprintf(buffer, "%d", numInts); + HalpSetValueKeyString(key, + "Ints - Number of Primary PCI Interrupts", buffer); + + while (numInts-- > 0) { + sprintf(keyName, "Ints - Primary PCI Entry %d", i); + if (NonIIC == TRUE) { + pair = &DefaultPair[i]; + } + else { + pair = &DefaultPair[0]; + } + bStatus = HalpI2CGetIntsAPair(address, i++, pair); + if ((NonIIC == FALSE) && (bStatus == FALSE)) break; + sprintf(buffer, "Vector#%d Slot#%d", pair->Int, pair->SlotNumber); + HalpSetValueKeyString(key, keyName, buffer); + } + } + + return TRUE; +} + +BOOLEAN +HalpCreateNode(CCHAR * pszNodeName, UCHAR address, HANDLE * phNode) +{ + OBJECT_ATTRIBUTES objectAttributes; + NTSTATUS status; + HANDLE hNode; + ULONG disposition; + STRING strNodeName; + UNICODE_STRING ucNodeName; + + *phNode = NULL; + + RtlInitString (&strNodeName, pszNodeName); + status = RtlAnsiStringToUnicodeString( + &ucNodeName, + &strNodeName, + TRUE); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, HalpDebugPrint("Could not create unicode strings: (0x%x) \n", + status)); + return FALSE; + } + + InitializeObjectAttributes ( + &objectAttributes, + &ucNodeName, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL + ); + + status = ZwCreateKey(&hNode, + KEY_READ, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_VOLATILE, + &disposition ); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, HalpDebugPrint("Did not create key: (0x%x) \n", status);); + RtlFreeUnicodeString(&ucNodeName); + return FALSE; + } + + *phNode = hNode; + RtlFreeUnicodeString(&ucNodeName); + return TRUE; +} + +BOOLEAN +HalpSetUpRegistryForI2C(SYSTEM_TYPE System) +{ + HANDLE hNode; + BOOLEAN bStatus = FALSE; +#if defined(HALDEBUG_ON) + BOOLEAN SystemTypeFound = FALSE; +#endif + UCHAR address; + ULONG StructureTypes; + + CCHAR szCPU[256]; + CCHAR szMEM[256]; + CCHAR szSystem[] = "\\Registry\\Machine\\Hardware\\Powerized\\System"; + CHAR CpuCardLabel[] = + "\\Registry\\Machine\\Hardware\\Powerized\\Cpu Card"; + SHORT CpuCardNo = 0; + CHAR MemCardLabel[] = + "\\Registry\\Machine\\Hardware\\Powerized\\Memory Card"; + SHORT MemCardNo = 0; + + address = 0; + // Loop through all possible IIC addresses + while (address < 16) { + // Since all of the structure type flags are mutually exclusive + // bits, we can lump together into one mask. + StructureTypes = FindDataTypes(address, System); + + // Determine what identifying structures are present and create + // nodes corresponding to them. + // - an IIC with a SYS_DATA structure is a System board; there must + // be ONE and only ONE system board on a system + // - an IIC with a CPU_DATA structure and no SYS_DATA structure is + // a Cpu Card; there may be multiple Cpu Cards in a system. + // - an IIC with a MEM_DATA structure and no CPU or SYS_DATA structure + // is a Memory Card; there may be multiple Memory Cards in a system + if ((StructureTypes & SYS_DATA) != 0) { + bStatus = HalpCreateNode(szSystem, address, &hNode); + if (hNode != NULL) { + HalpFillUpRegistryForIIC(hNode, address, System); + ZwClose(hNode); + } +#if defined(HALDEBUG_ON) + SystemTypeFound = TRUE; +#endif + } + else if ((StructureTypes & CPU_DATA) != 0) { + sprintf(szCPU, "%s %d", CpuCardLabel, CpuCardNo); + bStatus = HalpCreateNode(szCPU, address, &hNode); + if (hNode != NULL) { + HalpFillUpRegistryForIIC(hNode, address, System); + ZwClose(hNode); + CpuCardNo++; + } + } + else if ((StructureTypes & + (DRAM_DATA|SRAM_DATA|VRAM_DATA|EDORAM_DATA) ) != 0) { + sprintf(szMEM, "%s %d", MemCardLabel, MemCardNo); + bStatus = HalpCreateNode(szMEM, address, &hNode); + if (hNode != NULL) { + HalpFillUpRegistryForIIC(hNode, address, System); + ZwClose(hNode); + MemCardNo++; + } + } + address++; + } +#if defined(HALDEBUG_ON) + if (SystemTypeFound == FALSE) { + HalpDebugPrint ("HalpSetUpRegistryForI2C: no MLB IIC found.\n"); + } +#endif + + return bStatus; +} + +/* end of fpi2c.c */ diff --git a/private/ntos/nthals/halfire/ppc/fpi2c.h b/private/ntos/nthals/halfire/ppc/fpi2c.h new file mode 100644 index 000000000..e3c5e1a18 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpi2c.h @@ -0,0 +1,39 @@ +/* fpi2c.h */ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpi2c.h $ + * $Revision: 1.5 $ + * $Date: 1996/02/06 02:20:28 $ + * $Locker: $ + * +/* + system board ROM data (I2C address 0x00) + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 0x00: 26 59 41 31 10 26 59 41 31 ?? ?? 02 01 80 00 00 Meta + 0x10: 00 04 00 00 20 42 41 41 44 00 93 73 00 03 01 00 Board + 0x20: 04 01 00 + 0x30: 01 00 00 00 10 01 00 System + 0x40: 08 00 00 00 10 00 00 00 00 08 00 04 Memory + 0x50: 40 00 00 00 10 01 08 80 80 Bus + 0x60: 80 00 00 00 00 05 26 04 25 01 23 03 22 02 21 05 Ints + + * typical CPU card ROM data for LX (I2C address 0x01) + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F + 0x00: 26 59 41 31 10 26 59 41 31 ?? ?? 02 01 80 00 00 Meta + 0x10: 00 04 00 00 20 42 41 41 44 00 03 75 00 03 01 09 Board + 0x20: 00 01 00 + 0x30: 02 00 00 00 10 02 42 14 Processor + 0x40: 04 00 00 00 00 02 20 00 20 02 11 31 00 00 00 00 Cache + 0x50: 08 00 00 00 00 00 + + */ + +extern BOOLEAN HalpI2CGetSystem(SYSTEM_TYPE *psystemtype); +extern BOOLEAN HalpSetUpRegistryForI2C(SYSTEM_TYPE System); +extern BOOLEAN HalpDoesI2CExist(UCHAR address); +extern BOOLEAN HalpI2CGetInterrupt(); + +/* end of fpi2c.h */ + diff --git a/private/ntos/nthals/halfire/ppc/fpi2csup.h b/private/ntos/nthals/halfire/ppc/fpi2csup.h new file mode 100644 index 000000000..861821621 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpi2csup.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpi2csup.h $ + * $Revision: 1.6 $ + * $Date: 1996/02/19 23:54:29 $ + * $Locker: $ + */ +#ifndef FPI2CSUP_H +#define FPI2CSUP_H +// C4103 : "used #pragma pack to change alignment" +//#pragma warning(disable:4103) // disable C4103 warning +//#pragma pack(1) + +/* This is an implementation according to 1.5 specification */ +/* + * + * Each data structure has in common a STRUCT_HEADER which holds clues + * about the 'DataType' of the structure and it's 'OffSet'. The data + * type tells software what data is in the structure hence how to + * interpret the data. The OffSet indicates how far to the next + * data structure, or, if the value is 0, whether there is another data + * structure. return to index + * + */ + +#define EMPTY_DATA 0x00000000 // indicates there is no data. +#define SYS_DATA 0x00000001 // general system registers +#define CPU_DATA 0x00000002 // processor +#define CACHE_DATA 0x00000004 // cache control +#define DRAM_DATA 0x00000008 // memory control +#define SRAM_DATA 0x00000010 // memory control +#define VRAM_DATA 0x00000020 // memory control +#define EDORAM_DATA 0x00000040 // memory control +#define INT_DATA 0x00000080 // int control, not initialization. +#define BUS_DATA 0x00000400 // I O control, mainly configuration and +// initialization. +#define DMA_DATA 0x00000100 +#define DISPLAY_DATA 0x00000200 +// mogawa +#define BOARD_DATA 0x40000000 +#define META_DATA 0x80000000 + +#define STRUCT_HEADER \ +ULONG DataType; UCHAR OffSet + // The type of data contained in the structure + // The Offset to the next data structure, relative + // the beginning of this structure. Typically, it's + // value is set as the length of the structure, but + // is set to zero if no more structures exist. + +/* + * + * + * Meta data effectively describes the structure of the IIC rom data. + * The size of the total rom is given, along with pointers to the beginning of + * the other data areas. Finally, there is a major/minor version numbering + * system to provide some means of evaluating what data the rom contains. + * return to index + * + */ +#define CURRENT_META_REV 0x0103 // this is in the form of: USHORT 0x0101 +#define CURRENT_SIGNATURE 0x31415926 // numbers of PI: e is (27182818) next + + +typedef struct _Meta_ { + STRUCT_HEADER; + ULONG Signature; + USHORT ChkSum; // a sum of byte pairs (USHORT) in little endian + // order. + USHORT Revision; + UCHAR Size; // in bytes, the size of the entire rom. +} META; + + +/* + * + * Manufacturing's part number is built out of four pieces: a two letter + * description of the item ( BA for board assembly ), a five digit part + * designator, a two digit board version, and a two letter board turn + * identifier ( as in AA, AB, AC, AD ... ). + * + * E.G. BA-007393-01-AD is an LX series Board Assembly (BA) whose board + * variation is 01, and board revision is "AD." + * + */ + +#define BOARD_REV_MASK 0x000000ff // the manufacturing number's rev bits +#define BOARD_PART_MSK 0xffffff00 // the 6 digits used as the part number + // ( 4 digits actually ) +/* + * + * + * The general board data contains data fields common to all boards. A version + * to correlate this structure with the meta data structure, along with + * the type of board, cpu or mlu, the board system, lx or tx, the board family + * as in PREP, CHRP or something else, return to index + * + */ + +typedef struct _Board_ { + STRUCT_HEADER; + UCHAR PartType[2]; // Currently a two ascii value 'B''A' that stands + // for Board Assembly. + UCHAR PartRev[2]; // Colloquially the Board Rev. E.G. Mx has this as + // 'A''D' for the Rev AD board. + ULONG BoardNumber; // Board ID consists of two parts: Rev fields + // which are the least two significant nibbles, + // and Part Number field which is the 6 most + // nificant nibbles. The digits are stored + // in "BCD" format as in one decimal digit per + // nibble, in little endian order. + + USHORT Version; // major/minor versioning value of this board. + UCHAR SerialNumber[8]; // board serial number. Format TBD.... +} BOARD; + + + +/* + * : + * System data structure: Mainly a catch all for data needed but not readily + * associated with any one hardware function. for instance, we use it here to + * say whether the system is TX, LX, MX or whatever. return * to index + * + */ + +#define DEV_SYS 0x0000 +#define LX_SYSTEM 0x0001 +#define MX_SYSTEM 0x0002 +#define TX_SYSTEM 0x0003 +#define TX_PROTO 0x0004 + +typedef struct _SYSTEM_ { + STRUCT_HEADER; + USHORT type; // what kind of system is this: This is a value field + // rather than a bit map.... +} SYSTEM; + +/* + * For the board specific information, there is a specific structure. This + * allows for varying data requirements of different boards such as a changing + * sense of where some registers may sit. + * + */ + +typedef struct _Processor_ { + STRUCT_HEADER; + UCHAR Total; // total number of cpus on this board. + UCHAR BusFrequency; // frequency of the bus serving the cpu(s) + UCHAR TenXFactor; // 10 times the bus frequency multiplier for the cpu. + // This allows fractional multipliers as in 3/2 + // (becomes 15) or 5/2 ( becomes 25 ). +} PROCESSOR; + + +#define LOOKASIDE_L2 0x00000001 // this cache is a look aside cache +#define INLINE_L2 0x00000002 // this cache is an inline cache +#define PIPELINED_L2 0x00010000 // pipelined cache + +typedef struct _Cache_ { + STRUCT_HEADER; + UCHAR MaxSets; // Maximum number of "sets" available for this cache. + // direct mapped, then there is only 1. + UCHAR Bytes2Line; // line size in bytes: i.e. number of bytes per set. + USHORT Lines2Set; // number of lines per set. + UCHAR SramBanks; // # of memory banks: indicates both cache + // size and max set associativity. + ULONG Performance; // 3-1-1-1, 2-1-1-1 or some other cycle latency. + // the data is stored in BCD format. + ULONG MaxSize; // size of cache in bytes. + ULONG Properties; // properties of the cache's behavior: pipelined + // or not, lookaside or not... +} CACHE; + +typedef struct _Memory_Device_ { + STRUCT_HEADER; + ULONG BaseAddress; // the base physical address for this memory. + USHORT MaxBankSize; // Maximum size of banks in Megabytes + UCHAR MaxNumBanks; // Maximum number of memory banks on this board; +} MEMORY; + + +/* + * + * + * Describe any busses on the system. Current plans account only + * for the pci bus but will expand to allow for complete bus typing. + * return to index + * + */ +typedef struct _BUS_ { + STRUCT_HEADER; + UCHAR NumIoBus; // number of io busses on main logic board. + ULONG ConfigAddr; // the location of the config space. Zero + // means there is no config space. This value + // points to the first device's address, and is + // assumed to be device 0. +} BUS; + + +/* + * + * The INT structure describes some set of interrupts on the system that + * software needs knowledge of. In this case software needs to know what + * pci config addresses map to what interrupts. + * In a later implementation, this should fully describe the system's + * interrupt space. return to index + * + */ +struct PAIRS { + UCHAR Int; + UCHAR SlotNumber; +}; + +typedef struct _INTS_ { + STRUCT_HEADER; + UCHAR Total; // how many interrupts are we talking about here? + struct PAIRS Pairs[0]; // pairs of numbers in the form: int, slot number: + // for ints on config addresses on a secondary + // bus, the slot number will be greater than 10 + // where the more significant nibble describes + // bus number as seen from a low to high descending + // bus probe. + +} INTS; + +//#pragma warning(enable:4103) // disable C4103 warning +//#pragma pack + +#endif // FPI2CSUP_H diff --git a/private/ntos/nthals/halfire/ppc/fpints.c b/private/ntos/nthals/halfire/ppc/fpints.c new file mode 100644 index 000000000..e69c09813 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpints.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpints.c $ + * $Revision: 1.13 $ + * $Date: 1996/07/13 01:15:58 $ + * $Locker: $ + */ + +// TITLE("Manipulate Interrupt Request Level") +//++ +// +// Module Name: +// +// FPINTS.C +// +// Abstract: +// +// This module implements the arrays required to handle interrupt +// priorities including generation of the arrays, and anything else +// that is hardware specific interrupt oriented. This is not intended, +// in it's original incarnation, to be an OS policy file, merely a hw one. +// +// The theory of ops is given a set of interrupts ordered by priority, +// that is for any occurance of an interrupt, only those interrupts pre- +// ceding it in the list may now occur. So, if int 5 is the highest +// priority then when it occurrs, no other interrupt will be visible. Any +// lesser interrupt may be interruptable by an int 5. And so on. +// +// Author: +// +// Bill Rees ( FirePOWER ) +// Sol Kavy ( FirePOWER ) +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 16-Jul-95 Created +// +//-- +#include "fpdebug.h" +#include "halp.h" +#include "phsystem.h" +#include "fppci.h" +#include "pxpcisup.h" +extern ULONG atoi(PCHAR); + +#define MAX_IRQL_NUM 32 +#define MAX_VECTORS 32 + +// +// Note: this is declared poorly in pxsiosup.c and should be +// moved to PCR. +// +extern ULONG registeredInts[]; + +// +// This array spec's which interrupts go with which devices +// on the host-pci bus ( bus 0, i.e. primary bus ). +// NOTE: 0xff => no device interrupt provided. +// +UCHAR PciDevicePrimaryInts[MAXIMUM_PCI_SLOTS]; + +/* + * Given an IRQL, provide a register mask that sets allowable interrupts + * and blocks all ints that are set at "lower" priority. + * + * This array is automatically generated from the Vector2Irql array by the + * HalpSetIntPriorityMask() call in fpints.c. For each entry in the V2I array + * that sits at an IRQL or above, it's interrupt bit is or'd into the Irql2Mask + * value. For example, at irql 0, almost every entry in the V2I array has an + * irql greater than 0 ( except for the reserved interrupts ) so the mask value + * in the Irql2Mask array has nearly every bit turned on. Conversely, at IRQL + * 24, only a few interrupts have irql values above 21 ( ints 0, 1, 22, 23, + * 28, 29, 30, 31 ) + * + */ +ULONG Irql2Mask[MAX_IRQL_NUM]; + +/* + * This array matches an IRQL to an Interrupt Vector. Since the array is + * indexed by interrupt vector, there can be a many interrupts to single IRQL + * mapping allowing interrupts to share IRQL settings. IRQLs determine + * relative operational order such that any code operating at any irql, will + * block code from a lower priority from occuring and in turn this same code + * can be interrupted by code trying to run at a higher priority. + * + * So this array becomes a prioritization of interrupts, determining which + * interrupts will block each other or not block each other. In this case, + * a higher number means higher priority hence blocking more interrupts. + * + * explanation on how this array is used is above the Irql2Mask[] declaration. + * + */ +ULONG Vector2Irql[MAX_VECTORS] = { + 26, // int 0 (Timer) is IRQL 26 so it blocks most other interrupts: + 25, // int 1 (KEYBD) blocks all other ISA devices except RTC. + + 24, // int 2 is the cascade bit so all interrupts on the cascaded + // interrupt controller ( 8259 ) are higher priority than the + // rest of the interrupts on the master interrupt controller. + + 15, // int 3 (COM2) is on the master but after the slave ints, so it + // blocks only those ints left on the master chip. + + 14, // int 4 (COM1) is lower priority than com 2. + 13, // int 5 Display: + 12, // int 6 Floppy: + 11, // int 7 Parallel: + 23, // int 8 (RTC): First int on Slave: only ints 0,1,2 are higher pri. + 22, // int 9: + 21, // int 10 (AUDIO). + 20, // int 11: + 19, // int 12 Mouse int. Lower than keyboard. + 18, // int 13 old scsi + 17, // int 14 old enet: + 16, // int 15: + 00, // reserved: hence lowest priority + 00, // reserved: hence lowest priority + 00, // reserved: hence lowest priority + 00, // reserved: hence lowest priority + 00, // int 20 | + 00, // int 21 | + 00, // int 22 | + 00, // int 23 - PCI interrupts configured dynamically from the I2C + 00, // int 24 | + 00, // int 25 | + 00, // int 26 | + 00, // reserved: hence lowest priority + 28, // int 28(CPU) Set CPU Bus error IRQL to IPI_LEVEL + 28, // int 29(PCI) Set PCI Bus error IRQL to IPI_LEVEL + 28, // int 30(MEM/VID) Set MEMORY error IRQL to IPI_LEVEL + 29 // int 31(IPI) this is the cpu message level: > clock +}; + +ULONG LX_Vector2Irql[MAX_VECTORS] = { + 26, // int 0 (Timer) is IRQL 26 so it blocks most other interrupts: + 25, // int 1 (KEYBD) blocks all other ISA devices except RTC. + + 24, // int 2 is the cascade bit so all interrupts on the cascaded + // interrupt controller ( 8259 ) are higher priority than the + // rest of the interrupts on the master interrupt controller. + + 15, // int 3 (COM2) is on the master but after the slave ints, so it + // blocks only those ints left on the master chip. + + 14, // int 4 (COM1) is lower priority than com 2. + 13, // int 5 Display: + 12, // int 6 Floppy: + 11, // int 7 Parallel: + 23, // int 8 (RTC): First int on Slave: only ints 0,1,2 are higher pri. + 22, // int 9: + 21, // int 10 (AUDIO). + 20, // int 11: + 19, // int 12 Mouse int. Lower than keyboard. + 18, // int 13 old scsi + 17, // int 14 old enet: + 16, // int 15: + 00, // reserved: hence lowest priority + 00, // reserved: hence lowest priority + 00, // reserved: hence lowest priority + 00, // reserved: hence lowest priority + 23, // int 20 LX: rsrvd ; TX: PCI slot 3 + 22, // int 21 LX: IDE A ; TX: PCI slot 2 + 21, // int 22 LX: IDE A ; TX: PCI slot 1 + 20, // int 23 pci slot 3 IRQL + 19, // int 24 pci slot 2 IRQL + 18, // int 25 pci slot 1 IRQL scsi + 17, // int 26 pci slot 0 IRQL network + 00, // reserved: hence lowest priority + 28, // int 28(CPU) Set CPU Bus error IRQL to IPI_LEVEL + 28, // int 29(PCI) Set PCI Bus error IRQL to IPI_LEVEL + 28, // int 30(MEM/VID) Set MEMORY error IRQL to IPI_LEVEL + 29 // int 31(IPI) this is the cpu message level: > clock +}; + +// TX_PROTO & LX_PROTO: must reorder the IRQL table +VOID HalpInitializeVector2Irql(VOID) +{ + ULONG irql = 17; // Start the PCI interrupts at irql 17 + UCHAR slot; + UCHAR intNum; + + for (slot = 1; slot < MAXIMUM_PCI_SLOTS; slot++) { + intNum = PciDevicePrimaryInts[slot]; + if ((intNum != INVALID_INT) && (intNum < MAX_VECTORS)) { + Vector2Irql[intNum] = irql; + irql++; + } + } +} + +HalpSetIntPriorityMask(VOID) +{ + ULONG irql, vec, Value=0; + + // + // for each irql, search the Vector2Irql array and generate + // a mask suitable for writing to the mask register to block + // interrupts at the given irql. + // + for (irql = 0; irql < MAX_IRQL_NUM; irql++) { + Irql2Mask[irql] = 0; + for (vec = 0; vec < MAX_VECTORS; vec++) { + // + // Turn on bits for interrupts that are still allowed. + // + if (Vector2Irql[vec] > irql) { + Irql2Mask[irql] |= (1 << vec); + } + } + } + PRNTINTR(HalpDebugPrint("HalpSetIntPriorityMask: Irql2Mask: 0x%x\n", + &Irql2Mask[0])); + return(1); +} + + +// +// THis array gives the processor affinity for the given interrupt +// vector. Then NT will handle the interrupt on that processor. +// + +ULONG Vector2Affinity[MAX_VECTORS]; + + +// +/*++ + +Routine Description: void HalpInitProcAffinity () + This function sets the processor affinity for the given interrupt + in the Vector2Affinity array. If the values are wrong, cpu 0 is + set. + +Arguments: + + pProcnInts - pointer to the PROCNINTS nvram variable. + numProc - number of processors in the system. + + +Return Value: + + void + +--*/ + +void +HalpInitProcAffinity(PCHAR pProcnInts, ULONG NumProc) +{ + ULONG vec,proc; + CHAR delim = ';'; + + if ( NumProc == 1 ) { + for(vec=0; vec < MAX_VECTORS; vec++) { + Vector2Affinity[vec] = 1; // cpu 0 always + } + HDBG(DBG_MPINTS, + HalpDebugPrint("Affinity set to 1 for all vectors\n");); + return; + } + HDBG(DBG_MPINTS,HalpDebugPrint("vector affinity\n");); + // multiprocessor but no PROCNINTS given + // distribute on all processors round robin fashion + if ( pProcnInts == 0 ) { + for(vec=0; vec < MAX_VECTORS; vec++) { + Vector2Affinity[vec] = 1 << (vec%NumProc); // next cpu gets next vec + HDBG(DBG_MPINTS, + HalpDebugPrint("%6d %6d\n",vec,Vector2Affinity[vec]);); + } + return; + } + // otherwise go with the env variable PROCNINTS in pProcnInts + for(vec=0; vec < MAX_VECTORS; vec++) { + if ( *pProcnInts == 0 || *pProcnInts == delim ) + proc = 0; + else + proc = atoi(pProcnInts); + if ( proc >= NumProc ) + proc = (proc % NumProc); + Vector2Affinity[vec] = 1 << proc; + while(*pProcnInts && *pProcnInts != ';') + pProcnInts++; // skip current affinity + if (*pProcnInts == ';') + pProcnInts++; // skip delimiter + HDBG(DBG_MPINTS, + HalpDebugPrint("%6d %6d\n",vec,Vector2Affinity[vec]);); + } + return; +} diff --git a/private/ntos/nthals/halfire/ppc/fpio.h b/private/ntos/nthals/halfire/ppc/fpio.h new file mode 100644 index 000000000..e06763e14 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpio.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpio.h $ + * $Revision: 1.9 $ + * $Date: 1996/01/11 07:06:50 $ + * $Locker: $ + * + * This file contains references to registers in I/O space only. That is any + * access to the ISA or PCI space ( or any future additions ) are contained in + * this file. Access to device registers that do not lie in I/O space should + * be defined in the file fpreg.h + * + */ + +#ifndef FPIO_H +#define FPIO_H + +// +// Define macros for handling accesses to io-space: +// + +// HalpIoControlBase is extern'd in pxhalp.h which is included by halp.h + +#define _IOBASE ((PUCHAR)HalpIoControlBase) +#define _IOREG(_OFFSET) (*(volatile UCHAR * const)((_IOBASE + (_OFFSET)))) +#define _IOADDR(_OFFSET) ((_IOBASE + (_OFFSET))) + +#define _PCIOBASE ((PUCHAR)HalpPciConfigBase) +#define _PCIOREG(_OFFSET) (*(volatile UCHAR * const)((_PCIOBASE + (_OFFSET)))) +#define _PCIOADDR(_OFFSET) ((_PCIOBASE + (_OFFSET))) + +// +// The Physical IO Space for generation one machines starts at 0x8000_0000. +// All IO external devices in either ISA space or PCI space live within +// this domain. This also includes the on-board ethernet and scsi drivers, +// the ISA bus interrupt controllers, display control. +// + +// +// PCI Configuration Space: +// +// +// device cpu relative Address Config space address +// ------ -------------------- ---------------- +// +// 82378 ( SIO ) 0x8080_0800 - 0x8080_08ff 0x80_0800 - 0x80_08ff +// scsi (79c974) 0x8080_1000 - 0x8080_10ff 0x80_1000 - 0x80_10ff +// pci slot A 0x8080_2000 - 0x8080_20ff 0x80_2000 - 0x80_20ff +// pci slot B 0x8080_4000 - 0x8080_40ff 0x80_4000 - 0x80_40ff +// enet (79c974) 0x8080_8000 - 0x8080_80ff 0x80_8000 - 0x80_80ff + +#define RPciConfig(Slot,Offset) \ + (*(volatile ULONG * const)(_PCIOBASE + (HalpPciConfigSlot[Slot] + Offset)) ) + +#define RPciVendor(Slot) \ + (*(volatile ULONG * const)(_PCIOBASE + (UCHAR)(HalpPciConfigSlot[Slot])) ) + +#define RPciVendorId(Slot) \ + (*(volatile ULONG * const) (_PCIOBASE + (HalpPciConfigSlot[Slot])) ) + //(*(volatile ULONG * const) (_PCIOBASE + (0x800 << Slot) ) ) + +// +// I/O Device Addresses +// + +// Device Registers IO Space Cpu Space +// ---------------- -------- --------- +// +// Dma 1 registers, control 0x0000 - 0x000f 0x8000_0000 - _000f + +// 8259 interrupt 1 control 0x0020 0x8000_0020 +// 8259 interrupt 1 mask 0x0021 0x8000_0021 +#define MasterIntPort0 0x0020 +#define MasterIntPort1 0x0021 + +// +// AIP Primary xbus index 0x0022 +// AIP Primary Xbus target 0x0023 +// AIP Secondary Xbus +// target 0x0024 +// AIP Secondary xbus +// index 0x0025 +// +#define AIP_PRIMARY_XBUS_INDEX 0x0022 +#define AIP_PRIMARY_XBUS_TARGET 0x0023 +#define AIP_SECONDARY_XBUS_INDEX 0x0024 +#define AIP_SECONDARY_XBUS_TARGET 0x0025 + + + +// keyboard cs, Reset 0x0060 +// ( xbus irq 12 ) +// nmi status and control 0x0061 +// keyboard cs 0x0062 +// keyboard cs 0x0064 +// keyboard cs 0x0066 + +/* +** ******************************************* +** +** Dallas 1385 Real Time Clock : System macros +** dallas specific macros are in pxds1585.h +*/ +// RTC address 0x0070 +// RTC read/writ 0x0071 +// NVRAM addr strobe 0 0x0072 +// NVRAM addr strobe 1 0x0075 +// NVRAM Read/Write 0x0077 +// RTC and NVRAM 0x0070 - 0077 + +#define RTC_INDEX 0x0070 // index register +#define RTC_DATA 0x0071 // data register +#define NVRAM_ADDR0 0x0072 // address strobe 0 +#define NVRAM_ADDR1 0x0075 // address strobe 1 +#define NVRAM_RW 0x0077 // read write nvram? + + +// Timer 0x0078 - 007f +// DMA Page Registers 0x0080 - 0090 +// Port 92 Register 0x0080 - 0092 +// DMA Page Registers 0x0094 - 009f + +// 8259 interrupt 2 control 0x00A0 0x8000_00A0 +// 8259 interrupt 2 mask 0x00A1 0x8000_00A1 +#define SlaveIntPort0 0x00A0 +#define SlaveIntPort1 0x00A1 + +// DMA 2 registers and +// control 0x00c0 - 00df + + +// AIP Configuration +// Registers 0x026e - 026f +// ( primary addr block ) +#define AIP_PRIMARY_CONFIG_INDEX_REG 0x026e +#define AIP_PRIMARY_CNFG_DATA_REG 0x026f + + +// Parallel Port 3 0x0278 - 027d +// serial port2 0x02f8 - 02ff +// secondary floppy +// controller 0x0370 - 0377 +// parallel port 2 0x0378 - 037d + + +// AIP Configuraiton Registers 0x0398 - 0399 +// ( secondary addr blck ) +#define AIP_SECOND_CONFIG_INDEX_REG 0x0398 +#define AIP_SECOND_CNFG_DATA_REG 0x0399 + + +// parallel port 1 0x03bc - 03bf +// pcmcia config registers 0x03e0 - 03e3 +// primary floppy controller 0x03f0 - 03f7 +// serial port 1 0x03f8 - 03ff +// dma 1 extended +// mode regsiter 0x040b +// dma scatter/gather +// command status 0x0410 - 041f +// dma scatter/gather +// Dscrptr ( channel 0-3 ) 0x0420 - 042f +// dma scatter/gather +// Dscrptr ( channel 5-7 ) 0x0434 - 043f +// dma high page registers 0x0481 - 0483 +// dma high page registers 0x0487 +// dma high page registers 0x0489 +// dma high page registers 0x048a - 048b +// dma 2 extended mode +// register 0x04d6 +// business audio control, +// status, data registers 0x0830 - 0833 + + +// video asic registers 0x0840 - 0841 +#define DCC_INDEX 0x0840 +#define DCC_DATA 0x0841 + + +// bt445 ramdac registers 0x0860 - 086f +#define BT445_ADDRESS 0x0860 +#define ADDRESS_REGISTER 0x0860 // same as the BT445_ADDR +#define PRIMARY_PALETTE 0x0861 // Primary Color Palette address +#define CHIP_CONTROL 0x0862 // function control register +#define OVERLAY_PALETTE 0x0863 // Overlay Color Palette +#define RGB_PIXEL_CONFIG 0x0865 // RGB configuration and control +#define TIMING_PIXEL_CONFIG 0x0866 // pixel timing, configuration, control +#define CURSOR_COLOR 0x0867 // cursor color + +// dram simm presence +// detect register 0x0880 +// vram simm presence +// detect register 0x0890 +// epxansion presence +// detect register 0x08a0 +// + +// +// Defines for Register Access: +// +#define rIndexRTC _IOREG( RTC_INDEX ) +#define rDataRTC _IOREG( RTC_DATA ) +#define rNvramData _IOREG( NVRAM_RW ) +#define rNvramAddr0 _IOREG( NVRAM_ADDR0 ) +#define rNvramAddr1 _IOREG( NVRAM_ADDR1 ) +#define rMasterIntPort0 _IOREG( MasterIntPort0 ) +#define rMasterIntPort1 _IOREG( MasterIntPort1 ) +#define rSlaveIntPort0 _IOREG( SlaveIntPort0 ) +#define rSlaveIntPort1 _IOREG( SlaveIntPort1 ) + +#define rIndexAIP1 _IOREG( AIP_PRIMARY_XBUS_INDEX ) +#define rTargetAIP1 _IOREG( AIP_PRIMARY_XBUS_TARGET ) +#define rIndexAIP2 _IOREG( AIP_SECONDARY_XBUS_INDEX ) +#define rTargetAIP2 _IOREG( AIP_SECONDARY_XBUS_TARGET ) + + +#define rDccIndex _IOREG( DCC_INDEX ) +#define rDccData _IOREG( DCC_DATA ) + +#define rRamDacAddr _IOREG( BT445_ADDRESS ) +#define rDacPrimeLut _IOREG( PRIMARY_PALETTE ) +#define rRamDacCntl _IOREG( CHIP_CONTROL ) +#define rDacOvlayLut _IOREG( OVERLAY_PALETTE ) +#define rDacPixelBit _IOREG( RGB_PIXEL_CONFIG ) +#define rDacPixelClks _IOREG( TIMING_PIXEL_CONFIG ) +#define rRamDacCursor _IOREG( CURSOR_COLOR ) + + +#endif diff --git a/private/ntos/nthals/halfire/ppc/fplibc.c b/private/ntos/nthals/halfire/ppc/fplibc.c new file mode 100644 index 000000000..b3461e904 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fplibc.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fplibc.c $ + * $Revision: 1.3 $ + * $Date: 1996/04/30 23:25:53 $ + * $Locker: $ + */ + +/* + * This file contains libc support routines that the kernel/hal do + * not include but that the HAL wants to use, so we have created + * our own. + */ + +#include "fpproto.h" + +int +atoi(char *s) +{ + int temp = 0, base = 10; + + if (*s == '0') { + ++s; + if (*s == 'x') { + ++s; + base = 16; + } else { + base = 8; + } + } + while (*s) { + switch (*s) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + temp = (temp * base) + (*s++ - '0'); + break; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + temp = (temp * base) + (*s++ - 'a' + 10); + break; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + temp = (temp * base) + (*s++ - 'A' + 10); + break; + default: + return (temp); + } + } + return (temp); +} + +char * +FpStrtok ( + char * string, + const char * control + ) +{ + unsigned char *str; + const unsigned char *ctrl = control; + + unsigned char map[32]; + int count; + + static char *nextoken; + + /* Clear control map */ + for (count = 0; count < 32; count++) { + map[count] = 0; + } + + /* Set bits in delimiter table */ + do { + map[*ctrl >> 3] |= (1 << (*ctrl & 7)); + } while (*ctrl++); + + /* Initialize str. If string is NULL, set str to the saved + * pointer (i.e., continue breaking tokens out of the string + * from the last strtok call) */ + if (string) { + str = string; + }else { + str = nextoken; + } + + /* Find beginning of token (skip over leading delimiters). Note that + * there is no token iff this loop sets str to point to the terminal + * null (*str == '\0') */ + while ( (map[*str >> 3] & (1 << (*str & 7))) && *str ) { + str++; + } + + string = str; + + /* Find the end of the token. If it is not the end of the string, + * put a null there. */ + for ( ; *str ; str++ ) { + if ( map[*str >> 3] & (1 << (*str & 7)) ) { + *str++ = '\0'; + break; + } + } + + /* Update nextoken (or the corresponding field in the per-thread data + * structure */ + nextoken = str; + + /* Determine if a token has been found. */ + if ( string == str ) { + return '\0'; + } else { + return string; + } +} + diff --git a/private/ntos/nthals/halfire/ppc/fpnvram.h b/private/ntos/nthals/halfire/ppc/fpnvram.h new file mode 100644 index 000000000..a4a0c03b4 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpnvram.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpnvram.h $ + * $Revision: 1.4 $ + * $Date: 1996/01/11 07:07:03 $ + * $Locker: $ + */ +#ifndef _PREPNVRM_H +#define _PREPNVRM_H +// +// This header describes the NVRAM definition for PREP +// +typedef struct _SECURITY { + ULONG BootErrCnt; // Count of boot password errors + ULONG ConfigErrCnt; // Count of config password errors + ULONG BootErrorDT[2]; // Date&Time from RTC of last error in pw + ULONG ConfigErrorDT[2]; // Date&Time from RTC of last error in pw + ULONG BootCorrectDT[2]; // Date&Time from RTC of last correct pw + ULONG ConfigCorrectDT[2]; // Date&Time from RTC of last correct pw + ULONG BootSetDT[2]; // Date&Time from RTC of last set of pw + ULONG ConfigSetDT[2]; // Date&Time from RTC of last set of pw + UCHAR Serial[16]; // Box serial Number +} SECURITY; + +typedef enum _OS_ID { + Unknown = 0, + Firmware = 1, + AIX = 2, + NT = 3, + MKOS2 = 4, + MKAIX = 5, + Taligent = 6, + Solaris = 7, + MK = 12 +} OS_ID; + +typedef struct _ERROR_LOG { + UCHAR ErrorLogEntry[40]; +} ERROR_LOG; + +typedef enum _NVRAM_BOOT_STATUS { + BootStarted = 0x001, + BootFinished = 0x002, + RestartStarted = 0x004, + RestartFinished = 0x008, + PowerFailStarted = 0x010, + PowerFailFinished = 0x020, + ProcessorReady = 0x040, + ProcessorRunning = 0x080, + ProcessorStart = 0x100 +} NVRAM_BOOT_STATUS; + +typedef struct _NVRAM_RESTART_BLOCK { + USHORT Version; + USHORT Revision; + ULONG ResumeReserved[2]; + volatile ULONG BootStatus; + ULONG CheckSum; + void * RestartAddress; + void * SaveAreaAddr; + ULONG SaveAreaLength; +} NVRAM_RESTART_BLOCK; + +typedef enum _OSAREA_USAGE { + Empty = 0, + Used = 1 +} OSAREA_USAGE; + +typedef enum _PM_MODE { + Suspend = 0x80, + Normal = 0x00 +} PMMode; + +typedef struct _HEADER { + USHORT Size; // NVRAM size in K + UCHAR Version; // Structure map different + UCHAR Revision; // Structure map same - may be new values in old fields + USHORT Crc1; + USHORT Crc2; + UCHAR LastOS; // OS_ID + UCHAR Endian; // B if big endian, L if little endian + UCHAR OSAreaUsage; + UCHAR PMMode; // Power Management shutdown mode + NVRAM_RESTART_BLOCK Restart; + SECURITY Security; + ERROR_LOG ErrorLog[2]; + + PVOID GEAddress; + ULONG GELength; + ULONG GELastWriteDT[2]; // Date&Time from RTC of last change to Global + + PVOID ConfigAddress; + ULONG ConfigLength; + ULONG ConfigLastWriteDT[2]; // Date&Time from RTC of last change to Config + ULONG ConfigCount; // Count of entries in Configuration + + PVOID OSAreaAddress; + ULONG OSAreaLength; + ULONG OSAreaLastWriteDT[2]; // Date&Time from RTC of last change to Var + +} HEADER, *PHEADER; + +#endif diff --git a/private/ntos/nthals/halfire/ppc/fppci.h b/private/ntos/nthals/halfire/ppc/fppci.h new file mode 100644 index 000000000..f11095fb4 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fppci.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fppci.h $ + * $Revision: 1.7 $ + * $Date: 1996/01/25 01:11:27 $ + * $Locker: $ + * + * Herein are the definitions used to interact with PCI based devices. The + * information is specific to the PCI spec as interpreted by FirePOWER and + * not specific to the hardware ( or at the least minimally relavent to hw). + * + * Please look in FPIO.H for system specific information relevant to the IO + * system such as memory maps or register read/write specifics. + * + */ + +#ifndef FPPCI_H +#define FPPCI_H + +#ifdef HALDEBUG_ON +#define PRINTBRIDGE(x) \ + if ( HalpDebugValue&DBG_PCI ) { \ + PULONG j; \ + ULONG i; \ + HalpDebugPrint("\nVendor: 0x%x, Dev: 0x%x, Cmd: 0x%x, Stat: 0x%x\n",\ + x->VendorID, x->DeviceID, x->Command, x->Status); \ + HalpDebugPrint("PrimaryBus: 0x%02x, SecondaryBus: 0x%02x", \ + x->u.type1.PrimaryBus, \ + x->u.type1.SecondaryBus); \ + HalpDebugPrint(" SubBus: 0x%02x, IOBase: 0x%02x, IOLimit:0x%02x\n", \ + x->u.type1.SubordinateBus,\ + x->u.type1.IOBase, \ + x->u.type1.IOLimit); \ + HalpDebugPrint("Secnd Status: 0x%04x, MemBase 0x%04x, MemLimit 0x%04x",\ + x->u.type1.SecondaryStatus, x->u.type1.MemoryBase, \ + x->u.type1.MemoryLimit ); \ + HalpDebugPrint(" IntLine: 0x%02x, IntPin: 0x%02x, BrdgeCntl: 0x%04x\n",\ + x->u.type1.InterruptLine, x->u.type1.InterruptPin, \ + x->u.type1.BridgeControl); \ + j=(PULONG)x; \ + for(i=0; i<(PCI_COMMON_HDR_LENGTH/4); j+=4, i+=4){ \ + HalpDebugPrint("%s 0x%08x, 0x%08x, 0x%08x, 0x%08x \n", \ + TBS, *j, *(j+1), *(j+2), *(j+3) ); \ + } \ + } +#else +#define PRINTBRIDGE(x) +#endif //haldebug_on + +// +// Hardware Specific Defines for FirePOWER: +// +#define TYPE1_ACCESS 0x1 // configuration space access is of Standard type 1 +#define TYPE2_ACCESS 0x2 // configuration space access is of Standard type 2 +#define BRIDGED_ACCESS 0x3 // FirePOWER specific access: modified type 1. + +/* + * PCI Register config read/write macros: dependent on defines + * in FPIO.H which must be included in the c file before this + * file is included ( not included here to avoid multiple + * includes of the file in any io specific file). + * + */ + +// +// type - what type of data access: uchar, ushort, or ulong: +// (UCHAR) bus - what pci bus ( up to 256 ) +// (UCHAR) Device - Which physical board: = physical slot. ( max of 32 ) +// (UCHAR) Fn - Which function on the board ( Max of 8 ) +// (UCHAR) Offset - The offset into the config header ( one of 64 words ) +// + +#define SLOT(DEV, FN ) (ULONG) ((ULONG)( (DEV & 0x1f) << 11 ) | \ + (ULONG)( (FN & 0x07) << 8 ) ) +#define CONFIG(BUSNUM, DEV, FN, OFFSET ) \ + (ULONG)( BUSNUM << 16 ) | SLOT(DEV, FN) | (ULONG)( OFFSET & 0xfc) + +#define RPciBusConfig(TYPE, BUSNUM, DEV, FN, OFFSET ) \ + (*(volatile type * const) (_PCIOBASE + \ + (ULONG)( CONFIG(BUSNUM, DEV, FN, OFFSET) ) ) ) +// (*(volatile type * const) (_PCIOBASE + (ULONG)( (0x800 << Slot) ) ) ) +//(*(volatile ULONG * const)(_PCIOBASE + (HalpPciConfigSlot[Slot] + Offset))) + +/* + * Pci Configuration Header Defines: + * These defines are in conjunction with what's in ntos\inc\pci.h. + * + */ + +// +// Major Classes ( also called BaseClasses ) of devices..... +// +#define PRE_REV2_CLASS 0x00 +#define MASS_STORAGE_CLASS 0x01 +#define NETWORK_CTLR_CLASS 0x02 +#define DISPLAY_CTLR_CLASS 0x03 +#define MULTIMEDIA_CLASS 0x04 +#define MEMORY_CTLR_CLASS 0x05 +#define BRIDGE_CLASS 0x06 + +// +// SubClasses and Programming interfaces.... +// + +// REV2 CLASS +// +#define NON_VGA_SUBCLASS 0x00 +#define NON_VGA_PROGIF 0x00 +#define VGA_SUB_CLASS 0x01 +#define VGA_PROGIF 0x01 + +// Mass Storage Classes +// +#define SCSI_SUBCLASS 0x00 +#define SCSI_PROGIF 0x00 +#define IDE_SUBCLASS 0x01 +#define IDE_PROGIF 0x00 +#define FLOPPY_SUBCLASS 0x02 +#define FLOPPY_PROGIF 0x00 +#define IPI_SUBCLASS 0x03 +#define IPI_PROGIF 0x00 +#define OTHER_SUBCLASS 0x80 +#define OTHER_PROGIF 0x00 + +// Network Controller Classes +// +#define ENET_SUBCLASS 0x00 +#define ENET_PROGIF 0x00 +#define TKNRING_SUBCLASS 0x01 +#define TKNRING_PROGIF 0x00 +#define FDDI_SUBCLASS 0x02 +#define FDDI_PROGIF 0x00 +#define OTHR_NTWK_SUBCLASS 0x80 +#define OTHR_PROGIF 0x00 + +// Display Controller Classes +// +#define VGA_SUBCLASS 0x00 +#define VGA_CTLR_PROGIF 0x00 +#define XGA_SUBCLASS 0x01 +#define XGA_PROGIF 0x00 +#define OTHR_DSPLY_SUBCLASS 0x80 +#define OTHR_DISPLY_PROGIF 0x00 + +// Multimedia Device Classes +// +#define VIDEO_SUBCLASS 0x00 +#define VIDEO_PROGIF 0x00 +#define AUDIO_SUBCLASS 0x01 +#define AUDIO_PROGIF 0x00 +#define OTHR_MLTIMDIA_SUBCLASS 0x80 +#define OTHR_MLTIMDIA_PROGIF 0x00 + +// Memory Controller Classes +// +#define RAM_SUBCLASS 0x00 +#define RAM_PROGIF 0x00 +#define FLASH_SUBCLASS 0x01 +#define FLASH_PROGIF 0x00 +#define OTHR_MEM_SUBCLASS 0x80 +#define OTHR_MEM_PROGIF 0x00 + +// Bridge Device Classes +// +#define HOST_PCI_SUBCLASS 0x00 +#define HOST_PCI_PROGIF 0x00 +#define PCI_ISA_SUBCLASS 0x01 +#define PCI_ISA_PROGIF 0x00 +#define PCI_EISA_SUBCLASS 0x02 +#define PCI_EISA_PROGIF 0x00 +#define PCI_MCHANL_SUBCLASS 0x03 +#define PCI_MCHANL_PROGIF 0x00 +#define PCI_PCI_SUBCLASS 0x04 +#define PCI_PCI_PROGIF 0x00 +#define PCI_PCMCIA_SUBCLASS 0x05 +#define PCI_PCMCIA_PROGIF 0x00 +#define OTHER_BRIDGE_SUBCLASS 0x80 +#define OTHER_BRIDGE_PROGIF 0x00 + +#define VENDOR_DIGITAL 0x1011 +#define DEVICE_21050 0x1 +#define PCI_ISA_IO_PHYSICAL_BASE 0x80000000 +#define PCI_IO_PHYSICAL_BASE 0x81000000 +#define PCI_IO_ADDRESS 0x00000001 +#define PCI_MEMORY_ADDRESS 0x00000000 + +#endif diff --git a/private/ntos/nthals/halfire/ppc/fppcisup.c b/private/ntos/nthals/halfire/ppc/fppcisup.c new file mode 100644 index 000000000..379c03ef0 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fppcisup.c @@ -0,0 +1,1101 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fppcisup.c $ + * $Revision: 1.33 $ + * $Date: 1996/07/02 02:26:11 $ + * $Locker: $ + * + */ + +#include +#include +#include +#include +#include "fpdebug.h" +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "pxpcisup.h" +#include "phsystem.h" +#include "fpio.h" +#include "fppci.h" +#include "fppcisup.h" + +#define DEC_BRIDGE_CHIP (0x1011) // Dec Bridge Chip VendorID + +extern KSPIN_LOCK HalpPCIConfigLock; +extern UCHAR PciDevicePrimaryInts[]; +PUCHAR ClassNames[] = { + "Pre rev 2.0 ", + "Mass Storage", + "Network", + "Display", + "MultiMedia", + "Memory", + "Bridge", + "UnkNown", + "UnkNown", + "UnkNown", + "UnkNown", + "UnkNown", + "UnkNown" + }; + +// +// scan the bus depth first, then pop back out and catch all the siblings +// on the way back. +// +ULONG +HalpScanPciBus( ULONG HwType, ULONG BusNo, PBUS_HANDLER ParentBus ) +{ + ULONG devs, fns, Stat=0, ValidDevs=0,BusDepth=0, BusLimits; + PUCHAR Buffer; + PCI_SLOT_NUMBER SlotNumber; + PCI_COMMON_CONFIG *PciData; + PBUS_HANDLER CurrentBus, ChildBus; + PFPHAL_BUSNODE FpBusData; + ULONG slot; + char buf[128]; + + // + // Added by Keith Son to support peer level bridge. + // + ULONG Bus_Current_Number, Bus_Next_Number, Bus_Child_Number=0; + + + HDBG(DBG_GENERAL, HalpDebugPrint("HalpScanPciBus: 0x%x, 0x%0x, 0x%08x\n", + HwType, BusNo, ParentBus );); + + // ENGINEERING DEVELOPMENT: allow optional toggle of Bridge mode + // in the IO ASIC. + if (HalGetEnvironmentVariable("BRIDGEMODE", sizeof(buf), buf) + == ESUCCESS) { + if (_stricmp(buf, "true") == 0) { + PRNTPCI(HalpDebugPrint( + "HalpScanPciBus: BRIDGEMODE enabled\n")); + rTscControl |= 0x20000000; + rPIOPendingCount |= 0x80; + FireSyncRegister(); + } + else { + PRNTPCI(HalpDebugPrint( + "HalpScanPciBus: BRIDGEMODE disabled\n")); + rTscControl &= ~0x20000000; + rPIOPendingCount &= ~0x80; + FireSyncRegister(); + } + } + + // + // Added by Keith Son. + // This variable is needed to keep track of the number of buses in the + // system. + // + Bus_Next_Number = BusNo; + + + + if ((CurrentBus = HalpAllocateAndInitPciBusHandler(HwType, BusNo, TRUE)) + == (PBUS_HANDLER) NULL ) { + HalpDebugPrint("\nHalpInitIoBuses: DID NOT ALLOCATE BUS HANDLER: \n"); + return 1; // add in status on return later... + } + + FpBusData = (PFPHAL_BUSNODE)CurrentBus->BusData; + + if (ParentBus) { + // + // Setup bus defaults for heirarchical buses. + // + Bus_Current_Number = BusNo; + FpBusData->Bus.MaxDevice = PCI_MAX_DEVICES; + BusLimits = PCI_MAX_DEVICES; + FpBusData->Bus.ParentBus = (UCHAR) ParentBus->BusNumber; + + slot = FpBusData->Bus.CommonData.ParentSlot.u.bits.DeviceNumber; + if (slot > MAXIMUM_PCI_SLOTS) { + HalpDebugPrint("HalpScanPciBus: child %d ILLEGAL PARENT SLOT %d\n", + BusNo, slot); + return 1; // add in status on return later... + } + // It doesn't matter if the BusInt is an INVALID_INT here + FpBusData->BusInt = PciDevicePrimaryInts[slot]; + FpBusData->BusMax = (UCHAR)BusNo; + FpBusData->Bus.CommonData.ParentSlot.u.AsULONG = + ((PFPHAL_BUSNODE)ParentBus->BusData)->SlotNumber.u.AsULONG; + FpBusData->SlotNumber.u.AsULONG = + ((PFPHAL_BUSNODE)ParentBus->BusData)->SlotNumber.u.AsULONG; + + + + if (!(FpBusData->Bus.CommonData.ParentSlot.u.AsULONG)) { + PRNTPCI( + HalpDebugPrint("HalpScanPciBus: Child (0x%x): no ParentSlot\n", + BusNo)); + FpBusData->Bus.CommonData.ParentSlot.u.AsULONG = 0xffffffff; + + + } + } else { + // + // This must be the host-pci bus handler, so setup the supported + // interrupts this bus will support... + // + BusLimits = MAXIMUM_PCI_SLOTS; + FpBusData->MemBase = 0; + FpBusData->MemTop = 0xffffffff; + FpBusData->IoBase = 0; + FpBusData->IoTop = 0xffffffff; + FpBusData->Bus.CommonData.ParentSlot.u.AsULONG = 0xffffffff; + // + // Keith Son. + // Added to support peer bridge. Keeping track the number of bridge in the scan process. + // + Bus_Current_Number = BusNo; + + + + } + // + // setup general data areas for use... + // + Buffer = ExAllocatePool (PagedPool, 1024); + PciData = (PPCI_COMMON_CONFIG) Buffer; + FpBusData->ValidDevs = 0xffffffff; // init valid dev structure + + HDBG(DBG_BREAK,DbgBreakPoint();); + + // + // Now scan this bus for contents... + // + SlotNumber.u.AsULONG = 0; // init structure to a known value.. + for (devs =0; devs < BusLimits; devs++) { + SlotNumber.u.bits.DeviceNumber = devs; + PRNTPCI(HalpDebugPrint("%s%x devs; %x",TBS,CurrentBus->BusNumber,devs)); + + for (fns =0; fns VendorID, PciData->DeviceID)); + + if (PciData->VendorID == PCI_INVALID_VENDORID ){ + // + // checking for invalid device status, and if + // there is no device on this slot then turn off + // the valid bit and break out of this loop + // + FpBusData->ValidDevs &= ~(1 << devs); + PRNTPCI(HalpDebugPrint("\t\tValidDevs now set to: 0x%08x\n", + FpBusData->ValidDevs) ); + break; + } + + PRNTPCI(HalpDebugPrint("\t\tDev is class type %s(%x)\n", + ClassNames[PciData->BaseClass], PciData->BaseClass)); + + // + // Check if this device is a bridge chip. Add in checking for + // what Type of bridge chip it is and tailor the configuration + // appropriately. + // + if (PciData->BaseClass == 0x6) { + // + // Set this bridge's primary bus number and pass it into + // the configuration routine. The config routine will set + // up the secondary bus fields and other required fields, + // write the config data out to the bridge, and return. + // + FpBusData->SlotNumber.u.AsULONG = SlotNumber.u.AsULONG; + // + // Keith Son. + // Needed to pass the bus no. to the next level of bridge. + // + PciData->u.type1.PrimaryBus = (UCHAR) Bus_Next_Number; + + + + switch (PciData->SubClass) { + case HOST_PCI_SUBCLASS: Stat =0; + break; + + case PCI_PCI_SUBCLASS: + Stat = HalpInitPciBridgeConfig( BusNo, + PciData, + CurrentBus); + break; + + case PCI_PCMCIA_SUBCLASS: + Stat = HalpConfigurePcmciaBridge(BusNo); + break; + default: + break; + }; + + // + // Now setup a bus and scan the secondary bus on this + // bridge chip. If it also contains a bridge, recurse. + // When we come back out, need to make sure the subordinate + // bus fields are setup correctly. + // + if (Stat) { + // + // If the bridge was successfully initted, then + // descend through the bridge and scan it's bus + // + FpBusData->BusLevel++; + HDBG(DBG_PCI, HalpDebugPrint("-------- Bus %x ---------\n", + FpBusData->BusLevel);); + + + // + // Keith Son. + // Keep updating the maximun bus variable and the value for the recursive scan. + // + if (Bus_Next_Number > FpBusData->BusMax) + FpBusData->BusMax = (UCHAR)Bus_Next_Number; + + // + // Keith Son. + // Bus_Next_Number is the place holder for counting number of buses. + // + + Bus_Next_Number = HalpScanPciBus( BRIDGED_ACCESS, + FpBusData->BusMax+1, + CurrentBus); + + + HDBG(DBG_PCI, HalpDebugPrint("-------- Bus_Next_Number %x ---------\n", + Bus_Next_Number);); + + // + // Keith Son. + // Update the secondary bus value after scanning the sub-bus. + // This is very important because bridge controller only forward acces based on + // the secondary and Subordinate. + // + PRINTBRIDGE(PciData); + PciData->u.type1.SecondaryBus = (UCHAR)Bus_Next_Number; + PciData->u.type1.SubordinateBus = (UCHAR)Bus_Next_Number; + // for now, prune on way back.. + + PRINTBRIDGE(PciData); + + HalpWritePCIConfig (CurrentBus, SlotNumber, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Keith Son. + // + + + ChildBus = HalpHandlerForBus(PCIBus, Bus_Next_Number ); + + if (ChildBus) { + PFPHAL_BUSNODE ChildData; + ChildData = (PFPHAL_BUSNODE)ChildBus->BusData; + ChildBus->ParentHandler = CurrentBus; + FpBusData->BusMax = ChildData->BusMax; +/* +#pragma NOTE("fixup memory/port assignments"); +should probably assign parent's fields first, then tell the child +what range he can use. +*/ + // + // setup the memory and port limits for this bridge: + // since the bridge itself uses the limit registers to + // effectively pick the last page ( for port addresses ) + // or last megabyte ( for memory ) rather than the last + // byte, we need to reflect that by translating the + // page ( or megabyte ) count to a byte count: hence the + // shift left and 'or' in of 'f's. + // + ChildData->MemBase = + (ULONG)PciData->u.type1.MemoryBase<<16; + ChildData->MemTop = + (ULONG)(PciData->u.type1.MemoryLimit<<16 | 0xfffff); + + ChildData->IoBase = (ULONG)PciData->u.type1.IOBase<<8; + ChildData->IoTop = + (ULONG)PciData->u.type1.IOLimit << 8 | 0xfff; + + HDBG(DBG_PCI, + HalpDebugPrint("ChildData->MemBase=%x MemTop=%x IoBase=%x IoTop=%x\n", + ChildData->MemBase, ChildData->MemTop, ChildData->IoBase, ChildData->IoTop);); + + + // + // Skim the memory from the parents list.. + // + FpBusData->MemTop = ChildData->MemBase -1; + FpBusData->IoTop = ChildData->IoBase -1; + + // + // Remind the child what slot he uses on the parent's + // bus. This allows someone, given the child's bus, + // to not only grab it's parent's bus handler but to + // know where the child bus is so memory and io address + // assignments can be dynamically altered. + // + ChildData->Bus.CommonData.ParentSlot = + FpBusData->SlotNumber; + + HDBG(DBG_PCI, + HalpDebugPrint("FpBusData->SlotNumber %x\n", FpBusData->SlotNumber);); + + + //FpBusData->Bus.CommonData.ParentSlot; + }else{ + HalpDebugPrint("Could Not find handler for bus %x\n", + BusNo+1); + } + + //clear out any pending ints due to child bus scanning... + // + rPCIBusErrorCause = 0xffffffff; + FireSyncRegister(); + + HDBG(DBG_PCI, + HalpDebugPrint("--------------------------\n");); + } else { + HDBG(DBG_PCI, + HalpDebugPrint(" Don't go into bridge\n");); + } + } + + if (PciData->BaseClass != 0x6) { + // + // this is not a bridge card so go ahead and fix the interrupt + // value for this device: + // + if ( CurrentBus->BusNumber != 0 ) { + PciData->u.type0.InterruptLine=(UCHAR)FpBusData->BusInt; + HalpWritePCIConfig(CurrentBus, // bus type + SlotNumber, // "Slot" + PciData, // data buffer, + 0, // Offset, + PCI_COMMON_HDR_LENGTH); // read first 64 bytes.. + + // + // Read it back in and make sure it is valid. + // + HalpReadPCIConfig(CurrentBus, // bus type + SlotNumber, // "Slot" + PciData, // data buffer, + 0, // Offset, + PCI_COMMON_HDR_LENGTH); // read first 64 bytes.. + + if ( PciData->u.type0.InterruptLine != FpBusData->BusInt ){ + HalpDebugPrint("HalpScanPciBus: Line=%x, BusInt=%x\n", + PciData->u.type0.InterruptLine, FpBusData->BusInt ); + } + } + } + if ( !(PciData->HeaderType & PCI_MULTIFUNCTION) ) { + // + // get out of here... + // + break; + } + } // .....for fns loop + } // .....for devs loop + + ExFreePool(Buffer); + + // + // Keith Son. + // Keep track the highest bus in the system. + // + + return (Bus_Next_Number); +} + +VOID HalpPCISynchronizeBridged ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg1 + ) +{ + // + // Now block interruptions and make this transaction appear + // atomic with respect to any one else trying to access this + // bus and device (especially any other cpu ). + // + KeRaiseIrql (PROFILE_LEVEL, Irql); + KiAcquireSpinLock (&HalpPCIConfigLock); + + // + // Initialize PciCfg1 + // + + // + // The Bus Number must share the 8 bits with a bit of config address + // space. Namely, the physical address to access config space requires + // 9 bits. This means that only buses whose numbers are less than 128 + // are available which shouldn't be a problem. + // + PciCfg1->u.AsULONG = 0; + // + // Limit bus totals to less than 128 buses: + PciCfg1->u.bits.BusNumber = ( (0x7f) & BusHandler->BusNumber); + PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber; + PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber; + PRNTPCI(HalpDebugPrint("HalpPCISynchronizeBridged: u.AsULONG: 0x%08x", + PciCfg1->u.AsULONG)); + + // + // add in base offset of pci config space's virtual address: + // + PciCfg1->u.AsULONG += (ULONG) HalpPciConfigBase; + + // + // Setup the config space address for access... + // + RInterruptMask(GetCpuId()) &= ~(PCI_ERROR_INT); // block pci error ints. + WaitForRInterruptMask(GetCpuId()); + + PRNTPCI(HalpDebugPrint(" ->u.AsULONG: 0x%08x\n", PciCfg1->u.AsULONG)); + +} + +VOID HalpPCIReleaseSynchronzationBridged ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ) +{ + //rPCIStatus = 0xffff; // clear out any latent interrutps at bus + rPCIBusErrorCause = 0xffffffff; //clear out ints at the pending register... + FireSyncRegister(); + + RInterruptPending(GetCpuId()) |= PCI_ERROR_INT; // clear any pending ints. + RInterruptMask(GetCpuId()) |= PCI_ERROR_INT; // turn pci ints back on. + WaitForRInterruptMask(GetCpuId()); + KiReleaseSpinLock (&HalpPCIConfigLock); + KeLowerIrql (Irql); + //HalSweepIcache(); + HalSweepDcache(); + +} + + +ULONG +HalpPCIReadUcharBridged ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + //PciCfg1->u.bits.Reserved1 = 0x1; // turn access into config cycle + rPCIConfigType |= PCI_TYPE1_CYCLE; // tell the system this is a type 1 + // configuration access cycle. + + FireSyncRegister(); + *Buffer = READ_PORT_UCHAR ((PUCHAR)(PciCfg1->u.AsULONG + i)); + rPCIConfigType &= ~(PCI_TYPE1_CYCLE); // tell the system this is a type 1 + FireSyncRegister(); + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshortBridged ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + //PciCfg1->u.bits.Reserved1 = 0x1; // turn access into config cycle + rPCIConfigType |= PCI_TYPE1_CYCLE; // tell the system this is a type 1 + // configuration access cycle. + + FireSyncRegister(); + *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT)(PciCfg1->u.AsULONG + i)); + rPCIConfigType &= ~(PCI_TYPE1_CYCLE); // tell the system this is a type 1 + FireSyncRegister(); + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlongBridged ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + + rPCIConfigType |= PCI_TYPE1_CYCLE; // tell the system pci config cycles + // will now be type 1 cycles. + FireSyncRegister(); + + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) (PciCfg1->u.AsULONG)); + + rPCIConfigType &= ~(PCI_TYPE1_CYCLE); // tell the system config cycles + // will now be type 0 cycles. + FireSyncRegister(); + + return sizeof (ULONG); +} + +ULONG +HalpPCIWriteUcharBridged ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + rPCIConfigType |= PCI_TYPE1_CYCLE; // tell the system this is a type 1 + // configuration access cycle. + FireSyncRegister(); + + WRITE_PORT_UCHAR (PciCfg1->u.AsULONG + i, *Buffer ); + rPCIConfigType &= ~(PCI_TYPE1_CYCLE); // tell the system this is a type 1 + FireSyncRegister(); + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshortBridged ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + //PciCfg1->u.bits.Reserved1 = 0x1; // turn access into config cycle + rPCIConfigType |= PCI_TYPE1_CYCLE; // tell the system this is a type 1 + // configuration access cycle. + FireSyncRegister(); + + WRITE_PORT_USHORT (PciCfg1->u.AsULONG + i, *((PUSHORT) Buffer) ); + rPCIConfigType &= ~(PCI_TYPE1_CYCLE); // tell the system this is a type 1 + FireSyncRegister(); + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlongBridged ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + rPCIConfigType |= PCI_TYPE1_CYCLE; // tell the system this is a type 1 + // configuration access cycle. + FireSyncRegister(); + + WRITE_PORT_ULONG (PciCfg1->u.AsULONG, *((PULONG) Buffer) ); + rPCIConfigType &= ~(PCI_TYPE1_CYCLE); // tell the system this is a type 1 + FireSyncRegister(); + return sizeof (ULONG); +} + +VOID +HalpInitIoBuses ( + VOID + ) +{ + ULONG BusNum, HwType; + + // + // Initialize bus handling structures for the primary PCI bus in + // the system. We know the bus is there if this system is a top + // or pro. When other buses are added, a peer pci for example, + // there will need to be a search done on the config tree to find + // the first available one, hopefully I can tell which one is the + // boot pci path. + // + BusNum = 0; + HwType = 1; // our system most closely resembles the Type1 + // config access model. + + if ( HalpScanPciBus( HwType, BusNum, (PBUS_HANDLER) NULL ) ) { +// HalpDebugPrint("HalpInitIoBuses: ScanPciBus returned non-zero: \n"); + } + +} + +/*-- + Routine: HalpAdjustBridge( PBUS_HANDLER, PPCI_COMMON_CONFIG ) + + Description: + + Given the child bus and a device on that bus, make sure + the bridge servicing the bus is adequately setup. This means + checking the memory and io base and limit registers, the command + and status registers. + + ChildBus This is the bus on the child's side of the bridge. It + should hold the parent slot so the bridge may be found + and read from or written to. + + PrivData Private Data to the device under resource control. This + provides the data to figure out how the bridge should be + adjusted. +--*/ + +ULONG +HalpAdjustBridge(PBUS_HANDLER ChildBus, + PPCI_COMMON_CONFIG PrivData, + PCM_RESOURCE_LIST CmList + ) +{ + PFPHAL_BUSNODE FpBusData; + ULONG BaseAddress=0, DCount, Range, TopAddr=0, i; + PCM_PARTIAL_RESOURCE_DESCRIPTOR TmpDescr; + ULONG PciCommandFlag=0; + PCI_COMMON_CONFIG Buffer, *BridgeData; + + BridgeData = &Buffer; + + // + // Pull out the resources that should describe the device under assignment. + // + TmpDescr = CmList->List[0].PartialResourceList.PartialDescriptors; + DCount = CmList->List[0].PartialResourceList.Count; + + // + // Find the device's memory needs + // + for (i=0; iType) { + case CmResourceTypeMaximum: + i = DCount; + break; + case CmResourceTypeMemory: + PciCommandFlag |= PCI_ENABLE_MEMORY_SPACE; + if (BaseAddress == 0 ) { + Range = TmpDescr->u.Memory.Length; + BaseAddress = TmpDescr->u.Memory.Start.LowPart; + TopAddr = BaseAddress + TmpDescr->u.Memory.Length; + } + if (BaseAddress > TmpDescr->u.Memory.Start.LowPart) { + // + // set baseaddress to new low address + BaseAddress = TmpDescr->u.Memory.Start.LowPart; + } + + // + // check that the new descriptor's range lies within + // the current TopAddr. + // + if ( (TmpDescr->u.Memory.Start.LowPart + + TmpDescr->u.Memory.Length ) > TopAddr ) { + TopAddr = TmpDescr->u.Memory.Start.LowPart + + TmpDescr->u.Memory.Length; + } + break; + + case CmResourceTypePort: + PciCommandFlag |= PCI_ENABLE_IO_SPACE; + break; + case CmResourceTypeDeviceSpecific: + case CmResourceTypeInterrupt: + case CmResourceTypeDma: + default: + break; + } + } + + + // + // now read the bridges base and limit registers and compare + // the devices memory needs with the bridge's abilities to + // properly decode and pass through the proper memory ranges + // + FpBusData = (PFPHAL_BUSNODE) ChildBus->BusData; + if (FpBusData->Bus.CommonData.ParentSlot.u.AsULONG) { + HalpReadPCIConfig(ChildBus->ParentHandler, // bus type + FpBusData->Bus.CommonData.ParentSlot, + BridgeData, // data buffer, + 0, // Offset, + PCI_COMMON_HDR_LENGTH); // read first 64 words.. + } + + // + // If the bridge does not sufficiently cover the devices needs, + // adjust the limits and make sure the command register is properly + // set. + + // + // Now write out the bridge's new data if any has changed. + // + return 0; +} + +/*-- + Routine: HalpInitPciBridgeConfig( ULONG ) + + Description: + To perform enough initialization of the bridge to allow + configuration scanning along the secondary bus to proceed. Ideally + setup bridge's config registers with initial state that will be + "pruned" by a call to HalpSetPciBridgeConfig. + +--*/ + +ULONG +HalpInitPciBridgeConfig( IN ULONG PrimaryBusNo, + IN OUT PPCI_COMMON_CONFIG PciData, + IN OUT PBUS_HANDLER PrimaryBus ) +{ + PCI_SLOT_NUMBER Slot; + PFPHAL_BUSNODE FpNode=(PFPHAL_BUSNODE)PrimaryBus->BusData; + PPCI_COMMON_CONFIG TmpPciData; + PUCHAR Buffer; + ULONG slotNum; + BOOLEAN DecBridgeChip = FALSE; + BOOLEAN BridgeReconfig = FALSE; + ULONG DeviceSpecificSize = 0; + ULONG ChipConfigReg = 0; + ULONG TimerConfigReg = 0; + char buf[128]; +#if HALDEBUG_ON + ULONG i; +#endif + + HDBG(DBG_GENERAL, + HalpDebugPrint("HalpInitPciBridgeConfig: 0x%x, 0x%08x, 0x%08x\n", + PrimaryBusNo, PciData, PrimaryBus);); + // + // Print out the incoming common config data... + PRINTBRIDGE(PciData); + + // We have been passed the PciData for a bridge chip; before we go any + // further, determine if it is DEC bridge, because we need to do some + // fix-ups if it is. + if( PciData->VendorID == DEC_BRIDGE_CHIP) { + DecBridgeChip = TRUE; + DeviceSpecificSize = 8; + // On POWERSERVE (TX platform) we MUST disable write posting from + // the DEC bridge. + if (SystemType == SYS_POWERSERVE) { + BridgeReconfig = TRUE; + ChipConfigReg = 0x00000006; + } + // Check for NVRAM reconfig values + if (HalGetEnvironmentVariable("DECCHIPCONFIGREG", sizeof(buf), buf) + == ESUCCESS) { + BridgeReconfig = TRUE; + ChipConfigReg = atoi(buf); + } + if (HalGetEnvironmentVariable("DECTIMERCONFIGREG", sizeof(buf), buf) + == ESUCCESS) { + BridgeReconfig = TRUE; + TimerConfigReg = atoi(buf); + } + } + + Buffer = ExAllocatePool (PagedPool, 1024); + TmpPciData = (PPCI_COMMON_CONFIG) Buffer; + TmpPciData->VendorID = 0xffff; + TmpPciData->u.type1.InterruptLine = 0xff; + + Slot.u.AsULONG=FpNode->SlotNumber.u.AsULONG; + +#if HALDEBUG_ON + PRNTPCI(HalpDebugPrint("%s ", TBS)); + for (i=0; iDeviceSpecific[i])); + } + PRNTPCI(HalpDebugPrint("0x%08x\n", PciData->DeviceSpecific[i])); +#endif + + // + // Enable commands in the command register address in first 64 bytes. + // For example, turn on bus mastering, + // + PciData->Command = PCI_ENABLE_IO_SPACE | + PCI_ENABLE_MEMORY_SPACE | + PCI_ENABLE_BUS_MASTER; + + + // + // Keith Son. + // Please do not change the order of assignment. + // I am using the PrimaryBus variable as a passed in value. + // The value is the parent bus number. + // + PciData->u.type1.SecondaryBus = PciData->u.type1.PrimaryBus + 1; + PciData->u.type1.PrimaryBus = (UCHAR) PrimaryBusNo; + PciData->u.type1.SubordinateBus = 0xff; // for now, prune on way back.. + PciData->u.type1.SecondaryStatus = 0xff; + PciData->Status = 0xff; + slotNum = Slot.u.bits.DeviceNumber; + if (slotNum > MAXIMUM_PCI_SLOTS) { + HalpDebugPrint("HalpInitPciBridgeConfig:"); + HalpDebugPrint(" ILLEGAL SLOT NUMBER %d\n", slotNum); + return 0; // add in status on return later... + } + // This can be INVALID_INT + PciData->u.type1.InterruptLine = PciDevicePrimaryInts[slotNum]; + PRNTPCI(HalpDebugPrint("slot=%x\n", + Slot.u.bits.DeviceNumber)); + + + // + // Keith Son. + // Right now we are support four peer level. + // Split the resource even for peer level. + // + if ( PciData->u.type1.SecondaryBus == 4 ) + { + PciData->u.type1.MemoryBase = 0x2000; // for now!! + PciData->u.type1.MemoryLimit= 0x2050; // for now!! + PciData->u.type1.IOBase = 0xa0; // for now!! + PciData->u.type1.IOLimit= 0xa0; // for now!! + + } + else if ( PciData->u.type1.SecondaryBus ==3) + { + PciData->u.type1.MemoryBase = 0x2060; // for now!! + PciData->u.type1.MemoryLimit= 0x2bf0; // for now!! + PciData->u.type1.IOBase = 0xb0; // for now!! + PciData->u.type1.IOLimit= 0xb0; // for now!! + + } + + + else if ( PciData->u.type1.SecondaryBus == 2) + { + PciData->u.type1.MemoryBase = 0x2c00; // for now!! + PciData->u.type1.MemoryLimit= 0x31f0; // for now!! + PciData->u.type1.IOBase = 0xe0; // for now!! + PciData->u.type1.IOLimit= 0xe0; // for now!! + + } + + else + { + PciData->u.type1.MemoryBase = 0x3200; // for now!! + PciData->u.type1.MemoryLimit= 0x3800; // for now!! + PciData->u.type1.IOBase = 0xc0; // for now!! + PciData->u.type1.IOLimit= 0xc0; // for now!! + + } + + + //PciData->Command = 0; // this disables everything?! + PciData->u.type1.BridgeControl = 0; // this disables bridge activity! + + // + // Print out the modified common config data... + PRINTBRIDGE(PciData); + + HalpWritePCIConfig (PrimaryBus, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + PciData->u.type1.BridgeControl = PCI_ASSERT_BRIDGE_RESET; + HalpWritePCIConfig (PrimaryBus, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH); + KeStallExecutionProcessor(100); // wait for 100 microseconds + + PciData->u.type1.BridgeControl = 0x0000; + + // + // Write out new config parameters, and read back in to do some sanity + // checking.... + // + HalpWritePCIConfig (PrimaryBus, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + if ((DecBridgeChip == TRUE) && (BridgeReconfig == TRUE)) { + PULONG ptr; + // Re-program the DEC device specific registers + HalpReadPCIConfig (PrimaryBus, Slot, TmpPciData, 0, + PCI_COMMON_HDR_LENGTH+DeviceSpecificSize); + ptr = (PULONG)&PciData->DeviceSpecific[0]; + *ptr++ = ChipConfigReg; + *ptr = TimerConfigReg; + HalpWritePCIConfig (PrimaryBus, Slot, PciData, 0, + PCI_COMMON_HDR_LENGTH+DeviceSpecificSize); + } + + HalpReadPCIConfig (PrimaryBus, Slot, TmpPciData, 0, + PCI_COMMON_HDR_LENGTH+DeviceSpecificSize); + if ( TmpPciData->u.type1.SecondaryBus != PciData->u.type1.SecondaryBus ){ + HalpDebugPrint("HalpInitPciBridgeConfig: Read no matchee Write!!\n"); + } + // + // Print out the New common config data... + PRINTBRIDGE(TmpPciData); +#if HALDEBUG_ON + PRNTPCI(HalpDebugPrint("%s ", TBS)); + for (i=0; iDeviceSpecific[i])); + } + PRNTPCI(HalpDebugPrint("0x%08x\n", PciData->DeviceSpecific[i])); +#endif + + ExFreePool(Buffer); + + return 1; + +} + +ULONG +HalpConfigurePcmciaBridge(ULONG ParentBusNo ) +{ + PRNTGENRL(HalpDebugPrint("HalpConfigurePcmciaBridge: 0x%x\n",ParentBusNo)); + + return 0; +} + +/*++ + Routine: ULONG HalpGetPciInterruptSlot(PBUS_HANDlER , PCI_SLOT ) + + Description: + + Given a bus ( bus handler ) and a slot on the bus, find the slot value + directly connected to a system interrupt ( I.E. a slot without an inter- + vening bridge ). + + Return: + Returns a slot value disguised as a ULONG. + +--*/ + +ULONG +HalpGetPciInterruptSlot(PBUS_HANDLER BusHandler, PCI_SLOT_NUMBER PciSlot ) +{ + PFPHAL_BUSNODE FpNode; + PBUS_HANDLER TmpBus=0; + + + FpNode = (PFPHAL_BUSNODE)BusHandler->BusData; + TmpBus = BusHandler; + + + // + // Keith Son. + // Rewrote this function to support peer level buses. + // Find the root bus and return the bridge slot on the root bus level. + // + + PRNTPCI(HalpDebugPrint("parent busnumber = 0x%x, \n",FpNode->Bus.ParentBus)); + + + PRNTPCI(HalpDebugPrint("BusHandler = 0x%x, slot = %x\n", BusHandler, PciSlot)); + + + TmpBus = BusHandler->ParentHandler ; + + PRNTPCI(HalpDebugPrint("BusNumber = 0x%x, \n",TmpBus->BusNumber)); + + PRNTPCI(HalpDebugPrint("aslong = 0x%x, \n",FpNode->Bus.CommonData.ParentSlot.u.AsULONG)); + + + while( (TmpBus) && ( TmpBus->BusNumber != 0)) { + PRNTPCI(HalpDebugPrint("aslong = 0x%x, \n",FpNode->Bus.CommonData.ParentSlot.u.AsULONG)); + + FpNode = (PFPHAL_BUSNODE)TmpBus->BusData; + TmpBus = TmpBus->ParentHandler; + + } + + return (FpNode->SlotNumber.u.AsULONG); + + +} + +/*++ + Routine: HalpStatSlot() + + Description: + + Given a known device ( slot ), "stat" the slot to discover + particular information such as memory/io space requirements, + vendor/device ids, device types, etc. + + Also, create a range description of this device to pass back + to the bus scan routine for inclusion into the bus resource + description. + + +--*/ + +ULONG +HalpStatSlot( + IN PPCI_COMMON_CONFIG StatData, + IN PBUS_HANDLER ThisBus, + IN PCI_SLOT_NUMBER Slot, + OUT PSUPPORTED_RANGES pRanges + ) +{ + PPCI_COMMON_CONFIG NewData; + PUCHAR Buffer; + ULONG Addr, Length, Limit, Index; + + Buffer = ExAllocatePool (PagedPool, 1024); + NewData = (PPCI_COMMON_CONFIG) Buffer; + RtlCopyMemory((PVOID)NewData, (PVOID)StatData, PCI_COMMON_HDR_LENGTH); + + // + // setup the NewData to probe memory and io space requirements for the + // device. Write those registers to all 'f's and read back resource needs. + // + for( Addr=0; Addr < PCI_TYPE0_ADDRESSES; Addr++ ) { + NewData->u.type0.BaseAddresses[Addr] = 0xffffffff; + } + + NewData->u.type0.ROMBaseAddress = 0xffffffff & ~(PCI_ROMADDRESS_ENABLED); + NewData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + + HalpWritePCIConfig( ThisBus, Slot, NewData, 0, PCI_COMMON_HDR_LENGTH ); + HalpReadPCIConfig( ThisBus, Slot, NewData, 0, PCI_COMMON_HDR_LENGTH ); + + for( Index=0; Index < PCI_TYPE0_ADDRESSES; Index++ ) { + + Addr = NewData->u.type0.BaseAddresses[Index]; + Length = ( Addr & ( ~(Addr & 0xfffffff0) << 1 )); + Limit = ( Addr & ( 0x80000000 | (~(Addr & 0xfffffff0) >> 1 ))); + + switch( Addr & 0x00000003 ) { + + case PCI_IO_ADDRESS: + ThisBus->BusAddresses->NoIO++; + break; + + default: + ThisBus->BusAddresses->NoMemory++; + break; + } + } + + + // HalpCreateRangeFromPciData(); + + // + // Restore the device to it's original settings. + // + HalpWritePCIConfig( ThisBus, Slot, StatData, 0, PCI_COMMON_HDR_LENGTH ); + + return 1; +} diff --git a/private/ntos/nthals/halfire/ppc/fppcisup.h b/private/ntos/nthals/halfire/ppc/fppcisup.h new file mode 100644 index 000000000..fb15495ae --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fppcisup.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fppcisup.h $ + * $Revision: 1.2 $ + * $Date: 1996/01/11 08:38:36 $ + * $Locker: $ + * + */ + +#define TBS " " + +ULONG +HalpStatSlot( + IN PPCI_COMMON_CONFIG StatData, + IN PBUS_HANDLER ThisBus, + IN PCI_SLOT_NUMBER SlotNumber, + OUT PSUPPORTED_RANGES pRanges + ); + +ULONG +HalpAdjustBridge( + PBUS_HANDLER ChildBus, + PPCI_COMMON_CONFIG PrivData, + PCM_RESOURCE_LIST CmList + ); + +ULONG +HalpConfigurePcmciaBridge( + IN ULONG ParentBusNo + ); + +ULONG +HalpInitPciBridgeConfig( + IN ULONG ParentBusNo, + IN OUT PPCI_COMMON_CONFIG, + IN OUT PBUS_HANDLER ParentBus + ); + +VOID +HalpInitIoBuses ( + VOID + ); + +VOID HalpPCISynchronizeBridged ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +VOID HalpPCIReleaseSynchronzationBridged ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +ULONG HalpPCIReadUlongBridged ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUcharBridged ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshortBridged ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlongBridged ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUcharBridged ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshortBridged ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpGetPciInterruptSlot( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER PciSlot + ); + +PCI_CONFIG_HANDLER PCIConfigHandlerBridged = { + HalpPCISynchronizeBridged, + HalpPCIReleaseSynchronzationBridged, + { + HalpPCIReadUlongBridged, // 0 + HalpPCIReadUcharBridged, // 1 + HalpPCIReadUshortBridged // 2 + }, + { + HalpPCIWriteUlongBridged, // 0 + HalpPCIWriteUcharBridged, // 1 + HalpPCIWriteUshortBridged // 2 + } +}; + + +typedef struct ABusInfo { + struct ABusInfo *ParentBus; + struct ABusInfo *ChildBus; + struct ABusInfo *PeerBus; + ULONG PeerCount; + ULONG ChildCount; +} BUSINFO, PBUSINFO; + +extern KSPIN_LOCK HalpPCIConfigLock; + +// +// scan within a bus for devices, accumulating info. Keep track of +// devices on current bus, how deep you are, who the parents are. +// +ULONG HalpScanPciBus(ULONG HwType, ULONG BusNo, PBUS_HANDLER ParentBus); + + +// +// Once a bus is fully known, then setup all the devs on the bus: +// +ULONG HalpInitPciBus(ULONG BusNo, PULONG ParentBus, PULONG CurrentBus); + diff --git a/private/ntos/nthals/halfire/ppc/fpproto.h b/private/ntos/nthals/halfire/ppc/fpproto.h new file mode 100644 index 000000000..90f7ae0c2 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpproto.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpproto.h $ + * $Revision: 1.1 $ + * $Date: 1996/04/30 23:25:58 $ + * $Locker: $ + */ + + +#ifndef FPPROTO_H +#define FPPROTO_H + +char * FpStrtok ( char * string, const char * control ); + +#endif //FPPROTO_H diff --git a/private/ntos/nthals/halfire/ppc/fpreg.h b/private/ntos/nthals/halfire/ppc/fpreg.h new file mode 100644 index 000000000..70af4feb3 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fpreg.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fpreg.h $ + * $Revision: 1.19 $ + * $Date: 1996/05/14 02:32:57 $ + * $Locker: $ + */ + +#ifndef FPREG_H +#define FPREG_H + +#define MAX_SYSTEM_CPU_NUM 2 +// +// This file contains all of the definitions for the FirePower Control +// registers. C code needing to access these registers should include this +// file. If future boards differ from these definitions, we should move +// the contents of this file into a board specific file, but still +// have c code include fpreg.h +// + +// +// This is a variable that when set contains the virtual address of +// where the system registers were mapped +// +extern PVOID HalpSystemRegisterBase; + +// +// Code to write to a safe place (generate external bus cycle to work +// around the TSC bug). +// +extern ULONG SafePlace; +#define WriteSafePlace() \ + SafePlace = 0x0; \ + HalSweepDcacheRange(&SafePlace, 8); + +// +// The following routine should be called whenever the order of writes +// to a control register needs to be guaranteed. +// +#define FireSyncRegister() \ + __builtin_eieio() ; + // __builtin_sync(); + +// +// After all writes to the Tsc registers, the system needs to +// generate an off chip write request. +// +#define FireTscSyncRegister() \ + WriteSafePlace(); \ + KeFlushWriteBuffer(); + +// +// The following macro handles the conversion from BigEndian to LittleEndian +// This is current setup as a compile time handling but could easily be' +// made dynamic. +// +// Note: The following is the proper definition for Endianess but +// it causes the Motorola Compiler to go nuts. +// +// #ifdef BIGENDIAN +// #define _BE 1 +// #else +// #define _BE 0 +// #endif +// +// #define _ENDIAN(_X) ((int)(_X) + (int)((_BE)?0:4)) +#ifdef BIGENDIAN +#define _ENDIAN(_X) ((ULONG)_X + 0) +#else +// the NT is running in little endian mode. +// The following conversion macro can be used only with +// the addresses at double word boundary and in ASIC. +// It is not required for the memory accesses. +#define _ENDIAN(_X) ((ULONG)_X + 4) +#endif + +// +// These defines provide the mapping to turn an offset into +// a pointer to the 32 bit register. +// + +#define _SYSBASE ((PUCHAR)HalpSystemRegisterBase) +#define _REG(_OFFSET) (*(volatile ULONG * const)(_ENDIAN(_SYSBASE + (_OFFSET)))) +#define _ADDR(_OFFSET) (_ENDIAN(_SYSBASE + (_OFFSET))) + +// +// Register definitions with appropriate bit field defintions below. +// Defines are used because not all of the compilers can be trusted +// to treat bit field definitions correctly for this architecture. +// +#define rInterruptRequest _REG( 0x000000 ) +#define rInterruptRequestSet _REG( 0x000008 ) +#define rInterruptMask0 _REG( 0x000100 ) +#define rInterruptMask1 _REG( 0x000108 ) +#define rInterruptMask2 _REG( 0x000110 ) +#define rInterruptMask3 _REG( 0x000118 ) +#define rInterruptPending0 _REG( 0x000200 ) +#define rInterruptPending1 _REG( 0x000208 ) +#define rInterruptPending2 _REG( 0x000210 ) +#define rInterruptPending3 _REG( 0x000218 ) +#define rCPUMessageInterrupt _REG( 0x000300 ) +#define rCPUMessageInterruptSet _REG( 0x000308 ) +#define rPCIBusErrorCause _REG( 0x000400 ) +#define rPCIBusErrorCauseSet _REG( 0x000408 ) +#define rPCIBusErrorAddressRegister _REG( 0x000410 ) +#define rCPUBusErrorCause _REG( 0x000800 ) +#define rCPUBusErrorCauseSet _REG( 0x000808 ) +#define rCPUBusErrorAddressRegister _REG( 0x000810 ) +#define rErrorStatus0 _REG( 0x001000 ) +#define rErrorStatus0Set _REG( 0x001008 ) +#define rErrorMask _REG( 0x001010 ) +#define rErrorAddr0 _REG( 0x001120 ) +#define rErrorAddr1 _REG( 0x001128 ) +#define rErrorAddr2 _REG( 0x001130 ) +#define rErrorAddr3 _REG( 0x001138 ) +#define rVidInt _REG( 0x001140 ) +#define rVidIntSet _REG( 0x001148 ) +#define rVidIntMask _REG( 0x001150 ) +#define rTscControl _REG( 0x100000 ) +#define rFbControl _REG( 0x100008 ) +#define rEsccControl _REG( 0x100010 ) +#define rEsccL2FLush _REG( 0x100018 ) +#define rScratchPad0 _REG( 0x100020 ) +#define rScratchPad1 _REG( 0x100028 ) +#define rScratchPad2 _REG( 0x100030 ) +#define rLowPowerControl _REG( 0x100080 ) +#define rRomControl _REG( 0x100100 ) +#define rTscStatus0 _REG( 0x100200 ) +#define rTscRevision _REG( 0x100300 ) +#define rMemBank0Config _REG( 0x100400 ) +#define rMemBank1Config _REG( 0x100408 ) +#define rMemBank2Config _REG( 0x100410 ) +#define rMemBank3Config _REG( 0x100418 ) +#define rMemBank4Config _REG( 0x100420 ) +#define rMemBank5Config _REG( 0x100428 ) +#define rMemBank6Config _REG( 0x100430 ) +#define rMemBank7Config _REG( 0x100438 ) +#define rMemDramTiming _REG( 0x100500 ) +#define rMemVramTiming _REG( 0x100508 ) +#define rMemRefresh _REG( 0x100510 ) +#define rVidControl _REG( 0x100518 ) +#define rVidPixelsPerLineLo _REG( 0x100520 ) +#define rVidPixelsPerLineHi _REG( 0x100528 ) +#define rIOControl _REG( 0x101000 ) +#define rPCIConfigType _REG( 0x101100 ) +#define rPIOPendingCount _REG( 0x101200 ) +#define rDMAPendingCount _REG( 0x101300 ) +#define rPCIVendorID _REG( 0x400100 ) +#define rPCIDeviceID _REG( 0x400108 ) +#define rPCICommand _REG( 0x400110 ) +#define rPCIStatus _REG( 0x400118 ) +#define rPCIRevisionID _REG( 0x400120 ) +#define rPCIClassCode _REG( 0x400128 ) +#define rPCIHeaderType _REG( 0x400140 ) + + +// +// Addrs non-dereferenced register declarations +// +#define rInterruptMask _ADDR(0x000100) +#define rInterruptPending _ADDR(0x000200) +//#define memCpuMailBox _ENDIAN(0x80002F80) +#define memCpuMailBox 0x80002F80 +// +// Use the value of the last defines register +// +#define NBPG 4096 +#define roundup(_X, _Y) (((_X) + ((_Y)-1)) / (_Y)) +#define btorp(_X) (roundup((_X), NBPG) ) +#define REGISTER_PAGES (btorp(0x400140)) + + +// +// Place Macros/Masks/Bit Definitions in this area for each of the +// control registers. +// + +// rInterruptRequest +// rInterruptRequestSet + +// rInterruptMask0 +// rInterruptMask1 +// rInterruptMask2 +// rInterruptMask3 + +#define RInterruptMask(_CPU) \ + (*(volatile ULONG * const)(rInterruptMask + (ULONG)((_CPU) << 3))) + //(*(volatile ULONG * const)(rInterruptMask + ((_CPU) * 8))) + +#define RInterruptPending(_CPU) \ + (*(volatile ULONG * const)(rInterruptPending + ((_CPU) * 8))) + +// +// To guarantee that the Mask write is complete we must insure that: +// a) the ordering does not change and b) the all pending reads are +// complete before we continue. Since we are reading the address +// we write, the processor will not re-order the read/write. We +// must use a "sync" to guarantee that the EE bit is not set +// until after the data from the read of RInterruptMask returns. +// +#define WaitForRInterruptMask(_CPU) \ + { \ + volatile ULONG dummyVar; \ + FireSyncRegister(); \ + dummyVar = RInterruptMask(_CPU);\ + __builtin_sync(); \ + } + + +#define MemSetCpuAddr(_CPU) \ + (*(volatile ULONG * const)( memCpuMailBox + ( (( _CPU ) * 8 ) + 0x4 ))) + +#define MemStartCpu(_CPU) \ + (*(volatile ULONG * const)( memCpuMailBox + (( _CPU ) * 8 ))) + +#define ALL_INTS_OFF 0x00000000 +#define ALL_INTS_ON 0xffffffff + +#define CPU_MESSAGE_NUM 31 +#define MEMORY_ERROR_VIDEO_NUM 30 +#define PCI_ERROR_NUM 29 +#define CPU_BUS_ERROR_NUM 28 +#define SIO_NMI_NUM 27 + +#define LX_PCI_SLOT_0_NUM 26 +#define LX_PCI_SLOT_1_NUM 25 +#define LX_PCI_SLOT_2_NUM 24 +#define LX_PCI_SLOT_3_NUM 23 +#define LX_PCI_IDE_INTA_NUM 22 +#define LX_PCI_IDE_INTB_NUM 21 + +#define ENET_NUM 26 +#define SCSI_NUM 25 +#define PCI_SLOT_1_NUM 23 +#define PCI_SLOT_0_NUM 22 +#define SOFTWARE0_NUM 19 +#define SOFTWARE1_NUM 18 +#define SOFTWARE2_NUM 17 +#define SOFTWARE3_NUM 16 +#define ISA_PIND06_NUM 15 +#define ISA_PIND07_NUM 14 +#define MOUSE_NUM 12 +#define ISA_PIND04_NUM 11 +#define AUDIO_NUM 10 +#define ISA_PINB04_NUM 9 +#define RTC_NUM 8 +#define PARALLEL_NUM 7 +#define FLOPPY_NUM 6 +#define DISPLAY_NUM 5 +#define SERIAL1_NUM 4 +#define SERIAL2_NUM 3 +#define KEYBOARD_NUM 1 +#define TIMER_NUM 0 + +#define NUM_2_INT(x) (1 << x ) + +#define CPU_MESSAGE_INT NUM_2_INT( CPU_MESSAGE_NUM ) +#define MEMORY_ERROR_VIDEO_INT NUM_2_INT( MEMORY_ERROR_VIDEO_NUM ) +#define PCI_ERROR_INT NUM_2_INT( PCI_ERROR_NUM ) +#define CPU_BUS_ERROR_INT NUM_2_INT( CPU_BUS_ERROR_NUM ) +#define SIO_NMI_INT NUM_2_INT( SIO_NMI_NUM ) + +#define LX_PCI_SLOT_0_INT NUM_2_INT( LX_PCI_SLOT_0_NUM ) +#define LX_PCI_SLOT_1_INT NUM_2_INT( LX_PCI_SLOT_1_NUM ) +#define LX_PCI_SLOT_2_INT NUM_2_INT( LX_PCI_SLOT_2_NUM ) +#define LX_PCI_SLOT_3_INT NUM_2_INT( LX_PCI_SLOT_3_NUM ) +#define LX_PCI_IDE_INTA_INT NUM_2_INT( LX_PCI_IDE_INTA_NUM ) +#define LX_PCI_IDE_INTB_INT NUM_2_INT( LX_PCI_IDE_INTB_NUM ) + +#define ENET_INT NUM_2_INT( ENET_NUM ) +#define SCSI_INT NUM_2_INT( SCSI_NUM ) +#define PCI_SLOT_1_INT NUM_2_INT( PCI_SLOT_1_NUM ) +#define PCI_SLOT_0_INT NUM_2_INT( PCI_SLOT_0_NUM ) +#define SOFTWARE0_INT NUM_2_INT( SOFTWARE0_NUM ) +#define SOFTWARE1_INT NUM_2_INT( SOFTWARE1_NUM ) +#define SOFTWARE2_INT NUM_2_INT( SOFTWARE2_NUM ) +#define SOFTWARE3_INT NUM_2_INT( SOFTWARE3_NUM ) +#define ISA_PIND06_INT NUM_2_INT( ISA_PIND06_NUM ) +#define ISA_PIND07_INT NUM_2_INT( ISA_PIND07_NUM ) +#define MOUSE_INT NUM_2_INT( MOUSE_NUM ) +#define ISA_PIND04_INT NUM_2_INT( ISA_PIND04_NUM ) +#define AUDIO_INT NUM_2_INT( AUDIO_NUM ) +#define ISA_PINB04_INT NUM_2_INT( ISA_PINB04_NUM ) +#define RTC_INT NUM_2_INT( RTC_NUM ) +#define PARALLEL_INT NUM_2_INT( PARALLEL_NUM ) +#define FLOPPY_INT NUM_2_INT( FLOPPY_NUM ) +#define DISPLAY_INT NUM_2_INT( DISPLAY_NUM ) +#define SERIAL1_INT NUM_2_INT( SERIAL1_NUM ) +#define SERIAL2_INT NUM_2_INT( SERIAL2_NUM ) +#define KEYBOARD_INT NUM_2_INT( KEYBOARD_NUM ) +#define TIMER_INT NUM_2_INT( TIMER_NUM ) + + +#define ALL_BITS_CLEAR 0xffffffff +#define ENABLE_EISA_MASK 0x0000ffff +#define SET_INTS_CLEAR 0xffffffff +#define EISA_INTS_ON 0xffff0000 +#define SCSI_EISA_INT 0x00002000 + + + +// rInterruptPending0 +// rInterruptPending1 +// rInterruptPending2 +// rInterruptPending3 +// rCPUMessageInterrupt +// rCPUMessageInterruptSet + + +// rPCIBusErrorCause +// rPCIBusErrorCauseSet +#define PCI_ERROR_SIGNALED_SYS 0x00000001 +#define PCI_ERROR_DATA_PARITY 0x00000002 +#define PCI_ERROR_DEV_TIMEOUT 0x00000004 +#define PCI_ERROR_TARGET_ABORT 0x00000008 + +// rPCIBusErrorAddressRegister +// rCPUBusErrorCause +#define CPU_ERROR_ILLEGAL_SAACC 0x00000001 +#define CPU_ERROR_ADDR_PARITY 0x00000002 +#define CPU_ERROR_DISCONTIG_ISA 0x00000004 + +// rCPUBusErrorCauseSet +// rCPUBusErrorAddressRegister +// rErrorStatus0 +#define ERROR_ECC_CORRECTED 0x02000000 +#define ERROR_ECC_FAILED 0x04000000 +#define ERROR_ADDR_PARITY 0x08000000 +#define ERROR_DATA_PARITY 0x10000000 +#define ERROR_MEM_PARITY 0x20000000 +#define ERROR_INVALID_XACT 0x40000000 + +// rErrorStatus0Set +// rErrorMask +#define ECC_CORRECTED 0x02000000 +#define ECC_FAILED 0x04000000 +#define ADDRESS_PARITY_ERROR 0x08000000 +#define DATA_PARITY_ERROR 0x10000000 +#define MEM_PARITY_ERROR 0x20000000 +#define INVALID_XACT 0x40000000 + +// rErrorAddr0 +// rErrorAddr1 +// rErrorAddr2 +// rErrorAddr3 +// rVidInt +// rVidIntSet +// rVidIntMask +// rTscControl +#define L2_PRESENT 0x01000000 +#define MP_CONFIG 0x04000000 +#define ECC_ENABLE 0x08000000 +#define LITTLE_ENDIAN 0x10000000 +#define BRIDGE_MODE 0x20000000 + +// rFbControl +#define CPU_VRAM_SWAP_BYTES 0x01000000 +#define CPU_VRAM_ADDR_MUNGE 0x02000000 +#define CPU_INVERT_FB_ADDR_LSB 0x04000000 +#define PCI_VRAM_SWAP_BYTES 0x08000000 +#define PCI_VRAM_SWAP_ENABLES 0x10000000 +#define PCI_INVERT_FB_ADDR2 0x20000000 + +// rEsccControl +// rEsccL2FLush +// rScratchPad0 +// rScratchPad1 +// rScratchPad2 +// rLowPowerControl +// rRomControl +// rTscStatus0 +#define ROM_BUSY 0x00000001 +#define WRQ_FULL 0x00000002 +#define I2Q_FULL 0x00000004 +#define WRQ_EMPTY 0x00000008 +#define I2Q_EMPTY 0x00000010 +//#define CPU_MASK 0x000000c0 +#define CPU_MASK 0xc0000000 +#define GetCpuId() ((rTscStatus0 & CPU_MASK) >> 30) + +// rTscRevision +// rMemBank0Config +// rMemBank1Config +// rMemBank2Config +// rMemBank3Config +// rMemBank4Config +// rMemBank5Config +// rMemBank6Config +// rMemBank7Config +// rMemDramTiming +// rMemVramTiming +// rMemRefresh +// rVidControl +// rVidPixelsPerLineLo +// rVidPixelsPerLineHi +// rIOControl +// rPCIConfigType +#define PCI_TYPE1_CYCLE 0x00000001 + +// rPIOPendingCount +#define PENDING_COUNTMASK 0x0000007f +#define PCI_BRIDGE_MODE 0x00000080 + +// rDMAPendingCount +// rPCIVendorID +// rPCIDeviceID +// rPCICommand +// rPCIStatus +#define PCI_DATA_PARITY_ERROR 0x00008000 +#define PCI_SIGNLD_SYSTEM_ERR 0x00004000 +#define PCI_RCVD_MASTER_ABORT 0x00002000 +#define PCI_RCVD_TARGET_ABORT 0x00001000 +#define PCI_SGNLD_TARGET_ABORT 0x00000800 +#define PCI_DATA_PARITY_DETECT 0x00000100 + +// rPCIRevisionID +// rPCIClassCode +// rPCIHeaderType + +#endif // FPREG_H diff --git a/private/ntos/nthals/halfire/ppc/fprgstry.c b/private/ntos/nthals/halfire/ppc/fprgstry.c new file mode 100644 index 000000000..846ecb301 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/fprgstry.c @@ -0,0 +1,871 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: fprgstry.c $ + * $Revision: 1.40 $ + * $Date: 1996/05/14 02:33:02 $ + * $Locker: $ + */ + +/* mogawa + * HalpInitializeRegistry fails if it is put in HalInitSystem(). + * So I moved it in HalReportResourceUsage(VOID) in pxpro.c. + * Still L"\\Registry\\Machine\\Software\\FirePower" can not be used. + * L"\\Registry\\Machine\\Hardware\\FirePower" can be created successfully. + */ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "pxpcisup.h" +#include "phsystem.h" +#include "stdio.h" +#include "string.h" +#include "fpdebug.h" +#include "fparch.h" +#include "fpi2c.h" +#include "fpcpu.h" + +#define TBS " " + +extern WCHAR rgzMultiFunctionAdapter[]; +extern WCHAR rgzConfigurationData[]; +extern WCHAR rgzIdentifier[]; +extern WCHAR rgzPCIIdentifier[]; +extern WCHAR rgzSystem[]; +extern WCHAR rgzSoftwareDescriptor[]; +extern WCHAR rgzFirePOWERNode[]; +extern WCHAR rgzCpuNode[]; +extern WCHAR rgzHalNode[]; +extern WCHAR rgzVeneerNode[]; +extern WCHAR rgzFirmwareNode[]; +extern NTSTATUS RtlCharToInteger ( PCSZ String, ULONG Base, PULONG Value ); +extern ULONG CpuClockMultiplier; +extern ULONG ProcessorBusFrequency; +extern ULONG TimeBaseCount; +extern ULONG HalpPerformanceFrequency; + + +BOOLEAN HalpInitializeRegistry (IN PLOADER_PARAMETER_BLOCK LoaderBlock); +VOID HalpTranslateSystemSpecificData ( VOID ); +VOID HalpSetUpFirePowerRegistry(VOID); +VOID HalpSetUpSystemBiosKeys( VOID ); + +/* unfortunately the following data must be stored somewhere + * because it is not possible to get these data except when HalinitSystem. + * Registry does not exist when HalInitSystem. + */ +#define FIRMWARE_BUF_SIZE 64 +static char firmwareBuf[FIRMWARE_BUF_SIZE]; +static char veneerBuf[64]; +static ULONG FirstLevelIcacheSize; +static ULONG FirstLevelDcacheSize; +static ULONG SecondLevelCacheSize; + +VOID +HalpTranslateSystemSpecificData ( VOID) +{ + UNICODE_STRING unicodeString, ConfigName, IdentName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE hMFunc, hBus; + NTSTATUS status = STATUS_SEVERITY_INFORMATIONAL; + UCHAR buffer [sizeof(PPCI_REGISTRY_INFO) + 99]; + WCHAR wstr[8]; + ULONG i, junk; + PPCI_REGISTRY_INFO PCIRegInfo = NULL; + + PKEY_VALUE_FULL_INFORMATION ValueInfo; + PCM_FULL_RESOURCE_DESCRIPTOR Desc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc; + + // + // Search the hardware description looking for the cpu node: + // + + RtlInitUnicodeString (&unicodeString, rgzCpuNode); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL); + + + status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, HalpDebugPrint("HalpTranslateSystemSpecificData: "); + HalpDebugPrint("ZwOpenKey returned !NT_SUCCESS \n")); + return; + } + + unicodeString.Buffer = wstr; + unicodeString.MaximumLength = sizeof (wstr); + + RtlInitUnicodeString (&ConfigName, rgzConfigurationData); + RtlInitUnicodeString (&IdentName, rgzIdentifier); + + ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer; + + // + // Now that we have a handler for the node, look for all instances of this + // type. I.E.: Instances are ordinally enumerated 0,1,... + // + for (i=0; TRUE; i++) { + RtlIntegerToUnicodeString (i, 10, &unicodeString); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + hMFunc, + NULL); + + status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + // + // Out of Cpu entries: + // + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("Out of CentralProcessor Entries \n");); + break; + } + + // + // The first CPU entry has the CM_SYSTEM_GENERAL_DATA structure + // attached to it. + // + + status = ZwQueryValueKey ( + hBus, + &ConfigName, + KeyValueFullInformation, + ValueInfo, + sizeof (buffer), + &junk + ); + + ZwClose (hBus); + if (!NT_SUCCESS(status)) { + continue ; + } + + // + // Set Desc to point to the classes at the proscribed offset. Since + // we're looking at a configuration_descriptor, all the data will be + // after the header, at the offset... + // + Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) + ((PUCHAR)ValueInfo + ValueInfo->DataOffset); + PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) + ((PUCHAR)Desc->PartialResourceList.PartialDescriptors); + + while (PDesc->Type != CmResourceTypeDeviceSpecific) { + //PDesc+= (PCM_PARTIAL_RESOURCE_DESCRIPTOR)1; + PDesc += 1; + } + if (PDesc->Type == CmResourceTypeDeviceSpecific) { + // got it.. + PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1); + break; + } + } + ZwClose (hMFunc); +} + +/*---------------------------------------------------------------------------*/ +VOID +HalpSetValueKeyString( + HANDLE key, + PCHAR nameBuffer, + PCHAR dataBuffer + ) +{ + UNICODE_STRING nameUnicodeString; + UNICODE_STRING dataUnicodeString; + ANSI_STRING nameString, dataString; + NTSTATUS status; + PCHAR junkPtr; + + if (NULL == dataBuffer) return; + + RtlInitString (&nameString, + nameBuffer + ); + status = RtlAnsiStringToUnicodeString( + &nameUnicodeString, + &nameString, + TRUE); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpSetValueKeyString: RtlAnsiStringToUnicodeString failed. '%s': (0x%x) \n", nameBuffer, status)); + return; + } + + dataString.MaximumLength = 256; + dataString.Buffer = dataBuffer; + + junkPtr = memchr( + &dataString.Buffer[0], + 0x00, + dataString.MaximumLength + ); + + if (!junkPtr) { + dataString.Length = dataString.MaximumLength; + } else { + dataString.Length = junkPtr - &dataString.Buffer[0]; + } + + status = RtlAnsiStringToUnicodeString( + &dataUnicodeString, + &dataString, + TRUE + ); + if (NT_SUCCESS(status)) { + status = ZwSetValueKey( + key, + &nameUnicodeString, + 0, + REG_SZ, + dataUnicodeString.Buffer, + dataUnicodeString.Length + sizeof(wchar_t)); + + RtlFreeUnicodeString(&dataUnicodeString); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("ZwSetValueKey failed. (0x%x) \n", status)); + } + } + RtlFreeUnicodeString(&nameUnicodeString); +} + + +/*---------------------------------------------------------------------------*/ +VOID +HalpSetValueKeyMultiString( + HANDLE key, + PCHAR nameBuffer, + PCHAR dataBuffer + ) +{ + UNICODE_STRING nameUnicodeString; + UNICODE_STRING dataUnicodeString; + ANSI_STRING nameString, dataString; + NTSTATUS status; + PCHAR junkPtr; + + if (NULL == dataBuffer) return; + + RtlInitString (&nameString, + nameBuffer + ); + status = RtlAnsiStringToUnicodeString( + &nameUnicodeString, + &nameString, + TRUE); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpSetValueKeyString: RtlAnsiStringToUnicodeString failed. '%s': (0x%x) \n", nameBuffer, status)); + return; + } + + dataString.MaximumLength = 256; + dataString.Buffer = dataBuffer; + + junkPtr = memchr( + &dataString.Buffer[0], + 0x00, + dataString.MaximumLength + ); + + if (!junkPtr) { + dataString.Length = dataString.MaximumLength; + } else { + dataString.Length = junkPtr - &dataString.Buffer[0]; + } + + status = RtlAnsiStringToUnicodeString( + &dataUnicodeString, + &dataString, + TRUE + ); + if (NT_SUCCESS(status)) { + status = ZwSetValueKey( + key, + &nameUnicodeString, + 0, + REG_MULTI_SZ, + dataUnicodeString.Buffer, + dataUnicodeString.Length + sizeof(wchar_t)); + + RtlFreeUnicodeString(&dataUnicodeString); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("ZwSetValueKey failed. (0x%x) \n", status)); + } + } + RtlFreeUnicodeString(&nameUnicodeString); +} + + +VOID +HalpSetValueKeyUlong( + HANDLE key, + PCHAR str, + ULONG version + ) +{ + CHAR buffer[16+1]; + + sprintf(buffer, "%08x", version); + HalpSetValueKeyString(key, str, buffer); +} + +ULONG +HalpVersionSystemInRegistry(SYSTEM_TYPE System, HANDLE key) +{ + ULONG TscRevision=0; + ULONG PciRevision=0; + ULONG ProcessorVersion, ProcessorRevision, ProcHertz; + PCHAR debugStr; + CCHAR buffer[256]; + extern RelInfo ThisOne; + extern ULONG HalpVideoMemorySize; // pxdisp.c + + + switch(System) { + + case SYS_POWERTOP : + case SYS_POWERSLICE: + case SYS_POWERSERVE: + TscRevision = (rTscRevision & 0xff000000) >> 24; // bits 7:0 + PciRevision = (rPCIRevisionID & 0xff000000) >> 24; // bits 7:0 + + sprintf(buffer, "%d", TscRevision); + HalpSetValueKeyString(key, "TSC Revision", buffer); + sprintf(buffer, "%d", PciRevision); + HalpSetValueKeyString(key, "TIO Revision", buffer); + break; + + case SYS_POWERPRO : + PciRevision = (rPCIRevisionID & 0xff000000) >> 24; // bits 7:0 + sprintf(buffer, "%d", PciRevision); + HalpSetValueKeyString(key, "ESCC Revision", buffer); + break; + + case SYS_UNKNOWN : + HalpDebugPrint("Unknown system type \n"); + break; + + default: // unknown stuff? should never get here + break; + } +#if DBG==1 + debugStr = "(DEBUG)"; +#else + debugStr = ""; +#endif + sprintf(buffer, "%d.%d %s %s, %s", + (ULONG)ThisOne.Major, (ULONG)ThisOne.Minor, debugStr, + ThisOne.BuildDate, ThisOne.BuildTime); + + HalpSetValueKeyString(key, "HAL Version", buffer); + + ProcessorVersion = HalpGetProcessorVersion(); + ProcessorRevision = ProcessorVersion & 0x0000ffff; + ProcessorVersion = ProcessorVersion >> 16; + + sprintf(buffer, "%d", 600+ProcessorVersion); + HalpSetValueKeyString(key, "Processor", buffer); + sprintf(buffer, "%d.%d", ProcessorRevision/256, ProcessorRevision%256); + HalpSetValueKeyString(key, "Processor Revision", buffer); + + // + // Display the Model Number and our company name + // + ProcHertz = HalpGetCycleTime(); + sprintf(buffer, "%d MHz", ProcHertz); + HalpSetValueKeyString(key, "Processor Clock Frequency", buffer); + + // + // Display the Frequency Multiplier for the Cpu: + // two digits are enough. bug 5182 + // + sprintf(buffer, "%d.%02d MHz",ProcessorBusFrequency/1000000, + (ProcessorBusFrequency - + ((ProcessorBusFrequency / 1000000) * 1000000))/ 10000); + HalpSetValueKeyString(key, "Processor Bus Frequency", buffer); + + // + // Now figure out what the clock multiplier should look like + // in the registery: + // + if ((CpuClockMultiplier == 25) || (CpuClockMultiplier==15)) { + sprintf(buffer, "%d.5", CpuClockMultiplier/10); + } else { + sprintf(buffer, "%d", CpuClockMultiplier/10); + } + HalpSetValueKeyString(key, "Processor Clock Multiplier", buffer); + + // + // For debug HALs, enable registry storage of timing calculations. + // + HDBG(DBG_TIME, sprintf(buffer, "%d",TimeBaseCount )); + HDBG(DBG_TIME, + HalpSetValueKeyString(key, "SYSTEM DEBUG: TimeBaseCount", buffer)); + HDBG(DBG_TIME,sprintf(buffer, "%d",HalpPerformanceFrequency )); + HDBG(DBG_TIME, + HalpSetValueKeyString(key, "SYSTEM DEBUG: HalpPerformanceFrequency", + buffer)); + +#if DBG==1 + sprintf(buffer, "0x%08x",HalpDebugValue ); + HalpSetValueKeyString(key, "DEBUG HALDEBUG", buffer); +#endif + + sprintf(buffer, "Powerized %s", SystemDescription[SystemType].SystemName); + + HalpSetValueKeyString(key, "Hardware", buffer); + HalpSetValueKeyString(key, "IEEE 1275 Firmware Version", firmwareBuf); + HalpSetValueKeyString(key, "ARC Veneer Version", veneerBuf); + sprintf(buffer, "%dK bytes", FirstLevelIcacheSize/1024); + HalpSetValueKeyString(key, "First Level Icache Size", buffer); + sprintf(buffer, "%dK bytes", FirstLevelDcacheSize/1024); + HalpSetValueKeyString(key, "First Level Dcache Size", buffer); + sprintf(buffer, "%dK bytes per CPU", SecondLevelCacheSize/1024); + HalpSetValueKeyString(key, "Second Level Cache Size", buffer); + + if (HalpVideoMemorySize < 0x100000) { + sprintf(buffer, "%dK bytes", HalpVideoMemorySize/1024); + } else { + sprintf(buffer, "%dM bytes", HalpVideoMemorySize/0x100000); + } + if ((System == SYS_POWERPRO) || (System == SYS_POWERTOP)) { + HalpSetValueKeyString(key, "MLU VRAM", buffer); + } + // ALL platforms fill in the registry information, even if they have + // no IIC + HalpSetUpRegistryForI2C(System); + + return(1); // success, true, good, ... +} + +NTSTATUS +HalpCreateKey(HANDLE *pNode, PWCHAR rgzKey) +{ + UNICODE_STRING unicodeString; + OBJECT_ATTRIBUTES objectAttributes; + NTSTATUS status; + ULONG disposition; + + RtlInitUnicodeString (&unicodeString, + rgzKey + ); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL + ); + + status = ZwCreateKey(pNode, + KEY_READ, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_VOLATILE, + &disposition ); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("Did not create key: (0x%x) \n", status)); + } else { + HDBG(DBG_REGISTRY, HalpDebugPrint("Did create key: (0x%x) \n", status)); + } + return status; +} + +/* called from HalReportResourceUsage(VOID) in pxproc. */ +VOID +HalpSetUpFirePowerRegistry( + VOID + ) +{ + OBJECT_ATTRIBUTES objectAttributes; + NTSTATUS status; + HANDLE hNode; + ULONG disposition; + + static CCHAR szFirePower[] = + "\\Registry\\Machine\\Hardware\\Powerized"; //mogawa + STRING strFirePower; + UNICODE_STRING ucFirePower; + // + // Open up the FirePOWER entry in the registry, create it if it's not there: + // Actually, just create it since create will default to open if the entry + // is already present. + // + RtlInitString (&strFirePower, + szFirePower + ); + status = RtlAnsiStringToUnicodeString( + &ucFirePower, + &strFirePower, + TRUE); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("Could not create unicode strings: (0x%x) \n", + status)); + return; + } + InitializeObjectAttributes ( + &objectAttributes, + &ucFirePower, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL + ); + + status = ZwCreateKey(&hNode, + KEY_READ, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_VOLATILE, + &disposition ); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("Did not create key: (0x%x) \n", status);); + RtlFreeUnicodeString(&ucFirePower); + return; + } + //ZwFlushKey(hNode); + HalpVersionSystemInRegistry(SystemType, hNode); + if (NULL != hNode) { + ZwClose (hNode); + } + RtlFreeUnicodeString(&ucFirePower); + HalpSetUpSystemBiosKeys(); + return; +} + + +/* called from HalReportResourceUsage(VOID) in pxproc. */ +VOID +HalpSetUpSystemBiosKeys( + VOID + ) +{ + OBJECT_ATTRIBUTES objectAttributes; + NTSTATUS status; + HANDLE hNode; + CCHAR versionString[256]; + PUCHAR pDateString = ""; + ULONG disposition; + ULONG i; + BOOLEAN DateStringFound = FALSE; + + static CCHAR szFirePower[] = + "\\Registry\\Machine\\Hardware\\Description\\System"; + STRING strFirePower; + UNICODE_STRING ucFirePower; + // + // Open up the FirePOWER entry in the registry, create it if it's not there: + // Actually, just create it since create will default to open if the entry + // is already present. + // + RtlInitString (&strFirePower, + szFirePower + ); + status = RtlAnsiStringToUnicodeString( + &ucFirePower, + &strFirePower, + TRUE); + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("Could not create unicode strings: (0x%x) \n", + status)); + return; + } + InitializeObjectAttributes ( + &objectAttributes, + &ucFirePower, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL + ); + + status = ZwCreateKey(&hNode, + KEY_READ, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_VOLATILE, + &disposition ); + + if (!NT_SUCCESS(status)) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("Did not create key: (0x%x) \n", status);); + RtlFreeUnicodeString(&ucFirePower); + return; + } + //ZwFlushKey(hNode); + + // Seperate the version and date strings in the firmwareBuf identifier + // ASSUMES that the month is the first item of the date and it starts + // with an uppercase letter. + for (i=0; i < FIRMWARE_BUF_SIZE; i++) { + if (firmwareBuf[i] >= 'A' && firmwareBuf[i] <= 'Z') { + pDateString = &firmwareBuf[i]; + versionString[i] = '\0'; + DateStringFound = TRUE; + break; + } + versionString[i] = firmwareBuf[i]; + } + + HASSERT(DateStringFound); + + HalpSetValueKeyString(hNode, "SystemBiosDate", pDateString); + HalpSetValueKeyString(hNode, "SystemBiosVersion", versionString); + HalpSetValueKeyString(hNode, "VideoBiosDate", ""); + HalpSetValueKeyString(hNode, "VideoBiosVersion", ""); + if (NULL != hNode) { + ZwClose (hNode); + } + RtlFreeUnicodeString(&ucFirePower); + return; +} + +/*----------------------------------------------------------------------------*/ + +static VOID HalpAppendSprintf( + PCHAR buffer, + PCHAR format, + ... + ) +{ + va_list arglist; + ULONG length; + UCHAR tempBuf[256]; + + va_start(arglist, format); + length = vsprintf(tempBuf, format, arglist); + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpAppendSprintf: tempBuf='%s'\n", tempBuf)); + if (length) { + strcat(buffer, tempBuf); + } else { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpAppendSprintf: vsprintf returned length=%n\n", + length)); + } +} + +static PCHAR +gettoken(PCHAR token, PCHAR buf, CHAR delim) +{ + CHAR c; + while (c = *buf) { + if (c == delim) { + buf++; + break; + } else { + *token++ = c; + buf++; + } + } + *token = '\0'; + return buf; +} + +static VOID +HalpSetVersionData( IN PCHAR VersionData + ) +{ + + while (*VersionData) { + enum {Firmware = 0, Veneer = 1, Nada}; + ULONG type; + PCHAR typeStr[2] = {"Firmware", "Veneer"}; + CHAR token[64]; + PCHAR tok = VersionData; + PCHAR buffer; + CHAR buf[80]; + buffer = (PCHAR)0; // to satisfy warnings + + VersionData += strlen(VersionData)+1; + + if (strstr(tok, typeStr[Firmware])) { + type = Firmware; + buffer = firmwareBuf; + buffer[0] = '\0'; + } else { + if (strstr(tok, typeStr[Veneer])) { + type = Veneer; + buffer = veneerBuf; + buffer[0] = '\0'; + } else { + type = Nada; + } + } + if (Nada == type) { + continue; + } + /* else */ + + if (*VersionData) { + LONG n; + + tok = VersionData; + VersionData += strlen(VersionData)+1; + n = 0; + tok = gettoken(token, tok, ','); + + while (*token) { + switch (n++) { + case 2: + strcpy(buf, token); + strcat(buf, "\0"); + if (strlen(buf) < 7) { + HalpAppendSprintf(buffer, "%-7s", buf); + } else { + HalpAppendSprintf(buffer, "%s ", buf); + } + break; + case 3: + // + // Put date in Mmm dd yyyy format if in yyyy-mm-dd + // No unicode here :-). + // isdigit() causes too many link hassles. + // We CANNOT change the case of the first letter of the + // month without changing HalpSetUpSystemBiosKeys + // + if (type == Firmware && *token >= '0' && *token <= '9') { + PCHAR day; + PCHAR month; + PCHAR year; + PCHAR Mmm[12] = { + "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec", + }; + + strcpy(buf, token); + if (day = strrchr(buf, '-')) { + *day++ = '\0'; + if (month = strrchr(buf, '-')) { + ULONG i; + *month++ = '\0'; + RtlCharToInteger(month, 10, &i); + if (i > 12 || i < 1) { + HalpAppendSprintf(buffer, "%s, ", token); + } else { + year = buf; + // + // Decrement the month by one to align with + // zero based nature of the Mmm array. + // + HalpAppendSprintf(buffer, "%s %s %s, ", + Mmm[i-1], day, year); + } + } + } else { + HalpAppendSprintf(buffer, "%s, ", token); + } + } else { + HalpAppendSprintf(buffer, "%s, ", token); + } + break; + case 4: + HalpAppendSprintf(buffer, "%s", token); + break; + } // end of switch...... + tok = gettoken(token, tok, ','); + + } + } + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpSetVersionData: %s\n", buffer); + ); + + } /* while */ +} + +/* called in HalInitSystem phase 1 in pxinithl.c */ +BOOLEAN +HalpInitializeRegistry ( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) +{ + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + ULONG MatchKey; + PCHAR versionData; + extern PCHAR HalpGetVersionData( IN PLOADER_PARAMETER_BLOCK ); + + + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: FirstLevelDcacheSize=0x%08x\n", + LoaderBlock->u.Ppc.FirstLevelDcacheSize)); + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: FirstLevelIcacheSize=0x%08x\n", + LoaderBlock->u.Ppc.FirstLevelDcacheSize)); + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: SecondLevelDcacheSize=0x%08x\n", + LoaderBlock->u.Ppc.SecondLevelDcacheSize)); + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: SecondLevelIcacheSize=0x%08x\n", + LoaderBlock->u.Ppc.SecondLevelIcacheSize)); + FirstLevelIcacheSize = LoaderBlock->u.Ppc.FirstLevelIcacheSize; + FirstLevelDcacheSize = LoaderBlock->u.Ppc.FirstLevelDcacheSize; + SecondLevelCacheSize = LoaderBlock->u.Ppc.SecondLevelDcacheSize; + MatchKey = 0; + ConfigurationEntry=KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + CacheClass, + PrimaryIcache, + &MatchKey); + if (ConfigurationEntry) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: PrimaryIcache Key=0x%08x\n", + ConfigurationEntry->ComponentEntry.Key);); + + } else { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: KeFindConfigurationEntry PrimaryICache failed\n")); + } + + MatchKey = 0; + ConfigurationEntry=KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + CacheClass, + PrimaryDcache, + &MatchKey); + + if (ConfigurationEntry) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: PrimaryDcache Key=0x%08x\n", + ConfigurationEntry->ComponentEntry.Key)); + } else { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: KeFindConfigurationEntry PrimaryDcache failed\n");); + } + + MatchKey = 0; + ConfigurationEntry=KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + CacheClass, + SecondaryCache, + &MatchKey); + if (ConfigurationEntry) { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: SecondaryCache Key=0x%x\n", + ConfigurationEntry->ComponentEntry.Key)); + } else { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: KeFindConfigurationEntry SecondaryCache failed\n")); + } + + if ( versionData = HalpGetVersionData(LoaderBlock) ) { + HalpSetVersionData(versionData); + } else { + HDBG(DBG_REGISTRY, + HalpDebugPrint("HalpInitializeRegistry: HalpGetVersionData failed.\n")); + } + return TRUE; +} diff --git a/private/ntos/nthals/halfire/ppc/halp.h b/private/ntos/nthals/halfire/ppc/halp.h new file mode 100644 index 000000000..14862b25e --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/halp.h @@ -0,0 +1,267 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: halp.h $ + * $Revision: 1.20 $ + * $Date: 1996/05/14 02:33:08 $ + * $Locker: $ + */ + +/*++ BUILD Version: 0003 // Increment this if a change has global effects + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + halp.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + interfaces. + +Author: + + David N. Cutler (davec) 25-Apr-1991 + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port + + Added PPC specific includes + Changed paramaters to HalpProfileInterrupt + Added function prototype for HalpWriteCompareRegisterAndClear() + Added include for ppcdef.h + +--*/ + +#ifndef _HALP_ +#define _HALP_ + +#if defined(NT_UP) + +#undef NT_UP + +#endif + +#include "nthal.h" + + +#include "ppcdef.h" + +#include "hal.h" +#include "pxhalp.h" + + + + +// Debug prints. see pxdisp.c +#include + +VOID HalpDebugPrint( PCHAR Format, ... ); +VOID HalpForceDisplay( PCHAR Format, ... ); + +// +// Resource usage information +// + +#define MAXIMUM_IDTVECTOR 255 + +typedef struct { + UCHAR Flags; + KIRQL Irql; + UCHAR BusReleativeVector; +} IDTUsage; + +typedef struct _HalAddressUsage{ + struct _HalAddressUsage *Next; + CM_RESOURCE_TYPE Type; // Port or Memory + UCHAR Flags; // same as IDTUsage.Flags + struct { + ULONG Start; + USHORT Length; + } Element[]; +} ADDRESS_USAGE; + +#define IDTOwned 0x01 // IDT is not available for others +#define InterruptLatched 0x02 // Level or Latched +#define InternalUsage 0x11 // Report usage on internal bus +#define DeviceUsage 0x21 // Report usage on device bus + +extern IDTUsage HalpIDTUsage[]; +extern ADDRESS_USAGE *HalpAddressUsageList; + +#define HalpRegisterAddressUsage(a) \ + (a)->Next = HalpAddressUsageList, HalpAddressUsageList = (a); + +#define HalpGetProcessorVersion() KeGetPvr() + +#define HalpEnableInterrupts() _enable() +#define HalpDisableInterrupts() _disable() + +#define KeFlushWriteBuffer() __builtin_eieio() + +// +// Bus handlers +// + + +PBUS_HANDLER HalpAllocateBusHandler ( + IN INTERFACE_TYPE InterfaceType, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN BUS_DATA_TYPE ParentBusDataType, + IN ULONG ParentBusNumber, + IN ULONG BusSpecificData + ); + +#define HalpAllocateConfigSpace HalpAllocateBusHandler + +#define HalpHandlerForBus HaliHandlerForBus + +#define SPRANGEPOOL NonPagedPool // for now, until crashdump is fixed +// +// Define function prototypes. +// + +BOOLEAN +HalpGrowMapBuffers( + PADAPTER_OBJECT AdapterObject, + ULONG Amount + ); + +PADAPTER_OBJECT +HalpAllocateAdapter( + IN ULONG MapRegistersPerChannel, + IN PVOID AdapterBaseVa, + IN PVOID MapRegisterBase + ); + + +BOOLEAN +HalpCalibrateTimingValues ( + VOID + ); + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ); + +VOID +HalpIpiInterrupt ( + VOID + ); + +BOOLEAN +HalpInitializeDisplay ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +BOOLEAN +HalpMapIoSpace ( + VOID + ); + +BOOLEAN +HalpInitPciIsaBridge ( + VOID + ); + +VOID +HalpHandleIoError ( + VOID + ); + +BOOLEAN +HalpInitPlanar ( + VOID + ); + +VOID +HalpHandleMemoryError( + VOID + ); + +BOOLEAN +HalpHandleProfileInterrupt ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + + +BOOLEAN +HalpInitSuperIo( + VOID + ); + +BOOLEAN +HalpEnableInterruptHandler ( + IN PKINTERRUPT Interrupt, + IN PKSERVICE_ROUTINE ServiceRoutine, + IN PVOID ServiceContext, + IN PKSPIN_LOCK SpinLock OPTIONAL, + IN ULONG Vector, + IN KIRQL Irql, + IN KIRQL SynchronizeIrql, + IN KINTERRUPT_MODE InterruptMode, + IN BOOLEAN ShareVector, + IN CCHAR ProcessorNumber, + IN BOOLEAN FloatingSave, + IN UCHAR ReportFlags, + IN KIRQL BusVector + ); + + +VOID +HalpRegisterVector ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql + ); + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE DeviceInterfaceToUse + ); + +NTSTATUS +HalpAdjustResourceListLimits ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList, + IN ULONG MinimumMemoryAddress, + IN ULONG MaximumMemoryAddress, + IN ULONG MinimumPrefetchMemoryAddress, + IN ULONG MaximumPrefetchMemoryAddress, + IN BOOLEAN LimitedIOSupport, + IN ULONG MinimumPortAddress, + IN ULONG MaximumPortAddress, + IN PUCHAR IrqTable, + IN ULONG IrqTableLength, + IN ULONG MinimumDmaChannel, + IN ULONG MaximumDmaChannel + ); + + +// +// Define external references. +// + +extern KSPIN_LOCK HalpBeepLock; +extern KSPIN_LOCK HalpDisplayAdapterLock; +extern KSPIN_LOCK HalpSystemInterruptLock; +extern KAFFINITY HalpIsaBusAffinity; +extern ULONG HalpProfileCount; +extern ULONG HalpCurrentTimeIncrement; +extern ULONG HalpNewTimeIncrement; + + +#define IRQ_VALID 0x01 +#define IRQ_PREFERRED 0x02 + +#endif // _HALP_ diff --git a/private/ntos/nthals/halfire/ppc/pcibios.c b/private/ntos/nthals/halfire/ppc/pcibios.c new file mode 100644 index 000000000..a6ec9a959 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pcibios.c @@ -0,0 +1,1084 @@ +/*++ + + +Copyright (C) 1996 Motorola Inc. + +Module Name: + + pcibios.c + +Abstract: + + Emulate PCI BIOS functions. + + Note that the HAL bus functions (HalGetBusData, etc.) are not + available at this phase of initialization, all of the work has + to be done here. + +Author: + + Scott Geranen + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" + +#include "pxmemctl.h" +#include "pxpcisup.h" + +#include "emulate.h" +#include "pcibios.h" + +UCHAR SBReadConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ); + +USHORT SBReadConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ); + +ULONG SBReadConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ); + +VOID SBWriteConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN UCHAR Data + ); + +VOID SBWriteConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN USHORT Data + ); + +VOID SBWriteConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN ULONG Data + ); + +// +// Last PCI bus in the system. +// +extern UCHAR HalpLastPciBus; + +// +// Ports to be used to access config space. +// +#define CONFIG_ADDR_PORT (0x00000CF8) +#define CONFIG_DATA_PORT (0x00000CFC) + +ULONG +x86BiosReadIoSpace ( + IN XM_OPERATION_DATATYPE DataType, + IN USHORT PortNumber + ); + + +VOID +x86BiosWriteIoSpace ( + IN XM_OPERATION_DATATYPE DataType, + IN USHORT PortNumber, + IN ULONG Value + ); + +BOOLEAN +HalpEmulatePciBios( + IN OUT PRXM_CONTEXT P + ) +/*++ + +Routine Description: + + This function emulates the PCI BIOS Specification, revision 2.1. The + specification is available from the PCI Special Interest Group. + + This function assumes that it is being called during phase 0 initialization. + The PCI bus functions are not available at this point, e.g. HalGetBusData. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + +Return Value: + + TRUE (PCI BIOS was emulated) + +--*/ +{ +#if DBG + VOID TestPciBios(int flag); + + TestPciBios(0); +#endif + + switch (P->Gpr[EAX].Xl) { + + case PCIBIOS_PCI_BIOS_PRESENT: // Installation Check + + KdPrint(("PCI_BIOS_PRESENT\n")); + + P->Gpr[EDX].Exx = 0x20494350; // "PCI " + + P->Gpr[EAX].Xh = 0x00; // 00 == BIOS present + P->Gpr[EAX].Xl = 0x11; // PCI Hardware Characteristics (mech #1) + + P->Gpr[EBX].Xh = 0x02; // PCI Interface Level Major Version + P->Gpr[EBX].Xl = 0x10; // PCI Interface Level (BCD) + + P->Gpr[ECX].Xl = HalpLastPciBus; // Last PCI bus number + + P->Eflags.CF = 0; // reset == PCI BIOS present + + break; + + case PCIBIOS_FIND_PCI_DEVICE: + { + USHORT DevID = P->Gpr[ECX].Xx; + USHORT VenID = P->Gpr[EDX].Xx; + USHORT DevIndex = P->Gpr[ESI].Xx; + + UCHAR Bus, Device, Function, Header, NumFunctions; + BOOLEAN Found = FALSE; + + KdPrint(("Looking for instance %d of 0x%X, 0x%X\n", DevIndex, DevID, VenID)); + + if (VenID == 0xFFFF) { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_VENDOR_ID; + P->Eflags.CF = 1; // set == error + + } else { + + for (Bus = 0; Bus <= HalpLastPciBus; Bus++) { + for (Device = 0; Device < PCI_MAX_DEVICES; Device++) { + + if (SBReadConfigWord(Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID)) == 0xFFFF) { + + continue; // no device here + + } + + Header = SBReadConfigByte( + Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType)); + + NumFunctions = Header & PCI_MULTIFUNCTION ? 8 : 1; + + for (Function = 0; Function < NumFunctions; Function++) { + + if (SBReadConfigWord(Bus, Device, Function, + FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID)) == VenID) { + + if (SBReadConfigWord(Bus, Device, Function, + FIELD_OFFSET(PCI_COMMON_CONFIG, DeviceID)) == DevID) { + + Found = (DevIndex == 0); + DevIndex--; + } + } + if (Found) break; // function + } + if (Found) break; // device + } + if (Found) break; // bus + } + + if (Found) { + + KdPrint(("Found at %d, %d, %d\n", Bus, Device, Function)); + + P->Gpr[EBX].Xh = Bus; + P->Gpr[EBX].Xl = (Device << 3) + Function; + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + + P->Eflags.CF = 0; // clear == success + + } else { + + KdPrint(("Not found\n")); + + P->Gpr[EAX].Xh = PCIBIOS_DEVICE_NOT_FOUND; + + P->Eflags.CF = 1; // set == error + } + + } + } + break; + + + case PCIBIOS_FIND_PCI_CLASS_CODE: + { + ULONG ClassCode = (P->Gpr[ECX].Exx) << 8; // see comments below + USHORT DevIndex = P->Gpr[ESI].Xx; + + UCHAR Bus, Device, Function, Header, NumFunctions; + BOOLEAN Found = FALSE; + + KdPrint(("Looking for class instance %d of 0x%X\n", DevIndex, P->Gpr[ECX].Exx)); + + for (Bus = 0; Bus <= HalpLastPciBus; Bus++) { + for (Device = 0; Device < PCI_MAX_DEVICES; Device++) { + + if (SBReadConfigWord(Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID)) == 0xFFFF) { + + continue; // no device here + + } + + Header = SBReadConfigByte( + Bus, Device, 0, + FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType)); + + NumFunctions = Header & PCI_MULTIFUNCTION ? 8 : 1; + + for (Function = 0; Function < NumFunctions; Function++) { + + // + // The class code bytes are in the same Dword as + // the revision id: + // + // Byte + // 3 2 1 0 + // +-------------------+--------+ + // | class code | Rev id | + // +-------------------+--------+ + // + // Read the Dword and mask off the revision id. + // The class code we are looking for has been + // shifted up already above. + // + if ((SBReadConfigDword(Bus, Device, Function, + FIELD_OFFSET(PCI_COMMON_CONFIG, RevisionID)) + & 0xFFFFFF00) == ClassCode) { + + Found = (DevIndex == 0); + DevIndex--; + } + if (Found) break; // function + } + if (Found) break; // device + } + if (Found) break; // bus + } + + if (Found) { + + KdPrint(("Found at %d, %d, %d\n", Bus, Device, Function)); + + P->Gpr[EBX].Xh = Bus; + P->Gpr[EBX].Xl = (Device << 3) + Function; + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + + P->Eflags.CF = 0; // clear == success + + } else { + + KdPrint(("Not found\n")); + + P->Gpr[EAX].Xh = PCIBIOS_DEVICE_NOT_FOUND; + + P->Eflags.CF = 1; // set == error + } + } + break; + + case PCIBIOS_READ_CONFIG_BYTE: + + KdPrint(("read byte %d, %d, %d, %d\n", + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + P->Gpr[ECX].Xl = SBReadConfigByte( + P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl); // Register + + KdPrint(("Data = 0x%X\n", P->Gpr[ECX].Xl)); + + break; + + case PCIBIOS_READ_CONFIG_WORD: + + KdPrint(("read word %d, %d, %d, %d\n", + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 1) == 0) { + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + P->Gpr[ECX].Xx = SBReadConfigWord( + P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl); // Register + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + KdPrint(("Data = 0x%X\n", P->Gpr[ECX].Xx)); + + break; + + case PCIBIOS_READ_CONFIG_DWORD: + + KdPrint(("read Dword %d, %d, %d, %d\n", + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 3) == 0) { + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + P->Gpr[ECX].Exx = SBReadConfigDword( + P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl); // Register + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + KdPrint(("Data = 0x%X\n", P->Gpr[ECX].Exx)); + + break; + + case PCIBIOS_WRITE_CONFIG_BYTE: + + KdPrint(("Write byte 0x%X to %d, %d, %d, %d\n", + P->Gpr[ECX].Xl, // Value + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + SBWriteConfigByte( P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl, // Register + P->Gpr[ECX].Xl); // Value + break; + + case PCIBIOS_WRITE_CONFIG_WORD: + + KdPrint(("Write word 0x%X to %d, %d, %d, %d\n", + P->Gpr[ECX].Xx, // Value + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 1) == 0) { + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + SBWriteConfigWord( P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl, // Register + P->Gpr[ECX].Xx); // Value + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + break; + + case PCIBIOS_WRITE_CONFIG_DWORD: + + KdPrint(("Write Dword 0x%X to %d, %d, %d, %d\n", + P->Gpr[ECX].Exx, // Value + P->Gpr[EBX].Xh, // Bus + (P->Gpr[EBX].Xl >> 3), // Device + (P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl)); // Register + + if ((P->Gpr[EDI].Xl & 3) == 0) { + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + + SBWriteConfigDword( P->Gpr[EBX].Xh, // Bus + (UCHAR)(P->Gpr[EBX].Xl >> 3), // Device + (UCHAR)(P->Gpr[EBX].Xl & 0x07), // Function + P->Gpr[EDI].Xl, // Register + P->Gpr[ECX].Exx); // Value + } else { + + P->Gpr[EAX].Xh = PCIBIOS_BAD_REGISTER_NUMBER; + P->Eflags.CF = 1; // set == error + } + + break; + + case PCIBIOS_GENERATE_SPECIAL_CYCLE: + { + PCI_TYPE1_CFG_BITS Addr; + + KdPrint(("Generate Special cycle %d, 0x%X\n", + P->Gpr[EBX].Xh, // Bus + P->Gpr[ECX].Exx)); // Value + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = P->Gpr[EBX].Xh; + Addr.u.bits.DeviceNumber = 0x1f; + Addr.u.bits.FunctionNumber = 7; + + x86BiosWriteIoSpace (LONG_DATA, CONFIG_ADDR_PORT, Addr.u.AsULONG); + x86BiosWriteIoSpace (LONG_DATA, CONFIG_DATA_PORT, P->Gpr[EDX].Exx); + + + P->Gpr[EAX].Xh = PCIBIOS_SUCCESSFUL; + P->Eflags.CF = 0; // clear == success + } + + break; + + + case PCIBIOS_GET_IRQ_ROUTING_OPTIONS: // not supported + case PCIBIOS_SET_IRQ_ROUTING_OPTIONS: // not supported + default: + + KdPrint(("PCI BIOS: function %x not supported\n", P->Gpr[EAX].Xl)); + + P->Gpr[EAX].Xh = PCIBIOS_FUNC_NOT_SUPPORTED; + + P->Eflags.CF = 1; // set == error + + break; + } + + return TRUE; +} + +UCHAR +SBReadConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ) +{ + ULONG ByteInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + ByteInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + x86BiosWriteIoSpace (LONG_DATA, CONFIG_ADDR_PORT, Addr.u.AsULONG); + return((UCHAR)x86BiosReadIoSpace (BYTE_DATA, (USHORT)(CONFIG_DATA_PORT + ByteInRegister))); + +} + +USHORT +SBReadConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ) +{ + ULONG WordInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + WordInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + x86BiosWriteIoSpace (LONG_DATA, CONFIG_ADDR_PORT, Addr.u.AsULONG); + return((USHORT)x86BiosReadIoSpace (WORD_DATA, (USHORT)(CONFIG_DATA_PORT + WordInRegister))); + +} + +ULONG +SBReadConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register + ) +{ + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + x86BiosWriteIoSpace (LONG_DATA, CONFIG_ADDR_PORT, Addr.u.AsULONG); + return(x86BiosReadIoSpace (LONG_DATA, (USHORT)CONFIG_DATA_PORT)); + +} + +VOID +SBWriteConfigByte( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN UCHAR Data + ) +{ + ULONG ByteInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + ByteInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + x86BiosWriteIoSpace (LONG_DATA, CONFIG_ADDR_PORT, Addr.u.AsULONG); + + x86BiosWriteIoSpace ( + BYTE_DATA, + (USHORT)(CONFIG_DATA_PORT + ByteInRegister), + Data + ); + +} + +VOID +SBWriteConfigWord( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN USHORT Data + ) +{ + ULONG WordInRegister; + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + WordInRegister = Register % sizeof(ULONG); + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + x86BiosWriteIoSpace (LONG_DATA, CONFIG_ADDR_PORT, Addr.u.AsULONG); + + x86BiosWriteIoSpace ( + WORD_DATA, + (USHORT)(CONFIG_DATA_PORT + WordInRegister), + Data + ); + +} + +VOID +SBWriteConfigDword( + IN UCHAR Bus, + IN UCHAR Device, + IN UCHAR Function, + IN UCHAR Register, + IN ULONG Data + ) +{ + PCI_TYPE1_CFG_BITS Addr; + + Addr.u.AsULONG = 0; // initialize reserved bits + + Addr.u.bits.Enable = TRUE; + + Addr.u.bits.BusNumber = Bus; + Addr.u.bits.DeviceNumber = Device; + Addr.u.bits.FunctionNumber = Function; + + Addr.u.bits.RegisterNumber = Register / sizeof(ULONG); + + x86BiosWriteIoSpace (LONG_DATA, CONFIG_ADDR_PORT, Addr.u.AsULONG); + + x86BiosWriteIoSpace ( + LONG_DATA, + CONFIG_DATA_PORT, + Data + ); + +} + + +#if DBG + +// Modify this code to match your particular HW configuration +// +// Use the debugger to force flag to 1. + +VOID +initregs(PRXM_CONTEXT P) +{ + P->Gpr[EAX].Exx = 0x1234B100; + P->Gpr[EBX].Exx = 0x23456789; + P->Gpr[ECX].Exx = 0x3456789A; + P->Gpr[EDX].Exx = 0x456789AB; + P->Gpr[ESP].Exx = 0x87654321; + P->Gpr[EBP].Exx = 0x98765432; + P->Gpr[ESI].Exx = 0xA9876543; + P->Gpr[EDI].Exx = 0xBA987654; + + P->Eflags.CF = 1; +} + +VOID +dumpregs(PRXM_CONTEXT P) +{ + DbgPrint("Carry = %d\n", P->Eflags.CF); + + DbgPrint("EAX = %X, EBX = %X, ECX = %X, EDX = %X\n", + P->Gpr[EAX], P->Gpr[EBX], P->Gpr[ECX], P->Gpr[EDX]); + + DbgPrint("ESP = %X, EBP = %X, ESI = %X, EDI = %X\n", + P->Gpr[ESP], P->Gpr[EBP], P->Gpr[ESI], P->Gpr[EDI]); +} + + +VOID +TestPciBios(int flag) +{ +int i; +XM_CONTEXT Context; +PRXM_CONTEXT P = &Context; + + if (flag == 0) return; + + DbgBreakPoint(); + initregs(P); + dumpregs(P); + DbgBreakPoint(); + + P->Gpr[EAX].Xl = 1; // bios present + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0xffff; + P->Gpr[EDX].Xx = 0xffff; + P->Gpr[ESI].Xx = 0; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x0453; + P->Gpr[EDX].Xx = 0x8086; + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x0002; + P->Gpr[EDX].Xx = 0x1011; // DEC ethernet + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x7278; + P->Gpr[EDX].Xx = 0x9004; // adaptec + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + + initregs(P); + P->Gpr[EAX].Xl = 2; // find device + P->Gpr[ECX].Xx = 0x1234; + P->Gpr[EDX].Xx = 0x5678; + P->Gpr[ESI].Xx = 0; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0x030000; // vga + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0x020000; // ethernet + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + for (P->Eflags.CF = 0, i = 0; P->Eflags.CF == 0; i++) + { + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0x010000; // scsi + P->Gpr[ESI].Xx = i; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + } + + initregs(P); + P->Gpr[EAX].Xl = 3; // find class code + P->Gpr[ECX].Exx = 0xABCDEF; // not found + P->Gpr[ESI].Xx = 0; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + + initregs(P); + P->Gpr[EAX].Xl = 6; // generate special cycle + P->Gpr[EBX].Xh = 0; + P->Gpr[EDX].Exx = 0x00000002; // x86 specific + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xE; // get irq routing + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xF; // set irq routing + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (2 << 3) + 0; // non-existent + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 1; // non-existent function + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 8; // read byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 4; // existent function + P->Gpr[EDI].Xx = 1; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 1; // bad register number + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (2 << 3) + 0; // non-existent + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 1; // non-existent function + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 9; // read word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 4; // existent function + P->Gpr[EDI].Xx = 2; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 2; // bad register number + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (2 << 3) + 0; // non-existent + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 1; // non-existent function + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 4; // existent function + P->Gpr[EDI].Xx = 4; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (17 << 3) + 0; + P->Gpr[EDI].Xx = 2; // bad register number + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3C; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xB; // write byte + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3C; + P->Gpr[ECX].Xl = 0xAB; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3C; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xC; // write word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3F; // bad register + P->Gpr[ECX].Xl = 0xAB; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xC; // write word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + P->Gpr[ECX].Xx = 0xFFFF; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xD; // write Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x3F; // bad register + P->Gpr[ECX].Xl = 0xAB; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xD; // write word + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + P->Gpr[ECX].Exx = 0xFFFFFFFF; + HalpEmulatePciBios(P); + dumpregs(P); + initregs(P); + P->Gpr[EAX].Xl = 0xA; // read Dword + P->Gpr[EBX].Xh = 0; + P->Gpr[EBX].Xl = (16 << 3) + 0; + P->Gpr[EDI].Xx = 0x30; + HalpEmulatePciBios(P); + dumpregs(P); + DbgBreakPoint(); + + DbgPrint("All done!\n"); + DbgBreakPoint(); +} +#endif diff --git a/private/ntos/nthals/halfire/ppc/pcibios.h b/private/ntos/nthals/halfire/ppc/pcibios.h new file mode 100644 index 000000000..2e47f6b23 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pcibios.h @@ -0,0 +1,58 @@ +/*++ BUILD Version: 0000 // Increment this if a change has global effects + +Copyright (c) 1996 Motorola Inc. + +Module Name: + + pcibios.h + +Abstract: + + This module contains the private header file for the PCI bios + emulation. + +Author: + + Scott Geranen (3-4-96) + +Revision History: + +--*/ + +#ifndef _PCIBIOS_ +#define _PCIBIOS_ + + +BOOLEAN HalpEmulatePciBios( + IN OUT PRXM_CONTEXT P + ); + +// +// PCI BIOS v2.1 functions +// +#define PCIBIOS_PCI_FUNCTION_ID 0xB1 +#define PCIBIOS_PCI_BIOS_PRESENT 0x01 +#define PCIBIOS_FIND_PCI_DEVICE 0x02 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0x03 +#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0x06 +#define PCIBIOS_READ_CONFIG_BYTE 0x08 +#define PCIBIOS_READ_CONFIG_WORD 0x09 +#define PCIBIOS_READ_CONFIG_DWORD 0x0A +#define PCIBIOS_WRITE_CONFIG_BYTE 0x0B +#define PCIBIOS_WRITE_CONFIG_WORD 0x0C +#define PCIBIOS_WRITE_CONFIG_DWORD 0x0D +#define PCIBIOS_GET_IRQ_ROUTING_OPTIONS 0x0E +#define PCIBIOS_SET_IRQ_ROUTING_OPTIONS 0x0F + +// +// PCI BIOS v2.1 status codes: +// +#define PCIBIOS_SUCCESSFUL 0x00 +#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 +#define PCIBIOS_BAD_VENDOR_ID 0x83 +#define PCIBIOS_DEVICE_NOT_FOUND 0x86 +#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 +#define PCIBIOS_SET_FAILED 0x88 +#define PCIBIOS_BUFFER_TOO_SMALL 0x89 + +#endif // _PCIBIOS_ diff --git a/private/ntos/nthals/halfire/ppc/pcip.h b/private/ntos/nthals/halfire/ppc/pcip.h new file mode 100644 index 000000000..262a4393e --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pcip.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pcip.h $ + * $Revision: 1.17 $ + * $Date: 1996/05/14 02:33:13 $ + * $Locker: $ + */ + +// +// Hal specific PCI bus structures +// + +typedef NTSTATUS +(*PciIrqTable) ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PUCHAR IrqTable + ); + +typedef struct tagPCIPBUSDATA { + // + // Defined PCI data + // + + PCIBUSDATA CommonData; + + // + // Implementation specific data + // + + union { + struct { + PULONG Address; + ULONG Data; + } Type1; + struct { + PUCHAR CSE; + PUCHAR Forward; + ULONG Base; + } Type2; + } Config; + + ULONG MaxDevice; + PciIrqTable GetIrqTable; + + BOOLEAN BridgeConfigRead; + UCHAR ParentBus; + BOOLEAN LimitedIO; + UCHAR reserved; + UCHAR SwizzleIn[4]; + + ULONG IOBase; + ULONG IOLimit; + ULONG MemoryBase; + ULONG MemoryLimit; + ULONG PFMemoryBase; + ULONG PFMemoryLimit; + + RTL_BITMAP DeviceConfigured; + ULONG ConfiguredBits[PCI_MAX_DEVICES * PCI_MAX_FUNCTION / 32]; +} PCIPBUSDATA, *PPCIPBUSDATA; + +#define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev); + +#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION) + +#define Is64BitBaseAddress(a) \ + (((a & PCI_ADDRESS_IO_SPACE) == 0) && \ + ((a & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT)) + + + +// +// Prototypes for functions in ixpcibus.c +// + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + + +VOID +HalpWritePCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +PBUS_HANDLER +HalpAllocateAndInitPciBusHandler ( + IN ULONG HwType, + IN ULONG BusNo, + IN BOOLEAN TestAllocation + ); + + +// +// Prototypes for functions in ixpciint.c +// + +ULONG +HalpGetPCIIntOnISABus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +NTSTATUS +HalpTranslatePCIBusAddress ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ); + +VOID +HalpPCIAcquireType2Lock ( + PKSPIN_LOCK SpinLock, + PKIRQL Irql + ); + +VOID +HalpPCIReleaseType2Lock ( + PKSPIN_LOCK SpinLock, + KIRQL Irql + ); + +NTSTATUS +HalpAdjustPCIResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +VOID +HalpPCIPin2ISALine ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciData + ); + +VOID +HalpPCIISALine2Pin ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciNewData, + IN PPCI_COMMON_CONFIG PciOldData + ); + +NTSTATUS +HalpGetISAFixedPCIIrq ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PUCHAR IrqTable + ); + +// +// Prototypes for functions in ixpcibrd.c +// + +BOOLEAN +HalpGetPciBridgeConfig ( + IN ULONG HwType, + IN PUCHAR MaxPciBus + ); + + + + + +typedef ULONG (*FncConfigIO) ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +typedef VOID (*FncSync) ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +typedef VOID (*FncReleaseSync) ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +typedef struct _PCI_CONFIG_HANDLER { + FncSync Synchronize; + FncReleaseSync ReleaseSynchronzation; + FncConfigIO ConfigRead[3]; + FncConfigIO ConfigWrite[3]; +} PCI_CONFIG_HANDLER, *PPCI_CONFIG_HANDLER; + + +// +// This is a "container" for pci private data that needs +// to be known per bus and for the set of functions that +// each bus uses to access data. +// There is also a couple of extra pci private data needs +// namely the configuration type of the config data accesses. +// + +typedef struct _BUS_NODE { + + // + // The standard bus data for pci buses + // + PCIPBUSDATA Bus; + + // + // Some extra data not part of PCIPBUSDATA: + // + ULONG HwType; // What HW config access type to use. + PPCI_CONFIG_HANDLER ThisNode; // used to point to the "Node" + PCI_SLOT_NUMBER SlotNumber; + UCHAR BusOrder, BusLevel, BusMax; + ULONG BusInt; // bit map of allowable interrupts... + ULONG ValidDevs; // bit map of valid DEVICES on this bus. + ULONG MemBase, MemTop, IoBase, IoTop; + + // + // set of bus specific functions to handle + // bus reading, writing, locking, unlocking. + // + PCI_CONFIG_HANDLER Node; + +} FPHAL_BUSNODE, *PFPHAL_BUSNODE; + + diff --git a/private/ntos/nthals/halfire/ppc/phcalls.c b/private/ntos/nthals/halfire/ppc/phcalls.c new file mode 100644 index 000000000..63dbfec4e --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/phcalls.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: phcalls.c $ + * $Revision: 1.14 $ + * $Date: 1996/01/11 07:08:05 $ + * $Locker: $ + */ + +#include "nthal.h" +#include "halp.h" +#include "phsystem.h" +#include "fpio.h" +#include "fpdcc.h" +#include "stdio.h" +#include "string.h" +#include "fparch.h" + +PUCHAR Types[] = { + "ArcSystem", + "CentralProcessor", + "FloatingPointProcessor", + "PrimaryIcache", + "PrimaryDcache", + "SecondaryIcache", + "SecondaryDcache", + "SecondaryCache", + "EisaAdapter", + "TcAdapter", + "ScsiAdapter", + "DtiAdapter", + "MultiFunctionAdapter", + "DiskController", + "TapeController", + "CdromController", + "WormController", + "SerialController", + "NetworkController", + "DisplayController", + "ParallelController", + "PointerController", + "KeyboardController", + "AudioController", + "OtherController", + "DiskPeripheral", + "FloppyDiskPeripheral", + "TapePeripheral", + "ModemPeripheral", + "MonitorPeripheral", + "PrinterPeripheral", + "PointerPeripheral", + "KeyboardPeripheral", + "TerminalPeripheral", + "OtherPeripheral", + "LinePeripheral", + "NetworkPeripheral", + "SystemMemory", + "MaximumType" +}; + +PUCHAR Classes[] = { + "SystemClass", + "ProcessorClass", + "CacheClass", + "AdapterClass", + "ControllerClass", + "PeripheralClass", + "MemoryClass", + "MaximumClass" +}; + +/* +** PHalDumpTree +** +** +** +*/ + +VOID +PHalpDumpLoaderBlock ( + PLOADER_PARAMETER_BLOCK lpb + ) +{ + DbgPrint("\nlpb is %x\n",lpb); + DbgPrint("Kernel stack: %x \n",lpb->KernelStack); + DbgPrint("ArcBootDeviceName: %s \n",lpb->ArcBootDeviceName); + DbgPrint("ArcHalDeviceName: %s \n",lpb->ArcHalDeviceName); + DbgPrint("NtBootPathName: %s \n",lpb->NtBootPathName); + DbgPrint("NtHalPathName: %s \n",lpb->NtHalPathName); + DbgPrint("Loader Options : %s \n",lpb->LoadOptions); + DbgPrint("ArcDiskInformation: %x \n",lpb->ArcDiskInformation); + DbgPrint("\nPArcDiskinfo: %x \n",lpb->ArcDiskInformation); +} + +VOID +PHalpDumpConfigData ( + PCONFIGURATION_COMPONENT_DATA ConfigurationNode, + PULONG depth + ) +{ + PCONFIGURATION_COMPONENT_DATA current=NULL, next=NULL; + + DbgPrint("\n======================================\n"); + for (next = ConfigurationNode; next; next = next->Child) { + current = next; + DbgPrint("\nNode address = 0x%8.8x, Parent = 0x%8.8x, Sibling = 0x%8.8x, Child = 0x%8.8x\n", current, current->Parent, current->Sibling, current->Child); + DbgPrint("\tComponent Class %d, Type %d", current->ComponentEntry.Class, current->ComponentEntry.Type); + DbgPrint(", Identifier = '%s' (Length = %d)\n", current->ComponentEntry.Identifier, current->ComponentEntry.IdentifierLength); + DbgPrint("\n\tComponent Class %s, Type %s\n", Classes[current->ComponentEntry.Class], Types[current->ComponentEntry.Type]); + } + + for ( ; current && !current->Sibling; current = current->Parent) ; + + if (current) { + current = current->Sibling; + PHalpDumpConfigData(current, &*depth++); + } +} + diff --git a/private/ntos/nthals/halfire/ppc/phprods.c b/private/ntos/nthals/halfire/ppc/phprods.c new file mode 100644 index 000000000..cc09923f2 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/phprods.c @@ -0,0 +1,794 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: phprods.c $ + * $Revision: 1.66 $ + * $Date: 1996/05/14 02:33:18 $ + * $Locker: $ + */ + +#include "fpdebug.h" +#include "halp.h" +#include "eisa.h" +#include "pxsiosup.h" +#include "pxpcisup.h" +#include "pxmemctl.h" +#include "bugcodes.h" + +#include "phsystem.h" +#include "fpio.h" +#include "fpcpu.h" +#include +#include "pcip.h" +#include // for ESUCCESS + + +// +// Define the context structure for use by the interrupt routine. +// + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine, + PVOID ServiceContext, + PVOID TrapFrame + ); + +VOID HalpHandleDecrementerInterrupt1( PKINTERRUPT , PVOID , PVOID ); + +HalState Dispatch; + + +extern BOOLEAN HalpHandleMachineCheck(PKINTERRUPT, PVOID); +extern KINTERRUPT HalpMachineCheckInterrupt; +extern ULONG HalpSetIntPriorityMask( VOID ); +extern ULONG Irql2Mask[]; + +KINTERRUPT HalpPciErrorInt; +KINTERRUPT HalpBusErrorInt; +KINTERRUPT HalpMemoryErrorInt; + +KINTERRUPT HalpHandleClockInterrruptOnOther; + + + +extern ULONG registeredInts[]; + +extern VOID KiDispatchSoftwareInterrupt( VOID); +extern BOOLEAN HalAcknowledgeIpi (VOID); +ULONG HalpGetHighVector(ULONG); + + +extern ULONG HalpSpuriousInterruptCount; +extern UCHAR HalpSioInterrupt1Mask,HalpSioInterrupt2Mask; +extern UCHAR HalpSioInterrupt1Level, HalpSioInterrupt2Level; +extern ULONG Vector2Irql[]; +ULONG HalpSpuriousInts = 0; + + +/* + * HalpHandleExternalInterrupt + * + * Description: + * + * This is the main external interrupt handler. It is called whenever + * an external interrupt occurs. It interfaces to the ASICs that + * cause the external interrupt and vectors to the corresponding + * interrupt handling routine. + * + * Issues: + * + * Not implemented Yet (sfk 8/26/95). + * The returnValue of the driver should be checked and if the driver + * did not handle the interrupt, we should consider clearing the interrupt + * and broadcasting an interrupt error message. + */ +BOOLEAN +HalpHandleExternalInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) +{ + PSECONDARY_DISPATCH SioHandler; + PKINTERRUPT SioInterrupt; + ULONG TmpSysVector; + USHORT interruptVector; + BOOLEAN returnValue; + KIRQL OldIrql; + ULONG OldMask; + UCHAR Irql, i; + register UCHAR CpuId; + + // + // Assert that interrupts are disabled (or just disable them for now) + // + HASSERT(!MSR(EE)); + + // + // Use a local variable for CPU. + // + CpuId = (UCHAR) GetCpuId(); + + // + // indicate are in interrupt handler... + // + SET_LEDS(0xf0 & ~(LED_1)); + + // + // Get the value out of the (ESCC/TIO) register + // Compute interrupt vector number. + // + TmpSysVector = RInterruptPending(CpuId); + if (TmpSysVector == 0) { + // For a spurious interrupt, simply return +#if defined(HALDEBUG_ON) + HalpDebugPrint("HalpHandleExternalInterrupt: Spurious Interrupt"); +#endif + return FALSE; + } + // + // We must now find the highest priority interrupt to service. + // Since the Pending register is not ordered in correct + // priority order, we muse "find" the highest priority + // interrupt. Servicing a lower priority interrupt will cause us + // to nest too deeply on the interrupt stack and panic. + // + for (i = HIGH_LEVEL; i > DISPATCH_LEVEL; i--) { + if ((Irql2Mask[i] & TmpSysVector) != 0) { + break; + } + } + HASSERT(i >= PCR->CurrentIrql); + TmpSysVector &= Irql2Mask[i]; + + // + // Now find any single bit of the bits left. + // + interruptVector = (USHORT) HalpGetHighVector(TmpSysVector); + + // + // Turns off ASIC Interrupts (ESCC/TIO). + // Need more protection than KeRaisIrql currently provides. + // + OldIrql = PCR->CurrentIrql; + Irql = (UCHAR) Vector2Irql[interruptVector]; + HASSERT(Irql > i); + PCR->CurrentIrql = Irql; + OldMask = RInterruptMask(CpuId); + + // + // Mask Handling has varied over time based on how well + // nesting works. The proper answer is to mask off all of the + // interrupts that are a lesser priority than the one + // we are currently handling. Using the same code as KeRaiseIrql + // does. + // + RInterruptMask(CpuId) = (Irql2Mask[Irql]®isteredInts[CpuId]); + WaitForRInterruptMask(CpuId); + HASSERT((RInterruptMask(CpuId) & (1 << interruptVector)) == 0); + + // + // Clear the interrupt out of the request register by writing a one + // for the handled interrupt. + // + rInterruptRequest = (1 << interruptVector); + FireSyncRegister(); + + // + // if the new IRQL level is lower than clock2_level, restore + // system interrupts to allow decrementer interrupts: + // Restoring the interrupt bit in the MSR here allows the + // debugger to break into this routine (or a driver ISR) if + // the system hangs + // + if (Irql < CLOCK2_LEVEL) { + HalpEnableInterrupts(); + } + + // + // Dispatch to the secondary interrupt service routine. + // + SioHandler = (PSECONDARY_DISPATCH) + PCR->InterruptRoutine[DEVICE_VECTORS + interruptVector]; + + // + // A small bit of hack logic. We need a way to make sure that a + // "valid" registration has occured for this interrupt. We compare + // the handler with the "known" Unexpected interrupt handler routine. + // Use location 255 to get it. + // + if (SioHandler == (PSECONDARY_DISPATCH) PCR->InterruptRoutine[255]) { + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpHandleExternalInterrupt: %d not registered\n", + interruptVector);); + returnValue = FALSE; + } else { + SioInterrupt = CONTAINING_RECORD(SioHandler, + KINTERRUPT, DispatchCode[0]); + returnValue = SioHandler(SioInterrupt, + SioInterrupt->ServiceContext, + TrapFrame); + } + + // + // Now disable the PowerPC interrupts to provide protection + // for the exit portion of the interrupt handling. + // + HalpDisableInterrupts(); + + // + // indicate are exiting the interrupt handler... + // + SET_LEDS(0xf0 & ~(0x1)); + + // + // Now lower the IRQL + // + PCR->CurrentIrql = OldIrql; + RInterruptMask(CpuId) = OldMask; + WaitForRInterruptMask(CpuId); + HASSERT(RInterruptMask(CpuId) == + (Irql2Mask[PCR->CurrentIrql] & registeredInts[CpuId])); + return(returnValue); +} + +/* + * HalpHandleIpiInterrupt + * + * Clear the IPI and call the kernel's handler + */ +BOOLEAN +HalpHandleIpiInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) +{ + if (HalAcknowledgeIpi()) { + KeIpiInterrupt(TrapFrame); + return TRUE; + } + return FALSE; +} + + +int +PHalpInterruptSetup( VOID ) +{ + UCHAR DataByte,Isr; + + HalpSetIntPriorityMask(); + DataByte = 0; + ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1; + ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1; + + rMasterIntPort0 = DataByte; + rSlaveIntPort0 = DataByte; + + // + // The second intitialization control word sets the iterrupt vector to + // 0-15. + // + + DataByte = 0; + rMasterIntPort1 = DataByte; + FireSyncRegister(); + + DataByte = 0x08; + rSlaveIntPort1 = DataByte; + FireSyncRegister(); + + // + // The third initialization control word set the slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a number. + // + DataByte = 1 << SLAVE_IRQL_LEVEL; + rMasterIntPort1 = DataByte; + FireSyncRegister(); + + DataByte = SLAVE_IRQL_LEVEL; + rSlaveIntPort1 = DataByte; + FireSyncRegister(); + // + // The fourth initialization control word is used to specify normal + // end-of-interrupt mode and not special-fully-nested mode. + // + DataByte = 0; + ((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1; + + // + // setup for auto end of interrupt mode in case of firepower + // + ((PINITIALIZATION_COMMAND_4) &DataByte)->AutoEndOfInterruptMode = 1; + + + rMasterIntPort1 = DataByte; + rSlaveIntPort1 = DataByte; + FireSyncRegister(); + + // + // Disable all of the interrupts except the slave. + // + + HalpSioInterrupt1Mask = (UCHAR)~(1 << SLAVE_IRQL_LEVEL); + + rMasterIntPort1 = DataByte; + + HalpSioInterrupt2Mask = 0xFF; + + rSlaveIntPort1 = DataByte; + +// define priority specifically IRQ 7 is set to priority 15, while IRQ 0 is set +// to 1. So, tell the SIO to affix the lowest priority to IRQ 7: 110 00 111 +// should do it: this sets the command to "set priority" and says IRQ 7 is +// the lowest priority [ 111 ]. + + DataByte=0xc7; + rMasterIntPort0 = DataByte; + rSlaveIntPort0 = DataByte; + +// Read the IRR: + DataByte=0x0a; + rMasterIntPort0 = DataByte; + Isr = rMasterIntPort0; + HDBG(DBG_GENERAL, HalpDebugPrint("Master: IRR is %x .. ",Isr);); + +// Read the ISR + DataByte=0x0b; + rMasterIntPort0 = DataByte; + Isr = rMasterIntPort0; + HDBG(DBG_GENERAL, HalpDebugPrint("ISR is %x .. \n",Isr);); + + // + // Set up the system error registers for use: Mask off Video ints, clear + // anything pending: + // + + // + // Clear the PCI Bus error cause register and mask-enable pci error ints + // + rPCIBusErrorCauseSet = 0x0; + rPCIBusErrorCause = 0xffffffff; + FireSyncRegister(); + + // + // Clear the Memory Bus error cause register and mask-enable memory + // error ints. Note: (breeze 3/6/95 ) I removed the earlier comments. + // + rErrorStatus0Set = 0x0; + rErrorStatus0 = 0xffffffff; + rErrorMask = + (ECC_CORRECTED|ECC_FAILED|ADDRESS_PARITY_ERROR|DATA_PARITY_ERROR| + MEM_PARITY_ERROR|INVALID_XACT); + + // + // IBM 604 Processors (revision 3.3) have parity problems. For these + // processors we unset DATA_PARITY to avoid dying from a false + // parity error. ES machines only used the Motorola processors + // so check for PowerTOP. + // + if ((SystemType == SYS_POWERTOP) && (ProcessorType == PPC_604)) { + if (HalpGetProcessorVersion() == 0x00040303) { + rErrorMask &= ~DATA_PARITY_ERROR; + } + } + FireSyncRegister(); + + // + // Clear the Video error register and disable video ints + // + rVidInt = 0xffffffff; + rVidIntMask = 0x00000000; + FireSyncRegister(); + + if (!HalpEnableInterruptHandler(&HalpPciErrorInt, + (PKSERVICE_ROUTINE) HalpMemoryHandler, + NULL, + NULL, + DEVICE_VECTORS + PCI_ERROR_NUM, + 28, + 28, + Latched, + FALSE, + 0, // Processor Number + FALSE, + InternalUsage, + DEVICE_VECTORS + PCI_ERROR_NUM)) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + if (!HalpEnableInterruptHandler(&HalpBusErrorInt, + (PKSERVICE_ROUTINE) HalpMemoryHandler, + NULL, + NULL, + DEVICE_VECTORS + CPU_BUS_ERROR_NUM, + 28, + 28, + Latched, + FALSE, + 0, // Processor Number + FALSE, + InternalUsage, + DEVICE_VECTORS + CPU_BUS_ERROR_NUM)) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + + if (SystemType == SYS_POWERPRO) { + if (!HalpEnableInterruptHandler(&HalpMemoryErrorInt, + (PKSERVICE_ROUTINE) HalpMemoryHandler, + NULL, + NULL, + DEVICE_VECTORS + MEMORY_ERROR_VIDEO_NUM, + 28, + 28, + Latched, + TRUE, // share with the video-in ISR... + // FALSE, + 0, // Processor Number + FALSE, + InternalUsage, + DEVICE_VECTORS + + MEMORY_ERROR_VIDEO_NUM)) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + } + + return(0); +} + + + +// +// Initialize interrupts on processors other than the main (boot) processor. +// +// +ULONG +HalpInitInts( ULONG ProcessorNumber ) +{ + + ULONG Mask; + + HDBG(DBG_INTERNAL, + HalpDebugPrint("HalpInitInts: entered Cpu (%d)\n", ProcessorNumber)); + + // + // Make sure all the interrupts are masked off and any potential + // interrupts are cleared from the pending register. This is a percpu + // action and makes sure that this cpu starts off with a known + // interrupt state. + // + HalpDisableInterrupts(); + RInterruptMask(GetCpuId()) = ALL_INTS_OFF; + WaitForRInterruptMask(GetCpuId()); + + // + // Connect the external interrupt handler first, then the other + // handlers for external events may be installed.... + // + + PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = + (PKINTERRUPT_ROUTINE) HalpHandleExternalInterrupt; + + // + // register the interrupt vector with the HAL + // + + HalpRegisterVector(InternalUsage, + EXTERNAL_INTERRUPT_VECTOR, + EXTERNAL_INTERRUPT_VECTOR, + HIGH_LEVEL); + + // + // Connect the IPI interrupt handler directly to the CPU dispatch table + // without registering with the kernel. The IPI interrupt has + // already been registered with the HAL by CPU 0 in HalpCreateSioStructures + // so we don't need to do it again here. + // + + PCR->InterruptRoutine[DEVICE_VECTORS + 31] = + (PKINTERRUPT_ROUTINE) HalpHandleIpiInterrupt; + + // + // Now enable the IPI interrupt on this CPU; the HAL must do this + // directly since we did not register with the kernel. + // It should be alright to call this routine directly rather than + // HalEnableSystemInterrupt because interrupts are disabled. + // + HalpEnableSioInterrupt(DEVICE_VECTORS + 31, Latched); + + HDBG(DBG_GENERAL, + HalpDebugPrint("HalpInitInts: Enabled IPI handler \n");); + + // + // Initialize the Machine Check interrupt handler + // + if (HalpEnableInterruptHandler(&HalpMachineCheckInterrupt, + HalpHandleMachineCheck, + NULL, + NULL, + MACHINE_CHECK_VECTOR, + MACHINE_CHECK_LEVEL, + MACHINE_CHECK_LEVEL, + Latched, + FALSE, + (CCHAR) ProcessorNumber, + FALSE, + InternalUsage, + MACHINE_CHECK_VECTOR + ) == FALSE) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + + // Connect directly to the decrementer handler. This is done + // directly rather than thru HalpEnableInterruptHandler due to + // special handling required because the handler calls KdPollBreakIn(). + // + + + PCR->InterruptRoutine[DECREMENT_VECTOR] = + (PKINTERRUPT_ROUTINE) HalpHandleDecrementerInterrupt1; + + HalpUpdateDecrementer(1000); // Get those decrementer ticks going + + // + // Make sure the mask is set correctly at the mask register for this cpu: + // + Mask = RInterruptMask(GetCpuId()); + if (Mask != CPU_MESSAGE_INT) { + HalpDebugPrint("HalpInitInts: no CPU_MESSAGE_INT\n"); + } + + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpInitInts: exit\n");); + return (0); +} + +// +// Some quick code for handling memory bus errors +// +BOOLEAN +HalpMemoryHandler( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) +{ + ULONG causeValue; + + // + // Proper handling of Memory, CPU and PCI errors. + // + switch ((Interrupt->Vector - DEVICE_VECTORS)) { + case MEMORY_ERROR_VIDEO_NUM: { + ULONG addr; + + // + // Read the register so that we can see it on a logic analyzer + // + causeValue = rErrorStatus0; + + // + // check for valid video-in interrupt if on a powertop system. If + // there is a valid video-in interrupt AND no valid cause other than + // a memory int, then return false and let the video driver handle + // this. + // If there is a cause, then handle the memory error cause + // regardless of the video-in case: + // + if ( causeValue == 0x0 ) { + return FALSE; // return false in any case since no + // cause was found!! + } + + // + // This is not a true error, just record it in the registry + // (recording in registry not implemented yet - sfk 2/20/95 - XXX) + // + // Don't bother checking for video-in interrupt here. If there is + // a video interrupt awaiting action, it should be picked up when + // the hal returns from interrupt since the uncleared int will be + // automatically re-asserted when cpu ints are re-enabled via the + // MSR(EE) action. + // + if (causeValue&ERROR_ECC_CORRECTED) { + ULONG rc; + ULONG count = 0, total = 0; + const PCHAR varname = "PARITY_ERROR"; + CHAR buf[80]; + + rErrorStatus0 |= ERROR_ECC_CORRECTED; + FireSyncRegister(); + + // + // record the error count to NVRAM as: + // # errors this boot, # errors forever + // + MemoryParityErrorsThisBoot++; + MemoryParityErrorsForever++; + sprintf(buf, "%d,%d", + MemoryParityErrorsThisBoot, + MemoryParityErrorsForever + ); + rc = HalSetEnvironmentVariable(MemoryParityErrorsVarName, buf); + if (ESUCCESS != rc) { + // what to do? + } + return TRUE; + } + // + // Now we panic: Make sure that in the process we don't fall + // into a loop of parity errors, so turn off memory parity errors, + // and the other errors as well: + // + rErrorMask &= ~(MEM_PARITY_ERROR | + INVALID_XACT + ); + + addr = (rErrorAddr0 & 0xff000000); + addr |= ((rErrorAddr1 & 0xff000000) >> 8); + addr |= ((rErrorAddr2 & 0xff000000) >> 16); + addr |= ((rErrorAddr3 & 0xff000000) >> 24); + + // + // Show the user what happened before we die + // + HalpForceDisplay("MEMORY_ERROR cause(0x%08x) at 0x%08x\n", + causeValue&0xff000000, addr); + + // + // Decode the cause into ascii strings for the user impatiently + // waiting for enlightenment from the dead machine: Before + // reincarnation, what major transgression did we commit? + // + + if( causeValue&ERROR_DATA_PARITY) { + HalpForceDisplay("DATA PARITY"); + } + if (causeValue&ERROR_MEM_PARITY) { + HalpForceDisplay(", MEMORY PARITY"); + } + if (causeValue&ERROR_ECC_FAILED) { + HalpForceDisplay(", ECC FAILED"); + } + if (causeValue&ERROR_INVALID_XACT) { + HalpForceDisplay(", Bad bus transaction: burst access to rom or io space?"); + } + HalpForceDisplay("\n\n"); + + // + // Clear the Memory Error. Since we only want one error + // of each type (max.), we mask off the error we just + // received. + // + rErrorMask &= ~causeValue; + rErrorStatus0 = causeValue; + FireSyncRegister(); + break; + + } + + case PCI_ERROR_NUM: + // + // Read the register so that we can see it on a logic analyzer + // + causeValue = rPCIBusErrorCause; + + // + // This is not a true error, just record it in the registry + // (recording in registry not implemented yet - sfk 2/20/95 - XXX) + // + if (causeValue&PCI_ERROR_DEV_TIMEOUT) { + rPCIBusErrorCause = PCI_ERROR_DEV_TIMEOUT; + FireSyncRegister(); + return TRUE; + } + + // This also may not be a true error; we must check the Pci status + // registers + if( causeValue& PCI_ERROR_TARGET_ABORT) { + // Scan the Primary Pci status registers + ULONG devs; + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciData; + + PciData = (PPCI_COMMON_CONFIG) buffer; + for (devs = 0; devs < MAXIMUM_PCI_SLOTS; devs++) { + HalGetBusData ( + PCIConfiguration, + 0, + devs, + PciData, + PCI_COMMON_HDR_LENGTH + ); + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != 0) { + continue; + } + + if (PciData->Status & PCI_STATUS_SIGNALED_TARGET_ABORT) { + // We can ignore this one; clear the error bits + rPCIBusErrorCause = PCI_ERROR_TARGET_ABORT; + PciData->Status = PCI_STATUS_SIGNALED_TARGET_ABORT; + HalSetBusDataByOffset( + PCIConfiguration, + 0, + devs, + &PciData->Status, + FIELD_OFFSET(PCI_COMMON_CONFIG, + Status), + 1); + FireSyncRegister(); + return TRUE; + } + } + } + + // + // Show the user what happened before we die + // + HalpForceDisplay("\nPCI_ERROR cause(0x%08x) at 0x%08x\n", + causeValue, rPCIBusErrorAddressRegister); + + if( causeValue& PCI_ERROR_SIGNALED_SYS) { + HalpForceDisplay("Address parity error on PCI bus\n"); + } + if( causeValue& PCI_ERROR_DATA_PARITY) { + HalpForceDisplay("Data parity error on PCI bus\n"); + } + if( causeValue& PCI_ERROR_DEV_TIMEOUT) { + HalpForceDisplay("Device Timeout: Master Aborted\n"); + } + if( causeValue& PCI_ERROR_TARGET_ABORT) { + HalpForceDisplay("Target Aborted or Master experienced a fatal error\n"); + } + HalpForceDisplay("\n\n"); + + // + // Clear the PCI Error + // + rPCIBusErrorCause = causeValue; + FireSyncRegister(); + break; + + case CPU_BUS_ERROR_NUM: + // + // Read the register so that we can see it on a logic analyzer + // + causeValue = rCPUBusErrorCause; + + // + // Show the user what happened before we die + // + HalpForceDisplay("CPU_ERROR cause(0x%08x) at 0x%08x\n", + causeValue, rCPUBusErrorAddressRegister); + + // + // Clear the Bus Error + // + rCPUBusErrorCause = causeValue; + FireSyncRegister(); + break; + + default: + // + // We should not be here, bug check because things are not sane + // if we got this far. + // + HalpForceDisplay("Unknown Bus Error (%d)\n", + (Interrupt->Vector - DEVICE_VECTORS)); + break; + + } // end of switch statement..... + + // + // If we make it to here, we just stop the system (cold). + // + KeBugCheck(NMI_HARDWARE_FAILURE); + + // + // This should never return but just in case + // + HalpDisableInterrupts(); +here: + goto here; + +} diff --git a/private/ntos/nthals/halfire/ppc/phsystem.h b/private/ntos/nthals/halfire/ppc/phsystem.h new file mode 100644 index 000000000..03b211f40 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/phsystem.h @@ -0,0 +1,270 @@ +/* + * Copyright (c) 1995 Firepower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: phsystem.h $ + * $Revision: 1.28 $ + * $Date: 1996/05/14 02:33:25 $ + * $Locker: $ + */ + +#ifndef PHSYSTEM_H +#define PHSYSTEM_H + +// +// (sfk 11/3/94) +// Should this be placed here or directly included? +// +#include "fpreg.h" +#include "stdio.h" +#include "ntverp.h" + +// defined 'special' address space for system memory [rdl:01.04.95] +#define MEMORY_ADDRESS_SPACE 0 +#define IO_ADDRESS_SPACE 1 +#define SYSTEM_ADDRESS_SPACE 2 + +BOOLEAN HalpInitializeDisplay1(PLOADER_PARAMETER_BLOCK); +ULONG HalpInitInts( ULONG CpuNumber ); +VOID HalpInitPciBusEarly( PLOADER_PARAMETER_BLOCK ); +int PHalTriggerEvent( ULONG returndata ); +int PHalSetupGpio( ULONG LEDFLAGS ); +VOID PHalBlinkLeds( UCHAR LEDS, ULONG Rate, ULONG LEDFLAGS ); +int PHalpInterruptSetup( VOID ); +BOOLEAN PHalpHandleIpi( PKINTERRUPT , PVOID , PVOID ); +VOID PHalpDumpLoaderBlock ( PLOADER_PARAMETER_BLOCK ); +VOID PHalpDumpConfigData ( PCONFIGURATION_COMPONENT_DATA, PULONG ); +VOID PHalDumpTree ( PCONFIGURATION_COMPONENT_DATA ); +BOOLEAN PHalpEisaDispatch( PKINTERRUPT , PVOID , PVOID ); +int PH_HalVersion( VOID ); +ULONG HalpCheckString( PCHAR , PCHAR ); +ULONG HalpSetPixelColorMap( ULONG , ULONG ); +BOOLEAN HalpInitIntelAIP ( VOID ); +VOID PH_HalVersionInternal( VOID ); +VOID PH_HalVersionExternal( VOID ); +VOID HalpResetByKeyboard(VOID); +VOID HalpSetupDCC(ULONG, ULONG); + +BOOLEAN HalpMemoryHandler( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame); + +BOOLEAN HalpHandleExternalInterrupt( IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); +ULONG HalpGetProcessorRev( VOID); + +// define the start address for system register space, apart +// from eisa/pci specific registers +// +// PVOID HalpSysBase = (PVOID) 0xff000000; +// PVOID HalpSysBase = (PVOID) 0x8000ff00; + +extern PVOID HalpSystemSpace; +extern PVOID HalpIoControl; +extern PVOID HalpVideMemoryBase; +extern PVOID HalpSystemControlBase; +extern BOOLEAN HalpInitializeRegistry (IN PLOADER_PARAMETER_BLOCK LoaderBlock); +extern ULONG HalpGetCycleTime(VOID); +extern ULONG HalpProcessorCount(VOID); +extern ULONG HalpGetCycleTime(VOID); + +#define LED_0 0x01 // led 0 +#define LED_1 0x02 // led 1 +#define LED_2 0x04 // led 2 +#define LED_3 0x08 // led 3 +#define LED_EMIT 0xf0 // led direction bits in gpio register + +#define LED_ON 0xffffffff +#define LED_OFF 0x00000000 +//#define DCC_INDX 0x840 +//#define DCC_DATA 0x841 +#define GPIOA 0x2 +// #define WAIT_TIME 0xf000000 +#define WAIT_TIME 0x800000 + +typedef struct _DCC_CONTROL { + UCHAR space[0x840]; + UCHAR DccIndxReg; // this should show up at address base + 840 + UCHAR DccDataReg; // this should show up at address base + 841 + UCHAR DccTestAddr; // this is for test purposes.... +} DCC_CONTROL, *P_DCC_CONTROL; + +typedef struct _Address_Map { + ULONG System; + ULONG IO; + ULONG General; +} Address_Map, *PAddress_Map; + + +typedef struct { + ULONG EntryCounter; + ULONG ExitCounter; + ULONG Flags; // keep track of where in the routine you are.. + ULONG Isr; + ULONG TmpMask; + ULONG MasksDifferFlag; + ULONG SysInterruptVector; + ULONG Intbucket; // bit map each int type seen + ULONG CompareMask; + ULONG BusyCount; + ULONG Bloob; + ULONG LastCount; +} HalState, *PHalState; + +// +// System Descriptions: +// Hold a description of the system for the hal to use +// to determine what form it should take. + +// +// Declare an enumerated type for asking which processor the +// system is currently running on. +// +typedef struct { + ULONG Flags; + ULONG HashSize; + PCHAR ProcessorName; + PCHAR ProductNumber; +} PROCESSOR_DESCRIPTION; + +// +// Flags for defining the capabilities of the cpu, +// and the enumerated labels for marking what +// cpu we're on. +// +#define PROC_NOSUPP 0x00000000 +#define PROC_SUPP 0x00000001 +#define PROC_HASHTABLE 0x00000002 +#define PROC_MPCAPABLE 0x00000004 + +typedef enum { + PPC_UNKNOWN = 0, + PPC_601 = 1, + PPC_602 = 2, + PPC_603 = 3, + PPC_604 = 4, + PPC_605 = 5, + PPC_606 = 6, + PPC_607 = 7, + PPC_608 = 8, + PPC_609 = 9, + nPROCESSOR_TYPE +} PROCESSOR_TYPE; + +extern PROCESSOR_DESCRIPTION ProcessorDescription[]; +extern PROCESSOR_TYPE ProcessorType; + +// +// System IDENT Values: +// +#define ESCC_IDENT 0x60730000 // chip only in pro +#define TSC_IDENT 0x60370000 // chip only in top ( currently ) + + +// +// Flags to label the capabilities of the system as a whole: +// +#define SYS_NOSUPP 0x00000000 // system is not supported by this hal. +#define SYS_SUPP 0x00000001 // system is supported by this hal. +#define SYS_MPCAPABLE 0x00000002 // system is able to support more than one cpu. +#define SYS_MPFOREAL 0x00000004 // system is able to have more than one cpu. + +typedef enum { + SYS_UNKNOWN = 0, + SYS_POWERPRO = 1, // 0x60730000 + SYS_POWERTOP = 2, // 0x60370000 + SYS_POWERSERVE = 3, // 0x60370000 ???? don't know yet + SYS_POWERSLICE = 4, + nSYSTEM_TYPE +} SYSTEM_TYPE ; + +typedef struct { + ULONG Flags; + PCHAR SystemName; +} SYSTEM_DESCRIPTION, PSYSTEM_DESCRIPTION; + +typedef struct _HW_DESCRIPTION { + ULONG HwFlags; + ULONG Spare; +}HARDWARE_DESCRIPTION; +extern SYSTEM_DESCRIPTION SystemDescription[]; +extern SYSTEM_TYPE SystemType; +extern VOID HalpInitIoBuses ( VOID ); + +#define IRQ0 1 + +extern ULONG PciDeviceIDs[4][256]; +extern ULONG PciClassInfo[4][256]; + + +// +// these values show up in the lower byte of the interrupt word read out of +// the system register... +// +#define VEC_Timer 0x0001 +#define VEC_Keyboard 0x0002 +#define VEC_Cascade 0x0004 +#define VEC_Serial2 0x0008 +#define VEC_Serial1 0x0010 +#define VEC_Display 0x0020 +#define VEC_Floppy 0x0040 +#define VEC_Parallel1 0x0080 +// +// these values show up in the secondary next byte +// of the SIO +// +#define VEC_RTC 0x0100 +#define VEC_Open9 0x0200 +#define VEC_Audio 0x0400 +#define VEC_PCI 0x0800 +#define VEC_Mouse 0x1000 +#define VEC_Scsi 0x2000 +#define VEC_Enet 0x4000 +#define VEC_Open15 0x8000 + +#define HalPrint HalpDebugPrint +#define HalpPrint HalpDebugPrint + +#define HalBreak(x) +#define SEE_DEFINES A_DEFINES +#define SET_STRING(x) #x + +// +//Declare The BAT Support Routines [ged] +// +ULONG HalpGetUpperIBAT(ULONG); +ULONG HalpGetLowerIBAT(ULONG); +ULONG HalpGetUpperDBAT(ULONG); +ULONG HalpGetLowerDBAT(ULONG); +VOID HalpSetLowerDBAT1(ULONG); +VOID HalpSetUpperDBAT1(ULONG); +// Add more BAT Support Routines [rdl:01.03.95] +VOID HalpSetUpperDBAT(ULONG,ULONG); +VOID HalpSetLowerDBAT(ULONG,ULONG); + +// +// Memory parity error variables +// + +#define MemoryParityErrorsVarName "MEMORY_PARITY_ERRORS" +extern ULONG MemoryParityErrorsThisBoot; +extern ULONG MemoryParityErrorsForever; + +// +// Useful macros for pragma message, ie. #pragma message(REVIEW "some text") +// +#define QUOTE(x) #x +#define IQUOTE(x) QUOTE(x) +#define REVIEW __FILE__ "(" IQUOTE(__LINE__) ") : REVIEW -> " + + +#define NOTE(x) message(REVIEW IQUOTE(x) ) + +#define PAUSE for(;;) { \ + } + + +#endif // PHSYSTEM_H diff --git a/private/ntos/nthals/halfire/ppc/phsystem.s b/private/ntos/nthals/halfire/ppc/phsystem.s new file mode 100644 index 000000000..b3ce390b9 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/phsystem.s @@ -0,0 +1,487 @@ +//++ +// +// Copyright (c) 1994 FirePower Systems INC. +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxsystem.s +// +// Abstract: +// +// This module implements the routines to handle system functions: +// Provides system specific info. +// Currently provides processor version type +// +// Author: +// breeze@firepower.com +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +//-- + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: phsystem.s $ + * $Revision: 1.7 $ + * $Date: 1996/01/11 07:08:26 $ + * $Locker: $ + */ + +#include "kxppc.h" + +//++ +// +// Routine Description: +// +// +// Arguments: +// HalProcessorRev, in r3 +// +// +// Return Value: +// Processor Version register value +// +// +//-- + + + LEAF_ENTRY(HalpGetProcessorRev) + mfpvr r.3 // get processor version + LEAF_EXIT(HalpGetProcessorRev) + + +/****************************************************************************** + Synopsis: + ULONG HalpGetUpperIBAT(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit upper instruction BAT value for a given . + + Returns: + Returns the 32-bit upper BAT value. +******************************************************************************/ + + .set BatNumber, r.3 + + LEAF_ENTRY(HalpGetUpperIBAT) + + cmpli 0,0,BatNumber,0 + bne NotUI0 + mfibatu BatNumber,0 + b ExitUI +NotUI0: + cmpli 0,0,BatNumber,1 + bne NotUI1 + mfibatu BatNumber,1 + b ExitUI +NotUI1: + cmpli 0,0,BatNumber,2 + bne NotUI2 + mfibatu BatNumber,2 + b ExitUI +NotUI2: + mfibatu BatNumber,3 // OK, it's three by default + +ExitUI: + + LEAF_EXIT(HalpGetUpperIBAT) + +/****************************************************************************** + Synopsis: + ULONG HalpGetLowerIBAT(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit lower instruction BAT value for a given . + + Returns: + Returns the 32-bit lower BAT value. +******************************************************************************/ + + LEAF_ENTRY(HalpGetLowerIBAT) + + cmpli 0,0,BatNumber,0 + bne NotLI0 + mfibatl BatNumber,0 + b ExitLI +NotLI0: + cmpli 0,0,BatNumber,1 + bne NotLI1 + mfibatl BatNumber,1 + b ExitLI +NotLI1: + cmpli 0,0,BatNumber,2 + bne NotLI2 + mfibatl BatNumber,2 + b ExitLI +NotLI2: + mfibatl BatNumber,3 // OK, it's three by default + +ExitLI: + + LEAF_EXIT(HalpGetLowerIBAT) + +/****************************************************************************** + Synopsis: + ULONG HalpGetUpperDBAT(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit upper data BAT value for a given . + + Returns: + Returns the 32-bit upper BAT value. +******************************************************************************/ + + LEAF_ENTRY(HalpGetUpperDBAT) + + cmpli 0,0,BatNumber,0 + bne NotUD0 + mfdbatu BatNumber,0 + b ExitUD +NotUD0: + cmpli 0,0,BatNumber,1 + bne NotUD1 + mfdbatu BatNumber,1 + b ExitUD +NotUD1: + cmpli 0,0,BatNumber,2 + bne NotUD2 + mfdbatu BatNumber,2 + b ExitUD +NotUD2: + mfdbatu BatNumber,3 // OK, it's three by default + +ExitUD: + + LEAF_EXIT(HalpGetUpperDBAT) + +/****************************************************************************** + Synopsis: + ULONG HalpGetLowerDBAT(ULONG BatNumber) [ged] + + Purpose: + Supplies the 32-bit lower data BAT value for a given . + + Returns: + Returns the 32-bit lower BAT value. +******************************************************************************/ + + LEAF_ENTRY(HalpGetLowerDBAT) + + cmpli 0,0,BatNumber,0 + bne NotLD0 + mfdbatl BatNumber,0 + b ExitLD +NotLD0: + cmpli 0,0,BatNumber,1 + bne NotLD1 + mfdbatl BatNumber,1 + b ExitLD +NotLD1: + cmpli 0,0,BatNumber,2 + bne NotLD2 + mfdbatl BatNumber,2 + b ExitLD +NotLD2: + mfdbatl BatNumber,3 // OK, it's three by default + +ExitLD: + + LEAF_EXIT(HalpGetLowerDBAT) + +/****************************************************************************** + Synopsis: + ULONG HalpSetUpperDBAT(ULONG BatNumber) [rdl] + + Purpose: + Stores the 32-bit upper data BAT value for a given . + + Returns: + N/A +******************************************************************************/ + + .set BatValueToSet, r.4 + + LEAF_ENTRY(HalpSetUpperDBAT) + + cmpli 0,0,BatNumber,0 + bne NotSetUD0 + mtdbatu 0,BatValueToSet + b ExitSetUD +NotSetUD0: + cmpli 0,0,BatNumber,1 + bne NotSetUD1 + mtdbatu 1,BatValueToSet + b ExitSetUD +NotSetUD1: + cmpli 0,0,BatNumber,2 + bne NotSetUD2 + mtdbatu 2,BatValueToSet + b ExitSetUD +NotSetUD2: + mtdbatu 3,BatValueToSet // OK, it's three by default + +ExitSetUD: + + LEAF_EXIT(HalpSetUpperDBAT) + +/****************************************************************************** + Synopsis: + ULONG HalpSetLowerDBAT(ULONG BatNumber) [rdl] + + Purpose: + Stores the 32-bit lower data BAT value for a given . + + Returns: + N/A +******************************************************************************/ + + LEAF_ENTRY(HalpSetLowerDBAT) + + cmpli 0,0,BatNumber,0 + bne NotSetLD0 + mtdbatl 0,BatValueToSet + b ExitSetLD +NotSetLD0: + cmpli 0,0,BatNumber,1 + bne NotSetLD1 + mtdbatl 1,BatValueToSet + b ExitSetLD +NotSetLD1: + cmpli 0,0,BatNumber,2 + bne NotSetLD2 + mtdbatl 2,BatValueToSet + b ExitSetLD +NotSetLD2: + mtdbatl 3,BatValueToSet // OK, it's three by default + +ExitSetLD: + + LEAF_EXIT(HalpSetLowerDBAT) + +/****************************************************************************** + Synopsis: + VOID HalpSetLowerDBAT3(ULONG BatValue) [ged] + + Purpose: + Writes the 32-bit lower data BAT value to DBAT3. + + Returns: + Nothing +******************************************************************************/ + + .set BatValue, r.3 + + LEAF_ENTRY(HalpSetLowerDBAT3) + + mtdbatl 3,BatValue + + LEAF_EXIT(HalpSetLowerDBAT3) + +/****************************************************************************** + Synopsis: + VOID HalpSetLowerDBAT1(ULONG BatValue) [ged] + + Purpose: + Writes the 32-bit lower data BAT value to DBAT1. + + Returns: + Nothing +******************************************************************************/ + + LEAF_ENTRY(HalpSetLowerDBAT1) + + mtdbatl 1,BatValue + + LEAF_EXIT(HalpSetLowerDBAT1) + +/****************************************************************************** + Synopsis: + VOID HalpSetUpperDBAT1(ULONG BatValue) [ged] + + Purpose: + Writes the 32-bit upper data BAT value to DBAT1. + + Returns: + Nothing +******************************************************************************/ + + LEAF_ENTRY(HalpSetUpperDBAT1) + + mtdbatu 1,BatValue + + LEAF_EXIT(HalpSetUpperDBAT1) + +/****************************************************************************** + + Synopsis: + VOID HalpDisableDCache() +******************************************************************************/ + + LEAF_ENTRY(HalpDisableDCache) + + .set HID0, 1008 + + mtspr HID0, r3 + + LEAF_EXIT(HalpDisableDCache) + + +//++ +// +// void +// KiSetDbat +// +// Routine Description: +// +// Writes a set of values to DBAT n +// +// No validation of parameters is done. Protection is set for kernel +// mode access only. +// +// Arguments: +// +// r.3 Number of DBAT +// r.4 Physical address +// r.5 Virtual Address +// r.6 Length (in bytes) +// r.7 Coherence Requirements (WIM) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY (KiSetDbat) + + mfpvr r.9 // different format for + // 601 vs other 6xx processors + cmpwi cr.5, r.3, 1 + cmpwi cr.6, r.3, 2 + cmpwi cr.7, r.3, 3 + + rlwinm. r.10, r.9, 0, 0xfffe0000// Check for 601 + + // calculate mask (ie BSM) If we knew the number passed in was + // always a power of two we could just subtract 1 and shift right + // 17 bits. But to be sure we will use a slightly more complex + // algorithm than will always generate a correct mask. + // + // the mask is given by + // + // ( 1 << ( 32 - 17 - cntlzw(Length - 1) ) ) - 1 + // == ( 1 << ( 15 - cntlzw(Length - 1) ) ) - 1 + + addi r.6, r.6, -1 + oris r.6, r.6, 1 // ensure min length 128KB + ori r.6, r.6, 0xffff + cntlzw r.6, r.6 + subfic r.6, r.6, 15 + li r.10, 1 + slw r.6, r.10, r.6 + addi r.6, r.6, -1 + + beq cr.0, KiSetDbat601 + + // processor is not a 601. + + rlwinm r.7, r.7, 3, 0x38 // position WIM (G = 0) + rlwinm r.6, r.6, 2, 0x1ffc // restrict BAT maximum (non 601) + // after left shifting by 2. + ori r.6, r.6, 0x2 // Valid (bit) in supervisor state only + ori r.7, r.7, 2 // PP = 0x2 + or r.5, r.5, r.6 // = Virt addr | BL | Vs | Vp + or r.4, r.4, r.7 // = Phys addr | WIMG | 0 | PP + + beq cr.5, KiSetDbat1 + beq cr.6, KiSetDbat2 + beq cr.7, KiSetDbat3 + +KiSetDbat0: + mtdbatl 0, r.4 + mtdbatu 0, r.5 + ALTERNATE_EXIT(KiSetDbat) + +KiSetDbat1: + mtdbatl 1, r.4 + mtdbatu 1, r.5 + ALTERNATE_EXIT(KiSetDbat) + +KiSetDbat2: + mtdbatl 2, r.4 + mtdbatu 2, r.5 + ALTERNATE_EXIT(KiSetDbat) + +KiSetDbat3: + mtdbatl 3, r.4 + mtdbatu 3, r.5 + ALTERNATE_EXIT(KiSetDbat) + + // 601 has different format BAT registers and actually only has + // one set unlike other PowerPC processors which have seperate + // Instruction and Data BATs. The 601 BAT registers are set + // with the mtibat[u|l] instructions. + +KiSetDbat601: + + rlwinm r.7, r.7, 3, 0x70 // position WIMG (601 has no G bit) + rlwinm r.6, r.6, 0, 0x3f // restrict BAT maximum (601 = 8MB) + ori r.6, r.6, 0x40 // Valid bit + ori r.7, r.7, 4 // Ks = 0 | Ku = 1 | PP = 0b00 + or r.4, r.4, r.6 // = Phys addr | Valid | BL + or r.5, r.5, r.7 // = Virt addr | WIM | Ks | Ku | PP + + beq cr.5, KiSet601Bat1 + beq cr.6, KiSet601Bat2 + beq cr.7, KiSet601Bat3 + +KiSet601Bat0: + mtibatl 0, r.4 + mtibatu 0, r.5 + ALTERNATE_EXIT(KiSet601Bat) + +KiSet601Bat1: + mtibatl 1, r.4 + mtibatu 1, r.5 + ALTERNATE_EXIT(KiSet601Bat) + +KiSet601Bat2: + mtibatl 2, r.4 + mtibatu 2, r.5 + ALTERNATE_EXIT(KiSet601Bat) + +KiSet601Bat3: + mtibatl 3, r.4 + mtibatu 3, r.5 + + LEAF_EXIT(KiSetDbat) + +/****************************************************************************** + Synopsis: + ULONG HalpGetHighVector(ULONG IntValue) + + Purpose: + Find the highest bit turned on and return the bit order + + Returns: + Number of leading zeroes +******************************************************************************/ + + .set IntValue, r.3 + + LEAF_ENTRY(HalpGetHighVector) + + cntlzw IntValue, IntValue + subfic IntValue, IntValue, 0x1f + + LEAF_EXIT(HalpGetHighVector) diff --git a/private/ntos/nthals/halfire/ppc/phvrsion.c b/private/ntos/nthals/halfire/ppc/phvrsion.c new file mode 100644 index 000000000..81f79d3b9 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/phvrsion.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 1995,1996 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: phvrsion.c $ + * $Revision: 1.47 $ + * $Date: 1996/06/25 16:06:34 $ + * $Locker: $ + */ + +#include "halp.h" +#include "phsystem.h" +#include "fparch.h" +#include "ntverp.h" +#include "string.h" + +typedef CHAR Names[20]; + + LONG i=0; + Names ScopeList[] = { + "Engineering", + "Manufacturing", + "Testing", + "Customer", + }; + Names RelList[] = { + "General", + "OfficiaL", + "Testing", + "Controlled", + "Lab use" + }; + +// +// to avoid cascading headers +// +NTSYSAPI +NTSTATUS +NTAPI +RtlCharToInteger ( + PCSZ String, + ULONG Base, + PULONG Value + ); + +#define HAL_DISPLAY_DEFINES(a) \ + if (state == 3) { \ + HalDisplayString("\n"); \ + state = 0; \ + } \ + HalDisplayString(" "); \ + HalDisplayString(a); \ + state++; + +#define ORG IQUOTE(BUILTBY) +// #define REVIEW __FILE__ "(" IQUOTE(__LINE__) ") : REVIEW -> " + +ULONG +HalpVersionSystem( + SYSTEM_TYPE +) ; +VOID +HalpVersionExternal( + IN RelInfo *, + IN PLOADER_PARAMETER_BLOCK +) ; +PCHAR +HalpGetVersionData( + IN PLOADER_PARAMETER_BLOCK LoaderBlock +) ; +VOID +HalpDisplayVersionData( + IN PCHAR VersionData +) ; +BOOLEAN +HalpSetRevs( + RelInfo * +) ; + +// int HalpProcessorCount(); + +#pragma alloc_text(INIT,HalpVersionSystem) +#pragma alloc_text(INIT,HalpVersionExternal) +#pragma alloc_text(INIT,HalpGetVersionData) +#pragma alloc_text(INIT,HalpDisplayVersionData) +#pragma alloc_text(INIT,HalpSetRevs) + +extern ULONG HalpGetCycleTime(VOID); +extern ULONG HalpGetInstructionTimes( VOID ); +extern ULONG HalpPerformanceFrequency; + + +#if DBG == 1 +VOID +HalpVersionInternal( VOID ) +{ + + int state = 0; + + HalpDebugPrint("\nWelcome to the %s (%s) Party\n", + SystemDescription[SystemType].SystemName, + ProcessorDescription[ProcessorType].ProcessorName); + HalpDebugPrint("HalpVersionInternal: Raw Processor Value (0x%x)\n", + HalpGetProcessorVersion()); + HalpDebugPrint("Hal compiled on %s at %s with the following defines:\n", + __DATE__, __TIME__); + + HalDisplayString("\n"); + HalpDebugPrint(" Hal Build Base: %d \n",VER_PRODUCTBUILD); + HalpVersionSystem(SystemType); +} +#endif // DBG + +/* + * Routine Description: ULONG HalpVersionSystem(SYSTEM_TYPE System) + * + * Extract as much version information out of the mother board as possible: + * + */ + +ULONG +HalpVersionSystem(SYSTEM_TYPE System) +{ + ULONG TscVersion=0; + ULONG PciVersion=0; + + TscVersion = rTscRevision; + PciVersion = rPCIRevisionID; + + switch(System) { + + case SYS_POWERSLICE: + HalpDebugPrint("TSC version: 0x%x \n", TscVersion ); + break; + + case SYS_POWERTOP : HalpDebugPrint("TSC version: 0x%x \n", TscVersion ); + break; + + case SYS_POWERPRO : HalpDebugPrint("Escc version: IS NOT DESIGNED IN!@!"); + break; + + case SYS_POWERSERVE : HalpDebugPrint("WHOOOAA pahdna, just what are you trying to pull here?\n"); + break; + + case SYS_UNKNOWN : HalpDebugPrint("Unknown system type \n"); + + default: // unknown stuff? should never get here + break; + } + HalpDebugPrint("\n===========================================================================\n"); + HalpDebugPrint("PCI revision id: 0x%x \n", PciVersion ); + HalpDebugPrint("TSC Control register: 0x%08x\n",rTscControl); + HalpDebugPrint("PioPending count: 0x%08x\n",rPIOPendingCount); + HalpDebugPrint("\n===========================================================================\n"); + + return(1); // success, true, good, ... +} +static PCHAR +gettoken(PCHAR token, PCHAR buf, CHAR delim) +{ + CHAR c; + while (c = *buf) { + if (c == delim) { + buf++; + break; + } else { + *token++ = c; + buf++; + } + } + *token = '\0'; + return buf; +} + +VOID +HalpDisplayVersionData( IN PCHAR VersionData ) +{ + + while (*VersionData) { + enum {Firmware = 0, Veneer = 1, Nada}; + ULONG type; + PCHAR typeStr[2] = {"Firmware", "Veneer"}; + CHAR token[64]; + PCHAR tok = VersionData; + VersionData += strlen(VersionData)+1; + + if (strstr(tok, typeStr[Firmware])) { + type = Firmware; + } else if (strstr(tok, typeStr[Veneer])) { + type = Veneer; + } else { + type = Nada; + } + if (Nada != type) { + CHAR buf[80]; + strcpy(buf, typeStr[type]); + strcat(buf, ":"); + if (strlen(buf) < 10) { + HalpDebugPrint("%-10s", buf); + } else { + HalpDebugPrint("%s: ", buf); + } + if (*VersionData) { + LONG n; + + tok = VersionData; + VersionData += strlen(VersionData)+1; + n = 0; + tok = gettoken(token, tok, ','); + while (token[0]) { + switch (n++) { + case 2: + strcpy(buf, token); + strcat(buf, ","); + if (strlen(buf) < 7) { + HalpDebugPrint("%-7s", buf); + } else { + HalpDebugPrint("%s ", buf); + } + break; + case 3: + // + // Put date in Mmm dd yyyy format if in yyyy-mm-dd + // No unicode here :-). + // isdigit() causes too many link hassles. + // + if (type == Firmware && *token >= '0' && *token <= '9') { + PCHAR day; + PCHAR month; + PCHAR year; + PCHAR Mmm[12] = { + "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec", + }; + + strcpy(buf, token); + if (day = strrchr(buf, '-')) { + *day++ = '\0'; + if (month = strrchr(buf, '-')) { + ULONG i; + *month++ = '\0'; + RtlCharToInteger(month, 10, &i); + if (i > 12 || i < 1) { + HalpDebugPrint("%s, ", token); + } else { + year = buf; + // + // Decrement the month by one to align with + // zero based nature of the Mmm array. + // + HalpDebugPrint("%s %s %s, ", Mmm[i-1], day, year); + } + } + } else { + HalpDebugPrint("%s, ", token); + } + } else { + HalpDebugPrint("%s, ", token); + } + break; + case 4: + HalpDebugPrint("%s", token); + break; + } + tok = gettoken(token, tok, ','); + } + HalpDebugPrint("\n"); + } + } + } +} + +PCHAR +HalpGetVersionData( IN PLOADER_PARAMETER_BLOCK LoaderBlock ) +{ + PCHAR versionData = NULL; + + // + // Read the Registry entry to get the Firmware and Veneer version info. + // + + if (LoaderBlock) { + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + + ConfigurationEntry = KeFindConfigurationEntry ( + LoaderBlock->ConfigurationRoot, + SystemClass, + ArcSystem, + NULL + ); + + if (ConfigurationEntry) { + if (ConfigurationEntry->ComponentEntry.ConfigurationDataLength) { + PCM_PARTIAL_RESOURCE_LIST List; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + LONG count; + + List = (PCM_PARTIAL_RESOURCE_LIST) ConfigurationEntry->ConfigurationData; + Descriptor = List->PartialDescriptors; + for (count = List->Count; count > 0; count--) { + if (CmResourceTypeDeviceSpecific == Descriptor->Type) { + if (Descriptor->u.DeviceSpecificData.DataSize) { + // + // Finally, got the device specific data! + // + + versionData = (PCHAR) Descriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); + break; + } + } + } + } + } + } + return versionData; +} + +VOID +HalpVersionExternal( IN RelInfo *yahoo, IN PLOADER_PARAMETER_BLOCK LoaderBlock ) +{ + PCHAR versionData; + CHAR debugStr[50]; + CHAR buf[BUFSIZ]; + + + // --> Make it look like this <-- + // + // FirePower (TM) Systems, Inc. Powerized (TM) MX4100/2 + // Copyright (C) 1994-1996 FirePower Systems, Inc. + // All rights reserved. + // + // Firmware: 00.23, Apr 27 1995, 14:42:21 + // Veneer: 1.0, May 13 1995, 18:59:56 + // Hal: 0,0, May 16 1995, 18:00:42 + + // + // Display the Model Number and our company name + // + HalpDebugPrint("\nFirePower (TM) Systems, Inc. Powerized_%s\n", + SystemDescription[SystemType].SystemName); + HalpDebugPrint("Copyright (C) 1994-1996 FirePower Systems, Inc.\n"); + HalpDebugPrint("All rights reserved.\n\n"); + + // + // Display Version Data from firmware/veneer + // + + if ( versionData = HalpGetVersionData(LoaderBlock) ) { + HalpDisplayVersionData(versionData); + } + + // + // Display HAL Version Data + // + + sprintf(buf, "%d.%d,", yahoo->Major, yahoo->Minor); +#if DBG +#if HALFIRE_EVAL + sprintf(debugStr, "DEBUG %s", HALFIRE_EVAL); +#else + strcpy(debugStr, "DEBUG"); +#endif +#else +#if HALFIRE_EVAL + sprintf(debugStr, "%s", HALFIRE_EVAL); +#else + strcpy(debugStr, ""); +#endif +#endif + if (strlen(buf) < 7) { + HalpDebugPrint("HAL: %-7s%s, %s %s\n\n", buf, + yahoo->BuildDate, yahoo->BuildTime, debugStr); + } else { + HalpDebugPrint("HAL: %s %s, %s %s\n\n", buf, + yahoo->BuildDate, yahoo->BuildTime, debugStr); + } +} + +/* +*/ +BOOLEAN +HalpSetRevs( RelInfo *yahoo ) +{ + CHAR *ads; + LONG i=0; + + ads = ORG; + while( *ads ) { + yahoo->Org[i] = *ads++; + i++; + } + yahoo->Scope = ENG; + i=0; + ads=__DATE__; + while( *ads ) { + yahoo->BuildDate[i] = *ads++; + i++; + } + i=0; + ads=__TIME__; + while( *ads ) { + yahoo->BuildTime[i] = *ads++; + i++; + } + yahoo->Major = HAL_MAJOR; + yahoo->Minor = HAL_MINOR; + yahoo->State = LAB; + return TRUE; +} + +#if DBG +/* + * Routine Description: BOOLEAN HalpPrintRevs() + * + * args: + * RelInfo + */ + +BOOLEAN +HalpPrintRevs( RelInfo *yahoo ) +{ + + HalpDebugPrint("Hal version-[%x.%x] \n",yahoo->Major, yahoo->Minor); + HalpDebugPrint("%s: ", yahoo->Org ); + HalpDebugPrint("%s: ", ScopeList[yahoo->Scope]); + HalpDebugPrint("%s: ",yahoo->BuildDate); + HalpDebugPrint("%s: ",yahoo->BuildTime); + HalpDebugPrint("%s: ", RelList[yahoo->State]); + + return TRUE; +} +#endif // DBG diff --git a/private/ntos/nthals/halfire/ppc/pxbeep.c b/private/ntos/nthals/halfire/ppc/pxbeep.c new file mode 100644 index 000000000..201b01d11 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxbeep.c @@ -0,0 +1,144 @@ +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Module Name: + + pxbeep.c + +Abstract: + + This module implements the HAL speaker "beep" routines for a Power PC + system. + + +Author: + + +Environment: + + Kernel mode + +Revision History: + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxbeep.c $ + * $Revision: 1.5 $ + * $Date: 1996/01/11 07:08:52 $ + * $Locker: $ + */ + +#include "halp.h" +#include "eisa.h" + +BOOLEAN +HalMakeBeep( + IN ULONG Frequency + ) + +/*++ + +Routine Description: + + This function sets the frequency of the speaker, causing it to sound a + tone. The tone will sound until the speaker is explicitly turned off, + so the driver is responsible for controlling the duration of the tone. + +Arguments: + + Frequency - Supplies the frequency of the desired tone. A frequency of + 0 means the speaker should be shut off. + +Return Value: + + TRUE - Operation was successful (frequency within range or zero). + FALSE - Operation was unsuccessful (frequency was out of range). + Current tone (if any) is unchanged. + +--*/ + +{ + + KIRQL OldIrql; + NMI_STATUS NmiStatus; + PEISA_CONTROL controlBase = HalpIoControlBase; + TIMER_CONTROL timerControl; + ULONG newCount; + BOOLEAN Result; + + // + // Raise IRQL to dispatch level and acquire the beep spin lock. + // + + KeAcquireSpinLock(&HalpBeepLock, &OldIrql); + + // + // Stop the speaker. + // + + *((PUCHAR)&NmiStatus) = READ_REGISTER_UCHAR(&controlBase->NmiStatus); + NmiStatus.SpeakerGate = 0; + NmiStatus.SpeakerData = 0; + WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR)&NmiStatus)); + + // + // If the specified frequency is zero, then the speaker is to be stopped. + // + + if (Frequency == 0) { + Result = TRUE; + + } else { + + // + // If the new count has a magnitude less than 65,536 (0x10000), then + // set the speaker time to the correct mode. Otherwise, return a value + // of FALSE sinc ethe frequency is out of range. + // + + newCount = TIMER_CLOCK_IN / Frequency; + if (newCount >= 0x10000) { + Result = FALSE; + + } else { + + // + // Set the speaker timer to the correct mode. + // + + timerControl.BcdMode = 0; + timerControl.Mode = TM_SQUARE_WAVE; + timerControl.SelectByte = SB_LSB_THEN_MSB; + timerControl.SelectCounter = SELECT_COUNTER_2; + WRITE_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl)); + + // + // Set the speaker timer to the correct mode. + // + + WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount & 0xff)); + WRITE_REGISTER_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount >> 8)); + + // + // Start the speaker. + // + + NmiStatus.SpeakerGate = 1; + NmiStatus.SpeakerData = 1; + WRITE_REGISTER_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus)); + Result = TRUE; + } + } + + // + // Release the beep spin lock and lower IRQL to its previous value. + // + + KeReleaseSpinLock(&HalpBeepLock, OldIrql); + return Result; +} diff --git a/private/ntos/nthals/halfire/ppc/pxbusdat.c b/private/ntos/nthals/halfire/ppc/pxbusdat.c new file mode 100644 index 000000000..a72ecf450 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxbusdat.c @@ -0,0 +1,207 @@ +/*++ + + +Copyright (C) 1989-1995 Microsoft Corporation + +Module Name: + + pxhwsup.c + +Abstract: + + This module contains the IoXxx routines for the NT I/O system that + are hardware dependent. Were these routines not hardware dependent, + they would reside in the iosubs.c module. + +Environment: + + Kernel mode + + +--*/ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxbusdat.c $ + * $Revision: 1.10 $ + * $Date: 1996/05/14 02:33:37 $ + * $Locker: $ + */ + + +#include "halp.h" +#include "fpdebug.h" + + +VOID HalpInitOtherBuses (VOID); + + +ULONG +HalpNoBusData ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN ULONG SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + + + + +// +// Prototype for system bus handlers +// + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +ULONG +HalpGetSystemInterruptVector ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +ULONG +HalpGetIsaInterruptVector ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + +BOOLEAN +HalpTranslateSystemBusAddress ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ); + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpRegisterInternalBusHandlers) +#pragma alloc_text(INIT,HalpAllocateBusHandler) +#endif + + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ) +{ + PBUS_HANDLER Bus; + + if (KeGetCurrentPrcb()->Number) { + // only need to do this once + return ; + } + + // + // Initalize BusHandler data before registering any handlers + // + + HalpInitBusHandler (); + + // + // Build internal-bus 0, or system level bus + // + Bus = HalpAllocateBusHandler (Internal, -1, 0, -1, 0, 0); + Bus->GetInterruptVector = HalpGetSystemInterruptVector; + Bus->TranslateBusAddress = HalpTranslateSystemBusAddress; + + // + // Build Isa bus 0 + + Bus = HalpAllocateBusHandler (Isa, -1, 0, Internal, 0, 0); + Bus->GetBusData = HalpNoBusData; + Bus->GetInterruptVector = HalpGetIsaInterruptVector; + Bus->AdjustResourceList = HalpAdjustIsaResourceList; + + + HalpInitOtherBuses (); +} + + + +PBUS_HANDLER +HalpAllocateBusHandler ( + IN INTERFACE_TYPE InterfaceType, + IN BUS_DATA_TYPE BusDataType, + IN ULONG BusNumber, + IN INTERFACE_TYPE ParentBusInterfaceType, + IN ULONG ParentBusNumber, + IN ULONG BusSpecificData + ) +/*++ + +Routine Description: + + Stub function to map old style code into new HalRegisterBusHandler code. + + Note we can add our specific bus handler functions after this bus + handler structure has been added since this is being done during + hal initialization. + +--*/ +{ + PBUS_HANDLER Bus; + NTSTATUS status; + + + // + // Create bus handler - new style + // + + status = HaliRegisterBusHandler ( + InterfaceType, + BusDataType, + BusNumber, + ParentBusInterfaceType, + ParentBusNumber, + BusSpecificData, + NULL, + &Bus + ); + + if( !NT_SUCCESS(status) ) { + HalDisplayString("HalpAllocateBusHandler: unable to HaliRegister \n"); + } + + if (InterfaceType != InterfaceTypeUndefined) { + Bus->BusAddresses = ExAllocatePool (SPRANGEPOOL, + sizeof (SUPPORTED_RANGES)); + RtlZeroMemory (Bus->BusAddresses, sizeof (SUPPORTED_RANGES)); + Bus->BusAddresses->Version = BUS_SUPPORTED_RANGE_VERSION; + Bus->BusAddresses->Dma.Limit = 7; + Bus->BusAddresses->Memory.Limit = 0x3EFFFFFF; + Bus->BusAddresses->Memory.SystemAddressSpace = 0; + Bus->BusAddresses->Memory.SystemBase = PCI_MEMORY_PHYSICAL_BASE; + Bus->BusAddresses->IO.SystemBase = 0x80000000; + Bus->BusAddresses->IO.Limit = 0x3F7FFFFF; + Bus->BusAddresses->IO.SystemAddressSpace = 0; + Bus->BusAddresses->PrefetchMemory.Base = 1; + } + + + return Bus; +} + diff --git a/private/ntos/nthals/halfire/ppc/pxcache.s b/private/ntos/nthals/halfire/ppc/pxcache.s new file mode 100644 index 000000000..5c20d501e --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxcache.s @@ -0,0 +1,1105 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxcache.s $ + * $Revision: 1.12 $ + * $Date: 1996/03/05 02:16:01 $ + * $Locker: $ + */ + +//++ +// +// Copyright (c) 1993, 1994, 1995 IBM Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxcache.s +// +// Abstract: +// +// This module implements the routines to flush cache on the PowerPC. +// +// Author: +// +// Peter L. Johnston (plj@vnet.ibm.com) September 1993 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 27-Dec-93 plj Added 603 support. +// 13-Mar-94 plj Fixed problem introduced during switch to pas, +// added 604 support. +// 18-Jan-95 plj Add 603+, 604+ and 620 support. +// +//-- + +#include "kxppc.h" + + .set HID0, 1008 // H/W Implementation Dependent reg 0 + +// +// Define various known processor types. +// + + .set PV601, 1 // 601 + .set PV603, 3 // 603 + .set PV603P, 6 // 603 plus + .set PV604, 4 // 604 + .set PV604P, 9 // 604 plus + .set PV620, 20 // 620 + +// +// Note, in the following, the 603's "I-Cache Flash Invalidate" +// and the 604's "I-Cache Invalidate All" basically perform the +// same function although the usage is slightly different. +// In the 603 case, ICFI must be cleared under program control +// after it is set. In the 604 the bit clears automatically. +// The 620's ICEFI behaves in the same way as the 604's ICIA. +// + + .set H0_603_ICFI, 0x0800 // I-Cache Flash Invalidate + .set H0_604_ICIA, 0x0800 // I-Cache Invalidate All + .set H0_620_ICEFI,0x0800 // I-Cache Edge Flash Invalidate + +// +// Cache layout +// +// Processor | Size (bytes) | Line Size | Block Size | PVR Processor +// | I-Cache | D-Cache | | | Version +// ---------------------------------------------------------------------- +// 601 | 32KB Unified | 64 bytes | 32 bytes | 0x0001xxxx +// 603 | 8KB | 8KB | 32 | 32 | 0x0003xxxx +// 603+ | 16KB | 16KB | 32 | 32 | 0x0006xxxx +// 604 | 16KB | 16KB | 32 | 32 | 0x0004xxxx +// 604+ | 32KB | 32KB | 32 | 32 | 0x0009xxxx +// 620 | 32KB | 32KB | 64 | 64 | 0x0014xxxx +// + + .set DCLSZ601, 64 // 601 cache line size + .set DCBSZ601, 32 // 601 cache block size + .set DCL601, 32 * 1024 / DCLSZ601 // 601 num cache lines + .set DCBSZL2601, 5 // 601 log2(block size) + + .set DCBSZ603, 32 // 603 cache block size + .set DCB603, 8 * 1024 / DCBSZ603 // 603 num cache blocks + .set DCBSZL2603, 5 // 603 log2(block size) + + .set DCB603P, 16 * 1024 / DCBSZ603 // 603+ num cache blocks + + .set DCBSZ604, 32 // 604 cache block size + .set DCB604, 16 * 1024 / DCBSZ604 // 604 num cache blocks + .set DCBSZL2604, 5 // 604 log2(block size) + + .set DCB604P, 32 * 1024 / DCBSZ604 // 604+ num cache blocks + + .set DCBSZ620, 64 // 620 cache block size + .set DCB620, 32 * 1024 / DCBSZ620 // 620 num cache blocks + .set DCBSZL2620, 6 // 620 log2(block size) + +// +// The following variables are declared locally so their addresses +// will appear in the TOC. During initialization, we overwrite +// the TOC entries with the entry points for the cache flushing +// routines appropriate for the processor we are running on. +// +// It is done this way rather than filling in a table to reduce the +// number of access required to get the address at runtime. +// (This is known as "Data in TOC" which is not very much used in +// NT at this time). +// + + .data + .globl HalpSweepDcache +HalpSweepDcache: .long 0 + .globl HalpSweepIcache +HalpSweepIcache: .long 0 + .globl HalpSweepDcacheRange +HalpSweepDcacheRange: .long 0 + .globl HalpSweepIcacheRange +HalpSweepIcacheRange: .long 0 + +//++ +// +// Routine Description: +// +// HalpCacheSweepSetup +// +// This routine is called during HAL initialization. Its function +// is to set the branch tables for cache flushing routines according +// to the processor type. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + LEAF_ENTRY(HalpCacheSweepSetup) + + mfpvr r.3 // get processor type + rlwinm r.3, r.3, 16, 0xffff // remove version + cmpwi r.3, PV603P // binary search for the right code + lwz r.4, [toc].data(r.toc) // get address of local data section + bge hcss.high // jif 603+ or greater + cmpwi r.3, PV603 + beq hcss.603 // jif 603 + bgt hcss.604 // > 603, < 603+ must be 604 + +// +// processor is a 601 +// + + lwz r.5, [toc]HalpSweepDcache601(r.toc) + lwz r.7, [toc]HalpSweepDcacheRange601(r.toc) + lwz r.8, [toc]HalpSweepIcacheRange601(r.toc) + mr r.6, r.5 // 601 icache use dcache routine + b hcss.done + +// +// processor is a 603 +// + +hcss.603: + + lwz r.5, [toc]HalpSweepDcache603(r.toc) + lwz r.6, [toc]HalpSweepIcache603(r.toc) + lwz r.7, [toc]HalpSweepDcacheRange603(r.toc) + lwz r.8, [toc]HalpSweepIcacheRange603(r.toc) + b hcss.done + +// +// processor is a 604 +// + +hcss.604: + + lwz r.5, [toc]HalpSweepDcache604(r.toc) + lwz r.6, [toc]HalpSweepIcache604(r.toc) + lwz r.7, [toc]HalpSweepDcacheRange604(r.toc) + lwz r.8, [toc]HalpSweepIcacheRange604(r.toc) + b hcss.done + +// +// Processor type >= 603+, continue isolation of processor type. +// + +hcss.high: + + beq hcss.603p // jif 603 plus + cmpwi cr.0, r.3, PV604P + cmpwi cr.1, r.3, PV620 + beq cr.0, hcss.604p // jif 604 plus + beq cr.1, hcss.620 // jif 620 + +// +// If we got here we are running on a processor whose cache characteristics +// are not known. Return non-zero for error. +// + + li r.3, 1 + blr + +// +// processor is a 603 plus +// + +hcss.603p: + + lwz r.5, [toc]HalpSweepDcache603p(r.toc) + lwz r.6, [toc]HalpSweepIcache603p(r.toc) + lwz r.7, [toc]HalpSweepDcacheRange603p(r.toc) + lwz r.8, [toc]HalpSweepIcacheRange603p(r.toc) + b hcss.done + +// +// processor is a 604 plus +// + +hcss.604p: + + lwz r.5, [toc]HalpSweepDcache604p(r.toc) + lwz r.6, [toc]HalpSweepIcache604p(r.toc) + lwz r.7, [toc]HalpSweepDcacheRange604p(r.toc) + lwz r.8, [toc]HalpSweepIcacheRange604p(r.toc) + b hcss.done + +// +// processor is a 620 +// + +hcss.620: + + lwz r.5, [toc]HalpSweepDcache620(r.toc) + lwz r.6, [toc]HalpSweepIcache620(r.toc) + lwz r.7, [toc]HalpSweepDcacheRange620(r.toc) + lwz r.8, [toc]HalpSweepIcacheRange620(r.toc) + b hcss.done + + +hcss.done: + +// +// r.5 thru r.9 contain the address of the function descriptors +// for the routines we really want to use. Dereference them to +// get at the entry point addresses. +// + lwz r.5, 0(r.5) + lwz r.6, 0(r.6) + lwz r.7, 0(r.7) + lwz r.8, 0(r.8) + +// +// Store the entry point addresses directly into the TOC. +// This is so direct linkage from within the HAL to the +// generic cache flushing routines can get to the desired +// routines for this processor. +// + + stw r.5, [toc]HalpSweepDcache(r.toc) + stw r.6, [toc]HalpSweepIcache(r.toc) + stw r.7, [toc]HalpSweepDcacheRange(r.toc) + stw r.8, [toc]HalpSweepIcacheRange(r.toc) + +// +// Modify the Function Descriptors for the generic routines to +// point directly at the target routines so that linkage from +// other executables (eg the kernel) will be direct rather +// than via the generic routines. +// + + lwz r.3, [toc]HalSweepDcache(r.toc) + lwz r.4, [toc]HalSweepIcache(r.toc) + stw r.5, 0(r.3) + stw r.6, 0(r.4) + lwz r.3, [toc]HalSweepDcacheRange(r.toc) + lwz r.4, [toc]HalSweepIcacheRange(r.toc) + stw r.7, 0(r.3) + stw r.8, 0(r.4) + + li r.3, 0 // return code = success + + LEAF_EXIT(HalpCacheSweepSetup) + +//++ +// +// Routines HalSweepDcache +// HalSweepIcache +// HalSweepDcacheRange +// HalSweepIcacheRange +// +// are simply dispatch points for the appropriate routine for +// the processor being used. +// +//-- + + + LEAF_ENTRY(HalSweepDcache) + + lwz r.12, [toc]HalpSweepDcache(r.toc) + mtctr r.12 + bctr + + DUMMY_EXIT(HalSweepDcache) + + + + LEAF_ENTRY(HalSweepIcache) + + lwz r.12, [toc]HalpSweepIcache(r.toc) + mtctr r.12 + bctr + + DUMMY_EXIT(HalSweepIcache) + + + + LEAF_ENTRY(HalSweepDcacheRange) + + lwz r.12, [toc]HalpSweepDcacheRange(r.toc) + mtctr r.12 + bctr + + DUMMY_EXIT(HalSweepDcacheRange) + + + + LEAF_ENTRY(HalSweepIcacheRange) + + lwz r.12, [toc]HalpSweepIcacheRange(r.toc) + mtctr r.12 + bctr + + DUMMY_EXIT(HalSweepIcacheRange) + + + + +//++ +// +// 601 Cache Flushing Routines +// +// The 601 has a unified instruction/data cache. For this reason +// we need only two routines, one to sweep the entire cache and +// another to sweep a given range. +// +// +// +// +// HalpSweepDcache601 +// +// Sweep the entire instruction/data cache. This is accomplished +// by loading the cache with data corresponding to a known address +// range and then ensuring that each block in the cache is not dirty. +// +// Note that the 601 line size is 64 bytes and its block size is 32 +// bytes. When we load any byte within a line, both blocks in that +// line are loaded into the cache (if not already present). We must +// clean each block individually. +// +// In an effort to maximize the possibilities that (a) the addressed +// data is already in the cache and (b) there is some use in having +// this data in the cache, we use the lower end of the hashed page +// table as the data to be loaded and we use dcbst rather than dcbf +// to force the block to memory (and leave it valid in the cache as +// well). +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepDcache601) + + mfsdr1 r.3 // fill the D cache from memory + // allocated to the hashed page + // table (it's something useful). + li r.4, DCL601 // size of cache in cache lines + mtctr r.4 + DISABLE_INTERRUPTS(r.10,r.11) + sync + oris r.3, r.3, 0x8000 // get VA of hashed page table + subi r.5, r.3, DCBSZ601 // dec addr prior to inc +hsd601.ld: + lbzu r.8, DCLSZ601(r.5) + bdnz hsd601.ld + ENABLE_INTERRUPTS(r.10) + + LEAF_EXIT(HalpSweepDcache601) + + + + +//++ +// +// HalpSweepDcacheRange601 +// +// HalpSweepDcacheRange603 +// +// HalpSweepDcacheRange603p +// +// HalpSweepDcacheRange604 +// +// HalpSweepDcacheRange604p +// +// Force data in a given address range to memory. +// +// Because this routine works on a range of blocks and block size +// is the same on 601, 603, 603+, 604 and 604+ we can use the same +// code for each of them. +// +// Arguments: +// +// r.3 Start address +// r.4 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepDcacheRange601) + + ALTERNATE_ENTRY(HalpSweepDcacheRange603) + + ALTERNATE_ENTRY(HalpSweepDcacheRange603p) + + ALTERNATE_ENTRY(HalpSweepDcacheRange604) + + ALTERNATE_ENTRY(HalpSweepDcacheRange604p) + + rlwinm r.5, r.3, 0, DCBSZ601-1 // isolate offset in start block + addi r.4, r.4, DCBSZ601-1 // bump range by block sz - 1 + add r.4, r.4, r.5 // add start block offset + srwi r.4, r.4, DCBSZL2601 // number of blocks + mtctr r.4 + sync +hsdr601.fl: + dcbst 0, r.3 // flush block + addi r.3, r.3, DCBSZ601 // bump address + bdnz hsdr601.fl + + LEAF_EXIT(HalpSweepDcacheRange601) + + + + +//++ +// +// HalpSweepIcacheRange601 +// +// Due to the unified cache, this routine is meaningless on a 601. +// The reason for flushing a range of instruction address is because +// of code modification (eg breakpoints) in which case the nature +// of the unified cache is that the *right* code is in the cache, +// or because of a transfer of a code page in which case the unified +// snooping cache will have done the right thing. +// +// Therefore this routine simply returns. +// +// Arguments: +// +// r.3 Start address +// r.4 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcacheRange601) + + // return + + LEAF_EXIT(HalpSweepIcacheRange601) + +//++ +// +// 603, 603+ Cache Flushing Routines +// +// The 603 has seperate instruction and data caches of 8 KB each. +// The 603+ has seperate instruction and data caches of 16 KB each. +// Line size = Block size = 32 bytes. +// +// The mechanics of cache manipulation are the same for the 603 and +// 603+. +// +// +// +// HalpSweepDcache603 HalpSweepDcache603p +// +// Sweep the entire data cache. This is accomplished by loading +// the cache with data corresponding to a known address range and +// then ensuring that each block in the cache is not dirty. +// +// The 603 does not have a hashed page table so we can't use the +// hashed page table as the data range. Instead use the start of +// KSEG0. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepDcache603p) + + li r.4, DCB603P // size of 603+ cache in blocks + b hsd603 + + DUMMY_EXIT(HalpSweepDcache603p) + + + + LEAF_ENTRY(HalpSweepDcache603) + + li r.4, DCB603 // size of 603 cache in blocks +hsd603: + mtctr r.4 + DISABLE_INTERRUPTS(r.10,r.11) + sync // ensure ALL previous stores completed + LWI(r.3,0x80000000) // known usable virtual address + subi r.5, r.3, DCBSZ603 // dec addr prior to inc +hsd603.ld: + lbzu r.8, DCBSZ603(r.5) + bdnz hsd603.ld + ENABLE_INTERRUPTS(r.10) + + mtctr r.4 +hsd603.fl: + dcbst 0, r.3 // ensure block is in memory + addi r.3, r.3, DCBSZ603 // bump address + bdnz hsd603.fl + + LEAF_EXIT(HalpSweepDcache603) + + + + +//++ +// +// HalpSweepIcache603 HalpSweepIcache603p +// +// Sweep the entire instruction cache. The instruction cache (by +// definition) can never contain modified code (hence there are no +// icbf or icbst instructions). Therefore what we really need to do +// here is simply invalidate every block in the cache. This can be +// done by toggling the Instruction Cache Flash Invalidate (ICFI) bit +// in the 603's HID0 register. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcache603) + + ALTERNATE_ENTRY(HalpSweepIcache603p) + + mfspr r.3, HID0 // 603, use Instruction + ori r.4, r.3, H0_603_ICFI // Cache Flash Invalidate + + isync + mtspr HID0, r.4 // invalidate I-Cache + mtspr HID0, r.3 // re-enable + + LEAF_EXIT(HalpSweepIcache603) + + + +//++ +// +// HalpSweepIcacheRange603 HalpSweepIcacheRange603p +// +// Remove a range of instructions from the instruction cache. +// +// Note that if this is going to take a long time we flash +// invalidate the I cache instead. Currently I define a +// "long time" as greater than 4096 bytes which amounts to +// 128 trips thru this loop (which should run in 256 clocks). +// This number was selected without bias or forethought from +// thin air - plj. I chose this number because gut feel tells +// me that it will cost me more than 256 clocks in cache misses +// trying to get back to the function that requested the cache +// flush in the first place. +// +// Arguments: +// +// r.3 Start address +// r.4 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcacheRange603) + + ALTERNATE_ENTRY(HalpSweepIcacheRange603p) + + cmpwi r.4, 4096 // if range > 4096 bytes, flush + bgt- ..HalpSweepIcache603 // entire I cache + + rlwinm r.5, r.3, 0, DCBSZ603-1 // isolate offset in start block + addi r.4, r.4, DCBSZ603-1 // bump range by block sz - 1 + add r.4, r.4, r.5 // add start block offset + srwi r.4, r.4, DCBSZL2603 // number of blocks + mtctr r.4 +hsir603.fl: + icbi 0, r.3 // invalidate block in I cache + addi r.3, r.3, DCBSZ603 // bump address + bdnz hsir603.fl + + LEAF_EXIT(HalpSweepIcacheRange603) + + +//++ +// +// 604 Cache Flushing Routines +// +// The 604 has seperate instruction and data caches of 16 KB each. +// The 604+ has seperate instruction and data caches of 32 KB each. +// Line size = Block size = 32 bytes. +// +// +// +// HalpSweepDcache604 HalpSweepDcache604p +// +// Sweep the entire data cache. This is accomplished by loading +// the cache with data corresponding to a known address range and +// then ensuring that each block in the cache is not dirty. +// +// As in the 601 case, we use the Hashed Page Table for the data +// in an effort to minimize performance lost by force feeding the +// cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + + LEAF_ENTRY(HalpSweepDcache604p) + + li r.4, DCB604P // size of 604+ cache in blocks + b hsd604 + + DUMMY_EXIT(HalpSweepDcache604p) + + + + LEAF_ENTRY(HalpSweepDcache604) + + li r.4, DCB604 // size of cache in cache blocks +hsd604: + mfsdr1 r.3 // fill the D cache from memory + // allocated to the hashed page + // table (it's something useful). + mtctr r.4 + DISABLE_INTERRUPTS(r.10,r.11) + sync // ensure ALL previous stores completed + oris r.3, r.3, 0x8000 // get VA of hashed page table + subi r.5, r.3, DCBSZ604 // dec addr prior to inc +hsd604.ld: + lbzu r.8, DCBSZ604(r.5) + bdnz hsd604.ld + ENABLE_INTERRUPTS(r.10) + + LEAF_EXIT(HalpSweepDcache604) + + + + +//++ +// +// HalpSweepIcache604 HalpSweepIcache604p +// +// Sweep the entire instruction cache. This routine is functionally +// similar to the 603 version except that on the 604 the bit in HID0 +// (coincidentally the *same* bit) is called Instruction Cache Invali- +// sate All (ICIA) and it clears automatically after being set. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcache604) + + ALTERNATE_ENTRY(HalpSweepIcache604p) + + mfspr r.3, HID0 // 604, use Instruction + ori r.3, r.3, H0_604_ICIA // Cache Invalidate All + isync + mtspr HID0, r.3 // invalidate I-Cache + + LEAF_EXIT(HalpSweepIcache604) + + + + +//++ +// +// HalpSweepIcacheRange604 HalpSweepIcacheRange604p +// +// Remove a range of instructions from the instruction cache. +// +// Arguments: +// +// r.3 Start address +// r.4 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcacheRange604) + + ALTERNATE_ENTRY(HalpSweepIcacheRange604p) + + rlwinm r.5, r.3, 0, DCBSZ604-1 // isolate offset in start block + addi r.4, r.4, DCBSZ604-1 // bump range by block sz - 1 + add r.4, r.4, r.5 // add start block offset + srwi r.4, r.4, DCBSZL2604 // number of blocks + mtctr r.4 +hsir604.fl: + icbi 0, r.3 // invalidate block in I cache + addi r.3, r.3, DCBSZ604 // bump address + bdnz hsir604.fl + + LEAF_EXIT(HalpSweepIcacheRange604) + +//++ +// +// 620 Cache Flushing Routines +// +// The 620 has seperate instruction and data caches of 32 KB each. +// Line size = Block size = 64 bytes. +// +// +// +// HalpSweepDcache620 +// +// Sweep the entire data cache. This is accomplished by loading +// the cache with data corresponding to a known address range and +// then ensuring that each block in the cache is not dirty. +// +// As in the 601 case, we use the Hashed Page Table for the data +// in an effort to minimize performance lost by force feeding the +// cache. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + + LEAF_ENTRY(HalpSweepDcache620) + + li r.4, DCB620 // size of cache in cache blocks +hsd620: + mfsdr1 r.3 // fill the D cache from memory + // allocated to the hashed page + // table (it's something useful). + mtctr r.4 + DISABLE_INTERRUPTS(r.10,r.11) + sync + oris r.3, r.3, 0x8000 // get VA of hashed page table + subi r.5, r.3, DCBSZ620 // dec addr prior to inc +hsd620.ld: + lbzu r.8, DCBSZ620(r.5) + bdnz hsd620.ld + ENABLE_INTERRUPTS(r.10) + + LEAF_EXIT(HalpSweepDcache620) + + + + +//++ +// +// HalpSweepIcache620 +// +// Sweep the entire instruction cache. This routine is functionally +// identical to the 604 version except that on the 620 the bit in HID0 +// (coincidentally the *same* bit) is called Instruction Cache Edge +// Flash Invalidate (ICEFI). +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcache620) + + mfspr r.3, HID0 // 620, use Instruction + ori r.3, r.3, H0_620_ICEFI // Cache Edge Flash Invalidate + isync + mtspr HID0, r.3 // invalidate I-Cache + + LEAF_EXIT(HalpSweepIcache620) + + + + +//++ +// +// HalpSweepIcacheRange620 +// +// Remove a range of instructions from the instruction cache. +// +// Arguments: +// +// r.3 Start address +// r.4 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepIcacheRange620) + + rlwinm r.5, r.3, 0, DCBSZ620-1 // isolate offset in start block + addi r.4, r.4, DCBSZ620-1 // bump range by block sz - 1 + add r.4, r.4, r.5 // add start block offset + srwi r.4, r.4, DCBSZL2620 // number of blocks + mtctr r.4 +hsir620.fl: + icbi 0, r.3 // invalidate block in I cache + addi r.3, r.3, DCBSZ620 // bump address + bdnz hsir620.fl + + LEAF_EXIT(HalpSweepIcacheRange620) + + + + +//++ +// +// HalpSweepDcacheRange620 +// +// Force data in a given address range to memory. +// +// Arguments: +// +// r.3 Start address +// r.4 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSweepDcacheRange620) + + rlwinm r.5, r.3, 0, DCBSZ620-1 // isolate offset in start block + addi r.4, r.4, DCBSZ620-1 // bump range by block sz - 1 + add r.4, r.4, r.5 // add start block offset + srwi r.4, r.4, DCBSZL2620 // number of blocks + mtctr r.4 + sync +hsdr620.fl: + dcbst 0, r.3 // flush block + addi r.3, r.3, DCBSZ620 // bump address + bdnz hsdr620.fl + + LEAF_EXIT(HalpSweepDcacheRange620) + + +//++ +// +// HalpSweepPhysicalRangeInBothCaches +// +// Force data in a given PHYSICAL address range to memory and +// invalidate from the block in the instruction cache. +// +// This implementation assumes a block size of 32 bytes. It +// will still work on the 620. +// +// Arguments: +// +// r.3 Start physical PAGE number. +// r.4 Starting offset within page. Cache block ALIGNED. +// r.5 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + .set PAGE_SHIFT, 12 + + + LEAF_ENTRY(HalpSweepPhysicalRangeInBothCaches) + +// +// Starting physical address = (PageNumber << PAGE_SHIFT) | Offset +// + + rlwimi r.4, r.3, PAGE_SHIFT, 0xfffff000 + + addi r.5, r.5, 31 // bump length by block size - 1 + srwi r.5, r.5, 5 // get number of blocks + mflr r.0 // save return address + mtctr r.5 // set loop count + +// +// Interrupts MUST be disabled for the duration of this function as +// we use srr0 and srr1 which will be destroyed by any exception or +// interrupt. +// + + DISABLE_INTERRUPTS(r.12,r.11) // r.11 <- disabled MSR + // r.12 <- previous MSR +// +// Find ourselves in memory. This is needed as we must disable +// both instruction and data translation. We do this while +// interrupts are disabled only to try to avoid changing the +// Link Register when an unwind might/could occur. +// +// The HAL is known to be in KSEG0 so its physical address is +// its effective address with the top bit stripped off. +// + + bl hspribc +hspribc: + + mflr r.6 // r.6 <- &hspribc + rlwinm r.6, r.6, 0, 0x7fffffff // r.6 &= 0x7fffffff + addi r.6, r.6, hspribc.real - hspribc + // r.6 = real &hspribc.real + + sync // ensure all previous loads and + // stores are complete. + + mtsrr0 r.6 // address in real space + + rlwinm r.11, r.11, 0, ~0x30 // turn off Data and Instr relocation + mtsrr1 r.11 + rfi // leap to next instruction + +hspribc.real: + mtsrr0 r.0 // set return address + mtsrr1 r.12 // set old MSR value + +hspribc.loop: + dcbst 0, r.4 // flush data block to memory + icbi 0, r.4 // invalidate i-cache + addi r.4, r.4, 32 // point to next block + bdnz hspribc.loop // jif more to do + + sync // ensure all translations complete + isync // don't even *think* about getting + // ahead. + rfi // return to caller and translated + // mode + + DUMMY_EXIT(HalpSweepPhysicalRangeInBothCaches) + +//++ +// +// HalpSweepPhysicalIcacheRange +// +// Invalidate a given PHYSICAL address range from the instruction +// cache. +// +// This implementation assumes a block size of 32 bytes. It +// will still work on the 620. +// +// Arguments: +// +// r.3 Start physical PAGE number. +// r.4 Starting offset within page. Cache block ALIGNED. +// r.5 Length (in bytes) +// +// Return Value: +// +// None. +// +//-- + + + LEAF_ENTRY(HalpSweepPhysicalIcacheRange) + +// +// Starting physical address = (PageNumber << PAGE_SHIFT) | Offset +// + + rlwimi r.4, r.3, PAGE_SHIFT, 0xfffff000 + + addi r.5, r.5, 31 // bump length by block size - 1 + srwi r.5, r.5, 5 // get number of blocks + mflr r.0 // save return address + mtctr r.5 // set loop count + +// +// Interrupts MUST be disabled for the duration of this function as +// we use srr0 and srr1 which will be destroyed by any exception or +// interrupt. +// + + DISABLE_INTERRUPTS(r.12,r.11) // r.11 <- disabled MSR + // r.12 <- previous MSR +// +// Find ourselves in memory. This is needed as we must disable +// both instruction and data translation. We do this while +// interrupts are disabled only to try to avoid changing the +// Link Register when an unwind might/could occur. +// +// The HAL is known to be in KSEG0 so its physical address is +// its effective address with the top bit stripped off. +// + + bl hspir +hspir: + + mflr r.6 // r.6 <- &hspribc + rlwinm r.6, r.6, 0, 0x7fffffff // r.6 &= 0x7fffffff + addi r.6, r.6, hspir.real - hspir + // r.6 = real &hspribc.real + + sync // ensure all previous loads and + // stores are complete. + + mtsrr0 r.6 // address in real space + +// +// N.B. It may not be required that Data Relocation be disabled here. +// I can't tell from my Arch spec if ICBI works on a Data or +// Instruction address. I believe it is probably a Data +// address even though it would be sensible for it to be an +// instruction address,.... +// + + rlwinm r.11, r.11, 0, ~0x30 // turn off Data and Instr relocation + mtsrr1 r.11 + rfi // leap to next instruction + +hspir.real: + mtsrr0 r.0 // set return address + mtsrr1 r.12 // set old MSR value + +hspir.loop: + icbi 0, r.4 // invalidate i-cache + addi r.4, r.4, 32 // point to next block + bdnz hspir.loop // jif more to do + + sync // ensure all translations complete + isync // don't even *think* about getting + // ahead. + rfi // return to caller and translated + // mode + + DUMMY_EXIT(HalpSweepPhysicalIcacheRange) diff --git a/private/ntos/nthals/halfire/ppc/pxcalstl.c b/private/ntos/nthals/halfire/ppc/pxcalstl.c new file mode 100644 index 000000000..bc75249d0 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxcalstl.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxcalstl.c $ + * $Revision: 1.13 $ + * $Date: 1996/01/11 07:09:11 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxcalstl.c + +Abstract: + + + This module implements the calibration of the stall execution HAL + service for a PowerPC system. + + +Author: + + David N. Cutler (davec) 26-Apr-1991 + Jim Wooldridge + Steve Johns (Motorola) + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "fpdebug.h" +#include "halp.h" + +// +// KeQueryPerformanceCounter & KeStallExecutionProcessor are called +// before Phase 0 initialization, so initialize it to a reasonable value. +// +ULONG HalpPerformanceFrequency = 80000000/16; +ULONG CpuFrequency; +ULONG ProcessorBusFrequency; +ULONG HalpGetCycleTime(VOID); +extern ULONG CpuClockMultiplier; +extern ULONG HalpClockCount; +extern ULONG HalpFullTickClockCount; + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpCalibrateTimingValues) + +#endif + + +/*++ + +Routine Description: BOOLEAN HalpCalibrateTimingValues ( VOID ) + + This function calibrates the stall execution HAL service. + + N.B. This routine is only called during phase 1 initialization. + +Arguments: + + None. + +Return Value: + + A value of TRUE is returned if the calibration is successfully + completed. Otherwise a value of FALSE is returned. + +--*/ + +BOOLEAN +HalpCalibrateTimingValues ( + VOID + ) +{ + ULONG TmpCpuHertz; + + // + // Set initial scale factor + // + PCR->StallScaleFactor = 1; + + // + // Compute the clock frequency of the Time Base & Decrementer + // + HalpPerformanceFrequency = HalpCalibrateTB(); + // HalpPerformanceFrequency = (HalpPerformanceFrequency / 1000) * 1000; + + // + // Since the TimeBase ticks once for every four bus clock cycles, multiply + // the HalpPerformanceFrequency by 4. This is the bus speed in Hertz. Now + // apply the cpu chip clock multiplier calculated back in + // HalpInitializeProcessor and perform rounding converting to MegaHertz. + // + ProcessorBusFrequency = (4 * HalpPerformanceFrequency); + + // + // Since the CpuClockMultiplier is really 10 times the true multiplier, + // add one more order of magnitude to the divisor when converting to + // megahertz + // + TmpCpuHertz = (CpuClockMultiplier * ProcessorBusFrequency)/1000000; + CpuFrequency = TmpCpuHertz/10; + + // + // check to see if the sub megahertz residual of the frequency + // calculations are large enough to round up to the next megahertz. + // + if ((TmpCpuHertz - ((TmpCpuHertz/10)*10)) >= 5) { + CpuFrequency++; // round up to the next Megahertz. + } + + // + // Initialize the system clock variable + // + HalpClockCount = + (HalpPerformanceFrequency * (MAXIMUM_INCREMENT/10000)) / 1000; + HalpFullTickClockCount = HalpClockCount; + + return TRUE; +} + +ULONG +HalpGetCycleTime() +{ + HDBG(DBG_TIME, + HalpDebugPrint("HalpGetCycleTime: PerfFreq(%d), ClockCount(%d)\n", + HalpPerformanceFrequency, HalpClockCount);); + return( CpuFrequency ); + +} diff --git a/private/ntos/nthals/halfire/ppc/pxcirrus.h b/private/ntos/nthals/halfire/ppc/pxcirrus.h new file mode 100644 index 000000000..32aee24df --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxcirrus.h @@ -0,0 +1,234 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxcirrus.h $ + * $Revision: 1.2 $ + * $Date: 1996/01/11 07:09:18 $ + * $Locker: $ + */ + +/* + * pxcirrus.h + * + * Defines for cirrus HAL support + */ + +#define CIRRUS_VIDEO_MEMORY_BASE 0xc0000000 +#define CIRRUS_VENDOR_ID 0x1013 +#define CIRRUS_COMMAND_MASK 0x03 + +#define CIRRUS_TEXT_MEM 0xb8000 +#define CIRRUS_FONT_MEM 0xa0000 + + +#define WRITE_CIRRUS_UCHAR(port,data) \ + *(volatile unsigned char *) \ + ((ULONG)HalpIoControlBase+(port))=(UCHAR)(data), \ + KeFlushWriteBuffer() + +#define WRITE_CIRRUS_VRAM(port,data) \ + *((PUCHAR)((ULONG) HalpVideoMemoryBase + (port))) = (UCHAR) (data), \ + KeFlushWriteBuffer() + +#define WRITE_CIRRUS_USHORT(port,data) \ + *(volatile unsigned short*) \ + ((ULONG)HalpIoControlBase+(port))=(USHORT)(data), \ + KeFlushWriteBuffer() + +#define READ_CIRRUS_VRAM(port) \ + *(HalpVideoMemoryBase + (port)) + +#define READ_CIRRUS_UCHAR(port) \ + *(volatile unsigned char *)((ULONG)HalpIoControlBase + (port)) + +#define setreg(port,index,data) \ + WRITE_CIRRUS_UCHAR(port,index), \ + WRITE_CIRRUS_UCHAR(port+1,data) + +#define outportb(port,data) \ + WRITE_CIRRUS_UCHAR(port,data) + +#define outp(port,data) outportb(port,data) + +#define inp(port) \ + READ_CIRRUS_UCHAR(port) + +#define INSTATUS_1 (PVOID) ((ULONG)((int)HalpIoControlBase + (int)0x03DA)) + + + + +// +// Attributes Registers +// + +static unsigned char attr3[] = +{ + 0x00, // AR0-ARF: Attribute Controller + 0x01, // Palette Registers + 0x02, + 0x03, + 0x04, + 0x05, + 0x14, + 0x07, + 0x38, + 0x39, + 0x3a, + 0x3b, + 0x3c, + 0x3d, + 0x3e, + 0x3f, + 0x0c, // AR10: Attribute Controller Mode + // Blink Enable + // Line Graphics Enable + 0x00, // AR11: Overscan (Border) color + 0x0f, // AR12: Color Plane Enable + // All planes enabled + 0x08, // AR13: Pixel Panning + 0x00 // AR14: Color Select +}; + +// +// CRT control +// + +static unsigned char crtc3[] = +{ + 0x5f, // CR0: Horizontal Total + 0x4f, // CR1: Horizontal Display End + 0x50, // CR2: Start Horizontal Blinking + 0x82, // CR3: End Horizontal Blanking + 0x55, // CR4: Start Horizontal Retrace Pulse + 0x81, // CR5: End Horizontal Retrace Pulse + 0xbf, // CR6: Vertical Total + 0x1f, // CR7: Overflow + 0x00, // CR8: Row Scan + 0x4f, // CR9: Character Cell Height (16) + 0x0d, // CRa: Text Cursor Start Register + 0x0e, // CRb: Text Cursor End Register + 0x00, // CRc: Screen Start High + 0x00, // CRd: Screen Start Low + 0x00, // CRe: Text Cursor Location High + 0x00, // CRf: Text Cursor Location Low + 0x9c, // CR10: Vertical Sync Start + 0xae, // CR11: Vertical Sync End + 0x8f, // CR12: Vertical Display End + 0x28, // CR13: Offset + 0x1f, // CR14: Underline Row Scanline + 0x96, // CR15: Vertical Blank Start + 0xb9, // CR16: Vertical Blank End + 0xa3, // CR17: Mode Control + 0xff, // CR18: Line Compare + 0x00, // CR19: Interlace End + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + + +// +// Graphics Registers +// + +static unsigned char graph3[] = +{ + 0x00, // GR0: Set/Reset Register + 0x00, // GR1: Set/Reset Enable Register + 0x00, // GR2: Color Compare + 0x00, // GR3: Data Rotate Register + 0x00, // GR4: Read Map Select Register + 0x10, // GR5: Mode Register (Odd/Even On) + + 0x0e, // GR6: Miscellaneous Register + // Memory Map b800:0 + // Chain Odd Maps to Even + 0x00, // GR7: Color Don't Care register + 0xff // GR8: Bit Mask Register +}; + +// +// Sequencer Registers +// + +static unsigned char seq3[] = +{ + 0x03, // SR0: Reset Register + // Asynchronous and Synchronous reset + 0x00, // SR1: Clocking Mode + 0x03, // SR2: Plane Mask Register + // Map 0 and 1 Enable + 0x00, // SR3: Character Map Select Register + 0x02, // SR4: Memory Mode + // Extended Memory +}; + +// +// Extended Sequencer Registers +// + +static unsigned char eseq3[] = +{ + 0x6,0x12, // SR6: Unlock All Extensions + 0x7,0x00, // SR7: Extended Sequencer Mode + 0x8,0x40, // SR8: EEPROM Control +// tsa 0x8,0x00, // SR8: EEPROM Control + 0xb,0x4a, // SRb: VCLK 0 Numerator Register + 0xc,0x5b, // SRc: VCLK 1 Numerator Register + 0xd,0x42, // SRd: VCLK 2 Numerator Register + 0xe,0x6e, // SRe: VCLK 3 Numerator Register +//tsa x 0xe,0x7e, // SRe: VCLK 3 Numerator Register + 0xf,0x1d, // SRf: DRAM control + 0x12,0x00, // SR12: Cursor Attributes + 0x16,0x71, // SR16: Performance Tuning + 0x18,0x00, // SR18: Signature Generator Control + 0x1b,0x2b, // SR1b: VCLK Denominator and Post-Scalar + 0x1c,0x2f, + 0x1d,0x1f, + 0x1e,0x2a, +//tsa x 0x1e,0x33, + 0x1f,0x1c, + 0xff +}; + +// +// Extended CRTC Registers +// + +static unsigned char ecrtc3[] = +{ + 0x19,0x00, // CR19: Inerlace End + 0x1a,0x00, // CR1a: Miscellaneous + 0x1b,0x00, // CR1b: Extended Display Controlls + 0xff +}; + +// +// Extended Graphics Registers +// + +static unsigned char egraph3[] = +{ + 0x9,0x00, // GR9: Offset Register 0 + 0xa,0x00, // GRa: Offset Register 1 + 0xb,0x00, // GRb: Graphics Controller Mode Extnsions + 0xc,0xff, // GRc: Color Key Compare + 0xd,0x00, // GRd: Color Key Compare Mask + 0x10,0x00, // GR10: Background Color Byte 1 + 0x11,0x00, // GR11: Foreground Color Byte 1 + 0xff +}; + +// +// Extended Attribute Registers +// + +static unsigned char eattr3[] = +{ + 0xff +}; diff --git a/private/ntos/nthals/halfire/ppc/pxclksup.s b/private/ntos/nthals/halfire/ppc/pxclksup.s new file mode 100644 index 000000000..2a3c37e99 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxclksup.s @@ -0,0 +1,163 @@ +/*********************************************************************** + + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + + File Name: + PXCLKSUP.S + + Globals: + none + + Functions: + HalpUpdateDecrementer + KeQueryPerformanceCounter + + History: + 11-Feb-1994 Steve Johns + Original Version + 23-Jun-1994 Steve Johns (sjohns@pets.sps.mot.com) + Fixed HalpZeroPerformanceCounter. Was writing to RTCU & RTCL. + Writes should go to SPR 20 & 21. +***********************************************************************/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxclksup.s $ + * $Revision: 1.7 $ + * $Date: 1996/05/14 02:33:44 $ + * $Locker: $ + */ + +#include +#define ERRATA603 TRUE + + + + + LEAF_ENTRY(HalpUpdateDecrementer) + + + mfpvr r.6 // Read Processor Version Register + rlwinm r.6,r.6,16,16,31 + cmpli 0,0,r.6,1 // Is it an MPC601 ? + bne Not_601 + rlwinm r.3,r.3,7,0,24 // Yes, Count *= 128 +Not_601: +// +// Read the DECREMENTER to get the interrupt latency and bias Count by +// that amount. Otherwise, the latencies would accumulate and the time +// of day would run slow. +// + mfdec r.7 // Read the DECREMENTER + add r.4,r.3,r.7 // + Count +// +// We expect that the DECREMENTER should be near 0xFFFFFFxx, so R4 should +// be less than r.3. If not, we don't want to cause an excessively long +// clock tick, so just ignore the latency and use Count. +// + cmpl 0,0,r.4,r.3 + ble SetDecr + mr r.4,r.3 +SetDecr: + + mtdec r.4 // Write to the DECREMENTER +#if ERRATA603 + isync +#endif + +// Undocumented return value: the latency in servicing this interrupt + neg r.3,r.7 + + + LEAF_EXIT(HalpUpdateDecrementer) + + + + .extern HalpPerformanceFrequency + .extern ..HalpGetTimerRoutine + + +/*********************************************************************** + Synopsis: + ULARGE_INTEGER KeQueryPerformanceCounter ( + OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL) + + Purpose: + Supplies a 64-bit realtime counter for use in evaluating performance + of routines. + + Returns: + This routine returns current 64-bit performance counter and, + optionally, the frequency of the Performance Counter. + + Global Variables Referenced: + HalpPerformanceFrequency + +***********************************************************************/ + +// +// Register Definitions +// + .set RetPtr, r.3 + .set Freq, r.4 + .set TimerLo, r.6 // MUST be same as defined in PXSTALL.S + .set TimerHi, r.7 // MUST be same as defined in PXSTALL.S + .set Temp, r.8 + + .set RTCU, 4 + .set RTCL, 5 + .set TB, 284 + .set TBU, 285 + + + LEAF_ENTRY(KeQueryPerformanceCounter) + + mflr r.0 // Save Link Register + + cmpli 0,0,Freq,0 // Was PerformanceFrequency passed ? + beq GetCpuVersion + + lwz Temp,[toc]HalpPerformanceFrequency(r.toc) + lwz Temp,0(Temp) // PerformanceFrequency.LowPart = + stw Temp,0(Freq) // HalpPerformanceFrequency; + li Temp,0 // PerformanceFrequency.HighPart = 0; + stw Temp,4(Freq) + +GetCpuVersion: + bl ..HalpGetTimerRoutine + + bctrl // ReadPerformanceCounter(); + + stw TimerLo,0(RetPtr) + stw TimerHi,4(RetPtr) + mtlr r.0 // Restore Link Register + + LEAF_EXIT(KeQueryPerformanceCounter) + + + LEAF_ENTRY(HalpZeroPerformanceCounter) + + + mfpvr r.4 // Read Processor Version Register + li r.3, 0 + rlwinm r.4,r.4,16,16,31 + cmpli 0,0,r.4,1 // Are we running on an MPC601 ? + beq ZeroRTC // Branch if yes + + mtspr TB,r.3 + mtspr TBU,r.3 + + blr + +ZeroRTC: + mtspr 20,r.3 // Zero the RTC registers + mtspr 21,r.3 + + + LEAF_EXIT(HalpZeroPerformanceCounter) + + diff --git a/private/ntos/nthals/halfire/ppc/pxclock.c b/private/ntos/nthals/halfire/ppc/pxclock.c new file mode 100644 index 000000000..8d34efa28 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxclock.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxclock.c $ + * $Revision: 1.19 $ + * $Date: 1996/05/14 02:33:49 $ + * $Locker: $ + */ + +/***************************************************************************** + + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + PXCLOCK.C + +Abstract: + + This module contains the system clock interrupt handler. + The DECREMENTER is used to implement the system clock. The + handler resets the DECREMENTER to SYSTEM_TIME (accounting + for interrupt latency), and updates the system time. + + +Author: + + Steve Johns 10-Feb-1994 + +Revision History: + +******************************************************************************/ + +#include "fpdebug.h" +#include "halp.h" +#include "phsystem.h" +#include "fpreg.h" +#include "fpcpu.h" + +extern ULONG HalpPerformanceFrequency; +extern ULONG Irql2Mask[]; +extern ULONG registeredInts[]; + +BOOLEAN KdPollBreakIn (VOID); + +ULONG HalpClockCount; +ULONG HalpFullTickClockCount; +ULONG HalpUpdateDecrementer(); +ULONG HalpCurrentTimeIncrement; +ULONG HalpNextIntervalCount; +ULONG HalpNewTimeIncrement; + +// VOID KeUpdateRunTime(PVOID); + +/*++ +Routine Description: + + Clock interrupt handler for processor 0. + +Arguments: + + Interrupt + + ServiceContext + + TrapFrame + +Return Value: + + TRUE + +--*/ +BOOLEAN +HalpHandleDecrementerInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) +{ + KIRQL OldIrql; + static int recurse = FALSE; + ULONG CpuId; + + HASSERT(!MSR(EE)); + + CpuId = GetCpuId(); + + // + // Raise irql via updating the PCR + // + OldIrql = PCR->CurrentIrql; + PCR->CurrentIrql = CLOCK2_LEVEL; + RInterruptMask(CpuId) = (Irql2Mask[CLOCK2_LEVEL] & registeredInts[CpuId]); + WaitForRInterruptMask(CpuId); + + // + // Reset DECREMENTER, accounting for interrupt latency. + // + HalpUpdateDecrementer(HalpClockCount); + + // + // Call the kernel to update system time + // + KeUpdateSystemTime(TrapFrame,HalpCurrentTimeIncrement); + HalpCurrentTimeIncrement = HalpNewTimeIncrement; + + if (!recurse) { + // + // In some circumstances the KdPollBreakIn can + // take longer than a decrementer interrupt + // to complete. This is do to a conflict + // between DMA and PIO. For now, just avoid + // recursing into the debugger check. + // + recurse = TRUE; + if (KdDebuggerEnabled && KdPollBreakIn()) { + HalpEnableInterrupts(); + DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); + HalpDisableInterrupts(); + } + recurse = FALSE; + } + + // + // Lower Irql to original value and enable interrupts + // + PCR->CurrentIrql = OldIrql; + RInterruptMask(CpuId) = (Irql2Mask[OldIrql] & registeredInts[CpuId]); + WaitForRInterruptMask(CpuId); + return (TRUE); +} + +/*++ + +Routine Description: + + Clock interrupt handler for processors other than 0. + +Arguments: + + Interrupt + + ServiceContext + + TrapFrame + +Return Value: + + TRUE + +--*/ +BOOLEAN +HalpHandleDecrementerInterrupt1( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) +{ + KIRQL OldIrql; + ULONG CpuId; + + HASSERT(!MSR(EE)); + + CpuId = GetCpuId(); + + // + // Raise irql via updating the PCR + // + OldIrql = PCR->CurrentIrql; + PCR->CurrentIrql = CLOCK2_LEVEL; + RInterruptMask(CpuId) = (Irql2Mask[CLOCK2_LEVEL] & registeredInts[CpuId]); + WaitForRInterruptMask(CpuId); + + // + // Reset DECREMENTER (no account for latency) + // + HalpUpdateDecrementer(HalpFullTickClockCount); + + // + // Call the kernel to update run time for this thread and process. + // + KeUpdateRunTime(TrapFrame); + + HDBG(DBG_PROC1DBG, + { + // + // Check for the debugger BreakIn only every minute or so. + // (decrementer is interms of ms so we multiple by 10,000 + // on the order of a minute). + // + static Count = 0; + if (++Count > 10000) { + Count = 0; + if (KdDebuggerEnabled && KdPollBreakIn()) { + HalpEnableInterrupts(); + DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C); + HalpDisableInterrupts(); + } + } + } + ); + + // + // Lower Irql to original value + // + PCR->CurrentIrql = OldIrql; + RInterruptMask(CpuId) = (Irql2Mask[OldIrql] & registeredInts[CpuId]); + WaitForRInterruptMask(CpuId); + + return TRUE; +} + + +/*++ + +Routine Description: + + This function is called to set the clock interrupt rate to the frequency + required by the specified time increment value. + + N.B. This function is only executed on the processor that keeps the + system time. + +Arguments: + + DesiredIncrement - Supplies desired number of 100ns units between clock + interrupts. + +Return Value: + + The actual time increment in 100ns units. + +--*/ + +ULONG +HalSetTimeIncrement ( + IN ULONG DesiredIncrement + ) +{ + + ULONG NewTimeIncrement; + ULONG NextIntervalCount; + KIRQL OldIrql; + + // + // Raise IRQL to the highest level, set the new clock interrupt + // parameters, lower IRQl, and return the new time increment value. + // + + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + // + // HalpPerformanceFrequence is the number of times the decrementer + // ticks in 1 second. MINIMUM_INCREMENT is the number of 100 is the + // number of 100ns units in 1 ms. + // Therefore, DesiredIncrement/MINUMUM_INCREMENT is the number of + // ms desired. This multiplied by the number of decrementer ticks + // in 1 second, divided by 1000 gives the number of ticks in the + // desired number of milliseconds. This value will go into the + // decrementer. + // + + NextIntervalCount = (HalpPerformanceFrequency * + (DesiredIncrement/MINIMUM_INCREMENT)) / 1000; + + // + // Calculate the number of 100ns units to report to the kernel every + // time the decrementer fires with this new period. Note, for small + // values of DesiredIncrement (min being 10000, ie 1ms), truncation + // in the above may result in a small decrement in the 5th decimal + // place. As we are effectively dealing with a 4 digit number, eg + // 10000 becomes 9999.something, we really can't do any better than + // the following. + // + + NewTimeIncrement = DesiredIncrement/MINIMUM_INCREMENT * MINIMUM_INCREMENT; + HalpClockCount = NextIntervalCount; + HalpNewTimeIncrement = NewTimeIncrement; + KeLowerIrql(OldIrql); + return NewTimeIncrement; +} + + diff --git a/private/ntos/nthals/halfire/ppc/pxdat.c b/private/ntos/nthals/halfire/ppc/pxdat.c new file mode 100644 index 000000000..6b220977a --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxdat.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxdat.c $ + * $Revision: 1.9 $ + * $Date: 1996/05/14 02:33:54 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pxdat.c + +Abstract: + + Declares various data which is initialize data, or pagable data. + +Author: + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge Ported to PowerPC + +--*/ + +#include "halp.h" + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg("INIT") +#endif + +// +// The following data is only valid during system initialiation +// and the memory will be re-claimed by the system afterwards +// + +ADDRESS_USAGE HalpDefaultIoSpace = { + NULL, CmResourceTypePort, InternalUsage, + { + 0x000, 0x10, // SIO DMA + 0x0C0, 0x20, // SIO DMA + 0x080, 0x10, // SIO DMA + 0x400, 0x40, // SIO DMA + 0x480, 0x10, // SIO DMA + 0x4D6, 0x2, // SIO DMA + + 0x020, 0x2, // PIC + 0x0A0, 0x2, // Cascaded PIC + + 0x040, 0x4, // Timer1, Referesh, Speaker, Control Word + + 0x061, 0x1, // NMI (system control port B) + 0x092, 0x1, // system control port A + + 0x070, 0x2, // Cmos/NMI enable + + 0x074, 0x4, // NVRAM + + 0x0F0, 0x10, // coprocessor ports + 0,0 + } +}; + + +// +// From usage.c +// + +ADDRESS_USAGE *HalpAddressUsageList = 0; + +// +// Misc hal stuff in the registry +// + +WCHAR rgzHALentry[] = L"\\Registry\\Machine\\Hardware\\ResourceMap\\Hardware Abstraction Layer\\Powerized HAL"; + + +// +// From ixpcibus.c +// + +WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter"; +WCHAR rgzSystem[] = L"\\Registry\\Machine\\Hardware\\Description\\System"; +WCHAR rgzSoftwareDescriptor[] = L"\\Registry\\Machine\\Software"; +WCHAR rgzFirePOWERNode[] = L"\\Registry\\Machine\\Software\\FirePOWER"; +WCHAR rgzConfigurationData[] = L"Configuration Data"; +WCHAR rgzIdentifier[] = L"Identifier"; +WCHAR rgzPCIIndetifier[] = L"PCI"; +WCHAR rgzCpuNode[] = L"Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor"; +WCHAR rgzHalNode[] = L"\\HardwareAbstractionLayer"; +WCHAR rgzVeneerNode[] = L"\\Veneer"; +WCHAR rgzFirmwareNode[] = L"\\OpenFIRMWARE"; + + + +#ifdef ALLOC_DATA_PRAGMA +#pragma data_seg() +#endif + +// +// IDT vector usage info +// + +IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR]; diff --git a/private/ntos/nthals/halfire/ppc/pxdisp.c b/private/ntos/nthals/halfire/ppc/pxdisp.c new file mode 100644 index 000000000..aa06f64db --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxdisp.c @@ -0,0 +1,2907 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxdisp.c $ + * $Revision: 1.44 $ + * $Date: 1996/07/02 04:58:11 $ + * $Locker: $ + */ + +/*++ + + Copyright (c) 1994 International Business Machines Corporation + + Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + + Module Name: + + pxdisp.c + + Abstract: + + This module implements the HAL display initialization and output routines + for a Sandalfoot PowerPC system using either an S3 or Weitek P9000 + video adapter. + + Author: + + Jim Wooldridge Sept 1994 - Ported to PowerPC Initial Version + + Environment: + + Kernel mode + + Revision History: + + Jess Botts S3 support in text mode Oct-1993 + Lee Nolan Added Weitek P9000 support Feb-1994 + Mike Haskell Added Weitek P9100 support Oct-1994 + Roger Lanser 02-23-95: Added FirePower Video and INT10, nuc'd others + + --*/ + +#include "halp.h" +#include "pxs3.h" // BUGBUG: generic output? +#include "string.h" +#include "fpbat.h" +#include "arccodes.h" +#include "phsystem.h" +#include "pxmemctl.h" +#include "fpdcc.h" +#include "fpcpu.h" +#include "fpdebug.h" +#include "phsystem.h" +#include "x86bios.h" +#include "pxpcisup.h" +#include "pxcirrus.h" + +#define MAX_DBATS 4 + +// for test only +NTSYSAPI +NTSTATUS +NTAPI +RtlCharToInteger ( + PCSZ String, + ULONG Base, + PULONG Value + ); + +//============================================================================= +// +// IBMBJB added include to get text mode values for the Brooktree 485 DAC's +// palette registers, removed definition of HDAL and added address +// definitions for PowerPC + +#include "txtpalet.h" +#include "pci.h" + +// PCI Vendor ID & Device ID +#define PCI_VENDOR_ID_WEITEK 0x100e +#define PCI_DEVICE_ID_WEITEK_P9000 0x9001 +#define PCI_DEVICE_ID_WEITEK_P9100 0x9100 +#define PCI_VENDOR_ID_S3 0x5333 +#define PCI_DEVICE_ID_S3_864_1 0x88c0 +#define PCI_DEVICE_ID_S3_864_2 0x88c1 + +#if defined(_PPC_) + +#define MEMORY_PHYSICAL_BASE VIDEO_MEMORY_BASE +#define CONTROL_PHYSICAL_BASE VIDEO_CONTROL_BASE + +#endif + +#define ROWS 25 +#define COLS 80 +#define TAB_SIZE 4 +#define ONE_LINE (80*2) +#define TWENTY_FOUR_LINES 24*ONE_LINE +#define TWENTY_FIVE_LINES 25*ONE_LINE +#define TEXT_ATTR 0x1F + +//PHYSICAL ADDRESS of WEITEK P9100 video ram +#define P91_VIDEO_MEMORY_BASE 0xC1800000 +//PHYSICAL ADDRESS of S3 video ram +#define S3_VIDEO_MEMORY_BASE 0xC0000000 + +#if DBG +extern VOID HalpDisplayBatForVRAM ( void ); +# define TRACE Trace +#else +# define TRACE +#endif + +BOOLEAN +HalpInitializeX86DisplayAdapter( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ); + +// +// Define forward referenced procedure prototypes. +// +BOOLEAN HalpDisplayINT10Setup (VOID); +VOID HalpOutputCharacterINT10 (IN UCHAR Character ); +VOID HalpScrollINT10 (IN UCHAR line); +VOID HalpDisplayCharacterVGA (IN UCHAR Character ); +VOID HalpDisplayCharacterVgaViaBios (IN UCHAR Character); +VOID HalpOutputCharacterVgaViaBios (IN UCHAR AsciiChar); +BOOLEAN HalpDisplaySetupVgaViaBios (VOID); + + +BOOLEAN HalpDisplayPowerizedGrapicsSetup (ULONG); +BOOLEAN HalpDisplayPowerizedGraphicsSetup (VOID); +VOID HalpDisplayCharacterPowerizedGraphics (IN UCHAR Character); +VOID HalpOutputCharacterPowerizedGraphics (IN PUCHAR Glyph); +BOOLEAN HalpInitializeDisplay (IN PLOADER_PARAMETER_BLOCK LoaderBlock); + + +VOID HalpOutputCharacterS3 (IN UCHAR AsciiChar); +BOOLEAN HalpDisplayPpcS3Setup (VOID); +VOID HalpScrollS3(IN UCHAR line); +BOOLEAN HalpDisplayPpcP91Setup (VOID); +VOID HalpDisplayCharacterP91 (IN UCHAR Character); +VOID HalpOutputCharacterP91(IN PUCHAR Glyph); +BOOLEAN HalpDisplayPpcP91BlankScreen (VOID); +VOID HalpDisplayCharacterCirrus(IN UCHAR Character); +VOID HalpOutputCharacterCirrus(IN UCHAR AsciiChar); +BOOLEAN HalpDisplayPpcCirrusSetup(VOID); +VOID HalpScrollCirrus(IN UCHAR line); + +static void updattr(IN int rg,IN unsigned char val); +static void set_ext_regs(IN int reg,IN unsigned char *p); +static void clear_text(VOID); +static void load8x16(VOID); +static void load_ramdac(); + + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(INIT, HalpInitializeDisplay) +#pragma alloc_text(INIT, HalpInitializeVRAM) +#if DBG +#pragma alloc_text(INIT, HalpDisplayBatForVRAM) +#endif +#endif + +#if !defined(NT_UP) +ULONG HalpDisplayLock; +#endif // !defined(NT_UP) + + +typedef VOID (*PHALP_SCROLL_SCREEN) (UCHAR); +typedef VOID (*PHALP_OUTPUT_CHARACTER) (UCHAR); +typedef BOOLEAN (*PHALP_CONTROLLER_SETUP) (VOID); +typedef VOID (*PHALP_DISPLAY_CHARACTER) (UCHAR); + +// +// Define global data. +// +ULONG HalpVideoMemorySize = (ULONG)DISPLAY_MEMORY_SIZE; +PUCHAR HalpVideoMemoryBase = (PUCHAR)NULL; + +// +// Define static data. +// + +static ULONG PowerizedGraphicsDisplayMode = 0; // default 640x480 +static PVOID HalpVideoConfigBase = NULL; +static BOOLEAN HalpDisplayOwnedByHal = FALSE; // make sure is false: [breeze:1/27/95] +static PHALP_CONTROLLER_SETUP HalpDisplayControllerSetup = NULL; +static PHALP_DISPLAY_CHARACTER HalpDisplayCharacter = NULL; +static PHALP_OUTPUT_CHARACTER HalpOutputCharacter = NULL; +static PHALP_SCROLL_SCREEN HalpScrollScreen = NULL; + +// +// Define OEM font variables. +// + +USHORT HalpBytesPerRow; +USHORT HalpCharacterHeight; +USHORT HalpCharacterWidth; +ULONG HalpDisplayText; +ULONG HalpDisplayWidth; +ULONG HalpScrollLength; +ULONG HalpScrollLine; + +// +// Define display variables. +// +ULONG HalpColumn; +ULONG HalpRow; +USHORT HalpHorizontalResolution; +USHORT HalpVerticalResolution; +USHORT HalpScreenStart = 0; // for cirrus + +BOOLEAN HalpDisplayTypeUnknown = FALSE; + +POEM_FONT_FILE_HEADER HalpFontHeader; + +extern ULONG HalpEnableInt10Calls; +#define PCI_DISPLAY_CONTROLLER 0x03 +#define PCI_PRE_REV_2 0x0 +#define DISPLAY_CLASS 0x03 + +/*----------------------------------------------------------------------------*/ +#if DBG +static VOID +Trace(PCHAR Format, ...) + +{ + va_list arglist; + UCHAR Buffer[256]; + ULONG Length; + if (HalpDebugValue & DBG_DISPLAY) { + va_start(arglist, Format); + Length = vsprintf(Buffer, Format, arglist); + DbgPrint(Buffer); + } +} +#endif +/*----------------------------------------------------------------------------*/ +#define SEQ_CLKMODE_INDEX 0x01 +#define SEQ_MISC_INDEX 0x11 +#define SEQ_OUTPUT_CTL_INDEX 0x12 /* Vendor specific */ + +VOID ScreenOn(VOID) +{ + UCHAR DataByte; + + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + WRITE_S3_UCHAR(Seq_Index, CLOCKING_MODE); + DataByte = READ_S3_UCHAR(Seq_Data); + DataByte = DataByte & 0xdf; + WRITE_S3_UCHAR(Seq_Data, DataByte); + + WRITE_S3_UCHAR(Seq_Index, RESET); // reset to normal operation ! + WRITE_S3_UCHAR(Seq_Data, 0x03); + + return; +} + +VOID ScreenOff(VOID) +{ + UCHAR DataByte; + + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + WRITE_S3_UCHAR(Seq_Index, CLOCKING_MODE); + DataByte = READ_S3_UCHAR(Seq_Data); + DataByte = DataByte | 0x20; + WRITE_S3_UCHAR(Seq_Data, DataByte); + + WRITE_S3_UCHAR(Seq_Index, RESET); // reset to normal operation ! + WRITE_S3_UCHAR(Seq_Data, 0x03); + + return; +} + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define CRYSTAL_FREQUENCY (14318180 * 2) +#define MIN_VCO_FREQUENCY 50000000 +#define MAX_NUMERATOR 130 +#define MAX_DENOMINATOR MIN(129, CRYSTAL_FREQUENCY / 400000) +#define MIN_DENOMINATOR MAX(3, CRYSTAL_FREQUENCY / 2000000) + +#define CLOCK(x) WRITE_S3_UCHAR(MiscOutW, (UCHAR)(iotemp | (x))) +#define C_DATA 0x0c +#define C_CLK 0x04 +#define C_BOTH 0x08 +#define C_NONE 0x00 + +long vclk_range[16] = { + 0, // should be MIN_VCO_FREQUENCY, but that causes problems. + 51000000, + 53200000, + 58500000, + 60700000, + 64400000, + 66800000, + 73500000, + 75600000, + 80900000, + 83200000, + 91500000, + 100000000, + 120000000, + 285000000, + 0, +}; +/****************************************************************************** + * Number theoretic function - GCD (Greatest Common Divisor) + *****************************************************************************/ +static long gcd(a, b) +register long a, b; +{ + register long c = a % b; + while (c) + a = b, b = c, c = a % b; + return b; +} +/**************************************************************************** + * calc_clock + * + * Usage: clock frequency [set] + * frequency is specified in MHz + * + ***************************************************************************/ +static long calc_clock(frequency, select) + +register long frequency; /* in Hz */ +int select; +{ + register long index; + long temp; + long min_m, min_n, min_diff; + long diff; + + int clock_m; + int clock_n; + int clock_p; + + min_diff = 0xFFFFFFF; + min_n = 1; + min_m = 1; + + /* Calculate 18 bit clock value */ + + clock_p = 0; + if (frequency < MIN_VCO_FREQUENCY) + clock_p = 1; + if (frequency < MIN_VCO_FREQUENCY / 2) + clock_p = 2; + if (frequency < MIN_VCO_FREQUENCY / 4) + clock_p = 3; + + frequency <<= clock_p; + + for (clock_n = 4; clock_n <= MAX_NUMERATOR; clock_n++) + { + index = CRYSTAL_FREQUENCY / (frequency / clock_n); + + if (index > MAX_DENOMINATOR) + index = MAX_DENOMINATOR; + if (index < MIN_DENOMINATOR) + index = MIN_DENOMINATOR; + + for (clock_m = index - 3; clock_m < index + 4; clock_m++) + if (clock_m >= MIN_DENOMINATOR && clock_m <= MAX_DENOMINATOR) + { + diff = (CRYSTAL_FREQUENCY / clock_m) * clock_n - frequency; + + if (diff < 0) + diff = -diff; + + if (min_m * gcd(clock_m, clock_n) / gcd(min_m, min_n) == clock_m && + min_n * gcd(clock_m, clock_n) / gcd(min_m, min_n) == clock_n) + + if (diff > min_diff) + diff = min_diff; + + if (diff <= min_diff) + { + min_diff = diff; + min_m = clock_m; + min_n = clock_n; + } + } + } + + clock_m = min_m; + clock_n = min_n; + + /* Calculate the index */ + + temp = (((CRYSTAL_FREQUENCY / 2) * clock_n) / clock_m) << 1; + for (index = 0; vclk_range[index + 1] < temp && index < 15; index++) + ; + + /* Pack the clock value for the frequency snthesizer */ + + temp = (((long)clock_n - 3) << 11) + ((clock_m - 2) << 1) + + (clock_p << 8) + (index << 18) + ((long)select << 22); + + return temp; + +} +static VOID SetICD2061AClock(LONG clock_value) /* 7bits M, 7bits N, 2bits P */ +{ + register long index; + register char iotemp; + int select; + + select = (clock_value >> 22) & 3; + + /* Shut off screen */ + ScreenOff(); + + iotemp = READ_S3_UCHAR(MiscOutR); + + /* Program the IC Designs 2061A frequency generator */ + + CLOCK(C_NONE); + + /* Unlock sequence */ + + CLOCK(C_DATA); + for (index = 0; index < 6; index++) + { + CLOCK(C_BOTH); + CLOCK(C_DATA); + } + CLOCK(C_NONE); + CLOCK(C_CLK); + CLOCK(C_NONE); + CLOCK(C_CLK); + + /* Program the 24 bit value into REG0 */ + + for (index = 0; index < 24; index++) + { + /* Clock in the next bit */ + clock_value >>= 1; + if (clock_value & 1) + { + CLOCK(C_CLK); + CLOCK(C_NONE); + CLOCK(C_DATA); + CLOCK(C_BOTH); + } + else + { + CLOCK(C_BOTH); + CLOCK(C_DATA); + CLOCK(C_NONE); + CLOCK(C_CLK); + } + } + + CLOCK(C_BOTH); + CLOCK(C_DATA); + CLOCK(C_BOTH); + + /* If necessary, reprogram other ICD2061A registers to defaults */ + + /* Select the CLOCK in the frequency synthesizer */ + + TRACE("select=%d\n", select); + CLOCK(C_NONE | select); + + /* Turn screen back on */ + ScreenOn(); +} + +static VOID EnableMemoryAndIO(PCI_CONFIG configBase) +{ + USHORT Cmd; + // Enable Memory & I/O spaces in command register. Firmware does not always set this. + Cmd = READ_REGISTER_USHORT(&configBase->Command); + //TRACE("Cmd=0x%x->", Cmd); + Cmd = Cmd | 3; + //TRACE("0x%x\n", Cmd); + WRITE_REGISTER_USHORT(&configBase->Command, Cmd); +} + +static VOID MakeP9100VGA(PVOID pConfigBase) +{ + UCHAR DataByte; + + //TRACE("MakeP9100VGA: starting\n"); + /* Disable the P9000 and enable VGA.*/ + /* unlocking the 5186/5286 registers */ + WRITE_S3_UCHAR(Seq_Index, SEQ_MISC_INDEX); + DataByte = READ_S3_UCHAR(Seq_Data); /* Read misc register */ + WRITE_S3_UCHAR(Seq_Data, DataByte); + WRITE_S3_UCHAR(Seq_Data, DataByte); /* Write back twice */ + DataByte = READ_S3_UCHAR(Seq_Data); /* Read misc register again */ + WRITE_S3_UCHAR(Seq_Data, DataByte & ~0x20); /* Clear bit 5 */ + + DataByte = READ_REGISTER_UCHAR(((PCHAR)pConfigBase)+65); + TRACE("HalpVideoConfigBase+65 DataByte=0x%02x->", DataByte); + DataByte = DataByte | 0x0e; // bit 1 VGA emulation + DataByte = 0xe2; + WRITE_REGISTER_UCHAR(((PCHAR)pConfigBase)+65, DataByte); // this makes display blank + DataByte = READ_REGISTER_UCHAR(((PCHAR)pConfigBase)+65); + TRACE("0x%02x\n", DataByte); + + { + ULONG ul; + ULONG clock_numbers; + + ul = 25175000; + clock_numbers = calc_clock(ul, 2); + SetICD2061AClock(clock_numbers); + } +} + +static BOOLEAN +WorkAroundBeforeInitBIOS() +{ + USHORT vendorID = 0; + USHORT deviceID = 0; + UCHAR revisionID = 0; + UCHAR Class; + UCHAR SubClass; + int i; + BOOLEAN Found = FALSE; + + for (i = 1 /* skip SIO */; ((i < MAXIMUM_PCI_SLOTS) && (Found == FALSE)); i++) { + HalpVideoConfigBase = (PVOID) ((ULONG) HalpPciConfigBase + HalpPciConfigSlot[i]); + + Class = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->ClassCode[2]); + SubClass = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->ClassCode[1]); + if ((Class == DISPLAY_CLASS && (SubClass == 0)) || + (Class == 0x00 && SubClass == 0x01)) { // pre-rev 2.0 display card + + vendorID = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->VendorID); + deviceID = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->DeviceID); + revisionID = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->RevisionID); + TRACE("vendorID=0x%04x deviceID=0x%04x revisionID=0x%02x\n", vendorID, deviceID, revisionID); + + if ((vendorID == PCI_VENDOR_ID_WEITEK) && (deviceID == PCI_DEVICE_ID_WEITEK_P9100)) { //viper Pro + EnableMemoryAndIO(HalpVideoConfigBase); + MakeP9100VGA(HalpVideoConfigBase); // let BIOS initialize chip + } + } + } + return Found; +} + +/* firmware gives 'VGA' even when S3 card is in. */ +static BOOLEAN +WorkAroundAfterInitBIOS() +{ + USHORT vendorID = 0; + USHORT deviceID = 0; + UCHAR revisionID = 0; + UCHAR Class; + UCHAR SubClass; + int i; + BOOLEAN Found = FALSE; + + TRACE("WorkAroundAfterInitBIOS starting.\n"); + + for (i = 1; ((i < MAXIMUM_PCI_SLOTS) && (Found == FALSE)); i++) { + HalpVideoConfigBase = (PVOID) ((ULONG) HalpPciConfigBase + HalpPciConfigSlot[i]); + + Class = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->ClassCode[2]); + SubClass = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->ClassCode[1]); + TRACE("ClassID=0x%02x SubClass=0x%02x\n", Class, SubClass); + + if ((Class == DISPLAY_CLASS && (SubClass == 0)) || + (Class == 0x00 && SubClass == 0x01)) { // pre-rev 2.0 display card + + vendorID = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->VendorID); + deviceID = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->DeviceID); + revisionID = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->RevisionID); + TRACE("vendorID=0x%04x deviceID=0x%04x revisionID=0x%02x\n", vendorID, deviceID, revisionID); + + if (vendorID == PCI_VENDOR_ID_S3) { + EnableMemoryAndIO(HalpVideoConfigBase); + HalpDisplayControllerSetup = HalpDisplayPpcS3Setup; + HalpDisplayCharacter = HalpDisplayCharacterVGA; + HalpOutputCharacter = HalpOutputCharacterS3; + HalpScrollScreen = HalpScrollS3; + Found = TRUE; + } + } + } + return Found; +} + +/*++ + + Routine Description: BOOLEAN HalpInitializeDisplay () + + This routine maps the video memory and control registers into the user + part of the idle process address space, initializes the video control + registers, and clears the video screen. + + Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + + --*/ + +BOOLEAN +HalpInitializeDisplay ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + ULONG MatchKey; + BOOLEAN Found = FALSE; + CHAR buf[BUFSIZ]; + BOOLEAN bUseVGA = TRUE; // TRUE: scan SVGA cards. FALSE: ignore SVGA cards. + + //IBMLAN Use font file from OS Loader + // + // For the Weitek P9000, set the address of the font file header. + // Display variables are computed later in HalpDisplayPpcP9Setup. + // + HalpFontHeader = (POEM_FONT_FILE_HEADER)LoaderBlock->OemFontFile; + + // + // Read the Registry entry to find out which video adapter the system + // is configured for. This code depends on the OSLoader to put the + // correct value in the Registry. + // + MatchKey = 0; + ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + ControllerClass, + DisplayController, + &MatchKey); + + if (NULL == ConfigurationEntry) { + TRACE("ConfigurationEntry is NULL.\n"); + return FALSE; + } + + if (HalGetEnvironmentVariable("DISPLAY", sizeof(buf), buf) == ESUCCESS) { + TRACE("DISPLAY='%s'\n", buf); + bUseVGA = FALSE; + } + TRACE("HalpInitializeDisplay: ConfigurationEntry->ComponentEntry.Identifier='%s'\n", ConfigurationEntry->ComponentEntry.Identifier); + + while ((TRUE == bUseVGA) && (FALSE == Found)) { + Found = WorkAroundBeforeInitBIOS(); + if (TRUE == Found) break; + + // + // Don't look for a PCI video adapter if the environment + // variable "DISPLAY" is defined. + // + if (HalpPciConfigBase) { + TRACE("HalpIoMemoryBase = 0x%08x\n", HalpIoMemoryBase); + TRACE("HalpPciConfigBase = 0x%08x\n", HalpPciConfigBase); + TRACE("HalpIoControlBase = 0x%08x\n", HalpIoControlBase); + + if (HalpInitializeX86DisplayAdapter(LoaderBlock)) { + TRACE("HalpInitializeX86DisplayAdapter() succeeded.\n"); + HalpDisplayControllerSetup = HalpDisplayINT10Setup; + HalpDisplayCharacter = HalpDisplayCharacterVGA; + HalpOutputCharacter = HalpOutputCharacterINT10; + HalpScrollScreen = HalpScrollINT10; + Found = TRUE; + } else { + TRACE("HalpInitializeX86DisplayAdapter() failed.\n"); + } + } + if (TRUE == Found) break; + + Found = WorkAroundAfterInitBIOS(); + if (TRUE == Found) break; + + if (!_stricmp(ConfigurationEntry->ComponentEntry.Identifier,"P9100")) { + HalpDisplayControllerSetup = HalpDisplayPpcP91Setup; + HalpDisplayCharacter = HalpDisplayCharacterP91; + Found = TRUE; + } else if (!_stricmp(ConfigurationEntry->ComponentEntry.Identifier,"S3")) { + HalpDisplayControllerSetup = HalpDisplayPpcS3Setup; + HalpDisplayCharacter = HalpDisplayCharacterVGA; + HalpOutputCharacter = HalpOutputCharacterS3; + HalpScrollScreen = HalpScrollS3; + Found = TRUE; + } else { + // Unsupported VGA display identifier or probably Powerized Graphics. + bUseVGA = FALSE; + } + } /* while */ + + while (FALSE == Found) { + if (!strcmp(ConfigurationEntry->ComponentEntry.Identifier,"Powerized Graphics")) { + HalpDisplayControllerSetup = HalpDisplayPowerizedGraphicsSetup; + HalpDisplayCharacter = HalpDisplayCharacterPowerizedGraphics; + // + // Set mode 15 which is 1024x768 60 Hz + // + PowerizedGraphicsDisplayMode = 15; + if (HalGetEnvironmentVariable("DISPLAY", sizeof(buf), buf) == ESUCCESS) { + if (!_stricmp(buf, "VGA")) { + // + // Just in case someone wants mode 0 (VGA) + // + PowerizedGraphicsDisplayMode = 0; + } + } + Found = TRUE; + } else if (!_stricmp(ConfigurationEntry->ComponentEntry.Identifier,"VGA")) { + // + // This is where the INT10 could go if the firmware were + // to be trusted. + // Just put the framebuffer in VGA mode for now. + // + HalpDisplayControllerSetup = HalpDisplayPowerizedGraphicsSetup; + HalpDisplayCharacter = HalpDisplayCharacterPowerizedGraphics; + // + // Set mode 0 which is 640x480 60 Hz + // + PowerizedGraphicsDisplayMode = 0; + Found = TRUE; + } else { + HalDisplayString("can't happen\n"); + return FALSE; + } + } + //===========end=IBMLAN=============================================== + + // + // Initialize the display controller. + // + + if (HalpDisplayControllerSetup != NULL) { + return HalpDisplayControllerSetup(); + } + + return FALSE; +} + + +/*++ + + Routine Description: VOID HalAcquireDisplayOwnership () + + This routine switches ownership of the display away from the HAL to + the system display driver. It is called when the system has reached + a point during bootstrap where it is self supporting and can output + its own messages. Once ownership has passed to the system display + driver any attempts to output messages using HalDisplayString must + result in ownership of the display reverting to the HAL and the + display hardware reinitialized for use by the HAL. + + Arguments: + + None. + + Return Value: + + None. + + --*/ + +VOID +HalAcquireDisplayOwnership ( + IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters + ) +{ + + // + // Set HAL ownership of the display to false. + // + + HalpDisplayOwnedByHal = FALSE; + return; +} + + + +/*++ + + Routine Description: VOID HalDisplayString () + + This routine displays a character string on the display screen. + + Arguments: + + String - Supplies a pointer to the characters that are to be displayed. + + Return Value: + + None. + + --*/ + +VOID +HalDisplayString ( + PUCHAR String + ) +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level, flush the TB, and map the display + // frame buffer into the address space of the current process. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + KiAcquireSpinLock(&HalpDisplayAdapterLock); + + // + // If ownership of the display has been switched to the system display + // driver, then reinitialize the display controller and revert ownership + // to the HAL. + // + + if (HalpDisplayControllerSetup != NULL) { + + if (HalpDisplayOwnedByHal == FALSE) { + HalpDisplayControllerSetup(); + } + + // + // Display characters until a null byte is encountered. + // + + while (*String != 0) { + HalpDisplayCharacter(*String++); + } + } + + KiReleaseSpinLock(&HalpDisplayAdapterLock); + + // + // Restore the previous mapping for the current process, flush the TB, + // and lower IRQL to its previous level. + // + KeLowerIrql(OldIrql); + return; + +} /* end of HalpDisplayString() */ + + +/*++ + + Routine Description: VOID HalQueryDisplayParameters () + + This routine return information about the display area and current + cursor position. + + Arguments: + + WidthInCharacter - Supplies a pointer to a varible that receives + the width of the display area in characters. + + HeightInLines - Supplies a pointer to a variable that receives the + height of the display area in lines. + + CursorColumn - Supplies a pointer to a variable that receives the + current display column position. + + CursorRow - Supplies a pointer to a variable that receives the + current display row position. + + Return Value: + + None. + + --*/ + +VOID +HalQueryDisplayParameters ( + OUT PULONG WidthInCharacters, + OUT PULONG HeightInLines, + OUT PULONG CursorColumn, + OUT PULONG CursorRow + ) +{ + + // + // Set the display parameter values and return. + // + KiAcquireSpinLock(&HalpDisplayAdapterLock); + + *WidthInCharacters = HalpDisplayWidth; //IBMLAN + *HeightInLines = HalpDisplayText; + *CursorColumn = HalpColumn; + *CursorRow = HalpRow; + + KiReleaseSpinLock(&HalpDisplayAdapterLock); + return; +} + + +/*++ + + Routine Description: VOID HalSetDisplayParameters () + + This routine set the current cursor position on the display area. + + Arguments: + + CursorColumn - Supplies the new display column position. + CursorRow - Supplies a the new display row position. + + Return Value: + + None. + + --*/ + +VOID +HalSetDisplayParameters ( + IN ULONG CursorColumn, + IN ULONG CursorRow + ) +{ + + // + // Set the display parameter values and return. + // + KiAcquireSpinLock(&HalpDisplayAdapterLock); + + if (CursorColumn > HalpDisplayWidth) { //IBMLAN + CursorColumn = HalpDisplayWidth; //IBMLAN + } + + if (CursorRow > HalpDisplayText) { + CursorRow = HalpDisplayText; + } + + HalpColumn = CursorColumn; + HalpRow = CursorRow; + KiReleaseSpinLock(&HalpDisplayAdapterLock); + return; +} + +/*++ + + Routine Description: BOOLEAN HalpDisplaySetupVgaViaBios () + + This routine initializes a vga controller via bios reset. + Arguments: + None. + Return Value: + None. + + --*/ + +BOOLEAN +HalpDisplaySetupVgaViaBios ( + VOID + ) +{ + // + // Routine Description: + // + // + + ULONG DataLong; + + HalpResetX86DisplayAdapter(); + + // + // Set screen into blue + // + + for (DataLong = 0xB8000; DataLong < 0xB8FA0; DataLong += 2) { + WRITE_S3_VRAM(DataLong, 0x20); + WRITE_S3_VRAM(DataLong+1, 0x1F); + } + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayWidth = 80; + HalpDisplayText = 25; + HalpScrollLine = 160; + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + + HalpDisplayOwnedByHal = TRUE; + + return TRUE; +} + +VOID +WaitForVSync (VOID) +{ + UCHAR DataByte; + BOOLEAN test; + + // + // Determine 3Dx or 3Bx + // + + DataByte = READ_S3_UCHAR(MiscOutR); + ColorMonitor = DataByte & 0x01 ? TRUE : FALSE; + + // Unlock S3 ( S3R8 ) + // UnLockS3(); + + // + // Test Chip ID = '81h' ? + // + + // For standard VGA text mode this action is not necessary. + // WRITE_S3_UCHAR(S3_3D4_Index, S3R0); + // if ((DataByte = READ_S3_UCHAR(S3_3D5_Data)) == 0x81) { + // + // Wait For Verttical Retrace + // + + test = TRUE; + while (test) { + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + + test = READ_S3_UCHAR(Stat1_In) & 0x08 ? FALSE : TRUE; + } + + // Wait for H/V blanking + test = TRUE; + while (test) { + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + READ_S3_UCHAR(Stat1_In); + + test = READ_S3_UCHAR(Stat1_In) & 0x01 ? TRUE : FALSE; + } + // } + + // Lock S3 ( S3R8 ) + // LockS3(); + + return; +} /* end of WaitForVsync() */ + +VOID +Scroll_Screen(IN UCHAR line) +{ + UCHAR i, DataByte; + ULONG target; + + for (i = 0; i < line; i ++) { + //======================================================================= + // + // IBMBJB added wait for vertical sync to make scroll smooth + + WaitForVSync(); + + //======================================================================= + + for (target = 0xB8000; target < 0xB8F00; target += 2) { + DataByte = READ_S3_VRAM(target+0xA0); + WRITE_S3_VRAM(target, DataByte); + } + for (target = 0xB8F00; target < 0xB8FA0; target += 2) { + WRITE_S3_VRAM(target, 0x20 ); + } + } +} + + +/*++ + Routine Description: VOID HalpDisplayCharacterVgaViaBios () + + This routine displays a character at the current x and y positions in + the frame buffer. If a newline is encounter, then the frame buffer is + scrolled. If characters extend below the end of line, then they are not + displayed. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ + +VOID +HalpDisplayCharacterVgaViaBios ( + IN UCHAR Character + ) +{ + + // + // If the character is a newline, then scroll the screen up, blank the + // bottom line, and reset the x position. + // + + if (Character == '\n') { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + } else { // need to scroll up the screen + Scroll_Screen(1); + } + } + + //========================================================================= + // + // IBMBJB added tab processing + // + + else if( Character == '\t' ) // tab? + { + HalpColumn += TAB_SIZE; + HalpColumn = (HalpColumn / TAB_SIZE) * TAB_SIZE; + + if( HalpColumn >= 80 ) // tab beyond end of screen? + { + HalpColumn = 0; // next tab stop is 1st column of next line + + if( HalpRow >= (HalpDisplayText - 1) ) + Scroll_Screen( 1 ); // scroll the screen up + else + ++HalpRow; + } + } + + //========================================================================= + + else if (Character == '\r') { + HalpColumn = 0; + } else if (Character == 0x7f) { /* DEL character */ + if (HalpColumn != 0) { + HalpColumn -= 1; + HalpOutputCharacterVgaViaBios(0); + HalpColumn -= 1; + } else /* do nothing */ + ; + } else if (Character >= 0x20) { + // Auto wrap for 80 columns per line + if (HalpColumn >= 80) { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + } else { // need to scroll up the screen + Scroll_Screen(1); + } + } + HalpOutputCharacterVgaViaBios(Character); + } else /* skip the nonprintable character */ + ; + + return; + +} + +/*++ + + Routine Description: VOID HalpOutputCharacterVgaViaBios () + + This routine insert a set of pixels into the display at the current x + cursor position. If the x cursor position is at the end of the line, + then no pixels are inserted in the display. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ + +VOID +HalpOutputCharacterVgaViaBios ( + IN UCHAR AsciiChar + ) +{ + ULONG I; + + // + // If the current x cursor position is within the current line, then insert + // the specified pixels into the last line of the text area and update the + // x cursor position. + // + if (HalpColumn < 80) { + I = (HalpRow*HalpScrollLine+HalpColumn*2); + WRITE_S3_VRAM(0xb8000 + I, AsciiChar); + + HalpColumn += 1; + } else // could expand to automatic wrap line. 9/9/92 By Andrew + ; + + return; +} + +/*************************************************************************/ +/* Following code (to EOF) added for PowerPro HAL Display Support [ged]. */ +/*************************************************************************/ + +BOOLEAN +HalpInitializeDisplay1 ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + PVOID fontheader; + + // Use font file from OS Loader + // + // During phase 1 initialization, a pool buffer is + // allocated and the font information is copied from + // the OS Loader heap into pool. + // + + fontheader = ExAllocatePool(NonPagedPool, HalpFontHeader->FileSize ); + if(fontheader == NULL ) { + return FALSE; + } + + RtlMoveMemory(fontheader, HalpFontHeader, HalpFontHeader->FileSize ); + HalpFontHeader = (POEM_FONT_FILE_HEADER) fontheader; + + return TRUE; +} + +/*++ + + Routine Description: BOOLEAN HalpDisplayPowerizedGraphicsSetup () + + This routine initializes the FirePower 'Powerized Graphics' frame buffer. + + Arguments: + + None. + + Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + + --*/ + +BOOLEAN +HalpDisplayPowerizedGraphicsSetup ( + VOID + ) +{ + PULONG buffer; + ULONG limit, index; + static ULONG vramWidth; // mogawa BUG3449 + static BOOLEAN onetime = TRUE; + + + /* NOTE: The following line remaps the virtual to physical mapping */ + /* of DBAT3 to the physical address of PowerPro's frame */ + /* buffer. This overrides the Kernel's mapping to PCI memory. */ + /* If Motorola changes this, we need to revisit it! [ged] */ + /* NOTE2: For speed, we may want to make this region cacheable. */ + + // Moved dbat mapping to init routines to remove it from normal code + // path [breeze-7.15.94] + // + // Moved mapping back here so various adapters can be supported, + // without getting the frame buffer init'd in the mainline init. + // [rlanser-02.06.95] + + + if (onetime) { + + onetime = FALSE; + + HalpVideoMemoryBase = + HalpInitializeVRAM( (PVOID)DISPLAY_MEMORY_BASE, &HalpVideoMemorySize, &vramWidth); + + // + // Set FrameBuffer Control Register + // + // Use a mask value of 7 + // + + { + ULONG ul = rFbControl; + ul &= ~0x07000000; + ul |= 0x07000000 & (vramWidth ? 0x0 : 0x03000000); + rFbControl = ul; + FireSyncRegister(); + } + + if (!HalpVideoMemoryBase) { + HalpDebugPrint("HalpVideoMemoryBase did not map...%x,%x\n", + HalpVideoMemoryBase,HalpVideoMemorySize); + HDBG(DBG_BREAK, DbgBreakPoint();); + return FALSE; + } + + HDBG(DBG_GENERAL, + HalpDebugPrint("HalpVideoMemoryBase is: 0x%x\n", + HalpVideoMemoryBase);); + HDBG(DBG_GENERAL, + HalpDebugPrint("HalpIoControlBase = 0x%x\n", + HalpIoControlBase);); + } + + if (15 == PowerizedGraphicsDisplayMode) { + HalpSetupDCC(15, vramWidth); // mode 15 - 1024x768 8 bit 60Hz + HalpHorizontalResolution = 1024; + HalpVerticalResolution = 768; + } else { + HalpSetupDCC(0, vramWidth); // mode 0 - 640x480 8 bit 60Hz + HalpHorizontalResolution = 640; + HalpVerticalResolution = 480; + } + + HalpBytesPerRow = (HalpFontHeader->PixelWidth + 7) / 8; + HalpCharacterHeight = HalpFontHeader->PixelHeight; + HalpCharacterWidth = HalpFontHeader->PixelWidth; + + // + // Compute character output display parameters. + // + + HalpDisplayText = + HalpVerticalResolution / HalpCharacterHeight; + + HalpScrollLine = + HalpHorizontalResolution * HalpCharacterHeight; + + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + + HalpDisplayWidth = + HalpHorizontalResolution / HalpCharacterWidth; + + // + // Set the video memory to address color one. + // + + buffer = (PULONG)HalpVideoMemoryBase; + limit = (HalpHorizontalResolution * + HalpVerticalResolution) / sizeof(ULONG); + + for (index = 0; index < limit; index += 1) { + *buffer++ = 0x01010101; + } + + // + // Since we use a cached Video Controler sweep the video memory + // range. + // + HalSweepDcacheRange(HalpVideoMemoryBase, HalpVideoMemorySize); + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayOwnedByHal = TRUE; + + return TRUE; + +} /* HalpDisplayPowerizedGraphicsSetup */ + + +/*++ + + Routine Description: VOID HalpDisplayCharacterPowerizedGraphics () + + This routine displays a character at the current x and y positions in + the frame buffer. If a newline is encountered, the frame buffer is + scrolled. If characters extend beyond the end of line, they are not + displayed. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ + +VOID +HalpDisplayCharacterPowerizedGraphics ( + IN UCHAR Character + ) +{ + + PUCHAR Destination; + PUCHAR Source; + ULONG Index; + + // + // If the character is a newline, then scroll the screen up, blank the + // bottom line, and reset the x position. + // + if (Character == '\n') { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + + } else { + //RtlMoveMemory((PVOID)PRO_VIDEO_MEMORY_BASE, + // (PVOID)(PRO_VIDEO_MEMORY_BASE + HalpScrollLine), + // HalpScrollLength); + + // Scroll up one line + Destination = HalpVideoMemoryBase; + Source = (PUCHAR) HalpVideoMemoryBase + HalpScrollLine; + for (Index = 0; Index < HalpScrollLength; Index++) { + *Destination++ = *Source++; + } + // Blue the bottom line + Destination = HalpVideoMemoryBase + HalpScrollLength; + for (Index = 0; Index < HalpScrollLine; Index += 1) { + *Destination++ = 1; + } + } + } else if( Character == '\t' ) { // tab? + HalpColumn += TAB_SIZE; + HalpColumn = (HalpColumn / TAB_SIZE) * TAB_SIZE; + + // tab beyond end of screen? + if (HalpColumn >= HalpDisplayWidth) { + // next tab stop is 1st column of next line + HalpColumn = 0; + + if( HalpRow >= (HalpDisplayText - 1) ) { + HalpDisplayCharacterPowerizedGraphics('\n'); + } else { + HalpRow++; + } + } + + } else if (Character == '\r') { + HalpColumn = 0; + + } else if (Character == 0x7f) { /* DEL character */ + if (HalpColumn != 0) { + HalpColumn--; + HalpDisplayCharacterPowerizedGraphics(' '); + HalpColumn--; + } + + } else if (Character >= 0x20) { + if ((Character < HalpFontHeader->FirstCharacter) || + (Character > HalpFontHeader->LastCharacter)) { + Character = HalpFontHeader->DefaultCharacter; + } + Character -= HalpFontHeader->FirstCharacter; + HalpOutputCharacterPowerizedGraphics((PUCHAR)HalpFontHeader + \ + HalpFontHeader->Map[Character].Offset); + } /* else skip the nonprintable character */ + + return; +} /* HalpDisplayCharacterPowerizedGraphics */ + + + +/*++ + + Routine Description: VOID HalpOutputCharacterPowerizedGraphics() + + This routine insert a set of pixels into the display at the current x + cursor position. If the current x cursor position is at the end of the + line, then a newline is displayed before the specified character. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ + +VOID +HalpOutputCharacterPowerizedGraphics( + IN PUCHAR Glyph + ) +{ + + PUCHAR Destination; + ULONG FontValue; + ULONG I; + ULONG J; + + // + // If the current x cursor position is at the end of the line, then + // output a line feed before displaying the character. + // + + if (HalpColumn >= HalpDisplayWidth) { + HalpDisplayCharacterPowerizedGraphics('\n'); + } + + // + // Output the specified character and update the x cursor position. + // + + Destination = (PUCHAR)(HalpVideoMemoryBase + + (HalpRow * HalpScrollLine) + (HalpColumn * HalpCharacterWidth)); + + for (I = 0; I < HalpCharacterHeight; I += 1) { + FontValue = 0; + for (J = 0; J < HalpBytesPerRow; J += 1) { + FontValue |= *(Glyph + (J * HalpCharacterHeight)) << (24 - (J * 8)); + } + + Glyph += 1; + for (J = 0; J < HalpCharacterWidth ; J += 1) { + if (FontValue >> 31 != 0) { + *Destination = 0xFF; //Make this pixel white + } else { + *Destination = 0x01; //Make this pixel blue + } + HalSweepDcacheRange(Destination, 1); // Push it out + Destination++; + //*Destination++ = (FontValue >> 31) ^ 1; + FontValue <<= 1; + } + + Destination += + (HalpHorizontalResolution - HalpCharacterWidth); + } + + HalpColumn += 1; + + return; + +} /* HalpOutputCharacterPowerizedGraphics */ + + +/// +/// Debug +/// + +VOID +HalpDebugPrint( + + PCHAR Format, + ... + ) + +{ + va_list arglist; + UCHAR Buffer[256]; + ULONG Length; + + // + // Format the output into a buffer and then print it. + // + + va_start(arglist, Format); + Length = vsprintf(Buffer, Format, arglist); + if (HalpDisplayOwnedByHal) { + HalDisplayString(Buffer); + } + DbgPrint(Buffer); +} + +VOID +HalpForceDisplay( + PCHAR Format, + ... + ) +{ + va_list arglist; + UCHAR Buffer[256]; + ULONG Length; + + // + // Format the output into a buffer and then display it. + // + va_start(arglist, Format); + Length = vsprintf(Buffer, Format, arglist); + HalDisplayString(Buffer); +} + +/*-----------------------------------------------------------------------------------------*/ +VOID +HalpDisplayCharacterVGA ( + IN UCHAR Character + ) + +/*++ + Routine Description: + + This routine displays a character at the current x and y positions in + the frame buffer. If a newline is encounter, then the frame buffer is + scrolled. If characters extend below the end of line, then they are not + displayed. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ +{ + + // + // If the character is a newline, then scroll the screen up, blank the + // bottom line, and reset the x position. + // + + if (Character == '\n') { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + } else { // need to scroll up the screen + HalpScrollScreen(1); + } + } + + //========================================================================= + // + // IBMBJB added tab processing + // + + else if( Character == '\t' ) // tab? + { + HalpColumn += TAB_SIZE; + HalpColumn = (HalpColumn / TAB_SIZE) * TAB_SIZE; + + if( HalpColumn >= 80 ) // tab beyond end of screen? + { + HalpColumn = 0; // next tab stop is 1st column of next line + + if( HalpRow >= (HalpDisplayText - 1) ) + HalpScrollScreen( 1 ); // scroll the screen up + else + ++HalpRow; + } + } + + //========================================================================= + + else if (Character == '\r') { + HalpColumn = 0; + } else if (Character == 0x7f) { /* DEL character */ + if (HalpColumn != 0) { + HalpColumn -= 1; + HalpOutputCharacter(0); + HalpColumn -= 1; + } else /* do nothing */ + ; + } else if (Character >= 0x20) { + // Auto wrap for 80 columns per line + if (HalpColumn >= 80) { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + } else { // need to scroll up the screen + HalpScrollScreen(1); + } + } + HalpOutputCharacter(Character); + } else /* skip the nonprintable character */ + ; + + return; + +} /* end of HalpDisplayCharacterVGA() */ + +VOID HalpOutputCharacterINT10 ( + IN UCHAR Character) +{ ULONG Eax,Ebx,Ecx,Edx,Esi,Edi,Ebp; + + Eax = 2 << 8; // AH = 2 + Ebx = 0; // BH = page number + Edx = (HalpRow << 8) + HalpColumn; + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + Eax = (0x0A << 8) + Character; // AH = 0xA AL = character + Ebx = 0; + Ecx = 1; + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + HalpColumn += 1; + +} + + +VOID HalpScrollINT10 ( + IN UCHAR LinesToScroll) + +{ ULONG Eax,Ebx,Ecx,Edx,Esi,Edi,Ebp; + + Eax = 6 << 8; // AH = 6 (scroll up) + Eax |= LinesToScroll; // AL = lines to scroll + Ebx = TEXT_ATTR << 8; // BH = attribute to fill blank line(s) + Ecx = 0; // CH,CL = upper left + Edx = (24 << 8) + 79; // DH,DL = lower right + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); +} + +BOOLEAN HalpDisplayINT10Setup (VOID) +{ ULONG Eax,Ebx,Ecx,Edx,Esi,Edi,Ebp; + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayWidth = 80; + HalpDisplayText = 25; + HalpScrollLine = 160; + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + + HalpDisplayOwnedByHal = TRUE; + + // + // Set cursor to (0,0) + // + Eax = 0x02 << 8; // AH = 2 + Ebx = 0; // BH = page Number + Edx = 0; // DH = row DL = column + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + // + // Make screen white on blue by scrolling entire screen + // + Eax = 0x06 << 8; // AH = 6 AL = 0 + Ebx = TEXT_ATTR << 8; // BH = attribute + Ecx = 0; // (x,y) upper left + Edx = ((HalpDisplayText-1) << 8); // (x,y) lower right + Edx += HalpScrollLine/2; + HalCallBios(0x10, &Eax,&Ebx,&Ecx,&Edx,&Esi,&Edi,&Ebp); + + return TRUE; +} +/*------------------------------------------------------------------------*/ + +BOOLEAN +HalpDisplayPpcS3Setup ( + VOID + ) +/*++ + + Routine Description: + This routine initializes the S3 display controller chip. + Arguments: + None. + Return Value: + TRUE if finished successfully + + --*/ +{ +// +// Routine Description: +// +// This is the initialization routine for S3 86C911. This routine initializes +// the S3 86C911 chip in the sequence of VGA BIOS for AT. +// + ULONG DataLong; + USHORT i,j; + UCHAR DataByte; + UCHAR Index; +// PVOID Index_3x4, Data_3x5; + ULONG MemBase; + + + if (HalpVideoMemoryBase == NULL) { + TRACE("HalpDisplayPpcS3Setup: calling KePhase0MapIo(S3_VIDEO_MEMORY_BASE,0x400000).\n"); + HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo((PVOID)S3_VIDEO_MEMORY_BASE, + 0x400000); // 4 MB + } + + // Enable Video Subsystem + // Accordint to chapter 5.4.2 regular VGA setup sequence + TRACE("HalpDisplayPpcS3Setup: starting.\n"); + + //========================================================================= + // + // IBMBJB changed from writing 0x10 and then 0x08 to writing 0x18 + // because the second write will wipe out the first one, the + // second write was originally done after the write to Setup_OP + // + // WRITE_S3_UCHAR(SUBSYS_ENB, 0x10); + // WRITE_S3_UCHAR(SUBSYS_ENB, 0x08); + + WRITE_S3_UCHAR(SUBSYS_ENB, 0x18); + + //========================================================================= + + TRACE(" Subsystem Enable = 0x10...\n"); + WRITE_S3_UCHAR(Setup_OP, 0x01); + + + WRITE_S3_UCHAR(DAC_Mask, 0x0); // Set screen into blank + WRITE_S3_UCHAR(Seq_Index, 0x01); + WRITE_S3_UCHAR(Seq_Data, 0x21); + + //========================================================================= + // + // IBMBJB removed this section because it is not currently used, this + // was left commented out instead of deleting it in case we use + // a monochrome monitor in the future + // + // // Check monitor type to decide index address (currently not use) + // DataByte = READ_S3_UCHAR(MiscOutR); + // ColorMonitor = DataByte & 0x01 ? TRUE : FALSE; + // + // if (ColorMonitor) { + // Index_3x4 = (PVOID)S3_3D4_Index; + // Data_3x5 = (PVOID)S3_3D5_Data; + // } else { + // Index_3x4 = (PVOID)Mono_3B4; + // Data_3x5 = (PVOID)Mono_3B5; + // } + // + //========================================================================= + + // + // -- Initialization Process Begin -- + // According to appendix B-4 "ADVANCED PROGRAMMER'S GUIDE TO THE EGA/VGA" + // to set the default values to VGA +3 mode. + // + WRITE_S3_UCHAR(VSub_EnB,VideoParam[0]); + // Note: Synchronous reset must be done before MISC_OUT write operation + + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + // For ATI card(0x63) we may want to change the frequence + WRITE_S3_UCHAR(MiscOutW,VideoParam[1]); + + // Note: Synchronous reset must be done before CLOCKING MODE register is + // modified + WRITE_S3_UCHAR(Seq_Index, RESET); // Synchronous Reset ! + WRITE_S3_UCHAR(Seq_Data, 0x01); + + // Sequencer Register + for (Index = 1; Index < 5; Index++) { + WRITE_S3_UCHAR(Seq_Index, Index); + WRITE_S3_UCHAR(Seq_Data, VideoParam[SEQ_OFFSET+Index]); + } + + + // Set CRT Controller + // out 3D4, 0x11, 00 (bit 7 must be 0 to unprotect CRT R0-R7) + // UnLockCR0_7(); + WRITE_S3_UCHAR(S3_3D4_Index, VERTICAL_RETRACE_END); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte = DataByte & 0x7f; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // CRTC controller CR0 - CR18 + for (Index = 0; Index < 25; Index++) { + WRITE_S3_UCHAR(S3_3D4_Index, Index); + WRITE_S3_UCHAR(S3_3D5_Data, VideoParam[CRT_OFFSET+Index]); + } + + // attribute write + // program palettes and mode register + TRACE(" Program palettes ...\n"); + for (Index = 0; Index < 21; Index++) { + WaitForVSync(); + + DataByte = READ_S3_UCHAR(Stat1_In); // Initialize Attr. F/F + WRITE_S3_UCHAR(Attr_Index,Index); + KeStallExecutionProcessor(5); + + WRITE_S3_UCHAR(Attr_Data,VideoParam[ATTR_OFFSET+Index]); + KeStallExecutionProcessor(5); + + WRITE_S3_UCHAR(Attr_Index,0x20); // Set into normal operation + } + + WRITE_S3_UCHAR(Seq_Index, RESET); // reset to normal operation ! + WRITE_S3_UCHAR(Seq_Data, 0x03); + + // graphics controller + TRACE(" Graphics controller...\n"); + for (Index = 0; Index < 9; Index++) { + WRITE_S3_UCHAR(GC_Index, Index); + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+Index]); + } + + // turn off the text mode cursor + WRITE_S3_UCHAR(S3_3D4_Index, CURSOR_START); + WRITE_S3_UCHAR(S3_3D5_Data, 0x2D); + + // Unlock S3 specific registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R8); + WRITE_S3_UCHAR(S3_3D5_Data, 0x48); + + // Unlock S3 SC registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R9); + WRITE_S3_UCHAR(S3_3D5_Data, 0xa0); + + // Disable enhanced mode + WRITE_S3_UCHAR(ADVFUNC_CNTL, 0x02); + + // Turn off H/W Graphic Cursor + WRITE_S3_UCHAR(S3_3D4_Index, SC5); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + //========================================================================= + // + // IBMBJB S3 errata sheet says that CR40 can not be read correctly after + // power up until it has been written to, suggested workaround is + // to use the power on default (0xA4) Since the intent of the + // existing code was to reset bit 0, 0xA4 will be used to reset + // the bit. The other bits that are reset select the desired + // default configuration. + // + // If this register is written by the firmware then this fix is + // unneccessary. If future modifications of the firmware were to + // remove all writes to this register then this fix would have to + // be added here. This is being added now to protect this code + // from possible firmware changes. + // + // // Disable enhanced mode registers access + // WRITE_S3_UCHAR(S3_3D4_Index, SC0); + // DataByte = READ_S3_UCHAR(S3_3D5_Data); + // DataByte &= 0xfe; + // DataByte ^= 0x0; + // + // WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + // + + WRITE_S3_UCHAR( S3_3D4_Index, SC0 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0xA4 ); + + //========================================================================= + + // Set Misc 1 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R0A); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte &= 0xc7; + DataByte ^= 0x0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // Set S3R1 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R1); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte &= 0x80; + DataByte ^= 0x0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // Set S3R2 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R2); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + // Set S3R4 register + WRITE_S3_UCHAR(S3_3D4_Index, S3R4); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte &= 0xec; + DataByte ^= 0x0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + //========================================================================= + // + // IBMBJB added this section to eliminate the DAC hardware cursor, this + // is done before setting registers 0x50 - 0x62 to default states + // so that R55's default state will not be undone. + // + // this sequence zeros the 2 least signifigant bits in command + // register 2 on the DAC + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); // set RS[3:2] to 10 + DataByte = READ_S3_UCHAR( S3_3D5_Data ); + DataByte &= 0xfc; + DataByte |= 0x02; + WRITE_S3_UCHAR( S3_3D5_Data, DataByte ); + + DataByte = READ_S3_UCHAR( DAC_Data ); + DataByte &= 0xfc; // zero CR21,20 in DAC command + WRITE_S3_UCHAR( DAC_Data, DataByte ); // register 2 + + //========================================================================= + // + // IBMBJB Added code to configure for 18 bit color mode and reload the + // palette registers because the firmware configures for 24 bit + // color. If this is done when the system driver initializes for + // graphics mode then the text mode colors can not be changed + // properly. + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); // RS[3:2] = 01B to address + WRITE_S3_UCHAR( S3_3D5_Data, 0x01 ); // DAC command register 0 + + DataByte = READ_S3_UCHAR( DAC_Mask ); // reset bit 1 in DAC command + DataByte &= 0xfd; // register 0 to select 6 bit + WRITE_S3_UCHAR( DAC_Mask, DataByte ); // operation (18 bit color) + + // IBMBJB added write to SDAC PLL control register to make sure CLK0 + // is correct if we have to reinitialize after graphics mode + // initialization, this does not bother the 928/Bt485 card + // because the Bt485 DAC looks very much like the SDAC + + WRITE_S3_UCHAR( DAC_WIndex, 0x0e ); // select SDAC PLL control reg + WRITE_S3_UCHAR( DAC_Data, 0x00 ); // select SDAC CLK0 + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); // select DAC color palette + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); // registers + + WRITE_S3_UCHAR( DAC_WIndex, 0 ); // start load in register 0 + + for( i = 0, j = 0; i < 256; ++i ) // load all color registers + { + WRITE_S3_UCHAR( DAC_Data, TextPalette[j++] ); // red intensity + WRITE_S3_UCHAR( DAC_Data, TextPalette[j++] ); // green intensity + WRITE_S3_UCHAR( DAC_Data, TextPalette[j++] ); // blue intensity + } + + //========================================================================= + // + // IBMBJB added writes to registers 0x50 - 0x62 to set them to a known + // state because some of them are set by the firmware and are + // not correct for our use + // + // NOTE: there are some writes to the DAC registers in code that + // executes later that depend on R55[1:0] being 00B, if the + // default state of R55 is changed make sure that these bits + // are not changed + + WRITE_S3_UCHAR( S3_3D4_Index, 0x50 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x51 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x52 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x53 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x54 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x55 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x56 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x57 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + + WRITE_S3_UCHAR( S3_3D4_Index, 0x58 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x59 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5a ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x0a ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5B ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5C ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5D ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5E ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x5F ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + // IBMBJB changed value written from 0 to 1 for an S3 864 based card to + // clear up bad display caused by 864->SDAC FIFO underrun + WRITE_S3_UCHAR( S3_3D4_Index, 0x60 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x01 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x61 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + WRITE_S3_UCHAR( S3_3D4_Index, 0x62 ); + WRITE_S3_UCHAR( S3_3D5_Data, 0x00 ); + + //========================================================================= + // + // IBMBJB added setting bits 7 and 6 of CR65, errata sheet fix for split + // transfer problem in parallel and continuous addressing modes + // Note: side effect of setting bit 7 was a garbled firmware screen after + // shutdown. + + // Set SR65 bits 7 and 6 + WRITE_S3_UCHAR(S3_3D4_Index, 0x65); + DataByte = READ_S3_UCHAR(S3_3D5_Data); + DataByte |= 0x40; +// DataByte |= 0xc0; + WRITE_S3_UCHAR(S3_3D5_Data, DataByte); + + // Lock S3 SC registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R9); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + // Lock S3 specific registers + WRITE_S3_UCHAR(S3_3D4_Index, S3R8); + WRITE_S3_UCHAR(S3_3D5_Data, 0x0); + + // Load character fonts into plane 2 (A0000-AFFFF) + TRACE(" Load Fonts into Plane2 ...\n"); + WRITE_S3_UCHAR(Seq_Index,0x02); // Enable Write Plane reg + WRITE_S3_UCHAR(Seq_Data,0x04); // select plane 2 + + WRITE_S3_UCHAR(Seq_Index,0x04); // Memory Mode Control reg + WRITE_S3_UCHAR(Seq_Data,0x06); // access to all planes, + + WRITE_S3_UCHAR(GC_Index,0x05); // Graphic, Control Mode reg + WRITE_S3_UCHAR(GC_Data,0x00); + + WRITE_S3_UCHAR(GC_Index,0x06); + WRITE_S3_UCHAR(GC_Data,0x04); + + WRITE_S3_UCHAR(GC_Index,0x04); + WRITE_S3_UCHAR(GC_Data,0x02); + + MemBase = 0xA0000; + for (i = 0; i < 256; i++) { + for (j = 0; j < 16; j++) { + WRITE_S3_VRAM(MemBase, VGAFont8x16[i*16+j]); + MemBase++; + } + // 32 bytes each character font + for (j = 16; j < 32; j++) { + WRITE_S3_VRAM(MemBase, 0 ); + MemBase++; + } + } + + // turn on screen + WRITE_S3_UCHAR(Seq_Index, 0x01); + DataByte = READ_S3_UCHAR(Seq_Data); + DataByte &= 0xdf; + DataByte ^= 0x0; + WRITE_S3_UCHAR(Seq_Data, DataByte); + + WaitForVSync(); + + // Enable all the planes through the DAC + WRITE_S3_UCHAR(DAC_Mask, 0xff); + + // select plane 0, 1 + WRITE_S3_UCHAR(Seq_Index, 0x02); // Enable Write Plane reg + WRITE_S3_UCHAR(Seq_Data, VideoParam[SEQ_OFFSET+0x02]); + + // access to planes 0, 1. + WRITE_S3_UCHAR(Seq_Index, 0x04); // Memory Mode Control reg + WRITE_S3_UCHAR(Seq_Data, VideoParam[SEQ_OFFSET+0x04]); + + WRITE_S3_UCHAR(GC_Index, 0x05); // Graphic, Control Mode reg + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+0x05]); + + WRITE_S3_UCHAR(GC_Index, 0x04); + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+0x04]); + + WRITE_S3_UCHAR(GC_Index, 0x06); + WRITE_S3_UCHAR(GC_Data, VideoParam[GRAPH_OFFSET+0x06]); + + // + // Set screen into blue + // + TRACE(" Set Screen into Blue ...\n"); + for (DataLong = 0xB8000; + DataLong < 0xB8000+TWENTY_FIVE_LINES; + DataLong += 2) { + WRITE_S3_VRAM(DataLong, ' '); + WRITE_S3_VRAM(DataLong+1, TEXT_ATTR); + } + // End of initialize S3 standard VGA +3 mode + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + //IBMLAN=============================================================== + // Added the following so that HalQueryDisplayParameters() and + // HalSetDisplayParameters() work with either S3 or P9. + HalpDisplayWidth = 80; + HalpDisplayText = 25; + HalpScrollLine = 160; + HalpScrollLength = + HalpScrollLine * (HalpDisplayText - 1); + + //end IBMLAN=========================================================== + HalpDisplayOwnedByHal = TRUE; + + return TRUE; +} /* end of HalpDisplayPpcS3Setup() */ + +VOID +HalpOutputCharacterS3 ( + IN UCHAR AsciiChar + ) + +/*++ + + Routine Description: + + This routine insert a set of pixels into the display at the current x + cursor position. If the x cursor position is at the end of the line, + then no pixels are inserted in the display. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ + +{ + ULONG I; + + // + // If the current x cursor position is within the current line, then insert + // the specified pixels into the last line of the text area and update the + // x cursor position. + // + if (HalpColumn < 80) { + I = (HalpRow*HalpScrollLine+HalpColumn*2); + WRITE_S3_VRAM(0xb8000 + I, AsciiChar); + + HalpColumn += 1; + } else // could expand to automatic wrap line. 9/9/92 By Andrew + ; + + return; +} /* end of HalpOutputCharacterS3() */ + + + +VOID +HalpScrollS3(IN UCHAR line) +{ + UCHAR i, DataByte; + ULONG target; + + for (i = 0; i < line; i ++) { + //======================================================================= + // + // IBMBJB added wait for vertical sync to make scroll smooth + + WaitForVSync(); + + //======================================================================= + + for (target = 0xB8000; + target < 0xB8000+TWENTY_FOUR_LINES; + target += 2) { + DataByte = READ_S3_VRAM(target+ONE_LINE); + WRITE_S3_VRAM(target, DataByte); + } + for (target = 0xB8000+TWENTY_FOUR_LINES; + target < 0xB8000+TWENTY_FIVE_LINES; + target += 2) { + WRITE_S3_VRAM(target, ' ' ); + } + } +} +/*------------------------------------------------------------------------*/ +static PUCHAR HalpP91VideoMemoryBase = (PUCHAR)0; + +BOOLEAN +HalpDisplayPpcP91Setup ( + VOID + ) +/*++ + + Routine Description: + + This routine initializes the Weitek P9100 display contoller chip. + + Arguments: + + None. + + Return Value: + + None. + + --*/ +{ + PULONG buffer; + ULONG limit, index; + TRACE("HalpDisplayPpcP91Setup: starting...\n"); + // For now I'll leave the P9100 in the same state that the firmware + // left it in. This should be 640x480. + + HalpHorizontalResolution = 640; + HalpVerticalResolution = 480; + + if (HalpP91VideoMemoryBase == NULL) { + + HalpP91VideoMemoryBase = (PUCHAR)KePhase0MapIo((PVOID)P91_VIDEO_MEMORY_BASE, + 0x800000); // 8 MB + } + + //IBMLAN Use font file from OS Loader + // + // Compute display variables using using HalpFontHeader which is + // initialized in HalpInitializeDisplay(). + // + // N.B. The font information suppled by the OS Loader is used during phase + // 0 initialization. During phase 1 initialization, a pool buffer is + // allocated and the font information is copied from the OS Loader + // heap into pool. + // + //FontHeader = (POEM_FONT_FILE_HEADER)LoaderBlock->OemFontFile; + //HalpFontHeader = FontHeader; + HalpBytesPerRow = (HalpFontHeader->PixelWidth + 7) / 8; + HalpCharacterHeight = HalpFontHeader->PixelHeight; + HalpCharacterWidth = HalpFontHeader->PixelWidth; + + // + // Compute character output display parameters. + // + + HalpDisplayText = + HalpVerticalResolution / HalpCharacterHeight; + + HalpScrollLine = + HalpHorizontalResolution * HalpCharacterHeight; + + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + + HalpDisplayWidth = + HalpHorizontalResolution / HalpCharacterWidth; + + + // + // Set the video memory to address color one. + // + + buffer = (PULONG)HalpP91VideoMemoryBase; + limit = (HalpHorizontalResolution * + HalpVerticalResolution) / sizeof(ULONG); + + limit = 0x100000/sizeof(ULONG); // mogawa + for (index = 0; index < limit; index += 1) { + *buffer++ = 0x01010101; + } + + + // + // Initialize the current display column, row, and ownership values. + // + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayOwnedByHal = TRUE; + return TRUE; + +} //end of HalpDisplayPpcP91Setup + +VOID +HalpDisplayCharacterP91 ( + IN UCHAR Character + ) +/*++ + + Routine Description: + + This routine displays a character at the current x and y positions in + the frame buffer. If a newline is encountered, the frame buffer is + scrolled. If characters extend below the end of line, they are not + displayed. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ + +{ + + PUCHAR Destination; + PUCHAR Source; + ULONG Index; + + // + // If the character is a newline, then scroll the screen up, blank the + // bottom line, and reset the x position. + // + if (Character == '\n') { + UCHAR DataByte; + DataByte = READ_REGISTER_UCHAR(((PCHAR)HalpVideoConfigBase)+65); + TRACE("Config[65]=0x%02x\n", DataByte); + + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) { + HalpRow += 1; + + } else { + //RtlMoveMemory((PVOID)P91_VIDEO_MEMORY_BASE, + // (PVOID)(P91_VIDEO_MEMORY_BASE + HalpScrollLineP9), + // HalpScrollLengthP9); + + // Scroll up one line + Destination = HalpP91VideoMemoryBase; + Source = (PUCHAR) HalpP91VideoMemoryBase + HalpScrollLine; + for (Index = 0; Index < HalpScrollLength; Index++) { + *Destination++ = *Source++; + } + // Blue the bottom line + Destination = HalpP91VideoMemoryBase + HalpScrollLength; + for (Index = 0; Index < HalpScrollLine; Index += 1) { + *Destination++ = 1; + } + } + + } else if (Character == '\r') { + HalpColumn = 0; + + } else { + if ((Character < HalpFontHeader->FirstCharacter) || + (Character > HalpFontHeader->LastCharacter)) { + Character = HalpFontHeader->DefaultCharacter; + } + + Character -= HalpFontHeader->FirstCharacter; + HalpOutputCharacterP91((PUCHAR)HalpFontHeader + HalpFontHeader->Map[Character].Offset); + } + + return; +} + +VOID +HalpOutputCharacterP91( + IN PUCHAR Glyph + ) + +/*++ + + Routine Description: + + This routine insert a set of pixels into the display at the current x + cursor position. If the current x cursor position is at the end of the + line, then a newline is displayed before the specified character. + + Arguments: + + Character - Supplies a character to be displayed. + + Return Value: + + None. + + --*/ + +{ + + PUCHAR Destination; + ULONG FontValue; + //ULONG tmp; + ULONG I; + ULONG J; + + // + // If the current x cursor position is at the end of the line, then + // output a line feed before displaying the character. + // + + if (HalpColumn == HalpDisplayWidth) { + HalpDisplayCharacterP91('\n'); + } + + // + // Output the specified character and update the x cursor position. + // + + Destination = (PUCHAR)(HalpP91VideoMemoryBase + + (HalpRow * HalpScrollLine) + (HalpColumn * HalpCharacterWidth)); + + for (I = 0; I < HalpCharacterHeight; I += 1) { + FontValue = 0; + for (J = 0; J < HalpBytesPerRow; J += 1) { + FontValue |= *(Glyph + (J * HalpCharacterHeight)) << (24 - (J * 8)); + } + + Glyph += 1; + for (J = 0; J < HalpCharacterWidth ; J += 1) { + if (FontValue >> 31 != 0) { + *Destination = 0xFF; //Make this pixel white + HalSweepDcacheRange(Destination, 1); // Push it out + } + Destination++; + //*Destination++ = (FontValue >> 31) ^ 1; + FontValue <<= 1; + } + + Destination += + (HalpHorizontalResolution - HalpCharacterWidth); + } + + HalpColumn += 1; + return; +} + +BOOLEAN +HalpDisplayPpcP91BlankScreen ( + VOID + ) +{ + PULONG buffer; + ULONG limit, index; + + if (HalpP91VideoMemoryBase == NULL) { + return FALSE; + } + + buffer = (PULONG)HalpP91VideoMemoryBase; + limit = (HalpHorizontalResolution * + HalpVerticalResolution) / sizeof(ULONG); + + limit = 0x100000/sizeof(ULONG); // mogawa + for (index = 0; index < limit; index += 1) { + *buffer++ = 0x00000000; + } + return TRUE; +} + + +/*------------------------------------------------------------------------*/ +// +// Cirrus Device Driver +// + +// Routine Description: +// +// This routine displays a character at the current x and y positions in +// the frame buffer. If a newline is encounter, then the frame buffer is +// scrolled. If characters extend below the end of line, then they are not +// displayed. +// +// Arguments: +// +// Character - Supplies a character to be displayed. +// +// Return Value: +// +// None. +// + +VOID +HalpDisplayCharacterCirrus ( + IN UCHAR Character + ) +{ + +// +// If the character is a newline, then scroll the screen up, blank the +// bottom line, and reset the x position. +// + + if (Character == '\n') + { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) + { + HalpRow += 1; + } + else + { // need to scroll up the screen + HalpScrollScreen(1); + } + } + +// +// added tab processing +// + + else if ( Character == '\t' ) // tab? + { + HalpColumn += TAB_SIZE; + HalpColumn = (HalpColumn / TAB_SIZE) * TAB_SIZE; + + if ( HalpColumn >= COLS ) // tab beyond end of screen? + { + HalpColumn = 0; // next tab stop is 1st column + // of next line + + if ( HalpRow >= (HalpDisplayText - 1) ) + HalpScrollScreen( 1 ); + else ++HalpRow; + } + } + else if (Character == '\r') + { + HalpColumn = 0; + } + else if (Character == 0x7f) + { // DEL character + if (HalpColumn != 0) + { + HalpColumn -= 1; + HalpOutputCharacterCirrus(0); + HalpColumn -= 1; + } + else // do nothing + ; + } + else if (Character >= 0x20) + { + // Auto wrap for 80 columns + // per line + if (HalpColumn >= COLS) + { + HalpColumn = 0; + if (HalpRow < (HalpDisplayText - 1)) + { + HalpRow += 1; + } + else + { // need to scroll up the screen + HalpScrollScreen(1); + } + } + HalpOutputCharacterCirrus(Character); + } + // skip the nonprintable character +} + + +// +// +// Routine Description: +// +// This routine insert a set of pixels into the display at the current x +// cursor position. If the x cursor position is at the end of the line, +// then no pixels are inserted in the display. +// +// Arguments: +// +// Character - Supplies a character to be displayed. +// +// Return Value: +// +// None. +// + + +VOID +HalpOutputCharacterCirrus ( + IN UCHAR AsciiChar + ) +{ + PUCHAR Destination; + ULONG I; + +// +// If the current x cursor position is within the current line, then insert +// the specified pixels into the last line of the text area and update the +// x cursor position. +// + + if (HalpColumn < COLS) + { + I = (HalpRow*HalpScrollLine+HalpColumn*2); + Destination = (PUCHAR)(CIRRUS_TEXT_MEM + I + HalpScreenStart); + WRITE_CIRRUS_VRAM(Destination, AsciiChar); + HalpColumn += 1; + } +} + + +// +// Routine Description: +// +// This routine initializes the Cirrus CL-GD5430 graphics controller chip +// + +static void updattr(IN int rg,IN unsigned char val) +{ + inp(0x3da); + outportb(0x3c0,rg); + outportb(0x3c0,val); + outportb(0x3c0,((unsigned char)(rg | 0x20))); +} + + +static void set_ext_regs(IN int reg,IN unsigned char *p) +{ + unsigned char index, data; + + while (*p != 0xff) + { + index= *p++; + data= *p++; + setreg(reg,index,data); + } +} + + +BOOLEAN +HalpDisplayPpcCirrusSetup ( + VOID + ) +{ + int i; + + //DbgBreakPoint(); + TRACE("HalpDisplayPpcCirrusSetup: starting.\n"); + if (HalpVideoMemoryBase == NULL) { + TRACE("HalpDisplayPpcCirrusSetup: calling KePhase0MapIo(CIRRUS_VIDEO_MEMORY_BASE,0x400000).\n"); + HalpVideoMemoryBase = (PUCHAR)KePhase0MapIo((PVOID)CIRRUS_VIDEO_MEMORY_BASE, 0x400000); // 4 MB + } else { + TRACE("HalpVideoMemoryBase=0x%08x\n", HalpVideoMemoryBase); + } + +// +// Assert synchronous reset while setting the clock mode +// + + setreg(0x3c4,0,1); // assert synchronous reset + + outportb(0x3c2,0x67); + + for ( i = 0; i < 21; i++ ) updattr(i,attr3[i]); + + setreg(0x3d4,0x11,0x20); + for ( i = 0; i < 32; i++ ) setreg(0x3d4,i,crtc3[i]); + + for ( i = 0x00;i < 9; i++ ) setreg(0x3ce,i,graph3[i]); + + for ( i = 0; i < 5; i++ ) setreg(0x3c4,i,seq3[i]); + + set_ext_regs (0x3c4,eseq3); + set_ext_regs (0x3d4,ecrtc3); + set_ext_regs (0x3ce,egraph3); + set_ext_regs (0x3c0,eattr3); + +// +// Load 8x16 font +// + + load8x16(); + +// +// Load color palette +// + + load_ramdac(); + + outportb(0x3c6,0xff); + +// +// Reset Hidden color register +// + +// inp(0x3c6); +// inp(0x3c6); +// inp(0x3c6); +// inp(0x3c6); +// outp(0x3c6,0x00); + +// +// Screen blank +// + + clear_text(); + +// +// Initialize the current display column, row, and ownership values. +// + + HalpColumn = 0; + HalpRow = 0; + HalpDisplayWidth = COLS; + HalpDisplayText = ROWS; + HalpScrollLine = ONE_LINE; + HalpScrollLength = HalpScrollLine * (HalpDisplayText - 1); + HalpDisplayOwnedByHal = TRUE; + HalpScreenStart = 0; + return TRUE; +} + +VOID HalpScrollCirrus( + IN UCHAR line + ) +{ + ULONG LogicalTarget, PhysicalTarget; + int i; + + for (i=0; i < line; i++) { + + HalpScreenStart = HalpScreenStart + ONE_LINE; + setreg(0x3d4,0xC, (UCHAR) (HalpScreenStart >> 9)); + setreg(0x3d4,0xD, (UCHAR) ((HalpScreenStart >> 1) & 0xFF)); + + for (LogicalTarget = TWENTY_FOUR_LINES; + LogicalTarget < TWENTY_FIVE_LINES; + LogicalTarget += 2) { + PhysicalTarget = LogicalTarget + HalpScreenStart + CIRRUS_TEXT_MEM; + WRITE_CIRRUS_VRAM(PhysicalTarget, ' ' ); + WRITE_CIRRUS_VRAM(PhysicalTarget+1, TEXT_ATTR ); + } + } +} + +static void clear_text(VOID) +{ + unsigned long p; + +// +// fill plane 0 and 1 with 0x20 and 0x1f +// + + for (p = CIRRUS_TEXT_MEM; + p < CIRRUS_TEXT_MEM+TWENTY_FIVE_LINES; + p += 2) + { + WRITE_CIRRUS_VRAM(p, ' '); + WRITE_CIRRUS_VRAM(p+1, TEXT_ATTR); + } +} + +static void load8x16(VOID) +{ + int i, j; + PUCHAR address; + +// +// load 8x16 font into plane 2 +// + + setreg(0x3c4,0x04,(seq3[4] | 0x04)); + +// +// disable video and enable all to cpu to enable maximum video +// memory access +// + + setreg(0x3c4,0x01,seq3[1] | 0x20); + setreg(0x3c4,2,4); + + setreg(0x3ce,0x05,graph3[5] & 0xef); + setreg(0x3ce,0x06,0x05); + + +// +// fill plane 2 with 8x16 font + + address = (void *) (CIRRUS_FONT_MEM); + for ( i = 0; i < 256; i++ ) + { + for ( j = 0; j < 16; j++ ) + { + WRITE_CIRRUS_VRAM(address,VGAFont8x16[i*16+j]); + address++; + } + + for ( j = 16; j < 32; j++ ) + { + WRITE_CIRRUS_VRAM(address,0); + address++; + } + } + + setreg(0x3c4,0x01,seq3[1]); + setreg(0x3c4,0x04,seq3[4]); + setreg(0x3c4,2,seq3[2]); + + setreg(0x3ce,0x06,graph3[6]); + setreg(0x3ce,0x05,graph3[5]); +} + + +static void load_ramdac() +{ + int ix,j; + + for ( ix = 0,j = 0; j <= 0x0FF ; ix = ix+3,j++ ) + { + outp(0x3c8,(unsigned char)j); // write ramdac index + outp(0x3c9,TextPalette[ix]); // write red + outp(0x3c9,TextPalette[ix+1]); // write green + outp(0x3c9,TextPalette[ix+2]); // write blue + } +} + diff --git a/private/ntos/nthals/halfire/ppc/pxenviro.c b/private/ntos/nthals/halfire/ppc/pxenviro.c new file mode 100644 index 000000000..55c3677b3 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxenviro.c @@ -0,0 +1,729 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxenviro.c $ + * $Revision: 1.12 $ + * $Date: 1996/05/18 00:28:50 $ + * $Locker: $ + */ + +/*********************************************************************** + + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + + File Name: + PXENVIRO.C + + Purpose: + Provides the interface to the PowerPC ARC firmware. + + Globals: + none + + Functions: + ULONG HalGetEnvironmentVariable(); + ULONG HalSetEnvironmentVariable(); + + History: + 27-Jul-1993 Steve Johns + Original version + 31-Jan-1994 Steve Johns + Added checksum logic + 08-Jul-1994 Steve Johns + Made Environment variable routines PReP compliant + 12-20-94 + Heavly re-written by Sol Kavy at FirePower to + clean-up the code and properly suppor the Prep spec. + + +NOTES: + + The fields in the NVRAM structure follow Big-Endian byte ordering. + + Each environment variable is stored as an zero-terminated ASCII string: + + =,0 + +***********************************************************************/ + + +#define USE_SPINLOCKS FALSE + +#include "halp.h" +//#include "fpdebug.h" +#include "arccodes.h" +#include "eisa.h" +#include "pxnvrsup.h" +#include "fpnvram.h" + +USHORT HalpComputeCrc(VOID); + +// +// Debug Define (first paramter is a place holder for future +// level handling: 1 = Calls, 2 = Routine Info). +// +#define NDBG(_lvl, _print) + +PKSPIN_LOCK NVRAM_Spinlock; + +#define NVSIZE 4096 + +// +// Location of the NVRAM registers +// +// #include "phsystem.h" +// extern PVOID HalpIoControlBase; +#define NVRAM ((PNVRAM_CONTROL) (HalpIoControlBase)) +// #define NVRAM ((PNVRAM_CONTROL) 0xb1000000) + +// +// Dummy pointer used to byte get offset information +// +PVOID NvramPtr=0; +#define NVMAP ((PHEADER) NvramPtr) + +extern BOOLEAN NvramFailure; + +// +// Use the routine from fpds1385.c to access the nvram chip. These +// routines protect their accesses with the appropriate spin locks +// to make sure the actions are atomic +// + +USHORT +HalpReadNvramUshort(USHORT Index) +{ + return (HalpDS1385ReadNVRAM(Index) << 8) + + HalpDS1385ReadNVRAM((USHORT)(Index+1)); +} + + +ULONG +HalpReadNvramUlong(USHORT Index) +{ + ULONG ReturnValue; + + // + // Read Big-Endian ULONG value & convert to Little-Endian + // + ReturnValue = ((ULONG) HalpReadNvramUshort(Index) << 16) + + (ULONG) HalpReadNvramUshort((USHORT)(Index+2)); + + return ReturnValue; +} + +VOID +HalpWriteNvramUshort(USHORT Index, + USHORT Value) +{ + // + // Write USHORT value in Big-Endian + // + HalpDS1385WriteNVRAM(Index, (UCHAR) (Value >> 8)); + HalpDS1385WriteNVRAM((USHORT)(Index+1),(UCHAR) Value); +} + + +VOID HalpWriteNvramUlong( + USHORT Index, + ULONG Value) +{ + // + // Write ULONG value in Big-Endian + // + HalpWriteNvramUshort(Index, (USHORT) (Value >> 16)); + HalpWriteNvramUshort((USHORT)(Index+2),(USHORT) Value); +} + +// +// DumpNVRAM +// +// Description: +// Used during bring-up to ensure that NVRAM is being handled +// correctly. Nothing more than a bunch of DbgPrint of NVRAM +// +VOID +DumpNVRAM() +{ + DbgPrint("HalpIoControlBase is at 0x%x\n", HalpIoControlBase); + DbgPrint("NVRAM is at 0x%x\n", NVRAM); + DbgPrint("NvramIndexLo is at 0x%x\n", &(NVRAM->NvramIndexLo)); + DbgPrint("NvramIndexHi is at 0x%x\n", &(NVRAM->NvramIndexHi)); + DbgPrint("NvramData is at 0x%x\n", &(NVRAM->NvramData)); + DbgPrint("NVRAM USHORT Size(%d): %d\n", + (USHORT)&NVMAP->Size, + HalpReadNvramUshort((USHORT)&NVMAP->Size)); + DbgPrint("NVRAM UCHAR Version(%d): %d\n", + (USHORT)&NVMAP->Version, + HalpDS1385ReadNVRAM((USHORT)&NVMAP->Version)); + DbgPrint("NVRAM UCHAR Revision(%d): %d\n", + (USHORT)&NVMAP->Revision, + HalpDS1385ReadNVRAM((USHORT)&NVMAP->Revision)); + DbgPrint("NVRAM USHORT Crc1(%d): 0x%x\n", + (USHORT)&NVMAP->Crc1, + HalpReadNvramUshort((USHORT)&NVMAP->Crc1)); + DbgPrint("NVRAM USHORT Crc2(%d): 0x%x\n", + (USHORT)&NVMAP->Crc2, + HalpReadNvramUshort((USHORT)&NVMAP->Crc2)); + DbgPrint("NVRAM UCHAR LastOS(%d): %d\n", + (USHORT)&NVMAP->LastOS, + HalpDS1385ReadNVRAM((USHORT)&NVMAP->LastOS)); + DbgPrint("NVRAM UCHAR Endian(%d): %d\n", + (USHORT)&NVMAP->Endian, + HalpDS1385ReadNVRAM((USHORT)&NVMAP->Endian)); + DbgPrint("NVRAM UCHAR OSAreaUsage(%d): %d\n", + (USHORT)&NVMAP->OSAreaUsage, + HalpDS1385ReadNVRAM((USHORT)&NVMAP->OSAreaUsage)); + DbgPrint("NVRAM UCHAR PMMode(%d): %d\n", + (USHORT)&NVMAP->PMMode, + HalpDS1385ReadNVRAM((USHORT)&NVMAP->PMMode)); + DbgPrint("NVRAM ULONG GEAddress(%d): %d\n", + (USHORT)&NVMAP->GEAddress, + HalpReadNvramUlong((USHORT)&NVMAP->GEAddress)); + DbgPrint("NVRAM ULONG GELength(%d): %d\n", + (USHORT)&NVMAP->GELength, + HalpReadNvramUlong((USHORT)&NVMAP->GELength)); + { + USHORT StartIndex, LastIndex, Index; + UCHAR NvramChar; + BOOLEAN LastNull = TRUE; // Assume it + + DbgPrint("NVRAM Global Environment Area:\n"); + + StartIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GEAddress)); + LastIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GELength)); + LastIndex += StartIndex - 1; + for (Index = StartIndex; Index <= LastIndex; Index++) { + NvramChar = HalpDS1385ReadNVRAM(Index); + if (NvramChar == '\0') { + LastNull = TRUE; + } else { + if (LastNull == TRUE) { + DbgPrint("\n[%d]: ", Index); + } + DbgPrint("%c", NvramChar); + LastNull = FALSE; + } + } + DbgPrint("\n"); + } + + DbgPrint("Checking Our version of CRC"); + DbgPrint("Compute CRC returns 0x%x\n", HalpComputeCrc()); +} + +UCHAR +HalpGetEnvironmentInfo( + OPTIONAL PUSHORT TotalSize, + OPTIONAL PUSHORT FreeSize, + OPTIONAL PULONG pCrc) +{ + USHORT Index; + USHORT InUse, TotalLength; + UCHAR DataByte1, DataByte2; + + NDBG(1, DbgPrint("HalpGetEnvironmentInfo: called\n");); + + TotalLength = (USHORT) HalpReadNvramUlong((USHORT) &NVMAP->GELength); + if (TotalSize != NULL) + *TotalSize = TotalLength; + + if (FreeSize != NULL) { + // + // Compute how much NVRAM is in use + // + InUse = 0; + Index = (USHORT)HalpReadNvramUlong ((USHORT) &NVMAP->GEAddress); + DataByte1 = HalpDS1385ReadNVRAM(Index++); + DataByte2 = DataByte1; + while (DataByte1 | DataByte2) { + DataByte1 = DataByte2; + DataByte2 = HalpDS1385ReadNVRAM(Index++); + InUse++; + } + *FreeSize = TotalLength - InUse; + } + + if (pCrc != NULL) { + *pCrc = HalpReadNvramUshort((USHORT) &NVMAP->Crc1); + } + return(HalpDS1385ReadNVRAM((USHORT) &NVMAP->Version)); +} + +// +// HalpAddByteCrc +// +// Description: +// Use the X^16 + X^12 + X^5 + 1, Polynomial for CRC +// +// Input: +// Stored in NVRAM +// +// Output: +// New Crc Value +// +USHORT +HalpAddByteCrc(USHORT CurrentCrc, USHORT Index) +{ + UCHAR Byte; + UCHAR CrcLo, CrcHi; + USHORT x,y,z; + + + Byte = HalpDS1385ReadNVRAM(Index); + CrcLo = CurrentCrc &0xff; + CrcHi = CurrentCrc >> 8; + x = (CrcLo << 8) | (CrcHi^Byte); + y = (CrcHi^Byte) << 8; + z = ((y >> 12) | (y << 4)) & 0xf00f; + x = x^z; + z = ((y << 13) | (y >> 3)) & 0x1fe0; + x = x^z; + z = y&0xf000; + x = x^z; + z = ((y<<9) | (y>>7)) & 0x1e0; + x = x^z; + return(x); +} + +// +// HalpComputeCrc +// +// Description: +// Find the parts that are part of the crc and compute the +// crc against them. +// +// Input: +// Stored in NVRAM +// +// Output: +// +USHORT +HalpComputeCrc(VOID) +{ + USHORT CurrentCrc = 0xffff; + USHORT Index, EndIndex; + + // + // Loop through different parts computing CRC + // This is from Size to Revision inclusive + // + for (Index = 0; Index <= 3; Index++) { + CurrentCrc = HalpAddByteCrc(CurrentCrc, Index); + } + + // + // Compute ending offset + // + EndIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->OSAreaAddress)); + + // + // Loop through second half + // This is from LastOS to OSArea (Note: 9 should be 8; however, + // IBM screwed up and we are all just going along with it). + // + for (Index = 9; Index < EndIndex; Index++) { + CurrentCrc = HalpAddByteCrc(CurrentCrc, Index); + } + return(CurrentCrc); +} + + +// +// HalpUpdateCrc +// +// Description: +// Compute the required Crc value and update the Header. This +// code only updates crc1. +// +VOID +HalpUpdateCrc() +{ + ULONG Crc; + + NDBG(1, DbgPrint("HalpUpdateCrc: called\n");); + Crc = HalpComputeCrc(); + HalpWriteNvramUshort((USHORT) &NVMAP->Crc1, (USHORT) Crc); +} + +// +// Returns the number of bytes removed +// +USHORT +HalpCompressEnvironmentSpace(IN USHORT StartIndex) +{ + USHORT Index, BytesRemoved; + UCHAR PreviousChar, NvramChar; + + Index = StartIndex+1; + while(HalpDS1385ReadNVRAM(Index++) != '=') { + /* Do Nothing */ + } + while(HalpDS1385ReadNVRAM(Index++) != 0) { + /* Do Nothing */ + } + BytesRemoved = Index - StartIndex; // Adjust amount of free space + + NvramChar = 0; + // + // Copy subsequent variables + // + do { + PreviousChar = NvramChar; + NvramChar = HalpDS1385ReadNVRAM(Index++); + HalpDS1385WriteNVRAM(StartIndex++, NvramChar); + } while (PreviousChar | NvramChar); + + // + // Make sure unused NVRAM area is zeroed + // + for (Index=0; Index = NVSIZE) { + break; + } + HalpDS1385WriteNVRAM((USHORT)(Index+StartIndex), 0); + } + return(BytesRemoved); +} + +// +//HalpFindEnviroVar +// Description: +// Searches the NVRAM for an environment variable. +// +// Parameters: +// Variable - ptr to the variable to search for. +// +// Return value: +// The NVRAM index where the environment variable's VALUE is stored. +// Returns 0 if the variable was not found. +// +// Assumes NVRAM_Spinlock has already been acquired by the caller. +// +USHORT +HalpFindEnviroVar(IN CHAR *Variable) +{ + USHORT Index, StartIndex, LastIndex; + CHAR *VariablePtr, UserChar, NvramChar; + + NDBG(1, DbgPrint("HalpFindEnviroVar: called for %s\n", Variable);); + + StartIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GEAddress)); + LastIndex = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GELength)); + LastIndex += StartIndex - 1; + + + // + // Search the NVRAM for the variable. + // + VariablePtr = Variable; + for (Index = StartIndex ; Index <= LastIndex; ) { + // + // Get a character from the NVRAM + // + NvramChar = HalpDS1385ReadNVRAM(Index++); + if (NvramChar == 0) { + break; + } + + // + // Are we at the end of the variable name in both the + // input string and the NVRAM ? + // If so, then it is an exact match. Return the NVRAM index. + // + UserChar = *VariablePtr++; + if (UserChar == 0 && NvramChar == '=') { + NDBG(2, DbgPrint("HalpFindEnviroVar: found %s at %d\n", + Variable, Index);); + return(Index); + } + + // + // Convert variable to UPPER case + // + UserChar = (UserChar >= 'a' && UserChar <= 'z') ? + UserChar-0x20 : UserChar; + + // + // Is there a match on this character ? + // + + if (UserChar != NvramChar) { + // + // No, then skip over this variable in NVRAM and begin + // search again at start of variable NAME. + // + VariablePtr = Variable; + while (Index <= LastIndex) { + NvramChar = HalpDS1385ReadNVRAM(Index++); + if (NvramChar == '=') + break; + } + while (Index <= LastIndex) { + NvramChar = HalpDS1385ReadNVRAM(Index++); + if (NvramChar == 0) { + break; + } + } + } + } + + // + // The variable was not found + // + NDBG(2, DbgPrint("HalpFindEnviroVar: %s not found\n", Variable);); + return(0); +} + +// +// HalGetEnvironmentVariable +// +// Parameters: +// +// Variables: +// Supplies a pointer to the zero-terminated, case ASCII string that contains +// the name of the environment variable to be returned. +// Length - Supplies the length of the buffer in bytes. +// Buffer - Supplies a pointer to a buffer that receives the variable value. +// +// Return Value: +// If the variable, the function returns the value ESUCCESS and its +// value in Buffer. Otherwise, ENOENT is returned. +// +ULONG +HalGetEnvironmentVariable(IN CHAR *Variable, + IN USHORT Length, + OUT CHAR *Buffer) +{ + USHORT Index; + static DumpNVRAMOnce = FALSE; + ULONG retVal = ENOENT + + + NDBG(1, DbgPrint("HalpGetEnvironmentVariable: called\n");); + + // + // Check input parameters + // + if (!Variable) { + if (*Variable == 0 || Length < 1 || Buffer == NULL) { + NDBG(2, DbgPrint("HalpGetEnvironmentVariable: return ENOENT\n");); + return(retVal); + } + } + + if (!DumpNVRAMOnce) { + NDBG(2, DumpNVRAM();); + DumpNVRAMOnce = TRUE; + } + + // + // Grab control of NVRAM + // +#if USE_SPINLOCKS + KIRQL Irql; + KeAcquireSpinLock(NVRAM_Spinlock, &Irql); +#endif + NvramFailure = FALSE; + + // + // Get NVRAM index of environment variable + // + Index = HalpFindEnviroVar(Variable); + if (Index == 0) { + // + // Environment variable was not found + // +#if USE_SPINLOCKS + KeReleaseSpinLock(NVRAM_Spinlock, Irql); +#endif + return(retVal); + } + + // + // Copy the environment variable's value to Buffer + // + do { + *Buffer = HalpDS1385ReadNVRAM(Index++); + if (*Buffer++ == 0) { + if (NvramFailure == TRUE) { + retVal = ENOMEM; + } else { + retVal = ESUCCESS; + } +#if USE_SPINLOCKS + KeReleaseSpinLock(NVRAM_Spinlock, Irql); +#endif + return(retVal); + } + } while (--Length); + + // + // Truncate the returned string. The buffer was too short. + // + *--Buffer = 0; +#if USE_SPINLOCKS + KeReleaseSpinLock(NVRAM_Spinlock, Irql); +#endif + return(ENOMEM); +} + +// +// HalSetEnvironmentVariable +// +// Parameters: +// Variable +// Supplies a pointer to the zero-terminated ASCII string that contains +// the name of the environment variable to be returned. The string is +// converted to UPPER CASE. +// +// Value +// Supplies a pointer to the zero-terminated string that contains the new +// value of the environment variable. +// +// There are 4 cases: +// 1) The environment variable is deleted if Value is a null string. +// 2) The environment variable does not currently exist. It is appended +// if there is enough NVRAM available. +// 3) The environment variable already exists, and the new Value is +// shorter than the old value. +// 4) The environment variable already exists, and the new Value is longer than +// the old value. +// +// In all cases the environment space will be compressed after +// insertion/deletion. +// +ULONG +HalSetEnvironmentVariable( + IN CHAR *Variable, + IN CHAR *Value) +{ + USHORT TotalSize, FreeSize, Index; + USHORT OldLength, NewLength; + USHORT StartIndex; + USHORT i; + USHORT NameLength, ValueLength; + CHAR *VariablePtr, *ValuePtr, Char; + ARC_STATUS ReturnValue; + + + NDBG(1, DbgPrint("HalSetEnvironmentVariable: called set %s to %s\n", + Variable, Value);); + + if (Value == NULL) { + NDBG(2, DbgPrint("HalSetEnvironmentVariable: returning ENOENT\n");); + return(ENOENT); + } + + // + // Compute length of environment NAME + // + VariablePtr = Variable; + NameLength = 0; + while (*VariablePtr != 0) { + NameLength++; + VariablePtr++; + } + + // + // Compute length of environment VALUE + // + ValuePtr = Value; + ValueLength = 0; + while (*ValuePtr != 0) { + ValueLength++; + ValuePtr++; + } +#if USE_SPINLOCKS + KIRQL Irql; + KeAcquireSpinLock(NVRAM_Spinlock, &Irql); // Grab control of NVRAM +#endif + NvramFailure = FALSE; + + HalpGetEnvironmentInfo(&TotalSize, &FreeSize, NULL); + + + // Get index of environment variable + Index = HalpFindEnviroVar(Variable); + + ReturnValue = ESUCCESS; + // Index to start of NAME + StartIndex = Index-NameLength-1; + + // DELETE environment variable + if (ValueLength == 0) { + if (Index != 0) { + HalpCompressEnvironmentSpace(StartIndex); + } + } else { + // ADD or REPLACE environment variable + // Compute # bytes needed to store variable + NewLength = ValueLength + NameLength + 2; + + + // REPLACE environment variable. + // First we see if there is room. If so, delete the current + // variable & fall through to the code that ADDs a new variable. + if (Index != 0) { + // Compute current length of variable + OldLength = 0; + i = Index; + do { + OldLength++; + } while (HalpDS1385ReadNVRAM(i++) != 0); + + // Is there room for the new variable ? + if (FreeSize-NewLength+OldLength >= 0) + FreeSize += HalpCompressEnvironmentSpace(StartIndex); + } + // + // ADD environment variable + // + + if ((FreeSize-NewLength) >= 0) { // Room for new + + Index = (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GEAddress)); + Index += (USHORT) HalpReadNvramUlong((USHORT) (&NVMAP->GELength)); + Index -= FreeSize; + + // + // Write Variable NVRAM. Convert to UPPER case first. + // + while (*Variable != 0) { + Char = *Variable++; + // + // Convert Variable to UPPER case + // + Char = (Char >= 'a' && Char <= 'z') ? Char-0x20 : Char; + HalpDS1385WriteNVRAM(Index++,Char); + } + + HalpDS1385WriteNVRAM(Index++,'='); // Write a "=" + + do { + // Write VALUE to NVRAM + HalpDS1385WriteNVRAM(Index++,*Value); + } while (*Value++ != 0); + + ReturnValue = ESUCCESS; + } + } + + // + // Update NVRAM checksum + // + HalpUpdateCrc(); + if (NvramFailure == TRUE) { + ReturnValue = ENOMEM; + } +#if USE_SPINLOCKS + KeReleaseSpinLock(NVRAM_Spinlock, Irql); +#endif + return(ReturnValue); +} + + diff --git a/private/ntos/nthals/halfire/ppc/pxflshbf.s b/private/ntos/nthals/halfire/ppc/pxflshbf.s new file mode 100644 index 000000000..c4cdad4fd --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxflshbf.s @@ -0,0 +1,159 @@ +#if defined(_PPC_) + +// TITLE("Miscellaneous Kernel Functions") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxflshbf.s +// +// Abstract: +// +// This module implements the system dependent kernel function to flush +// the write buffer or otherwise synchronize writes on a Power PC +// system. +// +// +// +// Author: +// +// David N. Cutler (davec) 24-Apr-1991 +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// +// Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port +// +// Used PowerPC eieio instruction to flush writes +// +//-- + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxflshbf.s $ + * $Revision: 1.7 $ + * $Date: 1996/05/14 02:34:14 $ + * $Locker: $ + */ + +#include "kxppc.h" + +// SBTTL("Flush Write Buffer") +// +//++ +// +// NTSTATUS +// KeFlushWriteBuffer ( +// VOID +// ) +// +// Routine Description: +// +// This function flushes the write buffer on the current processor. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(KeFlushWriteBuffer) + + eieio + + + LEAF_EXIT(KeFlushWriteBuffer) + + + +// +//++ +// +// NTSTATUS +// HalpSynchronizeExecution() +// VOID +// ) +// +// Routine Description: +// +// This function flushes the write buffer on the current processor. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpSynchronizeExecution) + + sync // synchronize + + LEAF_EXIT(HalpSynchronizeExecution) + + +// +//++ +// +// NTSTATUS +// HalpGetProcessorVersion() +// VOID +// ) +// +// Routine Description: +// +// This function gets the processor version of the current processor. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + LEAF_ENTRY(HalpGetProcessorVersion) + + mfpvr r.3 // get processor version + + LEAF_EXIT(HalpGetProcessorVersion) + +// +//++ +// +// VOID +// SetSDR1( +// ULONG HashedPageTableBase, +// ULONG HashedPageTableSize +// ) +// + + LEAF_ENTRY(SetSDR1) + + subi r.4,r.4,1 + rlwimi r.3,r.4,16,0x1ff + mtsdr1 r.3 + + LEAF_EXIT(SetSDR1) + +#endif diff --git a/private/ntos/nthals/halfire/ppc/pxflshio.c b/private/ntos/nthals/halfire/ppc/pxflshio.c new file mode 100644 index 000000000..c73638505 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxflshio.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxflshio.c $ + * $Revision: 1.11 $ + * $Date: 1996/05/14 02:34:19 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + psflshio.c + +Abstract: + + This module implements miscellaneous PowerPC HAL functions. + +Author: + + Jim Wooldridge (jimw@austin.ibm.com) + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "halp.h" +#include "arccodes.h" + + + +ULONG +HalGetDmaAlignmentRequirement ( + VOID + ) + +/*++ + +Routine Description: + + This function returns the alignment requirements for DMA transfers on + host system. + +Arguments: + + None. + +Return Value: + + The DMA alignment requirement is returned as the fucntion value. + +--*/ + +{ + + return 1; +} + +VOID +HalFlushIoBuffers ( + IN PMDL Mdl, + IN BOOLEAN ReadOperation, + IN BOOLEAN DmaOperation + ) + +/*++ + +Routine Description: + + This function flushes the I/O buffer specified by the memory descriptor + list from the data cache on the current processor. + +Arguments: + + Mdl - Supplies a pointer to a memory descriptor list that describes the + I/O buffer location. + + ReadOperation - Supplies a boolean value that determines whether the I/O + operation is a read into memory. + + DmaOperation - Supplies a boolean value that determines whether the I/O + operation is a DMA operation. + +Return Value: + + None. + +--*/ + +{ + + ULONG Length; + ULONG PartialLength; + ULONG Offset; + PULONG Page; + BOOLEAN DoDcache = FALSE; + + // + // check for 601, it has a combined I and D cache that bus snoops + // + // + + if ((HalpGetProcessorVersion() >> 16) != 1) { + + Length = Mdl->ByteCount; + + if ( !Length ) { + return; + } + // + // If the I/O operation is not a DMA operation, + // and the I/O operation is a page read operation, + // then sweep (index/writeback/invalidate) the data cache. + // + if (((DmaOperation == FALSE) && + (ReadOperation != FALSE) && + ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0))) { + DoDcache = TRUE; + } + + // + // If the I/O operation is a page read, then sweep (index/invalidate) + // the range from the cache. Note it is not reasonable to sweep + // the entire cache on an MP system as "Flash Invalidate" doesn't + // broadcast the invalidate to other processors. + // + if ((ReadOperation != FALSE) && + ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0)) { + + Offset = Mdl->ByteOffset; + PartialLength = PAGE_SIZE - Offset; + if (PartialLength > Length) { + PartialLength = Length; + } + + Page = (PULONG)(Mdl + 1); + + if (DoDcache == TRUE) { + HalpSweepPhysicalRangeInBothCaches( + *Page++, + Offset, + PartialLength + ); + Length -= PartialLength; + if (Length) { + PartialLength = PAGE_SIZE; + do { + if (PartialLength > Length) { + PartialLength = Length; + } + HalpSweepPhysicalRangeInBothCaches( + *Page++, + 0, + PartialLength + ); + Length -= PartialLength; + } while (Length != 0); + } + } else { + HalpSweepPhysicalIcacheRange( + *Page++, + Offset, + PartialLength + ); + Length -= PartialLength; + if (Length) { + PartialLength = PAGE_SIZE; + do { + if (PartialLength > Length) { + PartialLength = Length; + } + HalpSweepPhysicalIcacheRange( + *Page++, + 0, + PartialLength + ); + Length -= PartialLength; + } while (Length != 0); + } + } + } + } + return; +} diff --git a/private/ntos/nthals/halfire/ppc/pxhalp.h b/private/ntos/nthals/halfire/ppc/pxhalp.h new file mode 100644 index 000000000..ee880dedf --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxhalp.h @@ -0,0 +1,291 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxhalp.h $ + * $Revision: 1.15 $ + * $Date: 1996/05/15 00:06:21 $ + * $Locker: $ + */ + +/*++ BUILD Version: 0001 // Increment this if a change has global effects + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pxhalp.h + +Abstract: + + This header file defines the private Hardware Architecture Layer (HAL) + PowerPC specific interfaces, defines and structures. + + +Author: + + Jeff Havens (jhavens) 20-Jun-91 + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port + + Added externs for HalpInterruptBase,HalpPciConfigBase + Added extern for HalpIoControlBase + Added prototype for HalpHandleDecrementerInterrupt (was in halp.h) + changed adapter object structure to be compatible with the intel HAL + +--*/ + +#ifndef _PXHALP_ +#define _PXHALP_ + + +// +// Define global data used to locate the IO control space, the interrupt +// acknowlege, and the Pci config base. +// + +extern PVOID HalpIoControlBase; +extern PVOID HalpIoMemoryBase; +extern PVOID HalpInterruptBase; +extern PVOID HalpPciConfigBase; +extern PVOID HalpErrorAddressRegister; +extern PVOID HalpPciIsaBridgeConfigBase; + +// +// prototype x86 emulator +// + +extern BOOLEAN HalpInitX86Emulator(VOID); + +// +// Define adapter object structure. +// + +// +// The MAXIMUM_MAP_BUFFER_SIZE defines the maximum map buffers which the system +// will allocate for devices which require phyically contigous buffers. +// + +#define MAXIMUM_MAP_BUFFER_SIZE 0x40000 + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_SMALL_SIZE 0x10000 + +// +// Define the initial buffer allocation size for a map buffers for systems with +// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS. +// + +#define INITIAL_MAP_BUFFER_LARGE_SIZE 0x30000 + +// +// Define the incremental buffer allocation for a map buffers. +// + +#define INCREMENT_MAP_BUFFER_SIZE 0x10000 + +// +// Define the maximum number of map registers that can be requested at one time +// if actual map registers are required for the transfer. +// + +#define MAXIMUM_ISA_MAP_REGISTER 16 + +// +// Define the maximum physical address which can be handled by an Isa card. +// + +#define MAXIMUM_PHYSICAL_ADDRESS 0x01000000 + +// +// Define the scatter/gather flag for the Map Register Base. +// + +#define NO_SCATTER_GATHER 0x00000001 + +// +// Define the copy buffer flag for the index. +// + +#define COPY_BUFFER 0XFFFFFFFF + +// +// Define adapter object structure. +// + +typedef struct _ADAPTER_OBJECT { + CSHORT Type; + CSHORT Size; + struct _ADAPTER_OBJECT *MasterAdapter; + ULONG MapRegistersPerChannel; + PVOID AdapterBaseVa; + PVOID MapRegisterBase; + ULONG NumberOfMapRegisters; + ULONG CommittedMapRegisters; + struct _WAIT_CONTEXT_BLOCK *CurrentWcb; + KDEVICE_QUEUE ChannelWaitQueue; + PKDEVICE_QUEUE RegisterWaitQueue; + LIST_ENTRY AdapterQueue; + KSPIN_LOCK SpinLock; + PRTL_BITMAP MapRegisters; + PUCHAR PagePort; + UCHAR ChannelNumber; + UCHAR AdapterNumber; + USHORT DmaPortAddress; + UCHAR AdapterMode; + BOOLEAN NeedsMapRegisters; + BOOLEAN MasterDevice; + BOOLEAN Width16Bits; + BOOLEAN ScatterGather; + BOOLEAN IsaBusMaster; + INTERFACE_TYPE InterfaceType; // spec what bus this adapter is on +} ADAPTER_OBJECT; + +// +// Define function prototypes. +// + +PADAPTER_OBJECT +HalpAllocateIsaAdapter( + IN PDEVICE_DESCRIPTION DeviceDescription, + OUT PULONG NumberOfMapRegisters + ); + +BOOLEAN +HalpCreateSioStructures( + VOID + ); + +VOID +HalpDisableSioInterrupt( + IN ULONG Vector + ); + +BOOLEAN +HalpHandleExternalInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + +BOOLEAN +HalpFieldExternalInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + +BOOLEAN +HalpHandleDecrementerInterrupt ( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ); + +VOID +HalpIsaMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +VOID +HalpEnableSioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ); + +BOOLEAN +HalpAllocateMapBuffer( + VOID + ); + +ULONG +HalpUpdateDecrementer( + ULONG + ); + +BOOLEAN +HalpPhase0MapBusConfigSpace( + VOID + ); + +VOID +HalpPhase0UnMapBusConfigSpace( + VOID + ); + +ULONG +HalpPhase0GetPciDataByOffset( + ULONG BusNumber, + ULONG SlotNumber, + PUCHAR Buffer, + ULONG Offset, + ULONG Length + ); + +ULONG +HalpPhase0SetPciDataByOffset( + ULONG BusNumber, + ULONG SlotNumber, + PUCHAR Buffer, + ULONG Offset, + ULONG Length + ); + +PVOID +KePhase0MapIo( + IN PVOID PhysicalMemoryBase, + IN ULONG MemorySize + ); + +VOID +KePhase0DeleteIoMap( + IN PVOID PhysicalMemoryBase, + IN ULONG MemorySize + ); + +ULONG +HalpCalibrateTB( + VOID + ); + +VOID +HalpZeroPerformanceCounter( + VOID + ); + +VOID +HalpResetIrqlAfterInterrupt( + KIRQL TargetIrql + ); + +VOID +HalpLockDisplayString( + PVOID + ); +BOOLEAN +HalpCacheSweepSetup( + VOID + ); + +VOID +HalpSweepPhysicalRangeInBothCaches( + ULONG Page, + ULONG Offset, + ULONG Length + ); +VOID +HalpSweepPhysicalIcacheRange( + ULONG Page, + ULONG Offset, + ULONG Length + ); +#endif // _PXHALP_ diff --git a/private/ntos/nthals/halfire/ppc/pxhwsup.c b/private/ntos/nthals/halfire/ppc/pxhwsup.c new file mode 100644 index 000000000..a96e4ff23 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxhwsup.c @@ -0,0 +1,2212 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxhwsup.c $ + * $Revision: 1.12 $ + * $Date: 1996/05/14 02:34:25 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1990-1993 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxhwsup.c + +Abstract: + + This module contains the HalpXxx routines for the NT I/O system that + are hardware dependent. Were these routines not hardware dependent, + they would normally reside in the internal.c module. + +Author: + + Jeff Havens (jhavens) 14-Feb-1990 + +Environment: + + Kernel mode, local to I/O system + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC Port + Remove support for internal bus and devices + Changed HalFreeCommonBuffer to support S-FOOT address inversion + Added PCI, PCMCIA, and ISA bus support + Removed support for internal DMA controller + Change HalTranslateBusAddress to support S-FOOTS memory map + Deleted HalpReadEisaBus - this code was specific to EISA buses + Changed IoMapTransfer to support S-FOOT address inversion + Added support for guaranteed contigous common buffers + + + +--*/ + +#include "halp.h" +#include "bugcodes.h" +#include "eisa.h" +#include "phsystem.h" + +#include "pxmemctl.h" + + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +extern POBJECT_TYPE IoAdapterObjectType; + +// +// Define map buffer variables +// + +PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress; +ULONG HalpMapBufferSize; + + + +// +// The DMA controller has a larger number of map registers which may be used +// by any adapter channel. In order to pool all of the map registers a master +// adapter object is used. This object is allocated and saved internal to this +// file. It contains a bit map for allocation of the registers and a queue +// for requests which are waiting for more map registers. This object is +// allocated during the first request to allocate an adapter. +// + +PADAPTER_OBJECT MasterAdapterObject; + +VOID +HalpCopyBufferMap( + IN PMDL Mdl, + IN PTRANSLATION_ENTRY TranslationEntry, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ); + +BOOLEAN +HalpGrowMapBuffers( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Amount + ); + + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ); + + +/*++ + +Routine Description: NTSTATUS HalAllocateAdapterChannel() + + This routine allocates the adapter channel specified by the adapter object. + This is accomplished by placing the device object of the driver that wants + to allocate the adapter on the adapter's queue. If the queue is already + "busy", then the adapter has already been allocated, so the device object + is simply placed onto the queue and waits until the adapter becomes free. + + Once the adapter becomes free (or if it already is), then the driver's + execution routine is invoked. + + Also, a number of map registers may be allocated to the driver by specifying + a non-zero value for NumberOfMapRegisters. Then the map register must be + allocated from the master adapter. Once there are a sufficient number of + map registers available, then the execution routine is called and the + base address of the allocated map registers in the adapter is also passed + to the driver's execution routine. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + + Wcb - Supplies a wait context block for saving the allocation parameters. + The DeviceObject, CurrentIrp and DeviceContext should be initalized. + + NumberOfMapRegisters - The number of map registers that are to be allocated + from the channel, if any. + + ExecutionRoutine - The address of the driver's execution routine that is + invoked once the adapter channel (and possibly map registers) have been + allocated. + +Return Value: + + Returns STATUS_SUCESS unless too many map registers are requested. + +Notes: + + Note that this routine MUST be invoked at DISPATCH_LEVEL or above. + +--*/ + +NTSTATUS +HalAllocateAdapterChannel( + IN PADAPTER_OBJECT AdapterObject, + IN PWAIT_CONTEXT_BLOCK Wcb, + IN ULONG NumberOfMapRegisters, + IN PDRIVER_CONTROL ExecutionRoutine + ) +{ + + PADAPTER_OBJECT MasterAdapter; + BOOLEAN Busy = FALSE; + IO_ALLOCATION_ACTION Action; + KIRQL Irql; + ULONG MapRegisterNumber; + + // + // Begin by obtaining a pointer to the master adapter associated with this + // request. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Initialize the device object's wait context block in case this device + // must wait before being able to allocate the adapter. + // + + Wcb->DeviceRoutine = ExecutionRoutine; + Wcb->NumberOfMapRegisters = NumberOfMapRegisters; + + // + // Allocate the adapter object for this particular device. If the + // adapter cannot be allocated because it has already been allocated + // to another device, then return to the caller now; otherwise, + // continue. + // + + if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue, + &Wcb->WaitQueueEntry )) { + + // + // Save the parameters in case there are not enough map registers. + // + + AdapterObject->NumberOfMapRegisters = NumberOfMapRegisters; + AdapterObject->CurrentWcb = Wcb; + + // + // The adapter was not busy so it has been allocated. Now check + // to see whether this driver wishes to allocate any map registers. + // Ensure that this adapter has enough total map registers + // to satisfy the request. + // + + if (NumberOfMapRegisters != 0 && AdapterObject->NeedsMapRegisters) { + + // + // Lock the map register bit map and the adapter queue in the + // master adapter object. The channel structure offset is used as + // a hint for the register search. + // + + if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + return(STATUS_INSUFFICIENT_RESOURCES); + } + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + MapRegisterNumber = (ULONG)-1; + + if (IsListEmpty( &MasterAdapter->AdapterQueue)) { + + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + NumberOfMapRegisters, + 0 + ); + } + + if (MapRegisterNumber == (ULONG)-1) { + + // + // There were not enough free map registers. Queue this request + // on the master adapter where is will wait until some registers + // are deallocated. + // + + InsertTailList( &MasterAdapter->AdapterQueue, + &AdapterObject->AdapterQueue + ); + Busy = 1; + + } else { + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (!Busy) { + + AdapterObject->CurrentWcb = Wcb; + Action = ExecutionRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the driver would like to have the adapter deallocated, + // then release the adapter object. + // + + if (Action == DeallocateObject) { + + IoFreeAdapterChannel( AdapterObject ); + + } else if (Action == DeallocateObjectKeepRegisters) { + + // + // Set the NumberOfMapRegisters = 0 in the adapter object. + // This will keep IoFreeAdapterChannel from freeing the + // registers. After this it is the driver's responsiblity to + // keep track of the number of map registers. + // + + AdapterObject->NumberOfMapRegisters = 0; + IoFreeAdapterChannel(AdapterObject); + + } + } + } + else + { + HalpPrint("KeInsertDeviceQueue: branch not taken \n"); + } +return(STATUS_SUCCESS); + +} + +/*++ + +Routine Description: PVOID HalAllocateCommonBuffer() + + This function allocates the memory for a common buffer and maps so that it + can be accessed by a master device and the CPU. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer to be allocated. + + LogicalAddress - Returns the logical address of the common buffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + Returns the virtual address of the common buffer. If the buffer cannot be + allocated then NULL is returned. + +--*/ + +PVOID +HalAllocateCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + OUT PPHYSICAL_ADDRESS LogicalAddress, + IN BOOLEAN CacheEnabled + ) +{ + PVOID virtualAddress; + PHYSICAL_ADDRESS physicalAddress; + + + // + // Allocate the actual buffer. + // + + + physicalAddress.LowPart = 0xFFFFFFFF; + physicalAddress.HighPart = 0; + + virtualAddress = MmAllocateContiguousMemory( + Length, + physicalAddress + ); + + if (virtualAddress == NULL) { + return(NULL); + } + + + + + // + // Memory space inverion + // + + + + *LogicalAddress = MmGetPhysicalAddress(virtualAddress); + + if (!AdapterObject->IsaBusMaster) { + LogicalAddress->LowPart |= IO_CONTROL_PHYSICAL_BASE; + } + + // + // The allocation completed successfully. + // + + return(virtualAddress); + +} + +/*++ + +Routine Description: PVOID HalAllocateCrashDumpRegisters() + + This routine is called during the crash dump disk driver's initialization + to allocate a number map registers permanently. + +Arguments: + + AdapterObject - Pointer to the adapter control object to allocate to the + driver. + NumberOfMapRegisters - Number of map registers requested. If not all of + the registers could be allocated this field is updated to show how + many were. + +Return Value: + + Returns STATUS_SUCESS if map registers allocated. + +--*/ + +PVOID +HalAllocateCrashDumpRegisters( + IN PADAPTER_OBJECT AdapterObject, + IN PULONG NumberOfMapRegisters + ) +{ + PADAPTER_OBJECT MasterAdapter; + ULONG MapRegisterNumber; + + // + // Begin by obtaining a pointer to the master adapter associated with this + // request. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Check to see whether this driver needs to allocate any map registers. + // + + if (AdapterObject->NeedsMapRegisters) { + + // + // Ensure that this adapter has enough total map registers to satisfy + // the request. + // + + if (*NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) { + AdapterObject->NumberOfMapRegisters = 0; + return NULL; + } + + // + // Attempt to allocate the required number of map registers w/o + // affecting those registers that were allocated when the system + // crashed. + // + + MapRegisterNumber = (ULONG)-1; + + MapRegisterNumber = RtlFindClearBitsAndSet( + MasterAdapter->MapRegisters, + *NumberOfMapRegisters, + 0 + ); + + if (MapRegisterNumber == (ULONG)-1) { + + // + // Not enough free map registers were found, so they were busy + // being used by the system when it crashed. Force the appropriate + // number to be "allocated" at the base by simply overjamming the + // bits and return the base map register as the start. + // + + RtlSetBits( + MasterAdapter->MapRegisters, + 0, + *NumberOfMapRegisters + ); + MapRegisterNumber = 0; + + } + + // + // Calculate the map register base from the allocated map + // register and base of the master adapter object. + // + + AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + } + + return AdapterObject->MapRegisterBase; +} + +/*++ + +Routine Description: BOOLEAN HalFlushCommonBuffer() + + This function is called to flush any hardware adapter buffers when the + driver needs to read data written by an I/O master device to a common + buffer. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + +Return Value: + + Returns TRUE if no errors were detected; otherwise, FALSE is return. + +--*/ + +BOOLEAN +HalFlushCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress + ) +{ + + return(TRUE); + +} + +/*++ + +Routine Description: VOID HalFreeCommonBuffer() + + This function frees a common buffer and all of the resouces it uses. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object used by this + device. + + Length - Supplies the length of the common buffer. This should be the same + value used for the allocation of the buffer. + + LogicalAddress - Supplies the logical address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + VirtualAddress - Supplies the virtual address of the common buffer. This + must be the same value return by HalAllocateCommonBuffer. + + CacheEnable - Indicates whether the memeory is cached or not. + +Return Value: + + None + +--*/ + +VOID +HalFreeCommonBuffer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Length, + IN PHYSICAL_ADDRESS LogicalAddress, + IN PVOID VirtualAddress, + IN BOOLEAN CacheEnabled + ) +{ + + + UNREFERENCED_PARAMETER( AdapterObject ); + UNREFERENCED_PARAMETER( Length ); + UNREFERENCED_PARAMETER( LogicalAddress ); + UNREFERENCED_PARAMETER( CacheEnabled ); + + MmFreeContiguousMemory (VirtualAddress); + + return; + +} + +/*++ + +Routine Description: PADAPTER_OBJECT HalGetAdapter() + + This function returns the appropriate adapter object for the device defined + in the device description structure. Three bus types are supported for the + system: PCI, Isa. + +Arguments: + + DeviceDescription - Supplies a description of the deivce. + + NumberOfMapRegisters - Returns the maximum number of map registers which + may be allocated by the device driver. + +Return Value: + + A pointer to the requested adapter object or NULL if an adapter could not + be created. + +--*/ + +PADAPTER_OBJECT +HalGetAdapter( + IN PDEVICE_DESCRIPTION DeviceDescription, + IN OUT PULONG NumberOfMapRegisters + ) +{ + PADAPTER_OBJECT adapterObject; + + // + // Make sure this is the correct version. + // + + if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION1) { + + return(NULL); + + } + + + // + // If the request is for a unsupported bus then return NULL. + // + + + if (DeviceDescription->InterfaceType != Isa && + DeviceDescription->InterfaceType != PCIBus && + DeviceDescription->InterfaceType != PCMCIABus) { + + // + // This bus type is unsupported return NULL. + // + + return(NULL); + } + + // + // Create an adapter object. + // + + adapterObject = HalpAllocateIsaAdapter( DeviceDescription, + NumberOfMapRegisters); + return(adapterObject); +} + + +/*++ + +Routine Description: PADAPTER_OBJECT HalpAllocateAdapter() + + This routine allocates and initializes an adapter object to represent an + adapter or a DMA controller on the system. If no map registers are required + then a standalone adapter object is allocated with no master adapter. + + If map registers are required, then a master adapter object is used to + allocate the map registers. For Isa systems these registers are really + phyically contiguous memory pages. + +Arguments: + + MapRegistersPerChannel - Specifies the number of map registers that each + channel provides for I/O memory mapping. + + AdapterBaseVa - Address of the the DMA controller. + + ChannelNumber - Unused. + +Return Value: + + The function value is a pointer to the allocate adapter object. + +--*/ + +PADAPTER_OBJECT +HalpAllocateAdapter( + IN ULONG MapRegistersPerChannel, + IN PVOID AdapterBaseVa, + IN PVOID ChannelNumber + ) +{ + + PADAPTER_OBJECT AdapterObject; + OBJECT_ATTRIBUTES ObjectAttributes; + ULONG Size; + ULONG BitmapSize; + HANDLE Handle; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(ChannelNumber); + + // + // Initalize the master adapter if necessary. + // + + if (MasterAdapterObject == NULL && AdapterBaseVa != NULL ) { + + MasterAdapterObject = HalpAllocateAdapter( + MapRegistersPerChannel, + NULL, + NULL + ); + + // + // If we could not allocate the master adapter then give up. + // + if (MasterAdapterObject == NULL) { + return(NULL); + } + } + + // + // Begin by initializing the object attributes structure to be used when + // creating the adapter object. + // + + InitializeObjectAttributes( &ObjectAttributes, + NULL, + OBJ_PERMANENT, + (HANDLE) NULL, + (PSECURITY_DESCRIPTOR) NULL + ); + + // + // Determine the size of the adapter object. If this is the master object + // then allocate space for the register bit map; otherwise, just allocate + // an adapter object. + // + if (AdapterBaseVa == NULL) { + + // + // Allocate a bit map large enough MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE + // of map register buffers. + // + + BitmapSize = (((sizeof( RTL_BITMAP ) + + (( MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE ) + 7 >> 3)) + 3) & ~3); + + Size = sizeof( ADAPTER_OBJECT ) + BitmapSize; + + } else { + + Size = sizeof( ADAPTER_OBJECT ); + + } + + // + // Now create the adapter object. + // + + Status = ObCreateObject( KernelMode, + *((POBJECT_TYPE *)IoAdapterObjectType), + &ObjectAttributes, + KernelMode, + (PVOID) NULL, + Size, + 0, + 0, + (PVOID *)&AdapterObject ); + + // + // Reference the object. + // + + if (NT_SUCCESS(Status)) { + + Status = ObReferenceObjectByPointer( + AdapterObject, + FILE_READ_DATA | FILE_WRITE_DATA, + *((POBJECT_TYPE *)IoAdapterObjectType), + KernelMode + ); + + } + + // + // If the adapter object was successfully created, then attempt to insert + // it into the the object table. + // + + if (NT_SUCCESS( Status )) { + + Status = ObInsertObject( AdapterObject, + NULL, + FILE_READ_DATA | FILE_WRITE_DATA, + 0, + (PVOID *) NULL, + &Handle ); + + if (NT_SUCCESS( Status )) { + + ZwClose( Handle ); + + // + // Initialize the adapter object itself. + // + + AdapterObject->Type = IO_TYPE_ADAPTER; + AdapterObject->Size = (USHORT) Size; + AdapterObject->MapRegistersPerChannel = 1; + AdapterObject->AdapterBaseVa = AdapterBaseVa; + AdapterObject->PagePort = NULL; + AdapterObject->IsaBusMaster = FALSE; + + if (MapRegistersPerChannel) { + + AdapterObject->MasterAdapter = MasterAdapterObject; + + } else { + + AdapterObject->MasterAdapter = NULL; + + } + + // + // Initialize the channel wait queue for this + // adapter. + // + + KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue ); + + // + // If this is the MasterAdatper then initialize the register bit map, + // AdapterQueue and the spin lock. + // + + if ( AdapterBaseVa == NULL ) { + + KeInitializeSpinLock( &AdapterObject->SpinLock ); + + InitializeListHead( &AdapterObject->AdapterQueue ); + + AdapterObject->MapRegisters = (PVOID) ( AdapterObject + 1); + + RtlInitializeBitMap( AdapterObject->MapRegisters, + (PULONG) (((PCHAR) (AdapterObject->MapRegisters)) + sizeof( RTL_BITMAP )), + ( MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE ) + ); + // + // Set all the bits in the memory to indicate that memory + // has not been allocated for the map buffers + // + + RtlSetAllBits( AdapterObject->MapRegisters ); + AdapterObject->NumberOfMapRegisters = 0; + AdapterObject->CommittedMapRegisters = 0; + + // + // ALlocate the memory map registers. + // + + AdapterObject->MapRegisterBase = ExAllocatePool( + NonPagedPool, + (MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY) + ); + + if (AdapterObject->MapRegisterBase == NULL) { + + ObDereferenceObject( AdapterObject ); + AdapterObject = NULL; + return(NULL); + + } + + // + // Zero the map registers. + // + + RtlZeroMemory( + AdapterObject->MapRegisterBase, + (MAXIMUM_MAP_BUFFER_SIZE / PAGE_SIZE) * + sizeof(TRANSLATION_ENTRY) + ); + + if (!HalpGrowMapBuffers(AdapterObject, INITIAL_MAP_BUFFER_SMALL_SIZE)) + { + + // + // If no map registers could be allocated then free the + // object. + // + + ObDereferenceObject( AdapterObject ); + AdapterObject = NULL; + return(NULL); + + } + } + + } else { + + // + // An error was incurred for some reason. Set the return value + // to NULL. + // + + AdapterObject = (PADAPTER_OBJECT) NULL; + } + } else { + + AdapterObject = (PADAPTER_OBJECT) NULL; + + } + + + return AdapterObject; + +} + +/*++ + +Routine Description: VOID IoFreeMapRegisters() + + This routine deallocates the map registers for the adapter. If there are + any queued adapter waiting for an attempt is made to allocate the next + entry. + +Arguments: + + AdapterObject - The adapter object to where the map register should be + returned. + + MapRegisterBase - The map register base of the registers to be deallocated. + + NumberOfMapRegisters - The number of registers to be deallocated. + +Return Value: + + None + +--+*/ + +VOID +IoFreeMapRegisters( + PADAPTER_OBJECT AdapterObject, + PVOID MapRegisterBase, + ULONG NumberOfMapRegisters + ) +{ + PADAPTER_OBJECT MasterAdapter; + LONG MapRegisterNumber; + PWAIT_CONTEXT_BLOCK Wcb; + PLIST_ENTRY Packet; + IO_ALLOCATION_ACTION Action; + KIRQL Irql; + + + // + // Begin by getting the address of the master adapter. + // + + if (AdapterObject->MasterAdapter != NULL && MapRegisterBase != NULL) { + + MasterAdapter = AdapterObject->MasterAdapter; + + } else { + + // + // There are no map registers to return. + // + + return; + } + + // + // Strip no scatter/gather flag. + // + + MapRegisterBase = (PVOID) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + MapRegisterNumber = (PTRANSLATION_ENTRY) MapRegisterBase - + (PTRANSLATION_ENTRY) MasterAdapter->MapRegisterBase; + + // + // Acquire the master adapter spinlock which locks the adapter queue and the + // bit map for the map registers. + // + + KeAcquireSpinLock(&MasterAdapter->SpinLock, &Irql); + + // + // Return the registers to the bit map. + // + + RtlClearBits( MasterAdapter->MapRegisters, + MapRegisterNumber, + NumberOfMapRegisters + ); + + // + // Process any requests waiting for map registers in the adapter queue. + // Requests are processed until a request cannot be satisfied or until + // there are no more requests in the queue. + // + + while(TRUE) { + + if ( IsListEmpty(&MasterAdapter->AdapterQueue) ){ + break; + } + + Packet = RemoveHeadList( &MasterAdapter->AdapterQueue ); + AdapterObject = CONTAINING_RECORD( Packet, + ADAPTER_OBJECT, + AdapterQueue + ); + Wcb = AdapterObject->CurrentWcb; + + // + // Attempt to allocate map registers for this request. Use the previous + // register base as a hint. + // + + MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters, + AdapterObject->NumberOfMapRegisters, + MasterAdapter->NumberOfMapRegisters + ); + + if (MapRegisterNumber == -1) { + + // + // There were not enough free map registers. Put this request back on + // the adapter queue where is came from. + // + + InsertHeadList( &MasterAdapter->AdapterQueue, + &AdapterObject->AdapterQueue + ); + + break; + + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + + // + // Invoke the driver's execution routine now. + // + + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the driver wishes to keep the map registers then set the number + // allocated to zero and set the action to deallocate object. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + Action = DeallocateObject; + } + + // + // If the driver would like to have the adapter deallocated, + // then deallocate any map registers allocated and then release + // the adapter object. + // + + if (Action == DeallocateObject) { + + // + // The map registers registers are deallocated here rather than in + // IoFreeAdapterChannel. This limits the number of times + // this routine can be called recursively possibly overflowing + // the stack. The worst case occurs if there is a pending + // request for the adapter that uses map registers and whos + // excution routine decallocates the adapter. In that case if there + // are no requests in the master adapter queue, then IoFreeMapRegisters + // will get called again. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + + // + // Deallocate the map registers and clear the count so that + // IoFreeAdapterChannel will not deallocate them again. + // + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + RtlClearBits( MasterAdapter->MapRegisters, + MapRegisterNumber, + AdapterObject->NumberOfMapRegisters + ); + + AdapterObject->NumberOfMapRegisters = 0; + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + } + + IoFreeAdapterChannel( AdapterObject ); + } + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); +} + + +/*++ + +Routine Description: VOID IoFreeAdapterChannel() + + This routine is invoked to deallocate the specified adapter object. + Any map registers that were allocated are also automatically deallocated. + No checks are made to ensure that the adapter is really allocated to + a device object. However, if it is not, then kernel will bugcheck. + + If another device is waiting in the queue to allocate the adapter object + it will be pulled from the queue and its execution routine will be + invoked. + +Arguments: + + AdapterObject - Pointer to the adapter object to be deallocated. + +Return Value: + + None. + +--*/ + +VOID +IoFreeAdapterChannel( + IN PADAPTER_OBJECT AdapterObject + ) +{ + PKDEVICE_QUEUE_ENTRY Packet; + PWAIT_CONTEXT_BLOCK Wcb; + PADAPTER_OBJECT MasterAdapter; + BOOLEAN Busy = FALSE; + IO_ALLOCATION_ACTION Action; + KIRQL Irql; + LONG MapRegisterNumber; + + // + // Begin by getting the address of the master adapter. + // + + MasterAdapter = AdapterObject->MasterAdapter; + + // + // Pull requests of the adapter's device wait queue as long as the + // adapter is free and there are sufficient map registers available. + // + + while( TRUE ) { + + // + // Begin by checking to see whether there are any map registers that + // need to be deallocated. If so, then deallocate them now. + // + + if (AdapterObject->NumberOfMapRegisters != 0) { + IoFreeMapRegisters( AdapterObject, + AdapterObject->MapRegisterBase, + AdapterObject->NumberOfMapRegisters + ); + } + + // + // Simply remove the next entry from the adapter's device wait queue. + // If one was successfully removed, allocate any map registers that it + // requires and invoke its execution routine. + // + + Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue ); + if (Packet == NULL) { + + // + // There are no more requests break out of the loop. + // + + break; + } + + Wcb = CONTAINING_RECORD( Packet, + WAIT_CONTEXT_BLOCK, + WaitQueueEntry ); + + AdapterObject->CurrentWcb = Wcb; + AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters; + + // + // Check to see whether this driver wishes to allocate any map + // registers. If so, then queue the device object to the master + // adapter queue to wait for them to become available. If the driver + // wants map registers, ensure that this adapter has enough total + // map registers to satisfy the request. + // + + if (Wcb->NumberOfMapRegisters != 0 && + AdapterObject->MasterAdapter != NULL) { + + // + // Lock the map register bit map and the adapter queue in the + // master adapter object. The channel structure offset is used as + // a hint for the register search. + // + + KeAcquireSpinLock( &MasterAdapter->SpinLock, &Irql ); + + MapRegisterNumber = -1; + + if (IsListEmpty( &MasterAdapter->AdapterQueue)) { + MapRegisterNumber = RtlFindClearBitsAndSet( MasterAdapter->MapRegisters, + Wcb->NumberOfMapRegisters, + 0 + ); + } + if (MapRegisterNumber == -1) { + + // + // There were not enough free map registers. Queue this request + // on the master adapter where is will wait until some registers + // are deallocated. + // + + InsertTailList( &MasterAdapter->AdapterQueue, + &AdapterObject->AdapterQueue + ); + Busy = 1; + + } else { + + AdapterObject->MapRegisterBase = ((PTRANSLATION_ENTRY) + MasterAdapter->MapRegisterBase + MapRegisterNumber); + + // + // Set the no scatter/gather flag if scatter/gather not + // supported. + // + + if (!AdapterObject->ScatterGather) { + + AdapterObject->MapRegisterBase = (PVOID) + ((ULONG) AdapterObject->MapRegisterBase | NO_SCATTER_GATHER); + + } + } + + KeReleaseSpinLock( &MasterAdapter->SpinLock, Irql ); + + } else { + + AdapterObject->MapRegisterBase = NULL; + AdapterObject->NumberOfMapRegisters = 0; + + } + + // + // If there were either enough map registers available or no map + // registers needed to be allocated, invoke the driver's execution + // routine now. + // + + if (!Busy) { + AdapterObject->CurrentWcb = Wcb; + Action = Wcb->DeviceRoutine( Wcb->DeviceObject, + Wcb->CurrentIrp, + AdapterObject->MapRegisterBase, + Wcb->DeviceContext ); + + // + // If the execution routine would like to have the adapter + // deallocated, then release the adapter object. + // + + if (Action == KeepObject) { + + // + // This request wants to keep the channel a while so break + // out of the loop. + // + + break; + + } + + // + // If the driver wants to keep the map registers then set the + // number allocated to 0. This keeps the deallocation routine + // from deallocating them. + // + + if (Action == DeallocateObjectKeepRegisters) { + AdapterObject->NumberOfMapRegisters = 0; + } + + } else { + + // + // This request did not get the requested number of map registers so + // out of the loop. + // + + break; + } + } +} + +/*++ + +Routine Description: PHYSICAL_ADDRESS IoMapTransfer() + + This routine is invoked to set up the map registers in the DMA controller + to allow a transfer to or from a device. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel that has been allocated. + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + MapRegisterBase - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - Supplies the length of the transfer. This determines the + number of map registers that need to be written to map the transfer. + Returns the length of the transfer which was actually mapped. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + +Return Value: + + Returns the logical address that should be used bus master controllers. + +--*/ + +PHYSICAL_ADDRESS +IoMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN OUT PULONG Length, + IN BOOLEAN WriteToDevice + ) +{ + + ULONG pageOffset; + ULONG index; + ULONG transferLength; + PULONG pageFrame; + ULONG logicalAddress; + PTRANSLATION_ENTRY translationEntry; + BOOLEAN useBuffer; + PHYSICAL_ADDRESS returnAddress; + + + pageOffset = BYTE_OFFSET(CurrentVa); + + // + // Calculate how much of the transfer is contiguous. + // + + transferLength = PAGE_SIZE - pageOffset; + pageFrame = (PULONG)(Mdl+1); + pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT; + logicalAddress = ((*pageFrame << PAGE_SHIFT) + pageOffset) | IO_CONTROL_PHYSICAL_BASE; + + while( transferLength < *Length ){ + + if (*pageFrame + 1 != *(pageFrame + 1)) { + break; + } + + transferLength += PAGE_SIZE; + pageFrame++; + + } + + + // + // Limit the transferLength to the requested Length. + // + + transferLength = transferLength > *Length ? *Length : transferLength; + + // + // Determine if the data transfer needs to use the map buffer. + // + + if (MapRegisterBase != NULL) { + + // + // Strip no scatter/gather flag. + // +// #pragma message(REVIEW "No Scatter Gather currently: Fix it soon?") +// #pragma NOTE("No Scatter Gather currently: Fix it soon?") + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER + && transferLength < *Length) { + + // + // do the memory inversion on the logical address + // + + logicalAddress = ( translationEntry->PhysicalAddress + pageOffset) + | IO_CONTROL_PHYSICAL_BASE; + translationEntry->Index = COPY_BUFFER; + index = 0; + transferLength = *Length; + useBuffer = TRUE; + + } else { + + // + // If there are map registers, then update the index to indicate + // how many have been used. + // + + useBuffer = FALSE; + index = translationEntry->Index; + translationEntry->Index += ADDRESS_AND_SIZE_TO_SPAN_PAGES( + CurrentVa, + transferLength + ); + } + + // + // ISA masters require memory to be at less than 16 MB. + // always use map buffers for ISA busmasters + // + + if (((logicalAddress+transferLength) & ~IO_CONTROL_PHYSICAL_BASE) + >= MAXIMUM_PHYSICAL_ADDRESS) { + + logicalAddress = (translationEntry + index)->PhysicalAddress + + pageOffset | IO_CONTROL_PHYSICAL_BASE; + + useBuffer = TRUE; + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) { + + translationEntry->Index = COPY_BUFFER; + index = 0; + + } + + } + + // + // Copy the data if necessary. + // + + if (useBuffer && WriteToDevice) { + + HalpCopyBufferMap( + Mdl, + translationEntry + index, + CurrentVa, + *Length, + WriteToDevice + ); + + } + } + + // + // Return the length. + // + + *Length = transferLength; + + // + // We only support 32 bits, but the return is 64. Just + // zero extend + // + + if (AdapterObject != NULL) { + if (AdapterObject->IsaBusMaster == TRUE) { + returnAddress.LowPart = logicalAddress & ~IO_CONTROL_PHYSICAL_BASE; + } + else { + returnAddress.LowPart = logicalAddress; + } + } + else { + returnAddress.LowPart = logicalAddress; + } + returnAddress.HighPart = 0; + + // + // If no adapter was specificed then there is no more work to do so + // return. + // + + if (AdapterObject == NULL || AdapterObject->MasterDevice) { + + } else { + + + HalpIsaMapTransfer( + AdapterObject, + logicalAddress, + *Length, + WriteToDevice + ); + } + + + return(returnAddress); +} + + +/*++ + +Routine Description: BOOLEAN IoFlushAdapterBuffers() + + This routine flushes the DMA adapter object buffers. For the Jazz system + its clears the enable flag which aborts the dma. + +Arguments: + + AdapterObject - Pointer to the adapter object representing the DMA + controller channel. + + Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down + buffer to/from which the I/O occured. + + MapRegisterBase - A pointer to the base of the map registers in the adapter + or DMA controller. + + CurrentVa - The current virtual address in the buffer described the the Mdl + where the I/O operation occurred. + + Length - Supplies the length of the transfer. + + WriteToDevice - Supplies a BOOLEAN value that indicates the direction of + the data transfer was to the device. + +Return Value: + + TRUE - No errors are detected so the transfer must succeed. + +--*/ + +BOOLEAN +IoFlushAdapterBuffers( + IN PADAPTER_OBJECT AdapterObject, + IN PMDL Mdl, + IN PVOID MapRegisterBase, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) +{ + PTRANSLATION_ENTRY translationEntry; + PULONG pageFrame; + ULONG transferLength; + ULONG partialLength; + BOOLEAN masterDevice; + + masterDevice = AdapterObject == NULL || AdapterObject->MasterDevice ? + TRUE : FALSE; + + // + // If this is a slave device, then stop the DMA controller. + // + + if (!masterDevice) { + + // + // Mask the DMA request line so that DMA requests cannot occur. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_PORT_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber) + ); + + } + + } + + if (MapRegisterBase == NULL) { + return(TRUE); + } + + // + // Determine if the data needs to be copied to the orginal buffer. + // This only occurs if the data tranfer is from the device, the + // MapReisterBase is not NULL and the transfer spans a page. + // + + if (!WriteToDevice) { + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + // + // If this is not a master device, then just transfer the buffer. + // + + if ((ULONG) MapRegisterBase & NO_SCATTER_GATHER) { + + if (translationEntry->Index == COPY_BUFFER) { + + if (!masterDevice) { + + // + // Copy only the bytes that have actually been transfered. + // + + Length -= HalReadDmaCounter(AdapterObject); + + } + + // + // The adapter does not support scatter/gather copy the buffer. + // + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + Length, + WriteToDevice + ); + + } + + } else { + + // + // Cycle through the pages of the transfer to determine if there + // are any which need to be copied back. + // + + transferLength = PAGE_SIZE - BYTE_OFFSET(CurrentVa); + partialLength = transferLength; + pageFrame = (PULONG)(Mdl+1); + pageFrame += ((ULONG) CurrentVa - (ULONG) Mdl->StartVa) >> PAGE_SHIFT; + + while( transferLength <= Length ){ + + if (*pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) { + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + + (PCCHAR) CurrentVa += partialLength; + partialLength = PAGE_SIZE; + + // + // Note that transferLength indicates the amount which will be + // transfered after the next loop; thus, it is updated with the + // new partial length. + // + + transferLength += partialLength; + pageFrame++; + translationEntry++; + } + + // + // Process the any remaining residue. + // + + partialLength = Length - transferLength + partialLength; + + if (partialLength && *pageFrame >= BYTES_TO_PAGES(MAXIMUM_PHYSICAL_ADDRESS)) { + + HalpCopyBufferMap( + Mdl, + translationEntry, + CurrentVa, + partialLength, + WriteToDevice + ); + + } + } + } + + // + // Strip no scatter/gather flag. + // + + translationEntry = (PTRANSLATION_ENTRY) ((ULONG) MapRegisterBase & ~NO_SCATTER_GATHER); + + // + // Clear index in map register. + // + + translationEntry->Index = 0; + + return TRUE; +} + + +/*++ + +Routine Description: IO_ALLOCATION_ACTION HalpAllocationRoutine () + + This function is called by HalAllocateAdapterChannel when sufficent resources + are available to the driver. This routine saves the MapRegisterBase, + and set the event pointed to by the context parameter. + +Arguments: + + DeviceObject - Supplies a pointer where the map register base should be + stored. + + Irp - Unused. + + MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer. + + Context - Supplies a pointer to an event which is set to indicate the + AdapterObject has been allocated. + +Return Value: + + DeallocateObjectKeepRegisters - Indicates the adapter should be freed + and mapregisters should remain allocated after return. + +--*/ + +IO_ALLOCATION_ACTION +HalpAllocationRoutine ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ) +{ + + UNREFERENCED_PARAMETER(Irp); + + *((PVOID *) DeviceObject) = MapRegisterBase; + + (VOID) KeSetEvent( (PKEVENT) Context, 0L, FALSE ); + + return(DeallocateObjectKeepRegisters); +} + + +/*++ + +Routine Description: BOOLEAN HalpHandleMachineCheck() + + This function is called when a PPC Machine Check interrupt occurs. + It print the appropriate status information and bugchecks. + +Arguments: + + Interrupt - Supplies a pointer to the interrupt object + + ServiceContext - Unused + +Return Value: + + Returns TRUE. + +--*/ + +BOOLEAN +HalpHandleMachineCheck( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ) +{ + KIRQL OldIrql; + // + // raise irql to machine check level + // + + KeRaiseIrql(MACHINE_CHECK_LEVEL,&OldIrql); + + // + // check memory controller machine check sources + // + + // do not call this function now. + // + // HalpHandleMemoryError(); + // + // check Bus NMI sources + // + + HalpHandleIoError(); + + // + // Bug check + // + + KeBugCheck(NMI_HARDWARE_FAILURE); + + KeLowerIrql(OldIrql); + + return(TRUE); +} + + + +/*++ + +Routine Description: BOOLEAN HalpAllocateMapBuffer() + + This routine allocates the required map buffers. + + +Arguments: + + +Return Value: + + TRUE - success + FALSE - failure + +--*/ + +BOOLEAN +HalpAllocateMapBuffer( + VOID + ) +{ + + PVOID virtualAddress; + + // + // Allocate map buffers for the adapter objects + // + + HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE; + + HalpMapBufferPhysicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS; + HalpMapBufferPhysicalAddress.HighPart = 0; + + virtualAddress = MmAllocateContiguousMemory( + HalpMapBufferSize, + HalpMapBufferPhysicalAddress + ); + + if (virtualAddress == NULL) { + + // + // There was not a satisfactory block. Clear the allocation. + // + + HalpMapBufferSize = 0; + return FALSE; + + } + + HalpMapBufferPhysicalAddress = MmGetPhysicalAddress(virtualAddress); + + return TRUE; +} + + +/*++ + +Routine Description: VOID HalpCopyBufferMap() + + This routine copies the speicific data between the user's buffer and the + map register buffer. First a the user buffer is mapped if necessary, then + the data is copied. Finally the user buffer will be unmapped if + neccessary. + +Arguments: + + Mdl - Pointer to the MDL that describes the pages of memory that are + being read or written. + + TranslationEntry - The address of the base map register that has been + allocated to the device driver for use in mapping the transfer. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - The length of the transfer. This determines the number of map + registers that need to be written to map the transfer. + + WriteToDevice - Boolean value that indicates whether this is a write + to the device from memory (TRUE), or vice versa. + +Return Value: + + None. + +--*/ + +VOID +HalpCopyBufferMap( + IN PMDL Mdl, + IN PTRANSLATION_ENTRY TranslationEntry, + IN PVOID CurrentVa, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) +{ + PCCHAR bufferAddress; + PCCHAR mapAddress; + + // + // Get the system address of the MDL. + // + + bufferAddress = MmGetSystemAddressForMdl(Mdl); + + // + // Calculate the actual start of the buffer based on the system VA and + // the current VA. + // + + bufferAddress += (PCCHAR) CurrentVa - (PCCHAR) MmGetMdlVirtualAddress(Mdl); + + mapAddress = (PCCHAR) TranslationEntry->VirtualAddress + + BYTE_OFFSET(CurrentVa); + + // + // Copy the data between the user buffer and map buffer + // + + if (WriteToDevice) { + + RtlMoveMemory( mapAddress, bufferAddress, Length); + + } else { + + RtlMoveMemory(bufferAddress, mapAddress, Length); + + } + +} +/*++ + +Routine Description: BOOLEAN HalpGrowMapBuffers() + + This function attempts to allocate additional map buffers for use by I/O + devices. The map register table is updated to indicate the additional + buffers. + +Arguments: + + AdapterObject - Supplies the adapter object for which the buffers are to be + allocated. + + Amount - Indicates the size of the map buffers which should be allocated. + +Return Value: + + TRUE is returned if the memory could be allocated. + + FALSE is returned if the memory could not be allocated. + +--*/ + +BOOLEAN +HalpGrowMapBuffers( + PADAPTER_OBJECT AdapterObject, + ULONG Amount + ) +{ + ULONG MapBufferPhysicalAddress; + PVOID MapBufferVirtualAddress; + PTRANSLATION_ENTRY TranslationEntry; + ULONG NumberOfPages; + + LONG i; + KIRQL Irql; + PHYSICAL_ADDRESS physicalAddress; + + KeAcquireSpinLock( &AdapterObject->SpinLock, &Irql ); + + NumberOfPages = BYTES_TO_PAGES(Amount); + + // + // Make sure there is room for the addition pages. The maximum number of + // slots needed is equal to NumberOfPages + Amount / 64K + 1. + // + + i = BYTES_TO_PAGES(MAXIMUM_MAP_BUFFER_SIZE) - (NumberOfPages + + (NumberOfPages * PAGE_SIZE) / 0x10000 + 1 + + AdapterObject->NumberOfMapRegisters); + + if (i < 0) { + + // + // Reduce the allocatation amount to so it will fit. + // + + NumberOfPages += i; + } + + if (NumberOfPages <= 0) { + // + // No more memory can be allocated. + // + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + return(FALSE); + + } + + + if (AdapterObject->NumberOfMapRegisters == 0 && HalpMapBufferSize) { + + NumberOfPages = BYTES_TO_PAGES(HalpMapBufferSize); + + // + // Since this is the initial allocation, use the buffer allocated by + // HalInitSystem rather than allocationg a new one. + // + + MapBufferPhysicalAddress = HalpMapBufferPhysicalAddress.LowPart; + + // + // Map the buffer for access. + // + + MapBufferVirtualAddress = MmMapIoSpace( + HalpMapBufferPhysicalAddress, + HalpMapBufferSize, + TRUE // Cache enable. + ); + + if (MapBufferVirtualAddress == NULL) { + + // + // The buffer could not be mapped. + // + + HalpMapBufferSize = 0; + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + return(FALSE); + } + + } else { + + // + // Allocate the map buffers. + // + physicalAddress.LowPart = MAXIMUM_PHYSICAL_ADDRESS - 1; + physicalAddress.HighPart = 0; + MapBufferVirtualAddress = MmAllocateContiguousMemory( + NumberOfPages * PAGE_SIZE, + physicalAddress + ); + + if (MapBufferVirtualAddress == NULL) { + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + return(FALSE); + } + + // + // Get the physical address of the map base. + // + + MapBufferPhysicalAddress = MmGetPhysicalAddress( + MapBufferVirtualAddress + ).LowPart; + + } + + // + // Initailize the map registers where memory has been allocated. + // + + TranslationEntry = ((PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase) + + AdapterObject->NumberOfMapRegisters; + + for (i = 0; (ULONG) i < NumberOfPages; i++) { + + // + // Make sure the perivous entry is physically contiguous with the next + // entry and that a 64K physical bountry is not crossed unless this + // is an Eisa system. + // + + if (TranslationEntry != AdapterObject->MapRegisterBase && + (((TranslationEntry - 1)->PhysicalAddress + PAGE_SIZE) != + MapBufferPhysicalAddress || + (((TranslationEntry - 1)->PhysicalAddress & ~0x0ffff) != + (MapBufferPhysicalAddress & ~0x0ffff)))) { + + // + // An entry needs to be skipped in the table. This entry will + // remain marked as allocated so that no allocation of map + // registers will cross this bountry. + // + + TranslationEntry++; + AdapterObject->NumberOfMapRegisters++; + } + + // + // Clear the bits where the memory has been allocated. + // + + RtlClearBits( + AdapterObject->MapRegisters, + TranslationEntry - (PTRANSLATION_ENTRY) + AdapterObject->MapRegisterBase, + 1 + ); + + TranslationEntry->VirtualAddress = MapBufferVirtualAddress; + TranslationEntry->PhysicalAddress = MapBufferPhysicalAddress; + TranslationEntry++; + (PCCHAR) MapBufferVirtualAddress += PAGE_SIZE; + MapBufferPhysicalAddress += PAGE_SIZE; + + } + + // + // Remember the number of pages that where allocated. + // + + AdapterObject->NumberOfMapRegisters += NumberOfPages; + + KeReleaseSpinLock( &AdapterObject->SpinLock, Irql ); + return(TRUE); +} diff --git a/private/ntos/nthals/halfire/ppc/pxidaho.h b/private/ntos/nthals/halfire/ppc/pxidaho.h new file mode 100644 index 000000000..19ba01f69 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxidaho.h @@ -0,0 +1,149 @@ +/*++ BUILD Version: 0001 // Increment this if a change has global effects + + +Module Name: + + pxidaho.h + +Abstract: + + This header file defines the structures for the planar registers + for an Idaho memory controller. + + + + +Author: + + Jim Wooldridge + + +Revision History: + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxidaho.h $ + * $Revision: 1.5 $ + * $Date: 1996/01/11 07:10:40 $ + * $Locker: $ + */ + + +// +// define structures for the idaho memory controller +// + + + +typedef struct _IDAHO_CONTROL { + UCHAR Reserved1[0x808]; // Offset 0x000 + UCHAR HardfileLight; // Offset 0x808 + UCHAR Reserved2[3]; + UCHAR EquiptmentPresent; // Offset 0x80C + UCHAR Reserved3[3]; + UCHAR PasswordProtect1; // Offset 0x810 + UCHAR Reserved4; + UCHAR PasswordProtect2; // Offset 0x812 + UCHAR Reserved5; + UCHAR L2Flush; // Offset 0x814 + UCHAR Reserved6[7]; + UCHAR SystemControl; // Offset 0x81c + UCHAR Reserved9[0x1B]; + UCHAR Eoi9; // Offset 0x838 + UCHAR PciInterruptMap1; // Offset 0x839 + UCHAR Reserved10[2]; + UCHAR Eoi11; // Offset 0x83C + UCHAR PciInterruptMap2; // Offset 0x83D + UCHAR AudioSupport; // Offset 0x83E + UCHAR Reserved11[0x14]; + UCHAR Reserved12[0x2C]; + UCHAR MemorySimmId1; // Offset 0x880 + UCHAR Reserved13[3]; + UCHAR MemorySimmId2; // Offset 0x884 + UCHAR Reserved14[3]; + UCHAR MemorySimmId3; // Offset 0x888 + UCHAR Reserved15[3]; + UCHAR MemorySimmId4; // Offset 0x88C + UCHAR Reserved16[0x46B]; + ULONG ConfigAddress; // Offset 0xcf8 + ULONG ConfigData; // Offset 0xcfc +} IDAHO_CONTROL, *PIDAHO_CONTROL; + +typedef struct _IDAHO_CONFIG { + + UCHAR VendorId[2]; // Offset 0x00 read-only + UCHAR DeviceId[2]; // Offset 0x02 read-only + UCHAR Command[2]; // Offset 0x04 unused + UCHAR DeviceStatus[2]; // Offset 0x06 + UCHAR RevisionId; // Offset 0x08 read-only + UCHAR Reserved1; // Offset 0x09 + UCHAR SubclassCode; // Offset 0x0A + UCHAR ClassCode; // Offset 0x0B + UCHAR Reserved2; // Offset 0x0C + UCHAR Reserved3; // Offset 0x0D + UCHAR HeaderType; // Offset 0x0E + UCHAR BistControl; // Offset 0x0F + UCHAR Reserved4[0x2C]; + UCHAR InterruptLine; // Offset 0x3C + UCHAR InterruptPin; // Offset 0x3D + UCHAR MinGnt; // Offset 0x3E + UCHAR MaxGnt; // Offset 0x3F + UCHAR BridgeNumber; // Offset 0x40 + UCHAR SubordBusNumber; // Offset 0x41 + UCHAR DisconnectCounter; // Offset 0x42 + UCHAR ReservedAnger; + UCHAR SpecialCycleAddress[2]; // Offset 0x44 + UCHAR Reserved5[0x3A]; + UCHAR StartingAddress1; // Offset 0x80 + UCHAR StartingAddress2; // Offset 0x81 + UCHAR StartingAddress3; // Offset 0x82 + UCHAR StartingAddress4; // Offset 0x83 + UCHAR StartingAddress5; // Offset 0x84 + UCHAR StartingAddress6; // Offset 0x85 + UCHAR StartingAddress7; // Offset 0x86 + UCHAR StartingAddress8; // Offset 0x87 + UCHAR Reserved6[8]; + UCHAR EndingAddress1; // Offset 0x90 + UCHAR EndingAddress2; // Offset 0x91 + UCHAR EndingAddress3; // Offset 0x92 + UCHAR EndingAddress4; // Offset 0x93 + UCHAR EndingAddress5; // Offset 0x94 + UCHAR EndingAddress6; // Offset 0x95 + UCHAR EndingAddress7; // Offset 0x96 + UCHAR EndingAddress8; // Offset 0x97 + UCHAR Reserved7[8]; + UCHAR MemoryBankEnable; // Offset 0xA0 + UCHAR MemoryTiming1; // Offset 0xA1 + UCHAR MemoryTiming2; // Offset 0xA2 + UCHAR Reserved8; + UCHAR SimmBank1; // Offset 0xA4 + UCHAR SimmBank2; // Offset 0xA5 + UCHAR SimmBank3; // Offset 0xA6 + UCHAR SimmBank4; // Offset 0xA7 + UCHAR Reserved9[9]; + UCHAR L2CacheStatus; // Offset 0xB1 + UCHAR Reserved10[2]; + UCHAR RefreshCycle; // Offset 0xB4 + UCHAR RefreshTimer; // Offset 0xB5 + UCHAR WatchdogTimer; // Offset 0xB6 + UCHAR BusTimer; // Offset 0xB7 + UCHAR LocalBusTimer; // Offset 0xB8 + UCHAR LocalBusIdleTimer; // Offset 0xB9 + UCHAR Options1; // Offset 0xBA + UCHAR Options2; // Offset 0xBB + UCHAR Reserved11[4]; + UCHAR EnableDetection1; // Offset 0xC0 + UCHAR ErrorDetection1; // Offset 0xC1 + UCHAR ErrorSimulation1; // Offset 0xC2 + UCHAR CpuBusErrorStatus; // Offset 0xC3 + UCHAR EnableDetection2; // Offset 0xC4 + UCHAR ErrorDetection2; // Offset 0xC5 + UCHAR ErrorSimulation2; // Offset 0xC6 + UCHAR PciBusErrorStatus; // Offset 0xC7 + UCHAR ErrorAddress[4]; // Offset 0xC8 +} IDAHO_CONFIG, *PIDAHO_CONFIG; + diff --git a/private/ntos/nthals/halfire/ppc/pxidle.c b/private/ntos/nthals/halfire/ppc/pxidle.c new file mode 100644 index 000000000..51f1059ef --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxidle.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxidle.c $ + * $Revision: 1.9 $ + * $Date: 1996/01/11 07:10:47 $ + * $Locker: $ + */ + +/*++ +TITLE("Processor Idle") + + +Copyright (c) 1994 Microsoft Corporation + +Module Name: + + pxidle.c + +abstract: + + This module implements system platform dependent power management + support. + +Author: + + Jim Wooldridge + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + +#include "fpdebug.h" +#include "halp.h" +#include "phsystem.h" +#include "fpcpu.h" +ULONG HalpGetStack( VOID ); +extern ULONG registeredInts[]; + +/*++ + + Routine Description: VOID HalProcessorIdle( VOID ) + + + This function is called when the current processor is idle with + interrupts disabled. There is no thread active and there are no + DPCs to process. Therefore, power can be switched to a standby + mode until the the next interrupt occurs on the current processor. + + N.B. This routine is entered with EE in MSR clear. This routine + must do any power management enabling necessary, set the EE + bit in MSR, then either return or wait for an interrupt. + + Arguments: + + None. + + Return Value: + + None. + + +--*/ + +VOID +HalProcessorIdle(VOID) +{ + HASSERTMSG(PCR->CurrentIrql <= DISPATCH_LEVEL, "Wrong Dispatch Level"); + HASSERT(RInterruptMask(GetCpuId()) == registeredInts[GetCpuId()]); + + HalpEnableInterrupts(); +} diff --git a/private/ntos/nthals/halfire/ppc/pxinithl.c b/private/ntos/nthals/halfire/ppc/pxinithl.c new file mode 100644 index 000000000..2166d81e4 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxinithl.c @@ -0,0 +1,1114 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxinithl.c $ + * $Revision: 1.92 $ + * $Date: 1996/05/14 02:34:31 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxinithl.c + +Abstract: + + + This module implements the initialization of the system dependent + functions that define the Hardware Architecture Layer (HAL) for a + Power PC system. + + +Author: + + David N. Cutler (davec) 25-Apr-1991 + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge (jimw@austin.ibm.com) Initial Power PC port + + Removed call to HalpMapFixedTbEntries, the PPC port + maps all memory via calls to MmMapIoSpace(). + Removed call to HalpInializeInterrupts - 8259 initialized in phase 1 + Removed Cache error handler - 601 has no cache error interrupt + Removed call to HalpCreateDmaSturctures - it supports internal DMA + internal DMA contoller. + +--*/ + +#include +#include +#include +#include "halp.h" +#include "pxmemctl.h" +#include "fpproto.h" +#include "phsystem.h" +#include "fpio.h" +#include "fpdcc.h" +#include "fpds1385.h" +#include "fpcpu.h" +#include "arccodes.h" +//#include "arc.h" +#include "fpdebug.h" +#include "fparch.h" +#include "fpi2c.h" +#include "pxpcisup.h" + +ULONG TmpVramBase; +ULONG TmpDbatNum; +ULONG TmpDbatVal; +CHAR SysName[48]; +PCHAR SystemName="Unknown System"; + +ULONG CpuClockMultiplier=0; +ULONG MemoryParityErrorsThisBoot = 0; +ULONG MemoryParityErrorsForever = 0; + +extern ADDRESS_USAGE HalpDefaultIoSpace; +extern ULONG HalpGetInstructionTimes( VOID ); +extern VOID HalpInitializeVector2Irql(VOID); +extern UCHAR PciDevicePrimaryInts[]; +extern ULONG PciAllowedInts; + +VOID +HalpSynchronizeExecution( + VOID + ); + +BOOLEAN +HalpPhase0MapIo ( + VOID + ); + +BOOLEAN +HalpPhase0MapPCIConfig ( + VOID + ); + +VOID +HalpInitParityErrorLog ( + VOID + ); + +extern VOID HalpTranslateSystemSpecificData ( VOID ); +extern ULONG HalpPerformanceFrequency; +extern BOOLEAN HalpSetRevs( RelInfo * ); +VOID HalpRestoreDBATs(VOID); +VOID HalpSaveDBATs(VOID); +#if defined(HALDEBUG_ON) +VOID HalpDisplayBatForVRAM(void); +VOID HalpGetDebugValue(VOID); +extern BOOLEAN HalpPrintRevs( RelInfo * ); // from phvrsion.c +extern VOID HalpVersionInternal( VOID ); // from phvrsion.c +#endif +extern VOID HalpVersionExternal( RelInfo *, PLOADER_PARAMETER_BLOCK ); // from phvrsion.c + +ULONG TimeBaseCount=0; + + +// +// This prototype taken from ntrtl.h. +// Why not just include ntrtl.h? Well because I would need to include a dozen +// other files too. +// +NTSYSAPI // ntddk ntifs +NTSTATUS // ntddk ntifs +NTAPI // ntddk ntifs +RtlCharToInteger ( // ntddk ntifs + PCSZ String, // ntddk ntifs + ULONG Base, // ntddk ntifs + PULONG Value // ntddk ntifs + ); // ntddk ntifs + + +RelInfo ThisOne; + +PROCESSOR_DESCRIPTION ProcessorDescription [nPROCESSOR_TYPE] = { + // Flags HashSize ProcessorName; + {PROC_NOSUPP, 0, "Unknown", "X"}, + {PROC_SUPP, (64*1024), "601", "1"}, + {PROC_NOSUPP, 0, "602", "2"}, + {PROC_SUPP, 0, "603", "3"}, + {PROC_SUPP | + PROC_HASHTABLE | + PROC_MPCAPABLE, (64*1024), "604", "4"}, + {PROC_NOSUPP, 0, "605", "5"}, + {PROC_SUPP, 0, "606", "3"}, + {PROC_NOSUPP, 0, "607", "7"}, + {PROC_NOSUPP, 0, "608", "8"}, + {PROC_SUPP | + PROC_HASHTABLE | + PROC_MPCAPABLE, (64*1024), "609", "4"}, +}; +PROCESSOR_TYPE ProcessorType = PPC_UNKNOWN; + +SYSTEM_DESCRIPTION SystemDescription [] = { + {SYS_NOSUPP, "Unknown System Type"}, + {SYS_SUPP, "ES"}, + {SYS_SUPP| + SYS_MPCAPABLE, "MX"}, + {SYS_SUPP| + SYS_MPCAPABLE, "TX"}, + {SYS_SUPP| + SYS_MPCAPABLE, "LX"}, +}; +SYSTEM_TYPE SystemType = SYS_UNKNOWN; + +PVOID HalpSystemControlBase = NULL; +PVOID HalpSystemRegisterBase = NULL; +ULONG SafePlace; + +// +// Define memory allocation structure. +// +typedef struct _AVR_MEMORY_DESCRIPTOR { + LIST_ENTRY *NextEntry; + LIST_ENTRY *PrevEntry; + MEMORY_DESCRIPTOR MemoryEntry; +} AVR_MEMORY_DESCRIPTOR, *PAVR_MEMORY_DESCRIPTOR; + +CHAR *MemTypeList[] = { + "MemoryExceptionBlock", + "MemorySystemBlock", + "MemoryFree", + "MemoryBad", + "MemoryLoadedProgram", + "MemoryFirmwareTemporary", + "MemoryFirmwarePermanent", + "LoaderOsloaderHeap", + "LoaderOsloaderStack", + "LoaderSystemCode", + "LoaderHalCode", + "LoaderBootDriver", + "LoaderConsoleInDriver", + "LoaderConsoleOutDriver", + "LoaderStartupDpcStack", + "LoaderStartupKernelStack", + "LoaderStartupPanicStack", + "LoaderStartupPcrPage", + "LoaderStartupPdrPage", + "LoaderRegistryData", + "LoaderMemoryData", + "LoaderNlsData", + "LoaderSpecialMemory", + "LoaderMaximum" + }; + + +// +// There are two variables that control debug printouts, HALDEBUG_ON, +// and HALDEBUGVALUE. HALDEBUGVALUE is used to set a minimum level +// of printing and debug behavior, and HALDEBUG_ON turns on the +// environment variable. HALDEBUG_ON may be defined without HALPDEBUGVALUE, +// but defining HALPDEBUGVALUE should require HALDEBUG_ON also be defined. +// + +#if defined(HALDEBUG_ON) + // + // set the HalpDebugValue that determines what level of debug printout + // occurs. If one is defined on the cmd line, then 'or' it in with + // whatever is defined in the environment ( nvram ) area. + // +# if defined(HALPDEBUGVALUE) +int HalpDebugValue = HALPDEBUGVALUE; +# else +int HalpDebugValue = 0; +# endif // HALPDEBUGVALUE +#endif // HALPDEBUG_ON + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(INIT, HalInitSystem) +#pragma alloc_text(INIT, HalInitializeProcessor) +#pragma alloc_text(INIT, HalpInitParityErrorLog) +#endif + +PVOID HalpIoControlBase = (PVOID) 0; +PVOID HalpIoMemoryBase = (PVOID) 0; + +VOID +HalpInitBusHandlers ( + VOID + ); + +VOID +HalpRegisterInternalBusHandlers ( + VOID + ); + + + +// +// Define global spin locks used to synchronize various HAL operations. +// +KSPIN_LOCK HalpBeepLock; +KSPIN_LOCK HalpDisplayAdapterLock; +KSPIN_LOCK HalpSystemInterruptLock; +KSPIN_LOCK HalpDS1385Lock; +KSPIN_LOCK HalpRTCLock; + + +/*++ + +Routine Description: BOOLEAN HalInitSystem () + + This function initializes the Hardware Architecture Layer (HAL) for a + Power PC system. + +Arguments: + + Phase - Supplies the initialization phase (zero or one). + + LoaderBlock - Supplies a pointer to a loader parameter block. + +Return Value: + + A value of TRUE is returned is the initialization was successfully + complete. Otherwise a value of FALSE is returend. + +--*/ + +BOOLEAN +HalInitSystem ( + IN ULONG Phase, + IN PLOADER_PARAMETER_BLOCK LoaderBlock + ) +{ + + PKPRCB Prcb; + ULONG BuildType = 0; + SYSTEM_TYPE I2CSystemType; + UCHAR slot; + ULONG *TreeDepth = 0; + UCHAR CpuId; + KIRQL IrqlIn; + + // + // Initialize the HAL components based on the phase of initialization + // and the processor number. + // + Prcb = PCR->Prcb; + IrqlIn = PCR->CurrentIrql; + SET_LEDS(0xf7); + + // + // The following handles the initialization requirements for + // all processors greater than 1. + // + + if (Prcb->Number > 0) { + HDBG(DBG_INTERNAL, + HalpDebugPrint("HalInitSystem: Init of Cpu(%d)\n", GetCpuId());); + + // + // Mask interrrupts, clear all of them and then + // enable interrupts. + // + HalpDisableInterrupts(); + HalpInitInts(Prcb->Number); + HalpRestoreDBATs(); + HalpEnableInterrupts(); + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: Cpu (%d) Interrupt Mask (0x%08x)\n", + GetCpuId(), RInterruptMask(GetCpuId()));); + HDBG(DBG_INTERNAL, + HalpDebugPrint("HalInitSystem: exit Cpu(%d)\n", GetCpuId())); + + // + // Check the current irql level and make sure we exit at the same + // irql we entered with: + // + if( PCR->CurrentIrql >= IrqlIn ) { + KeLowerIrql(IrqlIn); + } else { + KIRQL dummyIrql; + KeRaiseIrql(IrqlIn, &dummyIrql); + } + return TRUE; + } + + // + // Phase 0 initialization. (Main Processor Only). + // + ASSERT(Prcb->Number == 0); + if (Phase == 0) { + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + ULONG MatchKey = 0; + + HalpInitParityErrorLog(); + +#if defined(HALDEBUG_ON) + // + // Get user defined debug variable and 'or' it into the + // compiled version of the debug variable. + // + HalpGetDebugValue(); +#endif + + // moved this from after ConfigurationEntry because HalpGet + if (NULL == HalpIoControlBase) { + if (!HalpPhase0MapIo() || !HalpPhase0MapPCIConfig()) { + return FALSE; + } + } + + // Initialize the Pci Primary Slot table to be invalid; this table + // is filled in on a per system basis. + for (slot = 0; slot < MAXIMUM_PCI_SLOTS; slot++) { + PciDevicePrimaryInts[slot] = INVALID_INT; + } + + ConfigurationEntry = + KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + SystemClass, + ArcSystem, + &MatchKey); + + if (ConfigurationEntry) { + // + // If configuration entry is not null, then look at the + // identifier returned for this arc system name. If its the MP + // system, it means we really do have more than one cpu and + // will want to set a flag so VRAM is handled + // differently, and some extra checking is done. + // + SystemName = ConfigurationEntry->ComponentEntry.Identifier; + + // Check if I2C is present + if (HalpI2CGetSystem(&I2CSystemType) == TRUE) { + SystemDescription[SystemType].Flags |= SYS_MPFOREAL; + // If I2C is present, determine if we are Slice or Serve + SystemType = I2CSystemType; + if ((SystemType != SYS_POWERSLICE) && + (SystemType != SYS_POWERSERVE)) { + SystemType = SYS_UNKNOWN; + } + // An I2C is present, find the interrupt table. If there + // is no interrupt table, set SystemType back to SYS_UNKNOWN + // so that we may die now, since this is an unrecoverable + // error. + if (HalpI2CGetInterrupt() == FALSE) { + SystemType = SYS_UNKNOWN; + } + } + // If I2c is not present, must be either Pro or Top + else { + if (SystemType == SYS_POWERTOP) { + SystemDescription[SystemType].Flags |= SYS_MPFOREAL; + } + PciDevicePrimaryInts[1] = 0x19; + PciDevicePrimaryInts[2] = 0x16; + PciDevicePrimaryInts[3] = 0x17; + PciDevicePrimaryInts[4] = 0x1a; + PciAllowedInts = 0x06c00000; + } + } else { + HalpDebugPrint("ConfigurationEntry is null \n"); + } + + // Now compute the allowed interrupt mask + for (slot = 0; slot < MAXIMUM_PCI_SLOTS; slot++) { + if (PciDevicePrimaryInts[slot] != INVALID_INT) { + PciAllowedInts |= (1 << PciDevicePrimaryInts[slot]); + } + } + PciAllowedInts |= 0x40000000; // Add the MemErr bit + + // If we are not a valid system type; die a horrible death + if (SystemType == SYS_UNKNOWN) { + HalpDebugPrint("HalInitSystem: Unknown SystemType\n"); + DbgBreakPoint(); + } + + // Once we have the interrupt structure, we can initialize the IRQL + // values for the PIO slots. + HalpInitializeVector2Irql(); + + HDBG(DBG_INTERNAL, + HalpDebugPrint("HalInitSystem: phase 0 init (processor 0)\n");); + + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: HalpIoControlBase set: 0x%08x\n", + HalpIoControlBase);); + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: HalpSystemRegisterBase(0x%x)\n", + HalpSystemRegisterBase);); + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: rInterruptRequest(0x%x)\n", + _ADDR(0x0));); + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: PciAllowedInts(0x%x)\n", + PciAllowedInts);); + + HalpInterruptBase = + (PULONG)HalpSystemRegisterBase + INTERRUPT_OFFSET; + + // + // clear out all the crap from the system interrupt registers: + // + RInterruptMask(GetCpuId()) = 0x0; + WaitForRInterruptMask(GetCpuId()); + rInterruptRequest = 0xffffffff; + FireSyncRegister(); + + // + // Verify that the processor block major version number conform + // to the system that is being loaded. + // + if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) { + KeBugCheck(MISMATCHED_HAL); + } + + // + // Init variables, spin locks, and the display adapter. + // + + // + // Set the interval clock increment value. + // + + HalpCurrentTimeIncrement = MAXIMUM_INCREMENT; + HalpNewTimeIncrement = MAXIMUM_INCREMENT; + KeSetTimeIncrement(MAXIMUM_INCREMENT, MINIMUM_INCREMENT); + + // + // Initialize all spin locks. + // + KeInitializeSpinLock(&HalpBeepLock); + KeInitializeSpinLock(&HalpDisplayAdapterLock); + KeInitializeSpinLock(&HalpSystemInterruptLock); + KeInitializeSpinLock(&HalpDS1385Lock); + KeInitializeSpinLock(&HalpRTCLock); + + HalpRegisterAddressUsage (&HalpDefaultIoSpace); + + // + // Initialize the display adapter. + // + if (!HalpInitializeDisplay(LoaderBlock)) { + HalpDebugPrint("HalInitSystem: did not init display\n"); + return FALSE; + } + + // + // set the background red for phase 0 + // + HDBG(DBG_COLORS, HalpSetPixelColorMap( 0x00ff0000, 0x00000001 );); + + HDBG(DBG_GENERAL, + HalpDebugPrint("Debug Value is 0x%x\n", HalpDebugValue);); + HDBG(DBG_DUMPTREE, + PHalpDumpConfigData(LoaderBlock->ConfigurationRoot, + TreeDepth);); + HDBG(DBG_DUMPTREE, + PHalpDumpLoaderBlock(LoaderBlock);); + + // + // Check if we should call a break point + // + HDBG(DBG_BREAK, + HalpDebugPrint("HalInitSystem: Calling Break Point\n")); + HDBG(DBG_BREAK, DbgBreakPoint()); + + // + // RTC: check that the RTC is working... + // + HDBG(DBG_GENERAL, HalpDebugPrint("Checking RTC ....\n");); + HalpInitFirePowerRTC(); + + // + // Calibrate execution stall + // + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: Calibrating stall\n");); + HalpCalibrateTimingValues(); + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: HalpPerformanceFrequency = %d\n", + HalpPerformanceFrequency);); + + // + // InitializeInterrupts + // + HDBG(DBG_GENERAL, HalpDebugPrint("HalInitSystem: Initting ints\n");); + if (!HalpInitializeInterrupts()) { + HalpDebugPrint("HalInitSystem: Did not init interrupts "); + return FALSE; + } + + HDBG(DBG_GENERAL, HalpDisplayBatForVRAM();); + HalpSaveDBATs(); + HDBG(DBG_GENERAL, + HalDisplayString("HalInitSystem: done with phase 0 \n");); + HDBG(DBG_GENERAL, + HalpDebugPrint("System Name: %s \n", SystemName );); + + } else { + // + // Phase 1 initialization. + // + + // + // set the display to green while in phase 1: + // + HDBG(DBG_COLORS, HalpSetPixelColorMap(0x00009900, 0x00000001);); + + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: phase 1 init (processor 0)\n");); + + HalpInitializeDisplay1(LoaderBlock ); + HalpRegisterInternalBusHandlers (); + if (!HalpAllocateMapBuffer()) { + HalpDebugPrint("HalInitSystem: Did not allocate map buffer"); + return FALSE; + } + + // + // Map I/O space and create ISA data structures. + // + if (!HalpMapIoSpace()) { + HalpDebugPrint("HalInitSystem: Did not map io space"); + return FALSE; + } + + + // + // Setup Io bus handlers ( really only setting up pci bus 0: + // the primary one). This needs to be done before the call + // to HalpCreateSioStructures so it can find the pci-e/isa + // bridge chip. + // + HalpInitIoBuses(); + + + if (!HalpCreateSioStructures()) { + HalpDebugPrint("HalInitSystem: No sio structures created"); + return FALSE; + } + + + // + // At this point, the interrupt handlers are installed so any + // interrupts pending are cleared... + // + if (!HalpInitIntelAIP()) { + HalpDebugPrint("HalInitSystem: AIP did not initialize\n"); + return FALSE; + } + + // + // Note: GetCpuId can not be called earlier + // because the registers are not mapped. + // + CpuId = (UCHAR) GetCpuId(); + if (SystemType == SYS_POWERPRO) { + CpuId = 0; + } + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: Cpu id is: %d\n", CpuId);); + + // + // Display HAL specific information + // + HalpSetRevs( &ThisOne ); + HDBG(DBG_GENERAL, HalpPrintRevs( &ThisOne );); + HDBG(DBG_GENERAL, HalpVersionInternal();); + HDBG(DBG_GENERAL, + HalpDebugPrint("CpuClockMultiplier = 0x%x ( %d ) \n", + CpuClockMultiplier, CpuClockMultiplier )); + HalpVersionExternal(&ThisOne, LoaderBlock); + + // + // Before we exit, make sure any device interrupts are masked + // off, and all interrupts are cleared. DON'T FORGET: by this + // point, several interrupts have gone through a connect call, + // they may already exist in the mask. None of the devices are + // currently in this set but the cpu message interrupt. DON"T + // MESS WITH THE CPU MESSAGE INTERRUPT BIT!! + // + switch(SystemType) { + case SYS_POWERSLICE: + RInterruptMask(GetCpuId()) &= ~(ENABLE_EISA_MASK); + break; + + case SYS_POWERSERVE: + // TX_PROTO: allowable PCI interrupts + RInterruptMask(GetCpuId()) &= + ~(ENABLE_EISA_MASK|0x06700000); + break; + case SYS_POWERTOP: + case SYS_POWERPRO: + RInterruptMask(GetCpuId()) &= ~(ENABLE_EISA_MASK| + SCSI_INT| + ENET_INT); + break; + default: + break; + }; + + WaitForRInterruptMask(GetCpuId()); + rInterruptRequest = SET_INTS_CLEAR; + FireSyncRegister(); + + //HalpEnableInterrupts(); + // Turn on interrupts, set the irql, and setup the system int masks: + // + KeLowerIrql(LOW_LEVEL); + HDBG(DBG_GENERAL, + HalpDebugPrint("HalInitSystem: Cpu (%d) Interrupt Mask (0x%x)\n", + GetCpuId(), RInterruptMask(GetCpuId()))); + + // + // Make sure the display is now a blue background with + // White letters: + // + HDBG(DBG_COLORS, HalpSetPixelColorMap( 0x00ffffff, 0x000000ff )); + HDBG(DBG_COLORS, HalpSetPixelColorMap( 0x000000ff, 0x00000001 )); + HalpInitializeRegistry(LoaderBlock); // mogawa + HalpTranslateSystemSpecificData (); + + HDBG(DBG_GENERAL, HalpDebugPrint("HalInitSystem: done phase 1\n");); + } + + // + // Check the current irql level and make sure we exit at the same + // irql we entered with: + // + if( PCR->CurrentIrql >= IrqlIn ) { + KeLowerIrql(IrqlIn); + } else { + KIRQL dummyIrql; + KeRaiseIrql(IrqlIn, &dummyIrql); + } + + return TRUE; +} + + +/*++ + +Routine Description: VOID HalInitializeProcessor () + + This function is called early in the initialization of the kernel + to perform platform dependent initialization for each processor + before the HAL Is fully functional. + + N.B. When this routine is called, the PCR is present but is not + fully initialized. + +Arguments: + + Number - Supplies the number of the processor to initialize. + +Return Value: + + None. + +--*/ + +VOID +HalInitializeProcessor ( + IN ULONG Number + ) +{ + PULONG pPCIBase; + BOOLEAN newMap; + ULONG IcacheSize, DcacheSize; + ULONG CacheBlockAlignment; + + // + // Initialize the processor type (601, 603, 604, ...) + // + ProcessorType = (HalpGetProcessorVersion() >> 16); + + // + // FireWorks ( FirePOWER and Firmworks ) veneer does not correctly set the + // processor cache size and alignment requirements in the loader parameter + // block so we forcibly replace the values that were copied from there + // into the PCR. + // + switch( ProcessorType ) { + case 1: // 601 processor + IcacheSize = 32 * 1024; + DcacheSize = 32 * 1024; + CacheBlockAlignment = 32 - 1; + break; + case 3: // 603 processor + IcacheSize = 8 * 1024; + DcacheSize = 8 * 1024; + CacheBlockAlignment = 32 - 1; + break; + case 6: // 603+ processor + case 4: // 604 processor + IcacheSize = 16 * 1024; + DcacheSize = 16 * 1024; + CacheBlockAlignment = 32 - 1; + break; + case 9: // 604+ processor + IcacheSize = 32 * 1024; + DcacheSize = 32 * 1024; + CacheBlockAlignment = 32 - 1; + break; + default: + KeBugCheck(HAL_INITIALIZATION_FAILED); + return; + } + PCRsprg1->FirstLevelIcacheSize = IcacheSize; + PCRsprg1->FirstLevelDcacheSize = DcacheSize; + PCRsprg1->DcacheAlignment = CacheBlockAlignment; + PCRsprg1->IcacheAlignment = CacheBlockAlignment; + + // + // Check what cpu we're on. Return now if this cpu is + // not the primary ( first ) cpu. + // + if (Number != 0) { + return; // Nothing to do here, just return + } + + // + // Initialize the system type register (PowerPro vs PowerTop). + // Use the System Register Base address if mapped to access + // the control page of the system. If not, map a virtual + // address temporarily and unmap it when finished. + // + if (NULL == HalpIoControlBase) { + if (!HalpPhase0MapIo() || !HalpPhase0MapPCIConfig()) { + DbgPrint("HalInitializeProcessor: Failed to map dbats\n"); + return; + } + } + + if (HalpSystemRegisterBase) { + pPCIBase = (PULONG)((PUCHAR)HalpSystemRegisterBase + + (SYSTEM_PCI_CONFIG_BASE - SYSTEM_REGISTER_SPACE)); + newMap = FALSE; + } else { + + pPCIBase = + (PULONG)KePhase0MapIo((PVOID)SYSTEM_PCI_CONFIG_BASE, 0x1000); + newMap = TRUE; + } + + if (pPCIBase) { + PULONG pDeviceId; + // for little endian reasons, add the 1 in. + pDeviceId = (PULONG)(pPCIBase + 0x42 + 0x01); + switch (*pDeviceId) { + case ESCC_IDENT: + SystemType = SYS_POWERPRO; + break; + case TSC_IDENT: + SystemType = SYS_POWERTOP; + break; + default: + SystemType = SYS_UNKNOWN; + break; + } + if (newMap) { + KePhase0DeleteIoMap((PVOID)SYSTEM_PCI_CONFIG_BASE, 0x1000); + } + } else { + SystemType = SYS_UNKNOWN; + } + + // + // If this is the first processor, initialize the cache + // sweeping routines depending on type of processor. + // + if (HalpCacheSweepSetup()) { + KeBugCheck(MISMATCHED_HAL); + } + + // + // Calculate the cpu clock rate: + // + + // Temporary fix until we understand the code + if (SystemType == SYS_POWERPRO) { + CpuClockMultiplier = 30; // fix it for the moment.... + } else { + if ((SystemType == SYS_POWERSLICE) || + (SystemType == SYS_POWERTOP) || + (SystemType == SYS_POWERSERVE)) { + // + // The times recorded from HalpGetInstructionTimes range about + // 80 to 256. + // times: Multiplier: + // 85/6 3x BusClock + // 128 2x + // 170/1 1.5x + // 256 1x + // + // Since there can be a non integer multiple of bus clocks, will + // do all integer math at a multiple of 10 and remove the extra + // order of magnitude downstream when the value is used + // + TimeBaseCount = HalpGetInstructionTimes(); + TimeBaseCount = HalpGetInstructionTimes(); + CpuClockMultiplier = ((480 * 10) / (10 * (TimeBaseCount/10))); + if (CpuClockMultiplier > 50 ) { + CpuClockMultiplier = 50; // limit frequency multiples to 5. + } + } + } + + return; +} + + +#define MAX_DBATS 4 +ULONG DBATUpper[MAX_DBATS]; +ULONG DBATLower[MAX_DBATS]; + +VOID +HalpRestoreDBATs() +{ + int i; + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpRestoreDBATs: entered\n");); + for (i = 0; i < MAX_DBATS; i++) { + HDBG(DBG_DBAT, + HalpDebugPrint("HalpRestoreDBATs: U(%d):Old(0x%08x) New(0x%08x)\n", + i, HalpGetUpperDBAT(i), DBATUpper[i]);); + HDBG(DBG_DBAT, + HalpDebugPrint("HalpRestoreDBATs: L(%d):Old(0x%08x) New(0x%08x)\n", + i, HalpGetLowerDBAT(i), DBATLower[i]);); + HalpSetUpperDBAT(i, DBATUpper[i]); + HalpSetLowerDBAT(i, DBATLower[i]); + } + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpRestoreDBATs: exit\n");); +} + + +VOID +HalpSaveDBATs() +{ + int i; + + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpSaveDBATs: entered\n");); + for (i = 0; i < MAX_DBATS; i++) { + DBATUpper[i] = HalpGetUpperDBAT(i); + DBATLower[i] = HalpGetLowerDBAT(i); + HDBG(DBG_DBAT, + HalpDebugPrint("HalpSaveDBATs: (%d): U(0x%08x) L(0x%08x)\n", + i, DBATUpper[i], DBATLower[i]);); + } +} + +/*++ + + Routine Description: BOOLEAN HalpPhase0MapIo () + + This function forces a very special DBAT mapping for Phase0. + The kernel routine KePhase0DeleteIoMap has a nasty bug, so + just map three (the max) DBATS: + + 1) system registers + 2) memory (to be reused for VRAM if no INT10 support) + 3) I/O control (change the size of its mapping) + + The idea is to let the kernel map the three DBATs. + It sets the boundary to 8Mb and maps 8Mb starting at + virtual address 0xb0000000. Thus you get the following + virtual to physical mappings: + + DBAT2 = 0xb0800000-0xb0ffffff -> 0xff000000-0xffffffff + DBAT3 = 0xb1000000-0xb17fffff -> 0x80000000-0x80ffffff + + The I/O control size will be changed (by HalpPhase0MapPCIConfig()) + to 16Mb so it maps 0x80000000 to 0x80ffffff which covers the PCI + config space. + + The mapping of the frame buffer or memory space (for INT10) + is left to pxdisp.c which will use DBAT1. + +Arguments: + + +Return Value: + + TRUE if success, FALSE if failure + +--*/ + +BOOLEAN +HalpPhase0MapIo ( + VOID + ) +{ + + // + // Get access to I/O space. + // + if (NULL == HalpIoControlBase) { + HalpIoControlBase = + (PVOID)KePhase0MapIo((PVOID)IO_CONTROL_PHYSICAL_BASE, 0x800000); + if (!HalpIoControlBase) { + DbgPrint("HalpPhase0MapIo: HalpIoControlBase map failed\n"); + return FALSE; + } + } + + // + // Get access to System Register space. + // + if (NULL == HalpSystemRegisterBase) { + HalpSystemRegisterBase = + (PVOID)KePhase0MapIo((PVOID)SYSTEM_REGISTER_SPACE, 0x800000); + if(HalpSystemRegisterBase) { + HalpInterruptBase = + (PULONG)HalpSystemRegisterBase + INTERRUPT_OFFSET; + HalpSystemControlBase = + (PULONG)HalpSystemRegisterBase + SYSTEM_CONTROL_OFFSET; + } else { + DbgPrint("HalpPhase0MapIo: HalpSystemRegisterBase map failed\n"); + return FALSE; + } + } + + return TRUE; +} + + +/*++ + + Routine Description: BOOLEAN HalpPhase0MapPCIConfig () + + This function extends the map length of I/O Control + to include PCI Config space. + +Arguments: + + +Return Value: + + TRUE if success, FALSE if failure + +--*/ + +BOOLEAN +HalpPhase0MapPCIConfig ( + VOID + ) +{ + ULONG hi, low; + LONG i; + + + // + // + // Look for the I/O control space DBAT mapping. + // + for (i = 1; i < MAX_DBATS; i++) { + PVOID va = NULL; + + low = HalpGetLowerDBAT(i); + if (IO_CONTROL_PHYSICAL_BASE == (low & 0xfffe0000)) { + hi = HalpGetUpperDBAT(i); + if ((PVOID)(hi & 0xfffe0000) == HalpIoControlBase) { + if (3 == i) { + // + // Change the size to 16Mb. + // + hi &= ~0x000001fc; + hi |= 0x000001fc; + HalpSetUpperDBAT(i, hi); + hi = HalpGetUpperDBAT(i); + if ((hi & 0x00001ffc) == 0x000001fc) { + HalpPciConfigBase = (PUCHAR)HalpIoControlBase + + ((ULONG)PCI_CONFIG_PHYSICAL_BASE - + (ULONG)IO_CONTROL_PHYSICAL_BASE); + } else { + DbgPrint("HalpPhase0MapPCIConfig: failed, invalid size\n"); + return FALSE; + } + } else { + DbgPrint("HalpPhase0MapPCIConfig: failed, invalid DBAT\n"); + } + } else { + DbgPrint("HalpPhase0MapPCIConfig: failed, invalid virtual address\n"); + return FALSE; + } + return TRUE; + } + } + + DbgPrint("HalpPhase0MapPCIConfig: failed, invalid physical address\n"); + return FALSE; +} + + +#if defined(HALDEBUG_ON) +VOID +HalpGetDebugValue() +{ + CHAR buf[30]; + int nvramValue; + + // + // Get Debug Value from NVRAM and or with compiler version + // + if (HalGetEnvironmentVariable("HALDEBUG", sizeof(buf), buf) == ESUCCESS) { + nvramValue = atoi(buf); + HalpDebugValue |= nvramValue; + } +} +#endif + +// +// Initialize the global variables for parity error count. +// +// The initial value for this boot is zero. +// The initial value forever is read from NVRAM. +// +// The NVRAM values are stored in the env variable +// "MEMORY_PARITY_ERRORS" as: +// # errors this boot, # errors forever +// +// +VOID +HalpInitParityErrorLog ( + VOID + ) +{ + ULONG rc; + CHAR buf[80]; + + rc = HalGetEnvironmentVariable(MemoryParityErrorsVarName, + sizeof(buf), buf); + if (ESUCCESS == rc) { + PCHAR tok; + const PCHAR delimiters = ",; "; + + if (buf && strlen(buf) && (tok = FpStrtok(buf, delimiters))) { + rc = RtlCharToInteger(tok, 0, &MemoryParityErrorsThisBoot); + if (STATUS_SUCCESS != rc) { + MemoryParityErrorsThisBoot = 0; + } + while ( tok = FpStrtok(NULL, delimiters) ) { + if (strlen(tok)) { + rc = RtlCharToInteger(tok, 10, &MemoryParityErrorsForever); + if (STATUS_SUCCESS != rc) { + MemoryParityErrorsForever = 0; + } + } + } + } + } +} diff --git a/private/ntos/nthals/halfire/ppc/pxintsup.s b/private/ntos/nthals/halfire/ppc/pxintsup.s new file mode 100644 index 000000000..4daf671c9 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxintsup.s @@ -0,0 +1,121 @@ +// TITLE("Enable and Disable Processor Interrupts") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxintsup.s +// +// Abstract: +// +// This module implements the code necessary to enable and disable +// interrupts on a PPC system. +// +// Author: +// +// Jim Wooldridge +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 30-Dec-93 plj Added 603 support. +// +//-- + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxintsup.s $ + * $Revision: 1.5 $ + * $Date: 1996/01/11 07:11:07 $ + * $Locker: $ + */ + +#include "halppc.h" + +//++ +// +// Routine Description: +// +// Enables interrupts. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + + LEAF_ENTRY(HalpEnableInterrupts) + + mfmsr r.5 + ori r.5,r.5,MASK_SPR(MSR_EE,1) + mtmsr r.5 + cror 0,0,0 // N.B. 603e/ev Errata 15 + + LEAF_EXIT(HalpEnableInterrupts) + + +//++ + +// +// Routine Description: +// +// Disables interrupts. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + + LEAF_ENTRY(HalpDisableInterrupts) + + mfmsr r.5 + rlwinm r.5,r.5,0,~MASK_SPR(MSR_EE,1) + mtmsr r.5 + cror 0,0,0 // N.B. 603e/ev Errata 15 + + LEAF_EXIT(HalpDisableInterrupts) + + +//++ + +// +// Routine Description: +// +// Disables interrupts. +// +// Arguments: +// +// None. +// +// Return Value: +// +// None. +// +//-- + + + LEAF_ENTRY(KiGetPcr) + + mfsprg r.3,1 + + LEAF_EXIT(KiGetPcr) diff --git a/private/ntos/nthals/halfire/ppc/pxirql.c b/private/ntos/nthals/halfire/ppc/pxirql.c new file mode 100644 index 000000000..773d892e4 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxirql.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxirql.c $ + * $Revision: 1.17 $ + * $Date: 1996/01/11 07:11:13 $ + * $Locker: $ + */ + +// TITLE("Manipulate Interrupt Request Level") +//++ +// +// Copyright (c) 1990 Microsoft Corporation +// Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// PXIRQL.C +// +// Abstract: +// +// This module implements the code necessary to lower and raise the current +// Interrupt Request Level (IRQL). +// +// +// Author: +// +// Jim Wooldridge (IBM) +// Steve Johns (Motorola) +// +// Environment: +// +// Kernel mode only. +// +// Revision History: +// 22-Feb-94 Steve Johns (Motorola) +// KeRaiseIrql - Disabled interrupts at PIC if IRQL >= DEVICE_LEVEL +// KeLowerIrql - Enabled interrupts at PIC if IRQL < DEVICE_LEVEL +// 15-Apr-94 Jim Wooldridge +// Added irql interrupt mask table and expanded irql range from (0-8) +// to (0-31). +// +// TODO: +// 1) Fix the forced mask assignments in the KeRaiseIrql and KeLowerIrql +// routines +//-- + +#include "fpdebug.h" +#include "halp.h" +#include "eisa.h" +#include "phsystem.h" +#include "fpcpu.h" + + +VOID KiDispatchSoftwareInterrupt(VOID); + +// +// Globals accessed. +// +extern ULONG registeredInts[]; +extern ULONG Irql2Mask[]; + +// +// VOID +// KeLowerIrql ( +// KIRQL NewIrql +// ) +// +// Routine Description: +// +// This function lowers the current IRQL to the specified value. +// +// Arguments: +// +// NewIrql - Supplies the new IRQL value. +// +// Return Value: +// +// None. +// +//-- +VOID +KeLowerIrql(KIRQL NewIrql) +{ + KIRQL OldIrql; + UCHAR CpuId; + + // + // All accesses to the PCR should be guarded by disabling interrupts + // in the CPU (MSR register). + // + HalpDisableInterrupts(); + + CpuId = (UCHAR)GetCpuId(); + + // + // We should no be raising our Irql with lower. + // + HASSERTEXEC(NewIrql <= PCR->CurrentIrql, + HalpDebugPrint("KeLowerIrql: New (0x%x) Current(0x%x)\n", + NewIrql, PCR->CurrentIrql)); + + // + // Switch to the new Irql. + // + OldIrql = PCR->CurrentIrql; + PCR->CurrentIrql = NewIrql; + + // + // Now make the coresponding hardware mask changes. + // + RInterruptMask(CpuId) = (Irql2Mask[NewIrql] & registeredInts[CpuId]); + WaitForRInterruptMask(CpuId); + + if (NewIrql < CLOCK2_LEVEL) { + + HalpEnableInterrupts(); + + // + // check for DPC's + // + if ((NewIrql < DISPATCH_LEVEL) && PCR->SoftwareInterrupt) { + KiDispatchSoftwareInterrupt(); + } + } +} + +// +// VOID KeRaiseIrql (KIRQL NewIrql, PKIRQL OldIrql) +// +// Routine Description: +// +// This function raises the current IRQL to the specified value and returns +// the old IRQL value. +// +// Arguments: +// +// NewIrql - Supplies the new IRQL value. +// +// OldIrql - Supplies a pointer to a variable that recieves the old +// IRQL value. +// + +VOID +KeRaiseIrql(IN KIRQL NewIrql, OUT PKIRQL OldIrql) +{ + UCHAR CpuId; + + // + // All accesses to the PCR should be guarded by disabling interrupts + // in the CPU (MSR register). + // + HalpDisableInterrupts(); + + CpuId = (UCHAR)GetCpuId(); + + // + // We should not be raising to a lower level. + // + HASSERTEXEC(NewIrql >= PCR->CurrentIrql, + HalpDebugPrint("KeRaiseIrql: New (0x%x) Current(0x%x)\n", + NewIrql, PCR->CurrentIrql)); + + // + // Switch to the new Irql. + // + *OldIrql = PCR->CurrentIrql; + PCR->CurrentIrql = NewIrql; + + // + // Now make the corresponding hardware mask changes. + // + RInterruptMask(CpuId) = (Irql2Mask[NewIrql] & registeredInts[CpuId]); + WaitForRInterruptMask(CpuId); + + if (NewIrql < CLOCK2_LEVEL) { + HalpEnableInterrupts(); + } +} diff --git a/private/ntos/nthals/halfire/ppc/pxisabus.c b/private/ntos/nthals/halfire/ppc/pxisabus.c new file mode 100644 index 000000000..59c62c743 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxisabus.c @@ -0,0 +1,576 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxisabus.c $ + * $Revision: 1.21 $ + * $Date: 1996/05/14 02:34:36 $ + * $Locker: $ + */ + +/*++ + + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + pxisabus.c + +Abstract: + +Author: + +Environment: + +Revision History: + + +--*/ + +#include "fpdebug.h" +#include "halp.h" +#include "phsystem.h" + +ULONG +HalpGetIsaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ); + +#define TBS " " + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetIsaInterruptVector) +#pragma alloc_text(PAGE,HalpAdjustIsaResourceList) +#pragma alloc_text(PAGE,HalpAdjustResourceListLimits) +#endif + + + +/*++ + +Routine Description: ULONG HalpGetIsaInterruptVector() + + This function returns the system interrupt vector and IRQL level + corresponding to the specified bus interrupt level and/or vector. The + system interrupt vector and IRQL are suitable for use in a subsequent call + to KeInitializeInterrupt. + +Arguments: + + BusHandle - Per bus specific structure + + Irql - Returns the system request priority. + + Affinity - Returns the system wide irq affinity. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ + +ULONG +HalpGetIsaInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) +{ + + // + // irq2 shows up on irq9 + // + + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetIsaInterruptVector: 0x%x, 0x%x, 0x%x 0x%x \n", + BusInterruptLevel, BusInterruptVector, *Irql, *Affinity );); + + if (BusInterruptLevel == 2) { + BusInterruptLevel = 9; + BusInterruptVector = 9; + } + + // + // Hack Hack: + // + // NOTE: NOTE: + // The Ethernet driver reports itself as an ISA device but with a + // PCI interrupt so need to fixup the interrupt if it looks correct + // for the pci bus vector: + if (BusInterruptLevel > 15) { + return 0; + } + + // + // There are 4 cases to check here: + // A) One of the entries ( BusIntLvl || BusIntVec ) is zero, + // B) Both of the entries are the same value, + // C) One of the entries is == 5 ( Which is the SPL for external + // devices on PowerPC NT ) + // D) none of the above + // + switch(BusInterruptLevel) { + case 0: + if (BusInterruptVector) { + BusInterruptLevel = BusInterruptVector; + } else { + // they're both zero, so hope this is the profile int. + } + break; + case 5: + // + // In this case, BusInterruptLevel is probably indicating the + // system SPL for external ints, so assume the BusInterruptVector + // contains the real interrupt info + // + + break; + default: + // + // Since BusInterruptLevel is nonzero and not equal to 5, then see + // if BusInterruptVector is zero or equal to 5. If it's neither, + // then print out the level and vector values and spin since this + // is a combination I've never seen before. + // + if( BusInterruptVector ) { + ULONG tmp; + if( BusInterruptVector == (BusInterruptLevel + 0x20) ) { + + BusInterruptVector = BusInterruptLevel; + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetISAInt: BusIntVec(0x%x) = BusIntLvl(0x%x) +0x20 \n", + BusInterruptVector, BusInterruptLevel )); + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetISAInt: ****** Please Fix Driver to use BusInterruptVector correctly \n")); +// NOTE("Hack for audio driver to work") + } + if(( BusInterruptLevel != BusInterruptVector) + && ( BusInterruptVector != 5 )) { + HalpDebugPrint("Wierd BusIntVec & BusIntLvl (spin now)\n"); + HalpDebugPrint(" BusIntLvl = 0x%x, BusIntVec = 0x%x\n", + BusInterruptLevel, BusInterruptVector ); + for (;;) { + } + } + // + // Here, BusInterruptVector is known to be non-zero, = 5 or + // BusLevel. So, assume it's the 5 choice and swap it with + // level. + // + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("\t\tSwap BusIntLvl & BusIntVec %x, %x...\n", + BusInterruptLevel, BusInterruptVector);); + tmp = BusInterruptLevel; + BusInterruptLevel = BusInterruptVector; + BusInterruptVector = tmp; + // + // Now, BusInterruptVector has the interesting value so the + // HalpGetSystemInterrupt can correctly key on + // BusInterruptVector. + // + } else { + // + // since BusInterruptVector is zero + // + BusInterruptVector = BusInterruptLevel; + } + } + + // + // Get parent's translation from here.. + // + return BusHandler->ParentHandler->GetInterruptVector ( + BusHandler->ParentHandler, + RootHandler, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); +} + + + +NTSTATUS +HalpAdjustIsaResourceList ( + IN PVOID BusHandler, + IN PVOID RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +{ + UCHAR Irq[15], c; + + for (c=0; c < 15; c++) { + Irq[c] = IRQ_VALID; + } + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpAdjustIsaResourceList: called\n")); + + return HalpAdjustResourceListLimits ( + BusHandler, RootHandler, pResourceList, + 0, 0xffffff, // Bus supports up to memory 0xFFFFFF + 0, 0, // No special range for prefetch + FALSE, + 0, 0xffff, // Bus supports up to I/O port 0xFFFF + Irq, 15, // Bus supports up to 15 IRQs + 0, 7 // Bus supports up to Dma channel 7 + ); +} + + +NTSTATUS +HalpAdjustResourceListLimits ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList, + IN ULONG MinimumMemoryAddress, + IN ULONG MaximumMemoryAddress, + IN ULONG MinimumPrefetchMemoryAddress, + IN ULONG MaximumPrefetchMemoryAddress, + IN BOOLEAN LimitedIOSupport, + IN ULONG MinimumPortAddress, + IN ULONG MaximumPortAddress, + IN PUCHAR IrqTable, + IN ULONG IrqTableSize, + IN ULONG MinimumDmaChannel, + IN ULONG MaximumDmaChannel + ) +{ + PIO_RESOURCE_REQUIREMENTS_LIST InCompleteList, OutCompleteList; + PIO_RESOURCE_LIST InResourceList, OutResourceList; + PIO_RESOURCE_DESCRIPTOR InDesc, OutDesc, HeadOutDesc; + BOOLEAN GotPFRange, FirstDescBuilt; + ULONG len, alt, cnt, i; + UCHAR LastIrqState, NewIrqState; + ULONG PFAddress, icnt, pcnt; + + HDBG(DBG_INTERNAL, + HalpDebugPrint("HalpAdjustResourceListLimits: BusHandler=0x%08x, ResList=0x%08x\n", + BusHandler, pResourceList);); + + InCompleteList = *pResourceList; + len = InCompleteList->ListSize; + PFAddress = + MinimumPrefetchMemoryAddress || MaximumPrefetchMemoryAddress ? 1 : 0; + icnt = 0; + pcnt = 0; + + // + // Worste case, add an extra interrupt descriptor for every different + // IRQ range present + // + + LastIrqState = 0; + for (i=0; i < IrqTableSize; i++) { + if (IrqTable[i] != LastIrqState) { + icnt += 1; + LastIrqState = IrqTable[i]; + } + } + + // + // If LimitiedIOSupport, then the supported I/O ranges are + // limited to 256bytes on every 1K aligned boundry within the + // range specified. Worste case add an extra N descriptors for + // every I/O range passed. + // + + if (LimitedIOSupport && MaximumPortAddress > MinimumPortAddress) { + pcnt = (MaximumPortAddress - MinimumPortAddress) / 1024; + } + + // + // Scan input list - verify revision #'s, and increase len varible + // by amount output list may increase. + // + + i = 0; + InResourceList = InCompleteList->List; + for (alt=0; alt < InCompleteList->AlternativeLists; alt++) { + if (InResourceList->Version != 1 || InResourceList->Revision < 1) { + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sVersion is not 1, or revision is < 1.\n", + TBS);); + return STATUS_INVALID_PARAMETER; + } + + InDesc = InResourceList->Descriptors; + for (cnt = InResourceList->Count; cnt; cnt--) { + switch (InDesc->Type) { + case CmResourceTypePort: i += pcnt; break; + case CmResourceTypeInterrupt: i += icnt; break; + case CmResourceTypeMemory: i += PFAddress; break; + case CmResourceTypeDma: break; + default: + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sINVALID PARAM ..InDesc->Type: 0x%x\n", + TBS,InDesc->Type);); + return STATUS_INVALID_PARAMETER; + } + + // Next descriptor + InDesc++; + } + + // Next Resource List + InResourceList = (PIO_RESOURCE_LIST) InDesc; + } + len += i * sizeof (IO_RESOURCE_DESCRIPTOR); + + // + // Allocate output list + // + + OutCompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) + ExAllocatePool (PagedPool, len); + + if (!OutCompleteList) { + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sOutCompleteList is null ( No memory? ) \n",TBS);); + return STATUS_NO_MEMORY; + } + + // + // Walk each ResourceList and build output structure + // + + InResourceList = InCompleteList->List; + *OutCompleteList = *InCompleteList; + OutResourceList = OutCompleteList->List; + + for (alt=0; alt < InCompleteList->AlternativeLists; alt++) { + OutResourceList->Version = 1; + OutResourceList->Revision = 1; + + InDesc = InResourceList->Descriptors; + OutDesc = OutResourceList->Descriptors; + HeadOutDesc = OutDesc; + + for (cnt = InResourceList->Count; cnt; cnt--) { + + // + // Copy descriptor + // + + *OutDesc = *InDesc; + + // + // Limit desctiptor to be with the buses supported ranges + // + + switch (OutDesc->Type) { + case CmResourceTypePort: + if (OutDesc->u.Port.MinimumAddress.QuadPart < MinimumPortAddress) { + OutDesc->u.Port.MinimumAddress.QuadPart = MinimumPortAddress; + } + + if (OutDesc->u.Port.MaximumAddress.QuadPart > MaximumPortAddress) { + OutDesc->u.Port.MaximumAddress.QuadPart = MaximumPortAddress; + } + + if (!LimitedIOSupport) { + break; + } + + // In the case of LimitiedIOSupport the caller will only + // pass in 1K aligned values + + FirstDescBuilt = FALSE; + for (i = MinimumPortAddress; i < MaximumPortAddress; i += 1024) { + if (InDesc->u.Port.MinimumAddress.QuadPart < i) { + OutDesc->u.Port.MinimumAddress.QuadPart = i; + } + + if (InDesc->u.Port.MaximumAddress.QuadPart > i + 256) { + OutDesc->u.Port.MaximumAddress.QuadPart = i + 256; + } + + if (OutDesc->u.Port.MinimumAddress.QuadPart <= + OutDesc->u.Port.MaximumAddress.QuadPart) { + + // + // Valid I/O descriptor build, start another one. + // + + FirstDescBuilt = TRUE; + + OutDesc++; + *OutDesc = *InDesc; + OutDesc->Option |= IO_RESOURCE_ALTERNATIVE; + } + } + + if (FirstDescBuilt) { + OutDesc--; + } + break; + + case CmResourceTypeInterrupt: + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpAdjustResourceListLimits: new CmResourceTypeInterrupt \n");); + + // + // Build a list of interrupt descriptors which are + // a subset of the IrqTable and the current descriptor + // passed in on the input list. + // + + FirstDescBuilt = FALSE; + LastIrqState = 0; + + for (i=0; i < IrqTableSize; i++) { + NewIrqState = IrqTable[i]; + + while (LastIrqState != NewIrqState) { + if (LastIrqState) { + OutDesc++; // done with last desc + LastIrqState = 0; // new state + continue; + } + + // + // Start a new descriptor + // + + *OutDesc = *InDesc; + OutDesc->u.Interrupt.MinimumVector = i; + if (NewIrqState & IRQ_PREFERRED) { + OutDesc->Option |= IO_RESOURCE_PREFERRED; + } + + if (FirstDescBuilt) { + OutDesc->Option |= IO_RESOURCE_ALTERNATIVE; + } + + LastIrqState = NewIrqState; + FirstDescBuilt = TRUE; + } + + OutDesc->u.Interrupt.MaximumVector = i; + } + + if (!LastIrqState) { + if (!FirstDescBuilt) { + OutDesc->u.Interrupt.MinimumVector = + IrqTableSize + 1; + } else { + OutDesc--; + } + } + + break; + + case CmResourceTypeMemory: + if (PFAddress && (OutDesc->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) ) { + // + // There's a Prefetch range & this resource supports + // Prefetching. Build two descriptors - one for the + // supported Prefetch range as preferred, and the other + // normal memory range. + // + + OutDesc->Option |= IO_RESOURCE_PREFERRED; + + if (OutDesc->u.Memory.MinimumAddress.QuadPart < MinimumPrefetchMemoryAddress) { + OutDesc->u.Memory.MinimumAddress.QuadPart = MinimumPrefetchMemoryAddress; + } + + if (OutDesc->u.Memory.MaximumAddress.QuadPart > MaximumPrefetchMemoryAddress) { + OutDesc->u.Memory.MaximumAddress.QuadPart = MaximumPrefetchMemoryAddress; + } + + GotPFRange = FALSE; + if (OutDesc->u.Memory.MaximumAddress.QuadPart >= + OutDesc->u.Memory.MinimumAddress.QuadPart) { + + // + // got a valid descriptor in the Prefetch range, keep it, + // + + OutDesc++; + GotPFRange = TRUE; + } + + *OutDesc = *InDesc; + + if (GotPFRange) { + // next descriptor is an alternative + OutDesc->Option |= IO_RESOURCE_ALTERNATIVE; + } + } + + // + // Fill in memory descriptor for range + // + + if (OutDesc->u.Memory.MinimumAddress.QuadPart < MinimumMemoryAddress) { + OutDesc->u.Memory.MinimumAddress.QuadPart = MinimumMemoryAddress; + } + + if (OutDesc->u.Memory.MaximumAddress.QuadPart > MaximumMemoryAddress) { + OutDesc->u.Memory.MaximumAddress.QuadPart = MaximumMemoryAddress; + } + break; + + case CmResourceTypeDma: + if (OutDesc->u.Dma.MinimumChannel < MinimumDmaChannel) { + OutDesc->u.Dma.MinimumChannel = MinimumDmaChannel; + } + + if (OutDesc->u.Dma.MaximumChannel > MaximumDmaChannel) { + OutDesc->u.Dma.MaximumChannel = MaximumDmaChannel; + } + break; + +#if DBG + default: + DbgPrint ("HalAdjustResourceList: Unkown resource type\n"); + break; +#endif + } + + // + // Next descriptor + // + + InDesc++; + OutDesc++; + } + + OutResourceList->Count = OutDesc - HeadOutDesc; + + // + // Next Resource List + // + + InResourceList = (PIO_RESOURCE_LIST) InDesc; + OutResourceList = (PIO_RESOURCE_LIST) OutDesc; + } + + // + // Free input list, and return output list + // + + ExFreePool (InCompleteList); + + OutCompleteList->ListSize = + (ULONG) ((PUCHAR) OutResourceList - (PUCHAR) OutCompleteList); + *pResourceList = OutCompleteList; + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/halfire/ppc/pxmapio.c b/private/ntos/nthals/halfire/ppc/pxmapio.c new file mode 100644 index 000000000..383fa1c05 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxmapio.c @@ -0,0 +1,134 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxmapio.c + +Abstract: + + This module implements the mapping of HAL I/O space for a POWER PC + system. + +Author: + + David N. Cutler (davec) 28-Apr-1991 + +Environment: + + Kernel mode + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial PowerPC port + + Map interrupt acknowledge base address + Map SIO config base address + Remove RTC map - S-FOOT mapsthe RTC into the ISA I/O space + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxmapio.c $ + * $Revision: 1.5 $ + * $Date: 1996/01/11 07:11:27 $ + * $Locker: $ + */ + +#include "halp.h" + +// +// Put all code for HAL initialization in the INIT section. It will be +// deallocated by memory management when phase 1 initialization is +// completed. +// + +#if defined(ALLOC_PRAGMA) + +#pragma alloc_text(INIT, HalpMapIoSpace) + +#endif + + +BOOLEAN +HalpMapIoControlSpace ( + VOID + ); + +BOOLEAN +HalpMapPlanarSpace ( + VOID + ); + +BOOLEAN +HalpMapBusConfigSpace ( + VOID + ); + +// +// Define global data used to locate the IO control space and the PCI config +// space. +// + +PVOID HalpInterruptBase; +PVOID HalpPciConfigBase; +PVOID HalpErrorAddressRegister; + + +BOOLEAN +HalpMapIoSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL I/O, planar control, and bus configuration + spaces for a PowerPC system. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + // + // Map bus/bridge I/O control space + // + + if (!HalpMapIoControlSpace()) + return FALSE; + + // + // Map Planar I/O control space + // + + if (!HalpMapPlanarSpace()) + return FALSE; + + // + // Map Bus configuration space + // + + if (!HalpMapBusConfigSpace()) + return FALSE; + + + return TRUE; +} diff --git a/private/ntos/nthals/halfire/ppc/pxmemctl.c b/private/ntos/nthals/halfire/ppc/pxmemctl.c new file mode 100644 index 000000000..4dc541cad --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxmemctl.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxmemctl.c $ + * $Revision: 1.16 $ + * $Date: 1996/05/14 02:34:41 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxmemctl.c + +Abstract: + + The module initializes any planar registers. + This module also implements machince check parity error handling. + +Author: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) + + +Revision History: + + + +--*/ + + +#include "halp.h" +#include "pxmemctl.h" +#include "phsystem.h" + + +BOOLEAN +HalpInitPlanar ( + VOID + ) + +{ + return TRUE; +} + + + +BOOLEAN +HalpMapPlanarSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the interrupt acknowledge and error address + spaces for a PowerPC system. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + + PHYSICAL_ADDRESS physicalAddress; + + + // + // Map interrupt control space. + // + + physicalAddress.HighPart = 0; + physicalAddress.LowPart = INTERRUPT_PHYSICAL_BASE; + + + if ( HalpInterruptBase == NULL ) { + HalpInterruptBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + } + + if ( HalpSystemControlBase == NULL ) { + physicalAddress.HighPart = 0; + physicalAddress.LowPart = SYSTEM_CONTROL_SPACE; + HalpSystemControlBase = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + } + + // + // Map the error address register + // + + physicalAddress.HighPart = 0; + physicalAddress.LowPart = ERROR_ADDRESS_REGISTER; + HalpErrorAddressRegister = MmMapIoSpace(physicalAddress, + PAGE_SIZE, + FALSE); + + if (HalpInterruptBase == NULL || HalpErrorAddressRegister == NULL) + return FALSE; + else + return TRUE; + + + +} + +BOOLEAN +HalpMapBusConfigSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL PCI config + spaces for a PowerPC system. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + + PHYSICAL_ADDRESS physicalAddress; + + + // + // Map the PCI config space. + // + + physicalAddress.LowPart = PCI_CONFIG_PHYSICAL_BASE; + HalpPciConfigBase = MmMapIoSpace(physicalAddress, + PCI_CONFIG_SIZE, + FALSE); + + if (HalpPciConfigBase == NULL) + return FALSE; + else + return TRUE; + +} + +BOOLEAN +HalpPhase0MapBusConfigSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL PCI config + spaces for a PowerPC system during phase 0 initialization. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + // + // Map the PCI config space. + // + + HalpPciConfigBase = (PUCHAR)KePhase0MapIo( (PVOID)PCI_CONFIG_PHYSICAL_BASE, 0x400000); + + if (HalpPciConfigBase == NULL) + return FALSE; + else + return TRUE; + +} + +VOID +HalpPhase0UnMapBusConfigSpace ( + VOID + ) + +/*++ + +Routine Description: + + This routine maps the HAL PCI config + spaces for a PowerPC system during phase 0 initialization. + +Arguments: + + None. + +Return Value: + + If the initialization is successfully completed, than a value of TRUE + is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + // + // Unmap the PCI config space and set HalpPciConfigBase to NULL. + // + + KePhase0DeleteIoMap( (PVOID)PCI_CONFIG_PHYSICAL_BASE, 0x400000); + HalpPciConfigBase = NULL; + +} + + diff --git a/private/ntos/nthals/halfire/ppc/pxmemctl.h b/private/ntos/nthals/halfire/ppc/pxmemctl.h new file mode 100644 index 000000000..691535694 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxmemctl.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxmemctl.h $ + * $Revision: 1.10 $ + * $Date: 1996/05/14 02:34:45 $ + * $Locker: $ + */ + +/*++ BUILD Version: 0001 // Increment this if a change has global effects + + +Module Name: + + pxmemctl.h + +Abstract: + + This header file defines the structures for the planar registers + on Masters systems. + + + + +Author: + + Jim Wooldridge + + +Revision History: + +--*/ +#ifndef _PXMEMCTL_H +#define _PXMEMCTL_H + +// +// define physical base addresses of planar +// +#define SYSTEM_REGISTER_SPACE 0xff000000 // where the system registers + // live +#define INTERRUPT_PHYSICAL_BASE 0xff000000 // sys interrupt register area +#define SYSTEM_PCI_CONFIG_BASE 0xff400000 // sys pci config space +#define ERROR_ADDRESS_REGISTER 0xff000400 +#define ERROR_STATUS_REGISTER 0xff001000 +#define SYSTEM_CONTROL_SPACE 0xff100000 // system control registers +#define SYSTEM_CONTROL_SIZE 0x2000 // address range covered +#define DISPLAY_MEMORY_BASE 0x70000000 // display memory start +#define DISPLAY_MEMORY_SIZE 0x400000 // 4 MB for pro and top + +// +// OFFSETS +// +#define INTERRUPT_OFFSET 0x000000 // offset from system base +#define SYSTEM_CONTROL_OFFSET 0x100000 // offset from system base +#define IO_MEMORY_PHYSICAL_BASE 0xC0000000 // physical base of IO memory + + +#define IO_CONTROL_PHYSICAL_BASE 0x80000000 // physical base of IO control +#define SYSTEM_IO_CONTROL_SIZE 0x00008000 + +#define PCI_CONFIG_PHYSICAL_BASE 0x80800000 // physical base of PCI config space +// used to be: +// #define PCI_CONFIG_SIZE PAGE_SIZE * 9 // for FIREPOWER +// #define PCI_CONFIG_SIZE PAGE_SIZE * 5 // for PPC +#define PCI_CONFIG_SIZE 0x00800000 + +#endif // _PXMEMCTL_H diff --git a/private/ntos/nthals/halfire/ppc/pxmisc.s b/private/ntos/nthals/halfire/ppc/pxmisc.s new file mode 100644 index 000000000..52ed5c5ec --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxmisc.s @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxmisc.s $ + * $Revision: 1.7 $ + * $Date: 1996/01/11 07:11:46 $ + * $Locker: $ + */ + +//++ +// +// Copyright (c) 1993 IBM Corporation +// +// Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Module Name: +// +// pxmisc.s +// +// Abstract: +// +// This module implements miscellaneous routines on the PowerPC. +// +// Author: +// +// Steve Johns (sjohns@pets.sps.mot.com) August 1994 +// +// Environment: +// +// Kernel mode only. +// + +#include "kxppc.h" + + .set HID0, 1008 // SPR # for HID0 + + + LEAF_ENTRY(HalpGetHID0) + + mfspr r.3, HID0 + + LEAF_EXIT(HalpGetHID0) + + + + + LEAF_ENTRY(HalpSetHID0) + + mtspr HID0, r.3 + + LEAF_EXIT(HalpSetHID0) + + + LEAF_ENTRY(HalpSetDecrementer) + + mtdec r.3 // Set the DECREMENTER + + LEAF_EXIT(HalpSetDecrementer) + + + + +// +// HalpLockDisplayString +// +// This routine implements a lock on the HalDisplayString function +// to avoid garbling the display when more than one processor attempts +// to display a string at the same time. +// +// r.3 is the address of the lock. +// + + LEAF_ENTRY(HalpLockDisplayString) + + li r.5, 1 + lis r.6, 0x99 +LkDis: lwarx r.4, 0, r.3 + addic. r.6, r.6, -1 + beq LkSync + cmpwi r.4, 0 + bne- LkDis // jif lock already held + stwcx. r.5, 0, r.3 // attempt to take lock + sync + beqlr+ // return if all was good + +// +// We lost the reserve, allow the other processor a chance to +// win this argument. +// + + sync + sync + sync + sync + sync + sync + sync + sync + sync + sync + sync + sync + b LkDis + +LkSync: + stw r.5, 0(r.3) // Grab the lock anyway + LEAF_EXIT(HalpLockDisplayString) + + + +// ULONG HalpDivide ( +// IN ULARGE_INTEGER Dividend, +// IN ULONG Divisor) +// +// Routine Description: +// +// This function divides an unsigned large integer by an unsigned long +// and returns the resultant quotient and optionally the remainder. +// +// N.B. It is assumed that no overflow will occur. +// +// Arguments: +// +// Dividend (r.3, r.4) - Supplies the dividend value. +// (High-order bits in r.4, low-order bits in r.3) +// +// Divisor (r.5) - Supplies the divisor value. +// +// Return Value: +// +// The ULONG quotient is returned as the function value. +// +//-- + + + + .set Quotient, r.3 + .set DividendLo, r.3 + .set DividendHi, r.4 + .set Divisor, r.5 + .set Q1, r.11 + .set N, r.12 + .set Q0, N // Use of N & Q0 don't overlap + + LEAF_ENTRY(HalpDivide) + + + cmplw DividendHi,Divisor + bge overflow // catch overflow or division by 0 + cmplwi DividendHi,0 // test high part for 0 + bne Divide64Bits + +// High 32 bits of Dividend == 0, so use 32 bit division. + divwu DividendLo,DividendLo,Divisor // result <- dividend / divisor + blr + +Divide64Bits: + +// Normalize: Shift divisor and dividend left to get rid of leading zeroes +// in the divisor. Since DividendHi < Divisor, only zeroes are shifted out +// of the dividend. + cntlzw N,Divisor // number of bits to shift (N) + slw Divisor,Divisor,N // shift divisor + slw DividendHi,DividendHi,N // shift upper part of divisor + mr r.8, DividendLo // Save unshifted DividendLo + slw DividendLo,DividendLo,N // shift lower part of divisor + subfic N,N,32 // 32-N + srw N,r.8,N // leftmost N bits of DividendLo, slid right + or DividendHi,DividendHi,N // and inserted into low end of DividendHi + +// Estimate high-order halfword of quotient. If the dividend is +// A0 A1 A2 A3 and the divisor is B0 B1 (where each Ai or Bi is a halfword), +// then the estimate is A0 A1 0000 divided by B0 0000, or A0 A1 divided by B0. +// (DividendHi holds A0 A1, DividendLo holds A2 A3, and Divisor holds B0 B1.) +// The estimate may be too high because it does not account for B1; in rare +// cases, the estimate will not even fit in a halfword. High estimates are +// corrected for later. + srwi r.8,Divisor,16 // r.8 <- B0 + divwu Q0,DividendHi,r.8 // Q0 <- floor([A0 A1]/B0) +// Subtract partial quotient times divisor from dividend: If Q0 is the quotient +// computed above, this means that Q0 0000 times B0 B1 is subtracted from +// A0 A1 A2 A3. We compute Q0 times B0 B1 and then shift the two-word +// product left 16 bits. + mullw r.9,Q0,Divisor // low word of Q0 times B0 B1 + mulhwu r.10,Q0,Divisor // high word of Q0 times B0 B1 + slwi r.10,r.10,16 // shift high word left 16 bits + inslwi r.10,r.9,16,16 // move 16 bits from left of low word + // to right of high word + slwi r.9,r.9,16 // shift low word left 16 bits + subfc DividendLo,r.9,DividendLo // low word of difference + subfe DividendHi,r.10,DividendHi // high word of difference +// If the estimate for Q0 was too high, the difference will be negative. +// While A0 A1 A2 A3 is negative, repeatedly add B0 B1 0000 to A0 A1 A2 A3 +// and decrement Q0 by one to correct for the overestimate. + cmpwi DividendHi,0 // A0 A1 A2 A3 is negative iff A0 A1 is + bge Q0_okay // no correction needed + inslwi r.10,Divisor,16,16 // high word of B0 B1 0000 (= 0000 B0) + slwi r.9,Divisor,16 // low word of B0 B1 0000 (= B1 0000) +adjust_Q0: + addc DividendLo,DividendLo,r.9 // add B0 B1 0000 to A0 A1 A2 A3 (low) + adde DividendHi,DividendHi,r.10 // add B0 B1 0000 to A0 A1 A2 A3 (high) + cmpwi DividendHi,0 // Is A0 A1 A2 A3 now nonnegative? + addi Q0,Q0,-1 // decrement Q0 + blt adjust_Q0 // if A0 A1 A2 A3 still negative, repeat +Q0_okay: +// Estimate low-order halfword of quotient. A0 is necessarily 0000 at this +// point, so if the remaining part of the dividend is A0 A1 A2 A3 then the +// estimate is A1 A2 0000 divided by B0 0000, or A1 A2 divided by B0. +// (DividendHi holds A0 A1, DividendLo holds A2 A3, and r.8 holds B0.) + slwi r.9,DividendHi,16 // r.9 <- A1 0000 + inslwi r.9,DividendLo,16,16 // r.9 <- A1 A2 + divwu Q1,r.9,r.8 // Q1 <- floor([A1 A2]/B0) +// Subtract partial quotient times divisor from remaining part of dividend: +// If Q1 is the quotient computed above, this means +// that Q1 times B0 B1 is subtracted from A0 A1 A2 A3. We compute + mullw r.9,Q1,Divisor // low word of Q1 times B0 B1 + mulhwu r.10,Q1,Divisor // high word of Q1 times B0 B1 + subfc DividendLo,r.9,DividendLo // low word of difference + subfe DividendHi,r.10,DividendHi // high word of difference +// If the estimate for Q1 was too high, the difference will be negative. +// While A0 A1 A2 A3 is negative, repeatedly add B0 B1 to A0 A1 A2 A3 +// and decrement Q1 by one to correct for the overestimate. + cmpwi DividendHi,0 // A0 A1 A2 A3 is negative iff A0 A1 is + bge Q1_okay // no correction needed +adjust_Q1: + addc DividendLo,DividendLo,Divisor // add B0 B1 to A0 A1 A2 A3 (low) + addze DividendHi,DividendHi // add B0 B1 to A0 A1 A2 A3 (high) + cmpwi DividendHi,0 // Is A0 A1 A2 A3 now nonnegative? + addi Q1,Q1,-1 // decrement Q1 + blt adjust_Q1 // if A0 A1 A2 A3 still negative, repeat +Q1_okay: + slwi Quotient,Q0,16 // Quotient <- Q0 A1 + or Quotient,Quotient,Q1 + blr + + +// The error cases: +overflow: + li Quotient, 0 // return(0); + LEAF_EXIT(HalpDivide) + + + + +// ULARGE_INTEGER HalpMultiply ( +// IN ULONG Multiplicand, +// IN ULONG Multiplier) +// +// Routine Description: +// +// This function multiplies two ULONGS and returns a ULARGE_INTEGER product. +// +// N.B. It is assumed that no overflow will occur. +// +// Arguments: +// +// Multiplicand (r.4) - Supplies the multiplicand value. +// +// Multiplier (r.5) - Supplies the multiplier value. +// +// Return Value: +// +// The ULARGE_INTEGER product is returned as the function value. +// + + .set Multiplicand, r.4 + .set Multiplier, r.5 + .set Product, r.3 + + + LEAF_ENTRY(HalpMultiply) + + mullw r.0, Multiplicand, Multiplier // Calculate low 32 bits + stw r.0, 0(Product) + mulhwu r.0, Multiplicand, Multiplier // Calculate high 32 bits + stw r.0, 4(Product) + + LEAF_EXIT(HalpMultiply) + diff --git a/private/ntos/nthals/halfire/ppc/pxnatsup.c b/private/ntos/nthals/halfire/ppc/pxnatsup.c new file mode 100644 index 000000000..94452fcdc --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxnatsup.c @@ -0,0 +1,90 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxnatsup.c + +Abstract: + + The module provides the National SuperIO (PC87311) support for Power PC. + +Author: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) + + +Revision History: + + + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxnatsup.c $ + * $Revision: 1.5 $ + * $Date: 1996/01/11 07:11:59 $ + * $Locker: $ + */ + +#include "halp.h" +#include "pxnatsup.h" + + + +BOOLEAN +HalpInitSuperIo ( + VOID + ) + + +{ + + // + // Initialize the National SuperIO chip + // + + WRITE_REGISTER_UCHAR( + &((PNAT_SUPERIO_CONTROL)HalpIoControlBase)->SuperIoIndexRegister, + FER_ACCESS); + + WRITE_REGISTER_UCHAR( + &((PNAT_SUPERIO_CONTROL)HalpIoControlBase)->SuperIoDataRegister, + FER_PARALLEL_PORT_ENABLE | + FER_UART1_ENABLE | + FER_UART2_ENABLE | + FER_FDC_ENABLE | + FER_IDE); + + WRITE_REGISTER_UCHAR( + &((PNAT_SUPERIO_CONTROL)HalpIoControlBase)->SuperIoIndexRegister, + FAR_ACCESS); + + // + // LPT2 - irq5, uart1-com1, UART2-com2, + // + + WRITE_REGISTER_UCHAR( + &((PNAT_SUPERIO_CONTROL)HalpIoControlBase)->SuperIoDataRegister, + 0x10); + + WRITE_REGISTER_UCHAR( + &((PNAT_SUPERIO_CONTROL)HalpIoControlBase)->SuperIoIndexRegister, + PTR_ACCESS); + + WRITE_REGISTER_UCHAR( + &((PNAT_SUPERIO_CONTROL)HalpIoControlBase)->SuperIoDataRegister, + 0x04); + + return TRUE; + +} diff --git a/private/ntos/nthals/halfire/ppc/pxnatsup.h b/private/ntos/nthals/halfire/ppc/pxnatsup.h new file mode 100644 index 000000000..5c30c5a83 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxnatsup.h @@ -0,0 +1,67 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxnatsup.h + +Abstract: + + The module defines the structures, and defines for the + National (PC87311) SuperIO chip set. + +Author: + + Jim Wooldridge + +Revision History: + + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxnatsup.h $ + * $Revision: 1.5 $ + * $Date: 1996/01/11 07:12:05 $ + * $Locker: $ + */ + +// +// SuperIO configuration registers +// + +// +//index register select +// + +#define FER_ACCESS 0x00 +#define FAR_ACCESS 0x01 +#define PTR_ACCESS 0x02 + +// +//FER register bit fields +// + +#define FER_PARALLEL_PORT_ENABLE 0x01 +#define FER_UART1_ENABLE 0x02 +#define FER_UART2_ENABLE 0x04 +#define FER_FDC_ENABLE 0x08 +#define FER_FDD 0x10 +#define FER_FDC_MODE 0x20 +#define FER_IDE 0x30 +#define FER_IDE_MODE 0x40 + +// +// Lay the supio control registers onto the I/O control space +// + +typedef struct _NAT_SUPERIO_CONTROL { + UCHAR Reserved1[0x398]; + UCHAR SuperIoIndexRegister; // Offset 0x398 + UCHAR SuperIoDataRegister; // Offset 0x399 +} NAT_SUPERIO_CONTROL, *PNAT_SUPERIO_CONTROL; diff --git a/private/ntos/nthals/halfire/ppc/pxnvrsup.h b/private/ntos/nthals/halfire/ppc/pxnvrsup.h new file mode 100644 index 000000000..d719b05b5 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxnvrsup.h @@ -0,0 +1,35 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxnvrsup.h + +Abstract: + + The module defines the structures, and defines for the NVRAM support + in a PowerPC System. + + +Author: + + Jim Wooldridge + +Revision History: + + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxnvrsup.h $ + * $Revision: 1.8 $ + * $Date: 1996/05/14 02:34:50 $ + * $Locker: $ + */ + +#include "fpds1385.h" diff --git a/private/ntos/nthals/halfire/ppc/pxpcibus.c b/private/ntos/nthals/halfire/ppc/pxpcibus.c new file mode 100644 index 000000000..dd578510f --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxpcibus.c @@ -0,0 +1,2327 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxpcibus.c $ + * $Revision: 1.32 $ + * $Date: 1996/05/14 02:34:54 $ + * $Locker: $ + */ + +/*++ + + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + pxpcidat.c + +Abstract: + + Get/Set bus data routines for the PCI bus + +Author: + + Ken Reneris (kenr) 14-June-1994 + Jim Wooldridge Port to PowerPC + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "pxpcisup.h" + +#include "pxidaho.h" + +#include "phsystem.h" +#include "fpio.h" +#include "stdio.h" +#include "string.h" +#include "fpdebug.h" + +#define TBS " " +extern WCHAR rgzMultiFunctionAdapter[]; +extern WCHAR rgzConfigurationData[]; +extern WCHAR rgzIdentifier[]; +extern WCHAR rgzPCIIdentifier[]; +extern ULONG HalpAdjustBridge(PBUS_HANDLER, PPCI_COMMON_CONFIG, PCM_RESOURCE_LIST ); + +// +// Prototypes +// + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ); + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG SlotNumber, + IN OUT PCM_RESOURCE_LIST *AllocatedResources + ); + +VOID +HalpInitializePciBus ( + VOID + ); + +BOOLEAN +HalpIsValidPCIDevice ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ); + +BOOLEAN +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ); + +//------------------------------------------------- + +VOID HalpPCISynchronizeType1 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +VOID HalpPCIReleaseSynchronzationType1 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +ULONG HalpPCIReadUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +VOID HalpPCISynchronizeType2 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PVOID State + ); + +VOID HalpPCIReleaseSynchronzationType2 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ); + +ULONG HalpPCIReadUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIReadUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + +ULONG HalpPCIWriteUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PVOID State, + IN PUCHAR Buffer, + IN ULONG Offset + ); + + +// +// Globals +// + +KSPIN_LOCK HalpPCIConfigLock; + +PCI_CONFIG_HANDLER PCIConfigHandler; + +PCI_CONFIG_HANDLER PCIConfigHandlerType1 = { + HalpPCISynchronizeType1, + HalpPCIReleaseSynchronzationType1, + { + HalpPCIReadUlongType1, // 0 + HalpPCIReadUcharType1, // 1 + HalpPCIReadUshortType1 // 2 + }, + { + HalpPCIWriteUlongType1, // 0 + HalpPCIWriteUcharType1, // 1 + HalpPCIWriteUshortType1 // 2 + } +}; + +PCI_CONFIG_HANDLER PCIConfigHandlerType2 = { + HalpPCISynchronizeType2, + HalpPCIReleaseSynchronzationType2, + { + HalpPCIReadUlongType2, // 0 + HalpPCIReadUcharType2, // 1 + HalpPCIReadUshortType2 // 2 + }, + { + HalpPCIWriteUlongType2, // 0 + HalpPCIWriteUcharType2, // 1 + HalpPCIWriteUshortType2 // 2 + } +}; + +extern PCI_CONFIG_HANDLER PCIConfigHandlerBridged; + +UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} }; + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ); + +#if DBG +#define DBGMSG(a) HalpPrint(a) +VOID +HalpTestPci ( + ULONG + ); +#else +#define DBGMSG(a) +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpInitializePciBus) +#pragma alloc_text(INIT,HalpAllocateAndInitPciBusHandler) +#pragma alloc_text(INIT,HalpIsValidPCIDevice) +#endif + +VOID +HalpInitializePciBus ( + VOID + ) +{ + PCI_REGISTRY_INFO FirePCIRegInfo; + PPCI_REGISTRY_INFO PCIRegInfo = NULL; + UNICODE_STRING unicodeString, ConfigName, IdentName; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE hMFunc, hBus; + NTSTATUS status = STATUS_SEVERITY_INFORMATIONAL; + UCHAR buffer [sizeof(PPCI_REGISTRY_INFO) + 99]; + PWSTR p; + WCHAR wstr[8]; + ULONG i, d, junk, HwType; + PBUS_HANDLER BusHandler; + PCI_SLOT_NUMBER SlotNumber; + PKEY_VALUE_FULL_INFORMATION ValueInfo; + PCM_FULL_RESOURCE_DESCRIPTOR Desc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc; + + + // + + // + // Search the hardware description looking for any reported + // PCI bus. The first ARC entry for a PCI bus will contain + // the PCI_REGISTRY_INFO. + // + + RtlInitUnicodeString (&unicodeString, rgzMultiFunctionAdapter); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + NULL, // handle + NULL); + + + status = ZwOpenKey (&hMFunc, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + HalDisplayString("HalpInitializePCIBus: ZwOpenKey returned !NT_SUCCESS \n"); + return; + } + + unicodeString.Buffer = wstr; + unicodeString.MaximumLength = sizeof (wstr); + + RtlInitUnicodeString (&ConfigName, rgzConfigurationData); + RtlInitUnicodeString (&IdentName, rgzIdentifier); + + ValueInfo = (PKEY_VALUE_FULL_INFORMATION) buffer; + + for (i=0; TRUE; i++) { + RtlIntegerToUnicodeString (i, 10, &unicodeString); + InitializeObjectAttributes ( + &objectAttributes, + &unicodeString, + OBJ_CASE_INSENSITIVE, + hMFunc, + NULL); + + status = ZwOpenKey (&hBus, KEY_READ, &objectAttributes); + if (!NT_SUCCESS(status)) { + // + // Out of Multifunction adapter entries... + // + ZwClose (hMFunc); + break; + } + + // + // Check the Indentifier to see if this is a PCI entry + // + + status = ZwQueryValueKey ( + hBus, + &IdentName, + KeyValueFullInformation, + ValueInfo, + sizeof (buffer), + &junk + ); + + if (!NT_SUCCESS (status)) { + ZwClose (hBus); + continue; + } + + p = (PWSTR) ((PUCHAR) ValueInfo + ValueInfo->DataOffset); + if (p[0] != L'P' || p[1] != L'C' || p[2] != L'I' || p[3] != 0) { + ZwClose (hBus); + continue; + } + + // + // The first PCI entry has the PCI_REGISTRY_INFO structure + // attached to it. + // + + status = ZwQueryValueKey ( + hBus, + &ConfigName, + KeyValueFullInformation, + ValueInfo, + sizeof (buffer), + &junk + ); + + ZwClose (hBus); + if (!NT_SUCCESS(status)) { + continue ; + } + + Desc = (PCM_FULL_RESOURCE_DESCRIPTOR) ((PUCHAR) + ValueInfo + ValueInfo->DataOffset); + PDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) ((PUCHAR) + Desc->PartialResourceList.PartialDescriptors); + + if (PDesc->Type == CmResourceTypeDeviceSpecific) { + // got it.. + PCIRegInfo = (PPCI_REGISTRY_INFO) (PDesc+1); + break; + } + } + + + if(PCIRegInfo == NULL) { + + // + // FirePower only has one PCI bus. + // + PCIRegInfo = &FirePCIRegInfo; + PCIRegInfo->NoBuses = 1; + PCIRegInfo->HardwareMechanism = 1; + } + + + // + // Initialize spinlock for synchronizing access to PCI space + // + + KeInitializeSpinLock (&HalpPCIConfigLock); + + + // + // PCIRegInfo describes the system's PCI support as indicated by the BIOS. + // + + HwType = PCIRegInfo->HardwareMechanism & 0xf; + + // + // Some AMI bioses claim machines are Type2 configuration when they + // are really type1. If this is a Type2 with at least one bus, + // try to verify it's not really a type1 bus + // + + if (PCIRegInfo->NoBuses && HwType == 2) { + HalpDebugPrint("HalpInitializePCIBus: Setting HwType = 2 \n"); + + // + // Check each slot for a valid device. Which every style configuration + // space shows a valid device first will be used + // + + SlotNumber.u.bits.Reserved = 0; + SlotNumber.u.bits.FunctionNumber = 0; + + for (d = 0; d < PCI_MAX_DEVICES; d++) { + SlotNumber.u.bits.DeviceNumber = d; + + // + // First try what the BIOS claims - type 2. Allocate type2 + // test handle for PCI bus 0. + // + + HwType = 2; + BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE); + + if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) { + break; + } + + // + // Valid device not found on Type2 access for this slot. + // Reallocate the bus handler are Type1 and take a look. + // + + HwType = 1; + BusHandler = HalpAllocateAndInitPciBusHandler (HwType, 0, TRUE); + + if (HalpIsValidPCIDevice (BusHandler, SlotNumber)) { + break; + } + + HwType = 2; + } + + // + // Reset handler for PCI bus 0 to whatever style config space + // was finally decided. + // + + HalpAllocateAndInitPciBusHandler (HwType, 0, FALSE); + } + + + // + // For each PCI bus present, allocate a handler structure and + // fill in the dispatch functions + // + + for (i=0; i < PCIRegInfo->NoBuses; i++) { + + + // + // If handler not already built, do it now + // + if (!HalpHandlerForBus (PCIBus, i)) { + HalpDebugPrint("HalpInitializePciBus: Alloc PCI bus: 0x%0x\n",i); + HalpAllocateAndInitPciBusHandler (HwType, i, FALSE); + } + } + + // + // Bus handlers for all PCI buses have been allocated, go collect + // pci bridge information. + // + + +#if DBG + HalpTestPci (0); +#endif + //return; +} + +PBUS_HANDLER +HalpAllocateAndInitPciBusHandler ( + IN ULONG HwType, + IN ULONG BusNo, + IN BOOLEAN TestAllocation + ) +{ + PBUS_HANDLER Bus; + PPCIPBUSDATA BusData; + PFPHAL_BUSNODE FpBusData; + + HDBG(DBG_PCI, + HalpDebugPrint("HalpAllocAndInit: HwType=0x%x, BusNo=%x, TestAlloc=%x\n" + ,HwType, BusNo, TestAllocation);); + + Bus = HalpAllocateBusHandler ( + PCIBus, // Interface type + PCIConfiguration, // Has this configuration space + BusNo, // bus # + Internal, // child of this bus + 0, // and number + sizeof (FPHAL_BUSNODE) // FirePower hal bus specific buffer + ); + + // + // Fill in PCI handlers + // + if (!Bus) { + HalpDebugPrint("HalpAllocAndInit: No bus handler ...\n"); + return (PBUS_HANDLER) NULL; + } + + HDBG(DBG_PCI, + HalpDebugPrint("HalpAllocateAndInitPciBusHandler:@0x%08x \n", Bus->BusData);); + Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData; + Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData; + Bus->GetInterruptVector = (PGETINTERRUPTVECTOR) HalpGetPCIIntOnISABus; + Bus->AdjustResourceList = (PADJUSTRESOURCELIST) HalpAdjustPCIResourceList; + Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources; + Bus->TranslateBusAddress = (PTRANSLATEBUSADDRESS) HalpTranslatePCIBusAddress; + + FpBusData = (PFPHAL_BUSNODE) Bus->BusData; + BusData = (PPCIPBUSDATA) &(FpBusData->Bus); + HDBG(DBG_PCI, + HalpDebugPrint("HalpAllocateAndInitPciBusHandler:@0x%08x \n", BusData);); + + // + // Fill in common PCI data + // + + BusData->CommonData.Tag = PCI_DATA_TAG; + BusData->CommonData.Version = PCI_DATA_VERSION; + BusData->CommonData.ReadConfig = (PciReadWriteConfig) HalpReadPCIConfig; + BusData->CommonData.WriteConfig = (PciReadWriteConfig) HalpWritePCIConfig; + BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIPin2ISALine; + BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIISALine2Pin; + + FpBusData->HwType = HwType; + + // set defaults + BusData->LimitedIO = FALSE; + BusData->IOLimit = 0x3F7FFFFF; + BusData->MemoryLimit = 0x3EFFFFFF; + BusData->GetIrqTable = (PciIrqTable) HalpGetISAFixedPCIIrq; + + RtlInitializeBitMap (&FpBusData->Bus.DeviceConfigured, + FpBusData->Bus.ConfiguredBits, 256); + + switch (HwType) { + case 0: + // + // This case allows the hal to initialize buses without setting + // any PCIConfigHandler. The confighandlers can then be setup + // elsewhere + // + HalpDebugPrint(" Case 0:...\n"); + break; + case 1: + // + // Initialize access port information for Type1 handlers + // + + HDBG(DBG_PCI, + HalpDebugPrint(" Case 1:...\n");); + RtlCopyMemory ( &(FpBusData->Node), + &PCIConfigHandlerType1, + sizeof (PCIConfigHandler)); + FpBusData->Bus.MaxDevice = MAXIMUM_PCI_SLOTS -1; // 0 based *BJ* + break; + + case 2: + // + // Initialize access port information for Type2 handlers + // + + RtlCopyMemory ( &(FpBusData->Node), + &PCIConfigHandlerType2, + sizeof (PCIConfigHandler)); + + + // + // Early PCI machines didn't decode the last bit of + // the device id. Shrink type 2 support max device. + // + FpBusData->Bus.MaxDevice = MAXIMUM_PCI_SLOTS -1; + + break; + case 3: + // + // Initialize this bus as a bridged bus: I.E. this pci bus goes + // through a bridge. + // + + RtlCopyMemory ( &(FpBusData->Node), + &PCIConfigHandlerBridged, + sizeof (PCIConfigHandler)); + FpBusData->Bus.MaxDevice = MAXIMUM_PCI_SLOTS -1; // 0 based *BJ* + break; + + default: + // unsupport type + DBGMSG ("HAL: Unknown PCI type\n"); + } + + if (!TestAllocation) { + } + + return Bus; +} + +BOOLEAN +HalpIsValidPCIDevice ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ) +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + ULONG i, j; + + + PciData = (PPCI_COMMON_CONFIG) iBuffer; + + // + // Read device common header + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Valid device header? + // + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + + return FALSE; + } + + // + // Check fields for reasonable values + // + + if ((PciData->u.type0.InterruptPin && PciData->u.type0.InterruptPin > 4) || + (PciData->u.type0.InterruptLine & 0x70)) { + return FALSE; + } + + for (i=0; i < PCI_TYPE0_ADDRESSES; i++) { + j = PciData->u.type0.BaseAddresses[i]; + + if (j & PCI_ADDRESS_IO_SPACE) { + if (j > 0xffff) { + // IO port > 64k? + return FALSE; + } + } else { + if (j > 0xf && j < 0x80000) { + // Mem address < 0x8000h? + return FALSE; + } + } + + if (Is64BitBaseAddress(j)) { + i += 1; + } + } + + // + // Guess it's a valid device.. + // + + return TRUE; +} + + +/*++ + +Routine Description: ULONG HalpGetPCIData () + + The function returns the Pci bus data for a device. + +Arguments: + + BusNumber - Indicates which bus. + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Offset - Supplies the starting location within config space for requested + data. It's an address relative to the start of the config header. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + + If this PCI slot has never been set, then the configuration information + returned is zeroed. + + +--*/ + +ULONG +HalpGetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + PPCI_COMMON_CONFIG PciData; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + PPCIPBUSDATA BusData; + PFPHAL_BUSNODE FpNode; + ULONG Len; +#if DBG != 0 + ULONG i, bit; +#endif + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue + // in the device specific area. + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested at least some data within the + // common header. Read the whole header, effect the + // fields we need to and then copy the user's requested + // bytes from the header + // + + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + BusData = (PPCIPBUSDATA) &(FpNode->Bus); // ZZZ + + // + // Read this PCI devices slot data + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len); + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + PciData->VendorID = PCI_INVALID_VENDORID; + Len = 2; // only return invalid id + + } else { + + BusData->CommonData.Pin2Line ((PBUS_HANDLER) BusHandler, RootHandler, Slot, PciData); + } + + // + // Has this PCI device been configured? + // + +#if DBG + // + // On DBG build, if this PCI device has not yet been configured, + // then don't report any current configuration the device may have. + // + + bit = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); + if (!RtlCheckBit(&BusData->DeviceConfigured, bit)) { + + for (i=0; i < PCI_TYPE0_ADDRESSES; i++) { + PciData->u.type0.BaseAddresses[i] = 0; + } + + PciData->u.type0.ROMBaseAddress = 0; + PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + } +#endif + + + // + // Copy whatever data overlaps into the callers buffer + // + + if (Len < Offset) { + // no data at caller's buffer + return 0; + } + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory(Buffer, iBuffer + Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and read from it. + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpReadPCIConfig (BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +/*++ + +Routine Description: ULONG HalpSetPCIData () + + The function returns the Pci bus data for a device. + +Arguments: + + + VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word) + + Buffer - Supplies the space to store the data. + + Length - Supplies a count in bytes of the maximum amount to return. + +Return Value: + + Returns the amount of data stored into the buffer. + +--*/ + +ULONG +HalpSetPCIData ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + PPCI_COMMON_CONFIG PciData, PciData2; + UCHAR iBuffer[PCI_COMMON_HDR_LENGTH]; + UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH]; + PPCIPBUSDATA BusData; + PFPHAL_BUSNODE FpNode; + ULONG Len; +#if DBG != 0 + ULONG cnt; +#endif + + + if (Length > sizeof (PCI_COMMON_CONFIG)) { + Length = sizeof (PCI_COMMON_CONFIG); + } + + + Len = 0; + PciData = (PPCI_COMMON_CONFIG) iBuffer; + PciData2 = (PPCI_COMMON_CONFIG) iBuffer2; + + + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The user did not request any data from the common + // header. Verify the PCI device exists, then continue in + // the device specific area. + // + + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, sizeof(ULONG)); + + if (PciData->VendorID == PCI_INVALID_VENDORID) { + return 0; + } + + } else { + + // + // Caller requested to set at least some data within the + // common header. + // + + Len = PCI_COMMON_HDR_LENGTH; + HalpReadPCIConfig (BusHandler, Slot, PciData, 0, Len); + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != PCI_DEVICE_TYPE) { + + // no device, or header type unkown + return 0; + } + + + // + // Set this device as configured + // + + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + BusData = (PPCIPBUSDATA) &(FpNode->Bus); // ZZZ +#if DBG + cnt = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); + RtlSetBits (&BusData->DeviceConfigured, cnt, 1); +#endif + // + // Copy COMMON_HDR values to buffer2, then overlay callers changes. + // + + RtlMoveMemory (iBuffer2, iBuffer, Len); + BusData->CommonData.Pin2Line ((PBUS_HANDLER) BusHandler, RootHandler, Slot, PciData2); + + Len -= Offset; + if (Len > Length) { + Len = Length; + } + + RtlMoveMemory (iBuffer2+Offset, Buffer, Len); + + // in case interrupt line or pin was editted + BusData->CommonData.Line2Pin ((PBUS_HANDLER) BusHandler, RootHandler, Slot, PciData2, PciData); + +#if DBG + // + // Verify R/O fields haven't changed + // + if (PciData2->VendorID != PciData->VendorID || + PciData2->DeviceID != PciData->DeviceID || + PciData2->RevisionID != PciData->RevisionID || + PciData2->ProgIf != PciData->ProgIf || + PciData2->SubClass != PciData->SubClass || + PciData2->BaseClass != PciData->BaseClass || + PciData2->HeaderType != PciData->HeaderType || + PciData2->BaseClass != PciData->BaseClass || + PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant || + PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) { + HalpPrint ("PCI SetBusData: Read-Only configuration value changed\n"); + } +#endif + // + // Set new PCI configuration + // + + HalpWritePCIConfig (BusHandler, Slot, iBuffer2+Offset, Offset, Len); + + Offset += Len; + Buffer += Len; + Length -= Len; + } + + if (Length) { + if (Offset >= PCI_COMMON_HDR_LENGTH) { + // + // The remaining Buffer comes from the Device Specific + // area - put on the kitten gloves and write it + // + // Specific read/writes to the PCI device specific area + // are guarenteed: + // + // Not to read/write any byte outside the area specified + // by the caller. (this may cause WORD or BYTE references + // to the area in order to read the non-dword aligned + // ends of the request) + // + // To use a WORD access if the requested length is exactly + // a WORD long. + // + // To use a BYTE access if the requested length is exactly + // a BYTE long. + // + + HalpWritePCIConfig (BusHandler, Slot, Buffer, Offset, Length); + Len += Length; + } + } + + return Len; +} + +VOID +HalpReadPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + PFPHAL_BUSNODE FpNode; + + if (!HalpValidPCISlot (BusHandler, Slot)) { + // + // Invalid SlotID return no data + // + + RtlFillMemory (Buffer, Length, (UCHAR) -1); + return ; + } + + // + // Pull the "methods" this bus uses to get and set + // data. It's now appended to the bus data + // + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + FpNode->Node.ConfigRead); +} + +VOID +HalpWritePCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PVOID Buffer, + IN ULONG Offset, + IN ULONG Length + ) +{ + PFPHAL_BUSNODE FpNode; + + if (!HalpValidPCISlot (BusHandler, Slot)) { + // + // Invalid SlotID do nothing + // + return ; + } + + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length, + FpNode->Node.ConfigWrite); +} + +BOOLEAN +HalpValidPCISlot ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot + ) +{ + PCI_SLOT_NUMBER Slot2; + PPCIPBUSDATA BusData; + PFPHAL_BUSNODE FpNode; + UCHAR HeaderType; + ULONG i; + + + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + BusData = (PPCIPBUSDATA) &(FpNode->Bus); // ZZZ + + if (Slot.u.bits.Reserved != 0) { + return FALSE; + } + + if (Slot.u.bits.DeviceNumber > BusData->MaxDevice) { + return FALSE; + } + + i = Slot.u.bits.DeviceNumber; + + if ( !((FpNode->ValidDevs) & ( 1 << i )) ) { + // + // check the valid devs bitmap and see if this slot + // is marked. + // + //PRNTPCI(HalpDebugPrint("HalpValidPCISlot: Invalid dev (0x%08x) @%x\n", + // FpNode->ValidDevs, i)); + return FALSE; + } + + if (Slot.u.bits.FunctionNumber == 0) { + return TRUE; + } + + // + // Sandalfoot doesn't support Multifunction adapters + // + +// return FALSE; + + // + // Non zero function numbers are only supported if the + // device has the PCI_MULTIFUNCTION bit set in it's header + // + + i = Slot.u.bits.DeviceNumber; + + // + // Read DeviceNumber, Function zero, to determine if the + // PCI supports multifunction devices + // + + Slot2 = Slot; + Slot2.u.bits.FunctionNumber = 0; + + HalpReadPCIConfig ( + BusHandler, + Slot2, + &HeaderType, + FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType), + sizeof (UCHAR) + ); + + if (!(HeaderType & PCI_MULTIFUNCTION) || HeaderType == 0xFF) { + // this device doesn't exists or doesn't support MULTIFUNCTION types + return FALSE; + } + + return TRUE; +} + + +VOID +HalpPCIConfig ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PUCHAR Buffer, + IN ULONG Offset, + IN ULONG Length, + IN FncConfigIO *ConfigIO + ) +{ + KIRQL OldIrql; + ULONG i; + UCHAR State[20]; + PPCIPBUSDATA BusData; + PFPHAL_BUSNODE FpNode; + + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + BusData = (PPCIPBUSDATA) &FpNode->Bus; + FpNode->Node.Synchronize (BusHandler, Slot, &OldIrql, State); + + while (Length) { + i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; + i = ConfigIO[i] (BusData, State, Buffer, Offset); + + Offset += i; + Buffer += i; + Length -= i; + + i = RPciVendorId(0); + + } + FpNode->Node.ReleaseSynchronzation (BusHandler, OldIrql); +} + +VOID HalpPCISynchronizeType1 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg1 + ) +{ + // + // Initialize PciCfg1 + // + +// PciCfg1->u.AsULONG = (PUCHAR) HalpPciConfigBase + HalpPciConfigSlot[Slot.u.bits.DeviceNumber]; + // + // The HalpPciConfigBase value just happens to satisfy the requirements of + // pci config space addressing: The word written out says this is a write + // enabling config space mapping on bus number 1. + // + // The value pulled out of HalpPciConfigSlot determines the device/function + // number and sets the register number ( which of the 32 config space words) + // to access + // + PciCfg1->u.AsULONG = (ULONG) HalpPciConfigBase + HalpPciConfigSlot[Slot.u.bits.DeviceNumber]; + +} + +VOID HalpPCIReleaseSynchronzationType1 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ) +{ + + +} + + +ULONG +HalpPCIReadUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + *Buffer = READ_PORT_UCHAR ((PUCHAR)(PciCfg1->u.AsULONG + i)); + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUSHORT)(PciCfg1->u.AsULONG + i)); + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + *((PULONG) Buffer) = READ_PORT_ULONG ((PULONG) (PciCfg1->u.AsULONG)); + return sizeof (ULONG); +} + + +ULONG +HalpPCIWriteUcharType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_UCHAR (PciCfg1->u.AsULONG + i, *Buffer ); + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshortType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_USHORT (PciCfg1->u.AsULONG + i, *((PUSHORT) Buffer) ); + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlongType1 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (PciCfg1->u.AsULONG, *((PULONG) Buffer) ); + return sizeof (ULONG); +} + +VOID HalpPCISynchronizeType2 ( + IN PBUS_HANDLER BusHandler, + IN PCI_SLOT_NUMBER Slot, + IN PKIRQL Irql, + IN PPCI_TYPE1_CFG_BITS PciCfg1 + ) +{ + + // + // Initialize PciCfg1 + // + + PciCfg1->u.AsULONG = 0; + PciCfg1->u.bits.BusNumber = BusHandler->BusNumber; + PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber ? + Slot.u.bits.DeviceNumber + 10: + Slot.u.bits.DeviceNumber ; + PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber; + PciCfg1->u.bits.Enable = TRUE; + + KeRaiseIrql (PROFILE_LEVEL, Irql); + KiAcquireSpinLock (&HalpPCIConfigLock); + + + +} + + +VOID HalpPCIReleaseSynchronzationType2 ( + IN PBUS_HANDLER BusHandler, + IN KIRQL Irql + ) +{ + + KiReleaseSpinLock (&HalpPCIConfigLock); + KeLowerIrql (Irql); + +} + + +ULONG +HalpPCIReadUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + *((PUCHAR) Buffer) = READ_PORT_UCHAR ((PUCHAR)&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigData + i); + return sizeof (UCHAR); +} + +ULONG +HalpPCIReadUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + *((PUSHORT) Buffer) = READ_PORT_USHORT ((PUCHAR)&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigData + i); + return sizeof (USHORT); +} + +ULONG +HalpPCIReadUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG); + *((PULONG) Buffer) = READ_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigData); + return sizeof(ULONG); +} + + +ULONG +HalpPCIWriteUcharType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + WRITE_PORT_UCHAR ((PUCHAR)&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigData + i,*Buffer); + return sizeof (UCHAR); +} + +ULONG +HalpPCIWriteUshortType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + ULONG i; + + i = Offset % sizeof(ULONG); + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG ); + WRITE_PORT_USHORT ((PUCHAR)&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigData + (USHORT) i,*((PUSHORT)Buffer)); + return sizeof (USHORT); +} + +ULONG +HalpPCIWriteUlongType2 ( + IN PPCIPBUSDATA BusData, + IN PPCI_TYPE1_CFG_BITS PciCfg1, + IN PUCHAR Buffer, + IN ULONG Offset + ) +{ + PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG); + + WRITE_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigAddress, PciCfg1->u.AsULONG); + WRITE_PORT_ULONG (&((PIDAHO_CONTROL)HalpIoControlBase)->ConfigData,*((PULONG)Buffer)); + return sizeof(ULONG); +} + +/*++ + +Routine Description: NTSTATUS HalpAssignPCISlotResources () + + Reads the targeted device to determine it's required resources. + Calls IoAssignResources to allocate them. + Sets the targeted device with it's assigned resoruces + and returns the assignments to the caller. + +Arguments: + +Return Value: + + STATUS_SUCCESS or error + +--*/ + +NTSTATUS +HalpAssignPCISlotResources ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PUNICODE_STRING RegistryPath, + IN PUNICODE_STRING DriverClassName OPTIONAL, + IN PDRIVER_OBJECT DriverObject, + IN PDEVICE_OBJECT DeviceObject OPTIONAL, + IN ULONG Slot, + IN OUT PCM_RESOURCE_LIST *pAllocatedResources + ) +{ + NTSTATUS status; + PUCHAR WorkingPool; + PPCI_COMMON_CONFIG PciData, PciOrigData, PciData2; + PCI_SLOT_NUMBER PciSlot; + PPCIPBUSDATA BusData; + PFPHAL_BUSNODE FpNode; + PIO_RESOURCE_REQUIREMENTS_LIST CompleteList; + PIO_RESOURCE_DESCRIPTOR Descriptor; + PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor; + ULONG BusNumber; + ULONG i, j, m, length, memtype; + ULONG NoBaseAddress, RomIndex; + PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1]; + PULONG OrigAddress[PCI_TYPE0_ADDRESSES + 1]; + BOOLEAN Match, EnableRomBase; + + + PRNTPCI(HalpDebugPrint( + "HalpAssignPCISlotResources: BusHandler: 0x%x, Slot: 0x%x\n", + (ULONG)BusHandler, (ULONG)Slot )); + + *pAllocatedResources = NULL; + PciSlot = *((PPCI_SLOT_NUMBER) &Slot); + BusNumber = BusHandler->BusNumber; +// PRNTPCI(DbgBreakPoint()); + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + BusData = (PPCIPBUSDATA) &(FpNode->Bus); // ZZZ + + // + // Allocate some pool for working space + // + + i = sizeof (IO_RESOURCE_REQUIREMENTS_LIST) + + (sizeof (IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2) + + PCI_COMMON_HDR_LENGTH * 3; + i *= 3; + + // + // triple the calculated size just to make sure we don't run out of + // space. + // + WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i); + if (!WorkingPool) { + return STATUS_NO_MEMORY; + } + + // + // Zero initialize pool, and get pointers into memory + // + + RtlZeroMemory (WorkingPool, i); + CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool; + PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - + PCI_COMMON_HDR_LENGTH * 3); + PciData2 = (PPCI_COMMON_CONFIG) (WorkingPool + i - + PCI_COMMON_HDR_LENGTH * 2); + PciOrigData = (PPCI_COMMON_CONFIG) (WorkingPool + i - + PCI_COMMON_HDR_LENGTH * 1); + + // + // Read the PCI device's configuration + // + + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + if (PciData->VendorID == PCI_INVALID_VENDORID) { + ExFreePool (WorkingPool); + HalpDebugPrint("No such device found\n"); + return STATUS_NO_SUCH_DEVICE; + } + + // + // Make a copy of the device's current settings + // + + RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH); + + // + // Initialize base addresses base on configuration data type + // + + switch (PCI_CONFIG_TYPE(PciData)) { + case 0 : + NoBaseAddress = PCI_TYPE0_ADDRESSES+1; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type0.BaseAddresses[j]; + OrigAddress[j] = &PciOrigData->u.type0.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type0.ROMBaseAddress; + OrigAddress[j] = &PciOrigData->u.type0.ROMBaseAddress; + RomIndex = j; + break; + case 1: + NoBaseAddress = PCI_TYPE1_ADDRESSES+1; + for (j=0; j < PCI_TYPE1_ADDRESSES; j++) { + BaseAddress[j] = &PciData->u.type1.BaseAddresses[j]; + OrigAddress[j] = &PciOrigData->u.type1.BaseAddresses[j]; + } + BaseAddress[j] = &PciData->u.type1.ROMBaseAddress; + OrigAddress[j] = &PciOrigData->u.type1.ROMBaseAddress; + RomIndex = j; + break; + + default: + HalpDebugPrint("No such device of this type: %x \n", + PCI_CONFIG_TYPE(PciData)); + ExFreePool (WorkingPool); + return STATUS_NO_SUCH_DEVICE; + } + + // + // If the BIOS doesn't have the device's ROM enabled, then we won't + // enable it either. Remove it from the list. + // + + EnableRomBase = TRUE; + if (!(*BaseAddress[RomIndex] & PCI_ROMADDRESS_ENABLED)) { + ASSERT (RomIndex+1 == NoBaseAddress); + EnableRomBase = FALSE; + NoBaseAddress -= 1; + } + + // + // Set resources to all bits on to see what type of resources + // are required. + // + + for (j=0; j < NoBaseAddress; j++) { + *BaseAddress[j] = 0xFFFFFFFF; + } + +//*BJ* PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE); + *BaseAddress[RomIndex] &= ~PCI_ROMADDRESS_ENABLED; + HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // note type0 & type1 overlay ROMBaseAddress, InterruptPin, and + // InterruptLine + // + BusData->CommonData.Pin2Line ( (PBUS_HANDLER) BusHandler, + RootHandler, + PciSlot, + PciData + ); + + // + // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device + // + + CompleteList->InterfaceType = PCIBus; + CompleteList->BusNumber = BusNumber; + CompleteList->SlotNumber = Slot; + CompleteList->AlternativeLists = 1; + + CompleteList->List[0].Version = 1; + CompleteList->List[0].Revision = 1; + + Descriptor = CompleteList->List[0].Descriptors; + + // + // If PCI device has an interrupt resource, add it + // + + if (PciData->u.type0.InterruptPin) { + CompleteList->List[0].Count++; + + Descriptor->Option = 0; + Descriptor->Type = CmResourceTypeInterrupt; + Descriptor->ShareDisposition = CmResourceShareShared; + Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + + // Fill in any vector here - we'll pick it back up in + // HalAdjustResourceList and adjust it to it's allowed settings + Descriptor->u.Interrupt.MinimumVector = 0; + Descriptor->u.Interrupt.MaximumVector = 0xff; + Descriptor++; + } else { + PRNTINTR(HalpDebugPrint("%sDevice(%x,%x) has no interrupt resource\n", + TBS, Slot, BusNumber)); + PRNTINTR(HalpDebugPrint("\t\tPciData: 0x%x\n",PciData)); + } + + // + // Add a memory/port resoruce for each PCI resource + // + + // Clear ROM reserved bits + + *BaseAddress[RomIndex] &= ~0x7ff; + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + i = *BaseAddress[j]; + PRNTPCI(HalpDebugPrint("PCI: BaseAddress[%d] = %08lx\n", j, i)); + + // scan for first set bit, that's the length & alignment + length = 1 << (i & PCI_ADDRESS_IO_SPACE ? 2 : 4); + while (!(i & length) && length) { + length <<= 1; + } + + // scan for last set bit, that's the maxaddress + 1 + for (m = length; i & m; m <<= 1) ; + m--; + + // + // check for hosed PCI configuration requirements: + // + if (length & ~m) { +#if DBG + HalpPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n", + BusNumber, + PciSlot.u.bits.DeviceNumber, + PciSlot.u.bits.FunctionNumber + ); + + HalpPrint ("PCI: BaseAddress[%d] = %08lx\n", j, i); +#endif + // the device is in error - punt. don't allow this + // resource any option - it either gets set to whatever + // bits it was able to return, or it doesn't get set. + + if (i & PCI_ADDRESS_IO_SPACE) { + m = i & ~0x3; + Descriptor->u.Port.MinimumAddress.LowPart = m; + } else { + m = i & ~0xf; + Descriptor->u.Memory.MinimumAddress.LowPart = m; + } + + m += length; // max address is min address + length + } + + // + // Add requested resource + // + + Descriptor->Option = 0; + if (i & PCI_ADDRESS_IO_SPACE) { + memtype = 0; + + if (PciOrigData->Command & PCI_ENABLE_IO_SPACE) { + + // + // The IO range is/was already enabled at some location, add that + // as it's preferred setting. + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + Descriptor->Option = IO_RESOURCE_PREFERRED; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0x3; + Descriptor->u.Port.MaximumAddress.LowPart = + Descriptor->u.Port.MinimumAddress.LowPart + length - 1; + + CompleteList->List[0].Count++; + Descriptor++; + + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + } + + // + // Add this IO range + // + + Descriptor->Type = CmResourceTypePort; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Flags = CM_RESOURCE_PORT_IO; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MaximumAddress.LowPart = m; + PRNTPCI(HalpDebugPrint("FpNode: 0x%x ( %x:%x )\n", + FpNode, FpNode->MemBase,m)); + if( FpNode->IoTop < m ) { + Descriptor->u.Port.MinimumAddress.LowPart = + FpNode->IoBase; + Descriptor->u.Port.MaximumAddress.LowPart = + FpNode->IoTop | 0xfff; + PRNTINTR(HalpDebugPrint("HalpAssignPciSlot........%x, %x\n", + Descriptor->u.Port.MinimumAddress.LowPart, + Descriptor->u.Port.MaximumAddress.LowPart)); + } + + } else { + memtype = i & PCI_ADDRESS_MEMORY_TYPE_MASK; + + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; + if (j == RomIndex) { + // this is a ROM address + Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY; + } + + if (i & PCI_ADDRESS_MEMORY_PREFETCHABLE) { + Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE; + } + + if (!Is64BitBaseAddress(i) && + (j == RomIndex || + PciOrigData->Command & PCI_ENABLE_MEMORY_SPACE)) { + + // + // The memory range is/was already enabled at some location, add that + // as it's preferred setting. + // + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + Descriptor->Option = IO_RESOURCE_PREFERRED; + + Descriptor->u.Port.Length = length; + Descriptor->u.Port.Alignment = length; + Descriptor->u.Port.MinimumAddress.LowPart = *OrigAddress[j] & ~0xF; + Descriptor->u.Port.MaximumAddress.LowPart = + Descriptor->u.Port.MinimumAddress.LowPart + length - 1; + + CompleteList->List[0].Count++; + Descriptor++; + + Descriptor->Flags = Descriptor[-1].Flags; + Descriptor->Option = IO_RESOURCE_ALTERNATIVE; + } + + // + // Add this memory range + // + + Descriptor->Type = CmResourceTypeMemory; + Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; + + Descriptor->u.Memory.Length = length; + Descriptor->u.Memory.Alignment = length; + Descriptor->u.Memory.MaximumAddress.LowPart = m; + + if (memtype == PCI_TYPE_20BIT && m > 0xFFFFF) { + // limit to 20 bit address + Descriptor->u.Memory.MaximumAddress.LowPart = 0xFFFFF; + } + PRNTPCI(HalpDebugPrint("FpNode: 0x%x ( %x:%x )\n", + FpNode, FpNode->MemBase,m)); + if( FpNode->MemTop < m ) { + Descriptor->u.Memory.MinimumAddress.LowPart = + FpNode->MemBase; + Descriptor->u.Memory.MaximumAddress.LowPart = + FpNode->MemTop; + PRNTPCI(HalpDebugPrint("HalpAssignPciSlot....%x, %x\n", + FpNode->MemBase, FpNode->MemTop)); + } + if (Is64BitBaseAddress(i)) { + // skip upper half of 64 bit address since this processor + // only supports 32 bits of address space + j++; + } + + } + + CompleteList->List[0].Count++; + Descriptor++; + } + } + + CompleteList->ListSize = (ULONG) + ((PUCHAR) Descriptor - (PUCHAR) CompleteList); + + // + // Restore the device settings as we found them, enable memory + // and io decode after setting base addresses. This is done in + // case HalAdjustResourceList wants to read the current settings + // in the device. + // + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + &PciOrigData->Status, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status), + PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + // + // Have the IO system allocate resource assignments + // + + status = IoAssignResources ( + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + CompleteList, + pAllocatedResources + ); + + if (!NT_SUCCESS(status)) { + HalpDebugPrint("HalpAssignPCISlotResources: Failed IoAssignResources:%x\n", + status); + goto CleanUp; + } + + // + // Slurp the assigments back into the PciData structure and + // perform them + // + + CmDescriptor = (*pAllocatedResources)->List[0].PartialResourceList.PartialDescriptors; + + // + // If PCI device has an interrupt resource then that was + // passed in as the first requested resource + // + + if (PciData->u.type0.InterruptPin) { + PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector; + BusData->CommonData.Line2Pin ((PBUS_HANDLER) BusHandler, RootHandler, PciSlot, PciData, PciOrigData); + CmDescriptor++; + } + + // + // Pull out resources in the order they were passed to IoAssignResources + // + + m = 0; + for (j=0; j < NoBaseAddress; j++) { + i = *BaseAddress[j]; + if (i) { + if (i & PCI_ADDRESS_IO_SPACE) { + m |= PCI_ENABLE_IO_SPACE; + *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart; + } else { + m |= PCI_ENABLE_MEMORY_SPACE; + *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart; + + if (Is64BitBaseAddress(i)) { + // skip upper 32 bits + j++; + } + } + CmDescriptor++; + } + } + + // + // Set addresses, but do not turn on decodes + // + + HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH); + + // + // Read configuration back and verify address settings took + // + + HalpReadPCIConfig(BusHandler, PciSlot, PciData2, 0, PCI_COMMON_HDR_LENGTH); + Match = TRUE; + if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine || + PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin || + PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) { + Match = FALSE; + } + + for (j=0; j < NoBaseAddress; j++) { + if (*BaseAddress[j]) { + if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) { + i = (ULONG) ~0x3; + } else { + i = (ULONG) ~0xF; + } + + if ((*BaseAddress[j] & i) != + *((PULONG) ((PUCHAR) BaseAddress[j] - + (PUCHAR) PciData + + (PUCHAR) PciData2)) & i) { + + Match = FALSE; + } + if ( + !(*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) && + Is64BitBaseAddress(*BaseAddress[j]) + ) { + // skip upper 32 bits + j++; + } + } + } + + if (!Match) { +#if DBG + HalpPrint ("PCI: defective device! Bus %d, Slot %d, Function %d\n", + BusNumber, + PciSlot.u.bits.DeviceNumber, + PciSlot.u.bits.FunctionNumber + ); +#endif + status = STATUS_DEVICE_PROTOCOL_ERROR; + goto CleanUp; + } + + // + // Settings took - turn on the appropiate decodes + // + + if (EnableRomBase && *BaseAddress[RomIndex]) { + // a rom address was allocated and should be enabled + *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED; + HalpWritePCIConfig ( + BusHandler, + PciSlot, + BaseAddress[RomIndex], + (ULONG) ((PUCHAR) BaseAddress[RomIndex] - (PUCHAR) PciData), + sizeof (ULONG) + ); + } + + // + // Enable IO & Memory decodes (use HalSetBusData since valid settings now set) + // + + // Set Bus master bit on for win95 compatibility + m |= PCI_ENABLE_BUS_MASTER; + + PciData->Command |= (USHORT) m; + + HalSetBusDataByOffset ( + PCIConfiguration, + BusHandler->BusNumber, + PciSlot.u.AsULONG, + &PciData->Command, + FIELD_OFFSET (PCI_COMMON_CONFIG, Command), + sizeof (PciData->Command) + ); + + +CleanUp: + if (!NT_SUCCESS(status)) { + + // + // Failure, if there are any allocated resources free them + // + + if (*pAllocatedResources) { + IoAssignResources ( + RegistryPath, + DriverClassName, + DriverObject, + DeviceObject, + NULL, + NULL + ); + + ExFreePool (*pAllocatedResources); + *pAllocatedResources = NULL; + } + + // + // Restore the device settings as we found them, enable memory + // and io decode after setting base addresses + // + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + &PciOrigData->Status, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status), + PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + + HalpWritePCIConfig ( + BusHandler, + PciSlot, + PciOrigData, + 0, + FIELD_OFFSET (PCI_COMMON_CONFIG, Status) + ); + } + + ExFreePool (WorkingPool); + return status; +} + +#if DBG +VOID +HalpTestPci (ULONG flag2) +{ + PCI_SLOT_NUMBER SlotNumber; + PCI_COMMON_CONFIG PciData, OrigData; + ULONG i, f, j, k, bus; + BOOLEAN flag; + + + if (!flag2) { + return ; + } + SlotNumber.u.bits.Reserved = 0; + + // + // Read every possible PCI Device/Function and display it's + // default info. + // + // (note this destories it's current settings) + // + + flag = TRUE; + for (bus = 0; flag; bus++) { + + for (i = 0; i < PCI_MAX_DEVICES; i++) { + SlotNumber.u.bits.DeviceNumber = i; + + for (f = 0; f < PCI_MAX_FUNCTION; f++) { + SlotNumber.u.bits.FunctionNumber = f; + + // + // Note: This is reading the DeviceSpecific area of + // the device's configuration - normally this should + // only be done on device for which the caller understands. + // I'm doing it here only for debugging. + // + + j = HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + if (j == 0) { + // out of buses + flag = FALSE; + break; + } + + if (j < PCI_COMMON_HDR_LENGTH) { + continue; + } + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + 1 + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + memcpy (&OrigData, &PciData, sizeof PciData); + + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + PciData.u.type0.BaseAddresses[j] = 0xFFFFFFFF; + } + + PciData.u.type0.ROMBaseAddress = 0xFFFFFFFF; + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalpPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx", + bus, i, f, PciData.VendorID, PciData.DeviceID, + PciData.RevisionID); + + + if (PciData.u.type0.InterruptPin) { + HalpPrint (" IntPin:%x", PciData.u.type0.InterruptPin); + } + + if (PciData.u.type0.InterruptLine) { + HalpPrint (" IntLine:%x", PciData.u.type0.InterruptLine); + } + + if (PciData.u.type0.ROMBaseAddress) { + HalpPrint (" ROM:%08lx", PciData.u.type0.ROMBaseAddress); + } + + HalpPrint ("\n ProgIf:%04x SubClass:%04x BaseClass:%04lx\n", + PciData.ProgIf, PciData.SubClass, PciData.BaseClass); + + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (PciData.u.type0.BaseAddresses[j]) { + HalpPrint (" Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + if (PciData.u.type0.ROMBaseAddress == 0xC08001) { + + PciData.u.type0.ROMBaseAddress = 0xC00001; + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalGetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &PciData, + sizeof (PciData) + ); + + HalpPrint ("\n Bogus rom address, edit yields:%08lx", + PciData.u.type0.ROMBaseAddress); + } + + if (k) { + HalpPrint ("\n"); + } + + if (PciData.VendorID == 0x8086) { + // dump complete buffer + HalpPrint ("Command %x, Status %x, BIST %x\n", + PciData.Command, PciData.Status, + PciData.BIST + ); + + HalpPrint ("CacheLineSz %x, LatencyTimer %x", + PciData.CacheLineSize, PciData.LatencyTimer + ); + + for (j=0; j < 192; j++) { + if ((j & 0xf) == 0) { + HalpPrint ("\n%02x: ", j + 0x40); + } + HalpPrint ("%02x ", PciData.DeviceSpecific[j]); + } + HalpPrint ("\n"); + } + + + // + // now print original data + // + + if (OrigData.u.type0.ROMBaseAddress) { + HalpPrint (" oROM:%08lx", OrigData.u.type0.ROMBaseAddress); + } + + HalpPrint ("\n"); + k = 0; + for (j=0; j < PCI_TYPE0_ADDRESSES; j++) { + if (OrigData.u.type0.BaseAddresses[j]) { + HalpPrint (" oAd%d:%08lx", j, OrigData.u.type0.BaseAddresses[j]); + k = 1; + } + } + + // + // Restore original settings + // + + HalSetBusData ( + PCIConfiguration, + bus, + SlotNumber.u.AsULONG, + &OrigData, + sizeof (PciData) + ); + + // + // Next + // + + if (k) { + HalpPrint ("\n\n"); + } + } + } + } + +} +#endif diff --git a/private/ntos/nthals/halfire/ppc/pxpciint.c b/private/ntos/nthals/halfire/ppc/pxpciint.c new file mode 100644 index 000000000..960569d0e --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxpciint.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxpciint.c $ + * $Revision: 1.26 $ + * $Date: 1996/05/15 00:06:27 $ + * $Locker: $ + */ + +/*++ + + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + ixpciint.c + +Abstract: + + All PCI bus interrupt mapping is in this module, so that a real + system which doesn't have all the limitations which PC PCI + systems have can replaced this code easly. + (bus memory & i/o address mappings can also be fix here) + +Author: + + Ken Reneris + Jim Wooldridge - Ported to PowerPC + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "phsystem.h" +#include "pci.h" +#include "pcip.h" +#include "stdio.h" +#include "fpdebug.h" + +ULONG PciAllowedInts = 0; + +#define PCI_DEVICE_VECTOR 0x10 +#define PCI_IO_ADDRESS_SPACE 0x81000000 + + +ULONG HalpGetPciIntVector( PBUS_HANDLER, + PBUS_HANDLER, + ULONG, + ULONG, + PKIRQL, + PKAFFINITY ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetPCIIntOnISABus) +#pragma alloc_text(PAGE,HalpAdjustPCIResourceList) +#endif + + +/* + * HalpGetPciIntVector: + * This routine is a mirror ( but better ) version of HalpGetPCIIntOnISABus + * + */ + +ULONG +HalpGetPciIntVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) +{ + // since we can't see who's asking for an interrupt, must rely upon some + // known data: First, check to see if there is already one specified out + // among the pci devices: ( need to keep in mind some stubborn drivers + // that request several times for a particular interrupt i.e. scsi ). + // + // For now, to deal with a screwed up amd scsi driver, permanently map + // any requests for f ( as well as d which is what firmware sets this + // device to ) to 0x19, corresponding to the bit in our interrupt word. + // + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetPciIntVector: %x, %x \n", + BusInterruptLevel, BusInterruptVector );); + +#if defined(HALDEBUG_ON) + if (DBGSET(DBG_INTERRUPTS)) { + switch( BusInterruptVector ) { + case 0xd: + case 0xf: + HalpDebugPrint(" BusIntVec set to 0x%x \n", + BusInterruptVector); + break; + case 0xe: + HalpDebugPrint(" BusIntVec set to 0x%x \n", + BusInterruptVector); + break; + default: + HalpDebugPrint(" BusIntVec unchanged: \n"); + break; + } + } +#endif + + return HalGetInterruptVector ( + Internal, 0, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); +} + +ULONG +HalpGetPCIIntOnISABus ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) +{ + + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetPCIIntOnIsaBus: 0x%x, 0x%x, %x, %x, %x, %x \n", + BusHandler, + RootHandler, + BusInterruptLevel, + BusInterruptVector, + *Irql, + *Affinity );); + if (BusInterruptLevel < 1) { + // bogus bus level + return 0; + } + + // + // Check that the requested interrupt is valid and return 0 + // if the interrupt is not in the allowed set of interrupts. + if (((1 << BusInterruptVector) & PciAllowedInts) == 0) { + return 0; + } + + // + // + // For FirePOWER, pci interrupts are not mapped onto the isa bus ( with the + // exception of the amd ethernet drive which will always believe it's isa ) + // so for the moment map their "isa" int values so that they're picked up + // correctly by HalpGetSystem... + // + switch( BusInterruptVector ) { + case 0xa: + // + // For now, map this vector back down to ISA level since the + // audio driver is confused, thinking it's on the pci bus. + // + //BusInterruptVector = 0xa - PCI_DEVICE_VECTOR; + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sVector is not PCI based vector: 0x%x\n", + " ", BusInterruptVector );); + break; + case 0xd: + case 0xf: + BusInterruptVector = 0xd +0xc ; + HDBG(DBG_INTERRUPTS, + HalpDebugPrint(" BusIntVect set to 0x19 \n");); + break; + case 0xe: + BusInterruptVector = 0xe +0xc; + HDBG(DBG_INTERRUPTS, + HalpDebugPrint(" BusIntVect set to 0x1a \n");); + break; + default: + break; + } + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sBusInterruptVector set to: 0x%x \n", + " ", BusInterruptVector);); + //BusInterruptVector += PCI_DEVICE_VECTOR; + BusInterruptLevel = BusInterruptVector; + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("%sBusIntVec set to 0x%x \n", + " ", BusInterruptVector);); + + // + // Current PCI buses just map their IRQs ontop of the ISA space, + // so foreward this to the isa handler for the isa vector + // (the isa vector was saved away at either HalSetBusData or + // IoAssignReosurces time - if someone is trying to connect a + // PCI interrupt without performing one of those operations first, + // they are broken). + // + + return HalGetInterruptVector ( + Internal, 0, + BusInterruptLevel, + BusInterruptVector, + Irql, + Affinity + ); +} + + +/*++ + +// Routine Description: VOID HalpPCIPin2ISALine () +// +// This function maps the device's InterruptPin to an InterruptLine +// value. +// +// On Sandalfoot and Polo machines PCI interrupts are statically routed +// via slot number. This routine just returns and the static routing +// is done in HalpGetIsaFixedPCIIrq +// + +--*/ + +VOID +HalpPCIPin2ISALine ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciData + ) +{ + + +} + + + +/*++ + Routine Description: VOID HalpPCIISALine2Pin () + This functions maps the device's InterruptLine to it's + device specific InterruptPin value. + + +--*/ + +VOID +HalpPCIISALine2Pin ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER SlotNumber, + IN PPCI_COMMON_CONFIG PciNewData, + IN PPCI_COMMON_CONFIG PciOldData + ) +{ +} + + +/*++ + +Routine Description: VOID HalpPCIISALine2Pin () + + Translate PCI bus address. + Verify the address is within the range of the bus. + +Arguments: + +Return Value: + + STATUS_SUCCESS or error + +--*/ + +NTSTATUS +HalpTranslatePCIBusAddress ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ) +{ + BOOLEAN status; + PPCIPBUSDATA BusData; + + if (BusAddress.HighPart) { + return FALSE; + } + + BusData = (PPCIPBUSDATA) BusHandler->BusData; + switch (*AddressSpace) { + case MEMORY_ADDRESS_SPACE: + // + // verify memory address is within PCI buses memory limits + // + status = BusAddress.LowPart >= BusData->MemoryBase && + BusAddress.LowPart <= BusData->MemoryLimit; + + if (!status) { + status = BusAddress.LowPart >= BusData->PFMemoryBase && + BusAddress.LowPart <= BusData->PFMemoryLimit; + } + + break; + // + // Everyone should be assumed IO space if not otherwise requested + // + default: + case IO_ADDRESS_SPACE: + // + // verify memory address is within PCI buses io limits + // + status = BusAddress.LowPart >= BusData->IOBase && + BusAddress.LowPart <= BusData->IOLimit; + break; + + case SYSTEM_ADDRESS_SPACE: +// #pragma NOTE("SYSTEM_ADDRESS_SPACE, verify?") + status = BusAddress.LowPart < BusData->IOBase && + BusAddress.LowPart >= 0; + break; + + } + + if (!status) { + return FALSE; + } + + // + // Valid address for this bus - foreward it to the parent bus + // + + return BusHandler->ParentHandler->TranslateBusAddress ( + BusHandler->ParentHandler, + RootHandler, + BusAddress, + AddressSpace, + TranslatedAddress + ); +} + + +/*++ +Routine Description: NTSTATUS HalpAdjustPCIResourceList () + Rewrite the callers requested resource list to fit within + the supported ranges of this bus +--*/ + +NTSTATUS +HalpAdjustPCIResourceList ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList + ) +{ + NTSTATUS Status; + PPCIPBUSDATA BusData; + PCI_SLOT_NUMBER PciSlot; + UCHAR IrqTable[255]; + PFPHAL_BUSNODE FpNode; + + FpNode = (PFPHAL_BUSNODE) BusHandler->BusData; + // BusData = (PPCIPBUSDATA) BusHandler->BusData; + BusData = (PPCIPBUSDATA) &(FpNode->Bus); + PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber); + + // + // Determine PCI device's interrupt restrictions + // + // ======= Here's where thePCI interrupts are determined and set as a + // result of the call to HalpAdjustResourceListLimits + + RtlZeroMemory(IrqTable, sizeof (IrqTable)); + Status = BusData->GetIrqTable(BusHandler, RootHandler, PciSlot, IrqTable); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Adjust resources + // + + return HalpAdjustResourceListLimits ( + BusHandler, RootHandler, pResourceList, + BusData->MemoryBase, BusData->MemoryLimit, + BusData->PFMemoryBase, BusData->PFMemoryLimit, + BusData->LimitedIO, + BusData->IOBase, BusData->IOLimit, + IrqTable, 0xff, + 0, 0xffff // dma + ); +} + diff --git a/private/ntos/nthals/halfire/ppc/pxpcisup.c b/private/ntos/nthals/halfire/ppc/pxpcisup.c new file mode 100644 index 000000000..eecaa1e35 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxpcisup.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxpcisup.c $ + * $Revision: 1.18 $ + * $Date: 1996/05/14 02:35:00 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxmemctl.c + +Abstract: + + The module initializes any planar registers. + This module also implements machince check parity error handling. + +Author: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) + + +Revision History: + + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "pxpcisup.h" +#include "stdio.h" +#include "fpdebug.h" +#include "phsystem.h" + +extern PVOID HalpPciConfigBase; +extern UCHAR PciDevicePrimaryInts[]; +extern ULONG HalpGetPciInterruptSlot( PBUS_HANDLER, PCI_SLOT_NUMBER ); + +#define LX_PCI_INTERRUPT_ROUTING_SLOT0 25 +#define LX_PCI_INTERRUPT_ROUTING_SLOT1 22 +#define LX_PCI_INTERRUPT_ROUTING_SLOT2 23 +#define LX_PCI_INTERRUPT_ROUTING_SLOT3 26 +#define LX_PCI_INTERRUPT_ROUTING_IDEA 21 +#define LX_PCI_INTERRUPT_ROUTING_IDEB 20 + +#define PCI_INTERRUPT_ROUTING_SLOT0 0x16 // phys dev# 2, logical 1 +#define PCI_INTERRUPT_ROUTING_SLOT1 0x17 // phys dev# 3, logical 2 +#define PCI_INTERRUPT_ROUTING_SCSI 0x19 // phys dev# 1, logical 3 +#define PCI_INTERRUPT_ROUTING_ETHERNET 0x1a // phys dev# 4, logical 4 +#define IRQ_INVALID 0x0 // goes with IRQ_VALID defines + +ULONG HalpPciConfigSlot[] = { 0x0800, // phys dev# 0: SIO chip + 0x1000, // phys dev# 1: mobo scsi + 0x2000, // phys dev# 2: peripheral plug in + 0x4000, // phys dev# 3: peripheral plug in + 0x8000 // phys dev# 4: mobo ethernet + + ,0x10000, // IDE_IntA + 0x20000 // IDE_IntB + + }; + + + +/*++ + +Routine Description: ULONG HalpTranslatePciSlotNumber () + + This routine translate a PCI slot number to a PCI device number. + This is a sandalfoot memory map implementation. + +Arguments: + + None. + +Return Value: + + Returns length of data written. + +--*/ + +ULONG +HalpTranslatePciSlotNumber ( + ULONG BusNumber, + ULONG SlotNumber + ) +{ + // + // Sandalfoot only has 1 PCI bus so bus number is unused + // + + UNREFERENCED_PARAMETER(BusNumber); + + return ((ULONG) ((PUCHAR) HalpPciConfigBase + HalpPciConfigSlot[SlotNumber])); + +} + + + +/*++ + +Routine Description: ULONG HalpPhase0SetPciDataByOffset () + + This routine writes to PCI configuration space prior to bus handler installation. + +Arguments: + + None. + +Return Value: + + Returns length of data written. + +--*/ + +ULONG +HalpPhase0SetPciDataByOffset ( + ULONG BusNumber, + ULONG SlotNumber, + PUCHAR Buffer, + ULONG Offset, + ULONG Length + ) +{ + PUCHAR to; + PUCHAR from; + ULONG tmpLength; + + if (SlotNumber < MAXIMUM_PCI_SLOTS) { + + to = (PUCHAR)HalpPciConfigBase + HalpPciConfigSlot[SlotNumber]; + to += Offset; + from = Buffer; + tmpLength = Length; + while (tmpLength > 0) { + *to++ = *from++; + tmpLength--; + } + return(Length); + } + else { + return (0); + } +} + + +/*++ + +Routine Description: ULONG HalpPhase0GetPciDataByOffset () + + This routine reads PCI config space prior to bus handlder installation. + +Arguments: + + None. + +Return Value: + + Amount of data read. + +--*/ + +ULONG +HalpPhase0GetPciDataByOffset ( + ULONG BusNumber, + ULONG SlotNumber, + PUCHAR Buffer, + ULONG Offset, + ULONG Length + ) +{ + PUCHAR to; + PUCHAR from; + ULONG tmpLength; + + if (SlotNumber < MAXIMUM_PCI_SLOTS) { + + from = (PUCHAR)HalpPciConfigBase + HalpPciConfigSlot[SlotNumber]; + from += Offset; + to = Buffer; + tmpLength = Length; + while (tmpLength > 0) { + *to++ = *from++; + tmpLength--; + } + return(Length); + } + else { + return (0); + } +} + +NTSTATUS +HalpGetISAFixedPCIIrq ( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PCI_SLOT_NUMBER PciSlot, + OUT PUCHAR IrqTable + ) +{ + UCHAR buffer[PCI_COMMON_HDR_LENGTH]; + PPCI_COMMON_CONFIG PciData; + ULONG slot; + ULONG interrupt; + + PciData = (PPCI_COMMON_CONFIG) buffer; + HalGetBusData ( + PCIConfiguration, + BusHandler->BusNumber, + PciSlot.u.AsULONG, + PciData, + PCI_COMMON_HDR_LENGTH + ); + + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetISAFixedPCIIrq: %x, %x, %x, %x %x \n", + PCIConfiguration, + BusHandler->BusNumber, + PciSlot.u.AsULONG, + PciData, + PCI_COMMON_HDR_LENGTH )); + + if (PciData->VendorID == PCI_INVALID_VENDORID || + PCI_CONFIG_TYPE (PciData) != 0) { + return STATUS_UNSUCCESSFUL; + } + + // For Primary PCI slots, the interrupt corresponds to the primary + // slot number + if ( BusHandler->BusNumber == 0 ) { + slot = PciSlot.u.bits.DeviceNumber; + } + // For Secondary PCI slots, the interrupt corresponds to the slot + // number of the primary parent + else { + slot = HalpGetPciInterruptSlot(BusHandler, PciSlot ); + } + + // Search the interrupt table for the interrupt corresponding to the slot + if (slot < MAXIMUM_PCI_SLOTS) { + interrupt = PciDevicePrimaryInts[slot]; + if (interrupt != INVALID_INT) { + IrqTable[interrupt] = IRQ_VALID; + } else { + return STATUS_UNSUCCESSFUL; + } + } else { + return STATUS_UNSUCCESSFUL; + } + + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpGetISAFixedPCIIrq: index = 0x%x \n", + PciSlot.u.bits.DeviceNumber);); + return STATUS_SUCCESS; +} diff --git a/private/ntos/nthals/halfire/ppc/pxpcisup.h b/private/ntos/nthals/halfire/ppc/pxpcisup.h new file mode 100644 index 000000000..6fd05f401 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxpcisup.h @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxpcisup.h + +Abstract: + + The module provides the PCI bus interfaces for PowerPC systems. + +Author: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) + + +Revision History: + + + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxpcisup.h $ + * $Revision: 1.10 $ + * $Date: 1996/01/25 01:11:57 $ + * $Locker: $ + */ + +extern ULONG HalpPciConfigSlot[]; + +#include "phsystem.h" + +// The Maximum number of (Primary) PCI slots on a Firepower board +#define MAXIMUM_PCI_SLOTS 7 + +#define INVALID_INT 0xff +#define INVALID_SLOTNUMBER 0xff + + +typedef struct { + USHORT VendorID; + USHORT DeviceID; + USHORT Command; + USHORT Status; + UCHAR RevisionID; + UCHAR ClassCode[3]; + UCHAR CacheLineSize; + UCHAR LatencyTimer; + UCHAR HeaderType; + UCHAR BIST; + ULONG BaseAddress1; + ULONG BaseAddress2; + ULONG BaseAddress3; + ULONG BaseAddress4; + ULONG BaseAddress5; + ULONG BaseAddress6; + ULONG reserved1; + ULONG reserved2; + ULONG ROMbase; +} *PCI_CONFIG; + diff --git a/private/ntos/nthals/halfire/ppc/pxport.c b/private/ntos/nthals/halfire/ppc/pxport.c new file mode 100644 index 000000000..4149cd107 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxport.c @@ -0,0 +1,855 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxport.c $ + * $Revision: 1.13 $ + * $Date: 1996/05/14 02:35:04 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxport.c + +Abstract: + + This module implements the code that provides communication between + the kernel debugger on a PowerPC system. + + +Author: + + David N. Cutler (davec) 28-Apr-1991 + Chuck Bauman 02-Jun-1993 + +Environment: + + Kernel mode + +Revision History: + Steve Johns (sjohns@pets.sps.mot.com) + - added support for multple baud rates, alternate COM port + - implemented KdPortSave & KdPortRestore + +--*/ + +#include "halp.h" +#include "ppcserp.h" +#include "pxmemctl.h" + +VOID +HalpGetDivisorFromBaud( + IN ULONG ClockRate, + IN LONG DesiredBaud, + OUT PSHORT AppropriateDivisor + ); + + +#pragma alloc_text(INIT,HalpGetDivisorFromBaud) + + +// +// BUGBUG Temporarily, we use counter to do the timeout +// + +#define TIMEOUT_COUNT 1024*512 + +// +// BUGBUG Temp until we have a configuration manager. +// + +PUCHAR KdComPortInUse = NULL; +BOOLEAN KdUseModemControl = FALSE; +ULONG KdCurrentBaudRate= 19200; + +extern BOOLEAN HalpPhase0MapIo( VOID ); +ULONG KdCurrentComPort; +ULONG HalpSavedBaudRate; +ULONG HalpSavedComPort; + +// HalpIoControlBase is extern'd in pxhalp.h which is included in halp.h + +// +// Define serial port read and write addresses. +// + +#define SP_READ ((PSP_READ_REGISTERS)((PUCHAR)HalpIoControlBase + KdCurrentComPort)) +#define SP_WRITE ((PSP_WRITE_REGISTERS)((PUCHAR)HalpIoControlBase + KdCurrentComPort)) + + +// +// Define forward referenced prototypes. +// + +SP_LINE_STATUS +KdReadLsr ( + IN BOOLEAN WaitReason + ); + + +// +// Define baud rate divisor to be used on the debugger port. +// + +UCHAR HalpBaudRateDivisor = 6; + +// +// Define hardware PTE's that map the serial port used by the debugger. +// + + + +/*++ + +Routine Description: ULONG HalpGetByte () + + This routine gets a byte from the serial port used by the kernel + debugger. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + + Wait - Supplies a boolean value that detemines whether a timeout + is applied to the input operation. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error is encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +ULONG +HalpGetByte ( + IN PCHAR Input, + IN BOOLEAN Wait + ) +{ + + SP_LINE_STATUS LsrByte; + UCHAR DataByte; + ULONG TimeoutCount; + + + // + // Attempt to read a byte from the debugger port until a byte is + // available or until a timeout occurs. + // + + TimeoutCount = Wait ? TIMEOUT_COUNT : 1; + do { + TimeoutCount -= 1; + // + // Wait until data is available in the receive buffer. + // + + KeStallExecutionProcessor(1); + LsrByte = KdReadLsr(TRUE); + if (LsrByte.DataReady == 0) { + continue; + } + + // + // Read input byte and store in callers buffer. + // + + *Input = READ_REGISTER_UCHAR(&SP_READ->ReceiveBuffer); + + // + // If using modem controls, then skip any incoming data while + // ReceiveData not set. + // + + if (KdUseModemControl) { + DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus); + if ( ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect == 0) { + continue; + } + } + + // + // Return function value as the not of the error indicators. + // + if (LsrByte.ParityError || + LsrByte.FramingError || + LsrByte.OverrunError || + LsrByte.BreakIndicator) { + return CP_GET_ERROR; + } + + return CP_GET_SUCCESS; + } while(TimeoutCount != 0); + + return CP_GET_NODATA; +} + + +/*++ + +Routine Description: BOOLEAN KdPortInitialize () + + This routine initializes the serial port used by the kernel debugger + and must be called during system initialization. + +Arguments: + + DebugParameters - Supplies a pointer to the debug port parameters. + + LoaderBlock - Supplies a pointer to the loader parameter block. + + Initialize - Specifies a boolean value that determines whether the + debug port is initialized or just the debug port parameters + are captured. + +Return Value: + + A value of TRUE is returned is the port was successfully initialized. + Otherwise, a value of FALSE is returned. + +--*/ + +BOOLEAN +KdPortInitialize ( + PDEBUG_PARAMETERS DebugParameters, + PLOADER_PARAMETER_BLOCK LoaderBlock, + BOOLEAN Initialize + ) +{ + + UCHAR DataByte; +/* + PCONFIGURATION_COMPONENT_DATA ConfigurationEntry; + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; + PCM_SERIAL_DEVICE_DATA DeviceData; + ULONG KdPortEntry; + PCM_PARTIAL_RESOURCE_LIST List; + ULONG MatchKey; + + // + // Find the configuration information for the first serial port. + // + + if (LoaderBlock != NULL) { + MatchKey = 0; + ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot, + ControllerClass, + SerialController, + &MatchKey); + + } else { + ConfigurationEntry = NULL; + } + + if (DebugParameters->BaudRate != 0) { + BaudRate = DebugParameters->BaudRate; + } else { + BaudRate = 19200; + } + + + // + // If the serial configuration entry was not found or the frequency + // specified is not supported, then default the baud clock to 800000. + // + + BaudClock = 8000000; + if (ConfigurationEntry != NULL) { + List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData; + Descriptor = &List->PartialDescriptors[List->Count]; + DeviceData = (PCM_SERIAL_DEVICE_DATA)Descriptor; + if ((DeviceData->BaudClock == 1843200) || + (DeviceData->BaudClock == 4233600) || + (DeviceData->BaudClock == 8000000)) { + BaudClock = DeviceData->BaudClock; + } + } + + HalpGetDivisorFromBaud( + BaudClock, + BaudRate, + &HalpBaudRateDivisor + ); + + +*/ + + // + // Map I/O space if it has not already been mapped. + // + + if (HalpIoControlBase == NULL) { + HalpPhase0MapIo(); + if ( !HalpIoControlBase ) { + return FALSE; + } + } + + + + // + // Set COM parameters + // + if (DebugParameters != NULL) { + if (DebugParameters->BaudRate == 0) + KdCurrentBaudRate = 19200; // default baud rate + else + KdCurrentBaudRate = DebugParameters->BaudRate; + + if (DebugParameters->CommunicationPort > 2) + return (FALSE); + KdCurrentComPort = COM1_PORT; // default COM port + if (DebugParameters->CommunicationPort == 1) + KdCurrentComPort = COM1_PORT; + if (DebugParameters->CommunicationPort == 2) + KdCurrentComPort = COM2_PORT; + + + } + + HalpBaudRateDivisor = (UCHAR) ((1843200/16) / KdCurrentBaudRate); + + // + // If the debugger is not being enabled, then return. + // + + if (Initialize == FALSE) { + return TRUE; + } + + + + KdComPortInUse=(PUCHAR)KdCurrentComPort; + + + // + // Clear the divisor latch, clear all interrupt enables, and reset and + // disable the FIFO's. + // + + WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, 0x0); + WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0); + DataByte = 0; + ((PSP_FIFO_CONTROL)(&DataByte))->ReceiveFifoReset = 1; + ((PSP_FIFO_CONTROL)(&DataByte))->TransmitFifoReset = 1; + WRITE_REGISTER_UCHAR(&SP_WRITE->FifoControl, DataByte); + + // + // Set the divisor latch and set the baud rate to requested rate. + // + ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1; + WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte); + WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, HalpBaudRateDivisor); + WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0); + + // + // Clear the divisor latch and set the character size to eight bits + // with one stop bit and no parity checking. + // + + DataByte = 0; + ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS; + WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte); + + // + // Set data terminal ready and request to send. + // + + DataByte = 0; + ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1; + ((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1; + WRITE_REGISTER_UCHAR(&SP_WRITE->ModemControl, DataByte); + + return TRUE; +} + + +/*++ + +Routine Description: ULONG KdPortGetByte () + + This routine gets a byte from the serial port used by the kernel + debugger. + + N.B. It is assumed that the IRQL has been raised to the highest + level, and necessary multiprocessor synchronization has been + performed before this routine is called. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error is encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +ULONG +KdPortGetByte ( + OUT PUCHAR Input + ) +{ + + return HalpGetByte(Input, TRUE); +} + + +/*++ + +Routine Description: ULONG KdPortPollByte () + + This routine gets a byte from the serial port used by the kernel + debugger iff a byte is available. + + N.B. It is assumed that the IRQL has been raised to the highest + level, and necessary multiprocessor synchronization has been + performed before this routine is called. + +Arguments: + + Input - Supplies a pointer to a variable that receives the input + data byte. + +Return Value: + + CP_GET_SUCCESS is returned if a byte is successfully read from the + kernel debugger line. + + CP_GET_ERROR is returned if an error encountered during reading. + + CP_GET_NODATA is returned if timeout occurs. + +--*/ + +ULONG +KdPortPollByte ( + OUT PUCHAR Input + ) +{ + + ULONG Status; + + // + // Save port status, map the serial controller, get byte from the + // debugger port is one is avaliable, restore port status, unmap + // the serial controller, and return the operation status. + // + + + KdPortSave(); + Status = HalpGetByte(Input, FALSE); + KdPortRestore(); + return Status; +} + + +/*++ + +Routine Description: VOID KdPortPutByte () + + This routine puts a byte to the serial port used by the kernel debugger. + + N.B. It is assumed that the IRQL has been raised to the highest level, + and necessary multiprocessor synchronization has been performed + before this routine is called. + +Arguments: + + Output - Supplies the output data byte. + +Return Value: + + None. + +--*/ + +VOID +KdPortPutByte ( + IN UCHAR Output + ) +{ + + UCHAR DataByte; + + if (KdUseModemControl) { + // + // Modem control, make sure DSR, CTS and CD are all set before + // sending any data. + // + + for (; ;) { + DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus); + if ( ((PSP_MODEM_STATUS)&DataByte)->ClearToSend && + ((PSP_MODEM_STATUS)&DataByte)->DataSetReady && + ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect ) { + break; + } + + KdReadLsr(FALSE); + } + } + + // + // Wait for transmit ready. + // + + while (KdReadLsr(FALSE).TransmitHoldingEmpty == 0 ); + + // + // Wait for data set ready. + // + +// do { +// LsrByte = (PSP_MODEM_STATUS) READ_REGISTER_UCHAR(&SP_READ->ModemStatus); +// } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0); + + // + // Transmit data. + // + + WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, Output); + return; +} + + +/*++ + +Routine Description: VOID KdPortRestore () + + This routine restores the state of the serial port after the kernel + debugger has been active. + + N.B. This routine performs no function on the Jazz system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +VOID +KdPortRestore ( + VOID + ) +{ +DEBUG_PARAMETERS ComParams; + + if (HalpSavedComPort != KdCurrentComPort || + HalpSavedBaudRate != KdCurrentBaudRate) { + ComParams.CommunicationPort = HalpSavedComPort; + ComParams.BaudRate = HalpSavedBaudRate; + KdPortInitialize(&ComParams, NULL, TRUE); + } +} + + +/*++ + +Routine Description: VOID KdPortSave () + + This routine saves the state of the serial port and initializes the port + for use by the kernel debugger. + + N.B. This routine performs no function on the Jazz system. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +VOID +KdPortSave ( + VOID + ) +{ + + HalpSavedBaudRate = KdCurrentBaudRate; + HalpSavedComPort = KdCurrentComPort; + return; +} + + +/*++ + +Routine Description: SP_LINE_STATUS KdReadLsr () + + Returns current line status. + + If status which is being waited for is ready, then the function + checks the current modem status and causes a possible display update + of the current statuses. + +Arguments: + + WaitReason - Supplies a boolean value that determines whether the line + status is required for a receive or transmit. + +Return Value: + + The current line status is returned as the function value. + +--*/ + +SP_LINE_STATUS +KdReadLsr ( + IN BOOLEAN WaitReason + ) +{ + + static UCHAR RingFlag = 0; + UCHAR DataLsr, DataMsr; + + + // + // Get the line status for a recevie or a transmit. + // + + DataLsr = READ_REGISTER_UCHAR(&SP_READ->LineStatus); + if (WaitReason) { + + // + // Get line status for receive data. + // + + if (((PSP_LINE_STATUS)&DataLsr)->DataReady) { + return *((PSP_LINE_STATUS)&DataLsr); + } + + } else { + + // + // Get line status for transmit empty. + // + + if (((PSP_LINE_STATUS)&DataLsr)->TransmitEmpty) { + return *((PSP_LINE_STATUS)&DataLsr); + } + } + + DataMsr = READ_REGISTER_UCHAR(&SP_READ->ModemStatus); + RingFlag |= ((PSP_MODEM_STATUS)&DataMsr)->RingIndicator ? 1 : 2; + if (RingFlag == 3) { + + // + // The ring indicate line has toggled, use modem control from + // now on. + // + + KdUseModemControl = TRUE; + } + + + return *((PSP_LINE_STATUS) &DataLsr); +} + + + +/*++ + +Routine Description: VOID HalpGetDivisorFromBaud() + + This routine will determine a divisor based on an unvalidated + baud rate. + +Arguments: + + ClockRate - The clock input to the controller. + + DesiredBaud - The baud rate for whose divisor we seek. + + AppropriateDivisor - Given that the DesiredBaud is valid, the + SHORT pointed to by this parameter will be set to the appropriate + value. If the requested baud rate is unsupportable on the machine + return a divisor appropriate for 19200. + +Return Value: + + none. + +--*/ + +VOID +HalpGetDivisorFromBaud( + IN ULONG ClockRate, + IN LONG DesiredBaud, + OUT PSHORT AppropriateDivisor + ) +{ + + SHORT calculatedDivisor; + ULONG denominator; + ULONG remainder; + + // + // Allow up to a 1 percent error + // + + ULONG maxRemain18 = 18432; + ULONG maxRemain30 = 30720; + ULONG maxRemain42 = 42336; + ULONG maxRemain80 = 80000; + ULONG maxRemain; + + // + // Reject any non-positive bauds. + // + + denominator = DesiredBaud*(ULONG)16; + + if (DesiredBaud <= 0) { + + *AppropriateDivisor = -1; + + } else if ((LONG)denominator < DesiredBaud) { + + // + // If the desired baud was so huge that it cause the denominator + // calculation to wrap, don't support it. + // + + *AppropriateDivisor = -1; + + } else { + + if (ClockRate == 1843200) { + maxRemain = maxRemain18; + } else if (ClockRate == 3072000) { + maxRemain = maxRemain30; + } else if (ClockRate == 4233600) { + maxRemain = maxRemain42; + } else { + maxRemain = maxRemain80; + } + + calculatedDivisor = (SHORT)(ClockRate / denominator); + remainder = ClockRate % denominator; + + // + // Round up. + // + + if (((remainder*2) > ClockRate) && (DesiredBaud != 110)) { + + calculatedDivisor++; + } + + + // + // Only let the remainder calculations effect us if + // the baud rate is > 9600. + // + + if (DesiredBaud >= 9600) { + + // + // If the remainder is less than the maximum remainder (wrt + // the ClockRate) or the remainder + the maximum remainder is + // greater than or equal to the ClockRate then assume that the + // baud is ok. + // + + if ((remainder >= maxRemain) && ((remainder+maxRemain) < ClockRate)) { + calculatedDivisor = -1; + } + + } + + // + // Don't support a baud that causes the denominator to + // be larger than the clock. + // + + if (denominator > ClockRate) { + + calculatedDivisor = -1; + + } + + // + // Ok, Now do some special casing so that things can actually continue + // working on all platforms. + // + + if (ClockRate == 1843200) { + + if (DesiredBaud == 56000) { + calculatedDivisor = 2; + } + + } else if (ClockRate == 3072000) { + + if (DesiredBaud == 14400) { + calculatedDivisor = 13; + } + + } else if (ClockRate == 4233600) { + + if (DesiredBaud == 9600) { + calculatedDivisor = 28; + } else if (DesiredBaud == 14400) { + calculatedDivisor = 18; + } else if (DesiredBaud == 19200) { + calculatedDivisor = 14; + } else if (DesiredBaud == 38400) { + calculatedDivisor = 7; + } else if (DesiredBaud == 56000) { + calculatedDivisor = 5; + } + + } else if (ClockRate == 8000000) { + + if (DesiredBaud == 14400) { + calculatedDivisor = 35; + } else if (DesiredBaud == 56000) { + calculatedDivisor = 9; + } + + } + + *AppropriateDivisor = calculatedDivisor; + + } + + + if (*AppropriateDivisor == -1) { + + HalpGetDivisorFromBaud( + ClockRate, + 19200, + AppropriateDivisor + ); + + } + + +} diff --git a/private/ntos/nthals/halfire/ppc/pxproc.c b/private/ntos/nthals/halfire/ppc/pxproc.c new file mode 100644 index 000000000..ca6d2e3f3 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxproc.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxproc.c $ + * $Revision: 1.21 $ + * $Date: 1996/06/25 02:46:32 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pxproc.c + +Abstract: + + Stub functions for UP hals. + +Author: + + Ken Reneris (kenr) 22-Jan-1991 + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge Ported to PowerPC + +--*/ + +#include "fpdebug.h" +#include "halp.h" +#include "stdio.h" +#include "string.h" +#include "stdlib.h" +#include "arccodes.h" +#include "fpreg.h" +#include "phsystem.h" + + +UCHAR HalName[] = "Powerized HAL"; + +extern VOID HalpInitializePciBus (VOID); +VOID HalpInitOtherBuses (VOID); +ULONG HalpProcessorCount(VOID); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalStartNextProcessor) +#pragma alloc_text(INIT,HalAllProcessorsStarted) +#pragma alloc_text(INIT,HalReportResourceUsage) +#pragma alloc_text(INIT,HalReportResourceUsage) +#pragma alloc_text(INIT,HalpInitOtherBuses) +#endif + +/*++ + +Routine Description: + + This function is called to start the next processor. + +Arguments: + + LoaderBlock - Supplies a pointer to the loader parameter block. + + ProcessorState - Supplies a pointer to the processor state to be + used to start the processor. + +Return Value: + + If a processor is successfully started, then a value of TRUE is + returned. Otherwise a value of FALSE is returned. If a value of + TRUE is returned, then the logical processor number is stored + in the processor control block specified by the loader block. + +--*/ +BOOLEAN +HalStartNextProcessor ( + IN PLOADER_PARAMETER_BLOCK LoaderBlock, + IN PKPROCESSOR_STATE ProcessorState + ) +{ + PRESTART_BLOCK pRB; + ULONG Number; + PKPRCB Prcb; + char buf[128]; + + HDBG(DBG_INTERNAL, HalpDebugPrint("HalpStartNextProcessor: called\n");); + + + // + // Check if UNIPROCESSOR is set and ignore all other processors, + // this is done in a free HAL so that UP/MP performance measurements + // can be taken. + // + if (HalGetEnvironmentVariable("UNIPROCESSOR", sizeof(buf), buf) + == ESUCCESS) { + if (_stricmp(buf, "true") == 0) { + HalpDebugPrint("HalpStartNextProcessor: UNIPROCESSOR set\n"); + return FALSE; + } + } + + // + // If there is more than one restart block then this is a multi- + // processor system. + // + // N.B. The first restart parameter block must be for the boot master + // and must represent logical processor 0. + // + // Scan the restart parameter blocks for a processor that is ready, + // but not running. If a processor is found, then fill in the restart + // processor state, set the logical processor number, and set start + // in the boot status. + // + pRB = SYSTEM_BLOCK->RestartBlock; + Number = 0; + while (pRB != NULL) { + if ((pRB->BootStatus.ProcessorReady == TRUE) && + (pRB->BootStatus.ProcessorStart == FALSE)) { + + // + // Assert that we think this is an MP capable machine + // + if (!(SystemDescription[SystemType].Flags&SYS_MPCAPABLE) || + !(ProcessorDescription[ProcessorType].Flags&PROC_MPCAPABLE)) { + HalpDebugPrint("HalStartNextProcessor: HAL/Veneer mismatch\n"); + KeBugCheck(MISMATCHED_HAL); + } + + RtlZeroMemory(&pRB->u.Ppc, sizeof(PPC_RESTART_STATE)); + + // + // Set processor start address. + // + pRB->u.Ppc.Iar = ProcessorState->ContextFrame.Iar; + pRB->u.Ppc.Msr = ProcessorState->ContextFrame.Msr; + + // + // PowerPC linkage conventions pass parameters in registers + // r.3 thru r.10. Set all of them to allow as much flexibility + // to the kernel as possible. + // + pRB->u.Ppc.IntR3 = ProcessorState->ContextFrame.Gpr3; + pRB->u.Ppc.IntR4 = ProcessorState->ContextFrame.Gpr4; + pRB->u.Ppc.IntR5 = ProcessorState->ContextFrame.Gpr5; + pRB->u.Ppc.IntR6 = ProcessorState->ContextFrame.Gpr6; + pRB->u.Ppc.IntR7 = ProcessorState->ContextFrame.Gpr7; + pRB->u.Ppc.IntR8 = ProcessorState->ContextFrame.Gpr8; + pRB->u.Ppc.IntR9 = ProcessorState->ContextFrame.Gpr9; + pRB->u.Ppc.IntR10 = ProcessorState->ContextFrame.Gpr10; + + Prcb = (PKPRCB)(LoaderBlock->Prcb); + Prcb->Number = (CCHAR)Number; + Prcb->RestartBlock = pRB; + + // + // ARC interface is waiting for this bit to change + // so change it. + // + pRB->BootStatus.ProcessorStart = TRUE; + HDBG(DBG_GENERAL, + HalpDebugPrint("HalStartNextProcessor: started Cpu (%d)\n", + Number);); + return TRUE; + } + Number++; + pRB = pRB->NextRestartBlock; + } + return FALSE; +} + +BOOLEAN +HalAllProcessorsStarted(VOID) +{ + PRESTART_BLOCK pRB; + ULONG NumCpu=0; + + HDBG(DBG_INTERNAL, HalpDebugPrint("HalAllProcessorsStarted: called\n");); + + pRB = SYSTEM_BLOCK->RestartBlock; + while (pRB != NULL) { + if ((pRB->BootStatus.ProcessorReady == TRUE) && + (pRB->BootStatus.ProcessorStart == FALSE)) + HDBG(DBG_GENERAL,HalpDebugPrint( + "HalAllProcessorsStarted: NT disabled processor %d\n",NumCpu);); + NumCpu++; + pRB = pRB->NextRestartBlock; + } + HDBG(DBG_GENERAL, + HalpDebugPrint("HalAllProcessorsStarted: return TRUE\n");); + return TRUE; +} + +VOID +HalReportResourceUsage(VOID) +{ + extern VOID HalpSetUpFirePowerRegistry(VOID); + INTERFACE_TYPE interfacetype; + ANSI_STRING AHalName; + UNICODE_STRING UHalName; + + interfacetype = Internal; + + RtlInitAnsiString (&AHalName, HalName); + RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE); + HalpReportResourceUsage(&UHalName, interfacetype); + + interfacetype = Isa; + HalpReportResourceUsage (&UHalName, interfacetype); + RtlFreeUnicodeString (&UHalName); + + // + // Registry is now intialized, see if there are any PCI buses + // + HalpInitializePciBus (); + + + HalpSetUpFirePowerRegistry(); // in fprgstry.c +} + +ULONG +HalpProcessorCount() +{ + PRESTART_BLOCK pRB; + static ULONG Count = 0; + + if (Count) + return(Count); + + pRB = SYSTEM_BLOCK->RestartBlock; + while (pRB != NULL) { + if ((pRB->BootStatus.ProcessorReady == TRUE) && + (pRB->BootStatus.ProcessorStart == TRUE)) + Count++; + pRB = pRB->NextRestartBlock; + } + return Count; +} + +VOID +HalpInitOtherBuses(VOID) +{ + // no other internal buses supported +} diff --git a/private/ntos/nthals/halfire/ppc/pxprof.c b/private/ntos/nthals/halfire/ppc/pxprof.c new file mode 100644 index 000000000..ee3ed4532 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxprof.c @@ -0,0 +1,277 @@ + +/***************************************************************************** + +Copyright (c) 1993 Motorola Inc. + Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file + contains copyrighted material. Use of this file is restricted + by the provisions of a Motorola Software License Agreement. + +Module Name: + + PXPROF.C + +Abstract: + + This implements the HAL profile functions: + + HalSetProfileInterval + HalStartProfileInterrupt + HalStopProfileInterrupt + HalCalibratePerformanceCounter + HalpProfileInterrupt + + +Author: + + Steve Johns 11-Feb-1994 + +Revision History: + Changed from using the DECREMENTER to 8254 Timer 1 10-Feb-94 + +******************************************************************************/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxprof.c $ + * $Revision: 1.7 $ + * $Date: 1996/01/11 07:13:00 $ + * $Locker: $ + */ + +#include "halp.h" +#include "eisa.h" +#include "pxsiosup.h" + +#define TIMER ((PEISA_CONTROL)HalpIoControlBase) +#define TIMER0_COMMAND (COMMAND_8254_COUNTER0 + COMMAND_8254_RW_16BIT + COMMAND_8254_MODE2) + +ULONG HalpMaxProfileInterval = 540000; // 54 ms maximum +ULONG HalpMinProfileInterval = 10000; // 1 ms minimum +ULONG HalpProfileCount; +BOOLEAN HalpProfilingActive = FALSE; +ULONG HalpProfileInts = 0; + + +VOID HalStartProfileInterrupt ( + KPROFILE_SOURCE ProfileSource + ) + +/*++ + +Routine Description: + + This routine unmasks IRQ0 at the master interrupt controller, + enabling the profile interrupt. + + + N.B. This routine must be called at PROFILE_LEVEL while holding + the profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + if (ProfileSource == ProfileTime) { + HalpProfilingActive = TRUE; + // + // Unmasks IRQ 0 (Timer 1) + // + HalEnableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL, Latched); + } + +} + + + + + + +ULONG HalSetProfileInterval ( + IN ULONG Interval + ) + +/*++ + +Routine Description: + + This routine sets the profile interrupt interval. + +Arguments: + + Interval - Supplies the desired profile interval in 100ns units. + +Return Value: + + The actual profile interval, rounded to the nearest 100ns units. + +--*/ + +{ + ULONG ActualInterval; + LARGE_INTEGER BigNumber; + + // + // Clamp the requested profile interval between the minimum and + // maximum supported values. + // + if (Interval < HalpMinProfileInterval) + Interval = HalpMinProfileInterval; + else + if (Interval > HalpMaxProfileInterval) + Interval = HalpMaxProfileInterval; + // + // Compute Timer 1 counts for requested interval. + // + BigNumber.QuadPart = Int32x32To64(Interval, TIMER_CLOCK_IN); + + BigNumber = RtlExtendedLargeIntegerDivide(BigNumber, 10000000, NULL); + HalpProfileCount = BigNumber.LowPart; + + // + // Program Timer 1 to Mode 2 & program the timer count register. + // + WRITE_REGISTER_UCHAR (&(TIMER->CommandMode1), TIMER0_COMMAND); + WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount & 0xff)); + WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount >> 8)); + // + // Compute actual interval. + // + BigNumber.QuadPart = Int32x32To64(HalpProfileCount, 10000000); + BigNumber = RtlExtendedLargeIntegerDivide(BigNumber,TIMER_CLOCK_IN, NULL); + ActualInterval = BigNumber.LowPart; + + return (ActualInterval); +} + + + + +BOOLEAN HalpHandleProfileInterrupt( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext, + IN PVOID TrapFrame + ) +{ + + if (HalpProfilingActive) + KeProfileInterrupt(TrapFrame); + + return (TRUE); +} + + + +VOID +HalStopProfileInterrupt ( + KPROFILE_SOURCE ProfileSource +) + +/*++ + +Routine Description: + + This routine masks IRQ 0 (Timer 1) at the interrupt controller, thereby + stopping profile interrupts. + + N.B. This routine must be called at PROFILE_LEVEL while holding the + profile lock. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + if (ProfileSource == ProfileTime) { + HalpProfilingActive = FALSE; + + // + // Program Timer 1 to Mode 2 & program the LSB of the timer. + // That should keep it from interrupting in case IRQ0 accidently + // gets enabled. + // + WRITE_REGISTER_UCHAR (&(TIMER->CommandMode1), TIMER0_COMMAND); + WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount & 0xff)); + + + // + // Mask IRQ 0 (Timer 1) + // + HalDisableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL); + } + +} + + + + + + +VOID +HalCalibratePerformanceCounter ( + IN volatile PLONG Number + ) + +/*++ + +Routine Description: + + This routine resets the performance counter value for the current + processor to zero. The reset is done such that the resulting value + is closely synchronized with other processors in the configuration. + +Arguments: + + Number - Supplies a pointer to count of the number of processors in + the configuration. + +Return Value: + + None. + +--*/ + +{ + + KSPIN_LOCK Lock; + KIRQL OldIrql; + + // + // Raise IRQL to HIGH_LEVEL, decrement the number of processors, and + // wait until the number is zero. + // + KeInitializeSpinLock(&Lock); + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + if (ExInterlockedDecrementLong(Number, &Lock) != RESULT_ZERO) { + do { + } while (*Number !=0); + } + + // + // Zero the Time Base registers + // + + HalpZeroPerformanceCounter(); + + // + // Restore IRQL to its previous value and return. + // + + KeLowerIrql(OldIrql); + return; +} diff --git a/private/ntos/nthals/halfire/ppc/pxreturn.c b/private/ntos/nthals/halfire/ppc/pxreturn.c new file mode 100644 index 000000000..d9456cf41 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxreturn.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxreturn.c $ + * $Revision: 1.13 $ + * $Date: 1996/05/14 02:35:12 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxreturn.c + +Abstract: + + This module implements the HAL return to firmware function. + + +Author: + + David N. Cutler (davec) 21-Aug-1991 + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial Power PC port + + Keyboard mapping code was ported to PPC. + This function is currently a stub since our firmware is big endian + +--*/ + +#include "halp.h" +#include "phsystem.h" + +// +// Define keyboard registers structure. +// +typedef struct _KBD_REGISTERS { + union { + UCHAR Output; + UCHAR Input; + } Data; + + union { + UCHAR Status; + UCHAR Command; + } Control; +} KBD_REGISTERS; + +#define KEYBOARD_CONTROL_SPACE 0x80000000 +#define KBD_DATA_PORT 0x60 +#define KBD_COMMAND_PORT 0x64 +#define KBD_IBF_MASK 2 // input buffer full mask +#define KBD_OBF_MASK 1 // Output buffer full mask + +#define KbdGetStatus() \ + (READ_REGISTER_UCHAR(ControlSpace + KBD_COMMAND_PORT)) +#define KbdStoreCommand(Byte) \ + WRITE_REGISTER_UCHAR(ControlSpace + KBD_COMMAND_PORT, Byte) +#define KbdStoreData(Byte) \ + WRITE_REGISTER_UCHAR(ControlSpace + KBD_DATA_PORT, Byte) +#define KbdGetData() \ + (READ_REGISTER_UCHAR(ControlSpace + KBD_DATA_PORT)) + +#define KbdWriteSequence(_cmd, _data) { \ + while ((KbdGetStatus() & KBD_IBF_MASK) != 0) { \ + /* Do Nothing */ \ + } \ + KbdStoreCommand((_cmd)); \ + while ((KbdGetStatus() & KBD_IBF_MASK) != 0) { \ + /* Do Nothing */ \ + } \ + KbdStoreData((_data)); \ +} + +#define KbdReadSequence(_cmd, _pdata) { \ + while ((KbdGetStatus() & KBD_IBF_MASK) != 0) { \ + /* Do Nothing */ \ + } \ + KbdStoreCommand((_cmd)); \ + while ((KbdGetStatus() & KBD_OBF_MASK) == 0) { \ + /* Do Nothing */ \ + } \ + (*(_pdata)) = KbdGetData(); \ +} + +VOID +HalpPowerPcReset( + VOID + ); + +VOID +HalReturnToFirmware( + IN FIRMWARE_REENTRY Routine + ) + +/*++ + +Routine Description: + + This function returns control to the specified firmware routine. + In most cases it generates a soft reset by asserting the reset line + trough the keyboard controller. + The Keyboard controller is mapped using the same virtual address + and the same fixed entry as the DMA. + +Arguments: + + Routine - Supplies a value indicating which firmware routine to invoke. + +Return Value: + + Does not return. + +--*/ + +{ + + // + // Disable Interrupts. + // + HalpDisableInterrupts(); + + // + // Perform an appropriate action for each request type + // + switch (Routine) { + case HalPowerDownRoutine: + case HalRestartRoutine: + case HalRebootRoutine: + case HalInteractiveModeRoutine: + // Reset using 8042 keyboard command + HalpResetByKeyboard(); + + /* Fall Through to Hang */ + case HalHaltRoutine: + // + // Hang looping. + // + for (;;) { + /* Do Nothing */ + } + + default: + HalpDebugPrint("HalReturnToFirmware: invalid argument\n"); + for (;;) { + /* Do Nothing */ + } + } +} + +VOID +HalpResetByKeyboard( VOID ) +{ + PHYSICAL_ADDRESS physicalAddress; + PUCHAR ControlSpace; + UCHAR data; + + + // + // First job is to map the Keyboard registers into a virtual + // address. + // + physicalAddress.HighPart = 0; + physicalAddress.LowPart = KEYBOARD_CONTROL_SPACE; + ControlSpace = (PUCHAR)MmMapIoSpace(physicalAddress, PAGE_SIZE, FALSE); + + // + // Flush Keyboard Output Buffer (throw away data) + // Delay Loop (Wait for 8 milliseconds) + // + KeStallExecutionProcessor(8000); + while ((KbdGetStatus() & KBD_OBF_MASK) != 0) { + KbdGetData(); + // + // Delay Loop (Wait for 8 milliseconds) + // + KeStallExecutionProcessor(8000); + }; + + // + // Disable auxillary device + // + KbdStoreCommand(0xa7); + + // + // Disable Keyboard + // + KbdStoreCommand(0xad); + + // + // Disable Chip Level Interrupts for Mouse and Keyboard + // + KbdReadSequence(0x20, &data); + data |= 0x30; + data &= 0xfc; + KbdWriteSequence(0x60, data); + + // + // Request the reset + // + KbdWriteSequence(0xb8, 0x1e); + KbdWriteSequence(0xbd, 0x48); + KbdWriteSequence(0xbe, 0x1); + KbdWriteSequence(0xca, 0x1); + + // + // Now wait forever for the reset to happen + // + for (;;) { + /* Do Nothing */ + } +} + diff --git a/private/ntos/nthals/halfire/ppc/pxrtcsup.h b/private/ntos/nthals/halfire/ppc/pxrtcsup.h new file mode 100644 index 000000000..bb8050454 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxrtcsup.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxrtcsup.h $ + * $Revision: 1.7 $ + * $Date: 1996/05/14 02:35:17 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxrtcsup.h + +Abstract: + + The module defines the structures, and defines for the DALLAS rtc chip. + +Author: + + Jim Wooldridge + +Revision History: + + +--*/ + +#ifndef PXRTCSUP_H +#define PXRTCSUP_H + +#include "fpds1385.h" + +#endif // PXRTCSUP_H diff --git a/private/ntos/nthals/halfire/ppc/pxs3.h b/private/ntos/nthals/halfire/ppc/pxs3.h new file mode 100644 index 000000000..2b463c359 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxs3.h @@ -0,0 +1,770 @@ +/*++ + +Copyright (c) 1992 ACER Labs Inc. + +Module Name: + + pxs3.h + +Abstract: + + This header file defines the S3 86C911 GUI accelerator registers. + +Author: + + Version 1.0 Kevin Chen 2-Apr-1992 + Version 2.0 Andrew Chou Nov-24-1992 + Version 3.0 Jess Botts Oct-06-1993 Power PC Initial Version + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxs3.h $ + * $Revision: 1.6 $ + * $Date: 1996/01/11 07:13:27 $ + * $Locker: $ + */ + +#define VERTICALRESOLUTION 768 +#define HORIZONTALRESOLUTION 1024 +#define OriginalPoint 0 +#define BLUE 192 +#define WHITE 255 +#define CRT_OFFSET 2 +#define SEQ_OFFSET 27 +#define GRAPH_OFFSET 32 +#define ATTR_OFFSET 41 + +UCHAR DAC_Table[64] = { + // DAC for mode 3 + 0,16, 4,20, 1,17, 5,21, + 32,48,36,52,33,49,37,53, + 8,24,12,28, 9,25,13,29, + 40,56,44,60,41,57,45,61, + 2,18, 6,22, 3,19, 7,23, + 34,50,38,54,35,51,39,55, + 10,26,14,30,11,27,15,31, + 42,58,46,62,43,59,47,63 + }; + +UCHAR DAC_Color[4] = {0x00, 0x2a, 0x15, 0x3f}; + +// +// Define virtual address of the video memory and control registers. +// + +// HalpIoControlBase is extern'd in pxhalp.h which is included by halp.h + +// +// Define S3 register I/O Macros +// + +//============================================================================= +// +// IBMBJB Changed the semicolons separating statements in the write macros to +// commas so that if the macro is used as the only statement in a loop +// all of the statements in the macro will be part of the loop. +// +// Commas were used instead of putting braces around the statements +// because if the macro is used in the true part of a conditional the +// braces will cause the compiler to generate a syntax error. + +#define WRITE_S3_UCHAR(port,data) \ + *(volatile unsigned char *)((ULONG)HalpIoControlBase + (port)) = (UCHAR)(data), \ + KeFlushWriteBuffer() + +#define WRITE_S3_USHORT(port,data) \ + *(volatile PUSHORT)((ULONG)HalpIoControlBase + (port)) = (USHORT)(data), \ + KeFlushWriteBuffer() + +#define READ_S3_UCHAR(port) \ + *(volatile unsigned char *)((ULONG)HalpIoControlBase + (port)) + +#define READ_S3_USHORT(port) \ + *(volatile unsigned short *)((ULONG)HalpIoControlBase + (port)) + +#define READ_S3_VRAM(port) \ + *(HalpVideoMemoryBase + (port)) + +#define WRITE_S3_VRAM(port,data) \ + *(HalpVideoMemoryBase + (port)) = (data), \ + KeFlushWriteBuffer() + +//============================================================================= + +#define DISPLAY_BITS_PER_PIXEL 8 // display bits per pixel +#define NUMBER_OF_COLORS 256 // number of colors + +#define CURSOR_WIDTH 64 // width of hardware cursor +#define CURSOR_HEIGHT 64 // height of hardware cursor +#define CURSOR_BITS_PER_PIXEL 2 // hardware cursor bits per pixel + +// +// S3 86C911 GUI, accelerator Video Controller Definitions. +// +// Define video register format. +// +#define PosID_LO 0x100 // R/W +#define PosID_HI 0x101 // R/W +#define Setup_OP 0x102 // R/W +#define Chck_Ind 0x105 // R +#define Mono_3B4 0x3B4 // R/W +#define Mono_3B5 0x3B5 // R/W +#define MDA_Mode 0x3B8 // W +#define HGC_SLPEN 0x3B9 // R/W +#define Stat1_MonoIn 0x3BA // R +#define FC_MonoW 0x3BA // W +#define HGC_CLPEN 0x3BB // W +#define HGC_Config 0x3BF // W +#define Attr_Index 0x3C0 // R/W +#define Attr_Data 0x3C0 // R/W +#define Stat0_In 0x3C2 // R +#define MiscOutW 0x3C2 // W +#define VSub_EnB 0x3C3 // R/W +#define Seq_Index 0x3C4 // R/W +#define Seq_Data 0x3C5 // R/W +#define DAC_Mask 0x3C6 // R/W +#define DAC_RIndex 0x3C7 // W +#define DAC_Status 0x3C7 // W +#define DAC_WIndex 0x3C8 // R/W +#define DAC_Data 0x3C9 // R/W +#define FC_Read 0x3CA // R +#define MiscOutR 0x3CC // R +#define GC_Index 0x3CE // R/W +#define GC_Data 0x3CF // R/W +#define S3_3D4_Index 0x3D4 // R/W +#define S3_3D5_Data 0x3D5 // R/W + +#define CGA_Mode 0x3D8 // W +#define CGA_Color 0x3D9 // W +#define Stat1_In 0x3DA // R +#define FC_Write 0x3DA // W +#define CLPEN 0x3DB +#define SLPEN 0x3DC + +// +// Define Enhanced registers for S3_86C911 +// + +#define SUBSYS_STAT 0x42E8 // R +#define SUBSYS_CNTL 0x42E8 // W +#define SUBSYS_ENB 0x46E8 // R/W +#define ADVFUNC_CNTL 0x4AE8 // W +#define CUR_Y 0x82E8 // R/W +#define CUR_X 0x86E8 // R/W +#define DESTY 0x8AE8 // W +#define AXIAL_STEP 0x8AE8 // W +#define DESTX 0x8EE8 // W +#define DIAG_STEP 0x8EE8 // W +#define ERR_TERM 0x92E8 // R +#define MAJ_AXIS_PCNT 0x96E8 // W +#define RWIDTH 0x96E8 // W +#define GP_STAT 0x9AE8 // R +#define DRAW_CMD 0x9AE8 // W +#define SHORT_STROKE 0x9EE8 // W +#define BKGD_COLOR 0xA2E8 // W +#define FRGD_COLOR 0xA6E8 // W +#define WRITE_MASK 0xAAE8 // W +#define READ_MASK 0xAEE8 // W +#define BKGD_MIX 0xB6E8 // W +#define FRGD_MIX 0xBAE8 // W +#define MULTIFUNC_CNTL 0xBEE8 // W +#define RHEIGHT 0xBEE8 // W +#define PIX_TRANS 0xE2E8 // W + + +// +// Define Attribute Controller Indexes : ( out 3C0, Index ) +// + +#define PALETTE0 0 +#define PALETTE1 1 +#define PALETTE2 2 +#define PALETTE3 3 +#define PALETTE4 4 +#define PALETTE5 5 +#define PALETTE6 6 +#define PALETTE7 7 +#define PALETTE8 8 +#define PALETTE9 9 +#define PALETTE10 10 +#define PALETTE11 11 +#define PALETTE12 12 +#define PALETTE13 13 +#define PALETTE14 14 +#define PALETTE15 15 +#define ATTR_MODE_CTRL 16 +#define BORDER_COLOR 17 +#define COLOR_PLANE_ENABLE 18 +#define HORI_PIXEL_PANNING 19 +#define PIXEL_PADDING 20 + +// +// Define Sequencer Indexes ( out 3C4, Index) +// + +#define RESET 0 +#define CLOCKING_MODE 1 +#define ENABLE_WRITE_PLANE 2 +#define CHARACTER_FONT_SELECT 3 +#define MEMORY_MODE_CONTROL 4 + +// +// Define Graphics Controller Index ( out 3CE, Index ) +// + +#define SET_RESET 0 +#define ENABLE_SET_RESET 1 +#define COLOR_COMPARE 2 +#define DATA_ROTATE 3 +#define READ_PLANE_SELECT 4 +#define GRAPHICS_CTRL_MODE 5 +#define MEMORY_MAP_MODE 6 +#define COLOR_DONT_CARE 7 +#define BIT_MASK 8 + +// +// Define CRTC, VGA S3, SYS_CTRL Index : ( Out 3D4, Index ) +// +// Define CRTC Controller Indexes +// + +#define HORIZONTAL_TOTAL 0 +#define HORIZONTAL_DISPLAY_END 1 +#define START_HORIZONTAL_BLANK 2 +#define END_HORIZONTAL_BLANK 3 +#define HORIZONTAL_SYNC_POS 4 +#define END_HORIZONTAL_SYNC 5 +#define VERTICAL_TOTAL 6 +#define CRTC_OVERFLOW 7 +#define PRESET_ROW_SCAN 8 +#define MAX_SCAN_LINE 9 +#define CURSOR_START 10 +#define CURSOR_END 11 +#define START_ADDRESS_HIGH 12 +#define START_ADDRESS_LOW 13 +#define CURSOR_LOCATION_HIGH 14 +#define CURSOR_FCOLOR 14 +#define CURSOR_BCOLOR 15 +#define CURSOR_LOCATION_LOW 15 +#define VERTICAL_RETRACE_START 16 +#define VERTICAL_RETRACE_END 17 +#define VERTICAL_DISPLAY_END 18 +#define OFFSET_SCREEN_WIDTH 19 +#define UNDERLINE_LOCATION 20 +#define START_VERTICAL_BLANK 21 +#define END_VERTICAL_BLANK 22 +#define CRT_MODE_CONTROL 23 +#define LINE_COMPARE 24 +#define CPU_LATCH_DATA 34 +#define ATTRIBUTE_INDEX1 36 +#define ATTRIBUTE_INDEX2 38 + +// +// Define VGA S3 Indexes +// +#define S3R0 0x30 +#define S3R1 0x31 +#define S3R2 0x32 +#define S3R3 0x33 +#define S3R4 0x34 +#define S3R5 0x35 +#define S3R6 0x36 +#define S3R7 0x37 +#define S3R8 0x38 +#define S3R9 0x39 +#define S3R0A 0x3A +#define S3R0B 0x3B +#define S3R0C 0x3C +#define SC0 0x40 +#define SC2 0x42 +#define SC3 0x43 +#define SC5 0x45 + +// +// Define System Control Indexes +// +#define SYS_CNFG 64 +#define SOFT_STATUS 65 +#define MODE_CTRL 66 +#define EXT_MODE 67 +#define HGC_MODE 69 +#define HGC_ORGX0 70 +#define HGC_ORGX1 71 +#define HGC_ORGY0 72 +#define HGC_ORGY1 73 +#define HGC_YSTART0 76 +#define HGC_YSTART1 77 +#define HGC_DISPX 78 +#define HGC_DISPY 79 + +#define ENABLE_HARDWARE_CURSOR 1 +#define DISABLE_HARDWARE_CURSOR 0 + +// +// define advanced function control register structure +// +#define RES_640x480 0 +#define RES_1024x768 1 +#define RES_800x600 1 + +#define ENABLE_VGA 6 +#define ENABLE_ENHANCED 7 + +// +// define draw command register values +// +#define NOP_COMMAND 0x0 +#define DRAW_LINE_COMMAND 0x2000 +#define RECTANGLE_FILL_COMMAND 0x4000 +#define BITBLT_COMMAND 0xc000 +#define BYTE_SWAP 0x1000 +#define NO_BYTE_SWAP 0x0 +#define SIXTEEN_BIT_BUS 0x0200 +#define EIGHT_BIT_BUS 0x0 +#define WAIT 0x0100 +#define NO_WAIT 0x0 +#define R0 0x0 +#define R45 0x20 +#define R90 0x40 +#define R135 0x60 +#define R180 0x80 +#define R225 0xa0 +#define R270 0xc0 +#define R315 0xe0 +#define XMAJ 0x0 +#define YMAJ 0x40 +#define XPositive 0x20 +#define YPositive 0x80 +#define XNegative 0x0 +#define YNegative 0x0 + +#define DRAW_YES 0x10 +#define DRAW_NO 0x0 +#define RADIAL 8 +#define XY_BASE 0 +#define LAST_PIXEL_OFF 4 +#define LAST_PIXEL_ON 0 +#define MULTIPLE_PIXEL 2 +#define SINGLE_PIXEL 0 +#define DRAW_READ 0 +#define DRAW_WRITE 1 + +#define SSV_DRAW 0x1000 +#define SSV_MOVE 0x0 + +#define OneEmpty 0x80 +#define TwoEmpty 0x40 +#define ThreeEmpty 0x20 +#define FourEmpty 0x10 +#define FiveEmpty 0x8 +#define SixEmpty 0x4 +#define SevenEmpty 0x2 +#define EightEmpty 0x1 + +#define BACKGROUND_COLOR 0 +#define FOREGROUND_COLOR 0x20 +#define CPU_DATA 0x40 +#define DISPLAY_MEMORTY 0x60 +#define NOT_SCREEN 0 +#define LOGICAL_ZERO 1 +#define LOGICAL_ONE 2 +#define LEAVE_ALONE 3 +#define NOT_NEW 4 +#define SCREEN_XOR_NEW 5 +#define NOT_SCREEN_XOR_NEW 6 +#define OVERPAINT 7 //( NEW ) +#define NOT_SCREEN_OR_NOT_NEW 8 +#define SCREEN_OR_NOT_NEW 9 +#define NOT_SCREEN_OR_NEW 10 +#define SCREEN_OR_NEW 11 +#define SCREEN_AND_NEW 12 +#define NOT_SCREEN_AND_NEW 13 +#define SCREEN_AND_NOT_NEW 14 +#define NOT_SCREEN_AND_NOT_NEW 15 + +#define BEE8_1H 1 +#define BEE8_2H 2 +#define BEE8_3H 3 +#define BEE8_4H 4 +#define BEE8_0H 0 +#define L_CLIP 0x1000 +#define R_CLIP 0x2000 +#define B_CLIP 0x3000 +#define T_CLIP 0x4000 + +#define DATA_EXTENSION 0xa000 // 10100000B +#define CPU_EXT 0x80 +#define DISPLAY_EXT 0xc0 +#define NO_EXTENSION 0x0 +#define PACK_DATA 0x4 +#define NO_PACK_DATA 0x0 +#define SET_THIS_BIT_TO_ZERO 0; + +// +// Define bits per pixel codes. +// +#define ONE_BIT_PER_PIXEL 0 // 1-bit per pixel +#define TWO_BITS_PER_PIXEL 1 // 2-bits per pixel +#define FOUR_BITS_PER_PIXEL 2 // 4-bits per pixel +#define EIGHT_BITS_PER_PIXEL 3 // 8-bits per pixel + +// +// Define address step value. +// +#define ADDRESS_STEP_INCREMENT 1 // vram transfer address increment + +// +// Define cross hair thickness values. +// +#define ONE_PIXEL_THICK 0x0 // one pixel in thickness +#define THREE_PIXELS_THICK 0x1 // three pixels in thickness +#define FIVE_PIXELS_THICK 0x2 // five pixels in thickness +#define SEVEN_PIXELS_THICK 0x3 // seven pixels in thickness + +// +// Define multiplexer control values. +// +#define ONE_TO_ONE 0x0 // 1:1 multiplexing +#define FOUR_TO_ONE 0x1 // 4:1 multiplexing +#define FIVE_TO_ONE 0x2 // 5:1 multiplexing + +// +// Define cursor origin values. +// + +#define CURSOR_X_ORIGIN (((2*HORIZONAL_SYNC_VALUE)+BACK_PORCH_VALUE)*4-36) +#define CURSOR_Y_ORIGIN ((VERTICAL_BLANK_VALUE/2)+24) + +ULONG HotspotX, HotspotY; + +// Extended VGA BIOS +#define SUPER_VGA_SUPPORT 4FH +#define RET_EXT_VGA_INFO 00H +#define RET_EXT_VGA_MODE_INFO 01H +#define SET_EXT_VGA_MODE 02H +#define QUERY_CUR_EXT_VGA_MODE 03H + +#define SAVE_RESTORE_FUNCTION 04H +// Function 04.0 Query Save/Restore Buffer Size +#define GET_SAVE_BUFFER_SIZE 00H +// Function 04.1 Save Extended Video state +#define SAVE_STATE 01H +// Function 04.2 Restore Extended VGA state +#define RESTORE_STATE 02H + +#define WINDOWS_CONTROL 05H +// Function 05.0 Set Window Control +#define SELECT_PAGE_TO_BE_MAPPED 00H +// fUNCTION 05.1 Get Window Control Setting +#define GET_PAGE_MAPPED 01H + +#define SET_RESET_DUAL_DISPLAY_MODE FFH + +BOOLEAN ColorMonitor; +PVOID S3_3x4, S3_3x5; +UCHAR VideoParam[62] = { +// Mode +3 480 Lines +// External Registers 3C3, 3C2 +0x01,0x67, + +//============================================================================= +// +// IBMBJB changed value at offset 17 (5th number on second line) from 0x8e +// to 0xae to disable the vertical retrace interrupt + +// CRT Controller Registers 3D4, 3D5 +0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0d,0x0e,0x00, +// 0x00,0x00,0x00,0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff, + 0x00,0x00,0x00,0x9c,0xae,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff, + +//============================================================================= + +// Sequencer Registers 3C4, 3C5 +// 0x01,0x01,0x03,0x00,0x02, +0x01,0x20,0x03,0x00,0x02, + +// Graphic Control Registers +0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,0xff, + +// Attribute Controller Registers +0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,0x38,0x39,0x3a, +0x3b,0x3c,0x3d,0x3e,0x3f,0x0c,0x00,0x0f,0x08,0x00}; + + +UCHAR VGAFont8x16[4096] = { +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 00 +0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x7E,0xFF,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // 8 +0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00, // 9 +0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF, // a +0x00,0x00,0x3E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x30,0x38,0x3C,0x36,0x33,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00, // f + +0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00, // 10 +0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00, // 4 +0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 20 +0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // 1 +0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00, // 3 +0x00,0x18,0x18,0x7C,0xC6,0xC2,0x7C,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 6 +0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x30,0x60,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, // 30 +0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x60,0x00,0x00, // b +0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00, // 40 +0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, // a +0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, // b +0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, // c +0x00,0x00,0xC6,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // d +0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 50 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00, // 1 +0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00, // d +0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, // f + +0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 60 +0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00, // 7 +0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, // a +0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00, // 70 +0x00,0x00,0x00,0x00,0x00,0x7E,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00, // 1 +0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00, // 80 +0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 1 +0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 2 +0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 4 +0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 5 +0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00, // 7 +0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // 9 +0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // b +0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // c +0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // d +0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // e +0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // f + +0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00, // 90 +0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00, // 2 +0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 4 +0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 5 +0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 6 +0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00, // 8 +0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 9 +0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // a +0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00, // b +0x00,0x38,0x6C,0x64,0x60,0xF8,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // d +0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00, // e +0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00, // f + +0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // a0 +0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, // 1 +0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 2 +0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, // 4 +0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // 5 +0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 6 +0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00, // a +0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00, // b +0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00, // c +0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00, // f + +0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44, // b0 +0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA, // 1 +0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77, // 2 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 3 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 4 +0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 5 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 6 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 7 +0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 8 +0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 9 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // a +0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // b +0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // f + +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c0 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 2 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 3 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 4 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 5 +0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 6 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 7 +0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 9 +0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // b +0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // c +0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // e +0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // f + +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d0 +0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 1 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 2 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 3 +0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 5 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 6 +0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, // 7 +0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 8 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // a +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // b +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // c +0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, // d +0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, // e +0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00, // e0 +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xFC,0xC6,0xC6,0xC6,0xC6,0xDC,0xC0,0xC0,0x00,0x00, // 1 +0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00, // 3 +0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, // 4 +0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0xC0,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, // 7 +0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00, // a +0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00, // b +0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, // f + +0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00, // f0 +0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, // 1 +0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00, // 2 +0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00, // 3 +0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // 4 +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, // 5 +0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, // 6 +0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00, // 7 +0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9 +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // a +0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00, // b +0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c +0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d +0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00, // e +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 // f + }; diff --git a/private/ntos/nthals/halfire/ppc/pxsiosup.c b/private/ntos/nthals/halfire/ppc/pxsiosup.c new file mode 100644 index 000000000..39f42166f --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxsiosup.c @@ -0,0 +1,1866 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxsiosup.c $ + * $Revision: 1.38 $ + * $Date: 1996/05/14 02:35:22 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxsiosup.c + +Abstract: + + The module provides the PCI ISA bridge support. + +Author: + + Jim Wooldridge (jimw@vnet.ibm.com) + + +Revision History: + + +--*/ + + +#include "fpdebug.h" +#include "halp.h" +#include "eisa.h" +#include "pxsiosup.h" +#include "pxpcisup.h" +#include "pxmemctl.h" +#include "bugcodes.h" +#include "phsystem.h" +#include "fpio.h" +#include "fpcpu.h" + +extern BOOLEAN HalpHandleIpiInterrupt(PKINTERRUPT, PVOID); + +// +// TODO: +// 1) Move to PCR +// 2) Put on cache line boundaries for peformance (i.e. don't +// cache thrash. +// +#define MAX_CPU 32 +ULONG registeredInts[MAX_CPU] = {0}; + + +#define TBS " " +#define SioId 0x04848086 +#define AMD_ENET 0x20001022 +#define AMD_SCSI 0x20201022 +#define ESCId 0x04828086 + +PVOID HalpPciIsaBridgeConfigBase; + +extern PADAPTER_OBJECT MasterAdapterObject; + +extern ULONG BugLvl; + + +// +// Define the context structure for use by the interrupt routine. +// + + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine, + PVOID ServiceContext, + PVOID TrapFrame + ); + +// +// Declare the interrupt structure for profile interrupt +// + +KINTERRUPT HalpProfileInterrupt; + +// +// The following is the interrupt object used for DMA controller interrupts. +// DMA controller interrupts occur when a memory parity error occurs or a +// programming error occurs to the DMA controller. +// + +// +// Declare the interrupt structure for machine checks +// + +KINTERRUPT HalpMachineCheckInterrupt; + +// +// Declare the interrupt structure for the clock interrupt +// + +KINTERRUPT HalpDecrementerInterrupt; + +// +// Add spurious and bogus interrupt counts +// + +#if DBG +ULONG HalpSpuriousInterruptCount = 0; +ULONG HalpBogusInterruptCount = 0; +#endif + + +// +// Define Isa bus interrupt affinity. +// + +KAFFINITY HalpIsaBusAffinity; + + +// +// The following function is called when a machine check occurs. +// + +BOOLEAN +HalpHandleMachineCheck( + IN PKINTERRUPT Interrupt, + IN PVOID ServiceContext + ); + +// +// Define save area for ISA adapter objects. +// + +PADAPTER_OBJECT HalpIsaAdapter[8]; + +// +// Define save area for ISA interrupt mask resiters and level\edge control +// registers. +// + +UCHAR HalpSioInterrupt1Mask = 0xff; +UCHAR HalpSioInterrupt2Mask = 0xff; +UCHAR HalpSioInterrupt1Level; +UCHAR HalpSioInterrupt2Level; + + + + +/*++ + +Routine Description: BOOLEAN HalpInitializeInterrupts () + + This routine is called from phase 0 initialization, it initializes the + 8259 interrupt controller ( currently it masks all 8259 interrupts). + + +Arguments: + + None. + +Return Value: + + +--*/ + +BOOLEAN +HalpInitializeInterrupts ( + VOID + ) +{ + ULONG Vector; + + HDBG(DBG_BREAK, + HalpDebugPrint("HalpInitializeInterrupts: Calling Break\n");); + HDBG(DBG_BREAK, DbgBreakPoint();); + + // + // Mask all 8259 interrupts (except the cascade interrupt) + // + HalpDisableInterrupts(); + for (Vector=0;Vector<16;Vector++) { + if (Vector == 2) + continue; + HalpDisableSioInterrupt(Vector + DEVICE_VECTORS); + } + + // + // Reserve the external interrupt vector for exclusive use by the HAL. + // + + PCR->ReservedVectors |= (1 << EXTERNAL_INTERRUPT_VECTOR); + + return TRUE; + +} + + + +/*++ + +Routine Description: BOOLEAN HalpCreateSioStructures () + + This routine initializes the structures necessary for SIO operations + and connects the intermediate interrupt dispatcher. It also initializes the + SIO interrupt controller. + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatcher is connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ +BOOLEAN +HalpCreateSioStructures ( + VOID + ) + +{ + + UCHAR DataByte; + + // We have no interrupt handlers setup; make sure interrupts are + // disabled. (No need to re-enable them) + HalpDisableInterrupts(); + // + // Initialize the IPI for processor zero: + // Connect the IPI interrupt handler directly to the CPU dispatch table + // without registering with the kernel. + // + PCR->InterruptRoutine[DEVICE_VECTORS + 31] = + (PKINTERRUPT_ROUTINE) HalpHandleIpiInterrupt; + + // + // register the interrupt vector with the HAL + // + HalpRegisterVector(InternalUsage, + DEVICE_VECTORS + 31, + DEVICE_VECTORS + 31, + HIGH_LEVEL); + + // + // Now enable the IPI interrupt on this CPU; the HAL must do this + // directly since we did not register with the kernel. + // We cannot call HalEnableSystemInterrupt because the irql masks have + // not been set up. Interrupts are disabled anyway. + // + HalpEnableSioInterrupt(DEVICE_VECTORS + 31, Latched); + + // + // Initialize the Machine Check interrupt handler + // + if (HalpEnableInterruptHandler(&HalpMachineCheckInterrupt, + HalpHandleMachineCheck, + NULL, + NULL, + MACHINE_CHECK_VECTOR, + MACHINE_CHECK_LEVEL, + MACHINE_CHECK_LEVEL, + Latched, + FALSE, + 0, + FALSE, + InternalUsage, + MACHINE_CHECK_VECTOR + ) == FALSE) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + + // + // Enable NMI IOCHK# and PCI SERR# + // + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus); + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus, + DataByte & ~DISABLE_IOCHK_NMI & ~DISABLE_PCI_SERR_NMI); + + // + // Clear the SIO NMI disable bit. This bit is the high order of the + // NMI enable register. + // + + DataByte = 0; + + // + // Connect the external interrupt handler + // + + PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = + (PKINTERRUPT_ROUTINE) HalpHandleExternalInterrupt; + // PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = + // HalpFieldExternalInterrupt; + // PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = + // HalpHandleExternalInterrupt; + + // + // register the interrupt vector + // + + HalpRegisterVector(InternalUsage, + EXTERNAL_INTERRUPT_VECTOR, + EXTERNAL_INTERRUPT_VECTOR, + HIGH_LEVEL); + + + + + // Connect directly to the decrementer handler. This is done + // directly rather than thru HalpEnableInterruptHandler due to + // special handling required because the handler calls KdPollBreakIn(). + // + + + PCR->InterruptRoutine[DECREMENT_VECTOR] = (PKINTERRUPT_ROUTINE) HalpHandleDecrementerInterrupt; + + // + // Initialize and connect the Timer 1 interrupt (IRQ0) + // + + if (HalpEnableInterruptHandler( &HalpProfileInterrupt, + (PKSERVICE_ROUTINE) HalpHandleProfileInterrupt, + (PVOID) NULL, + (PKSPIN_LOCK)NULL, + PROFILE_VECTOR, + PROFILE_LEVEL, + PROFILE_LEVEL, + Latched, + TRUE, + 0, + FALSE, + DeviceUsage, + PROFILE_VECTOR + ) == FALSE) { + KeBugCheck(HAL_INITIALIZATION_FAILED); + } + + + // + // Disable Timer 1; only used by profiling + // + + HalDisableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL); + + // + // Set default profile rate + // + + HalSetProfileInterval(5000); + + // + // Initialize any planar registers + // + + HalpInitPlanar(); + + // + // Initialize the PCI/ISA bridge chip + // + + HalpInitPciIsaBridge(); + + PHalpInterruptSetup(); + + // + // Initialize the edge/level register masks to 0 which is the default + // edge sensitive value. + // + + HalpSioInterrupt1Level = 0; + HalpSioInterrupt2Level = 0; + + // + // Enable the clock interrupt + // + + HalpUpdateDecrementer(1000); // Get those decrementer ticks going + + + // + // Set ISA bus interrupt affinity. + // + + HalpIsaBusAffinity = PCR->SetMember; + + // + // DMA command - set assert level + // + + DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus); + WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus, + DataByte & ~DACK_ASSERT_HIGH & ~DREQ_ASSERT_LOW); + + // + // Initialize the DMA mode registers to a default value. + // Disable all of the DMA channels except channel 4 which is that + // cascade of channels 0-3. + // + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Dma1BasePort.AllMask, + 0x0F + ); + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort.AllMask, + 0x0E + ); + + return(TRUE); +} + + +BOOLEAN +HalpInitPciIsaBridge ( + VOID + ) + + +{ + + UCHAR DataByte; + BOOLEAN Found; + ULONG SlotNumber, Tval, bleah; + ULONG ChipId=0, DevInt=0, EvInt=0, AChipId=0; + UCHAR PCIReg; + ULONG BufferLength; + + + // + // Save off the interrupt mask for this cpu and then block all interrupts + // from coming through while probing the PCI bus. Decrementer is still + // enabled. + // + Tval = RInterruptMask(GetCpuId()); + RInterruptMask(GetCpuId()) = 0x0; + WaitForRInterruptMask(GetCpuId()); + rInterruptRequest = 0xffffffff; + FireSyncRegister(); + + Found = FALSE; + SlotNumber = 0; + HDBG(DBG_INTERRUPTS, + HalpDebugPrint("HalpInitPciIsaBridge:.......................\n");); + while (!Found && SlotNumber 15) { + + // Since this vector has no corollary with the SIO + // world, don't do any of the following stuff... + // + return; + } + + if (Vector & 0x08) { + + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpSioInterrupt2Mask |= (UCHAR) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpSioInterrupt1Mask |= (UCHAR) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + } + +} + +/*++ + +Routine Description: VOID HalpIsaMapTransfer() + + This function programs the SIO DMA controller for a transfer. + +Arguments: + + Adapter - Supplies the DMA adapter object to be programed. + + Offset - Supplies the logical address to use for the transfer. + + Length - Supplies the length of the transfer in bytes. + + WriteToDevice - Indicates the direction of the transfer. + +Return Value: + + None. + +--*/ + +VOID +HalpIsaMapTransfer( + IN PADAPTER_OBJECT AdapterObject, + IN ULONG Offset, + IN ULONG Length, + IN BOOLEAN WriteToDevice + ) +{ + + PUCHAR BytePtr; + UCHAR adapterMode; + UCHAR dataByte; + KIRQL Irql; + + + ASSERT(Offset >= IO_CONTROL_PHYSICAL_BASE); + + adapterMode = AdapterObject->AdapterMode; + + // + // Check to see if this request is for a master I/O card. + // + + if (((PDMA_EISA_MODE) &adapterMode)->RequestMode == CASCADE_REQUEST_MODE) { + + // + // Set the mode, Disable the request and return. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 1 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } + + return; + } + // + // Determine the mode based on the transfer direction. + // + + ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ? + WRITE_TRANSFER : READ_TRANSFER); + + BytePtr = (PUCHAR) &Offset; + + if (AdapterObject->Width16Bits) { + + // + // If this is a 16 bit transfer then adjust the length and the address + // for the 16 bit DMA mode. + // + + Length >>= 1; + + // + // In 16 bit DMA mode the low 16 bits are shifted right one and the + // page register value is unchanged. So save the page register value + // and shift the logical address then restore the page value. + // + + dataByte = BytePtr[2]; + Offset >>= 1; + BytePtr[2] = dataByte; + + } + + + // + // grab the spinlock for the system DMA controller + // + + KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql ); + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + BytePtr[0] + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + BytePtr[1] + ); + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[2] + ); + + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[3] + ); + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 1) & 0xff) + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + BytePtr[0] + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseAddress, + BytePtr[1] + ); + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageLowPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[2] + ); + + + WRITE_REGISTER_UCHAR( + ((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->DmaPageHighPort) + + (ULONG)AdapterObject->PagePort, + BytePtr[3] + ); + + // + // Notify DMA chip of the length to transfer. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 1) & 0xff) + ); + + WRITE_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount, + (UCHAR) ((Length - 1) >> 8) + ); + + + // + // Set the DMA chip to read or write mode; and unmask it. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) + ); + + } + + KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql); + +} + + + +/*++ + +Routine Description: VOID HalpEnableSioInterrupt() + + This function enables the SIO interrupt and sets + the level/edge register to the requested value. + +Arguments: + + Vector - Supplies the vector of the interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + None. + +--*/ + +VOID +HalpEnableSioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) +{ + + ULONG CpuId = GetCpuId(); + + HASSERT(!MSR(EE)); + + // Calculate the SIO interrupt vector. + // + + Vector -= DEVICE_VECTORS; + + // Make sure we're protected while we muck with the interrupt masks. + // since we asserted interrupts disabled on the way in, we can turn them + // off here and not worry about turning them on. If DbgPrint didn't + // turn ints off, we wouldn't have to worry about it. + // + // Remember which interrupts have been turned on or off + // + registeredInts[CpuId] |= (1 << Vector); + + // Turn on the bit in the hardware to allow the interrupt + // + RInterruptMask(CpuId) |= (1 << Vector); + WaitForRInterruptMask(CpuId); + + if (Vector > 0xf) { + + // 15 is the effective MAX_DEV_VECTORS after the device vector + // offset is removed + // + return; + + // Since this vector has no corollary with the SIO + // world, don't do any of the following stuff... + // + } + InterruptMode = Latched; + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpSioInterrupt2Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpSioInterrupt2Level |= (UCHAR) (1 << Vector); + + } else { + + HalpSioInterrupt2Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2EdgeLevel, + HalpSioInterrupt2Level + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpSioInterrupt1Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpSioInterrupt1Level |= (UCHAR) (1 << Vector); + + } else { + + HalpSioInterrupt1Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1EdgeLevel, + HalpSioInterrupt1Level + ); + } + +} + +/*++ + +Routine Description: PADAPTER_OBJECT HalpAllocateIsaAdapter() + + This function allocates an ISA adapter object according to the + specification supplied in the device description. The necessary device + descriptor information is saved. If there is + no existing adapter object for this channel then a new one is allocated. + The saved information in the adapter object is used to set the various DMA + modes when the channel is allocated or a map transfer is done. + +Arguments: + + DeviceDescription - Supplies the description of the device which want to + use the DMA adapter. + + NumberofMapRegisters - number of map registers required for the adapter + object created + + +Return Value: + + Returns a pointer to the newly created adapter object or NULL if one + cannot be created. + +--*/ + +PADAPTER_OBJECT +HalpAllocateIsaAdapter( + IN PDEVICE_DESCRIPTION DeviceDescriptor, + OUT PULONG NumberOfMapRegisters + ) +{ + + PADAPTER_OBJECT adapterObject; + PVOID adapterBaseVa; + ULONG channelNumber; + ULONG numberOfMapRegisters; + ULONG controllerNumber; + DMA_EXTENDED_MODE extendedMode; + UCHAR adapterMode; + BOOLEAN useChannel; + ULONG maximumLength; + + // + // Determine if the the channel number is important. Master cards + // do not use a channel number. + // + + + if ((DeviceDescriptor->Master) && (DeviceDescriptor->InterfaceType != Isa)) { + + useChannel = FALSE; + + } else { + + useChannel = TRUE; + } + + // + // Channel 4 cannot be used since it is used for chaining. Return null if + // it is requested. + // + + if ((DeviceDescriptor->DmaChannel == 4 || + DeviceDescriptor->DmaChannel > 7) && useChannel) { + + return(NULL); + } + + // + // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES + // macro works correctly. + // + + maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff; + + // + // Determine the number of map registers for this device. + // + + + if (DeviceDescriptor->ScatterGather && + !(DeviceDescriptor->InterfaceType == Isa && + DeviceDescriptor->Master)) { + + + // + // Scatter gather not supported in SIO + // + + if (!DeviceDescriptor->Master) + + // + // one map register will be required when the the SIO supports this + // + // numberOfMapRegisters = 1; + + return NULL; + + + // + // Since the device support scatter/Gather then map registers are not + // required. + // + + numberOfMapRegisters = 0; + + } else { + + // + // Determine the number of map registers required based on the maximum + // transfer length, up to a maximum number. + // + + numberOfMapRegisters = BYTES_TO_PAGES(maximumLength) + + 1; + numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ? + MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters; + + // + // If the device is not a master then it only needs one map register + // and does scatter/Gather. + // + + if (DeviceDescriptor->ScatterGather && !DeviceDescriptor->Master) { + + numberOfMapRegisters = 1; + } + } + + // + // Set the channel number number. + // + + channelNumber = DeviceDescriptor->DmaChannel & 0x03; + + // + // Set the adapter base address to the Base address register and controller + // number. + // + + if (!(DeviceDescriptor->DmaChannel & 0x04)) { + + controllerNumber = 1; + adapterBaseVa = (PVOID) &((PEISA_CONTROL) HalpIoControlBase)->Dma1BasePort; + + } else { + + controllerNumber = 2; + adapterBaseVa = &((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort; + + } + + // + // Determine if a new adapter object is necessary. If so then allocate it. + // + + if (useChannel && HalpIsaAdapter[DeviceDescriptor->DmaChannel] != NULL) { + + adapterObject = HalpIsaAdapter[DeviceDescriptor->DmaChannel]; + + if (adapterObject->NeedsMapRegisters) { + + if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) { + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + } + } + + } else { + + // + // Allocate an adapter object. + // + + adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter( + numberOfMapRegisters, + adapterBaseVa, + NULL + ); + + if (adapterObject == NULL) { + + return(NULL); + + } + + if (useChannel) { + + HalpIsaAdapter[DeviceDescriptor->DmaChannel] = adapterObject; + + } + + // + // Set the maximum number of map registers for this channel bus on + // the number requested and the type of device. + // + + if (numberOfMapRegisters) { + + // + // The specified number of registers are actually allowed to be + // allocated. + // + + adapterObject->MapRegistersPerChannel = numberOfMapRegisters; + + // + // Increase the commitment for the map registers. + // + + if (DeviceDescriptor->Master) { + + // + // Master I/O devices use several sets of map registers double + // their commitment. + // + + MasterAdapterObject->CommittedMapRegisters += + numberOfMapRegisters * 2; + + } else { + + MasterAdapterObject->CommittedMapRegisters += + numberOfMapRegisters; + + } + + // + // If the committed map registers is significantly greater than the + // number allocated then grow the map buffer. + // + + if (MasterAdapterObject->CommittedMapRegisters > + MasterAdapterObject->NumberOfMapRegisters && + MasterAdapterObject->CommittedMapRegisters - + MasterAdapterObject->NumberOfMapRegisters > + MAXIMUM_ISA_MAP_REGISTER ) { + + HalpGrowMapBuffers( + MasterAdapterObject, + INCREMENT_MAP_BUFFER_SIZE + ); + } + + adapterObject->NeedsMapRegisters = TRUE; + + } else { + + // + // No real map registers were allocated. If this is a master + // device, then the device can have as may registers as it wants. + // + + adapterObject->NeedsMapRegisters = FALSE; + + if (DeviceDescriptor->Master) { + + adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES( + maximumLength + ) + + 1; + + } else { + + // + // The device only gets one register. It must call + // IoMapTransfer repeatedly to do a large transfer. + // + + adapterObject->MapRegistersPerChannel = 1; + } + } + } + + adapterObject->ScatterGather = DeviceDescriptor->ScatterGather; + + if (DeviceDescriptor->Master) { + + adapterObject->MasterDevice = TRUE; + + } else { + + adapterObject->MasterDevice = FALSE; + + } + + + if (DeviceDescriptor->Master && (DeviceDescriptor->InterfaceType == Isa)) { + + adapterObject->IsaBusMaster = TRUE; + + } else { + + adapterObject->IsaBusMaster = FALSE; + + } + + // + // If the channel number is not used then we are finished. The rest of + // the work deals with channels. + // + + *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel; +// *NumberOfMapRegisters = numberOfMapRegisters; + + if (!useChannel) { + adapterObject->PagePort = (PVOID) (~0x0); + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; + return(adapterObject); + } + + // + // Setup the pointers to all the random registers. + // + + adapterObject->ChannelNumber = (UCHAR) channelNumber; + + if (controllerNumber == 1) { + + switch ((UCHAR)channelNumber) { + + case 0: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0; + break; + + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 1; + + // + // Save the extended mode register address. + // + + adapterBaseVa = + &((PEISA_CONTROL) HalpIoControlBase)->Dma1ExtendedModePort; + + } else { + + switch (channelNumber) { + case 1: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5; + break; + + case 2: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6; + break; + + case 3: + adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7; + break; + } + + // + // Set the adapter number. + // + + adapterObject->AdapterNumber = 2; + + // + // Save the extended mode register address. + // + adapterBaseVa = + &((PEISA_CONTROL) HalpIoControlBase)->Dma2ExtendedModePort; + + } + + + adapterObject->Width16Bits = FALSE; + + + // + // Initialize the extended mode port. + // + + *((PUCHAR) &extendedMode) = 0; + extendedMode.ChannelNumber = (UCHAR) channelNumber; + + switch (DeviceDescriptor->DmaSpeed) { + case Compatible: + extendedMode.TimingMode = COMPATIBLITY_TIMING; + break; + + case TypeA: + extendedMode.TimingMode = TYPE_A_TIMING; + break; + + case TypeB: + extendedMode.TimingMode = TYPE_B_TIMING; + break; + + case TypeC: + extendedMode.TimingMode = BURST_TIMING; + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + switch (DeviceDescriptor->DmaWidth) { + case Width8Bits: + extendedMode.TransferSize = BY_BYTE_8_BITS; + break; + + case Width16Bits: + extendedMode.TransferSize = BY_BYTE_16_BITS; + + // + // Note Width16bits should not be set here because there is no need + // to shift the address and the transfer count. + // + + break; + + default: + ObDereferenceObject( adapterObject ); + return(NULL); + + } + + WRITE_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode)); + + + // + // Initialize the adapter mode register value to the correct parameters, + // and save them in the adapter object. + // + + adapterMode = 0; + ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber; + + if (DeviceDescriptor->Master) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; + + // + // Set the mode, and enable the request. + // + + if (adapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } else { + + // + // This request is for DMA controller 1 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = adapterObject->AdapterBaseVa; + + WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); + + // + // Unmask the DMA channel. + // + + WRITE_REGISTER_UCHAR( + &dmaControl->SingleMask, + (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) + ); + + } + + } else if (DeviceDescriptor->DemandMode) { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE; + + } else { + + ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE; + + } + + if (DeviceDescriptor->AutoInitialize) { + + ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1; + + } + + adapterObject->AdapterMode = adapterMode; + + return(adapterObject); +} + +/*++ + +Routine Description: ULONG HalReadDmaCounter() + + This function reads the DMA counter and returns the number of bytes left + to be transferred. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still to be transferred. + +--*/ + +ULONG +HalReadDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +{ + ULONG count=0; + ULONG high; + + if (AdapterObject->PagePort) { + + // + // Determine the controller number based on the Adapter number. + // + + if (AdapterObject->AdapterNumber == 1) { + + // + // This request is for DMA controller 1 + // + + PDMA1_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + } else { + + // + // This request is for DMA controller 2 + // + + PDMA2_CONTROL dmaControl; + + dmaControl = AdapterObject->AdapterBaseVa; + + // + // Initialize count to a value which will not match. + // + + count = 0xFFFF00; + + // + // Loop until the same high byte is read twice. + // + + do { + + high = count; + + WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); + + // + // Read the current DMA count. + // + + count = READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ); + + count |= READ_REGISTER_UCHAR( + &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] + .DmaBaseCount + ) << 8; + + } while ((count & 0xFFFF00) != (high & 0xFFFF00)); + + } + + // + // The DMA counter has a bias of one and can only be 16 bit long. + // + + count = (count + 1) & 0xFFFF; + + } + + return(count); +} + + +VOID +HalpHandleIoError ( + VOID + ) +{ + + UCHAR StatusByte; + + + // + // Read NMI status + // + + StatusByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpIoControlBase)->NmiStatus); + + // + // Test for PCI bus error + // + + if (StatusByte & 0x40) { + HalDisplayString ("NMI: IOCHK\n"); + } + + // + // Test for ISA IOCHK + // + + if (StatusByte & 0x80) { + HalDisplayString ("NMI: PCI System Error\n"); + } + +} diff --git a/private/ntos/nthals/halfire/ppc/pxsiosup.h b/private/ntos/nthals/halfire/ppc/pxsiosup.h new file mode 100644 index 000000000..beb486488 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxsiosup.h @@ -0,0 +1,231 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pxsiosup.h + +Abstract: + + The module defines the structures, and defines for the SIO chip set. + The SIO_CONTROL structure is a superset of the EISA_CONTROL stucture. + Differences from the Eisa control stucture are marked with comments. + +Author: + + Jim Wooldridge + +Revision History: + + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxsiosup.h $ + * $Revision: 1.5 $ + * $Date: 1996/01/11 07:13:41 $ + * $Locker: $ + */ + +#ifndef _SIO_ +#define _SIO_ + + + + + +BOOLEAN +HalpInitSMCSuperIo ( + VOID + ); + +BOOLEAN +HalpInitNationalSuperIo ( + VOID + ); + +typedef struct _SIO_CONTROL { + DMA1_CONTROL Dma1BasePort; // Offset 0x000 + UCHAR Reserved0[16]; + UCHAR Interrupt1ControlPort0; // Offset 0x020 + UCHAR Interrupt1ControlPort1; // Offset 0x021 + UCHAR Reserved1[32 - 2]; + UCHAR Timer1; // Offset 0x40 + UCHAR RefreshRequest; // Offset 0x41 + UCHAR SpeakerTone; // Offset 0x42 + UCHAR CommandMode1; // Offset 0x43 + UCHAR Reserved14[28]; + UCHAR ResetUbus; // Offset 0x60 + UCHAR NmiStatus; // Offset 0x61 + UCHAR Reserved15[14]; + UCHAR NmiEnable; // Offset 0x70 + UCHAR Reserved16[7]; + UCHAR BiosTimer[4]; // Offset 0x78 + UCHAR Reserved13[4]; + DMA_PAGE DmaPageLowPort; // Offset 0x080 + UCHAR Reserved2; + UCHAR AlternateReset; // Offset 0x092 + UCHAR Reserved17[14]; + UCHAR Interrupt2ControlPort0; // Offset 0x0a0 + UCHAR Interrupt2ControlPort1; // Offset 0x0a1 + UCHAR Reserved3[32-2]; + DMA2_CONTROL Dma2BasePort; // Offset 0x0c0 + UCHAR CoprocessorError; // Offset 0x0f0 + UCHAR Reserved4[0x281]; + UCHAR SecondaryFloppyOutput; // Offset 0x372 + UCHAR Reserved18[0x27]; + UCHAR Reserved21[0x59]; + UCHAR PrimaryFloppyOutput; // Offset 0x3f2 + UCHAR Reserved5[19]; + UCHAR Dma1ExtendedModePort; // Offset 0x40b + UCHAR Reserved6[4]; + UCHAR Channel0ScatterGatherCommand; // Offset 0x410 + UCHAR Channel1ScatterGatherCommand; // Offset 0x411 + UCHAR Channel2ScatterGatherCommand; // Offset 0x412 + UCHAR Channel3ScatterGatherCommand; // Offset 0x413 + UCHAR Reserved19; // Offset 0x414 + UCHAR Channel5ScatterGatherCommand; // Offset 0x415 + UCHAR Channel6ScatterGatherCommand; // Offset 0x416 + UCHAR Channel7ScatterGatherCommand; // Offset 0x417 + UCHAR Channel0ScatterGatherStatus; // Offset 0x418 + UCHAR Channel1ScatterGatherStatus; // Offset 0x419 + UCHAR Channel2ScatterGatherStatus; // Offset 0x41a + UCHAR Channel3ScatterGatherStatus; // Offset 0x41b + UCHAR Reserved20; // Offset 0x41c + UCHAR Channel5ScatterGatherStatus; // Offset 0x41d + UCHAR Channel6ScatterGatherStatus; // Offset 0x41e + UCHAR Channel7ScatterGatherStatus; // Offset 0x41f + UCHAR Channel0ScatterGatherTable[4]; // Offset 0x420 + UCHAR Channel1ScatterGatherTable[4]; // Offset 0x424 + UCHAR Channel2ScatterGatherTable[4]; // Offset 0x428 + UCHAR Channel3ScatterGatherTable[4]; // Offset 0x42c + UCHAR Reserved22[4]; // Offset 0x430 + UCHAR Channel5ScatterGatherTable[4]; // Offset 0x434 + UCHAR Channel6ScatterGatherTable[4]; // Offset 0x438 + UCHAR Channel7ScatterGatherTable[4]; // Offset 0x43c + UCHAR Reserved8[0x40]; + DMA_PAGE DmaPageHighPort; // Offset 0x480 + UCHAR Reserved10[70]; + UCHAR Dma2ExtendedModePort; // Offset 0x4d6 +} SIO_CONTROL, *PSIO_CONTROL; + + + +typedef struct _SIO_CONFIG { + UCHAR VendorId[2]; // Offset 0x00 read-only + UCHAR DeviceId[2]; // Offset 0x02 read-only + UCHAR Command[2]; // Offset 0x04 unused + UCHAR DeviceStatus[2]; // Offset 0x06 + UCHAR RevisionId; // Offset 0x08 read-only + UCHAR Reserved1[0x37]; // Offset 0x09 + UCHAR PciControl; // Offset 0x40 + UCHAR PciArbiterControl; // Offset 0x41 + UCHAR PciArbiterPriorityControl; // Offset 0x42 + UCHAR Reserved2; // Offset 0x43 + UCHAR MemCsControl; // Offset 0x44 + UCHAR MemCsBottomOfHole; // Offset 0x45 + UCHAR MemCsTopOfHole; // Offset 0x46 + UCHAR MemCsTopOfMemory; // Offset 0x47 + UCHAR IsaAddressDecoderControl; // Offset 0x48 + UCHAR IsaAddressDecoderRomEnable; // Offset 0x49 + UCHAR IsaAddressDecoderBottomOfHole; // Offset 0x4a + UCHAR IsaAddressDecoderTopOfHole; // Offset 0x4b + UCHAR IsaControllerRecoveryTimer; // Offset 0x4c + UCHAR IsaClockDivisor; // Offset 0x4d + UCHAR UtilityBusEnableA; // Offset 0x4e + UCHAR UtilityBusEnableB; // Offset 0x4f + UCHAR Reserved3[4]; // Offset 0x50 + UCHAR MemCsAttribute1; // Offset 0x54 + UCHAR MemCsAttribute2; // Offset 0x55 + UCHAR MemCsAttribute3; // Offset 0x56 + UCHAR ScatterGatherBaseAddress; // Offset 0x57 + UCHAR Reserved4[0x8]; // Offset 0x58 + UCHAR PciIrq0RouteControl; // Offset 0x60 + UCHAR PciIrq1RouteControl; // Offset 0x61 + UCHAR PciIrq2RouteControl; // Offset 0x62 + UCHAR PciIrq3RouteControl; // Offset 0x63 + UCHAR Reserved5[0x1C]; // Offset 0x64 + UCHAR BiosTimerBaseAddress[2]; // Offset 0x80 +}SIO_CONFIG, *PSIO_CONFIG; + + +// +// Define constants used by SIO config +// + + +// PCI control register - bit values +#define ENABLE_PCI_POSTED_WRITE_BUFFER 0x04 +#define ENABLE_ISA_MASTER_LINE_BUFFER 0x02 +#define EANBLE_DMA_LINE_BUFFER 0x01 + +// PCI Arbiter contol register - bit values +#define ENABLE_GAT 0x01 + + +// ISA CLock Divisor register - bit values +#define ENABLE_COPROCESSOR_ERROR 0x20 +#define ENABLE_MOUSE_SUPPORT 0x10 +#define RSTDRV 0x08 +#define SYSCLK_DIVISOR 0x00 + +//Utility Bus Chip Select A - bit values +#define ENABLE_RTC 0x01 +#define ENABLE_KEYBOARD 0x02 +#define ENABLE_IDE_DECODE 0x10 + +//Utility Bus Chip Select B - bit values +#define ENABLE_RAM_DECODE 0x80 +#define ENABLE_PORT92 0x40 +#define DISABLE_PARALLEL_PORT 0x30 +#define DISABLE_SERIAL_PORTB 0x0c +#define DISABLE_SERIAL_PORTA 0x03 + +// Interrupt controller - bit values +#define LEVEL_TRIGGERED 0x08 +#define SINGLE_MODE 0x02 + +// NMI status/control - bit values +#define DISABLE_IOCHK_NMI 0x08 +#define DISABLE_PCI_SERR_NMI 0x04 + +// NMI enable - bit values +#define DISABLE_NMI 0x80 + +// DMA command - bit values +#define DACK_ASSERT_HIGH 0x80 +#define DREQ_ASSERT_LOW 0x40 +#endif + +// +// Define 8259 constants +// + +#define SPURIOUS_VECTOR 7 +#define HIGHEST_8259_VECTOR 15 +// +// Define 8254 timer constants +// + +// +// Convert the interval to rollover count for 8254 Timer1 device. +// Since timer1 counts down a 16 bit value at a rate of 1.193M counts-per- +// sec, the computation is: +// RolloverCount = (Interval * 0.0000001) * (1.193 * 1000000) +// = Interval * 0.1193 +// = Interval * 1193 / 10000 +// +// + + + +#define COMMAND_8254_COUNTER0 0x00 // Select count 0 +#define COMMAND_8254_RW_16BIT 0x30 // Read/Write LSB firt then MSB +#define COMMAND_8254_MODE2 0x4 // Use mode 2 +#define COMMAND_8254_BCD 0x0 // Binary count down +#define COMMAND_8254_LATCH_READ 0x0 // Latch read command diff --git a/private/ntos/nthals/halfire/ppc/pxstall.s b/private/ntos/nthals/halfire/ppc/pxstall.s new file mode 100644 index 000000000..d10f24ccb --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxstall.s @@ -0,0 +1,390 @@ +//#*********************************************************************** +// +// +// +// +// Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file +// contains copyrighted material. Use of this file is restricted +// by the provisions of a Motorola Software License Agreement. +// +// Copyright 1993 International Buisness Machines Corporation. +// All Rights Reserved. +// +// This file contains copyrighted material. Use of this file is +// restricted by the provisions of a Motorola/IBM Joint Software +// License Agreement. +// +// File Name: +// PXSTALL.S +// +// Functions: +// KeStallExecutionProcessor +// HalpCalibrateStall +// +// History: +// 21-Sep-1993 Steve Johns +// Original Version +// 24-Dec-1993 Peter Johnston +// Adapted to 601 HAL in an attempt to avoid having different +// versions if at all possible. Original was designed for both +// 601 and 603 but had some 601 difficulties. +// 17-Jan-1994 Steve Johns +// Changed to treat 601 vs PowerPC time base differences more +// transparently. +// +//#*********************************************************************** + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxstall.s $ + * $Revision: 1.6 $ + * $Date: 1996/01/11 07:13:48 $ + * $Locker: $ + */ + + +#include "kxppc.h" + +#define ERRATA603 TRUE +#define RTCU 4 +#define RTCL 5 +#define CMOS_INDEX 0x70 +#define CMOS_DATA 0x71 +#define RTC_SECOND 0x80 + + + .extern HalpPerformanceFrequency + .extern HalpIoControlBase + .extern ..HalpDivide + +// +// Register Definitions +// + .set Microsecs, r.3 + .set TimerLo , r.6 // MUST be same as defined in PXCLKSUP.S + .set TimerHi , r.7 // MUST be same as defined in PXCLKSUP.S + .set EndTimerLo, r.3 + .set EndTimerHi, r.4 + .set Temp , r.8 + .set Temp2 , r.9 + .set IO_Base , r.10 + +//#*********************************************************************** +// +// Synopsis: +// VOID KeStallExecutionProcessor( +// ULONG Microseconds) +// +// Purpose: +// This function stalls the execution at least the specified number +// of microseconds, but not substantially longer. +// +// Returns: +// Nothing. +// +// Global Variables Referenced: +// HalpPerformanceFrequency +//#*********************************************************************** + + SPECIAL_ENTRY(KeStallExecutionProcessor) + mflr r.0 // Save Link Register + PROLOGUE_END(KeStallExecutionProcessor) + + cmpli 0,0,Microsecs,0 // if (Microseconds == 0) + beqlr- // return; + + bl ..HalpGetTimerRoutine // Get appropriate timer routine +// +// Read START time +// + bctrl // ReadPerformanceCounter(); + +// +// Get PerformanceCounter frequency +// + lwz Temp,[toc]HalpPerformanceFrequency(r.toc) + lwz Temp,0(Temp) +// +// Compute: (Microseconds * PerformanceFrequency) / 1,000,000 +// + mulhwu. EndTimerHi,Microsecs,Temp + mullw EndTimerLo,Microsecs,Temp + + + + LWI (r.5, 1000000) + bl ..HalpDivide + +// +// Account for software overhead +// + .set Overhead, 30 + cmpwi r.3, Overhead + ble SkipOverhead + addi r.3, r.3, -Overhead // Reduce delay +SkipOverhead: + +// +// Add delay to start time +// + addc EndTimerLo, TimerLo, r.3 + addze EndTimerHi, TimerHi + + + +// +// while (ReadPerformanceCounter() < EndTimer); +// +StallLoop: + bctrl // ReadPerformanceCounter(); + cmpl 0,0,TimerHi,EndTimerHi // Is TimerHi >= EndTimerHi ? + blt- StallLoop // No + bgt+ StallExit // Yes + cmpl 0,0,TimerLo,EndTimerLo // Is TimerLo >= EndTimerLo ? + blt StallLoop // Branch if not + +StallExit: + mtlr r.0 // Restore Link Register + + SPECIAL_EXIT(KeStallExecutionProcessor) + + + + + +// +// This routine is the ReadPerformanceCounter routine for the 601 processor. +// The 601 RTC counts discontinuously (1 is added to RTCU when the value in +// RTCL passes 999,999,999). This routine converts the RTC count to a +// continuous 64-bit count by calculating: +// +// ((RTC.HighPart * 1,000,000,000) + RTC.LowPart) / 128 +// +// + LEAF_ENTRY (ReadRTC) + + mfspr TimerHi,RTCU // Read the RTC registers coherently + mfspr TimerLo,RTCL + mfspr Temp,RTCU + cmpl 0,0,TimerHi,Temp + bne- ..ReadRTC + + lis Temp,(1000000000 >> 16) // RTC.HighPart * 1,000,000 + ori Temp,Temp,(1000000000 & 0xFFFF) + mullw Temp2,Temp,TimerHi + mulhwu Temp,Temp,TimerHi + addc TimerLo,Temp2,TimerLo // + RTC.LowPart + addze TimerHi,Temp +// +// Each tick increments the RTC by 128, so let's divide that out. +// + mr Temp,TimerHi // Divide 64-bit value by 128 + rlwinm TimerLo,TimerLo,32-7,7,31 + rlwinm TimerHi,TimerHi,32-7,7,31 + rlwimi TimerLo,Temp,32-7,0,6 + + LEAF_EXIT (ReadRTC) + + + + + +// +// This routine is the ReadPerformanceCounter routine for PowerPC +// architectures (not the 601). +// + LEAF_ENTRY (ReadTB) + + mftbu TimerHi // Read the TB registers coherently + mftb TimerLo +#if ERRATA603 + mftb TimerLo + mftb TimerLo + mftb TimerLo +#endif + mftbu Temp + cmpl 0,0,Temp,TimerHi + bne- ..ReadTB + + LEAF_EXIT (ReadTB) + + +// +// Returns in the Count Register the entry point for the routine +// that reads the appropriate Performance Counter (ReadRTC or ReadTB). +// +// Called from KeQueryPerformanceCounter and KeStallExecutionProcessor +// + LEAF_ENTRY (HalpGetTimerRoutine) + + mfpvr Temp // Read Processor Version Register + rlwinm Temp,Temp,16,16,31 + cmpli 0,0,Temp,1 // Are we running on an MPC601 ? + lwz Temp,[toc]ReadTB(r.toc) + bne+ GetEntryPoint // Branch if not + + lwz Temp,[toc]ReadRTC(r.toc) + +GetEntryPoint: + lwz Temp,0(Temp) // Get addr to ReadRTC or ReadTB + mtctr Temp + + LEAF_EXIT (HalpGetTimerRoutine) + + + + + +// +// Returns the number of performance counter ticks/second. +// +// The DECREMENTER is clocked at the same rate as the PowerPC Time Base (TB) +// and the POWER RTC. The POWER RTC is supposed to be clocked at 7.8125 MHz, +// but on early prototypes of the Sandalfoot platform, this is not true). +// In either case, to keep the calibration routine simple and generic, we +// will determine the DECREMENTER clock rate by counting ticks for exactly +// 1 second (as measured against the CMOS RealTimeClock). We then use that +// value in the KeStallExecutionProcessor() and KeQueryPerformanceCounter() +// + + LEAF_ENTRY(HalpCalibrateTB) + + // Get base address of ISA I/O space so we can talk to the CMOS RTC + lwz IO_Base,[toc]HalpIoControlBase(r.toc) + lwz IO_Base,0(IO_Base) + + + li r.3,RTC_SECOND // Read seconds from CMOS RTC + stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index + eieio + lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data + + +WaitForTick1: + li r.3,RTC_SECOND // Read seconds from CMOS RTC + stb r.3,CMOS_INDEX(IO_Base) // Write CMOS index + eieio + lbz r.3,CMOS_DATA(IO_Base) // Read CMOS data + cmpl 0,0,r.3,r.4 // Loop until it changes + beq+ WaitForTick1 + + + li r.4,-1 // Start the decrementer at max. count + mtdec r.4 +#if ERRATA603 + isync +#endif + +WaitForTick2: + li r.4,RTC_SECOND // Read seconds from CMOS RTC + stb r.4,CMOS_INDEX(IO_Base) // Write CMOS index + eieio + lbz r.4,CMOS_DATA(IO_Base) // Read CMOS data + cmpl 0,0,r.3,r.4 + beq+ WaitForTick2 + + mfdec r.3 // Read the decrementer + neg r.3,r.3 // Compute delta ticks + + mfpvr Temp // Read Processor Version Register + rlwinm Temp,Temp,16,16,31 + cmpli 0,0,Temp,1 // if (CPU != 601) + bnelr // return(r.3); +// +// On the 601, the DECREMENTER decrements every ns, so the 7 LSBs are +// not implemented. +// + rlwinm r.3,r.3,32-7,7,31 // Divide count by 128 + + + LEAF_EXIT(HalpCalibrateTB) + + + + LEAF_ENTRY(HalpCalibrateTBPStack) + +#define NVRAM_INDEX_LO 0x74 +#define NVRAM_INDEX_HI 0x75 +#define NVRAM_DATA 0x77 +#define RTC_OFFSET 0x1ff8 +#define RTC_CONTROL 0x0 +// *BJ* Fix later. +#undef RTC_SECOND +#define RTC_SECOND 0x1 +#define RTC_MINUTE 0x2 + +#define SYNCHRONIZE \ + lwz Temp,[toc]HalpIoControlBase(r.toc);\ + stw Temp,[toc]HalpIoControlBase(r.toc);\ + nop;\ + sync + + + // Get base address of ISA I/O space so we can talk to the CMOS RTC + lwz IO_Base,[toc]HalpIoControlBase(r.toc) + lwz IO_Base,0(IO_Base) + + + li r.3,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC + stb r.3,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo + rlwinm r.3,r.3,32-8,24,31 // Shift > 8 and mask 0xff + stb r.3,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi + SYNCHRONIZE + lbz r.3,NVRAM_DATA(IO_Base) // Read CMOS data + +WaitForTick0.Ps: + li r.4,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC + stb r.4,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo + rlwinm r.4,r.4,32-8,24,31 // Shift > 8 and mask 0xff + stb r.4,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi + SYNCHRONIZE + lbz r.4,NVRAM_DATA(IO_Base) // Read CMOS data + cmpl 0,0,r.3,r.4 // Loop until it changes + beq+ WaitForTick0.Ps + + +WaitForTick1.Ps: + li r.3,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC + stb r.3,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo + rlwinm r.3,r.3,32-8,24,31 // Shift > 8 and mask 0xff + stb r.3,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi + SYNCHRONIZE + lbz r.3,NVRAM_DATA(IO_Base) // Read CMOS data + cmpl 0,0,r.3,r.4 // Loop until it changes + beq+ WaitForTick1.Ps + + + li r.4,-1 // Start the decrementer at max. count + mtdec r.4 +#if ERRATA603 + isync +#endif + +WaitForTick2.Ps: + li r.4,RTC_OFFSET+ RTC_SECOND // Read seconds from CMOS RTC + stb r.4,NVRAM_INDEX_LO(IO_Base) // Write CMOS index lo + rlwinm r.4,r.4,32-8,24,31 // Shift > 8 and mask 0xff + stb r.4,NVRAM_INDEX_HI(IO_Base) // Write CMOS index hi + SYNCHRONIZE + lbz r.4,NVRAM_DATA(IO_Base) // Read CMOS data + cmpl 0,0,r.3,r.4 + beq+ WaitForTick2.Ps + + mfdec r.3 // Read the decrementer + neg r.3,r.3 // Compute delta ticks + + mfpvr Temp // Read Processor Version Register + rlwinm Temp,Temp,16,16,31 + cmpli 0,0,Temp,1 // if (CPU != 601) + bnelr // return(r.3); +// +// On the 601, the DECREMENTER decrements every ns, so the 7 LSBs are +// not implemented. +// + rlwinm r.3,r.3,32-7,7,31 // Divide count by 128 + + LEAF_EXIT(HalpCalibrateTBPStack) + + diff --git a/private/ntos/nthals/halfire/ppc/pxsysbus.c b/private/ntos/nthals/halfire/ppc/pxsysbus.c new file mode 100644 index 000000000..651dae898 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxsysbus.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxsysbus.c $ + * $Revision: 1.30 $ + * $Date: 1996/07/13 01:16:01 $ + * $Locker: $ + */ + +/*++ + + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + pxsysbus.c + +Abstract: + +Author: + +Environment: + +Revision History: + Jim Wooldridge - ported to PowerPC + + +--*/ + +#include +#include +#include +#include +#include "fpdebug.h" +#include "halp.h" +#include "phsystem.h" +#include "eisa.h" +#include "pxmemctl.h" + +extern ULONG Vector2Irql[]; +extern ULONG Vector2Affinity[]; + +// +// Which Ints on Processor 1? +// +BOOLEAN HalpGetAffinityCalled = FALSE; + + +#define TBS " " + +void +HalpGetAffinity(); + +BOOLEAN +HalpTranslateSystemBusAddress( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ); + +ULONG +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,HalpGetSystemInterruptVector) +#endif + +/*++ + +Routine Description: + + This function translates a bus-relative address space and address into + a system physical address. + +Arguments: + + BusAddress - Supplies the bus-relative address + + AddressSpace - Supplies the address space number. + Returns the host address space number. + + AddressSpace == 0 => memory space + AddressSpace == 1 => I/O space + + TranslatedAddress - Supplies a pointer to return the translated address + +Return Value: + + A return value of TRUE indicates that a system physical address + corresponding to the supplied bus relative address and bus address + number has been returned in TranslatedAddress. + + A return value of FALSE occurs if the translation for the address was + not possible + +--*/ + +BOOLEAN +HalpTranslateSystemBusAddress( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN PHYSICAL_ADDRESS BusAddress, + IN OUT PULONG AddressSpace, + OUT PPHYSICAL_ADDRESS TranslatedAddress + ) + +{ + UNREFERENCED_PARAMETER( BusHandler ); + UNREFERENCED_PARAMETER( RootHandler ); + + TranslatedAddress->HighPart = BusAddress.HighPart; + + + + // + // Determine the address based on whether the bus address + // is in I/O space, system space, or bus memory space. + // + + switch (*AddressSpace) { + case MEMORY_ADDRESS_SPACE: + // + // The address is in memory space. + // + TranslatedAddress->LowPart = BusAddress.LowPart + + PCI_MEMORY_PHYSICAL_BASE; + if (VER_PRODUCTBUILD > 1233) { + // + // Due to a change in NT defined spaces, our previous method + // of using AddressSpace to communicate a driver's mapping + // needs no longer will work. So, starting with Build 1297 + // we need to make sure the display driver is not mapped into + // the PCI_MEMORY_PHYSICAL_BASE but into it's "natural" + // location. + // + // This is a temp fix and must be revisited so that we + // can more specifically detect the framebuffer based + // driver requirements and not affect other devices that + // may have a legitimate need for this address offset into + // a bus location. + // + if ((BusAddress.LowPart&0xf0000000)==(0x70000000)) { + TranslatedAddress->LowPart = BusAddress.LowPart; + } + } + break; + // + // Everyone should be assumed IO space if not otherwise requested + // + default: + case IO_ADDRESS_SPACE: + // + // The address is in I/O space. + // + TranslatedAddress->LowPart = BusAddress.LowPart + + IO_CONTROL_PHYSICAL_BASE; + break; + case SYSTEM_ADDRESS_SPACE: + // + // The address is in system space. + // + TranslatedAddress->LowPart = BusAddress.LowPart; + break; + } + + *AddressSpace = 0; + + if (TranslatedAddress->LowPart < BusAddress.LowPart) { + // + // A carry occurred. + // + TranslatedAddress->HighPart += 1; + + } + + return(TRUE); +} + +/*++ + +Routine Description: + +Arguments: + + BusInterruptLevel - Supplies the bus specific interrupt level. + + BusInterruptVector - Supplies the bus specific interrupt vector. + + Irql - Returns the system request priority. + + Affinity - Returns the system wide irq affinity. + +Return Value: + + Returns the system interrupt vector corresponding to the specified device. + +--*/ +ULONG +HalpGetSystemInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) + +{ + + UNREFERENCED_PARAMETER( BusHandler ); + UNREFERENCED_PARAMETER( RootHandler ); + UNREFERENCED_PARAMETER( BusInterruptLevel ); + + if (HalpGetAffinityCalled == FALSE) { + HalpGetAffinity(); + HalpGetAffinityCalled = TRUE; + } + + *Affinity = Vector2Affinity[BusInterruptVector]; + + HDBG(DBG_INTERRUPTS|DBG_MPINTS, + HalpDebugPrint("HalpGetSystemInterruptVector: %x, %x, %d, %x\n", + BusInterruptLevel, BusInterruptVector, *Irql, *Affinity);); + + + *Irql = (UCHAR) Vector2Irql[BusInterruptVector]; // see define in ntdef.h + + // + // The vector is equal to the specified bus level plus the DEVICE_VECTORS. + // + BusInterruptLevel = BusInterruptVector; + HDBG(DBG_INTERRUPTS|DBG_MPINTS, + HalpDebugPrint( "%sint request: returning %x + %x = %x\n", + TBS, BusInterruptVector, DEVICE_VECTORS, + BusInterruptVector + DEVICE_VECTORS );); + return(BusInterruptVector + DEVICE_VECTORS); + +} + +// +// HalpGetAffinity() +// +// This is a simple routine that gets a value from NVRAM to +// overwrite the default value for where interrupts go. +// This is mostly a hack for now. +// +void +HalpGetAffinity() +{ + CHAR buf[256]; + PKPRCB pPRCB; + ULONG count; + extern HalpInitProcAffinity(PCHAR,ULONG); + + if ((count = HalpProcessorCount()) < 2) { + HalpInitProcAffinity((PCHAR)0,1); + return; + } + + pPRCB = KeGetCurrentPrcb(); + if (pPRCB->BuildType & PRCB_BUILD_UNIPROCESSOR) { + HalpInitProcAffinity((PCHAR)0,1); + return; + } + + if (HalGetEnvironmentVariable("UNIPROCESSOR", sizeof(buf), buf) + == ESUCCESS) { + if (_stricmp(buf, "true") == 0) { + HalpInitProcAffinity((PCHAR)0,1); + return; + } + } + + // it is mulitprocessor system. + // + // Get PROCNINTS Value from NVRAM + // + if (HalGetEnvironmentVariable("PROCNINTS", sizeof(buf), buf) + == ESUCCESS) { + HalpInitProcAffinity(buf,count); + return; + } else { + HalpInitProcAffinity((PCHAR)0,count); + return; + } +} diff --git a/private/ntos/nthals/halfire/ppc/pxsysint.c b/private/ntos/nthals/halfire/ppc/pxsysint.c new file mode 100644 index 000000000..39ff55351 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxsysint.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxsysint.c $ + * $Revision: 1.12 $ + * $Date: 1996/05/14 02:35:34 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991-1993 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxsysint.c + +Abstract: + + This module implements the HAL enable/disable system interrupt, and + request interprocessor interrupt routines for a Power PC. + + + +Author: + + David N. Cutler (davec) 6-May-1991 + +Environment: + + Kernel mode + +Revision History: + + Jim Wooldridge + + Removed internal interrupt support + Changed irql mapping + Removed internal bus support + Removed EISA, added PCI, PCMCIA, and ISA bus support + + Steve Johns + Changed to support Timer 1 as profile interrupt + Added HalAcknowledgeIpi +--*/ + +#include "halp.h" +#include "phsystem.h" +#include "fpdebug.h" + + + +/*++ + +Routine Description: + + This routine disables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is disabled. + + Irql - Supplies the IRQL of the interrupting source. + +Return Value: + + None. + +--*/ +VOID +HalDisableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql + ) +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level and acquire device enable spinlock. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpSystemInterruptLock); + + + // + // If the vector number is within the range of the EISA interrupts, then + // disable the EISA interrupt. + // + + if (Vector >= DEVICE_VECTORS && + // + // For FirePOWER, allowable external device interrupts spans 32 bits + // not the 16 of sandalfoot ( or SIO ) architecture. The 16 bit limits + // will be enforced in HalpDisableSioInterrupts. We'll do our normal + // system interrupt stuff there for now but should move the system + // register activity to here and leave the SIO disable routine to deal + // ONLY with the SIO stuff. + // + Vector < (DEVICE_VECTORS + MAXIMUM_DEVICE_VECTOR + 16) ) { + HalpDisableSioInterrupt(Vector); + } + + // + // Release the device enable spin lock and lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + return; +} + + +/*++ + +Routine Description: + + This routine enables the specified system interrupt. + +Arguments: + + Vector - Supplies the vector of the system interrupt that is enabled. + + Irql - Supplies the IRQL of the interrupting source. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched. + +Return Value: + + TRUE if the system interrupt was enabled + +--*/ +BOOLEAN +HalEnableSystemInterrupt ( + IN ULONG Vector, + IN KIRQL Irql, + IN KINTERRUPT_MODE InterruptMode + ) +{ + + KIRQL OldIrql; + + // + // Raise IRQL to the highest level and acquire device enable spinlock. + // + + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + KiAcquireSpinLock(&HalpSystemInterruptLock); + + // + // If the vector number is within the range of the EISA interrupts, then + // enable the EISA interrupt and set the Level/Edge register. + // + + + if (Vector >= DEVICE_VECTORS && + // + // For FirePOWER, allowable external device interrupts spans 32 bits + // not the 16 of sandalfoot ( or SIO ) architecture. The 16 bit limits + // will be enforced in HalpEnableSioInterrupts. We'll do our normal + // system interrupt stuff there for now but should move the system + // register activity to here and leave the SIO enable routine to deal + // ONLY with the SIO stuff. + // + Vector < (DEVICE_VECTORS + MAXIMUM_DEVICE_VECTOR + 16) ) { + HalpEnableSioInterrupt(Vector, InterruptMode); + } + + // + // Release the device enable spin lock and lower IRQL to the previous level. + // + + KiReleaseSpinLock(&HalpSystemInterruptLock); + KeLowerIrql(OldIrql); + return TRUE; +} + + +/*++ + +Routine Description: + + This routine requests an interprocessor interrupt on a set of processors. + + N.B. This routine must ensure that the interrupt is posted at the target + processor(s) before returning. + +Arguments: + + Mask - Supplies the set of processors that are sent an interprocessor + interrupt. + +Return Value: + + None. + +--*/ +VOID +HalRequestIpi(IN ULONG Mask) +{ + // + // Request an interprocessor interrupt on each of the specified target + // processors. + // + rCPUMessageInterruptSet = Mask; + FireSyncRegister(); + return; +} + + +/*++ + +Routine Description: + + This routine aknowledges an interprocessor interrupt on a set of + processors. + +Arguments: + + None + +Return Value: + + TRUE if the IPI is valid; otherwise FALSE is returned. + +--*/ +BOOLEAN +HalAcknowledgeIpi (VOID) +{ + // + // Use this call to clear the interrupt from the Req register + // + rCPUMessageInterrupt = (ULONG)(1 << GetCpuId()); + FireSyncRegister(); + return (TRUE); +} diff --git a/private/ntos/nthals/halfire/ppc/pxtime.c b/private/ntos/nthals/halfire/ppc/pxtime.c new file mode 100644 index 000000000..450b6856f --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxtime.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxtime.c $ + * $Revision: 1.14 $ + * $Date: 1996/05/20 22:36:01 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file +contains copyrighted material. Use of this file is restricted +by the provisions of a Motorola Software License Agreement. + +Module Name: + + pxtime.c + +Abstract: + + This module implements the HAL set/query realtime clock routines for + a PowerPC system. + +Author: + + David N. Cutler (davec) 5-May-1991 + +Environment: + + Kernel mode + +Revision History: + + Jim Wooldridge (jimw@austin.vnet.ibm.com) Initial Power PC port + + Change real time clock mapping to port 71. + Code assumes the DS1385S chip is compatible with existing + PC/AT type RTC's. The only known exception to PC/AT + compatibility on S-FOOT is the use of ports 810 and 812. + These ports provide password security for the RTC's NVRAM, + and are currently unused in this port since this address space + is available from kernel mode only in NT. + + Steve Johns (sjohns@pets.sps.mot.com) + Changed to support years > 1999 + +--*/ + +#include "fpdebug.h" +#include "halp.h" +#include "pxrtcsup.h" +#include "fpreg.h" +#include "fpio.h" +#include "fpds1385.h" +#include "eisa.h" + + +extern BOOLEAN RtcBinaryMode; +extern BOOLEAN RtcFailure; + +// +// Define forward referenced procedure prototypes. +// + +UCHAR +HalpReadClockRegister ( + UCHAR Register + ); + +VOID +HalpWriteClockRegister ( + UCHAR Register, + UCHAR Value + ); + +/*++ + +Routine Description: + + This routine queries the realtime clock. + + N.B. This routine is required to provide any synchronization necessary + to query the realtime clock information. + +Arguments: + + TimeFields - Supplies a pointer to a time structure that receives + the realtime clock information. + +Return Value: + + If the power to the realtime clock has not failed, then the time + values are read from the realtime clock and a value of TRUE is + returned. Otherwise, a value of FALSE is returned. + +--*/ + +BOOLEAN +HalQueryRealTimeClock (OUT PTIME_FIELDS TimeFields) +{ + + UCHAR DataByte; + KIRQL OldIrql; + BOOLEAN retVal = FALSE; + + // + // Acquire the RTC spin lock to synchronize the collection of + // accesses to the RTC + KeAcquireSpinLock(&HalpRTCLock, &OldIrql); + + // + // If the realtime clock battery is still functioning, then read + // the realtime clock values, and return a function value of TRUE. + // Otherwise, return a function value of FALSE. + // + DataByte = HalpDS1385ReadReg(RTC_CONTROL_REGISTERD); + + // + // Make sure the time is valid before setting values: + // + if ((DataByte & RTC_VRT ) == RTC_VRT) { + + // + // Wait until the realtime clock is not being updated. + // + + do { + DataByte = HalpDS1385ReadReg(RTC_CONTROL_REGISTERA); + } while( (DataByte & RTC_UIP) == RTC_UIP); + + // + // According to the chip spec, the only way to read the chip that + // is guarenteed to give a coherent time is to assert the SET bit; + // this essentially prevents the chip from updating the user visible + // copy of the time while we are reading it. Since the time will + // not update, there is the possiblity that we will loose a second. + // + DataByte = HalpDS1385ReadReg(RTC_CONTROL_REGISTERB); + HalpDS1385WriteReg(RTC_CONTROL_REGISTERB, + (UCHAR)((DataByte & ~RTC_UIE) | RTC_SET)); + + // Reset the failure flag (see below) + RtcFailure = FALSE; + + // Read the values + TimeFields->Year = 1900 + (CSHORT)HalpReadClockRegister(RTC_YEAR); + if (TimeFields->Year < 1980) TimeFields->Year += 100; + TimeFields->Month = (CSHORT)HalpReadClockRegister(RTC_MONTH); + TimeFields->Day = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_MONTH); + TimeFields->Weekday = + (CSHORT)HalpReadClockRegister(RTC_DAY_OF_WEEK) - 1; + TimeFields->Hour = (CSHORT)HalpReadClockRegister(RTC_HOUR); + TimeFields->Minute = (CSHORT)HalpReadClockRegister(RTC_MINUTE); + TimeFields->Second = (CSHORT)HalpReadClockRegister(RTC_SECOND); + TimeFields->Milliseconds = 0; + + // + // Release the SET bit + // + HalpDS1385WriteReg(RTC_CONTROL_REGISTERB, DataByte); + + // + // We have a problem reading the RTC; see HalpDS1385ReadReg in + // fpds1385.c for a description. If we detect an + // error, that routine asserts RtcFailure. Use that value here. + // + retVal = !RtcFailure; + } + + KeReleaseSpinLock(&HalpRTCLock, OldIrql); + return retVal; +} + + +/*++ + +Routine Description: + + This routine sets the realtime clock. + + N.B. This routine is required to provide any synchronization necessary + to set the realtime clock information. + +Arguments: + + TimeFields - Supplies a pointer to a time structure that specifies the + realtime clock information. + +Return Value: + + If the power to the realtime clock has not failed, then the time + values are written to the realtime clock and a value of TRUE is + returned. Otherwise, a value of FALSE is returned. + +--*/ +BOOLEAN +HalSetRealTimeClock (IN PTIME_FIELDS TimeFields) +{ + + UCHAR DataByte; + KIRQL OldIrql; + BOOLEAN retVal = FALSE; + + // + // Acquire the RTC spin lock to synchronize the collection of + // accesses to the RTC + KeAcquireSpinLock(&HalpRTCLock, &OldIrql); + + // + // If the realtime clock battery is still functioning, then write + // the realtime clock values, and return a function value of TRUE. + // Otherwise, return a function value of FALSE. + // + DataByte = HalpDS1385ReadReg(RTC_CONTROL_REGISTERD); + + if (( DataByte & RTC_VRT ) == RTC_VRT) { + // + // Set the realtime clock control to set the time. + // RMW the control byte so we don't lose it's setup + // + DataByte = HalpDS1385ReadReg(RTC_CONTROL_REGISTERB); + + // + // set control parameters: leave daylight savings disabled + // since the control program needs to know and has no way of + // passing that info in to here. + // + HalpDS1385WriteReg(RTC_CONTROL_REGISTERB, + (UCHAR)((DataByte & ~RTC_UIE) | RTC_SET)); + + // + // Write the realtime clock values. + // + + if ( TimeFields->Year > 1999 ) { + HalpWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 2000)); + } else { + HalpWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 1900)); + } + + HalpWriteClockRegister(RTC_MONTH, (UCHAR)TimeFields->Month); + HalpWriteClockRegister(RTC_DAY_OF_MONTH, (UCHAR)TimeFields->Day); + HalpWriteClockRegister(RTC_DAY_OF_WEEK, + (UCHAR)(TimeFields->Weekday + 1)); + HalpWriteClockRegister(RTC_HOUR, (UCHAR)TimeFields->Hour); + HalpWriteClockRegister(RTC_MINUTE, (UCHAR)TimeFields->Minute); + HalpWriteClockRegister(RTC_SECOND, (UCHAR)TimeFields->Second); + + // + // Release the realtime clock control to update the time. + // + HalpDS1385WriteReg(RTC_CONTROL_REGISTERB, DataByte); + + retVal = TRUE; + } + + KeReleaseSpinLock(&HalpRTCLock, OldIrql); + return retVal; +} + + +/*++ + +Routine Description: + + This routine reads the specified realtime clock register. + change return value from BCD to binary integer. I think the chip + can be configured to do this,... but as a quick fix I am doing it + here. (plj) + +Arguments: + + Register - Supplies the number of the register whose value is read. + +Return Value: + + The value of the register is returned as the function value. + +--*/ + +UCHAR +HalpReadClockRegister (UCHAR Register) +{ + UCHAR BcdValue; + + BcdValue = HalpDS1385ReadReg(Register); + + // + // If the data mode is BCD, calculate the return value as BCD: + // + if ( FALSE == RtcBinaryMode ) { + BcdValue = (BcdValue >> 4) * 10 + (BcdValue & 0x0f); + } + return (BcdValue) ; +} + +/*++ + +Routine Description: + + This routine writes the specified value to the specified realtime + clock register. + +Arguments: + + Register - Supplies the number of the register whose value is written. + + Value - Supplies the value that is written to the specified register. + +Return Value: + + The value of the register is returned as the function value. + +--*/ + +VOID +HalpWriteClockRegister ( + UCHAR Register, + UCHAR Value + ) +{ + UCHAR BcdValue; + + if (TRUE == RtcBinaryMode) { + BcdValue = Value; + } else { + BcdValue = ((Value / 10) << 4) | (Value % 10); + } + + // + // Now insert the value into the RTC register + // + HalpDS1385WriteReg(Register, BcdValue); + + return; +} diff --git a/private/ntos/nthals/halfire/ppc/pxusage.c b/private/ntos/nthals/halfire/ppc/pxusage.c new file mode 100644 index 000000000..75d3b0fd5 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/pxusage.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: pxusage.c $ + * $Revision: 1.6 $ + * $Date: 1996/01/11 07:14:14 $ + * $Locker: $ + */ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + pxusage.c + +Abstract: + +Author: + + Ken Reneris (kenr) + +Environment: + + Kernel mode only. + +Revision History: + + Jim Wooldridge Ported to PowerPC + +--*/ + +#include "halp.h" + + +// +// Array to remember hal's IDT usage +// + +extern ADDRESS_USAGE *HalpAddressUsageList; +extern IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR]; + +KAFFINITY HalpActiveProcessors; + +VOID +HalpGetResourceSortValue ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, + OUT PULONG sortscale, + OUT PLARGE_INTEGER sortvalue + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT,HalpEnableInterruptHandler) +#pragma alloc_text(INIT,HalpRegisterVector) +#pragma alloc_text(INIT,HalpGetResourceSortValue) +#pragma alloc_text(INIT,HalpReportResourceUsage) +#endif + + + + +/*++ + +Routine Description: BOOLEAN HalpEnableInterruptHandler () + + This function connects & registers an IDT vectors usage by the HAL. + +Arguments: + +Return Value: + +--*/ + +BOOLEAN +HalpEnableInterruptHandler ( + IN PKINTERRUPT Interrupt, + IN PKSERVICE_ROUTINE ServiceRoutine, + IN PVOID ServiceContext, + IN PKSPIN_LOCK SpinLock OPTIONAL, + IN ULONG Vector, + IN KIRQL Irql, + IN KIRQL SynchronizeIrql, + IN KINTERRUPT_MODE InterruptMode, + IN BOOLEAN ShareVector, + IN CCHAR ProcessorNumber, + IN BOOLEAN FloatingSave, + IN UCHAR ReportFlags, + IN KIRQL BusVector + ) +{ + // + // Remember which vector the hal is connecting so it can be reported + // later on + // + + + KeInitializeInterrupt( Interrupt, + ServiceRoutine, + ServiceContext, + SpinLock, + Vector, + Irql, + SynchronizeIrql, + InterruptMode, + ShareVector, + ProcessorNumber, + FloatingSave + ); + + // + // Don't fail if the interrupt cannot be connected. + // + + if (!KeConnectInterrupt( Interrupt )) { + HalDisplayString("HalpEnableInterruptHandler: no connect \n"); + + return(FALSE); + } + + HalpRegisterVector (ReportFlags, BusVector, Vector, Irql); + + + // + // Connect the IDT and enable the vector now + // + + return(TRUE); + + +} + + + +/*++ + +Routine Description: VOID HalpRegisterVector () + + This registers an IDT vectors usage by the HAL. + +Arguments: + +Return Value: + +--*/ + +VOID +HalpRegisterVector ( + IN UCHAR ReportFlags, + IN ULONG BusInterruptVector, + IN ULONG SystemInterruptVector, + IN KIRQL SystemIrql + ) +{ +#if DBG + // There are only 0ff IDT entries... + ASSERT (SystemInterruptVector <= MAXIMUM_IDTVECTOR && + BusInterruptVector <= MAXIMUM_IDTVECTOR); +#endif + + // + // Remember which vector the hal is connecting so it can be reported + // later on + // + + HalpIDTUsage[SystemInterruptVector].Flags = ReportFlags; + HalpIDTUsage[SystemInterruptVector].Irql = SystemIrql; + HalpIDTUsage[SystemInterruptVector].BusReleativeVector = (UCHAR) BusInterruptVector; +} + +/*++ + +Routine Description: VOID HalpGetResourceSortValue () + + Used by HalpReportResourceUsage in order to properly sort + partial_resource_descriptors. + +Arguments: + + pRCurLoc - resource descriptor + +Return Value: + + sortscale - scaling of resource descriptor for sorting + sortvalue - value to sort on + + +--*/ + +VOID +HalpGetResourceSortValue ( + IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, + OUT PULONG sortscale, + OUT PLARGE_INTEGER sortvalue + ) +{ + switch (pRCurLoc->Type) { + case CmResourceTypeInterrupt: + *sortscale = 0; + *sortvalue = RtlConvertUlongToLargeInteger( + pRCurLoc->u.Interrupt.Level ); + break; + + case CmResourceTypePort: + *sortscale = 1; + *sortvalue = pRCurLoc->u.Port.Start; + break; + + case CmResourceTypeMemory: + *sortscale = 2; + *sortvalue = pRCurLoc->u.Memory.Start; + break; + + default: + *sortscale = 4; + *sortvalue = RtlConvertUlongToLargeInteger (0); + break; + } +} + +/*++ + +Routine Description: VOID HalpReportResourceUsage () + +Arguments: + +Return Value: + +--*/ + +VOID +HalpReportResourceUsage ( + IN PUNICODE_STRING HalName, + IN INTERFACE_TYPE DeviceInterfaceToUse + ) +{ + PCM_RESOURCE_LIST RawResourceList, TranslatedResourceList; + PCM_FULL_RESOURCE_DESCRIPTOR pRFullDesc, pTFullDesc; + PCM_PARTIAL_RESOURCE_LIST pRPartList=NULL, pTPartList=NULL; + PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, pTCurLoc; + PCM_PARTIAL_RESOURCE_DESCRIPTOR pRSortLoc, pTSortLoc; + CM_PARTIAL_RESOURCE_DESCRIPTOR RPartialDesc, TPartialDesc; + ULONG i, j, k, ListSize, Count; + ULONG curscale, sortscale; + UCHAR pass, reporton; + INTERFACE_TYPE interfacetype; + ULONG CurrentIDT, CurrentElement; + ADDRESS_USAGE *CurrentAddress; + LARGE_INTEGER curvalue, sortvalue; + + + // + // Allocate some space to build the resource structure + // + + RawResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, PAGE_SIZE*2); + TranslatedResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, PAGE_SIZE*2); + + // This functions assumes unset fields are zero + RtlZeroMemory (RawResourceList, PAGE_SIZE*2); + RtlZeroMemory (TranslatedResourceList, PAGE_SIZE*2); + + // + // Initialize the lists + // + + RawResourceList->List[0].InterfaceType = (INTERFACE_TYPE) -1; + + pRFullDesc = RawResourceList->List; + pRCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) RawResourceList->List; + pTCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) TranslatedResourceList->List; + + + for(i=0; i < DEVICE_VECTORS; i++) { + if (!(HalpIDTUsage[i].Flags & IDTOwned)) { + HalpIDTUsage[i].Flags = InternalUsage; + HalpIDTUsage[i].BusReleativeVector = (UCHAR) i; + } + } + + for(pass=0; pass < 2; pass++) { + if (pass == 0) { + // + // First pass - build resource lists for resources reported + // reported against device usage. + // + + reporton = DeviceUsage & ~IDTOwned; + interfacetype = DeviceInterfaceToUse; + } else { + + // + // Second pass = build reousce lists for resources reported + // as internal usage. + // + + reporton = InternalUsage & ~IDTOwned; + interfacetype = Internal; + } + + CurrentIDT = 0; + CurrentElement = 0; + CurrentAddress = HalpAddressUsageList; + + for (; ;) { + if (CurrentIDT <= MAXIMUM_IDTVECTOR) { + // + // Check to see if CurrentIDT needs to be reported + // + + if (!(HalpIDTUsage[CurrentIDT].Flags & reporton)) { + // Don't report on this one + CurrentIDT++; + continue; + } + + // + // Report CurrentIDT resource + // + + RPartialDesc.Type = CmResourceTypeInterrupt; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + RPartialDesc.Flags = + HalpIDTUsage[CurrentIDT].Flags & InterruptLatched ? + CM_RESOURCE_INTERRUPT_LATCHED : + CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; + RPartialDesc.u.Interrupt.Vector = HalpIDTUsage[CurrentIDT].BusReleativeVector; + RPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].BusReleativeVector; + RPartialDesc.u.Interrupt.Affinity = HalpActiveProcessors; + + RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc); + TPartialDesc.u.Interrupt.Vector = CurrentIDT; + TPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].Irql; + + CurrentIDT++; + + } else { + // + // Check to see if CurrentAddress needs to be reported + // + + if (!CurrentAddress) { + break; // No addresses left + } + + if (!(CurrentAddress->Flags & reporton)) { + // Don't report on this list + CurrentElement = 0; + CurrentAddress = CurrentAddress->Next; + continue; + } + + if (!CurrentAddress->Element[CurrentElement].Length) { + // End of current list, go to next list + CurrentElement = 0; + CurrentAddress = CurrentAddress->Next; + continue; + } + + // + // Report CurrentAddress + // + + RPartialDesc.Type = (UCHAR) CurrentAddress->Type; + RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive; + + if (RPartialDesc.Type == CmResourceTypePort) { + i = 1; // address space port + RPartialDesc.Flags = CM_RESOURCE_PORT_IO; + } else { + i = 0; // address space memory + RPartialDesc.Flags = CM_RESOURCE_MEMORY_READ_WRITE; + } + + // Notice: assuming u.Memory and u.Port have the same layout + RPartialDesc.u.Memory.Start.HighPart = 0; + RPartialDesc.u.Memory.Start.LowPart = + CurrentAddress->Element[CurrentElement].Start; + + RPartialDesc.u.Memory.Length = + CurrentAddress->Element[CurrentElement].Length; + + // translated address = Raw address + RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc); + HalTranslateBusAddress ( + interfacetype, // device bus or internal + 0, // bus number + RPartialDesc.u.Memory.Start, // source address + &i, // address space + &TPartialDesc.u.Memory.Start ); // translated address + + if (RPartialDesc.Type == CmResourceTypePort && i == 0) { + TPartialDesc.Flags = CM_RESOURCE_PORT_MEMORY; + } + + CurrentElement++; + } + + // + // Include the current resource in the HALs list + // + + if (pRFullDesc->InterfaceType != interfacetype) { + // + // Interface type changed, add another full section + // + + RawResourceList->Count++; + TranslatedResourceList->Count++; + + pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pRCurLoc; + pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pTCurLoc; + + pRFullDesc->InterfaceType = interfacetype; + pTFullDesc->InterfaceType = interfacetype; + + pRPartList = &pRFullDesc->PartialResourceList; + pTPartList = &pTFullDesc->PartialResourceList; + + // + // Bump current location pointers up + // + pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors; + pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors; + } + + + pRPartList->Count++; + pTPartList->Count++; + RtlCopyMemory (pRCurLoc, &RPartialDesc, sizeof RPartialDesc); + RtlCopyMemory (pTCurLoc, &TPartialDesc, sizeof TPartialDesc); + + pRCurLoc++; + pTCurLoc++; + } + } + + ListSize = (ULONG) ( ((PUCHAR) pRCurLoc) - ((PUCHAR) RawResourceList) ); + + // + // The HAL's resource usage structures have been built + // Sort the partial lists based on the Raw resource values + // + + pRFullDesc = RawResourceList->List; + pTFullDesc = TranslatedResourceList->List; + + for (i=0; i < RawResourceList->Count; i++) { + + pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors; + pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors; + Count = pRFullDesc->PartialResourceList.Count; + + for (j=0; j < Count; j++) { + HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue); + + pRSortLoc = pRCurLoc; + pTSortLoc = pTCurLoc; + + for (k=j; k < Count; k++) { + HalpGetResourceSortValue (pRSortLoc, &sortscale, &sortvalue); + + if (sortscale < curscale || + (sortscale == curscale && + RtlLargeIntegerLessThan (sortvalue, curvalue)) ) { + + // + // Swap the elements.. + // + + RtlCopyMemory (&RPartialDesc, pRCurLoc, sizeof RPartialDesc); + RtlCopyMemory (pRCurLoc, pRSortLoc, sizeof RPartialDesc); + RtlCopyMemory (pRSortLoc, &RPartialDesc, sizeof RPartialDesc); + + // swap translated descriptor as well + RtlCopyMemory (&TPartialDesc, pTCurLoc, sizeof TPartialDesc); + RtlCopyMemory (pTCurLoc, pTSortLoc, sizeof TPartialDesc); + RtlCopyMemory (pTSortLoc, &TPartialDesc, sizeof TPartialDesc); + + // get new curscale & curvalue + HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue); + } + + pRSortLoc++; + pTSortLoc++; + } + + pRCurLoc++; + pTCurLoc++; + } + + pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pRCurLoc; + pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pTCurLoc; + } + + + // + // Inform the IO system of our resources.. + // + + IoReportHalResourceUsage ( + HalName, + RawResourceList, + TranslatedResourceList, + ListSize + ); + + ExFreePool (RawResourceList); + ExFreePool (TranslatedResourceList); +} diff --git a/private/ntos/nthals/halfire/ppc/sysbios.c b/private/ntos/nthals/halfire/ppc/sysbios.c new file mode 100644 index 000000000..9aa6dc90c --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/sysbios.c @@ -0,0 +1,73 @@ +/*++ + + +Copyright (C) 1996 Motorola Inc. + +Module Name: + + sysbios.c + +Abstract: + + Emulate System BIOS functions. + +Author: + + Scott Geranen + +Environment: + + Kernel mode + +Revision History: + + +--*/ + +#include "halp.h" +#include "pci.h" +#include "pcip.h" +#include "emulate.h" +#include "sysbios.h" +#include "pcibios.h" + +BOOLEAN +HalpEmulateSystemBios( + IN OUT PRXM_CONTEXT P, + IN ULONG Number + ) +/*++ + +Routine Description: + + This function emulates a system BIOS. However, this is really + intended to support video bios functions, not all system BIOS + functions are implemented. + +Arguments: + + P - Supplies a pointer to an emulator context structure. + Number - interrupt number used to enter + +Return Value: + + TRUE = the function was emulated + FALSE = the function was not emulated + +--*/ +{ + switch (Number) { + case 0x1A: + if (P->Gpr[EAX].Xh == PCIBIOS_PCI_FUNCTION_ID) { + return HalpEmulatePciBios(P); + } + + // + // Fall into the default case. + // + + default: + return FALSE; // not supported + } +} + diff --git a/private/ntos/nthals/halfire/ppc/sysbios.h b/private/ntos/nthals/halfire/ppc/sysbios.h new file mode 100644 index 000000000..6119bc2d0 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/sysbios.h @@ -0,0 +1,31 @@ +/*++ BUILD Version: 0000 // Increment this if a change has global effects + +Copyright (c) 1996 Motorola Inc. + +Module Name: + + sysbios.h + +Abstract: + + This module contains the private header file for the system BIOS + emulation. + +Author: + + Scott Geranen (3-4-96) + +Revision History: + +--*/ + +#ifndef _SYSBIOS_ +#define _SYSBIOS_ + +BOOLEAN +HalpEmulateSystemBios( + IN OUT PRXM_CONTEXT P, + IN ULONG Number + ); + +#endif // _SYSBIOS_ diff --git a/private/ntos/nthals/halfire/ppc/txtpalet.h b/private/ntos/nthals/halfire/ppc/txtpalet.h new file mode 100644 index 000000000..ffb5e97b1 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/txtpalet.h @@ -0,0 +1,107 @@ +/****************************************************************************** + +txtpalet.h + + Author: Jess Botts + + This file contains the text mode palette. Most of the entries are 0 + because they are not used. The first 8 entries are used for all + background colors and normal intensity foregound colors. Background + colors are displayed at normal intensity only. The 8 entries that + begin at the 56th entry are used for high intensity foreground colors. + + Each entry consists of 3 values, 1 for each color gun. + +******************************************************************************/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: txtpalet.h $ + * $Revision: 1.4 $ + * $Date: 1996/01/11 07:14:21 $ + * $Locker: $ + */ + +UCHAR + TextPalette[] = + { /* + Line + R G B R G B R G B R G B Index + */ + +// all background colors and normal intensity foregound colors + + 0, 0, 0, 0, 0, 32, 0, 32, 0, 0, 32, 32, // 0 + 32, 0, 0, 32, 0, 32, 32, 32, 0, 32, 32, 32, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +// high intensity foreground colors + + 16, 16, 16, 0, 0, 63, 0, 63, 0, 0, 63, 63, // 56 + 63, 0, 0, 63, 0, 63, 63, 63, 0, 63, 63, 63, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + +/*****************************************************************************/ diff --git a/private/ntos/nthals/halfire/ppc/x86bios.c b/private/ntos/nthals/halfire/ppc/x86bios.c new file mode 100644 index 000000000..3bb1a9686 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/x86bios.c @@ -0,0 +1,1201 @@ +/*++ + +Copyright (C) 1994,1995 Microsoft Corporation + +Module Name: + + x86bios.c + +Abstract: + + + This module implements the platform specific interface between a device + driver and the execution of x86 ROM bios code for the device. + +Environment: + + Kernel mode only. + +--*/ + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: x86bios.c $ + * $Revision: 1.21 $ + * $Date: 1996/07/02 04:58:06 $ + * $Locker: $ + */ + + + + + +#include "halp.h" +#include "xm86.h" +#include "x86new.h" +#include "pxpcisup.h" +#include "pxmemctl.h" +#include "fpdebug.h" +#include "pci.h" +// +// Define global data. +// + +ULONG HalpX86BiosInitialized = FALSE; +ULONG HalpEnableInt10Calls = FALSE; +//PVOID HalpIoMemoryBase = NULL; +PUCHAR HalpRomBase = NULL; + +UCHAR HalpVideoBus; // Used as arguments to the PCI BIOS +UCHAR HalpVideoDevice; // init function. Set HalpInitX86Emulator, +UCHAR HalpVideoFunction; // used by HalpInitializeX86DisplayAdapter. + +UCHAR HalpLastPciBus; // Set by scanning the configuration data and + // used by PCI BIOS eumulation code. + +ULONG ROM_Length; +#define BUFFER_SIZE (128*1024) +UCHAR ROM_Buffer[BUFFER_SIZE]; + +static VOID DumpPCIConfig(PVOID ConfigBaseAddress) +{ + USHORT VendorID, DeviceID, RevisionID; + ULONG addr; + ULONG TempReg32; + + VendorID = READ_REGISTER_USHORT(&((PCI_CONFIG)ConfigBaseAddress)->VendorID); + DeviceID = READ_REGISTER_USHORT(&((PCI_CONFIG)ConfigBaseAddress)->DeviceID); + RevisionID = READ_REGISTER_UCHAR(&((PCI_CONFIG)ConfigBaseAddress)->RevisionID); + PRNTDISP(DbgPrint("vendorID=0x%04x deviceID=0x%04x revisionID=0x%02x\n", VendorID, DeviceID, RevisionID)); + + TempReg32 = READ_REGISTER_ULONG((PULONG)&((PCI_CONFIG)ConfigBaseAddress)->Command); + PRNTDISP(DbgPrint("Status Command=0x%08x\n", TempReg32)); + + TempReg32 = READ_REGISTER_ULONG((PULONG)&((PCI_CONFIG)ConfigBaseAddress)->RevisionID); + PRNTDISP(DbgPrint("Revision ID=0x%08x\n", TempReg32)); + + addr = READ_REGISTER_ULONG(&((PCI_CONFIG)ConfigBaseAddress)->BaseAddress1); PRNTDISP(DbgPrint("BaseAddress1=0x%08x\n", addr)); + + + addr = READ_REGISTER_ULONG(&((PCI_CONFIG)ConfigBaseAddress)->BaseAddress2); PRNTDISP(DbgPrint("BaseAddress2=0x%08x\n", addr)); + addr = READ_REGISTER_ULONG(&((PCI_CONFIG)ConfigBaseAddress)->BaseAddress3); PRNTDISP(DbgPrint("BaseAddress3=0x%08x\n", addr)); + addr = READ_REGISTER_ULONG(&((PCI_CONFIG)ConfigBaseAddress)->BaseAddress4); PRNTDISP(DbgPrint("BaseAddress4=0x%08x\n", addr)); + addr = READ_REGISTER_ULONG(&((PCI_CONFIG)ConfigBaseAddress)->BaseAddress5); PRNTDISP(DbgPrint("BaseAddress5=0x%08x\n", addr)); + addr = READ_REGISTER_ULONG(&((PCI_CONFIG)ConfigBaseAddress)->BaseAddress6); PRNTDISP(DbgPrint("BaseAddress6=0x%08x\n", addr)); +} + + + +BOOLEAN HalpInitX86Emulator( + VOID) + +{ + BOOLEAN Found = FALSE; + ULONG ROM_size = 0; + PHYSICAL_ADDRESS PhysAddr; + USHORT Cmd, VendorID, Slot; + PVOID HalpVideoConfigBase; + PUCHAR ROM_Ptr; + ULONG i; + UCHAR Class; + UCHAR SubClass; + USHORT DeviceID = 0; + UCHAR RevisionID = 0; + ULONG mapSize = 0x800000; + + PhysAddr.HighPart = 0x00000000; + + + // + // Scan PCI slots for video BIOS ROMs + // + for (Slot = 1; Slot < MAXIMUM_PCI_SLOTS; Slot++) { + + HalpVideoConfigBase = (PVOID) ((ULONG) HalpPciConfigBase + HalpPciConfigSlot[Slot]); + + // Read Vendor ID and check if slot is empty + VendorID = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->VendorID); + if (VendorID == 0xFFFF) + continue; // Slot is empty; go to next slot + + DumpPCIConfig(HalpVideoConfigBase); + + Class = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->ClassCode[2]); + SubClass = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->ClassCode[1]); +#define DISPLAY_CLASS 0x03 + if ( !(Class == DISPLAY_CLASS && (SubClass == 0)) && + !(Class == 0x00 && SubClass == 0x01)) + continue; + + DeviceID = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->DeviceID); + RevisionID = READ_REGISTER_UCHAR(&((PCI_CONFIG)HalpVideoConfigBase)->RevisionID); + //PRNTDISP(DbgPrint("vendorID=0x%04x deviceID=0x%04x revisionID=0x%02x\n", VendorID, DeviceID, RevisionID)); + //DbgBreakPoint(); + + // Get size of ROM + WRITE_REGISTER_ULONG(&((PCI_CONFIG)HalpVideoConfigBase)->ROMbase, 0xFFFFFFFF); + ROM_size = READ_REGISTER_ULONG(&((PCI_CONFIG)HalpVideoConfigBase)->ROMbase); + + + if ((ROM_size != 0xFFFFFFFF) && (ROM_size != 0)) { + ROM_size = ~(ROM_size & 0xFFFFFFFE) + 1; + PRNTDISP(DbgPrint("ROM_size=0x%08x\n", ROM_size)); + ROM_size += 0xC0000; + // if (ROM_size < 0xE0000) ROM_size = 0xE0000; // Map to end of option ROM space + + // + // Set Expansion ROM Base Address & enable ROM + // + PhysAddr.LowPart = 0x000C0000 | 1; + WRITE_REGISTER_ULONG(&((PCI_CONFIG)HalpVideoConfigBase)->ROMbase, PhysAddr.LowPart); + + // + // Enable Memory & I/O spaces in command register + // + Cmd = READ_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->Command); + WRITE_REGISTER_USHORT(&((PCI_CONFIG)HalpVideoConfigBase)->Command, Cmd | 3); + PRNTDISP(DbgPrint("HalpVideoConfigBase=0x%08x Slot=%d Cmd=0x%08x ROM_size=0x%08x\n", HalpVideoConfigBase, Slot, Cmd, ROM_size)); + + // + // Create a mapping to the PCI memory space + // + if (NULL == HalpIoMemoryBase) { + HalpIoMemoryBase = KePhase0MapIo((PVOID)IO_MEMORY_PHYSICAL_BASE, mapSize /*ROM_size*/); + + if (HalpIoMemoryBase == NULL) { + PRNTDISP(DbgPrint("\nCan't create mapping to PCI memory space\n")); + return FALSE; + } + } + // + // Look for PCI option video ROM signature + // + HalpRomBase = ROM_Ptr = (PUCHAR) HalpIoMemoryBase + 0xC0000; + if (*ROM_Ptr == 0x55 && *(ROM_Ptr+1) == 0xAA) { + // + // Copy ROM to RAM. PCI Spec says you can't execute from ROM. + // Sometimes option ROM and video RAM can't co-exist. + // + ROM_Length = *(ROM_Ptr+2) << 9; + PRNTDISP(DbgPrint("ROM_Length=0x%08x\n", ROM_Length)); + if (ROM_Length <= BUFFER_SIZE) { + for (i=0; iConfigurationRoot, + AdapterClass, MultiFunctionAdapter, &MatchKey)) != NULL) { + + if (!strcmp(ConfigurationEntry->ComponentEntry.Identifier,"PCI")) { + + Descriptor = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData; + + PCIRegInfo = (PPCI_REGISTRY_INFO)&Descriptor->PartialDescriptors[1]; + + HalpLastPciBus = PCIRegInfo->NoBuses - 1; + + break; + } + + MatchKey++; + } + +#endif + + // + // Initialize the x86 bios emulator. + // + + x86BiosInitializeBios(HalpIoControlBase, HalpIoMemoryBase); + HalpX86BiosInitialized = TRUE; + + // + // Attempt to initialize the display adapter by executing its ROM bios + // code. The standard ROM bios code address for PC video adapters is + // 0xC000:0000 on the ISA bus. + // + + State.Eax = (HalpVideoBus << 8) | + (HalpVideoDevice << 3) | + HalpVideoFunction; + + State.Ecx = 0; + State.Edx = 0; + State.Ebx = 0; + State.Ebp = 0; + State.Esi = 0; + State.Edi = 0; + + if (x86BiosInitializeAdapter(0xc0000, &State, HalpIoControlBase, HalpIoMemoryBase) != XM_SUCCESS) { + HalpEnableInt10Calls = FALSE; + return FALSE; + } + HalpEnableInt10Calls = TRUE; + + return TRUE; +} + + +VOID +HalpResetX86DisplayAdapter( + VOID + ) + +/*++ + +Routine Description: + + This function resets a display adapter using the x86 bios emulator. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + + XM86_CONTEXT Context; + + // + // Initialize the x86 bios context and make the INT 10 call to initialize + // the display adapter to 80x25 color text mode. + // + + Context.Eax = 0x0003; // Function 0, Mode 3 + Context.Ebx = 0; + Context.Ecx = 0; + Context.Edx = 0; + Context.Esi = 0; + Context.Edi = 0; + Context.Ebp = 0; + + HalCallBios(0x10, + &Context.Eax, + &Context.Ebx, + &Context.Ecx, + &Context.Edx, + &Context.Esi, + &Context.Edi, + &Context.Ebp); + + + return; +} + + +// +// This code came from ..\..\x86new\x86bios.c +// +#define LOW_MEMORY_SIZE 0x800 +extern UCHAR x86BiosLowMemory[LOW_MEMORY_SIZE + 3]; +extern ULONG x86BiosScratchMemory; +extern ULONG x86BiosIoMemory; +extern ULONG x86BiosIoSpace; + + +PVOID +x86BiosTranslateAddress ( + IN USHORT Segment, + IN USHORT Offset + ) + +/*++ + +Routine Description: + + This translates a segment/offset address into a memory address. + +Arguments: + + Segment - Supplies the segment register value. + + Offset - Supplies the offset within segment. + +Return Value: + + The memory address of the translated segment/offset pair is + returned as the function value. + +--*/ + +{ + + ULONG Value; + + // + // Compute the logical memory address and case on high hex digit of + // the resultant address. + // + + Value = Offset + (Segment << 4); + + Offset = (USHORT)(Value & 0xffff); + Value &= 0xf0000; + switch ((Value >> 16) & 0xf) { + + // + // Interrupt vector/stack space. + // + + case 0x0: + if (Offset > LOW_MEMORY_SIZE) { + x86BiosScratchMemory = 0; + return (PVOID)&x86BiosScratchMemory; + + } else { + return (PVOID)(&x86BiosLowMemory[0] + Offset); + } + + // + // The memory range from 0x10000 to 0x9ffff reads as zero + // and writes are ignored. + // + + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + case 0x8: + case 0x9: + x86BiosScratchMemory = 0; + return (PVOID)&x86BiosScratchMemory; + + // + // The memory range from 0xa0000 to 0xdffff maps to I/O memory. + // + + case 0xa: + case 0xb: + return (PVOID)(x86BiosIoMemory + Offset + Value); + + case 0xc: + case 0xd: + return (PVOID)(HalpRomBase + Offset); + + // + // The memory range from 0x10000 to 0x9ffff reads as zero + // and writes are ignored. + // + + case 0xe: + case 0xf: + x86BiosScratchMemory = 0; + return (PVOID)&x86BiosScratchMemory; + } + + // NOT REACHED - NOT EXECUTED - Prevents Compiler Warning. + return (PVOID)NULL; +} + + +VOID HalpCopyROMs(VOID) +{ + ULONG i; + PUCHAR ROM_Shadow; + + if (ROM_Buffer[0] == 0x55 && ROM_Buffer[1] == 0xAA) { + //DbgPrint("HalpCopyROMs: calling ExAllocatePool.\n"); + HalpRomBase = ROM_Shadow = ExAllocatePool(NonPagedPool, ROM_Length); + for (i=0; i> 8)); + WRITE_REGISTER_UCHAR(u.Byte + 2, (UCHAR)(Value >> 16)); + WRITE_REGISTER_UCHAR(u.Byte + 3, (UCHAR)(Value >> 24)); + + } else { + WRITE_REGISTER_ULONG(u.Long, Value); + } + } + } else { + if (((ULONG)u.Word & 0x1) != 0) { + WRITE_REGISTER_UCHAR(u.Byte + 0, (UCHAR)(Value)); + WRITE_REGISTER_UCHAR(u.Byte + 1, (UCHAR)(Value >> 8)); + + } else { + WRITE_REGISTER_USHORT(u.Word, (USHORT)Value); + } + } + + return; +} + +VOID +x86BiosInitializeBios ( + IN PVOID BiosIoSpace, + IN PVOID BiosIoMemory + ) + +/*++ + + Routine Description: + + This function initializes x86 BIOS emulation. + + Arguments: + + BiosIoSpace - Supplies the base address of the I/O space to be used + for BIOS emulation. + + BiosIoMemory - Supplies the base address of the I/O memory to be + used for BIOS emulation. + + Return Value: + + None. + + --*/ + +{ + + // + // Zero low memory. + // + + memset(&x86BiosLowMemory, 0, LOW_MEMORY_SIZE); + + // + // Save base address of I/O memory and I/O space. + // + + x86BiosIoSpace = (ULONG)BiosIoSpace; + x86BiosIoMemory = (ULONG)BiosIoMemory; + + // + // Initialize the emulator and the BIOS. + // + + XmInitializeEmulator(0, + LOW_MEMORY_SIZE, + x86BiosReadIoSpace, + x86BiosWriteIoSpace, + x86BiosTranslateAddress); + + x86BiosInitialized = TRUE; + return; +} + +XM_STATUS +x86BiosExecuteInterrupt ( + IN UCHAR Number, + IN OUT PXM86_CONTEXT Context, + IN PVOID BiosIoSpace OPTIONAL, + IN PVOID BiosIoMemory OPTIONAL + ) + +/*++ + + Routine Description: + + This function executes an interrupt by calling the x86 emulator. + + Arguments: + + Number - Supplies the number of the interrupt that is to be emulated. + + Context - Supplies a pointer to an x86 context structure. + + Return Value: + + The emulation completion status. + + --*/ + +{ + + XM_STATUS Status; + + // + // If a new base address is specified, then set the appropriate base. + // + + if (BiosIoSpace != NULL) { + x86BiosIoSpace = (ULONG)BiosIoSpace; + } + + if (BiosIoMemory != NULL) { + x86BiosIoMemory = (ULONG)BiosIoMemory; + } + + // + // Execute the specified interrupt. + // + + Status = XmEmulateInterrupt(Number, Context); + if (Status != XM_SUCCESS) { + DbgPrint("HAL: Interrupt emulation failed, status %lx\n", Status); + } + + return Status; +} + +XM_STATUS +x86BiosInitializeAdapter ( + IN ULONG Adapter, + IN OUT PXM86_CONTEXT Context OPTIONAL, + IN PVOID BiosIoSpace OPTIONAL, + IN PVOID BiosIoMemory OPTIONAL + ) + +/*++ + + Routine Description: + + This function initializes the adapter whose BIOS starts at the + specified 20-bit address. + + Arguments: + + Adpater - Supplies the 20-bit address of the BIOS for the adapter + to be initialized. + + Return Value: + + The emulation completion status. + + --*/ + +{ + + PUCHAR Byte; + XM86_CONTEXT State; + USHORT Offset; + USHORT Segment; + XM_STATUS Status; + + // + // If BIOS emulation has not been initialized, then return an error. + // + + if (x86BiosInitialized == FALSE) { + return XM_EMULATOR_NOT_INITIALIZED; + } + + // + // If an emulator context is not specified, then use a default + // context. + // + + if (ARGUMENT_PRESENT(Context) == FALSE) { + State.Eax = 0; + State.Ecx = 0; + State.Edx = 0; + State.Ebx = 0; + State.Ebp = 0; + State.Esi = 0; + State.Edi = 0; + Context = &State; + } + + // + // If a new base address is specified, then set the appropriate base. + // + + if (BiosIoSpace != NULL) { + x86BiosIoSpace = (ULONG)BiosIoSpace; + } + + if (BiosIoMemory != NULL) { + x86BiosIoMemory = (ULONG)BiosIoMemory; + } + + // + // If the specified adpater is not BIOS code, then return an error. + // + + Segment = (USHORT)((Adapter >> 4) & 0xf000); + Offset = (USHORT)(Adapter & 0xffff); + Byte = (PUCHAR)x86BiosTranslateAddress(Segment, Offset); + if ((*Byte++ != 0x55) || (*Byte != 0xaa)) { + return XM_ILLEGAL_CODE_SEGMENT; + } + + // + // Call the BIOS code to initialize the specified adapter. + // + + Adapter += 3; + Segment = (USHORT)((Adapter >> 4) & 0xf000); + Offset = (USHORT)(Adapter & 0xffff); + Status = XmEmulateFarCall(Segment, Offset, Context); + if (Status != XM_SUCCESS) { + DbgPrint("HAL: Adapter initialization falied, status %lx\n", Status); + } + + return Status; +} + diff --git a/private/ntos/nthals/halfire/ppc/x86bios.h b/private/ntos/nthals/halfire/ppc/x86bios.h new file mode 100644 index 000000000..fd5de89d4 --- /dev/null +++ b/private/ntos/nthals/halfire/ppc/x86bios.h @@ -0,0 +1,24 @@ +#ifndef _X86BIOS_H +#define _X86BIOS_H + +/* + * Copyright (c) 1995 FirePower Systems, Inc. + * DO NOT DISTRIBUTE without permission + * + * $RCSfile: x86bios.h $ + * $Revision: 1.6 $ + * $Date: 1996/01/11 07:14:34 $ + * $Locker: $ + */ + +#include "xm86.h" + + +VOID +HalpResetX86DisplayAdapter( + VOID + ); + +extern ULONG HalpEnableInt10Calls; + +#endif // _X86BIOS_H -- cgit v1.2.3