Here's the VIA vx800 patch from OLPC.

It's untested, but a good starting point for everyone.

Signed-off-by: Bari Ari <bari@onelabs.com>
Acked-by: Ronald G. Minnich <rminnich@gmail.com>
Acked-by: Uwe Hermann <uwe@hermann-uwe.de>



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@4313 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Bari Ari 2009-05-27 13:12:42 +00:00 committed by Uwe Hermann
parent e6e899dde9
commit 612163e383
36 changed files with 10213 additions and 0 deletions

View File

@ -0,0 +1,25 @@
##
## This file is part of the coreboot project.
##
## Copyright (C) 2009 One Laptop per Child, Association, Inc.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; version 2 of the License.
##
## This program 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 General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
##
config chip.h
object vgabios.o
driver northbridge.o
driver vga.o
driver vx800_lpc.o
driver vx800_ide.o

View File

@ -0,0 +1,70 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef DRIVINGCLKPHASEDATA_H
#define DRIVINGCLKPHASEDATA_H
//extern u8 DDR2_DQSA_Driving_Table[4] ;
//extern u8 DDR2_DQSB_Driving_Table[2] ;
//extern u8 DDR2_DQA_Driving_Table[4] ;
//extern u8 DDR2_DQB_Driving_Table[2] ;
//extern u8 DDR2_CSA_Driving_Table_x8[4] ;
//extern u8 DDR2_CSB_Driving_Table_x8[2] ;
//extern u8 DDR2_CSA_Driving_Table_x16[4];
//extern u8 DDR2_CSB_Driving_Table_x16[2];
#define MA_Table 3
//extern u8 DDR2_MAA_Driving_Table[MA_Table][4];
//extern u8 DDR2_MAB_Driving_Table[MA_Table][2];
//extern u8 DDR2_DCLKA_Driving_Table[4] ;
//extern u8 DDR2_DCLKB_Driving_Table[4];
#define DUTY_CYCLE_FREQ_NUM 6
#define DUTY_CYCLE_REG_NUM 3
//extern u8 ChA_Duty_Control_DDR2[DUTY_CYCLE_REG_NUM][DUTY_CYCLE_FREQ_NUM];
//extern u8 ChB_Duty_Control_DDR2[DUTY_CYCLE_REG_NUM][DUTY_CYCLE_FREQ_NUM];
#define Clk_Phase_Table_DDR2_Width 6
//extern u8 DDR2_ChA_Clk_Phase_Table_1R[3][Clk_Phase_Table_DDR2_Width];
//extern u8 DDR2_ChB_Clk_Phase_Table_1R[3][Clk_Phase_Table_DDR2_Width];
//extern u8 DDR2_ChA_Clk_Phase_Table_2R[3][Clk_Phase_Table_DDR2_Width];
#define WrtData_REG_NUM 4
#define WrtData_FREQ_NUM 6
//extern u8 DDR2_ChA_WrtData_Phase_Table[WrtData_REG_NUM ][WrtData_FREQ_NUM];
//extern u8 DDR2_ChB_WrtData_Phase_Table[WrtData_REG_NUM ][WrtData_FREQ_NUM];
#define DQ_DQS_Delay_Table_Width 4
//extern u8 DDR2_CHA_DQ_DQS_Delay_Table[4][DQ_DQS_Delay_Table_Width];
//extern u8 DDR2_CHB_DQ_DQS_Delay_Table[4][DQ_DQS_Delay_Table_Width];
#define DQS_INPUT_CAPTURE_REG_NUM 3
#define DQS_INPUT_CAPTURE_FREQ_NUM 6
//extern u8 DDR2_ChA_DQS_Input_Capture_Tbl[DQS_INPUT_CAPTURE_REG_NUM ][DQS_INPUT_CAPTURE_FREQ_NUM];
//extern u8 DDR2_ChB_DQS_Input_Capture_Tbl[DQS_INPUT_CAPTURE_REG_NUM ][DQS_INPUT_CAPTURE_FREQ_NUM];
//extern u8 Fixed_DQSA_1_2_Rank_Table[4][2];
//extern u8 Fixed_DQSA_3_4_Rank_Table[4][2];
//extern u8 Fixed_DQSB_1_2_Rank_Table[4][2];
//extern u8 Fixed_DQSB_3_4_Rank_Table[4][2];
#endif /* DRIVINGCLKPHASEDATA_H */

View File

@ -0,0 +1,24 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
struct northbridge_via_vx800_config
{
};
extern struct chip_operations northbridge_via_vx800_ops;

View File

@ -0,0 +1,86 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "lib/memset.c"
CB_STATUS DDR2_DRAM_INIT()
{
CB_STATUS Status;
u8 i;
u32 RamSize;
BOOLEAN bTest;
DRAM_SYS_ATTR DramAttr;
PRINT_DEBUG_MEM("DRAM_INIT \r");
memset(&DramAttr, 0, sizeof(DRAM_SYS_ATTR));
/*Step1 DRAM Detection; DDR1 or DDR2; Get SPD Data; Rank Presence;64 or 128bit; Unbuffered or registered; 1T or 2T */
DRAMDetect(&DramAttr);
//Step2 set Frequency; calculate CL and Frequncy from SPD data; set the Frequency
DRAMFreqSetting(&DramAttr);
//Step3 Set DRAM Timing; CL, tRP, tRCD, tRAS, tRFC, tRRD, tWR, tWTR, tRTP
DRAMTimingSetting(&DramAttr);
//Step4 DRDY
DRAMDRDYSetting(&DramAttr);
//Step5 Burst length
DRAMBurstLength(&DramAttr);
//Step6 DRAM Driving Adjustment
DRAMDriving(&DramAttr);
//Step7 duty cycle control
DutyCycleCtrl(&DramAttr);
//Step8 DRAM clock phase and delay control
DRAMClkCtrl(&DramAttr);
//Step9 set register before init DRAM device
DRAMRegInitValue(&DramAttr);
//Step10 DDR and DDR2 initialize process
DRAMInitializeProc(&DramAttr);
//Step13 Interleave function in rankmap.c
DRAMBankInterleave(&DramAttr);
//Step14 Sizing
DRAMSizingMATypeM(&DramAttr);
//Step11 Search DQS and DQ output delay
DRAMDQSOutputSearch(&DramAttr);
//Step12 Search DQS input delay
DRAMDQSInputSearch(&DramAttr);
//Step15 DDR fresh counter setting
DRAMRefreshCounter(&DramAttr);
//Step16 Final register setting for improve performance
DRAMRegFinalValue(&DramAttr);
RamSize = 0;
for (i = 0; i < MAX_RANKS; i++) {
if (DramAttr.RankSize[i] == 0) {
continue;
}
RamSize += DramAttr.RankSize[i];
}
PRINT_DEBUG_MEM("RamSize=");
PRINT_DEBUG_MEM_HEX32(RamSize);
PRINT_DEBUG_MEM("\r");
DumpRegisters(0, 3);
//bTest = DramBaseTest( M1, RamSize - M1 * 2,SPARE, FALSE);
/* the memory can not correct work, this is because the user set the incorrect memory
parameter from setup interface.so we must set the boot mode to recovery mode, let
the system to reset and use the spd value to initialize the memory */
SetUMARam();
return CB_SUCCESS;
}

View File

@ -0,0 +1,263 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __DRAMINIT_H_
#define __DRAMINIT_H_
//Dram Size
#define M (1024*1024)
#define M1 (1*M)
#define M64 (64*M)
#define M128 (128*M)
#define M256 (256*M)
#define M384 (384*M)
#define M512 (512*M)
// UMA size
#define UMASIZE M64
#define ENABLE_CHC 0 //CHC enable, how ever, this CHC,used some reg define in CHB
#define ENABLE_CHB 0 //CHB enable , CHB is VX800's, VX855 no this CHB.
//Dram Freq
#define DIMMFREQ_800 400
#define DIMMFREQ_667 333
//#define DIMMFREQ_600 300
#define DIMMFREQ_533 266
#define DIMMFREQ_400 200
#define DIMMFREQ_333 166
#define DIMMFREQ_266 133
#define DIMMFREQ_200 100
//Dram Type
#define RAMTYPE_FPMDRAM 1
#define RAMTYPE_EDO 2
#define RAMTYPE_PipelinedNibble 3
#define RAMTYPE_SDRAM 4
#define RAMTYPE_ROM 5
#define RAMTYPE_SGRAMDDR 6
#define RAMTYPE_SDRAMDDR 7
#define RAMTYPE_SDRAMDDR2 8
/* CAS latency constant */
#define CASLAN_15 15
#define CASLAN_2 20
#define CASLAN_25 25
#define CASLAN_3 30
#define CASLAN_35 35
#define CASLAN_4 40
#define CASLAN_45 45
#define CASLAN_5 50
#define CASLAN_NULL 00
//Burst length
#define BURSTLENGTH8 8
#define BURSTLENGTH4 4
//Data Width
//#define DATAWIDTHX16 16
//#define DATAWIDTHX8 8
//#define DATAWIDTHX4 4
#define SPD_MEMORY_TYPE 2 /*Memory type FPM,EDO,SDRAM,DDR,DDR2 */
#define SPD_SDRAM_ROW_ADDR 3 /*Number of row addresses on this assembly */
#define SPD_SDRAM_COL_ADDR 4 /*Number of column addresses on this assembly */
#define SPD_SDRAM_DIMM_RANKS 5 /*Number of RANKS on this assembly */
#define SPD_SDRAM_MOD_DATA_WIDTH 6 /*Data width of this assembly */
#define SPD_SDRAM_TCLK_X 9 /*Cycle time at Maximum supported CAS latency (CL=X) */
#define SPD_SDRAM_TAC_X 10 /*Access time for highest CL */
#define SPD_SDRAM_CONFIG_TYPE 11 /*Non-parity , Parity or ECC */
#define SPD_SDRAM_REFRESH 12 /*Refresh rate/type */
#define SPD_SDRAM_WIDTH 13 /*Primary sdram width */
#define SPD_SDRAM_MIN_CLK_DLY 15 /*Minimum clock delay */
#define SPD_SDRAM_BURSTLENGTH 16 /*Burst Lengths supported */
#define SPD_SDRAM_NO_OF_BANKS 17 /*Number of banks on this assembly */
#define SPD_SDRAM_CAS_LATENCY 18 /*CAS latency */
#define SPD_SDRAM_DIMM_TYPE_DDR2 20 /*DIMM type information; identifies the DDR2 memory module type */
#define SPD_SDRAM_DEV_ATTR_DDR1 20 /*WE latency */
#define SPD_SDRAM_MODULES_ATTR 21 /*This byte depicts various aspects of the modules; DDR DDR2 have different aspects */
#define SPD_SDRAM_DEV_ATTR_GEN 22 /*General device attributes */
#define SPD_SDRAM_TCLK_X_1 23 /*Minimum clock cycle time at Reduced CL, DDR: X-0.5 DDR2: X-1 */
#define SPD_SDRAM_TAC_X_1 24 /*Maximum Data Access time from Clock at reduced CL,DDR: X-0.5 DDR2: X-1 */
#define SPD_SDRAM_TCLK_X_2 25 /*Minimum clock cycle time at reduced CL, DDR: X-1 DDR2: X-2 */
#define SPD_SDRAM_TAC_X_2 26 /*Maximum Data Access time from Clock at reduced CL, DDR: X-1 DDR2: X-2 */
#define SPD_SDRAM_TRP 27 /*minimum row precharge time */
#define SPD_SDRAM_TRRD 28 /*minimum row active to row active delay */
#define SPD_SDRAM_TRCD 29 /*minimum RAS to CAS delay */
#define SPD_SDRAM_TRAS 30 /*minimum active to precharge time */
#define SPD_SDRAM_TWR 36 /*write recovery time, only DDR2 use it */
#define SPD_SDRAM_TWTR 37 /*internal write to read command delay, only DDR2 use it */
#define SPD_SDRAM_TRTP 38 /*internal read to prechange command delay, only DDR2 use it */
#define SPD_SDRAM_TRFC2 40 /*extension of byte 41 tRC and byte 42 tRFC, only DDR2 use it */
#define SPC_SDRAM_TRC 41 /*minimum active to active/refresh time */
#define SPD_SDRAM_TRFC 42 /*minimum refresh to active / refresh command period */
#define SPD_DATA_SIZE 44
//Dram cofig are
/*the most number of socket*/
//#define MAX_RAM_SLOTS 2
#define MAX_SOCKETS MAX_RAM_SLOTS
#define MAX_DIMMS MAX_SOCKETS /*every sockets can plug one DIMM */
/*the most number of RANKs on a DIMM*/
#define MAX_RANKS MAX_SOCKETS*2
struct mem_controller {
u8 channel0[MAX_DIMMS];
};
static const struct mem_controller ctrl = {
.channel0 = {0x50, 0x51},
};
typedef struct _DRAM_CONFIG_DATA {
u8 DramClk;
u8 DramTiming;
u8 CasLatency;
u8 BankIntlv;
u8 Trp;
u8 Tras;
u8 Trcd;
u8 Trfc;
u8 Trrd;
u8 Trtp;
u8 Twtr;
u8 Twr;
u8 CmdRate;
u8 DualEn;
//u8 IntLv0;
//u8 IntLv1;
//u8 Ba0Sel;
//u8 Ba1Sel;
//u8 Ba2Sel;
u8 BaScmb;
u8 DrdyTiming;
//u8 Above4G;
//u8 RdsaitMode;
//u8 Rdsait;
//u8 TopPerf;
u16 UMASize;
} DRAM_CONFIG_DATA;
/*DIMM(assembly) information*/
typedef struct _DIMM_INFO_tag {
u8 bPresence;
u8 SPDDataBuf[SPD_DATA_SIZE]; /*get all information from spd data */
} DIMM_INFO;
typedef struct _DRAM_SYS_ATTR_tag {
DIMM_INFO DimmInfo[MAX_DIMMS];
u8 RankPresentMap; /*bit0,1 Rank0,1 on DIMM0, bit2,3 Rank2,3 on DIMM1,
bit4,5 Rank4,5 on DIMM2, bit6,7 Rank6,7 on DIMM3 */
u8 DimmNumChA; /*Dimm number */
u8 DimmNumChB;
u8 RankNumChA; /*the number of Ranks on the mortherbaord */
u8 RankNumChB;
u8 LoadNumChA; /*the number of chips on all DIMM */
u8 LoadNumChB;
u8 DramType; /*DDR1 or DDR2 */
u16 DramFreq;
u16 DramCyc; /*10ns, 7.5ns, 6ns, 5ns, 3.75ns, 3ns, 2.5ns =1/SysFreq, unit: 100*ns. */
//u16 HFreq; /*100, 133, 166, 200, 266, 333, 400*/
u8 CL; /* CAS lantency */
u8 CmdRate; /*1T or 2T */
u32 RankSize[MAX_RANKS];
u8 Dual_Channel;
DRAM_CONFIG_DATA ConfigData;
u8 reserved[4];
} DRAM_SYS_ATTR;
typedef struct _DRAM_SIZE_INFO {
u32 RankLength[MAX_RANKS];
} DRAM_SIZE_INFO;
//detection.c
/*Step1 detect DRAM type, Read SPD data,command rate*/
CB_STATUS DRAMDetect(DRAM_SYS_ATTR * DramAttr);
//FreqSetting.c
/*Step2 set Frequency, calculate CAL*/
void DRAMFreqSetting(DRAM_SYS_ATTR * DramAttr);
//TimingSetting.c
/*Step3 Set DRAM Timing*/
void DRAMTimingSetting(DRAM_SYS_ATTR * DramAttr);
//DRDY_BL.c
/*Step4 DRDY*/
void DRAMDRDYSetting(DRAM_SYS_ATTR * DramAttr);
//DRDY_BL.c
/*Step5 Burst Length*/
void DRAMBurstLength(DRAM_SYS_ATTR * DramAttr);
//DrivingSetting.c
/*Step6 DRAM Driving Adjustment*/
void DRAMDriving(DRAM_SYS_ATTR * DramAttr);
//ClkCtrl.c
/*Step7 duty cycle control*/
void DutyCycleCtrl(DRAM_SYS_ATTR * DramAttr);
//ClkCtrl.c
/*Step8 DRAM clock phase and delay control*/
void DRAMClkCtrl(DRAM_SYS_ATTR * DramAttr);
//DevInit.c
/*Step9 set register before init DRAM device*/
void DRAMRegInitValue(DRAM_SYS_ATTR * DramAttr);
//DevInit.c
/*Step10 DDR and DDR2 initialize process*/
void DRAMInitializeProc(DRAM_SYS_ATTR * DramAttr);
//DQSSearch.c
/*Step11 Search DQS and DQ output delay*/
void DRAMDQSOutputSearch(DRAM_SYS_ATTR * DramAttr);
//DQSSearch.c
/*Step12 Search DQS input delay*/
void DRAMDQSInputSearch(DRAM_SYS_ATTR * DramAttr);
//RankMap.c
/*Step13 Interleav function in rankmap.c*/
void DRAMBankInterleave(DRAM_SYS_ATTR * DramAttr);
//RankMap.c
/*Step14 Sizing*/
void DRAMSizingMATypeM(DRAM_SYS_ATTR * DramAttr);
//FinalSetting.c
/*Step15 DDR fresh counter setting*/
void DRAMRefreshCounter(DRAM_SYS_ATTR * DramAttr);
//FinnalSetting.c
/*Step16 Final register setting for improve performance*/
void DRAMRegFinalValue(DRAM_SYS_ATTR * DramAttr);
/*set UMA*/
void SetUMARam();
CB_STATUS InstallMemory(DRAM_SYS_ATTR * DramAttr, u32 RamSize);
CB_STATUS DDR2_DRAM_INIT();
#endif

View File

@ -0,0 +1,249 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
void WaitMicroSec(UINTN MicroSeconds)
{
u32 i;
for (i = 0; i < 1024 * MicroSeconds; i++) {
__asm__ volatile ("nop\n\t");
}
return;
}
/*===================================================================
Function : via_write_phys()
Precondition :
Input : addr
value
Output : void
Purpose :
Reference : None
===================================================================*/
void via_write_phys(volatile u32 addr, volatile u32 value)
{
volatile u32 *ptr;
ptr = (volatile u32 *) addr;
*ptr = (volatile u32) value;
}
/*===================================================================
Function : via_read_phys()
Precondition :
Input : addr
Output : u32
Purpose :
Reference : None
===================================================================*/
u32 via_read_phys(volatile u32 addr)
{
volatile u32 *ptr;
volatile u32 y;
// ptr = (volatile u32 *)addr;
y = *(volatile u32 *) addr;
// return *ptr;
return y;
}
/*===================================================================
Function : DimmRead()
Precondition :
Input : x
Output : u32
Purpose :
Reference : None
===================================================================*/
u32 DimmRead(volatile u32 x)
{ // volatile u32 z;
volatile u32 y;
y = *(volatile u32 *) x;
return y;
}
/*===================================================================
Function : DramBaseTest()
Precondition : this function used to verify memory
Input :
BaseAdd,
length,
mode
Output : u32
Purpose :write into and read out to verify if dram is correct
Reference : None
===================================================================*/
BOOLEAN DramBaseTest(u32 BaseAdd, u32 Length,
DRAM_TEST_MODE Mode, BOOLEAN PrintFlag)
{
u32 TestSpan;
u32 Data, Address, Address2;
u8 i, TestCount;
//decide the test mode is continous or step
if (Mode == EXTENSIVE) {
//the test mode is continuos and must test each unit
TestSpan = 4;
TestCount = 1;
} else if (Mode == SPARE) {
// the test mode is step and test some unit
TestSpan = STEPSPAN;
TestCount = TESTCOUNT;
} else {
PRINT_DEBUG_MEM("the test mode is error\r");
return FALSE;
}
//write each test unit the value with TEST_PATTERN
for (Address = BaseAdd; Address < BaseAdd + Length;
Address += TestSpan) {
for (i = 0; i < TestCount; i++)
via_write_phys(Address + i * 4, TEST_PATTERN);
if (PrintFlag) {
if ((u32) Address % 0x10000000 == 0) {
PRINT_DEBUG_MEM("Write in Addr =");
PRINT_DEBUG_MEM_HEX32(Address);
PRINT_DEBUG_MEM("\r");
}
}
}
//compare each test unit with the value of TEST_PATTERN
//and write it with compliment of TEST_PATTERN
for (Address = BaseAdd; Address < BaseAdd + Length;
Address += TestSpan) {
for (i = 0; i < TestCount; i++) {
Data = via_read_phys(Address + i * 4);
via_write_phys(Address + i * 4,
(u32) (~TEST_PATTERN));
if (Data != TEST_PATTERN) {
PRINT_DEBUG_MEM
("TEST_PATTERN ERROR !!!!! ");
Address2 = Address + i * 4;
PRINT_DEBUG_MEM_HEX32(Address2);
PRINT_DEBUG_MEM(" : ");
PRINT_DEBUG_MEM_HEX32(Data);
PRINT_DEBUG_MEM(" \r");
return FALSE;
}
}
if (PrintFlag) {
if ((u32) Address % 0x10000000 == 0) {
PRINT_DEBUG_MEM("Write in Addr =");
PRINT_DEBUG_MEM_HEX32(Address);
PRINT_DEBUG_MEM("\r");
}
}
}
//compare each test unit with the value of ~TEST_PATTERN
for (Address = BaseAdd; Address < BaseAdd + Length;
Address += TestSpan) {
for (i = (u8) (TestCount); i > 0; i--) {
Data = via_read_phys(Address + (i - 1) * 4);
if (Data != ~TEST_PATTERN) {
PRINT_DEBUG_MEM
("~TEST_PATTERN ERROR !!!!! ");
Address2 = Address + (i - 1) * 4;
PRINT_DEBUG_MEM_HEX32(Address2);
PRINT_DEBUG_MEM(" : ");
PRINT_DEBUG_MEM_HEX32(Data);
PRINT_DEBUG_MEM(" \r");
return FALSE;
}
}
}
return TRUE;
}
/*===================================================================
Function : DumpRegisters()
Precondition :
Input :
pPCIPPI,
DevNum,
FuncNum
Output : Void
Purpose :
Reference : None
===================================================================*/
void DumpRegisters(INTN DevNum, INTN FuncNum)
{
INTN i, j;
u8 ByteVal;
ByteVal = 0;
//pci_write_config8(PCI_DEV(0, DevNum, FuncNum), 0xA1, ByteVal);
PRINT_DEBUG_MEM("\rDev %02x Fun %02x\r");
PRINT_DEBUG_MEM
("\r 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\r");
PRINT_DEBUG_MEM
("---------------------------------------------------\r");
for (i = 0; i < 0x10; i++) {
PRINT_DEBUG_MEM_HEX32(i);
for (j = 0; j < 0x10; j++) {
ByteVal =
pci_read_config8(PCI_DEV(0, DevNum, FuncNum),
i * 0x10 + j);
PRINT_DEBUG_MEM_HEX8(ByteVal);
PRINT_DEBUG_MEM(" ");
}
PRINT_DEBUG_MEM("\r");
}
return;
}
/*===================================================================
Function : dumpnorth()
Precondition :
Input :
pPCIPPI,
Func
Output : Void
Purpose :
Reference : None
===================================================================*/
void dumpnorth(u8 Func)
{
u16 r, c;
u8 ByteVal;
PRINT_DEBUG_MEM("Dump North!!!\r");
for (r = 0; r < 32; r++) {
for (c = (u16) (r << 3); c < (r << 3) + 8; c++) {
ByteVal = 0;
ByteVal = pci_read_config8(PCI_DEV(0, 0, Func), c);
PRINT_DEBUG_MEM_HEX16(c);
PRINT_DEBUG_MEM("= ");
PRINT_DEBUG_MEM_HEX8(ByteVal);
}
PRINT_DEBUG_MEM("\r");
}
}

View File

@ -0,0 +1,47 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __DRAM_UTIL_H__
#define __DRAM_UTIL_H__
#define STEPSPAN 0x1000 //the span when test memory in spare mode
#define TESTCOUNT 0x4 // the test count in each range when test memory in spare mode
#define TEST_PATTERN 0x5A5A5A5A //the test pattern
typedef enum __DRAM_TEST_MODE {
EXTENSIVE,
SPARE,
MAXMODE
} DRAM_TEST_MODE;
void WaitMicroSec(UINTN MicroSeconds);
void via_write_phys(u32 addr, u32 value);
u32 via_read_phys(u32 addr);
u32 DimmRead(u32 x);
BOOLEAN DramBaseTest(u32 BaseAdd, u32 Length,
DRAM_TEST_MODE mode, BOOLEAN PrintFlag);
void DumpRegisters(INTN DevNum, INTN FuncNum);
void dumpnorth(u8 Func);
#endif

View File

@ -0,0 +1,34 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define CB_SUCCESS 0x0
#define CB_INVALID_PARAMETER 0x2
#define CB_NOT_READY 0x6
#define CB_DEVICE_ERROR 0x7
#define TRUE 1
#define FALSE 0
typedef int8_t INT8;
typedef unsigned long uintn_t;
typedef uintn_t UINTN;
typedef long intn_t;
typedef intn_t INTN;
typedef UINTN CB_STATUS;
typedef uint8_t BOOLEAN;

View File

@ -0,0 +1,312 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
void DutyCycleCtrl(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 FreqId;
u8 i;
if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 3;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 4;
else if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 5;
else
FreqId = 5;
if (DramAttr->RankNumChA > 0) { // 1 rank
for (i = 0; i < DUTY_CYCLE_REG_NUM; i++) {
Data =
pci_read_config8(MEMCTRL,
ChA_Duty_Control_DDR2[i][0]);
Data &= ChA_Duty_Control_DDR2[i][1]; /*Mask */
Data |= ChA_Duty_Control_DDR2[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
ChA_Duty_Control_DDR2[i][0],
Data);
}
}
if (1 == ENABLE_CHC) { // 1 rank
for (i = 0; i < DUTY_CYCLE_REG_NUM; i++) {
Data =
pci_read_config8(MEMCTRL,
ChB_Duty_Control_DDR2[i][0]);
Data &= ChB_Duty_Control_DDR2[i][1]; /*Mask */
Data |= ChB_Duty_Control_DDR2[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
ChB_Duty_Control_DDR2[i][0],
Data);
}
}
}
/*
DRAM clock phase and delay control
*/
//sub routine list
void ClkPhsCtrlFBMDDR2(DRAM_SYS_ATTR * DramAttr);
void WrtDataPhsCtrl(DRAM_SYS_ATTR * DramAttr);
void DQDQSOutputDlyCtrl(DRAM_SYS_ATTR * DramAttr);
void DQSInputCaptureCtrl(DRAM_SYS_ATTR * DramAttr);
void DCLKPhsCtrl(DRAM_SYS_ATTR * DramAttr);
void DRAMClkCtrl(DRAM_SYS_ATTR * DramAttr)
{
/*write data clock phase control */
WrtDataPhsCtrl(DramAttr);
/*clock phase control */
ClkPhsCtrlFBMDDR2(DramAttr);
/**/ DQDQSOutputDlyCtrl(DramAttr);
/**/ DQSInputCaptureCtrl(DramAttr);
DCLKPhsCtrl(DramAttr);
}
void ClkPhsCtrlFBMDDR2(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 FreqId, i;
if (DramAttr->DramFreq == DIMMFREQ_800)
FreqId = 2;
else if (DramAttr->DramFreq == DIMMFREQ_667)
FreqId = 3;
else if (DramAttr->DramFreq == DIMMFREQ_533)
FreqId = 4;
else if (DramAttr->DramFreq == DIMMFREQ_400)
FreqId = 5;
else
FreqId = 5;
/*channel A */// 2~4 Rank
if (DramAttr->RankNumChA == 1) { // 1 rank
for (i = 0; i < 3; i++) {
Data =
pci_read_config8(MEMCTRL,
DDR2_ChA_Clk_Phase_Table_1R[i]
[0]);
Data &= DDR2_ChA_Clk_Phase_Table_1R[i][1]; /*Mask */
Data |= DDR2_ChA_Clk_Phase_Table_1R[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
DDR2_ChA_Clk_Phase_Table_1R[i]
[0], Data);
}
} else if (DramAttr->RankNumChA > 1) { // 2~4 Rank
for (i = 0; i < 3; i++) {
Data =
pci_read_config8(MEMCTRL,
DDR2_ChA_Clk_Phase_Table_2R[i]
[0]);
Data &= DDR2_ChA_Clk_Phase_Table_2R[i][1]; /*Mask */
Data |= DDR2_ChA_Clk_Phase_Table_2R[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
DDR2_ChA_Clk_Phase_Table_2R[i]
[0], Data);
}
}
#if ENABLE_CHB
if (DramAttr->RankNumChB > 0) { // 1 rank
for (i = 0; i < 3; i++) {
Data =
pci_read_config8(MEMCTRL,
DDR2_ChB_Clk_Phase_Table_1R[i]
[0]);
Data &= DDR2_ChB_Clk_Phase_Table_1R[i][1]; /*Mask */
Data |= DDR2_ChB_Clk_Phase_Table_1R[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
DDR2_ChB_Clk_Phase_Table_1R[i]
[0], Data);
}
}
#endif
}
void WrtDataPhsCtrl(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 FreqId, i;
if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 3;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 4;
else if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 5;
else
FreqId = 5;
if (DramAttr->RankNumChA > 0) { // 1 rank
for (i = 0; i < WrtData_REG_NUM; i++) {
Data =
pci_read_config8(MEMCTRL,
DDR2_ChA_WrtData_Phase_Table
[i][0]);
Data &= DDR2_ChA_WrtData_Phase_Table[i][1]; /*Mask */
Data |= DDR2_ChA_WrtData_Phase_Table[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
DDR2_ChA_WrtData_Phase_Table[i]
[0], Data);
}
}
#if ENABLE_CHB
if (DramAttr->RankNumChB > 0) { // 1 rank
for (i = 0; i < WrtData_REG_NUM; i++) {
Data =
pci_read_config8(MEMCTRL,
DDR2_ChB_WrtData_Phase_Table
[i][0]);
Data &= DDR2_ChB_WrtData_Phase_Table[i][1]; /*Mask */
Data |= DDR2_ChB_WrtData_Phase_Table[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
DDR2_ChB_WrtData_Phase_Table[i]
[0], Data);
}
}
#endif
Data = pci_read_config8(MEMCTRL, 0x8C);
Data &= 0xFC;
Data |= 0x03;
pci_write_config8(MEMCTRL, 0x8C, Data);
}
void DQDQSOutputDlyCtrl(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 FreqId;
if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 0;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 1;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 2;
else
FreqId = 0;
if (DramAttr->RankNumChA > 0) {
Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][0];
pci_write_config8(MEMCTRL, 0xf0, Data);
Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][1];
pci_write_config8(MEMCTRL, 0xf1, Data);
Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][2];
pci_write_config8(MEMCTRL, 0xf2, Data);
Data = DDR2_CHA_DQ_DQS_Delay_Table[FreqId][3];
pci_write_config8(MEMCTRL, 0xf3, Data);
}
#if ENABLE_CHB
if (DramAttr->RankNumChB > 0) {
Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][0];
pci_write_config8(MEMCTRL, 0xf4, Data);
Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][1];
pci_write_config8(MEMCTRL, 0xf5, Data);
Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][2];
pci_write_config8(MEMCTRL, 0xf6, Data);
Data = DDR2_CHB_DQ_DQS_Delay_Table[FreqId][3];
pci_write_config8(MEMCTRL, 0xf7, Data);
}
#endif
}
void DQSInputCaptureCtrl(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 FreqId, i;
if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 3;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 4;
else if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 5;
else
FreqId = 2;
Data = 0x8A;
pci_write_config8(MEMCTRL, 0x77, Data);
if (DramAttr->RankNumChA > 0) { // 1 rank
for (i = 0; i < DQS_INPUT_CAPTURE_REG_NUM; i++) {
Data =
pci_read_config8(MEMCTRL,
DDR2_ChA_DQS_Input_Capture_Tbl
[i][0]);
Data &= DDR2_ChA_DQS_Input_Capture_Tbl[i][1]; /*Mask */
Data |= DDR2_ChA_DQS_Input_Capture_Tbl[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
DDR2_ChA_DQS_Input_Capture_Tbl[i]
[0], Data);
}
}
#if ENABLE_CHB
if (DramAttr->RankNumChB > 0) { // 1 rank
for (i = 0; i < DQS_INPUT_CAPTURE_REG_NUM; i++) {
Data =
pci_read_config8(MEMCTRL,
DDR2_ChB_DQS_Input_Capture_Tbl
[i][0]);
Data &= DDR2_ChB_DQS_Input_Capture_Tbl[i][1]; /*Mask */
Data |= DDR2_ChB_DQS_Input_Capture_Tbl[i][FreqId]; /*set Value */
pci_write_config8(MEMCTRL,
DDR2_ChB_DQS_Input_Capture_Tbl[i]
[0], Data);
}
}
#endif
}
//This is very important, if you don't set it correctly, dram will be unreliable
//set DCLK Phase control(Reg99H[6:1]) according the DDRII in the dimm
void DCLKPhsCtrl(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
Data = 0;
Data = pci_read_config8(MEMCTRL, 0x99);
Data &= 0xE1;
//DDR in Dimm1, MCLKOA[4,3,0] will output MCLK
if (DramAttr->RankPresentMap & 0x03)
Data |= 0x09 << 1;
//DDR in Dimm2, MCLKOA[5,2,1] will output MCLK
if (DramAttr->RankPresentMap & 0x0C)
Data |= 0x06 << 1;
pci_write_config8(MEMCTRL, 0x99, Data);
}

