summaryrefslogtreecommitdiff
path: root/cpu/amd/geode_lx/gplvsa_ii/sysmgr/swapsif.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu/amd/geode_lx/gplvsa_ii/sysmgr/swapsif.c')
-rwxr-xr-xcpu/amd/geode_lx/gplvsa_ii/sysmgr/swapsif.c316
1 files changed, 316 insertions, 0 deletions
diff --git a/cpu/amd/geode_lx/gplvsa_ii/sysmgr/swapsif.c b/cpu/amd/geode_lx/gplvsa_ii/sysmgr/swapsif.c
new file mode 100755
index 0000000..c46409d
--- /dev/null
+++ b/cpu/amd/geode_lx/gplvsa_ii/sysmgr/swapsif.c
@@ -0,0 +1,316 @@
+/*
+* Copyright (c) 2006-2008 Advanced Micro Devices,Inc. ("AMD").
+*
+* This library is free software; you can redistribute it and/or modify
+* it under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of the
+* License, or (at your option) any later version.
+*
+* This code is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+
+* You should have received a copy of the GNU Lesser General
+* Public License along with this library; if not, write to the
+* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+* Boston, MA 02111-1307 USA
+*/
+
+//*****************************************************************************
+//* SWAPSiFs routines
+//*****************************************************************************
+
+
+
+#include "VSA2.H"
+#include "SYSMGR.H"
+#include "PROTOS.H"
+#include "VPCI.H"
+#include "PCI.H"
+
+
+// External Functions:
+extern void pascal Return_Virtual_Value(SmiHeader *, ULONG);
+
+
+// External Variables:
+extern PCI_HEADER_ENTRY ISA_Hdr[];
+extern DESCRIPTOR MSRs[];
+
+
+
+#define ACPI_FLAGS (0)
+#define ACPI_RANGE 0x20
+#define PMS_RANGE 0x80
+#define PMS_FLAGS (NOT_GLIU1)
+
+ULONG ACPI_Timer_MSR;
+
+
+//***********************************************************************
+// Enables/disables trapping of PMS or ACPI registers
+//***********************************************************************
+UCHAR pascal PM_Trapping(USHORT EnableFlag, USHORT Bar)
+{ ULONG DescrDefault[2];
+ UCHAR Link, i=0;
+ register DESCRIPTOR * Descr;
+
+ // For each linked item, update the associated MSR
+ Link = ISA_Hdr[Bar/4].Link;
+ while (Link) {
+ Descr = &MSRs[Link];
+
+ // Get link to next MSR
+ Link = Descr->Link;
+
+ // Ignore this MSR if not an I/O trap
+ if ((Descr->Flag & IO_TRAP) != IO_TRAP) {
+ continue;
+ }
+
+ if (EnableFlag) {
+ // Restore descriptor to original value (re-enable trapping)
+ Write_MSR(Descr->MsrAddr, Descr->MsrData);
+ } else {
+ i++;
+ // Set descriptor to default (disable trapping)
+ Get_Descriptor_Default(Descr->Type, DescrDefault);
+ Write_MSR(Descr->MsrAddr, DescrDefault);
+ }
+ }
+
+ return i;
+}
+
+
+//***********************************************************************
+// Enables/disables trapping of PM Support registers
+//***********************************************************************
+UCHAR pascal PMS_Trapping(USHORT EnableFlag)
+{
+ return PM_Trapping(EnableFlag, BAR4);
+}
+
+
+
+//***********************************************************************
+// Enables/disables trapping of ACPI registers
+//***********************************************************************
+UCHAR pascal ACPI_Trapping(USHORT EnableFlag)
+{
+ return PM_Trapping(EnableFlag, BAR5);
+}
+
+
+
+
+//***********************************************************************
+// Workaround for ACPI issues with A3 parts:
+// 1) Hang on byte accesses to ACPI registers 0x00-0x03
+// 2) Improper sharing of shadow register
+// Flag:
+// = 0 if PM Support registers
+// = 1 if ACPI registers
+//***********************************************************************
+void ACPI_Workaround(SmiHeader * SmiHdr, USHORT Flag)
+{ USHORT Address;
+ UCHAR Alignment, Size;
+ ULONG WriteToClearMask, Mask, Data, SrcData;
+ static ULONG WriteToClearMasks[] = {
+ 0xFFFF0000, // 00 PM1_STS
+ 0xFFFFFFFF, // 04 PM1_EN
+ 0xFFFFFDFF, // 08 PM1_CNT
+ 0xFFFFFFFF, // 0C PM2_CNT
+ 0xFFFFFFFF, // 10 PM_TMR
+ 0xFFFFFFFF, // 14 Reserved
+ 0x00000000, // 18 GPE0_STS
+ 0xFFFFFFFF, // 1C GPE0_EN
+ };
+
+
+ // Get info about the I/O from the SMM header
+ Data = SmiHdr->write_data;
+ Address = SmiHdr->IO_addr;
+ Size = (UCHAR)SmiHdr->data_size;
+
+ Alignment = (UCHAR)((Address & 3) << 3);
+ // Make Address dword-aligned
+ Address &= ~3;
+
+ if (Flag) {
+
+ // Get write-to-clear mask for ACPI registers
+ WriteToClearMask = WriteToClearMasks[(Address & 0x1F) >> 2];
+
+ // Disable I/O trapping
+ ACPI_Trapping(0);
+
+ } else {
+
+ // Get write-to-clear mask for PM Support registers
+ switch ((UCHAR)Address) {
+
+ case 0x00:
+ WriteToClearMask = 0xFFFF7FFF;
+ break;
+
+ case 0x54:
+ WriteToClearMask = 0xFFFF0000;
+ break;
+
+ default:
+ WriteToClearMask = 0xFFFFFFFF;
+ break;
+ }
+ // Disable I/O trapping
+ PMS_Trapping(0);
+
+ }
+
+
+ // Read initial value
+ SrcData = in_32(Address);
+
+ if (SmiHdr->SMI_Flags.IO_Write) {
+ // I/O WRITE
+
+ // Get mask appropriate to I/O size
+ switch (Size) {
+ case BYTE_IO:
+ Mask = 0x000000FF;
+ break;
+
+ case WORD_IO:
+ Mask = 0x0000FFFF;
+ break;
+
+ case DWORD_IO:
+ Mask = 0xFFFFFFFF;
+ break;
+ }
+
+
+ Data &= Mask;
+ Data <<= Alignment;
+ SrcData &= ~(Mask << Alignment);
+
+ // Write final data out; Don't rewrite write-to-clear bits
+ Data |= (SrcData & WriteToClearMask);
+ out_32(Address, Data);
+
+ } else {
+
+ // I/O READ
+ Data = (SrcData >> Alignment);
+
+ // Return value to the right environment
+ Return_Virtual_Value(SmiHdr, Data);
+ }
+
+ // Re-enable I/O trapping
+ if (Flag) {
+ ACPI_Trapping(1);
+ } else {
+ PMS_Trapping(1);
+ }
+}
+
+
+//***********************************************************************
+// An I/O BAR for devices in the MDD (e.g. PMS and ACPI) doesn't require
+// a GLIU descriptor since the MDD is the subtractive decode. Therefore,
+// if these registers are trapped, they are not linked to the BARs.
+// This function adds the linkages so when the BAR is changed, the
+// descriptor(s) generating the I/O trap are also changed.
+// NOTES:
+// 1) The descriptors must be linked in order of increasing address.
+// Increasing address does not imply increasing MSRs[] index, so the
+// search index starts over at 1 on an address hit.
+// 2) This function must handle the case where the BAR is of one size but
+// the trapped range is another (either longer or shorter).
+//***********************************************************************
+void pascal FixupLinkages(USHORT Bar)
+{ USHORT IO_Address;
+ UCHAR First = 0, Previous=0, Index;
+ register DESCRIPTOR * Descr;
+
+ IO_Address = ISA_Hdr[Bar/4].Value_LO;
+
+ // Walk through all the descriptors
+ for (Index=1; Index<MAX_DESCR ; Index++ ) {
+ Descr = &MSRs[Index];
+
+ // Only examine descriptors used for I/O traps
+ if ((Descr->Flag & (AVAILABLE | IO_TRAP)) != IO_TRAP) {
+ continue;
+ }
+ // Does this descriptor map the region covered by the BAR?
+ if (Descr->Address == IO_Address) {
+ // Yes
+ if (Previous) {
+ // Link it
+ MSRs[Previous].Link = Index;
+ } else {
+ First = Index;
+ }
+ Previous = Index;
+
+ // Mark it unavailable so we don't 'hit' again
+ Descr->Flag &= ~AVAILABLE;
+
+ // Advance the address
+ IO_Address += (USHORT)Descr->Range;
+
+ // Skip the ACPI timer register
+ if (Bar == BAR5) {
+ switch (IO_Address & (ACPI_RANGE-1)) {
+ case 0x10:
+ (UCHAR)IO_Address += 4;
+ break;
+ case 0x18:
+ // Record descriptor that skips ACPI timer
+ ACPI_Timer_MSR = Descr->MsrAddr;
+ break;
+ }
+ }
+ // Re-start search at beginning of MSR array
+ Index = 1;
+ }
+ }
+
+ if (First) {
+ // Re-link the 'expanded' list to the BAR's linkages
+ MSRs[Previous].Link = ISA_Hdr[Bar/4].Link;
+ ISA_Hdr[Bar/4].Link = First;
+ } else {
+ Log_Error("No links found by FixupLinkages()");
+ }
+}
+
+
+
+//***********************************************************************
+// Installs the trapping for ACPI and PMS register SWAPSiF
+//***********************************************************************
+void ACPI_PMS_SWAPSiF(void)
+{ USHORT IO_Address;
+
+ // Trap PMC registers (F0 BAR4)
+ IO_Address = ISA_Hdr[BAR4/4].IO_Base;
+ if (IO_Address) {
+ Register_Event(EVENT_IO_TRAP, 0, SysMgr_VSM, IO_Address, PMS_FLAGS | PMS_RANGE);
+ // Link the descriptors used for trapping the PMS registers
+ FixupLinkages(BAR4);
+ }
+
+ // Trap ACPI registers (F0 BAR5)
+ IO_Address = ISA_Hdr[BAR5/4].IO_Base;
+ if (IO_Address) {
+ Register_Event(EVENT_IO_TRAP, 0, SysMgr_VSM, IO_Address, ACPI_FLAGS | 0x10);
+ // Skip the ACPI Timer register
+ Register_Event(EVENT_IO_TRAP, 0, SysMgr_VSM, IO_Address+0x14, ACPI_FLAGS | 0x0C);
+ // Link the descriptors used for trapping the ACPI registers
+ FixupLinkages(BAR5);
+ }
+} \ No newline at end of file