/* * 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. */ 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; 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; } }