View File

@ -0,0 +1,98 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
void SetDQSOutputCHA(DRAM_SYS_ATTR * DramAttr);
void SetDQSOutputCHB(DRAM_SYS_ATTR * DramAttr);
/*===================================================================
Function : DRAMDQSOutputSearchCHA()
Precondition :
Input :
DramAttr: pointer point to DRAM_SYS_ATTR which consist the DDR and Dimm information
in MotherBoard
Output : Void
Purpose : set DQS output delay register reg70 and DQ output delay register reg71
===================================================================*/
#define CH_A 0
#define CH_B 1
void DRAMDQSOutputSearch(DRAM_SYS_ATTR * DramAttr)
{
if (DramAttr->RankNumChA > 0)
SetDQSOutputCHA(DramAttr);
}
/*===================================================================
Function : SetDQSOutputCHA()
Precondition :
Input :
DramAttr: pointer point to DRAM_SYS_ATTR which consist the DDR and Dimm information
in MotherBoard
Output : Void
Purpose : according the frequence set CHA DQS output
===================================================================*/
void SetDQSOutputCHA(DRAM_SYS_ATTR * DramAttr)
{
u8 Reg70, Reg71;
u8 Index;
if (DramAttr->DramFreq == DIMMFREQ_400)
Index = 3;
else if (DramAttr->DramFreq == DIMMFREQ_533)
Index = 2;
else if (DramAttr->DramFreq == DIMMFREQ_667)
Index = 1;
else if (DramAttr->DramFreq == DIMMFREQ_800)
Index = 0;
else
Index = 3;
if (DramAttr->RankNumChA > 2) {
Reg70 = Fixed_DQSA_3_4_Rank_Table[Index][0];
Reg71 = Fixed_DQSA_3_4_Rank_Table[Index][1];
} else {
Reg70 = Fixed_DQSA_1_2_Rank_Table[Index][0];
Reg71 = Fixed_DQSA_1_2_Rank_Table[Index][1];
}
pci_write_config8(MEMCTRL, 0x70, Reg70);
pci_write_config8(MEMCTRL, 0x71, Reg71);
}
//################
// STEP 12 #
//################
/*===================================================================
Function : DRAMDQSInputSearch()
Precondition :
Input :
DramAttr: pointer point to DRAM_SYS_ATTR which consist the DDR and Dimm information
in MotherBoard
Output : Void
Purpose : search DQS input delay for CHA/CHB
===================================================================*/
void DRAMDQSInputSearch(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
//auto mode
Data = 0x0;
pci_write_config8(MEMCTRL, 0x77, Data);
}

View File

@ -0,0 +1,600 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// Set P6IF DRDY Timing
// Because there are 1.5T & 2.5T CAS latency in DDR1 mode, we need to use RDELAYMD-0
//
// Entry:
// EBP[29:25] = DRAM Speed, Dual_Channel
// VIA_NB2HOST_REG54[7:5] Host Frequency
// VIA_NB3DRAM_REG62[2:0] CAS Latency
//
// Modify NB_Reg:
// VIA_NB2HOST_REG54[3,1]
// VIA_NB2HOST_REG55[1]
// VIA_NB2HOST_REG60
// VIA_NB2HOST_REG61
// VIA_NB2HOST_REG62[3:0]
// VIA_NB2HOST_REG63
// VIA_NB2HOST_REG64
// VIA_NB2HOST_REG65[3:0]
// VIA_NB2HOST_REG66
// VIA_NB2HOST_REG67[5:4]
//
// Processing:
//--------------------------------------------------------------------------
// P6IF DRDY Timing Control:
// *Following algorithm to set DRDY timing
// Set P6IF DRDY Timing by the following 3 conditions:
// 1. RDELAYMD
// a.RDRPH(MD input internal timing control)
// b.CAS Latency
// RDELAYMD(1bit) = bit0 of (CL + RDRPH)
// for example: RDRPH=10b, CL3 -> F3_Rx56[5:4]=11b, 10b + 11b = 101b, RDELAYMD=1 (bit0)
// RDRPH=00b, CL2.5 -> F3_Rx56[5:4]=10b, 00b + 10b = 010b, RDELAYMD=0 (bit0)
// 2. CPU Frequency
// 3. DRAM Frequency
//
// According to above conditions, we create different tables:
// 1. RDELAYMD=0 : for integer CAS latency(ex. CL=3)
// 2. RDELAYMD=1 : for non-integer CAS latency(ex. CL=2.5)
// 3. Normal performance
// 4. Top performance :
// Using phase0 to a case has better performance.
//
// Note: The setting are related to performance and maybe affect DRAM initialize.
// Turn OFF(F2_Rx51[7]=0) this feature at csDRAMRegInitValueJ procedure.
// Turn ON(F2_Rx51[7]=1) this feature at csDRAMRegFinalValueJ procedure.
//
// If F2_Rx51[7]=0, then CPU always wait 8QW, a slower but most stable way
// If F2_Rx51[7]=1, then the timing will refer to F2_Rx60 ~ F2_Rx67,
// a fast way but may cause the system to be unstable.
//
// Coding:
// 1. RDELAYMD and user's option for performance can determine which table
// 2. CPU Frequency can get block offset of table
// 3. DRAM Frequency can get row offset of block
// 4. Set value
//
// PS: Fun2 Rx62, Rx65, Rx67 are don't care bits in 3296, CPU 266MHz doesn't be supported by 3296,
// but I still keep these bits in table to avoid the usage in future
// and do the fewest modification for code.
//
// Early 3T
// Early 3T
#define P6IF_Misc_RFASTH 0x08
#define P6IF_Misc2_RRRDYH3E 0x10
#define P6IF_Misc2_RHTSEL 0x02
#define Rx54E3T P6IF_Misc_RFASTH
#define Rx55E3T P6IF_Misc2_RRRDYH3E
// Early 2T
#define Rx54E2T 0x00
#define Rx55E2T P6IF_Misc2_RRRDYH3E
// Early 1T
#define Rx54E1T 0x00
#define Rx55E1T 0x00
// Early 0T
#define Rx54E0T P6IF_Misc_RFASTH
#define Rx55E0T P6IF_Misc2_RRRDYH3E + P6IF_Misc2_RHTSEL
// Latter 1T
#define Rx54L1T P6IF_Misc_RFASTH
#define Rx55L1T P6IF_Misc2_RHTSEL
#define PH0_0_0_0 0x00
#define PH0_0_0_1 0x01
#define PH0_0_0_2 0x02
#define PH0_0_0_3 0x03
#define PH0_0_1_0 0x04
#define PH0_0_1_1 0x05
#define PH0_0_1_2 0x06
#define PH0_0_2_1 0x09
#define PH0_0_2_2 0x0a
#define PH0_0_2_3 0x0b
#define PH0_0_3_2 0x0e
#define PH0_0_3_3 0x0f
#define PH0_1_1_0 0x14
#define PH0_1_1_1 0x15
#define PH0_2_1_2 0x26
#define PH0_2_2_1 0x29
#define PH0_2_2_2 0x2a
#define PH0_2_2_3 0x2b
#define PH0_2_3_2 0x2e
#define PH0_2_3_3 0x2f
#define PH0_3_2_2 0x3a
#define PH0_3_3_3 0x3f
#define PH1_0_0_0 0x40
#define PH1_0_0_1 0x41
#define PH1_0_1_1 0x45
#define PH1_1_1_1 0x55
#define PH1_2_1_1 0x65
#define PH1_2_2_1 0x69
#define PH2_1_1_1 0x95
#define PH2_1_2_1 0x99
#define PH2_1_2_2 0x9a
#define PH2_2_1_2 0xa6
#define PH2_2_2_1 0xa9
#define PH2_2_2_2 0xaa
#define PH2_2_3_2 0xae
#define PH2_2_3_3 0xaf
#define PH2_3_2_2 0xba
#define PH2_3_2_3 0xbb
#define PH2_3_3_2 0xbe
#define PH3_2_2_3 0xeb
#define PH3_2_3_2 0xee
#define PH3_2_3_3 0xef
#define PH3_3_3_3 0xff
#define PT894_RDRDY_TBL_Width 10
#define PT894_RDRDY_TBL_Block 60
static const u8 PT894_128bit_DELAYMD0_RCONV0[6][6][PT894_RDRDY_TBL_Width] =
// -----------------------------------------------------------------------------------------------------------------
// RX60 RX61 RX62 RX63 RX64 RX65 RX66 RX67 RX54[3,1] RX55[3,1] CPU/DRAM
// LN4:1 LN8:5 LN10:9 QW4:1 QW8:5 QW10:9 WS8:1 WS10:9 RFASTH RRRDYH3E
// RCONV RHTSEL
// -----------------------------------------------------------------------------------------------------------------
{
// cpu100
{
{PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/100
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/133
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 100/333
},
// cpu133
{
{PH0_2_2_1, PH0_0_0_0, PH0_0_0_0, PH0_2_2_1, PH0_0_0_0, PH0_0_0_0, 0x01, 0x00, Rx54E3T, Rx55E3T}, // 133/100
{PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/133
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 133/333
},
// cpu200
{
{PH0_3_3_3, PH0_0_0_0, PH0_0_0_0, PH0_2_2_2, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E2T, Rx55E2T}, // 200/100
{PH2_3_2_3, PH0_0_0_0, PH0_0_0_0, PH2_3_2_3, PH0_0_0_0, PH0_0_0_0, 0x0a, 0x00, Rx54E3T, Rx55E3T}, // 200/133
{PH1_2_2_1, PH0_0_0_1, PH0_0_0_0, PH1_2_2_1, PH0_0_0_1, PH0_0_0_0, 0x01, 0x00, Rx54E3T, Rx55E3T}, // 200/166
{PH1_1_1_1, PH0_0_1_1, PH0_0_0_0, PH1_1_1_1, PH0_0_1_1, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 200/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 200/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 200/333
},
// cpu166
{
{PH0_2_3_3, PH0_0_0_0, PH0_0_0_0, PH0_2_2_3, PH0_0_0_0, PH0_0_0_0, 0x05, 0x00, Rx54E3T, Rx55E3T}, // 166/100
{PH1_2_2_1, PH0_0_0_0, PH0_0_0_0, PH1_2_2_1, PH0_0_0_0, PH0_0_0_0, 0x01, 0x00, Rx54E3T, Rx55E3T}, // 166/133
{PH1_1_1_1, PH0_0_0_1, PH0_0_0_0, PH1_1_1_1, PH0_0_0_1, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 166/333
},
// cpu266
{
{PH0_2_2_3, PH0_0_0_0, PH0_0_0_0, PH0_0_1_1, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E1T, Rx55E1T}, // 266/100
{PH3_3_3_3, PH0_0_0_0, PH0_0_0_0, PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E2T, Rx55E2T}, // 266/133
{PH3_2_3_3, PH0_0_0_3, PH0_0_0_0, PH3_2_3_3, PH0_0_0_2, PH0_0_0_0, 0x0d, 0x00, Rx54E3T, Rx55E3T}, // 266/166
{PH2_2_2_2, PH0_0_2_2, PH0_0_0_0, PH2_1_2_2, PH0_0_1_2, PH0_0_0_0, 0x12, 0x00, Rx54E3T, Rx55E3T}, // 266/200
{PH1_1_1_1, PH1_1_1_1, PH0_0_0_0, PH1_1_1_1, PH1_1_1_1, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 266/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 266/333
},
// cpu333
{
{PH0_1_1_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E0T, Rx55E0T}, // 333/100
{PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E1T, Rx55E1T}, // 333/133
{PH3_3_3_3, PH0_0_0_3, PH0_0_0_0, PH3_3_3_3, PH0_0_0_3, PH0_0_0_0, 0x1f, 0x00, Rx54E2T, Rx55E2T}, // 333/166
{PH2_2_1_2, PH0_0_2_1, PH0_0_0_0, PH1_2_1_1, PH0_0_2_1, PH0_0_0_0, 0x36, 0x00, Rx54E2T, Rx55E2T}, // 333/200
{PH2_1_1_1, PH2_1_1_1, PH0_0_0_0, PH2_1_1_1, PH2_1_1_1, PH0_0_0_0, 0x44, 0x00, Rx54E3T, Rx55E3T}, // 333/266
{PH2_2_2_2, PH2_2_2_2, PH0_0_2_2, PH2_2_2_2, PH2_2_2_2, PH0_0_2_2, 0x00, 0x00, Rx54E3T, Rx55E3T} // 333/333
}
};
static const u8 PT894_128bit_DELAYMD1_RCONV0[6][6][PT894_RDRDY_TBL_Width] =
// -----------------------------------------------------------------------------------------------------------------
// RX60 RX61 RX62 RX63 RX64 RX65 RX66 RX67 RX54[3,1] RX55[3,1] CPU/DRAM
// LN4:1 LN8:5 LN10:9 QW4:1 QW8:5 QW10:9 WS8:1 WS10:9 RFASTH RRRDYH3E
// RCONV RHTSEL
// -----------------------------------------------------------------------------------------------------------------
{
// cpu100
{
{PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/100
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/133
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 100/333
},
// cpu133
{
{PH0_3_2_2, PH0_0_0_0, PH0_0_0_0, PH0_3_2_2, PH0_0_0_0, PH0_0_0_0, 0x02, 0x00, Rx54E3T, Rx55E3T}, // 133/100
{PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/133
{PH1_0_0_0, PH0_0_0_0, PH0_0_0_0, PH1_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 133/333
},
// cpu200
{
{PH0_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E1T, Rx55E1T}, // 200/100
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH2_1_2_1, PH0_0_0_0, PH0_0_0_0, 0x0a, 0x00, Rx54E2T, Rx55E2T}, // 200/133
{PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, 0x04, 0x00, Rx54E3T, Rx55E3T}, // 200/166
{PH2_2_2_2, PH0_0_2_2, PH0_0_0_0, PH2_2_2_2, PH0_0_2_2, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 200/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 200/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 200/333
},
// cpu166
{
{PH0_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_2_1_2, PH0_0_0_0, PH0_0_0_0, 0x05, 0x00, Rx54E2T, Rx55E2T}, // 166/100
{PH2_3_2_2, PH0_0_0_0, PH0_0_0_0, PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, 0x02, 0x00, Rx54E3T, Rx55E3T}, // 166/133
{PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/166
{PH1_0_0_0, PH0_0_0_1, PH0_0_0_0, PH1_0_0_0, PH0_0_0_1, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 166/333
},
// cpu266
{
{PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E0T, Rx55E0T}, // 266/100
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E1T, Rx55E1T}, // 266/133
{PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, PH2_2_1_2, PH0_0_0_2, PH0_0_0_0, 0x15, 0x00, Rx54E2T, Rx55E2T}, // 266/166
{PH3_2_3_3, PH0_0_2_3, PH0_0_0_0, PH2_2_3_2, PH0_0_2_3, PH0_0_0_0, 0x24, 0x00, Rx54E3T, Rx55E3T}, // 266/200
{PH2_2_2_2, PH2_2_2_2, PH0_0_0_0, PH2_2_2_2, PH2_2_2_2, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 266/266
{PH0_0_0_1, PH0_0_1_1, PH0_0_1_0, PH0_0_0_1, PH0_0_1_1, PH0_0_1_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 266/333
},
// cpu333
{
{PH0_3_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E0T, Rx55E0T}, // 333/100
{PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E0T, Rx55E0T}, // 333/133
{PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, 0x1f, 0x00, Rx54E1T, Rx55E1T}, // 333/166
{PH2_3_2_2, PH0_0_3_2, PH0_0_0_0, PH2_2_2_2, PH0_0_2_2, PH0_0_0_0, 0x1b, 0x00, Rx54E2T, Rx55E2T}, // 333/200
{PH2_2_2_2, PH2_2_2_2, PH0_0_0_0, PH2_2_2_1, PH2_2_2_1, PH0_0_0_0, 0x88, 0x00, Rx54E3T, Rx55E3T}, // 333/266
{PH2_2_2_2, PH2_2_2_2, PH0_0_2_2, PH2_2_2_2, PH2_2_2_2, PH0_0_2_2, 0x00, 0x00, Rx54E3T, Rx55E3T} // 333/333
}
};
static const u8 PT894_64bit_DELAYMD0_RCONV0[6][6][PT894_RDRDY_TBL_Width] =
// -----------------------------------------------------------------------------------------------------------------
// RX60 RX61 RX62 RX63 RX64 RX65 RX66 RX67 RX54[3,1] RX55[3,1] CPU/DRAM
// LN4:1 LN8:5 LN10:9 QW4:1 QW8:5 QW10:9 WS8:1 WS10:9 RFASTH RRRDYH3E
// RCONV RHTSEL
// -----------------------------------------------------------------------------------------------------------------
{
// cpu100
{
{PH0_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E3T, Rx55E3T}, // 100/100
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x09, 0x00, Rx54E3T, Rx55E3T}, // 100/133
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 100/333
},
// cpu133
{
{PH0_2_3_2, PH0_0_0_0, PH0_0_0_0, PH0_0_1_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E2T, Rx55E2T}, // 133/100
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E3T, Rx55E3T}, // 133/133
{PH1_0_0_0, PH0_0_0_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E3T, Rx55E3T}, // 133/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 133/333
},
// cpu200
{
{PH0_3_3_3, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E0T, Rx55E0T}, // 200/100
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E1T, Rx55E1T}, // 200/133
{PH3_3_3_3, PH0_0_0_3, PH0_0_0_0, PH1_2_2_1, PH0_0_0_1, PH0_0_0_0, 0x1f, 0x00, Rx54E3T, Rx55E3T}, // 200/166
{PH2_2_2_2, PH0_0_2_2, PH0_0_0_0, PH1_1_1_1, PH0_0_1_1, PH0_0_0_0, 0x3f, 0x00, Rx54E3T, Rx55E3T}, // 200/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E1T, Rx55E1T}, // 200/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 200/333
// DDR2 Both E3T and E2T Fail, need set to E1T, db PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 00110011b, 00000000b, Rx54E3T, Rx55E3T ;200/266
},
// cpu166
{
{PH0_2_3_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E1T, Rx55E1T}, // 166/100
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_1_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E2T, Rx55E2T}, // 166/133
{PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, PH1_1_1_1, PH0_0_0_1, PH0_0_0_0, 0x1f, 0x00, Rx54E3T, Rx55E3T}, // 166/166
{PH1_0_0_1, PH0_0_1_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x1e, 0x00, Rx54E3T, Rx55E3T}, // 166/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 166/333
},
// cpu266
{
{PH0_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54L1T, Rx55L1T}, // 266/100
{PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54L1T, Rx55L1T}, // 266/133
{PH3_2_3_2, PH0_0_0_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x1f, 0x00, Rx54E1T, Rx55E1T}, // 266/166
{PH3_2_2_3, PH0_0_2_2, PH0_0_0_0, PH1_0_0_1, PH0_0_0_0, PH0_0_0_0, 0x3f, 0x00, Rx54E2T, Rx55E2T}, // 266/200
{PH2_2_2_2, PH2_2_2_2, PH0_0_0_0, PH1_1_1_1, PH1_1_1_1, PH0_0_0_0, 0xff, 0x00, Rx54E3T, Rx55E3T}, // 266/266
{PH0_0_1_1, PH0_1_1_1, PH0_0_1_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x9c, 0x03, Rx54E3T, Rx55E3T} // 266/333
},
// cpu333
{
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54L1T, Rx55L1T}, // 333/100 ;DO NOT Support
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54L1T, Rx55L1T}, // 333/133
{PH3_3_3_3, PH0_0_0_3, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x1f, 0x00, Rx54E0T, Rx55E0T}, // 333/166
{PH2_3_3_2, PH0_0_3_3, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x3f, 0x00, Rx54E1T, Rx55E1T}, // 333/200
{PH3_3_3_3, PH3_3_3_3, PH0_0_0_0, PH2_1_1_1, PH2_1_1_1, PH0_0_0_0, 0xff, 0x00, Rx54E3T, Rx55E3T}, // 333/266
{PH2_2_2_2, PH2_2_2_2, PH0_0_2_2, PH2_2_2_2, PH2_2_2_2, PH0_0_2_2, 0xff, 0x03, Rx54E3T, Rx55E3T} // 333/333
}
};
static const u8 PT894_64bit_DELAYMD1_RCONV0[6][6][PT894_RDRDY_TBL_Width] =
// -----------------------------------------------------------------------------------------------------------------
// RX60 RX61 RX62 RX63 RX64 RX65 RX66 RX67 RX54[3,1] RX55[3,1] CPU/DRAM
// LN4:1 LN8:5 LN10:9 QW4:1 QW8:5 QW10:9 WS8:1 WS10:9 RFASTH RRRDYH3E
// RCONV RHTSEL
// -----------------------------------------------------------------------------------------------------------------
{
// cpu100
{
{PH0_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E3T, Rx55E3T}, // 100/100
{PH1_0_0_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x06, 0x00, Rx54E3T, Rx55E3T}, // 100/133
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 100/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // ;100/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 100/333
},
// cpu133
{
{PH0_3_3_3, PH0_0_0_0, PH0_0_0_0, PH0_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E2T, Rx55E2T}, // 133/100
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH1_1_1_1, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E3T, Rx55E3T}, // 133/133
{PH1_0_1_1, PH0_0_0_1, PH0_0_0_0, PH1_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x1c, 0x00, Rx54E3T, Rx55E3T}, // 133/166
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x09, 0x00, Rx54E3T, Rx55E3T}, // 133/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 133/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 133/333
},
// cpu200
{
{PH0_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54L1T, Rx55L1T}, // 200/100
{PH3_3_3_3, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E1T, Rx55E1T}, // 200/133
{PH2_2_3_3, PH0_0_0_2, PH0_0_0_0, PH1_0_1_1, PH0_0_0_1, PH0_0_0_0, 0x1f, 0x00, Rx54E2T, Rx55E2T}, // 200/166
{PH3_3_3_3, PH0_0_3_3, PH0_0_0_0, PH2_2_2_2, PH0_0_2_2, PH0_0_0_0, 0x3f, 0x00, Rx54E3T, Rx55E3T}, // 200/200
{PH0_0_1_1, PH0_0_1_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0xcc, 0x00, Rx54E3T, Rx55E3T}, // 200/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 200/333
},
// cpu166
{
{PH0_3_3_3, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x07, 0x00, Rx54E1T, Rx55E1T}, // 166/100
{PH2_2_3_3, PH0_0_0_0, PH0_0_0_0, PH1_0_1_1, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54E2T, Rx55E2T}, // 166/133
{PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, 0x1f, 0x00, Rx54E3T, Rx55E3T}, // 166/166
{PH1_1_1_1, PH0_0_1_1, PH0_0_0_0, PH1_0_0_0, PH0_0_0_1, PH0_0_0_0, 0x39, 0x00, Rx54E3T, Rx55E3T}, // 166/200
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T}, // 166/266
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54E3T, Rx55E3T} // 166/333
},
// cpu266
{
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54L1T, Rx55L1T}, // 266/100 ;DO NOT Support
{PH2_2_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54L1T, Rx55L1T}, // 266/133
{PH2_2_1_2, PH0_0_0_1, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x1f, 0x00, Rx54E0T, Rx55E0T}, // 266/166
{PH3_3_3_3, PH0_0_3_3, PH0_0_0_0, PH1_1_1_1, PH0_0_1_1, PH0_0_0_0, 0x3f, 0x00, Rx54E2T, Rx55E2T}, // 266/200
{PH3_3_3_3, PH3_3_3_3, PH0_0_0_0, PH2_2_2_2, PH2_2_2_2, PH0_0_0_0, 0xff, 0x00, Rx54E3T, Rx55E3T}, // 266/266
{PH1_1_1_1, PH1_1_1_1, PH0_0_1_1, PH0_0_0_1, PH0_0_1_1, PH0_0_1_0, 0x73, 0x02, Rx54E3T, Rx55E3T} // 266/333
},
// cpu333
{
{PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x00, 0x00, Rx54L1T, Rx55L1T}, // 333/100 ;DO NOT Support
{PH3_3_3_3, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x0f, 0x00, Rx54L1T, Rx55L1T}, // 333/133
{PH2_2_2_2, PH0_0_0_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x1f, 0x00, Rx54L1T, Rx55L1T}, // 333/166
{PH2_2_2_2, PH0_0_2_2, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, PH0_0_0_0, 0x3f, 0x00, Rx54E1T, Rx55E1T}, // 333/200
{PH2_3_2_2, PH2_3_2_2, PH0_0_0_0, PH0_1_1_0, PH0_1_1_0, PH0_0_0_0, 0xff, 0x00, Rx54E2T, Rx55E2T}, // 333/266
{PH3_3_3_3, PH3_3_3_3, PH0_0_3_3, PH2_2_2_2, PH2_2_2_2, PH0_0_2_2, 0xff, 0x03, Rx54E3T, Rx55E3T} // 333/333
}
};
void DRAMDRDYSetting(DRAM_SYS_ATTR * DramAttr)
{
u8 Data, CL, RDRPH;
u8 CpuFreq, DramFreq;
u8 ProgData[PT894_RDRDY_TBL_Width];
u8 DelayMode;
u8 DrdyMode;
u8 Index;
/*
this function has 3 switchs, correspond to 3 level of Drdy setting.
0:Slowest, 1:Default, 2:Optimize
you can only open one switch
*/
#if 1 //this is slowest
// 0 -> Slowest
//Write slowest value to register
Data = 0xAA;
pci_write_config8(PCI_DEV(0, 0, 2), 0x60, Data);
Data = 0x0A;
pci_write_config8(PCI_DEV(0, 0, 2), 0x61, Data);
Data = 0x00;
pci_write_config8(PCI_DEV(0, 0, 2), 0x62, Data);
Data = 0xAA;
pci_write_config8(PCI_DEV(0, 0, 2), 0x63, Data);
Data = 0x0A;
pci_write_config8(PCI_DEV(0, 0, 2), 0x64, Data);
Data = 0x00;
pci_write_config8(PCI_DEV(0, 0, 2), 0x65, Data);
Data = 0x00;
pci_write_config8(PCI_DEV(0, 0, 2), 0x66, Data);
Data = 0x00;
pci_write_config8(PCI_DEV(0, 0, 2), 0x67, Data);
Data = pci_read_config8(PCI_DEV(0, 0, 2), 0x54);
Data = Data & 0xF5;
Data |= 0x08;
pci_write_config8(PCI_DEV(0, 0, 2), 0x54, Data);
//Data=pci_read_config8(PCI_DEV(0,0,2), 0x55);
//Data = Data & (~0x20);
//pci_write_config8(PCI_DEV(0,0,2), 0x55, Data);
//enable drdy timing
Data = pci_read_config8(PCI_DEV(0, 0, 2), 0x51);
Data = Data | 0x80;
pci_write_config8(PCI_DEV(0, 0, 2), 0x51, Data);
#endif
#if 0 //default
{
//disable drdy timing
Data = pci_read_config8(PCI_DEV(0, 0, 2), 0x51);
Data = Data & 0x7F;
pci_write_config8(PCI_DEV(0, 0, 2), 0x51, Data);
}
#endif
#if 0 // 2:Optimize
//CL :reg6x[2:0]
Data = pci_read_config8(MEMCTRL, 0x62);
CL = Data & 0x07;
//RDRPH: reg7B[6:4]
Data = pci_read_config8(MEMCTRL, 0x7B);
RDRPH = (Data & 0x70) >> 4;
//CpuFreq: F2Reg54[7:5]
Data = pci_read_config8(PCI_DEV(0, 0, 2), 0x54);
CpuFreq = (Data & 0xE0) >> 5;
//DramFreq:F3Reg90[2:0]
Data = pci_read_config8(MEMCTRL, 0x90);
DramFreq = Data & 0x07;
DelayMode = CL + RDRPH; // RDELAYMD = bit0 of (CAS Latency + RDRPH)
DelayMode &= 0x01;
//In 364, there is no 128 bit
if (DelayMode == 1) { // DelayMode 1
for (Index = 0; Index < PT894_RDRDY_TBL_Width; Index++)
ProgData[Index] =
PT894_64bit_DELAYMD1_RCONV0[CpuFreq][DramFreq]
[Index];
} else { // DelayMode 0
for (Index = 0; Index < PT894_RDRDY_TBL_Width; Index++)
ProgData[Index] =
PT894_64bit_DELAYMD0_RCONV0[CpuFreq][DramFreq]
[Index];
}
Data = ProgData[0];
pci_write_config8(PCI_DEV(0, 0, 2), 0x60, Data);
Data = ProgData[1];
pci_write_config8(PCI_DEV(0, 0, 2), 0x61, Data);
Data = ProgData[2];
pci_write_config8(PCI_DEV(0, 0, 2), 0x62, Data);
Data = ProgData[3];
pci_write_config8(PCI_DEV(0, 0, 2), 0x63, Data);
Data = ProgData[4];
pci_write_config8(PCI_DEV(0, 0, 2), 0x64, Data);
Data = ProgData[5];
pci_write_config8(PCI_DEV(0, 0, 2), 0x65, Data);
Data = ProgData[6];
pci_write_config8(PCI_DEV(0, 0, 2), 0x66, Data);
Data = ProgData[7];
pci_write_config8(PCI_DEV(0, 0, 2), 0x67, Data);
Data = pci_read_config8(PCI_DEV(0, 0, 2), 0x54);
Data = (Data & 0xF5) | ProgData[8];
pci_write_config8(PCI_DEV(0, 0, 2), 0x54, Data);
Data = pci_read_config8(PCI_DEV(0, 0, 2), 0x55);
Data = Data & (~0x22) | ProgData[9];
pci_write_config8(PCI_DEV(0, 0, 2), 0x62, Data);
//enable drdy timing
Data = pci_read_config8(PCI_DEV(0, 0, 2), 0x51);
Data = Data | 0x80;
pci_write_config8(PCI_DEV(0, 0, 2), 0x51, Data);
#endif
}
/*This routine process the ability for North Bridge side burst functionality
There are 3 variances that are valid:
1. DIMM BL=8, chipset BL=8
2. DIMM BL=4, chipset BL=4
3. DIMM BL=4, chipset BL=8 (only happened on Dual channel)
Device 0 function 2 HOST:REG54[4] must be 1 when 128-bit mode.
Since DIMM will be initialized in each rank individually,
1.If all DIMM BL=4, DIMM will initialize BL=4 first,
then check dual_channel flag to enable VIA_NB2HOST_REG54[4].
2.If all DIMM BL=8, DIMM will initialize BL=8 first,
then check dual_channel flag for re-initialize DIMM BL=4.
also VIA_NB2HOST_REG54[4] need to be enabled.
Chipset_BL8==>chipset side can set burst length=8
two register need to set
1. Device 0 function 2 HOST:REG54[4]
2. Device 0 function 3 DRAM:REG6C[3]
*/
void DRAMBurstLength(DRAM_SYS_ATTR * DramAttr)
{
u8 Data, BL;
u8 Sockets;
/*SPD byte16 bit3,2 describes the burst length supported. bit3=1 support BL=8 bit2=1 support BL=4 */
BL = 0x0c;
for (Sockets = 0; Sockets < 2; Sockets++) {
if (DramAttr->DimmInfo[Sockets].bPresence) {
BL &=
(DramAttr->DimmInfo[Sockets].
SPDDataBuf[SPD_SDRAM_BURSTLENGTH]);
}
}
/*D0F3Rx6c bit3 CHA SDRAM effective burst length, for 64bit mode ranks =0 BL=4 ; =1 BL=8 */
if (BL & 0x08) /*All Assembly support BL=8 */
BL = 0x8; /*set bit3 */
else
BL = 0x00; /*clear bit3 */
Data = pci_read_config8(MEMCTRL, 0x6c);
Data = (u8) ((Data & 0xf7) | BL);
#if ENABLE_CHB
if (DramAttr->RankNumChB > 0) {
BL = DramAttr->DimmInfo[2].
SPDDataBuf[SPD_SDRAM_BURSTLENGTH];
//Rx6c[1], CHB burst length
if (BL & 0x08) /*CHB support BL=8 */
BL = 0x2; /*set bit1 */
else
BL = 0x00; /*clear bit1 */
Data = (Data & 0xFD) | BL;
}
#endif
pci_write_config8(MEMCTRL, 0x6c, Data);
}

