diff options
Diffstat (limited to 'src/northbridge/via/vx800/timing_setting.c')
-rw-r--r-- | src/northbridge/via/vx800/timing_setting.c | 492 |
1 files changed, 492 insertions, 0 deletions
diff --git a/src/northbridge/via/vx800/timing_setting.c b/src/northbridge/via/vx800/timing_setting.c new file mode 100644 index 0000000000..5e1847800a --- /dev/null +++ b/src/northbridge/via/vx800/timing_setting.c @@ -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); +} |