diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-10-16 13:51:51 -0500 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2015-11-02 23:45:19 +0100 |
commit | 730a043fb6cb4dd3cb5af8f8640365727b598648 (patch) | |
tree | 59afe45caca1a8e1682939c7e44e95344104533e /src/northbridge/amd/amdfam10/raminit_amdmct.c | |
parent | d150006c4a4584bc9933c2d8ff580a54c4f0cc2a (diff) |
cpu/amd: Add initial AMD Family 15h support
TEST: Booted ASUS KGPE-D16 with single Opteron 6380
* Unbuffered DDR3 DIMMs tested and working
* Suspend to RAM (S3) tested and working
Change-Id: Idffd2ce36ce183fbfa087e5ba69a9148f084b45e
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
Reviewed-on: http://review.coreboot.org/11966
Tested-by: build bot (Jenkins)
Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/northbridge/amd/amdfam10/raminit_amdmct.c')
-rw-r--r-- | src/northbridge/amd/amdfam10/raminit_amdmct.c | 304 |
1 files changed, 281 insertions, 23 deletions
diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c b/src/northbridge/amd/amdfam10/raminit_amdmct.c index 30b5e8aa7a..d8023f808c 100644 --- a/src/northbridge/amd/amdfam10/raminit_amdmct.c +++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c @@ -38,8 +38,120 @@ static void print_tf(const char *func, const char *strval) #endif } -static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t freq) +static inline void fam15h_switch_dct(uint32_t dev, uint8_t dct) { + uint32_t dword; + + dword = Get_NB32(dev, 0x10c); + dword &= ~0x1; + dword |= (dct & 0x1); + Set_NB32(dev, 0x10c, dword); +} + +static inline void fam15h_switch_nb_pstate_config_reg(uint32_t dev, uint8_t nb_pstate) +{ + uint32_t dword; + + dword = Get_NB32(dev, 0x10c); + dword &= ~(0x3 << 4); + dword |= (nb_pstate & 0x3) << 4; + Set_NB32(dev, 0x10c, dword); +} + +static inline uint32_t Get_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg) +{ + if (is_fam15h()) { + /* Obtain address of function 0x1 */ + uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12); + fam15h_switch_dct(dev_map, dct); + return Get_NB32(dev, reg); + } else { + return Get_NB32(dev, (0x100 * dct) + reg); + } +} + +static inline void Set_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg, uint32_t val) +{ + if (is_fam15h()) { + /* Obtain address of function 0x1 */ + uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12); + fam15h_switch_dct(dev_map, dct); + Set_NB32(dev, reg, val); + } else { + Set_NB32(dev, (0x100 * dct) + reg, val); + } +} + +static inline uint32_t Get_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, uint8_t nb_pstate, uint32_t reg) +{ + if (is_fam15h()) { + /* Obtain address of function 0x1 */ + uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12); + fam15h_switch_dct(dev_map, dct); + fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate); + return Get_NB32(dev, reg); + } else { + return Get_NB32(dev, (0x100 * dct) + reg); + } +} + +static inline void Set_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, uint8_t nb_pstate, uint32_t reg, uint32_t val) +{ + if (is_fam15h()) { + /* Obtain address of function 0x1 */ + uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12); + fam15h_switch_dct(dev_map, dct); + fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate); + Set_NB32(dev, reg, val); + } else { + Set_NB32(dev, (0x100 * dct) + reg, val); + } +} + +static inline uint32_t Get_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, uint32_t index_reg, uint32_t index) +{ + if (is_fam15h()) { + /* Obtain address of function 0x1 */ + uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12); + fam15h_switch_dct(dev_map, dct); + return Get_NB32_index_wait(dev, index_reg, index); + } else { + return Get_NB32_index_wait(dev, (0x100 * dct) + index_reg, index); + } +} + +static inline void Set_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, uint32_t index_reg, uint32_t index, uint32_t data) +{ + if (is_fam15h()) { + /* Obtain address of function 0x1 */ + uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12); + fam15h_switch_dct(dev_map, dct); + Set_NB32_index_wait(dev, index_reg, index, data); + } else { + Set_NB32_index_wait(dev, (0x100 * dct) + index_reg, index, data); + } +} + +static uint16_t voltage_index_to_mv(uint8_t index) +{ + if (index & 0x8) + return 1150; + if (index & 0x4) + return 1250; + else if (index & 0x2) + return 1350; + else + return 1500; +} + +static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t highest_rank_count, uint8_t registered, uint8_t voltage, uint16_t freq) +{ + /* FIXME + * Mainboards need to be able to specify the maximum number of DIMMs installable per channel + * For now assume a maximum of 2 DIMMs per channel can be installed + */ + uint8_t MaxDimmsInstallable = 2; + /* Return limited maximum RAM frequency */ if (IS_ENABLED(CONFIG_DIMM_DDR2)) { if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) { @@ -62,34 +174,178 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t freq } } } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) { - if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) { - /* K10 BKDG Rev. 3.62 Table 34 */ - if (count > 2) { - /* Limit to DDR3-800 */ - if (freq > 400) { - freq = 400; - print_tf(__func__, ": More than 2 registered DIMMs on channel; limiting to DDR3-800\n"); + if (voltage == 0) { + printk(BIOS_DEBUG, "%s: WARNING: Mainboard DDR3 voltage unknown, assuming 1.5V!\n", __func__); + voltage = 0x1; + } + + if (is_fam15h()) { + if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) { + /* Fam15h BKDG Rev. 3.14 Table 27 */ + if (voltage & 0x4) { + /* 1.25V */ + if (count > 1) { + if (highest_rank_count > 1) { + /* Limit to DDR3-1066 */ + if (freq > 533) { + freq = 533; + printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1066\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else if (voltage & 0x2) { + /* 1.35V */ + if (count > 1) { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1600 */ + if (freq > 800) { + freq = 800; + printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else if (voltage & 0x1) { + /* 1.50V */ + if (count > 1) { + /* Limit to DDR3-1600 */ + if (freq > 800) { + freq = 800; + printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1866 */ + if (freq > 933) { + freq = 933; + printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1866\n", __func__, voltage_index_to_mv(voltage)); + } + } + } + } else { + /* Fam15h BKDG Rev. 3.14 Table 26 */ + if (voltage & 0x4) { + /* 1.25V */ + if (count > 1) { + if (highest_rank_count > 1) { + /* Limit to DDR3-1066 */ + if (freq > 533) { + freq = 533; + printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1066\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else if (voltage & 0x2) { + /* 1.35V */ + if (MaxDimmsInstallable > 1) { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1600 */ + if (freq > 800) { + freq = 800; + printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else if (voltage & 0x1) { + if (MaxDimmsInstallable == 1) { + if (count > 1) { + /* Limit to DDR3-1600 */ + if (freq > 800) { + freq = 800; + printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1866 */ + if (freq > 933) { + freq = 933; + printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1866\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else { + if (count > 1) { + if (highest_rank_count > 1) { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1600 */ + if (freq > 800) { + freq = 800; + printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage)); + } + } + } else { + /* Limit to DDR3-1600 */ + if (freq > 800) { + freq = 800; + printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, voltage_index_to_mv(voltage)); + } + } + } } - } else if (count == 2) { - /* Limit to DDR3-1066 */ - if (freq > 533) { - freq = 533; - print_tf(__func__, ": 2 registered DIMMs on channel; limiting to DDR3-1066\n"); + } + } else { + if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) { + /* K10 BKDG Rev. 3.62 Table 34 */ + if (count > 2) { + /* Limit to DDR3-800 */ + if (freq > 400) { + freq = 400; + printk(BIOS_DEBUG, "%s: More than 2 registered DIMMs on %dmV channel; limiting to DDR3-800\n", __func__, voltage_index_to_mv(voltage)); + } + } else if (count == 2) { + /* Limit to DDR3-1066 */ + if (freq > 533) { + freq = 533; + printk(BIOS_DEBUG, "%s: 2 registered DIMMs on %dmV channel; limiting to DDR3-1066\n", __func__, voltage_index_to_mv(voltage)); + } + } else { + /* Limit to DDR3-1333 */ + if (freq > 666) { + freq = 666; + printk(BIOS_DEBUG, "%s: 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); + } } } else { + /* K10 BKDG Rev. 3.62 Table 33 */ /* Limit to DDR3-1333 */ if (freq > 666) { freq = 666; - print_tf(__func__, ": 1 registered DIMM on channel; limiting to DDR3-1333\n"); + printk(BIOS_DEBUG, "%s: unbuffered DIMMs on %dmV channel; limiting to DDR3-1333\n", __func__, voltage_index_to_mv(voltage)); } } - } else { - /* K10 BKDG Rev. 3.62 Table 33 */ - /* Limit to DDR3-1333 */ - if (freq > 666) { - freq = 666; - print_tf(__func__, ": unbuffered DIMMs on channel; limiting to DDR3-1333\n"); - } } } @@ -219,11 +475,13 @@ void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 node) } +#if IS_ENABLED(CONFIG_SET_FIDVID) static u8 mctGetProcessorPackageType(void) { /* FIXME: I guess this belongs wherever mctGetLogicalCPUID ends up ? */ - u32 BrandId = cpuid_ebx(0x80000001); - return (u8)((BrandId >> 28) & 0x0F); + u32 BrandId = cpuid_ebx(0x80000001); + return (u8)((BrandId >> 28) & 0x0F); } +#endif static void raminit_amdmct(struct sys_info *sysinfo) { |