View File

@ -0,0 +1,192 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define SMBUS_ADDR_CH_A_1 0xA0 // Dimmx
#define SMBUS_ADDR_CH_A_2 0xA2 // Dimmx
#define SMBUS_ADDR_CH_B_1 0xA4 // Dimmx
#define SMBUS_ADDR_CH_B_2 0xA6 // Dimmx
/*read data*/
CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 * Buf);
void DRAMCmdRate(DRAM_SYS_ATTR * DramAttr);
CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR * DramAttr);
CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 * Buf)
{
// CB_STATUS Status = CB_NOT_READY;
u8 Val;
u8 i;
if (1 > Length || NULL == Buf)
return CB_INVALID_PARAMETER;
for (i = 0; i < Length; i++) {
Val = get_spd_data(ctrl.channel0[Slot], i);
*(Buf + i) = Val;
}
return CB_SUCCESS;
}
CB_STATUS DRAMDetect(DRAM_SYS_ATTR * DramAttr)
{
CB_STATUS Status = CB_SUCCESS;
PRINT_DEBUG_MEM("Dram Detection \r");
/*Read D0F3Rx6C , detect memory type DDR1 or DDR2 */
// 353 supports DDR2 only
DramAttr->DramType = RAMTYPE_SDRAMDDR2;
/*get information for SPD */
Status = GetInfoFromSPD(DramAttr);
if (CB_SUCCESS == Status) {
/*64bit or 128Bit */
//
// if (RAMTYPE_SDRAMDDR == DramAttr->DramType)
/*select command rate */
DRAMCmdRate(DramAttr);
}
return Status;
}
// Determine 1T or 2T Command Rate:
// To enable 1T command Rate, the system will satisfy the following 3 conditions:
// 1. Each DRAM channel may have 1 or 2 ranks of DIMM. 3/4 ranks can not support 1T command rate
// It's for loading issue. 1T can supports (a). only one socket with two ranks OR
// (b). two sockets each with 1 rank.
// 2. User wishes to enable 1T command rate mode and turn on by Setup menu
// 3. If 1T command rate can be enabled, just set EBP bit here.
void DRAMCmdRate(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
// 5.1t/2t command rate, use the stable set
//offset50
DramAttr->CmdRate = 2;
Data = pci_read_config8(MEMCTRL, 0x50);
Data = (u8) (Data & 0xEE);
pci_write_config8(MEMCTRL, 0x50, Data);
}
/*get SPD data and set RANK presence map*/
/*
Sockets0,1 is Channel A / Sockets2,3 is Channel B
socket0 SPD device address 0x50 / socket1 SPD device address 0x51
socket2 SPD device address 0x52 / socket3 SPD device address 0x53
*/
CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR * DramAttr)
{
CB_STATUS Status;
u8 *pSPDDataBuf;
u8 ModuleDataWidth;
u8 ChipWidth;
u8 RankNum;
u8 LoadNum;
u8 Sockets, i;
BOOLEAN bFind;
bFind = FALSE;
Status = CB_DEVICE_ERROR;
for (Sockets = 0; Sockets < MAX_SOCKETS; Sockets++) {
pSPDDataBuf = DramAttr->DimmInfo[Sockets].SPDDataBuf;
pSPDDataBuf[SPD_MEMORY_TYPE] =
get_spd_data(ctrl.channel0[Sockets], SPD_MEMORY_TYPE);
if (pSPDDataBuf[SPD_MEMORY_TYPE] == 0) {
Status = CB_NOT_READY;
} else {
Status =
GetSPDData(Sockets, SPD_DATA_SIZE,
pSPDDataBuf);
PRINT_DEBUG_MEM("SPD : \r");
for (i = 0; i < SPD_DATA_SIZE; i++) {
PRINT_DEBUG_MEM(" ");
PRINT_DEBUG_MEM_HEX8(pSPDDataBuf[i]);
}
}
if (CB_SUCCESS == Status) {
/*if Dram Controller detected type not same as the type got from SPD, There are ERROR */
if (pSPDDataBuf[SPD_MEMORY_TYPE] !=
DramAttr->DramType) {
Status = CB_DEVICE_ERROR; /*Memory int error */
PRINT_DEBUG_MEM
("Memory Device ERROR: Dram Controller detected type != type got from SPD \r");
break;
}
DramAttr->DimmInfo[Sockets].bPresence = TRUE;
/*calculate load number (chips number) */
ModuleDataWidth =
(u8) (DramAttr->DimmInfo[Sockets].
SPDDataBuf[SPD_SDRAM_MOD_DATA_WIDTH +
1]);
ModuleDataWidth = (u8) (ModuleDataWidth << 8);
ModuleDataWidth |=
(u8) (DramAttr->DimmInfo[Sockets].
SPDDataBuf[SPD_SDRAM_MOD_DATA_WIDTH]);
ChipWidth =
(u8) ((DramAttr->DimmInfo[Sockets].
SPDDataBuf[SPD_SDRAM_WIDTH]) & 0x7F);
LoadNum = (u8) (ModuleDataWidth / ChipWidth);
/*set the RANK map */
RankNum = (u8) (pSPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x3); /*get bit0,1, the Most number of supported RANK is 2 */
if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
RankNum++; /*for DDR bit[0,1] 01->1 RANK 10->2 RANK; for DDR2 bit[0,1] = 00 -> 1 RANK 01 -> 2 RANK */
if (RankNum != 2 && RankNum != 1) { /*every DIMM have 1 or 2 ranks */
Status = CB_DEVICE_ERROR;
PRINT_DEBUG_MEM
("Memory Device ERROR: the number of RANK not support!\r");
break;
}
if (Sockets < 2) { /*sockets0,1 is channel A */
DramAttr->RankNumChA =
(u8) (DramAttr->RankNumChA + RankNum);
DramAttr->DimmNumChA++;
DramAttr->LoadNumChA =
(u8) (DramAttr->LoadNumChA * LoadNum *
RankNum);
} else { /*sockets2,3 is channel B */
DramAttr->RankNumChB =
(u8) (DramAttr->RankNumChB + RankNum);
DramAttr->DimmNumChB++;
DramAttr->LoadNumChB =
(u8) (DramAttr->LoadNumChB * LoadNum *
RankNum);;
}
RankNum |= 1; /*set rank map */
DramAttr->RankPresentMap |=
(RankNum << (Sockets * 2));
bFind = TRUE;
}
}
PRINT_DEBUG_MEM("Rank Present Map:");
PRINT_DEBUG_MEM_HEX8(DramAttr->RankPresentMap);
PRINT_DEBUG_MEM("\r");
if (bFind)
Status = CB_SUCCESS;
return Status;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,396 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Driving setting: ODT/DQS/DQ/CS/MAA/MAB/DCLK
*/
void DrivingODT(DRAM_SYS_ATTR * DramAttr);
void DrivingDQS(DRAM_SYS_ATTR * DramAttr);
void DrivingDQ(DRAM_SYS_ATTR * DramAttr);
void DrivingCS(DRAM_SYS_ATTR * DramAttr);
void DrivingMA(DRAM_SYS_ATTR * DramAttr);
void DrivingDCLK(DRAM_SYS_ATTR * DramAttr);
/* DRAM Driving Adjustment*/
void DRAMDriving(DRAM_SYS_ATTR * DramAttr)
{
PRINT_DEBUG_MEM("set ODT!\r");
DrivingODT(DramAttr);
PRINT_DEBUG_MEM("set DQS!\r");
DrivingDQS(DramAttr);
PRINT_DEBUG_MEM(("set DQ!\r"));
DrivingDQ(DramAttr);
PRINT_DEBUG_MEM("set CS!\r");
DrivingCS(DramAttr);
PRINT_DEBUG_MEM("set MAA!\r");
DrivingMA(DramAttr);
PRINT_DEBUG_MEM("set DCLK!\r");
DrivingDCLK(DramAttr);
}
/*
ODT Control for DQ/DQS/CKE/SCMD/DCLKO in ChA & ChB
which include driving enable/range and strong/weak selection
Processing: According to DRAM frequency to ODT control bits.
Because function enable bit must be the last one to be set.
So the register VIA_NB3DRAM_REGD4 and VIA_NB3DRAM_REGD3 should be
the last register to be programmed.
*/
//-------------------------------------------------------------------------------
// ODT Lookup Table
//-------------------------------------------------------------------------------
#define Rank0_ODT 0
#define Rank1_ODT 1
#define Rank2_ODT 2
#define Rank3_ODT 3
#define NA_ODT 0
#define NB_ODT_75ohm 0
#define NB_ODT_150ohm 1
#define DDR2_ODT_75ohm 0x20
#define DDR2_ODT_150ohm 0x40
// Setting of ODT Lookup TBL
// RankMAP , Rank 3 Rank 2 Rank 1 Rank 0 , DRAM & NB ODT setting
// db 0000b , Reserved
#define ODTLookup_Tbl_count 8
static const u8 ODTLookup_TBL[ODTLookup_Tbl_count][3] = {
// 0001b
{0x01,
(Rank3_ODT << 6) + (Rank2_ODT << 4) + (Rank1_ODT << 2) +
Rank0_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 0010b , Reserved
// 0011b
{0x03,
(Rank3_ODT << 6) + (Rank2_ODT << 4) + (Rank0_ODT << 2) +
Rank1_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 0100b
{0x04,
(Rank3_ODT << 6) + (Rank2_ODT << 4) + (Rank1_ODT << 2) +
Rank0_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 0101b
{0x05,
(Rank3_ODT << 6) + (Rank0_ODT << 4) + (Rank1_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm},
// 0110b , Reserved
// 0111b
{0x07,
(Rank3_ODT << 6) + (Rank0_ODT << 4) + (Rank2_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm},
// 1000b , Reserved
// 1001b , Reserved
// 1010b , Reserved
// 1011b , Reserved
// 1100b
{0x0c,
(Rank2_ODT << 6) + (Rank3_ODT << 4) + (Rank1_ODT << 2) +
Rank0_ODT, DDR2_ODT_150ohm + NB_ODT_75ohm},
// 1101b
{0x0d,
(Rank0_ODT << 6) + (Rank0_ODT << 4) + (Rank1_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm},
// 1110b , Reserved
// 1111b
{0x0f,
(Rank0_ODT << 6) + (Rank0_ODT << 4) + (Rank2_ODT << 2) +
Rank2_ODT, DDR2_ODT_75ohm + NB_ODT_150ohm}
};
#define ODT_Table_Width_DDR2 4
// RxD6 RxD3
static const u8 ODT_Control_DDR2[ODT_Table_Width_DDR2] = { 0xFC, 0x01 };
void DrivingODT(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 i;
BOOLEAN bFound;
pci_write_config8(MEMCTRL, 0xD0, 0x88);
Data = ODT_Control_DDR2[0];
pci_write_config8(MEMCTRL, 0xd6, Data);
Data = ODT_Control_DDR2[1];
pci_write_config8(MEMCTRL, 0xd3, Data);
Data = pci_read_config8(MEMCTRL, 0x9e);
//set MD turn_around wait state
Data &= 0xCF; /*clear bit4,5 */
if (DIMMFREQ_400 == DramAttr->DramFreq)
Data |= 0x0;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
Data |= 0x10;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
Data |= 0x20;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
Data |= 0x20;
else
Data |= 0;
pci_write_config8(MEMCTRL, 0x9e, Data);
if (DIMMFREQ_400 == DramAttr->DramFreq)
Data = 0x0;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
Data = 0x11;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
Data = 0x11;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
Data = 0x11;
else
Data = 0;
pci_write_config8(MEMCTRL, 0x9f, Data);
/*channel A ODT select */
if (DramAttr->DimmNumChA > 0) {
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0x5F; /*clear bit7,5 */
if (DramAttr->RankNumChA > 2)
Data |= 0xA0; /*if rank number > 2 (3or4), set bit7,5 */
else
Data |= 0x00; /*if rank number is 1or2, clear bit5 */
pci_write_config8(MEMCTRL, 0xd5, Data);
Data = pci_read_config8(MEMCTRL, 0xd7);
Data &= 0xEF; /*clear bit7 */
if (DramAttr->RankNumChA > 2)
Data |= 0x80; /*if rank number > 2 (3or4), set bit7 */
else
Data |= 0x00; /*if rank number is 1or2, clear bit7 */
pci_write_config8(MEMCTRL, 0xd7, Data);
/*channel A */
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0xF3; //bit2,3
if (DramAttr->DimmNumChA == 2) /*2 Dimm, 3or4 Ranks */
Data |= 0x00;
else if (DramAttr->DimmNumChA == 1)
Data |= 0x04;
pci_write_config8(MEMCTRL, 0xd5, Data);
if ((DramAttr->RankPresentMap & 0x0F) != 0) { /*channel A */
// MAA ODT Lookup Table
bFound = FALSE;
for (i = 0; i < ODTLookup_Tbl_count; i++) {
if ((DramAttr->RankPresentMap & 0x0F) ==
ODTLookup_TBL[i][0]) {
Data = ODTLookup_TBL[i][1];
bFound = TRUE;
}
}
if (!bFound) { /*set default value */
Data =
ODTLookup_TBL[ODTLookup_Tbl_count -
1][1];
}
pci_write_config8(MEMCTRL, 0x9c, Data);
//set CHA MD ODT control State Dynamic-on
Data = pci_read_config8(MEMCTRL, 0xD4);
Data &= 0xC9;
Data |= 0x30;
pci_write_config8(MEMCTRL, 0xD4, Data);
Data = pci_read_config8(MEMCTRL, 0x9e);
Data |= 0x01;
pci_write_config8(MEMCTRL, 0x9e, Data);
}
}
/*channel B */
if (1 == ENABLE_CHC) {
//CHB has not auto compensation mode ,so must set it manual,or else CHB initialization will not successful
// Data =0x88;
//pci_write_config8(MEMCTRL, 0xd0, Data);
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0xAF;
if (DramAttr->RankNumChB > 2) /*rank number 3 or 4 */
Data |= 0x50;
else
Data |= 0x00;
pci_write_config8(MEMCTRL, 0xd5, Data);
Data = pci_read_config8(MEMCTRL, 0xd7);
Data &= 0xBF; /*clear bit6 */
if (DramAttr->RankNumChB > 2)
Data |= 0x40; /*if rank number > 2 (3or4), set bit7 */
else
Data |= 0x00; /*if rank number is 1or2, clear bit7 */
pci_write_config8(MEMCTRL, 0xd7, Data);
Data = pci_read_config8(MEMCTRL, 0xd5);
Data &= 0xFC;
if (DramAttr->DimmNumChB == 2) /*2 Dimm, 3or4 Ranks */
Data |= 0x00; // 2 dimm RxD5[2,0]=0,0b
else if (DramAttr->DimmNumChB == 1)
Data |= 0x01; // 1 dimm RxD5[2,0]=1,1b
pci_write_config8(MEMCTRL, 0xd5, Data);
//set CHB MD ODT control State Dynamic-on
Data = pci_read_config8(MEMCTRL, 0xD4);
Data &= 0xF6;
Data |= 0x08;
pci_write_config8(MEMCTRL, 0xD4, Data);
//enable CHB differential DQS input
Data = pci_read_config8(MEMCTRL, 0x9E);
Data |= 0x02;
pci_write_config8(MEMCTRL, 0x9E, Data);
}
//enable ODT Control
Data = pci_read_config8(MEMCTRL, 0x9e);
Data |= 0x80;
pci_write_config8(MEMCTRL, 0x9e, Data);
}
void DrivingDQS(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
/*channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_DQSA_Driving_Table[DramAttr->RankNumChA - 1];
pci_write_config8(MEMCTRL, 0xe0, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_DQSB_Driving_Table[DramAttr->RankNumChB - 1];
pci_write_config8(MEMCTRL, 0xe1, Data);
}
}
void DrivingDQ(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
/*channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_DQA_Driving_Table[DramAttr->RankNumChA - 1];
pci_write_config8(MEMCTRL, 0xe2, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_DQB_Driving_Table[DramAttr->RankNumChB - 1];
pci_write_config8(MEMCTRL, 0xe3, Data);
}
}
void DrivingCS(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
/*Channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_CSA_Driving_Table_x8[DramAttr->RankNumChA - 1];
pci_write_config8(MEMCTRL, 0xe4, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_CSB_Driving_Table_x8[DramAttr->RankNumChB - 1];
pci_write_config8(MEMCTRL, 0xe5, Data);
}
}
void DrivingMA(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 i, FreqId;
if (DramAttr->RankNumChA > 0) {
if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 1;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 3;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 4;
else
FreqId = 1;
for (i = 0; i < MA_Table; i++) {
if (DramAttr->LoadNumChA <=
DDR2_MAA_Driving_Table[i][0]) {
Data = DDR2_MAA_Driving_Table[i][FreqId];
break;
}
}
pci_write_config8(MEMCTRL, 0xe8, Data);
}
if (1 == ENABLE_CHC) {
for (i = 0; i < MA_Table; i++) {
if (DramAttr->LoadNumChA <=
DDR2_MAB_Driving_Table[i][0]) {
Data = DDR2_MAB_Driving_Table[i][1];
break;
}
}
pci_write_config8(MEMCTRL, 0xe9, Data);
}
}
void DrivingDCLK(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 FreqId;
if (DIMMFREQ_400 == DramAttr->DramFreq)
FreqId = 0;
else if (DIMMFREQ_533 == DramAttr->DramFreq)
FreqId = 1;
else if (DIMMFREQ_667 == DramAttr->DramFreq)
FreqId = 2;
else if (DIMMFREQ_800 == DramAttr->DramFreq)
FreqId = 4;
else
FreqId = 0;
/*channel A */
if (DramAttr->RankNumChA > 0) {
Data = DDR2_DCLKA_Driving_Table[FreqId];
pci_write_config8(MEMCTRL, 0xe6, Data);
}
/*channel B */
if (1 == ENABLE_CHC) {
Data = DDR2_DCLKB_Driving_Table[FreqId];
pci_write_config8(MEMCTRL, 0xe7, Data);
}
}

View File

@ -0,0 +1,129 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
static const u8 RefreshCounter[7][2] = {
//Non_256Mbit, 256Mbit
{0xCA, 0xA8}, // DRAM400
{0xCA, 0xA8}, // DRAM333
{0xCA, 0x86}, // DRAM266
{0xCA, 0x65}, // DRAM200
{0xA8, 0x54}, // DRAM166
{0x86, 0x43}, // DRAM133
{0x65, 0x32} // DRAM100
};
void DRAMRefreshCounter(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 Freq = 5, i, Dram_256_Mb;
if (DramAttr->DramFreq == DIMMFREQ_800)
Freq = 0;
else if (DramAttr->DramFreq == DIMMFREQ_667)
Freq = 1;
else if (DramAttr->DramFreq == DIMMFREQ_533)
Freq = 2;
else if (DramAttr->DramFreq == DIMMFREQ_400)
Freq = 3;
else if (DramAttr->DramFreq == DIMMFREQ_333)
Freq = 4;
else if (DramAttr->DramFreq == DIMMFREQ_266)
Freq = 5;
else if (DramAttr->DramFreq == DIMMFREQ_200)
Freq = 6;
else
Freq = 6;
Dram_256_Mb = 0;
for (i = 0; i < MAX_SOCKETS; i++) {
if (DramAttr->DimmInfo[i].SPDDataBuf[SPD_SDRAM_ROW_ADDR] ==
13) {
Dram_256_Mb = 1;
break;
}
}
Data = RefreshCounter[Freq][Dram_256_Mb];
pci_write_config8(MEMCTRL, 0x6a, Data);
}
/*===================================================================
Function : DRAMRegFinalValue()
Precondition :
Input :
DramAttr: pointer point to DRAM_SYS_ATTR which consist the DDR and Dimm information
in MotherBoard
Output : Void
Purpose : Chipset Performance UP and other setting after DRAM Sizing
Turn on register directly to promote performance
===================================================================*/
//--------------------------------------------------------------------------
// register AND OR
//--------------------------------------------------------------------------
#define DRAM_table_item 9
static const u8 DRAM_table[DRAM_table_item][3] = {
{0x60, 0xff, 0xD0},
{0x66, 0xcf, 0x80}, // DRAMC queue > 2
{0x69, 0xff, 0x07}, // Enable multiple page
{0x95, 0x00, 0x0D},
{0x96, 0x0F, 0xA0},
{0xFB, 0x00, 0x3E},
{0xFD, 0x00, 0xA9},
{0xFE, 0x00, 0x0f},
{0xFF, 0x00, 0x3D}
};
#define PM_table_item 5
static const u8 PM_table[PM_table_item][3] = {
{0xA0, 0x0F, 0xF0},
{0xA1, 0x1F, 0xE0},
{0xA2, 0x00, 0xFE},
{0xA3, 0x7F, 0x80},
{0xA5, 0x7E, 0x81},
};
void DRAMRegFinalValue(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 i;
for (i = 0; i < DRAM_table_item; i++) {
Data = pci_read_config8(MEMCTRL, DRAM_table[i][0]);
Data = (u8) ((Data & DRAM_table[i][1]) | DRAM_table[i][2]);
pci_write_config8(MEMCTRL, DRAM_table[i][0], Data);
}
//enable dram By-Rank self refresh
Data = pci_read_config8(MEMCTRL, 0x96);
Data &= 0xF0;
for (i = 0x01; i < 0x10; i = i << 1) {
if ((DramAttr->RankPresentMap & i) != 0x00)
Data |= i;
}
pci_write_config8(MEMCTRL, 0x96, Data);
for (i = 0; i < PM_table_item; i++) {
Data = pci_read_config8(PCI_DEV(0, 0, 4), PM_table[i][0]);
Data = (u8) ((Data & PM_table[i][1]) | PM_table[i][2]);
pci_write_config8(PCI_DEV(0, 0, 4), PM_table[i][0], Data);
}
}

View File

@ -0,0 +1,235 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr);
/*
Set DRAM Frequency
*/
void DRAMFreqSetting(DRAM_SYS_ATTR * DramAttr)
{
u8 Data = 0;
PRINT_DEBUG_MEM("Dram Frequency setting \r");
//calculate dram frequency using SPD data
CalcCLAndFreq(DramAttr);
//init some Dramc control by Simon Chu slide
//Must use "CPU delay" to make sure VLINK is dis-connect
Data = pci_read_config8(PCI_DEV(0, 0, 7), 0x47);
Data = (u8) (Data | 0x04);
pci_write_config8(PCI_DEV(0, 0, 7), 0x47, Data);
//in order to make sure NB command buffer don`t have pending request(C2P cycle)
//CPU DELAY
WaitMicroSec(20);
//Before Set Dram Frequency, we must set 111 by Simon Chu slide.
Data = pci_read_config8(MEMCTRL, 0x90);
Data = (u8) ((Data & 0xf8) | 7);
pci_write_config8(MEMCTRL, 0x90, Data);
WaitMicroSec(20);
//Set Dram Frequency.
Data = pci_read_config8(MEMCTRL, 0x90);
switch (DramAttr->DramFreq) {
case DIMMFREQ_400:
Data = (u8) ((Data & 0xf8) | 3);
break;
case DIMMFREQ_533:
Data = (u8) ((Data & 0xf8) | 4);
break;
case DIMMFREQ_667:
Data = (u8) ((Data & 0xf8) | 5);
break;
case DIMMFREQ_800:
Data = (u8) ((Data & 0xf8) | 6);
break;
default:
Data = (u8) ((Data & 0xf8) | 1);;
}
pci_write_config8(MEMCTRL, 0x90, Data);
//CPU Delay
WaitMicroSec(20);
// Manual reset and adjust DLL when DRAM change frequency
Data = pci_read_config8(MEMCTRL, 0x6B);
Data = (u8) ((Data & 0x2f) | 0xC0);
pci_write_config8(MEMCTRL, 0x6B, Data);
//CPU Delay
WaitMicroSec(20);
Data = pci_read_config8(MEMCTRL, 0x6B);
Data = (u8) (Data | 0x10);
pci_write_config8(MEMCTRL, 0x6B, Data);
//CPU Delay
WaitMicroSec(20);
Data = pci_read_config8(MEMCTRL, 0x6B);
Data = (u8) (Data & 0x3f);
pci_write_config8(MEMCTRL, 0x6B, Data);
//disable V_LINK Auto-Disconnect, or else program may stopped at some place and
//we cannot find the reason
Data = pci_read_config8(PCI_DEV(0, 0, 7), 0x47);
Data = (u8) (Data & 0xFB);
pci_write_config8(PCI_DEV(0, 0, 7), 0x47, Data);
}
/*
calculate CL and dram freq
DDR1
+---+---+---+---+---+---+---+---+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---+---+---+---+---+---+---+---+
|TBD| 4 |3.5| 3 |2.5| 2 |1.5| 1 |
+---+---+---+---+---+---+---+---+
DDR2
+---+---+---+---+---+---+---+---+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---+---+---+---+---+---+---+---+
|TBD| 6 | 5 | 4 | 3 | 2 |TBD|TBD|
+---+---+---+---+---+---+---+---+
*/
static const u8 CL_DDR1[7] = { 10, 15, 20, 25, 30, 35, 40 };
static const u8 CL_DDR2[7] = { 0, 0, 20, 30, 40, 50, 60 };
void CalcCLAndFreq(DRAM_SYS_ATTR * DramAttr)
{
u8 AllDimmSupportedCL, Tmp;
u8 CLMask, tmpMask, IndexDelta;
u8 SckId, BitId, TmpId;
u16 CycTime, TmpCycTime;
/*1.list the CL value that all DIMM supported */
AllDimmSupportedCL = 0xFF;
if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
AllDimmSupportedCL &= 0x7C; /*bit2,3,4,5,6 */
else /*DDR1 */
AllDimmSupportedCL &= 0x7F; /*bit0,1,2,3,4,5,6 */
for (SckId = 0; SckId < MAX_SOCKETS; SckId++) {
if (DramAttr->DimmInfo[SckId].bPresence) { /*all DIMM supported CL */
AllDimmSupportedCL &=
(DramAttr->DimmInfo[SckId].
SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
}
}
if (!AllDimmSupportedCL) { /*if equal 0, no supported CL */
PRINT_DEBUG_MEM("SPD Data Error, Can not get CL !!!! \r");
for (;;);
}
/*Get CL Value */
CLMask = 0x40; /*from Bit6 */
for (BitId = 7; BitId > 0; BitId--) {
if ((AllDimmSupportedCL & CLMask) == CLMask) { /*find the first bit */
if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
DramAttr->CL = CL_DDR2[BitId - 1];
else /*DDR1 */
DramAttr->CL = CL_DDR1[BitId - 1];
break;
}
CLMask >>= 1;
}
/*according the CL value calculate the cycle time, for X or X-1 or X-2 */
CycTime = 0;
TmpCycTime = 0;
for (SckId = 0; SckId < MAX_SOCKETS; SckId++) {
if (DramAttr->DimmInfo[SckId].bPresence) {
Tmp =
(DramAttr->DimmInfo[SckId].
SPDDataBuf[SPD_SDRAM_CAS_LATENCY]);
tmpMask = 0x40;
for (TmpId = 7; TmpId > 0; TmpId--) {
if ((Tmp & tmpMask) == tmpMask)
break;
tmpMask >>= 1;
}
if (TmpId - BitId == 0) { /*get Cycle time for X, SPD BYTE9 */
TmpCycTime =
DramAttr->DimmInfo[SckId].
SPDDataBuf[SPD_SDRAM_TCLK_X];
} else if (TmpId - BitId == 1) { /*get Cycle time for X-1, SPD BYTE23 */
TmpCycTime =
DramAttr->DimmInfo[SckId].
SPDDataBuf[SPD_SDRAM_TCLK_X_1];
} else if (TmpId - BitId == 2) { /*get cycle time for X-2, SPD BYTE25 */
TmpCycTime =
DramAttr->DimmInfo[SckId].
SPDDataBuf[SPD_SDRAM_TCLK_X_2];
} else {
//error!!!
}
if (TmpCycTime > CycTime) /*get the most cycle time,there is some problem! */
CycTime = TmpCycTime;
}
}
if (CycTime <= 0) {
//error!
for (;;);
}
/* cycle time value
0x25-->2.5ns Freq=400 DDR800
0x30-->3.0ns Freq=333 DDR667
0x3D-->3.75ns Freq=266 DDR533
0x50-->5.0ns Freq=200 DDR400
0x60-->6.0ns Freq=166 DDR333
0x75-->7.5ns Freq=133 DDR266
0xA0-->10.0ns Freq=100 DDR200
*/
if (CycTime <= 0x25) {
DramAttr->DramFreq = DIMMFREQ_800;
DramAttr->DramCyc = 250;
} else if (CycTime <= 0x30) {
DramAttr->DramFreq = DIMMFREQ_667;
DramAttr->DramCyc = 300;
} else if (CycTime <= 0x3d) {
DramAttr->DramFreq = DIMMFREQ_533;
DramAttr->DramCyc = 375;
} else if (CycTime <= 0x50) {
DramAttr->DramFreq = DIMMFREQ_400;
DramAttr->DramCyc = 500;
} else if (CycTime <= 0x60) {
DramAttr->DramFreq = DIMMFREQ_333;
DramAttr->DramCyc = 600;
} else if (CycTime <= 0x75) {
DramAttr->DramFreq = DIMMFREQ_266;
DramAttr->DramCyc = 750;
} else if (CycTime <= 0xA0) {
DramAttr->DramFreq = DIMMFREQ_200;
DramAttr->DramCyc = 1000;
}
//if set the frequence mannul
PRINT_DEBUG_MEM("Dram Frequency:");
PRINT_DEBUG_MEM_HEX16(DramAttr->DramFreq);
PRINT_DEBUG_MEM(" \r");
}

View File

@ -0,0 +1,363 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
extern void DRAMSetVRNum(DRAM_SYS_ATTR * DramAttr,
u8 PhyRank, u8 VirRank, BOOLEAN Enable);
extern void SetEndingAddr(DRAM_SYS_ATTR * DramAttr, u8 VirRank, // Ending address register number indicator (INDEX
INT8 Value); // (value) add or subtract value to this and after banks
void DRAMClearEndingAddress(DRAM_SYS_ATTR * DramAttr);
void DRAMSizingEachRank(DRAM_SYS_ATTR * DramAttr);
BOOLEAN DoDynamicSizing1XM(DRAM_SYS_ATTR * DramAttr,
u8 * nRA, u8 * nCA, u8 * nBS, u8 PhyRank);
void DRAMSetRankMAType(DRAM_SYS_ATTR * DramAttr);
void DRAMSetEndingAddress(DRAM_SYS_ATTR * DramAttr);
void DRAMPRToVRMapping(DRAM_SYS_ATTR * DramAttr);
/*===================================================================
Function : DRAMBankInterleave()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : STEP 13 Set Bank Interleave VIANB3DRAMREG69[7:6] 00:No Interleave 01:2 Bank 10:4 Bank 11:8 Bank
Scan all DIMMs on board to find out the lowest Bank Interleave among these DIMMs and set register.
===================================================================*/
void DRAMBankInterleave(DRAM_SYS_ATTR * DramAttr)
{
u8 Data, SpdBAData;
DIMM_INFO *CurrentDimminfo;
u8 Bank = 3, Shift, RankNO, Count;
Shift = 1;
for (RankNO = 0; RankNO < 4; RankNO += 2) //all_even 0 RankNO 4 6
{
if ((DramAttr->RankPresentMap & Shift) != 0) {
CurrentDimminfo = &(DramAttr->DimmInfo[RankNO >> 1]); //this Rank in a dimm
SpdBAData =
(u8) (CurrentDimminfo->
SPDDataBuf[SPD_SDRAM_NO_OF_BANKS]);
if (SpdBAData == 4)
Count = 2;
else if (SpdBAData == 8)
Count = 3;
else
Count = 0;
if (Count < Bank)
Bank = Count;
}
Shift <<= 2;
}
Data = pci_read_config8(MEMCTRL, 0x69);
Data &= ~0xc0;
Data |= (Bank << 6);
pci_write_config8(MEMCTRL, 0x69, Data);
if (DramAttr->DimmNumChB > 0) {
CurrentDimminfo = &(DramAttr->DimmInfo[3]); //this Rank in a dimm
SpdBAData =
(u8) (CurrentDimminfo->
SPDDataBuf[SPD_SDRAM_NO_OF_BANKS]);
if (SpdBAData == 4)
Bank = 2;
else if (SpdBAData == 2)
Bank = 1;
else
Bank = 0;
pci_write_config8(MEMCTRL, 0x87, Bank);
}
}
/*===================================================================
Function : DRAMSizingMATypeM()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : STEP 14 1 DRAM Sizing 2 Fill MA type 3 Prank to vrankMapping
===================================================================*/
void DRAMSizingMATypeM(DRAM_SYS_ATTR * DramAttr)
{
DRAMClearEndingAddress(DramAttr);
DRAMSizingEachRank(DramAttr);
//DRAMReInitDIMMBL (DramAttr);
DRAMSetRankMAType(DramAttr);
DRAMSetEndingAddress(DramAttr);
DRAMPRToVRMapping(DramAttr);
}
/*===================================================================
Function : DRAMClearEndingAddress()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : clear Ending and Start adress from 0x40-4f to zero
===================================================================*/
void DRAMClearEndingAddress(DRAM_SYS_ATTR * DramAttr)
{
u8 Data, Reg;
Data = 0;
for (Reg = 0x40; Reg <= 0x4f; Reg++) {
pci_write_config8(MEMCTRL, Reg, Data);
}
}
/*===================================================================
Function : DRAMSizingEachRank()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : Sizing each Rank invidually, by number of rows column banks pins, be care about 128bit
===================================================================*/
void DRAMSizingEachRank(DRAM_SYS_ATTR * DramAttr)
{
u8 Slot, RankIndex, Rows, Columns, Banks;
u32 Size;
BOOLEAN HasThreeBitBA;
u8 Data;
u32 Address;
HasThreeBitBA = FALSE;
for (Slot = 0; Slot < 2; Slot++) {
if (!DramAttr->DimmInfo[Slot].bPresence)
continue;
Rows =
DramAttr->DimmInfo[Slot].
SPDDataBuf[SPD_SDRAM_ROW_ADDR];
Columns =
DramAttr->DimmInfo[Slot].
SPDDataBuf[SPD_SDRAM_COL_ADDR];
Banks = DramAttr->DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_NO_OF_BANKS]; //this is Bank number not Bank address bit
if (Banks == 4)
Banks = 2;
else if (Banks == 8)
Banks = 3;
else
Banks = 0;
Size = (u32) (1 << (Rows + Columns + Banks + 3));
RankIndex = 2 * Slot;
DramAttr->RankSize[RankIndex] = Size;
//if this module have two ranks
if ((DramAttr->DimmInfo[Slot].
SPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x07) == 0x01) {
RankIndex++;
DramAttr->RankSize[RankIndex] = Size;
}
PRINT_DEBUG_MEM("rows: ");
PRINT_DEBUG_MEM_HEX8(Rows);
PRINT_DEBUG_MEM(", columns:");
PRINT_DEBUG_MEM_HEX8(Columns);
PRINT_DEBUG_MEM(", banks:");
PRINT_DEBUG_MEM_HEX8(Banks);
PRINT_DEBUG_MEM("\r");
if (Banks == 3)
HasThreeBitBA = TRUE;
}
//must set BA2 enable if any 8-bank device exists
if (HasThreeBitBA) {
Data = pci_read_config8(MEMCTRL, 0x53);
Data |= 0x80;
pci_write_config8(MEMCTRL, 0x53, Data);
}
#if 1
for (RankIndex = 0; DramAttr->RankSize[RankIndex] != 0;
RankIndex++) {
PRINT_DEBUG_MEM("Rank:");
PRINT_DEBUG_MEM_HEX8(RankIndex);
PRINT_DEBUG_MEM(", Size:");
PRINT_DEBUG_MEM_HEX32(DramAttr->RankSize[RankIndex] >> 20);
PRINT_DEBUG_MEM("\r");
}
#endif
}
/*===================================================================
Function : DRAMSetRankMAType()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : set the matype Reg by MAMapTypeTbl, which the rule can be found in memoryinit
===================================================================*/
void DRAMSetRankMAType(DRAM_SYS_ATTR * DramAttr)
{
u8 SlotNum, Data, j, Reg, or, and;
u8 ShiftBits[] = { 5, 1, 5, 1 }; /* Rank 0/1 MA Map Type is 7:5, Rank 2/3 MA Map Type is 3:1. See Fun3Rx50. */
u8 MAMapTypeTbl[] = { /* Table 12 of P4M800 Pro DataSheet. */
2, 9, 0, /* Bank Address Bits, Column Address Bits, Rank MA Map Type */
2, 10, 1,
2, 11, 2,
2, 12, 3,
3, 10, 5,
3, 11, 6,
3, 12, 7,
0, 0, 0
};
Data = pci_read_config8(MEMCTRL, 0x50);
Data &= 0x1;
pci_write_config8(MEMCTRL, 0x50, Data);
// disable MA32/16 MA33/17 swap in memory init it has this Reg fill
Data = pci_read_config8(MEMCTRL, 0x6b);
Data &= ~0x08;
pci_write_config8(MEMCTRL, 0x6b, Data);
Data = 0x00;
for (SlotNum = 0; SlotNum < MAX_DIMMS; SlotNum++) {
if (DramAttr->DimmInfo[SlotNum].bPresence) {
for (j = 0; MAMapTypeTbl[j] != 0; j += 3) {
if ((1 << MAMapTypeTbl[j]) ==
DramAttr->DimmInfo[SlotNum].
SPDDataBuf[SPD_SDRAM_NO_OF_BANKS]
&& MAMapTypeTbl[j + 1] ==
DramAttr->DimmInfo[SlotNum].
SPDDataBuf[SPD_SDRAM_COL_ADDR]) {
break;
}
}
if (0 == MAMapTypeTbl[j]) {
PRINT_DEBUG_MEM
("UNSUPPORTED Bank, Row and Column Addr Bits!\r");
return;
}
or = MAMapTypeTbl[j + 2] << ShiftBits[SlotNum];
if (DramAttr->CmdRate == 1)
or |= 0x01 << (ShiftBits[SlotNum] - 1);
Reg = SlotNum / 2;
if ((SlotNum & 0x01) == 0x01) {
and = 0xf1; // BUGBUG: it should be 0xf0
} else {
and = 0x1f; // BUGBUG: it should be 0x0f
}
Data = pci_read_config8(MEMCTRL, 0x50 + Reg);
Data &= and;
Data |= or;
pci_write_config8(MEMCTRL, 0x50 + Reg, Data);
}
}
//may have some Reg filling at add 3-52 11 and 3-53 in his function
}
/*===================================================================
Function : DRAMSetEndingAddress()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : realize the Vrank 40...Reg (Start and Ending Regs). Vrank have same order with phy Rank, Size is actual Size
===================================================================*/
void DRAMSetEndingAddress(DRAM_SYS_ATTR * DramAttr)
{
u8 Shift = 1, Data, RankNO, Size, Start = 0, End = 0, Vrank;
for (RankNO = 0; RankNO < 4; RankNO++) {
if ((DramAttr->RankPresentMap & Shift) != 0) {
Size = (u8) (DramAttr->RankSize[RankNO] >> 26); // current Size in the unit of 64M
if (Size != 0) {
End = End + Size; // calculate current ending address, add the current Size to ending
Vrank = RankNO; // get virtual Rank
Data = End; // set begin/End address register to correspondig virtual Rank #
pci_write_config8(MEMCTRL, 0x40 + Vrank,
Data);
Data = Start;
pci_write_config8(MEMCTRL, 0x48 + Vrank,
Data);
PRINT_DEBUG_MEM("Rank: ");
PRINT_DEBUG_MEM_HEX8(Vrank);
PRINT_DEBUG_MEM(", Start:");
PRINT_DEBUG_MEM_HEX8(Start);
PRINT_DEBUG_MEM(", End:");
PRINT_DEBUG_MEM_HEX8(End);
PRINT_DEBUG_MEM("\r");
Start = End;
}
}
Shift <<= 1;
}
if (DramAttr->RankNumChB > 0) {
//this is a bug,fixed is to 2,so the max LL size is 128M
Data = 0x02;
pci_write_config8(MEMCTRL, 0x44, Data);
}
Data = End * 4;
pci_write_config8(PCI_DEV(0, 17, 7), 0x60, Data);
// We should directly write to south Bridge, not in north bridge
// program LOW TOP Address
Data = pci_read_config8(MEMCTRL, 0x88);
pci_write_config8(MEMCTRL, 0x85, Data);
// also program vlink mirror
// We should directly write to south Bridge, not in north bridge
pci_write_config8(PCI_DEV(0, 17, 7), 0xe5, Data);
}
/*===================================================================
Function : DRAMPRToVRMapping()
Precondition :
Input :
DramAttr: pointer point to DRAMSYSATTR which consist the DDR and Dimm information in MotherBoard
Output : Void
Purpose : set the Vrank-prank map with the same order
===================================================================*/
void DRAMPRToVRMapping(DRAM_SYS_ATTR * DramAttr)
{
u8 Shift, Data, and, or, DimmNO = 0, PhyRankNO, Reg;
for (Reg = 0x54; Reg <= 0x57; Reg++) //clear the map-reg
{
Data = 0;
pci_write_config8(MEMCTRL, Reg, Data);
}
Shift = 1;
for (PhyRankNO = 0; PhyRankNO < MAX_RANKS; PhyRankNO++) {
if ((DramAttr->RankPresentMap & Shift) != 0) {
or = PhyRankNO; // get virtual Rank ,same with PhyRank
or |= 0x08;
if ((PhyRankNO & 0x01) == 0x01) // get mask for register
and = 0xf0;
else {
and = 0x0f;
or <<= 4;
}
DimmNO = (PhyRankNO >> 1);
Data = pci_read_config8(MEMCTRL, 0x54 + DimmNO);
Data &= and;
Data |= or;
pci_write_config8(MEMCTRL, 0x54 + DimmNO, Data);
}
Shift <<= 1;
}
}

View File

@ -0,0 +1,492 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Set Dram Timing functions
*/
void SetCL(DRAM_SYS_ATTR * DramAttr);
void SetTrp(DRAM_SYS_ATTR * DramAttr);
void SetTrcd(DRAM_SYS_ATTR * DramAttr);
void SetTras(DRAM_SYS_ATTR * DramAttr);
void SetTrfc(DRAM_SYS_ATTR * DramAttr);
void SetTrrd(DRAM_SYS_ATTR * DramAttr);
void SetTwr(DRAM_SYS_ATTR * DramAttr);
void SetTwtr(DRAM_SYS_ATTR * DramAttr);
void SetTrtp(DRAM_SYS_ATTR * DramAttr);
/* Set DRAM Timing*/
void DRAMTimingSetting(DRAM_SYS_ATTR * DramAttr)
{
PRINT_DEBUG_MEM("Set CAS latency value!");
SetCL(DramAttr);
PRINT_DEBUG_MEM("Set tRP value!");
SetTrp(DramAttr);
PRINT_DEBUG_MEM("Set tRCD value!");
SetTrcd(DramAttr);
PRINT_DEBUG_MEM("Set tRAS value!");
SetTras(DramAttr);
PRINT_DEBUG_MEM("Set tRFC value!");
SetTrfc(DramAttr);
PRINT_DEBUG_MEM("Set tRRD value!");
SetTrrd(DramAttr);
PRINT_DEBUG_MEM("Set tWR value!");
SetTwr(DramAttr);
PRINT_DEBUG_MEM("Set tWTR value!");
SetTwtr(DramAttr);
PRINT_DEBUG_MEM("Set tRTP value!");
SetTrtp(DramAttr);
}
/*
Set DRAM Timing: CAS Latency for DDR1
D0F3RX62 bit[0:2] for CAS Latency;
*/
void SetCL(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u8 CL;
/*DDR2 CL Value: 20, 30, 40, 50 -> 2, 3, 4, 5 */
CL = (u8) ((DramAttr->CL - 20) / 10); //000,001,010,011
PRINT_DEBUG_MEM("CAS = ");
PRINT_DEBUG_MEM_HEX8(CL);
PRINT_DEBUG_MEM("\n");
Data = pci_read_config8(MEMCTRL, 0x62);
Data = (u8) ((Data & 0xf8) | CL);
pci_write_config8(MEMCTRL, 0x62, Data);
}
/*
Minimum row precharge time, Trp for DDR1/DDR2
D0F3Rx64[3:2] for Trp 2T~5T
*/
#define MAX_TRP 6
#define MIN_TRP 2
void SetTrp(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u16 Max, Tmp;
u8 Socket;
/*get the max Trp value from SPD data
SPD Byte27, Bit7:2->1ns~63ns, Bit1:0->0ns, 0.25ns, 0.50ns, 0.75ns */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u16) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TRP]);
if (Tmp > Max)
Max = Tmp;
}
/*Calculate clock,this value should be 2T,3T,4T,5T */
}
Tmp =
(u16) ((Max * 100 + ((DramAttr->DramCyc) << 2) -
1) / ((DramAttr->DramCyc) << 2));
PRINT_DEBUG_MEM("Trp = ");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
if (Tmp > MAX_TRP)
Tmp = MAX_TRP;
else if (Tmp < MIN_TRP)
Tmp = MIN_TRP;
Tmp -= 2; //00->2T, 01->3T, 10->4T, 11->5T
Tmp <<= 1; //bit1,2,3
Data = pci_read_config8(MEMCTRL, 0x64);
Data = (u8) ((Data & 0xf1) | (u8) Tmp);
pci_write_config8(MEMCTRL, 0x64, Data);
//enable DDR2 8-Bank Device Timing Constraint
Data = pci_read_config8(MEMCTRL, 0x62);
Data = (u8) ((Data & 0xf7) | 0x08);
pci_write_config8(MEMCTRL, 0x62, Data);
}
/*
Minimum RAS to CAS dely,Trcd for DDR1/DDR2
D0F3Rx64[7:6] for Trcd
*/
#define MAX_TRCD 6
#define MIN_TRCD 2
void SetTrcd(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u16 Max, Tmp;
u8 Socket;
/*get the max Trcd value from SPD data
SPD Byte29, Bit7:2->1ns~63ns, Bit1:0->0ns, 0.25ns, 0.50ns, 0.75ns */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u16) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TRCD]);
if (Tmp > Max)
Max = Tmp;
}
}
/*Calculate clock,this value should be 2T,3T,4T,5T */
Tmp =
(u16) ((Max * 100 + ((DramAttr->DramCyc) << 2) -
1) / ((DramAttr->DramCyc) << 2));
PRINT_DEBUG_MEM("Trcd =");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
if (Tmp > MAX_TRCD)
Tmp = MAX_TRCD;
else if (Tmp < MIN_TRCD)
Tmp = MIN_TRCD;
Tmp -= 2; //00->2T, 01->3T, 10->4T, 11->5T
Tmp <<= 5; //bit5,6,7
Data = pci_read_config8(MEMCTRL, 0x64);
Data = (u8) ((Data & 0x1f) | (u8) Tmp);
pci_write_config8(MEMCTRL, 0x64, Data);
}
/*
minimum active to precharge time,Tras for DDR1/DDR2
D0F3Rx62[7:4] Tras
*/
#define MAX_TRAS 20 //20T
#define MIN_TRAS 5 //5T
void SetTras(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u16 Max, Tmp;
u8 Socket;
/*get the max Tras value from SPD data
SPD byte30: bit0:7 1ns~255ns */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u16) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TRAS]);
if (Tmp > Max)
Max = Tmp;
}
}
/*Calculate clock,value range 5T-20T */
Tmp =
(u16) ((Max * 100 + DramAttr->DramCyc -
1) / (DramAttr->DramCyc));
PRINT_DEBUG_MEM("Tras =");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
if (Tmp > MAX_TRAS)
Tmp = MAX_TRAS;
else if (Tmp < MIN_TRAS)
Tmp = MIN_TRAS;
Tmp -= 5; //0->5T ... 1111->20T
Tmp <<= 4; //bit4:7
Data = pci_read_config8(MEMCTRL, 0x62);
Data = (u8) ((Data & 0x0f) | (u8) Tmp);
pci_write_config8(MEMCTRL, 0x62, Data);
}
/*
Minimum refresh to activate/refresh command period Trfc for DDR1/DDR2
D0F3Rx61[5:0] for Trfc
*/
#define MAX_TRFC 71 // Max supported,71T
#define MIN_TRFC 8 // Min supported,8T
void SetTrfc(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u32 Max, Tmp;
u8 Byte40;
u8 Socket;
/*get the max Trfc value from SPD data */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u32) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TRFC]) * 100;
/*only DDR2 need to add byte 40 bit[7:4] */
Byte40 =
(DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TRFC2]);
/*if bit0 = 1, byte42(RFC)+256ns, SPD spec JEDEC standard No.21.c */
if (Byte40 & 0x01)
Tmp += (256 * 100);
/*bit1,2,3 000->0ns+byte42; 001->0.25ns+byte42; 010->0.33ns+byte42; 011->0.5ns+byte42;100-> 0.75ns+byte42 */
switch ((Byte40 >> 1) & 0x07) { /*bit1,2,3 */
case 1:
Tmp += 25;
break;
case 2:
Tmp += 33;
break;
case 3:
Tmp += 50;
break;
case 4:
Tmp += 66;
break;
case 5:
Tmp += 75;
break;
case 6: //what is FRU???
default:
break;
}
if (Tmp > Max)
Max = Tmp;
}
}
/*Calculate clock,value range 8T-71T */
Tmp = (u16) ((Max + DramAttr->DramCyc - 1) / (DramAttr->DramCyc));
PRINT_DEBUG_MEM("Trfc = ");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
if (Tmp > MAX_TRFC)
Tmp = MAX_TRFC;
else if (Tmp < MIN_TRFC) {
// return;
Tmp = 0x40;
}
/*D0F3Rx61 bit[0:5] 0->8T ... 63->71T */
Tmp -= 8;
Data = pci_read_config8(MEMCTRL, 0x61);
Data = (u8) ((Data & 0xc0) | ((u8) Tmp & 0x3f));
pci_write_config8(MEMCTRL, 0x61, Data);
}
/*
Minimum row active to row active delay: Trrd for DDR1/DDR2
D0F3Rx61[7:6]:Trrd 00->2T, 01->3T, 10->4T, 11->5T
*/
#define MAX_TRRD 5
#define MIN_TRRD 2
void SetTrrd(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u16 Max, Tmp;
u8 Socket;
/*get the max Trrd value from SPD data
SPD Byte28, Bit7:2->1ns~63ns, Bit1:0->0ns, 0.25ns, 0.50ns, 0.75ns */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u16) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TRRD]);
if (Tmp > Max)
Max = Tmp;
}
}
/*Calculate clock,this value should be 2T,3T,4T,5T */
Tmp =
(u16) ((Max * 100 + ((DramAttr->DramCyc) << 2) -
1) / ((DramAttr->DramCyc) << 2));
PRINT_DEBUG_MEM("Trrd =");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
if (Tmp > MAX_TRRD)
Tmp = MAX_TRRD;
else if (Tmp < MIN_TRRD)
Tmp = MIN_TRRD;
Tmp -= 2; //00->2T, 01->3T, 10->4T, 11->5T
Tmp <<= 6;
Data = pci_read_config8(MEMCTRL, 0x61);
Data = (u8) ((Data & 0x3f) | (u8) Tmp);
pci_write_config8(MEMCTRL, 0x61, Data);
}
/*
Write recovery time: Twr for DDR1/DDR2
Device 0 Function 3:REG63[7:5]:Twr 00->2T 01->3T 10->4T 11->5T
*/
#define MAX_TWR 6
#define MIN_TWR 2
void SetTwr(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u16 Max, Tmp;
u8 Socket;
/*get the max Trtp value from SPD data
SPD Byte36, Bit7:2->1ns~63ns, Bit1:0->0ns, 0.25ns, 0.50ns, 0.75ns */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u16) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TWR]);
if (Tmp > Max)
Max = Tmp;
}
}
/*Calculate clock */
Tmp = (u16) ((Max * 100 + ((DramAttr->DramCyc) << 2) - 1) / ((DramAttr->DramCyc) << 2)); //this value should be 2T,3T,4T,5T
PRINT_DEBUG_MEM("Twr = ");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
if (Tmp > MAX_TWR)
Tmp = MAX_TWR;
else if (Tmp < MIN_TWR)
Tmp = MIN_TWR;
Tmp -= 2; //00->2T, 01->3T, 10->4T, 11->5T
Tmp <<= 5;
Data = pci_read_config8(MEMCTRL, 0x63);
Data = (u8) ((Data & 0x1f) | (u8) Tmp);
pci_write_config8(MEMCTRL, 0x63, Data);
}
/*
Internal write to read command delay: Twtr for DDR1/DDR2
Device 0 Function 3:REG63[1,0]:Twtr DDR: 1T or 2T; DDR2 2T or 3T
*/
#define MAX_TWTR 5 //5T
#define MIN_TWTR 2 //2T
void SetTwtr(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u16 Max, Tmp;
u8 Socket;
/*get the max Trtp value from SPD data
SPD Byte37, Bit7:2->1ns~63ns, Bit1:0->0ns, 0.25ns, 0.50ns, 0.75ns */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u16) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TWTR]);
if (Tmp > Max)
Max = Tmp;
}
}
/*Calculate clock */
Tmp = (u16) ((Max * 100 + ((DramAttr->DramCyc) << 2) - 1) / ((DramAttr->DramCyc) << 2)); //this value should be 2T or 3T
PRINT_DEBUG_MEM("Twtr =");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
if (Tmp > MAX_TWR)
Tmp = MAX_TWTR;
else if (Tmp < MIN_TWR)
Tmp = MIN_TWTR;
Tmp -= 2; //00->2T, 01->3T, 10->4T, 11->5T
Data = pci_read_config8(MEMCTRL, 0x63);
Data = (u8) ((Data & 0xFC) | Tmp);
pci_write_config8(MEMCTRL, 0x63, Data);
}
/*
Internal read to precharge command delay, Trtp for DDR1/DDR2
Device 0 Function 3:REG63[3]:Trtp 2T or 3T
*/
#define MAX_TRTP 3 //3T
#define MIN_TRTP 2 //2T
void SetTrtp(DRAM_SYS_ATTR * DramAttr)
{
u8 Data;
u16 Max, Tmp;
u8 Socket;
/*get the max Trtp value from SPD data
SPD Byte38, Bit7:2->1ns~63ns, Bit1:0->0ns, 0.25ns, 0.50ns, 0.75ns */
Max = 0;
for (Socket = 0; Socket < MAX_SOCKETS; Socket++) {
if (DramAttr->DimmInfo[Socket].bPresence) {
Tmp =
(u16) (DramAttr->DimmInfo[Socket].
SPDDataBuf[SPD_SDRAM_TRTP]);
if (Tmp > Max)
Max = Tmp;
}
}
/*Calculate clock */
Tmp = (u16) ((Max * 100 + ((DramAttr->DramCyc) << 2) - 1) / ((DramAttr->DramCyc) << 2)); //this value should be 2T or 3T
PRINT_DEBUG_MEM("Trtp =");
PRINT_DEBUG_MEM_HEX16(Tmp);
PRINT_DEBUG_MEM("\r");
Data = pci_read_config8(MEMCTRL, 0x63);
if (Tmp > MIN_TRTP)
Data = (u8) (Data | 0x08); /*set bit3, set 3T */
else
Data = (u8) (Data & 0xf7); /*clear bit3, set 2T */
pci_write_config8(MEMCTRL, 0x63, Data);
}

