mail.coreboot.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
List overview
Download
coreboot-gerrit
November 2015
----- 2024 -----
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
coreboot-gerrit@coreboot.org
1 participants
1544 discussions
Start a n
N
ew thread
Patch set updated for coreboot: amd/amdmct/mct_ddr3: Fix poor performance on Family 15h CPUs
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12029
-gerrit commit fb4c5070636cc216197d6c50ec9756caa7a71feb Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Fri Aug 7 19:05:29 2015 -0500 amd/amdmct/mct_ddr3: Fix poor performance on Family 15h CPUs Change-Id: Ib6bc197e43e40ba2b923b1eb1229bacafc8be360 Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 371 +++++++++++++++++++++---- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h | 1 + src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 65 ++++- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c | 49 +++- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c | 216 +++++++++++++- src/northbridge/amd/amdmct/mct_ddr3/mctwl.c | 4 + 6 files changed, 614 insertions(+), 92 deletions(-) diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c index d76eea0..aad813a 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c @@ -32,6 +32,8 @@ * supported. */ +// #define DEBUG_DIMM_SPD 1 + static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA); static void DQSTiming_D(struct MCTStatStruc *pMCTstat, @@ -168,7 +170,8 @@ static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel); static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dimm); -static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2); +static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, + uint8_t dct, uint32_t misc2, uint32_t DramControl); static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat); static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, uint8_t Pass); @@ -1366,6 +1369,8 @@ static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t dc static void set_2t_configuration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) { + printk(BIOS_DEBUG, "%s: Start\n", __func__); + uint32_t dev; uint32_t reg; uint32_t dword; @@ -1388,6 +1393,8 @@ static void set_2t_configuration(struct MCTStatStruc *pMCTstat, else dword &= ~(0x1 << 20); /* Clear 2T CMD mode */ Set_NB32_DCT(dev, dct, reg, dword); + + printk(BIOS_DEBUG, "%s: Done\n", __func__); } static void precise_ndelay_fam15(struct MCTStatStruc *pMCTstat, uint32_t nanoseconds) { @@ -2019,6 +2026,8 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, /* Disable training mode */ uint8_t lane; uint8_t dimm; + uint16_t max_cdd_we_delta; + uint16_t cdd_trwtto_we_delta; uint8_t receiver; uint8_t max_lane; uint8_t ecc_enabled; @@ -2033,21 +2042,37 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, uint16_t twrwrdd; uint16_t cdd_twrwrdd; uint16_t twrrd; + uint16_t cdd_twrrd; + uint16_t cdd_trwtto; uint16_t trwtto; uint8_t first_dimm; uint16_t delay; uint16_t delay2; + uint8_t min_value; + uint8_t write_early; uint8_t read_odt_delay; uint8_t write_odt_delay; + uint8_t buffer_data_delay; + int16_t latency_difference; uint16_t difference; uint16_t current_total_delay_1[MAX_BYTE_LANES]; uint16_t current_total_delay_2[MAX_BYTE_LANES]; + uint8_t ddr_voltage_index; + uint8_t max_dimms_installable; /* FIXME * This should be platform configurable */ uint8_t dimm_event_l_pin_support = 0; + if (pDCTstat->DIMMValidDCT[dct] == 0) + ddr_voltage_index = 1; + else + ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); + + ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); + max_dimms_installable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); + ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); if (ecc_enabled) max_lane = 9; @@ -2081,6 +2106,24 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, else write_odt_delay = 0; + dword = (Get_NB32_DCT(dev, dct, 0xa8) >> 24) & 0x3; + write_early = dword / 2; + + latency_difference = Get_NB32_DCT(dev, dct, 0x200) & 0x1f; + dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f; + latency_difference -= dword; + + if (pDCTstat->Status & (1 << SB_LoadReduced)) { + /* LRDIMM */ + + /* TODO + * Implement LRDIMM support + * See Fam15h BKDG Rev. 3.14 section 2.10.5.5 + */ + } else { + buffer_data_delay = 0; + } + /* TODO: * Adjust trdrdsddc if four-rank DIMMs are installed per * section 2.10.5.5.1 of the Family 15h BKDG. @@ -2116,7 +2159,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, } /* Convert the difference to MEMCLKs */ - cdd_trdrddd = (((cdd_trdrddd >> 5) & 0x1f) + 1) / 2; + cdd_trdrddd = (((cdd_trdrddd + (1 << 6) - 1) >> 6) & 0xf); /* Calculate Trdrddd */ delay = (read_odt_delay + 3) * 2; @@ -2162,7 +2205,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, } /* Convert the difference to MEMCLKs */ - cdd_twrwrdd = (((cdd_twrwrdd >> 5) & 0x1f) + 1) / 2; + cdd_twrwrdd = (((cdd_twrwrdd + (1 << 6) - 1) >> 6) & 0xf); /* Calculate Twrwrdd */ delay = (write_odt_delay + 3) * 2; @@ -2181,6 +2224,107 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, dword &= ~(0x1 << 18); /* DisAutoRefresh = 0 */ Set_NB32_DCT(dev, dct, 0x8c, dword); /* DRAM Timing High */ + /* Configure power saving options */ + dword = Get_NB32_DCT(dev, dct, 0xa8); /* Dram Miscellaneous 2 */ + dword |= (0x1 << 22); /* PrtlChPDEnhEn = 0x1 */ + dword |= (0x1 << 21); /* AggrPDEn = 0x1 */ + Set_NB32_DCT(dev, dct, 0xa8, dword); /* Dram Miscellaneous 2 */ + + /* Configure partial power down delay */ + dword = Get_NB32(dev, 0x244); /* DRAM Controller Miscellaneous 3 */ + dword &= ~0xf; /* PrtlChPDDynDly = 0x2 */ + dword |= 0x2; + Set_NB32(dev, 0x244, dword); /* DRAM Controller Miscellaneous 3 */ + + /* Configure power save delays */ + delay = 0xa; + delay2 = 0x3; + + /* Family 15h BKDG Table 214 */ + if ((pDCTstat->Status & (1 << SB_Registered)) + || (pDCTstat->Status & (1 << SB_LoadReduced))) { + if (memclk_index <= 0x6) { + if (ddr_voltage_index < 0x4) + /* 1.5 or 1.35V */ + delay2 = 0x3; + else + /* 1.25V */ + delay2 = 0x4; + } + else if ((memclk_index == 0xa) + || (memclk_index == 0xe)) + delay2 = 0x4; + else if (memclk_index == 0x12) + delay2 = 0x5; + else if (memclk_index == 0x16) + delay2 = 0x6; + } else { + if (memclk_index <= 0x6) + delay2 = 0x3; + else if ((memclk_index == 0xa) + || (memclk_index == 0xe)) + delay2 = 0x4; + else if (memclk_index == 0x12) + delay2 = 0x5; + else if (memclk_index == 0x16) + delay2 = 0x6; + } + + /* Family 15h BKDG Table 215 */ + if (memclk_index <= 0x6) + delay = 0xa; + else if (memclk_index == 0xa) + delay = 0xd; + else if (memclk_index == 0xe) + delay = 0x10; + else if (memclk_index == 0x12) + delay = 0x14; + else if (memclk_index == 0x16) + delay = 0x17; + + dword = Get_NB32_DCT(dev, dct, 0x248); /* Dram Power Management 0 */ + dword &= ~(0x3f << 24); /* AggrPDDelay = 0x0 */ + dword &= ~(0x3f << 16); /* PchgPDEnDelay = 0x1 */ + dword |= (0x1 << 16); + dword &= ~(0x1f << 8); /* Txpdll = delay */ + dword |= ((delay & 0x1f) << 8); + dword &= ~0xf; /* Txp = delay2 */ + dword |= delay2 & 0xf; + Set_NB32_DCT(dev, dct, 0x248, dword); /* Dram Power Management 0 */ + + /* Family 15h BKDG Table 216 */ + if (memclk_index <= 0x6) { + delay = 0x5; + delay2 = 0x3; + } + else if (memclk_index == 0xa) { + delay = 0x6; + delay2 = 0x3; + } + else if (memclk_index == 0xe) { + delay = 0x7; + delay2 = 0x4; + } + else if (memclk_index == 0x12) { + delay = 0x8; + delay2 = 0x4; + } + else if (memclk_index == 0x16) { + delay = 0xa; + delay2 = 0x5; + } + + dword = Get_NB32_DCT(dev, dct, 0x24c); /* Dram Power Management 1 */ + dword &= ~(0x3f << 24); /* Tcksrx = delay */ + dword |= ((delay & 0x3f) << 24); + dword &= ~(0x3f << 16); /* Tcksre = delay */ + dword |= ((delay & 0x3f) << 16); + dword &= ~(0x3f << 8); /* Tckesr = delay2 + 1 */ + dword |= (((delay2 + 1) & 0x3f) << 8); + dword &= ~0xf; /* Tpd = delay2 */ + dword |= delay2 & 0xf; + Set_NB32_DCT(dev, dct, 0x24c, dword); /* Dram Power Management 1 */ + dword = Get_NB32_DCT(dev, dct, 0x94); /* DRAM Configuration High */ dword |= (0xf << 24); /* DcqBypassMax = 0xf */ dword |= (0x1 << 22); /* BankSwizzleMode = 1 */ @@ -2233,15 +2377,98 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, } } - /* TODO - * Calculate Twrrd per section 2.10.5.5.3 of the Family 15h BKDG - */ - twrrd = 0xb; + /* Calculate the Critical Delay Difference for Twrrd */ + cdd_twrrd = 0; + for (receiver = 0; receiver < 8; receiver += 2) { + dimm = (receiver >> 1); - /* TODO - * Calculate TrwtTO per section 2.10.5.5.4 of the Family 15h BKDG - */ - trwtto = 0x16; + if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) + continue; + + read_dqs_write_timing_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); + read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); + + for (lane = 0; lane < max_lane; lane++) { + if (current_total_delay_1[lane] > current_total_delay_2[lane]) + difference = current_total_delay_1[lane] - current_total_delay_2[lane]; + else + difference = current_total_delay_2[lane] - current_total_delay_1[lane]; + + if (difference > cdd_twrrd) + cdd_twrrd = difference; + } + } + + /* Convert the difference to MEMCLKs */ + cdd_twrrd = (((cdd_twrrd + (1 << 6) - 1) >> 6) & 0xf); + + /* Fam15h BKDG section 2.10.5.5.3 */ + if (pDCTstat->Status & (1 << SB_LoadReduced)) { + /* LRDIMM */ + + /* TODO + * Implement LRDIMM support + * See Fam15h BKDG Rev. 3.14 section 2.10.5.5 + */ + twrrd = 0xb; + } else { + max_cdd_we_delta = (((int16_t)cdd_twrrd + 1 - ((int16_t)write_early * 2)) + 1) / 2; + if (max_cdd_we_delta < 0) + max_cdd_we_delta = 0; + if (((uint16_t)max_cdd_we_delta) > write_odt_delay) + dword = max_cdd_we_delta; + else + dword = write_odt_delay; + dword += 3; + if (latency_difference < dword) { + dword -= latency_difference; + if (dword < 1) + twrrd = 1; + else + twrrd = dword; + } else { + twrrd = 1; + } + } + + /* Calculate the Critical Delay Difference for TrwtTO */ + cdd_trwtto = 0; + for (receiver = 0; receiver < 8; receiver += 2) { + dimm = (receiver >> 1); + + if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) + continue; + + read_dqs_receiver_enable_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); + read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); + + for (lane = 0; lane < max_lane; lane++) { + if (current_total_delay_1[lane] > current_total_delay_2[lane]) + difference = current_total_delay_1[lane] - current_total_delay_2[lane]; + else + difference = current_total_delay_2[lane] - current_total_delay_1[lane]; + + if (difference > cdd_trwtto) + cdd_trwtto = difference; + } + } + + /* Convert the difference to MEMCLKs */ + cdd_trwtto = (((cdd_trwtto + (1 << 6) - 1) >> 6) & 0xf); + + /* Fam15h BKDG section 2.10.5.5.4 */ + if (max_dimms_installable == 1) + min_value = 0; + else + min_value = read_odt_delay + buffer_data_delay; + cdd_trwtto_we_delta = (((int16_t)cdd_trwtto - 1 + ((int16_t)write_early * 2)) + 1) / 2; + cdd_trwtto_we_delta += latency_difference + 3; + if (cdd_trwtto_we_delta < 0) + cdd_trwtto_we_delta = 0; + if ((cdd_trwtto_we_delta) > min_value) + trwtto = cdd_trwtto_we_delta; + else + trwtto = min_value; dword = Get_NB32_DCT(dev, dct, 0xa4); /* DRAM Controller Temperature Throttle */ dword &= ~(0x1 << 11); /* BwCapEn = 0 */ @@ -2252,6 +2479,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, dword = Get_NB32_DCT(dev, dct, 0x110); /* DRAM Controller Select Low */ dword &= ~(0x1 << 2); /* DctSelIntLvEn = interleave_channels */ dword |= (interleave_channels & 0x1) << 2; + dword |= (0x3 << 6); /* DctSelIntLvAddr = 0x3 */ Set_NB32_DCT(dev, dct, 0x110, dword); /* DRAM Controller Select Low */ /* NOTE @@ -2259,22 +2487,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, * otherwise semi-random lockups will occur due to misconfigured scrubbing hardware! */ - /* FIXME - * The BKDG-recommended settings cause memory corruption on the ASUS KGPE-D16. - * Investigate and fix... - */ -#if 0 - /* Fam15h BKDG section 2.10.5.5.1 */ - dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */ - dword &= ~(0xf << 24); /* TrdrdSdSc = 0x1 */ - dword |= (0x1 << 24); - dword &= ~(0xf << 16); /* TrdrdSdDc = trdrdsddc */ - dword |= ((trdrdsddc & 0xf) << 16); - dword &= ~(0xf); /* TrdrdDd = trdrddd */ - dword |= (trdrddd & 0xf); - Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */ -#endif - /* Fam15h BKDG section 2.10.5.5.2 */ dword = Get_NB32_DCT(dev, dct, 0x214); /* DRAM Timing 4 */ dword &= ~(0xf << 16); /* TwrwrSdSc = 0x1 */ @@ -2287,8 +2499,14 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, /* Fam15h BKDG section 2.10.5.5.3 */ dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */ + dword &= ~(0xf << 24); /* TrdrdSdSc = 0x1 */ + dword |= (0x1 << 24); + dword &= ~(0xf << 16); /* TrdrdSdDc = trdrdsddc */ + dword |= ((trdrdsddc & 0xf) << 16); dword &= ~(0xf << 8); /* Twrrd = twrrd */ dword |= ((twrrd & 0xf) << 8); + dword &= ~(0xf); /* TrdrdDd = trdrddd */ + dword |= (trdrddd & 0xf); Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */ /* Fam15h BKDG section 2.10.5.5.4 */ @@ -2299,12 +2517,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, dword |= ((((dword >> 8) & 0x1f) + 1) << 16); Set_NB32_DCT(dev, dct, 0x21c, dword); /* DRAM Timing 6 */ - /* Configure partial power down delay */ - dword = Get_NB32(dev, 0x244); /* DRAM Controller Miscellaneous 3 */ - dword &= ~0xf; /* PrtlChPDDynDly = 0x2 */ - dword |= 0x2; - Set_NB32(dev, 0x244, dword); /* DRAM Controller Miscellaneous 3 */ - /* Enable prefetchers */ dword = Get_NB32(dev, 0x11c); /* Memory Controller Configuration High */ dword &= ~(0x1 << 13); /* PrefIoDis = 0 */ @@ -2393,6 +2605,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat, mct_TrainDQSPos_D(pMCTstat, pDCTstatA); + TrainMaxRdLatency_En_D(pMCTstat, pDCTstatA); + if (is_fam15h()) exit_training_mode_fam15(pMCTstat, pDCTstatA); else @@ -2971,6 +3185,13 @@ static void ClearDCT_D(struct MCTStatStruc *pMCTstat, } while(reg < reg_end) { + if ((reg & 0xFF) == 0x84) { + if (is_fam15h()) { + val = Get_NB32_DCT(dev, dct, reg); + val &= ~(0x1 << 23); /* Clear PchgPDModeSel */ + val &= ~0x3; /* Clear BurstCtrl */ + } + } if ((reg & 0xFF) == 0x90) { if (pDCTstat->LogicalCPUID & AMD_DR_Dx) { val = Get_NB32_DCT(dev, dct, reg); /* get DRAMConfigLow */ @@ -3089,14 +3310,30 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat, /* Convert DRAM CycleTiming values and store into DCT structure */ byte = pDCTstat->DIMMAutoSpeed; - if (byte == 7) - tCK16x = 20; - else if (byte == 6) - tCK16x = 24; - else if (byte == 5) - tCK16x = 30; - else - tCK16x = 40; + if (is_fam15h()) { + if (byte == 0x16) + tCK16x = 17; + else if (byte == 0x12) + tCK16x = 20; + else if (byte == 0xe) + tCK16x = 24; + else if (byte == 0xa) + tCK16x = 30; + else if (byte == 0x6) + tCK16x = 40; + else + tCK16x = 48; + } + else { + if (byte == 7) + tCK16x = 20; + else if (byte == 6) + tCK16x = 24; + else if (byte == 5) + tCK16x = 30; + else + tCK16x = 40; + } /* Notes: 1. All secondary time values given in SPDs are in binary with units of ns. @@ -3129,7 +3366,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat, val = Max_TrpT; pDCTstat->Trp = val; - /*Trrd*/ + /* Trrd */ pDCTstat->DIMMTrrd = Trrd; val = Trrd / tCK16x; if (Trrd % tCK16x) { /* round up number of busclocks */ @@ -3247,21 +3484,31 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat, dword = Get_NB32_DCT(dev, dct, 0x200); /* DRAM Timing 0 */ dword &= ~(0x3f1f1f1f); - dword |= ((pDCTstat->Tras + 0xf) & 0x3f) << 24; /* Tras */ - dword |= ((pDCTstat->Trp + 0x5) & 0x1f) << 16; /* Trp */ - dword |= ((pDCTstat->Trcd + 0x5) & 0x1f) << 8; /* Trcd */ + dword |= (pDCTstat->Tras & 0x3f) << 24; /* Tras */ + val = pDCTstat->Trp; + val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val); + dword |= (val & 0x1f) << 16; /* Trp */ + dword |= (pDCTstat->Trcd & 0x1f) << 8; /* Trcd */ dword |= (pDCTstat->CASL & 0x1f); /* Tcl */ Set_NB32_DCT(dev, dct, 0x200, dword); /* DRAM Timing 0 */ dword = Get_NB32_DCT(dev, dct, 0x204); /* DRAM Timing 1 */ dword &= ~(0x0f3f0f3f); - dword |= ((pDCTstat->Trtp + 0x4) & 0xf) << 24; /* Trtp */ - if (pDCTstat->Tfaw != 0) - dword |= ((((pDCTstat->Tfaw - 0x1) * 2) + 0x10) & 0x3f) << 16; /* FourActWindow */ - dword |= ((pDCTstat->Trrd + 0x4) & 0xf) << 8; /* Trrd */ - dword |= ((pDCTstat->Trc + 0xb) & 0x3f); /* Trc */ + dword |= (pDCTstat->Trtp & 0xf) << 24; /* Trtp */ + if (pDCTstat->Tfaw != 0) { + val = pDCTstat->Tfaw; + val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val); + if ((val > 0x5) && (val < 0x2b)) + dword |= (val & 0x3f) << 16; /* FourActWindow */ + } + dword |= (pDCTstat->Trrd & 0xf) << 8; /* Trrd */ + dword |= (pDCTstat->Trc & 0x3f); /* Trc */ Set_NB32_DCT(dev, dct, 0x204, dword); /* DRAM Timing 1 */ + /* Trfc0-Trfc3 */ + for (i=0; i<4; i++) + if (pDCTstat->Trfc[i] == 0x0) + pDCTstat->Trfc[i] = 0x4; dword = Get_NB32_DCT(dev, dct, 0x208); /* DRAM Timing 2 */ dword &= ~(0x07070707); dword |= (pDCTstat->Trfc[3] & 0x7) << 24; /* Trfc3 */ @@ -3272,14 +3519,14 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat, dword = Get_NB32_DCT(dev, dct, 0x20c); /* DRAM Timing 3 */ dword &= ~(0x00000f00); - dword |= ((pDCTstat->Twtr + 0x4) & 0xf) << 8; /* Twtr */ + dword |= (pDCTstat->Twtr & 0xf) << 8; /* Twtr */ dword &= ~(0x0000001f); dword |= (Tcwl & 0x1f); /* Tcwl */ Set_NB32_DCT(dev, dct, 0x20c, dword); /* DRAM Timing 3 */ dword = Get_NB32_DCT(dev, dct, 0x22c); /* DRAM Timing 10 */ dword &= ~(0x0000001f); - dword |= ((pDCTstat->Twr + 0x4) & 0x1f); /* Twr */ + dword |= (pDCTstat->Twr & 0x1f); /* Twr */ Set_NB32_DCT(dev, dct, 0x22c, dword); /* DRAM Timing 10 */ if (pDCTstat->Speed > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) { @@ -3875,6 +4122,8 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, } } + DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, DramConfigMisc2, DramControl); + printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %08x\n", DramControl); printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %08x\n", DramTimingLo); printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %08x\n", DramConfigMisc); @@ -3886,7 +4135,6 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, Set_NB32_DCT(dev, dct, 0x78, DramControl); Set_NB32_DCT(dev, dct, 0x88, DramTimingLo); Set_NB32_DCT(dev, dct, 0xa0, DramConfigMisc); - DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, DramConfigMisc2); Set_NB32_DCT(dev, dct, 0xa8, DramConfigMisc2); Set_NB32_DCT(dev, dct, 0x90, DramConfigLo); ProgDramMRSReg_D(pMCTstat, pDCTstat, dct); @@ -5257,6 +5505,16 @@ static void mct_PhyController_Config(struct MCTStatStruc *pMCTstat, u32 dev = pDCTstat->dev_dct; if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3 | AMD_FAM15_ALL)) { + if (is_fam15h()) { + /* Set F2x[1, 0]98_x0D0F0F13 DllDisEarlyU and DllDisEarlyL to save power */ + for (index = 0; index < 0x9; index++) { + dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8)); + dword |= (0x1 << 1); /* DllDisEarlyU = 1 */ + dword |= 0x1; /* DllDisEarlyL = 1 */ + Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8), dword); + } + } + if (pDCTstat->Dimmx4Present == 0) { /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 0]98_x0D0F0F13 for * additional power saving when x4 DIMMs are not present. @@ -5301,8 +5559,9 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat, mct_ExtMCTConfig_Dx(pDCTstat); } else { /* Family 15h CPUs */ - val = 0x0ce00f00 | 0x1 << 29; /* FlushWrOnStpGnt */ - val |= 0x10 << 2; /* MctWrLimit = 16 */ + val = 0x0ce00f00; /* FlushWrOnStpGnt = 0x0 */ + val |= 0x10 << 2; /* MctWrLimit = 0x10 */ + val |= 0x1; /* DctWrLimit = 0x1 */ Set_NB32(pDCTstat->dev_dct, 0x11c, val); val = Get_NB32(pDCTstat->dev_dct, 0x1b0); @@ -6543,8 +6802,8 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat, dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84); if (is_fam15h()) { - dword |= DramMRS; dword &= ~0x00800003; + dword |= DramMRS; } else { dword &= ~0x00fc2f8f; dword |= DramMRS; diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h index eb4c74e..b72b9da 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h +++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h @@ -984,6 +984,7 @@ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat uint64_t mctGetLogicalCPUID(u32 Node); u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA); void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u8 Pass); +void TrainMaxRdLatency_En_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA); void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA); void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA); void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA); diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c index 3615616..06597e2 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c @@ -20,6 +20,9 @@ static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_ static void read_read_dqs_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg); +static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat, + struct DCTStatStruc *pDCTstat); + static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u16 like, u8 scale, u8 ChipSel); @@ -214,6 +217,27 @@ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, } } +void TrainMaxRdLatency_En_D(struct MCTStatStruc *pMCTstat, + struct DCTStatStruc *pDCTstatA) +{ + uint8_t node; + struct DCTStatStruc *pDCTstat; + + for (node = 0; node < MAX_NODES_SUPPORTED; node++) { + pDCTstat = pDCTstatA + node; + + if (pDCTstat->DCTSysLimit) { + if (is_fam15h()) { + dqsTrainMaxRdLatency_SW_Fam15(pMCTstat, pDCTstat); + } else { + /* FIXME + * Implement Family 10h MaxRdLatency training + */ + } + } + } +} + static void SetEccDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 ChipSel) { @@ -894,7 +918,7 @@ static void TrainDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat, * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.5 */ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, uint8_t dct) + struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t calc_min) { uint8_t dimm; uint8_t lane; @@ -938,7 +962,8 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, p += (9 - dword); /* 2.10.5.8.5 (4) */ - p += 5; + if (!calc_min) + p += 5; /* 2.10.5.8.5 (5) */ dword = Get_NB32_DCT(dev, dct, 0xa8); @@ -965,7 +990,8 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, p += (max_delay >> 5); /* 2.10.5.8.5 (8) */ - p += 5; + if (!calc_min) + p += 5; /* 2.10.5.8.5 (9) */ t += 800; @@ -976,13 +1002,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, n = (((((uint64_t)p * 1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + ((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL; /* 2.10.5.8.5 (11) */ - n -= 1; + if (!calc_min) + n -= 1; /* 2.10.5.8.5 (12) */ - dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210); - dword &= ~(0x3ff << 22); - dword |= (((n - 1) & 0x3ff) << 22); - Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword); + if (!calc_min) { + dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210); + dword &= ~(0x3ff << 22); + dword |= (((n - 1) & 0x3ff) << 22); + Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword); + } /* Save result for later use */ pDCTstat->CH_MaxRdLat[dct] = n - 1; @@ -1103,6 +1132,9 @@ static void read_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat, } else if (lane < 8) { Set_NB32_DCT(dev, dct, 0x274, ~0x0); Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8))); + } else if (lane == 0xff) { + Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff); + Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff); } else { Set_NB32_DCT(dev, dct, 0x274, ~0x0); Set_NB32_DCT(dev, dct, 0x278, ~0x0); @@ -1110,8 +1142,9 @@ static void read_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat, dword = Get_NB32_DCT(dev, dct, 0x27c); dword &= ~(0xff); /* EccMask = 0 */ - if ((lane != 8) || (pDCTstat->DimmECCPresent == 0)) - dword |= 0xff; /* EccMask = 0xff */ + if (lane != 0xff) + if ((lane != 8) || (pDCTstat->DimmECCPresent == 0)) + dword |= 0xff; /* EccMask = 0xff */ Set_NB32_DCT(dev, dct, 0x27c, dword); dword = Get_NB32_DCT(dev, dct, 0x270); @@ -1180,6 +1213,9 @@ static void write_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat, } else if (lane < 8) { Set_NB32_DCT(dev, dct, 0x274, ~0x0); Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8))); + } else if (lane == 0xff) { + Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff); + Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff); } else { Set_NB32_DCT(dev, dct, 0x274, ~0x0); Set_NB32_DCT(dev, dct, 0x278, ~0x0); @@ -1187,8 +1223,9 @@ static void write_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat, dword = Get_NB32_DCT(dev, dct, 0x27c); dword &= ~(0xff); /* EccMask = 0 */ - if ((lane != 8) || (pDCTstat->DimmECCPresent == 0)) - dword |= 0xff; /* EccMask = 0xff */ + if (lane != 0xff) + if ((lane != 8) || (pDCTstat->DimmECCPresent == 0)) + dword |= 0xff; /* EccMask = 0xff */ Set_NB32_DCT(dev, dct, 0x27c, dword); dword = Get_NB32_DCT(dev, dct, 0x270); @@ -1274,7 +1311,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat, uint32_t dev = pDCTstat->dev_dct; /* Calculate and program MaxRdLatency */ - Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct); + Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0); Errors = 0; dual_rank = 0; @@ -1632,7 +1669,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg); /* Calculate and program MaxRdLatency */ - Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct); + Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0); /* 2.10.5.8.3 (4 B) */ dqs_results_array[current_phy_phase_delay[lane]] = TrainDQSRdWrPos_D_Fam15(pMCTstat, pDCTstat, dct, Receiver, Receiver + 2, lane, lane + 1); diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c index 0922193..cf13b40 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c @@ -15,7 +15,8 @@ */ /* mct_SetDramConfigMisc2_Cx & mct_SetDramConfigMisc2_Dx */ -u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2) +u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, + uint8_t dct, uint32_t misc2, uint32_t DramControl) { u32 val; @@ -24,17 +25,47 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2) if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) { uint8_t cs_mux_45; uint8_t cs_mux_67; + uint32_t f2x80; - /* BKDG v3.14 Table 200 / Table 201 */ - if (MaxDimmsInstallable < 3) { - cs_mux_45 = 1; - cs_mux_67 = 1; - } else { + misc2 &= ~(0x1 << 28); /* FastSelfRefEntryDis = 0x0 */ + if (MaxDimmsInstallable == 3) { + /* FIXME 3 DIMMS per channel unimplemented */ cs_mux_45 = 0; + } else { + uint32_t f2x60 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x60); + f2x80 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x80); + if ((((f2x80 & 0xf) == 0x7) || ((f2x80 & 0xf) == 0x9)) + && ((f2x60 & 0x3) == 0x3)) + cs_mux_45 = 1; + else if ((((f2x80 & 0xa) == 0x7) || ((f2x80 & 0xb) == 0x9)) + && ((f2x60 & 0x3) > 0x1)) + cs_mux_45 = 1; + else + cs_mux_45 = 0; + } + + if (MaxDimmsInstallable == 1) { + cs_mux_67 = 0; + } else if (MaxDimmsInstallable == 2) { + uint32_t f2x64 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x64); + f2x80 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x80); + if (((((f2x80 >> 4) & 0xf) == 0x7) || (((f2x80 >> 4) & 0xf) == 0x9)) + && ((f2x64 & 0x3) == 0x3)) + cs_mux_67 = 1; + else if (((((f2x80 >> 4) & 0xa) == 0x7) || (((f2x80 >> 4) & 0xb) == 0x9)) + && ((f2x64 & 0x3) > 0x1)) + cs_mux_67 = 1; + else + cs_mux_67 = 0; + } else { + /* FIXME 3 DIMMS per channel unimplemented */ cs_mux_67 = 0; } - misc2 |= (cs_mux_45 & 0x1) << 26; - misc2 |= (cs_mux_67 & 0x1) << 27; + + misc2 &= ~(0x1 << 27); /* CsMux67 = cs_mux_67 */ + misc2 |= ((cs_mux_67 & 0x1) << 27); + misc2 &= ~(0x1 << 26); /* CsMux45 = cs_mux_45 */ + misc2 |= ((cs_mux_45 & 0x1) << 26); } else if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) { if (pDCTstat->Status & (1 << SB_Registered)) { misc2 |= 1 << SubMemclkRegDly; @@ -46,8 +77,8 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2) if (pDCTstat->LogicalCPUID & AMD_DR_Cx) misc2 |= 1 << OdtSwizzle; - val = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x78); + val = DramControl; val &= 7; val = ((~val) & 0xff) + 1; val += 6; diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c index 19b1b8f..b36ecae 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c @@ -541,9 +541,8 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat, u32 dev; u32 index_reg; u32 ch_start, ch_end, ch; - u32 msr; + msr_t msr; u32 cr4; - u32 lo, hi; uint32_t dword; uint8_t dimm; @@ -594,15 +593,14 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat, cr4 |= (1 << 9); /* OSFXSR enable SSE2 */ write_cr4(cr4); - msr = HWCR; - _RDMSR(msr, &lo, &hi); + msr = rdmsr(HWCR); /* FIXME: Why use SSEDIS */ - if(lo & (1 << 17)) { /* save the old value */ + if(msr.lo & (1 << 17)) { /* save the old value */ _Wrap32Dis = 1; } - lo |= (1 << 17); /* HWCR.wrap32dis */ - lo &= ~(1 << 15); /* SSEDIS */ - _WRMSR(msr, lo, hi); /* Setting wrap32dis allows 64-bit memory references in real mode */ + msr.lo |= (1 << 17); /* HWCR.wrap32dis */ + msr.lo &= ~(1 << 15); /* SSEDIS */ + wrmsr(HWCR, msr); /* Setting wrap32dis allows 64-bit memory references in real mode */ _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat); @@ -935,10 +933,9 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat, } if(!_Wrap32Dis) { - msr = HWCR; - _RDMSR(msr, &lo, &hi); - lo &= ~(1<<17); /* restore HWCR.wrap32dis */ - _WRMSR(msr, lo, hi); + msr = rdmsr(HWCR); + msr.lo &= ~(1<<17); /* restore HWCR.wrap32dis */ + wrmsr(HWCR, msr); } if(!_SSE2){ cr4 = read_cr4(); @@ -1420,7 +1417,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, } /* Calculate and program MaxRdLatency */ - Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel); + Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel, 0); if(_DisableDramECC) { mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC); @@ -1483,6 +1480,199 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat, printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n"); } +static void write_max_read_latency_to_registers(struct MCTStatStruc *pMCTstat, + struct DCTStatStruc *pDCTstat, uint8_t dct, uint16_t latency) +{ + uint32_t dword; + uint8_t nb_pstate; + + for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) { + dword = Get_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, nb_pstate, 0x210); + dword &= ~(0x3ff << 22); + dword |= ((latency & 0x3ff) << 22); + Set_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, nb_pstate, 0x210, dword); + } +} + +/* DQS MaxRdLatency Training (Family 15h) + * Algorithm detailed in: + * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.5.1 + * This algorithm runs at the highest supported MEMCLK. + */ +static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat, + struct DCTStatStruc *pDCTstat) +{ + u8 Channel; + u8 Addl_Index = 0; + u8 Receiver; + u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0; + u32 Errors; + + u32 dev; + u32 index_reg; + u32 ch_start, ch_end; + u32 msr; + u32 cr4; + u32 lo, hi; + + uint32_t dword; + uint8_t dimm; + uint8_t lane; + uint8_t mem_clk; + uint32_t nb_clk; + uint8_t nb_pstate; + uint16_t current_total_delay[MAX_BYTE_LANES]; + uint16_t current_rdqs_total_delay[MAX_BYTE_LANES]; + uint8_t current_worst_case_total_delay_dimm; + uint16_t current_worst_case_total_delay_value; + + uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933}; + + print_debug_dqs("\nTrainMaxRdLatency: Node", pDCTstat->Node_ID, 0); + + dev = pDCTstat->dev_dct; + index_reg = 0x98; + ch_start = 0; + ch_end = 2; + + cr4 = read_cr4(); + if(cr4 & ( 1 << 9)) { /* save the old value */ + _SSE2 = 1; + } + cr4 |= (1 << 9); /* OSFXSR enable SSE2 */ + write_cr4(cr4); + + msr = HWCR; + _RDMSR(msr, &lo, &hi); + /* FIXME: Why use SSEDIS */ + if(lo & (1 << 17)) { /* save the old value */ + _Wrap32Dis = 1; + } + lo |= (1 << 17); /* HWCR.wrap32dis */ + lo &= ~(1 << 15); /* SSEDIS */ + _WRMSR(msr, lo, hi); /* Setting wrap32dis allows 64-bit memory references in real mode */ + + _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat); + + Errors = 0; + dev = pDCTstat->dev_dct; + + for (Channel = 0; Channel < 2; Channel++) { + print_debug_dqs("\tTrainMaxRdLatency51: Node ", pDCTstat->Node_ID, 1); + print_debug_dqs("\tTrainMaxRdLatency51: Channel ", Channel, 1); + pDCTstat->Channel = Channel; + + if (pDCTstat->DIMMValidDCT[Channel] == 0) + continue; + + mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f; + + Receiver = mct_InitReceiver_D(pDCTstat, Channel); + + /* Find DIMM with worst case receiver enable delays */ + current_worst_case_total_delay_dimm = 0; + current_worst_case_total_delay_value = 0; + + /* There are four receiver pairs, loosely associated with chipselects. + * This is essentially looping over each DIMM. + */ + for (; Receiver < 8; Receiver += 2) { + Addl_Index = (Receiver >> 1) * 3 + 0x10; + dimm = (Receiver >> 1); + + print_debug_dqs("\t\tTrainMaxRdLatency52: index ", Addl_Index, 2); + + if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) { + continue; + } + + /* Retrieve the total delay values from pass 1 of DQS receiver enable training */ + read_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg); + read_read_dqs_timing_control_registers(current_rdqs_total_delay, dev, Channel, dimm, index_reg); + + for (lane = 0; lane < 8; lane++) { + current_total_delay[lane] += current_rdqs_total_delay[lane]; + if (current_total_delay[lane] > current_worst_case_total_delay_value) { + current_worst_case_total_delay_dimm = dimm; + current_worst_case_total_delay_value = current_total_delay[lane]; + } + } + +#if DQS_TRAIN_DEBUG > 0 + for (lane = 0; lane < 8; lane++) + print_debug_dqs_pair("\t\tTrainMaxRdLatency56: Lane ", lane, " current_total_delay ", current_total_delay[lane], 2); +#endif + } + + /* 2.10.5.8.5.1.1 */ + Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel, 1); + + /* 2.10.5.8.5.1.[2,3] + * Write the DRAM training pattern to the test address + */ + write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff); + + /* 2.10.5.8.5.1.4 + * Incrementally test each MaxRdLatency candidate + */ + for (; pDCTstat->CH_MaxRdLat[Channel] < 0x3ff; pDCTstat->CH_MaxRdLat[Channel]++) { + write_max_read_latency_to_registers(pMCTstat, pDCTstat, Channel, pDCTstat->CH_MaxRdLat[Channel]); + read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff); + dword = Get_NB32_DCT(dev, Channel, 0x268) & 0x3ffff; + if (!dword) + break; + Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000050, 0x13131313); + } + + /* 2.10.5.8.5.1.5 */ + nb_pstate = 0; + mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f; + if (fam15h_freq_tab[mem_clk] == 0) { + return; + } + dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 4))); /* Retrieve NbDid, NbFid */ + nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) & 0x1)?2:1); + + pDCTstat->CH_MaxRdLat[Channel]++; + pDCTstat->CH_MaxRdLat[Channel] += ((((uint64_t)15 * 100000000000ULL) / ((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL)) + * ((uint64_t)nb_clk * 1000)) / 1000000000ULL; + + write_max_read_latency_to_registers(pMCTstat, pDCTstat, Channel, pDCTstat->CH_MaxRdLat[Channel]); + } + + if(_DisableDramECC) { + mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC); + } + + if(!_Wrap32Dis) { + msr = HWCR; + _RDMSR(msr, &lo, &hi); + lo &= ~(1<<17); /* restore HWCR.wrap32dis */ + _WRMSR(msr, lo, hi); + } + if(!_SSE2){ + cr4 = read_cr4(); + cr4 &= ~(1<<9); /* restore cr4.OSFXSR */ + write_cr4(cr4); + } + +#if DQS_TRAIN_DEBUG > 0 + { + u8 ChannelDTD; + printk(BIOS_DEBUG, "TrainMaxRdLatency: CH_MaxRdLat:\n"); + for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) { + printk(BIOS_DEBUG, "Channel:%x: %x\n", + ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]); + } + } +#endif + + printk(BIOS_DEBUG, "TrainMaxRdLatency: Status %x\n", pDCTstat->Status); + printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrStatus %x\n", pDCTstat->ErrStatus); + printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrCode %x\n", pDCTstat->ErrCode); + printk(BIOS_DEBUG, "TrainMaxRdLatency: Done\n\n"); +} + u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct) { if (pDCTstat->DIMMValidDCT[dct] == 0 ) { diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c index 4bfcc40..b354d92 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c @@ -168,6 +168,8 @@ static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat, static void ChangeMemClk(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) { + printk(BIOS_DEBUG, "%s: Start\n", __func__); + uint8_t DCT0Present; uint8_t DCT1Present; uint32_t dword; @@ -309,6 +311,8 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat, mct_Wait(15000); /* Wait for 750us */ } } + + printk(BIOS_DEBUG, "%s: Done\n", __func__); } /*
1
0
0
0
Patch set updated for coreboot: cpu/amd/family_10h-family_15h: Set up Family 15h Link Base Channel Buffer Count registers
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12038
-gerrit commit e0b12fee012228d417b73289bcb82447a60a07c6 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Sat Aug 8 20:30:36 2015 -0500 cpu/amd/family_10h-family_15h: Set up Family 15h Link Base Channel Buffer Count registers Change-Id: I8d616a64a5a9cf0b51288535f5050c6866d0996b Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/cpu/amd/family_10h-family_15h/init_cpus.c | 131 +++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c b/src/cpu/amd/family_10h-family_15h/init_cpus.c index 439e4fa..55df7a4 100644 --- a/src/cpu/amd/family_10h-family_15h/init_cpus.c +++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c @@ -1201,6 +1201,133 @@ static void cpuSetAMDPCI(u8 node) dword |= (compute_unit_buffer_count << 4); pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword); + uint8_t link; + uint8_t ganged; + uint8_t iolink; + uint8_t probe_filter_enabled = !!dual_node; + + /* Set up the Link Base Channel Buffer Count */ + uint8_t isoc_rsp_data; + uint8_t isoc_np_req_data; + uint8_t isoc_rsp_cmd; + uint8_t isoc_preq; + uint8_t isoc_np_req_cmd; + uint8_t free_data; + uint8_t free_cmd; + uint8_t rsp_data; + uint8_t np_req_data; + uint8_t probe_cmd; + uint8_t rsp_cmd; + uint8_t preq; + uint8_t np_req_cmd; + + /* Common settings for all links and system configurations */ + isoc_rsp_data = 0; + isoc_np_req_data = 0; + isoc_rsp_cmd = 0; + isoc_preq = 0; + isoc_np_req_cmd = 1; + free_cmd = 8; + + for (link = 0; link < 4; link++) { + if (AMD_CpuFindCapability(node, link, &offset)) { + ganged = !!(pci_read_config32(NODE_PCI(node, 0), (link << 2) + 0x170) & 0x1); + iolink = (AMD_checkLinkType(node, link, offset) & HTPHY_LINKTYPE_NONCOHERENT); + + if (!iolink && ganged) { + if (probe_filter_enabled) { + free_data = 0; + rsp_data = 3; + np_req_data = 3; + probe_cmd = 4; + rsp_cmd = 9; + preq = 2; + np_req_cmd = 8; + } else { + free_data = 0; + rsp_data = 3; + np_req_data = 3; + probe_cmd = 8; + rsp_cmd = 9; + preq = 2; + np_req_cmd = 4; + } + } else if (!iolink && !ganged) { + if (probe_filter_enabled) { + free_data = 0; + rsp_data = 3; + np_req_data = 3; + probe_cmd = 4; + rsp_cmd = 9; + preq = 2; + np_req_cmd = 8; + } else { + free_data = 0; + rsp_data = 3; + np_req_data = 3; + probe_cmd = 8; + rsp_cmd = 9; + preq = 2; + np_req_cmd = 4; + } + } else if (iolink && ganged) { + free_data = 0; + rsp_data = 1; + np_req_data = 0; + probe_cmd = 0; + rsp_cmd = 2; + preq = 7; + np_req_cmd = 14; + } else { + /* FIXME + * This is an educated guess as the BKDG does not specify + * the appropriate buffer counts for this case! + */ + free_data = 1; + rsp_data = 1; + np_req_data = 1; + probe_cmd = 0; + rsp_cmd = 2; + preq = 4; + np_req_cmd = 12; + } + + dword = pci_read_config32(NODE_PCI(node, 0), (link * 0x20) + 0x94); + dword &= ~(0x3 << 27); /* IsocRspData = isoc_rsp_data */ + dword |= ((isoc_rsp_data & 0x3) << 27); + dword &= ~(0x3 << 25); /* IsocNpReqData = isoc_np_req_data */ + dword |= ((isoc_np_req_data & 0x3) << 25); + dword &= ~(0x7 << 22); /* IsocRspCmd = isoc_rsp_cmd */ + dword |= ((isoc_rsp_cmd & 0x7) << 22); + dword &= ~(0x7 << 19); /* IsocPReq = isoc_preq */ + dword |= ((isoc_preq & 0x7) << 19); + dword &= ~(0x7 << 16); /* IsocNpReqCmd = isoc_np_req_cmd */ + dword |= ((isoc_np_req_cmd & 0x7) << 16); + pci_write_config32(NODE_PCI(node, 0), (link * 0x20) + 0x94, dword); + + dword = pci_read_config32(NODE_PCI(node, 0), (link * 0x20) + 0x90); + dword &= ~(0x1 << 31); /* LockBc = 0x1 */ + dword |= ((0x1 & 0x1) << 31); + dword &= ~(0x7 << 25); /* FreeData = free_data */ + dword |= ((free_data & 0x7) << 25); + dword &= ~(0x1f << 20); /* FreeCmd = free_cmd */ + dword |= ((free_cmd & 0x1f) << 20); + dword &= ~(0x3 << 18); /* RspData = rsp_data */ + dword |= ((rsp_data & 0x3) << 18); + dword &= ~(0x3 << 16); /* NpReqData = np_req_data */ + dword |= ((np_req_data & 0x3) << 16); + dword &= ~(0xf << 12); /* ProbeCmd = probe_cmd */ + dword |= ((probe_cmd & 0xf) << 12); + dword &= ~(0xf << 8); /* RspCmd = rsp_cmd */ + dword |= ((rsp_cmd & 0xf) << 8); + dword &= ~(0x7 << 5); /* PReq = preq */ + dword |= ((preq & 0x7) << 5); + dword &= ~(0x1f << 0); /* NpReqCmd = np_req_cmd */ + dword |= ((np_req_cmd & 0x1f) << 0); + pci_write_config32(NODE_PCI(node, 0), (link * 0x20) + 0x90, dword); + } + } + /* Set up the Link to XCS Token Counts */ uint8_t isoc_rsp_tok_1; uint8_t isoc_preq_tok_1; @@ -1218,10 +1345,6 @@ static void cpuSetAMDPCI(u8 node) uint8_t preq_tok_0; uint8_t req_tok_0; - uint8_t link; - uint8_t ganged; - uint8_t iolink; - uint8_t probe_filter_enabled = !!dual_node; for (link = 0; link < 4; link++) { if (AMD_CpuFindCapability(node, link, &offset)) { ganged = !!(pci_read_config32(NODE_PCI(node, 0), (link << 2) + 0x170) & 0x1);
1
0
0
0
Patch set updated for coreboot: northbridge/amd/amdfam10: Add Family 15h cache partitioning support
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12036
-gerrit commit db0fcfa11d598ae9ef8e0063945d41ec34b47602 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Sat Aug 8 20:29:27 2015 -0500 northbridge/amd/amdfam10: Add Family 15h cache partitioning support Certain workloads may evict too many lines of other cores from the L3 cache if configured as one monolithic shared cache region. Forcibly partition L3 cache to improve performance. Change-Id: Ie4e28dd886aaa1c586b0919c5fe87ef1696f47e9 Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/northbridge/amd/amdfam10/northbridge.c | 94 ++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c index 17dabae..ced64aa 100644 --- a/src/northbridge/amd/amdfam10/northbridge.c +++ b/src/northbridge/amd/amdfam10/northbridge.c @@ -1805,9 +1805,103 @@ static void detect_and_enable_probe_filter(device_t dev) } } +static void detect_and_enable_cache_partitioning(device_t dev) +{ + uint8_t i; + uint32_t dword; + + if (is_fam15h()) { + printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n"); + + uint32_t f5x80; + uint8_t cu_enabled; + uint8_t compute_unit_count = 0; + + uint32_t f3xe8; + uint8_t dual_node = 0; + + for (i = 0; i < sysconf.nodes; i++) { + device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3)); + device_t f4x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 4)); + device_t f5x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 5)); + + f3xe8 = pci_read_config32(f3x_dev, 0xe8); + + /* Check for dual node capability */ + if (f3xe8 & 0x20000000) + dual_node = 1; + + /* Determine the number of active compute units on this node */ + f5x80 = pci_read_config32(f5x_dev, 0x80); + cu_enabled = f5x80 & 0xf; + if (cu_enabled == 0x1) + compute_unit_count = 1; + if (cu_enabled == 0x3) + compute_unit_count = 2; + if (cu_enabled == 0x7) + compute_unit_count = 3; + if (cu_enabled == 0xf) + compute_unit_count = 4; + + /* Disable BAN mode */ + dword = pci_read_config32(f3x_dev, 0x1b8); + dword &= ~(0x7 << 19); /* L3BanMode = 0x0 */ + pci_write_config32(f3x_dev, 0x1b8, dword); + + /* Set up cache mapping */ + dword = pci_read_config32(f4x_dev, 0x1d4); + if (compute_unit_count == 1) { + dword |= 0xf; /* ComputeUnit0SubCacheEn = 0xf */ + } + if (compute_unit_count == 2) { + dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0xc */ + dword |= (0xc << 4); + dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */ + dword |= 0x3; + } + if (compute_unit_count == 3) { + dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x8 */ + dword |= (0x8 << 8); + dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x4 */ + dword |= (0x4 << 4); + dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x3 */ + dword |= 0x3; + } + if (compute_unit_count == 4) { + dword &= ~(0xf << 12); /* ComputeUnit3SubCacheEn = 0x8 */ + dword |= (0x8 << 12); + dword &= ~(0xf << 8); /* ComputeUnit2SubCacheEn = 0x4 */ + dword |= (0x4 << 8); + dword &= ~(0xf << 4); /* ComputeUnit1SubCacheEn = 0x2 */ + dword |= (0x2 << 4); + dword &= ~0xf; /* ComputeUnit0SubCacheEn = 0x1 */ + dword |= 0x1; + } + pci_write_config32(f4x_dev, 0x1d4, dword); + + /* Enable cache partitioning */ + pci_write_config32(f4x_dev, 0x1d4, dword); + if (compute_unit_count == 1) { + dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x1 */ + dword |= (0x1 << 26); + } else if (compute_unit_count == 2) { + dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x3 */ + dword |= (0x3 << 26); + } else if (compute_unit_count == 3) { + dword &= ~(0xf << 26); /* MaskUpdateForComputeUnit = 0x7 */ + dword |= (0x7 << 26); + } else if (compute_unit_count == 4) { + dword |= (0xf << 26); /* MaskUpdateForComputeUnit = 0xf */ + } + pci_write_config32(f4x_dev, 0x1d4, dword); + } + } +} + static void cpu_bus_init(device_t dev) { detect_and_enable_probe_filter(dev); + detect_and_enable_cache_partitioning(dev); initialize_cpus(dev->link_list); #if CONFIG_AMD_SB_CIMX sb_After_Pci_Init();
1
0
0
0
Patch set updated for coreboot: arch/x86/acpi: Add IVRS table generation routines
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12043
-gerrit commit 11be922f94578e254dcafebb7495fa843bd50de9 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Tue Aug 11 17:48:32 2015 -0500 arch/x86/acpi: Add IVRS table generation routines Change-Id: Ia5d97d01dc9ddc45f81d998d126d592a915b4a75 Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/arch/x86/acpi.c | 25 +++++++++++++++++++++++++ src/arch/x86/include/arch/acpi.h | 31 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/arch/x86/acpi.c b/src/arch/x86/acpi.c index c540b5c..ccaab9e 100644 --- a/src/arch/x86/acpi.c +++ b/src/arch/x86/acpi.c @@ -6,6 +6,7 @@ * * Copyright (C) 2004 SUSE LINUX AG * Copyright (C) 2005-2009 coresystems GmbH + * Copyright (C) 2015 Timothy Pearson <tpearson(a)raptorengineeringinc.com>, Raptor Engineering * * ACPI FADT, FACS, and DSDT table support added by * Nick Barker <nick.barker9(a)btinternet.com>, and those portions @@ -531,6 +532,30 @@ void acpi_create_hpet(acpi_hpet_t *hpet) header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t)); } +void acpi_create_ivrs(acpi_ivrs_t *ivrs, + unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, unsigned long current)) +{ + acpi_header_t *header = &(ivrs->header); + unsigned long current = (unsigned long)ivrs + sizeof(acpi_ivrs_t); + + memset((void *)ivrs, 0, sizeof(acpi_ivrs_t)); + + /* Fill out header fields. */ + memcpy(header->signature, "IVRS", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(acpi_ivrs_t); + header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */ + + current = acpi_fill_ivrs(ivrs, current); + + /* (Re)calculate length and checksum. */ + header->length = current - (unsigned long)ivrs; + header->checksum = acpi_checksum((void *)ivrs, header->length); +} + unsigned long acpi_write_hpet(device_t device, unsigned long current, acpi_rsdp_t *rsdp) { acpi_hpet_t *hpet; diff --git a/src/arch/x86/include/arch/acpi.h b/src/arch/x86/include/arch/acpi.h index 87810b6..79ae7ed 100644 --- a/src/arch/x86/include/arch/acpi.h +++ b/src/arch/x86/include/arch/acpi.h @@ -4,6 +4,7 @@ * Copyright (C) 2004 SUSE LINUX AG * Copyright (C) 2004 Nick Barker * Copyright (C) 2008-2009 coresystems GmbH + * Copyright (C) 2015 Timothy Pearson <tpearson(a)raptorengineeringinc.com>, Raptor Engineering * (Written by Stefan Reinauer <stepan(a)coresystems.de>) * * This program is free software; you can redistribute it and/or modify @@ -190,6 +191,32 @@ typedef struct acpi_madt { u32 flags; /* Multiple APIC flags */ } __attribute__ ((packed)) acpi_madt_t; +typedef struct acpi_ivrs_info { +} __attribute__ ((packed)) acpi_ivrs_info_t; + +/* IVRS IVHD (I/O Virtualization Hardware Definition Block) */ +typedef struct acpi_ivrs_ivhd { + uint8_t type; + uint8_t flags; + uint16_t length; + uint16_t device_id; + uint16_t capability_offset; + uint32_t iommu_base_low; + uint32_t iommu_base_high; + uint16_t pci_segment_group; + uint16_t iommu_info; + uint32_t efr; + uint8_t entry[0]; +} __attribute__ ((packed)) acpi_ivrs_ivhd_t; + +/* IVRS (I/O Virtualization Reporting Structure) */ +typedef struct acpi_ivrs { + struct acpi_table_header header; + uint32_t iv_info; + uint32_t reserved[2]; + struct acpi_ivrs_ivhd ivhd; +} __attribute__ ((packed)) acpi_ivrs_t; + enum dev_scope_type { SCOPE_PCI_ENDPOINT = 1, SCOPE_PCI_SUB = 2, @@ -498,6 +525,7 @@ unsigned long fw_cfg_acpi_tables(unsigned long start); unsigned long write_acpi_tables(unsigned long addr); unsigned long acpi_fill_madt(unsigned long current); unsigned long acpi_fill_mcfg(unsigned long current); +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current); void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char *oem_table_id); void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs, void *dsdt); #if IS_ENABLED(CONFIG_COMMON_FADT) @@ -536,6 +564,9 @@ void acpi_create_srat(acpi_srat_t *srat, void acpi_create_slit(acpi_slit_t *slit, unsigned long (*acpi_fill_slit)(unsigned long current)); +void acpi_create_ivrs(acpi_ivrs_t *ivrs, + unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, unsigned long current)); + #if ENV_RAMSTAGE void acpi_create_hpet(acpi_hpet_t *hpet); unsigned long acpi_write_hpet(device_t device, unsigned long start, acpi_rsdp_t *rsdp);
1
0
0
0
Patch set updated for coreboot: northbridge/amd/amdht: Add isochronous setup support for coherent fabric
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12042
-gerrit commit 483408ffa58f95cdb2664cd4723eb0afa610309e Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Tue Aug 11 17:47:48 2015 -0500 northbridge/amd/amdht: Add isochronous setup support for coherent fabric Change-Id: Idd7c9b94a65f856b0059e1d45f8719d9475771b6 Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/cpu/amd/family_10h-family_15h/init_cpus.c | 61 +++++++++++++++++++++++++++ src/northbridge/amd/amdht/h3ffeat.h | 3 ++ src/northbridge/amd/amdht/h3finit.c | 35 ++++++++++++++- src/northbridge/amd/amdht/h3finit.h | 4 +- src/northbridge/amd/amdht/h3ncmn.c | 30 ++++++++++++- 5 files changed, 129 insertions(+), 4 deletions(-) diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c b/src/cpu/amd/family_10h-family_15h/init_cpus.c index da45888..635f357 100644 --- a/src/cpu/amd/family_10h-family_15h/init_cpus.c +++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c @@ -1666,6 +1666,67 @@ static void cpuSetAMDPCI(u8 node) pci_write_config32(NODE_PCI(node, 3), 0x140, dword); } + uint8_t link; + uint8_t isochronous; + uint8_t isochronous_link_present; + + /* Set up isochronous buffers if needed */ + isochronous_link_present = 0; + if (revision & AMD_FAM15_ALL) { + for (link = 0; link < 4; link++) { + if (AMD_CpuFindCapability(node, link, &offset)) { + isochronous = (pci_read_config32(NODE_PCI(node, 0), (link * 0x20) + 0x84) >> 12) & 0x1; + + if (isochronous) + isochronous_link_present = 1; + } + } + } + + uint8_t free_tok; + uint8_t up_rsp_cbc; + uint8_t isoc_preq_cbc; + uint8_t isoc_preq_tok; + uint8_t xbar_to_sri_free_list_cbc; + if (isochronous_link_present) { + /* Adjust buffer counts */ + dword = pci_read_config32(NODE_PCI(node, 3), 0x70); + isoc_preq_cbc = (dword >> 24) & 0x7; + up_rsp_cbc = (dword >> 16) & 0x7; + up_rsp_cbc--; + isoc_preq_cbc++; + dword &= ~(0x7 << 24); /* IsocPreqCBC = isoc_preq_cbc */ + dword |= ((isoc_preq_cbc & 0x7) << 24); + dword &= ~(0x7 << 16); /* UpRspCBC = up_rsp_cbc */ + dword |= ((up_rsp_cbc & 0x7) << 16); + pci_write_config32(NODE_PCI(node, 3), 0x70, dword); + + dword = pci_read_config32(NODE_PCI(node, 3), 0x74); + isoc_preq_cbc = (dword >> 24) & 0x7; + isoc_preq_cbc++; + dword &= ~(0x7 << 24); /* IsocPreqCBC = isoc_preq_cbc */ + dword |= (isoc_preq_cbc & 0x7) << 24; + pci_write_config32(NODE_PCI(node, 3), 0x74, dword); + + dword = pci_read_config32(NODE_PCI(node, 3), 0x7c); + xbar_to_sri_free_list_cbc = dword & 0x1f; + xbar_to_sri_free_list_cbc--; + dword &= ~0x1f; /* Xbar2SriFreeListCBC = xbar_to_sri_free_list_cbc */ + dword |= xbar_to_sri_free_list_cbc & 0x1f; + pci_write_config32(NODE_PCI(node, 3), 0x7c, dword); + + dword = pci_read_config32(NODE_PCI(node, 3), 0x140); + free_tok = (dword >> 20) & 0xf; + isoc_preq_tok = (dword >> 14) & 0x3; + free_tok--; + isoc_preq_tok++; + dword &= ~(0xf << 20); /* FreeTok = free_tok */ + dword |= ((free_tok & 0xf) << 20); + dword &= ~(0x3 << 14); /* IsocPreqTok = isoc_preq_tok */ + dword |= ((isoc_preq_tok & 0x3) << 14); + pci_write_config32(NODE_PCI(node, 3), 0x140, dword); + } + printk(BIOS_DEBUG, " done\n"); } diff --git a/src/northbridge/amd/amdht/h3ffeat.h b/src/northbridge/amd/amdht/h3ffeat.h index 628b86e..bcd4c10 100644 --- a/src/northbridge/amd/amdht/h3ffeat.h +++ b/src/northbridge/amd/amdht/h3ffeat.h @@ -75,6 +75,7 @@ #define HTSLAVE_LINK01_OFFSET 4 #define HTSLAVE_LINK_CONTROL_0_REG 4 #define HTSLAVE_FREQ_REV_0_REG 0xC +#define HTSLAVE_FEATURE_CAP_REG 0x10 /* HT3 gen Capability */ #define IS_HT_GEN3_CAPABILITY(reg) \ @@ -122,10 +123,12 @@ typedef struct u8 SelWidthIn; u8 SelWidthOut; u8 SelFrequency; + uint8_t enable_isochronous_mode; /* This section is for keeping track of capabilities and possible configurations */ BOOL RegangCap; uint32_t PrvFrequencyCap; + uint32_t PrvFeatureCap; u8 PrvWidthInCap; u8 PrvWidthOutCap; uint32_t CompositeFrequencyCap; diff --git a/src/northbridge/amd/amdht/h3finit.c b/src/northbridge/amd/amdht/h3finit.c index e4ce768..6a45f10 100644 --- a/src/northbridge/amd/amdht/h3finit.c +++ b/src/northbridge/amd/amdht/h3finit.c @@ -1415,6 +1415,38 @@ static void regangLinks(sMainData *pDat) #endif /* HT_BUILD_NC_ONLY */ } +static void detectIoLinkIsochronousCapable(sMainData *pDat) +{ + uint8_t i; + unsigned char iommu; + uint8_t isochronous_capable = 0; + + iommu = 1; + get_option(&iommu, "iommu"); + + for (i = 0; i < pDat->TotalLinks*2; i += 2) { + if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && (pDat->PortList[i+1].Type == PORTLIST_TYPE_IO)) { + if ((pDat->PortList[i].PrvFeatureCap & 0x1) && (pDat->PortList[i+1].PrvFeatureCap & 0x1)) { + pDat->PortList[i].enable_isochronous_mode = 1; + pDat->PortList[i+1].enable_isochronous_mode = 1; + isochronous_capable = 1; + } else { + pDat->PortList[i].enable_isochronous_mode = 0; + pDat->PortList[i+1].enable_isochronous_mode = 0; + } + } + } + + if (isochronous_capable && iommu) { + printk(BIOS_DEBUG, "Forcing HT links to isochronous mode due to enabled IOMMU\n"); + /* Isochronous mode must be set on all links if the IOMMU is enabled */ + for (i = 0; i < pDat->TotalLinks*2; i += 2) { + pDat->PortList[i].enable_isochronous_mode = 1; + pDat->PortList[i+1].enable_isochronous_mode = 1; + } + } +} + /*---------------------------------------------------------------------------------------- * void * selectOptimalWidthAndFrequency(sMainData *pDat) @@ -1535,7 +1567,6 @@ static void selectOptimalWidthAndFrequency(sMainData *pDat) temp = cbPCBBAUpstreamWidth; pDat->PortList[i].SelWidthIn = (u8)temp; pDat->PortList[i+1].SelWidthOut = (u8)temp; - } } @@ -1697,6 +1728,8 @@ static void linkOptimization(sMainData *pDat) { pDat->nb->gatherLinkData(pDat, pDat->nb); regangLinks(pDat); + if (is_fam15h()) + detectIoLinkIsochronousCapable(pDat); selectOptimalWidthAndFrequency(pDat); hammerSublinkFixup(pDat); pDat->nb->setLinkData(pDat, pDat->nb); diff --git a/src/northbridge/amd/amdht/h3finit.h b/src/northbridge/amd/amdht/h3finit.h index 1bd8616..ab2dace 100644 --- a/src/northbridge/amd/amdht/h3finit.h +++ b/src/northbridge/amd/amdht/h3finit.h @@ -227,6 +227,7 @@ typedef struct { * @param[in,out] u8* LinkWidthIn = modify to change the Link Witdh In * @param[in,out] u8* LinkWidthOut = modify to change the Link Witdh Out * @param[in,out] u32* FreqCap = modify to change the link's frequency capability + * @param[in,out] u32* FeatureCap = modify to change the link's feature capability * * --------------------------------------------------------------------------------------- */ @@ -241,7 +242,8 @@ typedef struct { u8 Link, u8 *LinkWidthIn, u8 *LinkWidthOut, - u32 *FreqCap + u32 *FreqCap, + u32 *FeatureCap ); /**---------------------------------------------------------------------------------------- diff --git a/src/northbridge/amd/amdht/h3ncmn.c b/src/northbridge/amd/amdht/h3ncmn.c index c97d592..7937c6e 100644 --- a/src/northbridge/amd/amdht/h3ncmn.c +++ b/src/northbridge/amd/amdht/h3ncmn.c @@ -1429,12 +1429,15 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge *nb) temp &= 0x7; /* Mask off reserved values */ pDat->PortList[i].PrvFrequencyCap |= (temp << 17); } + + AmdPCIReadBits(linkBase + HTHOST_FEATURE_CAP_REG, 9, 0, &temp); + pDat->PortList[i].PrvFeatureCap = (u16)temp; } else { linkBase = pDat->PortList[i].Pointer; if (pDat->PortList[i].Link == 1) - linkBase += HTSLAVE_LINK01_OFFSET; + linkBase += HTSLAVE_LINK01_OFFSET; AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 22, 20, &temp); pDat->PortList[i].PrvWidthOutCap = convertBitsToWidth((u8)temp, pDat->nb); @@ -1445,6 +1448,9 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge *nb) AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 16, &temp); pDat->PortList[i].PrvFrequencyCap = (u16)temp; + AmdPCIReadBits(linkBase + HTSLAVE_FEATURE_CAP_REG, 7, 0, &temp); + pDat->PortList[i].PrvFeatureCap = (u16)temp; + if (pDat->HtBlock->AMD_CB_DeviceCapOverride) { linkBase &= 0xFFFFF000; @@ -1461,7 +1467,8 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge *nb) pDat->PortList[i].Link, &(pDat->PortList[i].PrvWidthInCap), &(pDat->PortList[i].PrvWidthOutCap), - &(pDat->PortList[i].PrvFrequencyCap)); + &(pDat->PortList[i].PrvFrequencyCap), + &(pDat->PortList[i].PrvFeatureCap)); } } } @@ -1562,6 +1569,16 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb) if (is_gt_rev_d()) AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG_2, 0, 0, &temp2); AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, &temp); + + /* Enable isochronous flow control mode if supported by chipset */ + if (is_fam15h()) { + if (pDat->PortList[i].enable_isochronous_mode) + temp = 1; + else + temp = 0; + setHtControlRegisterBits(linkBase + HTHOST_LINK_CONTROL_REG, 12, 12, &temp); + } + if (frequency_index > HT_FREQUENCY_1000M) /* Gen1 = 200MHz -> 1000MHz, Gen3 = 1200MHz -> 3200MHz */ { /* Enable for Gen3 frequencies */ @@ -1579,6 +1596,7 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb) CPU_HTNB_FUNC_00, REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link), 0, 0, &temp); + /* and Scrambling enable / disable */ AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID), makePCIBusFromNode(pDat->PortList[i].NodeID), @@ -1617,6 +1635,14 @@ static void setLinkData(sMainData *pDat, cNorthBridge *nb) bits = 0; } + /* Enable isochronous flow control mode if supported by chipset */ + if (is_fam15h()) { + if (pDat->PortList[i].enable_isochronous_mode) + temp = 1; + else + temp = 0; + } + /* Retry Enable */ isFound = FALSE; currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI Offset to 0 */
1
0
0
0
Patch set updated for coreboot: amd/amdfam10: Control Family 15h cache partitioning and memory performance via nvram
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12041
-gerrit commit f6478cf9a18f4a6fdbec347b1e1f6433d0e0fe75 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Sun Aug 9 02:47:51 2015 -0500 amd/amdfam10: Control Family 15h cache partitioning and memory performance via nvram Change-Id: I3dd5d7f3640aee0395a68645c0242307605d3ce7 Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/cpu/amd/family_10h-family_15h/defaults.h | 5 ++--- src/cpu/amd/family_10h-family_15h/init_cpus.c | 16 ++++++++++++++-- src/mainboard/asus/kgpe-d16/cmos.default | 3 +++ src/mainboard/asus/kgpe-d16/cmos.layout | 9 +++++++-- src/northbridge/amd/amdfam10/northbridge.c | 22 ++++++++++++++++++++++ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 11 ++++++++++- 6 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h b/src/cpu/amd/family_10h-family_15h/defaults.h index d4999b9..7fd115c 100644 --- a/src/cpu/amd/family_10h-family_15h/defaults.h +++ b/src/cpu/amd/family_10h-family_15h/defaults.h @@ -135,9 +135,8 @@ static const struct { 0x00000000, 1 << (42-32)}, /* Bx [PwcDisableWalkerSharing]=1 */ { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL, - (0x3 << 20) | (0x1 << 22), 0x00000000, - (0x3 << 20) | (0x1 << 22), 0x00000000}, /* C0 or above [PfcDoubleStride]=1, - PfcStrideMul]=0x3 */ + 1 << 22, 0x00000000, + 1 << 22, 0x00000000}, /* C0 or above [PfcDoubleStride]=1 */ { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL, 0x00000000, 1 << (54-32), diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c b/src/cpu/amd/family_10h-family_15h/init_cpus.c index 55df7a4..da45888 100644 --- a/src/cpu/amd/family_10h-family_15h/init_cpus.c +++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c @@ -953,6 +953,7 @@ void cpuSetAMDMSR(uint8_t node_id) */ msr_t msr; u8 i; + uint8_t nvram; u32 platform; uint64_t revision; uint8_t enable_c_states; @@ -977,6 +978,13 @@ void cpuSetAMDMSR(uint8_t node_id) /* Revision C0 and above */ if (revision & AMD_OR_C0) { + uint8_t enable_experimental_memory_speed_boost; + + /* Check to see if cache partitioning is allowed */ + enable_experimental_memory_speed_boost = 0; + if (get_option(&nvram, "experimental_memory_speed_boost") == CB_SUCCESS) + enable_experimental_memory_speed_boost = !!nvram; + uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 0x1fc); msr = rdmsr(FP_CFG); msr.hi &= ~(0x7 << (42-32)); /* DiDtCfg4 */ @@ -996,11 +1004,15 @@ void cpuSetAMDMSR(uint8_t node_id) msr.lo &= ~(0x1 << 16); /* DiDtMode */ msr.lo |= ((f3x1fc & 0x1) << 16); wrmsr(FP_CFG, msr); + + if (enable_experimental_memory_speed_boost) { + msr = rdmsr(BU_CFG3); + msr.lo |= (0x3 << 20); /* PfcStrideMul = 0x3 */ + wrmsr(BU_CFG3, msr); + } } #if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800) - uint8_t nvram; - if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) { /* Set up message triggered C1E */ msr = rdmsr(0xc0010055); diff --git a/src/mainboard/asus/kgpe-d16/cmos.default b/src/mainboard/asus/kgpe-d16/cmos.default index 9994dad..9e36690 100644 --- a/src/mainboard/asus/kgpe-d16/cmos.default +++ b/src/mainboard/asus/kgpe-d16/cmos.default @@ -20,6 +20,9 @@ cpu_cc6_state = Enable sata_ahci_mode = Enable sata_alpm = Disable maximum_p_state_limit = 0xf +probe_filter = Auto +l3_cache_partitioning = Disable ieee1394_controller = Enable +experimental_memory_speed_boost = Disable power_on_after_fail = On boot_option = Fallback diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout b/src/mainboard/asus/kgpe-d16/cmos.layout index e17fec6..648091a 100644 --- a/src/mainboard/asus/kgpe-d16/cmos.layout +++ b/src/mainboard/asus/kgpe-d16/cmos.layout @@ -44,8 +44,11 @@ entries 468 1 e 1 sata_alpm 469 4 h 0 maximum_p_state_limit 473 2 e 13 dimm_spd_checksum -475 1 r 0 allow_spd_nvram_cache_restore -477 1 e 1 ieee1394_controller +475 1 e 14 probe_filter +476 1 e 1 l3_cache_partitioning +477 1 e 1 experimental_memory_speed_boost +478 1 r 0 allow_spd_nvram_cache_restore +479 1 e 1 ieee1394_controller 728 256 h 0 user_data 984 16 h 0 check_sum # Reserve the extended AMD configuration registers @@ -142,6 +145,8 @@ enumerations 13 0 Enforce 13 1 Ignore 13 2 Override +14 0 Disable +14 1 Auto checksums diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c index ced64aa..600fdf8 100644 --- a/src/northbridge/amd/amdfam10/northbridge.c +++ b/src/northbridge/amd/amdfam10/northbridge.c @@ -1650,6 +1650,17 @@ static void detect_and_enable_probe_filter(device_t dev) { uint32_t dword; + uint8_t nvram; + uint8_t enable_probe_filter; + + /* Check to see if the probe filter is allowed */ + enable_probe_filter = 1; + if (get_option(&nvram, "probe_filter") == CB_SUCCESS) + enable_probe_filter = !!nvram; + + if (!enable_probe_filter) + return; + uint8_t fam15h = 0; uint8_t rev_gte_d = 0; uint8_t dual_node = 0; @@ -1810,6 +1821,17 @@ static void detect_and_enable_cache_partitioning(device_t dev) uint8_t i; uint32_t dword; + uint8_t nvram; + uint8_t enable_l3_cache_partitioning; + + /* Check to see if cache partitioning is allowed */ + enable_l3_cache_partitioning = 0; + if (get_option(&nvram, "l3_cache_partitioning") == CB_SUCCESS) + enable_l3_cache_partitioning = !!nvram; + + if (!enable_l3_cache_partitioning) + return; + if (is_fam15h()) { printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n"); diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c index aad813a..a6cc70f 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c @@ -5559,6 +5559,14 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat, mct_ExtMCTConfig_Dx(pDCTstat); } else { /* Family 15h CPUs */ + uint8_t nvram; + uint8_t enable_experimental_memory_speed_boost; + + /* Check to see if cache partitioning is allowed */ + enable_experimental_memory_speed_boost = 0; + if (get_option(&nvram, "experimental_memory_speed_boost") == CB_SUCCESS) + enable_experimental_memory_speed_boost = !!nvram; + val = 0x0ce00f00; /* FlushWrOnStpGnt = 0x0 */ val |= 0x10 << 2; /* MctWrLimit = 0x10 */ val |= 0x1; /* DctWrLimit = 0x1 */ @@ -5572,7 +5580,8 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat, val &= ~(0x7 << 8); /* CohPrefPrbLmt = 0x1 */ val |= (0x1 << 8); val |= (0x1 << 12); /* EnSplitDctLimits = 0x1 */ - val |= (0x1 << 20); /* DblPrefEn = 0x1 */ + if (enable_experimental_memory_speed_boost) + val |= (0x1 << 20); /* DblPrefEn = 0x1 */ val |= (0x7 << 22); /* PrefFourConf = 0x7 */ val |= (0x7 << 25); /* PrefFiveConf = 0x7 */ val &= ~(0xf << 28); /* DcqBwThrotWm = 0x0 */
1
0
0
0
Patch set updated for coreboot: northbridge/amd/amdfam10: Fix gart setup not working on Family 15h processors
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12047
-gerrit commit 4b23d82e221161d9f63e6a771a6abf7e3cf13425 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Tue Aug 11 17:52:31 2015 -0500 northbridge/amd/amdfam10: Fix gart setup not working on Family 15h processors Change-Id: Ib78620c30502df6add9cc2ea1dbd4fb6dc89203e Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/northbridge/amd/amdfam10/misc_control.c | 34 ++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/northbridge/amd/amdfam10/misc_control.c b/src/northbridge/amd/amdfam10/misc_control.c index ed932a9..0b312b1 100644 --- a/src/northbridge/amd/amdfam10/misc_control.c +++ b/src/northbridge/amd/amdfam10/misc_control.c @@ -73,7 +73,7 @@ static void mcf3_read_resources(device_t dev) } } -static void set_agp_aperture(device_t dev) +static void set_agp_aperture(device_t dev, uint32_t pci_id) { struct resource *resource; @@ -93,7 +93,7 @@ static void set_agp_aperture(device_t dev) /* Update the other northbriges */ pdev = 0; - while((pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1203, pdev))) { + while ((pdev = dev_find_device(PCI_VENDOR_ID_AMD, pci_id, pdev))) { /* Store the GART size but don't enable it */ pci_write_config32(pdev, 0x90, gart_acr); @@ -109,10 +109,19 @@ static void set_agp_aperture(device_t dev) } } -static void mcf3_set_resources(device_t dev) +static void mcf3_set_resources_fam10h(device_t dev) { /* Set the gart apeture */ - set_agp_aperture(dev); + set_agp_aperture(dev, 0x1203); + + /* Set the generic PCI resources */ + pci_dev_set_resources(dev); +} + +static void mcf3_set_resources_fam15h(device_t dev) +{ + /* Set the gart apeture */ + set_agp_aperture(dev, 0x1603); /* Set the generic PCI resources */ pci_dev_set_resources(dev); @@ -151,9 +160,18 @@ static void misc_control_init(struct device *dev) } -static struct device_operations mcf3_ops = { +static struct device_operations mcf3_ops_fam10h = { + .read_resources = mcf3_read_resources, + .set_resources = mcf3_set_resources_fam10h, + .enable_resources = pci_dev_enable_resources, + .init = misc_control_init, + .scan_bus = 0, + .ops_pci = 0, +}; + +static struct device_operations mcf3_ops_fam15h = { .read_resources = mcf3_read_resources, - .set_resources = mcf3_set_resources, + .set_resources = mcf3_set_resources_fam15h, .enable_resources = pci_dev_enable_resources, .init = misc_control_init, .scan_bus = 0, @@ -161,13 +179,13 @@ static struct device_operations mcf3_ops = { }; static const struct pci_driver mcf3_driver __pci_driver = { - .ops = &mcf3_ops, + .ops = &mcf3_ops_fam10h, .vendor = PCI_VENDOR_ID_AMD, .device = 0x1203, }; static const struct pci_driver mcf3_driver_fam15 __pci_driver = { - .ops = &mcf3_ops, + .ops = &mcf3_ops_fam15h, .vendor = PCI_VENDOR_ID_AMD, .device = 0x1603, };
1
0
0
0
Patch set updated for coreboot: northbridge/amd/amdfam10: Rename mislabeled iommu nvram option to gart
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12046
-gerrit commit c54d037feed64cbc9bd7e0bdf556b9fee08f2dc9 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Tue Aug 11 17:52:03 2015 -0500 northbridge/amd/amdfam10: Rename mislabeled iommu nvram option to gart Change-Id: Ia24102e164eb5753ade3f9b5ab21eba2fa60836b Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/mainboard/advansus/a785e-i/cmos.layout | 2 +- src/mainboard/amd/bimini_fam10/cmos.layout | 2 +- src/mainboard/amd/mahogany_fam10/cmos.layout | 2 +- src/mainboard/amd/serengeti_cheetah_fam10/cmos.layout | 2 +- src/mainboard/amd/tilapia_fam10/cmos.layout | 2 +- src/mainboard/asus/kfsn4-dre/cmos.layout | 2 +- src/mainboard/asus/kgpe-d16/cmos.layout | 2 +- src/mainboard/asus/m4a78-em/cmos.layout | 2 +- src/mainboard/asus/m4a785-m/cmos.layout | 2 +- src/mainboard/asus/m4a785t-m/cmos.layout | 2 +- src/mainboard/asus/m5a88-v/cmos.layout | 2 +- src/mainboard/avalue/eax-785e/cmos.layout | 2 +- src/mainboard/gigabyte/ma785gm/cmos.layout | 2 +- src/mainboard/gigabyte/ma785gmt/cmos.layout | 2 +- src/mainboard/gigabyte/ma78gm/cmos.layout | 2 +- src/mainboard/hp/dl165_g6_fam10/cmos.layout | 2 +- src/mainboard/iei/kino-780am2-fam10/cmos.layout | 2 +- src/mainboard/jetway/pa78vm5/cmos.layout | 2 +- src/mainboard/msi/ms9652_fam10/cmos.layout | 2 +- src/mainboard/supermicro/h8dmr_fam10/cmos.layout | 2 +- src/mainboard/supermicro/h8qme_fam10/cmos.layout | 2 +- src/mainboard/supermicro/h8scm_fam10/cmos.layout | 2 +- src/mainboard/tyan/s2912_fam10/cmos.layout | 2 +- src/northbridge/amd/amdfam10/misc_control.c | 12 ++++++------ 24 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/mainboard/advansus/a785e-i/cmos.layout b/src/mainboard/advansus/a785e-i/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/advansus/a785e-i/cmos.layout +++ b/src/mainboard/advansus/a785e-i/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/amd/bimini_fam10/cmos.layout b/src/mainboard/amd/bimini_fam10/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/amd/bimini_fam10/cmos.layout +++ b/src/mainboard/amd/bimini_fam10/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/amd/mahogany_fam10/cmos.layout b/src/mainboard/amd/mahogany_fam10/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/amd/mahogany_fam10/cmos.layout +++ b/src/mainboard/amd/mahogany_fam10/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/cmos.layout b/src/mainboard/amd/serengeti_cheetah_fam10/cmos.layout index 14e45ef..3c0a4ed 100644 --- a/src/mainboard/amd/serengeti_cheetah_fam10/cmos.layout +++ b/src/mainboard/amd/serengeti_cheetah_fam10/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 446 1 e 1 power_on_after_fail 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection diff --git a/src/mainboard/amd/tilapia_fam10/cmos.layout b/src/mainboard/amd/tilapia_fam10/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/amd/tilapia_fam10/cmos.layout +++ b/src/mainboard/amd/tilapia_fam10/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/asus/kfsn4-dre/cmos.layout b/src/mainboard/asus/kfsn4-dre/cmos.layout index 66bc3a0..bd5fdbe 100644 --- a/src/mainboard/asus/kfsn4-dre/cmos.layout +++ b/src/mainboard/asus/kfsn4-dre/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 446 1 e 1 power_on_after_fail 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout b/src/mainboard/asus/kgpe-d16/cmos.layout index 648091a..a34547a 100644 --- a/src/mainboard/asus/kgpe-d16/cmos.layout +++ b/src/mainboard/asus/kgpe-d16/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 446 2 e 3 power_on_after_fail 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection diff --git a/src/mainboard/asus/m4a78-em/cmos.layout b/src/mainboard/asus/m4a78-em/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/asus/m4a78-em/cmos.layout +++ b/src/mainboard/asus/m4a78-em/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/asus/m4a785-m/cmos.layout b/src/mainboard/asus/m4a785-m/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/asus/m4a785-m/cmos.layout +++ b/src/mainboard/asus/m4a785-m/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/asus/m4a785t-m/cmos.layout b/src/mainboard/asus/m4a785t-m/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/asus/m4a785t-m/cmos.layout +++ b/src/mainboard/asus/m4a785t-m/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/asus/m5a88-v/cmos.layout b/src/mainboard/asus/m5a88-v/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/asus/m5a88-v/cmos.layout +++ b/src/mainboard/asus/m5a88-v/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/avalue/eax-785e/cmos.layout b/src/mainboard/avalue/eax-785e/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/avalue/eax-785e/cmos.layout +++ b/src/mainboard/avalue/eax-785e/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/gigabyte/ma785gm/cmos.layout b/src/mainboard/gigabyte/ma785gm/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/gigabyte/ma785gm/cmos.layout +++ b/src/mainboard/gigabyte/ma785gm/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/gigabyte/ma785gmt/cmos.layout b/src/mainboard/gigabyte/ma785gmt/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/gigabyte/ma785gmt/cmos.layout +++ b/src/mainboard/gigabyte/ma785gmt/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/gigabyte/ma78gm/cmos.layout b/src/mainboard/gigabyte/ma78gm/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/gigabyte/ma78gm/cmos.layout +++ b/src/mainboard/gigabyte/ma78gm/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/hp/dl165_g6_fam10/cmos.layout b/src/mainboard/hp/dl165_g6_fam10/cmos.layout index 73d53af..5602c70 100644 --- a/src/mainboard/hp/dl165_g6_fam10/cmos.layout +++ b/src/mainboard/hp/dl165_g6_fam10/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection 728 256 h 0 user_data diff --git a/src/mainboard/iei/kino-780am2-fam10/cmos.layout b/src/mainboard/iei/kino-780am2-fam10/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/iei/kino-780am2-fam10/cmos.layout +++ b/src/mainboard/iei/kino-780am2-fam10/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/jetway/pa78vm5/cmos.layout b/src/mainboard/jetway/pa78vm5/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/jetway/pa78vm5/cmos.layout +++ b/src/mainboard/jetway/pa78vm5/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/msi/ms9652_fam10/cmos.layout b/src/mainboard/msi/ms9652_fam10/cmos.layout index 14e45ef..3c0a4ed 100644 --- a/src/mainboard/msi/ms9652_fam10/cmos.layout +++ b/src/mainboard/msi/ms9652_fam10/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 446 1 e 1 power_on_after_fail 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection diff --git a/src/mainboard/supermicro/h8dmr_fam10/cmos.layout b/src/mainboard/supermicro/h8dmr_fam10/cmos.layout index 14e45ef..3c0a4ed 100644 --- a/src/mainboard/supermicro/h8dmr_fam10/cmos.layout +++ b/src/mainboard/supermicro/h8dmr_fam10/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 446 1 e 1 power_on_after_fail 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection diff --git a/src/mainboard/supermicro/h8qme_fam10/cmos.layout b/src/mainboard/supermicro/h8qme_fam10/cmos.layout index 14e45ef..3c0a4ed 100644 --- a/src/mainboard/supermicro/h8qme_fam10/cmos.layout +++ b/src/mainboard/supermicro/h8qme_fam10/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 446 1 e 1 power_on_after_fail 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection diff --git a/src/mainboard/supermicro/h8scm_fam10/cmos.layout b/src/mainboard/supermicro/h8scm_fam10/cmos.layout index 0ad18a2..bf58aac 100644 --- a/src/mainboard/supermicro/h8scm_fam10/cmos.layout +++ b/src/mainboard/supermicro/h8scm_fam10/cmos.layout @@ -12,7 +12,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 456 1 e 1 ECC_memory 728 256 h 0 user_data 984 16 h 0 check_sum diff --git a/src/mainboard/tyan/s2912_fam10/cmos.layout b/src/mainboard/tyan/s2912_fam10/cmos.layout index 14e45ef..3c0a4ed 100644 --- a/src/mainboard/tyan/s2912_fam10/cmos.layout +++ b/src/mainboard/tyan/s2912_fam10/cmos.layout @@ -31,7 +31,7 @@ entries 412 4 e 6 debug_level 440 4 e 9 slow_cpu 444 1 e 1 nmi -445 1 e 1 iommu +445 1 e 1 gart 446 1 e 1 power_on_after_fail 456 1 e 1 ECC_memory 457 1 e 1 ECC_redirection diff --git a/src/northbridge/amd/amdfam10/misc_control.c b/src/northbridge/amd/amdfam10/misc_control.c index 847b599..ed932a9 100644 --- a/src/northbridge/amd/amdfam10/misc_control.c +++ b/src/northbridge/amd/amdfam10/misc_control.c @@ -38,7 +38,7 @@ * * @param dev * - * There is only one AGP aperture resource needed. The resoruce is added to + * There is only one AGP aperture resource needed. The resource is added to * the northbridge of BSP. * * The same trick can be used to augment legacy VGA resources which can @@ -50,7 +50,7 @@ static void mcf3_read_resources(device_t dev) { struct resource *resource; - unsigned char iommu; + unsigned char gart; /* Read the generic PCI resources */ pci_dev_read_resources(dev); @@ -59,13 +59,13 @@ static void mcf3_read_resources(device_t dev) return; } - iommu = 1; - get_option(&iommu, "iommu"); + gart = 1; + get_option(&gart, "gart"); - if (iommu) { + if (gart) { /* Add a Gart apeture resource */ resource = new_resource(dev, 0x94); - resource->size = iommu?CONFIG_AGP_APERTURE_SIZE:1; + resource->size = gart?CONFIG_AGP_APERTURE_SIZE:1; resource->align = log2(resource->size); resource->gran = log2(resource->size); resource->limit = 0xffffffff; /* 4G */
1
0
0
0
Patch set updated for coreboot: southbridge/amd/sr5650: Hide clock configuration device after setup is complete
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12045
-gerrit commit eeb64f1d8631b3fadc140bf8e0a22400a4e698f4 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Thu Aug 13 17:45:12 2015 -0500 southbridge/amd/sr5650: Hide clock configuration device after setup is complete Change-Id: I043f2eb0993660d0a9351867eca1e73e0b2c37f1 Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/southbridge/amd/sr5650/early_setup.c | 16 ++++++++-------- src/southbridge/amd/sr5650/pcie.c | 3 +++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/southbridge/amd/sr5650/early_setup.c b/src/southbridge/amd/sr5650/early_setup.c index 95e6ebf..1fc0427 100644 --- a/src/southbridge/amd/sr5650/early_setup.c +++ b/src/southbridge/amd/sr5650/early_setup.c @@ -410,14 +410,14 @@ static void sr5650_por_misc_index_init(device_t nb_dev) set_nbmisc_enable_bits(nb_dev, 0x01, 0xFFFFFFFF, 0x00000310); /* NBCFG (NBMISCIND 0x0): NB_CNTL - - * HIDE_NB_AGP_CAP ([0], default=1)HIDE - * HIDE_P2P_AGP_CAP ([1], default=1)HIDE - * HIDE_NB_GART_BAR ([2], default=1)HIDE - * HIDE_MMCFG_BAR ([3], default=1)SHOW - * AGPMODE30 ([4], default=0)DISABLE - * AGP30ENCHANCED ([5], default=0)DISABLE - * HIDE_AGP_CAP ([8], default=1)ENABLE */ - set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 2 | 0 << 3 | 0 << 6); + * HIDE_NB_AGP_CAP ([0], default=1)HIDE + * HIDE_P2P_AGP_CAP ([1], default=1)HIDE + * HIDE_NB_GART_BAR ([2], default=1)HIDE + * HIDE_MMCFG_BAR ([3], default=1)SHOW + * AGPMODE30 ([4], default=0)DISABLE + * AGP30ENCHANCED ([5], default=0)DISABLE + * HIDE_CLKCFG_HEADER ([8], default=0)SHOW */ + set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 2 | 0 << 3 | 0 << 6 | 0 << 8); /* IOC_LAT_PERF_CNTR_CNTL */ set_nbmisc_enable_bits(nb_dev, 0x30, 0xFF, 0x00); diff --git a/src/southbridge/amd/sr5650/pcie.c b/src/southbridge/amd/sr5650/pcie.c index 4161c18..762e632 100644 --- a/src/southbridge/amd/sr5650/pcie.c +++ b/src/southbridge/amd/sr5650/pcie.c @@ -850,6 +850,9 @@ void sr56x0_lock_hwinitreg(void) /* Lock HWInit Register NBMISCIND:0x0 NBCNTL[7] HWINIT_WR_LOCK */ set_nbmisc_enable_bits(nb_dev, 0x00, 1 << 7, 1 << 7); + + /* Hide clock configuration PCI device HIDE_CLKCFG_HEADER */ + set_nbmisc_enable_bits(nb_dev, 0x00, 0x00000100, 1 << 8); } /*****************************************
1
0
0
0
Patch set updated for coreboot: southbridge/amd/sr5650: Add IOMMU support
by Timothy Pearson
23 Nov '15
23 Nov '15
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at
http://review.coreboot.org/12044
-gerrit commit 46799be68bc6ea8e9031fdb31f90081e7e7a2635 Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com> Date: Tue Aug 11 17:49:06 2015 -0500 southbridge/amd/sr5650: Add IOMMU support Change-Id: I2083d0c5653515c27d4626c62a6499b850f7547b Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com> --- src/include/device/pci_ids.h | 1 + src/mainboard/asus/kgpe-d16/acpi_tables.c | 37 ++ src/mainboard/supermicro/h8scm_fam10/acpi_tables.c | 37 ++ src/southbridge/amd/sr5650/cmn.h | 3 + src/southbridge/amd/sr5650/early_setup.c | 50 ++- src/southbridge/amd/sr5650/sr5650.c | 479 ++++++++++++++++++++- src/southbridge/amd/sr5650/sr5650.h | 14 + 7 files changed, 611 insertions(+), 10 deletions(-) diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h index 664ac49..72f1ece 100644 --- a/src/include/device/pci_ids.h +++ b/src/include/device/pci_ids.h @@ -429,6 +429,7 @@ #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV12 0x5A20 #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV13 0x5A1E #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV8 0x5A21 +#define PCI_DEVICE_ID_AMD_SR5650_IOMMU 0x5A23 #define PCI_DEVICE_ID_AMD_CZ_HDA 0x157A #define PCI_DEVICE_ID_AMD_CZ_LPC 0x790E diff --git a/src/mainboard/asus/kgpe-d16/acpi_tables.c b/src/mainboard/asus/kgpe-d16/acpi_tables.c index 3a4e6d8..24c1724 100644 --- a/src/mainboard/asus/kgpe-d16/acpi_tables.c +++ b/src/mainboard/asus/kgpe-d16/acpi_tables.c @@ -69,3 +69,40 @@ unsigned long acpi_fill_madt(unsigned long current) return current; } + +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current) +{ + uint8_t *p; + + uint32_t apicid_sp5100; + uint32_t apicid_sr5650; + + apicid_sp5100 = 0x20; + apicid_sr5650 = apicid_sp5100 + 1; + + /* Describe NB IOAPIC */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = apicid_sr5650; /* IOAPIC ID */ + p[5] = 0x1; /* Device 0 Function 1 */ + p[6] = 0x0; /* Northbridge bus */ + p[7] = 0x1; /* Variety */ + current += 8; + + /* Describe SB IOAPIC */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0xd7; /* Data */ + p[4] = apicid_sp5100; /* IOAPIC ID */ + p[5] = 0x14 << 3; /* Device 0x14 Function 0 */ + p[6] = 0x0; /* Southbridge bus */ + p[7] = 0x1; /* Variety */ + current += 8; + + return current; +} \ No newline at end of file diff --git a/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c b/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c index 0421d57..08910cc 100644 --- a/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c +++ b/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c @@ -62,3 +62,40 @@ unsigned long acpi_fill_madt(unsigned long current) return current; } + +unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current) +{ + uint8_t *p; + + uint32_t apicid_sp5100; + uint32_t apicid_sr5650; + + apicid_sp5100 = 0x20; + apicid_sr5650 = apicid_sp5100 + 1; + + /* Describe NB IOAPIC */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = apicid_sr5650; /* IOAPIC ID */ + p[5] = 0x1; /* Device 0 Function 1 */ + p[6] = 0x0; /* Northbridge bus */ + p[7] = 0x1; /* Variety */ + current += 8; + + /* Describe SB IOAPIC */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0xd7; /* Data */ + p[4] = apicid_sp5100; /* IOAPIC ID */ + p[5] = 0x14 << 3; /* Device 0x14 Function 0 */ + p[6] = 0x0; /* Southbridge bus */ + p[7] = 0x1; /* Variety */ + current += 8; + + return current; +} diff --git a/src/southbridge/amd/sr5650/cmn.h b/src/southbridge/amd/sr5650/cmn.h index db27d4f..0c0fd29 100644 --- a/src/southbridge/amd/sr5650/cmn.h +++ b/src/southbridge/amd/sr5650/cmn.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson <tpearson(a)raptorengineeringinc.com>, Raptor Engineering * * 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 @@ -22,6 +23,8 @@ #define NBHTIU_INDEX 0x94 /* Note: It is different with RS690, whose HTIU index is 0xA8 */ #define NBMC_INDEX 0xE8 #define NBPCIE_INDEX 0xE0 +#define L2CFG_INDEX 0xF0 +#define L1CFG_INDEX 0xF8 #define EXT_CONF_BASE_ADDRESS CONFIG_MMCONF_BASE_ADDRESS #define TEMP_MMIO_BASE_ADDRESS 0xC0000000 diff --git a/src/southbridge/amd/sr5650/early_setup.c b/src/southbridge/amd/sr5650/early_setup.c index b7bd1ab..95e6ebf 100644 --- a/src/southbridge/amd/sr5650/early_setup.c +++ b/src/southbridge/amd/sr5650/early_setup.c @@ -20,6 +20,8 @@ #include <arch/io.h> #include <console/console.h> #include <cpu/x86/msr.h> +#include <option.h> +#include <reset.h> #include "sr5650.h" #include "cmn.h" @@ -267,6 +269,34 @@ void sr5650_htinit(void) /* HT Buffer Allocation for Ganged Links!!! */ #endif /* CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 */ } + +} + +/* Must be run immediately after HT setup is complete and first warm reset has occurred (if applicable) + * Attempting to switch the NB into isochronous mode before the CPUs have engaged isochronous mode + * will cause a system hard lockup... + */ +void sr5650_htinit_dect_and_enable_isochronous_link(void) +{ + device_t sr5650_f0; + unsigned char iommu; + + sr5650_f0 = PCI_DEV(0, 0, 0); + + iommu = 1; + get_option(&iommu, "iommu"); + + if (iommu) { + /* Enable isochronous mode */ + set_nbcfg_enable_bits(sr5650_f0, 0xc8, 1 << 12, 1 << 12); + + /* Apply pending changes */ + if (!((pci_read_config32(sr5650_f0, 0xc8) >> 12) & 0x1)) { + printk(BIOS_INFO, "...WARM RESET...\n\n\n"); + soft_reset(); + die("After soft_reset_x - shouldn't see this message!!!\n"); + } + } } #if CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 /* save some spaces */ @@ -331,8 +361,21 @@ static void sr5650_por_pcicfg_init(device_t nb_dev) *****************************************/ static void sr5650_por_misc_index_init(device_t nb_dev) { - /* disable IOMMU */ - set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0); + unsigned char iommu; + + iommu = 1; + get_option(&iommu, "iommu"); + + if (iommu) { + /* enable IOMMU */ + printk(BIOS_DEBUG, "Enabling IOMMU\n"); + set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x1); + } else { + /* disable IOMMU */ + printk(BIOS_DEBUG, "Disabling IOMMU\n"); + set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0); + } + /* NBMISCIND:0x75[29]= 1 Device ID for hotplug and PME message */ set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 29, 1 << 29); set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 9, 1 << 9); /* no doc reference, comply with BTS */ @@ -370,10 +413,11 @@ static void sr5650_por_misc_index_init(device_t nb_dev) * HIDE_NB_AGP_CAP ([0], default=1)HIDE * HIDE_P2P_AGP_CAP ([1], default=1)HIDE * HIDE_NB_GART_BAR ([2], default=1)HIDE + * HIDE_MMCFG_BAR ([3], default=1)SHOW * AGPMODE30 ([4], default=0)DISABLE * AGP30ENCHANCED ([5], default=0)DISABLE * HIDE_AGP_CAP ([8], default=1)ENABLE */ - set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 2 | 0 << 6); + set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 2 | 0 << 3 | 0 << 6); /* IOC_LAT_PERF_CNTR_CNTL */ set_nbmisc_enable_bits(nb_dev, 0x30, 0xFF, 0x00); diff --git a/src/southbridge/amd/sr5650/sr5650.c b/src/southbridge/amd/sr5650/sr5650.c index 514e654..07b4a02 100644 --- a/src/southbridge/amd/sr5650/sr5650.c +++ b/src/southbridge/amd/sr5650/sr5650.c @@ -22,7 +22,9 @@ #include <device/pci_ops.h> #include <cpu/x86/msr.h> #include <cpu/amd/mtrr.h> +#include <stdlib.h> #include <delay.h> +#include <option.h> #include "sr5650.h" #include "cmn.h" @@ -83,6 +85,26 @@ void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 data) nb_write_index((nb_dev), NBPCIE_INDEX, (index), (data)); } +uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index) +{ + return nb_read_index((nb_dev), L2CFG_INDEX, (index)); +} + +void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data) +{ + nb_write_index((nb_dev), L2CFG_INDEX | (0x1 << 8), (index), (data)); +} + +uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index) +{ + return nb_read_index((nb_dev), L1CFG_INDEX, (index)); +} + +void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data) +{ + nb_write_index((nb_dev), L1CFG_INDEX | (0x1 << 31), (index), (data)); +} + /*********************************************************** * To access bar3 we need to program PCI MMIO 7 in K8. * in_out: @@ -282,6 +304,240 @@ u32 get_vid_did(device_t dev) return pci_read_config32(dev, 0); } +void detect_and_enable_iommu(device_t iommu_dev) { + uint32_t dword; + uint8_t l1_target; + unsigned char iommu; + void * mmio_base; + + iommu = 1; + get_option(&iommu, "iommu"); + + if (iommu) { + printk(BIOS_DEBUG, "Initializing IOMMU\n"); + + device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0)); + + if (!nb_dev) { + printk(BIOS_WARNING, "Unable to find SR5690 device! IOMMU NOT initialized\n"); + return; + } + + mmio_base = (void*)(pci_read_config32(iommu_dev, 0x44) & 0xffffc000); + + // if (get_nb_rev(nb_dev) == REV_SR5650_A11) { + // dword = pci_read_config32(iommu_dev, 0x6c); + // dword &= ~(0x1 << 8); + // pci_write_config32(iommu_dev, 0x6c, dword); + // } + + dword = pci_read_config32(iommu_dev, 0x50); + dword &= ~(0x1 << 22); + pci_write_config32(iommu_dev, 0x50, dword); + + dword = pci_read_config32(iommu_dev, 0x44); + dword |= 0x1; + pci_write_config32(iommu_dev, 0x44, dword); + + write32((void*)(mmio_base + 0x8), 0x0); + write32((void*)(mmio_base + 0xc), 0x08000000); + write32((void*)(mmio_base + 0x10), 0x0); + write32((void*)(mmio_base + 0x2008), 0x0); + write32((void*)(mmio_base + 0x2010), 0x0); + + /* IOMMU L1 initialization */ + for (l1_target = 0; l1_target < 6; l1_target++) { + dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) + 0xc); + dword |= (0x7 << 28); + l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0xc, dword); + + dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) + 0x7); + dword |= (0x1 << 5); + l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0x7, dword); + } + + /* IOMMU L2 initialization */ + dword = l2cfg_ind_read_index(nb_dev, 0xc); + dword |= (0x7 << 29); + l2cfg_ind_write_index(nb_dev, 0xc, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x10); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x10, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x14); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x14, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x18); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x18, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x1c); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x1c, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x50); + dword &= ~(0x3 << 8); + dword |= (0x2 << 8); + l2cfg_ind_write_index(nb_dev, 0x50, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x10); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x10, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x14); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x14, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x18); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x18, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x1c); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x1c, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x50); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x50, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 7); + l2cfg_ind_write_index(nb_dev, 0x6, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 0); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + +// if (get_nb_rev(nb_dev) == REV_SR5650_A21) { + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 1); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 1); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 2); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 3); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 3); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 5); + l2cfg_ind_write_index(nb_dev, 0x6, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 6); + l2cfg_ind_write_index(nb_dev, 0x6, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 5); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x44); + dword |= (0x1 << 4); + l2cfg_ind_write_index(nb_dev, 0x44, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 6); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x7); + dword |= (0x1 << 7); + l2cfg_ind_write_index(nb_dev, 0x7, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x6); + dword |= (0x1 << 8); + l2cfg_ind_write_index(nb_dev, 0x6, dword); +// } + + l2cfg_ind_write_index(nb_dev, 0x52, 0xf0000002); + + dword = l2cfg_ind_read_index(nb_dev, 0x80); + dword |= (0x1 << 0); + l2cfg_ind_write_index(nb_dev, 0x80, dword); + + dword = l2cfg_ind_read_index(nb_dev, 0x30); + dword |= (0x1 << 0); + l2cfg_ind_write_index(nb_dev, 0x30, dword); + } +} + +void sr5650_iommu_read_resources(device_t dev) +{ + unsigned char iommu; + struct resource *res; + + iommu = 1; + get_option(&iommu, "iommu"); + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + if (iommu) { + /* Request MMIO range allocation */ + res = new_resource(dev, 0x44); /* IOMMU */ + res->base = 0x0; + res->size = 0x4000; + res->limit = 0xFFFFFFFFUL; /* res->base + res->size -1; */ + res->align = 14; /* 16k alignment */ + res->gran = 14; + res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE; + } + + compact_resources(dev); +} + +void sr5650_iommu_set_resources(device_t dev) +{ + unsigned char iommu; + struct resource *res; + + iommu = 1; + get_option(&iommu, "iommu"); + + /* Get the normal pci resources of this device */ + pci_dev_read_resources(dev); + + if (iommu) { + /* Get the allocated range */ + res = find_resource(dev, 0x44); + + if (res->base == 0) { + printk(BIOS_WARNING, "Unable to allocate MMIO range to IOMMU\n"); + } + + /* Assign the range to hardware */ + pci_write_config32(dev, 0x44, res->base & 0xffffc000); + pci_write_config32(dev, 0x48, 0x0); + } + + /* Run standard resource set routine */ + pci_dev_set_resources(dev); +} + +void sr5650_iommu_enable_resources(device_t dev) +{ + detect_and_enable_iommu(dev); +} + void sr5650_nb_pci_table(device_t nb_dev) { /* NBPOR_InitPOR function. */ u8 temp8; @@ -361,13 +617,23 @@ void sr5650_enable(device_t dev) dev_ind = dev->path.pci.devfn >> 3; switch (dev_ind) { case 0: /* bus0, dev0, fun0; */ - printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n"); - enable_pcie_bar3(nb_dev); /* PCIEMiscInit */ - - config_gpp_core(nb_dev, sb_dev); - sr5650_gpp_sb_init(nb_dev, sb_dev, 8); - - sr5650_nb_pci_table(nb_dev); + switch (dev->path.pci.devfn & 0x7) { + case 0: + printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n"); + enable_pcie_bar3(nb_dev); /* PCIEMiscInit */ + + config_gpp_core(nb_dev, sb_dev); + sr5650_gpp_sb_init(nb_dev, sb_dev, 8); + + sr5650_nb_pci_table(nb_dev); + break; + case 1: + printk(BIOS_INFO, "Bus-0, Dev-0, Fun-1.\n"); + break; + case 2: + printk(BIOS_INFO, "Bus-0, Dev-0, Fun-2.\n"); + break; + } break; case 2: /* bus0, dev2,3 GPP1 */ @@ -434,6 +700,205 @@ void sr5650_enable(device_t dev) } } +static void add_ivrs_device_entries(struct device *parent, struct device *dev, int depth, int linknum, int8_t *root_level, unsigned long *current, uint16_t *length) +{ + uint8_t *p; + struct device *sibling; + struct bus *link; + + if (!root_level) { + root_level = malloc(sizeof(int8_t)); + *root_level = -1; + } + + if (dev->path.type == DEVICE_PATH_PCI) { + if ((dev->bus->secondary == 0x0) && (dev->path.pci.devfn == 0x0)) + *root_level = depth; + + if (*root_level != -1) { + if (depth >= *root_level) { + if (dev->enabled) { + if (depth == *root_level) { + if (dev->path.pci.devfn < (0x1 << 3)) { + /* SR5690 control device */ + } else if ((dev->path.pci.devfn >= (0x1 << 3)) && (dev->path.pci.devfn < (0xe << 3))) { + /* SR5690 PCIe bridge device */ + } else { + if (dev->path.pci.devfn == (0x14 << 3)) { + /* SMBUS controller */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x97; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } else { + /* Other southbridge device */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } + } + } else { + if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_NORMAL) { + /* Device behind bridge */ + if (pci_find_capability(dev, PCI_CAP_ID_PCIE)) { + /* Device is PCIe */ + p = (uint8_t *) *current; + p[0] = 0x2; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Padding */ + p[5] = 0x0; /* Padding */ + p[6] = 0x0; /* Padding */ + p[7] = 0x0; /* Padding */ + *length += 8; + *current += 8; + } else { + /* Device is legacy PCI or PCI-X */ + p = (uint8_t *) *current; + p[0] = 0x42; /* Entry type */ + p[1] = dev->path.pci.devfn; /* Device */ + p[2] = dev->bus->secondary; /* Bus */ + p[3] = 0x0; /* Data */ + p[4] = 0x0; /* Reserved */ + p[5] = parent->path.pci.devfn; /* Device */ + p[6] = parent->bus->secondary; /* Bus */ + p[7] = 0x0; /* Reserved */ + *length += 8; + *current += 8; + } + } + } + } + } + } + } + + for (link = dev->link_list; link; link = link->next) + for (sibling = link->children; sibling; sibling = sibling->sibling) + add_ivrs_device_entries(dev, sibling, depth + 1, depth, root_level, current, length); + + free(root_level); +} + +static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current) +{ + uint8_t *p; + + device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0)); + if (!nb_dev) { + printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 device! IVRS table not generated...\n"); + return (unsigned long)ivrs; + } + + device_t iommu_dev = dev_find_slot(0, PCI_DEVFN(0, 2)); + if (!iommu_dev) { + printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 IOMMU device! IVRS table not generated...\n"); + return (unsigned long)ivrs; + } + + ivrs->iv_info = 0x0; + ivrs->iv_info |= (0x40 << 15); /* Maximum supported virtual address size */ + ivrs->iv_info |= (0x34 << 8); /* Maximum supported physical address size */ + + ivrs->ivhd.type = 0x10; + ivrs->ivhd.flags = 0x0e; + // if (get_nb_rev(nb_dev) != REV_SR5650_A11) { + ivrs->ivhd.flags |= 0x10; /* Enable ATS support on all revisions except A11 */ + // } + ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd); + ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8); /* BDF <bus>:00.2 */ + ivrs->ivhd.capability_offset = 0x40; /* Capability block 0x40 (type 0xf, "Secure device") */ + ivrs->ivhd.iommu_base_low = pci_read_config32(iommu_dev, 0x44) & 0xffffc000; + ivrs->ivhd.iommu_base_high = pci_read_config32(iommu_dev, 0x48); + ivrs->ivhd.pci_segment_group = 0x0; + ivrs->ivhd.iommu_info = 0x0; + ivrs->ivhd.iommu_info |= (0x14 << 8); + ivrs->ivhd.efr = 0x0; + + /* Describe HPET */ + p = (uint8_t *)current; + p[0] = 0x48; /* Entry type */ + p[1] = 0; /* Device */ + p[2] = 0; /* Bus */ + p[3] = 0xd7; /* Data */ + p[4] = 0x0; /* HPET number */ + p[5] = 0x14 << 3; /* HPET device */ + p[6] = nb_dev->bus->secondary; /* HPET bus */ + p[7] = 0x2; /* Variety */ + ivrs->ivhd.length += 8; + current += 8; + + /* Describe PCI devices */ + add_ivrs_device_entries(NULL, all_devices, 0, -1, NULL, ¤t, &ivrs->ivhd.length); + + /* Describe IOAPICs */ + unsigned long prev_current = current; + current = acpi_fill_ivrs_ioapic(ivrs, current); + ivrs->ivhd.length += (current - prev_current); + + return current; +} + +unsigned long southbridge_write_acpi_tables(device_t device, + unsigned long current, + struct acpi_rsdp *rsdp) +{ + unsigned char iommu; + + iommu = 1; + get_option(&iommu, "iommu"); + + if (iommu) { + acpi_ivrs_t *ivrs; + + /* IVRS */ + current = ALIGN(current, 8); + printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current); + ivrs = (acpi_ivrs_t *) current; + acpi_create_ivrs(ivrs, acpi_fill_ivrs); + current += ivrs->header.length; + acpi_add_table(rsdp, ivrs); + } + + return current; +} + +static struct pci_operations iommu_ops_pci = { + .set_subsystem = pci_dev_set_subsystem, +}; + +static struct device_operations iommu_ops = { + .read_resources = sr5650_iommu_read_resources, + .set_resources = sr5650_iommu_set_resources, + .enable_resources = sr5650_iommu_enable_resources, + .write_acpi_tables = southbridge_write_acpi_tables, + .init = 0, + .scan_bus = 0, + .ops_pci = &iommu_ops_pci, +}; + +static const struct pci_driver ht_driver_sr5690 __pci_driver = { + .ops = &iommu_ops, + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_AMD_SR5650_IOMMU, +}; + struct chip_operations southbridge_amd_sr5650_ops = { CHIP_NAME("ATI SR5650") .enable_dev = sr5650_enable, diff --git a/src/southbridge/amd/sr5650/sr5650.h b/src/southbridge/amd/sr5650/sr5650.h index 21acca3..bad3529 100644 --- a/src/southbridge/amd/sr5650/sr5650.h +++ b/src/southbridge/amd/sr5650/sr5650.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2010 Advanced Micro Devices, Inc. + * Copyright (C) 2015 Timothy Pearson <tpearson(a)raptorengineeringinc.com>, Raptor Engineering * * 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 @@ -17,6 +18,7 @@ #define __SR5650_H__ #include <stdint.h> +#include <arch/acpi.h> #include <device/pci_ids.h> #include "chip.h" #include "rev.h" @@ -91,16 +93,24 @@ u32 nbpcie_p_read_index(device_t dev, u32 index); void nbpcie_p_write_index(device_t dev, u32 index, u32 data); u32 nbpcie_ind_read_index(device_t nb_dev, u32 index); void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 data); +uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index); +void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data); +uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index); +void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data); u32 pci_ext_read_config32(device_t nb_dev, device_t dev, u32 reg); void pci_ext_write_config32(device_t nb_dev, device_t dev, u32 reg, u32 mask, u32 val); void sr5650_set_tom(device_t nb_dev); +unsigned long southbridge_write_acpi_tables(device_t device, unsigned long current, + struct acpi_rsdp *rsdp); + void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add); void enable_pcie_bar3(device_t nb_dev); void disable_pcie_bar3(device_t nb_dev); void enable_sr5650_dev8(void); void sr5650_htinit(void); +void sr5650_htinit_dect_and_enable_isochronous_link(void); void sr5650_early_setup(void); void sr5650_before_pci_init(void); void sr5650_enable(device_t dev); @@ -114,6 +124,10 @@ void pcie_config_misc_clk(device_t nb_dev); void fam10_optimization(void); void sr5650_disable_pcie_bridge(void); u32 get_vid_did(device_t dev); +void detect_and_enable_iommu(device_t iommu_dev); +void sr5650_iommu_read_resources(device_t dev); +void sr5650_iommu_set_resources(device_t dev); +void sr5650_iommu_enable_resources(device_t dev); void sr5650_nb_pci_table(device_t nb_dev); void init_gen2(device_t nb_dev, device_t dev, u8 port); void sr56x0_lock_hwinitreg(void);
1
0
0
0
← Newer
1
...
29
30
31
32
33
34
35
...
155
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
Results per page:
10
25
50
100
200