firmware/coreboot: Subtree merged blobs

This commit is contained in:
David Hendricks
2018-06-14 15:16:35 -07:00
489 changed files with 97177 additions and 1 deletions

Submodule firmware/coreboot/3rdparty/blobs deleted from 78a02a7f9d

View File

@@ -0,0 +1,9 @@
This VSA is taken from
http://marcjonesconsulting.com/gplvsa/gpl_vsa_lx_102.bin.gz
and decompressed for simplicity. The original SHA1 was:
96a6097331278d644230eac4fc39bcfebc3c9a16 gpl_vsa_lx_102.bin.gz
While we have the source code (see gplvsa_ii), it requires a rather
esoteric build system. Should this be fixed, we could consider adding
VSA to the coreboot tree. Until then, source and binary can reside here.

View File

@@ -0,0 +1,27 @@
This is the VSA (Virtual Systems Architecture) code used on the AMD
Geode series of processors. The Geode, rather than carrying lots of
legacy hardware interfaces that are presumed to exist on x86 systems
that might be painful to implement on a highly integrated, low power
processor, the Geode often emulates such interfaces by use of software that is
invoked by special traps that take place when the processor accesses
these devices.
Note that the code here is not currently buildable on open source
systems, being only buildable using very obsolete and no longer
commercially availble Windows based commercial toolchains. On the
OLPC system, these "blobs" of binary code are concatenated together
with LinuxBIOS and the bootloader, and set up to be executed by
LinuxBIOS early in the Geode's initialization sequence (no linking is
involved).
If you are interested for some reason in making this code buildable on
free systems, please let us know of your progress. It is under the
GNU LGPL.
Also note that VESA emulation is *not* included in this (nor does what
we use on the OLPC machine use VESA at this date; we use frame
buffer code for our console); that code was not owned by AMD and
therefore not theirs to make available. Our thanks to AMD to making
the VSA code available.
Jim Gettys, OLPC, September 27, 2006

View File

@@ -0,0 +1,42 @@
#
# Copyright (c) 2006 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
#
VSMNAME = legacy
VSMDIR = $(VSA2ROOT)\$(VSMNAME)
all:
cd $(VSMDIR)
$(MAKE) /nologo all "VSA2ROOT=$(VSA2ROOT)" "USER=$(USER)" "BUILDOBJ=$(OBJECT)" "CPU=$(CPU)"
cd $(MAKEDIR)
clean:
cd $(VSMDIR)
$(MAKE) /nologo clean
cd $(MAKEDIR)
cleanlocal:
cd $(VSMDIR)
$(MAKE) /nologo cleanlocal
cd $(MAKEDIR)
cleanall:
cd $(VSMDIR)
$(MAKE) /nologo cleanall
cd $(MAKEDIR)

View File

@@ -0,0 +1,40 @@
# Copyright (c) 2007-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
VSMNAME = lxvg
VSMDIR = $(VSA2ROOT)\$(VSMNAME)
all:
cd $(VSMDIR)
$(MAKE) /nologo all "VSA2ROOT=$(VSA2ROOT)" "USER=$(USER)" "BUILDOBJ=$(OBJECT)" "CPU=$(CPU)"
cd $(MAKEDIR)
clean:
cd $(VSMDIR)
$(MAKE) /nologo clean
cd $(MAKEDIR)
cleanlocal:
cd $(VSMDIR)
$(MAKE) /nologo cleanlocal
cd $(MAKEDIR)
cleanall:
cd $(VSMDIR)
$(MAKE) /nologo cleanall
cd $(MAKEDIR)

View File

@@ -0,0 +1,99 @@
#
# Copyright (c) 2006 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
#
# makefile for VSA2
!ifndef VSA2ROOT
VSA2ROOT = $(MAKEDIR)\..
!endif
USER = $(VSA2ROOT)
OBJECT = $(MAKEDIR)\obj
.SUFFIXES:
.SUFFIXES : .exe .vsm .lib .bin .mak .cln
!include setvars.mak
VSMS = \
$(OBJECT)\sysmgr.vsm \
$(OBJECT)\vsainit.bin \
$(OBJECT)\legacy.vsm \
$(OBJECT)\lxvg.vsm
VSM_CLN0 = $(VSMS:.vsm=.cln)
VSM_CLN = $(VSM_CLN0:.bin=.cln)
#######################################################################
#
# Targets
#
#######################################################################
all: $(OBJECT) $(VSMS) basic
basic: setenv
@$(ECHO) Make LX VSA Image
$(MAKE) /nologo vsa_lx.bin
$(VSMS): setenv
vsa_lx.bin $(OBJECT)\amd_vsa_lx.bin: $(OBJECT)\vsainit.bin $(OBJECT)\vsa2.bin
@$(ECHO) Concatenate for LX Image ...
-$(BINCOPY) $(OBJECT)\vsainit.bin+$(OBJECT)\vsa2.bin+$(OBJECT)\lxvg.vsm $(OBJECT)\amd_vsa_lx.bin
vsa2.bin $(OBJECT)\vsa2.bin: $(OBJECT)\sysmgr.vsm $(OBJECT)\legacy.vsm
@$(ECHO) Concatenate for VSA2.BIN Image ...
-$(BINCOPY) $(OBJECT)\sysmgr.vsm+$(OBJECT)\legacy.vsm $(OBJECT)\vsa2.bin
#This and only this clean target must exist as it is called by cleanall
#cleanall and cleanlocal are defined in rules.mak
clean: cleanlocal cleanlib $(VSM_CLN) tools_clean
$(OBJECT):
-@md $(OBJECT)
############################################
# Tools.lib
############################################
tools_clean:
-@cd $(VSA2ROOT)\vsm_lib
-@$(MAKE) /nologo cleanall
-@cd $(MAKEDIR)
###########################################################################
# All VSMs
###########################################################################
{$(MAKEDIR)}.mak{$(OBJECT)}.vsm:
$(MAKE) /nologo -f $(MAKEDIR)\%|fF.mak "VSA2ROOT=$(VSA2ROOT)" "USER=$(VSA2ROOT)" "OBJECT=$(OBJECT)" "CPU=$(CPU)"
{$(MAKEDIR)}.mak{$(OBJECT)}.bin:
$(MAKE) /nologo -f $(MAKEDIR)\%|fF.mak "VSA2ROOT=$(VSA2ROOT)" "USER=$(VSA2ROOT)" "OBJECT=$(OBJECT)" "CPU=$(CPU)"
{$(MAKEDIR)}.mak{$(OBJECT)}.cln:
-@$(MAKE) /nologo -f $(MAKEDIR)\%|fF.mak cleanall "VSA2ROOT=$(VSA2ROOT)" "USER=$(VSA2ROOT)"
!include rules.mak

View File

@@ -0,0 +1,138 @@
#
# Copyright (c) 2006 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
#
##############################################################################
#
# Common targets
#
##############################################################################
setenv:
!if "$(VARS_SET)" != "VSA_II"
@$(SETENV) PATH=.\;$(VSA2ROOT)\uti;$(PATH);
@$(SETENV) Lib=.\;$(VSA2ROOT)\lib;$(VSA2ROOT)\build;$(LIB);
@$(SETENV) VARS_SET=VSA_II
!endif
@echo INCLUDE=$(INCLUDE)
$(BUILD_DIR)\obj\$(TOOL_LIB):
cd $(VSA2ROOT)\vsm_lib
$(MAKE) /nologo all "BUILDOBJ=$(OBJECT)" "CPU=$(CPU)"
cd $(MAKEDIR)
cleanlib:
cd $(VSA2ROOT)\vsm_lib
$(MAKE) /nologo cleanall
cd $(MAKEDIR)
cleanlocal:
-@IF EXIST $(OBJECT)\*.def $(DEL) $(OBJECT)\*.def
-@IF EXIST $(OBJECT)\*.lnk $(DEL) $(OBJECT)\*.lnk
-@IF EXIST $(OBJECT)\*.map $(DEL) $(OBJECT)\*.map
-@IF EXIST $(OBJECT)\*.obj $(DEL) $(OBJECT)\*.obj
-@IF EXIST $(OBJECT)\*.exe $(DEL) $(OBJECT)\*.exe
-@IF EXIST $(OBJECT)\*.rom $(DEL) $(OBJECT)\*.rom
-@IF EXIST $(OBJECT)\*.cpu $(DEL) $(OBJECT)\*.cpu
-@IF EXIST $(OBJECT)\*.scc $(DEL) $(OBJECT)\*.scc
-@IF EXIST $(OBJECT)\*.inc $(DEL) $(OBJECT)\*.inc
-@IF EXIST $(OBJECT)\*.h $(DEL) $(OBJECT)\*.h
-@IF EXIST $(OBJECT)\*.lst $(DEL) $(OBJECT)\*.lst
-@IF EXIST $(OBJECT)\*.bak $(DEL) $(OBJECT)\*.bak
-@IF EXIST $(OBJECT)\*.mac $(DEL) $(OBJECT)\*.mac
-@IF EXIST $(OBJECT)\*.asm $(DEL) $(OBJECT)\*.asm
-@IF EXIST $(OBJECT)\*.cod $(DEL) $(OBJECT)\*.cod
-@IF EXIST $(MAKEDIR)\*.map $(DEL) $(MAKEDIR)\*.map
-@IF EXIST $(MAKEDIR)\arccode.h $(DEL) $(MAKEDIR)\arccode.h
cleanall: clean
-@IF EXIST $(MAKEDIR)\*.vsm $(DEL) $(MAKEDIR)\*.vsm
-@IF EXIST $(OBJECT)\*.vsm $(DEL) $(OBJECT)\*.vsm
-@IF EXIST $(OBJECT)\*.bin $(DEL) $(OBJECT)\*.bin
-@IF EXIST $(OBJECT)\*.lib $(DEL) $(OBJECT)\*.lib
-@IF EXIST $(OBJECT) rd $(OBJECT)
##############################################################################
#
# Common inference rules
#
##############################################################################
{$(INC_DIR)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /C $<
{$(INC_DIR)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /C $<
{$(SYSMGR_SRC)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /C $<
{$(SYSMGR_SRC)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /C $<
{$(MAKEDIR)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /C $<
{$(MAKEDIR)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /C $<
{$(INC_DIR)}.h{$(OBJECT)}.h:
$(COPY) $< $@
{$(INC_DIR)\$(CPU)}.h{$(OBJECT)}.h:
$(COPY) $< $@
{$(SYSMGR_SRC)}.h{$(OBJECT)}.h:
$(COPY) $< $@
{$(SYSMGR_SRC)\$(CPU)}.h{$(OBJECT)}.h:
$(COPY) $< $@
{$(MAKEDIR)}.h{$(OBJECT)}.h:
$(COPY) $< $@
{$(MAKEDIR)\$(CPU)}.h{$(OBJECT)}.h:
$(COPY) $< $@
{$(MAKEDIR)}.inc{$(OBJECT)}.inc:
$(COPY) $< $@
{$(MAKEDIR)\$(CPU)}.inc{$(OBJECT)}.inc:
$(COPY) $< $@
{$(MAKEDIR)}.c{$(OBJECT)}.obj:
$(CC) /nologo $(CC_OPTS) /Fo$@ $<
{$(MAKEDIR)\$(CPU)}.c{$(OBJECT)}.obj:
$(CC) /nologo $(CC_OPTS) /Fo$@ $<
{$(MAKEDIR)}.asm{$(OBJECT)}.obj:
$(AS) /nologo $(AS_OPTS) /Fo$@ $<
{$(MAKEDIR)\$(CPU)}.asm{$(OBJECT)}.obj:
$(AS) /nologo $(AS_OPTS) /Fo$@ $<
{$(SYSMGR_SRC)}.mac{$(OBJECT)}.mac:
$(COPY) $< $@
{$(SYSMGR_SRC)\$(CPU)}.mac{$(OBJECT)}.mac:
$(COPY) $< $@

View File

@@ -0,0 +1,65 @@
#
# Copyright (c) 2006 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
#
##############################################################################
#
# Directories
#
##############################################################################
BUILD_DIR = $(VSA2ROOT)\build
SYSMGR_SRC = $(VSA2ROOT)\sysmgr
VSMUTILS_SRC = $(VSA2ROOT)\vsm_lib
LEGACY_SRC = $(VSA2ROOT)\legacy
INC_DIR = $(VSA2ROOT)\inc
H_DIR = $(VSA2ROOT)\sysmgr
SHELL =
##############################################################################
#
# Tools / Options for tools
#
##############################################################################
ECHO = echo
COPY = copy
BINCOPY = copy /b
MOVE = move
DEL = del
REN = ren
SETENV = set
CD = cd
AS = ml
CC = cl
H2 = h2inc
LN = link
LB = lib
X2ROM = exe2bin
AS_OPTS = /c /Cx /Sa /W3 $(ALIST) /I$(OBJECT)
CC_OPTS = /c /AT /Gs /FPi87 /G3fsy /W3 /Fc$(OBJECT)\ /I$(OBJECT) $(COPTS_OPT) $(CLIST)
COPTS_OPT = /Ow /W3
LOPTS_OPT = /NONULLS /nologo /MAP
LOPTS_SYS = /MAP /TINY /nologo
LOPTS_VSM = /MAP /TINY /nologo
TOOL_LIB = tools.lib
HEAD_LIB = header.lib

View File

@@ -0,0 +1,42 @@
#
# Copyright (c) 2006 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
#
VSMNAME = sysmgr
VSMDIR = $(VSA2ROOT)\$(VSMNAME)
all:
cd $(VSMDIR)
$(MAKE) /nologo all "VSA2ROOT=$(VSA2ROOT)" "USER=$(USER)" "BUILDOBJ=$(OBJECT)" "CPU=$(CPU)"
cd $(MAKEDIR)
clean:
cd $(VSMDIR)
$(MAKE) /nologo clean
cd $(MAKEDIR)
cleanlocal:
cd $(VSMDIR)
$(MAKE) /nologo cleanlocal
cd $(MAKEDIR)
cleanall:
cd $(VSMDIR)
$(MAKE) /nologo cleanall
cd $(MAKEDIR)

View File

@@ -0,0 +1,42 @@
#
# Copyright (c) 2006 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
#
VSMNAME = vsainit
VSMDIR = $(VSA2ROOT)\sysmgr
all:
cd $(VSMDIR)
$(MAKE) /nologo all "VSA2ROOT=$(VSA2ROOT)" "USER=$(USER)" "BUILDOBJ=$(OBJECT)" "CPU=$(CPU)"
cd $(MAKEDIR)
clean:
cd $(VSMDIR)
$(MAKE) /nologo clean
cd $(MAKEDIR)
cleanlocal:
cd $(VSMDIR)
$(MAKE) /nologo cleanlocal
cd $(MAKEDIR)
cleanall:
cd $(VSMDIR)
$(MAKE) /nologo cleanall
cd $(MAKEDIR)

View File

@@ -0,0 +1,249 @@
/*
* 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
*/
//*********************************************************
// Private messages used between ACPI VSM and PMCORE VSM **
//*********************************************************
#define PMSG_GOTO_SLEEP 0x70
#define PMSG_BLINK_LED 0x71
/* device power states */
#define D0_STATE (0)
#define D1_STATE (1)
#define D2_STATE (2)
#define D3_STATE (3)
/**************************************************************
* smi_cmd Definitions
* These values must match the corresponding values in ACPI
* FADT. OS writes these values to SMI_CMD I/O location.
****************************************************************/
#define ACPI_ENABLE (0xA1)
#define ACPI_DISABLE (0xA2)
#define S4BIOS_REQ (0xA3)
// Bitmap of IRQ's PM VSM can map SCI to
#define ALLOWED_SCI_IRQ (0x0E20) // 11,10,9,5
#define DEFAULT_SCI_IRQ (9)
/**************************************************************
* PM1_STS bit definitions
****************************************************************/
#define WAKE_STS (0x8000)
#define RTC_STS (0x0400)
#define SLPBTN_STS (0x0200)
#define PWRBTN_STS (0x0100)
#define GBL_STS (0x0020)
#define BM_STATUS (0x0010)
#define TMR_STS (0x0001)
#define PM1_STS_CLR (0x8731)
/**************************************************************
* PM1_EN bit definitions
****************************************************************/
#define RTC_EN (0x0400)
#define SLPBTN_EN (0x0200)
#define PWRBTN_EN (0x0100)
#define GBL_EN (0x0020)
#define TMR_EN (0x0001)
/**************************************************************
* PM1_CNT bit definitions
****************************************************************/
#define SLP_EN (0x2000)
#define SLP_ENB (0x20)
#define SLP_TYPx_MASK (0x1C00) // mask for setting SLP_TYPx
#define SLP_TYPx_MASKB (0x1C)
#define SLP_TYPx_SHFT (10)
#define SLP_TYPx_SHFTB (2)
#define GBL_RLS (0x0004)
#define BM_RLD (0x0002)
#define SCI_EN (0x0001)
#define ACPI_S0 (0)
#define ACPI_S1 (1)
#define ACPI_S1_CLKOFF (0x81)
#define ACPI_S2 (2)
#define ACPI_S3 (3)
#define ACPI_S4 (4)
#define ACPI_S5 (5)
/**************************************************************
* PM2_CNT bit definitions
**************************************************************/
#define ARB_DIS (0x0001)
/**************************************************************
* P_CNT bit definitions
****************************************************************/
#define CLK_VAL_MASK (0x0000000F)
#define CLK_VAL_OFFSET (0)
#define CLK_VAL_WIDTH (4)
#define THT_EN (0x00000010)
/********************************************************************
* FACS
********************************************************************/
#define FACS_SIG_OFS (0x00)
#define FACS_LEN_OFS (0x04)
#define FACS_HWSIG_OFS (0x08)
#define FACS_OSWV_OFS (0x0C)
#define FACS_GBLOCK_OFS (0x10)
#define FACS_GBL_OWNED (0x02)
#define FACS_GBL_PENDING (0x01)
#define FACS_FLAGS_OFS (0x14)
/********************************************************************
* CS5536 PM stuff
********************************************************************/
#define YIG_SCI (5) // Y Interrupt Group 5 is all SCI sources
#define MSR_SYS_RESET (0x0014) // 5536 GLCP SYS_RESET MSR
// default location of PMC regs
#define PMC5536_BASE (0x9D00)
// default location of ACPI regs (32 bytes)
#define ACPI5536_BASE (0x9C00)
#define PM1_STS_OFS (0x00)
#define PM1_EN_OFS (0x02)
#define PM1_CNT_OFS (0x08)
#define PM2_CNT_OFS (0x0C)
#define PM_TMR_OFS (0x10)
#define GPE0_STS_OFS (0x18)
#define GPE0_EN_OFS (0x1C)
// Virtualized ACPI registers, these offsets were picked to provide
// minimal overlap of misaligned accesses.
// Note: PM1_STS/EN and GPE0_STS/EN must be back-to-back AND
// PM1_STS and PM1_EN must be 16-bit only.
#define VACPI_TRAP_BASE 0x9C20
#define VACPI_TRAP_LEN (32)
#define VPM1_STS_OFS (0x00)
#define VPM1_EN_OFS (0x02)
#define VPM1_CNT_OFS (0x08)
#define VGPE0_STS_OFS (0x10)
#define VGPE0_EN_OFS (0x14)
#define VACPI_ENABLE (0x1C)
// 5536 GPIO13 AUX1_IN is dedicated to Sleep Button. It's controlled
// by SLPB_STS in PM1_STS and SLPB_EN in PM1_EN.
// Unfortunately, GPIO13 is in Working Power Domain so it is useless as
// a wake event for anything other than S1.
#define DFLT_5536_SLPB_GPIO (13)
// Bit[9] of PM1_CNT, ignored bit in ACPI spec. On 5536 this bit indicates
// software has written a 1 to GBL_RLS(bit[2]) of PM1_CNT. Bit[9] can be cleared
// by writing a 1 to it.
#define GBL_RLS_FLAG (0x0200)
// Bit[11] of PM1_STS, ignored bit in ACPI spec. On 5536 writing this bit=1 causes
// GBL_STS(bit[5]) to be set to 1. Bit[11] always reads as 0.
#define SET_GBL_STS (0x0800)
// 5536 specific bits in ACPI GPE0_STS & GPE0_EN
#define GPE0_PIC_INT (0x00000001L)
#define GPE0_PIC_ASMI (0x00000002L)
#define GPE0_SMB (0x00000004L)
#define GPE0_UART1 (0x00000008L)
#define GPE0_UART2 (0x00000010L)
#define GPE0_USB1 (0x00000020L)
#define GPE0_USB2 (0x00000040L)
#define GPE0_PME0 (0x00010000L)
#define GPE0_PME1 (0x00020000L)
#define GPE0_PME2 (0x00040000L)
#define GPE0_PME3 (0x00080000L)
#define GPE0_PME4 (0x00100000L)
#define GPE0_PME5 (0x00200000L)
#define GPE0_PME6 (0x40000000L)
#define GPE0_PME7 (0x80000000L)
/*##
*## ACPI Indicator Designations
*##
*/
#define LED_OFF 0x00 // LED turned off
#define LED_SLOW 0x01 // 1/4Hz rate (4 second cycle time), 50% duty cycle
#define LED_FAST 0x02 // 1Hz rate (1 second cycle time), 50% duty cycle
#define LED_ON 0x03 // LED always on
#define NO_LED 0x00 // No LEDs here
//#define MB_LED0 0x01 // The motherboard LED 0 bit mask
//#define MB_LED1 0x02 // The motherboard LED 1 bit mask
//#define MB_LED2 0x04 // The motherboard LED 2 bit mask
//#define MB_LED3 0x08 // The motherboard LED 3 bit mask
#define MB_LEDALL 0x0F // The all motherboard LEDs bit mask
//#define SIO_LED0 0x10 // The SIO LED 0 bit mask
//#define SIO_LED1 0x20 // The SIO LED 1 bit mask
//#define SIO_LED2 0x40 // The SIO LED 2 bit mask
//#define SIO_LED3 0x80 // The SIO LED 3 bit mask
#define SIO_LEDALL 0xF0 // The SIO LEDs are in the upper nibble
//The LEDS used to indicate sleep/wake
#define INDICATOR_SLEEP 0x11
/*
* table indexes for gx2/lx msrs
* (This may be moved *)
*/
// Northbridge
#define IDX_GLIU0 (0)
#define IDX_MC (1)
#define IDX_GLIU1 (2)
#define IDX_VG (3)
#define IDX_GP (4)
#define IDX_DF (5)
#define IDX_GLCP (6)
#define IDX_GLPCI (7)
#define IDX_FG (8)
#define IDX_CPU (9)
#define IDX_VIP (10)
#define IDX_AES (11)
// Southbridge
#define IDX_SB_GLPCI (12)
#define IDX_SB_GLIU (13)
#define IDX_SB_USB2 (14)
#define IDX_SB_ATA (15)
#define IDX_SB_MDD (16)
#define IDX_SB_AC97 (17)
#define IDX_SB_USB1 (18)
#define IDX_SB_GLCP (19)
#define NUM_DEVS (IDX_SB_GLCP+1)
// definitions for callbacks for PM functions
#define PM_CALLBACK 0xBD50
#define PM_CB_LED 0x00
#define PM_CB_PME 0x01
#define PM_CB_PME_DISARM 0x00
#define PM_CB_PME_ARM 0x01
#define PM_CB_SLEEP 0x02
#define PM_CB_ENTER_S3 0x00
#define PM_CB_ENTER_SLEEP 0x01
#define PM_CB_LEAVE_SLEEP 0x02
#define PM_CB_DONE_S3 0x03

View File

@@ -0,0 +1,374 @@
/*
* 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
*/
#define VENDOR_ID_COMPAQ 0x0E11
#define VENDOR_ID_CYRIX 0x1078
#define VENDOR_ID_NATIONAL 0x100B
#define VENDOR_ID_AMD 0x1022
#define DEVICE_ID_MEDIAGX 0x0001
#define DEVICE_ID_5530 0x0100
#define DEVICE_ID_GX2 0x0028
#define DEVICE_ID_GFX2 0x0030
#define DEVICE_ID_5535 0x002B
#define DEVICE_ID_FLASH 0x002C
#define DEVICE_ID_ATA 0x002D
#define DEVICE_ID_AUDIO 0x002E
#define DEVICE_ID_OHCI 0x002F
#define DEVICE_ID_LX 0x2080
#define DEVICE_ID_GFX3 0x2081
#define DEVICE_ID_AES 0x2082
#define DEVICE_ID_5536 0x2090
#define DEVICE_ID_AMD_FLASH 0x2091
#define DEVICE_ID_AMD_ATA 0x2092
#define DEVICE_ID_AMD_AUDIO 0x2093
#define DEVICE_ID_AMD_OHCI 0x2094
#define DEVICE_ID_AMD_EHCI 0x2095
#define DEVICE_ID_AMD_UDC 0x2096
#define DEVICE_ID_AMD_OTG 0x2097
#define DEVICE_ID_AMD_THOR 0x209A
#define LEGACY_FUNCTION 0x0000
#define PM_FUNCTION 0x0100
#define IDE_FUNCTION 0x0200
#define AUDIO_FUNCTION 0x0300
#define VIDEO_FUNCTION 0x0400
#define XBUS_FUNCTION 0x0500
// SMI sources relative to Function 1 BAR0
#define SMI_STATUS_RO 0x0000
#define SMI_STATUS 0x0002
#define SMI_SRC_PM (1L << 0)
#define SMI_SRC_AUDIO_INDEX 1
#define SMI_SRC_AUDIO (1L << SMI_SRC_AUDIO_INDEX)
#define SMI_SRC_ACPI (1L << 2)
#define SMI_SRC_VG (1L << 3)
#define SMI_SRC_INT_MEMORY (1L << 4)
#define SMI_SRC_RETRACE (1L << 5)
#define SMI_SRC_VGA_TIMER (1L << 6)
#define SMI_SRC_A20_INDEX 7
#define SMI_SRC_A20 (1L << SMI_SRC_A20_INDEX)
#define SMI_SRC_SW_INDEX 8
#define SMI_SRC_SW (1L << SMI_SRC_SW_INDEX)
#define GTT_INDEX 9
#define SMI_SRC_GTT (1L << GTT_INDEX)
#define SMI_SRC_DEBUG (1L << 10)
#define SMI_SRC_MFGPT (1L << 11)
#define SMI_SRC_NMI (1L << 12)
#define SMI_SRC_RESET (1L << 13)
#define SMI_SRC_USB1 (1L << 14)
#define SMI_SRC_USB2 (1L << 15)
#define SMI_IGNORE 0x7FFF
#define GTT_STATUS 0x0006
// NOTE: The following source definitions are shifted left 16 bits because
// Get_SMI_Sources passes them that way in the SMI_Sources variable.
#define GTT_SRC_GT1 (1L << ( 0+16))
#define GTT_SRC_GT2 (1L << ( 1+16))
#define GTT_SRC_USR_DEF_TRAP1 (1L << ( 2+16))
#define GTT_SRC_USR_DEF_TRAP2 (1L << ( 3+16))
#define GTT_SRC_USR_DEF_TRAP3 (1L << ( 4+16))
#define SMI_SRC_PCI_TRAP (1L << ( 5+16))
#define GTT_SRC_1MS_TMR (1L << ( 6+16))
#define GTT_SRC_1SEC_TMR (1L << ( 7+16))
#define SMI_SRC_MPCI (1L << ( 8+16)) // Virtualized PCI access
#define SMI_SRC_DESCR_HIT (1L << ( 9+16)) // Hit on MBus descriptor
#define SMI_SRC_STAT (1L << (10+16)) // Hit on MBus statistics counter
#define SMI_SRC_PIC (1L << (11+16)) // PIC event
#define SMI_SRC_KEL (1L << (12+16)) // KEL event
#define SMI_SRC_PME (1L << (13+16)) // PME event
#define SMI_SRC_BLOCKIO (1L << (14+16)) // BLOCKIO event
#define SMI_SPEEDUP_DISABLE 0x0008
#define AUDIO_STATUS 0x0010 // relative to F3 BAR0
//############################################################################################
#define PCI_CFG_CONTROL 0x40
#define LEGACY_CFG_SMI (1L << 8)
#define PM_CFG_SMI (1L << 11)
#define IDE_CFG_SMI (1L << 14)
#define AUDIO_CFG_SMI (1L << 16)
#define VIDEO_CFG_SMI (1L << 17)
#define USB_PM_SMI (1L << 22)
#define USB_CFG_SMI (1L << 23)
#define USB_ENABLE (1L << 24)
#define PM_CFG_SMI_SCxxxx (1L << 9)
#define IDE_CFG_SMI_SCxxxx (1L << 10)
#define AUDIO_CFG_SMI_SCxxxx (1L << 11)
#define VIDEO_CFG_SMI_SCxxxx (1L << 12)
#define XBUS_CFG_SMI_SCxxxx (1L << 13)
#define RESET_CONTROL 0x44
#define X_BUS_WARM_START (1L << 0)
#define PCI_RESET (1L << 1)
#define IDE_RESET (1L << 2)
#define IDE_CONTROLLER_RESET (1L << 3)
#define AC97_RESET (1L << 7)
#define ROM_AT_LOGIC 0x52
#define LOWER_ROM_ENABLE (1 << 0)
#define ROM_WRITE_ENABLE (1 << 1)
#define ROM_1MB_WRITE_ENABLE (1 << 2)
#define PORT_92_ENABLE (1 << 3)
#define A20M_DEASSERT (1 << 4)
#define GAMEPORT_CS_ON_READS (1 << 5)
#define GAMEPORT_CS_ON_WRITES (1 << 6)
#define FAST_KEYBOARD_DISABLE (1 << 7)
#define CPU_SUPPORT 0x53
#define A20M_ENABLE (1 << 0)
#define RTC_ENABLE (1 << 2)
#define GAMEPORT_ENABLE (1 << 3)
#define DECODE_CONTROL 0x5A
#define RTC_POSITIVE_DECODE (1 << 0)
#define KBD_POSITIVE_DECODE (1 << 1)
#define COM1_POSITIVE_DECODE (1 << 2)
#define COM2_POSITIVE_DECODE (1 << 3)
#define COM3_POSITIVE_DECODE (1 << 4)
#define COM4_POSITIVE_DECODE (1 << 5)
#define FLPY1_POSITIVE_DECODE (1 << 6)
#define FLPY2_POSITIVE_DECODE (1 << 7)
#define LPT1_POSITIVE_DECODE (1 << 8)
#define LPT2_POSITIVE_DECODE (1 << 9)
#define LPT3_POSITIVE_DECODE (1 << 10)
#define IDE1_POSITIVE_DECODE (1 << 11)
#define IDE2_POSITIVE_DECODE (1 << 12)
#define ROM_POSITIVE_DECODE (1 << 13)
#define KBD_6X_DECODE (1 << 15)
#define PCI_STEERING 0x5C
// Top-level SMI enables (registers 0x80-0x83)
#define ENABLE_TRAPS_TIMERS 0x80
#define ENABLE_PM (1L << 0)
#define ENABLE_TIMERS (1L << 1)
#define ENABLE_TRAPS (1L << 2)
#define ENABLE_IRQ_SPEEDUP (1L << 3)
#define ENABLE_VIDEO_SPEEDUP (1L << 4)
#define ENABLE_CODEC_SMI (1L << 5)
#define ENABLE_RESERVED1 (1L << 6)
#define ENABLE_RESERVED2 (1L << 7)
#define ENABLE_HDD0_TIMER (1L << 8)
#define ENABLE_FDD_TIMER (1L << 9)
#define ENABLE_PAR_SER_TIMER (1L << 10)
#define ENABLE_KYBD_MOUSE_TIMER (1L << 11)
#define ENABLE_USR_DEF_TIMER1 (1L << 12)
#define ENABLE_USR_DEF_TIMER2 (1L << 13)
#define ENABLE_USR_DEF_TIMER3 (1L << 14)
#define ENABLE_VIDEO_TIMER (1L << 15)
#define ENABLE_HDD0_TRAP (1L << 16)
#define ENABLE_FDD_TRAP (1L << 17)
#define ENABLE_PAR_SER_TRAP (1L << 18)
#define ENABLE_KYBD_MOUSE_TRAP (1L << 19)
#define ENABLE_USR_DEF_TRAP1 (1L << 20)
#define ENABLE_USR_DEF_TRAP2 (1L << 21)
#define ENABLE_USR_DEF_TRAP3 (1L << 22)
#define ENABLE_VIDEO_TRAP (1L << 23)
#define ENABLE_GT1 (1L << 24)
#define ENABLE_GT2 (1L << 25)
#define ENABLE_RETRACE (1L << 26)
#define ENABLE_VGA_TIMER (1L << 27)
#define ENABLE_THERMAL (1L << 28) // SCxxxx only
#define ENABLE_ACPI_TIMER (1L << 29)
#define ENABLE_HDD1_TRAP (1L << 30)
#define ENABLE_HDD1_TIMER (1L << 31)
#define GT1_COUNT 0x88
#define GT1_CONTROL 0x89
#define GT1_RESET_HDD (1 << 0)
#define GT1_RESET_FDD (1 << 1)
#define GT1_RESET_PARALLEL_SERIAL (1 << 2)
#define GT1_RESET_KEYBD_MOUSE (1 << 3)
#define GT1_RESET_USR_DEF1 (1 << 4)
#define GT1_RESET_USR_DEF2 (1 << 5)
#define GT1_RESET_USR_DEF3 (1 << 6)
#define GT1_TIMEBASE (1 << 7)
#define GT2_COUNT 0x8A
#define GT2_CONTROL 0x8B
#define GT2_RESET_GPIO7 (1 << 2)
#define GT2_TIMEBASE (1 << 3) // 0=second 1=ms
#define GT1_SHIFT (1 << 4) // 0=8 bit 1=16 bit
#define GT2_SHIFT (1 << 5) // 0=8 bit 1=16 bit
#define VGA_TIMEBASE (1 << 6) // 0=ms 1=32 us
#define GT1_RESET_SEC_HDD (1 << 7) // 0=disable 1=enable
#define IRQ_SPEEDUP_COUNT 0x8C
#define VIDEO_SPEEDUP_COUNT 0x8D
#define VGA_TIMER_LOAD_COUNT 0x8E
#define GPIO_DIRECTION 0x90
#define GPIO_DATA 0x91
#define GPIO_CONTROL 0x92
#define GPIO0_ENABLE (1 << 0)
#define GPIO1_ENABLE (1 << 1)
#define GPIO2_ENABLE (1 << 2)
#define GPIO0_EDGE (1 << 3)
#define GPIO1_EDGE (1 << 4)
#define GPIO2_EDGE (1 << 5)
#define GPIO6_ENABLE (1 << 6)
#define GPIO6_EDGE (0 << 6)
#define GPIO7_EDGE (1 << 7)
#define MISCELLANEOUS 0x93
#define SERIAL_MOUSE_SELECT (1 << 0)
#define SERIAL_MOUSE (1 << 1)
#define HDD1_PARTIAL_DECODE (1 << 4)
#define HDD0_PARTIAL_DECODE (1 << 5)
#define HDD_SELECT (1 << 6)
#define FDD_SELECT (1 << 7)
#define SUSPEND_MODULATION_OFF 0x94
#define SUSPEND_MODULATION_ON 0x95
#define SUSPEND_CONFIGURATION 0x96
#define SUSPEND_MOD_ENABLE (1 << 0)
#define SMI_SPEEDUP (1 << 1)
#define SUSPEND_MODE (1 << 2)
#define GPIO_CONTROL2 0x97
#define GPIO3_ENABLE (1 << 0)
#define GPIO4_ENABLE (1 << 1)
#define GPIO5_ENABLE (1 << 2)
#define GPIO7_ENABLE (1 << 3)
#define GPIO3_EDGE (1 << 4)
#define GPIO4_EDGE (1 << 5)
#define GPIO5_EDGE (1 << 6)
#define GPIO7_EDGE (1 << 7)
#define HDD_IDLE_TIMEOUT 0x98
#define FDD_IDLE_TIMEOUT 0x9A
#define PAR_SER_IDLE_TIMEOUT 0x9C
#define KYBD_MOUSE_IDLE_TIMEOUT 0x9E
#define USR_DEF1_IDLE_TIMEOUT 0xA0
#define USR_DEF2_IDLE_TIMEOUT 0xA2
#define USR_DEF3_IDLE_TIMEOUT 0xA4
#define VIDEO_IDLE_TIMEOUT 0xA6
#define SEC_HDD_TIMEOUT 0xAC
#define CPU_SUSPEND_COMMAND 0xAE
#define CPU_STOP_CLOCK_COMMAND 0xAF
#define CPU_CACHE_MISS_ACTIVITY 0xB0
#define CPU_CACHE_MISS_INACTIVITY 0xB1
#define CPU_CACHE_MISS_THRESHOLD 0xB2
#define FLOPPY_SHADOW 0xB4
#define FLOPPY_3F2 0xB4
#define FLOPPY_3F7 0xB5
#define FLOPPY_372 0xB6
#define FLOPPY_377 0xB7
#define DMA_SHADOW 0xB8
#define DMA_SHADOW_CNT 10
#define PIC_SHADOW 0xB9
#define PIC_SHADOW_CNT 12
#define PIT_SHADOW 0xBA
#define PIT_SHADOW_CNT 9
#define RTC_SHADOW 0xBB
#define RTC_SHADOW_CNT 1
#define PIC_SHADOW 0xB9
#define PIT_SHADOW 0xBA
#define RTC_SHADOW 0xBB
#define CLOCK_STOP_CONTROL 0xBC
#define USR_DEF_1_BASE 0xC0
#define USR_DEF_2_BASE 0xC4
#define USR_DEF_3_BASE 0xC8
#define USR_DEF_1_CONTROL 0xCC
#define USR_DEF_2_CONTROL 0xCD
#define USR_DEF_3_CONTROL 0xCE
#define USR_DEF_MEMORY (1 << 7) // Bit 7 = 1
#define USR_DEF_IO (0 << 7) // Bit 7 = 0
#define USR_DEF_WRITE (1 << 6) // Bit 6 = 1 (only for I/O)
#define USR_DEF_READ (1 << 5) // Bit 5 = 1 (only for I/O)
#define SW_SMI 0xD0
// Relative to PCI Function 0
#define PM_STATUS 0xF4
#define PM_SRC_GPIO3 (1L << 0)
#define PM_SRC_GPIO4 (1L << 1)
#define PM_SRC_GPIO5 (1L << 2)
#define PM_SRC_GPIO7 (1L << 3)
#define PM_SRC_GAMEPORT (1L << 4)
#define PM_SRC_HDD_IDLE (1L << 8) // Primary
#define PM_SRC_FDD_IDLE (1L << 9)
#define PM_SRC_PARSER_IDLE (1L << 10)
#define PM_SRC_KEYBMS_IDLE (1L << 11)
#define PM_SRC_USER_DEF1_IDLE (1L << 12)
#define PM_SRC_USER_DEF2_IDLE (1L << 13)
#define PM_SRC_USER_DEF3_IDLE (1L << 14)
#define PM_SRC_VIDEO_IDLE (1L << 15)
#define PM_SRC_HDD_TRAP (1L << 16) // Primary
#define PM_SRC_FDD_TRAP (1L << 17)
#define PM_SRC_PAR_SER_TRAP (1L << 18)
#define PM_SRC_KYBD_MOUSE_TRAP (1L << 19)
#define PM_SRC_SECONDARY_IDLE (1L << 20)
#define PM_SRC_SECONDARY_TRAP (1L << 21)
#define PM_SRC_reserved (1L << 22)
#define PM_SRC_VIDEO_TRAP (1L << 23)
#define PM_SRC_ACPI_TIMER (1L << 24)
#define PM_SRC_RTC_ALARM (1L << 25)
#define PM_SRC_AC97_CODEC (1L << 26)
#define PM_SRC_LID_SWITCH (1L << 27)
#define PM_SRC_LID_POSITION (1L << 28) // Not an SMI source
#define PM_SRC_GPIO0 (1L << 29)
#define PM_SRC_GPIO1 (1L << 30) // CS55x0 only
#define PM_SRC_THERMAL (1L << 30) // SCxxxx only
#define PM_SRC_GPIO2 ((ULONG)(1L << 31))
#define GPIO_PINS (PM_SRC_GPIO0 | PM_SRC_GPIO1 | PM_SRC_GPIO2 | PM_SRC_GPIO3 | PM_SRC_GPIO4 | PM_SRC_GPIO5 | PM_SRC_LID_SWITCH | PM_SRC_GPIO7)

View File

@@ -0,0 +1,230 @@
/*
* 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
*/
//************************** CS5536 related defines ***************************
// Southbridge MPCI CTRL:
#define ME (1 << 0) // Enable in-bound memory accesses
#define IE (1 << 1) // Enable in-bound I/O accesses
#define CIS_MASK (3 << 3) // CIS Mode
#define CIS_A (1 << 3)
#define CIS_B (2 << 3)
#define CIS_C (3 << 3)
#define MPCI_SOUTH 0x51000000 // 2.4.2.0
#define MDD_PORT 4 // Port that MDD is at
#define REGION_R0 0x20
#define REGION_R15 (REGION_R0 + 15)
/****** 5536 GPIO definitions ******/
// offsets from GPIO base
#define GPIO5536_BASE (0x6100)
#define NUM_5536_GPIO (28)
#define GPIOH_OFFSET (0x80)
#define GPIO_OUT_VAL (0x00)
#define GPIO_OUT_EN (0x04)
#define GPIO_OUT_OD_EN (0x08)
#define GPIO_OUT_INV_EN (0x0C)
#define GPIO_OUT_AUX1_SEL (0x10)
#define GPIO_OUT_AUX2_SEL (0x14)
#define GPIO_PU_EN (0x18)
#define GPIO_PD_EN (0x1C)
#define GPIO_IN_EN (0x20)
#define GPIO_IN_INV_EN (0x24)
#define GPIO_IN_FIL_EN (0x28)
#define GPIO_IN_EVC_EN (0x2C)
#define GPIO_READBACK (0x30)
#define GPIO_IN_AUX_SEL (0x34)
#define GPIO_EVENT_EN (0x38)
#define GPIO_LOCK_EN (0x3C)
#define GPIO_IN_PEDG_EN (0x40)
#define GPIO_IN_NEDG_EN (0x44)
#define GPIO_IN_PEDG_STS (0x48)
#define GPIO_IN_NEDG_STS (0x4C)
#define GPIO00_FILA (0x50)
#define GPIO00_FILC (0x52)
#define GPIO00_EVCNT (0x54)
#define GPIO00_EVCMP (0x56)
#define GPIO01_FILA (0x58)
#define GPIO01_FILC (0x5A)
#define GPIO01_EVCNT (0x5C)
#define GPIO01_EVCMP (0x5E)
#define GPIO02_FILA (0x60)
#define GPIO02_FILC (0x62)
#define GPIO02_EVCNT (0x64)
#define GPIO02_EVCMP (0x66)
#define GPIO03_FILA (0x68)
#define GPIO03_FILC (0x6A)
#define GPIO03_EVCNT (0x6C)
#define GPIO03_EVCMP (0x6E)
#define GPIO04_FILA (0x70)
#define GPIO04_FILC (0x72)
#define GPIO04_EVCNT (0x74)
#define GPIO04_EVCMP (0x76)
#define GPIO05_FILA (0x78)
#define GPIO05_FILC (0x7A)
#define GPIO05_EVCNT (0x7C)
#define GPIO05_EVCMP (0x7E)
#define GPIO06_FILA (0xD0)
#define GPIO06_FILC (0xD2)
#define GPIO06_EVCNT (0xD4)
#define GPIO06_EVCMP (0xD6)
#define GPIO07_FILA (0xD8)
#define GPIO07_FILC (0xDA)
#define GPIO07_EVCNT (0xDC)
#define GPIO07_EVCMP (0xDE)
#define GPIO_MAPX (0xE0)
#define GPIO_MAPY (0xE4)
#define GPIO_MAPZ (0xE8)
#define GPIO_MAPW (0xEC)
#define GPIO_FE0 (0xF0)
#define GPIO_FE1 (0xF1)
#define GPIO_FE2 (0xF2)
#define GPIO_FE3 (0xF3)
#define GPIO_FE4 (0xF4)
#define GPIO_FE5 (0xF5)
#define GPIO_FE6 (0xF6)
#define GPIO_FE7 (0xF7)
#define GPIOL_IN_EVENT_DECR (0xF8)
#define GPIOH_IN_EVENT_DECR (0xFC)
// GPIO atomic register values
#define GPIO00_SET (0x00000001L)
#define GPIO00_CLR (0x00010000L)
#define GPIO01_SET (0x00000002L)
#define GPIO01_CLR (0x00020000L)
#define GPIO02_SET (0x00000004L)
#define GPIO02_CLR (0x00040000L)
#define GPIO03_SET (0x00000008L)
#define GPIO03_CLR (0x00080000L)
#define GPIO04_SET (0x00000010L)
#define GPIO04_CLR (0x00100000L)
#define GPIO05_SET (0x00000020L)
#define GPIO05_CLR (0x00200000L)
#define GPIO06_SET (0x00000040L)
#define GPIO06_CLR (0x00400000L)
#define GPIO07_SET (0x00000080L)
#define GPIO07_CLR (0x00800000L)
#define GPIO08_SET (0x00000100L)
#define GPIO08_CLR (0x01000000L)
#define GPIO09_SET (0x00000200L)
#define GPIO09_CLR (0x02000000L)
#define GPIO10_SET (0x00000400L)
#define GPIO10_CLR (0x04000000L)
#define GPIO11_SET (0x00000800L)
#define GPIO11_CLR (0x08000000L)
#define GPIO12_SET (0x00001000L)
#define GPIO12_CLR (0x10000000L)
#define GPIO13_SET (0x00002000L)
#define GPIO13_CLR (0x20000000L)
#define GPIO14_SET (0x00004000L)
#define GPIO14_CLR (0x40000000L)
#define GPIO15_SET (0x00008000L)
#define GPIO15_CLR (0x80000000L)
#define GPIO16_SET (0x00000001L)
#define GPIO16_CLR (0x00010000L)
#define GPIO17_SET (0x00000002L)
#define GPIO17_CLR (0x00020000L)
#define GPIO18_SET (0x00000004L)
#define GPIO18_CLR (0x00040000L)
#define GPIO19_SET (0x00000008L)
#define GPIO19_CLR (0x00080000L)
#define GPIO20_SET (0x00000010L)
#define GPIO20_CLR (0x00100000L)
#define GPIO21_SET (0x00000020L)
#define GPIO21_CLR (0x00200000L)
#define GPIO22_SET (0x00000040L)
#define GPIO22_CLR (0x00400000L)
#define GPIO23_SET (0x00000080L)
#define GPIO23_CLR (0x00800000L)
#define GPIO24_SET (0x00000100L)
#define GPIO24_CLR (0x01000000L)
#define GPIO25_SET (0x00000200L)
#define GPIO25_CLR (0x02000000L)
#define GPIO26_SET (0x00000400L)
#define GPIO26_CLR (0x04000000L)
#define GPIO27_SET (0x00000800L)
#define GPIO27_CLR (0x08000000L)
#define GPIO28_SET (0x00001000L)
#define GPIO28_CLR (0x10000000L)
#define GPIO29_SET (0x00002000L)
#define GPIO29_CLR (0x20000000L)
#define GPIO30_SET (0x00004000L)
#define GPIO30_CLR (0x40000000L)
#define GPIO31_SET (0x00008000L)
#define GPIO31_CLR (0x80000000L)
// Hawk platform has Sleep Button connected to GPIO25
#define DEFAULT_SLPB_GPIO (25)
// GPIO13 AUX_IN is dedicated 5536 Sleep Button but it is only connected
// to Working Power Domain and can't wake the system from Standby.
// #define DEFAULT_SLPB_GPIO (13)
// 5536 Power Management Controller
// offsets from base PMC I/O address, all are 32-bit regs
#define PM_SSD (0x00) // Sleep start delay
#define PM_SCXA (0x04) // Sleep control X Assert Delay and Enable
#define PM_SCYA (0x08) // Sleep control Y Assert Delay and Enable
#define PM_SODA (0x0C) // Sleep Output Disable Assert Delay and Enable
#define PM_SCLK (0x10) // Sleep Clock Delay and Enable
#define PM_SED (0x14) // Sleep End Delay
#define PM_SCXD (0x18) // Sleep Control X De-assert Delay and Enable
#define PM_SCYD (0x1C) // Sleep Control Y De-assert Delay and Enable
#define PM_SIDD (0x20) // Sleep Input Disable De-assert Delay and Enable
#define PM_WKD (0x30) // Working De-assert Delay and Enable
#define PM_WKXD (0x34) // Work_AUX De-assert Delay and Enable
#define PM_RD (0x38) // De-assert Delay from Standby
#define PM_WKXA (0x3C) // Work_AUX Assert Delay from Standby Wakeup
#define PM_FSD (0x40) // Fail-Safe Delay and Enable
#define PM_TSD (0x44) // Thermal-Safe Delay and Enable
#define PM_PSD (0x48) // Power-Safe Delay and Enable
#define PM_NWKD (0x4C) // Normal Work Delay and Enable
#define PM_AWKD (0x50) // Abnormal Work Delay and Enable
#define PM_SSC (0x54) // Standby Status and Control
#define USBMSROHCB 0x0008
#define USBMSREHCB 0x0009
#define USBMSRUDCB 0x000A
#define USBMSRUOCB 0x000B
#define PMEEN (1L << 3)

View File

@@ -0,0 +1,443 @@
/*
* 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
*/
// Vail MSRs
#define MSR_SMM_CTRL 0x1301
#define SMM_NMI_EN (1L << 0) // Enables NMIs during SMM
#define SMM_SUSP_EN (1L << 1) // Enables SUSP# pin during SMM
#define NEST_SMI_EN (1L << 2) // Enables SSMIs during SMM
#define SMM_INST_EN (1L << 3) // Enables SMM instructions
#define INTL_SMI_EN (1L << 4) // Enables SSMIs
#define EXTL_SMI_EN (1L << 5) // Enables SMI# pin
#define MSR_SMM_HDR 0x132B
#define MSR_SMM_LOC 0x133B
#define MSR_EFLAGS 0x1418
#define MSR_CR0 0x1420
#define MSR_DR7 0x1343
//
// Region Control Registers (see page 10-188 of Vail spec)
//
#define REGION_CD (1L << 0) // Cache disabled
#define REGION_WA (1L << 1) // Write-allocate
#define REGION_WP (1L << 2) // Write-protect
#define REGION_WT (1L << 3) // Write-through
#define REGION_WC (1L << 4) // Write-combine
#define REGION_WS (1L << 5) // Write-serialize
#define REGION_EN (1L << 8) // Region enable
#define MSR_RCONF_DEFAULT 0x1808
#define MSR_RCONF_BYPASS 0x180A
#define MSR_RCONF_A0_BF 0x180B
#define MSR_RCONF_C0_DF 0x180C
#define MSR_RCONF_E0_FF 0x180D
#define MSR_RCONF_SMM 0x180E
#define MSR_RCONF_DMM 0x180F
// Bit(s) Field
// ------ -----------------------------------------------
// 7:0 Region Properties
// 8 Enable
// 11:9 reserved
// 31:12 Start of region (4 KB granularity; inclusive)
// 43:32 reserved
// 63:44 Top of region (4 KB granularity; inclusive)
#define MSR_RCONF0 0x1810
#define MSR_RCONF1 0x1811
#define MSR_RCONF2 0x1812
#define MSR_RCONF3 0x1813
#define MSR_RCONF4 0x1814
#define MSR_RCONF5 0x1815
#define MSR_RCONF6 0x1816
#define MSR_RCONF7 0x1817
//========================================================================================
#define BIZARRO (1L << 28)
#define ROUTING 0xFFFFC000 // Mask for routing field
// Ports under Redcloud MBIU0
#define PORT_MBIU0 0x10000000L // By convention
// Standard MBus Device MSRs:
#define MBD_MSR_CAP 0x2000
#define MBD_MSR_CONFIG 0x2001 // 3 LSBs = subtractive port
// MBIU0: 0x00000002
// MBIU1: 0x00000004
// MBIU2: 0x00000004
#define MBD_MSR_SMI 0x2002
#define MBD_MSR_ERROR 0x2003
#define MBD_MSR_PM 0x2004
#define MBD_MSR_DIAG 0x2005
// Northbridge MPCI
#define MPCI_CTRL 0x2010
#define LDE (1 << 9) // Enable latency disconnect timer
#define MPCI_ARB 0x2011
#define MPCI_PBUS 0x2012
#define MPCI_REN 0x2014 // Fixed Region Enables
#define MPCI_A0_BF 0x2015 // Fixed Regions Properties A0000-BFFFF
#define MPCI_C0_DF 0x2016 // Fixed Regions Properties C0000-DFFFF
#define MPCI_E0_FF 0x2017 // Fixed Regions Properties E0000-FFFFF
#define MPCI_R0 0x2018 // Base memory
#define MPCI_R1 0x2019 // Extended memory
#define MPCI_R2 0x201A // SMM memory
#define MPCI_R3 0x201B
#define MPCI_R4 0x201C
#define MPCI_R5 0x201D
// MPCI Region Control Registers (see page 89 of MPCI spec)
#define REGION_CD (1L << 0) // Cache disabled
#define REGION_DD (1L << 1) // Discard data
#define REGION_WP (1L << 2) // Write protect
#define REGION_WT (1L << 3) // Write through
#define REGION_WC (1L << 4) // Write combine
#define REGION_PF (1L << 5) // Prefetchable
#define MPCI_ExtMSR 0x201E
// Revision IDs
#define CPU_REV_1_0 0x11
#define CPU_REV_1_1 0x12
#define CPU_REV_2_0 0x20
// MBus Device IDs:
#define ID_SHIFT 12
#define ID_MBIU 0x01
#define ID_MC 0x20
#define ID_VAIL 0x86
#define ID_AES 0x30
#define ID_VIP 0x3C
#define ID_GP 0x3D
#define ID_VG 0x3E
#define ID_DF 0x3F
#define ID_MCP 0x02
#define ID_MPCI 0x05
#define ID_FG 0xF0
#define ID_OHCI 0x42
#define ID_USB_20 0x43
#define ID_ATA 0x47
#define ID_ATA100 0x48
#define ID_MDD 0xDF
#define ID_AC97 0x33
/////////////////////////////////////////////////////////////
// Northbridge
/////////////////////////////////////////////////////////////
// MBIU0
//
// Capabilities: 22711830 010C1086
// P2D_BM = 6; 0x20-0x25
// P2D_BMO = 2; 0x26-0x27
// P2D_R = 1; 0x28
// P2D_RO = 3; 0x29-0x2B
// P2D_SC = 1; 0x2C
// P2D_SCO = 0;
// IOD_BM = 3; 0xE0-0xE2
// IOD_SC = 6; 0xE3-0xE8
// NPORTS = 5;
// STATS = 2;
//
// Port Dev_ID Routing FS/2 Device Description
// ----- -------- ------------------- -------- ------------------
// 0 01h 10000000 0.1.0.0.0 20000000 MBIU0
// 1 20h 20000000 1.0.0.0.0 24000000 Memory Controller
// 2 01h 40000000 2.0.0.0.0 MBIU1 (subtractive)
// 3 86h 60000000 3.0.0.0.0 2C000000 Vail (self-reference)
// 4 3Eh 80000000 4.0.0.0.0 30000000 Video Generator
// 5 3Dh A0000000 5.0.0.0.0 34000000 Graphics Processor
// 6 3Fh C0000000 6.0.0.0.0 38000000 Display Filter
// 7 <empty>
#define VG_PORT 4L
#define GP_PORT 5L
#define VG_SMI_MSR (VG_PORT << 29) + MBD_MSR_SMI
#define GP_SMI_MSR (GP_PORT << 29) + MBD_MSR_SMI
//
// MBIU1
//
// Capabilities: 20281830 01004009
// P2D_BM = 9; 0x20-0x28
// P2D_BMO = 0;
// P2D_R = 4; 0x29-0x2C
// P2D_RO = 0;
// P2D_SC = 1; 0x2D
// P2D_SCO = 0;
// IOD_BM = 3; 0xE0-0xE2
// IOD_SC = 6; 0xE3-0xE8
// NPORTS = 5;
// STATS = 2;
//
// Port Dev_ID Routing FS/2 Device Description
// ----- -------- ------------------- -------- ------------------
// 0 <empty>
// 1 01h 44000000 2.1.0.0.0 01000000 MBIU1 (self-reference)
// 2 <empty>
// 3 02h 4C000000 2.3.0.0.0 00000000 MCP
// 4 05h 50000000 2.4.0.0.0 80000000 MPCI Northbridge (subtractive)
// 5 F0h 54000000 2.5.0.0.0 A0000000 FooGlue
// 6 <empty>
// 7 <empty>
#define MBIU0_PORT 1 // From MBIU1's point of view
/////////////////////////////////////////////////////////////
// CS5535
/////////////////////////////////////////////////////////////
//
// Capabilities: 327920A0 80000003 (simulator: 303820a0)
// P2D_BM = 3; 0x20-0x22
// P2D_BMK = 2; 0x23-0x24
// IOD_BM = 10; 0xE0-0xE9
// IOD_SC = 8; 0xEA-0xF1
// NPORTS = 7;
// STATS = 3;
//
//
// Port Dev_ID Routing FS/2 Device Description
// ----- -------- ------------------- -------- -----------------
// 05h 51000000 2.4.2.0.0 88000000 MPCI Southbridge
// 0 01h 51020000 2.4.2.0.1 88100000 MBIU2
// 1 51100000 2.4.2.1.0 MPCI (self-reference)
// 2 42h 51200000 2.4.2.2.0 89000000 OHCI #2
// 3 47h 51300000 2.4.2.3.0 89800000 ATA-5
// 4 DFh 51400000 2.4.2.4.0 8A000000 MDD (subtractive)
// 5 33h 51500000 2.4.2.5.0 8A800000 AC97 codec
// 6 42h 51600000 2.4.2.6.0 8B000000 OHCI #1
// 7 02h 51700000 2.4.2.7.0 8B800000 MCP
/////////////////////////////////////////////////////////////
// CS5536
/////////////////////////////////////////////////////////////
//
// Capabilities: 327920A0 80000003
// P2D_BM = 3; 0x20-0x22
// P2D_BMK = 2; 0x23-0x24
// IOD_BM = 10; 0xE0-0xE9
// IOD_SC = 8; 0xEA-0xF1
// NPORTS = 7;
// STATS = 3;
//
//
// Port Dev_ID Routing FS/2 Device Description
// ----- -------- ------------------- -------- -----------------
// 05h 51000000 2.4.2.0.0 88000000 MPCI Southbridge
// 0 01h 51020000 2.4.2.0.1 88100000 MBIU2
// 1 51100000 2.4.2.1.0 MPCI (self-reference)
// 2 42h 51200000 2.4.2.2.0 89000000 <empty>
// 3 47h 51300000 2.4.2.3.0 89800000 ATA-5
// 4 DFh 51400000 2.4.2.4.0 8A000000 MDD (subtractive)
// 5 33h 51500000 2.4.2.5.0 8A800000 AC97 codec
// 6 43h 51600000 2.4.2.6.0 8B000000 USB 2.0
// 7 02h 51700000 2.4.2.7.0 8B800000 MCP
//
// Arcturus
//
// Device AD PIN Physical Device
// ------ ------ ---------------------------------------------------
// 13 23 MacPhyter
// 14 24 PCI Slot 1
// 15 25 PCI Slot 2
// 16 26 Chipset Register Space - pin H26 High
// 17 27 USB Register Space - pin H26 High
// 18 28 Chipset Register Space - pin H26 Low
// 19 29 USB Register Space - pin H26 Low
//
// MPCI
//
// Fields for both MPCI_MSR_SMI and MPCI_MSR_ERROR
#define MARM (1L << 0)
#define TARM (1L << 1)
#define BMM (1L << 2)
#define SSMM (1L << 2) // only in MPCI SB MSR_SMI
#define VPHM (1L << 3) // only in MPCI NB MSR_SMI
#define SYSM (1L << 4)
#define PARM (1L << 5)
#define MARE (1L << 16)
#define TARE (1L << 17)
#define BME (1L << 18) // Northbridge only ?
#define VPHE (1L << 19) // only in MPCI NB MSR_SMI
#define SYSE (1L << 20)
#define PARE (1L << 21)
#define TASE (1L << 22)
// FooGlue MSRs:
#define FG_IIOC 0x0010
#define MODE_5530 0
#define MODE_5535A 1
#define MODE_5535B 2
#define FG_A20M 0x0011
#define A20M (1 << 0)
#define FG_NMI 0x0012
#define NMI (1 << 0)
#define FG_INIT 0x0013
#define INIT (1 << 0)
#define MBIU_COH 0x0080
#define MBIU_PAE 0x0081
#define MBIU_ARB 0x0082
#define MBIU_ASMI 0x0083
#define MBIU_ERR 0x0084
#define MBIU_DEBUG 0x0085
#define MBIU_CAP 0x0086
#define MBIU_NOUT_RESP 0x0087
#define MBIU_NOUT_WDATA 0x0088
#define MBIU_WHOAMI 0x008B
// MBIU_WHOAMI tells self-reference:
// MBIU0: 0x00000003
// MBIU1: 0x00000001
// MBIU2: 0x00000001
#define MBIU_SLV 0x008C
//
// Descriptor MSRs
//
#define MSR_MEM_DESCR 0x0020
#define MSR_IO_DESCR 0x00E0
// Defines for IOD_SC
#define REN (1L << 20)
#define WEN (1L << 21)
//
// Descriptor Statistics MSRs
//
#define MSR_STATISTICS_CNT 0x00A0 // and A4, A8, AC
// High dword is Load Value; Low dword is Count
#define MSR_STATISTICS_MASK 0x00A1 // and A5, A9, AD
// High dword is IOD mask; Low dword is P2D mask
#define MSR_STATISTICS_ACTION 0x00A2 // and A6, AA, AE
#define HIT_LDEN (1L << 0) // Load CNT on descriptor hit
#define HIT_DEC (1L << 1) // Decrement CNT on descriptor hit
#define HIT_SMI (1L << 2) // Assert ASMI on descriptor hit
#define HIT_ERR (1L << 3) // Assert AERR on descriptor hit
#define ALWAYS_DEC (1L << 4) // Always decrement CNT (unless loading or (CNT = 0 & !RELOAD))
#define ZERO_SMI (1L << 5) // Assert ASMI on CNT = 0
#define ZERO_ERR (1L << 6) // Assert AERR on CNT = 0
#define WRAP (1L << 7) // Reload CNT from LOAD_VAL on CNT = 0
// Vail PM stuff
#define BC_MSR0 0x1900
#define SUSP_EN (0x1000L)
#define XC_CONFIG 0x1210
#define XC_CLK_SUSP (0x01L)
// GX2 Memory Controller PM stuff
// MC PMode1 Up Delay
#define MC_CF1017_DATA 0x001A
#define PM1_UP_DLY_MASK (0xFF00L)
// 240ns delay, DDR spec. state minimum delay is 200ns
#define PM1_UP_DLY_VAL (0xF000L)
// MC PMode Sensitivity
// bits[63:32]=PMode1, bits[31:0]=PMode0
#define MC_CF_PMCTR 0x0020
// number of MC clocks that MC must be inactive
// before entering PMode1
#define PM1_SENS_VAL (0x020L)
// GX2 GLCP PM stuff
// Clock Disable Delay
#define MCP_CLK_DIS_DLY 0x0008
#define CLKDIS_MASK (0x00FFFFFFL)
// PM Clock Disable
#define MCP_PMCLKDISABLE (0x0009)
#define MCP_PMCLKOFF (0x0010)
// PM CLK4ACK MSR
#define MCP_CLK4ACK 0x0013
#define S3_CLK4ACK (0x07BE7FC3L)
#define S1_CLK4ACK S3_CLK4ACK
// Throttling PM I/O regs default location
#define MCP_GLB_PM 0x000B
#define MCP_GLB_THEN (0x01L)
#define MCP_DOTPLL 0x0015
#define MCP_DBGCLKCTL 0x0016
// default location to map GLCP P_CNT I/O space regs
#define PMGX2_BASE (0x9E00)
/* offset from PMGX2_BASE */
#define P_CNT_OFS (0)
#define P_LVL2_OFS (4)
#define P_LVL3_OFS (8)
// GLCP MSR offsets for clock throttling
#define MCP_CNT (0x0018)
#define CNT_THEN (0x10L)
#define CNT_MASK (0x0FL)
#define CNT_MAX (0x01L)
#define CNT_NONE (0x0FL)
#define MCP_LVL2 (0x0019)
#define MCP_TH_SD (0x001C)
#define SD_MASK (0x0FFFL)
#define PLVL2_IN (0x1000L)
#define MCP_TH_SF (0x001D)
#define SF_MASK (0x0FFL)
#define MCP_TH_OD (0x001E)
#define OD_IRQ (0x8000L)
#define OD_SMI (0x4000L)
#define OD_MASK (0x3FFFL)

View File

@@ -0,0 +1,97 @@
/*
* 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
*/
typedef struct {
union {
unsigned long HceUlong;
unsigned short HceUshort;
struct {
unsigned short EmulationEnable: 1;
unsigned short EmulationInterrupt: 1;
unsigned short CharacterPending: 1;
unsigned short IRQEn: 1;
unsigned short ExternalIRQEn: 1;
unsigned short GateA20Sequence: 1;
unsigned short IRQ1Active: 1;
unsigned short IRQ12Active: 1;
unsigned short A20State: 1;
};
};
} HCE_CONTROL;
// Host Controller Operational Registers
typedef struct {
unsigned long HcRevision;
unsigned long HcControl;
unsigned long HcCommandStatus;
unsigned long HcInterruptStatus;
unsigned long HcInterruptEnable;
unsigned long HcInterruptDisable;
unsigned long HcHCCA;
unsigned long HcPeriodCurrentED;
unsigned long HcControlHeadED;
unsigned long HcControlCurrentED;
unsigned long HcBulkHeadED;
unsigned long HcBulkCurrentED;
unsigned long HcDoneHead;
unsigned long HcFmInterval;
unsigned long HcFmRemaining;
unsigned long HcFmNumber;
unsigned long HcPeriodicStart;
unsigned long HcLSThreshold;
unsigned long HcRhDescriptorA;
unsigned long HcRhDescriptorB;
unsigned long HcRhStatus;
unsigned long HcRhPortStatus[2];
unsigned char Reserved[0x100-0x54-2*4]; // Reserved for use by HC
HCE_CONTROL HceControl; // 0x100
unsigned long HceInput; // 0x104
unsigned long HceOutput; // 0x108
unsigned long HceStatus; // 0x10C
} HCOR;
// HcInterruptStatus & HcInterruptDisable fields:
#define SO 0x00000001L // Scheduling Overrun
#define WDH 0x00000002L // HcDoneHead Writeback
#define SF 0x00000004L // Start of Frame
#define RD 0x00000008L // Resume Detect
#define UE 0x00000010L // Unrecoverable Error
#define FNO 0x00000020L // Frame Number Overflow
#define RHSC 0x00000040L // Root Hub Status Change
#define OC 0x40000000L // Ownership Change
#define MIE 0x80000000L // Master Interrupt Enable
// HceControl fields:
#define EMULATION_ENABLE 0x01
#define EMULATION_INTERRUPT 0x02
#define CHARACTER_PENDING 0x04
#define IRQ_ENABLE 0x08
#define EXTERNAL_IRQ_ENABLE 0x10
#define GATE_A20_SEQUENCE 0x20
#define IRQ1_ACTIVE 0x40
#define IRQ12_ACTIVE 0x80
#define A20_STATE 0x100
// HceStatus fields:
#define CMD_DATA 0x08

View File

@@ -0,0 +1,183 @@
/*
* 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
*/
// Real Time Clock (RTC) definitions
#define CMOS_INDEX 0x70
#define CMOS_DATA CMOS_INDEX+1
#define CMOS_SECONDS 0x00
#define CMOS_MINUTES 0x02
#define CMOS_HOURS 0x04
#define CMOS_DAY 0x07
#define CMOS_MONTH 0x08
#define CMOS_YEAR 0x09
#define CMOS_STATUS_A 0x0A
#define UIP 0x80
#define CMOS_STATUS_B 0x0B
#define SET 0x80
#define PI 0x40
#define AI 0x20
#define UI 0x10
#define SQUARE 0x08
#define DM 0x04
#define HOUR24 0x02
#define DLS 0x01
#define CMOS_STATUS_C 0x0C
#define IRQ 0x80
#define PS 0x40
#define AS 0x20
#define US 0x10
#define CMOS_CENTURY 0x32
// Programmable Interrupt Controller (PIC) definitions
#define PIC1_BASE 0x20
#define PIC1_MASK PIC1_BASE+1
#define PIC2_BASE 0xA0
#define PIC2_MASK PIC2_BASE+1
#define NONSPECIFIC_EOI 0x20
#define SPECIFIC_EOI 0x60
#define PIC1_EDGE 0x4D0
#define PIC2_EDGE 0x4D1
#define PIC1_ICW1 0x20
#define PIC1_ICW2 0x21
#define PIC1_ICW3 0x21
#define PIC1_ICW4 0x21
#define PIC1_OCW1 0x21
#define PIC1_OCW2 0x20
#define PIC1_OCW3 0x20
#define PIC2_ICW1 0xA0
#define PIC2_ICW2 0xA1
#define PIC2_ICW3 0xA1
#define PIC2_ICW4 0xA1
#define PIC2_OCW1 0xA1
#define PIC2_OCW2 0xA0
#define PIC2_OCW3 0xA0
// DMA definitions
#define TRANSFER_MASK (0x0C)
#define DMA_VERIFY (0x00)
#define DMA_WRITE (0x04)
#define DMA_READ (0x08)
#define MODE_MASK (0xC0)
#define MODE_DEMAND (0x00)
#define MODE_SINGLE (0x40)
#define MODE_BLOCK (0x80)
#define MODE_CASCADE (0xC0)
#define DMA1_ADDR0 0x00
#define DMA1_CNT0 0x01
#define DMA1_ADDR1 0x02
#define DMA1_CNT1 0x03
#define DMA1_ADDR2 0x04
#define DMA1_CNT2 0x05
#define DMA1_ADDR3 0x06
#define DMA1_CNT3 0x07
#define DMA1_MODE 0x0B
#define DMA1_CPTR 0x0C
#define DMA1_MASK 0x0F
#define DMA2_ADDR0 0xC0
#define DMA2_CNT0 0xC2
#define DMA2_ADDR1 0xC4
#define DMA2_CNT1 0xC6
#define DMA2_ADDR2 0xC8
#define DMA2_CNT2 0xCA
#define DMA2_ADDR3 0xCC
#define DMA2_CNT3 0xCE
#define DMA2_MODE 0xD6
#define DMA2_CPTR 0xD8
#define DMA2_MASK 0xDE
#define DMA_PAGE 0x80
#define DMA_HPAGE 0x480
// Programmable Interval Timer (PIT) definitions
#define PIT_CTR0 0x40
#define PIT_CTR1 0x41
#define PIT_CTR2 0x42
#define PIT_CMD 0x43
#define PIT_CMD_BOTH_BYTES 0x30 // Sets CMD word to read/write both bytes
#define READ_IRR 0x0A
#define READ_ISR 0x0B
// Keyboard controller registers
#define KYBD_DATA 0x60
#define KYBD_STATUS 0x64
#define STAT_OBF 0x01
#define STAT_IBF 0x02
#define STAT_FLAG 0x04
#define STAT_CMD 0x08
#define STAT_INHIBIT 0x10
#define STAT_AUX_OBF 0x20
#define STAT_TIMEOUT 0x40
#define STAT_PARITY 0x80
#define KYBD_COMMAND 0x64
// Keyboard controller output port bits
#define KYBD_SYSR 0x01 // Processor reset
#define KYBD_GA20 0x02 // Gate A20 (1=on)
#define KYBD_ADAT 0x04 // AUX data
#define KYBD_ACLK 0x08 // AUX clock
#define KYBD_KOBF 0x10 // Keyboard OBF
#define KYBD_AOBF 0x20 // AUX OBF
#define KYBD_KCLK 0x40 // Keyboard clock
#define KYBD_KDAT 0x80 // Keyboard data
// Keyboard controller commands
#define KYBD_RD_OUT 0xD0
#define KYBD_WR_OUT 0xD1
// Keyboard controller command byte
#define OBF_INTERRUPT 0x01
#define AUX_INTERRUPT 0x02
#define SYSTEM_STATUS 0x04
#define KBD_DISABLED 0x10
#define AUX_DISABLED 0x20
#define XT_SCANSET 0x40
#define PORT_B 0x92
#define GAMEPORT 0x200
#define PRIMARY_IDE 0x1F6
#define SECONDARY_IDE 0x176
#define PRIMARY_FLOPPY 0x3F5
#define SECONDARY_FLOPPY 0x375
#define COM1 0x3F8
#define COM2 0x2F8
#define COM3 0x3E8
#define COM4 0x2E8
#define LPT1 0x378
#define LPT2 0x278

View File

@@ -0,0 +1,111 @@
/*
* 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
*/
// PCI related definitions
#define PCI_CONFIG_ADDRESS 0xCF8
#define PCI_CONFIG_DATA 0xCFC
#define VENDOR_ID 0x00
#define COMMAND 0x04
#define IO_SPACE (1 << 0)
#define MEM_SPACE (1 << 1)
#define BUS_MASTER (1 << 2)
#define SPECIAL_CYCLES (1 << 3)
#define MEM_WR_INVALIDATE (1 << 4)
#define VGA_PALETTE_SNOOP (1 << 5)
#define PARITY_RESPONSE (1 << 6)
#define WAIT_CYCLE_CONTROL (1 << 7)
#define SERR_ENABLE (1 << 8)
#define FAST_BACK_TO_BACK (1 << 9)
#define STATUS 0x06
#define CAPABILITIES_LIST (1L << 20)
#define PCI_66MHZ_CAPABLE (1L << 21)
#define BACK2BACK_CAPABLE (1L << 23)
#define MASTER_PARITY_ERROR (1L << 24)
#define DEVSEL_FAST (0L << 25)
#define DEVSEL_MEDIUM (1L << 25)
#define DEVSEL_SLOW (2L << 25)
#define SIGNALED_TARGET_ABORT (1L << 27)
#define RECEIVED_TARGET_ABORT (1L << 28)
#define RECEIVED_MASTER_ABORT (1L << 29)
#define SIGNALED_SYSTEM_ERROR (1L << 30)
#define DETECTED_PARITY_ERROR (1L << 31)
#define REVISION_ID 0x08
#define CACHE_LINE 0x0C
#define LATENCY_TIMER 0x0D
#define HEADER_TYPE 0x0E
#define BIST 0x0F
// Capability List IDs
#define CAP_ID_PM 0x01
#define CAP_ID_AGP 0x02
#define CAP_ID_VPD 0x03
#define CAP_ID_SLOT 0x04
#define CAP_ID_MSI 0x05
#define CAP_ID_HOT_SWAP 0x06
#define SUBSYSTEM_VENDOR_ID 0x2C
#define INTERRUPT_LINE 0x3C
#define INTERRUPT_PIN 0x3D
#define MIN_GNT 0x3E
#define MAX_LAT 0x3F
#define BAR0 0x10
#define BAR1 0x14
#define BAR2 0x18
#define BAR3 0x1C
#define BAR4 0x20
#define BAR5 0x24
// PCI Power Management:
#define PCI_PM_REG 0x40
// Graphics-specific registers:
#define OEM_BAR0 0x50
#define OEM_BAR1 0x54
#define OEM_BAR2 0x58
#define OEM_BAR3 0x5C
// EHCI-specific registers
#define EECP 0x50
#define USBLEGSUP (EECP)
#define OS_OWNED_SEMAPHORE 0x01000000
#define BIOS_OWNED_SEMAPHORE 0x00010000
#define USBLEGCTLSTS (EECP+4)
#define SMI_ON_BAR 0x80000000
#define SMI_ON_COMMAND 0x40000000
#define SMI_ON_OC 0x20000000
#define SRBN_REG 0x60
// 5536 B0 ATA-specific registers:
#define IDE_CFG 0x40
#define IDE_DTC 0x48
#define IDE_CAST 0x4C
#define IDE_ETC 0x50
#define IDE_PM 0x54

View File

@@ -0,0 +1,485 @@
/*
* 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
*/
#define VRC_INDEX 0xAC1C // Index register
#define VRC_DATA 0xAC1E // Data register
#define VR_UNLOCK 0xFC53 // Virtual register unlock code
#define NO_VR -1 // No virtual registers
#define VRC_MISCELLANEOUS 0x00 // Miscellaneous Class
#define VSA_VERSION_NUM 0x00
#define HIGH_MEM_ACCESS 0x01
#define GET_VSM_INFO 0x02 // Used by INFO
#define GET_BASICS 0x00
#define GET_EVENT 0x01
#define GET_STATISTICS 0x02
#define GET_HISTORY 0x03
#define GET_HARDWARE 0x04
#define GET_ERROR 0x05
#define SET_VSM_TYPE 0x06
#define SIGNATURE 0x03
#define VSA2_SIGNATURE 0x56534132 // 'VSA2' returned in EAX
#define GET_HW_INFO 0x04
#define VSM_VERSION 0x05
#define CTRL_ALT_DEL 0x06
#define MSR_ACCESS 0x07
#define GET_DESCR_INFO 0x08
#define PCI_INT_AB 0x09 // GPIO pins for INTA# and INTB#
#define PCI_INT_CD 0x0A // GPIO pins for INTC# and INTD#
#define WATCHDOG 0x0B // Watchdog timer
#define MAX_MISC WATCHDOG
// NOTE: Do not change the order of the following registers:
#define VRC_AUDIO 0x01 // XpressAudio Class
#define AUDIO_VERSION 0x00
#define PM_STATE 0x01
#define SB_16_IO_BASE 0x02
#define MIDI_BASE 0x03
#define CPU_USAGE 0x04
#define CODEC_TYPE 0x05
#define STATE_INDEX 0x06
#define STATE_DATA 0x07
#define AUDIO_IRQ 0x08 // For use by native audio drivers
#define STATUS_PTR 0x09 // For use by native audio drivers
#define MAX_AUDIO STATUS_PTR
#define VRC_VG 0x02 // SoftVG Class
#define VRC_VGA 0x02 // SoftVGA Class
#define VG_MEM_SIZE 0x00 // bits 7:0 - 512K unit size, bit 8 controller priority
#define VG_CONFIG 0x00 // Main configuration register
#define VG_CFG_BYPASS 0x0001 // DOTPLL bypass bit
#define VG_MEM_MASK 0x00FE // Memory size mask bits, 2MB increment
#define VG_CFG_DSMASK 0x0700 // Active display mask bits
#define VG_CFG_DSCRT 0x0000 // Active display is CRT
#define VG_CFG_DSPAN 0x0100 // Active display is panel
#define VG_CFG_DSTV 0x0200 // Active display is TV
#define VG_CFG_DSSIM 0x0400 // Simultaneous CRT
#define VG_CFG_PRIORITY 0x0800 // Controller priority bit
#define VG_CFG_MONO 0x1000 // External monochrome card support bit
#define VG_CFG_DRIVER 0x2000 // Driver active bit
#define VG_CRTC_DIAG 0x8000 // Enable CRTC emulation
// Defined for LX/LXVG
#define VG_REFRESH 0x01 // Mode refresh, a mode switch without changing modes
#define VG_FRSH_REF_MASK 0xE000 // Refresh rate mask
#define VG_FRSH_REF_GO 0x1000 // Refresh rate GO bit
// Uses CFP_REF_xxx values from below
#define VG_FRSH_BPP_MASK 0x0E00 // Color depth mask
#define VG_FRSH_BPP_GO 0x0100 // Color depth GO bit
#define FRSH_BPP_8RGB 0x0200 // 8 bits per pixel, RGB
#define FRSH_BPP_16ARGB 0x0400 // 16BPP, ARGB (4:4:4:4)
#define FRSH_BPP_15RGB 0x0600 // 15BPP, RGB (1:5:5:5)
#define FRSH_BPP_16RGB 0x0800 // 16BPP, RGB (5:6:5)
#define FRSH_BPP_24RGB 0x0A00 // 24BPP, RGB (0:8:8:8)
#define FRSH_BPP_32ARGB 0x0C00 // 32BPP, ARGB (8:8:8:8)
#define VG_CFG_DPMS 0x00C0 // DPMS mask bits
#define VG_CFG_DPMS_H 0x0040 // HSYNC mask bit
#define VG_CFG_DPMS_V 0x0080 // VSYNC mask bit
#define VG_VESA_SV_RST 0x0020 // VESA Save/Restore state flag
#define VG_VESA_RST 0x0000 // VESA Restore state
#define VG_VESA_SV 0x0020 // VESA Save state
#define VG_FRSH_MODE 0x0002 // Mode refresh flag
#define VG_FRSH_TIMINGS 0x0001 // Timings only refresh flag
// Defined for GX2/SoftVG
#define VG_PLL_REF 0x01 // PLL reference frequency selection register
#define PLL_14MHZ 0x0000 // 14.31818MHz PLL reference frequency (Default)
#define PLL_48MHZ 0x0100 // 48MHz PLL reference frequency
// Defined for GX1/SoftVGA
#define VGA_MEM_SIZE 0x01 // bits 7:1 - 128K unit size, bit 0 controller enable
#define VG_FP_TYPE 0x02 // Flat panel type data
// VG_FP_TYPE definitions for GX2/SoftVG
#define FP_TYPE_SSTN 0x0000 // SSTN panel type value
#define FP_TYPE_DSTN 0x0001 // DSTN panel type value
#define FP_TYPE_TFT 0x0002 // TFT panel type value
#define FP_TYPE_LVDS 0x0003 // LVDS panel type value
#define FP_RES_6X4 0x0000 // 640x480 resolution value
#define FP_RES_8X6 0x0008 // 800x600 resolution value
#define FP_RES_10X7 0x0010 // 1024x768 resolution value
#define FP_RES_11X8 0x0018 // 1152x864 resolution value
#define FP_RES_12X10 0x0020 // 1280x1024 resolution value
#define FP_RES_16X12 0x0028 // 1600x1200 resolution value
#define FP_WIDTH_8 0x0000 // 8 bit data bus width
#define FP_WIDTH_9 0x0040 // 9 bit data bus width
#define FP_WIDTH_12 0x0080 // 12 bit data bus width
#define FP_WIDTH_18 0x00C0 // 18 bit data bus width
#define FP_WIDTH_24 0x0100 // 24 bit data bus width
#define FP_WIDTH_16 0x0140 // 16 bit data bus width - 16 bit Mono DSTN only
#define FP_COLOR_COLOR 0x0000 // Color panel
#define FP_COLOR_MONO 0x0200 // Mono Panel
#define FP_PPC_1PPC 0x0000 // One pixel per clock
#define FP_PPC_2PPC 0x0400 // Two pixels per clock
#define FP_H_POL_LGH 0x0000 // HSync at panel, normally low, active high
#define FP_H_POL_HGL 0x0800 // HSync at panel, normally high, active low
#define FP_V_POL_LGH 0x0000 // VSync at panel, normally low, active high
#define FP_V_POL_HGL 0x1000 // VSync at panel, normally high, active low
#define FP_REF_60 0x0000 // 60Hz refresh rate
#define FP_REF_65 0x2000 // 65Hz refresh rate
#define FP_REF_70 0x4000 // 70Hz refresh rate
#define FP_REF_72 0x6000 // 72Hz refresh rate
#define FP_REF_75 0x8000 // 75Hz refresh rate
#define FP_REF_85 0xA000 // 85Hz refresh rate
// VG_FP_TYPE definitions for LX/LXVG
#define FP_TYPE_TYPE 0x0003 // Flat panel type bits mask
#define CFP_TYPE_TFT 0x0000 // TFT panel type value
#define CFP_TYPE_LVDS 0x0001 // LVDS panel type value
#define FP_TYPE_RES 0x0038 // Panel resolution bits mask
#define CFP_RES_3X2 0x0000 // 320x240 resolution value
#define CFP_RES_6X4 0x0008 // 640x480 resolution value
#define CFP_RES_8X6 0x0010 // 800x600 resolution value
#define CFP_RES_10X7 0x0018 // 1024x768 resolution value
#define CFP_RES_11X8 0x0020 // 1152x864 resolution value
#define CFP_RES_12X10 0x0028 // 1280x1024 resolution value
#define CFP_RES_16X12 0x0030 // 1600x1200 resolution value
#define FP_TYPE_BUS 0x00C0 // Data bus width and pixels/clock mask
#define CFP_BUS_1PPC 0x0040 // 9, 12, 18 or 24 bit data bus, 1 pixel per clock
#define CFP_BUS_2PPC 0x0080 // 18 or 24 bit data bus, 2 pixels per clock
#define FP_TYPE_HPOL 0x0800 // HSYNC polarity into the panel
#define CFP_HPOL_HGL 0x0000 // HSync at panel, normally high, active low
#define CFP_HPOL_LGH 0x0800 // HSync at panel, normally low, active high
#define FP_TYPE_VPOL 0x1000 // VSYNC polarity into the panel
#define CFP_VPOL_HGL 0x0000 // VSync at panel, normally high, active low
#define CFP_VPOL_LGH 0x1000 // VSync at panel, normally low, active high
#define FP_TYPE_REF 0xE000 // Panel refresh rate
#define CFP_REF_60 0x0000 // 60Hz refresh rate
#define CFP_REF_70 0x2000 // 70Hz refresh rate
#define CFP_REF_75 0x4000 // 75Hz refresh rate
#define CFP_REF_85 0x6000 // 85Hz refresh rate
#define CFP_REF_100 0x8000 // 100Hz refresh rate
#define VG_FP_OPTION 0x03 // Flat panel option data
#define FP_OPT_SCLK_NORMAL 0x0000 // SHFTClk not inverted to panel
#define FP_OPT_SCLK_INVERTED 0x0010 // SHFTClk inverted to panel
#define FP_OPT_SCLK_ACT_ACTIVE 0x0000 // SHFTClk active during "active" only
#define FP_OPT_SCLK_ACT_FREE 0x0020 // SHFTClk free-running
#define FP_OPT_LP_ACT_FREE 0x0000 // LP free-running
#define FP_OPT_LP_ACT_ACTIVE 0x0040 // LP active during "active" only
#define FP_OPT_LDE_POL_LGH 0x0000 // LDE/MOD, normally low, active high
#define FP_OPT_LDE_POL_HGL 0x0080 // LDE/MOD, normally high, active low
#define FP_OPT_PWR_DLY_32MS 0x0000 // 32MS delay for each step of pwr seq.
#define FP_OPT_PWR_DLY_128MS 0x0100 // 128MS delay for each step of pwr seq.
#define VG_TV_CONFIG 0x04 // TV configuration register
#define VG_TV_ENC 0x000F // TV encoder select mask
#define VG_TV_ADV7171 0x0000 // ADV7171 Encoder
#define VG_TV_SAA7127 0x0001 // ADV7171 Encoder
#define VG_TV_ADV7300 0x0002 // ADV7300 Encoder
#define VG_TV_FS454 0x0003 // FS454 Encoder
#define VG_TV_FMT 0x0070 // TV encoder output format mask
#define VG_TV_FMT_SHIFT 0x0004 // Right shift value
#define VG_TV_NTSC 0x0000 // NTSC output format
#define VG_TV_PAL 0x0010 // PAL output format
#define VG_TV_HDTV 0x0020 // HDTV output format
// The meaning of the VG_TV_RES field is dependent on the selected
// encoder and output format. The translations are:
// ADV7171 - Not Used
// SAA7127 - Not Used
// ADV7300 - HDTV resolutions only
// LO -> 720x480p
// MED -> 1280x720p
// HI -> 1920x1080i
// FS454 - Both SD and HD resolutions
// SD Resolutions - NTSC and PAL
// LO -> 640x480
// MED -> 800x600
// HI -> 1024x768
// HD Resolutions
// LO -> 720x480p
// MED -> 1280x720p
// HI -> 1920x1080i
#define VG_TV_RES 0x0780 // TV resolution select mask
#define VG_TV_RES_SHIFT 0x0007 // Right shift value
#define VG_TV_RES_LO 0x0000 // Low resolution
#define VG_TV_RES_MED 0x0080 // Medium resolution
#define VG_TV_RES_HI 0x0100 // High resolution
#define VG_TV_PASSTHRU 0x0800 // TV passthru mode
#define VG_TV_SCALE_ADJ 0x05 // Modifies scaling factors for TV resolutions
#define VG_TV_HACT_ADJ 0x00FF // Horizontal active scale adjust value mask
#define VG_TV_VACT_ADJ 0xFF00 // Vertical active scale adjust value mask
#define VG_DEBUG 0x0F // A debug register
#define VG_FT_HTOT 0x10 // Fixed timings, horizontal total
#define VG_FT_HACT 0x11 // Fixed timings, horizontal active
#define VG_FT_HBST 0x12 // Fixed timings, horizontal blank start
#define VG_FT_HBND 0x13 // Fixed timings, horizontal blank end
#define VG_FT_HSST 0x14 // Fixed timings, horizontal sync start
#define VG_FT_HSND 0x15 // Fixed timings, horizontal sync end
#define VG_FT_VTOT 0x16 // Fixed timings, vertical total
#define VG_FT_VACT 0x17 // Fixed timings, vertical active
#define VG_FT_VBST 0x18 // Fixed timings, vertical blank start
#define VG_FT_VBND 0x19 // Fixed timings, vertical blank end
#define VG_FT_VSST 0x1A // Fixed timings, vertical sync start
#define VG_FT_VSND 0x1B // Fixed timings, vertical sync end
#define VG_START_OFFS_LO 0x20 // Framebuffer start offset bits 15:0
#define VG_START_OFFS_HI 0x21 // Framebuffer start offset bits 27:16
#define VG_FT_VEACT 0x28 // Fixed timings, vertical active
#define VG_FT_VETOT 0x29 // Fixed timings, vertical total
#define VG_FT_VEBST 0x2A // Fixed timings, vertical blank start
#define VG_FT_VEBND 0x2B // Fixed timings, vertical blank end
#define VG_FT_VESST 0x2C // Fixed timings, vertical sync start
#define VG_FT_VESND 0x2D // Fixed timings, vertical sync end
#define MAX_VGA VGA_MEM_SIZE
// #define MAX_VG VG_FP_OPTION
// #define MAX_VG VG_START_OFFS_HI
#define MAX_VG VG_FT_VESND
#define VRC_APM 0x03
#define REPORT_EVENT 0x00
#define CAPABILITIES 0x01
#define APM_PRESENT 0x02
#define MAX_APM APM_PRESENT
#define VRC_PM 0x04 // Legacy PM Class
#define POWER_MODE 0x00
#define POWER_STATE 0x01
#define DOZE_TIMEOUT 0x02
#define STANDBY_TIMEOUT 0x03
#define SUSPEND_TIMEOUT 0x04
#define PS2_TIMEOUT 0x05
#define RESUME_ON_RING 0x06
#define VIDEO_TIMEOUT 0x07
#define DISK_TIMEOUT 0x08
#define FLOPPY_TIMEOUT 0x09
#define SERIAL_TIMEOUT 0x0A
#define PARALLEL_TIMEOUT 0x0B
#define IRQ_WAKEUP_MASK 0x0C
// #define SUSPEND_MODULATION 0x0D
#define SLEEP_PIN 0x0E
#define SLEEP_PIN_ATTR 0x0F
// #define SMI_WAKEUP_MASK 0x10
#define INACTIVITY_CONTROL 0x11
#define PM_S1_CLOCKS 0x12
#define S1_CLOCKS_ON 0x00
#define S1_CLOCKS_OFF 0x01
// #define PM_S2_CLOCKS 0x13
// #define PM_S3_CLOCKS 0x14
// #define PM_S4_CLOCKS 0x15
// #define PM_S5_CLOCKS 0x16
#define PM_S0_LED 0x17
#define PM_S1_LED 0x18
#define PM_S2_LED 0x19
#define PM_S3_LED 0x1A
#define PM_S4_LED 0x1B
#define PM_S5_LED 0x1C
#define PM_LED_GPIO 0x1D
#define PM_IMM_LED 0x1E
#define PM_PWR_LEDS 0x1F
#define MB_LED0 0x01
#define MB_LED1 0x02
#define MB_LED2 0x04
#define MB_LED3 0x08
#define SIO_LED0 0x10
#define SIO_LED1 0x20
#define SIO_LED2 0x40
#define SIO_LED3 0x80
#define PM_PME_MASK 0x20
#define MAX_PM PM_PME_MASK
#define VRC_INFRARED 0x05
#define MAX_INFRARED NO_VR
#define VRC_TV 0x06 // TV Encoder Class
#define TV_ENCODER_TYPE 0x00
#define TV_CALLBACK_MASK 0x01
#define TV_MODE 0x02
#define TV_POSITION 0x03
#define TV_BRIGHTNESS 0x04
#define TV_CONTRAST 0x05
#define TV_OUTPUT 0x06
#define TV_TIMING 0x10 // 0x10...0x1D are all timings
#define MAX_TV TV_TIMING
#define VRC_EXTERNAL_AMP 0x07
#define EAPD_VERSION 0x00
#define AMP_POWER 0x01
#define AMP_OFF 0x00
#define AMP_ON 0x01
#define AMP_TYPE 0x02
#define MAX_EXTERNAL_AMP AMP_TYPE
#define VRC_ACPI 0x08
#define ENABLE_ACPI 0x00 // Enable ACPI Mode
#define SCI_IRQ 0x01 // Set the IRQ the SCI is mapped to, sysbios use.
#define ACPINVS_LO 0x02 // new calls to send 32bit physAddress of
#define ACPINVS_HI 0x03 // ACPI NVS region to VSA
#define GLOBAL_LOCK 0x04 // read requests semaphore, write clears
#define ACPI_UNUSED1 0x05
#define RW_PIRQ 0x06 // read/write PCI IRQ router regs in SB Func0 cfg space
#define SLPB_CLEAR 0x07 // clear sleep button GPIO status's
#define PIRQ_ROUTING 0x08 // read the PCI IRQ routing based on BIOS setup
#define ACPI_UNUSED2 0x09
#define ACPI_UNUSED3 0x0A
#define PIC_INTERRUPT 0x0B
#define ACPI_PRESENT 0x0C
#define ACPI_GEN_COMMAND 0x0D
#define ACPI_GEN_PARAM1 0x0E
#define ACPI_GEN_PARAM2 0x0F
#define ACPI_GEN_PARAM3 0x10
#define ACPI_GEN_RETVAL 0x11
#define MAX_ACPI ACPI_GEN_RETVAL
#define VRC_ACPI_OEM 0x09
#define MAX_ACPI_OEM NO_VR
#define VRC_POWER 0x0A
#define BATTERY_UNITS 0x00 // No. battery units
#define BATTERY_SELECT 0x01
#define AC_STATUS 0x02
#define BATTERY_STATUS 0x03
#define BATTERY_FLAG 0x04
#define BATTERY_PERCENTAGE 0x05
#define BATTERY_TIME 0x06
#define MAX_POWER BATTERY_TIME
#define VRC_OHCI 0x0B // OHCI Class
#define SET_LED 0x00
#define INIT_OHCI 0x01
#define MAX_OHCI INIT_OHCI
#define VRC_KEYBOARD 0x0C // Kbd Controller Class
#define KEYBOARD_PRESENT 0x00
#define SCANCODE 0x01
#define MOUSE_PRESENT 0x02
#define MOUSE_BUTTONS 0x03
#define MOUSE_XY 0x04
#define TYPEMATIC_DISABLE 0x05
#define MAX_KEYBOARD TYPEMATIC_DISABLE
#define VRC_DDC 0x0D // Video DDC Class
#define VRC_DDC_ENABLE 0x00 // Enable/disable register
#define DDC_DISABLE 0x00
#define DDC_ENABLE 0x01
#define VRC_DDC_IO 0x01 // A non-zero value for safety
#define MAX_DDC VRC_DDC_IO
#define VRC_DEBUGGER 0x0E
#define MAX_DEBUGGER NO_VR
#define VRC_STR 0x0F // Virtual Register class
#define RESTORE_ADDR 0x00 // Physical address of MSR restore table
#define VRC_COP8 0x10 // Virtual Register class
#define VRC_HIB_ENABLE 0x00 // HIB enable/disable index
#define HIB_ENABLE 0x00 // HIB enable command
#define HIB_DISABLE 0x01 // HIB disable command
#define VRC_HIB_SEND 0x01 // Send packet to COP8
#define VRC_HIB_READUART 0x02 // Read byte from COP8 UART
#define VRC_HIB_VERSION 0x03 // Read COP8 version
#define VRC_HIB_SERIAL 0x04 // Read 8 byte serial number
#define VRC_HIB_USRBTN 0x05 // Read POST button pressed status
#define MAX_COP8 NO_VR
#define VRC_OWL 0x11 // Virtual Register class
#define VRC_OWL_DAC 0x00 // DAC (Backlight) Control
#define VRC_OWL_GPIO 0x01 // GPIO Control
#define MAX_OWL VRC_OWL_GPIO
#define VRC_SYSINFO 0x12 // Virtual Register class
#define VRC_SI_VERSION 0x00 // Sysinfo VSM version
#define VRC_SI_CPU_MHZ 0x01 // CPU speed in MHZ
#define VRC_SI_CHIPSET_BASE_LOW 0x02
#define VRC_SI_CHIPSET_BASE_HI 0x03
#define VRC_SI_CHIPSET_ID 0x04
#define VRC_SI_CHIPSET_REV 0x05
#define VRC_SI_CPU_ID 0x06
#define VRC_SI_CPU_REV 0x07
#define MAX_SYSINFO VRC_SI_CPU_REV
#define VRC_SUPERIO 0x13
#define VRC_SIO_CHIPID 0x00
#define VRC_SIO_NUMLD 0x01
#define VRC_SIO_FDCEN 0x02
#define VRC_SIO_FDCIO 0x03
#define VRC_SIO_FDCIRQ 0x04
#define VRC_SIO_FDCDMA 0x05
#define VRC_SIO_FDCCFG1 0x06
#define VRC_SIO_FDCCFG2 0x07
#define VRC_SIO_PP1EN 0x08
#define VRC_SIO_PP1IO 0x09
#define VRC_SIO_PP1IRQ 0x0A
#define VRC_SIO_PP1DMA 0x0B
#define VRC_SIO_PP1CFG1 0x0C
#define VRC_SIO_SP1EN 0x0D
#define VRC_SIO_SP1IO 0x0E
#define VRC_SIO_SP1IRQ 0x0F
#define VRC_SIO_SP1CFG1 0x10
#define VRC_SIO_SP2EN 0x11
#define VRC_SIO_SP2IO 0x12
#define VRC_SIO_SP2IRQ 0x13
#define VRC_SIO_SP2CFG1 0x14
#define VRC_SIO_KBEN 0x15
#define VRC_SIO_KBIO1 0x16
#define VRC_SIO_KBIO2 0x17
#define VRC_SIO_KBIRQ 0x18
#define VRC_SIO_KBCFG1 0x19
#define VRC_SIO_MSEN 0x1A
#define VRC_SIO_MSIO 0x1B
#define VRC_SIO_MSIRQ 0x1C
#define VRC_SIO_RTCEN 0x1D
#define VRC_SIO_RTCIO1 0x1E
#define VRC_SIO_RTCIO2 0x1F
#define VRC_SIO_RTCIRQ 0x20
#define VRC_SIO_RTCCFG1 0x21
#define VRC_SIO_RTCCFG2 0x22
#define VRC_SIO_RTCCFG3 0x23
#define VRC_SIO_RTCCFG4 0x24
#define MAX_SUPERIO VRC_SIO_RTCCFG4
#define VRC_CHIPSET 0x14
#define VRC_CS_PWRBTN 0x00
#define VRC_CS_UART1 0x01
#define VRC_CS_UART2 0x02
#define MAX_CHIPSET VRC_CS_UART2
#define VRC_THERMAL 0x15
#define VRC_THERMAL_CURR_RTEMP 0x00 // read only
#define VRC_THERMAL_CURR_LTEMP 0x01 // read only
#define VRC_THERMAL_FAN 0x02
#define VRC_THERMAL_LOW_THRESHOLD 0x03
#define VRC_THERMAL_HIGH_THRESHOLD 0x04
#define VRC_THERMAL_INDEX 0x05
#define VRC_THERMAL_DATA 0x06
#define VRC_THERMAL_SMB_ADDRESS 0x07
#define VRC_THERMAL_SMB_INDEX 0x08
#define VRC_THERMAL_SMB_DATA 0x09
#define MAX_THERMAL VRC_THERMAL_SMB_DATA
#define MAX_VR_CLASS VRC_THERMAL

View File

@@ -0,0 +1,700 @@
/*
* 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
*/
#define VSM_SIGNATURE 0x204D5356 // 'VSM '
#define VSA_VERSION 0x03B0 // SysMgr Version
#define BYTE_IO 0x01
#define WORD_IO 0x03
#define DWORD_IO 0x0F
#define IO_WRITE 0x80
typedef unsigned char UCHAR;
typedef unsigned long ULONG;
typedef unsigned short USHORT;
#define HIWORD(p) ((USHORT) ((p) >> 16))
typedef struct {
unsigned short Alignment: 5; // 2^(n+5) (e.g. 00000 = 32-byte boundary)
unsigned short LoadHi: 1; // 1 = must load VSM above top of memory
unsigned short LoadLo: 1; // 1 = must load VSM below 1 MB
unsigned short SkipMe: 1; // 1 = Skip this VSM
unsigned short Reserved: 8;
} Requirements;
//*********************************************************************
// Structures
//*********************************************************************
typedef struct {
union {
ULONG Reg_EAX;
USHORT Reg_AX;
struct {
UCHAR Reg_AL;
UCHAR Reg_AH;
};
};
union {
ULONG Reg_EBX;
USHORT Reg_BX;
struct {
UCHAR Reg_BL;
UCHAR Reg_BH;
};
};
union {
ULONG Reg_ECX;
USHORT Reg_CX;
struct {
UCHAR Reg_CL;
UCHAR Reg_CH;
};
};
union {
ULONG Reg_EDX;
USHORT Reg_DX;
struct {
UCHAR Reg_DL;
UCHAR Reg_DH;
};
};
union {
ULONG Reg_EBP;
USHORT Reg_BP;
};
union {
ULONG Reg_ESI;
USHORT Reg_SI;
};
union {
ULONG Reg_EDI;
USHORT Reg_DI;
};
USHORT Reg_DS;
USHORT Reg_ES;
USHORT Flags;
UCHAR PIC0_Mask;
UCHAR PIC1_Mask;
} INT_REGS;
typedef struct { // Used by SVDC & RSDC instructions
USHORT limit_15_0;
USHORT base_15_0;
UCHAR base_23_16;
UCHAR attr;
#define G_BIT 0x80
#define D_BIT 0x40
UCHAR limit_19_16;
UCHAR base_31_24;
USHORT selector;
} Descriptor;
typedef struct {
ULONG Reserved;
ULONG SMM_CTL_MSR;
ULONG write_data;
USHORT IO_addr;
USHORT data_size;
union {
struct {
USHORT CS_Writable: 1;
USHORT IO_Write: 1;
USHORT REP_Prefix: 1;
USHORT SMINT: 1;
USHORT HALT: 1;
USHORT Ext_IO_Trap: 1;
USHORT External: 1;
USHORT IO_Trap: 1;
USHORT Nested: 1;
USHORT Reserved: 6;
USHORT CS_Readable: 1;
} SMI_Flags;
USHORT SMI_Flags_Ushort;
};
USHORT SS_Flags;
struct {
ULONG limit;
ULONG base;
USHORT selector;
USHORT attr;
} _CS;
union {
USHORT Next_IP;
ULONG Next_EIP;
};
union {
USHORT Current_IP;
ULONG Current_EIP;
};
ULONG r_CR0;
ULONG EFLAGS;
ULONG r_DR7;
} SmiHeader;
typedef USHORT MSG;
typedef USHORT PRIORITY;
typedef USHORT EVENT;
typedef ULONG VSM;
#define MAX_MSG_PARAM 4 // Parameter count
#define MAX_MSG_CNT 10 // # entries in message queue
typedef struct {
MSG Msg; // Message code
PRIORITY Priority; // Priority
ULONG From_VSM; // VSM that sent the message
ULONG Param[MAX_MSG_PARAM]; // Parameters
ULONG Timestamp; // Timestamp when message was entered
} Message;
typedef struct {
// VSM's state
SmiHeader State; // SMM header for this VSM
// NOTE: Flink field must be immediately after State structure
ULONG Flink; // Forward link to next VSM
ULONG Blink; // Backward link to previous VSM
ULONG SavedESP; // VSM's stack pointer
ULONG SysMgr_Ptr; // Ptr to SysMgr's InfoStuff structure
ULONG Southbridge; // PCI address of Southbridge
// Statistics
ULONG Adjustment; // Clocks used by SMM entry/exit
ULONG Clocks[2]; // Total clocks used by this VSM
ULONG NumSMIs[2]; // Total SMI count for this VSM
ULONG FrozenClocks[2]; // Copied from Clocks[]
ULONG FrozenNumSMIs[2]; // Copied from NumSMIs[]
ULONG StartTime[2]; // Timestamp @ start of timeslice
ULONG StartClocks[2]; // Timestamp of last INFO /S
// Floating Point
UCHAR FPU_State[108]; // Saved FPU state
UCHAR FPU_Flag; // Non-zero if FPU in use
UCHAR RunFlag; // VSM's scheduler state
USHORT ResumeVector; // Used by SaveToRAM
USHORT Pad[5];
// Message Queue
USHORT EndMsgQ; // Offset of *end* of message queue
USHORT Qhead; // Message queue head offset
USHORT Qtail; // Message queue tail offset
// MsgQueue is variable length, so it must be the last field
Message MsgQueue[MAX_MSG_CNT]; // The VSM's message queue
} System;
//*********************************************************************
// VSM Header
//*********************************************************************
typedef struct {
ULONG Signature; // 'VSM '
UCHAR VSM_Type; // Type of VSM
UCHAR ForCPU; // Required CPU (FFFFh for any)
USHORT ForChipset; // Required companion I/O (FFFFh for any)
USHORT VSM_Version; // Version of VSM
ULONG VSM_Length; // Length of VSM module in bytes
USHORT EntryPoint; // Offset of entry point
ULONG DS_Limit;
Requirements Flag; // Special requirements/capabilities
USHORT VSA_Version;
Descriptor _SS; // SS: descriptor for this VSM
Descriptor _DS; // DS: descriptor for this VSM
Descriptor _ES; // ES: descriptor for this VSM
USHORT AlignSystem; // SysStuff must be DWORD aligned
System SysStuff; // Reserved for use by System Manager
} VSM_Header;
//*********************************************************************
// VSM Types
//*********************************************************************
#define VSM_SYS_MGR 0x00 // System Manager
#define VSM_AUDIO 0x01 // Xpress Audio
#define VSM_VGA 0x02 // SoftVGA
#define VSM_LEGACY 0x03 // Standard AT peripherals
#define VSM_PM 0x04 // Legacy Power Management
#define VSM_OHCI 0x05 // OHCI
#define VSM_i8042 0x06 // 8042 emulator
#define VSM_DEBUGGER 0x07 // SMI based debugger
#define VSM_ACPI 0x08 // Virtual ACPI
#define VSM_APM 0x09 // APM 1.2
#define VSM_OEM_ACPI 0x0A // OEM ACPI customizations
#define VSM_SMB 0x0B // System Management Bus
#define VSM_BATTERY 0x0C // Battery controller
#define VSM_RTC 0x0D // Virtual RTC
#define VSM_S2D 0x0E // SaveToDisk
#define VSM_EXT_AMP 0x0F // External audio amplifier
#define VSM_PCMCIA 0x10 // PCMCIA
#define VSM_SPY 0x11 // Spy. Receives ALL messages first.
#define VSM_NETWORK 0x12 // Network
#define VSM_GPIO 0x13 // GPIO handler
#define VSM_KEYBOARD 0x14 // USB keyboard to PC/AT emulation
#define VSM_MOUSE 0x15 // USB mouse to PS/2 emulation
#define VSM_USB 0x16 // Universal Serial Bus
#define VSM_FLASH 0x17 // FLASH
#define VSM_INFRARED 0x18 // Infrared
#define VSM_THERMAL 0x19 // Thermal monitor
#define VSM_NULL 0x1A // Unspecified
#define VSM_MPEG 0x1B // MPEG video decoder (EMMA)
#define VSM_VIP 0x1C // Video processor (VIDEC)
#define VSM_LPC 0x1D // Low Pin Count bus
#define VSM_VUART 0x1E // Virtual UART
#define VSM_MICRO 0x1F // MicroController
#define VSM_USER1 0x20 // USER 1
#define VSM_USER2 0x21 // USER 2
#define VSM_USER3 0x22 // USER 3
#define VSM_SYSINFO 0x23 // System Information
#define VSM_SUPERIO 0x24 // PM for SuperIO
#define VSM_EHCI 0x25 // EHCI
#define VSM_MAX_TYPE VSM_EHCI // Highest valid VSM type
#define VSM_ANY 0xFF // Wildcard for SYS_BROADCAST
#define VSM_NOT_SELF 0x4000 // Flag used by SYS_BROADCAST
#define VSM_ALL_EXCEPT 0x8000 // Flag used by SYS_BROADCAST
//*********************************************************************
// SMINT codes used by non-VSA components (BIOS, INIT, etc.)
//*********************************************************************
#define SYS_BIOS_INIT 0x00F0 // VSA installation from POST
#define SYS_DOS_INSTALL 0x00F2 // VSA installation from DOS prompt
#define SYS_VSM_INSTALL 0x00F3 // Install VSM dynamically
#define SYS_REMOVE 0x00F4 // Unregister events belonging to VSM
#define SYS_INT_RETURN 0x00F5 // Return from call to INT vector
#define SYS_RESUME_FROM_RAM 0x6789 // Resume from RAM
#define SYS_END_OF_POST 0x5000 // Issued by GeodeROM at end of POST
#define SYS_INT13_SMI 0x5001 // Issued by Int 13 module (USB floppy)
#define SYS_INT13CDR_SMI 0x5003 // Issued by Int 13 module (USB CD-ROM)
#define SYS_USB_DEVICE_SMI 0x7777 // Issued by USBBOOT.ROM to access device table
//*********************************************************************
// Event Priorities
//*********************************************************************
#define NORMAL_PRIORITY 0x0000
#define MAX_PRIORITY 0x7FFF
#define BROADCAST_PRIORITY 0x9000
#define UNREGISTER_PRIORITY 0xFFF0
//*********************************************************************
// Messages
//*********************************************************************
#define MSG_INITIALIZE 0 // Perform VSM initialization
#define EARLY_INIT 0
#define END_OF_POST_INIT 1
#define MSG_SHUTDOWN 1 // Prepare for system shutdown (cold boot)
#define MSG_SAVE_STATE 2 // Save entire state of device(s) controlled by VSM
#define MSG_RESTORE_STATE 3 // Restore saved state of device(s) controlled by VSM
#define MSG_SET_POWER_STATE 4 // Set device(s) to specified power state
#define MSG_EVENT 5 // A registered event has occurred
#define MSG_QUEUE_OVERFLOW 6 // The message queue is full.
#define MSG_WARM_BOOT 7 // Prepare for a warm boot
#define MSG_SET_POWER_MODE 9 // Restore saved state of device(s) controlled by VSM
#define MSG_ABORT_POWER_STATE 10 // Power state is to be aborted
//*********************************************************************
// Events
//*********************************************************************
#define EVENT_GRAPHICS 1 // Video event
#define EVENT_AUDIO 2 // Audio event
#define EVENT_USB 3 // USB event
#define EVENT_ACPI 4 // ACPI register access
#define EVENT_ACPI_TIMER 5 // The ACPI timer expired
#define EVENT_IO_TRAP 6 // I/O trap
#define EVENT_IO_TIMEOUT 7 // I/O timeout
#define EVENT_PME 8 // Power Management
#define EVENT_KEL 9 // KEL
#define EVENT_VIDEO_INACTIVITY 0x0A // Not supported in GX2
#define EVENT_GPIO 0x0B // GPIO transition
#define FALLING_EDGE (1 << 0)
#define RISING_EDGE (1 << 1)
#define BOTH_EDGES (FALLING_EDGE | RISING_EDGE)
#define PME (1 << 2)
#define DEBOUNCE (1 << 3)
#define PULLDOWN (1 << 4)
#define PULLUP (1 << 5)
#define INVERT (1 << 6)
#define OUTPUT (1 << 7)
#define OPEN_DRAIN (1 << 8)
// INPUT may be removed as if it is not OUTPUT it is assumed to be INPUT
// this will have almost no impact on the code
// Do Not use INPUT
#define INPUT (1 << 9)
#define AUX1 (1 << 10)
#define AUX2 (1 << 11)
#define NO_ASMI (1 << 12)
#define PM1 (1 << 13)
#define GPE (1 << 14)
#define NO_ENABLE (1L << 15) // do not enable in GPE0_EN or PM1_EN
// when using EVENT_PME
#define EVENT_SOFTWARE_SMI 0x0C // Software SMI
#define EVENT_PCI_TRAP 0x0D // PCI trap
#define EVENT_VIRTUAL_REGISTER 0x0E // Virtual register access
#define EVENT_NMI 0x0F // NMI
#define EVENT_TIMER 0x10 // Millisecond timer
#define EVENT_DEVICE_TIMEOUT 0x11 // Device timeout
#define EVENT_SEMAPHORE 0x12 // ACPI global lock
#define EVENT_VBLANK 0x13 // Vertical blank
#define EVENT_A20 0x14 // A20 mask toggled
#define EVENT_SMB 0x15 // SMB Controller
#define EVENT_RTC 0x16 // RTC Alarm
#define EVENT_THERMAL 0x17 // THRM pin
#define EVENT_LPC 0x18 // Low Pin Count bus
#define EVENT_UART 0x19
#define EVENT_BLOCKIO 0x1A
#define EVENT_PWM 0x1B
#define MAX_EVENT EVENT_PWM
// Flags for event registration
#define WRITES_ONLY (1L << 16)
#define READS_ONLY (1L << 17)
#define GLIU_ID (1L << 19)
#define NOT_GLIU0 (1L << 20)
#define NOT_GLIU1 (1L << 21)
#define NOT_GLIU2 (1L << 22)
#define ALL_GLIUS (NOT_GLIU0 | NOT_GLIU1 | NOT_GLIU2)
// Flags used for EVENT_TIMER must be >= bit 24
#define ONE_SHOT (1L << 24)
#define FOR_STANDBY (1L << 25)
//*********************************************************************
// Resources
//*********************************************************************
#define RESOURCE_MEMORY 0 // Physical Memory
#define RESOURCE_MMIO 1 // Memory mapped I/O
#define RESOURCE_IO 2 // I/O space
#define RESOURCE_SCIO 3 // Swiss-cheese I/O
#define RESOURCE_GPIO 4 // General-purpose I/O pin
#define RESOURCE_IRQ 5 // IRQ
//*********************************************************************
// Macros
//*********************************************************************
#define SYS_GET_NEXT_MSG(p) sys_get_next_msg(p)
#define SYS_QUERY_MSG_QUEUE(p) sys_query_msg_queue(p)
#define SYS_UNREGISTER_EVENT(e, p1, p2) sys_register_event(e, p1, p2, UNREGISTER_PRIORITY)
#define SYS_REGISTER_EVENT(e, p1, p2, p) sys_register_event(e, p1, p2, p)
#define SYS_PASS_EVENT(e, p1, p2, p3) // no longer needed
#define SYS_VSM_PRESENT(vsm) sys_vsm_present(vsm)
#define SYS_YIELD_CONTROL(p1) sys_yield_control(p1)
#define SYS_SW_INTERRUPT(interrupt, regs) sys_software_interrupt(interrupt, regs)
#define SYS_BROADCAST_MSG(msg, p, vsm) sys_broadcast_msg(msg, p, vsm)
#define SYS_GET_SYSTEM_INFO(buffer) sys_get_system_info(buffer)
#define SYS_REPORT_ERROR(err, info1, info2) sys_report_error(err, info1, info2)
#define SYS_GENERATE_IRQ(irq) sys_generate_IRQ(irq)
#define SYS_UNLOAD_VSM() sys_unload_vsm()
#define SYS_LOGICAL_TO_PHYSICAL(addr) sys_logical_to_physical(addr)
#define SYS_ALLOCATE_RESOURCE(f,p,q,r,s) sys_resource(f, p, q, r, s)
#define SYS_DEALLOCATE_RESOURCE(f,p,q,r,s) sys_resource((UCHAR)(f|0x80), p, q, r, s)
#define SYS_MBUS_DESCRIPTOR(addr, p) sys_mbus_descriptor(addr, p, 0)
#define SYS_IO_DESCRIPTOR(addr, p) sys_mbus_descriptor(addr, p, 3)
#define SYS_LOOKUP_DEVICE(id, i) sys_lookup_device(id, i)
#define SYS_SAVE_STATE(buffer) sys_state(0, buffer)
#define SYS_RESTORE_STATE(buffer) sys_state(1, buffer)
#define SYS_SET_DECODE(addr, flag) sys_address_decode(addr, flag)
#define SYS_MAP_IRQ(Source, Irq) sys_map_irq(Source, Irq)
#define SYS_RETURN_RESULT(Data) sys_return_result(Data)
#define SYS_DUPLICATE_VSM(MemModel) sys_duplicate_vsm(MemModel)
#define READ_PCI_BYTE(addr) read_PCI_byte(addr)
#define READ_PCI_WORD(addr) read_PCI_word(addr)
#define READ_PCI_DWORD(addr) read_PCI_dword(addr)
#define WRITE_PCI_BYTE(addr, data) write_PCI_byte(addr, data)
#define WRITE_PCI_WORD(addr, data) write_PCI_word(addr, data)
#define WRITE_PCI_DWORD(addr, data) write_PCI_dword(addr, data)
#define WRITE_PCI_BYTE_NO_TRAP(addr, data) write_PCI_no_trap(addr, (ULONG)data, BYTE_IO)
#define WRITE_PCI_WORD_NO_TRAP(addr, data) write_PCI_no_trap(addr, (ULONG)data, WORD_IO)
#define WRITE_PCI_DWORD_NO_TRAP(addr, data) write_PCI_no_trap(addr, data, DWORD_IO)
#define READ_PCI_BYTE_NO_TRAP(addr) ((UCHAR)read_PCI_no_trap(addr, BYTE_IO))
#define READ_PCI_WORD_NO_TRAP(addr) ((USHORT)read_PCI_no_trap(addr, WORD_IO))
#define READ_PCI_DWORD_NO_TRAP(addr) read_PCI_no_trap(addr, DWORD_IO)
#define WRITE_MEMORY(addr, data) write_flat(addr, data)
#define READ_MEMORY(addr) read_flat(addr)
#define ENTER_CRITICAL_SECTION EnterCriticalSection();
#define EXIT_CRITICAL_SECTION ExitCriticalSection();
void __pascal sys_register_event(EVENT, ULONG, ULONG, USHORT);
void __pascal sys_software_interrupt(USHORT, INT_REGS *);
void __pascal sys_broadcast_msg(MSG, void *, USHORT);
void __pascal sys_yield_control(ULONG);
void __pascal sys_get_system_info(void *);
void __pascal sys_generate_IRQ(USHORT);
void __pascal sys_state(USHORT, void *);
void __pascal sys_address_decode(USHORT, USHORT);
void __pascal sys_map_irq(UCHAR, UCHAR);
void __pascal sys_return_result(ULONG);
void __pascal sys_get_descriptor(USHORT, void *);
void __pascal sys_set_descriptor(USHORT, void *);
void __pascal sys_set_header_data(USHORT, ULONG);
void __pascal sys_set_register(USHORT, ULONG);
void __pascal sys_set_virtual_register(USHORT, USHORT);
void __pascal sys_report_error(USHORT, ULONG, ULONG);
void __pascal write_PCI_byte(ULONG, UCHAR);
void __pascal write_PCI_word(ULONG, USHORT);
void __pascal write_PCI_dword(ULONG, ULONG);
void __pascal write_PCI_no_trap(ULONG, ULONG, USHORT);
void EnterCriticalSection(void);
void ExitCriticalSection(void);
void sys_fast_path_return(void);
void sys_unload_vsm(void);
void __pascal sys_duplicate_vsm(USHORT);
void __pascal write_flat(ULONG, ULONG);
ULONG __pascal read_flat(ULONG);
UCHAR __pascal sys_vsm_present(UCHAR);
USHORT __pascal sys_get_virtual_register(USHORT);
ULONG __pascal sys_get_header_data(USHORT);
ULONG __pascal sys_get_register(USHORT);
UCHAR __pascal read_PCI_byte(ULONG);
USHORT __pascal read_PCI_word(ULONG);
ULONG __pascal read_PCI_dword(ULONG);
ULONG __pascal read_PCI_no_trap(ULONG, USHORT);
ULONG __pascal sys_logical_to_physical(void *);
ULONG __pascal sys_resource(UCHAR, USHORT, ULONG, USHORT, USHORT);
ULONG __pascal sys_mbus_descriptor(USHORT, ULONG *, USHORT);
ULONG __pascal sys_lookup_device(USHORT, USHORT);
MSG sys_get_next_msg(void *);
MSG sys_query_msg_queue(void *);
// Macros for use by VSMs to access the non-SMM context
#define SET_HEADER_DATA(reg, data) sys_set_header_data(reg, data)
#define GET_HEADER_DATA(reg) (ULONG)sys_get_header_data(reg)
#define GET_DESCRIPTOR(reg, buffer) sys_get_descriptor(reg, buffer);
#define SET_DESCRIPTOR(reg, buffer) sys_set_descriptor(reg, buffer);
#define GET_REGISTER(reg) (ULONG)sys_get_register(reg)
#define SET_REGISTER(reg, data) sys_set_register(reg, data)
#define SET_EAX(data) SET_REGISTER(R_EAX, (ULONG) (data))
#define SET_AX(data) SET_REGISTER(R_AX, (USHORT)(data))
#define SET_AL(data) SET_REGISTER(R_AL, (UCHAR) (data))
#define SET_AH(data) SET_REGISTER(R_AH, (UCHAR) (data))
#define SET_EFLAGS(data) SET_HEADER_DATA(R_EFLAGS, data)
#define GET_EAX() ((ULONG) GET_REGISTER(R_EAX))
#define GET_AX() ((USHORT)GET_REGISTER(R_AX))
#define GET_AL() ((UCHAR) GET_REGISTER(R_AL))
#define GET_AH() ((UCHAR) GET_REGISTER(R_AH))
#define GET_EFLAGS() (GET_HEADER_DATA(R_EFLAGS))
// Macros for accessing virtual registers
#define GET_VIRTUAL_REGISTER(reg) (USHORT)sys_get_virtual_register(reg)
#define SET_VIRTUAL_REGISTER(reg, data) sys_set_virtual_register(reg, data)
//*********************************************************************
// Error Codes
//*********************************************************************
#define ERR_UNDEF_EVENT 1 // Attempt to register an undefined event
//#define ERR_SCHEDULER 2 // Scheduler error
#define ERR_BAD_PARAMETER 3 // Illegal system call parameter
#define ERR_RESOURCE_CONFLICT 4 // Multiple VSMs requested conflicting resources
#define ERR_UNHANDLED_EVENT 5 // An event occurred that no VSM handled
#define ERR_INVALID_EVENT 6 // SysMgr attempted to send an invalid event
//#define ERR_TIME_LIMIT 7 // A VSM exceeded its allotted runtime
#define ERR_REGISTRATION_LOST 8 // A registered event is lost due to too many event registrations
#define ERR_HW_MISMATCH 9 // A VSM could not find the correct hardware (e.g. OHCI)
#define ERR_BAD_DESCRIPTOR 0x0A // A descriptor in a VSM header is not valid
//#define ERR_MSG_QUEUE_FULL 0x0B // A VSM's message queue is full
//#define ERR_MULTIPLE_EVENT 0x0C // A VSM attempted to register the same event twice
#define ERR_UNREGISTRATION 0x0D // A VSM attempted to unregister an event for which it was not registered
#define ERR_UNREGISTERED_EVENT 0x0E // An event occurred for which no VSM is registered
#define ERR_MISALIGNED_IO 0x0F // An misaligned I/O access occurred
//#define ERR_UNEXPECTED_EVENT 0x10 // A handler routine was passed an unexpected SMI event
//#define ERR_BAD_VSM 0x11 // A VSM header doesn't look right (no signature, etc.)
#define ERR_NESTED_ACCESS 0x12 // A VSM directly accessed a ACPI or virtual register
//#define ERR_BAD_MSG 0x13 // An attempt was made to send an illegal message code
//#define ERR_UNHANDLED_VIRTUAL 0x14 // An access was made by a VSM to an unhandled virtual register
#define ERR_BAD_INTERRUPT 0x15 // A VSM attempted to call an illegal INT vector
#define ERR_ILLEGAL_MACRO 0x16 // Illegal use of GET/SET_REGISTER or GET/SET_HEADER_DATA macros
#define ERR_UNDEF_SYS_CALL 0x17 // Undefined system call
//#define ERR_BAD_POWER_STATE 0x18 // Invalid power state
#define ERR_BAD_VR_ACCESS 0x19 // Access to undefined VR class by an application
#define ERR_UNDEF_VIRTUAL_REG 0x1A // Access to undefined VR class by a VSM
//#define ERR_UNSUPPORTED_CHIPSET 0x1B // This chipset is not supported
#define ERR_PCI_TRAP 0x1C // A VSM requested an unsupported PCI trap
#define ERR_RESOURCE_NOT_FOUND 0x1D // A VSM requested an unsupported resource
#define ERR_NO_MORE_DESCRIPTORS 0x1E // Out of MBIU descriptors
//#define ERR_INTERNAL_ERROR 0x1F // System error, e.g. inconsistent data structure
#define ERR_DATA_STRUCTURE 0x20 // A system structure is too small
// Used as 2nd parameter to SYS_SET_DECODE macro:
#define POSITIVE_DECODE 1
#define SUBTRACTIVE_DECODE 0
//****************************************************************************************************
#define FROM_HEADER 0x2000
#define WORD_SIZE 0x4000
#define DWORD_SIZE 0x8000
// Field names for GET_REGISTER and SET_REGISTER macros
// These offsets must match the register order on the stack (PUSHAD)
#define R_DI 0 + WORD_SIZE
#define R_EDI 0 + DWORD_SIZE
#define R_SI 4 + WORD_SIZE
#define R_ESI 4 + DWORD_SIZE
#define R_BP 8 + WORD_SIZE
#define R_EBP 8 + DWORD_SIZE
#define R_BL 16
#define R_BH R_BL + 1
#define R_BX R_BL + WORD_SIZE
#define R_EBX R_BL + DWORD_SIZE
#define R_DL 20
#define R_DH R_DL + 1
#define R_DX R_DL + WORD_SIZE
#define R_EDX R_DL + DWORD_SIZE
#define R_CL 24
#define R_CH R_CL + 1
#define R_CX R_CL + WORD_SIZE
#define R_ECX R_CL + DWORD_SIZE
#define R_AL 28
#define R_AH R_AL + 1
#define R_AX R_AL + WORD_SIZE
#define R_EAX R_AL + DWORD_SIZE
#define R_SP 32 + WORD_SIZE
#define R_ESP 32 + DWORD_SIZE
// Segment registers
// NOTE: offset points to .selector field
#define DESCRIPTOR_SIZE 10 // sizeof(Descriptor)
#define R_SS 36-2 + DESCRIPTOR_SIZE + WORD_SIZE
#define R_DS R_SS + DESCRIPTOR_SIZE
#define R_ES R_DS + DESCRIPTOR_SIZE
#define R_FS R_ES + DESCRIPTOR_SIZE
#define R_GS R_FS + DESCRIPTOR_SIZE
// Fields from SMM header
#define WRITE_DATA 0x08 + DWORD_SIZE + FROM_HEADER
#define IO_ADDRESS 0x0C + WORD_SIZE + FROM_HEADER
#define DATA_SIZE 0x0E + FROM_HEADER
#define SMM_FLAGS 0x10 + WORD_SIZE + FROM_HEADER
#define CS_LIMIT 0x14 + DWORD_SIZE + FROM_HEADER
#define CS_BASE 0x18 + DWORD_SIZE + FROM_HEADER
#define CS_SELECTOR 0x1C + WORD_SIZE + FROM_HEADER
#define CS_ATTR 0x1E + WORD_SIZE + FROM_HEADER
#define R_CS 0x1C + WORD_SIZE + FROM_HEADER
#define R_IP 0x20 + WORD_SIZE + FROM_HEADER
#define R_EIP 0x20 + DWORD_SIZE + FROM_HEADER
#define CURRENT_EIP 0x24 + DWORD_SIZE + FROM_HEADER
#define R_CR0 0x28 + DWORD_SIZE + FROM_HEADER
#define R_EFLAGS 0x2C + DWORD_SIZE + FROM_HEADER
#define EFLAGS_CF 0x0001
#define EFLAGS_ZF 0x0040
#define EFLAGS_IF 0x0200
#define EFLAGS_DF 0x0400
#define R_DR7 0x30 + DWORD_SIZE + FROM_HEADER
typedef struct {
ULONG Chipset_Base;
USHORT Chipset_ID;
USHORT Chipset_Rev;
USHORT CPU_ID;
USHORT CPU_Revision;
USHORT CPU_MHz;
ULONG SystemMemory; // Units = bytes
ULONG VSA_Location; // Physical location
USHORT VSA_Size; // Units = KB
USHORT PCI_MHz;
USHORT DRAM_MHz;
} Hardware;

View File

@@ -0,0 +1,88 @@
/*
* 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
*/
//* Function: *
//* Handler for blocked PIO during UDMA
#include "vsa2.h"
#include "protos.h"
#define RESET_DRIVE 0x08
USHORT UDMA_IO_Base;
//***********************************************************************
// Enables/disables BLOCKIO
//***********************************************************************
void pascal BlockIO(UCHAR EnableFlag)
{ USHORT Priority=UNREGISTER_PRIORITY;
if (EnableFlag) {
Priority = MAX_PRIORITY;
}
SYS_REGISTER_EVENT(EVENT_BLOCKIO, 0, 0, Priority);
}
//***********************************************************************
// Handler for EVENT_BLOCKIO
//***********************************************************************
void Handle_BLOCKIO(USHORT IO_Address, ULONG Data, UCHAR DataSize)
{ UCHAR Command;
switch (IO_Address) {
case 0x1F7:
// Check for drive reset command
if ((UCHAR)Data == RESET_DRIVE) {
break;
}
return;
case 0x3F6:
if ((UCHAR)Data & 4) {
break;
}
default:
// Ignore I/O to all other IDE registers
return;
}
// Disable BLOCKIO
BlockIO(0);
// Terminate bus mastering
Command = in_8(UDMA_IO_Base);
out_8(UDMA_IO_Base, (UCHAR)(Command & ~1));
// Re-issue the I/O
out_8(IO_Address, (UCHAR)Data);
// Re-enable BLOCKIO
BlockIO(1);
}

View File

@@ -0,0 +1,479 @@
/*
* 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
*/
//* Function: *
//* This file contains routines specific to the CS5536.
#include "vsa2.h"
#include "chipset.h"
#include "pci.h"
#include "vr.h"
#include "mapper.h"
#include "gx2.h"
#include "legacy.h"
#include "protos.h"
#include "isa.h"
// External Function prototypes
extern void GetDrivesPresent(void);
extern void Allocate_Flash_BARs(void);
extern void pascal Flash_IDE_Switch(USHORT, ULONG);
extern void BlockIO(UCHAR);
extern void Register_DMA_Fix(void);
extern UCHAR FlashIsEnabled(void);
// Local function prototypes:
void Handle_5536_PCI_Traps(USHORT, USHORT, ULONG);
void Register_PCI_Trap(USHORT, UCHAR);
// External variables:
extern Hardware SystemInfo;
extern ULONG ChipsetBase;
extern ULONG Param[];
extern USHORT UDMA_IO_Base;
extern ULONG OHCI_Address[];
// Local variables:
typedef void (* PCI_HANDLER)(USHORT, USHORT, ULONG);
extern PCI_HANDLER Handle_PCI_Traps;
USHORT uart1 = 0;
USHORT uart2 = 0;
USHORT Flash_Function=0x00FF, IDE_Function = 0x00FF;
USHORT PCI_Int_AB = ((USHORT)((INTB_PIN << 8) | INTA_PIN));
USHORT PCI_Int_CD = ((USHORT)((INTD_PIN << 8) | INTC_PIN));
USHORT Y_Sources[8];
USHORT Flash_PME;
USHORT Steering = 0x0000;
USHORT Hidden_Function = 0x0000;
UCHAR IDE_Allocated = 0;
UCHAR Flash_Allocated = 0;
ULONG MDD_Base;
USHORT pmc_base = 0;
USHORT gpio_base = 0;
USHORT acpi_base = 0;
typedef struct {
UCHAR Pin;
UCHAR Z_Source;
UCHAR Lbar;
} PCI_INTERRUPT;
PCI_INTERRUPT PCI_Interrupt[] = {
// Pin Z_Source
{INTA_PIN, Z_IRQ_INTA},
{INTB_PIN, Z_IRQ_INTB},
{INTC_PIN, Z_IRQ_INTC},
{INTD_PIN, Z_IRQ_INTD}
};
//***********************************************************************
// Hides the PCI header of the specified function
//***********************************************************************
void Hide_Hdr(USHORT Function)
{
// If a function is currently being hidden, un-hide it
if (Hidden_Function) {
SYS_UNREGISTER_EVENT(EVENT_PCI_TRAP, ChipsetBase+Hidden_Function, 0x000000FF);
SYS_UNREGISTER_EVENT(EVENT_PCI_TRAP, ChipsetBase+Function+0x40, WRITES_ONLY);
}
// Register for IDE/Flash config space (to make invisible)
Register_PCI_Trap(Function, 0xFF);
// Record which function is hidden
Hidden_Function = Function;
// Get the 'other' function
if (Function == IDE_Function) {
Function = Flash_Function;
} else {
Function = IDE_Function;
}
// Trap IDE/Flash register 0x40 (used for Flash<->IDE switch)
SYS_REGISTER_EVENT(EVENT_PCI_TRAP, ChipsetBase+Function+0x40, WRITES_ONLY, 0);
}
//***********************************************************************
// Maps the NAND Flash PMEs to the specified IRQ
//***********************************************************************
void Map_Flash_IRQ(UCHAR Irq)
{
SYS_MAP_IRQ((UCHAR)(Flash_PME+0), Irq);
SYS_MAP_IRQ((UCHAR)(Flash_PME+1), Irq);
}
//***********************************************************************
// Hides the IDE function and un-hides the Flash function
//***********************************************************************
void Hide_IDE_Hdr(void)
{ UCHAR Shift, Irq;
// Map NAND Flash interrupts
Shift = (UCHAR)(((Flash_PME >> 8)-1) * 4);
Irq = (UCHAR)(Steering >> Shift) & 0x0F;
Map_Flash_IRQ(Irq);
// Hide the IDE header
Hide_Hdr(IDE_Function);
}
//***********************************************************************
// Hides the Flash function and un-hides the IDE function
//***********************************************************************
void Hide_Flash_Hdr(void)
{ USHORT Bar;
// Unmap NAND Flash interrupts
Map_Flash_IRQ(0);
// If Flash BARs have been allocated, then zero them to disable linked MSRs
if (Flash_Allocated) {
for (Bar = BAR0; Bar <= BAR3; Bar += 0x10) {
WRITE_PCI_DWORD(ChipsetBase+IDE_Function+Bar, 0x00000000);
}
}
Hide_Hdr(Flash_Function);
if (!IDE_Allocated) {
// Allocate UDMA BAR
SYS_ALLOCATE_RESOURCE(RESOURCE_IO, BAR4, 16, DEVICE_ID_AMD_THOR, ID_ATA);
IDE_Allocated = 1;
}
}
//***********************************************************************
// Performs early initialization for CS5536
//***********************************************************************
void CS5536_Early_Init(void)
{ USHORT Function;
ULONG PciAddr, PciData;
Handle_PCI_Traps = Handle_5536_PCI_Traps;
MDD_Base = SYS_LOOKUP_DEVICE(ID_MDD, 1);
// Get I/O base of PMC, ACPI & GPIO
pmc_base = READ_PCI_WORD(ChipsetBase + BAR4) & 0xFFFE;
gpio_base = READ_PCI_WORD(ChipsetBase + BAR1) & 0xFFFE;
acpi_base = READ_PCI_WORD(ChipsetBase + BAR5) & 0xFFFE;
// Scan Southbridge functions to:
// - Get Unrestricted Sources Y IRQ.
// - Find Flash & IDE functions.
for (Function = 0; Function < 8; Function++) {
// Generate PCI configuration address
PciAddr = ChipsetBase | (Function << 8);
// For functions that have PCI interrupts, Interrupt Line
// contains Y Sources field number.
(UCHAR)PciAddr = INTERRUPT_LINE;
// If PCI interrupt is defined, record linked Unrestricted Y Source
Y_Sources[Function] = READ_PCI_WORD(PciAddr);
if (Y_Sources[Function]) {
// clear Interrupt Line
WRITE_PCI_WORD(PciAddr, 0x0000);
}
// Read Class Code
(UCHAR)PciAddr = REVISION_ID;
PciData = READ_PCI_DWORD(PciAddr);
// Ignore Revision ID
PciData &= 0xFFFFFF00;
// Record function # of Flash header
if (PciData == 0x05010000) {
Flash_Function = (USHORT)PciAddr & 0x0700;
Flash_PME = Y_Sources[Function];
}
// Record function # of IDE header
if (PciData == 0x01018000) {
IDE_Function = (USHORT)PciAddr & 0x0700;
Y_Sources[Function] = Flash_PME+1;
}
}
switch (SystemInfo.Chipset_ID) {
case DEVICE_ID_5536:
SYS_REGISTER_EVENT(EVENT_PCI_TRAP, ChipsetBase+IDE_Function+BAR4, WRITES_ONLY, 0);
break;
}
// Is Flash controller enabled ?
if (FlashIsEnabled()) {
// Allocate Flash BARs
Allocate_Flash_BARs();
// Hide the IDE header
Hide_IDE_Hdr();
} else {
// Hide the Flash header
Hide_Flash_Hdr();
}
// Register for virtual registers VRC_MISCELLANEOUS::PCI_INT_AB->WATCHDOG
SYS_REGISTER_EVENT(EVENT_VIRTUAL_REGISTER, VRC_MISCELLANEOUS, (PCI_INT_AB<<8) | WATCHDOG, MAX_PRIORITY);
// Register for SB PCI register 0x5C-0x5D (emulation of 5530 PCI steering register)
Register_PCI_Trap(0x005C, 0x01);
/*MEJ
// If Power Management VSM is present...
if (SYS_VSM_PRESENT(VSM_PM)) {
// Register for virtual register timeouts on legacy devices
SYS_REGISTER_EVENT(EVENT_VIRTUAL_REGISTER, VRC_PM, (DISK_TIMEOUT<<8) | PARALLEL_TIMEOUT, 0);
}
*/
// Register for virtual register class VRC_CHIPSET
SYS_REGISTER_EVENT(EVENT_VIRTUAL_REGISTER, VRC_CHIPSET, 0, NORMAL_PRIORITY);
}
//***********************************************************************
// Performs End-of-POST initialization for CS5536
//***********************************************************************
void CS5536_Late_Init(void)
{
// Determine how many ATA drives are present
GetDrivesPresent();
// Set ISA bridge Latency Timer to 0x40
WRITE_PCI_BYTE(ChipsetBase + LATENCY_TIMER, 0x40);
}
//***********************************************************************
// Handler for writes to VRC_MISCELLANEOUS PCI_INT_AB & PCI_INT_CD
// These registers define what GPIOs are to be used for PCI interrupts.
//***********************************************************************
void Handle_Misc_VR(UCHAR Index, USHORT Data)
{ int i, j;
ULONG Param2;
static UCHAR Flag = 0x00;
if (Index == PCI_INT_AB) {
// PCI interrupt GPIOs can only be allocated once
if (Flag & 1) {
return;
}
// Record data for readback
PCI_Int_AB = Data;
Flag |= 1;
i = 0;
} else {
// PCI interrupt GPIOs can only be allocated once
if (Flag & 2) {
return;
}
// Record data for readback
PCI_Int_CD = Data;
Flag |= 2;
i = 2;
}
// Set GPIOs as level-sensitive (no ASMI!), inverted inputs
j = i + 2;
while (i < j) {
// Record the GPIO pin
PCI_Interrupt[i].Pin = (UCHAR)Data;
if (PCI_Interrupt[i].Pin < 32) {
Param2 = ((ULONG)PCI_Interrupt[i].Z_Source << 16) | PCI_Interrupt[i].Pin;
SYS_REGISTER_EVENT(EVENT_GPIO, Param2, INVERT, MAX_PRIORITY);
}
// Shift the next pin # into the 8 LSBs
Data >>= 8;
i++;
}
}
//***********************************************************************
// Emulates CS5530's PCI Interrupt steering registers 0x5C & 0x5D
// Register 0x5C:
// 3:0 INTA#
// 7:4 INTB#
// Register 0x5D:
// 3:0 INTC#
// 7:4 INTD#
// Maps PCI INT pins to Unrestricted Z sources
//***********************************************************************
void PCI_Interrupt_Steering(USHORT Data)
{ UCHAR i, j, Irq;
// Register for PCI interrupt GPIOs in case BIOS never wrote to the VR
Handle_Misc_VR(PCI_INT_AB, PCI_Int_AB);
Handle_Misc_VR(PCI_INT_CD, PCI_Int_CD);
for (i=0; i < 4; i++) {
// Extract IRQ from next nibble
Irq = (UCHAR)(Data & 0x0F);
// Don't allow IRQ2 (SMI)
if (Irq != 2) {
// Map the Unrestricted Z Source to the requested IRQ
SYS_MAP_IRQ((UCHAR)(PCI_Interrupt[i].Z_Source+16), Irq);
// Map the Unrestricted Y Source (if any) to the requested IRQ
for (j=0; j < 8; j++) {
UCHAR InterruptPin;
InterruptPin = (UCHAR)(Y_Sources[j] >> 8);
if (InterruptPin == i+1) {
SYS_MAP_IRQ((UCHAR)Y_Sources[j], Irq);
}
}
}
// Shift the next nibble into the 4 LSBs
Data >>= 4;
}
}
//***********************************************************************
// Handler for emulation of 5530 PCI steering registers on a 5536 system
//***********************************************************************
void Handle_5536_PCI_Traps(USHORT PCI_Addr, USHORT IO_Params, ULONG Data)
{ UCHAR PCI_Reg, Shift, IO_Size;
USHORT Function;
PCI_Reg = (UCHAR) PCI_Addr;
IO_Size = (UCHAR) IO_Params;
Function = PCI_Addr & 0x0700;
Shift = (PCI_Reg & 3) << 3;
// Record OHCI BAR values
if (PCI_Addr == 0x7C10 || PCI_Addr == 0x7D10) {
if (IO_Params & IO_WRITE) {
Function = (Function >> 8) - 4;
OHCI_Address[Function] = Data & 0xFFFFF000;
}
return;
}
// PCI Interrupt Steering register
if (Function == 0x0000) {
if (IO_Params & IO_WRITE) {
// Handle mis-aligned accesses
if (Shift) {
Steering &= 0x00FF;
Steering |= (USHORT)Data << 8;
} else {
Steering = (USHORT)Data;
}
PCI_Interrupt_Steering(Steering);
return;
} else {
if (PCI_Reg < 0x5C) {
Data = (ULONG)Steering << (32-Shift);
Shift = 0;
} else {
Data = Steering;
}
}
} else {
// Flash/IDE configuration space
if (Function == Flash_Function || Function == IDE_Function) {
if (IO_Params & IO_WRITE) {
// PCI writes to IDE/Flash function
switch (PCI_Reg) {
case BAR4:
if (Function == IDE_Function && (USHORT)Data != 0xFFFF) {
// Record UDMA I/O base for BLOCK_IO logic
UDMA_IO_Base = (USHORT)Data & 0xFFF0;
}
break;
// Write to IDE<->Flash switch
case 0x40:
if (Data == 0xDEADBEEF || Data == 0xBEEFDEAD) {
// Switch Flash<->IDE
Flash_IDE_Switch(Function, Data);
}
}
return;
} else {
// PCI reads of hidden function
if (Function == Hidden_Function) {
Data = 0xFFFFFFFF;
}
}
}
}
// Handle non-dword aligned accesses
Data >>= Shift;
Data |= 0xFFFFFFFFL << (32-Shift);
// Return the PCI register value
SYS_RETURN_RESULT(Data);
}
//***********************************************************************
// Registers a PCI trap for the specified Addr/Mask
//***********************************************************************
void Register_PCI_Trap(USHORT Addr, UCHAR Mask)
{
SYS_REGISTER_EVENT(EVENT_PCI_TRAP, ChipsetBase+Addr, (ULONG)Mask, 0);
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright (c) 2006 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
*/
//* Function: *
//* This file handles the Legacy VSM's event messages.
#include "vsa2.h"
#include "chipset.h"
#include "vr.h"
#include "legacy.h"
#include "protos.h"
#include "pci.h"
#include "isa.h"
// Function prototypes
extern void Handle_BLOCKIO(USHORT, ULONG, UCHAR);
extern void Handle_VirtualRegs(UCHAR, UCHAR, UCHAR, USHORT);
extern void Do_OHCI_SWAPSiF(void);
// External variables:
extern ULONG ChipsetBase;
extern USHORT DiskTimeout, SerialTimeout, ParallelTimeout, FloppyTimeout;
// Local variables:
USHORT IDE_Interface = MASTER_IDE; // Default to "bus master capable"
typedef void (* PCI_HANDLER)(USHORT, USHORT, ULONG);
PCI_HANDLER Handle_PCI_Traps;
//***********************************************************************
// Register I/O trap to fix 118.409 - Block/Demand mode fails
//***********************************************************************
void Register_DMA_Fix(void)
{
#define DMA_FLAGS (WRITES_ONLY | ONE_SHOT)
SYS_REGISTER_EVENT(EVENT_IO_TRAP, DMA1_MODE, DMA_FLAGS | 1, 0);
}
//***********************************************************************
// Handler for MSG_EVENT
//***********************************************************************
void Handle_Events(ULONG * Param)
{ USHORT Event, IO_Address;
ULONG Data;
UCHAR WrFlag, DataSize, Class, Index;
Event = (USHORT)Param[0];
IO_Address = (USHORT)Param[2];
DataSize = (UCHAR)(Param[2] >> 16);
Data = Param[3];
switch (Event) {
case EVENT_IO_TRAP:
// If it is an I/O to the 8237 DMA controller...
if (IO_Address == DMA1_MODE) {
static UCHAR Mode = 0x00;
UCHAR ByteData;
// and it is a I/O write...
if (Param[1] & 2) {
ByteData = (UCHAR)Data;
// and the Mode is either Block or Demand...
Mode = ByteData & MODE_MASK;
if (Mode == MODE_DEMAND || Mode == MODE_BLOCK) {
// then change the mode to Single
ByteData &= ~MODE_MASK;
ByteData |= MODE_SINGLE;
}
// Re-issue the I/O (trapping is disabled since it was a ONE_SHOT)
out_8(DMA1_MODE, ByteData);
}
// Re-register for the I/O trap
Register_DMA_Fix();
break;
}
// Handle PM traps here...
break;
case EVENT_IO_TIMEOUT:
// Handle PM timeout here...
break;
case EVENT_SOFTWARE_SMI:
if (Param[1] == SYS_DMA_DRIVER) {
// Allow the UDMA driver to see that IDE is bus master capable.
IDE_Interface = MASTER_IDE;
} else if (Param[1] == SYS_DMA_DRIVER+1) {
// Prevent the UDMA driver from seeing that IDE is bus master capable.
IDE_Interface = 0;
}
break;
case EVENT_PCI_TRAP:
Handle_PCI_Traps((USHORT)Param[1], (USHORT)Param[2], Data);
break;
case EVENT_VIRTUAL_REGISTER:
// Extract virtual register parameters from message
Class = (UCHAR)(Param[1] >> 8);
Index = (UCHAR)Param[1];
WrFlag = (UCHAR)Param[2];
Handle_VirtualRegs(Class, Index, WrFlag, (USHORT)Data);
break;
case EVENT_BLOCKIO:
Handle_BLOCKIO(IO_Address, Data, DataSize);
break;
case EVENT_TIMER:
// Fix for attach/detach hardware bug
if (Param[2] == USBF_HANDLE) {
Do_OHCI_SWAPSiF();
break;
}
/*MEJ // Broadcast to all VSM's
Param[0] = S5_STATE;
Param[1] = CLASS_ALL;
SYS_BROADCAST_MSG(MSG_SET_POWER_STATE, &Param[0], VSM_ANY);
*/
break;
}
}

View File

@@ -0,0 +1,174 @@
/*
* 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
*/
//******************************************************************************
//* Routines related to the Flash device.
//******************************************************************************
#include "VSA2.H"
#include "CHIPSET.H"
#include "SYSMGR.H"
#include "MDD.H"
#include "PCI.H"
#include "GX2.H"
#include "LEGACY.H"
#include "PROTOS.H"
// Function prototypes:
extern void Hide_IDE_Hdr(void);
extern void Hide_Flash_Hdr(void);
// External variables:
extern ULONG MDD_Base;
extern USHORT Flash_Function, IDE_Function;
extern UCHAR Flash_Allocated;
//***********************************************************************
// Returns non-zero if Flash device is enabled
//***********************************************************************
UCHAR FlashIsEnabled(void)
{ UCHAR Pin;
Pin = (UCHAR)Read_MSR_LO(MDD_Base + MSR_PIN_OPTS) & PIN_OPT_IDE;
Pin ^= PIN_OPT_IDE;
return Pin;
}
//***********************************************************************
// Allocates Flash BARs
//***********************************************************************
void Allocate_Flash_BARs(void)
{ ULONG MsrAddr, MsrData[2], Size;
USHORT Bar;
UCHAR Resource;
static UCHAR Flash_LBARs[4] = {
MSR_LBAR_FLSH0,
MSR_LBAR_FLSH1,
MSR_LBAR_FLSH2,
MSR_LBAR_FLSH3,
};
// BARs are only to be allocated once
if (Flash_Allocated == 0) {
Flash_Allocated = 1;
// Determine type/size of PCI BAR for each Flash device
MsrAddr = MDD_Base;
for (Bar = BAR0; Bar <= BAR3; Bar += 4) {
// Read the Flash LBAR
(UCHAR)MsrAddr = Flash_LBARs[(Bar-BAR0)/4];
Read_MSR(MsrAddr, MsrData);
// If LBAR size has not been programmed, then don't configure the PCI BAR
Size = MsrData[1] & ~(MEM_IO | NOR_NAND | LBAR_EN);
if (Size == 0x00000000) {
continue;
}
// NAND or NOR Flash ?
if (MsrData[1] & NOR_NAND) {
// NAND Flash
// Required for proper byte count calculation
Size |= 0xFFFF0000;
Resource = RESOURCE_IO;
} else {
// NOR Flash
Size &= LBAR_MEM_MASK;
Resource = RESOURCE_MMIO;
}
// Convert mask to byte count
Size = ~Size + 1;
// Allocate BAR
SYS_ALLOCATE_RESOURCE(Resource, Bar, Size, DEVICE_ID_AMD_FLASH, ID_MDD);
}
}
}
//***********************************************************************
// Switches between Flash and IDE headers
//***********************************************************************
void pascal Flash_IDE_Switch(USHORT Function, ULONG Data)
{ ULONG PinOptions, PinMsr, FlashMsr, LBar[2], SavedLBar[2];
// Switch pins to Flash mode
PinMsr = MDD_Base + MSR_PIN_OPTS;
PinOptions = Read_MSR_LO(PinMsr);
if (Function == Flash_Function) {
// Currently in Flash mode
// Switching to IDE mode ?
if (Data == 0xBEEFDEAD) {
// Hide the Flash header
Hide_Flash_Hdr();
// Switch pins to IDE mode
PinOptions |= PIN_OPT_IDE;
Write_MSR_LO(PinMsr, PinOptions);
// Disconnect the ROM from the DMA pins
in_8(0x3F6);
}
} else {
// Currently in IDE mode
// Switching to Flash mode ?
if (Data == 0xDEADBEEF) {
// Hide the IDE header
Hide_IDE_Hdr();
// Allocate Flash BARs
Allocate_Flash_BARs();
// Enable Flash mode
PinOptions &= ~PIN_OPT_IDE;
Write_MSR_LO(PinMsr, PinOptions);
// Handle Canary circuit
// Set CS1# to respond to I/O address 22h
FlashMsr = MDD_Base + MSR_LBAR_FLSH1;
Read_MSR(FlashMsr, SavedLBar);
LBar[0] = 0x00000022;
LBar[1] = 0x0000FFF0 | LBAR_EN;
Write_MSR(FlashMsr, LBar);
// Turn Canary circuit on
in_8(0x22);
// Restore CS1 LBAR
Write_MSR(FlashMsr, SavedLBar);
}
}
}

View File

@@ -0,0 +1,174 @@
/*
* 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
*/
//******************************************************************************
//* Routines related to the Flash device.
//******************************************************************************
#include "VSA2.H"
#include "CHIPSET.H"
#include "SYSMGR.H"
#include "MDD.H"
#include "PCI.H"
#include "GX2.H"
#include "LEGACY.H"
#include "PROTOS.H"
// Function prototypes:
extern void Hide_IDE_Hdr(void);
extern void Hide_Flash_Hdr(void);
// External variables:
extern ULONG MDD_Base;
extern USHORT Flash_Function, IDE_Function;
extern UCHAR Flash_Allocated;
//***********************************************************************
// Returns non-zero if Flash device is enabled
//***********************************************************************
UCHAR FlashIsEnabled(void)
{ UCHAR Pin;
Pin = (UCHAR)Read_MSR_LO(MDD_Base + MSR_PIN_OPTS) & PIN_OPT_IDE;
Pin ^= PIN_OPT_IDE;
return Pin;
}
//***********************************************************************
// Allocates Flash BARs
//***********************************************************************
void Allocate_Flash_BARs(void)
{ ULONG MsrAddr, MsrData[2], Size;
USHORT Bar;
UCHAR Resource;
static UCHAR Flash_LBARs[4] = {
MSR_LBAR_FLSH0,
MSR_LBAR_FLSH1,
MSR_LBAR_FLSH2,
MSR_LBAR_FLSH3,
};
// BARs are only to be allocated once
if (Flash_Allocated == 0) {
Flash_Allocated = 1;
// Determine type/size of PCI BAR for each Flash device
MsrAddr = MDD_Base;
for (Bar = BAR0; Bar <= BAR3; Bar += 4) {
// Read the Flash LBAR
(UCHAR)MsrAddr = Flash_LBARs[(Bar-BAR0)/4];
Read_MSR(MsrAddr, MsrData);
// If LBAR size has not been programmed, then don't configure the PCI BAR
Size = MsrData[1] & ~(MEM_IO | NOR_NAND | LBAR_EN);
if (Size == 0x00000000) {
continue;
}
// MMIO or IO resource
if (MsrData[1] & MEM_IO ) {
// MMIO mode
Size &= LBAR_MEM_MASK;
Resource = RESOURCE_MMIO;
} else {
// IO mode
// Required for proper byte count calculation
Size |= 0xFFFF0000;
Resource = RESOURCE_IO;
}
// Convert mask to byte count
Size = ~Size + 1;
// Allocate BAR
SYS_ALLOCATE_RESOURCE(Resource, Bar, Size, DEVICE_ID_AMD_FLASH, ID_MDD);
}
}
}
//***********************************************************************
// Switches between Flash and IDE headers
//***********************************************************************
void pascal Flash_IDE_Switch(USHORT Function, ULONG Data)
{ ULONG PinOptions, PinMsr, FlashMsr, LBar[2], SavedLBar[2];
// Switch pins to Flash mode
PinMsr = MDD_Base + MSR_PIN_OPTS;
PinOptions = Read_MSR_LO(PinMsr);
if (Function == Flash_Function) {
// Currently in Flash mode
// Switching to IDE mode ?
if (Data == 0xBEEFDEAD) {
// Hide the Flash header
Hide_Flash_Hdr();
// Switch pins to IDE mode
PinOptions |= PIN_OPT_IDE;
Write_MSR_LO(PinMsr, PinOptions);
// Disconnect the ROM from the DMA pins
in_8(0x3F6);
}
} else {
// Currently in IDE mode
// Switching to Flash mode ?
if (Data == 0xDEADBEEF) {
// Hide the IDE header
Hide_IDE_Hdr();
// Allocate Flash BARs
Allocate_Flash_BARs();
// Enable Flash mode
PinOptions &= ~PIN_OPT_IDE;
Write_MSR_LO(PinMsr, PinOptions);
// Handle Canary circuit
// Set CS1# to respond to I/O address 22h
FlashMsr = MDD_Base + MSR_LBAR_FLSH1;
Read_MSR(FlashMsr, SavedLBar);
LBar[0] = 0x00000022;
LBar[1] = 0x0000FFF0 | LBAR_EN;
Write_MSR(FlashMsr, LBar);
// Turn Canary circuit on
in_8(0x22);
// Restore CS1 LBAR
Write_MSR(FlashMsr, SavedLBar);
}
}
}

View File

@@ -0,0 +1,53 @@
;
; 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
;
;* Function: *
;* This file contains the VSM header for the legacy VSM
.model tiny,c
.586
.CODE
include VSA2.INC
externdef edata:proc
externdef _end:proc
externdef VSM_msg_loop:proc
public VSM_Hdr
VSM_Hdr:
dd VSM_SIGNATURE ; VSM signature
db VSM_LEGACY ; VSM type
db 0FFh ; Any CPU
dw 0FFFFh ; Any Chipset
dw 0106h ; VSM version
dd OFFSET edata ; Size of VSM module
dw OFFSET VSM_msg_loop ; EntryPoint
dd OFFSET _end ; DS Limit
dw 0000h ; Requirements
dw VSA_VERSION ; VSA version
db sizeof(VSM_Header) - ($-VSM_Hdr) dup (0)
END

View File

@@ -0,0 +1,158 @@
/*
* 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
*/
//* Function: *
//* This file contains code for power-managing the ATA drives.
#include "vsa2.h"
#include "isa.h"
extern UCHAR pascal in_8(USHORT);
extern void pascal out_8(USHORT, UCHAR);
// NOTE: Win95 touches CD-ROMs every 4.2 seconds for AutoDetect
#define HDD0 1
#define HDD1 2
#define HDD2 4
#define HDD3 8
#define IDE_BSY 0x80 // Status register
#define IDE_RDY 0x40 // Status register
#define IDE_MSK IDE_BSY+IDE_RDY
#define IDE_CMD_SPINDOWN 0xE0 // Spindown Command
#define IDE_CMD_SPINUP 0xE1 // Spinup Command
#define IDE_CMD_CHECK_POWER_MODE 0xE5 // Get Power Management State Command
#define IDE_CMD_SLEEP 0xE6
UCHAR DrivesPresent = 0, DrvHd;
//*************************************************************************
// Issues specified command to one or more drive units
//*************************************************************************
void pascal IDE_Command(UCHAR DriveUnit, UCHAR Command)
{ UCHAR DriveSelect, Mask = 1;
USHORT IO_Port;
ULONG Timeout;
// Only spindown drives that are present
DriveUnit &= DrivesPresent;
while (DriveUnit) {
// Is drive present ?
if (DriveUnit & Mask) {
// Yes, determine I/O port
IO_Port = PRIMARY_IDE;
if (Mask & (HDD2+HDD3)) {
IO_Port = SECONDARY_IDE;
}
// Determine master/slave
DriveSelect = 0xA0; // Master drive
if (Mask & (HDD1+HDD3)) {
DriveSelect = 0xB0; // Slave drive
}
// Wait for IDE channel READY
for (Timeout=0xFFFFF; Timeout; Timeout--) {
if ((IDE_MSK & in_8(IO_Port+1)) == IDE_RDY)
break;
}
DrvHd = in_8(IO_Port); // Save Drive/Head register
out_8(IO_Port, DriveSelect); // Select drive to spin down
out_8(IO_Port+1, Command); // Issue command to the the drive
for (Timeout=0xFFFFF; Timeout; Timeout--) {
if (!(in_8(IO_Port+1) & IDE_BSY))
break;
}
in_8(IO_Port+1); // Clear IRQ
DriveUnit &= ~Mask;
}
// Next drive
Mask <<= 1;
}
}
//*************************************************************************
// Spins down specified drive(s)
//*************************************************************************
void pascal SpinDownHardDrive(UCHAR DriveUnit)
{
IDE_Command(DriveUnit, IDE_CMD_SPINDOWN);
}
//*************************************************************************
// Puts drive(s) into sleep mode
//*************************************************************************
void pascal DriveSleep(UCHAR DriveUnit)
{
// IDE_Command(DriveUnit, IDE_CMD_SLEEP);
}
//*************************************************************************
// Determines what hard drives are present
// Input: I/O address of IDE Drive/Head register
//*************************************************************************
UCHAR Check_IDE_Channel(USHORT IDE_DrvHd)
{ UCHAR HDD_Status, DrivesPresent=0;
DrvHd = in_8(IDE_DrvHd); // Save Drive/Head register
out_8(IDE_DrvHd, (UCHAR)(DrvHd & ~0x10)); // Select master drive
HDD_Status = in_8(IDE_DrvHd);
if (in_8(IDE_DrvHd+1) == 0x50) { // Is drive present ?
DrivesPresent |= HDD0;
out_8(IDE_DrvHd, (UCHAR)(DrvHd | 0x10)); // Select slave drive
HDD_Status = in_8(IDE_DrvHd);
if (in_8(IDE_DrvHd+1) == 0x50) { // Is drive present ?
DrivesPresent |= HDD1;
}
}
// Restore Drive/Head register
out_8(IDE_DrvHd, DrvHd);
return DrivesPresent;
}
//*************************************************************************
// Determines what hard drives are present
// Input: I/O address of IDE Drive/Head register
//*************************************************************************
UCHAR GetDrivesPresent(void)
{
DrivesPresent = Check_IDE_Channel(PRIMARY_IDE);
DrivesPresent |= Check_IDE_Channel(SECONDARY_IDE) << 2;
return DrivesPresent;
}

View File

@@ -0,0 +1,83 @@
/*
* 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
*/
//*****************************************************************************
//* This file performs Legacy VSM initialization.
//*****************************************************************************
#include "vsa2.h"
#include "chipset.h"
#include "sysmgr.h"
#include "vr.h"
// External variables:
extern Hardware SystemInfo;
// Function prototypes:
extern void pascal out_8(USHORT, UCHAR);
extern void CS5536_Early_Init(void);
extern void CS5536_Late_Init(void);
extern void Init_OHCI_SWAPSiF(UCHAR);
//***********************************************************************
// Performs early initialization
//***********************************************************************
void Legacy_Early_Init(void)
{
// Register for VRC_SYSINFO virtual registers
SYS_REGISTER_EVENT(EVENT_VIRTUAL_REGISTER, VRC_SYSINFO, 0, NORMAL_PRIORITY);
switch (SystemInfo.Chipset_ID) {
case DEVICE_ID_5536:
CS5536_Early_Init();
break;
}
}
//***********************************************************************
// Performs End-of-POST initialization
//***********************************************************************
void Legacy_Late_Init(void)
{
switch (SystemInfo.Chipset_ID) {
case DEVICE_ID_5536:
CS5536_Late_Init();
break;
}
// Initialize A20 to '1MB wrap'
// SDG - removed for OLPC
// out_8(0x92, 0);
}

View File

@@ -0,0 +1,92 @@
/*
* 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
*/
//* Function: *
//* This file implements miscellaneous VSA functionality: *
//* *
//* All chipsets: *
//* 1) SYSINFO virtual registers *
//* *
//* CS5536 : *
//* 1) Emulation of CS5530 PCI interrupt steering registers. *
//* 2) Flash-IDE switching *
//* 3) Power management *
#include "vsa2.h"
#include "chipset.h"
#include "protos.h"
// Function prototypes
extern void Legacy_Early_Init(void);
extern void Legacy_Late_Init(void);
extern void Handle_Events(ULONG *);
// Local variables
Hardware SystemInfo;
ULONG ChipsetBase;
ULONG Param[MAX_MSG_PARAM];
//***********************************************************************
// Message handler for the Legacy VSM
//***********************************************************************
void VSM_msg_loop()
{ MSG Msg;
// Get information about the system I'm executing on.
SYS_GET_SYSTEM_INFO(&SystemInfo);
ChipsetBase = SystemInfo.Chipset_Base;
//
// Message Handling Loop
//
do {
// Get the next message
Msg = SYS_GET_NEXT_MSG(&Param);
switch (Msg) {
case MSG_INITIALIZE:
switch (Param[0]) {
case EARLY_INIT:
Legacy_Early_Init();
break;
case END_OF_POST_INIT:
Legacy_Late_Init();
break;
}
break;
case MSG_EVENT:
Handle_Events(Param);
break;
case MSG_SET_POWER_MODE:
case MSG_SET_POWER_STATE:
case MSG_SAVE_STATE:
case MSG_RESTORE_STATE:
break;
} // end switch(Msg)
} while (1);
}

View File

@@ -0,0 +1,37 @@
/*
* 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
*/
#define SYS_DMA_DRIVER 0x5006
#define MASTER_IDE 0x8000
// Default GPIOs for PCI interrupts on the Hawk reference design
#define INTA_PIN 0
#define INTB_PIN 7
#define INTC_PIN 12
#define INTD_PIN 13
#define USBF_PERIOD 2000 // 2 seconds
#define USBF_HANDLE 0x3333

View File

@@ -0,0 +1,165 @@
#
# Copyright (c) 2006 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
#
#
######################################################################
#
# Init variables
#
######################################################################
.SUFFIXES: .asm .c .h .inc .map .obj .mac
!ifndef VSA2ROOT
VSA2ROOT = ..
!endif
BUILD_DIR = $(VSA2ROOT)\build
OBJECT = obj
!include $(BUILD_DIR)\setvars.mak
INCLUDE = $(OBJECT);$(INCLUDE)
VSMNAME = legacy
######################################################################
#
# Build Macros
#
######################################################################
LEGACY_ASM_OBJS = \
$(OBJECT)\header.obj \
$(OBJECT)\msr.obj \
LEGACY_C_OBJS = \
$(OBJECT)\legacy.obj \
$(OBJECT)\init.obj \
$(OBJECT)\events.obj \
$(OBJECT)\flash.obj \
$(OBJECT)\cs5536.obj \
$(OBJECT)\ide.obj \
$(OBJECT)\blockio.obj \
$(OBJECT)\uarts.obj \
$(OBJECT)\virtregs.obj \
$(OBJECT)\swapsif.obj \
$(OBJECT)\sysinfo.obj \
LEGACY_LNK_OBJS = \
header.obj \
legacy.obj \
msr.obj \
init.obj \
events.obj \
flash.obj \
cs5536.obj \
ide.obj \
blockio.obj \
uarts.obj \
virtregs.obj \
swapsif.obj \
sysinfo.obj \
LEGACY_OBJS = $(LEGACY_ASM_OBJS) $(LEGACY_C_OBJS)
LEGACY_VSM = legacy.vsm
#######################################################################
#
# Targets
#
#######################################################################
all: $(OBJECT) setenv legacy.vsm
$(COPY) $(LEGACY_VSM) $(BUILDOBJ)
legacy.vsm: $(LEGACY_OBJS)
cd $(OBJECT)
$(LN) $(LOPTS_VSM) $(LEGACY_LNK_OBJS), ..\$(LEGACY_VSM),, ..\..\build\obj\$(TOOL_LIB);
cd ..
#This and only this clean target must exist as it is called by cleanall
#cleanall and cleanlocal are defined in rules.mak
clean: cleanlocal cleanlib
$(OBJECT):
-@md $(OBJECT)
#######################################################################
#
# Dependencies
#
#######################################################################
$(LEGACY_ASM_OBJS): $(MAKEDIR)\makefile \
$(OBJECT)\sysmgr.inc \
$(OBJECT)\smimac.mac \
$(OBJECT)\vsa2.inc \
$(OBJECT)\isa.inc \
$(OBJECT)\chipset.inc \
$(OBJECT)\vr.inc \
$(OBJECT)\pci.inc \
$(OBJECT)\acpi.inc \
$(OBJECT)\gx2.inc \
$(OBJECT)\cs5536.inc \
$(OBJECT)\pci.inc \
$(OBJECT)\mdd.inc \
$(LEGACY_C_OBJS): $(MAKEDIR)\makefile \
$(BUILD_DIR)\obj\$(TOOL_LIB) \
$(OBJECT)\sysmgr.h \
$(OBJECT)\vsa2.h \
$(OBJECT)\isa.h \
$(OBJECT)\chipset.h \
$(OBJECT)\vr.h \
$(OBJECT)\pci.h \
$(OBJECT)\legacy.h \
$(OBJECT)\mapper.h \
$(OBJECT)\protos.h \
$(OBJECT)\mdd.h \
$(OBJECT)\acpi.h \
$(OBJECT)\gx2.h \
$(OBJECT)\cs5536.h \
######################################################################
#
# Common Targets
#
######################################################################
# include common targets and inference rules
!include $(BUILD_DIR)\rules.mak
######################################################################
#
# Inference Rules
#
######################################################################
# Override common inference rules here
{$(INC_DIR)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zni /C $<
{$(INC_DIR)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zni /C $<
{$(SYSMGR_SRC)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zns /C $<
{$(SYSMGR_SRC)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zns /C $<

View File

@@ -0,0 +1,97 @@
;
; 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
;
.model tiny,c
.586p
.CODE
;***********************************************************************
; Returns the low DWORD of an MSR.
; Usage: LowMsrValue = Read_MSR_LO(Msr_Address);
;***********************************************************************
Read_MSR_LO proc pascal \
Msr: dword
mov ecx, [Msr]
rdmsr
mov edx, eax
shr edx, 16
ret
Read_MSR_LO endp
;***********************************************************************
; Writes the low DWORD of an MSR. The high DWORD is preserved.
; Usage: Write_MSR_LO(Msr_Address, Data);
;***********************************************************************
Write_MSR_LO proc pascal \
Msr: dword, \
Data: dword
mov ecx, [Msr]
rdmsr ; Get high 32 bits
mov eax, [Data]
wrmsr
ret
Write_MSR_LO endp
;***********************************************************************
; Returns an MSR value in a buffer.
; Usage: Read_MSR(ULONG Msr, ULONG * Buffer);
;***********************************************************************
Read_MSR proc pascal \
Msr: dword, \
Buffer: PTR
mov ecx, [Msr]
rdmsr
mov bx, [Buffer]
mov [bx+0], eax
mov [bx+4], edx
ret
Read_MSR endp
;***********************************************************************
; Writes an MSR.
; Usage: Write_MSR(ULONG Msr, ULONG * Buffer);
;***********************************************************************
Write_MSR proc pascal \
Msr: dword, \
Buffer: PTR
mov ecx, [Msr]
mov bx, [Buffer]
mov eax, [bx+0]
mov edx, [bx+4]
wrmsr
ret
Write_MSR endp
END

View File

@@ -0,0 +1,130 @@
/*
* 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
*/
//******************************************************************************
//* This file contains SWAPSiFs
//******************************************************************************
#include "vsa2.h"
#include "protos.h"
#include "chipset.h"
#include "legacy.h"
#include "pci.h"
// External variables
extern Hardware SystemInfo;
// Local variables
ULONG OHCI_Address[2];
UCHAR WinCE_Flag = 1;
//*****************************************************************
// Fixes 118.438 - OHCI May Not Recognize Device Attach/Removal
//*****************************************************************
void pascal OHCI_SWAPSiF(UCHAR Flag)
{ PRIORITY Priority = 0;
static PRIORITY LastPriority = 0x5555;
switch (SystemInfo.Chipset_ID) {
case DEVICE_ID_5536:
break;
default:
if (Flag == 0) {
Priority = UNREGISTER_PRIORITY;
}
if (Priority != LastPriority) {
LastPriority = Priority;
SYS_REGISTER_EVENT(EVENT_TIMER, USBF_PERIOD, USBF_HANDLE, Priority);
}
break;
}
}
#define HcControl 0x0004
#define HCFS 0x000000C0L
#define USB_RESET 0x00000000L
#define USB_RESUME 0x00000040L
#define USB_OPERATIONAL 0x00000080L
#define USB_SUSPEND 0x000000C0L
#define IR 0x00000100L
#define HceControl 0x0100
//***********************************************************************
void Do_OHCI_SWAPSif(void)
{ ULONG i, PCI_Addr, HC_Addr, OldValue;
for (i=0; i<=1; i++) {
// Get base of Host Controller's registers
HC_Addr = OHCI_Address[i];
// Ignore this tick if BAR is being sized
if (HC_Addr == 0xFFFFF000 || HC_Addr == 0x00000000) {
continue;
}
// Check if Host Controller registers are accessible
PCI_Addr = 0x80007C00L + (i<<8);
if (READ_PCI_BYTE(PCI_Addr + COMMAND) & MEM_SPACE) {
OldValue = READ_MEMORY(HC_Addr + HcControl);
// WinCE doesn't perform a valid Ownership Change.
// It disables MIE then performs the Ownership Change request.
// This code detects that situation and turns emulation off.
// Otherwise, neither the USB keyboard or PS/2 keyboard works.
if ((i == 0) && (OldValue & IR) == 0 && WinCE_Flag) {
WinCE_Flag = 0; // Only do this once
WRITE_MEMORY(HC_Addr + HceControl, 0x00);
}
// Transition through Operational to clear possible attach/detach glitch
if ((OldValue & USB_SUSPEND) == USB_SUSPEND) {
WRITE_MEMORY(HC_Addr + HcControl, USB_OPERATIONAL);
WRITE_MEMORY(HC_Addr + HcControl, OldValue);
}
}
}
}
//***********************************************************************
// Initialization for the OHCI attach/detach hardware bug
//***********************************************************************
void Init_OHCI_SWAPSiF(UCHAR InitStage)
{
switch (InitStage) {
case EARLY_INIT:
// Trap writes to SB F4 & F5 BAR0 in order keep current OHCI BAR values
SYS_REGISTER_EVENT(EVENT_PCI_TRAP, 0x7C10, WRITES_ONLY | 0x100, 0);
break;
case END_OF_POST_INIT:
// Turn on the timer
OHCI_SWAPSiF(1);
break;
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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
*/
//* Function: *
//* This file implementes the SYSINFO virtual registers.
#include "vsa2.h"
#include "vr.h"
void pascal Hex_8(UCHAR);
void pascal Hex_16(USHORT);
void pascal Hex_32(ULONG);
// Local variables
extern Hardware SystemInfo;
void Handle_SysInfo_VR(UCHAR i)
{ USHORT Data;
switch (i) {
case VRC_SI_VERSION:
Data = 0x100; // Version 1.0
break;
case VRC_SI_CPU_MHZ:
Data = SystemInfo.CPU_MHz;
break;
case VRC_SI_CHIPSET_BASE_LOW:
Data = (USHORT) SystemInfo.Chipset_Base;
break;
case VRC_SI_CHIPSET_BASE_HI:
Data = (USHORT) (SystemInfo.Chipset_Base >> 16);
break;
case VRC_SI_CHIPSET_ID:
Data = SystemInfo.Chipset_ID;
break;
case VRC_SI_CHIPSET_REV:
Data = SystemInfo.Chipset_Rev;
break;
case VRC_SI_CPU_ID:
Data = SystemInfo.CPU_ID;
break;
case VRC_SI_CPU_REV:
Data = SystemInfo.CPU_Revision;
break;
default:
Data = 0xFFFF;
break;
}
SET_AX(Data);
}

View File

@@ -0,0 +1,210 @@
/*
* 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
*/
//* Function: *
//* This file contains routines specific to the CS5536 UARTs.
#include "vsa2.h"
#include "vr.h"
#include "mdd.h"
#include "protos.h"
// Function prototypes:
void Handle_5536_UART(UCHAR, UCHAR, USHORT);
USHORT Get_5536_UART(USHORT);
void Prog_5536_UART(USHORT, USHORT);
// External variables:
extern ULONG MDD_Base;
extern USHORT gpio_base;
// 5536 implements two UART's. The resources for both are controlled
// by MDD MSR_LEG_IO, MSR_IRQM_YHIGH.
// IRQ Enable, Clock freeze and soft reset controlled by MSR_UARTx_CONF
//
// One Virtual Register is implemented for each UART.
// bit15 = 1 Soft-Reset
// bits[14:13] = unused
// bit12 = 1 UART GPIO's have been setup by BIOS, RO bit
// bit11 = 1 enable UART I/O space extended register banks
// bit10 = 1 enable test mode
// bit9 = 1 Freeze device clocks, IRQ still enabled
// bit8 = 1 enable interrupt & functionality, doesn't affect I/O
// bits[7:4] = IRQ number
// bit3 = unused
// bit2 = 1 I/O decode enabled
// bits[1:0] = I/O location
//
void Handle_5536_UART(UCHAR vrIndex, UCHAR wFlag, USHORT wData)
{
if (wFlag) { // write
Prog_5536_UART(vrIndex, wData);
} else {
SYS_RETURN_RESULT((ULONG)Get_5536_UART(vrIndex));
}
}
USHORT Get_5536_UART(USHORT vri)
{
ULONG d;
USHORT u;
u = 0;
(USHORT)MDD_Base = MSR_LEG_IO;
d = Read_MSR_LO(MDD_Base);
switch (vri) {
case VRC_CS_UART1:
d >>= UART1_SHIFT;
break;
case VRC_CS_UART2:
d >>= UART2_SHIFT;
break;
default:
return 0;
}
u = (USHORT)d & UART_MASK;
// get the IRQ number
(USHORT)MDD_Base = MSR_IRQM_YHIGH;
d = Read_MSR_LO(MDD_Base);
if (vri == VRC_CS_UART1) {
d >>= 20;
} else {
d >>= 24;
}
u |= ((USHORT)d & 0x00F0);
// fill in the other flags from MSR_UARTx_CONF
if (vri == VRC_CS_UART1) {
(USHORT)MDD_Base = MSR_UART1_CONF;
} else {
(USHORT)MDD_Base = MSR_UART2_CONF;
}
d = Read_MSR_LO(MDD_Base);
// MSR bit0 = soft-reset -> bit15
// MSR bit1 = deven -> bit8
// MSR bit2 = freeze -> bit9
// MSR bit3 = test mode -> bit10
// MSR bit4 = upper banks -> bit11
if ((USHORT)d & 0x0001) {
u |= 0x8000;
}
d <<= 7;
u |= ((USHORT)d & 0x0F00);
// check if GPIO's for this UART have been setup
// This is used as an indicator the UART is 'hidden' from OS
d = in_32(gpio_base + GPIO_IN_AUX1_SELECT);
if (vri == VRC_CS_UART1) {
// UART1 GPIO9 should be IN_AUX
if (d & 0x0200L) {
u |= 0x1000; // set bit12
}
} else {
// UART2 GPIO3 should be IN_AUX
if (d & 0x0008L) {
u |= 0x1000; // set bit12
}
}
return u;
}
void Prog_5536_UART(USHORT vri, USHORT vrval)
{
ULONG d, r;
USHORT curval, uartmsr, shift, irqshift;
r = 0L;
// clear reserved/unused bits
vrval &= 0x8FF7;
switch (vri) {
case VRC_CS_UART1:
uartmsr = MSR_UART1_CONF;
shift = UART1_SHIFT;
irqshift = 24;
break;
case VRC_CS_UART2:
uartmsr = MSR_UART2_CONF;
shift = UART2_SHIFT;
irqshift = 28;
break;
default:
return;
}
// get current settings
curval = Get_5536_UART(vri);
// change?
if (curval ^ vrval) { // Yes
// I/O change?
if ((curval & 0x0007) ^ (vrval & 0x0007)) {
// Program I/O
(USHORT)MDD_Base = MSR_LEG_IO;
d = Read_MSR_LO(MDD_Base);
// don't trust C compiler when expanding a 'define' to
// long unless 'define' is a long constant.
(USHORT)r = UART_MASK;
d &= ~(r << shift);
d |= ((ULONG)(vrval & 0x0007)) << shift;
Write_MSR_LO(MDD_Base, d);
}
// IRQ change?
if ((curval & 0x00F0) ^ (vrval & 0x00F0)) {
// Program IRQ
(USHORT)MDD_Base = MSR_IRQM_YHIGH;
d = Read_MSR_LO(MDD_Base);
d &= ~(0x0FL << irqshift);
d |= ((ULONG)(vrval & 0x00F0)) << (irqshift-4);
Write_MSR_LO(MDD_Base, d);
}
// control bit(s) changed?
if ((curval & 0x8F00) ^ (vrval & 0x8F00)) {
// Program control bits in MSR_UARTx_CONF
// bits[11:8] of vr map to bits[4:1] of MSR
// bit[15] of vr maps to bit[0] of MSR
(USHORT)MDD_Base = uartmsr;
d = Read_MSR_LO(MDD_Base);
// clear bits[4:0]
d &= ~(0x1FL);
(USHORT)d |= ((vrval & 0x0F00) >> 7);
if (vrval & 0x8000) {
(USHORT)d |= 0x0001;
}
Write_MSR_LO(MDD_Base, d);
}
}
}

View File

@@ -0,0 +1,131 @@
/*
* 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
*/
//* Function: *
//* This file handles virtual registers.
#include "vsa2.h"
#include "chipset.h"
#include "vr.h"
#include "protos.h"
#include "acpi.h"
extern void Handle_Misc_VR(UCHAR, USHORT);
extern void Handle_SysInfo_VR(UCHAR);
extern void Handle_5536_UART(UCHAR, UCHAR, USHORT);
extern USHORT PCI_Int_AB, PCI_Int_CD;
extern USHORT DiskTimeout, SerialTimeout, ParallelTimeout, FloppyTimeout;
USHORT WatchDogDelay;
void Handle_VirtualRegs(UCHAR Class, UCHAR Index, UCHAR WrFlag, USHORT Data)
{
ULONG Param[MAX_MSG_PARAM]; // Select on virtual register class
switch (Class) {
case VRC_MISCELLANEOUS:
if (WrFlag) {
if (Index == WATCHDOG) {
static ULONG WatchDogKey=0;
ULONG Key;
Key = GET_REGISTER(R_ECX);
if (WatchDogKey) {
// The key has already been set...check it
if (WatchDogKey != Key) {
/*MEJ // Broadcast to all VSM's
Param[0] = S5_STATE;
Param[1] = CLASS_ALL;
SYS_BROADCAST_MSG(MSG_SET_POWER_STATE, &Param[0], VSM_ANY);
*/
}
} else {
// Set the key (only once)
WatchDogKey = Key;
}
WatchDogDelay = Data;
SYS_REGISTER_EVENT(EVENT_TIMER, WatchDogDelay*1000L, ONE_SHOT, 0);
break;
}
Handle_Misc_VR(Index, Data);
} else {
switch (Index) {
case PCI_INT_AB:
SET_AX(PCI_Int_AB);
break;
case PCI_INT_CD:
SET_AX(PCI_Int_CD);
break;
case WATCHDOG:
SET_AX(WatchDogDelay);
break;
}
}
break;
case VRC_PM:
// Ignore READs
if (WrFlag) {
/*MEJ switch (Index) {
case DISK_TIMEOUT:
DiskTimeout = Data;
break;
case SERIAL_TIMEOUT:
SerialTimeout = Data;
break;
case PARALLEL_TIMEOUT:
ParallelTimeout = Data;
break;
case FLOPPY_TIMEOUT:
FloppyTimeout = Data;
break;
}
*/
}
break;
case VRC_SYSINFO:
if (!WrFlag) {
Handle_SysInfo_VR(Index);
}
break;
case VRC_CHIPSET:
switch (Index) {
case VRC_CS_UART1:
case VRC_CS_UART2:
Handle_5536_UART(Index, WrFlag, Data);
break;
}
break;
}
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2007-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
*/
// This module decodes the SoftVG SMI sources.
#include "lxvg.h"
#include "vsa2.h"
#include "vr.h"
#include "pci.h"
extern void pascal out_8(USHORT, UCHAR);
extern void pascal out_16(USHORT, USHORT);
extern UCHAR pascal in_8(USHORT);
extern USHORT pascal in_16(USHORT);
//---------------------------------------------------------------------------
// virtual_register_event
//
// This routine is called when LXVG receives a VRC_VG virtual register
// access event.
//
//---------------------------------------------------------------------------
void virtual_register_event(unsigned char reg, unsigned long rwFlag, unsigned long vrData)
{
// Look for virtual register read case first
if (!(rwFlag & SMM_VR_WRITE))
{
// Determine if we are initialized
if (!(VGState & SF_SECONDARY))
{
SET_AX(0xFFFF);
}else{
SET_AX(vReg[reg]);
}
return;
}
// If we get here, we know its a write, so handle the requests
switch (reg)
{
case VG_CONFIG:
// We only need to initialize once!
if (!(VGState & SF_SECONDARY))
{
// Initialize the secondary controller portion of the engine.
lxvg_initialize((unsigned short)vrData);
// REGISTER PCI EVENTS - DO NOT ENABLE PCI EVENTS IF DISABLED.
if (VGState & SF_SECONDARY)
{
// If we've initialized to the secondary state, we need to support
// PCI config accesses. If we are disabled, the SysMgr will handle
// the support. We may be initialized to the primary state, but the
// minimum level is secondary.
SYS_REGISTER_EVENT(EVENT_PCI_TRAP, vga_config_addr, 0xFF, NORMAL_PRIORITY);
}
}
break;
default:
break;
}
// Finally, store the data...
vReg[reg] = (unsigned short)vrData;
return;
}
//---------------------------------------------------------------------------
// pci_trap_event
//
// This routine is called when the VSA2 system manager receives an SMI for
// a PCI configuration cycle that we have registered for.
//
// The "flags" parameter indicates the size in bits [3:0] (0x1 = byte,
// 0x3 = word, and 0xF = dword). Bit 7 indicates a write.
//---------------------------------------------------------------------------
void pci_trap_event(unsigned long address, unsigned long flags, unsigned long data)
{
unsigned char reg = (unsigned char) address & 0x000000FF;
unsigned char size = (unsigned char) flags & 0x0000000F;
unsigned long pciSave;
if ((address & PCI_CONFIG_MASK) == vga_config_addr)
{
// CHECK IF PCI WRITE
if (flags & PCI_TRAP_WRITE)
{
// Handle the trapped register writes
if (reg == PCI_CMD_REG)
{
if ((unsigned char)data & PCI_MEM_SPACE)
// Change the frame buffer base realated stuff.
hw_fb_map_init(framebuffer_base);
}
else if ((reg >= BAR0) && (reg <= BAR4))
{
// NOTE: SysMgr now delivers DWORD aligned values with all reserved bits zeroed.
if ((data < VGdata.pci_fb_mask) && (data != 0L))
{
// We have to assume that the changing agent won't put the framebuffer
// on top of program memory. The check for zero above was added when
// Windows was observed clearing out the BARS by writing 0's to them.
// This is still susceptible to failure due to bad address choices by
// the changing agent.
switch (reg)
{
case BAR0:
if ((data != framebuffer_base) && (data >= 0x1000000))
{
// Set the frame buffer base.
framebuffer_base = data;
// If the PCI memory is on, change the framebuffer base
// related stuff.
pciSave = READ_PCI_DWORD_NO_TRAP(PCI_CMD_REG);
if (pciSave & PCI_MEM_SPACE)
// Change the frame buffer base realated stuff.
hw_fb_map_init(framebuffer_base);
}
break;
case BAR1:
// Set the GP register base
GPregister_base = data;
break;
case BAR2:
// Set the VG register base
VGregister_base = data;
break;
case BAR3:
// Set the DF register base
DFregister_base = data;
break;
case BAR4:
// Set the VIP register base
VIPregister_base = data;
break;
}
}
}
}
else
{
// Always mask off the invalid bits, but preserve the
// bottom 4 bits.
if (size == DWORD_IO)
{
pciSave = GET_EAX();
switch (reg)
{
case BAR0:
pciSave &= VGdata.pci_fb_mask | 0x0000000F;
break;
case BAR1:
case BAR2:
case BAR3:
case BAR4:
pciSave &= MASK16K;
break;
}
SET_EAX(pciSave);
}
}
}
}
// END OF FILE

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2007-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
*/
// This module performs LXVG initialization.
#include "lxvg.h"
#include "vsa2.h"
#include "pci.h"
#include "vr.h"
//---------------------------------------------------------------------------
// lxvg_initialize
//
// This routine initializes LXVG. This is the routine called when
// VG_CONFIG virtual register is written the first time.
//---------------------------------------------------------------------------
void lxvg_initialize(unsigned short init_parms)
{
int index;
unsigned char *ptr;
// CLEAR THE ENTIRE LXVG DATA STRUCTURE TO ZERO - This is a tedious loop
ptr = (unsigned char *) &VGdata;
for (index = 0; index < sizeof(VGdata); index++)
*ptr++ = 0;
// Start with virtual registers = 0
for (index = 0; index < MAX_VG+1; index++)
{
if (index != VG_CONFIG)
{
vReg[index] = 0;
}
}
// DEVICE DEPENDENT INITIALIZATION
// -------------------------------
// This MUST be done first. The routine handles all of the MBUS related
// initialization and determines various register and base address values
// that get used during later initialization.
hw_initialize(init_parms);
// If we haven't initialized because of error, just leave...
if (VGState & SF_DISABLED) return;
// LXVG is operating strictly as a secondary controller
VGState |= SF_DRIVER_ENABLED;
// Disable the graphics system in the PCI header command register
WRITE_PCI_BYTE(vga_config_addr+0x04, 0);
return;
}
// END OF FILE

View File

@@ -0,0 +1,298 @@
/*
* Copyright (c) 2007-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
*/
// This module contains the routines that access the LX hardware.
#include "lxvg.h"
#include "vsa2.h"
#include "vr.h"
#include "pci.h"
// This is required here because of inclusion problems in LXVG.h
extern Hardware SystemInfo;
//---------------------------------------------------------------------------
// hw_initialize
//
// This routine performs the device dependent initialization.
//---------------------------------------------------------------------------
void hw_initialize(unsigned short config)
{
unsigned long base,tbase;
struct mValue mVal;
unsigned short i;
// Find the list of devices so we can get to their MSRs. If any one
// device is missing, bail out because we don't know how to handle
// partial systems.
if (FALSE == msrInit())
{
VGState = SF_DISABLED;
return;
}
// Initialize the MSRs for the graphics processor
hw_gp_msr_init();
// Initialize the MSRs for the video generator
hw_vg_msr_init();
// Initialize the MSRs for the display filter
hw_df_msr_init();
// Initialize the MSRs for the display filter
hw_vip_msr_init();
// Initialize the DOT PLL MSR in the MCP
hw_mcp_msr_init();
// Compute graphics memory requirement from config. The following strips
// off the PLL bypass bit and shifts the number of 1MB hunks up
// to the point where it is a size in bytes. Base is used as a temp.
base = (unsigned long)(config & MEM_SIZE_MASK) << 20;
// Now compute the memory size mask we will use when we return the contents of
// BAR0
VGdata.pci_fb_mask = 0;
tbase = base;
for (i=0;i<32,tbase!=0L;i++)
{
VGdata.pci_fb_mask |= (1L << i);
tbase = tbase >> 1;
}
VGdata.pci_fb_mask = ~(VGdata.pci_fb_mask);
// ALLOCATE DESCRIPTORS
vga_config_addr = SYS_ALLOCATE_RESOURCE(RESOURCE_MEMORY, BAR0, base, PCI_DEV_ID, ID_MC); // Graphics memory
SYS_ALLOCATE_RESOURCE(RESOURCE_MMIO, BAR1, SIZE16K, PCI_DEV_ID, ID_GP); // GP registers
SYS_ALLOCATE_RESOURCE(RESOURCE_MMIO, BAR2, SIZE16K, PCI_DEV_ID, ID_VG); // VG registers
SYS_ALLOCATE_RESOURCE(RESOURCE_MMIO, BAR3, SIZE16K, PCI_DEV_ID, ID_DF); // DF registers
SYS_ALLOCATE_RESOURCE(RESOURCE_MMIO, BAR4, SIZE16K, PCI_DEV_ID, ID_VIP); // VIP registers
// Modify vga_config_addr to point to the beginning of the header, because all the accesses
// to the header are based on the beginning of the header rather than BAR0.
vga_config_addr -= BAR0;
// SET BASE ADDRESS VALUES.
// The base addresses are all relative to the framebuffer base address which
// is defined to be on the next 256MB boundary above the SYSMGR. Initially,
// it was hard coded to be at 0x50000000, and now it should show up at 0x90000000.
framebuffer_base = (SYS_LOGICAL_TO_PHYSICAL(0) & 0xF0000000) + 0x10000000;
WRITE_PCI_DWORD_NO_TRAP(vga_config_addr+BAR0, framebuffer_base); // Frame buffer address
GPregister_base = framebuffer_base - 0x00004000;
WRITE_PCI_DWORD_NO_TRAP(vga_config_addr+BAR1, GPregister_base); // Graphics processor register space
VGregister_base = GPregister_base - 0x00004000;
WRITE_PCI_DWORD_NO_TRAP(vga_config_addr+BAR2, VGregister_base); // Video generator register space
DFregister_base = VGregister_base - 0x00004000;
WRITE_PCI_DWORD_NO_TRAP(vga_config_addr+BAR3, DFregister_base); // Display filter register space
VIPregister_base = DFregister_base - 0x00004000;
WRITE_PCI_DWORD_NO_TRAP(vga_config_addr+BAR4, VIPregister_base); // Display filter register space
// Turn on the descriptors
WRITE_PCI_BYTE(vga_config_addr+0x04,PCI_MEM_SPACE);
// Unlock the display controller registers
saveLock = read_vg_32(DC_UNLOCK);
write_vg_32(DC_UNLOCK, DC_UNLOCK_VALUE);
// Set up the DV Address offset in the DC_DV_CTL register to the offset from frame
// buffer descriptor. First, get the frame buffer descriptor so we can set the
// DV Address Offset in the DV_CTL register. Because this is a pointer to real
// silicon memory, we don't need to do this whenever we change the framebuffer BAR,
// so it isn't included in the hw_fb_map_init routine.
SYS_MBUS_DESCRIPTOR((unsigned short)(vga_config_addr+BAR0),(void *)&mVal);
mVal.high &= DESC_OFFSET_MASK;
mVal.high <<= 4;
mVal.high += framebuffer_base; // Watch for overflow issues here...
write_vg_32(DC_DV_CTL, mVal.high);
// Initialize the frame buffer base realated stuff.
hw_fb_map_init(framebuffer_base);
// CLEAR Video Generator START ADDRESS VALUES
write_vg_32(DC_FB_ST_OFFSET, 0L);
write_vg_32(DC_CB_ST_OFFSET, 0L);
write_vg_32(DC_CURS_ST_OFFSET, 0L);
write_vg_32(DC_UNLOCK, saveLock);
// Put VIP input and output sections into reset state with default values.
write_vip_32(VIP_CTRL1, 0x42000001);
// Set flags indicating the hardware registers are available and that we are not
// disabled. Among other things, the SF_SECONDARY flag controls the hardware
// register locking and unlocking at the top of the message handling loop.
VGState |= SF_SECONDARY;
VGState &= ~SF_DISABLED;
return;
}
// Initialize the graphics processor MSR registers.
void hw_gp_msr_init(void)
{
// Initialize the configuration MSR - 0x00000000 00000010
msrModify(msrIdx_GP, MBD_MSR_CONFIG, MSR_CLR_ALL, MSR_CLR_ALL_BUT_PID, 0, GP_DEF_PRI);
// Initialize the SMI MSR. Clear and disable all SMIs - 0x00000001 00000001
msrModify(msrIdx_GP, MBD_MSR_SMI, MSR_CLR_ALL, MSR_CLR_ALL, GP_SMI_CLR, GP_SMI_DIS);
return;
}
// Initialize the video input port MSR registers.
void hw_vip_msr_init(void)
{
msrModify(msrIdx_VIP, MBD_MSR_CONFIG, MSR_CLR_ALL, MSR_CLR_ALL_BUT_PID, 0L, VIP_DEF_PRI);
// Initialize the SMI MSR. Clear and disable all SMIs - 0x00000000 7FFF7FFF
msrModify(msrIdx_VIP, MBD_MSR_SMI, MSR_CLR_ALL, MSR_CLR_ALL, 0L, 0x7FFF7FFF);
return;
}
// Initialize the video generator MSR registers.
void hw_vg_msr_init(void)
{
// Initialize the configuration MSR - 0x00000000 00000320
msrModify(msrIdx_VG, MBD_MSR_CONFIG, MSR_CLR_ALL, MSR_CLR_ALL_BUT_PID, 0, VG_DEF_PRI);
// Initialize the SMI MSR. Clear and disable all SMIs - 0x0000001f 0000001f
msrModify(msrIdx_VG, MBD_MSR_SMI, MSR_CLR_ALL, MSR_CLR_ALL, VG_SMI_DIS, VG_SMI_DIS);
// Initialize the DELAY MSR.
msrModify(msrIdx_VG, MBD_MSR_DELAY, MSR_CLR_ALL, MSR_CLR_ALL, 0L, 0x00000302);
// Turn off the bad VG fetch state machine hardware fix and the video FIFO watermarks
msrModify(msrIdx_VG, MBD_MSR_SPARE, MSR_CLR_ALL, MSR_CLR_ALL, 0L, 0x00000042);
return;
}
// Initialize the display filter MSR registers.
void hw_mcp_msr_init(void)
{
unsigned long orValLo, orValHi;
struct mValue mVal;
unsigned char i;
// Initialize the DOT PLL MSR. We need to default to a known clock so
// the PLL doesn't exceed its limits, and if the bypass bit is set, we
// need to also set the power down bit.
if (vReg[VG_CONFIG] & VG_CFG_BYPASS)
{
// Bypassed, so just set the bypass and power down bits.
orValLo = DOTPLL_BYPASS | DOTPLL_PDBIT;
orValHi = 0L;
}
else
{
orValLo = DOTPLL_RESET;
orValHi = 0x0000216C; // 28.322MHz
}
msrModify(msrIdx_MCP, MCP_DOTPLL, MSR_CLR_ALL, MSR_CLR_ALL, orValHi, orValLo);
// LEDA has indicated that there may be up to a 42 clock delay from the time the
// DOTPLL comes out of powerdown until the lock bit is guaranteed to go low. In
// order to make sure we don't read an errant value, we need to delay a bit.
for (i=0;i<8;i++)
outp(0xed,0xf5);
// Wait for lock (maybe)
msrRead(msrIdx_MCP, MCP_DOTPLL, &mVal);
while (!(mVal.low & DOTPLL_LOCKBIT))
{
// Read the current contents...
msrRead(msrIdx_MCP, MCP_DOTPLL, &mVal);
};
msrModify(msrIdx_MCP, MCP_DOTPLL, 0, MSR_CLR_ALL, 0, 0); // Clear the reset bit
return;
}
// Initialize the display filter MSR registers.
void hw_df_msr_init(void)
{
unsigned long orVal;
unsigned long mDiv, mMul, pSpd, mSpd, mbClk;
struct mValue mVal;
// Get a colletion of information necessary to compute the divisor for the
// CONFIG MSR. This includes the processor speed, the CPU multiplier and
// divisor and the MBus multiplier and divisor. There are two different
// versions of the computation. The commented out version doesn't depend
// on the bootstrap pin, and the other starts with a known PCI speed based
// on that pin.
msrRead(msrIdx_MCP, MCP_SYSPLL, &mVal); // Returns the divisors...
pSpd = (mVal.low & 0x00000008)?66:33;
mDiv = ((mVal.high & 0x00000040) >> 6) + 1;
mMul = ((mVal.high & 0x00000F80) >> 7) + 1;
mbClk = (pSpd * mMul) / mDiv;
mSpd = (mbClk / 14) & 0x0000003F;
// Initialize the configuration MSR
orVal = DF_DEF_PRI;
orVal |= (mSpd << 8);
msrModify(msrIdx_DF, MBD_MSR_CONFIG, MSR_CLR_ALL, MSR_CLR_ALL_BUT_PID, 0, orVal);
return;
}
//---------------------------------------------------------------------------
// hw_fb_map_init
//
// This routine initializes the hardware pointers that are specifically
// related to the framebuffer address.
//---------------------------------------------------------------------------
void hw_fb_map_init(unsigned long fbLoc)
{
unsigned long ltemp;
// Insist upon a certain alignment...
fbLoc &= VGdata.pci_fb_mask;
// Set the MBus Memory Offset register.
write_vg_32(PHY_MEM_OFFSET, fbLoc);
// Set GP2 base offset - different from Redcloud. There are both source
// and destination fields the need to be set.
ltemp = fbLoc | (fbLoc >> 10);
write_gp_32(GP2_BASE_OFFSET, ltemp);
return;
}

View File

@@ -0,0 +1,915 @@
/*
* Copyright (c) 2007-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
*/
// This is the main header file for LXVG.
// VERSION NUMBERS
#define LXVG_MAJOR_VER 0x00
#define LXVG_MINOR_VER 0x11
// PROCESSOR IDS
// Keep as bitwise flags to make "either" comparisons easier.
#define PROCESSOR_GXM 0x01
#define PROCESSOR_REDC 0x02
#define PROCESSOR_CSTL 0x03
// A pair of LONG generic masks
#define CLR_HIWORD 0x0000FFFF
#define CLR_LOWORD 0xFFFF0000
// Some LXVG configuration flags and masks
#define MEM_SIZE_MASK 0x00FE // Bits 7:1 (size in 2MB hunks)
#define ADAPTER_PRIMARY 0x0100 // Bit 8
#define PLL_REF_MASK 0x0600 // Bits 10:9
#define PLL_BYPASS 0x0800 // Bit 11
#define VGDATA_PLL_14MHZ 0x00 // VGdata PLL reference frequency flag value
#define VGDATA_PLL_48MHZ 0x01 // VGdata PLL reference frequency flag value
#define VGDATA_PLL_ERROR 0xFF // Bad PLL or hardware error
#define MONOCHROME_CARD 0x1000 // Bit 12
// SOME REDCLOUD DEFINITIONS
#define FAKE_ADDRESS 0xFFFFFFFF
#define CLASS_MASK 0x000FF000
#define DEVID_MASK 0x00FFFF00
// A memory space enable value for the PCI command register
#define PCI_CMD_REG 0x04
#define PCI_IO_SPACE (1 << 0)
#define PCI_MEM_SPACE (1 << 1)
// Some commonly used size definitions
#define SIZE4K 0x00001000 // A 4K range indicator
#define SIZE16K 0x00004000 // A 16K range indicator
#define MASK16K 0xFFFFC00F // A 16K range mask
#define SIZE32K 0x00008000 // A 32K range indicator
#define SIZE64K 0x00010000 // A 64K range indicator
#define SIZE128K 0x00020000 // A 128K range indicator
// PCI device ID assigned to LX graphics system
#define PCI_DEV_ID 0x2081
// MBus device IDs. These IDs will have to be shifted into place by the System
// manager when it goes to access the devices.
#define ID_MBIU 0x01 // Default MBIU device ID
#define ID_MCP 0x02 // MBus Control Processor device ID
#define ID_MC 0x20 // Default Memory Controller device ID
#define ID_GP 0x3D // Graphics Processor device ID
#define ID_VG 0x3E // Video Generator device ID
#define ID_DF 0x3F // Display Filter device ID
#define ID_VIP 0x3C // Display Filter device ID
// MSR Register Offsets
#define MBD_MSR_CAP 0x2000
#define MBD_MSR_CONFIG 0x2001
#define MBD_MSR_SMI 0x2002
#define MBD_MSR_ERROR 0x2003
#define MBD_MSR_PM 0x2004
#define MBD_MSR_DIAG 0x2005
#define MBD_MSR_SPARE 0x2011
#define MBD_MSR_DELAY 0x2012
// DF specific MSRs
#define DF_MSR_DIAG_DF 0x2010
#define DF_MSR_PAD_SEL 0x2011
// MSR stuff specific to the MCP_DOTPLL
#define MCP_SYSPLL 0x0014
#define MCP_DOTPLL 0x0015
#define DOTPLL_DIV_MASK 0x00007FFF
#define DOTPLL_DIV4 0x00010000
#define DOTPLL_RESET 0x00000001
#define DOTPLL_CAPEN 0x00002000
#define DOTPLL_PDBIT 0x00004000
#define DOTPLL_BYPASS 0x00008000
#define DOTPLL_HALFPIX 0x01000000
#define DOTPLL_LOCKBIT 0x02000000
// MCP Error and SMI MSR error bits related to the DOTPLL reset during power-on bug PBz#3344.
#define MCP_SMI_ERRBIT 0x00010000
#define MCP_DOTPLL_ERRBIT 0x00000004
#define MCP_CHIPREV 0x0017
//
// msrDev indices for the devices that we care about/know about
//
#define msrIdx_MCP 0
#define msrIdx_MC 1
#define msrIdx_GP 2
#define msrIdx_VG 3
#define msrIdx_DF 4
#define msrIdx_VIP 5
#define msrIdx_MBIU 6
// A mask to isolate the offset field of the frame buffer descriptor.
#define DESC_OFFSET_MASK 0x0FFFFF00
#define DV_OFFSET_MASK 0xFFFFF000
#define DV_LINE_1K 0x00000000
#define DV_LINE_2K 0x00000400
#define DV_LINE_4K 0x00000800
#define DV_LINE_8K 0x00000C00
// Structures of MSRs.
//
// Proper usage is as follows:
//
// MSR access routines (MSRAR) should first check the 'Present' field and :
//
// 1) If the field is set to 'REQ_NOT_FOUND' :
// - The device was not detected on the MBUS but a request was made to
// find it at some point since/during initization [ see msrInit() ].
// Therefore, MSRAR should not attempt to access the device.
//
// 2) If the field is set to 'FOUND' :
// - The device was detected on the MBUS, the rest of the structure
// has been filled in and MSRAR should use the address provided.
//
// 3) If the field is set to 'UNKNOWN' :
// - There has never been a request to find this device. MSRAR returns
// to caller. Caller should first call msrInit().
//
// The address field is set to FAKE_ADDRESS just in case "renegade software" doesn't
// check the 'Present' field and just grabs the 'address' field.
// FAKE_ADDRESS has been set to a value that should never appear in
// a real system. It is only meant to protect the system 99%
// of the time from badly written software....
typedef struct tagMSR {
unsigned short Present; // Present - Read above under "Structures of MSRs"
unsigned short Id; // Id - Device ID number (from MSR specs)
unsigned long Routing; // Routing - 32-bit address at which 'Id' was found
} MSR;
//
// mValue is used to hold the 64-bit msr data value.
//
typedef struct mValue {
unsigned long low;
unsigned long high;
};
// Capabilities bits
#define DF_BOND_MASK 0x000000C0 // CRT bond value
#define BOND_CRT 0x00 // CRT bond value
#define BOND_FP 0x40 // flat panel bond value
#define HALF_MEG 0x00080000 // 512K
#define QRTR_MEG 0x00040000 // 256K
#define MAX_ICON 0x4C00 // 19K
// MSR AND masks used by rc_msrModify. These masks define bits that are
// always cleared in the register.
#define MSR_CLR_ALL 0xFFFFFFFF // Clear all bits
#define MSR_CLR_NONE 0L // Clear no bits
#define MSR_CLR_OUT 0x00008038 // Clear bits 15, 5:3
#define MSR_CLR_ALL_BUT_PID 0xFFFFFFF8 // Clear all bits except [2:0]
// GP
#define GP_SMI_MSK_HI 0xFFFFFFFF // SMI MSR
#define GP_SMI_MSK_LO 0xFFE0FFE0
#define GP_ERR_MSK_HI 0xFFFFFFFF // Error MSR
#define GP_ERR_MSK_LO 0xFFF0FFF0
#define GP_PM_MSK_HI 0xFFFFFFFC // PM MSR
#define GP_PM_MSK_LO 0xFFFFFFF0
// VG
#define VG_SMI_MSK_HI 0xFFFFFFFF // SMI MSR
#define VG_SMI_MSK_LO 0xFFE0FFE0
#define VG_ERR_MSK_HI 0xFFFFFFFF // Error MSR
#define VG_ERR_MSK_LO 0xFFF0FFF0
#define VG_PM_MSK_HI 0xFFFFFFFC // PM MSR
#define VG_PM_MSK_LO 0xFFFFFFF0
// DF
#define DF_SMI_MSK_HI 0xFFFFFFFF // SMI MSR
#define DF_SMI_MSK_LO 0xFFFCFFFC
#define DF_ERR_MSK_HI 0xFFFFFFFE // Error MSR
#define DF_ERR_MSK_LO 0xFFFFFFFE
#define DF_PM_MSK_HI 0xFFFFFFE0 // PM MSR
#define DF_PM_MSK_LO 0xF0FFFC00
// MSR bit field AND masks. These are added to the above masks to
// clear particular fields
// GP
#define GP_CFG_PRI 0x00000070 // Both priority fields
#define GP_CFG_PID 0x00000007 // PID field
#define GP_DEF_PRI 0x00000010 // Default priorities
#define GP_SMI_CLR 0x00000001 // SMI clear bits
#define GP_SMI_DIS 0x00000001 // SMI disable bits
#define GP_CLK_RQ 0x00000001 // Software clock PM request bits field
#define GP_PM_MODE 0x00000003 // Clock PM mode fields
#define GP_CLK_ON 0x00000000 // Both clocks always on
#define GP_CLK_HW 0x00000001 // Both clocks hardware gated
#define GP_CLK_SW 0x00000002 // Both clocks software gated
#define GP_CLK_BOTH 0x00000003 // Both clocks software and hardware gated
// VG
#define VG_CFG_PRI 0x00000770 // Both priority fields
#define VG_CFG_PID 0x00000007 // PID field
#define VG_DEF_PRI 0x00000720 // Default priorities
#define VG_DEF_PRI_10 0x00000620 // Default priorities for 1.0 parts
// LX 2.0 changes
#define VG_SMI_DIS 0x1001FFFF // SMI disable and clear bits
#define VG_SMI_ALLNB 0x10000016 // All "Standard" SMIs but VBLANKs
#define VG_SMI_INV_CRTC 0x00000010 // Invalid CRTC SMI disable mask
#define VG_SMI_VBLANK 0x00000009 // Vertical blanks SMI disable mask
#define VG_SMI_ISR0 0x00000004 // Input status register SMI disable mask
#define VG_SMI_MISC_W 0x00000002 // Miscellaneous output register SMI disable mask
#define VG_SMI_ALLCRTC 0x00000060 // All CRTC reads and writes
#define VG_SMI_ALLSEQ 0x00000180 // All SEQ reads and writes
#define VG_SMI_ALLGDC 0x00000600 // All GFX reads and writes
#define VG_SMI_ALLATC 0x00001800 // All ATC reads and writes
#define VG_SMI_ALLDAC 0x00006000 // All DAC reads and writes
#define VG_SMI_CRTC_W 0x00000020 // All CRTC writes
#define VG_SMI_CRTC_R 0x00000040 // All CRTC reads
#define VG_SMI_SEQ_W 0x00000080 // All SEQ writes
#define VG_SMI_SEQ_R 0x00000100 // All SEQ reads
#define VG_SMI_GDC_W 0x00000200 // All GDC writes
#define VG_SMI_GDC_R 0x00000400 // All GDC reads
#define VG_SMI_ATC_W 0x00000800 // All ATC writes
#define VG_SMI_ATC_R 0x00001000 // All ATC reads
#define VG_SMI_DAC_W 0x00002000 // All DAC writes
#define VG_SMI_DAC_R 0x00004000 // All DAC reads
#define VG_SMI_MISC_R 0x00008000 // Miscellaneous output register reads
#define VG_SMI_ISR1_R 0x00010000 // Input status register 1 reads
// VG_DEBUG trap request bits
#define TRAP_ALL_CRTC 0x0100
#define TRAP_ALL_SEQ 0x0200
#define TRAP_ALL_GDC 0x0400
#define TRAP_ALL_ATC 0x0800
#define TRAP_ALL_DAC 0x1000
#define TRAP_MISC_RDS 0x2000
#define TRAP_ISR1_RDS 0x4000
// LX 2.0 changes
#define VG_CLK_RQ 0x00000003 // Software clock PM request bits field
#define VG_PM_MODE 0x0000000F // Clock PM mode fields
#define VG_CLK_ON 0x00000000 // Both clocks always on
#define VG_CLK_HW 0x00000005 // Both clocks hardware gated
#define VG_CLK_SW 0x0000000A // Both clocks software gated
#define VG_CLK_BOTH 0x0000000F // Both clocks software and hardware gated
// DF
#define DF_CFG_PID 0x00000007 // PID field
#define DF_CFG_FMT 0x00000038 // Output format select field
#define DF_CFG_FMBO 0x000000C0 // Output format byte order field
#define DF_CFG_DIV 0x00003F00 // Clock divider field
#define DF_CFG_IUV 0x00004000 // Interchange UV field
#define DF_CFG_FPC 0x00008000 // Simultaneous CRT and panel/VOP bit
#define DF_CFG_PRI 0x00070000 // MBus master priority field
#define DF_DEF_PRI 0x00040000 // Default priority
#define DF_DEF_DIV 0x00003F00 // Default clock divider
//#define DF_SMI_CLR 0x00030000 // SMI clear bits
#define DF_SMI_CLR 0x00000000 // SMI clear bits
#define DF_SMI_DIS 0x00000003 // SMI disable bits
#define DF_CLK_RQ 0x0000001F // Software clock PM request bits field
#define DF_PM_MODE 0x000003FF // Clock PM mode fields
#define DF_CLK_ON 0x00000000 // All clocks always on
#define DF_CLK_HW 0x00000155 // All clocks hardware gated
#define DF_CLK_SW 0x000002AA // All clocks software gated
#define DF_CLK_BOTH 0x000003FF // All clocks software and hardware gated
#define DF_CLR_CRC 0x80000000 // Clear the CRC select bit
// VIP
#define VIP_CFG_PID 0x00000007 // PID field
#define VIP_PRI_PRI 0x00000070 // MBus master priority field
#define VIP_SEC_PRI 0x00000700 // Default priority
#define VIP_DEF_PRI_10 0x00000630 // Default priority
#define VIP_DEF_PRI 0x00000620 // Default priority
#define VIP_SMI_CLR 0x3FFF0000 // SMI clear bits
#define VIP_SMI_DIS 0x00003FFF // SMI disable bits
#define VIP_CLK_RQ 0x0000001F // Software clock PM request bits field
#define VIP_PM_MODE 0x000003FF // Clock PM mode fields
#define VIP_CLK_ON 0x00000000 // All clocks always on
#define VIP_CLK_HW 0x00000155 // All clocks hardware gated
#define VIP_CLK_SW 0x000002AA // All clocks software gated
#define VIP_CLK_BOTH 0x000003FF // All clocks software and hardware gated
//
// SMI event id bits
//
#define EVT_VG_VBLANK 0x00000001
#define EVT_VG_MISC_WR 0x00000002
#define EVT_VG_ISR0_RD 0x00000004
#define EVT_VGA_VBLANK 0x00000008
#define EVT_VG_INV_CRTC 0x00000010
#define EVT_VG_CRTC_W 0x00000020
#define EVT_VG_CRTC_R 0x00000040
#define EVT_VG_SEQ_W 0x00000080
#define EVT_VG_SEQ_R 0x00000100
#define EVT_VG_GFX_W 0x00000200
#define EVT_VG_GFX_R 0x00000400
#define EVT_VG_ATC_W 0x00000800
#define EVT_VG_ATC_R 0x00001000
#define EVT_VG_DAC_W 0x00002000
#define EVT_VG_DAC_R 0x00004000
#define EVT_VG_MISC_R 0x00008000
#define EVT_VG_ISR1_R 0x00010000
#define EVT_VGA_RES_CHG 0x10000000
#define EVT_WRITES 0x00000AB2 // The register write bits
#define EVT_READS 0x0001D554 // The register read bits + ISR0 & Inv CRTC
//#define EVT_GP_SMI0 0x20000000
//#define EVT_DF_SMI0 0x40000000
//#define EVT_DF_SMI1 0x80000000
// Castle 2.0 Defs
//
// GP2 Memory Mapped Register Set
//
#define GP2_DST_OFFSET 0x0000
#define GP2_SRC_OFFSET 0x0004
#define GP2_VEC_ERR 0x0004
#define GP2_STRIDE 0x0008
#define GP2_WID_HEIGHT 0x000C
#define GP2_SRC_COLOR_FG 0x0010
#define GP2_SRC_COLOR_BG 0x0014
#define GP2_PAT_COLOR_0 0x0018
#define GP2_PAT_COLOR_1 0x001C
#define GP2_PAT_COLOR_2 0x0020
#define GP2_PAT_COLOR_3 0x0024
#define GP2_PAT_COLOR_4 0x0028
#define GP2_PAT_COLOR_5 0x002C
#define GP2_PAT_DATA_0 0x0030
#define GP2_PAT_DATA_1 0x0034
#define GP2_RASTER_MODE 0x0038
#define GP2_VECTOR_MODE 0x003C
#define GP2_BLT_MODE 0x0040
#define GP2_BLT_STATUS 0x0044
#define GP2_RESET 0x0044
#define GP2_HST_SRC 0x0048
#define GP2_BASE_OFFSET 0x004C
//
// VG Memory Mapped Register Set
//
#define DC_UNLOCK 0x0000
#define DC_GENERAL_CFG 0x0004
#define DC_DISPLAY_CFG 0x0008
#define DC_ARB_CFG 0x000C
//#define DC_GFX_SCL 0x000C
#define DC_FB_ST_OFFSET 0x0010
#define DC_CB_ST_OFFSET 0x0014
#define DC_CURS_ST_OFFSET 0x0018
//#define DC_ICON_ST_OFFSET 0x001C
#define DC_VID_Y_ST_OFFSET 0x0020
#define DC_VID_U_ST_OFFSET 0x0024
#define DC_VID_V_ST_OFFSET 0x0028
#define DC_DV_TOP 0x002C
//#define DC_VID_SP_ST_OFFSET 0x002C
#define DC_LINE_SIZE 0x0030
#define DC_GFX_PITCH 0x0034
#define DC_VID_YUV_PITCH 0x0038
//#define DC_VID_SP_PITCH 0x003C
#define DC_H_ACTIVE_TIMING 0x0040
#define DC_H_BLANK_TIMING 0x0044
#define DC_H_SYNC_TIMING 0x0048
//#define DC_FP_HSYNC_TIMING 0x004C
#define DC_V_ACTIVE_TIMING 0x0050
#define DC_V_BLANK_TIMING 0x0054
#define DC_V_SYNC_TIMING 0x0058
#define DC_FB_ACTIVE 0x005C
//#define DC_FP_VSYNC_TIMING 0x005C
#define DC_CURSOR_X 0x0060
#define DC_CURSOR_Y 0x0064
//#define DC_ICON_X 0x0068
#define DC_LINE_CNT 0x006C
#define DC_PAL_ADDRESS 0x0070
#define DC_PAL_DATA 0x0074
#define DC_DFIFO_DIAG 0x0078
#define DC_CFIFO_DIAG 0x007C
#define DC_VID_DS_DELTA 0x0080
#define PHY_MEM_OFFSET 0x0084
#define DC_DV_CTL 0x0088
#define DC_ACCESS 0x008C
#define DC_GFX_SCALE 0x0090
#define DC_IRQ_FLT_CTL 0x0094
#define DC_FLT_COEFF1 0x0098
#define DC_FLT_COEFF2 0x009C
#define DC_VBI_EVN_CTL 0x00A0
#define DC_VBI_ODD_CTL 0x00A4
#define DC_VBI_HOR_CTL 0x00A8
#define DC_VBI_LN_ODD 0x00AC
#define DC_VBI_LN_EVN 0x00B0
#define DC_VBI_PITCH 0x00B4
#define DC_VBI_CLR_KEY 0x00B8
#define DC_VBI_CK_MASK 0x00BC
#define DC_VBI_CK_X 0x00C0
#define DC_VBI_CK_Y 0x00C4
#define DC_IRQ 0x00C8
#define DC_GENLK_CTL 0x00D4
#define DC_VID_EVN_Y_ST 0x00D8
#define DC_VID_EVN_U_ST 0x00DC
#define DC_VID_EVN_V_ST 0x00E0
#define DC_VID_EVN_ACT 0x00E4
#define DC_VID_EVN_BLANK 0x00E8
#define DC_VID_EVN_SYNC 0x00EC
#define DC_VGA_CONFIG 0x0100
#define DC_VGA_STATUS 0x0104
//#define DC_VGA_EXTADDR 0x0108
#define DC_UNLOCK_VALUE 0x00004758
#define DC_LOCK_VALUE 0x00000000
//-----------------------------------//
// DC_GENERAL_CFG Bit Definitions //
//-----------------------------------//
// DC_GCFG_CLR_MASK turns off everything but VGA fixed timing enable, VGA enable,
// compression and decompression enables and Display-FIFO Load Enable
#define DC_GCFG_CLR_MASK 0x0004FF00
#define DC_GCFG_DFLE 0x00000001
#define DC_GCFG_CURE 0x00000002
#define DC_GCFG_ICNE 0x00000004
#define DC_GCFG_VIDE 0x00000008
//#define DC_GCFG_VSPE 0x00000010
#define DC_GCFG_FSSEL 0x00000010
#define DC_GCFG_CMPE 0x00000020
#define DC_GCFG_DECE 0x00000040
#define DC_GCFG_VGAE 0x00000080
#define DC_GCFG_DFIFO_ST 0x00000F00
#define DC_GCFG_DFIFO_END 0x0000F000
#define DC_GCFG_WATERMARKS 0x00007200
#define DC_GCFG_STFM 0x00010000
#define DC_GCFG_FDTY 0x00020000
#define DC_GCFG_VGAFT 0x00040000
#define DC_GCFG_VDSE 0x00080000
#define DC_GCFG_YUVM 0x00100000
//#define DC_GCFG_FTSTR 0x00200000
#define DC_GCFG_FRC8PIX 0x00400000
#define DC_GCFG_SIGSEL 0x00800000
#define DC_GCFG_CLR_CRC 0xF8FFFFFF
//#define DC_GCFG_CLR_CRC_ALL 0xF07FFFFF
#define DC_GCFG_CLR_CRC_ALL 0xF07FFFEF
#define DC_GCFG_SIGE 0x01000000
#define DC_GCFG_SGRE 0x02000000
#define DC_GCFG_SGFR 0x04000000
#define DC_GCFG_CRCMODE 0x08000000
//#define DC_GCFG_GXRFS4 0x08000000
//-----------------------------------//
// DC_DISPLAY_CFG Bit Definitions //
//-----------------------------------//
// DC_DCFG_CLR_MASK turns off everything but display center, color depth fields,
// and scale enable.
#define DC_DCFG_CLR_MASK 0xC0000F00
#define DC_DCFG_BLANK_MASK 0xFFFFFFC0
#define DC_DCFG_TGEN 0x00000001
//#define DC_DCFG_PCKE 0x00000002
//#define DC_DCFG_VCKE 0x00000004
#define DC_DCFG_GDEN 0x00000008
//#define DC_DCFG_VDEN 0x00000010
#define DC_DCFG_VIEN 0x00000020
#define DC_DCFG_TRUP 0x00000040
#define DC_DCFG_SCLE 0x00000080
// Color depth related masks and values
#define DC_DCFG_MODE_MASK 0x00000F00
#define DC_DCFG_16BPP_MODE 0x00000C00
#define DC_DCFG_DISP_MODE 0x00000300
#define DC_DCFG_BPP16 0x00000100
#define DC_DCFG_BPP15 0x00000500
#define DC_DCFG_BPP12 0x00000900
#define DC_DCFG_BPP32 0x00000200
#define DC_DCFG_VFHPSL 0x0000F000
//#define DC_DCFG_PLNR 0x00001000
//#define DC_DCFG_SSLC 0x00002000
//#define DC_DCFG_PXDB 0x00004000
//#define DC_DCFG_LNDB 0x00008000
#define DC_DCFG_VFHPEL 0x000F0000
//#define DC_DCFG_BLNK 0x00010000
//#define DC_DCFG_BKRT 0x00020000
//#define DC_DCFG_RFS4 0x00040000
//#define DC_DCFG_DCEN 0x00080000
//#define DC_DCFG_PIX_PAN 0x00F00000
//#define DC_DCFG_PPC 0x01000000
#define DC_DCFG_DCEN 0x01000000
#define DC_DCFG_PALB 0x02000000
//#define DC_DCFG_FRLK 0x04000000
#define DC_DCFG_VISL 0x08000000
//#define DC_DCFG_A18M 0x40000000
//#define DC_DCFG_A20M 0x80000000
//-----------------------------------//
// DC_IRQ_FLT_CTL Bit Definitions //
//-----------------------------------//
#define IF_FLT_ADDR_MASK 0x000000FF
#define IF_HFILT_SEL 0x00000400
#define IF_INTL_EN 0x00000800
#define IF_HFILT_EN 0x00001000
#define IF_VFILT_EN 0x00002000
#define IF_HALPH_FILT_EN 0x00004000
#define IF_VALPH_FILT_EN 0x00008000
#define IF_LIN_CNT_MASK 0x07FF0000
#define IF_IRQ_EN 0x08000000
#define IF_INTL_ADDR 0x10000000
//
// DF Memory Mapped Register Set
//
#define DF_VCFG 0x0000
#define DF_DCFG 0x0008
#define DF_VID_X 0x0010
#define DF_VID_Y 0x0018
#define DF_VID_SCL 0x0020
#define DF_VID_CK 0x0028
#define DF_VID_CM 0x0030
#define DF_PAL_ADDR 0x0038
#define DF_PAL_DATA 0x0040
#define DF_SLR 0x0048
#define DF_MISC 0x0050
#define DF_CRT_CS 0x0058
#define DF_VYS 0x0060
#define DF_VXS 0x0068
#define DF_VID_DSC 0x0078
//#define DF_VID_DCO 0x0080
#define DF_CRC_SIG 0x0088
#define DF_CRCS_CLR_CRC 0xFFFFFFF8
#define DF_CRCS_SIGE 0x00000001
#define DF_CRCS_SGFR 0x00000004
#define DF_CRC32_SIG 0x0090
#define DF_VID_VDE 0x0098
#define DF_VID_CCK 0x00A0
#define DF_VID_CCM 0x00A8
#define DF_VID_CC1 0x00B0
#define DF_VID_CC2 0x00B8
#define DF_VID_A1X 0x00C0
#define DF_VID_A1Y 0x00C8
#define DF_VID_A1C 0x00D0
#define DF_VID_A1T 0x00D8
#define DF_VID_A2X 0x00E0
#define DF_VID_A2Y 0x00E8
#define DF_VID_A2C 0x00F0
#define DF_VID_A2T 0x00F8
#define DF_VID_A3X 0x0100
#define DF_VID_A3Y 0x0108
#define DF_VID_A3C 0x0110
#define DF_VID_A3T 0x0118
#define DF_VID_VRR 0x0120
#define DF_VID_AWT 0x0128
// Flat panel specific
#define DF_FP_PT1 0x0400
#define DF_FP_PT2 0x0408
#define DF_FP_PM 0x0410
#define DF_FP_DFC 0x0418
#define DF_DFC_NO_DITHER 0x00000070
//#define DF_FP_BLFSR 0x0420
//#define DF_FP_RLFSR 0x0428
//#define DF_FP_FMI 0x0430
//#define DF_FP_FMD 0x0438
//#define DF_FP_RSVD 0x0440
#define DF_FP_DCA 0x0448
#define DF_FP_DMD 0x0450
#define DF_FP_CRC 0x0458
//#define DF_FP_FBB 0x0460
#define DF_FP_CRC32 0x0468
// VOP specific
#define DF_VOP_CFG 0x0800
#define DF_VOP_SIG 0x0808
#define DF_VID_VCR 0x1000
#define DF_DCFG_VID_EN 0x00000001
//-----------------------------------//
// DF_DCFG Bit Definitions //
//-----------------------------------//
// DF_DCFG_CLR_MASK turns off everything but CRT sync skew. The blank mask turns off
// CRT DACs, the CRT sync enables and resets the display logic.
#define DF_DCFG_CLR_MASK 0x0001C000
#define DF_DCFG_BLANK_MASK 0xFFFFFFF0 // 0xF431FF30
#define DF_DCFG_ENABLE_MASK 0x0000000F
#define DF_DCFG_DPMS_STBY 0x00000005
#define DF_DCFG_DPMS_SUSP 0x00000003
#define DF_DCFG_DIS_EN 0x00000001
#define DF_DCFG_HSYNC_EN 0x00000002
#define DF_DCFG_VSYNC_EN 0x00000004
#define DF_DCFG_DAC_BL_EN 0x00000008
//#define DF_DCFG_DAC_PWDNX 0x00000020
//#define DF_DCFG_FP_PWR_EN 0x00000040
//#define DF_DCFG_FP_DATA_EN 0x00000080
#define DF_DCFG_CRT_HSYNC_POL 0x00000100
#define DF_DCFG_CRT_VSYNC_POL 0x00000200
//#define DF_DCFG_FP_HSYNC_POL 0x00000400
//#define DF_DCFG_FP_VSYNC_POL 0x00000800
//#define DF_DCFG_XGA_FP 0x00001000
//#define DF_DCFG_FP_DITH_EN 0x00002000
#define DF_DCFG_CRT_SYNC_SKW_MASK 0x0001C000
#define DF_DCFG_CRT_SYNC_SKW_POS 14
//#define DF_DCFG_PWR_SEQ_DLY_MASK 0x000E0000
//#define DF_DCFG_PWR_SEQ_DLY_POS 17
//#define DF_DCFG_PWR_SEQ_DLY_VAL 0x00080000
#define DF_DCFG_VG_CK 0x00100000
#define DF_DCFG_GV_PAL_BYP 0x00200000
//#define DF_DCFG_DDC_SCL 0x00400000
//#define DF_DCFG_DDC_SDA 0x00800000
//#define DF_DCFG_DDC_OE 0x01000000
#define DF_DCFG_DAC_VREF 0x04000000
//#define DF_DCFG_FP_PWR_ON 0x08000000
//-----------------------------------//
// DF_FP_PT1 Bit Definitions //
//-----------------------------------//
#define DF_PT1_HPULSE_MASK 0x0000001F
#define DF_PT1_HDELAY_MASK 0x000000E0 // Not used in LXVG
#define DF_PT1_HDELAY_SHIFT 5
#define DF_PT1_O 0x00004000
#define DF_PT1_U 0x00008000
#define DF_PT1_VSIZE_MASK 0x07FF0000
#define DF_PT1_VSIZE_SHIFT 16
#define DF_PT1_HSRC 0x08000000
#define DF_PT1_HSIP 0x20000000
#define DF_PT1_VSIP 0x40000000
//-----------------------------------//
// DF_FP_PT2 Bit Definitions //
//-----------------------------------//
#define DF_PT2_CLP 0x00002000
#define DF_PT2_PIXF_MASK 0x00070000
#define DF_PT2_PIXF_SHIFT 16
#define DF_PT2_PIXF_000 0x00000000
#define DF_PT2_PIXF_001 0x00010000
#define DF_PT2_PIXF_002 0x00020000
#define DF_PT2_PIXF_003 0x00030000
#define DF_PT2_MCS 0x00080000
#define DF_PT2_PSEL_MASK 0x00300000
#define DF_PT2_PSEL_STN 0x00000000
#define DF_PT2_PSEL_TFT 0x00100000
#define DF_PT2_HSP 0x00400000
#define DF_PT2_VSP 0x00800000
#define DF_PT2_VFS 0x01000000
#define DF_PT2_LMS 0x02000000
#define DF_PT2_LHS 0x04000000
#define DF_PT2_SCRC 0x08000000
#define DF_PT2_LPOL 0x20000000
#define DF_PT2_TPASS 0x40000000
//-----------------------------------//
// DF_FP_PM Bit Definitions //
//-----------------------------------//
#define DF_PM_SINV 0x00002000
#define DF_PM_VDEL_MASK 0x0000C000
#define DF_PM_VDEL_SHIFT 14
#define DF_PM_HDEL_MASK 0x00030000
#define DF_PM_HDEL_SHIFT 16
#define DF_PM_PD0 0x00040000
#define DF_PM_PD1 0x00080000
#define DF_PM_PD2 0x00100000
#define DF_PM_PUB0 0x00200000
#define DF_PM_PUB1 0x00400000
#define DF_PM_PUB2 0x00800000
#define DF_PM_P 0x01000000
#define DF_PM_D 0x02000000
#define DF_PM_PWR_SEQ 0x08000000
//-----------------------------------//
// DF_VOP_CFG Bit Definitions //
//-----------------------------------//
#define DF_VOP_ENABLE_MASK 0x00000003
#define DF_VOP_VIP11 0x00000001
#define DF_VOP_VIP2 0x00000002
#define DF_VOP_CCIR656 0x00000003
#define DF_VOP_LVL2 0x00000004
#define DF_VOP_EXTSAV 0x00000008
#define DF_VOP_422CO 0x00000000
#define DF_VOP_422RCO 0x00000010
#define DF_VOP_422ASS 0x00000020
#define DF_VOP_SC120X 0x00000040
#define DF_VOP_SIGE 0x00000080
#define DF_VOP_SIGFR 0x00000100
//
// VIP Memory Mapped Register Set
//
#define VIP_CTRL1 0x0000
#define VIP_CTRL2 0x0004
#define VIP_STATUS 0x0008
#define VIP_INTS 0x000C
#define VIP_CURTGT 0x0010
#define VIP_MAX_ADDR 0x0014
#define VIP_AVID_EBASE 0x0018
#define VIP_AVID_OBASE 0x001C
#define VIP_AVBI_EBASE 0x0020
#define VIP_AVBI_OBASE 0x0024
#define VIP_A_PITCH 0x0028
#define VIP_CTRL3 0x002C
#define VIP_A_VOBUF 0x0030
#define VIP_A_UOBUF 0x0034
#define VIP_BVID_EBASE 0x0038
#define VIP_BVID_OBASE 0x003C
#define VIP_BVBI_EBASE 0x0040
#define VIP_BVBI_OBASE 0x0044
#define VIP_B_PITCH 0x0048
#define VIP_B_VBUF 0x0050
#define VIP_B_UBUF 0x0054
#define VIP_AMSG_1BASE 0x0058
#define VIP_AMSG_2BASE 0x005C
#define VIP_AMSG_SIZE 0x0060
#define VIP_PAGE_OFFS 0x0068
#define VIP_VERT_ST 0x006C
#define VIP_FIFO_ADDR 0x0070
#define VIP_FIFO_RW 0x0074
#define VIP_FRM_DCNT 0x0078
#define VIP_A_VEBUF 0x007C
#define VIP_A_UEBUF 0x0080
// CHIPSET IDS
// Keep as bitwise flags to make "either" comparisons easier.
#define CHIPSET_CX5530 0x01
#define CHIPSET_REDC 0x02
#define CHIPSET_DHRUVA 0x10
#define CHIPSET_BHARGAVA 0x20
#define CX5530_DISPLAY_CONFIG 0x00000004
// TRAPPED PCI DEVICES
#define PCI_CONFIG_MASK 0xFFFFFF00 // bits for comparison
#define PCI_NSM_FLAGS_REG0 0x44 // register for flags
#define PCI_NSM_FLAGS_REG1 0x45 // register for flags
#define PCI_NSM_FLAGS_REG2 0x46 // register for flags
#define PCI_NSM_FLAGS_REG3 0x47 // register for flags
#define PCI_NSM_FLAG_DISABLE 0x01 // flag to disable LXVG
// SYSTEM FLAGS (stored in VGState)
#define SF_DISABLED 0x00000001 // LXVG is disabled
#define SF_SECONDARY 0x00000002 // Init to secondary controller capability
#define SF_PRIMARY 0x00000004 // Init to primary controller capability
// The next flag indicates a mode switch has occurred. Generally only the first mode
// switch is interesting.
#define SF_MODE_SET 0x00000008
#define SF_END_POST 0x00000010 // POST is complete
#define SF_DRIVER_ENABLED 0x00000020 // Graphics driver is controlling system
#define SF_DIAG_SMI 0x00000040 // Use diagnostic SMI settings
#define SF_MONOCHROME 0x00000100 // monochrome mode
#define SF_3D0_RANGE 0x00000200 // remembers state of ioaddr bit in misc output
#define SF_SCALE_DISABLED 0x00000400 // Disable graphics scaling during fixed timings
#define SF_FORCE_VALIDATION 0x00000800 // force all HW validation
// SMM HEADER FLAGS
#define SMM_IO_WRITE 0x0002
#define SMM_VR_WRITE 0x0001
// FLAGS FOR PCI TRAP EVENTS
#define PCI_TRAP_WRITE 0x80
#include "VGdata.h"
#define TRUE 1
#define FALSE 0
extern VGDATA VGdata;
extern unsigned long VGState;
extern unsigned long lockNest; // Nested SMI recognition scheme
extern unsigned long saveLock; // Nested SMI recognition scheme
extern unsigned short vReg[];
extern unsigned long vga_config_addr;
extern unsigned long GPregister_base;
extern unsigned long VGregister_base;
extern unsigned long DFregister_base;
extern unsigned long VIPregister_base;
extern unsigned long framebuffer_base;
extern unsigned long VG_SMI_Mask;
extern unsigned char crc_time;
//------------//
// ROUTINES //
//------------//
// ROUTINES IN MSR.C
unsigned char msrInit(void);
unsigned short msrFindDevice(struct tagMSR *);
unsigned short msrIdDevice(unsigned long);
unsigned short msrRead(unsigned short msrIdx, unsigned short msrReg, struct mValue *);
unsigned short msrWrite(unsigned short msrIdx, unsigned short msrReg, unsigned long outHi, unsigned long outLo);
void msrModify(unsigned short msrIdx, unsigned short msrReg,
unsigned long andHi, unsigned long andLo, unsigned long orHi, unsigned long orLo);
void msrSave(unsigned short msrIdx, unsigned short *, struct mValue *);
void msrRestore(unsigned short msrIdx, unsigned short *, struct mValue *);
void msrDump(unsigned short msrIdx, unsigned short msrReg);
// ROUTINES IN VSA2.C
void decode_vsa2_event(void);
void vsa2_io_read(unsigned short size, unsigned long data);
// ROUTINES IN DECODE.C
void virtual_register_event(unsigned char reg, unsigned long rwFlag, unsigned long vrData);
void pci_trap_event(unsigned long address, unsigned long size, unsigned long data);
// ROUTINES IN GXHWCTL.C
void hw_initialize(unsigned short config);
void hw_gp_msr_init(void);
void hw_vip_msr_init(void);
void hw_vg_msr_init(void);
void hw_df_msr_init(void);
void hw_mcp_msr_init(void);
void hw_fb_map_init(unsigned long fbLoc);
// ROUTINES IN INIT.C
void lxvg_initialize(unsigned short init_parms);
// ROUTINES IN UTILS.ASM
unsigned long read_fb_32(unsigned long offset);
void write_fb_32(unsigned long offset, unsigned long data);
unsigned long read_gp_32(unsigned long offset);
void write_gp_32(unsigned long offset, unsigned long data);
unsigned char read_vg_8(unsigned long offset);
void write_vg_8(unsigned long offset, unsigned char data);
unsigned long read_vg_32(unsigned long offset);
void write_vg_32(unsigned long offset, unsigned long data);
unsigned long read_df_32(unsigned long offset);
void write_df_32(unsigned long offset, unsigned long data);
unsigned long read_vip_32(unsigned long offset);
void write_vip_32(unsigned long offset, unsigned long data);
void asmRead(unsigned short msrReg, unsigned long msrAddr, unsigned long *ptrHigh, unsigned long *ptrLow);
void asmWrite(unsigned short msrReg, unsigned long msrAddr, unsigned long *ptrHigh, unsigned long *ptrLow);

View File

@@ -0,0 +1,55 @@
;/*
;* Copyright (c) 2007-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
;*/
;* This file contains the VSM header for the LXVG VSM
.model tiny,c
.486
.CODE
include VSA2.INC
externdef edata:proc
externdef _end:proc
externdef vsa2_message_loop:proc
public VSM_Hdr
VSM_Hdr:
dd VSM_SIGNATURE ; VSM signature
db VSM_VGA ; VSM type
db 0FFh ; Any CPU
dw 0FFFFh ; Any Chipset
dw 0101h ; VSM version 01.01
dd OFFSET edata ; Size of VSM module
dw OFFSET vsa2_message_loop; EntryPoint
dd OFFSET _end ; DS Limit
dw 0000h ; Requirements
dw VSA_VERSION ; VSA version
db sizeof(VSM_Header) - ($-VSM_Hdr) dup (0)
END VSM_Hdr

View File

@@ -0,0 +1,158 @@
# Copyright (c) 2007-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
######################################################################
#
# Init variables
#
######################################################################
!ifndef VSA2ROOT
VSA2ROOT = ..
!endif
BUILD_DIR = $(VSA2ROOT)\build
OBJECT = obj
!include $(BUILD_DIR)\setvars.mak
.SUFFIXES: .asm .c .h .inc .map .obj .mac
INCLUDE = $(OBJECT)
######################################################################
#
# Build Macros
#
######################################################################
VGA_C_OBJS = \
$(OBJECT)\vsa2.obj \
$(OBJECT)\init.obj \
$(OBJECT)\msr.obj \
$(OBJECT)\decode.obj \
$(OBJECT)\vgdata.obj \
$(OBJECT)\lxhwctl.obj \
VGA_ASM_OBJS = \
$(OBJECT)\main.obj \
$(OBJECT)\utils.obj \
VGA_OBJS = $(VGA_ASM_OBJS) $(VGA_C_OBJS)
VGA_VSM = $(OBJECT)\lxvg.vsm
#######################################################################
#
# Targets
#
#######################################################################
all: setenv
$(MAKE) lxvga.vsm "CPU=lx"
lxvga.vsm: $(OBJECT) $(VGA_OBJS)
$(LN) $(LOPTS_VSM) @<<
$(VGA_OBJS: =+^
)
$(VGA_VSM)
lxvg.map
$(BUILD_DIR)\obj\$(TOOL_LIB) ;
<<NOKEEP
$(COPY) $(VGA_VSM) $(BUILDOBJ)
#This and only this clean target must exist as it is called by cleanall
#cleanall and cleanlocal are defined in rules.mak
clean: cleanlocal cleanlib
$(OBJECT):
-@md $(OBJECT)
#######################################################################
#
# Dependencies
#
#######################################################################
$(VGA_ASM_OBJS): $(MAKEDIR)\makefile \
$(OBJECT)\vsa2.inc \
$(VGA_C_OBJS): $(MAKEDIR)\makefile \
$(BUILD_DIR)\obj\$(TOOL_LIB) \
$(OBJECT)\vsa2.h \
$(OBJECT)\isa.h \
$(OBJECT)\chipset.h \
$(OBJECT)\vr.h \
$(OBJECT)\pci.h \
$(OBJECT)\lxvg.h \
$(OBJECT)\vgdata.h \
######################################################################
#
# Common Targets
#
######################################################################
# include common targets and inference rules
!include $(BUILD_DIR)\rules.mak
######################################################################
#
# Inference Rules
#
######################################################################
# Override common inference rules here
{$(INC_DIR)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zni /C $<
{$(INC_DIR)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zni /C $<
{$(SYSMGR_SRC)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zns /C $<
{$(SYSMGR_SRC)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zns /C $<
{$(MAKEDIR)}.c{$(OBJECT)}.obj:
$(CC) /AT /W3 /G3s /Gx /Oi /c /I$(OBJECT) $(CDEFS) /Fo$@ $<
{$(MAKEDIR)\$(CPU)}.c{$(OBJECT)}.obj:
$(CC) /AT /W3 /G3s /Gx /Oi /c /I$(OBJECT) $(CDEFS) /Fo$@ $<
{$(MAKEDIR)}.asm{$(OBJECT)}.obj:
$(AS) /nologo $(AS_OPTS) $(CDEFS) /Fo$@ $<
{$(MAKEDIR)\$(CPU)}.asm{$(OBJECT)}.obj:
$(AS) /nologo $(AS_OPTS) $(CDEFS) /Fo$@ $<
{$(MAKEDIR)}.h{$(OBJECT)}.h:
copy $< $@
{$(USER)\lxvg}.h{$(OBJECT)}.h:
copy $< $@
{$(USER)\lxvg}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zns /C $<
{$(USER)\lxvg}.asm{$(OBJECT)}.obj:
$(AS) /nologo $(AS_OPTS) $(CDEFS) /Fo$@ $<
{$(USER)\lxvg}.c{$(OBJECT)}.obj:
$(CC) /AT /W3 /G3s /Gx /Oi /c /I$(OBJECT) $(CDEFS) /Fo$@ $<

View File

@@ -0,0 +1,305 @@
/*
* Copyright (c) 2007-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
*/
#include "lxvg.h"
#include "vsa2.h"
#define FOUND 0
#define UNKNOWN 1
#define REQ_NOT_FOUND 2
struct tagMSR msrDev[] = {
{ UNKNOWN, ID_MCP, FAKE_ADDRESS },
{ UNKNOWN, ID_MC, FAKE_ADDRESS },
{ UNKNOWN, ID_GP, FAKE_ADDRESS },
{ UNKNOWN, ID_VG, FAKE_ADDRESS },
{ UNKNOWN, ID_DF, FAKE_ADDRESS },
{ UNKNOWN, ID_VIP, FAKE_ADDRESS } };
// DEBUG
// { UNKNOWN, ID_MBIU, FAKE_ADDRESS } };
// DEBUG
#define NUM_DEVS sizeof(msrDev) / sizeof(struct tagMSR)
//=================================================================
// BOOL msrInit(void)
//
// Handles the details of finding each possible device on the MBUS.
// If a given device is not found, its structure is left inited at default.
// If a given device is found, its structure is updated.
//
// This init routine only checks for devices already in the structure.
//
// Returns:
// TRUE - If, for every device, its address was found.
// FALSE - If, for any device, an error was encountered.
//
unsigned char msrInit(void)
{
unsigned short issues=0, i;
//
// For each item in the list, try to find its address
//
for (i=0; i < NUM_DEVS; i++)
{
msrDev[i].Present = msrFindDevice(&msrDev[i]);
if (msrDev[i].Present != FOUND) issues++;
}
if (issues) return(FALSE);
/*
//
// For each item in the list, get its real device ID
//
for (i=0; i < NUM_DEVS; i++)
msrDev[i].Id = msrIdDevice(msrDev[i].Address);
*/
return(TRUE);
}
//=================================================================
// unsigned short msrFindDevice(struct msr *pDev)
//
// Returns:
// FOUND - if no errors were detected. msrAddress has been updated.
// REQ_NOT_FOUND - Address for 'devId' is unknown. Caller should
// call msrInit() first. ptr->Address is not updated.
//
// NOTE: The structure default for the 'Present' field is "UNKNOWN".
// Therefore, if a given id is passed to msrFindDevice, the 'Present'
// field will be updated with either 'FOUND' or 'REQ_NOT_FOUND'. If
// a given ID is not passed to msrFindDevice, the 'Present' field will
// be left as 'UNKNOWN'.
//
unsigned short msrFindDevice(struct tagMSR *pDev)
{
unsigned long msrAdr;
msrAdr = SYS_LOOKUP_DEVICE(pDev->Id,1);
if (0 != msrAdr)
{
pDev->Routing = msrAdr;
return(FOUND);
}
// All done...
return(REQ_NOT_FOUND);
}
//=================================================================
// unsigned short msrIdDevice(unsigned long address)
//
// Reads the capabilities MSR register (typically 0x2000)
// and returns the 'id' field (bits 23:8)
//
// Returns:
// Bits 23:8 of MSR low DWORD
//
unsigned short msrIdDevice(unsigned long address)
{
struct mValue msrValue;
asmRead(MBD_MSR_CAP, address, &msrValue.high, &msrValue.low);
return((unsigned short)((msrValue.low & DEVID_MASK) >> 8));
}
//=================================================================
// unsigned short msrRead(unsigned short msrIdx, unsigned short msrReg, struct mValue msrValue)
//
// Performs a 64-bit read from 'msrReg' in device 'devID'.
//
// Returns:
// FOUND - if no errors were detected and msrValue has been updated.
// UNKNOWN - an error was detected. msrValue is not updated.
// REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown. Caller
// should call msrInit() first. msrValue is not updated.
//
unsigned short msrRead(unsigned short msrIdx, unsigned short msrReg, struct mValue *msrValue)
{
if (msrDev[msrIdx].Present == FOUND) {
asmRead(msrReg, msrDev[msrIdx].Routing, &msrValue->high, &msrValue->low);
}
return (msrDev[msrIdx].Present);
}
//=================================================================
// unsigned short msrWrite(unsigned short msrIdx, unsigned short msrReg, unsigned long outHi, unsigned long outLo)
//
// Performs a 64-bit write to 'msrReg' in device 'devID'.
//
// Returns:
// FOUND - if no errors were detected and msrValue has been updated.
// UNKNOWN - an error was detected. msrValue is not updated.
// REQ_NOT_FOUND - 'msrAddress' for 'devID' is unknown. Caller
// should call msrInit() first. msrValue is not updated.
//
unsigned short msrWrite(unsigned short msrIdx, unsigned short msrReg, unsigned long outHi, unsigned long outLo)
{
struct mValue mVal;
if (msrDev[msrIdx].Present == FOUND) {
// Incorporate the OR values
mVal.high = outHi;
mVal.low = outLo;
asmWrite(msrReg, msrDev[msrIdx].Routing, &mVal.high, &mVal.low);
}
return (msrDev[msrIdx].Present);
}
//=================================================================
// void msrModify(unsigned short msrIdx, unsigned short msrReg, unsigned long maskHi, unsigned long maskLo,
// unsigned long orHi, unsigned long orLo)
//
// Performs a 64-bit read-modify-write of 'msrReg' in device 'msrIdx'.
// The mask values indicate the bits that are to be changed, so the
// register values are ANDed with the NOT of the mask values to clear
// out the affected bits.
//
// Returns:
// NONE
//
void msrModify(unsigned short msrIdx, unsigned short msrReg, unsigned long maskHi, unsigned long maskLo, unsigned long orHi, unsigned long orLo)
{
struct mValue mVal;
if (msrDev[msrIdx].Present == FOUND) {
asmRead(msrReg, msrDev[msrIdx].Routing, &mVal.high, &mVal.low);
// Incorporate the AND values
mVal.high &= ~maskHi;
mVal.low &= ~maskLo;
// Incorporate the OR values
mVal.high |= orHi;
mVal.low |= orLo;
asmWrite(msrReg, msrDev[msrIdx].Routing, &mVal.high, &mVal.low);
}
return;
}
//=================================================================
// void msrSave(unsigned short msrIdx, unsigned short *msrList[], struct mValue *msrValue[])
//
// Saves a list of MSRs limited by an index value of 0xFFFF.
//
//
void msrSave(unsigned short msrIdx, unsigned short *msrList, struct mValue *msrValue)
{
unsigned char finished = FALSE;
unsigned char i = 0;
if (msrDev[msrIdx].Present == FOUND)
{
while (FALSE == finished)
{
if (0xFFFF == msrList[i])
finished = TRUE;
else
{
asmRead(msrList[i], msrDev[msrIdx].Routing, &msrValue[i].high, &msrValue[i].low);
i++;
}
}
}
return;
}
//=================================================================
// void msrRestore(unsigned short msrIdx, unsigned short *msrList[], struct mValue *msrValue[])
//
// Restores a previously saved list of MSRs limited by an index value of 0xFFFF.
//
//
void msrRestore(unsigned short msrIdx, unsigned short *msrList, struct mValue *msrValue)
{
unsigned char finished = FALSE;
unsigned char i = 0;
if (msrDev[msrIdx].Present == FOUND)
{
while (FALSE == finished)
{
if (0xFFFF == msrList[i])
finished = TRUE;
else
{
asmWrite(msrList[i], msrDev[msrIdx].Routing, &msrValue[i].high, &msrValue[i].low);
i++;
}
}
}
return;
}
//=================================================================
// void msrDump(unsigned short msrIdx, unsigned short msrReg)
//
// Performs a 64-bit read of 'msrReg' in device 'msrIdx' for debug.
//
// Returns:
// NONE
//
void msrDump(unsigned short msrIdx, unsigned short msrReg)
{
struct mValue mVal;
asmRead(msrReg, msrDev[msrIdx].Routing, &mVal.high, &mVal.low);
return;
}

View File

@@ -0,0 +1,271 @@
;/*
;* Copyright (c) 2007-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
;*/
.MODEL TINY,c
.CODE
.586p
;----------------------------------------------------------------------------
; BASE ADDRESSES
; These global variables are used to access the memory mapped regions.
; VSA II maintains a flat 4 Gig selector in FS.
;----------------------------------------------------------------------------
extrn framebuffer_base:dword
extrn GPregister_base:dword
extrn VGregister_base:dword
extrn DFregister_base:dword
extrn VIPregister_base:dword
;----------------------------------------------------------------------------
; READ_FB_32: Returns a 32-bit value from the frame buffer.
;
; Parameter specifies 32-bit offset.
;----------------------------------------------------------------------------
read_fb_32 proc c address: dword
mov ebx, [address]
add ebx, [framebuffer_base]
mov eax, fs:[ebx]
mov edx, eax
shr edx, 16
ret
read_fb_32 endp
;----------------------------------------------------------------------------
; WRITE_FB_32: Writes a 32-bit value to the frame buffer.
;
; Parameters specify 32-bit offset and 32-bit data value.
;----------------------------------------------------------------------------
write_fb_32 proc c address: dword, data: dword
mov ebx, [address]
add ebx, [framebuffer_base]
mov eax, [data]
mov fs:[ebx], eax
ret
write_fb_32 endp
;----------------------------------------------------------------------------
; READ_GP_32: Returns 32-bit value from the graphics processor register space.
;
; Parameter specifies 32-bit offset.
;----------------------------------------------------------------------------
read_gp_32 proc c address: dword
mov ebx, [address]
add ebx, [GPregister_base]
mov eax, fs:[ebx]
mov edx, eax
shr edx, 16
ret
read_gp_32 endp
;----------------------------------------------------------------------------
; WRITE_GP_32: Writes 32-bit value to graphics processor register space.
;
; Parameters specify 32-bit offset and 32-bit data value.
;----------------------------------------------------------------------------
write_gp_32 proc c address: dword, data: dword
mov ebx, [address]
add ebx, [GPregister_base]
mov eax, [data]
mov fs:[ebx], eax
ret
write_gp_32 endp
;----------------------------------------------------------------------------
; READ_VG_8: Returns 8-bit value from the video generator register space.
;
; Parameter specifies 32-bit offset.
;----------------------------------------------------------------------------
read_vg_8 proc c address: dword
mov ebx, [address]
add ebx, [VGregister_base]
mov al, fs:[ebx]
ret
read_vg_8 endp
;----------------------------------------------------------------------------
; WRITE_VG_8: Writes 8-bit value to video generator register space.
;
; Parameters specify 32-bit offset and 8-bit data value.
;----------------------------------------------------------------------------
write_vg_8 proc c address: dword, data: byte
mov ebx, [address]
add ebx, [VGregister_base]
mov al, [data]
mov fs:[ebx], al
ret
write_vg_8 endp
;----------------------------------------------------------------------------
; READ_VG_32: Returns 32-bit value from the video generator register space.
;
; Parameter specifies 32-bit offset.
;----------------------------------------------------------------------------
read_vg_32 proc c address: dword
mov ebx, [address]
add ebx, [VGregister_base]
mov eax, fs:[ebx]
mov edx, eax
shr edx, 16
ret
read_vg_32 endp
;----------------------------------------------------------------------------
; WRITE_VG_32: Writes 32-bit value to video generator register space.
;
; Parameters specify 32-bit offset and 32-bit data value.
;----------------------------------------------------------------------------
write_vg_32 proc c address: dword, data: dword
mov ebx, [address]
add ebx, [VGregister_base]
mov eax, [data]
mov fs:[ebx], eax
ret
write_vg_32 endp
;----------------------------------------------------------------------------
; READ_DF_32: Returns 32-bit value from the display filter register space.
;
; Parameter specifies 32-bit offset.
;----------------------------------------------------------------------------
read_df_32 proc c address: dword
mov ebx, [address]
add ebx, [DFregister_base]
mov eax, fs:[ebx]
mov edx, eax
shr edx, 16
ret
read_df_32 endp
;----------------------------------------------------------------------------
; WRITE_DF_32: Writes 32-bit value to display filter register space.
;
; Parameters specify 32-bit offset and 32-bit data value.
;----------------------------------------------------------------------------
write_df_32 proc c address: dword, data: dword
mov ebx, [address]
add ebx, [DFregister_base]
mov eax, [data]
mov fs:[ebx], eax
ret
write_df_32 endp
;----------------------------------------------------------------------------
; READ_VIP_32: Returns 32-bit value from the video input port register space.
;
; Parameter specifies 32-bit offset.
;----------------------------------------------------------------------------
read_vip_32 proc c address: dword
mov ebx, [address]
add ebx, [VIPregister_base]
mov eax, fs:[ebx]
mov edx, eax
shr edx, 16
ret
read_vip_32 endp
;----------------------------------------------------------------------------
; WRITE_VIP_32: Writes 32-bit value to video input port register space.
;
; Parameters specify 32-bit offset and 32-bit data value.
;----------------------------------------------------------------------------
write_vip_32 proc c address: dword, data: dword
mov ebx, [address]
add ebx, [VIPregister_base]
mov eax, [data]
mov fs:[ebx], eax
ret
write_vip_32 endp
asmRead proc public uses bx eax ecx edx, msrReg:word, msrAddr:dword, ptrHigh:word, ptrLow:word
mov ecx, msrAddr
mov cx, msrReg
RDMSR
mov bx, ptrHigh
mov [bx], edx
mov bx, ptrLow
mov [bx], eax
ret
asmRead endp
asmWrite proc public uses bx eax ecx edx, msrReg:word, msrAddr:dword, ptrHigh:word, ptrLow:word
mov ecx, msrAddr
mov cx, msrReg
mov bx, ptrHigh
mov edx, [bx]
mov bx, ptrLow
mov eax, [bx]
WRMSR
ret
asmWrite endp
END

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2007-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
*/
// This file declares the data structures and arrays used by lxvg.
#include "lxvg.h"
#include "vsa2.h"
#include "vr.h"
//---------------------------------------------------------------------------
// MAIN lxvg DATA STRUCTURE
// This data structure maintains the current lxvg state.
//---------------------------------------------------------------------------
VGDATA VGdata;
unsigned long vga_config_addr;
unsigned long GPregister_base;
unsigned long VGregister_base;
unsigned long DFregister_base;
unsigned long VIPregister_base;
unsigned long framebuffer_base;
unsigned long VG_SMI_Mask;
// General system information...
Hardware SystemInfo;
// The main VG state information flag.
unsigned long VGState = SF_DISABLED;
unsigned long lockNest = 0; // Nested SMI recognition scheme
unsigned long saveLock; // Locking
// The virtual registers
unsigned short vReg[MAX_VG+1];
// END OF FILE

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2007-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
*/
// This file defines the main data structure for LXVG.
#define SIZE_PCI_HEADER 0x50
typedef struct tagVGDATA
{
// PCI HEADER
unsigned char pci_header[SIZE_PCI_HEADER]; // PCI header data
unsigned long pci_fb_mask;
} VGDATA;
// END OF FILE

View File

@@ -0,0 +1,133 @@
/*
* 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
*/
// Function:
// This module contains the main code to handle the VSA II interface.
#include "vsa2.h"
#include "vr.h"
#include "lxvg.h"
// This is required here because of inclusion problems in LXVG.h
extern Hardware SystemInfo;
// ARRAY TO STORE VSA II MESSAGE PARAMETERS
unsigned long VSAparam[MAX_MSG_PARAM];
//---------------------------------------------------------------------------
// vsa2_message_loop
//
// This is the main routine that handles the VSA II message interface.
//---------------------------------------------------------------------------
void vsa2_message_loop(void)
{
MSG Msg;
// SPIN FOREVER ON MESSAGE LOOP
// The VSA system manager branches here after loading the VSM. Control
// is returned to the system manager using an SMI.
do {
// GET THE NEXT MESSAGE
// If a message is available, the macro reads the parameter data
// from the VSM header and copies it to the VSAparam global array.
// If a message is not available, control returns to the main VSA
// dispatcher.
Msg = SYS_GET_NEXT_MSG(&VSAparam);
// DECODE THE MESSAGE
switch(Msg)
{
case MSG_INITIALIZE:
// CHECK IF NORMAL INITIALIZATION
// Currently there is no "end of post" initialization.
if (VSAparam[0] == EARLY_INIT) {
// Get information about the system I'm executing on.
SYS_GET_SYSTEM_INFO(&SystemInfo);
// REGISTER FOR VGA VIRTUAL REGISTER EVENTS
SYS_REGISTER_EVENT(EVENT_VIRTUAL_REGISTER, VRC_VG, 0, NORMAL_PRIORITY);
}
else
{
// Now we can handle DPMS and driver active
VGState |= SF_END_POST;
}
break;
case MSG_EVENT:
// DECODE THE EVENT
decode_vsa2_event();
break;
case MSG_WARM_BOOT:
break;
default:
break;
}
} while(1);
}
//---------------------------------------------------------------------------
// decode_vsa2_event
//
// This routine is called when the message loop receives an event. For
// LXVG, this is either a Virtual Rgister event or a pci event
// (trapping PCI config cycles to our device).
//---------------------------------------------------------------------------
void decode_vsa2_event(void)
{
// PARSE EVENT
switch((unsigned short)VSAparam[0])
{
case EVENT_VIRTUAL_REGISTER:
if (VRC_VG == (unsigned char)(VSAparam[1] >> 8))
virtual_register_event((unsigned char)VSAparam[1], VSAparam[2], VSAparam[3]);
break;
case EVENT_PCI_TRAP:
// If LXVG isn't enabled, just leave
if (VGState & SF_DISABLED) break;
// CALL LXVG TO DECODE THE PCI TRAP EVENT
// address = VSAparam[1]
// size = VSAparam[2], bit 7 indicates write.
// data = VSAparam[3]
pci_trap_event(VSAparam[1], VSAparam[2], VSAparam[3]);
break;
default:
break;
}
}

View File

@@ -0,0 +1,221 @@
;
; 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
;
;* Function: *
;* This file contains hardware bug fixes.
include VSA2.INC
include ISA.INC
include GX2.INC
include CHIPSET.INC
.model tiny,c
.586p
.CODE
externdef Nested_SMI: proc
externdef SysMgr_Entry: proc
externdef Restore_IDT: proc
externdef Install_IDT: proc
externdef Sample_SMI_Pin: proc
externdef Clear_SMI_Pin: proc
externdef Header_Addr: dword
externdef HC_Status: dword
externdef SMI_Sources: dword
externdef HardwareInfo: Hardware
;*******************************************************************************
; Remove the RTC fix if an RTC VSM is installed.
;*******************************************************************************
Remove_RTC_Fix proc
mov word ptr [Fix_RTC], 0C3F8h ; CLC RET
ret
Remove_RTC_Fix endp
; *******************************************************************************
; This routine is called upon entry to a non-nested SMI.
; *******************************************************************************
VSA_Entry proc
; Patch a "jmp Nested_SMI" at Start
mov word ptr ds:[1], OFFSET Nested_SMI-3
; Install exception handlers
call Install_IDT
ret
VSA_Entry endp
; *******************************************************************************
; This routine is called upon exit from a non-nested SMI.
; It performs:
; 1) RTC fix
; 2) USB fix
; 3) IDT restore
; 4) Re-enable Suspend Modulation
;
; If CF=1 is returned, then loop back to SMI handlers.
; *******************************************************************************
VSA_Exit proc
mov eax, [Header_Addr] ; Restore the original SMM header
mov ecx, MSR_SMM_HDR
wrmsr
call Fix_RTC
jc short Exit ; Don't exit from VSA
; Restore "JMP SysMgr_Entry" at Start
mov word ptr ds:[1], OFFSET SysMgr_Entry-3
call Restore_IDT ; Restore IDT
clc
Exit: ret
VSA_Exit endp
; *******************************************************************************
; Handle the case where the RTC UIP bit was clear, application code was about to
; read the RTC, but an SMI occurs. When VSA returns, the RTC is updating, so the
; application reads a bad value.
;
; The Solution:
;
; The Time Stamp Counter is read upon entry to VSA. On exit, if UIP is low or
; it is determined that the SMI has taken < 250 us, then just exit. This leaves
; 44 us for the application to finish reading the RTC safely. If the SMI has
; taken > 250 us, then spin for 500 us minus the time spent servicing the SMI.
; This guarantees the RTC has finished updating. Then set the SET bit, wait for
; UIP to go low, then clear the SET bit.
;
; *******************************************************************************
RTC_TIME equ 250
Fix_RTC proc
in al, CMOS_INDEX ; Get RTC index
cmp al, 9 ; Only RTC indices 0-9 are UIP sensitive
ja Exit
mov bl, al ; Save RTC index
push si
mov al, CMOS_STATUS_A ; Read RTC Status A
out CMOS_INDEX, al
in al, CMOS_DATA
test al, UIP
jz Restore_RTC_Index
mov al, CMOS_STATUS_B ; Exit if StatusB[SET] = 1
out CMOS_INDEX, al
in al, CMOS_DATA
test al, SET
jz Restore_RTC_Index
ASSUME SI: PTR System ; Compute time servicing SMI in us
mov si, OFFSET VSM_Header.SysStuff
rdtsc
sub eax, [si+0].StartTime
sbb edx, [si+4].StartTime
movzx ecx, [HardwareInfo].CPU_MHz
cmp edx, ecx ; If sitting in Dowser or Standby too long,
jae Restore_RTC_Index ; the divide could overflow.
div ecx
cmp eax, RTC_TIME ; If < RTC_TIME us, exit
jb Restore_RTC_Index
call Clear_SMI_Pin
WaitForUpdate:
call Sample_SMI_Pin
stc
jnz short SMI_Abort ; Yes, go process it
rdtsc ; Wait for additional 300 us
sub eax, [si+0].StartTime
sbb edx, [si+4].StartTime
div ecx
cmp eax, RTC_TIME + 300
jb WaitForUpdate
ASSUME SI: NOTHING
; StatusB[SET] = 1;
mov al, CMOS_STATUS_B ; Read RTC StatusB
out CMOS_INDEX, al
in al, CMOS_DATA
test al, SET ; If (SET == 1)
jnz short Restore_RTC_Index ; bail
or al, SET ; else
out CMOS_DATA, al ; SET = 1
; Wait for StatusA[UIP] to go inactive
mov cx, 0FFFFh ; RTC timeout
SpinUIP:
mov al, CMOS_STATUS_A ; Yes, spin until UIP is clear
out CMOS_INDEX, al
in al, CMOS_DATA
test al, UIP
loopnz SpinUIP
mov al, CMOS_STATUS_B ; SET = 0
out CMOS_INDEX, al
in al, CMOS_DATA
and al, NOT SET
out CMOS_DATA, al
Restore_RTC_Index:
clc
SMI_Abort:
pop si
mov al, bl ; Restore CMOS index
out CMOS_INDEX, al
Exit: ret
Fix_RTC endp
END

View File

@@ -0,0 +1,262 @@
;
; 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
;
;********************************************************************************
;* This file contains the Southbridge specific code.
;********************************************************************************
include smimac.mac
include chipset.inc
include pci.inc
include sysmgr.inc
include init.inc
include cs5536.inc
.model small,c
.586
.CODE
externdef Errors: word
externdef Device_ID: word
externdef Chipset_Base: dword
;***********************************************************************
; Clear all SMI source registers
;***********************************************************************
Clear_SMIs proc
mov ax, [Device_ID] ; Get Southbridge Device ID
cmp ax, DEVICE_ID_5536 ; If CS5536, exit
clc
je Exit
or [Errors], ERR_NO_CHIPSET
stc
jmp Exit
Exit: ret
Clear_SMIs endp
;****************************************************************
; Returns information about the Southbridge
;
; On Exit, if CF clear:
; EBX = PCI address of Southbridge
; CL = Chipset Revision
; DX = Device ID
;****************************************************************
Get_Sbridge_Info proc
mov ebx, 80000000h+(15 SHL 11) ; Start at Bus 0; DevNum 15
SouthbridgeLoop:
call Read_PCI32
cmp ax, VENDOR_ID_CYRIX ; Is it a Cyrix chipset ?
je short CorrectVendorID
cmp ax, VENDOR_ID_NATIONAL ; Is it a National Semiconductor chipset ?
je short CorrectVendorID
cmp ax, VENDOR_ID_AMD ; Is it an AMD chipset ?
jne short NextDevice
CorrectVendorID:
shr eax, 16
push ax ; Save device ID
mov bl, 8 ; Read Class Code & Rev ID
call Read_PCI32
mov cl, al ; Save revision in CL
shr eax, 16
cmp ax, 0601h ; Is it an ISA bridge ?
pop dx
mov bl, 0 ; Vendor & Device ID
je Exit ; CF is cleared
; Check the DeviceID
cmp dx, DEVICE_ID_5536-1 ; Hardware CS5536 Device ID
jne NextDevice
FoundSB:
; On CS5536, the virtualized Device ID is h/w Device ID + 1
inc dx
push cx
push dx
mov ecx, 5100002Fh ; Write-post I/O to port 84h for debug
mov edx, 00084001h
mov eax, edx
or al, 8
wrmsr
pop dx
pop cx
jmp Exit
NextDevice:
add bh, 8 ; Next device
cmp bh, (19 SHL 3) ; Last possible DevNum ?
jbe SouthbridgeLoop
; Can't find supported Southbridge chipset
or [Errors], ERR_NO_CHIPSET
stc
Exit: ret
Get_Sbridge_Info endp
;****************************************************************
; Generates a s/w SMI
;****************************************************************
Software_SMI proc
smint
ret
Software_SMI endp
;*********************************************************************************
; Reads 32-bit PCI config register specified by EBX
;*********************************************************************************
Read_PCI32 proc
mov dx, PCI_CONFIG_ADDRESS
mov eax, ebx
out dx, eax
mov dx, PCI_CONFIG_DATA
in eax, dx
ret
Read_PCI32 endp
;*********************************************************************************
; Writes a 32 bit Southbridge register
; Input:
; DL - register offset
; EAX - value to write
;*********************************************************************************
SetReg_32 proc uses bx
push eax
mov bl, dl
call Address8
pop eax
out dx, eax
ret
SetReg_32 endp
;*********************************************************************************
; Writes an 8 bit register
; Input:
; BL = register #
; BH = Data
;*********************************************************************************
SetReg_8 proc
call Address8
mov al, bh
out dx, al
ret
SetReg_8 endp
;*********************************************************************************
; Reads an 8 bit register
; Input:
; BL = register #
; Output:
; AL = Data
;*********************************************************************************
GetReg_8 proc
call Address8
in al, dx
ret
GetReg_8 endp
;*********************************************************************************
; Helper routine for SetReg_32, SetReg_8 & GetReg_8
;*********************************************************************************
Address8 proc
mov dx, PCI_CONFIG_ADDRESS
mov eax, [Chipset_Base]
mov al, bl
and al, NOT 3
out dx, eax
mov dx, PCI_CONFIG_DATA
and bl, 3
add dl, bl
ret
Address8 endp
;*********************************************************************************
; Determines the base address of the top-level SMI status register
; On Exit:
; EAX = address
;*********************************************************************************
Get_SMI_Base proc
mov ebx, [Chipset_Base] ; Patch SMI_Base
add bx, PM_FUNCTION + BAR0
call Read_PCI32
mov al, SMI_STATUS
ret
Get_SMI_Base endp
;*********************************************************************************
; Determines the base address of the internal IRQ register
; On Exit:
; EAX = address
;*********************************************************************************
Get_IRQ_Base proc
mov ebx, [Chipset_Base] ; Patch SMI_Base
add bx, AUDIO_FUNCTION + BAR0 ; Patch IRQ_Base
call Read_PCI32
mov al, 1Ah
ret
Get_IRQ_Base endp
END

View File

@@ -0,0 +1,239 @@
/*
* 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
*/
/*****************************************************************************
* The routines in this file translate requests for hardware
* support to Southbridge-specific function calls.
*****************************************************************************/
#include "VSA2.H"
#include "CHIPSET.H"
#include "CS5536.H"
#include "ISA.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#include "GX2.H"
// External function prototypes
extern void MillisecondTimer(UCHAR, EVENT_ENTRY *);
extern void InitTimers(void);
extern void Init_CS5536(void);
extern void pascal Enable_USB_5536(UCHAR, USHORT);
extern void pascal Address_Decode_5536(UCHAR, USHORT);
extern void pascal MBus_IO_Trap(ULONG, ULONG, UCHAR);
extern void pascal MBus_IO_Timeout(ULONG, ULONG, UCHAR);
extern void pascal A20_Init(UCHAR);
extern void pascal InactivityTimer(UCHAR, USHORT, UCHAR);
extern void pascal Program_PWM(UCHAR, UCHAR, USHORT, UCHAR);
// External variables
extern EVENT_ENTRY Events[];
extern Hardware HardwareInfo;
extern ULONG MPCI_NB;
extern ULONG ATA_Error;
// Local variables:
typedef void (pascal * CHIPSET_DEPENDENT)(unsigned char, unsigned short);
CHIPSET_DEPENDENT Address_Decode;
CHIPSET_DEPENDENT Enable_USB;
GPIO_FUNCTION GPIO_Control;
ULONG ClocksPerMs;
//*****************************************************************************
// Initializes the Southbridge
//*****************************************************************************
void InitChipset(void)
{
ClocksPerMs = HardwareInfo.CPU_MHz * 1000L;
InitTimers();
switch (HardwareInfo.Chipset_ID) {
case DEVICE_ID_5536:
Address_Decode = Address_Decode_5536;
Enable_USB = Enable_USB_5536;
// Initialize the CS5536
Init_CS5536();
break;
}
}
//*****************************************************************************
// Enables trapping of a PCI function
// Return value:
// 0 = not supported
// 1 = already enabled
// 2 = previously disabled
//*****************************************************************************
UCHAR pascal Enable_PCI_Trapping(USHORT PCI_Address, UCHAR EnableFlag)
{ UCHAR ReturnValue = 0;
// Call the appropriate chipset routine
switch (HardwareInfo.Chipset_ID) {
default:
// Use PBUS MSR to trap this address
Trap_PCI_IDSEL(PCI_Address, EnableFlag);
ReturnValue = 1;
break;
}
return ReturnValue;
}
//*****************************************************************************
// Diables an event
//*****************************************************************************
void pascal Disable_Event(EVENT Event, USHORT Index)
{
Enable_Event(Event, Index, 0);
}
//*****************************************************************************
// Enables an event
//
// EnableFlag:
// 0 = Disable event
// 1 = Enable event
// 2 = Reset event logic (e.g. timer, GPIO)
//*****************************************************************************
void pascal Enable_Event(EVENT Event, USHORT Index, UCHAR EnableFlag)
{ USHORT Device_ID;
UCHAR Error = 0;
ULONG Param1, Param2;
EVENT_ENTRY * EventPtr;
Device_ID = HardwareInfo.Chipset_ID;
EventPtr = &Events[Index];
Param1 = EventPtr->Param1;
Param2 = EventPtr->Param2;
switch (Event) {
case EVENT_USB:
Enable_USB(EnableFlag, (USHORT)Param1);
case EVENT_KEL:
break;
case EVENT_TIMER:
// Initialize RemainingInterval field to Interval
if (EnableFlag == 1) {
EventPtr->RemainingInterval = EventPtr->Param1;
}
MillisecondTimer(EnableFlag, EventPtr);
break;
case EVENT_IO_TRAP:
MBus_IO_Trap(Param1, Param2, EnableFlag);
break;
case EVENT_DEVICE_TIMEOUT:
// If programmer forgot to specify Instance, assume 1st instance
if ((USHORT)Param2 == 0x0000) {
(USHORT)Param2 = 1;
}
Param2 |= GLIU_ID;
case EVENT_IO_TIMEOUT:
MBus_IO_Timeout(Param1, Param2, EnableFlag);
break;
case EVENT_PME:
(USHORT)Param2 |= PME;
case EVENT_GPIO:
GPIO_Control(Param1, Param2, EnableFlag);
break;
case EVENT_PCI_TRAP:
if (Enable_PCI_Trapping((USHORT)Param1, EnableFlag) == 0) {
// Companion I/O can't trap requested PCI function.
Error = ERR_PCI_TRAP;
}
break;
case EVENT_ACPI:
switch (Device_ID) {
case DEVICE_ID_5536:
Enable_ACPI_5536(EnableFlag);
break;
}
break;
case EVENT_PWM:
// GPIO pin Duty cycle (%) Rate (ms)
Program_PWM((UCHAR)Param1, (UCHAR)(Param2 >> 16), (USHORT)(Param1 >> 16), EnableFlag);
// 8 LSBs are GPIO pin number
Param1 &= 0x000000FF;
// Mask all except valid flags
Param2 &= OPEN_DRAIN | PULLDOWN | PULLUP | INVERT;
// Insert flags appropriate to PWM
Param2 |= OUTPUT | NO_ASMI;
if (EnableFlag) {
Param2 |= AUX1;
}
GPIO_Control(Param1, Param2, EnableFlag);
break;
} // end switch (Event)
if (Error) {
Report_VSM_Error(Error, Event, Param1);
}
}
void pascal Set_Address_Decode(USHORT Address, UCHAR Decode)
{
Address_Decode(Decode, Address);
}
void pascal Allocate_Resource(USHORT Resource, ULONG Param)
{
switch ((UCHAR)Resource) {
case RESOURCE_IRQ:
break;
default:
break;
}
}

View File

@@ -0,0 +1,59 @@
;
; 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
;
;* Function: *
;* Implementation of routines specific to the Vail core.
.model tiny,c
.586p
.ALPHA
DGROUP GROUP _CODE, _TEXT
_CODE SEGMENT PUBLIC use16 'CODE'
ASSUME DS:_CODE
;************************************************************************
;************************************************************************
Sample_SMI_Pin proc
ret
Sample_SMI_Pin endp
;************************************************************************
;************************************************************************
Clear_SMI_Pin proc
ret
Clear_SMI_Pin endp
_CODE ENDS
END

View File

@@ -0,0 +1,339 @@
;
; 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
;
;* Function: *
;* This file contains code specific to the processor core.
include vsa2.inc
include gx2.inc
include sysmgr.inc
include init.inc
include chipset.inc
.model small,c
.586
.CODE
externdef BIOS_ECX: dword
externdef BIOS_EDX: dword
externdef VSA_Image:byte
SMM_Size dd 0
FooGlue dd 54000000h
;***********************************************************************
; Sets CPU dependent fields in the SMM header
; On entry:
; SI = pointer to VSM header
;***********************************************************************
Set_CPU_Fields proc
SMM_CONTROL equ EXTL_SMI_EN + INTL_SMI_EN + SMM_INST_EN + NEST_SMI_EN
mov (VSM_Header PTR [si]).SysStuff.State.SMM_CTL_MSR, SMM_CONTROL
ret
Set_CPU_Fields endp
;***********************************************************************
; - Sets the SMM entry point to the location in EBX
; - Sets the SMM header location
; - Write protects the SMM regions
;***********************************************************************
Init_SMM_Region proc
; Set the SMM entry point
mov ecx, MSR_SMM_LOC
mov eax, ebx
mov edx, [SMM_Size] ; SMM Code Limit
wrmsr
; Set the SMM header location
lea eax, (VSM_Header PTR [eax]).SysStuff.State + sizeof(SmiHeader)
mov ecx, MSR_SMM_HDR
xor edx, edx
wrmsr
; Write protect the SMM memory
mov ecx, MSR_RCONF_SMM
rdmsr
or al, REGION_WP
wrmsr
ret
Init_SMM_Region endp
;***********************************************************************
; Returns information about the LX CPU
; On exit:
; AX = CPU Revision
; SI = CPU ID
; BX = PCI MHz
; CX = CPU MHz
; DX = DRAM MHz
;***********************************************************************
Get_CPU_Info proc
mov ecx, 4C000014h ; GLCP_SYS_RSTPLL
rdmsr
; PCI Speed
mov bx, 33
test al, 1 SHL 7 ; RSTPPL_LOWER_PCISPEED_SHIFT
jz not66
mov bx, 66
not66:
push bx ; save PCI speed
; CPU Speed
mov ax, 333 ; 33.3MHZ * 10
ror dx, 1 ; RSTPLL_UPPER_CPUMULT_SHIFT
mov bx, dx
rol dx, 1 ; RSTPLL_UPPER_CPUMULT_SHIFT
push dx ; save RSTPLL
and bx, 1Fh
inc bx ; 0 = multiply by 1....
mul bx ; ax=PCI * bl=Mul
; Rounding divide
mov bx, 10
xor dx, dx
div bx ; ax= quotent and dx=remainder
cmp dx, 5
jb NoRound ; can round because of /10
inc ax ; round up
NoRound:
pop dx ; restore RSTPLL
pop bx ; restore PCI * 10
push ax ; save CPU speed
; DRAM speed
mov ax, 333 ; 33.3MHZ * 10
ror dx, 7 ; RSTPLL_UPPER_GLMULT_SHIFT
mov bx, dx
rol dx, 7 ; RSTPLL_UPPER_GLMULT_SHIFT
push dx ; save RSTPLL
and bx, 1Fh
inc bx ; 0 = multiply by 1....
mul bx ; ax=PCI * bl=Mul
; Rounding divide
mov bx, 10
xor dx, dx
div bx ; ax= quotent and dx=remainder
cmp dx, 5
jb NoRoundmem ; can round because of /10
inc ax ; round up
NoRoundmem:
; DDR is 1/2 GeodeLink speed.
xor dx, dx
mov bx, 2
div bx
push ax ; save mem speed
; Get CPU Revision
mov cx, 0017h
rdmsr
push ax
mov ecx, 10002000h ; Read MBIU0 Capabilities MSR
rdmsr
and ah, 0Fh ; Extract 4 LSBs of DEVID
cmp ah, 04h ; Is it LX ?
mov si, DEVICE_ID_GX2
jne RestoreInfo
mov si, DEVICE_ID_LX ; Yes
mov [FooGlue], 4C000020h ; FooGlue is at Northbridge MCP + 20h
RestoreInfo:
pop ax ; Restore CPU Revision
pop dx ; Restore DRAM MHz
pop cx ; Restore CPU MHz
pop bx ; Restore PCI MHz
ret
Get_CPU_Info endp
;***********************************************************************
; Returns the SMM information
; On Exit:
; EAX = SMM entry point
; BX = Size of SMM memory in KB
;***********************************************************************
Get_SMM_Region proc
Local Attributes: byte
mov ecx, MSR_RCONF_DEFAULT
rdmsr
mov [Attributes], al
mov ecx, [BIOS_ECX] ; Descriptor for SMM memory
rdmsr
cmp cl, 27h ; P2D_BMO or P2D_RO ?
jbe BaseMaskOffset
mov ebx, eax ; P2D_RO
shl eax, 12 ; EAX = SMM base
shrd ebx, edx, 8 ; EBX = end of SMM range
and bx, 0F000h
sub ebx, eax ; Compute length of range
add ebx, 1000h ; Adjust for 4KB granularity
shr ebx, 10 ; Convert to KB
jmp short Save_SMM_Base
BaseMaskOffset:
mov ebx, eax ; BX = length of SMM memory in KB
shrd eax, edx, 8 ; EAX = Base
and ax, 0F000h
or ebx, 0FFF00000h
neg ebx
shl ebx, 2 ; Adjust for 4KB granularity
Save_SMM_Base:
push eax ; Save SMM base
push bx ; Save SMM size in KB
shl ebx, 10 ; Convert KB to bytes
dec ebx
mov [SMM_Size], ebx ; Save size for MSR_SMM_LOC
; Set SMM RCONF
and bx, 0F000h
mov edx, ebx ; SMM_TOP = SMM_BASE + sizeof(SMM region)
add edx, eax
mov dl, [Attributes] ; SMM active properties mirror RCONF_DEFAULT
or ah, 1 ; Set Enable
mov al, dl ; SMM inactive properties (R/W for now)
and al, NOT REGION_WP
mov ecx, MSR_RCONF_SMM
wrmsr
pop bx ; BX = size of SMM region in KB
pop eax ; EAX = base of SMM region
ret
Get_SMM_Region endp
;****************************************************************
; Enables SMIs
;****************************************************************
Enable_SMIs proc
; Enable internal and external SMIs
mov ecx, MSR_SMM_CTRL
rdmsr
or eax, INTL_SMI_EN + EXTL_SMI_EN
wrmsr
ret
Enable_SMIs endp
;***********************************************************************
; Enables the SMM instructions
;***********************************************************************
Enable_SMM_Instr proc
mov ecx, MSR_SMM_CTRL
rdmsr
or eax, SMM_INST_EN
wrmsr
ret
Enable_SMM_Instr endp
;***********************************************************************
; Disables the A20 masking at the processor.
;***********************************************************************
Disable_A20 proc
mov ecx, [FooGlue]
add cx, FG_A20M
rdmsr
and al, NOT A20M ; A20M = 0
wrmsr
ret
Disable_A20 endp
;***********************************************************************
; Gets the size of physical memory
; On Exit:
; EAX = physical memory size in bytes
;***********************************************************************
Get_Memory_Size proc
mov ecx, [BIOS_EDX] ; P2D_R descriptor of physical memory
jecxz Exit
rdmsr
; EDX = 2000001F
; EAX = FDF00100
; 1MB thru <512MB-192K)
shrd eax, edx, 20 ; Extract PMAX field
shl eax, 12 ; Convert units from 4KB to bytes
Exit: ret
Get_Memory_Size endp
; The linker won't allow code to be put in a PARA aligned segment.
; The following will align the next module to a paragraph boundary.
TEXT SEGMENT PARA 'CODE'
db 16 dup (0)
TEXT ENDS
END

View File

@@ -0,0 +1,328 @@
/*
* 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
*/
//*****************************************************************************
//* Routines related to the CS5536
//*****************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#include "GX2.H"
#include "VPCI.H"
#include "DESCR.H"
#include "PCI.H"
#include "CHIPSET.H"
#include "CS5536.H"
#include "MDD.H"
ULONG Mbiu2 = MPCI_SOUTH + 0x00020000; // 2.4.2.0.1
ULONG MPCI_SB = MPCI_SOUTH; // 2.4.2.0.0
ULONG MCP_SB = MPCI_SOUTH + 0x00700000; // 2.4.2.7.0
ULONG OHCI1_Smi=0, OHCI2_Smi=0;
CAPABILITIES Southbridge_MBIU;
ULONG ATA_Error;
// External Functions:
extern void CS5536_GPIO_Init(void);
extern void Init_MDD(void);
extern ULONG Write_EPCI(UCHAR, ULONG);
extern void ACPI_PMS_SWAPSiF(void);
extern PCI_HEADER_ENTRY * Get_Structure(USHORT);
extern void pascal Handle_EHCI_Wr(PCI_HEADER_ENTRY *);
extern PCI_HEADER_ENTRY * pascal Find_Register(PCI_HEADER_ENTRY *, UCHAR);
// External Variables:
extern ULONG MPCI_NB, MDD_Base;
extern Hardware HardwareInfo;
extern PCI_HEADER_ENTRY ISA_Hdr[];
extern PCI_HEADER_ENTRY Audio_Hdr[];
extern VIRTUAL_DEVICE * SouthBridge;
extern PCI_HEADER_ENTRY * Virtual_5536[];
//***********************************************************************
// Enables USB SMIs on CS5536
//***********************************************************************
void pascal Enable_USB_5536(UCHAR EnableFlag, USHORT Instance)
{ ULONG MsrData;
UCHAR Mask;
// OHCI is the only valid setting for now
if (Instance == 1) {
MsrData = Read_MSR_LO(OHCI1_Smi);
Mask = 0x10 << (Instance-1);
if (EnableFlag) {
(UCHAR)MsrData &= ~Mask;
} else {
(UCHAR)MsrData |= Mask;
}
Write_MSR_LO(OHCI1_Smi, MsrData);
} else {
static UCHAR * Msg_Enable = "enable";
static UCHAR * Msg_Disable = "disable";
UCHAR * OnOff;
if (EnableFlag) {
OnOff = Msg_Enable;
} else {
OnOff = Msg_Disable;
}
Log_Error("Attempt to %s invalid USB instance: 0x%04X", OnOff, Instance);
}
}
//***********************************************************************
// Enables/disables writes to PM1_CNT register
//***********************************************************************
void Enable_ACPI_5536(UCHAR EnableFlag)
{ ULONG MsrAddr, MsrData;
// Get address to MDDs SMI MSR
MsrAddr = MDD_Base;
(USHORT)MsrAddr = MBD_MSR_SMI;
// Get current value
MsrData = Read_MSR_LO(MsrAddr);
// Set/clear enable for trapping of writes to PM1_CNT
if (EnableFlag) {
MsrData |= PM1_CNT_SSMI_EN;
} else {
MsrData &= ~PM1_CNT_SSMI_EN;
}
// Update the MSR
Write_MSR_LO(MsrAddr, MsrData);
}
//***********************************************************************
// Sets positive/subtractive decode
//***********************************************************************
void pascal Address_Decode_5536(UCHAR Decode, USHORT Address)
{
// Not yet implemented
}
//***********************************************************************
// Initializes BARs in the Southbridge virtual headers
//***********************************************************************
void Init_SB_Headers(void)
{ ULONG MsrAddr, BAR_Value;
USHORT PCI_Addr, Bar;
//*********************************************
// Allocate BARs for CS5536's F0 header
//*********************************************
MsrAddr = MDD_Base;
for (Bar = BAR0; Bar <= BAR5; Bar += 4) {
ULONG BAR_Length;
(UCHAR)MsrAddr = ISA_Hdr[Bar/4].LBar;
// Get current LBAR value
BAR_Value = Read_MSR_LO(MsrAddr);
// Determine the length of the I/O range
BAR_Length = ISA_Hdr[Bar/4].Mask;
// Allocate a PCI BAR corresponding to the LBAR
PCI_Addr = Allocate_BAR(RESOURCE_IO, Bar, BAR_Length, ID_MDD, ISA_Hdr[0].Device_ID);
// Synchronize with any LBARs that have already been initialized by the BIOS
Virtual_PCI_Write_Handler(PCI_Addr, DWORD_IO, BAR_Value);
}
// Initialize Southbridge's COMMAND register
(UCHAR)PCI_Addr = COMMAND;
Virtual_PCI_Write_Handler(PCI_Addr, BYTE_IO, SPECIAL_CYCLES | IO_SPACE);
//*********************************************
// Allocate Audio BAR
//*********************************************
Allocate_BAR(RESOURCE_IO, BAR0, 128, ID_AC97, Audio_Hdr[0].Device_ID);
}
//***********************************************************************
// Initializes the CS5536 chipset
//***********************************************************************
void Init_CS5536(void)
{ register PCI_HEADER_ENTRY * Header;
ULONG MsrAddr, USB20_Msr, MsrData[2];
UCHAR i, CS5536_DevNum;
//*********************************************
// Get routing address of CS5536's MPCI
//*********************************************
MPCI_SB = MPCI_NB;
CS5536_DevNum = (UCHAR)((USHORT)HardwareInfo.Chipset_Base >> 11);
MsrData[0] = Read_MSR_LO(MPCI_NB + MPCI_ExtMSR);
while (MsrData[0]) {
MPCI_SB += 1L << 23;
if ((UCHAR)MsrData[0] == CS5536_DevNum) {
break;
}
MsrData[0] >>= 8;
}
//*********************************************
// Get routing address to Southbridge's GLIU
//*********************************************
Mbiu2 = MPCI_SB + 0x00020000;
// Read Southbridge's GLIU capabilities
Read_MSR(Mbiu2 + MBIU_CAP, &MsrData[0]);
//*********************************************
// Initialize GLIU2
//*********************************************
Parse_Capabilities(MsrData, &Southbridge_MBIU);
// The NP2D_SCO field is actually the NP2D_BMK field
Southbridge_MBIU.NP2D_BMK = Southbridge_MBIU.NP2D_SCO;
Southbridge_MBIU.NP2D_SCO = 0;
// SWAPSiF for erroneous P2D_BM/BMK numbering
if (HardwareInfo.Chipset_ID == DEVICE_ID_5536) {
Southbridge_MBIU.NP2D_BM = 3;
}
// Find address of MCP in Southbridge
MCP_SB = Find_MBus_ID(ID_MCP, 2) & 0xFFFF0000;
// Default range for IDE P2D_BM descriptor is 16 bytes.
// Change range to 8 bytes.
MsrAddr = Mbiu2 + MSR_IO_DESCR;
Write_MSR_LO(MsrAddr, Read_MSR_LO(MsrAddr) | 0x00000008);
// Initialize the descriptor structure for Southbridge's GLIU
Init_MBIU((UCHAR *)&Southbridge_MBIU, Mbiu2);
// Get Southbridge's Revision ID from MCP
ISA_Hdr[REVISION_ID/4].Revision_ID = (UCHAR)Read_MSR_LO(MCP_SB + 0x0017);
//*********************************************
// Initialize the MDD
//*********************************************
Init_MDD();
//*********************************************
// Add MPCI R0-R15 to available descriptor list
//*********************************************
MsrAddr = MPCI_SB;
// REGION_R15 is reserved for port 84h
for ((USHORT)MsrAddr = REGION_R0; (UCHAR)MsrAddr <= REGION_R15-1; MsrAddr++) {
if (Init_Descr(MPCI_RCONF, MsrAddr)) {
break;
}
}
// Enable SSMI Received event
(USHORT)MsrAddr = MBD_MSR_SMI;
Write_MSR_LO(MsrAddr, Read_MSR_LO(MsrAddr) | SSMM);
// Add ATA LBAR to available descriptor list
// NOTE: Not really part of MDD (just leveraging MDD logic)
MsrAddr = Find_MBus_ID(ID_ATA, 1);
ATA_Error = MsrAddr;
(USHORT)ATA_Error = MBD_MSR_ERROR;
#if 1
// Enable SSMI Received event
(USHORT)MsrAddr = MBD_MSR_SMI;
Write_MSR_LO(MsrAddr, Read_MSR_LO(MsrAddr) | SSMM);
#endif
(USHORT)MsrAddr = MSR_LBAR_ATA;
Init_Descr(MDD_LBAR, MsrAddr);
//*********************************************
// Initialize the virtual Southbridge headers
//*********************************************
Init_SB_Headers();
//*********************************************
// Initialize the GPIO logic
//*********************************************
CS5536_GPIO_Init();
//*********************************************
// Install workaround for ACPI & PMS bugs
//*********************************************
ACPI_PMS_SWAPSiF();
// Find address of USB 2.0
OHCI1_Smi = USB20_Msr = Find_MBus_ID(ID_USB_20, 1);
if (OHCI1_Smi == 0) {
return;
}
(USHORT)OHCI1_Smi = MBD_MSR_SMI;
// Set PMEEN for each USB 2.0 controller
for (i=USBMSROHCB; i<=USBMSRUOCB; i++) {
(UCHAR)USB20_Msr = i;
Read_MSR(USB20_Msr, MsrData);
MsrData[1] |= PMEEN;
Write_MSR(USB20_Msr, MsrData);
}
// Initialize the USB 2.0 devices
for (i=0; i <= 7; i++) {
// If the header exists...
if (Header = Virtual_5536[i]) {
// Read Class Code to see it is USB class
if ((Header+REVISION_ID/4)->Class == 0x0C03) {
// Initialize USB LBAR
(UCHAR)USB20_Msr = (Header+BAR0/4)->LBar;
Init_Descr(USB_LBAR, USB20_Msr);
// Allocate the PCI BAR
Allocate_BAR(RESOURCE_MMIO, BAR0, (Header+BAR0/4)->Mask, ID_USB_20, Header->Device_ID);
// If EHCI, initialize FLADJ
if (Header->Device_ID == DEVICE_ID_AMD_EHCI) {
Header = Find_Register(Header, SRBN_REG);
if ((USHORT)Header != UNIMPLEMENTED_REGISTER) {
Header->FLADJ = 0x20;
Handle_EHCI_Wr(Header);
}
}
}
}
}
}

View File

@@ -0,0 +1,220 @@
;
; 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
;
;* Function: *
;* Debug routines for GX2-based systems
include vsa2.inc
include vr.inc
include sysmgr.inc
.model tiny,c
.586p
.CODE
CR equ 0Dh
LF equ 0Ah
externdef SMM_Header: SmiHeader
;***********************************************************************
; Hex dump routines
;***********************************************************************
Hex_32 proc pascal Num:dword
pushad
mov ebx, Num
mov cx, 8
@@: rol ebx, 4
call Hex_4
loop @b
call Space
popad
ret
Hex_32 endp
Hex_16 proc pascal Num:word
pusha
mov cx, 4
mov bx, Num
@@: rol bx, 4
call Hex_4
loop @b
call Space
popa
ret
Hex_16 endp
Hex_8 proc pascal Num:byte
pusha
mov cx, 2
mov bl, Num
@@: rol bl, 4
call Hex_4
loop @b
call Space
popa
ret
Hex_8 endp
Hex_4: mov al, bl
and al, 0Fh
add al, '0' ; Convert to ASCII
cmp al, '9'
jbe @f
add al, 7 ; 'A'-'F'
@@: mov dx, DBG_PORT
jmp Char
Space: mov al, ' '
Char: out dx, al
in al, 80h
ret
;***********************************************************************
; Displays SMI source(s)
;
; On Entry:
; ECX = SMI source(s)
;***********************************************************************
Show_SMI_Source proc
pushad
cld
mov dx, DBG_PORT
lea bx, SMI_Source_Strings-2
MsgLoop:jecxz Exit
add bx, 2
shr ecx, 1
jnc MsgLoop
mov si, [bx] ; Get message ptr
cmp si, OFFSET Msg_DescrHit
jne short CharLoop
mov ax, [SMM_Header].IO_addr
cmp ax, VRC_INDEX
je IsVirtualReg
cmp ax, VRC_DATA
jne CharLoop
IsVirtualReg:
lea si, [Msg_VirtReg]
CharLoop:
lodsb
or al, al ; End of string ?
jz Blank
out dx, al ; No, display next character
jmp CharLoop
Blank: mov al, ' ' ; Yes, display trailing blank
out dx, al
jmp MsgLoop
Exit: popad
ret
Show_SMI_Source endp
SMI_Source_Strings:
dw OFFSET Msg_PM
dw OFFSET Msg_Audio
dw OFFSET Msg_ACPI
dw OFFSET Msg_VG
dw OFFSET Msg_Reserved
dw OFFSET Msg_Retrace
dw OFFSET Msg_VGA_Timer
dw OFFSET Msg_A20
dw OFFSET Msg_SW_SMI
dw OFFSET Msg_GTT
dw OFFSET Msg_Reserved
dw OFFSET Msg_MFGPT
dw OFFSET Msg_NMI
dw OFFSET Msg_Reset
dw OFFSET Msg_USB
dw OFFSET Msg_Graphics
dw OFFSET Msg_GT1
dw OFFSET Msg_GT2
dw OFFSET Msg_USR_DEF_1
dw OFFSET Msg_VirtReg
dw OFFSET Msg_USR_DEF_3
dw OFFSET Msg_PCI_Trap
dw OFFSET Msg_Reserved
dw OFFSET Msg_Reserved
dw OFFSET Msg_MPCI
dw OFFSET Msg_DescrHit
dw OFFSET Msg_Stat_Hit
dw OFFSET Msg_PIC
dw OFFSET Msg_KEL
dw OFFSET Msg_PME
dw OFFSET Msg_BlockIO
dw OFFSET Msg_Reserved
Msg_Reserved db '???',0
Msg_VG db 'VG',0
Msg_PM db 'PM',0
Msg_Audio db 'Audio',0
Msg_ACPI db 'ACPI',0
Msg_Retrace db 'Vsync',0
Msg_VGA_Timer db 'Vga',0
Msg_SW_SMI db 'S/W',0
Msg_A20 db 'A20',0
Msg_GTT db 'GTT',0
Msg_MFGPT db 'MFGPT',0
Msg_NMI db 'NMI',0
Msg_GT1 db 'GT1',0
Msg_GT2 db 'Timer',0
Msg_USB db 'USB',0
Msg_Reset db 'Reset',0
Msg_Graphics db 'VGA',0
Msg_USR_DEF_1 db 'PIC',0
Msg_VirtReg db 'VR',0
Msg_USR_DEF_3 db 'UDef3',0
Msg_PCI_Trap db 'PCI',0
Msg_MPCI db 'MPCI',0
Msg_DescrHit db 'I/O',0
Msg_Stat_Hit db 'StatHit',0
Msg_PIC db 'PIC',0
Msg_KEL db 'KEL',0
Msg_PME db 'PME',0
Msg_BlockIO db 'BlockIO',0
end

View File

@@ -0,0 +1,521 @@
/*
* 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
*/
//******************************************************************************
//* Utility routines for managing descriptors
//******************************************************************************
#include "VSA2.H"
#include "PROTOS.H"
#include "GX2.H"
#include "VPCI.H"
#include "DESCR.H"
#include "SYSMGR.H"
// External variables:
extern UCHAR NumMbius;
extern UCHAR MBIU1_SelfReference;
// Local variables:
UCHAR NumDescriptors = 1;
DESCRIPTOR MSRs[MAX_DESCR]={0};
UCHAR DynamicVSALoad=0;
//***********************************************************************
// Computes the 32 LSBs of an IOD_SC descriptor from Address/Range
//***********************************************************************
ULONG pascal Compute_IOD_SC(ULONG * AddressPtr, USHORT * RangePtr, UCHAR Flag)
{ ULONG IO_Mask, Address;
USHORT Range;
UCHAR Addr_LSBs, Bit_Mask, Max_Bits;
Address = * AddressPtr;
Range = * RangePtr;
// Set IOD_SC Base field
IO_Mask = Address & 0x0000FFF8;
// Compute the R/W attributes
if (!(Address & WRITES_ONLY)) {
IO_Mask |= REN;
}
if (!(Address & READS_ONLY)) {
IO_Mask |= WEN;
}
// Initialize bit mask
Addr_LSBs = (UCHAR)Address & 0x7;
Max_Bits = 8 - Addr_LSBs;
if (Range > Max_Bits) {
Range = Max_Bits;
}
Bit_Mask = (UCHAR)(0x01 << Range) - 1;
Bit_Mask <<= Addr_LSBs;
// Insert byte enables
IO_Mask |= (ULONG)Bit_Mask << 24;
// Adjust Address & Range parameters by # bytes handled by this descriptor
if (Flag) {
* AddressPtr += (ULONG)Range;
* RangePtr -= (USHORT)Range;
}
return IO_Mask;
}
//***********************************************************************
// Returns the default value for the given descriptor Type
//***********************************************************************
void pascal Get_Descriptor_Default(UCHAR Type, ULONG * Msr)
{
*Msr = *(Msr+1) = 0x00000000;
switch (Type) {
case IOD_BM:
case P2D_BM:
case P2D_BMO:
case P2D_BMK:
*Msr = 0xFFF00000;
*(Msr+1) = 0x000000FF;
break;
case P2D_R:
case P2D_RO:
*(Msr) = 0x000FFFFF;
break;
default:
break;
}
}
//***********************************************************************
// Initializes a MSRs[] entry
//***********************************************************************
UCHAR pascal Init_Descr(UCHAR Type, ULONG MsrAddr)
{ register DESCRIPTOR * Descr;
// Keep count of total # descriptors
if (NumDescriptors >= MAX_DESCR) {
// Log an error: Not enough descriptor entries.
Report_VSM_Error(ERR_NO_MORE_DESCRIPTORS, MAX_DESCR, 0x77 );
return 0x01;
}
Descr = &MSRs[NumDescriptors++];
// Initialize the descriptor entry
Descr->Mbiu = NumMbius;
Descr->Split = 0x00;
Descr->Flag = AVAILABLE;
Descr->Type = Type;
Descr->Link = 0x00;
Descr->Owner = 0x0000;
Descr->MsrAddr = MsrAddr;
Descr->Physical = 0x00000000;
return 0x00;
}
//***********************************************************************
// Returns a descriptor to the available pool
//***********************************************************************
void Deallocate_Descriptor(DESCRIPTOR * Descr)
{
// Mark MSR available
Descr->Flag = AVAILABLE;
Descr->Link = 0x00;
Descr->Owner = 0x0000;
// Set MSR to default value
Get_Descriptor_Default(Descr->Type, Descr->MsrData);
Write_MSR(Descr->MsrAddr, Descr->MsrData);
}
//***********************************************************************
// Restores all descriptors owned by VSA to their default values.
// Used when VSA is installed from DOS.
//***********************************************************************
void ReInit_Descriptors(void)
{ register USHORT Index;
register DESCRIPTOR * Descr;
ULONG MDD_Msr;
DynamicVSALoad = 1;
Descr = &MSRs[1];
MDD_Msr = Find_MBus_ID(ID_MDD, 1) & ROUTING;
// Restore VSA-owned MSRs to their default values
for (Index = 1; Index < NumDescriptors; Index++) {
// Don't zero MDD LBARs
if ((Descr->MsrAddr & ROUTING) == MDD_Msr) {
Descr->Flag = AVAILABLE;
} else {
if (Descr->MsrAddr == 0x5100002F) {
continue;
}
Deallocate_Descriptor(Descr);
}
Descr++;
}
NumDescriptors = 1;
}
//***********************************************************************
// Searches for an unused descriptor of the specified type(s) on the
// specified MBIU.
// NOTE: This implementation makes multiple passes through the table, but
// this removes the requirement that they be in a particular order.
//***********************************************************************
UCHAR pascal Allocate_Descriptor(UCHAR Type, UCHAR EndType, ULONG Msr)
{ register DESCRIPTOR * Descr;
register UCHAR Index;
ULONG Mask;
UCHAR Incr = 1;
if (EndType < Type) {
Incr = 0xFF;
}
EndType += Incr;
do {
// Find an available descriptor of the right type
Index = 1;
do {
Descr = &MSRs[Index];
if ((Descr->Flag & AVAILABLE) && (Type == Descr->Type)) {
switch (Type) {
case MPCI_RCONF:
case GX2_RCONF:
// Any register will do
Mask = 0x00000000;
break;
case USB_LBAR:
case MDD_LBAR:
// Entire MSR must match
Mask = 0xFFFFFFFF;
break;
case EPCI:
// Entire routing field must match
Mask = ROUTING;
break;
default:
// MSR must match in 1st 3 routing fields
Mask = 0xFF800000;
break;
}
if ((Descr->MsrAddr & Mask) == (Msr & Mask)) {
// Mark descriptor in-use
Descr->Flag &= ~AVAILABLE;
return Index;
}
}
Index++;
} while (Index != NumDescriptors);
Type += Incr;
} while (Type != EndType);
return DESCRIPTOR_NOT_FOUND;
}
//***********************************************************************
// Searches existing descriptors for the specified address range.
// If possible, a descriptor is updated to add/remove the new range.
// Parameter Enable:
// = 0, the range is removed
// = 1, the range is added for I/O timeout
// = 2, the range is added for I/O trap
// = 3, the range is being searched (SYS_IO_DESCRIPTOR)
//***********************************************************************
UCHAR pascal Find_Matching_IO_Descriptor(ULONG * AddressPtr, USHORT * RangePtr, UCHAR Enable)
{ UCHAR Index, HitFlag, DescrFlag;
ULONG Attributes, Mask;
USHORT Address, StartRange, EndRange, Length, Range;
register DESCRIPTOR * Descr;
static ULONG GLIU_Masks[3] = {NOT_GLIU0, NOT_GLIU1, NOT_GLIU2};
Range = * RangePtr;
Address = (USHORT) * AddressPtr;
Attributes = * AddressPtr;
// Scan descriptors for those used for I/O trap or timeout
// NOTE: We must be careful about mixing I/O traps with I/O address that
// are directed to Northbridge devices. This may cause multiple
// MBUI descriptors set to the same address.
for (Index = 1; Index < NumDescriptors; Index++) {
Descr = &MSRs[Index];
DescrFlag = Descr->Flag;
// Only examine allocated descriptors
if (DescrFlag & AVAILABLE) {
continue;
}
// Ignore descriptors that route transactions Northbound
if (Descr->MsrData[1] >> 29 == MBIU1_SelfReference) {
continue;
}
// If an MBIU is to be excluded, don't allow a match on that MBIU
if (Attributes & GLIU_Masks[Descr->Mbiu]) {
continue;
}
// Check if this descriptor matches the requested address range.
// Cases:
// - Descriptor needs to be split, since I/O ranges are not compatible.
// - Subtractive port: timeout is set for this I/O range
// - It is currently routed to an MBus device: change Port to 0
// - Address ranges need to be merged
switch (Descr->Type) {
case IOD_SC:
HitFlag = 1;
// Does the I/O range overlap an existing Swiss-cheese descriptor ?
if ((USHORT)Descr->MsrData[0] == (Address & 0xFFF8)) {
UCHAR CurrentByteEnables, NewByteEnables, CommonByteEnables;
// Yes, compute the byte enables
Mask = Compute_IOD_SC(AddressPtr, RangePtr, 1);
CurrentByteEnables = (UCHAR)(Descr->MsrData[0] >> 24);
NewByteEnables = (UCHAR)(Mask >> 24);
// Compute # bytes of overlap
CommonByteEnables = CurrentByteEnables & NewByteEnables;
Length = 0;
while (CommonByteEnables) {
if (CommonByteEnables & 1) {
Length++;
}
CommonByteEnables >>= 1;
}
switch (Enable) {
case 0:
if (CurrentByteEnables == NewByteEnables) {
if (Descr->MsrData[0] == Mask) {
// Entire range is being disabled
Deallocate_Descriptor(Descr);
} else {
// Only change REN/WEN, not byte enables
Mask &= 0x00FFFFFF;
}
} else {
// Only subset of range is being disabled
// Don't change REN/WEN
Mask &= ~(WEN | REN);
}
if (Length) {
// Don't change base address
(USHORT)Mask = 0x0000;
Descr->MsrData[0] &= ~Mask;
} else {
HitFlag = 0;
}
break;
case 1:
if ((Descr->MsrData[0] & (WEN | REN)) != (Mask & (WEN | REN))) {
// R/W attributes mismatch; descriptor is not compatible
HitFlag = 0;
} else {
// Descriptors are compatible: set additional byte enables
Descr->MsrData[0] |= Mask;
}
break;
case 2:
if ((Descr->MsrData[0] & (WEN | REN)) != (Mask & (WEN | REN))) {
// R/W attributes mismatch.
// Descriptor is not compatible unless byte enables are the same.
if (CurrentByteEnables != NewByteEnables) {
HitFlag = 0;
break;
}
}
// Descriptors are compatible: set additional byte enables
Descr->MsrData[0] |= Mask;
// If the descriptors overlap but not exactly (disjoint enables)
// then Address & Range need to be handled according to special cases
if (CurrentByteEnables != NewByteEnables) {
// Restore Address & Range (modified above by Compute_IOD_SC)
* (USHORT *)AddressPtr = Address;
* RangePtr = Range;
if (NewByteEnables > CurrentByteEnables) {
// For example: 01110000 - NewByteEnables
// 00011100 - CurrentByteEnables
// Increment Address by overlapped range
* (USHORT *)AddressPtr += Length;
}
// Decrement Range by overlapped range
* RangePtr -= Length;
}
break;
case 3:
if (CurrentByteEnables & NewByteEnables) {
return Index;
}
continue;
} // end switch(Enable)
Write_MSR(Descr->MsrAddr, Descr->MsrData);
if (HitFlag == 0) {
// Restore Address/Range.
* (USHORT *)AddressPtr = Address;
* RangePtr = Range;
continue;
} else {
return Index;
}
}
break;
case IOD_BM:
HitFlag = 0;
Mask = ~((USHORT)Descr->MsrData[0])+1;
Length = 1 << BitScanForward(Mask);
StartRange = Descr->Address;
EndRange = StartRange + Length;
// Check if the requested range is covered by the existing descriptor
if ((Address >= StartRange) && (Address < EndRange)) {
if (Enable == 3) {
return Index;
}
HitFlag = 1;
Range -= Address - StartRange;
}
Mask = Address ^ StartRange;
if (Enable) {
if (HitFlag) {
Length = Range;
break; //??????????????????????????
}
} else {
// Range is being disabled
if (HitFlag) {
if (Length <= Range) {
Deallocate_Descriptor(Descr);
} else {
// Descriptor must be trimmed
if (Address == StartRange) {
// I/O Base needs to be adjusted up
Descr->MsrData[0] += (ULONG)Range << 20;
Mask = (1L << Range) - 1;
Length = Range;
} else {
// Adjust IO_MASK to trim range down
(USHORT)Descr->MsrData[0] &= ~(Range-1);
}
// Adjust IO_MASK
(USHORT)Descr->MsrData[0] |= Mask;
HitFlag = 2;
}
}
}
// Recompute start address of descriptor
if (HitFlag == 2) {
Descr->Address = (USHORT)(Descr->MsrData[0] >> 20);
Descr->Address |= (USHORT)(Descr->MsrData[1] << 12);
}
if (HitFlag) {
if (Length > Range) {
Length = Range;
}
* AddressPtr += Length;
* RangePtr -= Length;
// Write descriptor if matching descriptor was modified
if (HitFlag == 2) {
Write_MSR(Descr->MsrAddr, Descr->MsrData);
}
return Index;
}
break;
} // end switch(Descr->Type)
}
// If a descriptor gets deallocated, need to clean up any possible links to a BAR
return DESCRIPTOR_NOT_FOUND;
}

View File

@@ -0,0 +1,47 @@
/*
* 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
*/
// Descriptor types: (don't use 0)
#define P2D_BM 1
#define P2D_BMO 2
#define P2D_R 3
#define P2D_RO 4
#define P2D_SC 5
#define P2D_SCO 6
#define P2D_BMK 7
#define IOD_BM 8
#define IOD_SC 9
#define MDD_LBAR 10
#define GX2_RCONF 11
#define MPCI_RCONF 12
#define EPCI 13
#define USB_LBAR 14
typedef struct {
unsigned long Mbiu;
unsigned long SubtrPid;
unsigned long ClockGating;
unsigned char NumCounters; // Number of statistic counters on this MBIU
unsigned char ActiveCounters; // Count of # active statistic counters in use
} MBIU_INFO;
#define MAX_MBIU 3

View File

@@ -0,0 +1,371 @@
/*
* 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
*/
//*****************************************************************************
//* Implements the error reporting code.
//*****************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
extern void pascal write_flat_size(ULONG, ULONG, UCHAR);
extern ULONG pascal Get_SysCall_Address(ULONG, UCHAR);
extern ULONG VSMs_EAX;
extern ULONG Saved_EAX, Saved_EBX, Saved_ECX, Saved_EDX, Saved_ESI, Saved_EDI;
extern ULONG Current_VSM;
#define MAX_ERROR_BUFFER 500
UCHAR ErrorStrings[MAX_ERROR_BUFFER];
UCHAR * ErrorBuffer = ErrorStrings;
UCHAR * CurrentError;
UCHAR * PreviousError = ErrorStrings;
UCHAR DuplicateFlag;
int letbase;
//***************************************************************************
// Input:
// BH - 1 to clear error log
// CL - Error number (0 for 1st)
// Exit:
// AL - 0 if last error
//***************************************************************************
void Get_Errors()
{ USHORT ErrorNumber, Flag;
ULONG Destination;
// Get parameters passed in from INFO
Flag = (UCHAR)(Saved_EBX >> 8);
ErrorNumber = (UCHAR)Saved_ECX;
Destination = Saved_EDI;
(UCHAR)Saved_EAX = 0x00;
// If no errors, return AL = 0;
if (ErrorBuffer == ErrorStrings) {
return;
}
// If request for 1st error, initialize buffer ptr
if (ErrorNumber == 0) {
CurrentError = ErrorStrings;
}
// Copy next message to EDI
while (CurrentError < ErrorBuffer) {
// Copy 1 byte of error message
write_flat_size(Destination++, (ULONG)*CurrentError, BYTE_IO);
// If end of this message, return
if (*CurrentError++ == 0) {
write_flat_size(Destination-1, '$', BYTE_IO);
(UCHAR)Saved_EAX = 1;
// Is this the last message ?
if (*CurrentError == 0) {
// Clear error log ? (/E flag)
if (Flag == 1) {
PreviousError = ErrorBuffer = ErrorStrings;
}
}
return;
}
}
}
//*****************************************************************************
//*****************************************************************************
static void printchar(char **str, int c)
{
out_8(DBG_PORT, (UCHAR)c);
in_8(0x80);
if (ErrorBuffer < &ErrorStrings[MAX_ERROR_BUFFER-2]) {
*ErrorBuffer = c;
if (*ErrorBuffer++ != *PreviousError++) {
DuplicateFlag = 0;
}
}
}
#define PAD_RIGHT 1
#define PAD_ZERO 2
//*****************************************************************************
//*****************************************************************************
static int prints(char **out, const char *string, int width, int pad)
{ register int pc = 0, padchar = ' ';
if (width > 0) {
register int len = 0;
register const char *ptr;
for (ptr = string; *ptr; ++ptr) {
++len;
}
if (len >= width) {
width = 0;
} else {
width -= len;
}
if (pad & PAD_ZERO) {
padchar = '0';
}
}
if (!(pad & PAD_RIGHT)) {
for ( ; width > 0; --width) {
printchar(out, padchar);
++pc;
}
}
for ( ; *string ; ++string) {
printchar(out, *string);
++pc;
}
for ( ; width > 0; --width) {
printchar(out, padchar);
++pc;
}
return pc;
}
/* the following should be enough for 32 bit int */
#define PRINT_BUF_LEN 12
//*****************************************************************************
// Prints an integer with the specified formatting
//*****************************************************************************
static int printi(char **out, unsigned long u, int base, int sg, int width, int pad)
{ char print_buf[PRINT_BUF_LEN];
register char *s;
register int t, neg = 0, pc = 0;
if (u == 0) {
print_buf[0] = '0';
print_buf[1] = '\0';
return prints (out, print_buf, width, pad);
}
if (sg && (base == 10) && (u & 0x8000)) {
neg = 1;
u = ~u;
u++;
}
s = print_buf + PRINT_BUF_LEN-1;
*s = '\0';
while (u) {
t = (int)(u % base);
if (t >= 10 ) {
t += letbase - '0' - 10;
}
*--s = t + '0';
u /= base;
}
if (neg) {
if (width && (pad & PAD_ZERO) ) {
printchar(out, '-');
++pc;
--width;
} else {
*--s = '-';
}
}
return pc + prints(out, s, width, pad);
}
//*****************************************************************************
//*****************************************************************************
static int print(char **out, int *varg)
{ register int width, pad;
register int pc = 0;
register char *format = (char *)(*varg++);
char scr[2];
unsigned long number;
char *s;
for (; *format != 0; ++format) {
if (*format == '%') {
++format;
pad = 0;
if (*format == '\0') {
break;
}
switch (*format) {
case '%':
printchar(out, *format);
++pc;
continue;
case '-':
++format;
pad = PAD_RIGHT;
break;
}
while (*format == '0') {
++format;
pad |= PAD_ZERO;
}
for (width = 0; *format >= '0' && *format <= '9'; ++format) {
width *= 10;
width += *format - '0';
}
letbase = 'a';
switch (*format) {
case 's':
s = *((char **)varg++);
pc += prints (out, s ? s :"(null)", width, pad);
break;
case 'u':
number = *varg++;
pc += printi (out, number, 10, 0, width, pad);
break;
case 'd':
number = *varg++;
pc += printi (out, number, 10, 1, width, pad);
break;
case 'x':
// pc += printi (out, number, 16, 0, width, pad);
// break;
case 'X':
letbase = 'A';
number = (USHORT)*varg++;
if (width > 4) {
number |= (ULONG)(*varg++) << 16;
}
pc += printi (out, number, 16, 0, width, pad);
break;
case 'c':
// char are converted to int then pushed on the stack
scr[0] = *varg++;
scr[1] = '\0';
pc += prints (out, scr, width, pad);
break;
} // end switch
} else {
printchar(out, *format);
++pc;
}
} // end for
if (out) {
**out = '\0';
}
return pc;
}
//*****************************************************************************
//*****************************************************************************
void Log_Error(const char *format, ...)
{ register int *varg = (int *)(&format);
UCHAR * SavedErrorBuffer;
UCHAR * SavedPrevious;
SavedErrorBuffer = ErrorBuffer;
SavedPrevious = PreviousError;
if (PreviousError == ErrorStrings) {
DuplicateFlag = 0;
} else {
DuplicateFlag = 1;
}
// Store a formatted error message
print(0, varg);
// Terminate the error buffer
if (ErrorBuffer < &ErrorStrings[MAX_ERROR_BUFFER]) {
*(ErrorBuffer++) = 0;
}
// Same error as previous?
if (DuplicateFlag) {
// Yes, then restore ptrs
PreviousError = SavedPrevious;
ErrorBuffer = SavedErrorBuffer;
*(ErrorBuffer) = 0;
} else {
// No, then advance previous error buffer ptr
PreviousError = SavedErrorBuffer;
}
}
//*****************************************************************************
// Inserts an error entry into the error log.
//*****************************************************************************
void pascal Error_Report(UCHAR ErrorCode, ULONG Info1, ULONG Info2, ULONG Vsm, UCHAR Depth)
{ ULONG CallingAddress;
static UCHAR ErrorString[50];
CallingAddress = Get_SysCall_Address(Vsm, Depth);
Log_Error("Error code 0x%02X reported at %08X. Parameters: 0x%08X and 0x%08X.", \
ErrorCode, CallingAddress, Info1, Info2);
}
//*****************************************************************************
// Reports an error from a VSM.
//*****************************************************************************
void pascal Report_VSM_Error(UCHAR ErrorCode, ULONG Info1, ULONG Info2)
{
if (Current_VSM == 0) {
Error_Report(ErrorCode, Info1, Info2, SysMgr_VSM, 0);
} else {
Error_Report(ErrorCode, Info1, Info2, Current_VSM, 1);
}
}

View File

@@ -0,0 +1,616 @@
/*
* 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
*/
//******************************************************************************
//* This file contains code for:
//* 1) Initialization of the Events[] array
//* 2) Registering events
//* 3) Sending event messages
//******************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#define MAX_HIT 10 // Max. # of hits on any single event
// External function prototypes:
extern USHORT FilterTimer(EVENT_ENTRY *, EVENT);
extern UCHAR VSM_Is_Yielded(VSM);
// External variables:
extern ULONG VSM_Ptrs[];
// Local variables:
//*****************************************************************************
// The first MAX_EVENT entries are indexed by the EVENT code.
// The Link field contains the index of the next VSM registered for that event.
// A link of 00h terminates the list.
//*****************************************************************************
EVENT_ENTRY Events[MAX_REGISTRATIONS];
UCHAR FreeEvent; // Head of available Events[] entries
ULONG MsgPacket[MAX_MSG_PARAM+1];
ULONG MsgParams[MAX_HIT][4];
UCHAR * VsmNames[] = {
"SYS_MGR",
"AUDIO",
"VGA",
"LEGACY",
"PM",
"OHCI",
"i8042",
"DEBUGGER",
"ACPI",
"APM",
"OEM_ACPI",
"SMB",
"BATTERY",
"RTC",
"S2D",
"EXT_AMP",
"PCMCIA",
"SPY",
"NETWORK",
"GPIO",
"KEYBOARD",
"MOUSE",
"USB",
"FLASH",
"INFRARED",
"THERMAL",
"NULL",
"MPEG",
"VIP",
"LPC",
"VUART",
"MICRO",
"USER1",
"USER2",
"USER3",
"SYSINFO",
"SUPERIO",
"EHCI",
};
UCHAR * EventNames[] = {
"????",
"GRAPHICS",
"AUDIO",
"USB",
"ACPI",
"ACPI_TIMER",
"IO_TRAP",
"IO_TIMEOUT",
"PME",
"KEL",
"VIDEO_INACTIVITY",
"GPIO",
"SOFTWARE_SMI",
"PCI_TRAP",
"VIRTUAL_REGISTER",
"NMI",
"TIMER",
"DEVICE_TIMEOUT",
"SEMAPHORE",
"VBLANK",
"A20",
"SMB",
"RTC",
"THERMAL",
"LPC",
"UART",
"BLOCKIO",
};
//*****************************************************************************
// Copies an Events[] entry
//*****************************************************************************
void pascal Copy_Event(USHORT From, USHORT To)
{
Events[To].Vsm = Events[From].Vsm;
Events[To].Param1 = Events[From].Param1;
Events[To].Param2 = Events[From].Param2;
Events[To].Param3 = Events[From].Param3;
Events[To].Link = Events[From].Link;
Events[To].Priority = Events[From].Priority;
}
//*****************************************************************************
// Initializes the Events[] array
//*****************************************************************************
void Initialize_Events(void)
{ int i;
Events[0].RemainingInterval = 0xFFFFFFFF;
for (i = 0; i < MAX_REGISTRATIONS ; i++) {
Events[i].Priority = 0xffff;
Events[i].Index = i;
}
// Initialize the list of free event entries
for (i = MAX_REGISTRATIONS-2; i > MAX_EVENT ; i--) {
Events[i].Link = i+1;
}
FreeEvent = MAX_EVENT+1;
}
//*****************************************************************************
// Checks Events[EventIndex] for parameters matching those in MsgPacket[].
// Return value is EventIndex if the parameters match else 0x00.
//*****************************************************************************
USHORT pascal FilterEvent(EVENT Event, EVENT EventIndex)
{ USHORT IO_Hit, IO_Base, IO_Range, ClassIndex, RdWrAttribute;
UCHAR Size;
ULONG Vsm;
register EVENT_ENTRY * EventPtr;
USHORT PCI_Hit;
static ULONG PCI_Data;
static USHORT PCI_Addr;
static UCHAR PCI_Size;
EventPtr = &Events[EventIndex];
Vsm = EventPtr->Vsm;
switch (Event) {
case EVENT_USB:
if ((UCHAR)MsgPacket[2] == (UCHAR)EventPtr->Param1) {
return EventIndex;
}
break;
case EVENT_TIMER:
// Check if the registered interval has expired
return FilterTimer(EventPtr, EventIndex);
case EVENT_GPIO:
// Verify the pin & edge match the event registration
if (MsgPacket[1] == EventPtr->Pin && (MsgPacket[2] & EventPtr->Attributes)) {
// If GPIO is Sleep button being used to wake system, don't send event
return EventIndex;
}
break;
case EVENT_PME:
// MsgPacket[1] = ACPI GPE0_STS
// MsgPacket[2] = ACPI PM1_STS
if (EventPtr->Attributes & GPE) {
if ((1L << EventPtr->Pme) & MsgPacket[1]) {
return EventIndex;
}
}
if (EventPtr->Attributes & PM1) {
if ((1L << EventPtr->Pm1) & MsgPacket[2]) {
return EventIndex;
}
}
break;
case EVENT_IO_TRAP:
case EVENT_IO_TIMEOUT:
IO_Base = EventPtr->IO_Base;
IO_Range = EventPtr->IO_Range;
IO_Hit = (USHORT)MsgPacket[2];
// Check address range
if ((IO_Hit >= IO_Base) && (IO_Hit <= (IO_Base+IO_Range-1))) {
if (Event == EVENT_IO_TIMEOUT) {
return EventIndex;
}
// Filter reads/writes
if (MsgPacket[1] & 2) {
RdWrAttribute = READS_ONLY >> 16;
} else {
RdWrAttribute = WRITES_ONLY >> 16;
}
if (!(EventPtr->Flags & RdWrAttribute)) {
return EventIndex;
}
}
break;
case EVENT_VIRTUAL_REGISTER:
// Check for correct Class::Index
ClassIndex = (USHORT)MsgPacket[1];
if ((ClassIndex >= EventPtr->ClassLow) && (ClassIndex <= EventPtr->ClassHigh)) {
return EventIndex;
}
break;
case EVENT_PCI_TRAP:
if (EventIndex == EVENT_PCI_TRAP) {
// Save original parameters
PCI_Addr = (USHORT)MsgPacket[1];
PCI_Size = (UCHAR)MsgPacket[2];
PCI_Data = MsgPacket[3];
} else {
// Restore original parameters
(USHORT)MsgPacket[1] = PCI_Addr;
(UCHAR)MsgPacket[2] = PCI_Size;
MsgPacket[3] = PCI_Data;
}
// Ignore SysMgr's virtualization
if (Vsm == SysMgr_VSM) {
break;
}
if (MsgPacket[2] & 0x20000) {
RdWrAttribute = READS_ONLY >> 16;
} else {
RdWrAttribute = WRITES_ONLY >> 16;
}
PCI_Hit = PCI_Addr;
Size = PCI_Size & DWORD_IO;
while (Size) {
// Check for PCI address match after applying mask
if (EventPtr->PCI_Addr == (PCI_Hit & ~(EventPtr->PCI_Mask))) {
// Filter reads/writes
if (!(EventPtr->Flags & RdWrAttribute)) {
// Limit Size to correct boundaries
Size = PCI_Size & DWORD_IO;
switch (PCI_Hit & 0x3) {
case 2:
if (Size == DWORD_IO) {
Size = WORD_IO;
}
break;
case 3:
Size = BYTE_IO;
break;
}
MsgPacket[2] &= ~DWORD_IO;
MsgPacket[2] |= Size;
(USHORT)MsgPacket[1] = PCI_Hit;
return EventIndex;
}
}
// Don't cross DWORD boundaries
if ((++PCI_Hit & 0x3) == 0) {
break;
}
MsgPacket[3] >>= 8;
if (!(PCI_Size & IO_WRITE)) {
MsgPacket[3] |= 0xFF000000;
}
Size >>= 1;
}
break;
case EVENT_SOFTWARE_SMI:
// Check for code match after applying mask
if (EventPtr->Param1 == (MsgPacket[1] & ~EventPtr->Param2)) {
return EventIndex;
}
break;
default:
return EventIndex;
}
return 0;
}
//*****************************************************************************
//
// Sends a MSG_EVENT to all VSMs registered for the specified event.
//
//*****************************************************************************
EVENT pascal Send_Event(EVENT Event, VSM From_VSM)
{ ULONG To_VSM, ErrorParam = Event;
UCHAR HitCount = 0;
EVENT Hits[MAX_HIT], EventIndex;
USHORT i;
register EVENT_ENTRY * EventPtr;
// Perform sanity checks
if (Event == 0 || Event > MAX_EVENT) {
Log_Error("Invalid event 0x%04X", Event);
return 0;
}
if (Events[Event].Vsm == 0) {
// No VSM has registered this event.
Log_Error("EVENT_%s[0x%08X;0x%08X] is not registered to a VSM", EventNames[Event], MsgPacket[1], MsgPacket[2]);
return 0;
}
EventIndex = Event;
#if HISTORY
Keep_History(Event, EventIndex);
#endif
// Store Event code as message parameter[0]
MsgPacket[0] = Event;
// Walk the entire event chain looking for parameter matches
while (EventIndex) {
EventPtr = &Events[EventIndex];
// Check if the parameters for the current event match this event registration
if (FilterEvent(Event, EventIndex)) {
if (HitCount < MAX_HIT-1) {
// Record the hit
Hits[++HitCount] = EventIndex;
MsgParams[HitCount][1] = MsgPacket[1];
MsgParams[HitCount][2] = MsgPacket[2];
MsgParams[HitCount][3] = MsgPacket[3];
} else {
// ERROR: MAX_HIT is too small
Log_Error("Hits[] array is too small");
break;
}
}
// Point to the next registered VSM
EventIndex = EventPtr->Link;
}
// Send messages in priority order
for (i = HitCount; i > 0; i--) {
EventPtr = &Events[Hits[i]];
To_VSM = EventPtr->Vsm;
// Is the VSM being awakened prematurely from SYS_YIELD_CONTROL?
if (VSM_Is_Yielded(To_VSM)) {
EVENT_ENTRY * TimerPtr;
// Find the wakeup timer being used
EventIndex = EVENT_TIMER;
while (EventIndex) {
TimerPtr = &Events[EventIndex];
if ((TimerPtr->Vsm == To_VSM) && (TimerPtr->Param2 & SYS_YIELD)) {
Unregister_Event(EVENT_TIMER, To_VSM, TimerPtr->Param1, TimerPtr->Param2);
break;
}
EventIndex = TimerPtr->Link;
}
}
// Send a message to the VSM
if (!(EventPtr->Param2 & SYS_YIELD)) {
MsgPacket[1] = MsgParams[i][1];
MsgPacket[2] = MsgParams[i][2];
MsgPacket[3] = MsgParams[i][3];
Send_Message(From_VSM, To_VSM, MSG_EVENT);
}
// Unregister one-shot events
if (EventPtr->Param2 & ONE_SHOT) {
Unregister_Event(Event, To_VSM, EventPtr->Param1, EventPtr->Param2);
}
}
// Send message to Spy VSM, if present
if (HitCount && VSM_Ptrs[VSM_SPY]) {
Send_Message(From_VSM, VSM_Ptrs[VSM_SPY], MSG_EVENT);
}
return HitCount;
}
//*****************************************************************************
// Associates a VSM with an Event and associated Parameters.
// The System Manager maintains a table indexed by the Event. Each entry
// contains a Link (array index) to the next VSM registered as a handler for
// that Event. Entries are ordered by Priority (high to low). Unused array
// elements are denoted by the Vsm field == 0000.
//*****************************************************************************
void pascal Register_Event(EVENT Event, PRIORITY Priority, VSM Vsm, ULONG Param1, ULONG Param2)
{ UCHAR index, previous, next, Match=0;
register EVENT_ENTRY * EventPtr;
if (Event > MAX_EVENT) {
// Illegal Event
Log_Error("Attempt to register invalid event 0x%04X by the %s VSM", Event, VsmNames[Get_VSM_Type(Vsm)]);
return;
}
// Handle special cases
switch (Event) {
case EVENT_VIRTUAL_REGISTER:
// Param2[15:8] = low index Param2[7:0] = high index
// If index == 0x00, then any index is valid
Param1 <<= 8; // Shift class to bits 15:8
index = 0xFF; // Default upper index
if (Param2) {
index = (UCHAR)Param2; // Get upper index
(UCHAR)Param1 = (UCHAR)(Param2 >> 8); // Get lower index
}
Param2 = Param1;
(UCHAR)Param2 = index;
break;
case EVENT_IO_TRAP:
// 16 MSBs of Param1 are reserved
Param1 &= 0x0000FFFF;
// Don't allow PCI config cycles to be trapped
if (Param1 >= 0xCF8 && Param1 <= 0xCFF) {
Log_Error("Attempt to trap I/O 0xCF8-0xCFF by the %s VSM", VsmNames[Get_VSM_Type(Vsm)]);
return;
}
break;
case EVENT_TIMER:
// Mask all except Handle and valid flags
Param2 &= FOR_STANDBY | ONE_SHOT | SYS_YIELD | 0xFFFF;
if (Param1 == 0) {
Priority = UNREGISTER_PRIORITY;
}
break;
}
// If unregistering event(s)...
if (Priority >= UNREGISTER_PRIORITY) {
Unregister_Event(Event, Vsm, Param1, Param2);
return;
}
index = (UCHAR)Event;
next = 0;
if (Events[Event].Vsm) {
// Ensure a VSM doesn't register for the same event twice
do {
EventPtr = &Events[index];
// If it is the same VSM...
if (EventPtr->Vsm == Vsm) {
switch (Event) {
// If existing timer handle, assign new interval and/or priority
case EVENT_TIMER:
if (EventPtr->Handle == (USHORT)Param2) {
Match = 2;
}
break;
case EVENT_PWM:
// If existing pin, change rate and/or duty cycle
if (EventPtr->Pin == (USHORT)Param1) {
Match = 3;
}
break;
// If existing pin, accumulate attributes
case EVENT_GPIO:
if (EventPtr->Pin == Param1 && EventPtr->Priority == Priority) {
EventPtr->Attributes |= Param2;
Match = 1;
}
break;
default:
// If params match, then just update the event priority
if (EventPtr->Param1 == Param1 && EventPtr->Param2 == Param2) {
#if SUPPORT_PRIORITY
// Sort list again according to priority
#endif
Match = 1;
break;
}
}
}
// Early out
if (Match) {
break;
}
// Get link to next event
index = EventPtr->Link;
} while (index);
if (Match == 0) {
// Report error if no more Events[] entries
if (FreeEvent == 0) {
Log_Error("Failed attempt to register EVENT_%s[0x%08X;0x%08X] by the %s VSM", EventNames[Event], Param1, Param2, VsmNames[Get_VSM_Type(Vsm)]);
return;
}
// Get an unused Events[] entry
index = FreeEvent;
FreeEvent = Events[index].Link;
//
// Find the insertion point. There are two cases:
// 1) The new entry is higher priority than the current 1st entry
// 2) The new entry belongs somewhere down the chain.
//
previous = next = (UCHAR)Event;
while (next = Events[next].Link) {
if (Priority > Events[next].Priority) {
break;
}
previous = next;
}
if (Priority > Events[Event].Priority) {
// case 1: Need to copy 1st entry to Events[index]
Copy_Event(Event, index);
next = index;
index = (UCHAR)Event;
} else {
// case 2:
// Insert new event into linked list
Events[previous].Link = index;
}
}
}
// Create new Events[] entry
EventPtr = &Events[index];
switch (Match) {
// New registration
case 0:
EventPtr->Link = next;
EventPtr->Vsm = Vsm;
case 3:
EventPtr->Param2 = Param2;
// Update of Priority
case 1:
EventPtr->Priority = Priority;
// Update of Parameter (e.g. timer interval)
case 2:
EventPtr->Param1 = Param1;
}
// Enable the appropriate hardware
Enable_Event(Event, index, 1);
}

View File

@@ -0,0 +1,62 @@
/*
* 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
*/
//* Function: *
//* This file contains non-chipset specific GPIO code.
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
extern ULONG MsgPacket[];
extern Hardware HardwareInfo;
//************************************************************************************
// Reports invalid GPIO pin
//************************************************************************************
void Report_GPIO_Error(USHORT Pin)
{
Report_VSM_Error(ERR_HW_MISMATCH, EVENT_GPIO, Pin);
}
//************************************************************************************
// Sends the EVENT_GPIO message
//************************************************************************************
void Send_GPIO_Event(USHORT Pin, USHORT Edge)
{
MsgPacket[1] = Pin;
MsgPacket[2] = Edge;
Send_Event(EVENT_GPIO, 0);
}

View File

@@ -0,0 +1,488 @@
/*
* 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
*/
//******************************************************************************
//* This file contains code specific to CS5536 GPIOs
//******************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#include "VPCI.H"
#include "PCI.H"
#include "MDD.H"
#include "MAPPER.H"
#define POWER_BUTTON_PIN 28
// External Functions:
extern void Send_GPIO_Event(USHORT Pin, USHORT Edge);
extern void Enable_PME_Event(UCHAR, UCHAR, UCHAR, USHORT);
extern UCHAR pascal BitScanReverse(ULONG);
// External Variables:
extern PCI_HEADER_ENTRY ISA_Hdr[];
extern GPIO_FUNCTION GPIO_Control;
// Local Variables:
ULONG Enable_Mask;
USHORT Lock_Port, Lock_Data;
USHORT GPIO_Port;
UCHAR Bank=0;
UCHAR ShiftCount;
typedef struct {
UCHAR SelectOffset; // Offset to filter select register
UCHAR FilterOffset; // Offset to filter amount register
UCHAR Pin; // Pin this filter is associated to
UCHAR FilterRestore;
} FILTERS;
FILTERS FilterInfo[8] = {
{GPIO_FILTER_SELECT0, GPIO_FILTER_AMOUNT+0*8, 0xFF, 0},
{GPIO_FILTER_SELECT1, GPIO_FILTER_AMOUNT+1*8, 0xFF, 0},
{GPIO_FILTER_SELECT2, GPIO_FILTER_AMOUNT+2*8, 0xFF, 0},
{GPIO_FILTER_SELECT3, GPIO_FILTER_AMOUNT+3*8, 0xFF, 0},
{GPIO_FILTER_SELECT4, GPIO_FILTER_AMOUNT+4*8, 0xFF, 0},
{GPIO_FILTER_SELECT5, GPIO_FILTER_AMOUNT+5*8, 0xFF, 0},
{GPIO_FILTER_SELECT6, GPIO6_FILTER_AMOUNT, 28, 1}, // power button pre-defined
{GPIO_FILTER_SELECT7, GPIO7_FILTER_AMOUNT, 0xFF, 0},
};
//*****************************************************************************
// Sends EVENT_GPIO messages for pins that have the specified edge status pending
//*****************************************************************************
void GPIO_Helper(UCHAR Edge, UCHAR PinBase)
{ ULONG PinMask;
UCHAR Pin;
if (Edge == RISING_EDGE) {
(UCHAR)GPIO_Port = GPIO_POSEDGE_STATUS;
} else {
(UCHAR)GPIO_Port = GPIO_NEGEDGE_STATUS;
}
if (PinBase) {
(UCHAR)GPIO_Port |= GPIO_HIGH_BANK_SELECT;
}
// Get edge status
PinMask = in_32(GPIO_Port);
// Clear the edge status
out_32(GPIO_Port, PinMask);
// Ignore transitions that are not enabled
GPIO_Port -= GPIO_POSEDGE_STATUS;
GPIO_Port += GPIO_POSEDGE_ENABLE;
PinMask &= in_32(GPIO_Port) & 0x0000FFFFL;
// Loop through all pending GPIO edges
while (PinMask) {
// Determine next pending GPIO pin
Pin = BitScanReverse(PinMask);
PinMask &= ~(1L << Pin);
// Send the event to the VSM(s)
Send_GPIO_Event(PinBase+Pin, Edge);
}
}
//*****************************************************************************
// Handles GPIO SMIs
//*****************************************************************************
void CS5536_GPIO_Handler(ULONG Active_GPIOs)
{
// Get the current GPIO address
GPIO_Port = ISA_Hdr[BAR1/4].Value_LO;
Bank = GPIO_LOW_BANK_SELECT;
GPIO_Helper( RISING_EDGE, 0); // Handle GPIO[15:00] rising edges
GPIO_Helper(FALLING_EDGE, 0); // Handle GPIO[15:00] falling edges
Bank = GPIO_HIGH_BANK_SELECT;
GPIO_Helper( RISING_EDGE, 16); // Handle GPIO[31:16] rising edges
GPIO_Helper(FALLING_EDGE, 16); // Handle GPIO[31:16] falling edges
}
//*****************************************************************************
// Unlocks specified GPIO register(s).
// After GPIO registers are accessed, Relock_GPIO_Regs() should be invoked.
//*****************************************************************************
void Unlock_GPIO_Regs(USHORT UnlockMask)
{
// Get current Lock register
Lock_Port = ISA_Hdr[BAR1/4].Value_LO;
(UCHAR)Lock_Port = Bank + GPIO_LOCK_ENABLE;
Lock_Data = in_16(Lock_Port);
// Unlock required registers
out_16(Lock_Port, Lock_Data & ~UnlockMask);
}
//*****************************************************************************
// Restores GPIO register lock
//*****************************************************************************
void Relock_GPIO_Regs(void)
{
out_16(Lock_Port, Lock_Data);
}
//*****************************************************************************
// Writes a 32-bit value to a GPIO register
//*****************************************************************************
void Write_GPIO_Register(UCHAR Register, ULONG Data)
{
// Write register
(UCHAR)GPIO_Port = Bank + Register;
out_32(GPIO_Port, Data);
// Handle registers that are slow due to being in the Standby power domain
if (Bank == GPIO_HIGH_BANK_SELECT) {
in_32(GPIO_Port);
}
}
//*****************************************************************************
// Writes Enable_Mask to a GPIO register
//*****************************************************************************
void Configure_GPIO(UCHAR Reg)
{
Write_GPIO_Register(Reg, Enable_Mask);
}
//*****************************************************************************
// Maps the specified GPIO pin to the specified GPIO Interrupt
//*****************************************************************************
void GPIO_Mapper(UCHAR Pin, UCHAR Irq)
{ ULONG Data;
// Unlock GPIO register(s)
Unlock_GPIO_Regs(LKIE | LKOE | LKPU | LKPD);
// Configure pin as Input
if (Pin != POWER_BUTTON_PIN) { // Keeps sleep pin from generating SMI
Configure_GPIO(GPIO_INPUT_ENABLE);
}
// Disable Output, Pullup & Pulldown
Data = Enable_Mask << 16;
Write_GPIO_Register(GPIO_OUTPUT_ENABLE, Data);
Write_GPIO_Register(GPIO_PULLDOWN_ENABLE, Data);
Write_GPIO_Register(GPIO_PULLUP_ENABLE, Data);
// Restore Lock register
Relock_GPIO_Regs();
// Program GPIO Mapper
(UCHAR)GPIO_Port = (UCHAR)(GPIO_MAPPER_X + ((Pin >> 1) & 0x0C));
ShiftCount = (Pin % 8) * 4;
Data = in_32(GPIO_Port);
Data &= ~(0x0000000FL << ShiftCount);
Data |= (ULONG)Irq << ShiftCount;
out_32(GPIO_Port, Data);
}
//*****************************************************************************
// Clears the positive & negative edge status registers for the specified GPIOs
//*****************************************************************************
void ClearEdgeStatus(ULONG Mask)
{
Write_GPIO_Register(GPIO_POSEDGE_STATUS, Mask);
Write_GPIO_Register(GPIO_NEGEDGE_STATUS, Mask);
}
//*****************************************************************************
// Enables/Disables generation of SMI on GPIO edge(s) for the CS5536 chipset
//*****************************************************************************
void CS5536_GPIO_Control(ULONG Param1, ULONG Param2, UCHAR EnableFlag)
{ ULONG Attributes;
UCHAR Pin, Pme, Pm1, i, PinToMatch, FilterAmount, filter_to_use;
ULONG Clear_Mask;
// Unpack parameters
Pin = (UCHAR)Param1;
Pme = (UCHAR)(Param1 >> 16);
Pm1 = (UCHAR)(Param2 >> 16);
Attributes = Param2 & 0xff00ffff;
GPIO_Port = ISA_Hdr[BAR1/4].Value_LO;
// Log_Error("GPIO %d (%d) %d %d 0x%08X 0x%08X 0x%08X\r\n",Pin,EnableFlag,Pme,Pm1,Attributes,Param1,Param2);
// Validate parameters
if (Pin >= 32) {
Log_Error("Invalid GPIO pin # = 0x%02X\r\n", Pin);
return;
}
if ((Pme > 7) && (Attributes & PME)) {
Log_Error("Invalid PME # = 0x%02X\r\n", Pme);
return;
}
if ((Pm1 > 10) && (Attributes & PM1)) {
Log_Error("Invalid PM1 # = 0x%02X\r\n", Pm1);
return;
}
// Select Low/High bank
ShiftCount = Pin;
Bank = GPIO_LOW_BANK_SELECT;
if (Pin >= 16) {
ShiftCount -= 16;
Bank = GPIO_HIGH_BANK_SELECT;
}
// Generate masks
Clear_Mask = Enable_Mask = 1L << ShiftCount;
// Clear possible false edge events
ClearEdgeStatus(Clear_Mask);
// If disable, set 16 MSBs of Enable_Mask
if (!EnableFlag) {
Enable_Mask <<= 16;
}
// Set GPIO Interrupt/PME Mapper to generate an ASMI or PME
if (Attributes & PME) {
// Map the GPIO as a PME
GPIO_Mapper(Pin, (UCHAR)(Pme | 0x08));
} else {
// Route to ASMI unless PCI interrupt is specified
if (Pme) {
// Map the GPIO to a GPIO Interrupt
GPIO_Mapper(Pin, (UCHAR)(Pme & 0x07));
} else {
if (!(Attributes & NO_ASMI)) {
// Map the GPIO to an ASMI
GPIO_Mapper(Pin, (Z_IRQ_SMI & 0x07));
}
}
}
// This will set the MDD MSR_SMI bit for SMI on any PM event
// and program the appropriate ACPI PM1_EN or GPE0_EN bit.
// Additionally, it will clear the corresponding ACPI PM1_STS or GPE0_STS bit.
Enable_PME_Event(EnableFlag, Pm1, Pme, (USHORT)Attributes);
// If power button, don't touch any GPIO regs!
if (Pin == POWER_BUTTON_PIN) {
return;
}
// Unlock GPIO registers
Unlock_GPIO_Regs(LKPE | LKNE | LKFE | LKEE);
// Configure as Output ?
if (Attributes & OUTPUT) {
Configure_GPIO(GPIO_OUTPUT_ENABLE);
// Configure output pin inversion
if (Attributes & INVERT) {
Configure_GPIO(GPIO_OUTPUT_INVERT);
}
// Configure open drain
if (Attributes & OPEN_DRAIN) {
Configure_GPIO(GPIO_OUTPUT_OPENDRAIN);
}
// Configure AUX output selects
if (Attributes & AUX1) {
Configure_GPIO(GPIO_OUT_AUX1_SELECT);
} else {
if (Attributes & AUX2) {
Configure_GPIO(GPIO_OUT_AUX2_SELECT);
}
}
}
// Configure as Input ?
if ((Attributes & INPUT) || !(Attributes & OUTPUT)) {
// Configure input pin inversion
if (Attributes & INVERT) {
Configure_GPIO(GPIO_INPUT_INVERT);
}
if (Attributes & AUX1) {
Configure_GPIO(GPIO_IN_AUX1_SELECT);
}
// Configure input for correct edge(s)
switch (Attributes & BOTH_EDGES) {
case BOTH_EDGES:
case RISING_EDGE:
// Enable/Disable the RISING edge
Configure_GPIO(GPIO_POSEDGE_ENABLE);
if ((Attributes & BOTH_EDGES) == RISING_EDGE) {
break;
}
// fall through intended
case FALLING_EDGE:
// Enable/Disable the FALLING edge
Configure_GPIO(GPIO_NEGEDGE_ENABLE);
break;
default:
// If neither edge is enabled, an event is 'active' as long
// as the input is high (or low if inverted).
break;
}
}
// NOTE: If pullup is enabled, pulldown is automatically disabled
// Configure pullup
if (Attributes & PULLUP) {
Configure_GPIO(GPIO_PULLUP_ENABLE);
} else {
// Configure pulldown
if (Attributes & PULLDOWN) {
Configure_GPIO(GPIO_PULLDOWN_ENABLE);
}
}
// Configure debounce filter
if (Attributes & DEBOUNCE) {
PinToMatch = (UCHAR)Pin;
if (EnableFlag) {
FilterAmount = 1; // Units = ~30 usec
} else {
FilterAmount = 0;
}
// Find a filter
i=0;
if (Attributes & FOR_STANDBY ) {
i=6; // if pme 6/7 set for filter 6/7 (in standby domain)
}
filter_to_use=0xff;
for (; i < 8; i++) {
if (FilterInfo[i].Pin == PinToMatch) {
filter_to_use=i;
break;
}
// see if we have found an open filter - use only for enable
if ((filter_to_use == 0xff) && (FilterInfo[i].Pin == 0xff) && (EnableFlag)) {
filter_to_use=i;
}
}
// Log_Error("GPIO %d using filter %d\r\n",Pin,filter_to_use);
// found an matching pin for filter or an open one
if (filter_to_use != 0xff) { // found one
i=filter_to_use; // use this filter
if (EnableFlag) {
// Mark filter in-use
FilterInfo[i].Pin = (UCHAR)Pin;
// Save the filter select register
(UCHAR)GPIO_Port = FilterInfo[i].SelectOffset;
FilterInfo[i].FilterRestore = in_8(GPIO_Port);
// Select the filter
out_8(GPIO_Port, (UCHAR)Pin);
}
// Program filter Amount & Count
(UCHAR)GPIO_Port = FilterInfo[i].FilterOffset;
out_32(GPIO_Port, (ULONG)FilterAmount);
if (!EnableFlag) {
// Mark filter as available
FilterInfo[i].Pin = 0xFF;
// Restore the filter select register
(UCHAR)GPIO_Port = FilterInfo[i].SelectOffset;
out_8(GPIO_Port, FilterInfo[i].FilterRestore);
}
// Enable/Disable filter
Configure_GPIO(GPIO_IN_FILTER_ENABLE);
}
else {
// no filter found
Log_Error("No filter found for GPIO %d\r\n",Pin);
}
}
// Enable/Disable GPIO as an event unless it is EVENT_PWM
if ((Attributes & (OUTPUT | NO_ASMI)) != (OUTPUT | NO_ASMI)) {
Configure_GPIO(GPIO_EVENTS_ENABLE);
}
// Clear possible false edge events
ClearEdgeStatus(Clear_Mask);
// Restore Lock register
Relock_GPIO_Regs();
}
//*****************************************************************************
// Initialized CS5536 GPIO logic
//*****************************************************************************
void CS5536_GPIO_Init(void)
{
// Point GPIO_Control to correct GPIO routine for CS5536
GPIO_Control = CS5536_GPIO_Control;
// Clear pending GPIOs
CS5536_GPIO_Handler(0);
// Map the GPIO SMI source
IRQZ_Mapper(Z_IRQ_SMI, 2);
}

View File

@@ -0,0 +1,645 @@
/*
* 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
*/
//*****************************************************************************
//* Implements the handlers for top-level SMI source
//*****************************************************************************
#include "VSA2.H"
#include "CHIPSET.H"
#include "PROTOS.H"
#include "SYSMGR.H"
#include "VPCI.H"
#include "PCI.H"
// External variables
extern SmiHeader SMM_Header;
extern SmiHeader Nested_Header;
extern ULONG Saved_EAX, Saved_EBX, Saved_ECX;
extern ULONG MsgPacket[];
extern ULONG VSM_ListHead;
extern ULONG Virtualized_PCI_Devices;
extern ULONG Stats_Sources;
extern ULONG IRQ_Mask;
extern ULONG MPCI_NB;
extern ULONG VSM_Buffer;
extern ULONG Nested_Flag;
extern ULONG Video_Sources;
extern USHORT Audio_Sources;
extern Hardware HardwareInfo;
extern EVENT_ENTRY Events[];
extern PCI_HEADER_ENTRY ISA_Hdr[];
extern PCI_HEADER_ENTRY HostBridge_Hdr[];
// External function prototypes
extern void pascal Timer_Handler(USHORT);
extern void CS5536_GPIO_Handler(ULONG);
extern void INT_Return(void);
extern void Send_OHCI_Event(UCHAR);
extern void VR_Handler(SmiHeader *);
extern void ACPI_Workaround(SmiHeader *, USHORT);
extern void Remove_RTC_Fix(void);
extern void set_reset_state(void);
extern void pascal Unblock_VSM(ULONG);
extern void pascal Return_Virtual_Value(SmiHeader *, ULONG);
extern SmiHeader * pascal Get_Header_Params(ULONG);
extern ULONG Get_ACPI_Status(ULONG *);
extern USHORT Get_Timeout(ULONG, UCHAR *);
extern USHORT CS5536_MFGPT_Handler(void);
extern void ReInit_Descriptors(void);
extern void Init_SysMgr();
extern void A20_Sync(void);
extern void Update_VSMs_CR0(void);
ULONG INT_Vectors[MAX_INT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xF000F859};
ULONG VSM_Ptrs[VSM_MAX_TYPE+1];
ULONG Audio_IRQ = 0;
ULONG NativeAudioStatus = 0x4F0; // Defaults to 0040:00F0
UCHAR End_of_POST = 0;
void Broadcast_SysMgr_Msg (MSG Message, UCHAR Param1)
{
MsgPacket[0] = (ULONG)Param1;
MsgPacket[1] = MsgPacket[2] = 0;
Broadcast_Message(Message, VSM_ANY, 0x00000000);
}
//***********************************************************************
// Sends a message for an asynchronous event
//***********************************************************************
void pascal Send_Asynchronous_Event(EVENT Event)
{
MsgPacket[1] = MsgPacket[3] = MsgPacket[4] = 00000000;
if (Event != EVENT_IO_TIMEOUT) {
MsgPacket[2] = 00000000;
}
Send_Event(Event, 0x00000000);
}
//***********************************************************************
// Sends a message for a synchronous event
// Returns TRUE if the event was registered.
//***********************************************************************
USHORT pascal Send_Synchronous_Event(EVENT Event, SmiHeader * SmiHdr)
{ ULONG Vsm;
USHORT EventRegistered;
if ((USHORT)SmiHdr == 0x0000 || (USHORT)SmiHdr == (USHORT)&SMM_Header) {
Vsm = SysMgr_VSM;
} else {
Vsm = Current_VSM;
}
EventRegistered = Send_Event(Event, Vsm);
if (!EventRegistered) {
// No VSM is registered for this event
// If nested event, change the VSM's state from 'Blocked' to 'Ready'
if (Nested_Flag) {
Unblock_VSM(Vsm);
}
}
return EventRegistered;
}
//***********************************************************************
// This routine walks the VSM linked list, recording ptrs to VSMs that
// have special requirements.
//***********************************************************************
void Record_VSM_Locations(void)
{ ULONG VSM_Ptr;
UCHAR VSM_Type;
for (VSM_Type=0; VSM_Type<=VSM_MAX_TYPE; VSM_Type++) {
VSM_Ptrs[VSM_Type] = 0x00000000;
}
VSM_Ptr = VSM_ListHead;
while (VSM_Ptr) {
VSM_Type = Get_VSM_Type(VSM_Ptr);
if (VSM_Type < sizeof(VSM_Ptrs)/4) {
VSM_Ptrs[VSM_Type] = VSM_Ptr;
}
if (VSM_Type == VSM_RTC) {
Remove_RTC_Fix();
}
VSM_Ptr = GetFlink(VSM_Ptr);
}
}
//***********************************************************************
// This routine handles software SMI events.
//***********************************************************************
void pascal SMINT_Handler(USHORT Code)
{ int i;
// Handle return from INT callback
if (VSM_Buffer) {
INT_Return();
return;
}
switch (Code) {
case SYS_BIOS_INIT:
// If installing VSA from DOS, restore descriptors to default state
if (Saved_EBX != 0) {
ReInit_Descriptors();
}
// VSA Initialization
Init_SysMgr();
if (Saved_EBX == 0) {
break;
}
case SYS_END_OF_POST:
Current_VSM = 0;
End_of_POST = 1;
//
// Take a snapshot of the interrupt vectors
//
for (i = 0; i < MAX_INT; i++) {
if (INT_Vectors[i] == 0) {
INT_Vectors[i] = read_flat((ULONG) i << 2 );
}
}
// Entry point to video ROM
INT_Vectors[1] = 0xC0000003;
//
// The BIOS may have enabled the changed the cache setting
// since early init, so update each VSM's CR0 field
//
Update_VSMs_CR0();
// Send a phase 1 initialization message to each VSM
Broadcast_SysMgr_Msg(MSG_INITIALIZE, END_OF_POST_INIT);
break;
case SYS_REMOVE:
Unregister_VSM_Events(Saved_ECX);
break;
case SYS_VSM_INSTALL:
// EBX points to the new VSM
// ECX points to the old VSM
Unregister_VSM_Events(Saved_ECX);
Record_VSM_Locations();
//
// Send both phase 0 & 1 initialization messages to the new VSM
//
MsgPacket[0] = EARLY_INIT;
MsgPacket[1] = 1;
Send_Message(SysMgr_VSM, Saved_EBX, MSG_INITIALIZE);
MsgPacket[0] = END_OF_POST_INIT;
MsgPacket[1] = 1;
Send_Message(SysMgr_VSM, Saved_EBX, MSG_INITIALIZE);
break;
default:
//
// Send event to appropriate VSM
//
MsgPacket[1] = (ULONG)Code;
MsgPacket[2] = Saved_EBX;
MsgPacket[3] = Saved_ECX;
Send_Synchronous_Event(EVENT_SOFTWARE_SMI, 0);
break;
} // end switch
}
//***********************************************************************
// This routine handles graphics events.
//***********************************************************************
void VG_Handler(void)
{ register SmiHeader * SmiHdr;
SmiHdr = Get_Header_Params(0);
// Set bit 24 of MsgPacket[2] if I/O write
if (SmiHdr->SMI_Flags.IO_Write) {
MsgPacket[2] |= 0x01000000L;
}
MsgPacket[1] = Video_Sources;
Send_Synchronous_Event(EVENT_GRAPHICS, SmiHdr);
// Reset video event flags
Video_Sources = 0;
}
//***********************************************************************
// This routine handles A20
//***********************************************************************
void A20_Handler(void)
{
A20_Sync();
// Send event so it will be recorded in the history buffer
// Send_Synchronous_Event(EVENT_A20, SMM_Header);
}
//***********************************************************************
// This routine handles reset
//***********************************************************************
void Reset_Handler(void)
{
// Schedule reset routine after VSMs have processes MSG_SHUTDOWN
Schedule_VSM((ULONG)((USHORT)set_reset_state));
// Tell each VSM to get ready for cold boot
// No VSMs use this message at this time, so don't broadcast message
// (to keep overhead down)
// Broadcast_SysMgr_Msg(MSG_SHUTDOWN, 0);
}
//***********************************************************************
// This routine handles NMI
//***********************************************************************
void NMI_Handler(void)
{
Send_Asynchronous_Event(EVENT_NMI);
}
//***********************************************************************
// This routine handles trapped PCI events.
// The event may come from an SSMI (CPU) or an external SMI (chipset)
//***********************************************************************
void PCI_Handler(void)
{ ULONG ID_Select, Data;
USHORT Address;
UCHAR Size;
register SmiHeader * SmiHdr;
SmiHdr = Get_Header_Params(SMI_SRC_PCI_TRAP);
Address = (USHORT)MsgPacket[2];
Size = (UCHAR)SmiHdr->data_size;
ID_Select = 1L << ((Address >> 11) & 0x1F);
if (SmiHdr->SMI_Flags.IO_Write) {
//
// Trapped PCI header WRITE
//
Data = MsgPacket[3];
// Is it is a totally virtual PCI header ?
if (ID_Select & Virtualized_PCI_Devices) {
MsgPacket[3] = Virtual_PCI_Write_Handler(Address, Size, Data);
Address &= 0xFFFC;
Size = DWORD_IO;
}
// Set the write flag
Size |= IO_WRITE;
} else {
//
// Trapped PCI header READ
//
// Is it is a totally virtual PCI header ?
if (ID_Select & Virtualized_PCI_Devices) {
Data = Virtual_PCI_Read_Handler(Address);
} else {
Trap_PCI_IDSEL(Address, 0);
out_32(PCI_CONFIG_ADDRESS, 0x80000000 | Address);
Data = in_32(PCI_CONFIG_DATA);
Trap_PCI_IDSEL(Address, 1);
}
// Return virtualized PCI device value to the right environment
Return_Virtual_Value(SmiHdr, Data);
MsgPacket[3] = Data;
}
// Repackage the parameters
MsgPacket[2] = MsgPacket[1] << 16;
MsgPacket[1] = 0x80000000 + (USHORT)Address;
(USHORT)MsgPacket[2] = Size;
// Send EVENT_PCI_TRAP message
if (!Send_Synchronous_Event(EVENT_PCI_TRAP, SmiHdr)) {
// This PCI register was not trapped.
// Re-issue configuration writes to real PCI hardware devices.
if (Size & IO_WRITE) {
if (!(ID_Select & Virtualized_PCI_Devices)) {
USHORT PCI_Data_Reg;
// Disable trapping for this device
Trap_PCI_IDSEL(Address, 0);
// Re-issue the configuration write to the h/w device
out_32(PCI_CONFIG_ADDRESS, 0x80000000 | Address);
PCI_Data_Reg = PCI_CONFIG_DATA + (Address & 3);
switch (Size & ~IO_WRITE) {
case BYTE_IO:
out_8(PCI_Data_Reg, (UCHAR)Data);
break;
case WORD_IO:
out_16(PCI_Data_Reg, (USHORT)Data);
break;
case DWORD_IO:
out_32(PCI_Data_Reg, Data);
break;
}
// Re-enable trapping for this device
Trap_PCI_IDSEL(Address, 1);
}
}
}
}
//***********************************************************************
// This routine handles USB1 events.
//***********************************************************************
void USB1_Handler(void)
{
Send_OHCI_Event(1);
}
//***********************************************************************
// This routine handles USB2 events.
//***********************************************************************
void USB2_Handler(void)
{
Send_OHCI_Event(2);
}
//***********************************************************************
// This routine handles the CS5536's KEL events
//***********************************************************************
void KEL_Handler(void)
{
Send_OHCI_Event(1);
}
//***********************************************************************
// This routine handles a BLOCKIO event (PIO to ATA during UDMA).
//***********************************************************************
void BLOCKIO_Handler(void)
{ SmiHeader * SmiHdr;
SmiHdr = Get_Header_Params(SMI_SRC_BLOCKIO);
Send_Synchronous_Event(EVENT_BLOCKIO, SmiHdr);
}
//***********************************************************************
// This routine handles hits on MBus descriptors.
//***********************************************************************
void Descr_Hit_Handler(void)
{ USHORT Address;
SmiHeader * SmiHdr;
SmiHdr = Get_Header_Params(SMI_SRC_DESCR_HIT);
// Ignore if one of the other sources of SSMI_FLAGS
if (!SmiHdr->SMI_Flags.Ext_IO_Trap && !SmiHdr->SMI_Flags.IO_Trap) {
return;
}
Address = (USHORT)SmiHdr->IO_addr;
// Handle virtual registers
if ((Address & 0xFFFC) == (HostBridge_Hdr[BAR0/4].Value_LO)) {
if (SmiHdr == &SMM_Header) {
// Handle virtual register
VR_Handler(SmiHdr);
} else {
Report_VSM_Error(ERR_NESTED_ACCESS, 0, 0);
}
return;
}
// Handle workaround for PM Support registers
if ((Address & (USHORT)ISA_Hdr[BAR4/4].Mask) == (ISA_Hdr[BAR4/4].Value_LO)) {
ACPI_Workaround(SmiHdr, 0);
}
// Handle workaround for ACPI registers
if ((Address & 0xFFE0) == (ISA_Hdr[BAR5/4].Value_LO)) {
ACPI_Workaround(SmiHdr, 1);
}
// Send the event
Send_Synchronous_Event(EVENT_IO_TRAP, SmiHdr);
}
//***********************************************************************
// This routine handles statistic counter ASMIs
//***********************************************************************
void StatCntr_Handler(void)
{ UCHAR StartIndex = 0;
USHORT Address;
ULONG SFlag;
while (Stats_Sources) {
SFlag = 1L << BitScanForward(Stats_Sources);
Address = Get_Timeout(SFlag, &StartIndex);
if (Address) {
(USHORT)MsgPacket[2] = Address;
Send_Asynchronous_Event(EVENT_IO_TIMEOUT);
} else {
// Clear status bit
Stats_Sources &= ~SFlag;
}
}
}
//***********************************************************************
// This routine handles the Southbridge's PIC events
//***********************************************************************
void PIC_Handler(void)
{ USHORT ExpiredTimerMask, Timer;
// Need to read PIC registers to determine if one of:
// USB1, USB2, S/W Generated, RTC Alarm, Audio, PM, NAND Flash,
// SMB, KEL, UART1, UART2, MFGPT comparator, or GPIO.
CS5536_GPIO_Handler(0);
// Check if any MFGPT events occurred
ExpiredTimerMask = CS5536_MFGPT_Handler();
Timer = 0;
while (ExpiredTimerMask) {
if (ExpiredTimerMask & 1) {
Timer_Handler(Timer);
}
Timer++;
ExpiredTimerMask >>= 1;
}
}
//***********************************************************************
// This routine handles the CS5536's ACPI events
//***********************************************************************
void ACPI_Handler(void)
{ SmiHeader * SmiHdr;
SmiHdr = Get_Header_Params(0);
// Handle mis-aligned access to the PM1_CNT register
while ((UCHAR)SmiHdr->IO_addr != 0x08) {
(UCHAR)SmiHdr->IO_addr++;
(UCHAR)SmiHdr->data_size >>= 1;
SmiHdr->write_data >>= 8;
}
if ((UCHAR)SmiHdr->data_size == 0x07) {
(UCHAR)SmiHdr->data_size = WORD_IO;
}
Send_Synchronous_Event(EVENT_ACPI, SmiHdr);
}
//***********************************************************************
// This routine handles the CS5536's Power Management Events
//***********************************************************************
void PME_Handler(void)
{
// Handle GPIOs that are routed to PM logic
CS5536_GPIO_Handler(0);
// Filter any false event caused by enabling PME
if (Get_ACPI_Status(MsgPacket)) {
Send_Synchronous_Event(EVENT_PME, 0);
}
}
//***********************************************************************
// This routine handles events for which no other handler applies.
//***********************************************************************
void Leftover_Handler(void)
{
// Report that the event was not handled.
Log_Error("Unhandled event");
}
//*************************************************************************
//
// The SMI_Sources table is used for determining the proper handler for
// a top-level SMI source. Note that a single handler may process multiple
// SMI sources. The order of entries in this table governs the order that
// the handlers will be invoked. This is NOT the order that the VSMs will
// be given control. Therefore, the order of entries is unimportant with
// respect to controlling priority. However, in terms of finding a match
// more quickly, the more frequent SMI events should be placed earlier in
// the table.
//
//*************************************************************************
SMI_ENTRY Handler_Table[] = {
PCI_Handler, SMI_SRC_PCI_TRAP,
VG_Handler, SMI_SRC_VG,
USB1_Handler, SMI_SRC_USB1,
USB2_Handler, SMI_SRC_USB2,
A20_Handler, SMI_SRC_A20,
Reset_Handler, SMI_SRC_RESET,
NMI_Handler, SMI_SRC_NMI,
Descr_Hit_Handler, SMI_SRC_DESCR_HIT,
PIC_Handler, SMI_SRC_PIC,
StatCntr_Handler, SMI_SRC_STAT,
KEL_Handler, SMI_SRC_KEL,
ACPI_Handler, SMI_SRC_ACPI,
PME_Handler, SMI_SRC_PME,
BLOCKIO_Handler, SMI_SRC_BLOCKIO,
Leftover_Handler, 0xFFFFFFFF,
};

View File

@@ -0,0 +1,193 @@
/*
* 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
*/
//* Function: *
//* This file contains the code for recording event history.
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
extern EVENT_ENTRY Events[];
extern ULONG MsgPacket[];
extern UCHAR VSM_Filter;
#if HISTORY
EVENT NonReportableEvents[] = {
EVENT_A20,
EVENT_GRAPHICS,
EVENT_ACPI_TIMER
};
#define UNREPORT_COUNT (sizeof(NonReportableEvents)/sizeof(EVENT))
//
// Event history
//
EVENT_HISTORY History[HISTORY];
int HistoryWrap = 0;
int HistoryStart = 0;
int HistoryEnd = 0;
//*****************************************************************************
//
// Record the event history
//
//*****************************************************************************
void Keep_History(EVENT Event, EVENT EventIndex)
{ int i;
ULONG ParamMask, Param2;
UCHAR VSM_Type;
register EVENT_ENTRY * EventPtr;
EventPtr = &Events[EventIndex];
VSM_Type = Get_VSM_Type(EventPtr->Vsm);
// Filter out VSM(s)
if (VSM_Filter != VSM_ANY && VSM_Type != VSM_Filter)
return;
//
// Filter events from reporting
//
for (i=0; i < UNREPORT_COUNT; i++) {
if (Event == NonReportableEvents[i])
return;
}
// Generate mask for Param1
ParamMask = 0xFFFFFFFF;
Param2 = EventPtr->Param2;
switch (Event) {
case EVENT_PCI_TRAP:
// Report all PCI events together by PCI function
ParamMask = ~Param2;
break;
case EVENT_GPIO:
// Get current edge
Param2 = EventPtr->CurrentEdge;
break;
case EVENT_SOFTWARE_SMI:
// Don't report APM calls CPU_Busy or CPU_Idle
if ((EventPtr->Param1 & 0xFF00) == 0x5300) {
switch (EventPtr->Param1 & 0x00FF) {
case 0x05:
case 0x06:
return;
}
break;
}
break;
case EVENT_VIRTUAL_REGISTER:
// Report all VR events together by classes
ParamMask = 0x0000FF00;
break;
}
// If it's the same event for the same VSM...
if ((History[HistoryEnd].Event == Event) &&
(History[HistoryEnd].Vsm == EventPtr->Vsm) ) {
switch (Event) {
case EVENT_IO_TRAP:
if (History[HistoryEnd].Param1 != (MsgPacket[2] & 0x0000FFFFL)) {
break;
}
// Events to be recorded together if (Param1 & ParamMask) matches
case EVENT_PCI_TRAP:
case EVENT_SOFTWARE_SMI:
case EVENT_VIRTUAL_REGISTER:
if (History[HistoryEnd].Param1 != (MsgPacket[1] & ParamMask)) {
break;
}
default:
// Record together if 1st two parameters match
if (History[HistoryEnd].Param1 == EventPtr->Param1 &&
History[HistoryEnd].Param2 == EventPtr->Param2 ) {
History[HistoryEnd].Count++;
Store_Timestamp(&History[HistoryEnd].TimeStamp);
return;
}
} // end switch
}
//
// Report event in a new history entry.
//
// Increment HistoryEnd unless it's the 1st event
if (History[HistoryEnd].Vsm) {
HistoryEnd++;
if (HistoryEnd >= HISTORY) {
HistoryEnd = 0;
HistoryWrap = 1;
}
// Increment HistoryStart index too if HistoryEnd has wrapped
if (HistoryWrap) {
HistoryStart++;
if (HistoryStart >= HISTORY)
HistoryStart = 0;
}
}
History[HistoryEnd].Vsm = EventPtr->Vsm;
History[HistoryEnd].Event = Event;
History[HistoryEnd].Param1 = MsgPacket[1] & ParamMask;
History[HistoryEnd].Param2 = Param2;
History[HistoryEnd].Count = 1;
Store_Timestamp(&History[HistoryEnd].TimeStamp);
}
void Initialize_History(void)
{
// Initialize timestamp field of history buffer entry "previous" to 1st entry
Store_Timestamp(&History[HISTORY-1].TimeStamp);
HistoryWrap = 0;
HistoryStart = 0;
HistoryEnd = 0;
}
#else
void Initialize_History(void) { }
#endif

View File

@@ -0,0 +1,697 @@
;
; 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
;
;********************************************************************************
; Routines to:
; -set up an SMM-based IDT
; -save/restore of FPU state only as needed
;********************************************************************************
include sysmgr.inc
include vsa2.inc
include gx2.inc
.model tiny,c
.586p
.CODE
CR equ 0Dh
LF equ 0Ah
public Saved_INTs
public Trap_Common
externdef Trap_Code: dword
externdef SysMgr_VSM: dword
externdef Current_VSM: dword
externdef IDT_Base: dword
externdef IDT_Limit: dword
externdef IDT_Selector:dword
externdef pascal Parse_Capabilities: proc
externdef pascal Read_MSR_HI: proc
FPU_Owner dd 0
FPU_State db 108 dup (0)
CR0_PE equ 1
CR0_EM equ 4
;***********************************************************************
; Saves the non-SMM IDT and installs VSA's exception vectors
;***********************************************************************
Install_IDT proc
; Save IDT of interrupted thread
mov ecx, 1329h
rdmsr
mov [IDT_Selector], eax
mov eax, IDT_SIZE-1
wrmsr
mov cl, 39h
rdmsr
mov [IDT_Base], eax
mov [IDT_Limit], edx
mov eax, [SysMgr_VSM]
add eax, OFFSET Saved_INTs
mov dx, IDT_SIZE
wrmsr
nop
mov byte ptr [$-1], 0C3h ; Patch a RET at the NOP above
mov eax, [SysMgr_VSM] ; Initialize FPU owner
mov [FPU_Owner], eax
; The following code is only necessary if SysMgr starts on a non-MB boundary.
; HandlerBase = {SMM_base[31:20], CS_selector[15:0], 4'b0}
; lea di, [Saved_INTs+2] ; Patch SysMgr's CS into vector table
; mov cx, IDT_SIZE/4
; shr eax, 4 ; Compute SysMgr's CS
;InsertCS:
; mov [di], ax ; Store SysMgr's CS into vector table
; add di, 4
; loop InsertCS
ret
Install_IDT endp
;***********************************************************************
; Restores the IDT ptr and FPU state (if modified)
;***********************************************************************
Restore_IDT proc
; Restore the IDT of interrupted thread
mov ecx, 1329h
mov eax, [IDT_Selector]
wrmsr
mov cl, 39h
mov eax, [IDT_Base]
mov edx, [IDT_Limit]
wrmsr
; The RET will be patched with a NOP if FPU usage occurs
RestoreRET::
ret
; Restore the RET at RestoreRET
mov byte ptr [RestoreRET], 0C3h
; Get last VSM to use FPU
mov esi, [SysMgr_VSM]
xchg [FPU_Owner], esi
; Set VSM's CR0.EM
or fs:(VSM_Header PTR [esi]).SysStuff.State.r_CR0, CR0_EM
; Save VSM's FPU state
; NOTE: This can be done in real-mode
fnsave fs:(VSM_Header PTR [esi]).SysStuff.FPU_State
; Restore non-SMM FPU state
; NOTE: This must be done in 32-bit protected mode
mov eax, CR0 ; Enter protected mode for FPU save
or al, CR0_PE
mov CR0, eax
jmp $+2
db 66h
frstor byte ptr cs:[FPU_State]
and al, NOT CR0_PE ; Return to real mode
mov CR0, eax
ret
Restore_IDT endp
;***********************************************************************
; Handler for Trap 7 (Device Not Available)
;***********************************************************************
Trap7 proc
push eax
; Clear interrupted VSM's CR0.EM (so it will own the FPU)
mov eax, CR0
and al, NOT CR0_EM
mov CR0, eax
; Get current owner of FPU
mov eax, cs:[FPU_Owner]
; Is it non-SMM thread ?
cmp eax, cs:[SysMgr_VSM]
jne Set_EM
; Yes, enable FPU restore code in Restore_IDT
mov byte ptr cs:[RestoreRET], 90h
; Save non-SMM FPU state
; NOTE: This must be done in 32-bit protected mode
mov eax, CR0 ; Enter protected mode for FPU save
or al, CR0_PE
mov CR0, eax
jmp $+2
db 66h
fnsave byte ptr cs:[FPU_State]
and al, NOT CR0_PE ; Return to real mode
mov CR0, eax
jmp short Record_FPU_Owner
Set_EM:
; Set previous owner's CR0.EM
or fs:(VSM_Header PTR [eax]).SysStuff.State.r_CR0, CR0_EM
; Save the FPU state of the previous owner
; NOTE: This can be done in 16-bit real-mode
fnsave byte ptr fs:(VSM_Header PTR [eax]).SysStuff.FPU_State
; Set FPU flag
mov fs:(VSM_Header PTR [eax]).SysStuff.FPU_Flag, 1
Record_FPU_Owner:
; Record the new owner of the FPU
mov eax, cs:[Current_VSM]
mov cs:[FPU_Owner], eax
; Has this VSM used the FPU previously ?
cmp fs:(VSM_Header PTR [eax]).SysStuff.FPU_Flag, 0
je short Exit
; Yes, restore its FPU state
; NOTE: This can be done in 16-bit real-mode
lea eax, (VSM_Header PTR [eax]).SysStuff.FPU_State
frstor byte ptr fs:[eax]
Exit: pop eax
iret ; Return to the interrupted VSM
Trap7 endp
;***********************************************************************
; Exception vectors (segments will be patched)
;***********************************************************************
Saved_INTs:
dd OFFSET Trap_Code + 8*0
dd OFFSET Trap_Code + 8*1
dd OFFSET Trap_Code + 8*2
dd OFFSET Trap_Code + 8*3
dd OFFSET Trap_Code + 8*4
dd OFFSET Trap_Code + 8*5
dd OFFSET Trap_Code + 8*6
dd OFFSET Trap_Code + 8*7
dd OFFSET Trap_Code + 8*8
dd OFFSET Trap_Code + 8*9
dd OFFSET Trap_Code + 8*0Ah
dd OFFSET Trap_Code + 8*0Bh
dd OFFSET Trap_Code + 8*0Ch
dd OFFSET Trap_Code + 8*0Dh
dd OFFSET Trap_Code + 8*0Eh
dd OFFSET Trap_Code + 8*0Fh
IDT_SIZE equ ($-Saved_INTs)
;***********************************************************************
; Macros for performing stackless CALLs & RETs
;***********************************************************************
ROM_CALL macro Subr
local RetAddr
mov dx, RetAddr ; Put return addr in BP
jmp Subr
RetAddr:
endm
ROM_RET macro
jmp dx ; Return to caller
endm
;***********************************************************************
; BX = Exception #
;***********************************************************************
Trap_Common:
mov cs:[TrapNum], bx
mov cs:[Reg_ECX], ecx
; Disable SMIs
mov ecx, MSR_SMM_CTRL
xor eax, eax
wrmsr
ROM_CALL NewLine
cmp bl, LastTrap
jbe @f
mov bl, LastTrap
@@:
add bx, bx
mov bx, cs:[bx+TrapMsgTbl]
ROM_CALL String
lea bx, [Msg_in]
ROM_CALL String
;
; Display the VSM which generated the exception
;
pop ecx ; Get SEG:OFFSET of faulting code
mov cs:[SegOff], ecx
mov esi, cs:[Current_VSM]
mov ah, fs:(VSM_Header PTR [esi]).VSM_Type
lea si, [VSM_Table]
ASSUME SI: PTR TableItem
test ecx, 0FFFF0000h ; Is it System Manager ?
jnz ScanVSM
mov eax, cs:[SysMgr_VSM]
mov cs:[Current_VSM], eax
jmp ShowVSM
ScanVSM:
mov al, cs:[si].Vsm ; Get VSM Type from table
cmp ah, al
je ShowVSM
cmp al, VSM_ANY ; End of table ?
je ShowVSM
add si, sizeof(TableItem) ; Advance to next table entry
jmp ScanVSM
ShowVSM:
mov bx, cs:[si].MsgStr
ROM_CALL String
lea bx, Msg_VSM ; VSM
ROM_CALL String
ROM_CALL NewLine
lea bx, Msg_IP ; IP = xxxx
ROM_CALL String
cmp cs:[TrapNum], 000Dh ; Is it Trap 0Dh ?
jne ShowIP
mov ebx, cs:[Current_VSM] ; Yes, check for bad MSR address
test ecx, 0FFFF0000h ; Did SysMgr cause it ?
jnz ComputeAddr
mov ebx, cs:[SysMgr_VSM] ; Yes
ComputeAddr:
movzx esi, cx
add esi, ebx
mov eax, dword ptr fs:[esi]
cmp al, 0Fh
jne short ShowIP
cmp ah, 30h ; WRMSR ?
je short BadMSR
cmp ah, 32h ; RDMSR ?
jne ShowIP
BadMSR:
mov cs:[MSR_Access], ah
mov si, sp ; Show caller
mov cx, ss:[si+4]
sub cx, 3
; If one of the MSR routines, show caller
cmp si, OFFSET Read_MSR_HI
jb short ShowIP
cmp si, OFFSET Parse_Capabilities
jae short ShowIP
mov cx, ss:[si+2]
ShowIP:
mov ax, cx
ROM_CALL Hex16
mov al, '/'
out dx, al
movzx eax, cx
add eax, cs:[Current_VSM]
ROM_CALL Hex32
lea bx, Msg_SP ; SP = xxxx
ROM_CALL String
mov ax, sp
ROM_CALL Hex16
lea bx, Msg_BP ; BP = xxxx
ROM_CALL String
mov ax, bp
ROM_CALL Hex16
cmp cs:[MSR_Access], 0 ; Was it an MSR access ?
je Beep
ROM_CALL NewLine ; Yes
lea bx, [Msg_MSR]
ROM_CALL String
lea bx, [Msg_MSR_Wr]
cmp cs:[MSR_Access], 30h
je short ShowMSR
lea bx, [Msg_MSR_Rd]
ShowMSR:
ROM_CALL String
mov eax, cs:[Reg_ECX] ; Display invalid MSR address
ROM_CALL Hex32
HI_TONE equ 1193180/3000 ; 3 KHz
LO_TONE equ 1193180/750 ; 750 Hz
INTERVAL equ 100000/15 ; .10 second
BEEP_LOOPS equ 10
Beep:
mov bx, BEEP_LOOPS
in al, 61h
or al, 3 ; connect speaker to timer 2
out 61h, al
BeepLoop:
mov dx, HI_TONE ; Start frequency
TwoTone:
mov al, 0B6h ; timer 2 mode set
out 43h, al ; set mode
mov ax, dx
out 42h, al ; set LSB of counter
mov al, ah
out 42h, al ; set MSB of counter
mov cx, INTERVAL ; # 15 usec intervals
Interval:
in al, 61h ; Wait for 15 usec
xor al, ah
test al, 10h
jz Interval
xor ah, 10h
loop Interval
shl dx, 1 ; Divide frequency by 2
cmp dx, LO_TONE ; End frequency
jb TwoTone
dec bx ; Decrement loop counter
jnz BeepLoop ; Start tones over
in al, 61h ; Turn off speaker
and al, NOT 3
out 61h, al
Halt: hlt
jmp Halt
;***********************************************************************
; VSM strings for display of VSM causing the exception
;***********************************************************************
TableItem struc
Vsm db ?
MsgStr dw ?
TableItem ends
VSM_Table:
TableItem {VSM_SYS_MGR, Sys_Mgr_VSM}
TableItem {VSM_AUDIO, XpressAudio}
TableItem {VSM_VGA, SoftVGA}
TableItem {VSM_LEGACY, Legacy_VSM}
TableItem {VSM_PM, PM_VSM}
TableItem {VSM_OHCI, OHCI_VSM}
TableItem {VSM_i8042, i8042_VSM}
TableItem {VSM_ACPI, ACPI_VSM}
TableItem {VSM_APM, APM_VSM}
TableItem {VSM_SMB, SMB_VSM}
TableItem {VSM_BATTERY, Battery_VSM}
TableItem {VSM_RTC, RTC_VSM}
TableItem {VSM_S2D, S2D_VSM}
TableItem {VSM_SPY, Spy_VSM}
TableItem {VSM_NETWORK, Network_VSM}
TableItem {VSM_GPIO, GPIO_VSM}
TableItem {VSM_USB, USB_VSM}
TableItem {VSM_FLASH, Flash_VSM}
TableItem {VSM_INFRARED,Infrared_VSM}
TableItem {VSM_THERMAL, Thermal_VSM}
TableItem {VSM_NULL, Null_VSM}
TableItem {VSM_VIP, VIP_VSM}
TableItem {VSM_LPC, LPC_VSM}
TableItem {VSM_VUART, VUART_VSM}
TableItem {VSM_MICRO, Micro_VSM}
TableItem {VSM_USER1, User1_VSM}
TableItem {VSM_USER2, User2_VSM}
TableItem {VSM_USER3, User3_VSM}
TableItem {VSM_SUPERIO, SuperIO_VSM}
TableItem {VSM_ANY, Unknown_VSM} ; Catch-all
Msg macro TrapString
db TrapString
db 0
endm
XpressAudio: Msg "Audio"
SoftVGA: Msg "SoftVG"
Legacy_VSM: Msg "Legacy"
USB_VSM: Msg "USB"
GPIO_VSM: Msg "GPIO"
ACPI_VSM: Msg "ACPI"
Sample_VSM: Msg "Sample"
APM_VSM: Msg "APM"
Battery_VSM: Msg "Battery"
PM_VSM: Msg "PM"
S2D_VSM: Msg "SaveToRAM"
Sys_Mgr_VSM: Msg "SysMgr"
i8042_VSM: Msg "i8042"
OHCI_VSM: Msg "OHCI"
SuperIO_VSM: Msg "SuperIO"
Null_VSM: Msg "Null"
Spy_VSM: Msg "Spy"
RTC_VSM: Msg "RTC"
SPY_VSM: Msg "Spy"
Network_VSM: Msg "Network"
Infrared_VSM: Msg "Infrared"
Thermal_VSM: Msg "Thermal"
VIP_VSM: Msg "VIP"
LPC_VSM: Msg "LPC"
User1_VSM: Msg "User1"
User2_VSM: Msg "User2"
User3_VSM: Msg "User3"
SMB_VSM: Msg "SMB"
Flash_VSM: Msg "Flash"
VUART_VSM: Msg "VUART"
Micro_VSM: Msg "Micro"
Unknown_VSM: Msg "VSM???"
;***********************************************************************
; Strings describing the type of exception
;***********************************************************************
TrapMsgTbl:
dw OFFSET Trap00
dw OFFSET Trap01
dw OFFSET Trap02
dw OFFSET Trap03
dw OFFSET Trap04
dw OFFSET Trap05
dw OFFSET Trap06
dw OFFSET Trap07
dw OFFSET Trap08
dw OFFSET Trap09
dw OFFSET Trap0A
dw OFFSET Trap0B
dw OFFSET Trap0C
dw OFFSET Trap0D
dw OFFSET Trap0E
dw OFFSET Trap0F
dw OFFSET Trap10
dw OFFSET Trap11
dw OFFSET Trapnn
LastTrap equ ($-TrapMsgTbl)/2
Trap00: Msg "Divide by Zero"
Trap01: Msg "Debug"
Trap02: Msg "NMI/INT 02h"
Trap03: Msg "Breakpoint"
Trap04: Msg "Overflow"
Trap05: Msg "Bounds Check"
Trap06: Msg "Invalid Opcode"
Trap07: Msg "Device Not Available"
Trap08: Msg "Double Fault"
Trap09: Msg "Invalid TSS"
Trap0A: Msg "INT 0Ah"
Trap0B: Msg "Segment Not Present"
Trap0C: Msg "Stack Fault"
Trap0D: Msg "General Protection"
Trap0E: Msg "Page Fault"
Trap0F: Msg "INT 0Fh"
Trap10: Msg "INT 10h"
Trap11: Msg "Aligment Check"
Trapnn: Msg "Trap ??"
;***********************************************************************
; Miscellaneous strings
;***********************************************************************
Msg_in: Msg " in "
Msg_VSM: Msg " VSM"
Msg_SP: Msg " SP="
Msg_BP: Msg " BP="
Msg_IP: Msg "IP="
Msg_MSR: Msg "Invalid MSR "
Msg_MSR_Rd: Msg "read: "
Msg_MSR_Wr: Msg "write: "
;***********************************************************************
; Stackless display routines
;***********************************************************************
NewLine:
mov al, CR
out DBG_PORT, al
ROM_RET
String:
mov al, cs:[bx]
or al, al
jz StringExit
out DBG_PORT, al
in al, 80h
inc bx ; Advance ptr
jmp String
StringExit:
ROM_RET
Seg_Addr:
mov si, bp
rol eax, 16
xchg ah, al
ROM_CALL Hex8
xchg ah, al
ROM_CALL Hex8
mov al, ':'
out DBG_PORT, al
rol eax, 16
xchg ah, al
ROM_CALL Hex8
xchg ah, al
ROM_CALL Hex8
mov bp, si ; Restore ret addr
ROM_RET
Hex32: rol edx, 16 ; Save return address in upper EDX
rol eax, 8
ROM_CALL Hex8
rol eax, 8
ROM_CALL Hex8
rol eax, 8
ROM_CALL Hex8
rol eax, 8
ROM_CALL Hex8
mov al, ' '
out DBG_PORT, al
rol edx, 16 ; Restore return address
ROM_RET
Hex16: rol edx, 16 ; Save return address in upper EDX
xchg ah, al
ROM_CALL Hex8
xchg ah, al
ROM_CALL Hex8
rol edx, 16 ; Restore return address
mov al, ' '
out DBG_PORT, al
ROM_RET
Hex8:
; Display 4 MSBs
mov di, ax
rol al, 4
and al, 0Fh
add al, '0' ; Convert to ASCII
cmp al, '9'
jbe @f
add al, 7 ; 'A'-'F'
@@: out DBG_PORT, al
in al, 80h
mov ax, di
; Display 4 LSBs
and al, 0Fh
add al, '0' ; Convert to ASCII
cmp al, '9'
jbe Char
add al, 7 ; 'A'-'F'
Char: out DBG_PORT, al
in al, 80h
ROM_RET
SegOff dd 0
Reg_ECX dd 0
TrapNum dw 0
MSR_Access db 0
end

View File

@@ -0,0 +1,37 @@
;
; 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
;
;* Function: *
;* This file contains the label for the beginning of the VSA image *
;* It MUST be the last .OBJ file in the link
.model small,c
.586
.CODE
public VSA_Image
TEXT SEGMENT PARA 'CODE'
VSA_Image:
TEXT ENDS
END

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,39 @@
/*
* 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
*/
#define CR 0x0D
#define LF 0x0A
#define ERR_NO_FIT (1 << 0)
#define ERR_NO_SYS_MGR (1 << 1)
#define ERR_BAD_TYPE (1 << 2)
#define ERR_SMI_STATUS (1 << 3)
#define ERR_BAD_CPU (1 << 4)
#define ERR_NO_CHIPSET (1 << 5)
#define ERR_NOT_CPL0 (1 << 6)
#define ERR_VERIFY (1 << 7)
#define ERR_VERSION (1 << 8)
#define ERR_INTERNAL (1 << 9)
#define ERR_INVALID_VSM (1 << 10)
#define DOS_LOAD (1 << 0)
#define VSM_LOAD (1 << 1)

View File

@@ -0,0 +1,196 @@
/*
* 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
*/
//* Function: *
//* Handles trapped and virtualized I/O
#include "VSA2.H"
#include "PROTOS.H"
#include "SYSMGR.H"
// External variables
extern ULONG Saved_EAX, Saved_EDI;
extern ULONG Nested_EAX, Nested_EDI;
extern Descriptor Saved_ES, Flat_Descriptor;
extern SmiHeader SMM_Header;
// External routines
extern void pascal write_flat_size(ULONG, ULONG, UCHAR);
extern ULONG pascal Convert_To_Physical_Addr(ULONG);
#define PAGING_ENABLED 0x80000001
#define ADDR32 1
#define DATA32 2
typedef struct {
union {
ULONG Ulong;
struct {
USHORT LowAddr;
UCHAR MidAddr;
UCHAR HiAddr;
};
};
} DESCR;
//***********************************************************************
// Returns the physical address of the location to return the value
//***********************************************************************
ULONG pascal Get_Logical_Address(SmiHeader * SmiHdr, ULONG * CR0_Ptr)
{ UCHAR Override = 0, Size, Instruction;
static UCHAR SizeToIncr[16] = {0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,4};
ULONG EDI, Logical_Addr, Incr, Phys_Addr, Reg_Ptr;
register Descriptor * Callers_ES;
DESCR Mem_Ptr;
Size = (UCHAR)SmiHdr->data_size;
if (SmiHdr == &SMM_Header) {
Reg_Ptr = SysMgr_VSM + (ULONG)((USHORT)&Saved_EAX);
// Get ES:EDI in case it's INSW
Callers_ES = &Saved_ES;
EDI = Saved_EDI;
} else {
// Nested_EAX is a flat ptr to EAX on the VSM's stack
Reg_Ptr = Nested_EAX;
// Get ES:EDI in case it's INSW
Callers_ES = &Flat_Descriptor;
EDI = Nested_EDI;
}
// Determine default operand and address size
if (Callers_ES->attr & D_BIT) {
Override = DATA32 | ADDR32;
}
// Get address of trapped code
Logical_Addr = SmiHdr->Current_EIP + SmiHdr->_CS.base;
do {
// If paging is enabled...
if ((SmiHdr->r_CR0 & PAGING_ENABLED) == PAGING_ENABLED){
// translate logical to physical address via the page tables
Phys_Addr = Convert_To_Physical_Addr(Logical_Addr);
} else {
Phys_Addr = Logical_Addr;
}
// Get opcode
Instruction = (UCHAR)read_flat(Phys_Addr);
switch (Instruction) {
case 0xE4: // IN AL, <nn>
case 0xE5: // IN AX, <nn>
case 0xEC: // IN AL, DX
case 0xED: // IN AX, DX
*CR0_Ptr = 0x00000000;
return Reg_Ptr;
case 0x67: // Address Size
Override ^= ADDR32;
break;
case 0x66: // Data Size
// Override ^= DATA32;
case 0xF2: // REPNE
case 0xF3: // REPE
break;
case 0x6C: // INSB
case 0x6D: // INSW/INSD
Mem_Ptr.LowAddr = Callers_ES->base_15_0;
Mem_Ptr.MidAddr = Callers_ES->base_23_16;
Mem_Ptr.HiAddr = Callers_ES->base_31_24;
// (E)DI has already been inc'd/dec'd
Incr = SizeToIncr[Size];
if (SmiHdr->EFLAGS & EFLAGS_DF) {
EDI += Incr;
} else {
EDI -= Incr;
}
// If 16-bit mode, mask 16 MSBs of ptr
if (!(Override & ADDR32)) {
EDI &= 0x0000FFFF;
}
Mem_Ptr.Ulong += EDI;
*CR0_Ptr = SmiHdr->r_CR0;
return Mem_Ptr.Ulong;
default:
// Unexpected opcode
Log_Error("Unexpected opcode at 0x%08X = 0x%08X", Phys_Addr, read_flat(Phys_Addr));
return 0xFFFFFFFF;
}
// Increment code ptr
Logical_Addr++;
} while (1);
}
//***********************************************************************
// Returns an I/O value to AL/AX/EAX or ES:(E)DI
//***********************************************************************
void pascal Return_Virtual_Value(SmiHeader * SmiHdr, ULONG Data)
{ ULONG PhysicalAddr, LogicalAddr, CR0;
UCHAR Size;
LogicalAddr = Get_Logical_Address(SmiHdr, &CR0);
if (LogicalAddr == 0xFFFFFFFF)
return;
Size = (UCHAR)SmiHdr->data_size;
if ((CR0 & PAGING_ENABLED) == PAGING_ENABLED){
// If paging is enabled, translate logical to physical address and
// write one byte at a time since buffer could cross page boundary.
do {
PhysicalAddr = Convert_To_Physical_Addr(LogicalAddr++);
write_flat_size(PhysicalAddr, Data, BYTE_IO);
Data >>= 8;
Size >>= 1;
} while (Size);
} else {
// Write the data to memory
write_flat_size(LogicalAddr, Data, Size);
}
}

View File

@@ -0,0 +1,218 @@
/*
* 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
*/
//******************************************************************************
//* Routines for setting I/O traps
//******************************************************************************
#include "VSA2.H"
#include "PROTOS.H"
#include "GX2.H"
#include "VPCI.H"
#include "DESCR.H"
#include "CHIPSET.H"
ULONG pascal Compute_IOD_SC(ULONG *, USHORT *, UCHAR);
// External variables:
extern DESCRIPTOR MSRs[];
extern UCHAR NumMbius;
extern MBIU_INFO MbiuInfo[MAX_MBIU];
extern Hardware HardwareInfo;
extern UCHAR * VsmNames[];
extern ULONG Current_VSM;
// Local variables:
UCHAR MbiuSearchOrder[MAX_MBIU] = {2,1,0};
ULONG MbiuSkipFlags[] = {NOT_GLIU0, NOT_GLIU1, NOT_GLIU2};
//***********************************************************************
// Creates an I/O descriptor for the specified Address/Range.
// UsePID:
// 0 = set PID to zero (generate SMI)
// 1 = set PID to MBIU's subtractive port
//***********************************************************************
UCHAR pascal Setup_IO_Descriptor(ULONG * AddressPtr, USHORT * RangePtr, UCHAR UsePID)
{ UCHAR i, j, Index, FirstChoice, SecondChoice;
USHORT Range, MaxRange;
ULONG Address, Flags;
MBIU_INFO * MbiuPtr;
register DESCRIPTOR * Descr;
Range = * RangePtr;
Flags = Address = * AddressPtr;
// Determine type(s) of I/O descriptor to use
FirstChoice = IOD_BM;
SecondChoice = IOD_SC;
if (Flags & (READS_ONLY | WRITES_ONLY)) {
FirstChoice = IOD_SC;
} else {
// Check if we should try to use a swiss-cheese descriptor
if (Address & 7 || Range < 8) {
FirstChoice = IOD_SC;
SecondChoice = IOD_BM;
}
}
// Find an appropriate descriptor
for (i = 0; i < NumMbius; i++) {
j = MbiuSearchOrder[i];
// Skip this MBIU ?
if (Flags & MbiuSkipFlags[j]) {
continue;
}
MbiuPtr = &MbiuInfo[j];
Index = Allocate_Descriptor(FirstChoice, SecondChoice, MbiuPtr->Mbiu);
if (Index != DESCRIPTOR_NOT_FOUND) {
break;
}
}
if (Index == DESCRIPTOR_NOT_FOUND) {
return Index;
}
Descr = &MSRs[Index];
Descr->Address = (USHORT)Address;
// Set appropriate port
if (UsePID) {
Descr->MsrData[1] = MbiuPtr->SubtrPid;
}
switch (Descr->Type) {
case IOD_BM:
// Mask must not include any valid address bits
MaxRange = 1 << BitScanForward(Address);
if (Range > MaxRange) {
Range = MaxRange;
} else {
while (!IsPowerOfTwo(Range)) {
Range--;
}
}
(USHORT)Descr->MsrData[1] = (USHORT)Address >> 12;
Descr->MsrData[0] = ~(Range-1) | 0x000F0000;
Descr->MsrData[0] |= Address << 20;
Descr->Range = Range;
* AddressPtr += Range;
* RangePtr -= Range;
break;
case IOD_SC:
Descr->MsrData[0] = Compute_IOD_SC(AddressPtr, RangePtr, 1);
Descr->Range = Range - * RangePtr;
break;
default:
return DESCRIPTOR_NOT_FOUND;
}
Write_MSR(Descr->MsrAddr, Descr->MsrData);
return Index;
}
//***********************************************************************
// Clears an I/O trap on the specified I/O Range
//***********************************************************************
void pascal Clr_MBus_IO_Trap(ULONG Address, USHORT Range)
{ UCHAR Index;
while (Range) {
// Find an existing descriptor that matches Address
Index = Find_Matching_IO_Descriptor(&Address, &Range, 0);
if (Index == DESCRIPTOR_NOT_FOUND) {
// Report error
Log_Error("Unregistration of I/O 0x%04X by the %s VSM", Address, VsmNames[Get_VSM_Type(Current_VSM)]);
return;
}
}
}
//***********************************************************************
// Sets an I/O trap on the specified I/O Range
//***********************************************************************
void pascal Set_MBus_IO_Trap(ULONG Address, USHORT Range)
{ UCHAR Index;
// If the range is > 8 bytes and/or is not a power of 2,
// multiple descriptors may be required.
while (Range) {
// Find an existing descriptor that matches Address
Index = Find_Matching_IO_Descriptor(&Address, &Range, 2);
if (Index == DESCRIPTOR_NOT_FOUND) {
// An existing descriptor does not match the range.
// Allocate a new descriptor
Index = Setup_IO_Descriptor(&Address, &Range, 0);
if (Index == DESCRIPTOR_NOT_FOUND) {
// Report resource error
Log_Error("No descriptors for I/O trap of 0x%04X by the %s VSM", Address, VsmNames[Get_VSM_Type(Current_VSM)]);
break;
}
} else {
// An existing descriptor was modified for the new Addr/Range
}
MSRs[Index].Flag |= IO_TRAP;
}
}
//***********************************************************************
// Enable/Disable I/O trap
//***********************************************************************
void pascal MBus_IO_Trap(ULONG Param1, ULONG Param2, UCHAR EnableFlag)
{ ULONG Address;
USHORT Range;
// Repackage parameters
Address = Param2;
(USHORT)Address = (USHORT)Param1;
Range = (USHORT)Param2;
// Check for illegal combination of flags
if ((Address & ALL_GLIUS) == ALL_GLIUS) {
// Report error
Log_Error("Illegal combination of flags for I/O 0x%04X by the %s VSM", Address, VsmNames[Get_VSM_Type(Current_VSM)]);
return;
}
if (EnableFlag) {
Set_MBus_IO_Trap(Address, Range);
} else {
Clr_MBus_IO_Trap(Address, Range);
}
}

View File

@@ -0,0 +1,222 @@
#
# Copyright (c) 2006 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
#
######################################################################
#
# Init variables
#
######################################################################
!ifndef VSA2ROOT
VSA2ROOT = ..
!endif
BUILD_DIR = $(VSA2ROOT)\build
OBJECT = obj
!include $(BUILD_DIR)\setvars.mak
.SUFFIXES: .asm .c .h .inc .map .obj .mac
INCLUDE = $(OBJECT);$(INCLUDE)
VSMNAME = sysmgr
######################################################################
#
# Build Macros
#
######################################################################
INIT_ASM_OBJS = \
$(OBJECT)\init.obj \
$(OBJECT)\cpu_init.obj \
$(OBJECT)\chip.obj \
$(OBJECT)\image.obj \
SYSMGR_ASM_OBJS = \
$(OBJECT)\sysmgr.obj \
$(OBJECT)\bugs.obj \
$(OBJECT)\utils.obj \
$(OBJECT)\syscalls.obj \
$(OBJECT)\smis.obj \
$(OBJECT)\port92.obj \
$(OBJECT)\sw_int.obj \
$(OBJECT)\debug.obj \
$(OBJECT)\vr_misc.obj \
$(OBJECT)\cpu.obj \
$(OBJECT)\idt.obj \
$(OBJECT)\message.obj \
$(OBJECT)\msr.obj \
SYSMGR_C_OBJS = \
$(OBJECT)\events.obj \
$(OBJECT)\handlers.obj \
$(OBJECT)\chipset.obj \
$(OBJECT)\gpio.obj \
$(OBJECT)\errors.obj \
$(OBJECT)\history.obj \
$(OBJECT)\io.obj \
$(OBJECT)\virt_pci.obj \
$(OBJECT)\mbus.obj \
$(OBJECT)\vsa_init.obj \
$(OBJECT)\descr.obj \
$(OBJECT)\vr.obj \
$(OBJECT)\topology.obj \
$(OBJECT)\pci_rd.obj \
$(OBJECT)\pci_wr.obj \
$(OBJECT)\cs5536.obj \
$(OBJECT)\swapsif.obj \
$(OBJECT)\unregstr.obj \
$(OBJECT)\mdd.obj \
$(OBJECT)\pci_pm.obj \
$(OBJECT)\gpio5536.obj \
$(OBJECT)\mfgpt.obj \
$(OBJECT)\mapper.obj \
$(OBJECT)\timeout.obj \
$(OBJECT)\io_trap.obj \
$(OBJECT)\mbiu.obj \
$(OBJECT)\timer.obj \
$(OBJECT)\ohci.obj \
SYSMGR_C_CODS = $(SYSMGR_C_SRCS:.obj=.cod)
SYSMGR_OBJS = $(SYSMGR_ASM_OBJS) $(SYSMGR_C_OBJS)
SYSMGR_VSM = $(OBJECT)\sysmgr.vsm
#######################################################################
#
# Targets
#
#######################################################################
all: $(OBJECT) setenv sysmgr.vsm vsainit.bin
!ifdef BUILDOBJ
$(COPY) $(OBJECT)\sysmgr.vsm $(BUILDOBJ)
$(COPY) $(OBJECT)\vsainit.bin $(BUILDOBJ)
!endif
sysmgr.vsm: $(SYSMGR_OBJS)
$(LN) /MAP $(LOPTS_VSM) @<<sysmgr.lnk
$(SYSMGR_OBJS: =+^
)
$(SYSMGR_VSM)
;
<<NOKEEP
vsainit.bin init.exe: $(INIT_ASM_OBJS)
$(LN) $(LD_OPTS) /MAP $**,$(OBJECT)\init.exe,$(OBJECT)\init.map;
$(X2ROM) $(OBJECT)\init.exe $(OBJECT)\vsainit.bin
# $(COPY) $(OBJECT)\init.rom $(OBJECT)\vsainit.bin
#This and only this clean target must exist as it is called by cleanall
#cleanall and cleanlocal are defined in rules.mak
clean: cleanlocal
$(OBJECT):
-@md $(OBJECT)
#######################################################################
#
# Dependencies
#
#######################################################################
$(SYSMGR_ASM_OBJS): $(MAKEDIR)\makefile \
$(OBJECT)\sysmgr.inc \
$(OBJECT)\smimac.mac \
$(OBJECT)\vsa2.inc \
$(OBJECT)\isa.inc \
$(OBJECT)\chipset.inc \
$(OBJECT)\vr.inc \
$(OBJECT)\pci.inc \
$(OBJECT)\hce.inc \
$(OBJECT)\gx2.inc \
$(OBJECT)\protos.inc \
$(OBJECT)\descr.inc \
$(OBJECT)\mdd.inc \
$(OBJECT)\cs5536.inc \
$(SYSMGR_C_OBJS): $(MAKEDIR)\makefile \
$(OBJECT)\sysmgr.h \
$(OBJECT)\vsa2.h \
$(OBJECT)\isa.h \
$(OBJECT)\chipset.h \
$(OBJECT)\vr.h \
$(OBJECT)\pci.h \
$(OBJECT)\vpci.h \
$(OBJECT)\protos.h \
$(OBJECT)\mdd.h \
$(OBJECT)\timer.h \
$(OBJECT)\mapper.h \
$(OBJECT)\gx2.h \
$(OBJECT)\hce.h \
$(OBJECT)\acpi.h \
$(OBJECT)\cs5536.h \
$(INIT_ASM_OBJS): $(MAKEDIR)\makefile \
$(OBJECT)\sysmgr.inc \
$(OBJECT)\smimac.mac \
$(OBJECT)\vsa2.inc \
$(OBJECT)\isa.inc \
$(OBJECT)\chipset.inc \
$(OBJECT)\vr.inc \
$(OBJECT)\pci.inc \
$(OBJECT)\init.inc \
$(OBJECT)\mdd.inc \
$(OBJECT)\gx2.inc \
$(OBJECT)\cs5536.inc \
######################################################################
#
# Common Targets
#
######################################################################
# include common targets and inference rules
!include $(BUILD_DIR)\rules.mak
######################################################################
#
# Inference Rules
#
######################################################################
# Override common inference rules here
{$(INC_DIR)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zni /C $<
{$(INC_DIR)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zni /C $<
{$(SYSMGR_SRC)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zns /C $<
{$(SYSMGR_SRC)\$(CPU)}.h{$(OBJECT)}.inc:
$(H2) /Fa$(OBJECT)\$(@F) /nologo /Zns /C $<
$(OBJECT)\hce.inc:
$(H2) /Fa$(OBJECT)\hce.inc /Znh /C $(INC_DIR)\hce.h
$(OBJECT)\protos.inc:
$(H2) /Fa$(OBJECT)\protos.inc /Zn"q" /C $(SYSMGR_SRC)\protos.h

View File

@@ -0,0 +1,118 @@
/*
* 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
*/
//******************************************************************************
//* This file contains code specific to the IRQ Mapper
//******************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#include "VPCI.H"
#include "PCI.H"
#include "MDD.H"
#include "MAPPER.H"
#include "ISA.H"
// Local Variables:
UCHAR PCI_INTs[4] = {0,0,0,0}; // Current PCI INT mappings
UCHAR Max_PCI_Interrupt=4;
// External Variables:
extern ULONG MDD_Base;
extern USHORT Saved_AX;
// External Functions:
void PCI_Interrupts(void);
//************************************************************************************
// Maps an Unrestricted Source to a PIC IRQ via the IRQ Mapper logic
//************************************************************************************
void pascal IRQ_Mapper(UCHAR Reg, UCHAR Source, UCHAR Irq)
{ ULONG MsrAddr, MsrData;
UCHAR ShiftCount;
// 8 sources per MSR
Reg += Source/8;
MsrAddr = MDD_Base + Reg;
// 4 bits per field
ShiftCount = (Source % 8) * 4;
// Map Unrestricted Source[Source] to Irq via IRQ Mapper
MsrData = Read_MSR_LO(MsrAddr);
MsrData &= ~(0x0000000FL << ShiftCount);
MsrData |= (ULONG)Irq << ShiftCount;
Write_MSR_LO(MsrAddr, MsrData);
}
//************************************************************************************
// Maps an Unrestricted Source Y to a PIC IRQ
//************************************************************************************
void pascal IRQY_Mapper(UCHAR Y_Source, UCHAR Irq)
{
IRQ_Mapper(MSR_IRQM_YLOW, Y_Source, Irq);
}
//************************************************************************************
// Maps an Unrestricted Source Z to a PIC IRQ
//************************************************************************************
void pascal IRQZ_Mapper(UCHAR Z_Source, UCHAR Irq)
{
IRQ_Mapper(MSR_IRQM_ZLOW, Z_Source, Irq);
}
//************************************************************************************
// Implements the SYS_GENERATE_IRQ macro for CS5536
//************************************************************************************
void pascal Generate_IRQ_5536(USHORT IRQ_Mask)
{ UCHAR Irq=0;
USHORT Level;
Level = in_16(PIC1_EDGE);
// Don't attempt to generate a level-sensitive interrupt
if (IRQ_Mask & Level) {
Log_Error("Attempt to generate a level-sensitive IRQ. Mask= 0x%04X", IRQ_Mask);
return;
}
while (IRQ_Mask) {
if (IRQ_Mask & 1) {
// Map the software IRQ to the requested IRQ
IRQY_Mapper(Y_IRQ_SW, Irq);
// Generate an edge to the PIC
Write_MSR_LO(MDD_Base + MSR_SOFT_IRQ, 0L);
Write_MSR_LO(MDD_Base + MSR_SOFT_IRQ, 1L);
}
IRQ_Mask >>= 1;
Irq++;
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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
*/
// Unrestricted Y usage:
#define Y_IRQ_SW 0
#define Y_IRQ_USB1 1
#define Y_IRQ_USB2 2
#define Y_IRQ_RTC 3
#define Y_IRQ_AUDIO 4
#define Y_IRQ_PME 5
#define Y_IRQ_FLASH 6
#define Y_IRQ_SMB 12
#define Y_IRQ_KEL 13
#define Y_IRQ_UART1 14
#define Y_IRQ_UART2 15
// Unrestricted Z usage:
#define Z_IRQ_MFGPT_04 0
#define Z_IRQ_MFGPT_15 1
#define Z_IRQ_MFGPT_26 2
#define Z_IRQ_MFGPT_37 3
#define Z_IRQ_SMI 8
#define Z_IRQ_INTA 9
#define Z_IRQ_INTB 10
#define Z_IRQ_INTC 11
#define Z_IRQ_INTD 12

View File

@@ -0,0 +1,135 @@
/*
* 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
*/
//* Function: *
//* Utility routines for managing MBIUs
#include "VSA2.H"
#include "PROTOS.H"
#include "GX2.H"
#include "VPCI.H"
#include "DESCR.H"
#include "SYSMGR.H"
extern void InitStatCounters(ULONG, UCHAR);
// External variables:
extern ULONG Mbiu0;
// Local variables:
ULONG ExtendedMemoryDescr0, ExtendedMemoryDescr1 = 0;
MBIU_INFO MbiuInfo[MAX_MBIU];
UCHAR NumMbius=0;
//***********************************************************************
// Called once for each MBIU:
// - Initializes statistic counters
// - Records all available descriptors
//***********************************************************************
void pascal Init_MBIU(UCHAR * CountPtr, ULONG Msr)
{ UCHAR Type, i;
ULONG Default[2], MsrData[2];
// Record info about MBIU
MbiuInfo[NumMbius].Mbiu = Msr;
MbiuInfo[NumMbius].SubtrPid = Read_MSR_LO(Msr + MBD_MSR_CONFIG) << 29;
MbiuInfo[NumMbius].NumCounters = ((CAPABILITIES *)CountPtr)->NSTATS;
MbiuInfo[NumMbius].ActiveCounters = 0x00;
MbiuInfo[NumMbius].ClockGating = Read_MSR_LO(Msr + MBD_MSR_PM);
// Clear SMIs on this MBIU & disable all events except HW Emulation
MsrData[0] = 0x0000000E;
MsrData[1] = 0x0000000F;
(USHORT)Msr = MBD_MSR_SMI;
Write_MSR(Msr, MsrData);
//*********************************************
// Initialize Statistics MSRs
//*********************************************
InitStatCounters(Msr, ((CAPABILITIES *)CountPtr)->NSTATS);
//*********************************************
// Begin with P2D_BM descriptors
//*********************************************
Type = P2D_BM;
(USHORT)Msr = MSR_MEM_DESCR;
do {
// Get number of next type of descriptor
if (i = *(CountPtr++)) {
// Get the default value for this descriptor type
Get_Descriptor_Default(Type, Default);
// Loop through all descriptors of a given type
do {
// If descriptor is already in use by the BIOS, skip it
Read_MSR(Msr, MsrData);
if ((MsrData[0] == Default[0]) && (MsrData[1] == Default[1])) {
// Initialize Descriptor[] entry
if (Init_Descr(Type, Msr)) {
// Not enough table entries...abort
Type = 0x99;
break;
}
} else {
// Descriptor is in use.
// If it's an extended memory descriptor, record the routing address.
if (Type == P2D_R) {
if ((Msr & ROUTING) == Mbiu0) {
ExtendedMemoryDescr0 = Msr;
} else {
ExtendedMemoryDescr1 = Msr;
}
}
}
Msr++;
} while (--i);
}
// Check next descriptor type.
// If transitioning from P2D to IOD descriptors...
if (++Type == IOD_BM) {
// change MSR offset to 0xE0
(USHORT)Msr = MSR_IO_DESCR;
}
} while (Type <= IOD_SC);
// Increment number of MBIUs
NumMbius++;
}

View File

@@ -0,0 +1,758 @@
/*
* 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
*/
//******************************************************************************
//* Routines related to the MBus
//******************************************************************************
#include "VSA2.H"
#include "PROTOS.H"
#include "PCI.H"
#include "GX2.H"
#include "VPCI.H"
#include "CHIPSET.H"
#include "DESCR.H"
#include "MDD.H"
#include "SYSMGR.H"
// Externals:
extern void InitLogicalCounters(void);
extern UCHAR GetPortID(ULONG);
extern void pascal ClearMbiu(ULONG);
extern UCHAR pascal Get_MBus_Status(ULONG, USHORT);
extern UCHAR pascal Is_LBAR_Enabled(PCI_HEADER_ENTRY * Pci);
extern ULONG pascal Compute_IOD_SC(ULONG *, USHORT *, UCHAR);
extern PCI_HEADER_ENTRY * pascal Get_Structure(USHORT);
extern USHORT Class;
extern CAPABILITIES Southbridge_MBIU;
extern ULONG Mbiu2, MPCI_SB;
extern ULONG ACPI_Timer_MSR;
extern Hardware HardwareInfo;
extern MBIU_INFO MbiuInfo[];
extern DESCRIPTOR MSRs[];
// Local Variables:
static ULONG PCI_Value;
ULONG Mbiu0 = PORT_MBIU0;
ULONG Mbiu1;
ULONG LookupMbiu;
ULONG MPCI_NB=0;
ULONG MCP_NB =0;
ULONG FooGlue=0;
UCHAR MBIU1_SelfReference;
UCHAR VG_Port;
UCHAR MC_Port;
CAPABILITIES Northbridge_MBIU0, Northbridge_MBIU1;
typedef struct {
ULONG Routing;
USHORT MBus_ID;
UCHAR Instance;
} SCAN_RESULTS;
#define MAX_HITS (3*8) // Num-GLIUs * Max-Ports-per-GLIU
SCAN_RESULTS PriorScans[MAX_HITS];
int j;
//***********************************************************************
// Scans an MBIU for the specified MBus_ID.
// Returns MBIU routing address (LSB = MBIU port)
//***********************************************************************
ULONG pascal Scan_MBIU(ULONG Mbiu, USHORT Port_ID, UCHAR * Instance, UCHAR Shift)
{ USHORT Port;
ULONG RoutingMask;
RoutingMask = 1L << Shift;
LookupMbiu = Mbiu;
// Adjustment for Southbridge MPCI
if (Port_ID == ID_MPCI && Mbiu == Mbiu2) {
Mbiu &= ~(RoutingMask - 1);
}
// Scan MBIU's ports for specified ID
for (Port = 0; Port <= 7; Port++) {
// If correct ID...
if (GetPortID(Mbiu) == Port_ID) {
// and correct instance...
if (--(* Instance) == 0) {
// return the routing address and port # (in 3 LSBs)
return (Mbiu | Port);
}
}
// Get MSR address to next device
Mbiu &= ~(RoutingMask - 1);
Mbiu += RoutingMask;
}
return 0x00000000;
}
// Port = 1
// Mbiu = Southbridge = 0x51000000
// Port_ID = 0x47
// RoutingMask = 1 << 20 = 0x00100000
//***********************************************************************
// Finds an MBUS ID and returns the routing address.
// The port number is also returned in the 3 LSBs.
//***********************************************************************
ULONG pascal Find_MBus_ID(USHORT MBus_ID, UCHAR Instance)
{ ULONG DeviceAddr;
int i, SavedInstance=Instance;
// Check results of previous scans for a match
for (i=0; i<j; i++) {
if (PriorScans[i].MBus_ID == MBus_ID && PriorScans[i].Instance == Instance) {
return PriorScans[i].Routing;
}
}
// Filter out MBIU1 self-reference
if (MBus_ID == ID_MBIU) {
if (Instance > 2) {
Instance++;
}
}
// MBus_ID = 0x47
// Instance = 1
if (!(DeviceAddr = Scan_MBIU(Mbiu0, MBus_ID, &Instance, 29))) {
if (!(DeviceAddr = Scan_MBIU(Mbiu1, MBus_ID, &Instance, 26))) {
if (!(DeviceAddr = Scan_MBIU(Mbiu2, MBus_ID, &Instance, 20)) && MBus_ID == ID_ATA) {
DeviceAddr = Scan_MBIU(Mbiu2, ID_ATA100, &Instance, 20);
}
}
}
// Clear h/w emulation events generated by scanning empty ports
ClearMbiu(Mbiu0);
ClearMbiu(Mbiu1);
// SDG: if Mbiu2 is 0x51020000, then the folliwng call
// sets bit 32 (EDX[0]) in 0x51022002. Does this actually talk
// MSR 0x51000002? If so... BUG!
ClearMbiu(Mbiu2);
// Record this scan for future reference
if (DeviceAddr && j < MAX_HITS-1) {
PriorScans[j].Instance = SavedInstance;
PriorScans[j].MBus_ID = MBus_ID;
PriorScans[j].Routing = DeviceAddr;
j++;
}
return DeviceAddr;
}
//***********************************************************************
// Returns the MSR address of the MPCI associated with the current device
//***********************************************************************
ULONG pascal GetMSR(void)
{
switch (Class) {
case 0x0600: // Bridge: Host
return MPCI_NB;
case 0x0601: // Bridge: ISA
return MPCI_SB;
default:
return 0x00000000;
}
}
//***********************************************************************
// Gets the PCI Latency Timer
//***********************************************************************
UCHAR pascal Get_Latency(PCI_HEADER_ENTRY * Pci)
{ ULONG MsrAddr, MPCI_Ctrl[2];
UCHAR LatencyTimer=Pci->LatencyTimer;
// If bridge device, get MSR address of its MPCI
if (MsrAddr = GetMSR()) {
// Read Latency timer from MPCI_CTRL.LAT
Read_MSR(MsrAddr + MPCI_CTRL, MPCI_Ctrl);
LatencyTimer = (UCHAR)MPCI_Ctrl[1];
}
return LatencyTimer;
}
//***********************************************************************
// Sets the PCI Latency timer
//***********************************************************************
void pascal Set_Latency(UCHAR Latency)
{ ULONG MsrAddr=0, MPCI_Ctrl[2];
// If bridge device, get MSR address of its MPCI
if (MsrAddr = GetMSR()) {
// Set the PCI Latency timer
Read_MSR(MsrAddr + MPCI_CTRL, MPCI_Ctrl);
(UCHAR)MPCI_Ctrl[1] = Latency;
// LDE is only defined in Northbridge MPCI
if (MsrAddr == MPCI_NB) {
if (Latency) {
// Issues 118.176 & 118.197 require LDE to be set unless Latency Timer == 0
(USHORT)MPCI_Ctrl[0] |= LDE;
} else {
// Clear MPCI_CTRL[LDE] if Latency Timer = 0x00
(USHORT)MPCI_Ctrl[0] &= ~LDE;
}
}
Write_MSR(MsrAddr + MPCI_CTRL, MPCI_Ctrl);
}
}
//***********************************************************************
// Enables/Disables a trap on a PCI Address
//***********************************************************************
void pascal Trap_PCI_IDSEL(USHORT PCI_Address, UCHAR EnableFlag)
{ ULONG Pbus, IDSEL_Mask;
IDSEL_Mask = 1L << (UCHAR)(PCI_Address >> 11);
Pbus = Read_MSR_LO(MPCI_NB + MPCI_PBUS);
if (EnableFlag) {
Pbus |= IDSEL_Mask;
} else {
Pbus &= ~IDSEL_Mask;
}
Write_MSR_LO(MPCI_NB + MPCI_PBUS, Pbus);
}
//***********************************************************************
// Initializes MBus related structures and MSRs
// Input:
// IDSEL_Mask = Mask of IDSELs to be virtualized
//***********************************************************************
void Init_MBus(void)
{ ULONG MsrAddr, MsrData[2];
//*********************************************
// Add RCONF0-RCONF7 to available descriptor list
//*********************************************
for (MsrAddr = MSR_RCONF0; MsrAddr <= MSR_RCONF7; MsrAddr++) {
if (Init_Descr(GX2_RCONF, MsrAddr)) {
break;
}
}
//*********************************************
// Initialize MBIU0
//*********************************************
Read_MSR(Mbiu0 + MBIU_CAP, &MsrData[0]);
Parse_Capabilities(&MsrData[0], &Northbridge_MBIU0);
Init_MBIU((UCHAR *)&Northbridge_MBIU0, Mbiu0);
//*********************************************
// Initialize MBIU1
//*********************************************
// MBIU1 is MBIU0's subtractive port
Mbiu1 = MbiuInfo[0].SubtrPid;
// Determine MBIU1 self-reference
MBIU1_SelfReference = (UCHAR)Read_MSR_LO(Mbiu1 + MBIU_WHOAMI);
Read_MSR(Mbiu1 + MBIU_CAP, &MsrData[0]);
Parse_Capabilities(&MsrData[0], &Northbridge_MBIU1);
Init_MBIU((UCHAR *)&Northbridge_MBIU1, Mbiu1);
// Find address of MPCI_NB
MPCI_NB = Find_MBus_ID(ID_MPCI, 1) & 0xFFFF0000;
// Find address of MCP
MCP_NB = Find_MBus_ID(ID_MCP, 1) & 0xFFFF0000;
// Enable SMIs from the companion I/O
MsrAddr = MCP_NB | MBD_MSR_SMI;
Write_MSR_LO(MsrAddr, Read_MSR_LO(MsrAddr) & ~0x00000010L);
PriorScans[j].Routing = 0x00000000;
PriorScans[j].MBus_ID = ID_VAIL;
PriorScans[j].Instance = 1;
j++;
// On LX, FooGlue MSRs == MCP_NB+0x20
if (HardwareInfo.CPU_ID == DEVICE_ID_LX) {
PriorScans[j].Routing = MCP_NB+0x20;
PriorScans[j].MBus_ID = ID_FG;
PriorScans[j].Instance = 1;
j++;
}
// Find address of FooGlue
FooGlue = Find_MBus_ID(ID_FG, 1) & 0xFFFFFFF0;
// Find port of Video Generator
VG_Port = (UCHAR)Find_MBus_ID(ID_VG, 1);
// Find port of Memory Controller
MC_Port = (UCHAR)Find_MBus_ID(ID_MC, 1);
// Enable MPCI error masks
MsrAddr = MPCI_NB | MBD_MSR_ERROR;
Write_MSR_LO(MsrAddr, Read_MSR_LO(MsrAddr) & ~(MARM | TARM | BMM | SYSM | PARM));
// Initialize logical timeout counters
InitLogicalCounters();
}
//***********************************************************************
// Computes the MSR data corresponding to an enabled PCI BAR
//***********************************************************************
void Compute_Msr_Value(register DESCRIPTOR * Descr, register PCI_HEADER_ENTRY * Pci)
{ ULONG PBase, PMask, POffset=0;
Descr->MsrData[0] = Pci->Value;
if (Pci->Flag & IO_BAR) {
if (Descr->MsrAddr == ACPI_Timer_MSR) {
PCI_Value += 4; // Skip over ACPI timer
}
Descr->Address = (USHORT)PCI_Value;
}
switch (Descr->Type) {
case USB_LBAR:
Descr->MsrData[1] |= MEM_SPACE;
return;
case MDD_LBAR:
Descr->MsrData[1] |= Pci->Mask | LBAR_EN;
// If Memory LBAR, set MEM_IO
if (!(Pci->Flag & IO_BAR)) {
Descr->MsrData[1] |= MEM_IO;
} else {
Descr->MsrData[1] &= 0x0000FFFF;
Descr->MsrData[0] &= 0x0000FFFF;
}
return;
case MPCI_RCONF:
Descr->MsrData[1] = Pci->Value;
// If I/O BAR, set SPACE bit & shift BASE & TOP
if (Pci->Flag & IO_BAR) {
Descr->MsrData[0] <<= 12; // Move BASE to MSR[31:14]
Descr->MsrData[1] += ~(Pci->Mask | 3);
Descr->MsrData[1] <<= 12; // Move TOP to MSR[63:46]
Descr->MsrData[1] |= 1; // Set SPACE bit
} else {
Descr->MsrData[1] += ~Pci->Mask & 0xFFFFF000;
}
Descr->MsrData[0] |= 1; // Enable region
return;
case EPCI:
return;
case GX2_RCONF:
// Mark region non-cacheable and write-combined
Descr->MsrData[0] |= REGION_CD | REGION_EN;
Descr->MsrData[1] = Pci->Value + ~Pci->Mask & 0xFFFFF000;
if (Pci->Flag & MMIO_BAR) {
// Memory-mapped I/O must be write-serialized to avoid deadlocks
// They are also marked write-burstable
// Descr->MsrData[0] |= REGION_WS | REGION_WT;
}
if (Pci->Flag & MEM_BAR) {
// Mark frame buffers write-combined
Descr->MsrData[0] |= REGION_WC;
}
return;
case IOD_SC:
PMask = Descr->Range;
Descr->MsrData[0] = Compute_IOD_SC(&PCI_Value, &(USHORT)PMask, 1);
break;
case IOD_BM:
PMask = ~(Descr->Range-1) | 0xF0000;
PBase = PCI_Value & PMask;
PCI_Value += Descr->Range;
break;
case P2D_BMK:
case P2D_BMO:
case P2D_BM:
PMask = Pci->Mask >> 12;
PBase = Pci->Value >> 12;
break;
case P2D_RO:
// Fixup for VG alias bug
if (Descr->Physical) {
POffset = (~Pci->Value + 1) >> 12;
}
case P2D_R:
PMask = Pci->Value >> 12;
PBase = PMask + ((Descr->Range-1) >> 12);
break;
// These descriptor types are not used for PCI BARs
case P2D_SCO:
case P2D_SC:
default:
Log_Error("Compute_Msr_Value() was called with an invalid descriptor type: 0x%0x", Descr->Type);
return;
} // end switch()
if (Descr->Type != IOD_SC) {
if (Pci->Flag & MEM_BAR) {
POffset = (Descr->Physical - Pci->Value) >> 12;
}
// Assemble fields into MSR value
MergeFields(Descr->MsrData, PMask, PBase, POffset);
}
// Set PID field
Descr->MsrData[1] |= (ULONG)Descr->Port << 29;
// Set Bizarro bit, if necessary
if (Pci->Flag & USE_BMK) {
Descr->MsrData[1] |= BIZARRO;
}
}
//***********************************************************************
// Updates all descriptors/LBARs/RCONF associated with a PCI BAR
//***********************************************************************
void pascal Update_BAR(register PCI_HEADER_ENTRY * Pci, UCHAR Enable)
{ register DESCRIPTOR * Descr;
UCHAR Link;
PCI_Value = Pci->Value;
Link = Pci->Link;
// For each linked item, update the associated MSR
while (Link) {
Descr = &MSRs[Link];
// Get link to next MSR
Link = Descr->Link;
// Section 3.2.2 of PCI Spec 2.1: A BAR of zero is not a valid address.
// If the BAR value is zero, the corresponding MSR will be disabled.
if (Enable && Pci->Value != 0) {
// Don't update MSRs if querying resource requirements
if (Pci->Value == Pci->Mask) {
continue;
}
// BAR is being enabled
Compute_Msr_Value(Descr, Pci);
} else {
// Graphics device ignores disabling Command[1] (Issue 118.181)
if (Class == 0x0300) {
if (!(Pci->Flag & IO_BAR)) {
continue;
}
}
// BAR is being disabled
Read_MSR(Descr->MsrAddr, Descr->MsrData);
switch (Descr->Type) {
case USB_LBAR:
Descr->MsrData[1] &= ~2;
break;
case MDD_LBAR:
Descr->MsrData[1] &= ~LBAR_EN;
break;
case EPCI:
break;
case GX2_RCONF:
Descr->MsrData[0] &= ~REGION_EN;
break;
case MPCI_RCONF:
Descr->MsrData[0] &= ~1;
break;
case IOD_SC:
Descr->MsrData[0] &= ~(WEN | REN);
break;
default:
Get_Descriptor_Default(Descr->Type, Descr->MsrData);
break;
}
}
// Write the MSR
Write_MSR(Descr->MsrAddr, Descr->MsrData);
}
}
//***********************************************************************
// Parses a MBD_MSR_ERROR & returns the Status register equivalent.
// NOTE:
// PERR# is not implemented, so MASTER_PARITY_ERROR always reads 0.
//***********************************************************************
ULONG pascal Get_Device_Status(PCI_HEADER_ENTRY * Pci)
{ ULONG MsrAddr, MsrData, Status=0;
// Read MBD_MSR_ERROR
if (MsrAddr = GetMSR()) {
(USHORT)MsrAddr = MBD_MSR_ERROR;
MsrData = Read_MSR_LO(MsrAddr);
if (MsrData & (BME | TASE))
Status |= SIGNALED_TARGET_ABORT; // Status[11]
if (MsrData & TARE)
Status |= RECEIVED_TARGET_ABORT; // Status[12]
if (MsrData & MARE)
Status |= RECEIVED_MASTER_ABORT; // Status[13]
if (MsrData & SYSE)
Status |= SIGNALED_SYSTEM_ERROR; // Status[14]
if (MsrData & PARE)
Status |= DETECTED_PARITY_ERROR; // Status[15]
}
return Status;
}
//***********************************************************************
// Clears error(s) pending on a device according to the Status mask
//***********************************************************************
void pascal Clear_MBus_Error(PCI_HEADER_ENTRY * Pci, ULONG Status)
{ ULONG MsrAddr, MsrData;
// Read MBD_MSR_ERROR
if (MsrAddr = GetMSR()) {
(USHORT)MsrAddr = MBD_MSR_ERROR;
MsrData = Read_MSR_LO(MsrAddr);
// Status[15:11] write-1-to-clear.
// Only clear the MSR bits corresponding to Status[15:11]
MsrData &= ~(TASE | BME | TARE | MARE | SYSE | PARE);
if (Status & SIGNALED_TARGET_ABORT) // Status[11]
MsrData |= TASE | BME;
if (Status & RECEIVED_TARGET_ABORT) // Status[12]
MsrData |= TARE;
if (Status & RECEIVED_MASTER_ABORT) // Status[13]
MsrData |= MARE;
if (Status & SIGNALED_SYSTEM_ERROR) // Status[14]
MsrData |= SYSE;
if (Status & DETECTED_PARITY_ERROR) // Status[15]
MsrData |= PARE;
Write_MSR_LO(MsrAddr, MsrData);
}
}
//***********************************************************************
// Enables/disables bus mastering on a GLIU device
// Returns non-zero if no more bus-master MSRs for this device
//***********************************************************************
UCHAR pascal Update_BusMaster(PCI_HEADER_ENTRY * Pci, UCHAR EnableFlag)
{ register DESCRIPTOR * Descr;
ULONG MsrAddr, MsrData[2];
USHORT Mask;
UCHAR Link, Shift;
switch (Class) {
// Filter out devices that don't affect PAE when Command[2] is changed
case 0x0600: // Bridge: Host
case 0x0601: // Bridge: ISA
case 0x0300: // Graphics
case 0x1010: // AES
return 1;
default:
Link = Pci->Link;
// For each linked item, update the associated MSR
while (Link) {
Descr = &MSRs[Link];
// Get link to next MSR
Link = Descr->Link;
MsrAddr = Descr->MsrAddr;
// Each USB 2.0 device on port 2 has its own bus-master control
if (Descr->Type == USB_LBAR) {
// Modify bus-master control
Read_MSR(MsrAddr, MsrData);
(UCHAR)MsrData[1] &= ~BUS_MASTER;
if (EnableFlag) {
(UCHAR)MsrData[1] |= BUS_MASTER;
}
Write_MSR(MsrAddr, MsrData);
Descr->MsrData[1] = MsrData[1];
return 1;
}
// Only change PAE in MBIU0 & MBIU2
MsrAddr &= ROUTING;
if (MsrAddr == Mbiu0 || MsrAddr == Mbiu2) {
(USHORT)MsrAddr = MBIU_PAE;
// Generate shift count from port #
Shift = 14; // Port 0 is in 8th position (bits 15:14)
if (Descr->Port) {
Shift = (Descr->Port-1) * 2;
}
// Generate mask for PAE MSR. 2 bits/field.
Mask = 3 << Shift;
// Modify bus-master control
Read_MSR(MsrAddr, MsrData);
(USHORT)MsrData[0] &= ~Mask;
if (EnableFlag) {
(USHORT)MsrData[0] |= Mask;
}
Write_MSR(MsrAddr, MsrData);
}
}
break;
}
return 0;
}
//***********************************************************************
// Supports macro SYS_MBUS_DESCRIPTOR.
// Returns the MSR address associated with a virtualized PCI resource.
//***********************************************************************
ULONG pascal Lookup_PCI(USHORT Address)
{ register PCI_HEADER_ENTRY * Pci;
register DESCRIPTOR * Descr;
UCHAR LO_Address, Index=0;
LO_Address = (UCHAR)Address;
// Limit search to PCI BARs and OEM registers
if (((LO_Address >= BAR0) && (LO_Address <= BAR5)) || (LO_Address >= 0x40)) {
Pci = Get_Structure(Address);
if ((USHORT)Pci > UNIMPLEMENTED_REGISTER) {
if (Index = Pci->Link) {
// For OHCI devices, return embedded PCI address
if (Pci->Flag & EPCI_RW ) {
do {
Descr = &MSRs[Index];
if (Descr->Type == EPCI) {
break;
}
} while (Index = Descr->Link);
}
}
}
}
Descr = &MSRs[Index];
return Descr->MsrAddr;
}
//***********************************************************************
// Supports macro SYS_IO_DESCRIPTOR.
// Returns the MSR address associated with an I/O address.
//***********************************************************************
ULONG pascal Lookup_IO(USHORT Address)
{ USHORT Range;
ULONG Addr;
UCHAR Index=0;
Range = 1;
Addr = (ULONG)Address;
Index = Find_Matching_IO_Descriptor(&Addr, &Range, 3);
return MSRs[Index].MsrAddr;
}

View File

@@ -0,0 +1,367 @@
/*
* 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
*/
//******************************************************************************
//* Routines related to the MBus Diverse Device
//******************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "GX2.H"
#include "MDD.H"
#include "PROTOS.H"
#include "DESCR.H"
#include "ACPI.H"
#include "VPCI.H"
#include "PCI.H"
#include "ACPI.H"
#include "CHIPSET.H"
#define A20_EN (A20_P_EN | A20_K_EN)
#define INIT_EN (INIT_K_EN | INIT_P_EN)
// External function prototypes:
void Init_MFGPT(void);
UCHAR pascal ACPI_Trapping(USHORT);
// Local function prototypes:
void pascal Control_MDD_SMI(USHORT, ULONG);
// Local variables:
ULONG MDD_Base;
// External variables:
extern PCI_HEADER_ENTRY ISA_Hdr[];
extern Hardware HardwareInfo;
//***********************************************************************
// Enables/disables KEL SMIs
//***********************************************************************
void pascal Control_KEL_SMI(USHORT EnableFlag)
{
Control_MDD_SMI(EnableFlag, KEL_ASMI_EN);
}
//***********************************************************************
// Enable/disable keyboard command snooping by KEL
//***********************************************************************
void pascal Control_KEL_Snoop(USHORT EnableFlag)
{ ULONG MsrAddr, MsrData;
MsrAddr = MDD_Base;
(USHORT)MsrAddr = MSR_KEL_CNTRL;
MsrData = Read_MSR_LO(MsrAddr);
if (EnableFlag) {
MsrData |= KEL_SNOOP;
} else {
MsrData &= ~KEL_SNOOP;
}
Write_MSR_LO(MsrAddr, MsrData);
}
//***********************************************************************
// Initializes the MBus Diverse Device
//***********************************************************************
void Init_MDD(void)
{ ULONG MsrAddr;
USHORT ACPI_Bar;
UCHAR i;
// Find address of MBus Diverse Device
MsrAddr = MDD_Base = Find_MBus_ID(ID_MDD, 1) & 0xFFFF0000;
//*********************************************
// Record MDD's LBARs in MSRs[]
//*********************************************
for (i = MSR_LBAR_IRQ; i <= MSR_LBAR_FLSH3; i++) {
(UCHAR)MsrAddr = i;
if (Init_Descr(MDD_LBAR, MsrAddr)) {
break;
}
}
// Clear PM1_STS
(UCHAR)MsrAddr = ISA_Hdr[BAR5/4].LBar;
ACPI_Bar = (USHORT)Read_MSR_LO(MsrAddr);
out_16(ACPI_Bar, in_16(ACPI_Bar));
// Initialize KEL
// Enable keyboard snooping by KEL
Control_KEL_Snoop(1);
// Enable SMIs from:
// - A20 & Init (keyboard and port 92h)
// - KEL
// - Extended PIC Mapper
Control_MDD_SMI(1, A20_EN | INIT_EN | PIC_ASMI_EN | KEL_ASMI_EN);
// Initialize the MFGPT
Init_MFGPT();
// Clear any pending PIC events
(USHORT)MsrAddr = MBD_MSR_SMI;
Write_MSR_HI(MsrAddr, PIC_ASMI_EN);
}
//***********************************************************************
// Implements CS5536's F0 Special Cycles.
// Linked to MDD's MSR_LEG_IO[31].
//
// When set, a Shutdown special cycle causes a reset. When the Special
// Cycles bit is cleared, a Shutdown special cycle is ignored. Before
// updating MSR_LEG_IO, VSA will check MSR_ERR[15] and MSR_SMI[1]. If
// either of these MSR bits are set, then no action is taken. It will
// be assumed that a debugger is in use and VSA will not interfere.
//***********************************************************************
void pascal Update_Special_Cycles(USHORT EnableFlag)
{ ULONG MSR_Addr, MSR_Data;
// If either MSR_ERR[15] and MSR_SMI[1] is set, then bail.
if (Read_MSR_LO(MDD_Base + MBD_MSR_SMI) & 2) {
return;
}
if (Read_MSR_LO(MDD_Base + MBD_MSR_ERROR) & 0x8000) {
return;
}
// Link MSR_LEG_IO[RESET_SHUT_EN] to COMMAND[3]
MSR_Addr = MDD_Base + MSR_LEG_IO;
MSR_Data = Read_MSR_LO(MSR_Addr);
if (EnableFlag) {
MSR_Data |= RESET_SHUT_EN;
} else {
MSR_Data &= ~RESET_SHUT_EN;
}
Write_MSR_LO(MSR_Addr, MSR_Data);
}
//***********************************************************************
// Enable/disable of MDD ASMI(s)
//***********************************************************************
void pascal Control_MDD_SMI(USHORT EnableFlag, ULONG EnableMask)
{ ULONG MsrAddr, MsrData;
MsrAddr = MDD_Base;
(USHORT)MsrAddr = MBD_MSR_SMI;
MsrData = Read_MSR_LO(MsrAddr);
if (EnableFlag) {
MsrData |= EnableMask;
} else {
MsrData &= ~EnableMask;
}
Write_MSR_LO(MsrAddr, MsrData);
}
//***********************************************************************
// Clears the ACPI Status register
// This routine fills in MsgPacket[0] = ACPI GPE0_STS
// and MsgPacket[1] bits[15:0] = ACPI PM1_STS
//***********************************************************************
USHORT Get_ACPI_Status(ULONG *msgp)
{ USHORT ACPI_Bar, PM1_Status;
ULONG GPE_Status;
UCHAR Flag;
// Disable ACPI trapping
Flag = ACPI_Trapping(0);
// Get ACPI Status
ACPI_Bar = ISA_Hdr[BAR5/4].Value_LO;
(UCHAR)ACPI_Bar = GPE0_STS_OFS;
GPE_Status = in_32(ACPI_Bar);
// Don't clear PIC status
GPE_Status &= ~1;
msgp[1] = GPE_Status;
(UCHAR)ACPI_Bar = PM1_STS_OFS;
PM1_Status = in_16(ACPI_Bar);
// Enable ACPI trapping
if (Flag) {
ACPI_Trapping(1);
}
msgp[2] = (ULONG)PM1_Status;
return (PM1_Status || GPE_Status);
}
//***********************************************************************
// Enable PM logic
//***********************************************************************
void Enable_PME_Event(UCHAR EnableFlag, UCHAR Pm1Bit, UCHAR PmeBit, USHORT Attributes)
{ ULONG Gpe, Pm1, bmGPE0;
USHORT ACPI_Bar, bmPM1;
UCHAR Flag;
static UCHAR pme_instance = 0;
static UCHAR PM1_Instance[11] = {0,0,0,0,0,0,0,0,0,0,0};
static UCHAR PME_Instance[8] = {0,0,0,0,0,0,0,0};
static ULONG GPE0_Masks[] = { // Maps PME # to GPE0 bits
0x00010000,
0x00020000,
0x00040000,
0x00080000,
0x00100000,
0x00200000,
0x40000000,
0x80000000,
};
bmPM1 = 0;
bmGPE0 = 0L;
if (Attributes & PM1) {
bmPM1 = 1 << Pm1Bit;
if (EnableFlag) {
PM1_Instance[Pm1Bit]++;
} else {
if (PM1_Instance[Pm1Bit]) {
// If there are still registrations for this PM1 bit...
if (--PM1_Instance[Pm1Bit]) {
// then don't turn disable it
return;
}
} else {
// Error:
return;
}
}
}
if (Attributes & GPE) {
bmGPE0 = GPE0_Masks[PmeBit];
if (EnableFlag) {
PME_Instance[PmeBit]++;
} else {
if (PME_Instance[PmeBit]) {
// If there are still registrations for this GEP0 bit...
if (--PME_Instance[PmeBit]) {
// then don't turn disable it
return;
}
} else {
// Error:
return;
}
}
}
if (!(Attributes & NO_ASMI)) {
// Keep a count of PME events.
// Once all have been de-registered, turn off PM_ASMI bit.
if (EnableFlag) {
if (Attributes & PME) {
pme_instance++;
}
// Enable ASMIs from Power Management logic
Control_MDD_SMI(EnableFlag, PM_ASMI_EN);
} else {
if (Attributes & PME) {
if (pme_instance != 0) {
if (--pme_instance == 0) {
// Disable ASMIs from Power Management logic
Control_MDD_SMI(0, PM_ASMI_EN);
}
}
}
}
}
// See if we want to enable the approriate bits in PM1_EN and GPE0_EN
// if set to NO_ENALE we don't enable (Used by ACPI as the OS controls)
if (!(Attributes & NO_ENABLE)) {
// Disable ACPI trapping
Flag = ACPI_Trapping(0);
// Get ACPI base address
ACPI_Bar = ISA_Hdr[BAR5/4].Value_LO;
if (bmPM1) {
// Must do 32-bit I/O to avoid shadow register bug (IAeng00003062)
(UCHAR)ACPI_Bar = 0x00;
Pm1 = in_32(ACPI_Bar);
if (EnableFlag) {
Pm1 |= (ULONG)bmPM1 << 16;
} else {
Pm1 &= ~((ULONG)bmPM1 << 16);
}
out_32(ACPI_Bar, Pm1);
// Serialize the previous I/O write
in_16(ACPI_Bar);
// Clear spurious status
(UCHAR)ACPI_Bar = PM1_STS_OFS;
out_32(ACPI_Bar, (ULONG)Pm1);
}
if (bmGPE0) {
(UCHAR)ACPI_Bar = GPE0_EN_OFS;
Gpe = in_32(ACPI_Bar);
if (EnableFlag) {
Gpe |= bmGPE0;
} else {
Gpe &= ~bmGPE0;
}
out_32(ACPI_Bar, Gpe);
// Serialize the previous I/O write
in_32(ACPI_Bar);
// Clear spurious status
(UCHAR)ACPI_Bar = GPE0_STS_OFS;
out_32(ACPI_Bar, Gpe);
}
// Serialize the previous I/O write
in_32(ACPI_Bar);
// Re-enable ACPI trapping
if (Flag) {
ACPI_Trapping(1);
}
}
}

View File

@@ -0,0 +1,226 @@
/*
* 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
*/
// ATA
#define MSR_LBAR_ATA 0x0008
// Diverse Integration Logic
#define MSR_MAST_CONF 0x0001
#define NON_COH_RD (1L << 12)
#define NON_COH_WR (1L << 13)
#define LBAR_EN (1 << 0)
#define NOR_NAND (1 << 1)
#define MEM_IO (1 << 2)
#define LBAR_IO_MASK 0x0001FFF0
#define LBAR_MEM_MASK 0xFFFFF000
#define MSR_LBAR_IRQ 0x0008
#define MSR_LBAR_KEL1 0x0009
#define MSR_LBAR_KEL2 0x000A
#define MSR_LBAR_SMB 0x000B
#define MSR_LBAR_GPIO 0x000C
#define GPIO_LOW_BANK_SELECT 0x00
#define GPIO_HIGH_BANK_SELECT 0x80
#define GPIO_OUTPUT_VALUE 0x00
#define GPIO_OUTPUT_ENABLE 0x04
#define GPIO_OUTPUT_OPENDRAIN 0x08
#define GPIO_OUTPUT_INVERT 0x0C
#define GPIO_OUT_AUX1_SELECT 0x10
#define GPIO_OUT_AUX2_SELECT 0x14
#define GPIO_PULLUP_ENABLE 0x18
#define GPIO_PULLDOWN_ENABLE 0x1C
#define GPIO_INPUT_ENABLE 0x20
#define GPIO_INPUT_INVERT 0x24
#define GPIO_IN_FILTER_ENABLE 0x28
#define GPIO_IN_EVENTCOUNT 0x2C
#define GPIO_READ_BACK 0x30
#define GPIO_IN_AUX1_SELECT 0x34
#define GPIO_EVENTS_ENABLE 0x38
#define GPIO_LOCK_ENABLE 0x3C
#define LKOV (1 < 0)
#define LKOE (1 < 1)
#define LKOD (1 < 2)
#define LKOI (1 < 3)
#define LKA1 (1 < 4)
#define LKA2 (1 < 5)
#define LKPU (1 < 6)
#define LKPD (1 < 7)
#define LKIE (1 < 8)
#define LKII (1 < 9)
#define LKFE (1 < 10)
#define LKEE (1 < 11)
#define LKIA (1 < 12)
#define LKIP (1 < 13)
#define LKPE (1 < 14)
#define LKNE (1 < 15)
#define GPIO_POSEDGE_ENABLE 0x40
#define GPIO_NEGEDGE_ENABLE 0x44
#define GPIO_POSEDGE_STATUS 0x48
#define GPIO_NEGEDGE_STATUS 0x4C
// GPIO IRQ Mapper
#define GPIO_MAPPER_X 0xE0
#define GPIO_MAPPER_Y 0xE4
#define GPIO_MAPPER_Z 0xE8
#define GPIO_MAPPER_W 0xEC
// Digital Filter
#define GPIO_FILTER_AMOUNT 0x50
#define GPIO_FILTER_COUNT 0x52
#define GPIO_EVENT_COUNT 0x54
#define GPIO_EVENT_COMPARE 0x56
#define GPIO6_FILTER_AMOUNT 0xD0
#define GPIO7_FILTER_AMOUNT 0xD8
#define GPIO_FILTER_SELECT0 0xF0
#define GPIO_FILTER_SELECT1 0xF1
#define GPIO_FILTER_SELECT2 0xF2
#define GPIO_FILTER_SELECT3 0xF3
#define GPIO_FILTER_SELECT4 0xF4
#define GPIO_FILTER_SELECT5 0xF5
#define GPIO_FILTER_SELECT6 0xF6
#define GPIO_FILTER_SELECT7 0xF7
#define MSR_LBAR_MFGPT 0x000D
// I/O offsets relative to MFGPT LBAR
#define MFGPT_CMP1 0x00
#define MFGPT_CMP2 0x02
#define MFGPT_COUNTER 0x04
#define MFGPT_SETUP 0x06
#define MFGPT_OFFSET 8
#define MSR_LBAR_ACPI 0x000E
#define MSR_LBAR_PMS 0x000F
#define MSR_LBAR_FLSH0 0x0010
#define MSR_LBAR_FLSH1 0x0011
#define MSR_LBAR_FLSH2 0x0012
#define MSR_LBAR_FLSH3 0x0013
#define MSR_LEG_IO 0x0014
#define RESET_SHUT_EN (0x80000000L)
#define UART1_SHIFT (16)
#define UART2_SHIFT (20)
#define UART_MASK (0x07)
#define UART_IO_MASK (0x03)
#define UART_EN (0x04)
#define MSR_PIN_OPTS 0x0015
#define PIN_OPT_IDE (1 << 0)
#define MSR_SOFT_IRQ 0x0016
#define MSR_SOFT_RESET 0x0017
#define MSR_AC_DMA 0x0019
#define MSR_KEL_CNTRL 0x001F
#define KEL_SNOOP (1 << 0)
#define KEL_EER (1 << 1)
#define KEL_PRTA_EN (1 << 4)
// IRQ Mask & Mapper (from MDD Specification)
#define MSR_IRQM_YLOW 0x0020
#define MSR_IRQM_YHIGH 0x0021
#define MSR_IRQM_ZLOW 0x0022
#define MSR_IRQM_ZHIGH 0x0023
#define MSR_IRQM_PRIM 0x0024
#define MSR_IRQM_LPC 0x0025
#define MSR_IRQM_LXIRR 0x0026
#define MSR_IRQM_HXIRR 0x0027
#define MSR_MFGPT_IRQ 0x0028
#define MSR_MFGPT_NR 0x0029
#define MSR_MFGPT_CLR_SETUP 0x002B
#define MSR_FLOP_S3F2 0x0030
#define MSR_FLOP_S3F7 0x0031
#define MSR_FLOP_S372 0x0032
#define MSR_FLOP_S377 0x0033
#define MSR_PIC_SHADOW 0x0034
#define MSR_PIT_SHADOW 0x0036
// UART's
#define MSR_UART1_MOD 0x0038
#define MSR_UART1_DONG 0x0039
#define MSR_UART1_CONF 0x003A
#define UART_SOFT_RESET (0x01L)
#define UART_DEVEN (0x02L)
#define UART_FREEZE (0x04L)
#define UART_TEST (0x08L)
#define UART_EXT_BANKS (0x10L)
#define MSR_UART2_MOD 0x003C
#define MSR_UART2_DONG 0x003D
#define MSR_UART2_CONF 0x003E
#define MSR_DMA_MAP 0x0040
#define MSR_DMA_SHAD0 0x0041
#define MSR_DMA_SHAD1 0x0042
#define MSR_DMA_SHAD2 0x0043
#define MSR_DMA_SHAD3 0x0044
#define MSR_DMA_SHAD4 0x0045
#define MSR_DMA_SHAD5 0x0046
#define MSR_DMA_SHAD6 0x0047
#define MSR_DMA_SHAD7 0x0048
#define MSR_DMA_MSK_SHAD 0x0049
// LPC
#define MSR_LPC_SIRQ 0x004E
// MSR_SMI
#define HLT_ASMI_EN (1L << 0)
#define SHUTDOWN_ASMI_EN (1L << 1)
#define KEL_ASMI_EN (1L << 2)
#define PIC_ASMI_EN (1L << 3)
#define PM_ASMI_EN (1L << 4)
#define INIT_K_EN (1L << 5)
#define A20_P_EN (1L << 6)
#define INIT_P_EN (1L << 7)
#define UART1_SSMI_EN (1L << 8)
#define UART2_SSMI_EN (1L << 9)
#define RESERVED_EN (1L << 10)
#define LPC_SSMI_EN (1L << 11)
#define DMA_SSMI_EN (1L << 12)
#define A20_K_EN (1L << 13)
#define PM2_CNT_SSMI_EN (1L << 14)
#define PM1_CNT_SSMI_EN (1L << 15)
#define HLT_ASMI_STAT (1L << 32)
#define SHUTDOWN_ASMI_STAT (1L << 33)
#define KEL_ASMI_STAT (1L << 34)
#define PIC_ASMI_STAT (1L << 35)
#define PM_ASMI_STAT (1L << 36)
#define INIT_K_STAT (1L << 37)
#define A20_P_STAT (1L << 38)
#define INIT_P_STAT (1L << 39)
#define UART1_SSMI_STAT (1L << 40)
#define UART2_SSMI_STAT (1L << 41)
#define RESERVED_STAT (1L << 42)
#define LPC_SSMI_STAT (1L << 43)
#define DMA_SSMI_STAT (1L << 44)
#define A20_K_STAT (1L << 45)
#define PM2_CNT_SSMI_STAT (1L << 46)
#define PM1_CNT_SSMI_STAT (1L << 47)

View File

@@ -0,0 +1,393 @@
;
; 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
;
;* Function: *
;* Implements message handling routines
include SYSMGR.INC
include VSA2.INC
.model tiny,c
.586p
.CODE
externdef SysMgr_VSM: dword
externdef MsgPacket: dword
externdef VSM_ListHead: dword
externdef Current_VSM: dword
externdef Events: EVENT_ENTRY
externdef Sys_Exit: proc
externdef pascal Schedule_VSM: proc
;***********************************************************************
; This routine is called from the System Manager to enter a message
; packet into a VSM's message queue.
;
; Input:
; To_VSM = Flat ptr to VSM to which message is to be sent
; MsgCode = Priority::Message
; From_VSM = value to be put in Async_VSM field
; MsgPacket contains the message parameters
;***********************************************************************
Send_Message proc pascal uses di si \
From_VSM: dword, \
To_VSM: dword, \
MsgCode: dword
mov edi, [To_VSM]
cmp edi, [SysMgr_VSM] ; Don't send messages to SysMgr
je short Exit
mov eax, [MsgCode]
lea si, [MsgPacket]
mov ebx, [From_VSM]
call Insert_Msg
Exit: ret
Send_Message endp
;***********************************************************************
; This routine enters a message packet into a VSM's message queue.
;
; Input:
; EAX = Priority::Message
; EBX = From_VSM
; EDI = To_VSM
; SI = Ptr to message packet
;***********************************************************************
Insert_Msg proc
cld
push ebx ; Save From_VSM
; Get ptr to the head of the message queue
movzx ebx, fs:(VSM_Header PTR [edi]).SysStuff.Qhead
; Compute ptr to the next available message queue entry
lea dx, [bx+sizeof(Message)]
cmp dx, fs:(VSM_Header PTR [edi]).SysStuff.EndMsgQ
jb short Check_Q_Overflow
mov dx, OFFSET VSM_Header.SysStuff.MsgQueue
Check_Q_Overflow:
; Is Qhead == Qtail ?
cmp dx, fs:(VSM_Header PTR [edi]).SysStuff.Qtail
jne short UpdateQueueHead
; Yes, then message queue has overflowed
mov [si+8], eax ; Store previous message into Param2
mov ax, MSG_QUEUE_OVERFLOW ; Replace previous message
mov dx, bx ; Qhead = old Qhead
UpdateQueueHead:
mov fs:(VSM_Header PTR [edi]).SysStuff.Qhead, dx
pop edx ; From_VSM
push edi ; Parameter to Schedule_VSM() below
; Store the message into the VSM's message queue.
; NOTE: This code is dependent on "#typedef Message"
add edi, ebx
stosd [edi] ; Priority::Message
mov eax, edx ; From_VSM
stosd [edi]
REPEAT MAX_MSG_PARAM
lodsd ; Copy parameters to message queue
stosd [edi]
ENDM
; Sort messages by Priority
if SUPPORT_PRIORITY
pop ebx ; To_VSM
push ebx
push fs:(VSM_Header PTR [ebx]).SysStuff.Qhead
BubbleSort:
; Get ptr to latest queue entry
movzx esi, fs:(VSM_Header PTR [ebx]).SysStuff.Qhead
sub esi, sizeof(Message)
cmp si, OFFSET VSM_Header.SysStuff.MsgQueue
jae short @f
mov si, fs:(VSM_Header PTR [ebx]).SysStuff.EndMsgQ
sub si, sizeof(Message)
@@:
cmp si, fs:(VSM_Header PTR [ebx]).SysStuff.Qtail
je Bail
; Get ptr to previous queue entry
lea edi, [esi-sizeof(Message)]
cmp di, OFFSET VSM_Header.SysStuff.MsgQueue
jae short @f
mov di, fs:(VSM_Header PTR [ebx]).SysStuff.EndMsgQ
sub di, sizeof(Message)
@@:
mov fs:(VSM_Header PTR [ebx]).SysStuff.Qhead, di
; Add VSM base to ptrs
add edi, ebx
add esi, ebx
; Compare their priorities
mov ax, fs:(Message PTR [esi]).Priority
cmp ax, fs:(Message PTR [edi]).Priority
jbe short Bail
; Swap the entries in the message queue
mov cx, sizeof(Message)/4 ; Assumes entry is multiple of dword
Interchange:
mov eax, fs:[edi]
xchg fs:[esi], eax
stosd [edi]
add esi, 4
loop Interchange
jmp BubbleSort
Bail:
pop fs:(VSM_Header PTR [ebx]).SysStuff.Qhead
endif
; Schedule the VSM to execute
pop eax
cmp eax, [SysMgr_VSM]
je short Exit
push eax
call Schedule_VSM
Exit:
ret
Insert_Msg endp
;************************************************************************
;
; Sends a message to each VSM of type VSM_Type (or all if VSM_ANY).
; Called from HANDLERS.C
;
;************************************************************************
Broadcast_Message proc pascal uses si di \
MsgCode: word, \
VSM_Type: word, \
From_VSM: dword
mov edi, [VSM_ListHead] ; Get ptr to list of VSMs
VSM_Loop:
or edi, edi ; End of VSM list ?
jz Exit_Broadcast
mov dx, [VSM_Type]
mov ah, fs:(VSM_Header PTR [edi]).VSM_Type
cmp dl, VSM_ANY ; Schedule all VSMs ?
je Schedule_It
test dh, (VSM_ALL_EXCEPT SHR 8)
jz CheckType
cmp dl, ah ; Skip the one that matches
je Skip_VSM
jmp Schedule_It
CheckType:
cmp dl, ah ; Is it the correct VSM ?
jne Skip_VSM
Schedule_It:
cmp edi, [From_VSM] ; Is it the requesting VSM ?
je Skip_VSM ; Yes, don't send to sender
push edi
movzx eax, [MsgCode] ; Send the message
xor ebx, ebx
lea si, [MsgPacket]
; EAX = Priority::Message
; EBX = 00000000h (a broadcast is not a synchronous event)
; SI = Ptr to message packet
; EDI = Ptr to VSM header where message is to be sent
call Insert_Msg
pop edi
Skip_VSM:
mov edi, fs:(VSM_Header PTR [edi]).SysStuff.Flink
jmp VSM_Loop
Exit_Broadcast:
ret
Broadcast_Message endp
;************************************************************************
; Broadcasts a message to one or more VSMs.
;
; Input:
; EBX = message code (16 MSBs)
; BH = Flags
; BL = VSM_Type
; ECX = Param1
; ESI = Param2
; EDI = Param3
;************************************************************************
Sys_Broadcast proc
mov dx, bx ; Put VSM_Type::Flags into DX
shr ebx, 16 ; Put message into BX
mov eax, esi
lea si, [MsgPacket]
mov [si+0], ecx
mov [si+4], eax
mov [si+8], edi
; Re-schedule the broadcasting VSM
; RunFlag will be changed from RUN_FLAG_ACTIVE to RUN_FLAG_READY
mov edi, [Current_VSM]
push edi
call Schedule_VSM
; If RunFlag == RUN_FLAG_READY, Insert_Msg() won't schedule it again
mov fs:(VSM_Header PTR [edi]).SysStuff.RunFlag, RUN_FLAG_BLOCKED
; Push parameters for call to Broadcast_Message()
push bx ; Message code
push dx ; VSM type
push edi ; From_VSM
; Normally, the message is sent to the broadcasting VSM
; after all VSMs have handled the broadcasted message.
; There are two exceptions to this rule:
; 1) VSM_NOT_SELF | <VSM type>
; 2) VSM_ALL_EXCEPT | <self>
test dh, (VSM_NOT_SELF SHR 8)
jnz short Broadcast
test dh, (VSM_ALL_EXCEPT SHR 8)
jz short SendToSelf
cmp dl, fs:(VSM_Header PTR [edi]).VSM_Type
je short Broadcast
SendToSelf:
; Put callback address onto the scheduler stack
mov eax, OFFSET BroadcastCallback
push eax
call Schedule_VSM
mov ax, BROADCAST_PRIORITY ; EAX = Priority::Message
shl eax, 16
mov ax, bx
mov edi, [SysMgr_VSM] ; EDI = To_VSM
mov ebx, [Current_VSM] ; EBX = From_VSM
call Insert_Msg
Broadcast:
call Broadcast_Message
jmp Sys_Exit ; Exit w/o scheduling current VSM
Sys_Broadcast endp
;************************************************************************
; Control comes here when all VSMs have processed the broadcasted message.
; Copies the broadcasted message from SysMgr's message queue to the
; broadcasting VSM's message queue.
;************************************************************************
BroadcastCallback proc
ASSUME DI: PTR VSM_Header
ASSUME BX: PTR Message
; Point BX to parameters in SysMgr's message queue head
xor di, di
mov bx, [di].SysStuff.Qhead
sub bx, sizeof(Message)
cmp bx, OFFSET VSM_Header.SysStuff.MsgQueue
jb short BadMsgStack
mov [di].SysStuff.Qhead, bx
mov eax, dword ptr [bx].Msg ; Get Priority::Message
mov edi, [bx].From_VSM ; To_VSM (the VSM it was originally from)
lea si, [bx].Param
xor ebx, ebx ; From_VSM (asynchronous)
call Insert_Msg
BadMsgStack:
ret
ASSUME BX: NOTHING
ASSUME DI: NOTHING
BroadcastCallback endp
;***********************************************************************
; Passes an event to the next VSM registered for this event
; NOTE: This system call is now obsolete.
;***********************************************************************
Sys_PassEvent proc
jmp Sys_Exit ; Exit to VSM dispatcher
Sys_PassEvent endp
END

View File

@@ -0,0 +1,500 @@
/*
* 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
*/
//*****************************************************************************
//* This file contains code specific to CS5536 MFGPTs
//*****************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#include "MDD.H"
#include "MAPPER.H"
#include "TIMER.H"
// External variables:
extern ULONG MDD_Base;
// Local variables:
USHORT MFGPT_Base=0;
ULONG MFGPT_LBAR[2];
// NOTE: Timers that use the 32KHz clock interfere with LPC DMA (see PBZ 709)
// Clock Prescalar Period
#define TIMER_SETUP (MFGPT_SCALE_1K | MFGPT_CMP1MODE | MFGPT_CLK_SEL) // 14 MHz 1024 71 us
#define STDBY_SETUP (MFGPT_SCALE_32 | MFGPT_CMP1MODE) // 32 KHz 32 1 ms
#define PWM_SETUP (MFGPT_SCALE_32 | MFGPT_CMP1GE) // 32 KHz 32 1 ms
TIMERS TimerInfo[] = {
// # Z Mapper Setup
// Save for OS (Linux) use { 0, Z_IRQ_MFGPT_04, PWM_SETUP},
{ 1, Z_IRQ_MFGPT_15, PWM_SETUP},
{ 2, Z_IRQ_MFGPT_26, PWM_SETUP},
{ 3, Z_IRQ_MFGPT_37, TIMER_SETUP},
// Save for OS (Linux) use { 4, Z_IRQ_MFGPT_04, TIMER_SETUP},
{ 5, Z_IRQ_MFGPT_15, TIMER_SETUP},
{ 6, Z_IRQ_MFGPT_26, STDBY_SETUP},
{ 7, Z_IRQ_MFGPT_37, PWM_SETUP},
};
#define NUM_MFGPTS (sizeof(TimerInfo)/sizeof(TIMERS)) // Number of MFGPTs available
//************************************************************************************
// Saves the MFGPT LBAR setting and enables the LBAR
//************************************************************************************
void Enable_MFGPT_LBAR()
{ ULONG Tmp;
int i;
// Get MFGPT LBAR
Read_MSR(MDD_Base + MSR_LBAR_MFGPT, MFGPT_LBAR);
// Has the MFGPT base address changed?
if (MFGPT_Base != (USHORT)MFGPT_LBAR[0]) {
// Yes, record the new base address of MFGPT
MFGPT_Base = (USHORT)MFGPT_LBAR[0];
// Update the individual timer base addresses
for (i = 0; i < NUM_MFGPTS; i++) {
TimerInfo[i].TimerBase = MFGPT_Base + TimerInfo[i].Timer*MFGPT_OFFSET;
}
}
// Save the current LBAR enable
Tmp = MFGPT_LBAR[1];
// Enable the LBAR
MFGPT_LBAR[1] |= LBAR_EN;
Write_MSR(MDD_Base + MSR_LBAR_MFGPT, MFGPT_LBAR);
MFGPT_LBAR[1] = Tmp;
}
//************************************************************************************
// Restores the MFGPT LBAR
//************************************************************************************
void Restore_MFGPT_LBAR()
{
// Restore MFGPT LBAR
Write_MSR(MDD_Base + MSR_LBAR_MFGPT, MFGPT_LBAR);
}
//************************************************************************************
// Checks for MFGPT events
// Returns a mask of which timer(s) have expired
//************************************************************************************
USHORT CS5536_MFGPT_Handler(void)
{ USHORT Setup, Status, Accum_Status=0, i;
register TIMERS * TimerPtr;
Enable_MFGPT_LBAR();
for (i = 0; i < NUM_MFGPTS; i++) {
TimerPtr = &TimerInfo[i];
// Get timer status
Setup = TimerPtr->TimerBase + MFGPT_SETUP;
Status = in_16(Setup);
if (Status & MFGPT_INITED) {
out_16(Setup, Status);
}
// Check if MFGPT is reserved for EVENT_PWM
if(TimerPtr->Setup == PWM_SETUP) {
continue;
}
// If timer is enabled and expired...
Status &= MFGPT_ENABLE | MFGPT_COMPARE1;
if (Status == (MFGPT_ENABLE | MFGPT_COMPARE1)) {
// disable the timer
out_16(Setup, Status & (~MFGPT_ENABLE));
// record timer event
Accum_Status |= TimerPtr->Mask;
}
}
// Restore the MFGPT LBAR
Restore_MFGPT_LBAR();
return Accum_Status;
}
//************************************************************************************
// Initializes a single MFGPT
//************************************************************************************
void Init_Timer(TIMERS * TimerPtr)
{ USHORT Setup, TimerKHz;
ULONG MicrosPerCount;
TimerPtr->TimerBase = MFGPT_Base + TimerPtr->Timer*MFGPT_OFFSET;
TimerPtr->Mask = 1 << TimerPtr->Timer;
Setup = TimerPtr->Setup;
// Compute microseconds / tick
MicrosPerCount = 1000L << (Setup & 0xF);
TimerKHz = 32;
if (Setup & MFGPT_CLK_SEL) {
TimerKHz = 14318;
}
TimerPtr->Period = (USHORT)(MicrosPerCount / TimerKHz);
// Initialize the timer
out_16(TimerPtr->TimerBase + MFGPT_SETUP, Setup);
// NOTE: Counter resets to 0 when Counter == Comparator2 register
out_32(TimerPtr->TimerBase + MFGPT_CMP1, 0xFFFFFFFF);
}
//***********************************************************************
// Marks a MFGPT as available
//***********************************************************************
void pascal MarkTimerAvailable(USHORT Timer)
{ USHORT i;
for (i = 0; i < NUM_MFGPTS; i++) {
if (TimerInfo[i].Timer == Timer) {
TimerInfo[i].Interval = 0x00000000;
return;
}
}
Log_Error("Invalid timer: %d.", Timer);
}
//************************************************************************************
// Initializes the MFGPT timers to be used for EVENT_TIMER
//************************************************************************************
void Init_MFGPT(void)
{ ULONG MsrAddr, IRQ_Enables;
USHORT i;
register TIMERS * TimerPtr;
Enable_MFGPT_LBAR();
// Get current MFGPT IRQ mask
MsrAddr = MDD_Base;
(USHORT)MsrAddr = MSR_MFGPT_IRQ;
IRQ_Enables = Read_MSR_LO(MsrAddr);
for (i = 0; i < NUM_MFGPTS; i++) {
TimerPtr = &TimerInfo[i];
// Initialize a MFGPT
Init_Timer(TimerPtr);
// Mark timer as available
MarkTimerAvailable(TimerPtr->Timer);
// Route Compare 1 events to SMI
IRQZ_Mapper(TimerPtr->Mapper, 2);
// Enable timer event
IRQ_Enables |= TimerPtr->Mask;
}
// Restore the MFGPT LBAR
Restore_MFGPT_LBAR();
// Enable MFGPT SMIs
Write_MSR_LO(MsrAddr, IRQ_Enables);
}
//***********************************************************************
// Disables a millisecond timer
//***********************************************************************
void DisableMsTimer_5536(USHORT Timer)
{ USHORT Setup, i;
Enable_MFGPT_LBAR();
for (i = 0; i < NUM_MFGPTS; i++) {
if (TimerInfo[i].Timer == Timer) {
// Mark timer as available
MarkTimerAvailable(Timer);
// Clear timer event and disable timer
Setup = TimerInfo[i].TimerBase + MFGPT_SETUP;
out_16(Setup, MFGPT_COMPARE1 | MFGPT_COMPARE2);
break;
}
}
// Restore the MFGPT LBAR
Restore_MFGPT_LBAR();
}
//***********************************************************************
// Allocates a h/w timer for the specified interval
// Returns the timer # allocated else 0xFFFF
//***********************************************************************
USHORT AllocateTimer_5536(ULONG Interval, UCHAR Attributes)
{ UCHAR i, Exact = 0, Unused=0, Compat=0, Mask;
register TIMERS * TimerPtr;
// Find the MFGPT whose timebase is the best-match
for (i = 0; i < NUM_MFGPTS; i++) {
TimerPtr = &TimerInfo[i];
// Don't use timers reserved for EVENT_PWM
if (TimerPtr->Setup == PWM_SETUP) {
continue;
}
if (Attributes & (FOR_STANDBY >> 24)) {
// Timers used for PM must be in the 32 KHz domain
if (TimerPtr->Setup & MFGPT_CLK_SEL) {
continue;
}
} else {
if (TimerPtr->Timer >= 6) {
// Timers 6 & 7 are reserved for PM
continue;
}
}
Mask = (UCHAR)TimerPtr->Mask;
// Is timer unused?
if (TimerPtr->Interval == 0x00000000) {
Unused |= Mask;
}
// Is timebase a perfect match?
if ((Interval*1000 % TimerPtr->Period) == 0) {
Exact |= Mask;
}
// Is timebase compatible?
if (Interval*1000 >= TimerPtr->Period) {
Compat |= Mask;
}
}
// Is there an UNUSED timer whose timebase is an exact match?
if (!(Mask = (Unused & Exact))) {
// No, is there an UNUSED timer that is compatible?
if (!(Mask = (Unused & Compat))) {
// No, is there ANY timer whose timebase is an exact match?
if (!(Mask = Exact)) {
// No, is there ANY timer that is compatible?
if (!(Mask = Compat)) {
// No timers are available
return 0xFFFF;
}
}
}
}
// Return the MFGPT index
Mask = 1 << BitScanReverse(Mask);
for (i = 0; i < NUM_MFGPTS; i++) {
if (TimerInfo[i].Mask == Mask) {
return i;
}
}
return 0xFFFF;
}
//***********************************************************************
// Enables a millisecond timer
//***********************************************************************
UCHAR EnableMsTimer_5536(ULONG Interval, UCHAR Attributes)
{ USHORT i, Count, TimerBase;
ULONG MsrAddr, IRQ_Enables, TotalCounts, Roundoff;
register TIMERS * TimerPtr;
// Get current MFGPT IRQ mask
MsrAddr = MDD_Base;
(USHORT)MsrAddr = MSR_MFGPT_IRQ;
IRQ_Enables = Read_MSR_LO(MsrAddr);
// Allocate a h/w timer
i = AllocateTimer_5536(Interval, Attributes);
if (i == 0xFFFF) {
Log_Error("Attempt to enable %d ms timer interval failed", Interval);
return 0;
}
TimerPtr = &TimerInfo[i];
// A timer was allocated, is it already in use?
if (TimerPtr->Interval) {
// Yes, does it need to be reprogrammed?
if (Interval > TimerPtr->Interval) {
// No, but since the timer has already been running for an
// indeterminate period, the 1st interval will be shortened.
return (UCHAR)TimerPtr->Timer;
}
}
if (Interval) {
Enable_MFGPT_LBAR();
// Get I/O address of this timer
TimerBase = TimerPtr->TimerBase;
// The MFGPT document specifies the following sequence in order
// to prevent any spurious resets, interrupt, or output events:
// - Set Counter Enable bit to 0.
// - Clear SMI enable in MSR_MFGPT_IRQ
// - Update Count as desired
// - When updates are completed, clear event bits
// - Set SMI enable in MSR_MFGPT_IRQ
// - Set Counter Enable bit to 1
// Does this timer need to be initialized again (e.g. after S3) ?
if (!(in_16(TimerBase + MFGPT_SETUP) & MFGPT_INITED)) {
// Initialize the timer
Init_Timer(TimerPtr);
}
// Set Counter Enable to 0
out_16(TimerBase + MFGPT_SETUP, 0);
// Disable SMIs
Write_MSR_LO(MsrAddr, 0x00000000);
// Scale the interval appropriately
Roundoff = 0;
if (TimerPtr->Period < 1000) {
Roundoff = TimerPtr->Period;
}
TotalCounts = (Interval*1000 + Roundoff)/TimerPtr->Period;
Count = (USHORT)TotalCounts;
if (TotalCounts & 0xFFFF0000) {
Count = 0xFFFF;
}
// Record the timer's interval
TimerPtr->Interval = ((ULONG)Count * TimerPtr->Period)/1000;
// Zero the counter
out_16(TimerBase + MFGPT_COUNTER, 0x0000);
// Set Comparator1 to Count and Comparator2 to 0xFFFF
out_32(TimerBase + MFGPT_CMP1, 0xFFFF0000L | Count);
// Clear timer event(s)
out_16(TimerBase + MFGPT_SETUP, MFGPT_COMPARE1 | MFGPT_COMPARE2);
// Re-enable SMIs
Write_MSR_LO(MsrAddr, IRQ_Enables);
// Set Counter Enable to 1
out_16(TimerBase + MFGPT_SETUP, MFGPT_ENABLE);
// Restore the MFGPT LBAR
Restore_MFGPT_LBAR();
}
return (UCHAR)TimerPtr->Timer;
}
//***********************************************************************
// Configures a MFGPT as a PWM signal generator
//***********************************************************************
void pascal Program_PWM(UCHAR Gpio, UCHAR Duty, USHORT Rate, UCHAR EnableFlag)
{ USHORT i, Timer;
register TIMERS * TimerPtr;
// Determine the MFGPT associated with the specified GPIO
switch (Gpio) {
case 5:
Timer = 0;
break;
case 6:
Timer = 1;
break;
case 7:
Timer = 2;
break;
case 27:
Timer = 7;
break;
default:
Log_Error("EVENT_PWM is not supported on GPIO%d", Gpio);
return;
}
// Program the MFGPT to the specified rate and duty cycle
for (i = 0; i < NUM_MFGPTS; i++) {
TimerPtr = &TimerInfo[i];
if (TimerPtr->Timer == Timer) {
// Check if MFGPT is reserved for EVENT_PWM
if(TimerPtr->Setup != PWM_SETUP) {
continue;
}
// Enable the MFGPT LBAR
Enable_MFGPT_LBAR();
// Clear this timer's SETUP register in case it has been used previously as a timer
// Write_MSR_LO(MDD_Base + MSR_MFGPT_CLR_SETUP, TimerPtr->Mask);
// out_16(TimerPtr->TimerBase + MFGPT_SETUP, PWM_SETUP);
// Clamp duty cycle to 100%
if (Duty > 100) {
Duty = 100;
}
// Program the Count registers
out_16(TimerPtr->TimerBase + MFGPT_COUNTER, 0x0000);
out_16(TimerPtr->TimerBase + MFGPT_CMP1, (USHORT)(((ULONG)Rate * Duty)/100));
out_16(TimerPtr->TimerBase + MFGPT_CMP2, Rate);
// Enable the counter
out_16(TimerPtr->TimerBase + MFGPT_SETUP, EnableFlag ? MFGPT_ENABLE: 0);
Restore_MFGPT_LBAR();
return;
}
}
Log_Error("EVENT_PWM on GPIO%d failed because MFGPT%d is reserved.", Gpio, Timer);
}

View File

@@ -0,0 +1,348 @@
;
; 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
;
;* Function: *
;* Routines related to MSRs.
include VSA2.INC
include DESCR.INC
.model tiny,c
.586p
.CODE
extern SMM_Header: SmiHeader
;***********************************************************************
; Returns the high DWORD of an MSR.
; Usage: HighMsrValue = Read_MSR_HI(Msr_Address);
;***********************************************************************
Read_MSR_HI proc pascal \
Msr: dword
mov ecx, [Msr]
rdmsr
mov ax, dx
shr edx, 16
ret
Read_MSR_HI endp
;***********************************************************************
; Writes the high DWORD of an MSR. The low DWORD is preserved.
; Usage: Write_MSR_HI(Msr_Address, Data);
;***********************************************************************
Write_MSR_HI proc pascal \
Msr: dword, \
Data: dword
mov ecx, [Msr]
rdmsr ; Get low 32 bits
mov edx, [Data]
wrmsr
ret
Write_MSR_HI endp
;***********************************************************************
; Returns the low DWORD of an MSR.
; Usage: LowMsrValue = Read_MSR_LO(Msr_Address);
;***********************************************************************
Read_MSR_LO proc pascal \
Msr: dword
mov ecx, [Msr]
rdmsr
mov edx, eax
shr edx, 16
ret
Read_MSR_LO endp
;***********************************************************************
; Writes the low DWORD of an MSR. The high DWORD is preserved.
; Usage: Write_MSR_LO(Msr_Address, Data);
;***********************************************************************
Write_MSR_LO proc pascal \
Msr: dword, \
Data: dword
mov ecx, [Msr]
rdmsr ; Get high 32 bits
mov eax, [Data]
wrmsr
ret
Write_MSR_LO endp
;***********************************************************************
; Returns an MSR value in a buffer.
; Usage: Read_MSR(ULONG Msr, ULONG * Buffer);
;***********************************************************************
Read_MSR proc pascal \
Msr: dword, \
Buffer: PTR
mov ecx, [Msr]
rdmsr
mov bx, [Buffer]
mov [bx+0], eax
mov [bx+4], edx
ret
Read_MSR endp
;***********************************************************************
; Writes an MSR.
; Usage: Write_MSR(ULONG Msr, ULONG * Buffer);
;***********************************************************************
Write_MSR proc pascal \
Msr: dword, \
Buffer: PTR
mov ecx, [Msr]
mov bx, [Buffer]
mov eax, [bx+0]
mov edx, [bx+4]
wrmsr
ret
Write_MSR endp
;***********************************************************************
; Parses MSR_MBIU_CAP of an MBIU and returns descriptor counts in
; a byte buffer.
;***********************************************************************
Parse_Capabilities proc pascal \
Msr: PTR, \
Buffer: PTR
mov bx, [Msr]
mov eax, [bx+0] ; Get 1st dword of CAPABILITIES
mov edx, [bx+4] ; Get 2nd dword of CAPABILITIES
mov bx, [Buffer]
mov cl, 6 ; Number of P2D descriptors
NxtCount:
mov ch, al
and ch, 3Fh ; 6 bits per field
mov [bx], ch
inc bx
shrd eax, edx, 6 ; Shift next field into LSBs
shr edx, 6
dec cl
jnz NxtCount
mov ch, al ; Get NIOD_BM
and ch, 3Fh
mov [bx+1], ch
shr eax, 6 ; Get NIOD_SC
mov ch, al
and ch, 3Fh
mov [bx+2], ch
shr eax, 9 ; Skip NCOH field
mov ch, al
and ch, 07h ; Get NPORTS
mov [bx+3], ch
shr ax, 9 ; Get NSTAT_CNT
and al, 07h
mov [bx+4], al
ret
Parse_Capabilities endp
;***********************************************************************
; Extract the 3 main fields from a P2D descriptor
;***********************************************************************
Parse_Descriptor proc pascal uses edi \
P2D_Type: byte, \
Source: ptr, \
Dest: ptr
mov bx, [Source]
mov ecx, [bx] ; Get low MSR
mov eax, ecx
mov edx, [bx+4] ; Get high MSR
cmp bl, IOD_BM
je Descr_IO_BM
shl ecx, 12 ; Extract 1st field
shrd eax, edx, 20 ; Extract 2nd field
shl eax, 12
xor dl, dl ; Extract 3rd field
shl edx, 12-8
mov edi, edx ; EDI = Offset
mov bl, [P2D_Type] ; Dispatch to correct descriptor parser
cmp bl, P2D_BM
je Descr_BM
cmp bl, P2D_BMO
je Descr_BMO
cmp bl, P2D_BMK
je Descr_BMK
cmp bl, P2D_R
je Descr_R
cmp bl, P2D_RO
je Descr_RO
jmp Exit
Descr_IO_BM:
and ecx, 000FFFFFh ; ECX = IMASK
shrd eax, edx, 20 ; EAX = IBASE
xor edi, edi ; EDI = 00000000
Descr_BMO: ; Assume OFFSET == 0
Descr_BM:
Descr_BMK:
; ECX = PMASK
; EAX = PBASE
and eax, ecx ; Start = PBASE & PMASK
mov edx, eax ; End = Start + ~PMASK
not ecx
add edx, ecx
jmp StoreResult
Descr_RO: ; Assume OFFSET == 0
Descr_R:
; ECX = PMIN
; EAX = PMAX
xchg eax, ecx ; Start = PMIN
mov edx, ecx ; End = PMAX
or dx, 0FFFh
StoreResult:
mov bx, [Dest]
mov [bx], eax ; Start
mov [bx+4], edx ; End
add edi, eax ; Physical = Start + Offset
mov [bx+8], edi
Exit: ret
Parse_Descriptor endp
;***********************************************************************
;***********************************************************************
MergeFields proc pascal \
Dest: PTR, \
Field1: DWORD, \
Field2: DWORD, \
Field3: DWORD
mov bx, [Dest]
;// Descr->MsrData[0] = (PBase << 20) | (PMask & 0xFFFFF);
;// Descr->MsrData[1] = (PBase >> 12) | (POffset << 8);
mov eax, [Field2]
mov edx, eax
shl eax, 20
mov ecx, [Field1]
and ecx, 0FFFFFh
or eax, ecx
mov [bx], eax
shr edx, 12
mov eax, [Field3]
shl eax, 8
or eax, edx
mov [bx+4], eax
ret
MergeFields endp
;***********************************************************************
; Returns TRUE if Range is a power of 2
;***********************************************************************
IsPowerOfTwo proc pascal \
Range: dword
mov ebx, [Range]
bsf eax, ebx ; Scan LSB to MSB
bsr edx, ebx ; Scan MSB to LSB
cmp al, dl ; Same bit found ?
mov al, 0 ; No, return FALSE
jne Exit
mov al, 1 ; else return TRUE
Exit: ret
IsPowerOfTwo endp
;***********************************************************************
; Returns index of first bit set when scanning from MSB to LSB
;***********************************************************************
BitScanReverse proc pascal \
Range: dword
mov ebx, [Range]
bsr eax, ebx ; Scan MSB to LSB
ret
BitScanReverse endp
;***********************************************************************
; Returns index of first bit set when scanning from LSB to MSB
;***********************************************************************
BitScanForward proc pascal \
Range: dword
mov ebx, [Range]
bsf eax, ebx ; Scan LSB to MSB
ret
BitScanForward endp
end

View File

@@ -0,0 +1,164 @@
/*
* 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
*/
//*****************************************************************************
//* Handler for EVENT_USB and EVENT_KEL
//*****************************************************************************
#include "VSA2.H"
#include "PROTOS.H"
#include "CHIPSET.H"
#include "VPCI.H"
#include "PCI.H"
#include "HCE.H"
extern ULONG MsgPacket[];
extern SmiHeader SMM_Header;
extern Hardware HardwareInfo;
extern VIRTUAL_DEVICE * SouthBridge;
extern void pascal write_flat_size(ULONG, ULONG, UCHAR);
USHORT OHCI_Address;
ULONG OHCI_Command;
ULONG HC_Status;
#define HC ((ULONG)(&((HCOR *)0)
//***********************************************************************
// Restores the OHCI COMMAND register to the original value
//***********************************************************************
void Restore_OHCI_Command()
{
Virtual_PCI_Write_Handler(OHCI_Address, BYTE_IO, OHCI_Command & ~MEM_SPACE);
}
//***********************************************************************
// Sends EVENT_USB or EVENT_KEL
//***********************************************************************
void Send_OHCI_Event(UCHAR HC_Number)
{ USHORT Hce_Status;
HCE_CONTROL Hce_Control;
ULONG HC_Enable, HC_Address;
ULONG Timeout;
PCI_HEADER_ENTRY * OHCI_Hdr;
// Get ptr to virtualized PCI header
OHCI_Hdr = *(SouthBridge+3 + HC_Number);
if (!OHCI_Hdr) {
Log_Error("Invalid HC number 0x%02X", HC_Number);
return;
}
// Get HC address from BAR0
if (!(HC_Address = (OHCI_Hdr+(BAR0/4))->Value)) {
return;
}
OHCI_Address = 0x7C00 + (((USHORT)HC_Number-1) << 8) + COMMAND;
// Are memory-mapped registers enabled?
if (!((OHCI_Hdr+(COMMAND/4))->Value & MEM_SPACE)) {
OHCI_Command = (OHCI_Hdr+(COMMAND/4))->Value;
// No, temporarily enable access to them
Virtual_PCI_Write_Handler(OHCI_Address, BYTE_IO, OHCI_Command | MEM_SPACE);
// Schedule a routine to restore the original COMMAND value
// after the VSM has processed the EVENT_USB or EVENT_KEL.
Schedule_VSM((USHORT)Restore_OHCI_Command);
}
// Get HC's Hce_Control register
Hce_Control.HceUshort = (USHORT)read_flat(HC_Address + HC->HceControl)));
// Prepare message packet
MsgPacket[1] = HC_Address;
MsgPacket[2] = HC_Number;
MsgPacket[3] = 0;
// Is it an emulation event ?
if (Hce_Control.EmulationInterrupt) {
// SiBZ 3069/3370: HceStatus[3] is not updated properly
if (SMM_Header.SMI_Flags.Ext_IO_Trap) {
if (SMM_Header.SMI_Flags.IO_Write) {
Hce_Status = (USHORT)read_flat(HC_Address + HC->HceStatus)));
switch ((USHORT)SMM_Header.IO_addr) {
case 0x60:
Hce_Status &= ~CMD_DATA;
break;
case 0x64:
Hce_Status |= CMD_DATA;
break;
}
write_flat_size(HC_Address + HC->HceStatus)), Hce_Status, BYTE_IO);
}
}
// SiBZ 3509/3571: KEL SMIs are level instead of edge-triggered
MsgPacket[3] = Hce_Control.HceUshort;
Timeout = 1000;
while (Timeout--) {
Hce_Control.HceUshort = (USHORT)read_flat(HC_Address + HC->HceControl)));
if (Hce_Control.IRQ1Active || Hce_Control.IRQ12Active) {
// Clear the active IRQ & disable emulation
Hce_Control.EmulationEnable = 0;
write_flat_size(HC_Address + HC->HceControl)), Hce_Control.HceUshort , WORD_IO);
// Read a byte from the data port to dismiss the 8042 interrupt
in_8(0x60);
// Re-enable emulation
Hce_Control.EmulationEnable = 1;
write_flat_size(HC_Address + HC->HceControl)), Hce_Control.HceUshort, WORD_IO);
} else {
break;
}
}
// Report if SiBZ 3571 workaround failed
if (Timeout == 0) {
Log_Error("IRQx_ACTIVE won't clear");
}
// Send emulation event to the i8042 VSM
Send_Event(EVENT_KEL, SysMgr_VSM);
}
// Any unmasked events pending ?
HC_Status |= read_flat(HC_Address + HC->HcInterruptStatus)));
HC_Enable = read_flat(HC_Address + HC->HcInterruptEnable)));
if (HC_Status & HC_Enable) {
// SWAPSiF for PBZ 2300:
MsgPacket[3] = HC_Status;
write_flat(HC_Address + HC->HcInterruptStatus)), HC_Status);
// Send Host Controller event to the OHCI VSM
Send_Event(EVENT_USB, 0x00000000);
}
HC_Status = 0;
}

View File

@@ -0,0 +1,539 @@
/*
* 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
*/
//* Routines related to PCI power management.
#include "VSA2.H"
#include "SYSMGR.H"
#include "VPCI.H"
#include "PROTOS.H"
#include "PCI.H"
#include "CHIPSET.H"
#include "GX2.H"
#include "ACPI.H"
#include "DESCR.H"
#if SUPPORT_CAPABILITIES
extern DESCRIPTOR MSRs[];
extern PCI_HEADER_ENTRY * HdrPtr;
extern PCI_HEADER_ENTRY * CommandPtr;
extern UCHAR End_of_POST;
extern ULONG OHCI1_Smi;
extern ULONG MCP_SB;
#define OHC_IN_D3 1
#define EHC_IN_D3 2
#define UDC_IN_D3 4
#define UOC_IN_D3 8
#define ALL_IN_D3 (OHC_IN_D3 | EHC_IN_D3 | UDC_IN_D3 | UOC_IN_D3)
typedef struct { // All bits are Read-Only
union {
ULONG AsDword;
struct {
ULONG CompatibilityID: 8;
ULONG NextItemPtr: 8;
ULONG Version: 3;
ULONG PME_Clock: 1;
ULONG Reserved: 1;
ULONG DSI: 1;
ULONG Aux_Current: 3;
ULONG D1_Support: 1;
ULONG D2_Support: 1;
ULONG PME_D0: 1;
ULONG PME_D1: 1;
ULONG PME_D2: 1;
ULONG PME_D3_Hot: 1;
ULONG PME_D3_Cold: 1;
};
};
} PMC;
typedef struct {
union {
ULONG AsDword;
struct {
union {
USHORT AsWord;
struct {
USHORT PowerState: 2; // Read-write
USHORT Reserved: 6; // Read-only
USHORT PME_En: 1; // Read-write
USHORT Data_Select: 4; // Read-write
USHORT Data_Scale: 2; // Read-only
USHORT PME_Status: 1; // Read/Write-Clear
};
};
UCHAR PMCSR_BSE; // Bridge Support Extensions
UCHAR Data;
};
};
} PMCR;
// R/W Mask = 1001_1111_0000_0011
#define PMCR_MASK 0x9F03
// Fields in USBMSROHCB, USBMSREHCB, USBMSRUDCB, USBMSRUOCB:
typedef struct {
union {
struct {
ULONG Reserved: 1;
ULONG MEMEN: 1;
ULONG BMEN: 1;
ULONG PMEEN: 1;
ULONG PMESTS: 1;
};
struct {
UCHAR Enables;
// NOTE: the next 3 fields are actually 6 bits, but the compiler
// generates crappy code if defined as such
UCHAR FLADJ;
UCHAR LEGSMIEN;
UCHAR LEGSMISTS;
};
};
} USBMSR;
// Fields in 32-MSBs of GLCP's PMCLKACTIVE, PMCLKOFF, PMCLKDISABLE, PMCLK4ACK, PMCLKDISABLE:
typedef struct {
union {
ULONG AsDword;
struct {
ULONG GL0_0: 1;
ULONG GL0_1: 1;
ULONG GLPCI_GLIU: 1;
ULONG GLPCI_PCI: 1;
ULONG GLPCI_PCIF: 1;
ULONG RSVD: 6;
ULONG ATAC_GLIU: 1;
ULONG ATAC_LB: 1;
ULONG ACC_GLIU: 1;
ULONG ACC_LB: 1;
ULONG ACC_BIT: 1;
ULONG DIVIL_GLIU: 1;
ULONG DIVIL_LB: 1;
ULONG DIVIL_LPC: 1;
ULONG DIVIL_DMA: 1;
ULONG DIVIL_SMB: 1;
ULONG DIVIL_PIT: 1;
ULONG DIVIL_UART1: 1;
ULONG DIVIL_UART2: 1;
ULONG DIVIL_PMC: 1;
ULONG DIVIL_PMC_STD: 1;
ULONG DIVIL_GPIO: 1;
ULONG DIVIL_GPIO_STD: 1;
ULONG DIVIL_MFGPT_32K: 1;
ULONG DIVIL_MFGPT_14M: 1;
ULONG DIVIL_32K_STD: 1;
ULONG GLCP_GLIU: 1;
};
};
union {
ULONG AsDword_HI;
struct {
ULONG GLCP_DBG: 1;
ULONG GLCP_PCI: 1;
ULONG OHC_CLK48: 1;
ULONG UDC_HCLK: 1;
ULONG EHC_HCLK: 1;
ULONG OHC_HCLK: 1;
ULONG EHC_CLK60: 1;
ULONG UDC_CLK60: 1;
ULONG USBP1_CLK60: 1;
ULONG USBP2_CLK60: 1;
ULONG USBP3_CLK60: 1;
ULONG USBP4_CLK60: 1;
ULONG OTC_HCLK: 1;
ULONG USB_GLIU: 1; // aka M2A_HCLK in USB 2.0 IDS
ULONG USBPHYPLLEN: 1;
};
};
} GLCP_CLKS;
// Local variables:
ULONG MsrAddr, MsrData[2];
USBMSR * UsbMsr = (USBMSR *)&MsrData[1];
GLCP_CLKS Clocks;
USHORT D3_Flag = 0;
ULONG EHCI_BAR;
//***********************************************************************
// Returns TRUE if the specified EHCI port is suspended
// NOTE: Port is 1-based
//***********************************************************************
UCHAR pascal EHCI_Port_Suspended(UCHAR Port)
{
if ((UCHAR)READ_MEMORY(EHCI_BAR + 0x50 + Port*4) & 0x80) {
return 1;
} else {
return 0;
}
}
//***********************************************************************
// Reads the MSR corresponding to the current USB 2.0 function
//***********************************************************************
void Get_USB_MSR(void)
{
MsrAddr = OHCI1_Smi;
(UCHAR)MsrAddr = (HdrPtr+BAR0/4)->LBar;
// Get current MSR value
Read_MSR(MsrAddr, MsrData);
}
//***********************************************************************
// Returns value of the EHCI Power Management register USBLEGCTLSTS
//***********************************************************************
ULONG pascal Handle_EHCI_Rd(PCI_HEADER_ENTRY * Pci)
{
// Filter out non-EHCI functions
if (((HdrPtr+REVISION_ID/4)->Value & 0xFFFFFF00) == 0x0C032000) {
// Read USBMSREHCB MSR
Get_USB_MSR();
Pci->EHCI_Errors = (UCHAR)UsbMsr->LEGSMISTS;
// Sync PCI register with MSR (optional):
Pci->EHCI_SMI_Enables = (UCHAR)UsbMsr->LEGSMIEN;
}
return Pci->Value;
}
//***********************************************************************
// Handles writes to the EHCI PCI registers:
// COMMAND
// BAR0
// USBLEGSUP
// USBLEGCTLSTS
// FLADJ
//***********************************************************************
void pascal Handle_EHCI_Wr(PCI_HEADER_ENTRY * Pci)
{ ULONG SMI_Status = SMI_ON_COMMAND;
// Read USBMSREHCB MSR
Get_USB_MSR();
switch (Pci->Reg & 0xFC) {
case BAR0:
EHCI_BAR = Pci->Value;
SMI_Status = SMI_ON_BAR;
case COMMAND:
if (End_of_POST) {
// Set USBLEGCTLSTS[31/30]
(HdrPtr+9)->Value |= SMI_Status;
}
return;
case USBLEGSUP: // EECP
// If ownership changing, set USBLEGCTLSTS[29]
if (Pci->Value & (OS_OWNED_SEMAPHORE | BIOS_OWNED_SEMAPHORE)) {
// Set USBLEGCTLSTS[29]
(Pci+1)->Value |= SMI_ON_OC;
}
// If system software is requesting ownership...
if (Pci->Value & OS_OWNED_SEMAPHORE) {
// Clear BIOS Owned Semaphore
Pci->Value &= ~BIOS_OWNED_SEMAPHORE;
// Clear SMI enables
UsbMsr->LEGSMIEN = 0x00;
}
// If BIOS is requesting ownership...
if (Pci->Value & BIOS_OWNED_SEMAPHORE) {
// Clear system software Owned Semaphore
Pci->Value &= ~OS_OWNED_SEMAPHORE;
}
break;
case USBLEGCTLSTS: // EECP+4
UsbMsr->LEGSMIEN = Pci->EHCI_SMI_Enables;
break;
case SRBN_REG:
UsbMsr->FLADJ = Pci->FLADJ;
break;
}
// Update USBMSREHCB
Write_MSR(MsrAddr, MsrData);
}
//***********************************************************************
// Handles reads from a PCI Power Management register
// Returns value of PCI register
//***********************************************************************
ULONG pascal Handle_PCI_PM_Rd(PCI_HEADER_ENTRY * Pci)
{ PMCR * PMCR_Ptr;
// Get PME status from MSR
Get_USB_MSR();
// Cast register ptr
PMCR_Ptr = (PMCR *)&Pci->Value;
PMCR_Ptr->PME_Status = UsbMsr->PMESTS ? 1: 0;
return Pci->Value;
}
//***********************************************************************
// Handles writes to the PCI Power Management register
//***********************************************************************
void pascal Handle_PCI_PM_Wr(PCI_HEADER_ENTRY * Pci, USHORT PreviousData)
{ PMCR Delta;
PMCR * PMCR_Ptr;
PMC * PMC_Ptr;
USHORT Value;
// Cast register ptrs
PMCR_Ptr = (PMCR *)&Pci->Value;
PMC_Ptr = (PMC *)&(Pci-1)->Value;
Value = (USHORT)Pci->Value;
// Mask read-only bits
Value &= PMCR_MASK;
// Compute changes
Delta.AsWord = (USHORT)PreviousData ^ PMCR_Ptr->AsWord;
// Select data to be reported through the Data register
// Return as "not implemented"
PMCR_Ptr->Data = 0; //Power[PMCR_Ptr->Data_Select].Data;
PMCR_Ptr->Data_Scale = 0; //Power[PMCR_Ptr->Data_Select].Scale;
Get_USB_MSR();
// PME# status write-to-clear
if (PMCR_Ptr->PME_Status) {
UsbMsr->PMESTS = 1;
}
// PME# enable
if (Delta.PME_En) {
// Check if PME# is supported
if (PMC_Ptr->PME_D3_Cold || PMC_Ptr->PME_D3_Hot ||
PMC_Ptr->PME_D0 || PMC_Ptr->PME_D1 || PMC_Ptr->PME_D2) {
if (PMCR_Ptr->PME_En) {
// Enable PME# assertion
UsbMsr->PMEEN = 1;
} else {
// Disable PME# assertion
UsbMsr->PMEEN = 0;
}
} else {
// PME# not supported
PMCR_Ptr->PME_En = 0;
}
}
// Update USBMSRxxCB
Write_MSR(MsrAddr, MsrData);
// Power state
if (Delta.PowerState) {
UCHAR SupportedState=0;
ULONG ClocksMsr;
register USHORT USB_20_D3_Flag = D3_Flag;
ClocksMsr = MCP_SB + MCP_PMCLKOFF;
Read_MSR(ClocksMsr, &Clocks.AsDword);
switch (PMCR_Ptr->PowerState) {
case D0_STATE:
// If D0 is supported...
if (PMC_Ptr->PME_D0) {
switch (HdrPtr->Device_ID) {
case DEVICE_ID_AMD_OHCI:
Clocks.OHC_HCLK = 0;
Clocks.OHC_CLK48 = 0;
USB_20_D3_Flag &= ~OHC_IN_D3;
break;
case DEVICE_ID_AMD_EHCI:
Clocks.EHC_HCLK = 0;
Clocks.EHC_CLK60 = 0;
Clocks.USBP1_CLK60 = 0;
Clocks.USBP2_CLK60 = 0;
Clocks.USBP3_CLK60 = 0;
Clocks.USBP4_CLK60 = 0;
Clocks.USBPHYPLLEN = 0;
USB_20_D3_Flag &= ~EHC_IN_D3;
break;
case DEVICE_ID_AMD_UDC:
Clocks.UDC_HCLK = 0;
Clocks.UDC_CLK60 = 0;
USB_20_D3_Flag &= ~UDC_IN_D3;
break;
case DEVICE_ID_AMD_OTG:
Clocks.OTC_HCLK = 0;
USB_20_D3_Flag &= ~UOC_IN_D3;
break;
}
SupportedState = 1;
}
break;
case D1_STATE:
case D2_STATE:
// D1 & D2 are not supported
switch (HdrPtr->Device_ID) {
case DEVICE_ID_AMD_OHCI:
USB_20_D3_Flag &= ~OHC_IN_D3;
break;
case DEVICE_ID_AMD_EHCI:
USB_20_D3_Flag &= ~EHC_IN_D3;
break;
case DEVICE_ID_AMD_UDC:
USB_20_D3_Flag &= ~UDC_IN_D3;
break;
case DEVICE_ID_AMD_OTG:
USB_20_D3_Flag &= ~UOC_IN_D3;
break;
}
break;
case D3_STATE: // D3hot
// If D3hot is supported...
if (PMC_Ptr->PME_D3_Hot) {
switch (HdrPtr->Device_ID) {
case DEVICE_ID_AMD_OHCI:
Clocks.OHC_HCLK = 0;
Clocks.OHC_CLK48 = 0;
USB_20_D3_Flag |= OHC_IN_D3;
break;
case DEVICE_ID_AMD_EHCI:
Clocks.EHC_HCLK = 0;
Clocks.EHC_CLK60 = 0;
Clocks.USBP1_CLK60 = 0;
Clocks.USBP2_CLK60 = 0;
Clocks.USBP3_CLK60 = 0;
Clocks.USBP4_CLK60 = 0;
Clocks.USBPHYPLLEN = 1;
// In D3 *only* USBPHYPLLEN should be gated (Phy Clock switched off).
// This guarantees max. power saving during S1 and proper USB Remote WakeUp functionality and Resume from S1
// If all EHC ports are suspended USBPHYPLLEN should not be gated, because USBPHYPLL is switched off by Phy-HW
if (EHCI_Port_Suspended(1) & EHCI_Port_Suspended(2) & EHCI_Port_Suspended(3) & EHCI_Port_Suspended(4)) {
Clocks.USBPHYPLLEN = 0;
}
USB_20_D3_Flag |= EHC_IN_D3;
break;
case DEVICE_ID_AMD_UDC:
USB_20_D3_Flag |= UDC_IN_D3;
break;
case DEVICE_ID_AMD_OTG:
USB_20_D3_Flag |= UOC_IN_D3;
break;
}
SupportedState = 1;
}
break;
} // end switch (PMCR_Ptr->PowerState)
if (SupportedState) {
PCI_HEADER_ENTRY * Bar;
DESCRIPTOR * Descr;
ULONG MsrData[2];
UCHAR Index;
// If going to D3, turn off P2D_BM descriptor so accesses will master-abort.
// Otherwise, the system hangs when the device registers are accessed since
// the clocks have been turned off. Restore the descriptor when going to D0.
Bar = HdrPtr+BAR0/4;
while ((Bar->Reg >= BAR0) && (Bar->Reg <= BAR5)) {
if (Bar->Flag & (MMIO_BAR | MEM_BAR)) {
// For each linked item, update the associated MSR
// Get the P2D_BM descriptor linked to this BAR
Index = Bar->Link;
do {
Descr = &MSRs[Index];
if (Descr->Type == P2D_BM || Descr->Type == P2D_BMK) {
if (PMCR_Ptr->PowerState == D3_STATE) {
Get_Descriptor_Default(Descr->Type, MsrData);
} else {
MsrData[0] = Descr->MsrData[0];
MsrData[1] = Descr->MsrData[1];
}
Write_MSR(Descr->MsrAddr, MsrData);
break;
}
} while (Index = Descr->Link);
}
if (Pci->Flag & EOL) {
break;
}
Bar++;
}
// PBZ 2292 - Can't turn off USB_GLIU else MSR read of USB 2.0 hangs
#if 0
// Are all USB 2.0 functions are in D3?
if (USB_20_D3_Flag == ALL_IN_D3) {
// Yes, then turn off USB_GLIU
Clocks.USB_GLIU = 1;
} else {
Clocks.USB_GLIU = 0;
}
#endif
// Update D3 state for each function
D3_Flag = USB_20_D3_Flag;
// Update clock settings
Write_MSR(ClocksMsr, &Clocks.AsDword);
} else {
PMCR Previous;
// PCI PM Specification (page 29; Table 7):
// Writes of an unsupported state should discard the data
Previous.AsWord = PreviousData;
PMCR_Ptr->PowerState = Previous.PowerState;
}
} // end if (Delta.PowerState)
// Record current value
Pci->Value = PMCR_Ptr->AsDword;
}
#endif

View File

@@ -0,0 +1,177 @@
/*
* 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
*/
//*****************************************************************************
//* Implements reads of virtualized PCI configuration headers
//*****************************************************************************
#include "VSA2.H"
#include "PCI.H"
#include "VPCI.H"
#include "PROTOS.H"
#include "SYSMGR.H"
#include "CHIPSET.H"
// External function declarations:
ULONG pascal Get_Device_Status(PCI_HEADER_ENTRY *);
ULONG pascal Handle_PCI_PM_Rd(PCI_HEADER_ENTRY *);
ULONG pascal Handle_EHCI_Rd(PCI_HEADER_ENTRY *);
ULONG pascal Read_MSR_LO(ULONG);
UCHAR pascal Get_Latency(PCI_HEADER_ENTRY *);
PCI_HEADER_ENTRY * pascal Get_Structure(USHORT);
extern Hardware HardwareInfo;
// External variable declarations:
extern DESCRIPTOR MSRs[];
extern UCHAR Shift, AlignedReg, Function;
extern PCI_HEADER_ENTRY * CommandPtr;
extern ULONG ATA_Error;
//***********************************************************************
// Reads an embedded PCI register
//***********************************************************************
ULONG pascal Read_EPCI(UCHAR AlignedReg)
{ ULONG MsrAddr;
MsrAddr = MSRs[CommandPtr->Link].MsrAddr;
if (MsrAddr) {
(UCHAR)MsrAddr = AlignedReg/4;
return Read_MSR_LO(MsrAddr);
} else {
return 0;
}
}
//***********************************************************************
//
// This routine implements reads to virtualized configuration space.
//
// NOTES:
// 1) Misaligned accesses are handled. If an access crosses a DWORD
// boundary, only the bytes within the addressed DWORD are read.
// The remaining bytes return FFs.
// 2) The variable Pci points to a PCI_HEADER_ENTRY entry that defines
// the state and characteristics of the register being read.
//***********************************************************************
ULONG pascal Virtual_PCI_Read_Handler(USHORT PCI_Address)
{ ULONG Data;
register PCI_HEADER_ENTRY * Pci;
// Get ptr to virtualized table entry
Pci = Get_Structure(PCI_Address);
switch ((USHORT)Pci) {
case UNIMPLEMENTED_FUNCTION:
Data = 0xFFFFFFFF;
break;
case UNIMPLEMENTED_REGISTER:
Data = 0x00000000;
break;
default:
// Handle special cases
if (Pci->Flag & EPCI_R && AlignedReg < 0x40) {
// Embedded PCI device: read its h/w PCI configuration space
Data = Read_EPCI(AlignedReg);
if (AlignedReg == COMMAND) {
// Mark device '66 MHz capable'
Data |= PCI_66MHZ_CAPABLE;
}
break;
}
Data = Pci->Value;
switch (AlignedReg) {
case COMMAND:
// Get device's Status
Data |= Get_Device_Status(Pci);
break;
case BAR0:
case BAR1:
case BAR2:
case BAR3:
case BAR4:
case BAR5:
// If I/O BAR, set bit 0
if (Pci->Flag & IO_BAR) {
Data |= 1;
}
break;
case CACHE_LINE:
Pci->LatencyTimer = Get_Latency(Pci);
Data = Pci->Value;
break;
#if SUPPORT_CAPABILITIES
case (PCI_PM_REG+4): // 0x44
if (Pci->Flag & PCI_PM) {
Data = Handle_PCI_PM_Rd(Pci);
break;
}
case USBLEGCTLSTS:
if (Pci->Flag & PCI_EHCI) {
Data = Handle_EHCI_Rd(Pci);
break;
}
#endif
// Thor ATA vendor-specific registers:
case IDE_CFG: // 0x40
case IDE_DTC: // 0x48
case IDE_CAST: // 0x4C
case IDE_ETC: // 0x50
if (Pci->LBar) {
ULONG MsrAddr = ATA_Error;
(USHORT)MsrAddr = (USHORT)Pci->LBar;
Data = Read_MSR_LO(MsrAddr);
}
break;
}
}
// Handle non-dword aligned accesses
Data >>= Shift;
Data |= 0xFFFFFFFFL << (32-Shift);
return Data;
}

View File

@@ -0,0 +1,375 @@
/*
* 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
*/
//*****************************************************************************
//* Implements writes of virtualized PCI configuration headers
//*****************************************************************************
#include "VSA2.H"
#include "PCI.H"
#include "GX2.H"
#include "VPCI.H"
#include "SYSMGR.H"
#include "CHIPSET.H"
#include "PROTOS.H"
#include "MAPPER.H"
// External function declarations:
PCI_HEADER_ENTRY * pascal Get_Structure(USHORT);
UCHAR pascal Update_BusMaster(PCI_HEADER_ENTRY *, UCHAR);
void pascal Set_Latency(UCHAR);
void pascal Clear_MBus_Error(PCI_HEADER_ENTRY *, ULONG);
void pascal SMINT_Handler(USHORT);
void pascal PCI_Interrupt_Steering(USHORT);
void pascal Handle_EHCI_Wr(PCI_HEADER_ENTRY *);
void pascal Handle_PCI_PM_Wr(PCI_HEADER_ENTRY *, USHORT);
void pascal Update_Special_Cycles(USHORT);
void Deallocate_Descriptor(DESCRIPTOR *);
// External variable declarations:
extern DESCRIPTOR MSRs[];
extern ULONG ATA_Error;
extern UCHAR Shift, AlignedReg, Function;
extern PCI_HEADER_ENTRY * CommandPtr;
extern PCI_HEADER_ENTRY * HdrPtr;
extern VIRTUAL_DEVICE * IDSELs;
extern Hardware HardwareInfo;
//***********************************************************************
// Writes an embedded PCI register
//***********************************************************************
void pascal Write_EPCI(UCHAR AlignedReg, ULONG Data)
{ ULONG MsrAddr;
MsrAddr = MSRs[CommandPtr->Link].MsrAddr;
if (MsrAddr) {
(UCHAR)MsrAddr = AlignedReg/4;
Write_MSR_LO(MsrAddr, Data);
}
}
//***********************************************************************
//
// Handle changes to the COMMAND register
//
//***********************************************************************
void pascal Update_Command(USHORT PreviousValue, USHORT NewValue)
{ UCHAR Changes, EnableFlag;
register PCI_HEADER_ENTRY * Pci;
ULONG OldValue;
Changes = (UCHAR)(PreviousValue ^ NewValue);
//
// Handle changes to Special Cycles
//
if (Changes & SPECIAL_CYCLES) {
Update_Special_Cycles((UCHAR)NewValue & SPECIAL_CYCLES);
}
//
// Handle changes to bus master & address space enables
//
if (Changes & (IO_SPACE | MEM_SPACE | BUS_MASTER)) {
Pci = CommandPtr + 2;
// Walk through BAR entries & enable/disable corresponding descriptors/LBARs
do {
// Advance ptr to next implemented register
Pci++;
// Only concerned with allocated BARs
if (Pci->Flag & (MMIO_BAR | MEM_BAR | IO_BAR)) {
// Only write descriptors for BARs that have had resources allocated
// and have a non-zero value.
if ((Pci->Link) && Pci->Value) {
// Check correct Command bit according to BAR type
EnableFlag = (Pci->Flag & IO_BAR) ? IO_SPACE : MEM_SPACE;
// Handle changes to address space enable
if (Changes & EnableFlag) {
EnableFlag &= (UCHAR)NewValue;
// Update the descriptor(s)
OldValue = Pci->Value;
Update_BAR(Pci, EnableFlag);
Pci->Value = OldValue;
}
//
// Handle changes to bus master enable
//
if (Changes & BUS_MASTER) {
EnableFlag = (UCHAR)NewValue & BUS_MASTER;
if (Update_BusMaster(Pci, EnableFlag)) {
// Early-out (e.g. bridge)
Changes &= ~BUS_MASTER;
}
}
}
}
} while (!(Pci->Flag & EOL));
}
}
//***********************************************************************
//
// This routine implements writes to virtualized configuration space.
//
// NOTES:
// 1) Misaligned accesses are handled. If an access crosses a DWORD
// boundary, only the bytes within the addressed DWORD are written.
// 2) The variable Pci points to a PCI_HEADER_ENTRY entry that defines
// the state and behavior of the accessed register.
//
//***********************************************************************
ULONG pascal Virtual_PCI_Write_Handler(USHORT PCI_Address, UCHAR Size, ULONG NewData)
{ UCHAR EnableFlag;
ULONG Mask, Data, PreviousData;
register PCI_HEADER_ENTRY * Pci;
// Get ptr to virtualized table entry
Pci = Get_Structure(PCI_Address);
// Unimplemented function ?
if ((USHORT)Pci == UNIMPLEMENTED_FUNCTION) {
return NewData;
}
// Unimplemented register ?
if ((USHORT)Pci == UNIMPLEMENTED_REGISTER) {
// Removing an entire PCI function ?
if (AlignedReg == 0x7C && NewData == 0xDEADBEEF) {
UCHAR i, Link;
DESCRIPTOR * Descr;
#if SUPPORT_CAPABILITIES
Pci = HdrPtr + BAR0/4;
do {
Pci++;
// If this device is PCI PM-aware...
if (Pci->Flag & PCI_PM) {
// then set device to D3
(UCHAR)PCI_Address = 0x44;
Virtual_PCI_Write_Handler(PCI_Address, BYTE_IO, 0x03);
break;
}
} while (!(Pci->Flag & EOL));
#endif
// Make function unimplemented
IDSELs[Function] = 0x0000;
// Walk through all BARs and deallocate associated MSRs
Pci = HdrPtr + BAR0/4;
if (Pci->Reg != BAR0) {
return NewData;
}
for (i = BAR0; i <= BAR5; i += 4) {
if (Pci->Flag & (MMIO_BAR | MEM_BAR | IO_BAR)) {
Link = Pci->Link;
// For each linked item, update the associated MSR
while (Link) {
Descr = &MSRs[Link];
// Get link to next MSR
Link = Descr->Link;
// Deallocate the descriptor & set MSR to default value
Deallocate_Descriptor(Descr);
}
}
if (Pci->Flag & EOL) {
break;
}
Pci++;
}
}
return NewData;
}
// Save a copy of original value
PreviousData = Pci->Value;
//
// Generate mask to preserve read-only fields
//
switch (Size) {
case BYTE_IO:
Mask = 0x000000FF;
break;
case WORD_IO:
Mask = 0x0000FFFF;
break;
case DWORD_IO:
Mask = 0xFFFFFFFF;
break;
default:
Mask = 0x00000000;
break;
}
Mask = Pci->Mask & (Mask << Shift);
//
// Compute new register value
// - preserves R/O fields
// - handles misaligned accesses
// - handles accesses smaller than dword
//
NewData <<= Shift;
Data = (NewData & Mask) | (PreviousData & ~Mask);
//
// Record the new register value
//
Pci->Value = Data;
// Handle Write-to-Clear bits
if (NewData & Pci->WriteToClear) {
Pci->Value &= ~(NewData & Pci->WriteToClear);
}
//
// Update the MBus hardware
//
switch (AlignedReg) {
case COMMAND:
// Handle writes to Command register
if ((USHORT)PreviousData != (USHORT)Data) {
// If the Command register has changed, update the h/w
Update_Command((USHORT)PreviousData, (USHORT)Data);
}
// Handle writes to Status[15:11] (write-to-clear);
if (NewData &= Pci->WriteToClear) {
// Clear status bits in device's MSR
Clear_MBus_Error(Pci, NewData);
}
// Handle SMI on EHCI COMMAND write
if (Pci->Flag & PCI_EHCI) {
Handle_EHCI_Wr(Pci);
break;
}
break;
case CACHE_LINE:
// PCI Spec: if an unsupported Cache Line value is written, treat as 0x00
if ((UCHAR)Data ^ (UCHAR)Pci->Mask) {
Pci->CacheLineSize = 0x00;
}
Set_Latency((UCHAR)(Data >> 8));
break;
// Emulation of CS5530 software SMI mechanism
case SW_SMI: // 0xD0
SMINT_Handler((USHORT)Data);
break;
case (PCI_PM_REG+4): // 0x44
#if SUPPORT_CAPABILITIES
if (Pci->Flag & PCI_PM) {
Handle_PCI_PM_Wr(Pci, (USHORT)PreviousData);
break;
}
#endif
case IDE_CFG:
// Don't write IDE_CFG if this is a IDE-to-Flash switch
if (NewData == 0xDEADBEEF && Pci->LBar) {
return NewData;
}
case IDE_DTC: // 0x48
case IDE_CAST: // 0x4C
case IDE_ETC: // 0x50
// Thor ATA vendor-specific registers:
if (Pci->LBar) {
ULONG MsrAddr = ATA_Error;
(USHORT)MsrAddr = (USHORT)Pci->LBar;
// Sync with the current MSR value
PreviousData = Read_MSR_LO(MsrAddr);
// Update Thor ATA MSR with the new value
Pci->Value = (NewData & Mask) | (PreviousData & ~Mask);
Write_MSR_LO(MsrAddr, Pci->Value);
break;
}
#if SUPPORT_CAPABILITIES
case BAR0:
case USBLEGCTLSTS:
case SRBN_REG:
if (Pci->Flag & PCI_EHCI) {
Handle_EHCI_Wr(Pci);
}
#endif
default:
// Is it a BAR ?
if (Pci->Flag & (MMIO_BAR | MEM_BAR | IO_BAR)) {
// If value has changed, update the MBus descriptor
if (PreviousData != Data) {
// I/O BAR and Memory BAR ?
EnableFlag = (Pci->Flag & IO_BAR) ? IO_SPACE : MEM_SPACE;
EnableFlag &= (UCHAR)CommandPtr->Value;
Update_BAR(Pci, EnableFlag);
}
}
break;
} // end switch(AlignedReg)
return Pci->Value;
}

View File

@@ -0,0 +1,387 @@
;
; 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
;
;*******************************************************************************
;* Port 92h routines
;*******************************************************************************
include SYSMGR.INC
include VSA2.INC
include GX2.INC
include CHIPSET.INC
include CS5536.INC
include ISA.INC
include PCI.INC
include MDD.INC
include HCE.INC
include SMIMAC.MAC
.model tiny,c
.586p
.CODE
externdef VSA_Exit: proc
externdef MDD_Base: dword
externdef FooGlue: dword
externdef OHCI1_Smi: dword
externdef OHCI2_Smi: dword
externdef Nested_Flag: dword
externdef Saved_EAX: dword
externdef Saved_EBX: dword
externdef Saved_ECX: dword
externdef Saved_EDX: dword
externdef Saved_ESI: dword
externdef Saved_EDI: dword
externdef Saved_EBP: dword
externdef Saved_ESP: dword
externdef IDT_Base: dword
externdef IDT_Limit: dword
externdef IDT_Selector: dword
externdef SMI_Sources: dword
externdef SMM_Header: SmiHeader
externdef Saved_SS: Descriptor
externdef Data_Descriptor: Descriptor
externdef HardwareInfo: Hardware
;***********************************************************************
;
; A20_Sync - synchronize port 92h and virtual A20 pin
;
;***********************************************************************
A20_Sync proc uses si edi
; Determine if it is a nested access to port 92h
btr word ptr [Nested_Flag], SMI_SRC_A20_INDEX
jc short Get_A20_Data
rsdc gs, cs:[Data_Descriptor]
Get_A20_Data:
ASSUME SI: ptr SmiHeader
mov si, OFFSET VSM_Header.SysStuff.State
mov bl, byte ptr gs:[si].write_data ; Get I/O data
mov si, gs:[si].IO_addr ; Get I/O address
ASSUME SI:NOTHING
; Set A20M in FooGlue appropriately
mov ecx, [FooGlue]
add cx, FG_A20M
rdmsr
and al, NOT A20M ; A20M = 0
and bl, 02h ; Check A20M setting
jnz short Set_A20
or al, A20M ; Force A20 low
Set_A20:
wrmsr
cmp si, 0092h ; If port 92h, no update necessary
je short SyncHceControl
cmp si, KYBD_DATA ; If not 8042 data port, ignore
jne Return
; Sync Port 92h to keyboard controller
mov ecx, [MDD_Base] ; Disable Port 92h trapping
mov cx, MBD_MSR_SMI
rdmsr
push ax
and al, NOT A20_P_EN
wrmsr
mov al, bl ; Update Port 92h A20 state
out 92h, al
pop ax ; Restore Port 92h trapping
wrmsr
; Synchronize HceControl[A20State] with port 92h
SyncHceControl:
mov ecx, [OHCI1_Smi] ; Read OHCI1 h/w BAR0
test ecx, 0FFF00000h
jnz short Get_HC_Base
mov ecx, [OHCI2_Smi] ; Use OHCI2 if OHCI1 not used
test ecx, 0FFF00000h
jz Return
Get_HC_Base:
mov cx, 1000h + BAR0/4 ; 5536 Embedded PCI MSR
cmp [HardwareInfo].Chipset_ID, DEVICE_ID_5536
je short ReadBAR
mov cx, USBMSROHCB ; 5536 OHCI MSR
ReadBAR:
rdmsr
mov bh, 0 ; Clear MSR restore flag
or eax, eax ; Is BAR initialized ?
jnz short SyncA20State
mov bh, 1 ; Set MSR restore flag
push eax ; Save current OHCI MSR
push edx
push ecx
; OHCI BAR is not initialized or OHCI header is hidden.
; Temporarily map the OHCI register set just above VSA
; This range has been declared as OS-reserved in INT 15h E820h
mov ecx, MSR_RCONF_SMM
rdmsr
lea edi, [edx+1000h]
pop ecx
push ecx
mov edx, 00000000Eh
mov eax, edi
wrmsr
mov ecx, [MDD_Base]
mov cx, MSR_LBAR_KEL1
rdmsr
push eax ; Save current KEL LBAR
push edx
push ecx
mov eax, edi
mov edx, 0FFFFF001h
wrmsr
; Synchronize HceControl.A20State
SyncA20State:
or ax, OFFSET (HCOR Ptr ds:[0]).HceControl
mov dx, fs:[eax]
cmp dx, 0FFFFh ; Is Memory Space enabled ?
je short Exit
CLEAR_A20 equ (A20_STATE OR IRQ1_ACTIVE OR IRQ12_ACTIVE)
; SWAPSiF for SiBZ 3509/3571: KEL SMIs are level instead of edge-triggered
; Manifests itself as PBZ 3878: PS/2 keyboard hangs after running PCIDIAG
test dx, (IRQ1_ACTIVE OR IRQ12_ACTIVE)
jz short NoIRQ
or [SMI_Sources], SMI_SRC_KEL ; Fake another KEL SMI
NoIRQ:
and dx, NOT CLEAR_A20 ; Clear A20State
test bl, 02h
jz Update_HceControl
or dx, A20_STATE ; Set A20State
Update_HceControl:
mov fs:[eax], dx
Exit:
or bh, bh ; Do OHCI MSRs need to be restored?
je short Return
pop ecx ; Restore KEL LBAR
pop edx
pop eax
wrmsr
pop ecx ; Restore OHCI MSR
pop edx
pop eax
wrmsr
Return:
ret
A20_Sync endp
;***********************************************************************
; Sets the top-level RSM state to the reset state:
; 1) Real-mode IDT
; 2) Real-mode descriptors; segment regisers = 0000
; 3) CS:EIP = F000:FFF0
; 4) CS base = FFFF0000
; 5) CS limit = 64K
; 6) DX = CPU ID
;***********************************************************************
set_reset_state proc uses si
; Check if user code is doing a 286-style shutdown
in al, CMOS_INDEX ; Preserve CMOS index
mov ah, al
mov al, 0Fh
out CMOS_INDEX, al
in al, CMOS_DATA
xchg al, ah
out CMOS_INDEX, al ; Restore CMOS index
cmp ah, 09H
je UserShutdown
cmp ah, 05H
je UserShutdown
cmp ah, 0AH
je UserShutdown
cmp ah, 0FFH ; JMP if no CMOS present
je UserShutdown
CACHE_LINE_SIZE equ 32
; If cache is disabled, there is no way to guarantee that
; the entire code sequence from DisableCKE to Pre_Fetch
; will be fetched before CKE is disabled. It was decided
; we'd rather see the original POST 0xBF hang rather than
; a hang in SMM.
mov ebp, [MDD_Base] ; Prepare reset MSR
mov bp, MSR_SOFT_RESET
mov eax, CR0 ; Is cache disabled ?
test eax, 40000000h
jnz Reset
lea si, [DisableCKE] ; Move code to start of a cache line
mov di, si
and di, NOT (CACHE_LINE_SIZE-1)
mov bx, di ; Remember where we moved it to
cld
@@: lodsd
mov [di], eax
add di, 4
cmp si, OFFSET Pre_Fetch
jb @b
mov ecx, 2000001Dh ; Memory controller
rdmsr
or ah, 3 ; Set CKE Mask = 11b
jmp Pre_Fetch
; Bug #118.226 - Some DIMMs hang at POST 0xBF on a reboot
;
; Need to de-assert CKE off before command signals are tri-stated.
; There can be no memory accesses after the following WRMSR.
; If cache is disabled, there is no way to satisfy this condition,
; so some DIMMs with cache disabled is not supported with
; respect to resets.
db CACHE_LINE_SIZE dup (90h)
DisableCKE:
wrmsr
; Reset the CPU via MDD MSR_SOFT_RESET
Reset: mov ecx, ebp
mov al, 1
wrmsr
jmp $
Pre_Fetch:
; Prefetch 4 cache lines of NOPs so there won't be any
; prefetching to memory after the MC MSR is written.
db 4*CACHE_LINE_SIZE dup (90h) ; 4 cache lines
jmp bx
UserShutdown:
mov ecx, [FooGlue] ; Disable A20 mask
add cx, FG_A20M
rdmsr
and al, NOT A20M ; A20M = 0
wrmsr
; Disable the cache & flush it
mov eax, CR0
or eax, 60000000h
mov CR0, eax
wbinvd
; Set real-mode IDT
mov [IDT_Limit], 0FFFFh ; Limit
mov [IDT_Base], 00000000h ; Base
mov [IDT_Selector], 00920000h ; Selector & Attributes
; INIT is broken on LX 2.x and 3.0
cmp [HardwareInfo].CPU_ID, DEVICE_ID_LX
jne short Set_INIT
mov ax, [HardwareInfo].CPU_Revision
cmp al, 30h ; Is it 3.0?
jae short FakeInit
and al, 0F0h ; Is it 2.x?
cmp al, 20h
je short FakeInit
call VSA_Exit
; Reset via INIT MSR
Set_INIT:
mov ecx, [FooGlue] ; Reset the CPU
add cx, FG_INIT
xor eax, eax
wrmsr
mov al, INIT
wrmsr
; Fake an INIT by setting up initial CPU state
FakeInit:
lea si, [Saved_SS] ; Set descriptors to 64K real-mode
mov cx, 5 ; # descriptors to fill
mov eax, 0000FFFFh ; limit_15_0 & base_15_0
DescrLoop:
mov [si+0], eax ; limit_15_0 & base_15_0
mov dword ptr [si+4], 00009200h ; base_23_16, attr, limit_19_16 & base_31_24
mov word ptr [si+8], 0000h ; selector
add si, sizeof (Descriptor) ; Advance ptr to next descriptor
loop DescrLoop
; Set top-level SMM header to reset state
mov bx, OFFSET SMM_Header
ASSUME BX: PTR SmiHeader
mov [bx]._CS.limit, eax
mov [bx]._CS.base, 0FFFF0000h
mov [bx]._CS.selector, 0F000h
mov [bx]._CS.attr, 92h
mov [bx].Next_EIP, 0000FFF0h
mov [bx].r_CR0, 60000010h ; Real-mode; cache disabled
mov [bx].r_DR7, 00000400h
mov [bx].EFLAGS, 00000002h
mov [bx].SMI_Flags, 8001h ; CS is R/W
mov [bx].SS_Flags, DATA_ATTR
; Initialize general purpose register
mov [Saved_EDX], 00000540h ; CPU ID
xor eax, eax
mov [Saved_EAX], eax
mov [Saved_EBX], eax
mov [Saved_ECX], eax
mov [Saved_EDI], eax
mov [Saved_ESI], eax
mov [Saved_EBP], eax
mov [Saved_ESP], eax
ret
set_reset_state endp
end

View File

@@ -0,0 +1,91 @@
/*
* 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
*/
typedef unsigned short EVENT;
typedef unsigned short MSG;
typedef unsigned short PRIORITY;
typedef unsigned long VSM;
typedef void (* GPIO_FUNCTION)(unsigned long, unsigned long, unsigned char);
void pascal out_8(unsigned short, unsigned char);
void pascal out_16(unsigned short, unsigned short);
void pascal out_32(unsigned short, unsigned long);
unsigned char pascal in_8(unsigned short);
unsigned short pascal in_16(unsigned short);
unsigned long pascal in_32(unsigned short);
void pascal Hex_8(unsigned char);
void pascal Hex_16(unsigned short);
void pascal Hex_32(unsigned long);
extern void pascal Trap_PCI_IDSEL(unsigned short, unsigned char);
extern unsigned char pascal Init_Descr(unsigned char, unsigned long);
extern unsigned char pascal BitScanReverse(unsigned long);
extern unsigned char pascal BitScanForward(unsigned long);
extern unsigned long pascal read_flat(unsigned long);
extern unsigned long pascal Read_MSR_LO(unsigned long);
extern unsigned long pascal Read_MSR_HI(unsigned long);
extern unsigned long pascal Virtual_PCI_Read_Handler(unsigned short);
extern unsigned long pascal GetFlink(unsigned long);
extern unsigned char pascal Get_VSM_Type(unsigned long);
extern unsigned char pascal IsPowerOfTwo(unsigned long);
extern unsigned short pascal Send_Event(EVENT, VSM);
extern unsigned char pascal Find_Matching_IO_Descriptor(unsigned long *, unsigned short *, unsigned char);
extern unsigned char pascal Setup_IO_Descriptor(unsigned long *, unsigned short *, unsigned char);
extern void pascal Init_MBIU(unsigned char *, unsigned long);
extern void pascal Get_Descriptor_Default(unsigned char, unsigned long *);
extern unsigned long pascal Virtual_PCI_Write_Handler(unsigned short, unsigned char, unsigned long);
extern void pascal write_flat(unsigned long, unsigned long);
extern void pascal Read_MSR(unsigned long, unsigned long *);
extern void pascal Write_MSR(unsigned long, unsigned long *);
extern void pascal Write_MSR_LO(unsigned long, unsigned long);
extern void pascal Write_MSR_HI(unsigned long, unsigned long);
extern void pascal Store_Timestamp(void *);
extern void pascal Schedule_VSM(unsigned long);
extern void pascal Report_Error(unsigned char, unsigned long, unsigned long);
extern void pascal Report_VSM_Error(unsigned char, unsigned long, unsigned long);
extern void pascal Send_Message(VSM, VSM, unsigned long);
extern void pascal Broadcast_Message(MSG, unsigned short, unsigned long);
extern void pascal Register_Event(EVENT, PRIORITY, VSM, unsigned long, unsigned long);
extern void pascal Enable_Event(EVENT, unsigned short, unsigned char);
extern void pascal Disable_Event(EVENT, unsigned short);
extern void pascal Unregister_VSM_Events(VSM);
extern void pascal IRQY_Mapper(unsigned char, unsigned char);
extern void pascal IRQZ_Mapper(unsigned char, unsigned char);
extern void Keep_History(EVENT, EVENT);
extern unsigned short pascal Unregister_Event(EVENT, VSM, unsigned long, unsigned long);
extern unsigned short pascal Allocate_BAR(unsigned char, unsigned short, unsigned long, unsigned short, unsigned short);
extern unsigned long Current_VSM;
extern unsigned long SysMgr_VSM;
extern void Log_Error(const char *format, ...);
extern unsigned long pascal Compute_IOD_SC(unsigned long *, unsigned short *, unsigned char);
extern void pascal MBus_IO_Trap(unsigned long, unsigned long, unsigned char);

View File

@@ -0,0 +1,209 @@
;
; Copyright (c) 2006 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
;
smint macro
db 0Fh, 38h
endm
EREG macro Reg
ifidni <Reg>, <eax>
db 0C8h
elseifidni <Reg>, <ecx>
db 0C9h
elseifidni <Reg>, <edx>
db 0CAh
elseifidni <Reg>, <ebx>
db 0CBh
elseifidni <Reg>, <esp>
db 0CCh
elseifidni <Reg>, <ebp>
db 0CDh
elseifidni <Reg>, <esi>
db 0CEh
elseifidni <Reg>, <edi>
db 0CFh
else
.err
endif
endm
RDSHR macro Reg
db 0Fh, 36h
EREG Reg
endm
WRSHR macro Reg
db 0Fh, 37h
EREG Reg
endm
MOV_EAX_CR4 macro
db 0Fh, 20h, 0E0h ; mov eax, CR4
ENDM
MOV_CR4_EAX macro
db 0Fh, 22h, 0E0h ; mov CR4, eax
ENDM
SMM_Instr macro Reg:REQ, Addr:REQ, Opcode:REQ
Local Place1, Place2, Attr, InstrLen
Place1:
ifidni <Reg>, <ES>
LFS ax, dword ptr Addr
elseifidni <Reg>, <SS>
LFS dx, dword ptr Addr
elseifidni <Reg>, <DS>
LFS bx, dword ptr Addr
elseifidni <Reg>, <FS>
LFS sp, dword ptr Addr
elseifidni <Reg>, <GS>
LFS bp, dword ptr Addr
elseifidni <Reg>, <CS>
LFS cx, dword ptr Addr
else
.err "Error in RSDC macro"
endif
Place2:
Extras = 1
SegOverride INSTR <Addr>, <:>
if SegOverride
Extras = Extras + 1
endif
AddrOverride INSTR <Addr>, <eax>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <EAX>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <ebx>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <EBX>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <ecx>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <ECX>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <edx>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <EDX>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <esi>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <ESI>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <edi>
if AddrOverride
Extras = Extras + 1
else
AddrOverride INSTR <Addr>, <EDI>
if AddrOverride
Extras = Extras + 1
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
endif
ORG Place1 + Extras
db Opcode
ORG Place2
endm
svdc macro Addr:REQ, Reg:REQ
SMM_Instr Reg, Addr, 78h
endm
rsdc macro Reg:REQ, Addr:REQ
SMM_Instr Reg, Addr, 79h
endm
svldt macro Addr:REQ
SMM_Instr <ES>, Addr, 7Ah
endm
rsldt macro Addr:REQ
SMM_Instr <ES>, Addr, 7Bh
endm
svts macro Addr:REQ
SMM_Instr <ES>, Addr, 7Ch
endm
rsts macro Addr:REQ
SMM_Instr <ES>, Addr, 7Dh
endm

View File

@@ -0,0 +1,354 @@
;
; 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
;
;********************************************************************************
;* This file contains the code for reading the source of SMIs.
;********************************************************************************
include GX2.INC
include VSA2.INC
include SYSMGR.INC
include CS5536.INC
include CHIPSET.INC
include MDD.INC
include PCI.INC
.model tiny,c
.586p
.CODE
ASSUME DS:_TEXT
SYNCHRONOUS equ (SMI_SRC_PCI_TRAP OR SMI_SRC_DESCR_HIT OR SMI_SRC_PM OR SMI_SRC_RESET OR SMI_SRC_BLOCKIO OR SMI_SRC_A20)
SMI_Sources dd 0
Video_Sources dd 0
Audio_Sources dw 0
Stats_Sources dd 0
SynchEvents dd SYNCHRONOUS
HiPrioritySMIs dd SMI_SRC_AUDIO OR SMI_SRC_USB1 OR SMI_SRC_USB2
public SynchEvents, HiPrioritySMIs
public SMI_Sources, Audio_Sources, Stats_Sources, Video_Sources
externdef pascal Hex_8:proc
externdef pascal Hex_16:proc
externdef pascal Hex_32:proc
externdef pascal Generate_IRQ_5536: proc
externdef SMI_Base: dword
externdef Mbiu0: dword
externdef Mbiu1: dword
externdef Mbiu2: dword
externdef MPCI_NB: dword
externdef MPCI_SB: dword
externdef MDD_Base: dword
externdef MCP_NB: dword
externdef ATA_Error: dword
externdef OHCI1_Smi: dword
externdef OHCI2_Smi: dword
externdef HardwareInfo: Hardware
;*************************************************************************
; Installs the SMI routine(s) appropriate to the chipset.
; The default routine(s) are for CS5536.
;*************************************************************************
Install_SMI_Routines proc
;5536 already set, do nothing. mov [OHCI_SMI], OHCSSTAT
Exit: ret
Install_SMI_Routines endp
;************************************************************************
; Asserts/deasserts internal IRQs
; On Entry:
; ECX = IRQ mask
; 16 LSBs - enable
; 16 MSBs - disable
;************************************************************************
Generate_IRQ proc
push cx
call word ptr [IRQ_Routine]
ret
IRQ_Routine::
dw OFFSET Generate_IRQ_5536
Generate_IRQ endp
;*************************************************************************
; Reads & clears all SMI source registers (MSRs & Southbridge)
; On Exit:
; EBX = SMI sources
; All other registers may be destroyed
;*************************************************************************
Get_SMI_Sources proc
mov ebx, [SMI_Sources] ; Get SMIs that have not yet been handled
call Get_Northbridge_SMIs
or ebx, ebx ; If any NB SMIs, handle them quickly
jz short Get_SB_SMIs
ret
Get_SB_SMIs:
jmp word ptr [SMI_Routine] ; Get Southbridge SMI(s)
SMI_Routine::
dw OFFSET Get_5536_SMIs
Get_SMI_Sources endp
;***********************************************************************
; Gets SMI sources from Northbridge
; On Entry:
; EBX = pending SMI sources
; NOTES:
; - May set SMI source bits in EBX.
;***********************************************************************
MPCI_ERROR equ (MARE + TARE + PARE + BME + SYSE)
VGA_BLANK equ 08h
VG_BLANK equ 01h
VERT_BLANK equ (VGA_BLANK OR VG_BLANK)
Get_Northbridge_SMIs proc
mov ecx, [MPCI_NB] ; MBIU1.MPCI.0.0.0.0
mov cx, MBD_MSR_SMI
rdmsr
wrmsr ; Clear the MPCI SMI event(s)
mov dl, al ; Only record enabled events
not dl
shr eax, 16
and al, dl ; Only consider unmasked events
jz short Graphics_SMIs ; Jmp if no MPCI SMI is pending
test al, VPHE SHR 16 ; Is it a virtualized PCI header ?
jz short CheckMPCI
or ebx, SMI_SRC_PCI_TRAP ; Yes, record the event
cmp al, VPHE SHR 16 ; Is VPHE the only SMI pending ?
je short Exit ; Yes, do a quick exit
CheckMPCI:
test ax, MPCI_ERROR SHR 16 ; Is it an MPCI error ?
jz short Graphics_SMIs
or ebx, SMI_SRC_MPCI ; Yes
mov cx, MBD_MSR_ERROR ; Clear the MPCI error(s)
rdmsr
wrmsr
;*******************************************
; Check for graphics SMIs
;*******************************************
; Value in Video_Sources:
;
; Bit Description
; ----- -----------------------------------
; 0 DF: SMI #1 (TBD)
; 1 DF: SMI #2 (TBD)
; 2 GP: SMI (address or type violation)
; 3 reserved
; 4 VG: Miscellaneous Output SMI
; 5 VG: Input Status register SMI
; 6 reserved
; 7 VG: CRTC invalid I/O SMI
Graphics_SMIs:
; Video Generator
mov ecx, VG_SMI_MSR
rdmsr
wrmsr ; Clear SMI(s)
; Because the VG records all events that occur in the upper half of the MSR
; regardless of whether or not they generate SMIs, we need to clear out the
; events that aren't generating SMIs and only look for valid ones.
not eax ; NOT the SMI mask
and edx,eax ; Clear out untrapped events
test dl, VERT_BLANK ; Is a vertical blank pending ?
jz short SaveVideoSources
and dl, NOT (VERT_BLANK)
or ebx, SMI_SRC_RETRACE ; Yes, record EVENT_VBLANK
SaveVideoSources:
or [Video_Sources], edx
jz short Statistic_SMIs
or ebx, SMI_SRC_VG ; Yes, then record EVENT_GRAPHICS
;*******************************************
; Check for Statistic Counter SMI(s)
;*******************************************
Statistic_SMIs:
mov ecx, [Mbiu0] ; Check MBIU0 Statistics Counters
call Get_MBD_SMIs
or byte ptr [Stats_Sources+0], dl
mov ecx, [Mbiu1] ; Check MBIU1 Statistics Counters
call Get_MBD_SMIs
or byte ptr [Stats_Sources+1], dl
Exit:
ret
Get_Northbridge_SMIs endp
;***********************************************************************
; Checks for events in MBD_MSR_SMI:
; - descriptor traps
; - statistic counters
; On entry: ECX = base address of GLIU
; Returns: DL = statistic event mask
;***********************************************************************
Get_MBD_SMIs proc
mov cx, MBD_MSR_ERROR ; Clear errors
rdmsr
wrmsr
mov cx, MBD_MSR_SMI
rdmsr
and dl, 1Fh ; Any SMIs pending ?
jz short Exit ; No, just exit
wrmsr
btr dx, 0 ; Is it a MBIU descriptor hit ?
jnc short StatCntrs
or ebx, SMI_SRC_DESCR_HIT ; Yes
StatCntrs:
or dl, dl ; Any hits on statistic counters ?
jz short Exit
or ebx, SMI_SRC_STAT ; Yes, record the event
or al, dl ; Disable further events
wrmsr
shr dl, 1
Exit:
ret
Get_MBD_SMIs endp
;*************************************************************************
; Reads and clears CS5536 SMI source registers
;*************************************************************************
Get_5536_SMIs proc
mov ecx, [MDD_Base] ; Check for MDD SMIs
mov cx, MBD_MSR_SMI
rdmsr
wrmsr ; Clear any pending SMI(s)
or dx, dx ; Any MDD SMIs pending ?
jz short Get_MPCI_SB ; No
xor eax, eax
MDD_Loop:
bsf ax, dx ; Determine next pending event
jz Exit
btr dx, ax ; Clear the status bit
or ebx, dword ptr [eax*4+MDD_Sources]
jmp short MDD_Loop
; MDD SMI sources
MDD_Sources:
dd 0 ; HLT_ASMI_STAT
dd 0 ; SHUTDOWN_ASMI_STAT
dd SMI_SRC_KEL ; KEL_ASMI_STAT
dd SMI_SRC_PIC ; PIC_ASMI_STAT
dd SMI_SRC_PME ; PM_ASMI_STAT
dd SMI_SRC_RESET ; INIT_K_STAT
dd SMI_SRC_A20 ; A20_P_STAT
dd SMI_SRC_RESET ; INIT_P_STAT
dd 0 ; UART1_SSMI_STAT
dd 0 ; UART2_SSMI_STAT
dd 0 ; RESERVED_STAT
dd 0 ; LPC_SSMI_STAT
dd 0 ; DMA_SSMI_STAT
dd SMI_SRC_A20 ; A20_K_STAT
dd SMI_SRC_ACPI ; PM2_CNT_SSMI_STAT
dd SMI_SRC_ACPI ; PM1_CNT_SSMI_STAT
Get_MPCI_SB:
mov ecx, [MPCI_SB] ; Get Southbridge MPCI events
mov cx, MBD_MSR_SMI
rdmsr
wrmsr ; Clear any pending SMI(s)
mov ecx, [Mbiu2] ; Check for MBIU2 SMIs
call Get_MBD_SMIs
or byte ptr [Stats_Sources+2], dl
mov ecx, [OHCI1_Smi] ; Check for USB #1 SMIs
jcxz short Exit
rdmsr
test dl, [OHCI_SMI] ; OHCI SMI pending ?
jz short Exit ; JMP if not
wrmsr ; Yes, clear the SMI
or ebx, SMI_SRC_USB1 ; Record the SMI event
Exit: ret
Get_5536_SMIs endp
OHCSSTAT equ 10h ; 5536
OHCI_SMI db OHCSSTAT ; Assume 5536; could patched by Install_SMI_Routines() if other
end

View File

@@ -0,0 +1,502 @@
;
; 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
;
;********************************************************************************
;* Implementation of BIOS callbacks
;********************************************************************************
include SYSMGR.INC
include VSA2.INC
include SMIMAC.MAC
include GX2.INC
include ISA.INC
.model tiny,c
.586p
.ALPHA
DGROUP GROUP _CODE, _TEXT
_CODE SEGMENT PUBLIC use16 'CODE'
ASSUME DS:_CODE
public VSM_Buffer
SMINT_SEGMENT equ 0E000h ; Segment to store SMINT instruction & ISR stack
ALLOW_SMM_SEGMENTS equ 0 ; 1 = ES segment allowed to point to SMM memory
externdef pascal Report_VSM_Error: proc
externdef pascal Schedule_VSM: proc
externdef Sys_Exit: proc
externdef pascal Hex_8: proc
externdef pascal Hex_16: proc
externdef pascal Hex_32: proc
externdef BracketFlag: byte
externdef SchedulerStack: word
externdef INT_Vectors: dword
externdef Current_VSM: dword
externdef StartSaveArea: dword
externdef EndSaveArea: dword
externdef SysMgr_VSM: dword
externdef Header_Addr: dword
externdef SMM_Header: SmiHeader
;************************************************************************
; Implements the SYS_STATE macro
;
; Input:
; CX = Flag: 0 = Save 1 = Restore
; EDI = Offset to VSM's register buffer
; DS = System Manager's data segment
;************************************************************************
Sys_State proc
cld
mov eax, [Current_VSM] ; Create flat ptr to calling VSM
add edi, eax
push eax ; Re-schedule the calling VSM
call Schedule_VSM
lea esi, [StartSaveArea]
add esi, [SysMgr_VSM]
jcxz CopyState ; Save or Restore ?
xchg esi, edi ; Restore
; Copy the non-SMM state
CopyState:
mov ecx, OFFSET EndSaveArea
sub cx, OFFSET StartSaveArea
shr cx, 1
rep movsw [edi], fs:[esi]
jmp Sys_Exit
Sys_State endp
;************************************************************************
; Implements the SYS_SW_INTERRUPT macro
;
; Input:
; EBX = 4 * INT number
; ECX = Offset to VSM's register buffer
;************************************************************************
Sys_SW_INT proc
cld
mov esi, [Current_VSM]
push esi ; Re-schedule the calling VSM
call Schedule_VSM
cmp bx, 4*MAX_INT ; Validate INT vector
ja Unsupported_INT
mov edx, [INT_Vectors+bx]
or edx, edx
jz Illegal_INT
mov [Saved_INT], ebx ; Save current vector &
mov edi, edx ; patch with the original vector
xchg fs:[ebx], edi
mov [Saved_Vector], edi
xor edi, edi ; Don't allow calling VSM to execute
push edi
call Schedule_VSM
ASSUME di:PTR VSM_Header ; Mark the requesting VSM blocked
mov gs:[di].SysStuff.RunFlag, RUN_FLAG_BLOCKED
; Handle PIC masks
in al, PIC1_MASK ; Save PIC masks & set user-defined masks
mov ah, al
in al, PIC2_MASK
mov [Saved_PIC], ax
ASSUME di:PTR INT_REGS
mov di, cx
mov ax, word ptr gs:[di].PIC0_Mask
not ax ; PIC masks are 0=enable
cmp ah, 0FFh ; Any PIC1 IRQs enabled ?
je short SetPIC
and al, NOT 04h ; Yes, enable IRQ2
SetPIC:
or al, 01h ; Always disable IRQ0
out PIC1_MASK, al
mov al, ah
out PIC2_MASK, al
cmp ax, 0FFFFh ; Are any IRQs enabled ?
je short RealMode
or gs:[di].Flags, EFLAGS_IF ; Yes, enable interrupts
;
; Initialize real-mode state
;
RealMode:
mov ax, gs:[di].Reg_ES ; Set up ES descriptor
push OFFSET BIOS_ES
call Set_Descriptor
mov ax, gs:[di].Reg_DS ; Set up DS descriptor
push OFFSET BIOS_DS
call Set_Descriptor
add esi, ecx ; Create flat ptr to calling VSM's registers
mov [VSM_Buffer], esi
ASSUME di:PTR SmiHeader
lea edi, [BIOS_Header] ; Set up CS descriptor & Next_EIP
mov word ptr [di].SS_Flags, DATA_ATTR
mov [di].SMI_Flags, SMI_FLAGS_CS_WRITABLE + SMI_FLAGS_CS_READABLE
mov word ptr [di].Next_EIP, dx ; IP
shr edx, 16 ; Convert segment to linear address
mov [di]._CS.selector, dx ; CS selector
shl edx, 4
mov [di]._CS.base, edx ; CS descriptor
mov [di]._CS.limit, 0FFFFh
mov [di]._CS.attr, CODE_ATTR ; CS attribute
mov eax, CR0 ; Preserve the CD & NW bits
and eax, 60000000h
or eax, VSM_CR0
mov [di].r_CR0, eax
if ALLOW_SMM_SEGMENTS
mov ecx, MSR_RCONF_SMM ; Make SMM memory writeable by interrupt code
rdmsr
mov [OldRCONF], al
and al, NOT REGION_WP
wrmsr
endif
ASSUME DI: NOTHING
mov ecx, 1000002Ch ; Save P2D_SC value & make UMBs R/W
rdmsr
mov [ShadowMSR], dx
or dx, 0FFFFh
wrmsr
mov ebx, SMINT_SEGMENT ; Patch SS descriptor
mov word ptr [BIOS_SS+8], bx
shl ebx, 4
mov dword ptr [BIOS_SS+2], ebx
mov byte ptr [BIOS_SS+5], DATA_ATTR
add ebx, 0FFF0h
mov [ShadowAddr], ebx
mov word ptr [BIOS_ESP], bx
; Build a stack frame:
; SMINT_SEGMENT:FFF0 SMINT_SEGMENT:FFF6 - return addresss
; SMINT_SEGMENT:FFF4 Flags
; SMINT_SEGMENT:FFF6 SMINT instruction
mov eax, SMINT_SEGMENT SHL 16 ; Segment
lea ax, [bx+6] ; Offset (SP+6)
xchg eax, dword ptr fs:[ebx]
mov [ShadowMemory], eax
mov eax, 380F0000h ; FLAGS & SMINT
xchg eax, fs:[ebx+4]
mov [ShadowMemory+4], eax
mov eax, [Header_Addr] ; Copy top-level header address
mov [Hdr_Address], eax
call VSM_Registers ; Get registers for ISR
call Swap_States ; S wap top-level state with BIOS state
Exit: jmp Sys_Exit
Unsupported_INT:
Illegal_INT:
mov ax, ERR_BAD_INTERRUPT
push ax ; Push error code
shr ebx, 2
push ebx ; Info1 = Interrupt #
push dword ptr 0 ; Info2 = 0x00000000
call Report_VSM_Error
jmp Exit
Sys_SW_INT endp
;********************************************************************************
; Returns here from INT callback
;********************************************************************************
INT_Return proc
mov ebx, [Saved_INT] ; Restore the INT vector
mov edx, [Saved_Vector]
mov fs:[ebx], edx
if ALLOW_SMM_SEGMENTS
mov ecx, MSR_RCONF_SMM ; Restore SMM region properties
rdmsr
mov al, [OldRCONF]
wrmsr
endif
mov esi, [Current_VSM] ; Mark the requesting VSM ready to run
mov fs:(VSM_Header PTR [esi]).SysStuff.RunFlag, RUN_FLAG_READY
call Swap_States ; Restore the original non-SMM state
call VSM_Registers ; Return register values & flags
xor eax, eax
mov [VSM_Buffer], eax
sub [SchedulerStack], 4 ; Pop the scheduler sentinel
mov ebx, [ShadowAddr] ; Restore shadow memory
mov eax, [ShadowMemory]
mov fs:[ebx], eax
mov eax, [ShadowMemory+4]
mov fs:[ebx+4], eax
mov ecx, 1000002Ch ; Restore R/W attributes of UMBs
rdmsr
mov dx, [ShadowMSR]
wrmsr
mov ax, [Saved_PIC] ; Restore PIC masks
out PIC2_MASK, al
mov al, ah
out PIC1_MASK, al
ret
INT_Return endp
;************************************************************************
; Swaps the top-level state with the BIOS callback state.
; Info to be saved:
; - SMM header & pointer
; - Descriptors
; - GP registers
; - IDT ptr
; - PCI config address
;************************************************************************
Swap_States proc
lea si, [StartSaveArea] ; Swap thread states
lea di, [Saved_State]
mov cx, OFFSET EndSaveArea ; Compute # dwords of state
sub cx, si
shr cx, 2
StateLoop:
lodsd ; Exchange a dword
xchg [di], eax
mov dword ptr [si-4], eax
add di, 4
loop StateLoop
lea si, [SMM_Header] ; Now do the top-level SMM header
lea di, [BIOS_Header]
mov cl, sizeof(SmiHeader)/4
Hdr_Loop:
lodsd
xchg [di], eax
mov [si-4], eax
add di, 4
loop Hdr_Loop
ret
Swap_States endp
;************************************************************************
; Swaps the VSM's registers with the local state
;************************************************************************
VSM_Registers proc
mov esi, [VSM_Buffer] ; Caller's register buffer
mov ax, word ptr [BIOS_Header].EFLAGS
xchg fs:(INT_REGS PTR [esi]).Flags, ax
mov word ptr [BIOS_Header].EFLAGS, ax
lea bx, [Reg_Table]
mov cx, (End_Reg_Table-Reg_Table)/2
Reg_Loop:
mov di, [bx] ; Get offset of register
mov eax, [di] ; Swap with register structure
xchg eax, fs:[esi]
mov [di], eax
add bx, 2 ; Increment ptrs
add esi, 4
loop Reg_Loop
ret
; This table translates between a INT_REGS structure and the PUSHA/POPA ordering
Reg_Table:
dw OFFSET BIOS_EAX
dw OFFSET BIOS_EBX
dw OFFSET BIOS_ECX
dw OFFSET BIOS_EDX
dw OFFSET BIOS_EBP
dw OFFSET BIOS_ESI
dw OFFSET BIOS_EDI
End_Reg_Table:
VSM_Registers endp
;************************************************************************
; Sets a descriptor to a real-mode descriptor
; Input:
; AX = selector
; If selector = 0x0000, a 4 GB descriptor (big-real) is used
; If selector = 0xFFFF, the calling VSM's base/limit is used
; DI = ptr to descriptor
;************************************************************************
Set_Descriptor proc pascal uses di \
DescrPtr: PTR Descriptor
ASSUME di: PTR Descriptor
mov di, [DescrPtr]
mov ebx, 0FFFFh ; 64K limit
or ax, ax ; Selector = 0000h?
jnz short SetSelector
mov ebx, 008FFFFFh ; Yes, then use 4 GB limit (big-real mode)
SetSelector:
movzx eax, ax
mov [di].selector, ax
shl eax, 4
if ALLOW_SMM_SEGMENTS
; If ES == 0xFFFF, use VSM's base
cmp ax, bx
jne short Set_Limit
mov eax, [Current_VSM] ; No, use VSM's base & limit
mov bx, ax
shr bx, 4
mov [di].selector, bx
mov ebx, (VSM_Header PTR fs:[eax]).DS_Limit
endif
Set_Limit:
; EAX = base
; EBX = limit
mov [di].limit_15_0, bx ; Store 24-bit limit
shr ebx, 16
mov [di].limit_19_16, bl
mov [di].base_15_0, ax ; Store 32-bit base
shr eax, 16
mov [di].base_23_16, al
mov [di].base_31_24, ah
ret
ASSUME di: NOTHING
Set_Descriptor endp
align 4
Saved_State:
;******************************************************************************
; The following must match the structure at StartSaveArea in SYSMGR.ASM
BIOS_PCI dd 80000000h
BIOS_EDI dd 0
BIOS_ESI dd 0
BIOS_EBP dd 0
dd 0 ; ESP (not used)
BIOS_EBX dd 0
BIOS_EDX dd 0
BIOS_ECX dd 0
BIOS_EAX dd 0
BIOS_ESP dd 0
BIOS_SS Descriptor {0FFFFh, 0, 0, DATA_ATTR, 0, 0, 0}
BIOS_DS Descriptor {0FFFFh, 0, 0, DATA_ATTR, 0, 0, 0}
BIOS_ES Descriptor {0FFFFh, 0, 0, DATA_ATTR, 0, 0, 0}
BIOS_FS Descriptor {0FFFFh, 0, 0, DATA_ATTR, 0, 0, 0}
BIOS_GS Descriptor {0FFFFh, 0, 0, DATA_ATTR, 0, 0, 0}
Hdr_Address dd 0
IDT_Selector dd 00920000h
IDT_Base dd 00000000h
IDT_Limit dd 0000FFFFh
dw 0 ; Pad
;******************************************************************************
SMM_CONTROL equ EXTL_SMI_EN + INTL_SMI_EN + SMM_INST_EN + NEST_SMI_EN
BIOS_Header SmiHeader {,SMM_CONTROL,,,,,,,,,VSM_CR0, VSM_EFLAGS, VSM_DR7}
ShadowMemory dd 0, 0
ShadowAddr dd 0
ShadowMSR dw 0
VSM_Buffer dd 0
Saved_PIC dw 0
Saved_INT dd 0
Saved_Vector dd 0
OldRCONF db 0
_CODE ENDS
END

View File

@@ -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);
}
}

View File

@@ -0,0 +1,772 @@
;
; 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
;
;*******************************************************************************
;* Implements several system calls
;*******************************************************************************
include SYSMGR.INC
include VSA2.INC
include PCI.INC
include SMIMAC.MAC
include CHIPSET.INC
include VR.INC
.model tiny,c
.586p
.CODE
public SysCall_Table
public ReturnULONG
externdef Sys_SW_INT: proc
externdef Sys_Broadcast: proc
externdef Sys_PassEvent: proc
externdef Sys_State: proc
externdef EmptyMsgQueue: proc
externdef ExitSysCall: proc
externdef Dispatcher: proc
externdef Sys_Exit: proc
externdef Record_VSM_Locations: proc
externdef pascal Lookup_PCI: proc
externdef pascal Lookup_IO: proc
externdef pascal Find_MBus_ID: proc
externdef pascal Send_Event: proc
externdef pascal Schedule_VSM: proc
externdef pascal Allocate_BAR: proc
externdef pascal Register_Event: proc
externdef pascal Report_VSM_Error: proc
externdef pascal Allocate_Resource: proc
externdef pascal Set_Address_Decode: proc
externdef pascal Enable_PCI_Trapping: proc
externdef pascal Unregister_VSM_Events: proc
externdef pascal IRQY_Mapper: proc
externdef pascal Return_Virtual_Value: proc
externdef SysMgr_VSM: dword
externdef VSM_ListHead: dword
externdef Current_VSM: dword
externdef MsgPacket: dword
externdef SMI_Base: dword
externdef IRQ_Base: dword
externdef VSM_Ptrs: dword
externdef Events: EVENT_ENTRY
externdef HardwareInfo: Hardware
align 2
SysCall_Table:
dw OFFSET Sys_Register ; 00 - SYS_CODE_EVENT
dw OFFSET Sys_Yield ; 01 - SYS_CODE_YIELD
dw OFFSET Sys_SW_INT ; 02 - SYS_CODE_SW_INT
dw OFFSET Sys_PassEvent ; 03 - SYS_CODE_PASS_EVENT
dw OFFSET Sys_Unload ; 04 - SYS_CODE_UNLOAD
dw OFFSET Sys_Registers ; 05 - SYS_CODE_REGISTER
dw OFFSET Sys_RdWrPCI ; 06 - SYS_CODE_PCI_ACCESS
dw OFFSET Sys_SetVirtual ; 07 - SYS_CODE_SET_VIRTUAL
dw OFFSET Sys_GetVirtual ; 08 - SYS_CODE_GET_VIRTUAL
dw OFFSET Sys_Broadcast ; 09 - SYS_CODE_BROADCAST
dw OFFSET Sys_State ; 0A - SYS_CODE_STATE
dw OFFSET Sys_Report_Error ; 0B - SYS_CODE_ERROR
dw OFFSET Sys_Resource ; 0C - SYS_CODE_RESOURCE
dw OFFSET Sys_Decode ; 0D - SYS_CODE_DECODE
dw OFFSET Sys_GetDescr ; 0E - SYS_CODE_DESCRIPTOR
dw OFFSET Sys_Lookup ; 0F - SYS_CODE_LOOKUP
dw OFFSET Sys_IRQ_Mapper ; 10 - SYS_CODE_IRQ_MAPPER
dw OFFSET Sys_Result ; 11 - SYS_CODE_RESULT
dw OFFSET Sys_Duplicate ; 12 - SYS_CODE_DUPLICATE
dw OFFSET EmptyMsgQueue ; 13 - SYS_CODE_EXIT
;************************************************************************
; Implements the WRITE_PCI_NO_TRAP macros
;
; On Entry:
; SI = data size (bit 7 = 1 if I/O write);
; EBX = PCI configuration address
; ECX = data (if write)
;************************************************************************
Sys_RdWrPCI proc
push ebx ; Save PCI address
push ecx ; Save data
; Disable trapping of PCI address
push bx ; PCI_Address
push word ptr 0000
call Enable_PCI_Trapping
movzx bp, al ; Save previous trap setting
pop ecx ; Restore data
pop ebx ; Restore PCI address
; Write the PCI address
mov dx, PCI_CONFIG_ADDRESS
mov eax, ebx
out dx, eax
add dl, 4
and al, 3
add dl, al
btr si, 7 ; Read or write ?
jc PCI_Write ; Jmp if write
cmp si, BYTE_IO ; Byte, Word, or Dword ?
je Read_Byte
cmp si, WORD_IO
je Read_Word
Read_Dword:
db 66h ; Force next instruction to be IN EAX,DX
Read_Word:
in ax, dx
jmp short ReturnValue
Read_Byte:
in al, dx
ReturnValue:
push eax ; Save return value
call Restore_Trapping ; Re-enable PCI trapping
pop ax ; Restore return value
pop dx
ReturnULONG::
mov bx, word ptr gs:(VSM_Header).SysStuff.SavedESP
mov word ptr gs:[bx+8*4], ax
mov word ptr gs:[bx+6*4], dx
jmp ExitSysCall
;************************************************************************
PCI_Write:
mov eax, ecx ; Get data to be written
cmp si, WORD_IO ; Byte, Word, or Dword ?
je short Write_Word
cmp si, DWORD_IO
je short Write_Dword
cmp si, BYTE_IO
jne short Ignore ; Ignore if error in parameter
Write_Byte:
out dx, al
jmp short Restore_PCI_Trap
Write_Dword:
db 66h ; Force next instruction to be OUT DX,EAX
Write_Word:
out dx, ax
Restore_PCI_Trap:
call Restore_Trapping ; Re-enable PCI trapping
Ignore:
jmp ExitSysCall
Sys_RdWrPCI endp
;***********************************************************************
; Restores PCI trapping
; On entry:
; BP = 1 means re-enable PCI trapping
;***********************************************************************
Restore_Trapping proc
; Is trapping to be re-enabled ?
cmp bp, 1
jne short Exit
; Yes, restore PCI trapping on this address
; Enable_PCI_Trapping(PCI_Address, EnableFlag);
push bx ; PCI address
push bp ; EnableFlag
call Enable_PCI_Trapping
Exit: ret
Restore_Trapping endp
;***********************************************************************
;
; Register an event to the calling VSM
;
; On entry:
; EBX = Event::Priority
; ECX = Parameter 1
; EDI = Parameter 2
;***********************************************************************
Sys_Register proc
; Register_Event(Event, Priority, VSM, Param1, Param2);
push ebx ; Event::Priority
push [Current_VSM] ; VSM ptr
push ecx ; Param1
push edi ; Param2
call Register_Event
jmp ExitSysCall
Sys_Register endp
;***********************************************************************
; Input:
; BX = Virtual register index
; Output:
; AX = returned data
;***********************************************************************
Sys_GetVirtual proc
xor cx, cx ; Data = 0000
xor di, di ; 0 = read
jmp VirtualCommon
Sys_GetVirtual endp
;***********************************************************************
; Input:
; BX = Virtual register index
; CX = Data
;***********************************************************************
Sys_SetVirtual proc
call Handle_PM
mov di, 1 ; 1 = write
VirtualCommon::
cmp bh, VRC_KEYBOARD ; Allow VRC_KEYBOARD to pass 32-bits
je Reschedule
movzx ecx, cx
Reschedule:
mov edx, [Current_VSM] ; Re-schedule calling VSM
push edx
call Schedule_VSM
call VirtualRegisterEvent
mov ax, 0FFFFh ; Value of an undefined virtual register
mov bx, word ptr gs:(VSM_Header).SysStuff.SavedESP
mov word ptr gs:[bx+8*4], ax
jmp Dispatcher
Sys_SetVirtual endp
Handle_PM proc
if 0;SUPPORT_PM ; requires 78 bytes
; If OHCI VSM is sending a USB event to KBD VSM, send an EVENT_IO_TRAP
; to the PM VSM so system will exit DOZE mode.
cmp bh, VRC_KEYBOARD
jne short Exit
mov eax, [VSM_Ptrs+4*VSM_PM]; Is PM installed ?
or eax, eax
jz short Exit
; Is PM VSM registered for the I/O trap ?
mov al, EVENT_IO_TRAP
FindPM:
mov ah, sizeof(EVENT_ENTRY)
mul ah
mov si, ax
mov eax, (EVENT_ENTRY PTR [Events+si]).Vsm
or eax, eax
jz short Exit
cmp eax, edi ; Is it the PM VSM ?
jne short Next_VSM
cmp (EVENT_ENTRY PTR [Events+si]).Param1, 0060h
je short PM_Is_Dozing
Next_VSM:
mov al, (EVENT_ENTRY PTR [Events+si]).Link
or al, al
jnz FindPM
jmp short Exit
PM_Is_Dozing:
push bx ; Yes, save virtual register info
push cx
mov eax, MSG_EVENT ; Send the PM VSM an EVENT_IO_TRAP[0x60] message
mov ebx, [SysMgr_VSM]
lea si, [PM_Packet]
call Insert_Msg
pop cx ; Restore virtual register info
pop bx
endif
Exit: ret
PM_Packet dd EVENT_IO_TRAP, 0, 0060h
Handle_PM endp
;***********************************************************************
; Sends an EVENT_VIRTUAL_REGISTER to VSM(s)
; On entry:
; BX = Class::Index
; CX = write data
; DI = 0 (read) or 1 (write)
; EDX = From_VSM
;***********************************************************************
VirtualRegisterEvent proc
lea si, [MsgPacket] ; Fill the message packet
movzx eax, bx
mov [si+1*4], eax ; MsgPacket[1] : virtual register index
mov ax, di
mov [si+2*4], eax ; MsgPacket[2] : 0=read 1=write
mov [si+3*4], ecx ; MsgPacket[3] : write data
mov ax, EVENT_VIRTUAL_REGISTER ; No, so it's a VR access
push ax ; Event
push edx ; From_VSM
call Send_Event
ret
VirtualRegisterEvent endp
;***********************************************************************
; Implements the SYS_UNLOAD_VSM macro
;***********************************************************************
Sys_Unload proc
; Find prior VSM to current VSM
mov eax, [Current_VSM]
or eax, eax
jz short Exit
; Remove current VSM from linked list
mov ebx, (VSM_Header PTR fs:[eax]).SysStuff.Blink
mov ecx, (VSM_Header PTR fs:[eax]).SysStuff.Flink
or ebx, ebx ; Is there a previous VSM ?
jnz short IsBackLink
mov [VSM_ListHead], ecx ; No, update VSM_ListHead with VSM at Flink
jmp short FixupBlink
IsBackLink:
mov (VSM_Header PTR fs:[ebx]).SysStuff.Flink, ecx
FixupBlink:
or ecx, ecx
jz short Unregister
mov (VSM_Header PTR fs:[ecx]).SysStuff.Blink, ebx
; Unregister events registered to this VSM
Unregister:
push eax
call Unregister_VSM_Events
call Record_VSM_Locations
Exit: jmp Sys_Exit ; Exit to SysMgr
Sys_Unload endp
;***********************************************************************
; Implements the SYS_ALLOCATE_RESOURCE macro
; Input:
; BL - Resource type
; Other registers - various parameters
;***********************************************************************
Sys_Resource proc
; Only BAR types are implemented at this time
cmp bl, RESOURCE_MEMORY
je short BAR_Resource
cmp bl, RESOURCE_MMIO
je short BAR_Resource
cmp bl, RESOURCE_IO
je short BAR_Resource
cmp bl, RESOURCE_SCIO
je short BAR_Resource
; Not a BAR resource
push bx ; Resource
push ecx ; Param
call Allocate_Resource
jmp ExitSysCall
BAR_Resource:
push bx ; BAR type
push si ; BAR offset
push ecx ; Range
ror edi, 16
push di ; MBus_ID
ror edi, 16
push di ; PCI Device_ID
call Allocate_BAR
jmp ReturnULONG
Sys_Resource endp
;***********************************************************************
; Implements the SYS_REPORT_ERROR macro
; DI = Error code
; EBX = Info1
; ECX = Info2
;***********************************************************************
Sys_Report_Error proc
push di
push ebx
push ecx
call Report_VSM_Error
jmp ExitSysCall
Sys_Report_Error endp
YIELD_HANDLE equ (ONE_SHOT OR SYS_YIELD OR 0000BEEFh)
;***********************************************************************
; Implements the SYS_YIELD macro
;
; Input:
; ECX = milliseconds to suspend the VSM
;***********************************************************************
Sys_Yield proc
mov eax, [Current_VSM] ; VSM that is yielding control
mov fs:(VSM_Header PTR [eax]).SysStuff.RunFlag, RUN_FLAG_WAITING
push word ptr EVENT_TIMER ; Event
push word ptr 0000 ; Priority
push eax ; Vsm
push ecx ; Param1 (ms)
push dword ptr YIELD_HANDLE ; Param2 (handle)
call Register_Event
jmp Sys_Exit ; Exit to SysMgr. Don't return to VSM
Sys_Yield endp
;***********************************************************************
; This system call is obsolete
; Input:
; BH = 0 for Set, 1 for Get
; BL = register definition
; ECX = data if Set
;***********************************************************************
Sys_Registers proc
jmp ExitSysCall
Sys_Registers endp
;***********************************************************************
; Implements the SYS_MAP_IRQ macro
; Maps IRQ source to specified IRQ
; Input:
; BL = Unrestricted Y source (0x00-0x0F)
; CL = IRQ setting
;***********************************************************************
Sys_IRQ_Mapper proc
push bx
push cx
call IRQY_Mapper
jmp ExitSysCall
Sys_IRQ_Mapper endp
;***********************************************************************
; Input:
; BX = Address
; CX = Decode flag
;***********************************************************************
Sys_Decode proc
push bx ; Address
push cx ; Decode (POSITIVE_DECODE or SUBTRACTIVE_DECODE)
call Set_Address_Decode
jmp ExitSysCall
Sys_Decode endp
;***********************************************************************
; Implements the SYS_MBUS_DESCRIPTOR & SYS_IO_DESCRIPTOR macros
;
; On entry:
; BX = Address
; CX = 0 if PCI else I/O
; Returns:
; MSR address of corresponding resource
;***********************************************************************
Sys_GetDescr proc
jcxz PCI
; MSR_Address = Lookup_IO(Address);
push bx
call Lookup_IO
mov bl, 2 ; Restore IO_Flag
jmp Common
; MSR_Address = Lookup_PCI(Address);
PCI: push bx
call Lookup_PCI
xor bx, bx
Common:
mov cx, dx ; Was resource found ?
shl ecx, 16
mov cx, ax
xor eax, eax ; EDX:EAX = 00000000:00000000
xor edx, edx
jecxz ReturnMSRInfo
rdmsr ; Yes, read MSR
test bl, 2 ; Set MSR to default ?
jz ReturnMSRInfo
push edx ; Yes, save current value
push eax
test eax, 000F0000h ; IOD_BM or IOD_SC ?
mov eax, 00000000h ; Default for IOD_SC
mov edx, eax
jz SetDefault
mov eax, 0FFF00000h ; Default for IOD_BM
mov edx, 0000000FFh
SetDefault:
wrmsr ; Set MSR to default value
pop eax ; Restore original MSR value
pop edx
; Return MSR address in ECX and MSR value in EDX:EAX
ReturnMSRInfo:
mov bx, word ptr gs:(VSM_Header).SysStuff.SavedESP
mov gs:[bx+7*4], ecx ; Return MSR address in ECX
mov gs:[bx+8*4], eax ; Return MSR value in EDX:EAX
mov gs:[bx+6*4], edx
jmp ExitSysCall
Sys_GetDescr endp
;***********************************************************************
; Implements the SYS_LOOKUP_DEVICE macro
;
; On entry:
; BX = MBus Device_ID
; CX = Instance
; Returns:
; DX:AX = MSR routing address to MBus device
;***********************************************************************
Sys_Lookup proc
; Find_MBus_ID(USHORT MBus_ID, UCHAR Instance);
push bx
push cx
call Find_MBus_ID
xor ax, ax
jmp ReturnULONG
Sys_Lookup endp
;***********************************************************************
; Implements the SYS_RETURN_RESULT macro
; Returns a byte/word/dword result to the correct context.
; Input:
; EBX = Result to be returned
;***********************************************************************
Sys_Result proc
push OFFSET VSM_Header.SysStuff.State
push ebx ; Value
call Return_Virtual_Value
jmp ExitSysCall
Sys_Result endp
;***********************************************************************
; Implements the SYS_DUPLICATE_VSM macro
; On entry: BX = memory model
; Legend: (C=copy of parent VSM) (N=new copy)
; CS DS SS
; 0: N N N
; 1: C N N
;***********************************************************************
Sys_Duplicate proc
; mov [MemoryModel], bx ; Ignore parameter for new
; Find end of VSMs in memory
mov esi, [Current_VSM]
mov ebx, esi
FindLastVSM:
mov edi, ebx
mov ebx, (VSM_Header PTR fs:[ebx]).SysStuff.Flink
or ebx, ebx
jnz FindLastVSM
; EDI points to last VSM in memory. Find end of last VSM.
mov edx, edi
add edi, (VSM_Header PTR fs:[edi]).DS_Limit
; Copy this VSM's image
mov ecx, (VSM_Header PTR fs:[esi]).DS_Limit
cmp [MemoryModel], 0 ; Use same Code segment ?
je short CopyImage
mov ecx, sizeof(VSM_Header) + VSM_STACK_SIZE
CopyImage:
push edi
push esi
push ecx
shr ecx, 2 ; Convert BYTE count to DWORDs
rep movsd [edi], es:[esi]
pop ecx
pop esi
pop edi
; Patch descriptors
mov (VSM_Header PTR fs:[edi])._DS.base_15_0, di
mov (VSM_Header PTR fs:[edi])._SS.base_15_0, di
mov eax, edi
shr eax, 16
mov (VSM_Header PTR fs:[edi])._DS.base_31_24, ah
mov (VSM_Header PTR fs:[edi])._DS.base_23_16, al
mov (VSM_Header PTR fs:[edi])._SS.base_31_24, ah
mov (VSM_Header PTR fs:[edi])._SS.base_23_16, al
mov (VSM_Header PTR fs:[edi])._DS.limit_15_0, cx
mov (VSM_Header PTR fs:[edi])._SS.limit_15_0, cx
; Required for segments > 64K
; shr ecx, 16
; mov (VSM_Header PTR fs:[edi])._DS.limit_19_16, cl
; mov (VSM_Header PTR fs:[edi])._SS.limit_19_16, cl
cmp [MemoryModel], 0 ; Use same Code segment ?
jne short LinkNewVSM
mov (VSM_Header PTR fs:[edi]).SysStuff.State._CS.base, edi
LinkNewVSM:
; Link the new VSM into the VSM list
mov (VSM_Header PTR fs:[edx]).SysStuff.Flink, edi
mov (VSM_Header PTR fs:[edi]).SysStuff.Blink, edx
mov (VSM_Header PTR fs:[edi]).SysStuff.Flink, 0
; Init EIP
movzx eax, (VSM_Header PTR fs:[edi]).EntryPoint
mov (VSM_Header PTR fs:[edi]).SysStuff.State.Next_EIP, eax
; Init ESP & create the initial stack frame
mov eax, (VSM_Header PTR fs:[edi]).DS_Limit
sub ax, VSM_STACK_FRAME
mov (VSM_Header PTR fs:[edi]).SysStuff.SavedESP, eax
; Schedule the new VSM
push edi
call Schedule_VSM
jmp ExitSysCall
ret ; Gets rid of assembler warning
; Warning: don't make MemoryModel a variable on the stack
; The JMP ExitSysCall bypasses the LEAVE instruction and BP is trashed
MemoryModel dw 0
Sys_Duplicate endp
;***********************************************************************
; Returns TRUE if the VSM is currently yielded
;***********************************************************************
VSM_Is_Yielded proc Vsm: dword
mov ebx, [Vsm]
mov al, 0 ; return FALSE
cmp fs:(VSM_Header PTR [ebx]).SysStuff.RunFlag, RUN_FLAG_WAITING
jne short Exit
mov al, 1 ; return TRUE
Exit:
ret
VSM_Is_Yielded endp
END

View File

@@ -0,0 +1,804 @@
;
; 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
;
;* Function: *
;* This file contains the entry point to the SMM code. *
;* This code performs the following: *
;* 1) saves the processor state *
;* 2) reads the top-level SMI source register(s) *
;* 3) issues message(s) to the appropriate VSM(s) *
;* 4) dispatches to VSM(s) until all messages are handled *
;* 5) restores the processor state
include SYSMGR.INC
include VSA2.INC
include PCI.INC
include SMIMAC.MAC
include CHIPSET.INC
include CS5536.INC
include GX2.INC
.model tiny,c
.586p
.ALPHA
DGROUP GROUP _CODE, _TEXT
_CODE SEGMENT PUBLIC use16 'CODE'
ASSUME DS:_CODE
BRACKETS equ 0
public SysMgr_Entry
public Nested_SMI
public Saved_EAX, Saved_AX
public Saved_EBX, Saved_ECX, Saved_EDX, Saved_PCI
public Saved_ESI, Saved_EDI, Saved_EBP, Saved_ESP
public Saved_SS, Saved_ES, Saved_DS, Saved_FS, Saved_GS
public IDT_Selector, IDT_Base, IDT_Limit
public VSMs_EAX
public Nested_PCI, Nested_EDI, Nested_EAX, Nested_ES
public StartSaveArea, EndSaveArea
public SchedulerStack
public Sys_Exit
public VSM_ListHead
public SMM_Header
public SysMgr_VSM
public Data_Descriptor
public Flat_Descriptor
public Current_VSM
public Nested_Flag
public HardwareInfo
public SMI_Base
public IRQ_Base, IRQ_Mask
public Header_Addr
public BracketFlag
public ExitSysCall
public EmptyMsgQueue
public Dispatcher
public Trap_Code
externdef Trap_Common: proc
externdef Trap7: proc
externdef Get_SMI_Sources: proc
externdef VSA_Entry: proc
externdef VSA_Exit: proc
externdef Show_SMI_Source: proc
externdef Generate_IRQ: proc
externdef pascal Hex_8: proc
externdef pascal Hex_16: proc
externdef pascal Hex_32: proc
externdef pascal SMINT_Handler:proc
externdef INT_Vectors: dword
externdef SMI_Sources: dword
externdef SynchEvents: dword
externdef HiPrioritySMIs: dword
externdef MSRs: dword
externdef SysCall_Table: word
externdef NumDescriptors: byte
externdef Events: byte
externdef MSRs: byte
externdef _end: byte
externdef edata: byte
externdef Handler_Table: SMI_ENTRY
; NOTE: "#define EXTRA_SAVE" in SYSMGR.H must match the number of bytes
; of state (over and above the registers) that is saved by the
; following two macros:
SAVE_STATE macro
pushad ; Save general purpose registers
mov dx, PCI_CONFIG_ADDRESS ; Save PCI Configuration Address
in eax, dx
push eax
endm
RESTORE_STATE macro
pop eax ; PCI Configuration Address
mov dx, PCI_CONFIG_ADDRESS
out dx, eax
popad ; Restore general purpose registers
endm
Start:
; NOTE: The VSA II installer patches a "JMP SysMgr_Entry" over the signature field
dd VSM_SIGNATURE ; VSM signature
db VSM_SYS_MGR ; VSM type
db 0FFh ; Any CPU
dw DEVICE_ID_5536 ; VSA for CS5536
dw VSA_VERSION ; System Manager version
dd OFFSET edata ; Size of System Manager
dw OFFSET SysMgr_Entry ; EntryPoint
dd OFFSET _end ; DS Limit
dw 0007h ; Requirements: 4096-byte boundary
dw VSA_VERSION ; VSA version
Stack_Descriptor:
Descriptor {_end, 0000h, 00h, DATA_ATTR, 00h, 00h, 0000h}
Data_Descriptor:
Descriptor {_end, 0000h, 00h, DATA_ATTR, 00h, 00h, 0000h}
Flat_Descriptor:
Descriptor {0FFFFh, 0000h, 00h, DATA_ATTR, 8Fh, 00h, 0000h}
dw 0 ; .AlignSystem
SMM_Header SmiHeader {} ; .State
VSM_ListHead dd 0 ; .Flink (ptr to 1st VSM; zero if no VSMs)
Trap macro Trap_Num
ORG Trap_Code + (Trap_Num * 8)
mov bx, Trap_Num
jmp Trap_Common
endm
ORG sizeof(VSM_Header)
align 16
;***********************************************************************
; Exception vectors
;***********************************************************************
Trap_Code:
Trap 0
Trap 1
Trap 2
Trap 3
Trap 4
Trap 5
Trap 6
ORG Trap_Code + (7 * 8)
jmp Trap7
Trap 8
Trap 9
Trap 0Ah
Trap 0Bh
Trap 0Ch
Trap 0Dh
Trap 0Eh
Trap 0Fh
;***********************************************************************
; Non-nested VSA entry point *
;***********************************************************************
SysMgr_Entry:
;
; Save state of interrupted task & initialize VSA environment
;
svdc cs:[Saved_DS], ds ; Save DS descriptor & set to SysMgr segment
rsdc ds, cs:[Data_Descriptor]
ASSUME DS:_CODE
svdc [Saved_ES], es ; Save ES descriptor
svdc [Saved_FS], fs ; Save FS descriptor
svdc [Saved_GS], gs ; Save GS descriptor
svdc [Saved_SS], ss ; Save SS descriptor & set to SysMgr segment
rsdc ss, [Stack_Descriptor]
mov [Saved_ESP], esp ; Save ESP & set up SysMgr stack
mov esp, OFFSET SysMgrStack
SAVE_STATE ; Save the general purpose registers on SysMgr's stack
rdtsc ; Get start time of this SMI
mov (VSM_Header PTR ds:[0]).SysStuff.StartTime, eax
mov (VSM_Header PTR ds:[4]).SysStuff.StartTime, edx
rsdc fs, [Flat_Descriptor] ; Set FS descriptor to a 4 GB flat segment
rsdc es, [Flat_Descriptor] ; Set ES descriptor to a 4 GB flat segment
if BRACKETS
cmp [BracketFlag], 0
je short NoBracket
mov dx, DBG_PORT
mov al, '['
out dx, al
NoBracket:
endif
call VSA_Entry ; Perform VSA entry setup
xor eax, eax
mov [Nested_Flag], eax
;
; Check for SMINT
;
test [SMM_Header].SMI_Flags, 1000b
jz short Main_SMI_Loop
push word ptr [Saved_EAX]
call SMINT_Handler
jmp Dispatcher
;***********************************************************************
;***********************************************************************
;***********************************************************************
; *
; Main SMI Loop *
; *
; 1) Read the top-level SMI sources. *
; 2) If no SMIs are pending, exit SMM. *
; 3) Call an SMI handler for each pending SMI source. *
; 4) Dispatch to VSMs that have non-empty message queues. *
; 5) Rinse and repeat. *
; *
;***********************************************************************
;***********************************************************************
;***********************************************************************
Main_SMI_Loop:
call Get_SMI_Sources ; Get source(s) of external SMIs
test ebx, ebx ; If no SMIs pending, exit SMM
jz SMI_Resume
;
; Invoke the handler for each pending SMI source
;
mov [SMI_Sources], ebx
RunHandlers:
lea di, Handler_Table - sizeof (SMI_ENTRY)
NextHandler:
add di, sizeof (SMI_ENTRY) ; Advance ptr to next handler entry
mov eax, (SMI_ENTRY PTR [di]).SMI_Mask
and eax, [SMI_Sources] ; Sources = TopLevelSources & Handler_Table.SMI_Mask
jz NextHandler
push eax ; call Handler_Table.Handler(Sources)
call (SMI_ENTRY PTR [di]).Handler
pop eax
not eax ; TopLevelSources &= ~Sources;
and [SMI_Sources], eax
jnz NextHandler ; if (!TopLevelSources) break;
;
; Dispatch to the VSM on top of the scheduler's stack
;
Dispatcher:
mov si, [SchedulerStack] ; Get scheduler's ptr
mov ebx, [si] ; Pop next VSM
sub si, 4
test ebx, 0FFFF0000h ; Is it a VSM ?
jnz RunTask
test bx, bx ; Callback routine ?
je Main_SMI_Loop
mov [SchedulerStack], si ; Yes, update scheduler ptr
call bx ; Go to callback routine
jmp Dispatcher
RunTask:
mov [SchedulerStack], si ; Save scheduler's ptr
mov [Current_VSM], ebx ; Save ptr to the current VSM
ExecuteTask:
;
; Point SMHR to the VSM's SMM header.
;
lea eax, (VSM_Header PTR [ebx+sizeof(SmiHeader)]).SysStuff.State
mov ecx, MSR_SMM_HDR
wrmsr
;
; Restore the VSM's state
;
rsdc ds, fs:(VSM_Header PTR [ebx])._DS
xor edi, edi
ASSUME di:PTR VSM_Header
rsdc gs, [di]._DS
rsdc ss, [di]._SS ; Restore VSM's SS:SP
lea bx, [di].SysStuff
ASSUME bx:PTR System
mov sp, word ptr [bx].SavedESP
;
; Update statistics
;
rdtsc ; Record start time of the VSM
mov [bx+0].StartTime, eax
add [bx+0].NumSMIs, 1 ; Increment SMI count
adc [bx+4].NumSMIs, edi
;
; Mark VSM active unless it is sleeping
;
mov al, RUN_FLAG_ACTIVE
SetRunFlag:
xchg [bx].RunFlag, al
cmp al, RUN_FLAG_SLEEPING
je SetRunFlag
RESTORE_STATE ; No, restore registers
rsm ; Resume to the VSM
ASSUME DI: NOTHING
ASSUME BX: NOTHING
;***********************************************************************
; Restore state & resume to non-SMM code *
;***********************************************************************
align 16
SMI_Resume:
; Generate internal IRQ(s)
xor ecx, ecx
xchg ecx, [IRQ_Mask]
jecxz NoIRQ
call Generate_IRQ
NoIRQ:
call VSA_Exit ; Perform VSA exit
jc Main_SMI_Loop
; Increment count of SMIs
mov si, OFFSET VSM_Header.SysStuff
ASSUME SI: PTR System
xor ecx, ecx
add [si+0].NumSMIs, 1
adc [si+4].NumSMIs, ecx
; Compute total clocks for this SMI
rdtsc
sub eax, [si+0].StartTime
; Accumulate total clocks spent executing VSA code
add [si+0].Clocks, eax
adc [si+4].Clocks, ecx
ASSUME SI:NOTHING
if BRACKETS
cmp [BracketFlag], 0
je @f
mov dx, DBG_PORT
mov al, ']'
out dx, al
@@:
endif
;***********************************************************************
; Restore the state of the interrupted task *
;***********************************************************************
RESTORE_STATE ; Restore GP registers & PCI addr
mov esp, [Saved_ESP] ; Restore ESP
rsdc ss, [Saved_SS] ; Restore descriptors
rsdc es, [Saved_ES]
rsdc fs, [Saved_FS]
rsdc gs, [Saved_GS]
rsdc ds, [Saved_DS] ; Must be restored last
rsm ; Resume to non-SMM thread
;***********************************************************************
; An SMI has occurred that is not a system call: *
; *
; If synchronous SMI: *
; - Save the state of the interrupted VSM *
; - Reschedule the interrupted VSM *
; - Execute SMI handlers *
; If asynchronous SMI: *
; - If event is not high priority or VSM is marked no-preempt, *
; return to interrupted VSM immediately. *
; - Otherwise, execute SMI handlers *
;***********************************************************************
align 16
NotSysCall:
;
; Save VSM's state and set up SysMgr stack
;
SAVE_STATE ; Save the VSM's state
mov word ptr gs:(VSM_Header).SysStuff.SavedESP, sp
rsdc ss, [Stack_Descriptor] ; Setup System Manager's stack
lea sp, [StartSaveArea]
call Get_SMI_Sources ; Get source(s) of nested SMIs
mov [SMI_Sources], ebx ; Record the pending SMI sources
test ebx, [SynchEvents] ; Is nested SMI a syncronous event ?
jz short AsyncSMI
;
; The SMI is synchronous (I/O or virtualized PCI trap)
;
and ebx, [SynchEvents] ; Record the nested SMI source
or [Nested_Flag], ebx
; It's a trapped or virtualized PCI.
; Record some info about the event.
svdc [Nested_ES], gs ; Save GS descriptor
mov esi, gs:(VSM_Header).SysStuff.SavedESP
mov eax, gs:[si+0] ; Get VSM's PCI address
mov edi, gs:[si+4] ; Get VSM's EDI
mov [Nested_PCI], eax ; Required by PCI_Handler
mov [Nested_EDI], edi ; Required if INS
add esi, VSM_STACK_FRAME - 4
add esi, [Current_VSM] ; Ptr to EAX on VSM's stack
mov [Nested_EAX], esi
ServiceNow:
mov gs:(VSM_Header).SysStuff.RunFlag, RUN_FLAG_READY
Reschedule:
add [SchedulerStack], 4 ; Re-schedule the interrupted VSM
mov ebp, [SMI_Sources] ; Needed by RunHandlers
; Update the clock count used by the VSM
rdtsc
sub eax, gs:(VSM_Header).SysStuff.StartTime
xor edx, edx
add gs:(VSM_Header).SysStuff.Clocks+0, eax
adc gs:(VSM_Header).SysStuff.Clocks+4, edx
jmp RunHandlers
;
; The SMI is asynchronous
;
AsyncSMI:
or ebx, ebx ; If null SMI, just return to VSM
jz short NoPreempt
cmp gs:(VSM_Header).SysStuff.RunFlag, RUN_FLAG_SLEEPING
je Reschedule
jmp ServiceNow
; Is this a high priority SMI ?
; test ebx, [HiPrioritySMIs]
; jnz short ServiceNow ; Yes, execute SMI handlers
;
; Resumes to a VSM from an low-priority asynchronous SMI
;
NoPreempt:
;
; Resumes to a VSM from a system call
;
ExitSysCall: ; Return to caller
rsdc ss, gs:(VSM_Header)._SS
mov sp, word ptr gs:(VSM_Header).SysStuff.SavedESP
rsdc ds, gs:(VSM_Header)._DS
RESTORE_STATE
rsm
;***********************************************************************
; The current VSM has emptied its message queue. It will not be *
; executed again until a new message is entered into its queue. *
; NOTE: SysMgr will be using the last VSM's stack. *
;***********************************************************************
EmptyMsgQueue:
mov gs:(VSM_Header).SysStuff.RunFlag, RUN_FLAG_INACTIVE
jmp short UpdateClocks
Sys_Exit:
; System calls should not count as an SMI
sub gs:(VSM_Header).SysStuff.NumSMIs+0, 1 ; Decrement number of SMIs
sbb gs:(VSM_Header).SysStuff.NumSMIs+4, 0
UpdateClocks:
; Update the clock count used by the VSM
rdtsc
sub eax, gs:(VSM_Header).SysStuff.StartTime
xor edx, edx
add gs:(VSM_Header).SysStuff.Clocks+0, eax
adc gs:(VSM_Header).SysStuff.Clocks+4, edx
jmp Dispatcher
;***********************************************************************
; Schedules a VSM to execute
;***********************************************************************
Schedule_VSM proc pascal uses bx \
Vsm: DWORD
mov eax, [Vsm]
test eax, 0FFFF0000h ; Is it a callback ?
jz Schedule
; Mark VSM ready, if not already on scheduler's stack
mov bl, RUN_FLAG_READY
xchg bl, fs:(VSM_Header PTR [eax]).SysStuff.RunFlag
; cmp bl, RUN_FLAG_READY
; je short Exit
Schedule:
mov bx, [SchedulerStack] ; Get scheduler's ptr
add bx, 4 ; Push the VSM
mov [bx], eax
mov [SchedulerStack], bx ; Update scheduler's ptr
Exit: ret
Schedule_VSM endp
;***********************************************************************
;***********************************************************************
;***********************************************************************
;* *
;* Nested SMI Entry Point *
;* *
;* A nested SMI can occur for one of four reasons: *
;* 1) A system call *
;* 2) An asynchronous event (timer, GPIO, etc.) *
;* 3) A trapped I/O from a VSM (virtual register, PCI access) *
;* 4) Return from a BIOS callback *
;* *
;***********************************************************************
;***********************************************************************
;***********************************************************************
align 16
Nested_SMI:
; Set DS descriptor to System Manager's
rsdc ds, cs:[Data_Descriptor]
; Is it a system call (SMINT) ?
test byte ptr gs:(VSM_Header).SysStuff.State.SMI_Flags, 1000b
jz NotSysCall
;*************************************************************************
;*************************************************************************
;*************************************************************************
; *
; SMI is a system call *
; *
; The VSM's registers are saved on the VSM's stack. *
; DS: and SS:SP are initialized to SysMgr's environment. *
; *
; On Entry: *
; AX = System call code *
; Other registers, depending on the system call *
; *
;*************************************************************************
;*************************************************************************
;*************************************************************************
SystemCall:
cmp ax, SYS_CODE_EXIT ; Check for valid system code
ja short IllegalSysCall ; If invalid, record an error
mov [VSMs_EAX], eax
SAVE_STATE ; Save the VSM's state
mov word ptr gs:(VSM_Header).SysStuff.SavedESP, sp
; Setup System Manager's stack
rsdc ss, [Stack_Descriptor]
lea sp, [StartSaveArea]
; Dispatch to system call routine
movzx eax, word ptr [VSMs_EAX]
jmp [SysCall_Table + eax*2]
;***********************************************************************
; An illegal system call was detected
;***********************************************************************
IllegalSysCall:
; Is it ResumeFromRAM ?
cmp ax, SYS_RESUME_FROM_RAM
je ResumeFromRAM
mov di, ERR_UNDEF_SYS_CALL
mov ebx, eax ; Info1 = system call code
mov ecx, [Current_VSM] ; Info2 = offending VSM
mov ax, SYS_CODE_ERROR ; Fake a SYS_CODE_ERROR
jmp SystemCall
;***********************************************************************
; BIOS is resuming after a Save-to-RAM:
; 1) Re-init VSA state
; 2) Re-schedule the suspended VSM
; 3) Go to VSM dispatcher
;***********************************************************************
ResumeFromRAM:
rsdc fs, [Flat_Descriptor] ; Set FS to a 4 GB flat segment
rsdc es, [Flat_Descriptor] ; Set ES to a 4 GB flat segment
mov ebx, [Current_VSM]
mov ax, fs:(VSM_Header PTR [ebx]).SysStuff.ResumeVector
mov fs:(VSM_Header PTR [ebx]).SysStuff.State.Next_IP, ax
mov fs:(VSM_Header PTR [ebx]).SysStuff.RunFlag, RUN_FLAG_READY
jmp ExecuteTask
align 4
Current_VSM dd 0
HardwareInfo Hardware { }
BracketFlag db 0
;*************************************************************************************
;
; IMPLEMENTATION NOTES:
;
; - The scheduler's stack and System Manager's stack grow toward each other.
;
; - The variables at StartSaveArea are grouped together because they, along with
; the SMM header, represent the entire state of the interrupted task. This is
; important since this state must be saved & restored across a BIOS callback.
;
;*************************************************************************************
align 2
SchedulerStack dw OFFSET Scheduled_VSMs
align 4
Scheduled_VSMs dd 0 ; Marks bottom of scheduler's stack
ORG SYSMGRS_STACK
StartSaveArea:
Saved_PCI dd ?
; NOTE: the following 8 variables must be in the correct order for PUSHAD/POPAD
Saved_EDI dd ?
Saved_ESI dd ?
Saved_EBP dd ?
dd ? ; ESP (not used)
Saved_EBX dd ?
Saved_EDX dd ?
Saved_ECX dd ?
Saved_AX:
Saved_EAX dd ?
SysMgrStack: ; <==== System Manager's stack begins here
Saved_ESP dd OFFSET SysMgrStack ; DO NOT MOVE !!!
;
; NOTE: The SET_REGISTER, GET_REGISTER, GET_DESCRIPTOR, & SET_DESCRIPTOR
; macros assume these are in this exact location and order:
Saved_SS Descriptor { }
Saved_DS Descriptor { }
Saved_ES Descriptor { }
Saved_FS Descriptor { }
Saved_GS Descriptor { }
Header_Addr dd 0 ; Ptr to end of SMM header
IDT_Selector dd 0 ; Saved IDT state
IDT_Base dd 0
IDT_Limit dd 0
dw 0 ; Pad
EndSaveArea label byte
;
; This table contains System Manager structures accesses by INIT.EXE and INFO.EXE.
; Must match the InfoStuff structure in VSA2.H
;
ORG SPECIAL_LOC
dw OFFSET Events
dw OFFSET MSRs
dw OFFSET INT_Vectors
dw OFFSET HardwareInfo
IRQ_Base dd 0 ; Memory-mapped location of Internal IRQs
IRQ_Mask dd 0 ; Mask of IRQs to be generated
; NOTE: The following fields are not referenced by VSMs.
; They are in this structure so INIT.ASM can initialize them.
SysMgr_VSM dd 0 ; Logical address of System Manager
SMI_Base dd 0 ; Memory-mapped location of SMI sources
dw OFFSET Header_Addr ; Offset of SysMgr.SysStuff.State
dw OFFSET StartSaveArea ; Initial value of SysMgr.SysStuff.SavedESP
dw OFFSET MSRs
dw OFFSET NumDescriptors
Nested_EAX dd 0 ; Flat ptr to interrupted VSM's EAX
Nested_EDI dd 0 ; Value of interrupted VSM's EDI
Nested_PCI dd 0 ; PCI config address of interrupted VSM
Nested_Flag dd 0
VSMs_EAX dd 0
Nested_ES Descriptor {}
_CODE ENDS
END Start

View File

@@ -0,0 +1,207 @@
/*
* 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
*/
// Build flags for various optional features
#define HISTORY 0 // History support (value determines size of history buffer; 0=disabled)
#define CHECKED_BUILD 1 // Perform internal sanity checks
#define SUPPORT_CAPABILITIES 1 // Enables support for PCI capabilities list
#define SUPPORT_PRIORITY 0 // Enables message priority logic
#define SUPPORT_FS2 1 // Enables MBIU1 descriptors so FS2 sees same map as GX2
#define USB_FIX 0 // 0=none 1=old 2=new
#define MAX_INT 0x1B // Maximum INT vector supported for BIOS callbacks
#define SYS_YIELD 0x40000000L // Must be >= bit 24
#define DBG_PORT 0x84
#define VSA_POST 0x84 // I/O port for VSA POST codes
#define EXTRA_SAVE 4 // State saved other than registers
#define VSM_STACK_FRAME (8*4+EXTRA_SAVE)// PUSHAD + EXTRA_SAVE
#define SPECIAL_LOC 0xA80 // Determines depth of SysMgr's stack
#define STACK_OFFSET 0x94 // Should be: EndSaveArea - StartSaveArea
#define SYSMGRS_STACK (SPECIAL_LOC-STACK_OFFSET)
#define MAX_REGISTRATIONS 100 // # entries in Events[]
// VSM specific definitions
#define CODE_ATTR 0x9B
#define DATA_ATTR 0x93
#define VSM_CR0 0x00000014
#define VSM_EFLAGS 0x00000002
#define VSM_DR7 0x00000400
#define VSM_STACK_SIZE 0x300 // Size of allocated stack in bytes
#define BIOS_STACK_SIZE 0x100
// VSM States
#define RUN_FLAG_INACTIVE 0x00 // VSM is idle
#define RUN_FLAG_SLEEPING 0x55 // VSM is in Standby/Suspend
#define RUN_FLAG_ACTIVE 0xAA // VSM is running or scheduled to run
#define RUN_FLAG_WAITING 0xEE // VSM has yielded control
#define RUN_FLAG_BLOCKED 0xBB // VSM is blocked
#define RUN_FLAG_READY 0x77 // VSM is ready to execute
// System calls
#define SYS_CODE_EVENT 0x0000 // Event registration
#define SYS_CODE_YIELD 0x0001 // VSM is yielding control
#define SYS_CODE_SW_INT 0x0002 // Software Interrupt (INT xx)
#define SYS_CODE_PASS_EVENT 0x0003 // VSM did not handle an event
#define SYS_CODE_UNLOAD 0x0004 // Unload VSM
#define SYS_CODE_REGISTER 0x0005 // Get/Set special registers
#define SYS_CODE_PCI_ACCESS 0x0006 // Access a PCI dword with trapping disabled
#define SYS_CODE_SET_VIRTUAL 0x0007 // Set virtual register
#define SYS_CODE_GET_VIRTUAL 0x0008 // Get virtual register
#define SYS_CODE_BROADCAST 0x0009 // Broadcast a message to one or more VSMs
#define SYS_CODE_STATE 0x000A // Save/Restore non-SMM state
#define SYS_CODE_ERROR 0x000B // Report error
#define SYS_CODE_RESOURCE 0x000C // Reserve resource
#define SYS_CODE_DECODE 0x000D // Set resource to be subtractive/positive decode
#define SYS_CODE_DESCRIPTOR 0x000E // Get descriptor of virtualized PCI BAR
#define SYS_CODE_LOOKUP 0x000F // Lookup routing for MBus device
#define SYS_CODE_IRQ_MAPPER 0x0010 // Set IRQ mapping (CS5535 only)
#define SYS_CODE_RESULT 0x0011 // Return virtualized result
#define SYS_CODE_DUPLICATE 0x0012 // Duplicate a VSM
#define SYS_CODE_EXIT 0x0013 // Exit to System Manager
#define GET_REG 0x80
#define SET_REG 0x81
#define GET_HDR 0x82
#define SET_HDR 0x83
#define GET_DESCR 0x84
#define SET_DESCR 0x85
// Fields in SMM header flag
#define SMI_FLAGS_CS_WRITABLE 0x0001 // "Cw" bit CS is writable
#define SMI_FLAGS_OUTPUT 0x0002 // "I" bit I/O indicator
#define SMI_FLAGS_REP 0x0004 // "P" bit REP indicator
#define SMI_FLAGS_SMINT 0x0008 // "S" bit SMI occured due to a SMINT
#define SMI_FLAGS_HALT 0x0010 // "H" bit SMI occured during CPU halt
#define SMI_FLAGS_MEMORY 0x0020 // "M" bit 0=I/O, 1=memory
#define SMI_FLAGS_EXT 0x0040 // "X" bit External SMI source
#define SMI_FLAGS_VGA 0x0080 // "V" bit VGA emulation source
#define SMI_FLAGS_NESTED 0x0100 // "N" bit Nested SMI
#define SMI_FLAGS_CS_READABLE 0x8000 // "Cr" bit CS is writable
typedef void (* SMI_Handler)(void);
typedef struct {
SMI_Handler Handler;
unsigned long SMI_Mask;
} SMI_ENTRY;
typedef struct {
unsigned long Vsm;
union {
struct {
unsigned long Param1;
unsigned long Param2;
unsigned long Param3;
};
struct { // Timers
unsigned long Interval;
unsigned short Handle;
unsigned char Timer;
unsigned char Attr;
unsigned long RemainingInterval;
};
struct { // GPIOs
unsigned short Pin;
unsigned short Pme;
unsigned short Attributes;
unsigned short Pm1;
unsigned long CurrentEdge;
};
struct { // PCI header
unsigned short PCI_Addr;
unsigned short Unused;
unsigned short PCI_Mask;
unsigned short Flags;
};
struct { // I/O trap & timeout
unsigned short IO_Base;
unsigned short IO_Timeout;
unsigned short IO_Range;
};
struct { // Virtual Register
unsigned long ClassLow;
unsigned long ClassHigh;
};
};
unsigned long Timestamp[2];
unsigned char Index;
unsigned char Link;
unsigned short Priority;
} EVENT_ENTRY;
typedef struct {
unsigned long Vsm;
unsigned long Event;
unsigned long Param1;
unsigned long Param2;
unsigned long Count;
unsigned long TimeStamp[2];
} EVENT_HISTORY;
typedef struct {
unsigned short History_Array;
int * History_Start;
int * History_End;
int * History_Wrap;
unsigned short HistoryEntries;
} HISTORY_INFO;
//
// An instance of this structure is found in the System Manager at offset SPECIAL_LOC
//
typedef struct {
unsigned short Events; // Events array
unsigned short Descriptors; // MBus Descriptors array
unsigned short Vectors; // INT vectors
unsigned short HardwareInfo; // Hardware structure
unsigned long IRQ_Base; // Used by SYS_GENERATE_IRQ
unsigned long IRQ_Mask; // Used by SYS_GENERATE_IRQ
unsigned long SysMgr_VSM; // Used in SysMgr only
unsigned long SMI_Base; // Used in SysMgr only
unsigned short Header_Addr; // Used in SysMgr only
unsigned short SysMgr_Stack; // Used in SysMgr only
unsigned short MSRs; // Used for DOS_BUILD
unsigned short NumDescrs; // Used for DOS_BUILD
} InfoStuff;

View File

@@ -0,0 +1,729 @@
/*
* 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
*/
//******************************************************************************
//* - Handles I/O inactivity counters
//******************************************************************************
#include "VSA2.H"
#include "PROTOS.H"
#include "GX2.H"
#include "VPCI.H"
#include "DESCR.H"
#include "CS5536.H"
// External prototypes:
void Deallocate_Descriptor(DESCRIPTOR *);
// External variables:
extern ULONG LookupMbiu;
extern ULONG ClocksPerMs;
extern DESCRIPTOR MSRs[];
extern UCHAR NumDescriptors;
extern ULONG Mbiu2;
extern UCHAR NumMbius;
extern MBIU_INFO MbiuInfo[MAX_MBIU];
extern ULONG MbiuSkipFlags[];
extern Hardware HardwareInfo;
#define NUM_PHYSICAL_COUNTERS 7 // Number of physical statistic counters
#define NUM_LOGICAL_COUNTERS 20 // Number of logical statistic counters
#define NUM_LINKED_DESCRIPTORS 3 // Number of descriptors per logical counter
// Local variables:
UCHAR NumPhysCounters= 0;
typedef struct {
ULONG MsrAddr; // MSR address of STATISTICS_CNT
ULONG Prescaler;
ULONG Mask; // IOD_MASK field
ULONG SFlags;
USHORT StandbyFlag;
USHORT Timeout;
USHORT MbiuNumber;
} PHYSICAL_COUNTERS;
typedef struct {
ULONG Mask;
USHORT Address;
USHORT DeviceID;
USHORT Timeout;
UCHAR PhysIndex; // Index to physical counter
UCHAR DescrIndex[NUM_LINKED_DESCRIPTORS]; // Indices to descriptors
} LOGICAL_COUNTERS;
PHYSICAL_COUNTERS PhysCounter[NUM_PHYSICAL_COUNTERS];
LOGICAL_COUNTERS LogCounter[NUM_LOGICAL_COUNTERS];
//***********************************************************************
// Initializes a logical timeout counter
//***********************************************************************
void InitLogicalCounter(LOGICAL_COUNTERS * LogicalPtr)
{ int i;
LogicalPtr->Mask = 0x00000000;
for (i = 0; i < NUM_LINKED_DESCRIPTORS; i++) {
LogicalPtr->DescrIndex[i] = 0xFF;
}
}
//***********************************************************************
// Deallocates a logical counter.
// Deallocates all descriptors associated with a logical counter,
// unless the descriptor is also being used for an I/O trap.
//***********************************************************************
void DeallocateLogicalCounter(LOGICAL_COUNTERS * LogicalPtr)
{ int i, j;
for (i = 0; i < NUM_LINKED_DESCRIPTORS; i++) {
// Get index of I/O descriptor used for this logical counter
j = LogicalPtr->DescrIndex[i];
if (j == 0xFF) {
// No more linked descriptors
break;
}
// If not used for I/O trap or virtualized PCI BAR
if (!(MSRs[j].Flag & IO_TRAP) && !(MSRs[j].Owner)) {
Deallocate_Descriptor(&MSRs[j]);
}
}
// Deallocate logical counter
InitLogicalCounter(LogicalPtr);
}
//***********************************************************************
// Initializes the logical timeout counter structures
//***********************************************************************
void InitLogicalCounters(void)
{ int i;
register LOGICAL_COUNTERS * LogicalPtr;
// Initialize logical counters
LogicalPtr = &LogCounter[0];
for (i=0; i < NUM_LOGICAL_COUNTERS; i++) {
InitLogicalCounter(LogicalPtr++);
}
}
//***********************************************************************
// Initializes the physical timeout counter structures & MSRs
// Called from Init_MBIU().
//***********************************************************************
void InitStatCounters(ULONG Msr, UCHAR NumStatCntrs)
{ int i;
ULONG MsrData[2], SFlags;
register PHYSICAL_COUNTERS * PhysPtr;
static UCHAR Shift=0;
// Initialize physical counters
MsrData[0] = MsrData[1] = 0x00000000;
(USHORT)Msr = MSR_STATISTICS_CNT;
SFlags = 1L << Shift;
// Prepare shift count for next MBIU
Shift += 8;
for (i = 0; i < NumStatCntrs; i++) {
// Initialize the statistic MSR
Write_MSR(Msr+0, MsrData); // MSR_STATISTICS_CNT
Write_MSR(Msr+1, MsrData); // MSR_STATISTICS_MASK
Write_MSR(Msr+2, MsrData); // MSR_STATISTICS_ACTION
// Initialize next physical counter
if (NumPhysCounters < NUM_PHYSICAL_COUNTERS) {
PhysPtr = &PhysCounter[NumPhysCounters];
PhysPtr->MbiuNumber = NumMbius;
PhysPtr->MsrAddr = Msr;
PhysPtr->Mask = 0x00000000;
PhysPtr->StandbyFlag = 0;
PhysPtr->SFlags = SFlags;
SFlags <<= 1;
// Determine 16-bit prescaler
if ((Msr & ROUTING) == Mbiu2) {
// Clock to Southbridge statistic counters is 66 MHz.
PhysPtr->Prescaler = 66000L/8;
} else {
// Clock to Northbridge statistic counters is DRAM clock.
PhysPtr->Prescaler = HardwareInfo.DRAM_MHz * 1000L/8;
// If memory is DDR, DRAM clock is running at 1/2 MBUS frequency
if (!(Read_MSR_LO(0x4C000014) & 0x400)) {
// so adjust the prescaler
PhysPtr->Prescaler >>= 1;
}
}
// Shift into PREDIV field
PhysPtr->Prescaler <<= 8;
// Set counter attributes
(UCHAR)PhysPtr->Prescaler = (ALWAYS_DEC | HIT_LDEN | ZERO_SMI);
// Increment number of statistics counters.
NumPhysCounters++;
} else {
Log_Error("The PhysCounter structure has fewer entries than # of h/w counters");
// Continue initializing, but don't record MSR in array
}
// Advance to next statistic MSR
Msr += 4;
}
}
//***********************************************************************
// Finds the Address corresponding to a bit set in MBD_MSR_SMI.
// Clears the next set bit in the EventMask variable.
//***********************************************************************
USHORT Get_Timeout(ULONG SFlag, UCHAR * StartIndex)
{ UCHAR i, j;
USHORT Address = 0x0000;
register PHYSICAL_COUNTERS * PhysPtr;
register LOGICAL_COUNTERS * LogicalPtr;
// Find the correct logical counter & return the associated address
LogicalPtr = &LogCounter[* StartIndex];
for (i = * StartIndex; i < NUM_LOGICAL_COUNTERS; i++) {
// Is logical counter in use ?
if (LogicalPtr->Mask != 0x00000000) {
// Get physical counter to which it is linked
j = LogicalPtr->PhysIndex;
PhysPtr = &PhysCounter[j];
// Is this counter generating an event ?
if (PhysPtr->SFlags & SFlag) {
// Yes, return either the DeviceID or the Inactive Address
Address = LogicalPtr->DeviceID;
if (!Address) {
Address = LogicalPtr->Address;
}
break;
}
}
LogicalPtr++;
}
// Return logical index
* StartIndex = i+1;
return Address;
}
//***********************************************************************
// Enables/Disables SMIs for a statistic counter
//***********************************************************************
void pascal StatCntrSMI(ULONG MsrAddr, UCHAR EnableFlag)
{ ULONG MsrData[2], Mask;
int j;
MsrData[0] = MsrData[1] = 0x00000000;
if (!EnableFlag) {
Write_MSR(MsrAddr, MsrData);
Write_MSR(MsrAddr+2, MsrData);
}
j = ((UCHAR)MsrAddr - MSR_STATISTICS_CNT) / 4;
j++; // HW Emulation is bit 0
(USHORT)MsrAddr = MBD_MSR_SMI;
Read_MSR(MsrAddr, MsrData);
Mask = 1L << j;
if (EnableFlag) {
MsrData[0] &= ~Mask;
} else {
MsrData[0] |= Mask;
}
Write_MSR(MsrAddr, MsrData);
}
//***********************************************************************
// Sets the IOD_MASK field of STATISTIC_MASK
//***********************************************************************
void pascal Set_IOD_MASK(PHYSICAL_COUNTERS * PhysPtr)
{
Write_MSR_HI(PhysPtr->MsrAddr | 1, PhysPtr->Mask);
}
//***********************************************************************
// Disables an inactivity timer for the specified parameters.
// Param1:
// 31:16 = Timeout in seconds
// 15:00 = I/O Base
// Param2:
// 31:16 = Flags (ONE_SHOT, WRITES_ONLY, READS_ONLY)
// 15:00 = I/O Range
//***********************************************************************
void pascal Clr_MBus_IO_Timeout(ULONG Param1, ULONG Param2)
{ int i;
USHORT Address, Range, Timeout;
MBIU_INFO * MbiuPtr;
register PHYSICAL_COUNTERS * PhysPtr;
register LOGICAL_COUNTERS * LogicalPtr;
// Unpack parameters
Range = (USHORT)Param2;
Address = (USHORT)Param1;
Timeout = (USHORT)(Param1 >> 16);
// Find the corresponding logical counter
LogicalPtr = &LogCounter[0];
for (i = 0; i < NUM_LOGICAL_COUNTERS; i++) {
if (LogicalPtr->Address == Address) {
break;
}
LogicalPtr++;
}
if (i >= NUM_LOGICAL_COUNTERS) {
// ERROR: VSM is unregistering a non-existent timeout.
Report_VSM_Error(ERR_UNREGISTRATION, Address, 0);
return;
}
// Get physical counter corresponding to this logical counter
PhysPtr = &PhysCounter[LogicalPtr->PhysIndex];
// Clear IOD_MASK in the corresponding physical counter
PhysPtr->Mask &= ~LogicalPtr->Mask;
Set_IOD_MASK(PhysPtr);
// Decrement timer count on this MBIU
MbiuPtr = &MbiuInfo[PhysPtr->MbiuNumber];
if (MbiuPtr->ActiveCounters) {
MbiuPtr->ActiveCounters--;
}
// If no more timeouts for this physical counter...
if (PhysPtr->Mask == 0x00000000) {
PhysPtr->StandbyFlag = 0;
// Disable the statistics counter
StatCntrSMI(PhysPtr->MsrAddr, 0);
if (MbiuPtr->ActiveCounters == 0) {
// Restore clock gating on this MBIU
if (MbiuPtr->ActiveCounters == 0) {
Write_MSR_LO(MbiuPtr->Mbiu + MBD_MSR_PM, MbiuPtr->ClockGating);
}
}
} else {
if (MbiuPtr->ActiveCounters == 0) {
Log_Error("MbiuInfo->ActiveCounters is out of sync");
}
}
// Deallocate descriptor(s)
DeallocateLogicalCounter(LogicalPtr);
}
//***********************************************************************
// Enables an inactivity timer for the specified I/O Range
// Param1:
// 31:16 = Timeout in seconds
// 15:00 = I/O Base
// Param2:
// 31:16 = Flags (NOT_GLIUx, ONE_SHOT, WRITES_ONLY, READS_ONLY)
// 15:00 = I/O Range
//***********************************************************************
void pascal Set_MBus_IO_Timeout(USHORT Address, USHORT Timeout, USHORT Range, USHORT Attr, USHORT DeviceID)
{ ULONG MsrAddr, MsrData[2], Addr, Candidate, Flags;
UCHAR i, j, k;
MBIU_INFO * MbiuPtr;
register DESCRIPTOR * Descr;
register PHYSICAL_COUNTERS * PhysPtr;
register LOGICAL_COUNTERS * LogicalPtr;
Flags = (ULONG)Attr << 16;
// Find an available logical counter
LogicalPtr = &LogCounter[0];
for (i=0; i < NUM_LOGICAL_COUNTERS; i++) {
if (LogicalPtr->Mask == 0x00000000) {
break;
}
LogicalPtr++;
}
if (i >= NUM_LOGICAL_COUNTERS) {
Log_Error("The LogCounter structure is not large enough");
return;
}
// Record info about this timeout
LogicalPtr->Address = Address;
LogicalPtr->DeviceID = DeviceID;
LogicalPtr->Timeout = Timeout;
// Set Flags:NOT_GLIUx for GLIUs with no available counters
for (k=0; k < NumMbius; k++) {
// Skip this MBIU ?
if (Flags & MbiuSkipFlags[k]) {
continue;
}
MbiuPtr = &MbiuInfo[k];
j = MbiuPtr->NumCounters;
//
PhysPtr = &PhysCounter[0];
for (i=0; i < NumPhysCounters; i++) {
// Is this counter on the current GLIU ?
if ((MbiuPtr->Mbiu & ROUTING) == (PhysPtr->MsrAddr & ROUTING)) {
// Is it available ?
if (PhysPtr->Mask) {
// No, is it the last counter on this GLIU ?
if (--j == 0) {
// Yes, then exclude from search
Flags |= MbiuSkipFlags[k];
break;
}
}
}
PhysPtr++;
}
}
// Allocate descriptor(s) for address range
Addr = Flags; // Set Addr = Flags::Address
(USHORT)Addr = Address;
k = 0;
while (Range) {
// Find existing descriptor(s) that match Address
j = Find_Matching_IO_Descriptor(&Addr, &Range, 1);
if (j == DESCRIPTOR_NOT_FOUND) {
// No compatible descriptor exists, so create one
// and route it to the subtractive port.
j = Setup_IO_Descriptor(&Addr, &Range, 1);
if (j == DESCRIPTOR_NOT_FOUND) {
// Error: No free descriptors
k = 0xFF;
break;
}
}
Descr = &MSRs[j];
// Record the descriptor index
LogicalPtr->DescrIndex[k] = j;
if (k++ == 0) {
// Record 1st descriptor
MsrAddr = Descr->MsrAddr;
} else {
// Check that all descriptors are on same MBIU
if ((MsrAddr & ROUTING) != (Descr->MsrAddr & ROUTING)) {
// No free descriptors on same MBIU
k = 0xFF;
break;
}
}
// Add the new descriptor to IOD_MASK
LogicalPtr->Mask |= 1L << ((UCHAR)Descr->MsrAddr - MSR_IO_DESCR);
}
// If no descriptor found...
if (k == 0xFF) {
// ERROR: Not enough descriptors to handle request
Report_VSM_Error(ERR_NO_MORE_DESCRIPTORS, Address, 0);
// Deallocate descriptor(s) and logical counter
DeallocateLogicalCounter(LogicalPtr);
return;
}
// Find an appropriate hardware statistic counter
Candidate = 0;
for (i=0; i < NumPhysCounters; i++) {
PhysPtr = &PhysCounter[i];
// Physical counter must be on the same MBIU as the I/O descriptor
if ((PhysPtr->MsrAddr & ROUTING) != (Descr->MsrAddr & ROUTING)) {
continue;
}
if (PhysPtr->Timeout == Timeout) {
// If same timeout, the leverage same counter
break;
}
// Is this counter being used for Standby inactivity detection ?
if (PhysPtr->StandbyFlag) {
// Yes, is the request for Standby ?
if (Flags & FOR_STANDBY) {
// Yes, then must use the same physical counter
break;
}
}
// Mark physical counter as a candidate
Candidate |= 1L << i;
}
// If an existing counter can't be leveraged, find a new one
if (i >= NumPhysCounters) {
// Among the candidates, find an unused counter
for (i=0; i < NumPhysCounters; i++) {
if (Candidate & (1L << i)) {
PhysPtr = &PhysCounter[i];
if (!(PhysPtr->Mask)) {
break;
}
}
}
}
// If physical counter is found, link it to the descriptor
if (i < NumPhysCounters) {
// Increment timer count on this MBIU
MbiuPtr = &MbiuInfo[PhysPtr->MbiuNumber];
MbiuPtr->ActiveCounters++;
// Turn off clock gating on this MBIU
Write_MSR_LO(MbiuPtr->Mbiu + MBD_MSR_PM, Read_MSR_LO(MbiuPtr->Mbiu + MBD_MSR_PM) & 0xFFFFFFF0);
// Record physical counter used for the logical counter
LogicalPtr->PhysIndex = i;
// Mark descriptor as used for I/O timeout
Descr->Flag |= IO_TIMEOUT;
// Record info about this timer
PhysPtr->Timeout = Timeout;
PhysPtr->Mask |= LogicalPtr->Mask;
// Set flag if counter is being used for Standby inactivity detection
if (Flags & FOR_STANDBY) {
PhysPtr->StandbyFlag = 1;
}
// Set STATISTIC_CNT[LOAD_VAL]
MsrAddr = PhysPtr->MsrAddr;
MsrData[0] = MsrData[1] = Timeout * 8*1000L;
Write_MSR(MsrAddr, MsrData);
// Link counter to the descriptor
Set_IOD_MASK(PhysPtr);
// Set STATISTIC_ACTION[PREDIV]
// Set Prescaler to decrement Count every ms
Write_MSR_LO(MsrAddr+2, PhysPtr->Prescaler);
// Enable the statistics counter in MBD_MSR_SMI
StatCntrSMI(MsrAddr, 1);
return;
}
// ERROR: Not enough statistics counter to handle request
Report_VSM_Error(ERR_NO_MORE_DESCRIPTORS, (ULONG)Address, NumPhysCounters);
}
typedef struct {
union {
ULONG dword;
struct {
USHORT IO_Base;
USHORT Timeout;
};
};
} TIMEOUT_P1;
typedef struct {
union {
ULONG Flags;
struct {
union {
USHORT Range;
UCHAR Instance;
};
USHORT Attributes;
};
};
} TIMEOUT_P2;
//***********************************************************************
// Enables/disables an inactivity timer for an I/O Range or GLIU device.
// Param1:
// 31:16 = Timeout in seconds
// 15:00 = I/O Base
// = GLIU DeviceID if Flags[GLIU_ID] is set
// Param2:
// 31:16 = Flags
// 15:00 = Length of I/O range
// = Instance if Flags[GLIU_ID] is set
// EnableFlag:
// 0 = disable
// 1 = enable
//***********************************************************************
void pascal MBus_IO_Timeout(ULONG Param1, ULONG Param2, UCHAR EnableFlag)
{ UCHAR Port, ByteEnables, i, Hit;
USHORT Address, DeviceID = 0x0000;
ULONG MsrAddr;
register DESCRIPTOR * Descr;
TIMEOUT_P1 p1;
TIMEOUT_P2 p2;
// Force use of descriptors in Southbridge
if (!(Param2 & FOR_STANDBY)) {
Param2 |= NOT_GLIU0 | NOT_GLIU1;
}
p1.dword = Param1;
p2.Flags = Param2;
if (p2.Flags & GLIU_ID) {
p2.Flags &= ~GLIU_ID;
DeviceID = p1.IO_Base;
// Don't allow stupid requests
switch (DeviceID) {
case ID_MBIU:
case ID_MDD:
case ID_MCP:
case ID_VAIL:
// Log an error
Report_VSM_Error(ERR_BAD_PARAMETER, EVENT_IO_TIMEOUT, Param1);
return;
}
// Find specified instance of the requested device
MsrAddr = Find_MBus_ID(DeviceID, p2.Instance);
Port = (UCHAR)MsrAddr;
if (!MsrAddr) {
// Log an error
Report_VSM_Error(ERR_HW_MISMATCH, EVENT_IO_TIMEOUT, Param2);
return;
}
MsrAddr = LookupMbiu & ROUTING; // LookupMbiu was set by Find_MBus_ID()
// Find all descriptors on this MBIU/Port
Hit = 0;
for (i = 1; i < NumDescriptors; i++) {
Descr = &MSRs[i];
// Is descriptor routing to a device ?
Address = Descr->Address;
if (Address == 0x0000) {
continue;
}
// Is descriptor on correct MBIU ?
if (MsrAddr != (Descr->MsrAddr & ROUTING)) {
continue;
}
// Is descriptor routing to the requested device ?
if (Port == (Descr->MsrData[1] >> 29)) {
// Yes, determine start address of descriptor
switch (Descr->Type) {
case IOD_SC:
// Determine start address of IOD_SC descriptor
ByteEnables = (UCHAR)(Descr->MsrData[0] >> 24);
while (ByteEnables) {
if (ByteEnables & 1) {
break;
} else {
Address++;
}
ByteEnables >>= 1;
}
// Fall through intended
case IOD_BM:
// Recursive call
p1.IO_Base = Address;
p2.Range = 1;
MBus_IO_Timeout(p1.dword, p2.Flags, EnableFlag);
Hit = 1;
break;
default:
break;
}
}
}
if (Hit || DeviceID != ID_VG) {
DeviceID = 0x0000;
return;
}
// Monitor external video card activity
p1.IO_Base = 0x03C0;
p2.Range = 32;
}
// Check for illegal combination of flags
if ((p2.Flags & ALL_GLIUS) == ALL_GLIUS) {
// ERROR: Illegal combination of EVENT_IO_TIMEOUT flags
Report_VSM_Error(ERR_BAD_PARAMETER, EVENT_IO_TIMEOUT, p2.Flags);
return;
}
if (EnableFlag) {
Set_MBus_IO_Timeout(p1.IO_Base, p1.Timeout, p2.Range, p2.Attributes, DeviceID);
} else {
Clr_MBus_IO_Timeout(p1.dword, p2.Flags);
}
}

View File

@@ -0,0 +1,183 @@
/*
* 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
*/
//*****************************************************************************
//* Routines related to timer management.
//*****************************************************************************
#include "VSA2.H"
#include "CHIPSET.H"
#include "SYSMGR.H"
#include "PROTOS.H"
#include "TIMER.H"
typedef unsigned char (* TIMER_ON)(ULONG, UCHAR);
typedef void (* TIMER_OFF)(unsigned short);
// External prototypes:
extern UCHAR EnableMsTimer_5536(ULONG, UCHAR);
extern USHORT DisableMsTimer_5536(USHORT);
extern void pascal MarkTimerAvailable(USHORT);
// External variables:
extern ULONG MsgPacket[];
extern EVENT_ENTRY Events[];
extern ULONG ClocksPerMs;
extern Hardware HardwareInfo;
extern TIMERS TimerInfo[];
// Local variables:
TIMER_ON EnableTimer;
TIMER_OFF DisableTimer;
USHORT ActiveTimer;
ULONG ActiveInterval;
//***********************************************************************
// Performs initialization related to timers
//***********************************************************************
void InitTimers(void)
{
switch (HardwareInfo.Chipset_ID) {
case DEVICE_ID_5536:
EnableTimer = EnableMsTimer_5536;
DisableTimer = DisableMsTimer_5536;
break;
}
}
//***********************************************************************
// This routine handles timer ticks.
//***********************************************************************
USHORT FilterTimer(EVENT_ENTRY * EventPtr, EVENT EventIndex)
{ USHORT ReturnValue=0;
ULONG Vsm;
static EVENT NextToExpire;
Vsm = EventPtr->Vsm;
// If 1st registered timer, initialize 'next interval' variables
if (EventIndex == EVENT_TIMER) {
NextToExpire = 0;
}
// Only decrement timers associated with the expired h/w timer
if (EventPtr->Timer == ActiveTimer) {
// Has this timer expired ?
if (ActiveInterval >= EventPtr->RemainingInterval) {
// Yes, reset the VSM's remaining interval
EventPtr->RemainingInterval = EventPtr->Interval;
// Fill message packet
MsgPacket[1] = EventPtr->Interval;
MsgPacket[2] = EventPtr->Handle;
// Was timer due to a SYS_YIELD ?
if (EventPtr->Param2 & SYS_YIELD) {
// Yes, schedule the slumbering VSM
Schedule_VSM(Vsm);
}
// Return its Events[] index
ReturnValue = EventIndex;
} else {
// Decrement RemainingInterval by the expired timer interval
EventPtr->RemainingInterval -= ActiveInterval;
}
// Find the next interval on the current h/w timer to expire
if (EventPtr->RemainingInterval < Events[NextToExpire].RemainingInterval) {
// Ignore one-shots that just expired
if (ReturnValue != EventIndex || !(EventPtr->Param2 & ONE_SHOT)) {
NextToExpire = EventIndex;
}
}
}
// If no more timers, then set timer h/w to next interval
if (!EventPtr->Link) {
// Set the timer h/w to the next interval to expire
if (Events[NextToExpire].Vsm) {
Enable_Event(EVENT_TIMER, NextToExpire, 2);
}
}
return ReturnValue;
}
//***********************************************************************
// This routine decrements all software timers. If a software timer has
// expired, it sends an event message to the VSM. The time to the next
// scheduled event and invokes Enable_Event() to restart the timer.
//
//***********************************************************************
void pascal Timer_Handler(USHORT TimerNumber)
{
// Record the active timer
ActiveTimer = TimerNumber;
ActiveInterval = TimerInfo[ActiveTimer].Interval;
// Mark this timer as available
MarkTimerAvailable(TimerNumber);
// Send the timer event
Send_Event(EVENT_TIMER, 0x00000000);
}
//*****************************************************************************
// Enables a millisecond timer to the specified interval
//
// EnableFlag
// 0 = disable
// 1 = new registration
// 2 = reprogram timer to new interval
//*****************************************************************************
void MillisecondTimer(UCHAR EnableFlag, EVENT_ENTRY * EventPtr)
{
if (EnableFlag == 0) {
// Disable the h/w timer
DisableTimer(EventPtr->Timer);
} else {
// Program a hardware timer
EventPtr->Timer = (UCHAR)EnableTimer(EventPtr->RemainingInterval, EventPtr->Attr);
}
}

View File

@@ -0,0 +1,51 @@
/*
* 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
*/
typedef struct {
UCHAR Timer; // Timer number
UCHAR Mapper; // Unrestricted Z field
USHORT Setup; // Scale factor & clock select
USHORT Period; // microseconds/count
ULONG Interval; // Current interval in milliseconds
USHORT Mask; // Bit mask
USHORT TimerBase; // I/O base
} TIMERS;
#define MFGPT_ENABLE 0x8000
#define MFGPT_COMPARE2 0x4000
#define MFGPT_COMPARE1 0x2000
#define MFGPT_INITED 0x1000
#define MFGPT_STOP_EN 0x0800
#define MFGPT_EXT_EN 0x0400
#define MFGPT_CMP2MODE 0x0300
#define MFGPT_CMP2GE 0x0200
#define MFGPT_CMP1MODE 0x00C0
#define MFGPT_CMP1GE 0x0080
#define MFGPT_REV_EN 0x0020
#define MFGPT_CLK_SEL 0x0010
#define MFGPT_SCALE_32 0x0005
#define MFGPT_SCALE_1K 0x000A
#define MFGPT_SCALE_2K 0x000B
#define MFGPT_SCALE_4K 0x000C
#define MFGPT_SCALE_8K 0x000D
#define MFGPT_SCALE_16K 0x000E
#define MFGPT_SCALE_32K 0x000F

View File

@@ -0,0 +1,348 @@
/*
* 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
*/
//*****************************************************************************
//* Implements tables that determine the virtualized PCI topology
//* and register definitions.
//*****************************************************************************
#include "VSA2.H"
#include "VPCI.H"
#include "PCI.H"
#include "CHIPSET.H"
#include "CS5536.H"
#include "SYSMGR.H"
#include "MDD.H"
#include "MAPPER.H"
//***********************************************************************
// Notes on Virtualized PCI Header Tables
//
// 1) The PCI_HEADER_ENTRY structure must contain at a minimum:
// - Vendor & Device IDs
// - Command/Status
// - RevisionID/ClassCode
// - CacheLine/LatencyTimer/HeaderType/BIST
// 2) The Flag field of the last (and only last) entry must have EOL set.
// 3) The Mask field contains a 1 in each bit position that is R/W,
// except for bits 11-15 of the Status register. In this case, a set
// bit means that this feature is reportable.
// 4) Memory BARs require a minimum of 4 KB alignment.
// 5) Registers up to and including BAR0 must be present and in ascending order
//***********************************************************************
// Write-to-Clear Status bits
#define WC_STATUS_BITS ((ULONG)(SIGNALED_TARGET_ABORT | RECEIVED_TARGET_ABORT | RECEIVED_MASTER_ABORT | \
SIGNALED_SYSTEM_ERROR | DETECTED_PARITY_ERROR ))
#define DEVSEL_TIMING (DEVSEL_MEDIUM)
// Defaults
#define DEF_STATUS (PCI_66MHZ_CAPABLE | DEVSEL_TIMING | BACK2BACK_CAPABLE)
#define DEF_MASK (FAST_BACK_TO_BACK | PARITY_RESPONSE)
// Northbridge
#define NB_STATUS (DEF_STATUS | BUS_MASTER) & ~(BACK2BACK_CAPABLE)
#define NB_MASK (DEF_MASK | BUS_MASTER | IO_SPACE) & \
~(SERR_ENABLE | PARITY_RESPONSE | SIGNALED_SYSTEM_ERROR | FAST_BACK_TO_BACK)
// Southbridge
#define SB_MASK (DEF_MASK | SPECIAL_CYCLES)
#define SB_STATUS (DEF_STATUS)
// Graphics
#define GFX_STATUS (DEF_STATUS) & ~(BACK2BACK_CAPABLE)
#define GFX_MASK (DEF_MASK | BUS_MASTER) & \
~(SERR_ENABLE | PARITY_RESPONSE | SIGNALED_SYSTEM_ERROR | FAST_BACK_TO_BACK)
// AES
#define AES_STATUS (DEF_STATUS)
#define AES_MASK (GFX_MASK)
// Bus Masters
#define BM_STATUS (DEF_STATUS)
#define BM_MASK (DEF_MASK | BUS_MASTER)
// OHCI Controllers
#define OHCI_MASK (BM_MASK | IO_SPACE | PARITY_RESPONSE)
//***********************************************************************
// Virtualized Northbridge PCI Device
//***********************************************************************
PCI_HEADER_ENTRY HostBridge_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20801022, 0x00000000},
{ COMMAND, 0x00, NB_STATUS, NB_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x06000000, 0x00000000}, // Bridge: Host
{ 0x0C, 0x00, 0x00800008, 0x0000F808},
{ BAR0, 0x00, 0x00000000, 0x00000000}, // Virtual registers
{ BAR1, 0x00, 0x00000000, 0x00000000}, // CPU PM functionality
{ 0x58, EOL, 0x00000000, 0xFFFFFFFF}, // Regression testing
};
PCI_HEADER_ENTRY Graphics_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20811022, 0x00000000},
{ COMMAND, 0x00, GFX_STATUS, GFX_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x03000000, 0x00000000}, // Display: VGA-compatible
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, 0x00, 0x00000000, 0x00000000}, // Graphics memory
{ BAR1, 0x00, 0x00000000, 0x00000000}, // GP
{ BAR2, 0x00, 0x00000000, 0x00000000}, // VG
{ BAR3, 0x00, 0x00000000, 0x00000000}, // DF
{ BAR4, 0x00, 0x00000000, 0x00000000}, // VIP (LX only)
{ 0x3C, 0x00, 0x00000000, 0x00000000}, // LX only
{ OEM_BAR0, 0x00, 0x00000000, 0x00000000}, // VG
{ OEM_BAR1, 0x00, 0x00000000, 0x00000000}, // VG
{ OEM_BAR2, 0x00, 0x00000000, 0x00000000}, // A0000-AFFFF or A0000-BFFFF if no MONO
{ OEM_BAR3, EOL, 0x00000000, 0x00000000}, // B8000-BFFFF only if MONO present
};
PCI_HEADER_ENTRY AES_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20821022, 0x00000000},
{ COMMAND, 0x00, AES_STATUS, AES_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x10100000, 0x00000000}, // Encryption: entertainment
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, 0x00, 0x00000000, 0x00000000}, //
{ 0x3C, EOL, 0x00000100, 0x000000FF}, // INTA
};
//***********************************************************************
// Virtualized Southbridge PCI Device
//***********************************************************************
PCI_HEADER_ENTRY ISA_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20901022, 0x00000000},
{ COMMAND, 0x00, SB_STATUS, SB_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x06010000, 0x00000000}, // Bridge: ISA
{ 0x0C, 0x00, 0x00800008, 0x0000F808},
{ BAR0, 0x00, 0x00000000, 0x00000008, MSR_LBAR_SMB }, // 8 byte I/O BAR (SMB)
{ BAR1, 0x00, 0x00000000, 0x00000100, MSR_LBAR_GPIO }, // 256 byte I/O BAR (GPIO)
{ BAR2, 0x00, 0x00000000, 0x00000040, MSR_LBAR_MFGPT}, // 64 byte I/O BAR (MFGPT)
{ BAR3, 0x00, 0x00000000, 0x00000020, MSR_LBAR_IRQ }, // 32 byte I/O BAR (IRQ)
{ BAR4, 0x00, 0x00000000, 0x00000080, MSR_LBAR_PMS }, // 128 byte I/O BAR (PMS)
{ BAR5, 0x00, 0x00000000, 0x00000040, MSR_LBAR_ACPI }, // 64 byte I/O BAR (ACPI)
{ 0xD0, EOL, 0x00000000, 0x0000FFFF}, // Software SMI
};
PCI_HEADER_ENTRY Flash_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20911022, 0x00000000},
{ COMMAND, 0x00, DEF_STATUS, DEF_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x05010000, 0x00000000}, // Memory controller: Flash
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, 0x00, 0x00000000, 0x00000000, MSR_LBAR_FLSH0}, // Flash0
{ BAR1, 0x00, 0x00000000, 0x00000000, MSR_LBAR_FLSH1}, // Flash1
{ BAR2, 0x00, 0x00000000, 0x00000000, MSR_LBAR_FLSH2}, // Flash2
{ BAR3, 0x00, 0x00000000, 0x00000000, MSR_LBAR_FLSH3}, // Flash3
{ 0x3C, 0x00, 0x00000100 | Y_IRQ_FLASH, 0x000000FF}, // INTA
{ 0x40, EOL, 0x00000000, 0xFFFFFFFF}, // IDE-Flash switch
};
PCI_HEADER_ENTRY Audio_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20931022, 0x00000000},
{ COMMAND, 0x00, BM_STATUS, BM_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x04010000, 0x00000000}, // Multimedia: Audio
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, 0x00, 0x00000000, 0x00000000}, // 128 byte I/O BAR
{ 0x3C, EOL, 0x00000200 | Y_IRQ_AUDIO, 0x000000FF} // INTB
};
#define USB20_INT (0x00000400 | Y_IRQ_USB2) // INTD
#if SUPPORT_CAPABILITIES
#define USB20_CMD (DEVSEL_TIMING | PCI_66MHZ_CAPABLE | CAPABILITIES_LIST)
#else
#define USB20_CMD (DEVSEL_TIMING | PCI_66MHZ_CAPABLE)
#endif
#define USB20_MASK (BM_MASK & ~(SERR_ENABLE | PARITY_RESPONSE | SIGNALED_SYSTEM_ERROR | FAST_BACK_TO_BACK | BACK2BACK_CAPABLE))
#define OTG_CMD USB20_CMD
#define OTG_MASK (USB20_MASK & ~BUS_MASTER)
PCI_HEADER_ENTRY OHC_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20941022, 0x00000000},
{ COMMAND, 0x00, USB20_CMD, USB20_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x0C031000, 0x00000000}, // Serial Bus: USB : OHCI
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, USE_BMK, 0x00000000, 0x00001000, USBMSROHCB},
#if SUPPORT_CAPABILITIES
{ 0x34, 0x00, PCI_PM_REG, 0x00000000}, // Capabilities pointer
{ PCI_PM_REG, 0x00, 0xC8020001, 0x00000000}, // PCI Power Management
{ PCI_PM_REG+4,PCI_PM, 0x00000000, 0x00008103},
#endif
{ 0x3C, EOL, USB20_INT, 0x000000FF},
};
PCI_HEADER_ENTRY EHC_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20951022, 0x00000000},
{ COMMAND,PCI_EHCI, USB20_CMD, USB20_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x0C032000, 0x00000000}, // Serial Bus: USB : EHCI
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, PCI_EHCI, 0x00000000, 0x00001000, USBMSREHCB},
#if SUPPORT_CAPABILITIES
{ 0x34, 0x00, PCI_PM_REG, 0x00000000}, // Capabilities pointer
{PCI_PM_REG, 0x00, 0xC8020001, 0x00000000}, // PCI Power Management
{PCI_PM_REG+4,PCI_PM, 0x00000000, 0x00008103},
#endif
{ EECP, PCI_EHCI, 0x00000001, 0x01010000}, // USBLEGSUP section 2.1.7 of EHCI spec
{ EECP+4, PCI_EHCI, 0x00000000, 0x0000E03F,0,0,0xE0000000}, // USBLEGCTLSTS section 2.1.8 of EHCI spec
{ SRBN_REG,PCI_EHCI, 0x00000020, 0x00003F00}, // FLADJ/SBRN
{ 0x3C, EOL, USB20_INT, 0x000000FF},
};
PCI_HEADER_ENTRY UDC_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20961022, 0x00000000},
{ COMMAND, 0x00, USB20_CMD, USB20_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x0C03FE00, 0x00000000}, // Serial Bus: USB : device
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, 0x00, 0x00000000, 0x00002000, USBMSRUDCB},
#if SUPPORT_CAPABILITIES
{ 0x34, 0x00, PCI_PM_REG, 0x00000000}, // Capabilities pointer
{PCI_PM_REG, 0x00, 0xC8020001, 0x00000000}, // PCI Power Management
{PCI_PM_REG+4,PCI_PM, 0x00000000, 0x00008103},
#endif
{ 0x3C, EOL, USB20_INT, 0x000000FF},
};
PCI_HEADER_ENTRY OTG_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x20971022, 0x00000000},
{ COMMAND, 0x00, OTG_CMD, OTG_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x0C038000, 0x00000000}, // Serial Bus: USB : No specific interface
{ 0x0C, 0x00, 0x00000008, 0x00000008},
{ BAR0, 0x00, 0x00000000, 0x00001000, USBMSRUOCB},
#if SUPPORT_CAPABILITIES
{ 0x34, 0x00, PCI_PM_REG, 0x00000000}, // Capabilities pointer
{PCI_PM_REG, 0x00, 0xC8020001, 0x00000000}, // PCI Power Management
{PCI_PM_REG+4,PCI_PM, 0x00000000, 0x00008103},
#endif
{ 0x3C, EOL, USB20_INT, 0x000000FF},
};
#define THOR_MASK (BM_MASK | IO_SPACE)
PCI_HEADER_ENTRY Thor_Hdr[] = {
// Reg Flag Value Mask
{ 0x00, 0x00, 0x209A1022, 0x00000000},
{ COMMAND, 0x00, BM_STATUS, THOR_MASK,0,0,WC_STATUS_BITS},
{ 0x08, 0x00, 0x01018000, 0x00000000}, // Mass Storage: IDE
{ 0x0C, 0x00, 0x0000F808, 0x00000008},
{ BAR4, 0x00, 0x00000000, 0x00000000, MSR_LBAR_ATA}, // 16 byte I/O BAR
// The following 4 registers must be contiguous:
{ IDE_CFG, 0x00, 0x00000000, 0x0003FFFF, 0x10},
{ IDE_DTC, 0x00, 0xA8A80000, 0xFFFF0000, 0x12},
{ IDE_CAST, 0x00, 0xFF0000F0, 0xFF0000F0, 0x13},
{ IDE_ETC, 0x00, 0x03030000, 0xC7C70000, 0x14},
{ IDE_PM, EOL, 0x00000000, 0x00000003, 0x15},
};
PCI_HEADER_ENTRY * Virtual_5536[] = {
ISA_Hdr, // F0 ISA bridge
Flash_Hdr, // F1 Flash
Thor_Hdr, // F2 ATA
Audio_Hdr, // F3 AC97
OHC_Hdr, // F4 OHCI
EHC_Hdr, // F5 EHCI
UDC_Hdr, // F6 UDC
OTG_Hdr, // F7 OTG
};
//***********************************************************************
// The following tables determine the virtualized PCI topology
//***********************************************************************
PCI_HEADER_ENTRY * NorthBridge[] = {
HostBridge_Hdr, // F0 Host bridge
0, // F1 Graphics (enabled via softvg)
AES_Hdr, // F2 Encryption
0, // F3
0, // F4
0, // F5
0, // F6
0 // F7
};
// Pointer to the virtualized Southbridge table
VIRTUAL_DEVICE * SouthBridge;
// NOTE: SouthBridge will be inserted into the following table
// at the same DEVSEL as the hardware header.
VIRTUAL_DEVICE * Virtual_Devices[32] = {
// IDSEL Dev# Address Description
// ----- ----- ---------- ---------------------
0, // N/A 0
NorthBridge, // 11 1 0x80000800 HostBridge + Graphics
0, // 12 2
0, // 13 3
0, // 14 4
0, // 15 5
0, // 16 6
0, // 17 7
0, // 18 8
0, // 19 9
0, // 20 10
0, // 21 11
0, // 22 12
0, // 23 13
0, // 24 14
0, // 25 15 0x80007800 CS5535 & CS5536
0, // 26 16
0, // 27 17
0, // 28 18 0x80009000 CS5530
0, // 29 19 0x80009800 CS5530 OHCI
0, // 30 20
0, // 31 21
0, // N/A 22
0, // N/A 23
0, // N/A 24
0, // N/A 25
0, // N/A 26
0, // N/A 27
0, // N/A 28
0, // N/A 29
0, // N/A 30
0, // N/A 31
};

View File

@@ -0,0 +1,338 @@
/*
* 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
*/
//******************************************************************************
//* This file contains the code that unregisters events
//******************************************************************************
#include "VSA2.H"
#include "SYSMGR.H"
#include "PROTOS.H"
// Externals:
extern void pascal Clr_MBus_IO_Trap(ULONG Address, USHORT Range);
extern UCHAR * VsmNames[];
extern UCHAR * EventNames[];
extern UCHAR FreeEvent;
extern EVENT_ENTRY Events[MAX_REGISTRATIONS];
//*****************************************************************************
// Copies an Events[] entry
//*****************************************************************************
extern void pascal Copy_Event(USHORT From, USHORT To);
//*****************************************************************************
// Retires an Events[] entry to the free list
//*****************************************************************************
void pascal Retire_Events_Entry(EVENT Event, USHORT match, USHORT previous)
{ USHORT i;
// Remove Events[match] from the linked list.
i = Events[match].Link;
if (previous) {
Events[previous].Link = (UCHAR)i;
i = match;
} else {
// The first entry in the linked list is being removed.
Copy_Event(i, Event);
}
// Mark the entry as available.
Events[i].Vsm = 0x00000000;
if (i) {
// Put Events[] entry on free list
Events[i].Link = FreeEvent;
FreeEvent = (UCHAR)i;
}
}
//*****************************************************************************
// Unregisters a PCI trap
//*****************************************************************************
USHORT pascal Unregister_PCI_Trap(VSM Vsm, USHORT PCI_Addr, USHORT PCI_Mask)
{ USHORT EventIndex, IDSEL_Count=0, previous=0, match=0;
register EVENT_ENTRY * EventPtr;
// The entire event chain must be traversed to find out how
// many registrations are trapping this IDSEL. If only this
// one, then the IDSEL in the MPCI_PBUS MSR will be cleared.
EventIndex = EVENT_PCI_TRAP;
while (Events[EventIndex].Vsm) {
EventPtr = &Events[EventIndex];
// Check if IDSEL matches
if ((EventPtr->PCI_Addr & 0xF800) == (PCI_Addr & 0xF800)) {
IDSEL_Count++;
// If it is the requested VSM...
if (EventPtr->Vsm == Vsm) {
// and the PCI Address/Mask match...
if (EventPtr->PCI_Addr == PCI_Addr && EventPtr->PCI_Mask == PCI_Mask) {
// Record the EventIndex to be removed
match = EventIndex;
}
}
}
// Record index immediately before the matching Events[] entry
if (!match) {
previous = EventIndex;
}
// Get the next entry in the linked list
EventIndex = EventPtr->Link;
} // end while
// If this is the only registration for this IDSEL...
if (IDSEL_Count == 1) {
// disable trapping this IDSEL
Disable_Event(EVENT_PCI_TRAP, match);
}
// Retire the Events[] entry
Retire_Events_Entry(EVENT_PCI_TRAP, match, previous);
return match;
}
//*****************************************************************************
// Disassociates an event from a VSM. This may occur as a result of a
// VSM performing the UNREGISTER_EVENT() macro, or if a VSM is being
// removed or replaced.
//*****************************************************************************
// RESOURCE_COUNT:
// 1) Must be power of 2 since the Mod (%) operator is used
// 2) A minimum of 32 (# GPIOs)
// 3) A maximum of 256
#define RESOURCE_COUNT 128
USHORT pascal Unregister_Event(EVENT Event, VSM Vsm, ULONG Param1, ULONG Param2)
{ USHORT EventIndex, i, j=4, k=0, previous=0, match=0;
static UCHAR HW_Resource[RESOURCE_COUNT];
UCHAR IO_Base, IO_Range;
ULONG Mask1=0x00000000, Mask2=0x00000000;
register EVENT_ENTRY * EventPtr;
// Determine which parameters must match
switch (Event) {
case EVENT_TIMER:
// Only require Handle to match
Mask2 = 0x0000FFFF;
j = 8; // # h/w timers
break;
case EVENT_PWM:
case EVENT_PME:
case EVENT_GPIO:
// Only require pin to match
Mask1 = 0x0000FFFF;
j = 32; // max # GPIO pins
break;
case EVENT_IO_TRAP:
j = RESOURCE_COUNT;
// Only require I/O addresses within range to match
Mask1 = 0x00010000 - RESOURCE_COUNT;
break;
case EVENT_PCI_TRAP:
match = Unregister_PCI_Trap(Vsm, (USHORT)Param1, (USHORT)Param2);
return match;
case EVENT_IO_TIMEOUT:
// Require Param1 to match
Mask1 = 0xFFFFFFFF;
break;
}
// Zero the h/w resource usage counters
for (i=0; i<j; i++) {
HW_Resource[i] = 0;
}
j = 0;
// The entire event chain must be traversed to find out how
// many registrations are using the resource. If more than
// one, then the hardware will not be disabled.
EventIndex = Event;
while (Events[EventIndex].Vsm) {
EventPtr = &Events[EventIndex];
switch (Event) {
case EVENT_TIMER:
j = (USHORT)EventPtr->Timer;
break;
case EVENT_PWM:
case EVENT_PME:
case EVENT_GPIO:
j = (USHORT)EventPtr->Pin;
break;
}
// Check if parameters match
if ((EventPtr->Param1 & Mask1) == (Param1 & Mask1) &&
(EventPtr->Param2 & Mask2) == (Param2 & Mask2)) {
if (Event == EVENT_IO_TRAP) {
// Accumulate usage count for each I/O location in range
IO_Base = (UCHAR)EventPtr->IO_Base;
IO_Range = (UCHAR)EventPtr->IO_Range;
for (i = 0; i < IO_Range; i++) {
k = (UCHAR)(i + IO_Base) % RESOURCE_COUNT;
HW_Resource[k]++;
}
}
// If it is the requested VSM...
if (EventPtr->Vsm == Vsm) {
// Record which h/w resource is being disabled
switch (Event) {
case EVENT_IO_TRAP:
if (match) {
// There are overlapping I/O ranges in the same VSM
if ((EventPtr->IO_Base != (USHORT)Param1) ||
(EventPtr->IO_Range != (USHORT)Param2)) {
// This is not the one being removed
break;
}
}
case EVENT_PWM:
case EVENT_PME:
case EVENT_GPIO:
case EVENT_TIMER:
k = j;
default:
// Record the EventIndex to be removed
if (!match) {
match = EventIndex;
}
break;
}
}
}
// Record entry previous to 'match'
if (!match) {
previous = EventIndex;
}
// Increment resource usage count
if (Event != EVENT_IO_TRAP) {
HW_Resource[j]++;
}
// Link to the next entry in the list.
EventIndex = EventPtr->Link;
} // end while
if (match) {
switch (Event) {
USHORT Range;
case EVENT_IO_TRAP:
Range=0x0000;
EventPtr = &Events[match];
Param1 |= Param2 & 0xFFFF0000;
for (j = 0; j < (UCHAR)Param2; j++) {
k = (UCHAR)((j + EventPtr->Param1) % RESOURCE_COUNT);
if (HW_Resource[k] > 1) {
if (Range) {
// Found end of a range used exclusively by this VSM
Clr_MBus_IO_Trap(Param1, Range);
Param1 += Range;
Range = 0;
} else {
(USHORT)Param1++;
}
} else {
Range++;
}
}
if (Range) {
Clr_MBus_IO_Trap(Param1, Range);
}
break;
default:
// If only one registration is using the h/w resource, disable it
if (HW_Resource[k] == 1) {
case EVENT_IO_TIMEOUT: // Statistic counter logic keeps track of usage
Disable_Event(Event, match);
}
case EVENT_SOFTWARE_SMI:
break;
}
// Retire the Events[] entry
Retire_Events_Entry(Event, match, previous);
} else {
// A VSM attempted to unregister a event that it is not registered for
Log_Error("Attempt to unregister EVENT_%s[0x%08X;0x%08X] by the %s VSM", EventNames[Event], Param1, Param2, VsmNames[Get_VSM_Type(Vsm)]);
}
return match;
}
//*****************************************************************************
// Removes all events registered to a VSM.
//*****************************************************************************
void pascal Unregister_VSM_Events(VSM Vsm)
{ register EVENT Event;
register EVENT_ENTRY * EventPtr;
// Unregister all events registered to this VSM
for (Event=1; Event <= MAX_EVENT; Event++) {
EventPtr = &Events[Event];
while (EventPtr->Vsm) {
if (EventPtr->Vsm == Vsm) {
if (Unregister_Event(Event, Vsm, EventPtr->Param1, EventPtr->Param2)) {
// Start over on this event since there might be others for this VSM.
Event--;
break;
}
}
EventPtr = &Events[EventPtr->Link];
}
}
}

View File

@@ -0,0 +1,642 @@
;
; 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
;
;*******************************************************************************
;* Miscellaneous utility routines
;*******************************************************************************
include SYSMGR.INC
include VSA2.INC
include PCI.INC
include GX2.INC
.model tiny,c
.586p
.CODE
externdef SchedulerStack: word
externdef SysMgr_VSM: dword
externdef Saved_PCI: dword
externdef Nested_PCI: dword
externdef MsgPacket: dword
externdef ClocksPerMs: dword
externdef StartSaveArea: dword
externdef Header_Addr: dword
externdef Nested_Flag: dword
externdef VSM_Ptrs: dword
externdef Events: EVENT_ENTRY
;************************************************************************
;
; 8 bit I/O routines
;
;************************************************************************
in_8 proc pascal \
io_port: word
mov dx, [io_port]
in al, dx
ret
in_8 endp
out_8 proc pascal \
io_port: word, \
io_data: byte
mov dx, [io_port]
mov al, [io_data]
out dx, al
ret
out_8 endp
;************************************************************************
;
; 16 bit I/O routines
;
;************************************************************************
in_16 proc pascal \
io_port: word
mov dx, [io_port]
in ax, dx
ret
in_16 endp
out_16 proc pascal \
io_port: word, \
io_data: word
mov dx, [io_port]
mov ax, [io_data]
out dx, ax
ret
out_16 endp
;************************************************************************
;
; 32 bit I/O routines
;
;************************************************************************
in_32 proc pascal \
io_port: word
mov dx, [io_port]
in eax, dx
mov edx, eax
shr edx, 16
ret
in_32 endp
out_32 proc pascal \
io_port: word, \
io_data: dword
mov dx, [io_port]
mov eax, [io_data]
out dx, eax
ret
out_32 endp
;************************************************************************
;
; Input:
; Ptr to a VSM header
;
; Output:
; Ptr to the next VSM in the chain
;
;************************************************************************
GetFlink proc pascal, \
VSM_Ptr: dword
mov ebx, [VSM_Ptr]
mov eax, (VSM_Header PTR fs:[ebx]).SysStuff.Flink
mov edx, eax
shr edx, 16
ret
GetFlink endp
;************************************************************************
; Writes a BYTE, WORD, DWORD to a 32-bit address
;************************************************************************
write_flat_size proc pascal \
Address: dword, \
Data: dword, \
Len: byte
mov ebx, [Address]
mov eax, [Data]
mov cl, [Len]
cld
cmp cl, BYTE_IO
jne short CheckWord
mov fs:[ebx], al
jmp short Exit
CheckWord:
cmp cl, WORD_IO
je short WriteWord
WriteDword:
db 66H
WriteWord:
mov fs:[ebx], ax
Exit: ret
write_flat_size endp
;************************************************************************
; Writes a DWORD to a 32-bit address
;************************************************************************
write_flat proc pascal \
Address: dword, \
Data: dword
mov ebx, [Address]
mov eax, [Data]
mov fs:[ebx], eax
ret
write_flat endp
;************************************************************************
; Reads a DWORD from a 32-bit address
;************************************************************************
read_flat proc pascal \
Address: dword
mov ebx, [Address]
mov eax, fs:[ebx]
mov edx, eax
shr edx, 16
ret
read_flat endp
;************************************************************************
;
; Copies the parameters for a synchronous event from the appropriate SMI
; header to the MsgPacket array.
; NOTE: This routine should only be called from a Synchronous SMI handler.
;
; On exit:
; MsgPacket[1]: 15:0 - Flags field from SMM header
; MsgPacket[2]: 15:0 - I/O address (or PCI address) from SMM header
; 31:16 - Data Size field from SMM header
; MsgPacket[3]: Data (if I/O write)
;
; Returns ptr to appropriate SMM header.
;
;************************************************************************
Get_Header_Params proc pascal \
SMI_Event: dword
mov bx, OFFSET VSM_Header.SysStuff.State
ASSUME BX: PTR SmiHeader
mov eax, [SMI_Event] ; Is it a nested event ?
test [Nested_Flag], eax
je Copy_Params
not eax ; Yes, clear the event
and [Nested_Flag], eax
push si ; Copy VSM's header to local buffer
mov si, bx
lea bx, [Nested_Header]
push bx
mov cx, sizeof(SmiHeader)/4
cld
CopyHdr:
lodsd gs:[si]
mov dword ptr [bx], eax
add bx, 4
loop CopyHdr
pop bx
pop si
; Copy parameters from SMM header to MsgPacket[]
Copy_Params:
movzx eax, [bx].SMI_Flags
mov [MsgPacket+4*1], eax ; MsgPacket[1]
; Is it a PCI trap ?
mov eax, dword ptr [bx].IO_addr
mov dx, ax
and dl, NOT 3
cmp dx, PCI_CONFIG_DATA
jne short StoreAddr
; Yes, get PCI address from appropriate context
mov cl, al ; Get 2 LSBs of PCI address
and cl, 3
mov ax, word ptr [Nested_PCI]
cmp bx, OFFSET [Nested_Header]
je short Get_PCI
mov ax, word ptr [Saved_PCI]
Get_PCI:
or al, cl
StoreAddr:
mov [MsgPacket+4*2], eax ; MsgPacket[2]
; Get write data
mov ecx, [bx].write_data
shr eax, 16 ; Put I/O size into AL
cmp al, DWORD_IO ; Dword I/O ?
je short StoreData
movzx ecx, cx
cmp al, WORD_IO ; Word I/O ?
je short StoreData
xor ch, ch ; Byte I/O
StoreData:
mov [MsgPacket+4*3], ecx ; MsgPacket[3]
mov ax, bx ; Return ptr to header
ret
Nested_Header SmiHeader {}
Get_Header_Params endp
ASSUME BX: NOTHING
;************************************************************************
; Returns the # milliseconds elapsed on a timer.
;************************************************************************
ElapsedSoFar proc StartTime: PTR
rdtsc ; Get current timestamp
mov bx, [StartTime] ; Subtract timer's start time
sub eax, [bx+0]
sbb edx, [bx+4]
idiv [ClocksPerMs] ; Convert delta to milliseconds
mov edx, eax
shr edx, 16
ret
ElapsedSoFar endp
;************************************************************************
; Returns the timestamp counter in the passed buffer
;************************************************************************
Store_Timestamp proc pascal \
TimeStamp: PTR
rdtsc
mov bx, [TimeStamp]
mov [bx+0], eax
mov [bx+4], edx
ret
Store_Timestamp endp
;************************************************************************
; Returns the type of the VSM pointed to by the Vsm parameter
;************************************************************************
Get_VSM_Type proc pascal \
Vsm:dword
mov ebx, [Vsm]
mov al, fs:(VSM_Header PTR [ebx]).VSM_Type
ret
Get_VSM_Type endp
;************************************************************************
; Translates a logical address to a physical address via the page tables
; NOTES:
; - This routine should only be called if paging is enabled.
; - All page & segment protection has already occurred.
;************************************************************************
PAGE_ATTR equ 0FFFh
CR4_PSE_BIT equ 0010h
PDIR_PS_BIT equ 0080h
OFFSET_4M equ 0003FFFFFh
PAGEBASE_4M equ 0FFC00000h
Convert_To_Physical_Addr proc pascal \
Logical: dword
; Start by checking for 4MB page possibility
mov eax, CR4
test ax, CR4_PSE_BIT
jz short page4K
mov ebx, CR3 ; Get ptr to page directory base
and ebx, 0FFFFFC00h ; Mask attribute bits
mov edx, [Logical] ; Get address to translate
shr edx, 22 ; Get page directory index
; See if this directory entry points to a 4MB page
mov ebx, fs:[ebx+edx*4]
test bx, PDIR_PS_BIT
jz short page4K
and ebx, PAGEBASE_4M ; Get the page base offset
mov eax, [Logical] ; Get address to translate
and eax, OFFSET_4M ; Peel off the directory index
or eax, ebx ; Combine the base and offset
jmp short Exit
page4K:
mov ebx, CR3 ; Get ptr to page directory base
and ebx, 0FFFFFC00h ; Mask attribute bits
mov eax, [Logical] ; Get address to translate
movzx ecx, ax ; Extract page offset
and cx, PAGE_ATTR ; (contains offset into 4K page)
shr eax, 12 ; Remove page offset
mov edx, eax
shr edx, 10 ; Get page directory offset
mov ebx, fs:[ebx+edx*4]
and bx, NOT PAGE_ATTR ; Remove page directory attributes
and eax, 03FFh ; Extract page table offset
mov eax, fs:[ebx+eax*4]
and ax, NOT PAGE_ATTR ; Remove page attributes
add eax, ecx ; Add page offset
Exit: mov edx, eax ; Return translated addr in DX:AX
shr edx, 16
ret
Convert_To_Physical_Addr endp
;************************************************************************
; Marks a 'Blocked' VSM to 'Ready'
;************************************************************************
Unblock_VSM proc pascal Vsm: dword
mov ebx, [Vsm]
mov fs:(VSM_Header PTR [ebx]).SysStuff.RunFlag, RUN_FLAG_READY
ret
Unblock_VSM endp
;MEJ
;************************************************************************
; This routine determines if an event should wake the system.
; If so, the PMCore VSM's RunFlag is changed from 'Sleeping' to 'Ready'.
; There currently are two cases:
; 1) A timer for either the APM or PMCore VSM
; 2) A press of the sleep button while in Legacy PM mode
;
; Returns TRUE if the event is a wake event.
;************************************************************************
;IsWakeEvent proc pascal \
; Vsm: DWORD
;
; mov ebx, [Vsm]
;
; ; Is event for a PM-related VSM ?
; cmp fs:(VSM_Header PTR [ebx]).VSM_Type, VSM_PM
; je short PossibleWakeEvent
; cmp fs:(VSM_Header PTR [ebx]).VSM_Type, VSM_APM
; jne short NotWakeEvent
;
; ; Yes, mark PM VSM 'Ready' if it is 'Sleeping'
;PossibleWakeEvent:
; mov ebx, [VSM_Ptrs+4*VSM_PM]
; mov al, fs:(VSM_Header PTR [ebx]).SysStuff.RunFlag
; cmp al, RUN_FLAG_SLEEPING
; jne short NotWakeEvent
; mov fs:(VSM_Header PTR [ebx]).SysStuff.RunFlag, RUN_FLAG_READY
; jmp Exit
;
;
;NotWakeEvent:
; xor al, al
;
;Exit: ret
;
;IsWakeEvent endp
;************************************************************************
; Returns the flat address to the VSM performing a system call
; Used for reporting errors in a system call.
;************************************************************************
Get_SysCall_Address proc pascal \
Vsm: dword, \
Depth: byte
mov eax, [Vsm]
cmp eax, [SysMgr_VSM]
jne short Get_VSM_Addr
if CHECKED_BUILD
mov dx, sp ; Save BP & SP
shl edx, 16
mov dx, bp
mov cl, [Depth]
add cl, 2 ; Include stack frames for this routine's & Error_Report()
PopStackFrame:
mov bx, sp
leave ; Pop a stack frame
cmp sp, OFFSET StartSaveArea
jae short Bail
cmp sp, [SchedulerStack]
jb short Bail
dec cl
jnz PopStackFrame
jmp short GetFault
Bail: mov sp, bx
GetFault:
mov bx, sp ; Get return address to faulting CALL
movzx ebx, word ptr [bx]
sub bx, 3 ; Account for CALL sys_xxxxx
mov bp, dx ; Restore BP & SP
shr edx, 16
mov sp, dx
else
xor ebx, ebx ; Don't attempt to determine address
endif
jmp short Result
Get_VSM_Addr:
ASSUME BX: PTR word
; There are 3 cases:
; 1) A system call.
; 2) In-line assembly (e.g. direct I/O virtual register)
; 3) A subroutine call to offending I/O
mov bx, word ptr gs:(VSM_Header).SysStuff.State.Next_EIP
cmp gs:[bx-2], 380Fh ; Was it from a SMINT (system call)
je short Sys_Call
mov dx, gs:[bx] ; Get next two bytes of VSM's code
dec bx ; In case it is in-line assembly
; If the next two instructions are LEAVE & RET, then it is a
; subroutine. Report the caller's address.
cmp dl, 0C9h ; Is the next instruction a LEAVE ?
jne short Result ; No, must be in-line assembly
and dh, NOT 1 ; Yes, is the next one a struction a RET ?
cmp dh, 0C2h
jne short Result ; No, must be in-line assembly
Sys_Call:
mov bx, word ptr gs:(VSM_Header).SysStuff.SavedESP
mov bx, gs:[bx+3*4] ; Get caller's BP
movzx ebx, gs:[bx+2] ; Get SP at time of CALL sys_xxxx
sub bx, 3 ; Account for CALL sys_xxxxx
Result:
add eax, ebx
mov edx, eax
shr edx, 16
ret
Get_SysCall_Address endp
;************************************************************************
; Returns the 8 MSBs of the DEVID field of the Device Capabilities MSR
;************************************************************************
GetPortID proc MBD_Addr: dword
mov ecx, [MBD_Addr]
mov cx, MBD_MSR_CAP
rdmsr
shr eax, ID_SHIFT
xor ah, ah
ret
GetPortID endp
;************************************************************************
; Clears pending h/w emulation events in an GeodeLink device
;************************************************************************
ClearMbiu proc pascal Mbiu: dword
mov ecx, [Mbiu]
or ecx, ecx
jz short Exit
mov cx, MBD_MSR_SMI
rdmsr
mov dl, 1
wrmsr
mov cx, MBD_MSR_ERROR
rdmsr
wrmsr
Exit: ret
ClearMbiu endp
;************************************************************************
; Trims a P2D_R descriptor by Range
;************************************************************************
Trim_P2D_R proc pascal uses esi \
MsrAddr: dword, \
Range: dword, \
MsrData: PTR
mov ecx, [MsrAddr] ; Get current MSR value
rdmsr
mov ebx, [Range] ; Adjust by Range bytes
mov esi, ebx
shr esi, (12+12)
shl ebx, (20-12)
sub eax, ebx
sbb edx, esi
wrmsr
mov bx, [MsrData] ; Return modified MSR
mov dword ptr [bx+0], eax
mov dword ptr [bx+4], edx
ret
Trim_P2D_R endp
end

View File

@@ -0,0 +1,885 @@
/*
* 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
*/
//******************************************************************************
//* Utility routines related to virtualized PCI config headers
//******************************************************************************
#include "VSA2.H"
#include "PCI.H"
#include "GX2.H"
#include "VPCI.H"
#include "SYSMGR.H"
#include "CHIPSET.H"
#include "PROTOS.H"
#include "DESCR.H"
#include "MDD.H"
// External function declarations:
extern void pascal Parse_Descriptor(UCHAR, ULONG *, ULONG *);
extern void pascal Trim_P2D_R(ULONG, ULONG, ULONG *);
// External variable declarations:
extern UCHAR DynamicVSALoad;
extern UCHAR MC_Port, VG_Port;
extern UCHAR MBIU1_SelfReference;
extern UCHAR End_of_POST;
extern ULONG MDD_Base;
extern ULONG Mbiu0, Mbiu1, Mbiu2;
extern ULONG MPCI_NB, MPCI_SB;
extern DESCRIPTOR MSRs[];
extern ULONG ExtendedMemoryDescr0, ExtendedMemoryDescr1;
extern Hardware HardwareInfo;
extern VIRTUAL_DEVICE * Virtual_Devices[];
extern VIRTUAL_DEVICE * SouthBridge;
extern PCI_HEADER_ENTRY * NorthBridge[];
extern PCI_HEADER_ENTRY * Virtual_5536[];
extern PCI_HEADER_ENTRY Graphics_Hdr[];
extern PCI_HEADER_ENTRY HostBridge_Hdr[];
extern PCI_HEADER_ENTRY AES_Hdr[];
extern PCI_HEADER_ENTRY ISA_Hdr[];
extern PCI_HEADER_ENTRY Thor_Hdr[];
extern PCI_HEADER_ENTRY Audio_Hdr[];
extern PCI_HEADER_ENTRY Flash_Hdr[];
// Local variable declarations:
PCI_HEADER_ENTRY * CommandPtr, * HdrPtr;
PCI_HEADER_ENTRY Dummy_Hdr[] = {
{0x00, 0x00, 0xFFFFFFFF, 0x00000000},
{0x00, 0x00, 0xFFFFFFFF, 0x00000000},
{0x00, 0x00, 0xFFFFFFFF, 0x00000000},
{0x00, EOL, 0xFFFFFFFF, 0x00000000},
};
VIRTUAL_DEVICE * IDSELs;
VIRTUAL_PTR * VirtDevPtr;
USHORT DeviceID;
USHORT Class;
UCHAR BaseClass;
UCHAR Shift, AlignedReg, Function;
ULONG Virtualized_PCI_Devices=0;
//***********************************************************************
// Given a ptr to a virtual PCI header, finds Register
//***********************************************************************
PCI_HEADER_ENTRY * pascal Find_Register(PCI_HEADER_ENTRY * Pci, UCHAR Register)
{
// Keep a ptr to the Vendor ID register
HdrPtr = Pci;
DeviceID = HdrPtr->Device_ID;
// Keep a ptr to the Command register
CommandPtr = Pci + COMMAND/4;
// Record the device Class
BaseClass = (HdrPtr+REVISION_ID/4)->BaseClass;
Class = (HdrPtr+REVISION_ID/4)->Class;
// Scan the table for the specified register entry
do {
if (Pci->Reg == Register) {
return Pci;
}
} while (!((Pci++)->Flag & EOL));
// If CommandPtr is used, avoid generating an exception
CommandPtr = Dummy_Hdr;
// Register is not in the table
return (PCI_HEADER_ENTRY *) UNIMPLEMENTED_REGISTER;
}
//***********************************************************************
// Parses PCI_Address & returns a pointer to the corresponding entry in a
// virtual header table.
// Computes global variables:
// AlignedReg, Function, Shift, HdrPtr, CommandPtr, & DeviceID
//***********************************************************************
PCI_HEADER_ENTRY * pascal Get_Structure(USHORT PCI_Address)
{ register PCI_HEADER_ENTRY * Pci;
UCHAR Reg;
// Compute Function #
Function = (UCHAR)(PCI_Address >> 8) & 0x07;
// Get register offset
Reg = (UCHAR) PCI_Address;
// Compute DWORD aligned register offset
AlignedReg = Reg & ~3;
// Compute shift count
Shift = (Reg & 3) << 3;
// Subsystem Vendor ID & Subsystem ID are same as Vendor ID & Device ID
if (AlignedReg == SUBSYSTEM_VENDOR_ID) {
AlignedReg = VENDOR_ID;
}
// Return value if function not implemented
Pci = (PCI_HEADER_ENTRY *) UNIMPLEMENTED_FUNCTION;
// Is this IDSEL virtualized ?
if (IDSELs = *(VirtDevPtr+(PCI_Address >> 11))) {
// Get ptr to this function (0000 if not implemented)
if (Pci = IDSELs[Function]) {
Pci = Find_Register(Pci, AlignedReg);
}
}
return Pci;
}
//***********************************************************************
// Trims the MSRs that map extended memory by RangeRequest bytes
//***********************************************************************
ULONG Trim_Extended_Memory(ULONG RangeRequest)
{ ULONG Fields[3], Ext_Mem[2], Msr;
// Trim the MPCI Region 1 configuration
Msr = MPCI_NB + MPCI_R1;
Read_MSR(Msr, Ext_Mem);
if (DynamicVSALoad) {
RangeRequest = 0;
}
Ext_Mem[1] -= RangeRequest;
Write_MSR(Msr, Ext_Mem);
// Adjust RCONF_DEFAULT[SYSTOP]
Read_MSR(MSR_RCONF_DEFAULT, Ext_Mem);
Ext_Mem[0] -= RangeRequest >> 4;
Write_MSR(MSR_RCONF_DEFAULT, Ext_Mem);
// Trim extended memory in GLIUs 0 & 1
Trim_P2D_R(ExtendedMemoryDescr0, RangeRequest, Ext_Mem);
Trim_P2D_R(ExtendedMemoryDescr1, RangeRequest, Ext_Mem);
// Copy Start/End to new descriptor
Parse_Descriptor(P2D_R, Ext_Mem, Fields);
return (Fields[1] + 1);
}
typedef struct {
UCHAR StartType;
UCHAR EndType;
UCHAR Port;
ULONG Msr;
} ROUTING_INFO;
#define MAX_ROUTE 5
ROUTING_INFO Routing[MAX_ROUTE];
//***********************************************************************
// Allocates a Region Configuration Register
//***********************************************************************
ROUTING_INFO * pascal Allocate_RCONF(ULONG DevAddress, ROUTING_INFO * RoutingPtr)
{
// Allocate a region configuration register
// If in Southbridge...
if ((DevAddress & MPCI_SB) == MPCI_SB) {
// then use SB MPCI R0-R15
RoutingPtr->StartType = MPCI_RCONF;
RoutingPtr->Msr = MPCI_SB;
} else {
// else use GX2 RCONF0-RCONF7
RoutingPtr->StartType = GX2_RCONF;
}
RoutingPtr++;
return RoutingPtr;
}
//***********************************************************************
// This routines creates an association between the virtualized PCI BAR
// (specified by BaseAddr and Device_ID) and an MBus device (specified by
// Geode_ID). The Resource parameter specifies the type of BAR (Memory,
// Memory-mapped I/O, or I/O) and the size of the region by RangeRequest.
//***********************************************************************
USHORT pascal Allocate_BAR(UCHAR Resource, USHORT BaseAddr, ULONG RangeRequest, \
USHORT Geode_ID, USHORT Device_ID)
{ ULONG DevAddress, Mbiu, Physical=0;
UCHAR LSB, MSB;
UCHAR Instance=1;
UCHAR Index, StartType, EndType;
UCHAR * LinkPtr;
USHORT DevNum, Function, PCI_Address;
register ROUTING_INFO * RoutingPtr;
register PCI_HEADER_ENTRY * Pci;
register VIRTUAL_DEVICE * VirtDev;
register DESCRIPTOR * Descr;
int i;
// Validate parameters
switch (Resource) {
case RESOURCE_MEMORY:
case RESOURCE_MMIO:
case RESOURCE_SCIO:
case RESOURCE_IO:
break;
default:
Log_Error("Invalid value for parameter Resource: 0x%02X", Resource);
return 0x0000;
}
// Ensure RangeRequest meets PCI & MBus requirements
LSB = BitScanForward(RangeRequest);
MSB = BitScanReverse(RangeRequest);
if (Resource == RESOURCE_MEMORY || Resource == RESOURCE_MMIO) {
// Memory BARs must be at least 4 KB because of granularity of descriptors
if (RangeRequest < 4096) {
MSB = LSB = 12;
}
}
// If RangeRequest is not a power of 2...
if (LSB != MSB) {
// Round size of BAR to next higher power of 2
MSB++;
}
// Do some massaging based on Device ID
switch (Device_ID) {
// Graphics header is invisible until SoftVG is enabled.
case DEVICE_ID_GFX2:
case DEVICE_ID_GFX3:
NorthBridge[1] = Graphics_Hdr;
break;
}
//
// Determine the PCI Address by scanning the PCI tables for Device_ID
//
for (DevNum = 1; DevNum <= 21; DevNum++) {
if (VirtDev = *(VirtDevPtr+DevNum)) {
// For each defined function...
for (Function = 0; Function <= 7; Function++) {
if (Pci = *VirtDev++) {
// Do the Device IDs match ?
if (Pci->Device_ID == Device_ID) {
// Handle the 2nd instance of 5536's OHCI
if ((Geode_ID == ID_OHCI) && ((Pci+BAR0/4)->Flag & (IO_BAR | MEM_BAR | MMIO_BAR))) {
continue;
}
break;
}
}
}
// If Device ID match is found...
if (Function < 8) {
// Compute the PCI address
PCI_Address = (DevNum << 11) + (Function << 8) + (UCHAR)BaseAddr;
Pci = Find_Register(Pci, (UCHAR)BaseAddr);
// Check for errors
if ((USHORT)Pci > UNIMPLEMENTED_REGISTER) {
// Has this BAR already been allocated ?
if (Pci->Flag & (IO_BAR | MEM_BAR | MMIO_BAR)) {
// Yes, log an error
Log_Error("Resource has already been allocated for PCI address 0x%X", PCI_Address);
}
}
break;
}
}
}
// Device_ID was not found in virtual PCI tables
if (DevNum > 21) {
Log_Error("DeviceID 0x%04X was not found", Device_ID);
return 0x0000;
}
// Record Mask for BAR
Pci->Mask = ~((1L << MSB)-1);
// Initialize routing structure
RoutingPtr = &Routing[0];
for (i=0; i<MAX_ROUTE; i++) {
RoutingPtr->StartType = 0x00;
RoutingPtr->EndType = 0x00;
RoutingPtr->Port = 0x00;
RoutingPtr->Msr = 0x00000000;
RoutingPtr++;
}
RoutingPtr = &Routing[0];
// Handle special cases
switch (Geode_ID) {
// SMI generation on access (no physical device, e.g. virtual registers)
case 0x0000:
DevAddress = 0x00000000;
break;
// Routing address of some devices has already been determined
case ID_MDD:
DevAddress = MDD_Base;
break;
// Handle the 2nd instance of 5536's OHCI
case ID_OHCI:
if (Function == 4) {
Instance = 2;
}
default:
// Search for the requested Geode_ID
DevAddress = Find_MBus_ID(Geode_ID, Instance);
if (!DevAddress) {
Log_Error("Geode ID 0x%04X was not found for Device ID 0x%04X", Geode_ID, Device_ID);
return 0x0000;
}
break;
}
// If an LBAR is required, allocate it
if (Pci->LBar) {
RoutingPtr->StartType = MDD_LBAR;
RoutingPtr->Msr = MDD_Base;
switch (Geode_ID) {
case ID_USB_20:
// OHCI needs an LBAR in the MDD
if ((HdrPtr+REVISION_ID/4)->Interface == 0x10) {
(UCHAR)RoutingPtr->Msr = MSR_LBAR_KEL1;
RoutingPtr++;
}
RoutingPtr->StartType = USB_LBAR;
case ID_ATA:
RoutingPtr->Msr = DevAddress;
break;
}
(UCHAR)RoutingPtr->Msr = Pci->LBar;
RoutingPtr++;
}
// Get an available descriptor appropriate to the type of BAR
switch (Resource) {
// Physical Memory
case RESOURCE_MEMORY:
// Mark it as a memory BAR
Pci->Flag |= MEM_BAR;
RoutingPtr->StartType = P2D_BMO;
RoutingPtr->EndType = P2D_RO;
RoutingPtr->Msr = Mbiu0;
// Legacy VGA frame buffers don't require physical memory
if ((UCHAR)BaseAddr > BAR5) {
ULONG RegionEnables, RegionProperties[2];
#define OFF_PROPS (REGION_WS) // Frame buffer properties to be disabled
#define OFF_PROPERTIES ((OFF_PROPS<<24) | (OFF_PROPS<<16) | (OFF_PROPS<<8) | (OFF_PROPS))
#define ON_PROPS (0) // Frame buffer properties to be enabled
#define ON_PROPERTIES (( ON_PROPS<<24) | ( ON_PROPS<<16) | ( ON_PROPS<<8) | ( ON_PROPS))
// Set MPCI Fixed Region Enables and disable write-serialize
Read_MSR(MSR_RCONF_A0_BF, RegionProperties);
Physical = 0xA0000;
RegionEnables = 0x00;
switch (RangeRequest) {
case 128L*1024:
RegionEnables = 0xFF; // A0000-BFFFF
RegionProperties[1] &= ~OFF_PROPERTIES;
RegionProperties[1] |= ON_PROPERTIES;
case 64L*1024:
RegionEnables |= 0x0F; // A0000-AFFFF
RegionProperties[0] &= ~OFF_PROPERTIES;
RegionProperties[0] |= ON_PROPERTIES;
break;
case 32L*1024:
RegionEnables = 0xC0; // B8000-BFFFF
RegionProperties[1] &= ~(OFF_PROPERTIES & 0xFFFF0000);
RegionProperties[1] |= (ON_PROPERTIES & 0xFFFF0000);
Physical = 0xB8000;
break;
}
// Set Vail Region Properties (0x180B)
Write_MSR(MSR_RCONF_A0_BF, RegionProperties);
// Set MPCI Fixed Region Enables (0x2014)
Write_MSR_LO(MPCI_NB + MPCI_REN, Read_MSR_LO(MPCI_NB + MPCI_REN) | RegionEnables);
// Allocate P2D_BM
switch (Device_ID) {
case DEVICE_ID_GFX2:
case DEVICE_ID_GFX3:
RoutingPtr->StartType = P2D_BM;
break;
}
RoutingPtr++;
} else {
// Trim required memory from the end of extended memory
Physical = Trim_Extended_Memory(RangeRequest);
DevAddress = Find_MBus_ID(ID_MC, 1);
// Allocate a Region Configuration Register
RoutingPtr++;
RoutingPtr = Allocate_RCONF(DevAddress, RoutingPtr);
}
break;
// Memory-mapped I/O
case RESOURCE_MMIO:
// Mark it as a memory-mapped BAR
Pci->Flag |= MMIO_BAR;
switch (Geode_ID) {
// Subtractive ports; no MBIU descriptor is necessary
case ID_MPCI:
case ID_MDD:
break;
case ID_USB_20:
case ID_OHCI:
// Allocate a P2D_BMK descriptor in MBIU2
RoutingPtr->StartType = P2D_BMK;
if (!(Pci->Flag & USE_BMK)) {
RoutingPtr->EndType = P2D_BM;
}
RoutingPtr->Msr = Mbiu2;
RoutingPtr->Port = (UCHAR)DevAddress;
RoutingPtr++;
if (Pci->Flag & EPCI_RW) {
// Allocate the appropriate mailbox address
RoutingPtr->StartType = EPCI;
RoutingPtr->Msr = DevAddress & ROUTING;
RoutingPtr++;
}
break;
case ID_VG:
RoutingPtr->StartType = P2D_RO;
RoutingPtr++;
// Fix for VG alias bug: POFFSET field should be set to -PBASE
// See Compute_Msr_Value()
Physical = 1;
break;
case ID_AES:
RoutingPtr->StartType = P2D_R;
RoutingPtr++;
break;
default:
RoutingPtr->StartType = P2D_BM;
RoutingPtr->EndType = P2D_RO;
RoutingPtr++;
break;
}
// Allocate a Region Configuration Register
RoutingPtr = Allocate_RCONF(DevAddress, RoutingPtr);
break;
// I/O Space
case RESOURCE_SCIO:
RoutingPtr->StartType = IOD_SC;
RoutingPtr++;
case RESOURCE_IO:
// Mark it as an I/O BAR
Pci->Flag |= IO_BAR;
switch (Geode_ID) {
// Subtractive ports; no MBIU descriptor is necessary
case ID_MPCI:
case ID_MDD:
break;
default:
if (Resource != RESOURCE_SCIO) {
RoutingPtr->StartType = IOD_BM;
RoutingPtr->EndType = IOD_SC;
RoutingPtr++;
}
break;
}
// If device is in the Southbridge...
if ((DevAddress & MPCI_SB) == MPCI_SB) {
// allocate a Region Configuration Register
RoutingPtr = Allocate_RCONF(DevAddress, RoutingPtr);
}
// PCI Spec requires I/O BAR a minimum of 4 bytes
Pci->Mask &= 0xFFFFFFFC;
break;
default:
Log_Error("Unknown resource requested: 0x%X", Resource);
return 0x0000;
}
//
// Get device's PCI Revision ID
//
switch (Device_ID) {
// Revision of some devices is already determined
case DEVICE_ID_OHCI:
case DEVICE_ID_5536:
case DEVICE_ID_GX2:
case DEVICE_ID_LX:
break;
// Graphic's Revision ID comes from GP, not VG or DF
case DEVICE_ID_GFX2:
case DEVICE_ID_GFX3:
if (Geode_ID != ID_GP) {
break;
}
default:
// Read MBD_MSR_CAP
Mbiu = DevAddress;
(USHORT)Mbiu = MBD_MSR_CAP;
// Insert Revision ID into header
(HdrPtr+REVISION_ID/4)->Revision_ID = (UCHAR)Read_MSR_LO(Mbiu);
break;
}
// Compute number of MSRs needed to support this BAR
i = (UCHAR)(RoutingPtr - &Routing[0]);
if (i >= MAX_ROUTE) {
Log_Error("Allocate_BAR- routing failed on PCI address 0x%X", PCI_Address);
}
//
// Allocate the required MSRs
//
RoutingPtr = &Routing[0];
LinkPtr = &Pci->Link;
while (i) {
// Force use of P2D_RO to prevent ROVER from complaining about overlapped
// physical addresses when the frame buffer length is not a power of 2.
if (Pci == &Graphics_Hdr[BAR0/4]) {
if(RoutingPtr->Msr == Mbiu0) {
RoutingPtr->StartType = P2D_RO;
}
}
StartType = RoutingPtr->StartType;
EndType = RoutingPtr->EndType;
// If 2nd choice is not specified, force it to 1st choice
if (EndType == 0x00) {
EndType = StartType;
}
// Has the correct MBIU been determined ?
if (RoutingPtr->Msr == 0x00000000) {
// Determine the MBIU as follows:
// - If the 2nd routing field == 0, then it's MBIU0
// - If the 1st three routing fields match MBIU2, then it's MBIU2
// - Otherwise it's MBIU1
if ((DevAddress & (7L << 26)) == 0) {
Mbiu = Mbiu0;
} else {
if ((DevAddress & 0xFF800000) == (Mbiu2 & 0xFF800000)) {
Mbiu = Mbiu2;
} else {
Mbiu = Mbiu1;
}
}
RoutingPtr->Msr = Mbiu;
}
if (StartType) {
Index = Allocate_Descriptor(StartType, EndType, RoutingPtr->Msr);
if (Index == DESCRIPTOR_NOT_FOUND) {
// If SMI generation, then any MBIU may be used
if (!Geode_ID) {
// Try MBIU1
Mbiu = Mbiu1;
Index = Allocate_Descriptor(StartType, EndType, Mbiu);
if (Index == DESCRIPTOR_NOT_FOUND) {
if (Mbiu = Mbiu2) {
Index = Allocate_Descriptor(StartType, EndType, Mbiu);
}
}
}
}
}
if (Index == DESCRIPTOR_NOT_FOUND) {
UCHAR Mbiu=9;
if (RoutingPtr->Msr == Mbiu0) Mbiu = 0;
else if (RoutingPtr->Msr == Mbiu1) Mbiu = 1;
else if (RoutingPtr->Msr == Mbiu2) Mbiu = 2;
Log_Error("MSR allocation failed for GeodeID=%02X/DeviceID=%04X/BAR%x/MBIU%1x", \
(UCHAR)Geode_ID, Device_ID, (USHORT)((BaseAddr-BAR0)/4), Mbiu);
goto NextMSR;
}
// Record info about the descriptor
Descr = &MSRs[Index];
Descr->Owner = PCI_Address;
Descr->Range = RangeRequest;
Descr->Physical = Physical;
if (RoutingPtr->Port == 0) {
RoutingPtr->Port = (UCHAR)DevAddress;
}
Descr->Port = RoutingPtr->Port;
// If embedded PCI device, record PCI mailbox MSR to Command register
if (StartType == EPCI) {
CommandPtr->Link = Index;
}
// Link to previous MSRs[] (or Pci->Link)
* LinkPtr = Index;
// Update link pointer
LinkPtr = &Descr->Link;
// Is an additional swiss-cheese descriptor necessary ?
if (Descr->Type == IOD_SC && RangeRequest > 8) {
RangeRequest -= 8;
continue;
}
// If the device is on GLIU0, then allocate a descriptor on GLIU1
// to route FS2 transactions to GLIU0.
if (RoutingPtr->Msr == Mbiu0 && RoutingPtr->StartType < GX2_RCONF ) {
// Don't allocate MBUI1 descriptor for virtual register BAR
if (Geode_ID) {
switch (RoutingPtr->StartType) {
case IOD_SC:
RoutingPtr->StartType = IOD_BM;
RoutingPtr->EndType = IOD_SC;
RangeRequest = 1L << MSB;
break;
case P2D_RO:
if (Pci == &Graphics_Hdr[BAR0/4]) {
RoutingPtr->StartType = P2D_R;
break;
} else {
RoutingPtr->StartType = P2D_BM;
}
default:
RangeRequest = 1L << MSB;
break;
}
// Use only 1 descriptor for northbound VG transactions
if (RangeRequest == 16 && Geode_ID == ID_VG) {
static UCHAR VG_FS2_Flag=0;
if (VG_FS2_Flag) {
break;
} else {
VG_FS2_Flag = 1;
RangeRequest = 32;
}
}
RoutingPtr->Msr = Mbiu1;
RoutingPtr->Port = MBIU1_SelfReference;
continue;
}
}
// Advance ptr to next MSR
NextMSR:
RoutingPtr++;
i--;
} // end while
// Make appropriate Command register bit R/W
if (Pci->Flag & IO_BAR) {
CommandPtr->Mask |= IO_SPACE;
} else {
CommandPtr->Mask |= MEM_SPACE;
}
return PCI_Address;
}
//***********************************************************************
//
// Perform early POST initialization of virtualized PCI config space
//
//***********************************************************************
void VirtualPCI_EarlyInit(void)
{ USHORT i;
ULONG PCI_Address;
ULONG MsrAddr;
VIRTUAL_PTR DevicePtr;
PCI_HEADER_ENTRY * Pci;
// Initialize ptr to virtualized PCI topology
VirtDevPtr = &Virtual_Devices[0];
// Virtualize CS5536's configuration space, if present,
// at the same device number as the h/w header.
i = (UCHAR)((USHORT)HardwareInfo.Chipset_Base >> 11);
switch (HardwareInfo.Chipset_ID) {
case DEVICE_ID_5536:
Virtual_Devices[i] = Virtual_5536;
break;
default:
return;
}
SouthBridge = Virtual_Devices[i];
// Compute mask of IDSELs that are to be virtualized
for (i = 1; i <= 21; i++) {
// If IDSEL is virtualized, set enable mask
DevicePtr = * (VirtDevPtr+i);
if (DevicePtr) {
// Record IDSEL to trap
Virtualized_PCI_Devices |= (1L << i);
// Register System Manager for this IDSEL
PCI_Address = ((ULONG)i << 11);
Register_Event(EVENT_PCI_TRAP, MAX_PRIORITY, SysMgr_VSM, PCI_Address, 0x07FF);
}
}
// Enable virtual PCI headers
MsrAddr = MPCI_NB + MBD_MSR_SMI;
Write_MSR_LO(MsrAddr, Read_MSR_LO(MsrAddr) & ~VPHM);
// Store CPU's Device & Revision IDs in Host Bridge's PCI header
HostBridge_Hdr[0].Device_ID = HardwareInfo.CPU_ID;
HostBridge_Hdr[2].Revision_ID = (UCHAR)HardwareInfo.CPU_Revision;
// AES header (F2) BAR
Allocate_BAR(RESOURCE_MMIO, BAR0, 16*1024, ID_AES, AES_Hdr[0].Device_ID);
// Implement Interrupt Pin/Line registers in LX graphic header
if (Pci = Find_Register(Graphics_Hdr, INTERRUPT_LINE)) {
// Make Interrupt Line read-write
(UCHAR)Pci->Mask = 0xFF;
// Set Interrupt Pin to INTA#
Pci->Interrupt_Pin = 0x01;
}
}
//***********************************************************************
// Routine to support INFO getting PCI<->MSR linkages
//***********************************************************************
ULONG pascal Get_MSR_Linkage(USHORT PCI_Address)
{ PCI_HEADER_ENTRY * Pci;
ULONG MsrAddr;
static UCHAR Link=0x00;
static DESCRIPTOR * Descr;
static USHORT LastPCI = 0x0000;
if (PCI_Address != LastPCI) {
LastPCI = PCI_Address;
Pci = Get_Structure(PCI_Address);
switch ((USHORT)Pci) {
case UNIMPLEMENTED_FUNCTION:
case UNIMPLEMENTED_REGISTER:
Link = 0x00;
break;
default:
Link = Pci->Link;
break;
}
}
Descr = &MSRs[Link];
// Get link to next descriptor
Link = Descr->Link;
if (!(MsrAddr = Descr->MsrAddr)) {
LastPCI = 0x0000;
}
return MsrAddr;
}

Some files were not shown because too many files have changed in this diff Show More