View File

@ -0,0 +1,445 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
typedef struct __UMA_RAM_tag {
u16 DramSize;
u8 D0F3Val;
u8 D1F0Val;
u8 VgaPortVal;
} UMARAM;
#define UMARAM_512M 7
#define UMARAM_256M 6
#define UMARAM_128M 5
#define UMARAM_64M 4
#define UMARAM_32M 3
#define UMARAM_16M 2
#define UMARAM_8M 1
#define UMARAM_0M 0
#define FB_512M 0
#define FB_256M 0x40
#define FB_128M 0x60
#define FB_64M 0x70
#define FB_32M 0x78
#define FB_16M 0x7c
#define FB_8M 0x7E
#define FB_4M 0x7F
#define VGA_PORT_512M 0x00
#define VGA_PORT_256M 0x80
#define VGA_PORT_128M 0xC0
#define VGA_PORT_64M 0xE0
#define VGA_PORT_32M 0xF0
#define VGA_PORT_16M 0xF8
static const UMARAM UMARamArr[] = {
{0, UMARAM_0M, FB_4M, 0xFE},
{8, UMARAM_8M, FB_8M, 0xFC},
{16, UMARAM_16M, FB_16M, VGA_PORT_16M},
{32, UMARAM_32M, FB_32M, VGA_PORT_32M},
{64, UMARAM_64M, FB_64M, VGA_PORT_64M},
{128, UMARAM_128M, FB_128M, VGA_PORT_128M},
{256, UMARAM_256M, FB_256M, VGA_PORT_256M},
{512, UMARAM_512M, FB_512M, VGA_PORT_512M},
{0xffff, 0xff, 0xff, 0xFF}
};
void SetUMARam(void)
{
#if 1
u8 ramregs[] = { 0x43, 0x42, 0x41, 0x40 };
device_t vga_dev = PCI_DEV(0, 1, 0), d0f0_dev = PCI_DEV(0, 0, 0);
u8 ByteVal, temp;
UMARAM *pUMARamTable;
u16 UmaSize;
u8 SLD0F3Val, SLD1F0Val, VgaPortVal;
u32 RamSize, SLBase, Tmp;
u8 i;
PRINT_DEBUG_MEM("Entering vx800 SetUMARam.\n");
SLD0F3Val = 0;
SLD1F0Val = 0;
VgaPortVal = 0;
ByteVal = pci_read_config8(MEMCTRL, 0xa1);
ByteVal |= 0x80;
pci_write_config8(MEMCTRL, 0xa1, ByteVal);
//set VGA Timer
pci_write_config8(MEMCTRL, 0xa2, 0xee);
//set agp misc
//GFX Data Delay to Sync with Clock
pci_write_config8(MEMCTRL, 0xa4, 0x01);
//page register life timer
pci_write_config8(MEMCTRL, 0xa6, 0x76);
//GMINT and GFX relatate
//note Bit 3 VGA Enable
pci_write_config8(MEMCTRL, 0xa7, 0x8c);
// ByteVal = 0x4c;
//GMINT Misc.1
//pci_write_config8(MEMCTRL, 0xb0, 0x80);
//pci_write_config8(MEMCTRL, 0xb1, 0xaa);
//AGPCINT MISC
//pci_write_config8(MEMCTRL, 0xb2, 0x82);
//ByteVal = 0x8A;
//GMINT MISC.2
//disable read pass write
pci_write_config8(MEMCTRL, 0xb3, 0x9A);
//EPLL Register
//pci_write_config8(MEMCTRL, 0xb4, 0x04);
//enable CHA and CHB merge mode
pci_write_config8(MEMCTRL, 0xde, 0x06);
//if can get the value from setup interface, so get the value
//else use the default value
UmaSize = CONFIG_VIDEO_MB;
for (pUMARamTable = UMARamArr; pUMARamTable->DramSize != 0xffff;
pUMARamTable++) {
if (UmaSize == pUMARamTable->DramSize) {
SLD0F3Val = pUMARamTable->D0F3Val;
SLD1F0Val = pUMARamTable->D1F0Val;
VgaPortVal = pUMARamTable->VgaPortVal;
}
}
//set SL size
//Fill in Fun3_RXA1[6:4] with the Frame Buffer size for the Integrated Graphic Device.
ByteVal = pci_read_config8(MEMCTRL, 0xa1);
ByteVal = (ByteVal & 0x8f) | (SLD0F3Val << 4);
pci_write_config8(MEMCTRL, 0xa1, ByteVal);
// vga_dev = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_VGA, 0);
//RxB2 may be for S.L. and RxB1 may be for L. L.
// It is different from Spec.
ByteVal = SLD1F0Val;
pci_write_config8(vga_dev, 0xb2, ByteVal);
//set M1 size
//ByteVal=pci_read_config8(MEMCTRL, 0xa3);
//ByteVal = 0x02;
//pci_write_config8(MEMCTRL, 0xa3, ByteVal);
PRINT_DEBUG_MEM("UMA setting - 3\n");
//Enable p2p IO/mem
ByteVal = 0x07;
pci_write_config8(vga_dev, 0x04, ByteVal);
//must set SL and MMIO base, or else when enable GFX memory space, system will hang
//set S.L base
Tmp = pci_read_config32(vga_dev, 0x10);
Tmp = 0xfffffff8;
pci_write_config32(vga_dev, 0x10, Tmp);
Tmp = pci_read_config32(vga_dev, 0x10);
Tmp = VIACONFIG_VGA_PCI_10;
pci_write_config32(vga_dev, 0x10, Tmp);
//set MMIO base
Tmp = pci_read_config32(vga_dev, 0x14);
Tmp = 0xfffffffC;
pci_write_config32(vga_dev, 0x14, Tmp);
Tmp = pci_read_config32(vga_dev, 0x14);
Tmp = VIACONFIG_VGA_PCI_14;
pci_write_config32(vga_dev, 0x14, Tmp);
//enable direct cpu frame buffer access
i = pci_rawread_config8(PCI_RAWDEV(0, 0, 3), 0xa1);
i = (i & 0xf0) | (VIACONFIG_VGA_PCI_10 >> 28);
pci_rawwrite_config8(PCI_RAWDEV(0, 0, 3), 0xa1, i);
pci_rawwrite_config8(PCI_RAWDEV(0, 0, 3), 0xa0, 0x01);
//enable GFx memory space access control for S.L and mmio
ByteVal = pci_read_config8(d0f0_dev, 0xD4);
ByteVal |= 0x03;
//ByteVal |= 0x01;
pci_write_config8(d0f0_dev, 0xD4, ByteVal);
//enable Base VGA 16 Bits Decode
ByteVal = pci_read_config8(d0f0_dev, 0xfe);
ByteVal |= 0x10;
pci_write_config8(d0f0_dev, 0xfe, ByteVal);
//disable CHB L.L
//set VGA memory selection
ByteVal = pci_read_config8(vga_dev, 0xb0);
ByteVal &= 0xF8;
//ByteVal |= 0x01;
ByteVal |= 0x03;
pci_write_config8(vga_dev, 0xb0, ByteVal);
//set LL size
//enable memory access to SL,MMIO,LL and IO to 3B0~3BB,3C0 ~3DF
//ByteVal = 0x03;
//pci_write_config8(d0f0_dev, 0xc0, ByteVal);
//Turn on Graphic chip IO port port access
ByteVal = inb(0x03C3);
ByteVal |= 0x01;
outb(ByteVal, 0x03C3);
//Turn off Graphic chip Register protection
outb(0x10, 0x03C4);
ByteVal = inb(0x03C5);
ByteVal |= 0x01;
outb(ByteVal, 0x03C5);
//set VGA memory Frequence
//direct IO port 0x3DX to vga io space 0x3C2[0]
ByteVal = inb(0x03CC);
ByteVal |= 0x03;
outb(ByteVal, 0x03C2);
// ByteVal=inb(0x03C2);
// ByteVal |= 0x01;
// outb(ByteVal,0x03C2);
#if 1 //bios porting guide has no this two defination: 3d on 3d4/3d5 and 39 on 3c4/3c5
//set frequence 0x3D5.3d[7:4]
outb(0x3d, 0x03d4);
temp = pci_read_config8(MEMCTRL, 0x90);
temp = (u8) (temp & 0x07);
ByteVal = inb(0x03d5);
switch (temp) {
case 0: //DIMMFREQ_200:
ByteVal = (u8) ((ByteVal & 0x0F) | 0x30);
break;
case 1: //DIMMFREQ_266:
ByteVal = (u8) ((ByteVal & 0x0F) | 0x40);
break;
case 3: //DIMMFREQ_400:
ByteVal = (u8) ((ByteVal & 0x0F) | 0x60);
break;
case 4: //DIMMFREQ_533:
ByteVal = (u8) ((ByteVal & 0x0F) | 0x70);
break;
case 5: //DIMMFREQ_667:
ByteVal = (u8) ((ByteVal & 0x0F) | 0x80);
break;
case 6: //DIMMFREQ_800:
ByteVal = (u8) ((ByteVal & 0x0F) | 0x90);
break;
default:
ByteVal = (u8) ((ByteVal & 0x0F) | 0x70);
break;
}
outb(ByteVal, 0x03d5);
// Set frame buffer size
outb(0x39, 0x03c4);
outb(1 << SLD0F3Val, 0x03c5);
#endif
// Set S.L. size in GFX's register
outb(0x68, 0x03c4);
outb(VgaPortVal, 0x03c5);
// ECLK Selection (00:166Mhz, 01:185Mhz, 10:250Mhz, 11:275Mhz)
// set 3C5.5A[0]=1, address maps to secondary resgiters
outb(0x5a, 0x03c4);
ByteVal = inb(0x03c5);
ByteVal |= 0x01;
outb(ByteVal, 0x03c5);
// Set 3D5.4C[7:6] (00:166Mhz, 01:185Mhz, 10:250Mhz, 11:275Mhz)
outb(0x4c, 0x03d4);
ByteVal = inb(0x03d5);
ByteVal = (ByteVal & 0x3F) | 0x80;
outb(ByteVal, 0x03d5);
// set 3C5.5A[0]=0, address maps to first resgiters
outb(0x5a, 0x03c4);
ByteVal = inb(0x03c5);
ByteVal &= 0xFE;
outb(ByteVal, 0x03c5);
// Set S.L. Address in System Memory
//calculate dram size
for (RamSize = 0, i = 0; i < ARRAY_SIZE(ramregs); i++) {
RamSize = pci_read_config8(MEMCTRL, ramregs[i]);
if (RamSize != 0)
break;
}
//calculate SL Base Address
SLBase = (RamSize << 26) - (UmaSize << 20);
outb(0x6D, 0x03c4);
//SL Base[28:21]
outb((u8) ((SLBase >> 21) & 0xFF), 0x03c5);
outb(0x6e, 0x03c4);
//SL Base[36:29]
outb((u8) ((SLBase >> 29) & 0xFF), 0x03c5);
outb(0x6f, 0x03c4);
outb(0x00, 0x03c5);
// Set SVID high byte
outb(0x36, 0x03c4);
outb(0x11, 0x03c5);
// Set SVID Low byte
outb(0x35, 0x03c4);
outb(0x06, 0x03c5);
// Set SID high byte
outb(0x38, 0x03c4);
outb(0x51, 0x03c5);
// Set SID Low byte
outb(0x37, 0x03c4);
outb(0x22, 0x03c5);
//start : For enable snapshot mode control
// program 3C5 for SNAPSHOT Mode control, set RxF3h=1Ah
outb(0xf3, 0x03c4);
ByteVal = inb(0x03c5);
ByteVal = (ByteVal & 0xE5) | 0x1A;
outb(ByteVal, 0x03c5);
outb(0xf3, 0x03d4);
ByteVal = inb(0x03d5);
ByteVal = (ByteVal & 0xE5) | 0x1A;
outb(ByteVal, 0x03d5);
u8 table3c43c5[0x70] = {
0x03, 0x01, 0x0F, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x78, 0x00, 0x00, 0x00, 0xBE, 0x20, 0x7F,
0x60, 0x7F, 0x08, 0x31, 0xCC, 0x00, 0x01, 0x00,
0x00, 0x18, 0x10, 0x00, 0x00, 0x00, 0x3D, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0xF3, 0xFF, 0xFC,
0xF8, 0x0C, 0x00, 0x00, 0x40, 0x06, 0x11, 0x22,
0x51, 0x10, 0x00, 0x01, 0x19, 0x0C, 0x00, 0xFF,
0x38, 0x40, 0x30, 0xFF, 0x70, 0x8C, 0x85, 0x9D,
0x80, 0x05, 0x54, 0x90, 0x03, 0x30, 0x00, 0x5F,
0x1F, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00,
0x06, 0xDF, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x20, 0x00, 0x20, 0x20,
0xE0, 0x20, 0xD0, 0x3F, 0x00, 0xE0, 0x00, 0x00
};
u8 table3d43d5[0x88] = {
0x7F, 0x63, 0x63, 0x83, 0x69, 0x19, 0x72, 0xE0,
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x58, 0x9C, 0x57, 0x90, 0x00, 0x57, 0x73, 0xE3,
0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x11, 0x06, 0x00, 0x20, 0x01, 0x34,
0xEE, 0x74, 0x01, 0x01, 0x08, 0x84, 0x00, 0x00,
0x00, 0xF3, 0x40, 0x90, 0x00, 0x00, 0x00, 0x01,
0x00, 0x12, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x9D, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x9D, 0x9D,
0x9D, 0x9D, 0x9D, 0x9D, 0x00, 0x9D, 0x1D, 0x00,
0x00, 0x00, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D,
0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1D,
};
u8 table3c0space[0xc0] = {
0x11, 0x00, 0x10, 0x01, 0x26, 0x3D, 0xFF, 0x00,
0x10, 0x3F, 0x00, 0x00, 0x2F, 0x00, 0x22, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x50, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
#if 0
//for(i=0;i<0xc0;i++)
for (i = 0; i < 0x40; i++) //
{
outb(table3c0space[i], 0x03c0 + i);
}
for (i = 0; i < 0x70; i++) {
outb(i, 0x03c4);
outb(table3c43c5[i], 0x03c5);
}
for (i = 0; i < 0x88; i++) {
outb(i, 0x03d4);
outb(table3d43d5[i], 0x03d5);
}
outb(0x92, 0x03d4);
outb(0x80, 0x03d5);
outb(0xa3, 0x03d4);
outb(0x00, 0x03d5);
outb(0xe8, 0x03d4);
outb(0x40, 0x03d5);
#endif
//3d4 3d freq
//IO Port / Index: 3X5.3D
//Scratch Pad Register 4
// outb(0x39,0x03c4);//
//outb(1 << SLD0F3Val ,0x03c5);
//
#endif
}

View File

@ -0,0 +1,242 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "northbridge/via/vx800/DrivingClkPhaseData.h"
// DQS Driving
//Reg0xE0, 0xE1
// According to #Bank to set DRAM DQS Driving
// #Bank 1 2 3 4 5 6 7 8
static const u8 DDR2_DQSA_Driving_Table[4] = { 0xEE, 0xEE, 0xEE, 0xEE};
static const u8 DDR2_DQSB_Driving_Table[2] = { 0xEE, 0xEE};
// DQ Driving
//Reg0xE2, 0xE3
// For DDR2: According to bank to set DRAM DQ Driving
static const u8 DDR2_DQA_Driving_Table[4] = { 0xAC, 0xAC, 0xAC, 0xAC };
static const u8 DDR2_DQB_Driving_Table[2] = { 0xCA, 0xCA };
// CS Driving
//Reg0xE4, 0xE5
// According to #Bank to set DRAM CS Driving
// DDR1 #Bank 1 2 3 4 5 6 7 8
static const u8 DDR2_CSA_Driving_Table_x8[4] = { 0x44, 0x44, 0x44, 0x44 };
static const u8 DDR2_CSB_Driving_Table_x8[2] = { 0x44, 0x44};
static const u8 DDR2_CSA_Driving_Table_x16[4]= { 0x44, 0x44, 0x44, 0x44};
static const u8 DDR2_CSB_Driving_Table_x16[2]= { 0x44, 0x44};
// MAA Driving
//Reg0xE8, Reg0xE9
static const u8 DDR2_MAA_Driving_Table[MA_Table][5] =
{
//Chip number, 400, 533, 667 800 ;(SRAS, SCAS, SWE)RxE8
{ 6, 0x86, 0x86, 0x86, 0x86}, // total MAA chips = 00 ~ 06
{ 18, 0x86, 0x86, 0x86, 0x86}, // total MAA chips = 06 ~ 18
{255, 0xDB, 0xDB, 0xDB, 0xDB} // total MAA chips = 18 ~
};
static const u8 DDR2_MAB_Driving_Table[MA_Table][2] =
{
// Chip number, Value ;(SRAS, SCAS, SWE)RxE9
{ 6, 0x86 }, // total MAB chips = 00 ~ 06
{ 18, 0x86 }, // total MAB chips = 06 ~ 18
{255, 0xDB } // total MAB chips = 18 ~
};
// DCLK Driving
//Reg0xE6, 0xE7
// For DDR2: According to #Freq to set DRAM DCLK Driving
// freq 400M, 533M, 667M, 800M
static const u8 DDR2_DCLKA_Driving_Table[4] = { 0xFF, 0xFF, 0xFF, 0xFF };
static const u8 DDR2_DCLKB_Driving_Table[4] = { 0xFF, 0xFF, 0xFF, 0xFF };
/*
Duty cycle
Duty cycle Control for DQ/DQS/DDRCKG in ChA & ChB
D0F3RxEC/D0F3RxED/D0F3RxEE/D0F3RxEF
According to DRAM frequency to control Duty Cycle
*/
static const u8 ChA_Duty_Control_DDR2[DUTY_CYCLE_REG_NUM][DUTY_CYCLE_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0xEC, 0x00, 0x30, 0x30, 0x30, 0x30 }, // 1Rank
{0xEE, 0x0F, 0x40, 0x40, 0x00, 0x00 },
{0xEF, 0xCF, 0x00, 0x30, 0x30, 0x30}
};
static const u8 ChB_Duty_Control_DDR2[DUTY_CYCLE_REG_NUM][DUTY_CYCLE_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0xED, 0x00, 0x88, 0x88, 0x84, 0x88 }, // 1Rank
{0xEE, 0xF0, 0x00, 0x00, 0x00, 0x00 },
{0xEF, 0xFC, 0x00, 0x00, 0x00, 0x00 }
};
/*
DRAM Clock Phase Control for FeedBack Mode
Modify NB Reg: Rx90[7]/Rx91/Rx92/Rx93/Rx94
Processing:
1.Program VIA_NB3DRAM_REG90[7]=0b for FeedBack mode
2.Program clock phase value with ChA/B DCLK enable, VIA_NB3DRAM_REG91[7:3]=00b
3.Check ChB rank #, if 0, VIA_NB3DRAM_REG91[7]=1b, to disable ChB DCLKO
ChA DCLKO can not be disable, so always program VIA_NB3DRAM_REG91[3]=0b
*/
static const u8 DDR2_ChA_Clk_Phase_Table_1R[3][Clk_Phase_Table_DDR2_Width] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x91, 0xF8, 0x02, 0x01, 0x00, 0x07 }, // 1Rank
{0x92, 0xF8, 0x04, 0x03, 0x03, 0x02 },
{0x93, 0xF8, 0x06, 0x05, 0x04, 0x03 }
};
static const u8 DDR2_ChB_Clk_Phase_Table_1R[3][Clk_Phase_Table_DDR2_Width] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x91, 0x0F, 0x20, 0x10, 0x00, 0x70 }, // 1Rank
{0x92, 0x0F, 0x40, 0x30, 0x30, 0x20 },
{0x93, 0x0F, 0x60, 0x50, 0x40, 0x30 }
};
/*static const u8 DDR2_ChA_Clk_Phase_Table_2R[3][Clk_Phase_Table_DDR2_Width] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x91, 0xF8, 0x04, 0x03, 0x04, 0x01 }, // 1Rank
{0x92, 0xF8, 0x03, 0x06, 0x05, 0x04 },
{0x93, 0xF8, 0x03, 0x07, 0x06, 0x05 }
};*/
static const u8 DDR2_ChA_Clk_Phase_Table_2R[3][Clk_Phase_Table_DDR2_Width] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x91, 0xF8, 0x02, 0x01, 0x00, 0x07}, // 1Rank
{0x92, 0xF8, 0x04, 0x03, 0x03, 0x02 },
{0x93, 0xF8, 0x06, 0x05, 0x04, 0x03 }
};
/*
DRAM Write Data phase control
Modify NB Reg: Rx74/Rx75/Rx76
*/
/*static const u8 DDR2_ChA_WrtData_Phase_Table[WrtData_REG_NUM ][WrtData_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x74, 0xF8, 0x03, 0x04, 0x05, 0x02 }, // 1Rank
{0x75, 0xF8, 0x03, 0x04, 0x05, 0x02 },
{0x76, 0x00, 0x10, 0x80, 0x00, 0x07 }
};*/
static const u8 DDR2_ChA_WrtData_Phase_Table[WrtData_REG_NUM ][WrtData_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x74, 0xF8, 0x01, 0x00, 0x00, 0x07 }, // 1Rank
{0x75, 0xF8, 0x01, 0x00, 0x00, 0x07 },
{0x76, 0x10, 0x80, 0x87, 0x07, 0x06 },
{0x8C, 0xFC, 0x03, 0x03, 0x03, 0x03 }
};
/*static const u8 DDR2_ChB_WrtData_Phase_Table[WrtData_REG_NUM ][WrtData_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x74, 0x8F, 0x30, 0x40, 0x30, 0x20 }, // 1Rank
{0x75, 0x8F, 0x30, 0x40, 0x30, 0x20 },
{0x8A, 0x00, 0x10, 0x80, 0x07, 0x07 }
};
*/
/*
DQ/DQS Output Delay Control
Modify NB D0F3: RxF0/RxF1/RxF2/RxF3
*/
static const u8 DDR2_CHA_DQ_DQS_Delay_Table[4][DQ_DQS_Delay_Table_Width] =
{
// RxF0 RxF1 RxF2 RxF3
{ 0x00, 0x00, 0x00, 0x00 },// DDR400
{ 0x00, 0x00, 0x00, 0x00 },// DDR533
{ 0x00, 0x00, 0x00, 0x00 },// DDR667
{ 0x00, 0x00, 0x00, 0x00 }// DDR800
};
static const u8 DDR2_CHB_DQ_DQS_Delay_Table[4][DQ_DQS_Delay_Table_Width] =
{
// RxF4 RxF5 RxF6 RxF7
{ 0x00, 0x00, 0x00, 0x00 },// DDR400
{ 0x00, 0x00, 0x00, 0x00 },// DDR533
{ 0x00, 0x00, 0x00, 0x00 },// DDR667
{ 0x00, 0x00, 0x00, 0x00 }// DDR800
};
/*
DQ/DQS input Capture Control
modify NB D0F3_Reg:Rx78/Rx79/Rx7A/Rx7B
*/
/*static const u8 DDR2_ChA_DQS_Input_Capture_Tbl[DQS_INPUT_CAPTURE_REG_NUM ][DQS_INPUT_CAPTURE_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x78, 0x00, 0x83, 0x8D, 0x87, 0x83 }, // 1Rank
{0x7A, 0xF0, 0x00, 0x00, 0x00, 0x00 },
{0x7B, 0x00, 0x10, 0x30, 0x20, 0x10 }
};*/
static const u8 DDR2_ChA_DQS_Input_Capture_Tbl[DQS_INPUT_CAPTURE_REG_NUM ][DQS_INPUT_CAPTURE_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x78, 0xC0, 0x0D, 0x07, 0x03, 0x01 }, // 1Rank
{0x7A, 0xF0, 0x00, 0x00, 0x00, 0x00 },
{0x7B, 0x00, 0x34, 0x34, 0x20, 0x10 }
};
static const u8 DDR2_ChB_DQS_Input_Capture_Tbl[DQS_INPUT_CAPTURE_REG_NUM ][DQS_INPUT_CAPTURE_FREQ_NUM] =
{
// (And NOT) DDR800 DDR667 DDR533 DDR400
//Reg Mask Value Value Value Value
{0x79, 0x00, 0x89, 0x89, 0x87, 0x83 }, // 1Rank
{0x7A, 0x0F, 0x00, 0x00, 0x00, 0x00 },
{0x8B, 0x00, 0x34, 0x34, 0x20, 0x10 }
};
static const u8 Fixed_DQSA_1_2_Rank_Table[4][2] =
{
// Rx70 Rx71
{ 0x00, 0x05 }, // DDR800
{ 0x00, 0x06 }, // DDR667
{ 0x00, 0x04 }, // DDR533
{ 0x00, 0x05 } // DDR400
};
static const u8 Fixed_DQSA_3_4_Rank_Table[4][2] =
{
// Rx70 Rx71
{0x00 , 0x04}, // DDR800
{0x00 , 0x04}, // DDR667
{0x00 , 0x03}, // DDR533
{0x00 , 0x04} // DDR400
};

