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:
parent
e6e899dde9
commit
612163e383
25
src/northbridge/via/vx800/Config.lb
Normal file
25
src/northbridge/via/vx800/Config.lb
Normal 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
|
70
src/northbridge/via/vx800/DrivingClkPhaseData.h
Normal file
70
src/northbridge/via/vx800/DrivingClkPhaseData.h
Normal 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 */
|
24
src/northbridge/via/vx800/chip.h
Normal file
24
src/northbridge/via/vx800/chip.h
Normal 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;
|
86
src/northbridge/via/vx800/ddr2init/DramInit.c
Normal file
86
src/northbridge/via/vx800/ddr2init/DramInit.c
Normal 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;
|
||||
}
|
263
src/northbridge/via/vx800/ddr2init/DramInit.h
Normal file
263
src/northbridge/via/vx800/ddr2init/DramInit.h
Normal 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
|
249
src/northbridge/via/vx800/ddr2init/DramUtil.c
Normal file
249
src/northbridge/via/vx800/ddr2init/DramUtil.c
Normal 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");
|
||||
}
|
||||
}
|
47
src/northbridge/via/vx800/ddr2init/DramUtil.h
Normal file
47
src/northbridge/via/vx800/ddr2init/DramUtil.h
Normal 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
|
34
src/northbridge/via/vx800/ddr2init/Translatorddr2init.c
Normal file
34
src/northbridge/via/vx800/ddr2init/Translatorddr2init.c
Normal 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;
|
312
src/northbridge/via/vx800/ddr2init/vx800/ClkCtrl.c
Normal file
312
src/northbridge/via/vx800/ddr2init/vx800/ClkCtrl.c
Normal 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);
|
||||
|
||||
}
|
98
src/northbridge/via/vx800/ddr2init/vx800/DQSSearch.c
Normal file
98
src/northbridge/via/vx800/ddr2init/vx800/DQSSearch.c
Normal 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);
|
||||
}
|
600
src/northbridge/via/vx800/ddr2init/vx800/DRDY_BL.c
Normal file
600
src/northbridge/via/vx800/ddr2init/vx800/DRDY_BL.c
Normal 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);
|
||||
}
|
192
src/northbridge/via/vx800/ddr2init/vx800/Detection.c
Normal file
192
src/northbridge/via/vx800/ddr2init/vx800/Detection.c
Normal 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;
|
||||
}
|
1318
src/northbridge/via/vx800/ddr2init/vx800/DevInit.c
Normal file
1318
src/northbridge/via/vx800/ddr2init/vx800/DevInit.c
Normal file
File diff suppressed because it is too large
Load Diff
396
src/northbridge/via/vx800/ddr2init/vx800/DrivingSetting.c
Normal file
396
src/northbridge/via/vx800/ddr2init/vx800/DrivingSetting.c
Normal 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);
|
||||
}
|
||||
|
||||
}
|
129
src/northbridge/via/vx800/ddr2init/vx800/FinalSetting.c
Normal file
129
src/northbridge/via/vx800/ddr2init/vx800/FinalSetting.c
Normal 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);
|
||||
}
|
||||
|
||||
}
|
235
src/northbridge/via/vx800/ddr2init/vx800/FreqSetting.c
Normal file
235
src/northbridge/via/vx800/ddr2init/vx800/FreqSetting.c
Normal 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");
|
||||
}
|
363
src/northbridge/via/vx800/ddr2init/vx800/RankMap.c
Normal file
363
src/northbridge/via/vx800/ddr2init/vx800/RankMap.c
Normal 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;
|
||||
}
|
||||
}
|
492
src/northbridge/via/vx800/ddr2init/vx800/TimingSetting.c
Normal file
492
src/northbridge/via/vx800/ddr2init/vx800/TimingSetting.c
Normal 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);
|
||||
}
|
445
src/northbridge/via/vx800/ddr2init/vx800/UMARamSetting.c
Normal file
445
src/northbridge/via/vx800/ddr2init/vx800/UMARamSetting.c
Normal 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
|
||||
|
||||
}
|
242
src/northbridge/via/vx800/examples/DrivingClkPhaseData.c
Normal file
242
src/northbridge/via/vx800/examples/DrivingClkPhaseData.c
Normal 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
|
||||
};
|
660
src/northbridge/via/vx800/examples/cache_as_ram_auto.c
Normal file
660
src/northbridge/via/vx800/examples/cache_as_ram_auto.c
Normal 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");
|
||||
|
||||
}
|
1298
src/northbridge/via/vx800/examples/chipset_init.c
Normal file
1298
src/northbridge/via/vx800/examples/chipset_init.c
Normal file
File diff suppressed because it is too large
Load Diff
247
src/northbridge/via/vx800/northbridge.c
Normal file
247
src/northbridge/via/vx800/northbridge.c
Normal 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,
|
||||
};
|
25
src/northbridge/via/vx800/northbridge.h
Normal file
25
src/northbridge/via/vx800/northbridge.h
Normal 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 */
|
74
src/northbridge/via/vx800/raminit.c
Normal file
74
src/northbridge/via/vx800/raminit.c
Normal 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");
|
||||
}
|
||||
|
||||
}
|
24
src/northbridge/via/vx800/raminit.h
Normal file
24
src/northbridge/via/vx800/raminit.h
Normal 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 */
|
51
src/northbridge/via/vx800/romstrap.inc
Normal file
51
src/northbridge/via/vx800/romstrap.inc
Normal 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
|
26
src/northbridge/via/vx800/romstrap.lds
Normal file
26
src/northbridge/via/vx800/romstrap.lds
Normal 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)
|
||||
}
|
||||
}
|
148
src/northbridge/via/vx800/vga.c
Normal file
148
src/northbridge/via/vx800/vga.c
Normal 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,
|
||||
};
|
862
src/northbridge/via/vx800/vgabios.c
Normal file
862
src/northbridge/via/vx800/vgabios.c
Normal 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;
|
||||
}
|
34
src/northbridge/via/vx800/vgachip.h
Normal file
34
src/northbridge/via/vx800/vgachip.h
Normal 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 */
|
125
src/northbridge/via/vx800/vx800.h
Normal file
125
src/northbridge/via/vx800/vx800.h
Normal 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
|
110
src/northbridge/via/vx800/vx800_early_serial.c
Normal file
110
src/northbridge/via/vx800/vx800_early_serial.c
Normal 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);
|
||||
}
|
||||
|
321
src/northbridge/via/vx800/vx800_early_smbus.c
Normal file
321
src/northbridge/via/vx800/vx800_early_smbus.c
Normal 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
|
204
src/northbridge/via/vx800/vx800_ide.c
Normal file
204
src/northbridge/via/vx800/vx800_ide.c
Normal 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,
|
||||
};
|
384
src/northbridge/via/vx800/vx800_lpc.c
Normal file
384
src/northbridge/via/vx800/vx800_lpc.c
Normal 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,
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user