Arthur Heymans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/35812 )
Change subject: [WIP]util/inteltool: Add dumping x4x timings ......................................................................
[WIP]util/inteltool: Add dumping x4x timings
TODO DQS RX settings.
Change-Id: I8816a3eb43b9a27ea09997e9cc0407c519485943 Signed-off-by: Arthur Heymans arthur@aheymans.xyz --- M util/inteltool/Makefile M util/inteltool/inteltool.h M util/inteltool/memory.c A util/inteltool/x4x_memory.c 4 files changed, 284 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/35812/1
diff --git a/util/inteltool/Makefile b/util/inteltool/Makefile index cd02fa8..6c7dc80 100644 --- a/util/inteltool/Makefile +++ b/util/inteltool/Makefile @@ -28,7 +28,7 @@ CPPFLAGS += -I$(top)/src/commonlib/include
OBJS = inteltool.o pcr.o cpu.o gpio.o gpio_groups.o rootcmplx.o powermgt.o \ - memory.o pcie.o amb.o ivy_memory.o spi.o gfx.o ahci.o \ + memory.o pcie.o amb.o ivy_memory.o spi.o gfx.o ahci.o x4x_memory.o \
OS_ARCH = $(shell uname) ifeq ($(OS_ARCH), Darwin) diff --git a/util/inteltool/inteltool.h b/util/inteltool/inteltool.h index fc6dc4b..cdd42da 100644 --- a/util/inteltool/inteltool.h +++ b/util/inteltool/inteltool.h @@ -400,5 +400,6 @@ int print_ahci(struct pci_dev *ahci); int print_sgx(void); void ivybridge_dump_timings(const char *dump_spd_file); +void x4x_dump_timings(void);
#endif diff --git a/util/inteltool/memory.c b/util/inteltool/memory.c index e80f1ba..6fe025d 100644 --- a/util/inteltool/memory.c +++ b/util/inteltool/memory.c @@ -200,6 +200,7 @@ case PCI_DEVICE_ID_INTEL_32X0: mchbar_phys = pci_read_long(nb, 0x48) & 0xfffffffe; mchbar_phys |= ((uint64_t)pci_read_long(nb, 0x4c)) << 32; + x4x_dump_timings(); break; case PCI_DEVICE_ID_INTEL_CORE_1ST_GEN: mchbar_phys = pci_read_long(nb, 0x48); diff --git a/util/inteltool/x4x_memory.c b/util/inteltool/x4x_memory.c new file mode 100644 index 0000000..a00ce82 --- /dev/null +++ b/util/inteltool/x4x_memory.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2014 Vladimir Serbinenko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 or (at your option) any later version of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include <errno.h> +#include "inteltool.h" + +extern volatile uint8_t *mchbar; + +struct dll_setting { + u8 tap; + u8 pi; + u8 db_en; + u8 db_sel; + u8 clk_delay; + u8 coarse; +}; + +static void print_dll_setting(char *s, const struct dll_setting *dll_setting) +{ + printf("\t%s: %x.%x.%x.%x:%x.%x\n", + s, + dll_setting->coarse, + dll_setting->clk_delay, + dll_setting->tap, + dll_setting->pi, + dll_setting->db_en, + dll_setting->db_sel); +} + + +static uint32_t read_mchbar32(uint32_t addr) +{ + return *(volatile uint32_t *)(mchbar + addr); +} + +static void get_clkset0(u8 channel, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = 0; + reg = read_mchbar32(0x400 * channel + 0x5a0); + setting->clk_delay = (reg >> 14) & 3; + setting->db_sel = (reg >> 6) & 1; + setting->db_en = (reg >> 10) & 1; + reg = read_mchbar32(0x400 * channel + 0x581); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_ctrlset0(u8 channel, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = 0; + reg = read_mchbar32(0x400 * channel + 0x59c); + setting->clk_delay = (reg >> 24) & 3; + setting->db_sel = (reg >> 20) & 1; + setting->db_en = (reg >> 21) & 1; + reg = read_mchbar32(0x400 * channel + 0x584); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_clkset1(u8 channel, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = 0; + reg = read_mchbar32(0x400 * channel + 0x5a0); + setting->clk_delay = (reg >> 16) & 3; + setting->db_sel = (reg >> 7) & 1; + setting->db_en = (reg >> 11) & 1; + reg = read_mchbar32(0x400 * channel + 0x582); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_cmdset(u8 channel, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = 0; + reg = read_mchbar32(0x400 * channel + 0x598); + setting->clk_delay = (reg >> 4) & 3; + reg = read_mchbar32(0x400 * channel + 0x594); + setting->db_sel = (reg >> 5) & 1; + setting->db_en = (reg >> 6) & 1; + reg = read_mchbar32(0x400 * channel + 0x580); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_ctrlset1(u8 channel, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = 0; + reg = read_mchbar32(0x400 * channel + 0x59c); + setting->clk_delay = (reg >> 27) & 3; + setting->db_sel = (reg >> 22) & 1; + setting->db_en = (reg >> 23) & 1; + reg = read_mchbar32(0x400 * channel + 0x585); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_ctrlset2(u8 channel, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = 0; + reg = read_mchbar32(0x400 * channel + 0x598); + setting->clk_delay = (reg >> 14) & 3; + setting->db_sel = (reg >> 12) & 1; + setting->db_en = (reg >> 13) & 1; + reg = read_mchbar32(0x400 * channel + 0x586); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_ctrlset3(u8 channel, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = 0; + reg = read_mchbar32(0x400 * channel + 0x598); + setting->clk_delay = (reg >> 10) & 3; + setting->db_sel = (reg >> 8) & 1; + setting->db_en = (reg >> 9) & 1; + reg = read_mchbar32(0x400 * channel + 0x587); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_dqs(u8 channel, u8 rank, u8 lane, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = (read_mchbar32(0x400 * channel + 0x5fc) >> (lane * 4 +1) & 1); + reg = read_mchbar32(0x400 * channel + rank * 4 + 0x5b4); + setting->db_sel = (reg >> lane) & 1; + setting->db_en = (reg >> (9 + lane)) & 1; + reg = read_mchbar32(0x400 * channel + rank * 4 + 0x5c8); + setting->clk_delay = (reg >> (16 + lane * 2)) & 3; + reg = read_mchbar32(0x400 * channel + rank + lane * 4 + 0x520); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +static void get_dq(u8 channel, u8 rank, u8 lane, struct dll_setting *setting) +{ + u32 reg; + setting->coarse = (read_mchbar32(0x400 * channel + 0x5fc) >> (lane * 4) & 1); + reg = read_mchbar32(0x400 * channel + rank * 4 + 0x5a4); + setting->db_sel = (reg >> lane) & 1; + setting->db_en = (reg >> (9 + lane)) & 1; + reg = read_mchbar32(0x400 * channel + rank * 4 + 0x5c8); + setting->clk_delay = (reg >> (lane * 2)) & 3; + reg = read_mchbar32(0x400 * channel + rank + lane * 4 + 0x500); + setting->pi = (reg >> 4) & 0xf; + setting->tap = reg & 0xf; +} + +void x4x_dump_timings(void) +{ + u32 reg = 0; + + printf("\nG45 Memory controller settings\n==============================\n\n"); + printf("Programmed timings:\n"); + switch (read_mchbar32(0xc00) & 0x7) { + case 0: + reg = 1066; + break; + case 2: + reg = 800; + break; + case 4: + reg = 1333; + break; + default: + printf("Unsupported FSB frequency.\n"); + break; + } + if (reg) + printf("\tFSB freq : %dMHZ\n", reg); + + u32 mem_clk = (read_mchbar32(0xc00) & 0x70) >> 4; + switch (mem_clk) { + case 0: + reg = 400; + break; + case 1: + reg = 533; + break; + case 2: + reg = 667; + break; + case 3: + reg = 800; + break; + case 4: + reg = 1066; + break; + case 5: + reg = 1333; + break; + default: + printf("Unsupported MEM frequency.\n"); + break; + } + if (reg) + printf("\tMEM freq : %dMT\n", reg); + + int is_ddr3 = (read_mchbar32(0x1a8) & 4) >> 2; + printf("\tDDR TYPE : %d\n", is_ddr3 ? 3 : 2); + + u8 tcas, tras, twl, twr, trrd, trp, trfc, trcd, twtr, trtp; + + for (int channel = 0; channel < 2; channel++) { + tcas = (read_mchbar32(0x240 + 0x400 * channel) & 0xf) + 3; + tras = read_mchbar32(0x25d + 0x400 * channel) & 0x3f; + twl = is_ddr3 ? (mem_clk - 3 + 5) : (tcas - 1U); + twr = ((read_mchbar32(0x250 + 0x400 * channel) >> 6) & 0x3f) - twl - 4; + trrd = (read_mchbar32(0x252 + 0x400 * channel) >> 17) & 0x1f; + trp = (read_mchbar32(0x252 + 0x400 * channel) >> 13) & 0x1f; + trfc = read_mchbar32(0x252 + 0x400 * channel) & 0x1ff; + trcd = (read_mchbar32(0x256 + 0x400 * channel) >> 12) & 0xf; + twtr = ((read_mchbar32(0x258 + 0x400 * channel) >> 12) & 0x1f) - 4 - twl; + trtp = ((read_mchbar32(0x250 + 0x400 * channel) >> 2) & 0xf) - 2; + + printf("Channel %d\n", channel); + printf("\ttCAS: %d\n", tcas); + printf("\ttRAS: %d\n", tras); + printf("\ttRP : %d\n", trp); + printf("\ttRCD: %d\n", trcd); + printf("\ttWR : %d\n", twr); + printf("\ttRFC: %d\n", trfc); + printf("\ttWTR: %d\n", twtr); + printf("\ttRRD: %d\n", trrd); + printf("\ttRTP: %d\n", trtp); + printf("\ttWL : %d\n", twl); + } + printf("\nProgrammed delays:\n"); + for (int channel = 0; channel < 2; channel++) { + printf("Channel %d\n", channel); + struct dll_setting setting; + char s[20]; + get_clkset0(channel, &setting); + print_dll_setting("clkset0 ", &setting); + get_ctrlset0(channel, &setting); + print_dll_setting("ctrlset0", &setting); + get_clkset1(channel, &setting); + print_dll_setting("clkset1 ", &setting); + get_cmdset(channel, &setting); + print_dll_setting("cmdset ", &setting); + get_ctrlset1(channel, &setting); + print_dll_setting("ctrlset1", &setting); + get_ctrlset2(channel, &setting); + print_dll_setting("ctrlset2", &setting); + get_ctrlset3(channel, &setting); + print_dll_setting("ctrlset3", &setting); + for (int lane = 0; lane < 8; lane++) { + sprintf(s, "DQS%d ", lane); + /* All rank should be programmed the same */ + get_dqs(channel, 0, lane, &setting); + print_dll_setting(s, &setting); + } + for (int lane = 0; lane < 8; lane++) { + sprintf(s, "DQ%d ", lane); + /* All rank should be programmed the same */ + get_dq(channel, 0, lane, &setting); + print_dll_setting(s, &setting); + } + } +}