View File

@ -0,0 +1,660 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define ASSEMBLY 1
#define __ROMCC__
#define RAMINIT_SYSINFO 1
#define CACHE_AS_RAM_ADDRESS_DEBUG 0
#include <stdint.h>
#include <device/pci_def.h>
#include <device/pci_ids.h>
#include <arch/io.h>
#include <device/pnp_def.h>
#include <arch/romcc_io.h>
#include <arch/hlt.h>
#include "pc80/serial.c"
#include "arch/i386/lib/console.c"
#include "ram/ramtest.c"
#include "northbridge/via/vx800/vx800.h"
#include "cpu/x86/mtrr/earlymtrr.c"
#include "cpu/x86/bist.h"
#include "pc80/udelay_io.c"
#include "lib/delay.c"
#if CONFIG_USE_INIT == 0
#include "lib/memcpy.c"
#endif
#include "cpu/x86/lapic/boot_cpu.c"
#include "DrivingClkPhaseData.c"
#include "northbridge/via/vx800/raminit.h"
#include "northbridge/via/vx800/raminit.c"
#include "cpu/x86/car/copy_and_run.c"
int acpi_is_wakeup_early_via_vx800(void)
{
device_t dev;
u16 tmp, result;
print_debug("In acpi_is_wakeup_early_via_vx800\r\n");
/* Power management controller */
dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_VX855_LPC), 0);
if (dev == PCI_DEV_INVALID)
die("Power management controller not found\r\n");
/* Set ACPI base address to I/O VX800_ACPI_IO_BASE. */
pci_write_config16(dev, 0x88, VX800_ACPI_IO_BASE | 0x1);
/* Enable ACPI accessm RTC signal gated with PSON. */
pci_write_config8(dev, 0x81, 0x84);
tmp = inw(VX800_ACPI_IO_BASE + 0x04);
result = ((tmp & (7 << 10)) >> 10) == 1 ? 3 : 0;
print_debug(" boot_mode=");
print_debug_hex16(result);
print_debug("\r\n");
return result;
}
static inline int spd_read_byte(unsigned device, unsigned address)
{
return smbus_read_byte(device, address);
}
static void enable_mainboard_devices(void)
{
device_t dev;
uint16_t values;
print_debug("In enable_mainboard_devices \r\n");
/*
Enable P2P Bridge Header for External PCI BUS.
*/
dev = pci_locate_device(PCI_ID(0x1106, 0xa353), 0);
pci_write_config8(dev, 0x4f, 0x41);
}
static void enable_shadow_ram(void)
{
uint8_t shadowreg;
pci_write_config8(PCI_DEV(0, 0, 3), 0x80, 0xff);
/* 0xf0000-0xfffff - ACPI tables */
shadowreg = pci_read_config8(PCI_DEV(0, 0, 3), 0x83);
shadowreg |= 0x30;
pci_write_config8(PCI_DEV(0, 0, 3), 0x83, shadowreg);
/* 0xe0000-0xeffff - elfload? */
pci_write_config8(PCI_DEV(0, 0, 3), 0x82, 0xff);
}
/*
this table contains the value needed to be set before begin to init dram.
Note: REV_Bx should be cared when porting a new board!!!!! */
static const struct VIA_PCI_REG_INIT_TABLE mNbStage1InitTbl[] = {
//VT3409 no pcie
0x00, 0xFF, NB_APIC_REG(0x61), 0xFF, 0x0E, // Set Exxxxxxx as pcie mmio config range
0x00, 0xFF, NB_APIC_REG(0x60), 0xF4, 0x0B, // Support extended cfg address of pcie
//0x00, 0xFF, NB_APIC_REG(0x42), 0xF9, 0x02, // APIC Interrupt((BT_INTR)) Control
// Set ROMSIP value by software
/*0x00, 0xFF, NB_HOST_REG(0x70), 0x77, 0x33, // 2x Host Adr Strobe/Pad Pullup Driving = 3
0x00, 0xFF, NB_HOST_REG(0x71), 0x77, 0x33, // 2x Host Adr Strobe/Pad Pulldown Driving = 3
0x00, 0xFF, NB_HOST_REG(0x72), 0x77, 0x33, // 4x Host Dat Strobe/Pad Pullup Driving = 3
0x00, 0xFF, NB_HOST_REG(0x73), 0x77, 0x33, // 4x Host Dat Strobe/Pad Pulldown Driving = 3
0x00, 0xFF, NB_HOST_REG(0x74), 0xFF, 0x21, // Memory I/F timing ctrl
0x00, 0xFF, NB_HOST_REG(0x74), 0xFF, 0xE1, // Memory I/F timing ctrl
0x00, 0xFF, NB_HOST_REG(0x75), 0xFF, 0x18, // AGTL+ I/O Circuit
0x00, 0xFF, NB_HOST_REG(0x76), 0xFB, 0x0C, // AGTL+ Compensation Status
0x00, 0xFF, NB_HOST_REG(0x78), 0xFF, 0x33, // 2X AGTL+ Auto Compensation Offset
0x00, 0xFF, NB_HOST_REG(0x79), 0xFF, 0x33, // 4X AGTL+ Auto Compensation Offset
0x00, 0xFF, NB_HOST_REG(0x7A), 0x3F, 0x72, // AGTL Compensation Status
0x00, 0xFF, NB_HOST_REG(0x7A), 0x3F, 0x77, // AGTL Compensation Status
0x00, 0xFF, NB_HOST_REG(0x7B), 0xFF, 0x44, // Input Host Address / Host Strobe Delay Control for HA Group
0x00, 0xFF, NB_HOST_REG(0x7B), 0xFF, 0x22, // Input Host Address / Host Strobe Delay Control for HA Group
0x00, 0xFF, NB_HOST_REG(0x7C), 0xFF, 0x00, // Output Delay Control of PAD for HA Group
0x00, 0xFF, NB_HOST_REG(0x7D), 0xFF, 0xAA, // Host Address / Address Clock Output Delay Control (Only for P4 Bus)
0x00, 0xFF, NB_HOST_REG(0x7E), 0xFF, 0x10, // Host Address CKG Rising / Falling Time Control (Only for P4 Bus)
0x00, 0xFF, NB_HOST_REG(0x7E), 0xFF, 0x40, // Host Address CKG Rising / Falling Time Control (Only for P4 Bus)
0x00, 0xFF, NB_HOST_REG(0x7F), 0xFF, 0x10, // Host Address CKG Rising / Falling Time Control (Only for P4 Bus)
0x00, 0xFF, NB_HOST_REG(0x7F), 0xFF, 0x40, // Host Address CKG Rising / Falling Time Control (Only for P4 Bus)
0x00, 0xFF, NB_HOST_REG(0x80), 0x3F, 0x44, // Host Data Receiving Strobe Delay Ctrl 1
0x00, 0xFF, NB_HOST_REG(0x81), 0xFF, 0x44, // Host Data Receiving Strobe Delay Ctrl 2
0x00, 0xFF, NB_HOST_REG(0x82), 0xFF, 0x00, // Output Delay of PAD for HDSTB
0x00, 0xFF, NB_HOST_REG(0x83), 0xFF, 0x00, // Output Delay of PAD for HD
0x00, 0xFF, NB_HOST_REG(0x84), 0xFF, 0x44, // Host Data / Strobe CKG Control (Group 0)
0x00, 0xFF, NB_HOST_REG(0x85), 0xFF, 0x44, // Host Data / Strobe CKG Control (Group 1)
0x00, 0xFF, NB_HOST_REG(0x86), 0xFF, 0x44, // Host Data / Strobe CKG Control (Group 2)
0x00, 0xFF, NB_HOST_REG(0x87), 0xFF, 0x44, // Host Data / Strobe CKG Control (Group 3) */
// CPU Host Bus Control
0x00, 0xFF, NB_HOST_REG(0x50), 0x1F, 0x08, // Request phase ctrl: Dynamic Defer Snoop Stall Count = 8
//0x00, 0xFF, NB_HOST_REG(0x51), 0xFF, 0x7F, // CPU I/F Ctrl-1: Disable Fast DRDY and RAW
0x00, 0xFF, NB_HOST_REG(0x51), 0xFF, 0x7C, // CPU I/F Ctrl-1: Disable Fast DRDY and RAW
0x00, 0xFF, NB_HOST_REG(0x52), 0xCB, 0xCB, // CPU I/F Ctrl-2: Enable all for performance
//0x00, 0xFF, NB_HOST_REG(0x53), 0xFF, 0x88, // Arbitration: Host/Master Occupancy timer = 8*4 HCLK
0x00, 0xFF, NB_HOST_REG(0x53), 0xFF, 0x44, // Arbitration: Host/Master Occupancy timer = 4*4 HCLK
0x00, 0xFF, NB_HOST_REG(0x54), 0x1E, 0x1C, // Misc Ctrl: Enable 8QW burst Mem Access
//0x00, 0xFF, NB_HOST_REG(0x55), 0x06, 0x06, // Miscellaneous Control 2
0x00, 0xFF, NB_HOST_REG(0x55), 0x06, 0x04, // Miscellaneous Control 2
0x00, 0xFF, NB_HOST_REG(0x56), 0xF7, 0x63, // Write Policy 1
//0x00, 0xFF, NB_HOST_REG(0x59), 0x3D, 0x01, // CPU Miscellaneous Control 1, enable Lowest-Priority IPL
//0x00, 0xFF, NB_HOST_REG(0x5c), 0xFF, 0x00, // CPU Miscellaneous Control 2
0x00, 0xFF, NB_HOST_REG(0x5D), 0xFF, 0xA2, // Write Policy
0x00, 0xFF, NB_HOST_REG(0x5E), 0xFF, 0x88, // Bandwidth Timer
0x00, 0xFF, NB_HOST_REG(0x5F), 0x46, 0x46, // CPU Misc Ctrl
// 0x00, 0xFF, NB_HOST_REG(0x90), 0xFF, 0x0B, // CPU Miscellaneous Control 3
//0x00, 0xFF, NB_HOST_REG(0x96), 0x0B, 0x0B, // CPU Miscellaneous Control 2
0x00, 0xFF, NB_HOST_REG(0x96), 0x0B, 0x0A, // CPU Miscellaneous Control 2
0x00, 0xFF, NB_HOST_REG(0x98), 0xC1, 0x41, // CPU Miscellaneous Control 3
0x00, 0xFF, NB_HOST_REG(0x99), 0x0E, 0x06, // CPU Miscellaneous Control 4
// Set APIC and SMRAM
0x00, 0xFF, NB_HOST_REG(0x97), 0xFF, 0x00, // APIC Related Control
0x00, 0xFF, NB_DRAMC_REG(0x86), 0xD6, 0x29, // SMM and APIC Decoding: enable APIC, MSI and SMRAM A-Seg
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // End of the table
};
#define USE_VCP 1 //0 means use DVP
#define USE_COM1 1
#define USE_COM2 0
#define gCom1Base 0x3f8
#define gCom2Base 0x2f8
void EmbedComInit()
{
u8 ByteVal;
u16 ComBase;
//enable NB multiple function control
ByteVal = pci_read_config8(PCI_DEV(0, 0, 0), 0x4f);
ByteVal = ByteVal | 0x01;
pci_write_config8(PCI_DEV(0, 0, 0), 0x4f, ByteVal);
//VGA Enable
ByteVal = pci_read_config8(PCI_DEV(0, 0, 3), 0xA1);
ByteVal = ByteVal | 0x80;
pci_write_config8(PCI_DEV(0, 0, 3), 0xA1, ByteVal);
ByteVal = pci_read_config8(PCI_DEV(0, 0, 3), 0xA7);
ByteVal = ByteVal | 0x08;
pci_write_config8(PCI_DEV(0, 0, 3), 0xA7, ByteVal);
//Enable p2p IO/mem
ByteVal = pci_read_config8(PCI_DEV(0, 1, 0), 0x4);
ByteVal = ByteVal | 0x07;
pci_write_config8(PCI_DEV(0, 1, 0), 0x4, ByteVal);
//Turn on Graphic chip IO port port access
ByteVal = inb(0x3C3);
ByteVal = ByteVal | 0x01;
outb(ByteVal, 0x3C3);
//Turn off Graphic chip Register protection
outb(0x10, 0x3C4);
ByteVal = inb(0x3C5);
ByteVal = ByteVal | 0x01;
outb(ByteVal, 0x3C5);
//south module pad share enable 0x3C5.78[7]
outb(0x78, 0x3C4);
ByteVal = inb(0x3C5);
ByteVal = ByteVal | 0x80;
outb(ByteVal, 0x3C5);
//enable UART Function multiplex with DVP or VCP pad D17F0Rx46[7,6]
ByteVal = pci_read_config8(PCI_DEV(0, 17, 0), 0x46);
//multiplex with VCP
if (USE_VCP == 1)
ByteVal = (ByteVal & 0x3F) | 0x40;
//multiplex with DVP
else
ByteVal = (ByteVal & 0x3F) | 0xC0;
pci_write_config8(PCI_DEV(0, 17, 0), 0x46, ByteVal);
//enable embeded com1 and com2 D17F0RxB0[5,4]
ByteVal = pci_read_config8(PCI_DEV(0, 17, 0), 0xB0);
ByteVal = ByteVal & 0xcf;
//multiplex with VCP
if (USE_COM1 == 1)
ByteVal = ByteVal | 0x10;
if (USE_COM2 == 1)
ByteVal = ByteVal | 0x20;
pci_write_config8(PCI_DEV(0, 17, 0), 0xB0, ByteVal);
if (USE_COM1 == 1)
ComBase = gCom1Base;
else
ComBase = gCom2Base;
//noharddrive
//set embeded com1 IO base = 0x3E8
//D17F0RB4
//ByteVal = 0xFD;
if (USE_COM1 == 1) {
ByteVal = (u8) ((gCom1Base >> 3) | 0x80);
pci_write_config8(PCI_DEV(0, 17, 0), 0xB4, ByteVal);
ByteVal = pci_read_config8(PCI_DEV(0, 17, 0), 0xb2);
ByteVal = (ByteVal & 0xf0) | 0x04;
pci_write_config8(PCI_DEV(0, 17, 0), 0xB2, ByteVal);
}
//set embeded com2 IO base = 0x2E8
//D17F0RB5
//ByteVal = 0xDD;
if (USE_COM2 == 1) {
ByteVal = (u8) ((gCom2Base >> 3) | 0x80);
pci_write_config8(PCI_DEV(0, 17, 0), 0xB5, ByteVal);
ByteVal = pci_read_config8(PCI_DEV(0, 17, 0), 0xb2);
ByteVal = (ByteVal & 0x0f) | 0x30;
pci_write_config8(PCI_DEV(0, 17, 0), 0xB2, ByteVal);
}
//no port 80 biger then 0x10
//disable interrupt
ByteVal = inb(ComBase + 3);
outb(ByteVal & 0x7F, ComBase + 3);
outb(0x00, ComBase + 1);
//set baudrate
ByteVal = inb(ComBase + 3);
outb(ByteVal | 0x80, ComBase + 3);
outb(0x01, ComBase);
outb(0x00, ComBase + 1);
//set frame fromat
ByteVal = inb(ComBase + 3);
outb(ByteVal & 0x3F, ComBase + 3);
outb(0x03, ComBase + 3);
outb(0x00, ComBase + 2);
outb(0x00, ComBase + 4);
//SOutput("Embeded com output\n");
//while(1);
}
/* cache_as_ram.inc jump to here
*/
void amd64_main(unsigned long bist)
{
unsigned cpu_reset = 0;
u16 boot_mode;
u8 rambits;
//device_t dev;
/* Enable multifunction for northbridge. */
pci_write_config8(PCI_DEV(0, 0, 0), 0x4f, 0x01);
EmbedComInit();
//enable_vx800_serial();
//uart_init();
/* 1. D15F0
a) RxBAh = 71h
b) RxBBh = 05h
c) RxBEh = 71h
d) RxBFh = 05h
2. D17F0
a) RxA0h = 06h
b) RxA1h = 11h
c) RxA2h = 27h
d) RxA3h = 32h
e) Rx79h = 40h
f) Rx72h = 27h
g) Rx73h = 32h
*/
u8 Data8;
pci_write_config16(PCI_DEV(0, 0xf, 0), 0xBA,
PCI_DEVICE_ID_VIA_VX855_IDE);
pci_write_config16(PCI_DEV(0, 0xf, 0), 0xBE,
PCI_DEVICE_ID_VIA_VX855_IDE);
pci_write_config16(PCI_DEV(0, 0x11, 0), 0xA0, PCI_VENDOR_ID_VIA);
pci_write_config16(PCI_DEV(0, 0x11, 0), 0xA2,
PCI_DEVICE_ID_VIA_VX855_LPC);
Data8 = pci_read_config8(PCI_DEV(0, 0x11, 0), 0x79);
Data8 &= ~0x40;
Data8 |= 0x40;
pci_write_config8(PCI_DEV(0, 0x11, 0), 0x79, Data8);
pci_write_config16(PCI_DEV(0, 0x11, 0), 0x72,
PCI_DEVICE_ID_VIA_VX855_LPC);
console_init(); //there are to function defination of console_init(), while the src/archi386/lib is the right one
/* decide if this is a s3 wakeup or a normal boot */
boot_mode = acpi_is_wakeup_early_via_vx800();
/*add this, to transfer "cpu restart" to "cold boot"
When this boot is not a S3 resume, and PCI registers had been written,
then this must be a cpu restart(result of os reboot cmd). so we need a real "cold boot". */
if ((boot_mode != 3)
&& (pci_read_config8(PCI_DEV(0, 0, 3), 0x80) != 0)) {
outb(6, 0xcf9);
}
/*x86 cold boot I/O cmd */
enable_smbus();
//smbus_fixup(&ctrl);// this fix does help vx800!, but vx855 no need this
if (bist == 0) {
// CAR need mtrr untill mem is ok, so i disable this early_mtrr_init();
//print_debug("doing early_mtrr\r\n");
//early_mtrr_init();
}
/* Halt if there was a built-in self test failure. */
report_bist_failure(bist);
print_debug("Enabling mainboard devices\r\n");
enable_mainboard_devices();
u8 Data;
device_t device;
/* Get NB Chip revision from D0F4RxF6, revision will be used in via_pci_inittable */
device = PCI_DEV(0, 0, 4);
Data = pci_read_config8(device, 0xf6);
print_debug("NB chip revision =");
print_debug_hex8(Data);
print_debug("\r\n");
/* make NB ready before draminit */
via_pci_inittable(Data, mNbStage1InitTbl);
/*add this.
When resume from s3, draminit is skiped, so need to recovery any PCI register related to draminit.
and d0f3 didnt lost its Power during whole s3 time, so any register not belongs to d0f3 need to be recoveried . */
#if 1
if (boot_mode == 3) {
u8 i;
u8 ramregs[] = { 0x43, 0x42, 0x41, 0x40 };
DRAM_SYS_ATTR DramAttr;
print_debug("This is a S3 wakeup\r\n");
memset(&DramAttr, 0, sizeof(DRAM_SYS_ATTR));
/*Step1 DRAM Detection; DDR1 or DDR2; Get SPD Data; Rank Presence;64 or 128bit; Unbuffered or registered; 1T or 2T */
DRAMDetect(&DramAttr);
/*begin to get ram size, 43,42 41 40 contains the end address of last rank in ddr2-slot */
device = PCI_DEV(0, 0, 3);
for (rambits = 0, i = 0; i < ARRAY_SIZE(ramregs); i++) {
rambits = pci_read_config8(device, ramregs[i]);
if (rambits != 0)
break;
}
DRAMDRDYSetting(&DramAttr);
Data = 0x80; // this value is same with DevInit.c
pci_write_config8(PCI_DEV(0, 0, 4), 0xa3, Data);
pci_write_config8(PCI_DEV(0, 17, 7), 0x60, rambits << 2);
Data = pci_read_config8(MEMCTRL, 0x88);
pci_write_config8(PCI_DEV(0, 17, 7), 0xE5, Data);
DRAMRegFinalValue(&DramAttr); // I just copy this function from draminit to here!
SetUMARam(); // I just copy this function from draminit to here!
print_debug("Resume from S3, RAM init was ignored\r\n");
} else {
ddr2_ram_setup();
ram_check(0, 640 * 1024);
}
#endif
//ddr2_ram_setup();
/*this line is the same with cx700 port . */
enable_shadow_ram();
/*
For coreboot most time of S3 resume is the same as normal boot, so some memory area under 1M become dirty,
so before this happen, I need to backup the content of mem to top-mem.
I will reserve the 1M top-men in LBIO table in coreboot_table.c and recovery the content of 1M-mem in wakeup.c
*/
#if PAYLOAD_IS_SEABIOS==1 //
if (boot_mode == 3) {
/* some idea of Libo.Feng at amd.com in http://www.coreboot.org/pipermail/coreboot/2008-December/043111.html
I want move the 1M data, I have to set some MTRRs myself. */
/* seting mtrr before back memoy save s3 resume time about 0.14 seconds */
/*because CAR stack use cache, and here to use cache , must be careful,
1 during these mtrr code, must no function call, (after this mtrr, I think it should be ok to use function)
2 before stack switch, no use variable that have value set before this
3 due to 2, take care of "cpu_reset", I directlly set it to ZERO.
*/
u32 memtop = *(u32 *) WAKE_MEM_INFO;
u32 memtop1 = *(u32 *) WAKE_MEM_INFO - 0x100000;
u32 memtop2 = *(u32 *) WAKE_MEM_INFO - 0x200000;
u32 memtop3 =
*(u32 *) WAKE_MEM_INFO - 64 * 1024 - 0x100000;
u32 memtop4 =
*(u32 *) WAKE_MEM_INFO - 64 * 1024 - 0x100000 +
0xe0000;
/* __asm__ volatile (
"movl $0x204, %%ecx\n\t"
"xorl %%edx, %%edx\n\t"
"movl %0,%%eax\n\t"
"orl $(0 | 6), %%eax\n\t"
"wrmsr\n\t"
"movl $0x205, %%ecx\n\t"
"xorl %%edx, %%edx\n\t"
"movl $0x100000,%%eax\n\t"
"decl %%eax\n\t"
"notl %%eax\n\t"
"orl $(0 | 0x800), %%eax\n\t"
"wrmsr\n\t"
::"g"(memtop2)
);
__asm__ volatile (
"movl $0x206, %%ecx\n\t"
"xorl %%edx, %%edx\n\t"
"movl %0,%%eax\n\t"
"orl $(0 | 6), %%eax\n\t"
"wrmsr\n\t"
"movl $0x207, %%ecx\n\t"
"xorl %%edx, %%edx\n\t"
"movl $0x100000,%%eax\n\t"
"decl %%eax\n\t"
"notl %%eax\n\t"
"orl $(0 | 0x800), %%eax\n\t"
"wrmsr\n\t"
::"g"(memtop1)
);
__asm__ volatile (
"movl $0x208, %ecx\n\t"
"xorl %edx, %edx\n\t"
"movl $0,%eax\n\t"
"orl $(0 | 6), %eax\n\t"
"wrmsr\n\t"
"movl $0x209, %ecx\n\t"
"xorl %edx, %edx\n\t"
"movl $0x100000,%eax\n\t"
"decl %eax\n\t"
"notl %eax\n\t"
"orl $(0 | 0x800), %eax\n\t"
"wrmsr\n\t"
);
*/
// WAKE_MEM_INFO is inited in get_set_top_available_mem in tables.c
// these two memcpy not not be enabled if set the MTRR around this two lines.
/*__asm__ volatile (
"movl $0, %%esi\n\t"
"movl %0, %%edi\n\t"
"movl $0xa0000, %%ecx\n\t"
"shrl $2, %%ecx\n\t"
"rep movsd\n\t"
::"g"(memtop3)
);
__asm__ volatile (
"movl $0xe0000, %%esi\n\t"
"movl %0, %%edi\n\t"
"movl $0x20000, %%ecx\n\t"
"shrl $2, %%ecx\n\t"
"rep movsd\n\t"
::"g"(memtop4)
);*/
print_debug("copy memory to high memory to protect s3 wakeup vector code \r\n"); //this can have function call, because no variable used before this
memcpy((unsigned char *) ((*(u32 *) WAKE_MEM_INFO) -
64 * 1024 - 0x100000),
(unsigned char *) 0, 0xa0000);
memcpy((unsigned char *) ((*(u32 *) WAKE_MEM_INFO) -
64 * 1024 - 0x100000 + 0xe0000),
(unsigned char *) 0xe0000, 0x20000);
/* restore the MTRR previously modified. */
/* __asm__ volatile (
"wbinvd\n\t"
"xorl %edx, %edx\n\t"
"xorl %eax, %eax\n\t"
"movl $0x204, %ecx\n\t"
"wrmsr\n\t"
"movl $0x205, %ecx\n\t"
"wrmsr\n\t"
"movl $0x206, %ecx\n\t"
"wrmsr\n\t"
"movl $0x207, %ecx\n\t"
"wrmsr\n\t"
"movl $0x208, %ecx\n\t"
"wrmsr\n\t"
"movl $0x209, %ecx\n\t"
"wrmsr\n\t"
);*/
}
#endif
/*
the following code is copied from src\mainboard\tyan\s2735\cache_as_ram_auto.c
Only the code around CLEAR_FIRST_1M_RAM is changed.
I remove all the code around CLEAR_FIRST_1M_RAM and #include "cpu/x86/car/cache_as_ram_post.c"
the CLEAR_FIRST_1M_RAM seems to make cpu/x86/car/cache_as_ram_post.c stop at somewhere,
and cpu/x86/car/cache_as_ram_post.c do not cache my $XIP_ROM_BASE+SIZE area.
So,I use: #include "cpu/via/car/cache_as_ram_post.c". my via-version post.c have some diff withx86-version
*/
#if 1
{
/* Check value of esp to verify if we have enough rom for stack in Cache as RAM */
unsigned v_esp;
__asm__ volatile ("movl %%esp, %0\n\t":"=a" (v_esp)
);
#if CONFIG_USE_INIT
printk_debug("v_esp=%08x\r\n", v_esp);
#else
print_debug("v_esp=");
print_debug_hex32(v_esp);
print_debug("\r\n");
#endif
}
#endif
#if 1
cpu_reset_x:
// it seems that cpu_reset is not used before this, so I just reset it, (this is because the s3 resume, setting in mtrr and copy data may destroy
//stack
cpu_reset = 0;
#if CONFIG_USE_INIT
printk_debug("cpu_reset = %08x\r\n", cpu_reset);
#else
print_debug("cpu_reset = ");
print_debug_hex32(cpu_reset);
print_debug("\r\n");
#endif
if (cpu_reset == 0) {
print_debug("Clearing initial memory region: ");
}
print_debug("No cache as ram now - ");
/* store cpu_reset to ebx */
__asm__ volatile ("movl %0, %%ebx\n\t"::"a" (cpu_reset)
);
/* cancel these lines, CLEAR_FIRST_1M_RAM cause the cpu/x86/car/cache_as_ram_post.c stop at somewhere
if(cpu_reset==0) {
#define CLEAR_FIRST_1M_RAM 1
#include "cpu/via/car/cache_as_ram_post.c"
}
else {
#undef CLEAR_FIRST_1M_RAM
#include "cpu/via/car/cache_as_ram_post.c"
}
*/
#include "cpu/via/car/cache_as_ram_post.c"
//#include "cpu/x86/car/cache_as_ram_post.c"
__asm__ volatile (
/* set new esp *//* before _RAMBASE */
"subl %0, %%ebp\n\t"
"subl %0, %%esp\n\t"::
"a" ((DCACHE_RAM_BASE + DCACHE_RAM_SIZE) -
_RAMBASE)
);
{
unsigned new_cpu_reset;
/* get back cpu_reset from ebx */
__asm__ volatile ("movl %%ebx, %0\n\t":"=a" (new_cpu_reset)
);
/* We can not go back any more, we lost old stack data in cache as ram */
if (new_cpu_reset == 0) {
print_debug("Use Ram as Stack now - done\r\n");
} else {
print_debug("Use Ram as Stack now - \r\n");
}
#if CONFIG_USE_INIT
printk_debug("new_cpu_reset = %08x\r\n", new_cpu_reset);
#else
print_debug("new_cpu_reset = ");
print_debug_hex32(new_cpu_reset);
print_debug("\r\n");
#endif
/*copy and execute coreboot_ram */
copy_and_run(new_cpu_reset);
/* We will not return */
}
#endif
print_debug("should not be here -\r\n");
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,247 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
part of this file is from cx700 port, part of is from cn700 port,
*/
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include <cpu/cpu.h>
#include "chip.h"
#include "northbridge.h"
#include "vx800.h"
static void memctrl_init(device_t dev)
{
/*
set VGA in UMARamSetting.c, not in this function.
*/
#if 0
pci_write_config8(dev, 0x85, 0x20);
pci_write_config8(dev, 0x86, 0x2d);
/* Set up VGA timers */
pci_write_config8(dev, 0xa2, 0x44);
/* Enable VGA with a 32mb framebuffer */
pci_write_config16(dev, 0xa0, 0xd000);
pci_write_config16(dev, 0xa4, 0x0010);
//b0: 60 aa aa 5a 0f 00 00 00 08
pci_write_config16(dev, 0xb0, 0xaa00);
pci_write_config8(dev, 0xb8, 0x08);
#endif
}
static const struct device_operations memctrl_operations = {
.read_resources = vx800_noop,
.init = memctrl_init,
};
static const struct pci_driver memctrl_driver __pci_driver = {
.ops = &memctrl_operations,
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_DEVICE_ID_VIA_VX855_MEMCTRL,
};
static void pci_domain_read_resources(device_t dev)
{
struct resource *resource;
printk_spew("Entering vx800 pci_domain_read_resources.\n");
/* Initialize the system wide io space constraints */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
resource->limit = 0xffffUL;
resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE |
IORESOURCE_ASSIGNED;
/* Initialize the system wide memory resources constraints */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
resource->limit = 0xffffffffULL;
resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE |
IORESOURCE_ASSIGNED;
printk_spew("Leaving vx800 pci_domain_read_resources.\n");
}
static void ram_resource(device_t dev, unsigned long index,
unsigned long basek, unsigned long sizek)
{
struct resource *resource;
if (!sizek) {
return;
}
resource = new_resource(dev, index);
resource->base = ((resource_t) basek) << 10;
resource->size = ((resource_t) sizek) << 10;
resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE |
IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
}
static void tolm_test(void *gp, struct device *dev, struct resource *new)
{
struct resource **best_p = gp;
struct resource *best;
best = *best_p;
if (!best || (best->base > new->base)) {
best = new;
}
*best_p = best;
}
static u32 find_pci_tolm(struct bus *bus)
{
print_debug("Entering find_pci_tolm\n");
struct resource *min;
u32 tolm;
min = 0;
search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM,
tolm_test, &min);
tolm = 0xffffffffUL;
if (min && tolm > min->base) {
tolm = min->base;
}
print_debug("Leaving find_pci_tolm\n");
return tolm;
}
static void pci_domain_set_resources(device_t dev)
{
/*
* the order is important to find the correct ram size.
*/
u8 ramregs[] = { 0x43, 0x42, 0x41, 0x40 };
device_t mc_dev;
u32 pci_tolm;
u8 reg;
printk_spew("Entering vx800 pci_domain_set_resources.\n");
pci_tolm = find_pci_tolm(&dev->link[0]);
mc_dev = dev_find_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_VX855_MEMCTRL, 0);
if (mc_dev) {
unsigned long tomk, tolmk;
unsigned char rambits;
u8 i, idx;
/*
* once the register value is not zero, the ramsize is
* this register's value multiply 64 * 1024 * 1024
*/
for (rambits = 0, i = 0; i < ARRAY_SIZE(ramregs); i++) {
unsigned char reg;
rambits = pci_read_config8(mc_dev, ramregs[i]);
if (rambits != 0)
break;
}
/*
Get memory size and frame buffer from northbridge's registers.
if register with invalid value we set frame buffer size to 32M for default, but it won't happen.
*/
reg = pci_read_config8(mc_dev, 0xa1);
reg &= 0x70;
reg = reg >> 4;
/* TOP 1M SM Memory */
if (reg == 0x0)
tomk = (((rambits << 6) - 32 - VIACONFIG_TOP_SM_SIZE_MB) * 1024); // Set frame buffer 32M for default
else
tomk =
(((rambits << 6) - (4 << reg) -
VIACONFIG_TOP_SM_SIZE_MB) * 1024);
printk_spew("tomk is 0x%x\n", tomk);
/* Compute the Top Of Low Memory, in Kb */
tolmk = pci_tolm >> 10;
if (tolmk >= tomk) {
/* The PCI hole does does not overlap the memory. */
tolmk = tomk;
}
/* Report the memory regions */
idx = 10;
/* TODO: Hole needed? */
ram_resource(dev, idx++, 0, 640); /* first 640k */
/* Leave a hole for vga, 0xa0000 - 0xc0000 */
ram_resource(dev, idx++, 768, (tolmk - 768));
}
assign_resources(&dev->link[0]);
}
static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
{
printk_debug("Entering vx800 pci_domain_scan_bus.\n");
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
return max;
}
static const struct device_operations pci_domain_ops = {
.read_resources = pci_domain_read_resources,
.set_resources = pci_domain_set_resources,
.enable_resources = enable_childrens_resources,
.init = 0,
.scan_bus = pci_domain_scan_bus,
};
static void cpu_bus_init(device_t dev)
{
initialize_cpus(&dev->link[0]);
}
static void cpu_bus_noop(device_t dev)
{
}
static const struct device_operations cpu_bus_ops = {
.read_resources = cpu_bus_noop,
.set_resources = cpu_bus_noop,
.enable_resources = cpu_bus_noop,
.init = cpu_bus_init,
.scan_bus = 0,
};
static void enable_dev(struct device *dev)
{
printk_spew("In VX800 enable_dev for device %s.\n", dev_path(dev));
/* Set the operations if it is a special bus type */
if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
dev->ops = &pci_domain_ops;
pci_set_method(dev);
} else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
dev->ops = &cpu_bus_ops;
}
}
struct chip_operations northbridge_via_vx800_ops = {
CHIP_NAME("VIA VX800 Chipset")
.enable_dev = enable_dev,
};

