diff options
author | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2016-05-03 15:53:33 -0700 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2016-05-17 21:38:17 +0200 |
commit | 4bab6e79b078c76d0a42883c4b4c9c68615d5a1e (patch) | |
tree | 2c7dda58587f464fa1baee712c95bb48c924ff76 /src/soc/intel/sch/raminit.c | |
parent | 083da160af4a0e3a76506af59477f105d78b9683 (diff) |
intel/sch: Merge northbridge and southbridge in src/soc
Change-Id: I6ea9b9d2353c0d767c837e6d629b45f23b306f6e
Signed-off-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Reviewed-on: https://review.coreboot.org/14599
Tested-by: build bot (Jenkins)
Reviewed-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
Diffstat (limited to 'src/soc/intel/sch/raminit.c')
-rw-r--r-- | src/soc/intel/sch/raminit.c | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/src/soc/intel/sch/raminit.c b/src/soc/intel/sch/raminit.c new file mode 100644 index 0000000000..d5ec4ef8ad --- /dev/null +++ b/src/soc/intel/sch/raminit.c @@ -0,0 +1,373 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009-2010 iWave Systems + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <string.h> +#include <cpu/x86/mtrr.h> +#include <cpu/x86/cache.h> +#include <spd.h> +#include "raminit.h" +#include "sch.h" + +#define DEBUG_RAM_SETUP +#define SOFTSTRSP(base, off) *((volatile u8 *)((base) + (off))) + +/* Debugging macros. */ +#if defined(DEBUG_RAM_SETUP) +#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x) +#else +#define PRINTK_DEBUG(x...) +#endif + +#define BOOT_MODE_RESUME 1 +#define BOOT_MODE_NORMAL 0 + +#include "port_access.c" + +static void detect_fsb(struct sys_info *sysinfo) +{ + u32 reg32; + + reg32 = sch_port_access_read(5, 3, 4); + if (reg32 & BIT(3)) + sysinfo->fsb_frequency = 533; + else + sysinfo->fsb_frequency = 400; +} + +static u32 detect_softstrap_base(void) +{ + u32 reg32, base_addr; + + reg32 = sch_port_access_read(4, 0x71, 2); + reg32 &= 0x700; + reg32 = reg32 >> 7; + switch (reg32) { + case 7: + base_addr = 0xFFFB0000; + break; + case 6: + base_addr = 0xFFFC0000; + break; + case 5: + base_addr = 0xFFFD0000; + break; + case 4: + base_addr = 0xFFFE0000; + break; + default: + base_addr = 0; + die("No valid softstrap base found.\n"); + } + return base_addr; +} + +static void detect_softstraps(struct sys_info *sysinfo) +{ + u8 reg8, temp; + u32 sbase = detect_softstrap_base(); + + reg8 = SOFTSTRSP(sbase, 0x87f2); + sysinfo->ranks = reg8; + if (reg8 == 0) { + sysinfo->ram_param_source = RAM_PARAM_SOURCE_SPD; + /* FIXME: Implement SPD reading. */ + die("No support for reading DIMM config from SPD yet!"); + return; + } else { + sysinfo->ram_param_source = RAM_PARAM_SOURCE_SOFTSTRAP; + /* Timings from soft strap */ + reg8 = SOFTSTRSP(sbase, 0x87f0); + temp = reg8 & 0x30; + temp = temp >> 4; + sysinfo->cl = temp; + temp = reg8 & 0x0c; + temp = temp >> 2; + sysinfo->trcd = temp; + temp = reg8 & 0x03; + sysinfo->trp = temp; + + /* Geometry from Softstrap */ + reg8 = SOFTSTRSP(sbase, 0x87f1); + + temp = reg8 & 0x06; + temp = temp >> 1; + sysinfo->device_density = temp; + + temp = reg8 & 0x01; + sysinfo->data_width = temp; + + /* Refresh rate default 7.8us */ + sysinfo->refresh = 3; + } +} + +static void program_sch_dram_data(struct sys_info *sysinfo) +{ + u32 reg32; + + /* + * Program DRP DRAM Rank Population and Interface Register as per data + * in sysinfo SCH port 1 register 0..0xFF. + */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4); + reg32 &= ~(DRP_FIELDS); /* Clear all DRP fields we'll change. */ + /* Rank0 Device Width, Density, Enable */ + reg32 |= sysinfo->data_width | (sysinfo->device_density << 1) | (1 << 3); + /* Rank1 Device Width, Density, Enable */ + reg32 |= (sysinfo->data_width << 4) + | ((sysinfo->device_density) << 5) | (1 << 7); + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4, reg32); + + /* + * Program DTR DRAM Timing Register as per data in sysinfo SCH port 1 + * register 1. + * + * tRD_dly = 2 (15:13 = 010b) + * 0X3F + */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4); + reg32 &= ~(DTR_FIELDS); /* Clear all DTR fields we'll change. */ + + reg32 = (sysinfo->trp); + reg32 |= (sysinfo->trcd) << 2; + reg32 |= (sysinfo->cl) << 4; + reg32 |= 0X4000; /* tRD_dly = 2 (15:13 = 010b) */ + sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DTR, 4, + reg32); + + /* + * DCO DRAM Controller Operation Register as per data in sysinfo + * SCH port 1 register 2 0xF. + */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4); + reg32 &= ~(DCO_FIELDS); /* Clear all DTR fields we'll change. */ + + if (sysinfo->fsb_frequency == 533) + reg32 |= 1; + else + reg32 &= ~(BIT(0)); + reg32 = 0x006911c; // FIXME ? + + sch_port_access_write(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4, + reg32); +} + +static void program_dll_config(struct sys_info *sysinfo) +{ + if (sysinfo->fsb_frequency == 533) { + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x46464646); + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x46464646); + } else { + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x21, 4, 0x58585858); + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x22, 4, 0x58585858); + } + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x23, 4, 0x2222); + if (sysinfo->fsb_frequency == 533) + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0x993B); + else + sch_port_access_write(SCH_MSG_DUNIT_PORT, 0x20, 4, 0xCC3B); +} + +static void do_jedec_init(struct sys_info *sysinfo) +{ + u32 reg32, rank, cmd, temp, num_ranks; + + /* Performs JEDEC memory initializattion for all memory rows */ + /* Set CKE0/1 low */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4); + reg32 |= DRP_CKE_DIS; + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4, reg32); + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DRP, 4); + rank = 0; + num_ranks = sysinfo->ranks; + + do { + /* Start clocks */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + reg32 &= ~(DRP_SCK_DIS); /* Enable all SCK/SCKB by def. */ + sch_port_access_write(1, SCH_MSG_DUNIT_REG_DRP, 4, reg32); + /* Program misc. SCH registers on rank 0 initialization. */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + if (rank == 0) + program_dll_config(sysinfo); + + printk(BIOS_DEBUG, "Setting up RAM \n"); + + /* + * Wait 200us + * reg32 = inb(ACPI_BASE + 8); PM1 Timer + * reg32 &=0xFFFFFF; + * reg32 +=0x2EE; + * do { + * reg32 = inb(ACPI_BASE + 8);PM1 Timer + * reg32 &= 0xFFFFFF; + * } while (reg32 < 0x2EE); + */ + + /* Apply NOP. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_NOP; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + /* Set CKE=high. */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + reg32 &= 0xFFFF9FFF; /* Clear both the CKE static disables. */ + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4, reg32); + /* + * Wait 400ns (not needed when executing from flash). + * Precharge all. + */ + reg32 = sch_port_access_read(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DRP, 4); + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_PALL; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* + * EMRS(2); High temp self refresh=disabled, + * partial array self refresh=full. + */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS2; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* EMRS(3) (no command). */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS3; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* EMRS(1); Enable DLL (Leave all bits in the command at 0). */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS1; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* MRS; Reset DLL (Set memory address bit 8). */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_MRS; + cmd |= (SCH_JEDEC_DLLRESET << SCH_DRAMINIT_ADDR_OFFSET); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* Precharge all. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_PALL; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* Issue 2 auto-refresh commands. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_AREF; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* MRS command including tCL, tWR, burst length (always 4). */ + cmd = rank; + cmd |= (SCH_DRAMINIT_CMD_MRS + JEDEC_STATIC_PARAM); /* Static param */ + temp = sysinfo->cl; + temp += TCL_LOW; /* Adjust for the TCL base. */ + temp = temp << ((SCH_JEDEC_CL_OFFSET + + SCH_DRAMINIT_ADDR_OFFSET)); /* Ready the CAS latency */ + cmd |= temp; + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* + * Wait 200 clocks (max of 1us, so no need to delay). + * Issue EMRS(1):OCD default. + */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS1; + cmd |= (SCH_JEDEC_OCD_DEFAULT << SCH_DRAMINIT_ADDR_OFFSET); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + + /* Issue EMRS(1): OCD cal. mode exit. */ + cmd = rank; + cmd |= SCH_DRAMINIT_CMD_EMRS1; + cmd |= (SCH_JEDEC_DQS_DIS << SCH_DRAMINIT_ADDR_OFFSET); + sch_port_access_write_ram_cmd(SCH_OPCODE_DRAMINIT, + SCH_MSG_DUNIT_PORT, 0, cmd); + rank += SCH_DRAMINIT_RANK_MASK; + num_ranks--; + } while (num_ranks); +} + +/** + * @param boot_mode 0 = normal, 1 = resume + */ +void sdram_initialize(int boot_mode) +{ + struct sys_info sysinfo; + u32 reg32; + + printk(BIOS_DEBUG, "Setting up RAM controller.\n"); + + memset(&sysinfo, 0, sizeof(sysinfo)); + + detect_fsb(&sysinfo); + detect_softstraps(&sysinfo); + + program_sch_dram_data(&sysinfo); + + /* cold boot */ + if (boot_mode == BOOT_MODE_NORMAL) + do_jedec_init(&sysinfo); + else + program_dll_config(&sysinfo); + + /* RAM init complete. */ + reg32 = + sch_port_access_read(SCH_MSG_DUNIT_PORT, SCH_MSG_DUNIT_REG_DCO, 4); + reg32 |= DCO_IC; + reg32 |= ((sysinfo.refresh) << 2); + reg32 = 0x006919c; + sch_port_access_write(SCH_MSG_DUNIT_PORT, + SCH_MSG_DUNIT_REG_DCO, 4, reg32); + + /* Setting up TOM. */ + reg32 = 0x10000000; + reg32 = reg32 >> sysinfo.data_width; + reg32 = reg32 << sysinfo.device_density; + reg32 = reg32 << sysinfo.ranks; + reg32 = 0x40000000; + sch_port_access_write(2, 8, 4, reg32); + + /* Resume mode. */ + if (boot_mode == BOOT_MODE_RESUME) + sch_port_access_write_ram_cmd(SCH_OPCODE_WAKEFULLON, + SCH_MSG_DUNIT_PORT, 0, 0); + + sch_port_access_write(2, 0, 4, 0x98); + sch_port_access_write(2, 3, 4, 0x7); + sch_port_access_write(3, 2, 4, 0x408); + sch_port_access_write(4, 0x71, 4, 0x600); +} |