View File

@ -0,0 +1,25 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NORTHBRIDGE_VIA_VX800_H
#define NORTHBRIDGE_VIA_VX800_H
extern unsigned int vx800_scan_root_bus(device_t root, unsigned int max);
#endif /* NORTHBRIDGE_VIA_VX800_H */

View File

@ -0,0 +1,74 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <spd.h>
#include <sdram_mode.h>
#include <delay.h>
#include <arch/pci_rawops.h>
#define DEBUG_RAM_SETUP 1
#ifdef DEBUG_RAM_SETUP
#define PRINT_DEBUG_MEM(x) print_debug(x)
#define PRINT_DEBUG_MEM_HEX8(x) print_debug_hex8(x)
#define PRINT_DEBUG_MEM_HEX16(x) print_debug_hex16(x)
#define PRINT_DEBUG_MEM_HEX32(x) print_debug_hex32(x)
#define DUMPNORTH() dump_pci_device(PCI_DEV(0, 0, 0))
#else
#define PRINT_DEBUG_MEM(x)
#define PRINT_DEBUG_MEM_HEX8(x)
#define PRINT_DEBUG_MEM_HEX16(x)
#define PRINT_DEBUG_MEM_HEX32(x)
#define DUMPNORTH()
#endif
#include "northbridge/via/vx800/ddr2init/Translatorddr2init.c"
#include "northbridge/via/vx800/ddr2init/DramInit.h"
#include "northbridge/via/vx800/vx800_early_smbus.c"
#include "northbridge/via/vx800/vx800_early_serial.c"
#include "northbridge/via/vx800/ddr2init/DramUtil.h"
#include "northbridge/via/vx800/ddr2init/DramUtil.c"
#include "northbridge/via/vx800/ddr2init/vx800/Detection.c"
#include "northbridge/via/vx800/ddr2init/vx800/FreqSetting.c"
#include "northbridge/via/vx800/ddr2init/vx800/TimingSetting.c"
#include "northbridge/via/vx800/ddr2init/vx800/DRDY_BL.c"
#include "northbridge/via/vx800/ddr2init/vx800/DrivingSetting.c"
#include "northbridge/via/vx800/ddr2init/vx800/ClkCtrl.c"
#include "northbridge/via/vx800/ddr2init/vx800/DevInit.c"
#include "northbridge/via/vx800/ddr2init/vx800/RankMap.c"
#include "northbridge/via/vx800/ddr2init/vx800/DQSSearch.c"
#include "northbridge/via/vx800/ddr2init/vx800/FinalSetting.c"
#include "northbridge/via/vx800/ddr2init/vx800/UMARamSetting.c"
#include "northbridge/via/vx800/ddr2init/DramInit.c"
/*
* Support one dimm with up to 2 ranks
*/
static void ddr2_ram_setup()
{
u8 Data;
CB_STATUS Status;
PRINT_DEBUG_MEM("In ddr2_ram_setup\r");
Status = DDR2_DRAM_INIT();
if (CB_SUCCESS != Status) {
PRINT_DEBUG_MEM("Dram init error. Status = %x\r");
}
}

View File

@ -0,0 +1,24 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef RAMINIT_H
#define RAMINIT_H
#define MEMCTRL PCI_DEV(0,0,3)
#endif /* RAMINIT_H */

View File

@ -0,0 +1,51 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2004 Tyan Computer
* (Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer)
* Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* This file constructs the ROM strap table for K8T890 and K8M890 */
.section ".romstrap", "a", @progbits
.globl __romstrap_start
__romstrap_start:
tblpointer:
.long 0x55aa66cc
.long 0x88012554
.long 0x77107777
.long 0x00770814
.long 0x00000000
.long 0x00000000
.long 0x00000000
.long 0x00000000
/*
* The pointer to above table should be at 0xffffffd0,
* the table itself MUST be aligned to 128B it seems!
*/
rspointers:
.long tblpointer // It will be 0xffffffd0
.globl __romstrap_end
__romstrap_end:
.previous

View File

@ -0,0 +1,26 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007 AMD
* (Written by Yinghai Lu <yinghai.lu@amd.com> for AMD)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
SECTIONS {
. = (_ROMBASE + ROM_IMAGE_SIZE - 0x2c) - (__romstrap_end - __romstrap_start);
.romstrap (.): {
*(.romstrap)
}
}

View File

@ -0,0 +1,148 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* Note: Some of the VGA control registers are located on the memory controller.
Registers are set both in raminit.c and northbridge.c */
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include <cpu/cpu.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/msr.h>
#include "chip.h"
#include "northbridge.h"
#include "vgachip.h"
/* PCI Domain 1 Device 0 Function 0 */
#define SR_INDEX 0x3c4
#define SR_DATA 0x3c5
#define CRTM_INDEX 0x3b4
#define CRTM_DATA 0x3b5
#define CRTC_INDEX 0x3d4
#define CRTC_DATA 0x3d5
void write_protect_vgabios(void)
{
device_t dev;
printk_info("write_protect_vgabios\n");
/* there are two possible devices. Just do both. */
dev =
dev_find_device(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_VX855_MEMCTRL, 0);
if (dev)
pci_write_config8(dev, 0x80, 0xff);
/*vx855 no th 0x61 reg */
/*dev = dev_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_NB_VLINK, 0);
//if(dev)
// pci_write_config8(dev, 0x61, 0xff); */
}
extern u8 acpi_sleep_type;
static void vga_init(device_t dev)
{
uint8_t reg8;
print_debug("Initiailizing VGA...\n");
u8 tmp8;
//A20 OPEN
tmp8 = inb(0x92);
tmp8 = tmp8 | 2;
outb(tmp8, 0x92);
//*
//pci_write_config8(dev, 0x04, 0x07);
//pci_write_config32(dev,0x10, 0xa0000008);
//pci_write_config32(dev,0x14, 0xdd000000);
pci_write_config32(dev, 0x10, VIACONFIG_VGA_PCI_10);
pci_write_config32(dev, 0x14, VIACONFIG_VGA_PCI_14);
pci_write_config8(dev, 0x3c, 0x0a); //same with vx855_lpc.c
//*/
printk_emerg("file '%s', line %d\n\n", __FILE__, __LINE__);
#if 1
printk_debug("INSTALL REAL-MODE IDT\n");
setup_realmode_idt();
printk_debug("DO THE VGA BIOS\n");
do_vgabios();
if ((acpi_sleep_type == 3) || (PAYLOAD_IS_SEABIOS == 0)) {
printk_debug("Enable VGA console\n");
// remove this function since in cn700 it is said "VGA seems to work without this, but crash & burn with it"
//but the existense of vga_enable_console() seems do not hurt my coreboot. XP+ubuntu s3 can resume with and without this function.
//and remove it also do not help my s3 problem: desktop screen have some thin black line, after resuming back to win.
vga_enable_console();
}
#else
/* Attempt to manually force the rom to load */
printk_debug("Forcing rom load\r\n");
pci_rom_load(dev, 0xfff80000);
run_bios(dev, 0xc0000);
#endif
if ((acpi_sleep_type == 3) || (PAYLOAD_IS_SEABIOS == 0)) {
/* It's not clear if these need to be programmed before or after
* the VGA bios runs. Try both, clean up later */
/* Set memory rate to 200MHz */
outb(0x3d, CRTM_INDEX);
reg8 = inb(CRTM_DATA);
reg8 &= 0x0f;
reg8 |= (0x3 << 4);
outb(0x3d, CRTM_INDEX);
outb(reg8, CRTM_DATA);
/* Set framebuffer size to CONFIG_VIDEO_MB mb */
/*reg8 = (CONFIG_VIDEO_MB/4);
outb(0x39, SR_INDEX);
outb(reg8, SR_DATA); */
}
printk_emerg("file '%s', line %d\n\n", __FILE__, __LINE__);
}
static void vga_read_resources(device_t dev)
{
dev->rom_address = (void *) (0xffffffff - FULL_ROM_SIZE + 1);
dev->on_mainboard = 1;
pci_dev_read_resources(dev);
}
static struct device_operations vga_operations = {
.read_resources = vga_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = vga_init,
.ops_pci = 0,
};
static const struct pci_driver vga_driver __pci_driver = {
.ops = &vga_operations,
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_DEVICE_ID_VIA_VX855_VGA,
};

View File

@ -0,0 +1,862 @@
#include <console/console.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#undef __KERNEL__
#include <arch/io.h>
#include <string.h>
#include "vgachip.h"
/* vgabios.c. Derived from: */
/*------------------------------------------------------------ -*- C -*-
* 2 Kernel Monte a.k.a. Linux loading Linux on x86
*
* Erik Arjan Hendriks <hendriks@lanl.gov>
*
* This version is a derivative of the original two kernel monte
* which is (C) 2000 Scyld.
*
* Copyright (C) 2000 Scyld Computing Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Portions related to the alpha architecture are:
*
* Copyright(C) 2001 University of California. LA-CC Number 01-67.
* This software has been authored by an employee or employees of the
* University of California, operator of the Los Alamos National
* Laboratory under Contract No. W-7405-ENG-36 with the U.S.
* Department of Energy. The U.S. Government has rights to use,
* reproduce, and distribute this software. If the software is
* modified to produce derivative works, such modified software should
* be clearly marked, so as not to confuse it with the version
* available from LANL.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by
* reference to http://www.gnu.org/licenses/gpl.html.
*
* This software is provided by the author(s) "as is" and any express
* or implied warranties, including, but not limited to, the implied
* warranties of merchantability and fitness for a particular purpose
* are disclaimed. In no event shall the author(s) be liable for any
* direct, indirect, incidental, special, exemplary, or consequential
* damages (including, but not limited to, procurement of substitute
* goods or services; loss of use, data, or profits; or business
* interruption) however caused and on any theory of liability,
* whether in contract, strict liability, or tort (including
* negligence or otherwise) arising in any way out of the use of this
* software, even if advised of the possibility of such damage.
*
* $Id: vgabios.c,v 1.5 2004/10/06 17:33:52 rminnich Exp $
*--------------------------------------------------------------------*/
/* Modified to be a self sufficient plug in so that it can be used
without reliance on other parts of coreboot's core
(C) 2005 Nick.Barker9@btinternet.com
Used initially for epia-m where there are problems getting the bios
emulator to successfully run this bios.
*/
/* Declare a temporary global descriptor table - necessary because the
Core part of the bios no longer sets up any 16 bit segments */
__asm__(
/* pointer to original gdt */
"gdtarg: \n"
" .word gdt_limit \n"
" .long gdt \n"
/* compute the table limit */
"__mygdt_limit = __mygdt_end - __mygdt - 1 \n"
"__mygdtaddr: \n"
" .word __mygdt_limit \n"
" .long __mygdt \n"
"__mygdt: \n"
/* selgdt 0, unused */
" .word 0x0000, 0x0000 \n"
" .byte 0x00, 0x00, 0x00, 0x00 \n"
/* selgdt 8, unused */
" .word 0x0000, 0x0000 \n"
" .byte 0x00, 0x00, 0x00, 0x00 \n"
/* selgdt 0x10, flat code segment */
" .word 0xffff, 0x0000 \n"
" .byte 0x00, 0x9b, 0xcf, 0x00 \n"
/* selgdt 0x18, flat data segment */
" .word 0xffff, 0x0000 \n"
" .byte 0x00, 0x93, 0xcf, 0x00 \n"
/* selgdt 0x20, unused */
" .word 0x0000, 0x0000 \n"
" .byte 0x00, 0x00, 0x00, 0x00 \n"
/* selgdt 0x28 16-bit 64k code at 0x00000000 */
" .word 0xffff, 0x0000 \n"
" .byte 0, 0x9a, 0, 0 \n"
/* selgdt 0x30 16-bit 64k data at 0x00000000 */
" .word 0xffff, 0x0000 \n"
" .byte 0, 0x92, 0, 0 \n"
"__mygdt_end: \n");
/* Declare a pointer to where our idt is going to be i.e. at mem zero */
__asm__("__myidt: \n"
/* 16-bit limit */
" .word 1023 \n"
/* 24-bit base */
" .long 0 \n" " .word 0 \n");
/* The address arguments to this function are PHYSICAL ADDRESSES */
extern u8 acpi_sleep_type;
static void real_mode_switch_call_vga(unsigned long devfn)
{
if ((acpi_sleep_type == 0) && (PAYLOAD_IS_SEABIOS == 1))
return;
__asm__ __volatile__(
// paranoia -- does ecx get saved? not sure. This is
// the easiest safe thing to do.
" pushal \n"
/* save the stack */
" mov %esp, __stack \n"
" jmp 1f \n"
"__stack: .long 0 \n" "1:\n"
/* get devfn into %ecx */
" movl %esp, %ebp \n"
" movl 8(%ebp), %ecx \n"
/* load 'our' gdt */
" lgdt %cs:__mygdtaddr \n"
/* This configures CS properly for real mode. */
" ljmp $0x28, $__rms_16bit\n"
"__rms_16bit: \n"
" .code16 \n"
/* 16 bit code from here on... */
/* Load the segment registers w/ properly configured segment
* descriptors. They will retain these configurations (limits,
* writability, etc.) once protected mode is turned off. */
" mov $0x30, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* Turn off protection (bit 0 in CR0) */
" movl %cr0, %eax \n"
" andl $0xFFFFFFFE, %eax \n"
" movl %eax, %cr0 \n"
/* Now really going into real mode */
" ljmp $0, $__rms_real\n"
"__rms_real: \n"
/* put the stack at the end of page zero.
* that way we can easily share it between real and protected,
* since the 16-bit ESP at segment 0 will work for any case.
/* Setup a stack */
" mov $0x0, %ax \n"
" mov %ax, %ss \n"
" movl $0x1000, %eax \n"
" movl %eax, %esp \n"
/* Load our 16 it idt */
" xor %ax, %ax \n"
" mov %ax, %ds \n"
" lidt __myidt \n"
/* Dump zeros in the other segregs */
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov $0x40, %ax \n"
" mov %ax, %ds \n"
" mov %cx, %ax \n"
/* run VGA BIOS at 0xc000:0003 */
" lcall $0xc000, $0x0003\n"
/* if we got here, just about done.
* Need to get back to protected mode */
" movl %cr0, %eax \n" " orl $0x0000001, %eax\n" /* PE = 1 */
" movl %eax, %cr0 \n"
/* Now that we are in protected mode jump to a 32 bit code segment. */
" data32 ljmp $0x10, $vgarestart\n"
"vgarestart:\n"
" .code32\n"
" movw $0x18, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* restore proper gdt and idt */
" lgdt %cs:gdtarg \n"
" lidt idtarg \n"
".globl vga_exit \n"
"vga_exit: \n"
" mov __stack, %esp \n"
" popal \n");
}
__asm__(".text\n" "real_mode_switch_end:\n");
extern char real_mode_switch_end[];
/* call vga bios int 10 function 0x4f14 to enable main console
epia-m does not always autosence the main console so forcing it on is good !! */
void vga_enable_console()
{
if ((acpi_sleep_type == 0) && (PAYLOAD_IS_SEABIOS == 1))
return;
__asm__ __volatile__(
/* paranoia -- does ecx get saved? not sure. This is
* the easiest safe thing to do. */
" pushal \n"
/* save the stack */
" mov %esp, __stack \n"
/* load 'our' gdt */
" lgdt %cs:__mygdtaddr \n"
/* This configures CS properly for real mode. */
" ljmp $0x28, $__vga_ec_16bit\n"
"__vga_ec_16bit: \n"
" .code16 \n"
/* 16 bit code from here on... */
/* Load the segment registers w/ properly configured segment
* descriptors. They will retain these configurations (limits,
* writability, etc.) once protected mode is turned off. */
" mov $0x30, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* Turn off protection (bit 0 in CR0) */
" movl %cr0, %eax \n"
" andl $0xFFFFFFFE, %eax\n"
" movl %eax, %cr0 \n"
/* Now really going into real mode */
" ljmp $0, $__vga_ec_real \n"
"__vga_ec_real: \n"
/* put the stack at the end of page zero.
* that way we can easily share it between real and protected,
* since the 16-bit ESP at segment 0 will work for any case.
/* Setup a stack */
" mov $0x0, %ax \n"
" mov %ax, %ss \n"
" movl $0x1000, %eax \n"
" movl %eax, %esp \n"
/* debugging for RGM */
" mov $0x11, %al \n"
" outb %al, $0x80 \n"
/* Load our 16 it idt */
" xor %ax, %ax \n"
" mov %ax, %ds \n"
" lidt __myidt \n"
/* Dump zeros in the other segregs */
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
/* ask bios to enable main console */
/* set up for int 10 call - values found from X server
* bios call routines */
" movw $0x4f14,%ax \n"
" movw $0x8003,%bx \n"
" movw $1, %cx \n"
" movw $0, %dx \n"
" movw $0, %di \n"
" int $0x10 \n"
" movb $0x55, %al \n"
" outb %al, $0x80 \n"
/* if we got here, just about done.
* Need to get back to protected mode */
" movl %cr0, %eax \n" " orl $0x0000001, %eax\n" /* PE = 1 */
" movl %eax, %cr0 \n"
/* Now that we are in protected mode jump to a 32 bit code segment. */
" data32 ljmp $0x10, $vga_ec_restart\n"
"vga_ec_restart:\n"
" .code32\n"
" movw $0x18, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* restore proper gdt and idt */
" lgdt %cs:gdtarg \n"
" lidt idtarg \n"
" .globl vga__ec_exit \n"
"vga_ec_exit:\n"
" mov __stack, %esp \n"
" popal\n");
}
void do_vgabios(void)
{
device_t dev;
unsigned long busdevfn;
unsigned int rom = 0;
unsigned char *buf;
unsigned int size = 64 * 1024;
int i;
u16 tmp;
u8 tmp8;
printk_emerg("file '%s', line %d\n\n", __FILE__, __LINE__);
/* clear vga bios data area */
for (i = 0x400; i < 0x500; i++) {
*(unsigned char *) i = 0;
}
dev = dev_find_class(PCI_CLASS_DISPLAY_VGA << 8, 0);
if (!dev) {
printk_debug("NO VGA FOUND\n");
return;
}
printk_debug("found VGA: vid=%x, did=%x\n", dev->vendor,
dev->device);
/* declare rom address here - keep any config data out of the way
* of core LXB stuff */
rom = 0xffffffff - FULL_ROM_SIZE + 1;
pci_write_config32(dev, PCI_ROM_ADDRESS, rom | 1);
printk_debug("rom base: %x\n", rom);
buf = (unsigned char *) rom;
printk_emerg("file '%s', line %d\n\n", __FILE__, __LINE__);
if ((buf[0] == 0x55) && (buf[1] == 0xaa)) {
memcpy((void *) 0xc0000, buf, size);
printk_emerg("file '%s', line %d\n\n", __FILE__, __LINE__);
write_protect_vgabios(); // in northbridge
// check signature again
buf = (unsigned char *) 0xc0000;
if (buf[0] == 0x55 && buf[1] == 0xAA) {
busdevfn =
(dev->bus->secondary << 8) | dev->path.pci.
devfn;
printk_debug("bus/devfn = %#x\n", busdevfn);
real_mode_switch_call_vga(busdevfn);
} else
printk_debug
("Failed to copy VGA BIOS to 0xc0000\n");
} else
printk_debug("BAD SIGNATURE 0x%x 0x%x\n", buf[0], buf[1]);
printk_emerg("file '%s', line %d\n\n", __FILE__, __LINE__);
pci_write_config32(dev, PCI_ROM_ADDRESS, 0);
}
// we had hoped to avoid this.
// this is a stub IDT only. It's main purpose is to ignore calls
// to the BIOS.
// no longer. Dammit. We have to respond to these.
struct realidt {
unsigned short offset, cs;
};
// from a handy writeup that andrey found.
// handler.
// There are some assumptions we can make here.
// First, the Top Of Stack (TOS) is located on the top of page zero.
// we can share this stack between real and protected mode.
// that simplifies a lot of things ...
// we'll just push all the registers on the stack as longwords,
// and pop to protected mode.
// second, since this only ever runs as part of coreboot,
// we know all the segment register values -- so we don't save any.
// keep the handler that calls things small. It can do a call to
// more complex code in coreboot itself. This helps a lot as we don't
// have to do address fixup in this little stub, and calls are absolute
// so the handler is relocatable.
void handler(void)
{
__asm__ __volatile__(" .code16 \n"
"idthandle: \n"
" pushal \n"
" movb $0, %al \n"
" ljmp $0, $callbiosint16\n"
"end_idthandle: \n"
" .code32 \n");
}
void debughandler(void)
{
__asm__ __volatile__(" .code16 \n"
"debughandle: \n"
" pushw %cx \n"
" movw $250, %cx \n"
"dbh1: \n"
" loop dbh1 \n"
" popw %cx \n"
" iret \n"
"end_debughandle: \n"
".code32 \n");
}
// Calling conventions. The first C function is called with this stuff
// on the stack. They look like value parameters, but note that if you
// modify them they will go back to the INTx function modified.
// the C function will call the biosint function with these as
// REFERENCE parameters. In this way, we can easily get
// returns back to the INTx caller (i.e. vgabios)
void callbiosint(void)
{
__asm__ __volatile__(" .code16 \n"
"callbiosint16: \n"
" push %ds \n"
" push %es \n"
" push %fs \n" " push %gs \n"
// clean up the int #. To save space we put it in the lower
// byte. But the top 24 bits are junk.
" andl $0xff, %eax\n"
// this push does two things:
// - put the INT # on the stack as a parameter
// - provides us with a temp for the %cr0 mods.
" pushl %eax \n" " movl %cr0, %eax\n" " orl $0x00000001, %eax\n" /* PE = 1 */
" movl %eax, %cr0\n"
/* Now that we are in protected mode jump to a 32 bit code segment. */
" data32 ljmp $0x10, $biosprotect\n"
"biosprotect: \n"
" .code32 \n"
" movw $0x18, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
" lidt idtarg \n"
" call biosint \n"
// back to real mode ...
" ljmp $0x28, $__rms_16bit2\n"
"__rms_16bit2: \n"
" .code16 \n"
/* 16 bit code from here on... */
/* Load the segment registers w/ properly configured segment
* descriptors. They will retain these configurations (limits,
* writability, etc.) once protected mode is turned off. */
" mov $0x30, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* Turn off protection (bit 0 in CR0) */
" movl %cr0, %eax \n"
" andl $0xFFFFFFFE, %eax \n"
" movl %eax, %cr0 \n"
/* Now really going into real mode */
" ljmp $0, $__rms_real2 \n"
"__rms_real2: \n"
/* Setup a stack
* FixME: where is esp? */
" mov $0x0, %ax \n"
" mov %ax, %ss \n"
/* ebugging for RGM */
" mov $0x11, %al \n"
" outb %al, $0x80 \n"
/* Load our 16 it idt */
" xor %ax, %ax \n"
" mov %ax, %ds \n"
" lidt __myidt \n"
/* Dump zeros in the other segregs */
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov $0x40, %ax \n"
" mov %ax, %ds \n"
/* pop the INT # that you pushed earlier */
" popl %eax \n"
" pop %gs \n"
" pop %fs \n"
" pop %es \n"
" pop %ds \n"
" popal \n"
" iret \n"
" .code32 \n");
}
enum {
PCIBIOS = 0x1a,
MEMSIZE = 0x12
};
int pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
unsigned long *pecx, unsigned long *peax,
unsigned long *pflags);
int handleint21(unsigned long *pedi, unsigned long *pesi,
unsigned long *pebp, unsigned long *pesp,
unsigned long *pebx, unsigned long *pedx,
unsigned long *pecx, unsigned long *peax,
unsigned long *pflags);
extern void vga_exit(void);
int biosint(unsigned long intnumber,
unsigned long gsfs, unsigned long dses,
unsigned long edi, unsigned long esi,
unsigned long ebp, unsigned long esp,
unsigned long ebx, unsigned long edx,
unsigned long ecx, unsigned long eax,
unsigned long cs_ip, unsigned short stackflags)
{
unsigned long ip;
unsigned long cs;
unsigned long flags;
int ret = -1;
ip = cs_ip & 0xffff;
cs = cs_ip >> 16;
flags = stackflags;
printk_debug("biosint: INT# 0x%lx\n", intnumber);
printk_debug("biosint: eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n",
eax, ebx, ecx, edx);
printk_debug("biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n",
ebp, esp, edi, esi);
printk_debug("biosint: ip 0x%x cs 0x%x flags 0x%x\n",
ip, cs, flags);
// cases in a good compiler are just as good as your own tables.
switch (intnumber) {
case 0...15:
// These are not BIOS service, but the CPU-generated exceptions
printk_info("biosint: Oops, exception %u\n", intnumber);
if (esp < 0x1000) {
printk_debug("Stack contents: ");
while (esp < 0x1000) {
printk_debug("0x%04x ",
*(unsigned short *) esp);
esp += 2;
}
printk_debug("\n");
}
printk_debug("biosint: Bailing out\n");
// "longjmp"
if ((acpi_sleep_type == 3) || (PAYLOAD_IS_SEABIOS == 0)) // add this to keep same with kevin's seabios patch in 2008-9-8
vga_exit();
break;
case PCIBIOS:
ret = pcibios(&edi, &esi, &ebp, &esp,
&ebx, &edx, &ecx, &eax, &flags);
break;
case MEMSIZE:
// who cares.
eax = 64 * 1024;
ret = 0;
break;
case 0x15:
ret = handleint21(&edi, &esi, &ebp, &esp,
&ebx, &edx, &ecx, &eax, &flags);
break;
default:
printk_info("BIOSINT: Unsupport int #0x%x\n", intnumber);
break;
}
if (ret)
flags |= 1; // carry flags
else
flags &= ~1;
stackflags = flags;
return ret;
}
void setup_realmode_idt(void)
{
extern unsigned char idthandle, end_idthandle;
extern unsigned char debughandle, end_debughandle;
int i;
struct realidt *idts = (struct realidt *) 0;
int codesize = &end_idthandle - &idthandle;
unsigned char *intbyte, *codeptr;
// for each int, we create a customized little handler
// that just pushes %ax, puts the int # in %al,
// then calls the common interrupt handler.
// this necessitated because intel didn't know much about
// architecture when they did the 8086 (it shows)
// (hmm do they know anymore even now :-)
// obviously you can see I don't really care about memory
// efficiency. If I did I would probe back through the stack
// and get it that way. But that's really disgusting.
for (i = 0; i < 256; i++) {
idts[i].cs = 0;
codeptr = (char *) 4096 + i * codesize;
idts[i].offset = (unsigned) codeptr;
memcpy(codeptr, &idthandle, codesize);
intbyte = codeptr + 3;
*intbyte = i;
}
// fixed entry points
// VGA BIOSes tend to hardcode f000:f065 as the previous handler of
// int10.
// calling convention here is the same as INTs, we can reuse
// the int entry code.
codeptr = (char *) 0xff065;
memcpy(codeptr, &idthandle, codesize);
intbyte = codeptr + 3;
*intbyte = 0x42; /* int42 is the relocated int10 */
/*
Fixed entry points
VBIOS will call f000:f859 instead of sending int15.
calling convertion here is the same as INTs, we can reuse the int entry code.
*/
codeptr = (char *) 0xff859;
memcpy(codeptr, &idthandle, codesize);
intbyte = codeptr + 3;
*intbyte = 0x15;
/* debug handler - useful to set a programmable delay between instructions if the
TF bit is set upon call to real mode */
idts[1].cs = 0;
idts[1].offset = 16384;
memcpy(16384, &debughandle, &end_debughandle - &debughandle);
}
enum {
CHECK = 0xb001,
FINDDEV = 0xb102,
READCONFBYTE = 0xb108,
READCONFWORD = 0xb109,
READCONFDWORD = 0xb10a,
WRITECONFBYTE = 0xb10b,
WRITECONFWORD = 0xb10c,
WRITECONFDWORD = 0xb10d
};
// errors go in AH. Just set these up so that word assigns
// will work. KISS.
enum {
PCIBIOS_NODEV = 0x8600,
PCIBIOS_BADREG = 0x8700
};
int
pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
unsigned long *pecx, unsigned long *peax, unsigned long *pflags)
{
unsigned long edi = *pedi;
unsigned long esi = *pesi;
unsigned long ebp = *pebp;
unsigned long esp = *pesp;
unsigned long ebx = *pebx;
unsigned long edx = *pedx;
unsigned long ecx = *pecx;
unsigned long eax = *peax;
unsigned long flags = *pflags;
unsigned short func = (unsigned short) eax;
int retval = 0;
unsigned short devid, vendorid, devfn;
short devindex; /* Use short to get rid of garbage in upper half of 32-bit register */
unsigned char bus;
device_t dev;
switch (func) {
case CHECK:
*pedx = 0x4350;
*pecx = 0x2049;
retval = 0;
break;
case FINDDEV:
{
devid = *pecx;
vendorid = *pedx;
devindex = *pesi;
dev = 0;
while ((dev =
dev_find_device(vendorid, devid, dev))) {
if (devindex <= 0)
break;
devindex--;
}
if (dev) {
unsigned short busdevfn;
*peax = 0;
// busnum is an unsigned char;
// devfn is an int, so we mask it off.
busdevfn = (dev->bus->secondary << 8)
| (dev->path.pci.devfn & 0xff);
printk_debug("0x%x: return 0x%x\n", func,
busdevfn);
*pebx = busdevfn;
retval = 0;
} else {
*peax = PCIBIOS_NODEV;
retval = -1;
}
}
break;
case READCONFDWORD:
case READCONFWORD:
case READCONFBYTE:
case WRITECONFDWORD:
case WRITECONFWORD:
case WRITECONFBYTE:
{
unsigned long dword;
unsigned short word;
unsigned char byte;
unsigned char reg;
devfn = *pebx & 0xff;
bus = *pebx >> 8;
reg = *pedi;
dev = dev_find_slot(bus, devfn);
if (!dev) {
printk_debug
("0x%x: BAD DEVICE bus %d devfn 0x%x\n",
func, bus, devfn);
// idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
*peax = PCIBIOS_BADREG;
retval = -1;
}
switch (func) {
case READCONFBYTE:
byte = pci_read_config8(dev, reg);
*pecx = byte;
break;
case READCONFWORD:
word = pci_read_config16(dev, reg);
*pecx = word;
break;
case READCONFDWORD:
dword = pci_read_config32(dev, reg);
*pecx = dword;
break;
case WRITECONFBYTE:
byte = *pecx;
pci_write_config8(dev, reg, byte);
break;
case WRITECONFWORD:
word = *pecx;
pci_write_config16(dev, reg, word);
break;
case WRITECONFDWORD:
dword = *pecx;
pci_write_config32(dev, reg, dword);
break;
}
if (retval)
retval = PCIBIOS_BADREG;
printk_debug
("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n",
func, bus, devfn, reg, *pecx);
*peax = 0;
retval = 0;
}
break;
default:
printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
break;
}
return retval;
}
/* return value of int0x15(int21)
AH AL Completion status
?? 5Fh Function call supported
?? !=5Fh Function not supported
00 5Fh Function call successful
01 5Fh Function call failed
*/
int handleint21(unsigned long *edi, unsigned long *esi, unsigned long *ebp,
unsigned long *esp, unsigned long *ebx, unsigned long *edx,
unsigned long *ecx, unsigned long *eax,
unsigned long *flags)
{
int res = -1;
switch (*eax & 0xffff) {
case 0x5f19:
*eax = 0x5f;
*ecx = 0x3;
res = 0;
break;
case 0x5f18:
{
/*
BL
Bit[7:4]
Memory Data Rate
0000: 66MHz
0001: 100MHz
0010: 133MHz
0011: 200MHz ( DDR200 )
0100: 266MHz ( DDR266 )
0101: 333MHz ( DDR333 )
0110: 400MHz ( DDR400 )
0111: 533MHz ( DDR I/II 533
1000: 667MHz ( DDR I/II 667)
Bit[3:0]
N: Frame Buffer Size 2^N MB
*/
u8 i;
device_t dev;
dev = dev_find_slot(0, PCI_DEVFN(0, 3));
i = pci_read_config8(dev, 0xa1);
i = (i & 0x70);
i = i >> 4;
if (i == 0) {
*eax = 0x00; //not support 5f18
break;
}
i = i + 2;
*ebx = (u32) i;
i = pci_read_config8(dev, 0x90);
i = (i & 0x07);
i = i + 3;
i = i << 4;
*ebx = (*ebx) + ((u32) i);
*eax = 0x5f;
res = 0;
break;
}
case 0x5f00:
*eax = 0x005f;
res = 0;
break;
case 0x5f01:
*eax = 0x5f;
*ecx = (*ecx & 0xffffff00) | 2; // panel type = 2 = 1024 * 768
res = 0;
break;
case 0x5f02:
*eax = 0x5f;
*ebx = (*ebx & 0xffff0000) | 2;
*ecx = (*ecx & 0xffff0000) | 0x401; // PAL + crt only
*edx = (*edx & 0xffff0000) | 0; // TV Layout - default
res = 0;
break;
case 0x5f0f:
*eax = 0x005f;
res = 0;
break;
default:
*eax = 0;
break;
}
return res;
}

View File

@ -0,0 +1,34 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Corey Osgood <corey.osgood@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PC80_VGABIOS
#define _PC80_VGABIOS
extern struct chip_control pc80_vgabios_control;
struct pc80_vgabios_config {
int nothing;
};
void vga_enable_console(void);
void do_vgabios(void);
void setup_realmode_idt(void);
void write_protect_vgabios(void);
#endif /* _PC80_VGABIOS */

View File

@ -0,0 +1,125 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef VX800_H
#define VX800_H 1
#ifndef __ROMCC__
static void vx800_noop(){}
#endif
#define REV_B0 0x10
#define REV_B1 0x11
#define REV_B2 0x12
#define REV_B3 0x13
#define REV_B4 0x14
#define REV_B2 0xB4
#define REV_B0 0x00
#define REV_B2 0x01
/* VGA stuff */
#define SR_INDEX 0x3c4
#define SR_DATA 0x3c5
#define CRTM_INDEX 0x3b4
#define CRTM_DATA 0x3b5
#define CRTC_INDEX 0x3d4
#define CRTC_DATA 0x3d5
/* Memory Controller Registers */
#define RANK0_END 0x40
#define RANK1_END 0x41
#define RANK2_END 0x42
#define RANK3_END 0x43
#define RANK0_START 0x48
#define RANK1_START 0x49
#define RANK2_START 0x4a
#define RANK3_START 0x4b
#define DDR_PAGE_CTL 0x69
#define DRAM_REFRESH_COUNTER 0x6a
#define DRAM_MISC_CTL 0x6b
#define CH_A_DQS_OUTPUT_DELAY 0x70
#define CH_A_MD_OUTPUT_DELAY 0x71
/* RAM Init Commands */
#define RAM_COMMAND_NORMAL 0x0
#define RAM_COMMAND_NOP 0x1
#define RAM_COMMAND_PRECHARGE 0x2
#define RAM_COMMAND_MRS 0x3
#define RAM_COMMAND_CBR 0x4
/* IDE specific bits */
#define IDE_MODE_REG 0x09
#define IDE0_NATIVE_MODE (1 << 0)
#define IDE1_NATIVE_MODE (1 << 2)
/* These are default addresses according to Via */
#define IDE0_DATA_ADDR 0x1f0
#define IDE0_CONTROL_ADDR 0x3f4
#define IDE1_DATA_ADDR 0x170
#define IDE1_CONTROL_ADDR 0x370
/* By Award default, Via default is 0xCC0 */
#define BUS_MASTER_ADDR 0xfe00
#define CHANNEL_ENABLE_REG 0x40
#define ENABLE_IDE0 (1 << 0)
#define ENABLE_IDE1 (1 << 1)
#define VX800_ACPI_IO_BASE 0x0400
#define NB_APIC_REG 0,0,5,
#define NB_PXPTRF_REG NB_APIC_REG
#define NB_MSGC_REG NB_APIC_REG
#define NB_HOST_REG 0,0,2,
#define NB_P6IF_REG NB_HOST_REG
#define NB_DRAMC_REG 0,0,3,
#define NB_PMU_REG 0,0,4,
#define NB_VLINK_REG 0,0,7,
#define NB_PEG_BRIDGE_REG 0,2, 0,
#define NB_D3F0_REG 0,3, 0,
#define NB_D3F1_REG 0,3, 1,
#define SB_LPC_REG 0,0x11,0,
#define SB_VLINK_REG 0,0x11,7,
#define SB_SATA_REG 0,0xf, 0,
#define SB_IDEC_REG 0,0xf, 0,
#define SB_P2PB_REG 0,0x13, 0,
#define SB_USB0_REG 0,0x10, 0,
#define SB_USB1_REG 0,0x10, 1,
#define SB_USB2_REG 0,0x10, 2,
#define SB_EHCI_REG 0,0x10, 4,
#define VX800SB_APIC_ID 0x4
#define VX800SB_APIC_BASE 0xfec00000ULL
#define VX800SB_APIC_DATA_OFFSET 0x10
#define VX800SB_APIC_ENTRY_NUMBER 0x40
#define VX800_D0F5_MMCONFIG_MBAR 0x61
#endif

View File

@ -0,0 +1,110 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Enable the serial devices on the VIA
*/
#include <arch/romcc_io.h>
/* The base address is 0x15c, 0x2e, depending on config bytes */
#define SIO_BASE 0x3f0
#define SIO_DATA SIO_BASE+1
static void vx800_writesuper(uint8_t reg, uint8_t val)
{
outb(reg, SIO_BASE);
outb(val, SIO_DATA);
}
static void vx800_writepnpaddr(uint8_t val)
{
outb(val, 0x2e);
outb(val, 0xeb);
}
static void vx800_writepnpdata(uint8_t val)
{
outb(val, 0x2f);
outb(val, 0xeb);
}
static void vx800_writesiobyte(uint16_t reg, uint8_t val)
{
outb(val, reg);
}
static void vx800_writesioword(uint16_t reg, uint16_t val)
{
outw(val, reg);
}
/* regs we use: 85, and the southbridge devfn is defined by the
mainboard
*/
static void enable_vx800_serial(void)
{
outb(6, 0x80);
outb(0x03, 0x22);
//pci_write_config8(PCI_DEV(0,17,0),0xb4,0x7e);
//pci_write_config8(PCI_DEV(0,17,0),0xb0,0x10);
// turn on pnp
vx800_writepnpaddr(0x87);
vx800_writepnpaddr(0x87);
// now go ahead and set up com1.
// set address
vx800_writepnpaddr(0x7);
vx800_writepnpdata(0x2);
// enable serial out
vx800_writepnpaddr(0x30);
vx800_writepnpdata(0x1);
// serial port 1 base address (FEh)
vx800_writepnpaddr(0x60);
vx800_writepnpdata(0xfe);
// serial port 1 IRQ (04h)
vx800_writepnpaddr(0x70);
vx800_writepnpdata(0x4);
// serial port 1 control
vx800_writepnpaddr(0xf0);
vx800_writepnpdata(0x2);
// turn of pnp
vx800_writepnpaddr(0xaa);
// set up reg to set baud rate.
vx800_writesiobyte(0x3fb, 0x80);
// Set 115 kb
vx800_writesioword(0x3f8, 1);
// Set 9.6 kb
// WRITESIOWORD(0x3f8, 12)
// now set no parity, one stop, 8 bits
vx800_writesiobyte(0x3fb, 3);
// now turn on RTS, DRT
vx800_writesiobyte(0x3fc, 3);
// Enable interrupts
vx800_writesiobyte(0x3f9, 0xf);
// should be done. Dump a char for fun.
vx800_writesiobyte(0x3f8, 48);
outb(7, 0x80);
}

View File

@ -0,0 +1,321 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <device/pci_ids.h>
#include "vx800.h"
#define SMBUS_IO_BASE 0x0500 //from award bios
#define PMIO_BASE VX800_ACPI_IO_BASE //might as well set this while we're here
#define SMBHSTSTAT SMBUS_IO_BASE + 0x0
#define SMBSLVSTAT SMBUS_IO_BASE + 0x1
#define SMBHSTCTL SMBUS_IO_BASE + 0x2
#define SMBHSTCMD SMBUS_IO_BASE + 0x3
#define SMBXMITADD SMBUS_IO_BASE + 0x4
#define SMBHSTDAT0 SMBUS_IO_BASE + 0x5
#define SMBHSTDAT1 SMBUS_IO_BASE + 0x6
/* Rest of these aren't currently used... */
#define SMBBLKDAT SMBUS_IO_BASE + 0x7
#define SMBSLVCTL SMBUS_IO_BASE + 0x8
#define SMBTRNSADD SMBUS_IO_BASE + 0x9
#define SMBSLVDATA SMBUS_IO_BASE + 0xa
#define SMLINK_PIN_CTL SMBUS_IO_BASE + 0xe
#define SMBUS_PIN_CTL SMBUS_IO_BASE + 0xf
/* Define register settings */
#define HOST_RESET 0xff
#define DIMM_BASE 0xa0 // 1010000 is base for DIMM in SMBus
#define READ_CMD 0x01 // 1 in the 0 bit of SMBHSTADD states to READ
#define SMBUS_TIMEOUT (100*1000*10)
#define I2C_TRANS_CMD 0x40
#define CLOCK_SLAVE_ADDRESS 0x69
#define SMBUS_DELAY() outb(0x80, 0x80)
/* Debugging macros. Only necessary if something isn't working right */
#define DEBUG_SMBUS 1
#ifdef DEBUG_SMBUS
#define PRINT_DEBUG(x) print_debug(x)
#define PRINT_DEBUG_HEX16(x) print_debug_hex16(x)
#else
#define PRINT_DEBUG(x)
#define PRINT_DEBUG_HEX16(x)
#endif
/* Internal functions */
static void smbus_print_error(unsigned char host_status_register, int loops)
{
// print_err("some i2c error\r\n");
/* Check if there actually was an error */
if ( host_status_register == 0x00 || host_status_register == 0x40 ||
host_status_register == 0x42) return;
print_err("smbus_error: ");
print_err_hex8(host_status_register);
print_err("\r\n");
if (loops >= SMBUS_TIMEOUT) {
print_err("SMBus Timout\r\n");
}
if (host_status_register & (1 << 4)) {
print_err("Interrup/SMI# was Failed Bus Transaction\r\n");
}
if (host_status_register & (1 << 3)) {
print_err("Bus Error\r\n");
}
if (host_status_register & (1 << 2)) {
print_err("Device Error\r\n");
}
if (host_status_register & (1 << 1)) {
/* This isn't a real error... */
print_debug("Interrupt/SMI# was Successful Completion\r\n");
}
if (host_status_register & (1 << 0)) {
print_err("Host Busy\r\n");
}
}
static void smbus_wait_until_ready(void)
{
int loops;
loops = 0;
/* Yes, this is a mess, but it's the easiest way to do it */
while(((inb(SMBHSTSTAT) & 1) == 1) && (loops <= SMBUS_TIMEOUT)) {
SMBUS_DELAY();
++loops;
}
smbus_print_error(inb(SMBHSTSTAT), loops);
}
static void smbus_reset(void)
{
outb(HOST_RESET, SMBHSTSTAT);
}
/* Public functions */
static unsigned int set_ics_data(unsigned char dev, int data, char len)
{
int i;
smbus_reset();
/* clear host data port */
outb(0x00, SMBHSTDAT0);
SMBUS_DELAY();
smbus_wait_until_ready();
/* read to reset block transfer counter */
inb(SMBHSTCTL);
/* fill blocktransfer array */
if (dev=0xd2) {
//char d2_data[] = {0x0d,0x00,0x3f,0xcd,0x7f,0xbf,0x1a,0x2a,0x01,0x0f,0x0b,0x00,0x8d,0x9b};
outb(0x0d,SMBBLKDAT);
outb(0x00,SMBBLKDAT);
outb(0x3f,SMBBLKDAT);
outb(0xcd,SMBBLKDAT);
outb(0x7f,SMBBLKDAT);
outb(0xbf,SMBBLKDAT);
outb(0x1a,SMBBLKDAT);
outb(0x2a,SMBBLKDAT);
outb(0x01,SMBBLKDAT);
outb(0x0f,SMBBLKDAT);
outb(0x0b,SMBBLKDAT);
outb(0x80,SMBBLKDAT);
outb(0x8d,SMBBLKDAT);
outb(0x9b,SMBBLKDAT);
} else {
//char d4_data[] = {0x08,0xff,0x3f,0x00,0x00,0xff,0xff,0xff,0xff};
outb(0x08,SMBBLKDAT);
outb(0xff,SMBBLKDAT);
outb(0x3f,SMBBLKDAT);
outb(0x00,SMBBLKDAT);
outb(0x00,SMBBLKDAT);
outb(0xff,SMBBLKDAT);
outb(0xff,SMBBLKDAT);
outb(0xff,SMBBLKDAT);
outb(0xff,SMBBLKDAT);
}
//for (i=0; i < len; i++)
// outb(data[i],SMBBLKDAT);
outb(dev, SMBXMITADD);
outb(0, SMBHSTCMD);
outb(len, SMBHSTDAT0);
outb(0x74, SMBHSTCTL);
SMBUS_DELAY();
smbus_wait_until_ready();
smbus_reset();
return 0;
}
static unsigned int get_spd_data(unsigned int dimm, unsigned int offset)
{
unsigned int val;
smbus_reset();
/* clear host data port */
outb(0x00, SMBHSTDAT0);
SMBUS_DELAY();
smbus_wait_until_ready();
/* Do some mathmatic magic */
dimm = (dimm << 1);
dimm &= 0x0E;
dimm |= 0xA0;
outb(dimm|0x1, SMBXMITADD);
outb(offset, SMBHSTCMD);
outb(0x48, SMBHSTCTL);
SMBUS_DELAY();
smbus_wait_until_ready();
val = inb(SMBHSTDAT0);
smbus_reset();
return val;
}
static void enable_smbus(void)
{
device_t dev;
dev = pci_locate_device(PCI_ID(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855_LPC), 0);
if (dev == PCI_DEV_INVALID) {
/* This won't display text if enable_smbus() is before serial init */
die("Power Managment Controller not found\r\n");
}
/* Set clock source */
pci_write_config8(dev, 0x94, 0x20);
/* Write SMBus IO base to 0xd0, and enable SMBus */
pci_write_config16(dev, 0xd0, SMBUS_IO_BASE | 1);
/* Set to Award value */
pci_write_config8(dev, 0xd2, 0x05);
/* Make it work for I/O ...*/
pci_write_config16(dev, 0x04, 0x0003);
/*
coreboot hangs at this two lines after os reboot(this even happen after I change os
reboot to cold reboot, this also interfere S3 wakeup)*/
/* Setup clock chips */
//set_ics_data(0xd2, 0, 14);
//set_ics_data(0xd4, 0, 9);
smbus_reset();
/* clear host data port */
outb(0x00, SMBHSTDAT0);
SMBUS_DELAY();
smbus_wait_until_ready();
}
/**
* A fixup for some systems that need time for the SMBus to "warm up". This is
* needed on some VT823x based systems, where the SMBus spurts out bad data for
* a short time after power on. This has been seen on the VIA Epia series and
* Jetway J7F2-series. It reads the ID byte from SMBus, looking for
* known-good data from a slot/address. Exits on either good data or a timeout.
*
* TODO: This should probably go into some global file, but one would need to
* be created just for it. If some other chip needs/wants it, we can
* worry about it then.
*
* @param ctrl The memory controller and SMBus addresses.
*/
void smbus_fixup(const struct mem_controller *ctrl)
{
int i, ram_slots, current_slot = 0;
u8 result = 0;
ram_slots = ARRAY_SIZE(ctrl->channel0);
if (!ram_slots) {
print_err("smbus_fixup() thinks there are no RAM slots!\r\n");
return;
}
PRINT_DEBUG("Waiting for SMBus to warm up");
/*
* Bad SPD data should be either 0 or 0xff, but YMMV. So we look for
* the ID bytes of SDRAM, DDR, DDR2, and DDR3 (and anything in between).
* VT8237R has only been seen on DDR and DDR2 based systems, so far.
*/
for (i = 0; (i < SMBUS_TIMEOUT && ((result < SPD_MEMORY_TYPE_SDRAM) ||
(result > SPD_MEMORY_TYPE_SDRAM_DDR3))); i++) {
if (current_slot > ram_slots)
current_slot = 0;
result = get_spd_data(ctrl->channel0[current_slot],
SPD_MEMORY_TYPE);
current_slot++;
PRINT_DEBUG(".");
}
if (i >= SMBUS_TIMEOUT)
print_err("SMBus timed out while warming up\r\n");
else
PRINT_DEBUG("Done\r\n");
}
/* Debugging Function */
#ifdef DEBUG_SMBUS
static void dump_spd_data(void)
{
int dimm, offset, regs;
unsigned int val;
for(dimm = 0; dimm < 8; dimm++)
{
print_debug("SPD Data for DIMM ");
print_debug_hex8(dimm);
print_debug("\r\n");
val = get_spd_data(dimm, 0);
if(val == 0xff)
{
regs = 256;
} else if(val == 0x80) {
regs = 128;
} else {
print_debug("No DIMM present\r\n");
regs = 0;
}
for(offset = 0; offset < regs; offset++)
{
print_debug(" Offset ");
print_debug_hex8(offset);
print_debug(" = 0x");
print_debug_hex8(get_spd_data(dimm, offset));
print_debug("\r\n");
}
}
}
#else
#define dump_spd_data()
#endif

View File

@ -0,0 +1,204 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ops.h>
#include <device/pci_ids.h>
#include <console/console.h>
#include "chip.h"
#include <arch/io.h>
#include "vx800.h"
static const idedevicepcitable[16 * 12] = {
//
/*0x02, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA8, 0xF0, 0x00, 0x00, 0xB6,
0x00, 0x00, 0x01, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0xC4, 0x06, 0x11, 0x09, 0xC4,
0x00, 0xC2, 0xF9, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
*/
//
0x02, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x99, 0x20, 0xf0, 0x00, 0x00, 0x20,
0x00, 0x00, 0x17, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0xC4, 0x06, 0x11, 0x09, 0xC4,
0x00, 0xc2, 0x09, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//legacybios xp pci value
/*0x02, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x20, 0x00, 0x00, 0x00, 0xb6,
0x00, 0x00, 0x16, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0xC4, 0x06, 0x11, 0x09, 0xC4,
0x00, 0x02, 0x09, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
*/
//rom legacybios on cn_8562b
/*
0x03, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x99, 0x20, 0x60, 0x00, 0x00, 0x20,
0x00, 0x00, 0x1E, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0xC4, 0x06, 0x11, 0x09, 0xC4,
0x00, 0x02, 0x09, 0x01, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
*/
//from egacybios on c7_8562b
/*0x03, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x5E, 0x20, 0x60, 0x00, 0x00, 0xB6,
0x00, 0x00, 0x1E, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x09, 0xC4, 0x06, 0x11, 0x09, 0xC4,
0x00, 0x02, 0x09, 0x01, 0x18, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x01, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, */
};
static void ide_init(struct device *dev)
{
uint8_t enables, Rx89, RxC0;
u8 i, data;
struct ATA_REG_INIT_TABLE *pEntry;
printk_info("ide_init\n");
#if 1
/*these 3 lines help to keep interl back door for DID VID SUBID untouched */
u16 data16_1, data16_2;
data16_1 = pci_read_config16(dev, 0xba);
data16_2 = pci_read_config16(dev, 0xbe);
for (i = 0; i < (16 * 12); i++) {
pci_write_config8(dev, 0x40 + i, idedevicepcitable[i]);
}
//pci_write_config8(dev, 0x0d, 0x20);
data = pci_read_config8(dev, 0x0d);
data &= 0x0f;
data |= 0x40;
pci_write_config8(dev, 0x0d, data);
//these 2 lines help to keep interl back door for DID VID SUBID untouched
pci_write_config16(dev, 0xba, data16_1);
pci_write_config16(dev, 0xbe, data16_2);
#endif
/* Force interrupts to use compat mode. */
pci_write_config8(dev, PCI_INTERRUPT_PIN, 0x0);
pci_write_config8(dev, PCI_INTERRUPT_LINE, 0xff);
#if 0
struct southbridge_via_vt8237r_config *sb =
(struct southbridge_via_vt8237r_config *) dev->chip_info;
u8 enables;
u32 cablesel;
pci_write_config16(dev, 0x04, 0x0007);
enables = pci_read_config8(dev, IDE_CS) & ~0x3;
enables |= 0x02;
pci_write_config8(dev, IDE_CS, enables);
enables = pci_read_config8(dev, IDE_CS);
printk_debug("Enables in reg 0x40 read back as 0x%x\n", enables);
/* Enable only compatibility mode. */
enables = pci_read_config8(dev, IDE_CONF_II);
enables &= ~0xc0;
pci_write_config8(dev, IDE_CONF_II, enables);
enables = pci_read_config8(dev, IDE_CONF_II);
printk_debug("Enables in reg 0x42 read back as 0x%x\n", enables);
/* Enable prefetch buffers. */
enables = pci_read_config8(dev, IDE_CONF_I);
enables |= 0xf0;
pci_write_config8(dev, IDE_CONF_I, enables);
/* Flush FIFOs at half. */
enables = pci_read_config8(dev, IDE_CONF_FIFO);
enables &= 0xf0;
enables |= (1 << 2) | (1 << 0);
pci_write_config8(dev, IDE_CONF_FIFO, enables);
/* PIO read prefetch counter, Bus Master IDE Status Reg. Read Retry. */
enables = pci_read_config8(dev, IDE_MISC_I);
enables &= 0xe2;
enables |= (1 << 4) | (1 << 3);
pci_write_config8(dev, IDE_MISC_I, enables);
/* Use memory read multiple, Memory-Write-and-Invalidate. */
enables = pci_read_config8(dev, IDE_MISC_II);
enables |= (1 << 2) | (1 << 3);
pci_write_config8(dev, IDE_MISC_II, enables);
/* Force interrupts to use compat mode. */
pci_write_config8(dev, PCI_INTERRUPT_PIN, 0x0);
pci_write_config8(dev, PCI_INTERRUPT_LINE, 0xff);
/* Cable guy... */
cablesel = pci_read_config32(dev, IDE_UDMA);
cablesel &= ~((1 << 28) | (1 << 20) | (1 << 12) | (1 << 4));
cablesel |= (sb->ide0_80pin_cable << 28) |
(sb->ide0_80pin_cable << 20) |
(sb->ide1_80pin_cable << 12) | (sb->ide1_80pin_cable << 4);
pci_write_config32(dev, IDE_UDMA, cablesel);
#endif
}
static struct device_operations ide_ops = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = ide_init,
.enable = 0,
.ops_pci = 0,
};
static struct pci_driver via_ide_driver __pci_driver = {
.ops = &ide_ops,
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_DEVICE_ID_VIA_VX855_IDE,
};

View File

@ -0,0 +1,384 @@
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2009 One Laptop per Child, Association, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ops.h>
#include <device/pci_ids.h>
#include <pc80/mc146818rtc.h>
#include <pc80/keyboard.h>
#include <pc80/i8259.h>
#include "vx800.h"
#include "chip.h"
static const unsigned char pciIrqs[4] = {0xa, 0x9, 0xb, 0xa};
static const unsigned char vgaPins[4] = { 'A', 'B', 'C', 'D' };//only INTA
static const unsigned char slotPins[4] = { 'A', 'A', 'A', 'A'};//all 4
static const unsigned char usbdevicePins[4] = { 'A', 'B', 'C', 'D' };//only INTA
static const unsigned char sdioPins[4] = { 'A', 'B', 'C', 'D' };//only INTA
static const unsigned char sd_ms_ctrl_Pins[4] = { 'B', 'C', 'D', 'A' };//only INTA
static const unsigned char ce_ata_nf_ctrl_Pins[4] = { 'C', 'C', 'D', 'A' };//only INTA
static const unsigned char idePins[4] = { 'B', 'C', 'D', 'A' };//only INTA
static const unsigned char usbPins[4] = { 'A', 'B', 'C', 'D' };//all 4
static const unsigned char hdacaudioPins[4] = { 'B', 'C', 'D', 'A' };//only INTA
static unsigned char *pin_to_irq(const unsigned char *pin)
{
static unsigned char Irqs[4];
int i;
for (i = 0 ; i < 4 ; i++)
Irqs[i] = pciIrqs[ pin[i] - 'A' ];
return Irqs;
}
static void pci_routing_fixup(struct device *dev)
{
printk_info("%s: dev is %p\n", __FUNCTION__, dev);
/* set up PCI IRQ routing */
pci_write_config8(dev, 0x55, pciIrqs[0] << 4);
pci_write_config8(dev, 0x56, pciIrqs[1] | (pciIrqs[2] << 4) );
pci_write_config8(dev, 0x57, pciIrqs[3] << 4);
/* VGA */
printk_info("setting vga\n");
pci_assign_irqs(0, 0x1, pin_to_irq(vgaPins));
/* PCI slot */
printk_info("setting pci slot\n");
pci_assign_irqs(0, 0x08, pin_to_irq(slotPins));
/* PCI slot */
printk_info("setting USB Device Controller\n");
pci_assign_irqs(0, 0x0b, pin_to_irq(usbdevicePins));
/* PCI slot */
printk_info("setting SDIO Controller\n");
pci_assign_irqs(0, 0x0c, pin_to_irq(sdioPins));
/* PCI slot */
printk_info("setting SD $ MS Controller\n");
pci_assign_irqs(0, 0x0d, pin_to_irq(sd_ms_ctrl_Pins));
/* PCI slot */
printk_info("setting CE-ATA NF Controller(Card Boot)\n");
pci_assign_irqs(0, 0x0e, pin_to_irq(ce_ata_nf_ctrl_Pins));
/* PCI slot */
printk_info("setting ide\n");
//pci_assign_irqs(0, 0x0f, pin_to_irq(idePins));
/* Standard usb components */
printk_info("setting usb1-2\n");
// pci_assign_irqs(0, 0x10, pin_to_irq(usbPins));
/* sound hardware */
printk_info("setting hdac audio\n");
pci_assign_irqs(0, 0x14, pin_to_irq(hdacaudioPins));
printk_spew("%s: DONE\n", __FUNCTION__);
}
void setup_pm(device_t dev)
{
u16 tmp;
/* Debounce LID and PWRBTN# Inputs for 16ms. */
pci_write_config8(dev, 0x80, 0x20);
/* Set ACPI base address to IO VX800_ACPI_IO_BASE */
pci_write_config16(dev, 0x88, VX800_ACPI_IO_BASE|1);
/* set ACPI irq to 9 */
pci_write_config8(dev, 0x82, 0x49);
/* Primary interupt channel, define wake events 0=IRQ0 15=IRQ15 1=en. */
// pci_write_config16(dev, 0x84, 0x30f2);
pci_write_config16(dev, 0x84, 0x609a); // 0x609a??
/* SMI output level to low, 7.5us throttle clock */
pci_write_config8(dev, 0x8d, 0x18);
/* GP Timer Control 1s */
pci_write_config8(dev, 0x93, 0x88);
/* Power Well */
pci_write_config8(dev, 0x94, 0x20); // 0x20??
/* 7 = stp to sust delay 1msec
* 6 = SUSST# Deasserted Before PWRGD for STD
*/
pci_write_config8(dev, 0x95, 0xc0); // 0xc1??
/* Disable GP2 & GP3 Timer */
pci_write_config8(dev, 0x98, 0);
/* GP2 Timer Counter */
pci_write_config8(dev, 0x99, 0xfb);
/* GP3 Timer Counter */
//pci_write_config8(dev, 0x9a, 0x20);
/* Multi Function Select 1 */
pci_write_config8(dev, 0xe4, 0x00);
/* Multi Function Select 2 */
pci_write_config8(dev, 0xe5, 0x41); //??
/* Enable ACPI access (and setup like award) */
pci_write_config8(dev, 0x81, 0x84);
/* Clear status events. */
outw(0xffff, VX800_ACPI_IO_BASE + 0x00);
outw(0xffff, VX800_ACPI_IO_BASE + 0x20);
outw(0xffff, VX800_ACPI_IO_BASE + 0x28);
outl(0xffffffff, VX800_ACPI_IO_BASE + 0x30);
/* Disable SCI on GPIO. */
outw(0x0, VX800_ACPI_IO_BASE + 0x22);
/* Disable SMI on GPIO. */
outw(0x0, VX800_ACPI_IO_BASE + 0x24);
/* Disable all global enable SMIs. */
outw(0x0, VX800_ACPI_IO_BASE + 0x2a);
/* All SMI off, both IDE buses ON, PSON rising edge. */
outw(0x0, VX800_ACPI_IO_BASE + 0x2c);
/* Primary activity SMI disable. */
outl(0x0, VX800_ACPI_IO_BASE + 0x34);
/* GP timer reload on none. */
outl(0x0, VX800_ACPI_IO_BASE + 0x38);
/* Disable extended IO traps. */
outb(0x0, VX800_ACPI_IO_BASE + 0x42);
tmp = inw(VX800_ACPI_IO_BASE + 0x04);
/* SCI is generated for RTC/pwrBtn/slpBtn. */
tmp |= 1;
outw(tmp, VX800_ACPI_IO_BASE + 0x04);
/* Allow SLP# signal to assert LDTSTOP_L.
* Will work for C3 and for FID/VID change.
*/
outb(0x1, VX800_ACPI_IO_BASE + 0x11);
/*
outw(0x0, 0x424);
outw(0x0, 0x42a);
outw(0x1, 0x42c);
outl(0x0, 0x434);
outl(0x01, 0x438);
outb(0x0, 0x442);
outl(0xffff7fff, 0x448);
outw(0x001, 0x404);
*/
}
void S3_ps2_kb_ms_wakeup(struct device *dev)
{ u8 enables;
enables = pci_read_config8(dev, 0x51);
enables |= 2;
pci_write_config8(dev, 0x51, enables);
outb(0xe0, 0x2e);
outb(0x0b, 0x2f);//if 09,then only support kb wakeup
outb(0xe1, 0x2e);//set any key scan code can wakeup
outb(0x00, 0x2f);
outb(0xe9, 0x2e);//set any mouse scan code can wakeup
outb(0x00, 0x2f);
enables &= 0xd;
pci_write_config8(dev, 0x51, enables);
outb(inb(VX800_ACPI_IO_BASE+0x02)|0x20, VX800_ACPI_IO_BASE+0x02);//ACPI golabe enable for sci smi trigger
outw(inw(VX800_ACPI_IO_BASE+0x22)|0x204, VX800_ACPI_IO_BASE+0x22);//ACPI SCI on Internal KBC PME and mouse PME
}
void S3_usb_wakeup(struct device *dev)
{
outw(inw(VX800_ACPI_IO_BASE+0x22)|0x4000, VX800_ACPI_IO_BASE+0x22);//SCI on USB PME
}
void S3_lid_wakeup(struct device *dev)
{
outw(inw(VX800_ACPI_IO_BASE+0x22)|0x800, VX800_ACPI_IO_BASE+0x22);//SCI on LID PME
}
/* This looks good enough to work, maybe */
static void vx800_sb_init(struct device *dev)
{
unsigned char enables;
// enable the internal I/O decode
enables = pci_read_config8(dev, 0x6C);
enables |= 0x80;
pci_write_config8(dev, 0x6C, enables);
// Map 4MB of FLASH into the address space
// pci_write_config8(dev, 0x41, 0x7f);
// Set bit 6 of 0x40, because Award does it (IO recovery time)
// IMPORTANT FIX - EISA 0x4d0 decoding must be on so that PCI
// interrupts can be properly marked as level triggered.
enables = pci_read_config8(dev, 0x40);
enables |= 0x44;
pci_write_config8(dev, 0x40, enables);
/* DMA Line buffer control */
enables = pci_read_config8(dev, 0x42);
enables |= 0xf0;
pci_write_config8(dev, 0x42, enables);
/* I/O recovery time */
pci_write_config8(dev, 0x4c, 0x44);
/* ROM memory cycles go to LPC. */
pci_write_config8(dev, 0x59, 0x80);
/* Set 0x5b to 0x01 to match Award */
//pci_write_config8(dev, 0x5b, 0x01);
enables = pci_read_config8(dev, 0x5b);
enables |= 0x01;
pci_write_config8(dev, 0x5b, enables);
/* Set Read Pass Write Control Enable */
pci_write_config8(dev, 0x48, 0x0c);
/* Set 0x58 to 0x42 APIC and RTC. */
//pci_write_config8(dev, 0x58, 0x42); this cmd cause the irq0 can not be triggerd,since bit 5 was set to 0.
enables=pci_read_config8(dev, 0x58);
enables|=0x41;//
pci_write_config8(dev, 0x58,enables);
/* Set bit 3 of 0x4f to match award (use INIT# as cpu reset) */
enables = pci_read_config8(dev, 0x4f);
enables |= 0x08;
pci_write_config8(dev, 0x4f, enables);
/* enable serial irq */
pci_write_config8(dev, 0x52, 0x9);
/* dma */
pci_write_config8(dev, 0x53, 0x00);
// Power management setup
setup_pm(dev);
/* set up isa bus -- i/o recovery time, rom write enable, extend-ale */
pci_write_config8(dev, 0x40, 0x54);
// Start the rtc
rtc_init(0);
}
/* total kludge to get lxb to call our childrens set/enable functions - these are
not called unless this device has a resource to set - so set a dummy one */
void vx800_read_resources(device_t dev)
{
struct resource *resource;
pci_dev_read_resources(dev);
resource = new_resource(dev, 1);
resource->flags |= IORESOURCE_FIXED | IORESOURCE_ASSIGNED | IORESOURCE_IO | IORESOURCE_STORED;
resource->size = 2;
resource->base = 0x2e;
}
void vx800_set_resources(device_t dev)
{
struct resource *resource;
resource = find_resource(dev,1);
resource->flags |= IORESOURCE_STORED;
pci_dev_set_resources(dev);
}
void vx800_enable_resources(device_t dev)
{
/* vx800 is not a pci bridge and has no resources of its own (other than
standard PC i/o addresses). however it does control the isa bus and so
we need to manually call enable childrens resources on that bus */
/* TODO: do we even care about ISA? If so, for what? SuperIO on LPC bus */
pci_dev_enable_resources(dev);
enable_childrens_resources(dev);
}
static void southbridge_init(struct device *dev)
{
printk_debug("vx800 sb init\n");
vx800_sb_init(dev);
pci_routing_fixup(dev);
setup_i8259(); // make sure interupt controller is configured before keyboard init
/* turn on keyboard and RTC, no need to visit this reg twice */
init_pc_keyboard(0x60, 0x64, 0);
printk_debug("ps2 usb lid, you set who can wakeup system from s3 sleep\n");
S3_ps2_kb_ms_wakeup(dev);
S3_usb_wakeup(dev);
/* enable acpi cpu c3 state. (c2 state need not do anything.)
#1
fadt->pm2_cnt_blk = 0x22;//to support cpu-c3
fadt->p_lvl2_lat = 0x50; //this is the coreboot source
fadt->p_lvl3_lat = 0x320;//
fadt->pm2_cnt_len = 1;//to support cpu-c3
#2
ssdt? ->every cpu has a P_BLK address. set it to 0x10 (so that "Read Processor Level3 register(PMIORx15<7:0>) to enter C3 state"---VIA vx800 P SPEC )
#3 write 0x17 in to PMIO=VX800_ACPI_IO_BASE + 0x26, following the describtion in the P-spec.
1 enable SLP# asserts in C3 state PMIORx26<1> =1
2 enable CPUSTP# asserts in C3 state; PMIORx26<2> =1
3 CLKRUN# is always asserted PMIORx26<3> =0
4 Disable PCISTP# When CLKRUN# is asserted
1: PCISTP# will not assert When CLKRUN# is asserted
PMIORx26<4> =1
5 This bit controls whether the CPU voltage is lowered when in C3/S1 state.
VRDSLP will be active in either this bit set in C3 or LVL4 register read
PMIORx26<0> =0
6 Read Processor Level3 register(PMIORx15<7:0>) to enter C3 state PMIORx15
*/
outb(0x17, VX800_ACPI_IO_BASE + 0x26);
}
static struct device_operations vx800_lpc_ops = {
.read_resources = vx800_read_resources,
.set_resources = vx800_set_resources,
.enable_resources = vx800_enable_resources,
.init = &southbridge_init,
.scan_bus = scan_static_bus,
};
static struct pci_driver lpc_driver __pci_driver = {
.ops = &vx800_lpc_ops,
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_DEVICE_ID_VIA_VX855_LPC,
};